Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in
Toggle navigation
F
Front-End
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
abdullh.alsoleman
Front-End
Commits
0768ea97
Commit
0768ea97
authored
Sep 25, 2015
by
Adam Barth
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #1341 from abarth/fn3_editing
Port Input and EditableText to fn3
parents
5f9cb4aa
481b764f
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
365 additions
and
0 deletions
+365
-0
fn3.dart
packages/flutter/lib/src/fn3.dart
+2
-0
editable_text.dart
packages/flutter/lib/src/fn3/editable_text.dart
+235
-0
input.dart
packages/flutter/lib/src/fn3/input.dart
+128
-0
No files found.
packages/flutter/lib/src/fn3.dart
View file @
0768ea97
...
...
@@ -18,6 +18,7 @@ export 'fn3/drawer.dart';
export
'fn3/drawer_divider.dart'
;
export
'fn3/drawer_header.dart'
;
export
'fn3/drawer_item.dart'
;
export
'fn3/editable_text.dart'
;
export
'fn3/flat_button.dart'
;
export
'fn3/floating_action_button.dart'
;
export
'fn3/focus.dart'
;
...
...
@@ -27,6 +28,7 @@ export 'fn3/homogeneous_viewport.dart';
export
'fn3/icon.dart'
;
export
'fn3/icon_button.dart'
;
export
'fn3/ink_well.dart'
;
export
'fn3/input.dart'
;
export
'fn3/material.dart'
;
export
'fn3/material_button.dart'
;
export
'fn3/mixed_viewport.dart'
;
...
...
packages/flutter/lib/src/fn3/editable_text.dart
0 → 100644
View file @
0768ea97
// 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
'dart:async'
;
import
'dart:sky'
as
sky
;
import
'package:mojo_services/keyboard/keyboard.mojom.dart'
;
import
'package:sky/painting.dart'
;
import
'package:sky/src/fn3/basic.dart'
;
import
'package:sky/src/fn3/framework.dart'
;
const
_kCursorBlinkPeriod
=
500
;
// milliseconds
const
_kCursorGap
=
1.0
;
const
_kCursorHeightOffset
=
2.0
;
const
_kCursorWidth
=
1.0
;
typedef
void
StringUpdated
(
);
class
TextRange
{
final
int
start
;
final
int
end
;
TextRange
({
this
.
start
,
this
.
end
});
TextRange
.
collapsed
(
int
position
)
:
start
=
position
,
end
=
position
;
const
TextRange
.
empty
()
:
start
=
-
1
,
end
=
-
1
;
bool
get
isValid
=>
start
>=
0
&&
end
>=
0
;
bool
get
isCollapsed
=>
start
==
end
;
}
class
EditableString
implements
KeyboardClient
{
String
text
;
TextRange
composing
=
const
TextRange
.
empty
();
TextRange
selection
=
const
TextRange
.
empty
();
final
StringUpdated
onUpdated
;
KeyboardClientStub
stub
;
EditableString
({
this
.
text
:
''
,
this
.
onUpdated
})
{
stub
=
new
KeyboardClientStub
.
unbound
()..
impl
=
this
;
}
String
textBefore
(
TextRange
range
)
{
return
text
.
substring
(
0
,
range
.
start
);
}
String
textAfter
(
TextRange
range
)
{
return
text
.
substring
(
range
.
end
);
}
String
textInside
(
TextRange
range
)
{
return
text
.
substring
(
range
.
start
,
range
.
end
);
}
void
_delete
(
TextRange
range
)
{
if
(
range
.
isCollapsed
||
!
range
.
isValid
)
return
;
text
=
textBefore
(
range
)
+
textAfter
(
range
);
}
TextRange
_append
(
String
newText
)
{
int
start
=
text
.
length
;
text
+=
newText
;
return
new
TextRange
(
start:
start
,
end:
start
+
newText
.
length
);
}
TextRange
_replace
(
TextRange
range
,
String
newText
)
{
assert
(
range
.
isValid
);
String
before
=
textBefore
(
range
);
String
after
=
textAfter
(
range
);
text
=
before
+
newText
+
after
;
return
new
TextRange
(
start:
before
.
length
,
end:
before
.
length
+
newText
.
length
);
}
TextRange
_replaceOrAppend
(
TextRange
range
,
String
newText
)
{
if
(!
range
.
isValid
)
return
_append
(
newText
);
return
_replace
(
range
,
newText
);
}
void
commitCompletion
(
CompletionData
completion
)
{
// TODO(abarth): Not implemented.
}
void
commitCorrection
(
CorrectionData
correction
)
{
// TODO(abarth): Not implemented.
}
void
commitText
(
String
text
,
int
newCursorPosition
)
{
// TODO(abarth): Why is |newCursorPosition| always 1?
TextRange
committedRange
=
_replaceOrAppend
(
composing
,
text
);
selection
=
new
TextRange
.
collapsed
(
committedRange
.
end
);
composing
=
const
TextRange
.
empty
();
onUpdated
();
}
void
deleteSurroundingText
(
int
beforeLength
,
int
afterLength
)
{
TextRange
beforeRange
=
new
TextRange
(
start:
selection
.
start
-
beforeLength
,
end:
selection
.
start
);
TextRange
afterRange
=
new
TextRange
(
start:
selection
.
end
,
end:
selection
.
end
+
afterLength
);
_delete
(
afterRange
);
_delete
(
beforeRange
);
selection
=
new
TextRange
(
start:
selection
.
start
-
beforeLength
,
end:
selection
.
end
-
beforeLength
);
onUpdated
();
}
void
setComposingRegion
(
int
start
,
int
end
)
{
composing
=
new
TextRange
(
start:
start
,
end:
end
);
onUpdated
();
}
void
setComposingText
(
String
text
,
int
newCursorPosition
)
{
// TODO(abarth): Why is |newCursorPosition| always 1?
composing
=
_replaceOrAppend
(
composing
,
text
);
selection
=
new
TextRange
.
collapsed
(
composing
.
end
);
onUpdated
();
}
void
setSelection
(
int
start
,
int
end
)
{
selection
=
new
TextRange
(
start:
start
,
end:
end
);
onUpdated
();
}
}
class
EditableText
extends
StatefulComponent
{
EditableText
({
Key
key
,
this
.
value
,
this
.
focused
:
false
,
this
.
style
,
this
.
cursorColor
})
:
super
(
key:
key
);
final
EditableString
value
;
final
bool
focused
;
final
TextStyle
style
;
final
Color
cursorColor
;
EditableTextState
createState
()
=>
new
EditableTextState
();
}
class
EditableTextState
extends
State
<
EditableText
>
{
Timer
_cursorTimer
;
bool
_showCursor
=
false
;
/// Whether the blinking cursor is visible (exposed for testing).
bool
get
test_showCursor
=>
_showCursor
;
/// The cursor blink interval (exposed for testing).
Duration
get
test_cursorBlinkPeriod
=>
new
Duration
(
milliseconds:
_kCursorBlinkPeriod
);
void
_cursorTick
(
Timer
timer
)
{
setState
(()
{
_showCursor
=
!
_showCursor
;
});
}
void
_startCursorTimer
()
{
_showCursor
=
true
;
_cursorTimer
=
new
Timer
.
periodic
(
new
Duration
(
milliseconds:
_kCursorBlinkPeriod
),
_cursorTick
);
}
void
dispose
()
{
if
(
_cursorTimer
!=
null
)
_stopCursorTimer
();
super
.
dispose
();
}
void
_stopCursorTimer
()
{
_cursorTimer
.
cancel
();
_cursorTimer
=
null
;
_showCursor
=
false
;
}
void
_paintCursor
(
sky
.
Canvas
canvas
,
Size
size
)
{
if
(!
_showCursor
)
return
;
double
cursorHeight
=
config
.
style
.
fontSize
+
2.0
*
_kCursorHeightOffset
;
Rect
cursorRect
=
new
Rect
.
fromLTWH
(
_kCursorGap
,
(
size
.
height
-
cursorHeight
)
/
2.0
,
_kCursorWidth
,
cursorHeight
);
canvas
.
drawRect
(
cursorRect
,
new
Paint
()..
color
=
config
.
cursorColor
);
}
Widget
build
(
BuildContext
context
)
{
assert
(
config
.
style
!=
null
);
assert
(
config
.
focused
!=
null
);
assert
(
config
.
cursorColor
!=
null
);
if
(
config
.
focused
&&
_cursorTimer
==
null
)
_startCursorTimer
();
else
if
(!
config
.
focused
&&
_cursorTimer
!=
null
)
_stopCursorTimer
();
final
EditableString
value
=
config
.
value
;
final
TextStyle
style
=
config
.
style
;
Widget
text
;
if
(
value
.
composing
.
isValid
)
{
TextStyle
composingStyle
=
style
.
merge
(
const
TextStyle
(
decoration:
underline
));
text
=
new
StyledText
(
elements:
[
style
,
value
.
textBefore
(
value
.
composing
),
[
composingStyle
,
value
.
textInside
(
value
.
composing
)],
value
.
textAfter
(
value
.
composing
)
]);
}
else
{
// TODO(eseidel): This is the wrong height if empty!
text
=
new
Text
(
value
.
text
,
style:
style
);
}
Widget
cursor
=
new
Container
(
height:
style
.
fontSize
*
style
.
height
,
width:
_kCursorGap
+
_kCursorWidth
,
child:
new
CustomPaint
(
callback:
_paintCursor
,
token:
_showCursor
)
);
return
new
Row
([
text
,
cursor
]);
}
}
packages/flutter/lib/src/fn3/input.dart
0 → 100644
View file @
0768ea97
// 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/services.dart'
;
import
'package:sky/painting.dart'
;
import
'package:sky/src/fn3/basic.dart'
;
import
'package:sky/src/fn3/editable_text.dart'
;
import
'package:sky/src/fn3/focus.dart'
;
import
'package:sky/src/fn3/framework.dart'
;
import
'package:sky/src/fn3/theme.dart'
;
export
'package:sky/services.dart'
show
KeyboardType
;
typedef
void
StringValueChanged
(
String
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
{
Input
({
GlobalKey
key
,
this
.
initialValue
:
''
,
this
.
placeholder
,
this
.
onChanged
,
this
.
keyboardType
:
KeyboardType
.
TEXT
}):
super
(
key:
key
);
final
String
initialValue
;
final
KeyboardType
keyboardType
;
final
String
placeholder
;
final
StringValueChanged
onChanged
;
InputState
createState
()
=>
new
InputState
();
}
class
InputState
extends
State
<
Input
>
{
String
_value
;
EditableString
_editableValue
;
KeyboardHandle
_keyboardHandle
=
KeyboardHandle
.
unattached
;
void
initState
(
BuildContext
context
)
{
super
.
initState
(
context
);
_value
=
config
.
initialValue
;
_editableValue
=
new
EditableString
(
text:
_value
,
onUpdated:
_handleTextUpdated
);
}
void
_handleTextUpdated
()
{
if
(
_value
!=
_editableValue
.
text
)
{
setState
(()
{
_value
=
_editableValue
.
text
;
});
if
(
config
.
onChanged
!=
null
)
config
.
onChanged
(
_value
);
}
}
Widget
build
(
BuildContext
context
)
{
ThemeData
themeData
=
Theme
.
of
(
context
);
bool
focused
=
FocusState
.
at
(
context
,
config
);
if
(
focused
&&
!
_keyboardHandle
.
attached
)
{
_keyboardHandle
=
keyboard
.
show
(
_editableValue
.
stub
,
config
.
keyboardType
);
}
else
if
(!
focused
&&
_keyboardHandle
.
attached
)
{
_keyboardHandle
.
release
();
}
TextStyle
textStyle
=
themeData
.
text
.
subhead
;
List
<
Widget
>
textChildren
=
<
Widget
>[];
if
(
config
.
placeholder
!=
null
&&
_value
.
isEmpty
)
{
Widget
child
=
new
Opacity
(
key:
const
ValueKey
<
String
>(
'placeholder'
),
child:
new
Text
(
config
.
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:
(
_
)
{
if
(
FocusState
.
at
(
context
,
config
))
{
assert
(
_keyboardHandle
.
attached
);
_keyboardHandle
.
showByRequest
();
}
else
{
FocusState
.
moveTo
(
context
,
config
);
// we'll get told to rebuild and we'll take care of the keyboard then
}
}
);
}
void
dispose
()
{
if
(
_keyboardHandle
.
attached
)
_keyboardHandle
.
release
();
super
.
dispose
();
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment