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
bdb74e16
Unverified
Commit
bdb74e16
authored
Sep 02, 2022
by
LongCatIsLooong
Committed by
GitHub
Sep 02, 2022
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Fix `Action.overridable` example (#110824)
parent
3c5a0747
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
104 additions
and
126 deletions
+104
-126
action.action_overridable.0.dart
.../api/lib/widgets/actions/action.action_overridable.0.dart
+43
-120
action.action_overridable.0_test.dart
...est/widgets/actions/action.action_overridable.0_test.dart
+51
-0
actions.dart
packages/flutter/lib/src/widgets/actions.dart
+10
-6
No files found.
examples/api/lib/widgets/actions/action.action_overridable.0.dart
View file @
bdb74e16
...
...
@@ -11,150 +11,73 @@ void main() {
runApp
(
const
MaterialApp
(
home:
Scaffold
(
body:
Center
(
child:
SimpleUSPhoneNumberEntry
()),
body:
Center
(
child:
VerificationCodeGenerator
()),
),
),
);
}
// This implements a custom phone number input field that handles the
// [DeleteCharacterIntent] intent.
class
DigitInput
extends
StatefulWidget
{
const
DigitInput
({
super
.
key
,
required
this
.
controller
,
required
this
.
focusNode
,
this
.
maxLength
,
this
.
textInputAction
=
TextInputAction
.
next
,
});
const
CopyTextIntent
copyTextIntent
=
CopyTextIntent
.
_
();
class
CopyTextIntent
extends
Intent
{
const
CopyTextIntent
.
_
();
}
final
int
?
maxLength
;
final
TextEditingController
controller
;
final
TextInputAction
textInputAction
;
final
FocusNode
focusNode
;
class
CopyableText
extends
StatelessWidget
{
const
CopyableText
({
super
.
key
,
required
this
.
text
});
@override
DigitInputState
createState
()
=>
DigitInputState
();
}
final
String
text
;
class
DigitInputState
extends
State
<
DigitInput
>
{
late
final
Action
<
DeleteCharacterIntent
>
_deleteTextAction
=
CallbackAction
<
DeleteCharacterIntent
>(
onInvoke:
(
DeleteCharacterIntent
intent
)
{
// For simplicity we delete everything in the section.
widget
.
controller
.
clear
();
return
null
;
},
);
void
_copy
(
CopyTextIntent
intent
)
=>
Clipboard
.
setData
(
ClipboardData
(
text:
text
));
@override
Widget
build
(
BuildContext
context
)
{
return
Actions
(
actions:
<
Type
,
Action
<
Intent
>>{
// Make the default `DeleteCharacterIntent` handler overridable.
DeleteCharacterIntent:
Action
<
DeleteCharacterIntent
>.
overridable
(
defaultAction:
_deleteTextAction
,
context:
context
),
},
child:
TextField
(
controller:
widget
.
controller
,
textInputAction:
TextInputAction
.
next
,
keyboardType:
TextInputType
.
phone
,
focusNode:
widget
.
focusNode
,
decoration:
const
InputDecoration
(
border:
OutlineInputBorder
(),
final
Action
<
CopyTextIntent
>
defaultCopyAction
=
CallbackAction
<
CopyTextIntent
>(
onInvoke:
_copy
);
return
Shortcuts
(
shortcuts:
const
<
ShortcutActivator
,
Intent
>
{
SingleActivator
(
LogicalKeyboardKey
.
keyC
,
control:
true
)
:
copyTextIntent
},
child:
Actions
(
actions:
<
Type
,
Action
<
Intent
>>
{
/// The Action is made overridable so the VerificationCodeGenerator
/// widget can override how copying is handled.
CopyTextIntent:
Action
<
CopyTextIntent
>.
overridable
(
defaultAction:
defaultCopyAction
,
context:
context
),
},
child:
Focus
(
autofocus:
true
,
child:
DefaultTextStyle
.
merge
(
style:
const
TextStyle
(
fontSize:
20
,
fontWeight:
FontWeight
.
bold
),
child:
Text
(
text
),
),
),
inputFormatters:
<
TextInputFormatter
>[
FilteringTextInputFormatter
.
digitsOnly
,
LengthLimitingTextInputFormatter
(
widget
.
maxLength
),
],
),
);
}
}
class
SimpleUSPhoneNumberEntry
extends
StatefulWidget
{
const
SimpleUSPhoneNumberEntry
({
super
.
key
});
@override
State
<
SimpleUSPhoneNumberEntry
>
createState
()
=>
_SimpleUSPhoneNumberEntryState
();
}
class
_DeleteDigit
extends
Action
<
DeleteCharacterIntent
>
{
_DeleteDigit
(
this
.
state
);
class
VerificationCodeGenerator
extends
StatelessWidget
{
const
VerificationCodeGenerator
({
super
.
key
});
final
_SimpleUSPhoneNumberEntryState
state
;
@override
void
invoke
(
DeleteCharacterIntent
intent
)
{
assert
(
callingAction
!=
null
);
callingAction
?.
invoke
(
intent
);
if
(
state
.
lineNumberController
.
text
.
isEmpty
&&
state
.
lineNumberFocusNode
.
hasFocus
)
{
state
.
prefixFocusNode
.
requestFocus
();
}
if
(
state
.
prefixController
.
text
.
isEmpty
&&
state
.
prefixFocusNode
.
hasFocus
)
{
state
.
areaCodeFocusNode
.
requestFocus
();
}
void
_copy
(
CopyTextIntent
intent
)
{
debugPrint
(
'Content copied'
);
Clipboard
.
setData
(
const
ClipboardData
(
text:
'111222333'
));
}
// This action is only enabled when the `callingAction` exists and is
// enabled.
@override
bool
get
isActionEnabled
=>
callingAction
?.
isActionEnabled
??
false
;
}
class
_SimpleUSPhoneNumberEntryState
extends
State
<
SimpleUSPhoneNumberEntry
>
{
final
FocusNode
areaCodeFocusNode
=
FocusNode
();
final
TextEditingController
areaCodeController
=
TextEditingController
();
final
FocusNode
prefixFocusNode
=
FocusNode
();
final
TextEditingController
prefixController
=
TextEditingController
();
final
FocusNode
lineNumberFocusNode
=
FocusNode
();
final
TextEditingController
lineNumberController
=
TextEditingController
();
@override
Widget
build
(
BuildContext
context
)
{
return
Actions
(
actions:
<
Type
,
Action
<
Intent
>>{
DeleteCharacterIntent:
_DeleteDigit
(
this
),
},
child:
Row
(
mainAxisAlignment:
MainAxisAlignment
.
spaceBetween
,
actions:
<
Type
,
Action
<
Intent
>>
{
CopyTextIntent:
CallbackAction
<
CopyTextIntent
>(
onInvoke:
_copy
)
},
child:
Column
(
mainAxisAlignment:
MainAxisAlignment
.
center
,
children:
<
Widget
>[
const
Expanded
(
child:
Text
(
'('
,
textAlign:
TextAlign
.
center
),
),
Expanded
(
flex:
3
,
child:
DigitInput
(
focusNode:
areaCodeFocusNode
,
controller:
areaCodeController
,
maxLength:
3
,
),
),
const
Expanded
(
child:
Text
(
')'
,
textAlign:
TextAlign
.
center
),
),
Expanded
(
flex:
3
,
child:
DigitInput
(
focusNode:
prefixFocusNode
,
controller:
prefixController
,
maxLength:
3
,
),
),
const
Expanded
(
child:
Text
(
'-'
,
textAlign:
TextAlign
.
center
),
),
Expanded
(
flex:
4
,
child:
DigitInput
(
focusNode:
lineNumberFocusNode
,
controller:
lineNumberController
,
textInputAction:
TextInputAction
.
done
,
maxLength:
4
,
),
const
Text
(
'Press Ctrl-C to Copy'
),
const
SizedBox
(
height:
10
),
Row
(
mainAxisAlignment:
MainAxisAlignment
.
center
,
children:
const
<
Widget
>[
CopyableText
(
text:
'111'
),
SizedBox
(
width:
5
,),
CopyableText
(
text:
'222'
),
SizedBox
(
width:
5
,),
CopyableText
(
text:
'333'
),
],
),
],
),
...
...
examples/api/test/widgets/actions/action.action_overridable.0_test.dart
0 → 100644
View file @
bdb74e16
// Copyright 2014 The Flutter 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
'package:flutter/services.dart'
;
import
'package:flutter_api_samples/widgets/actions/action.action_overridable.0.dart'
as
example
;
import
'package:flutter_test/flutter_test.dart'
;
void
main
(
)
{
TestWidgetsFlutterBinding
.
ensureInitialized
();
final
_MockClipboard
mockClipboard
=
_MockClipboard
();
testWidgets
(
'Copies text on Ctrl-C'
,
(
WidgetTester
tester
)
async
{
tester
.
binding
.
defaultBinaryMessenger
.
setMockMethodCallHandler
(
SystemChannels
.
platform
,
mockClipboard
.
handleMethodCall
);
await
tester
.
pumpWidget
(
const
MaterialApp
(
home:
Scaffold
(
body:
Center
(
child:
example
.
VerificationCodeGenerator
()),
),
),
);
expect
(
primaryFocus
,
isNotNull
);
expect
(
mockClipboard
.
clipboardData
,
isNull
);
await
tester
.
sendKeyDownEvent
(
LogicalKeyboardKey
.
control
);
await
tester
.
sendKeyDownEvent
(
LogicalKeyboardKey
.
keyC
);
await
tester
.
sendKeyUpEvent
(
LogicalKeyboardKey
.
control
);
await
tester
.
sendKeyUpEvent
(
LogicalKeyboardKey
.
keyC
);
expect
(
mockClipboard
.
clipboardData
?[
'text'
],
'111222333'
);
});
}
class
_MockClipboard
{
_MockClipboard
();
Map
<
String
,
dynamic
>?
clipboardData
;
Future
<
Object
?>
handleMethodCall
(
MethodCall
methodCall
)
async
{
switch
(
methodCall
.
method
)
{
case
'Clipboard.setData'
:
clipboardData
=
methodCall
.
arguments
as
Map
<
String
,
dynamic
>;
return
null
;
}
if
(
methodCall
.
method
.
startsWith
(
'Clipboard'
))
{
throw
StateError
(
'unrecognized method call:
${methodCall.method}
'
);
}
return
null
;
}
}
packages/flutter/lib/src/widgets/actions.dart
View file @
bdb74e16
...
...
@@ -145,12 +145,16 @@ abstract class Action<T extends Intent> with Diagnosticable {
/// parent widgets that also support this [Intent].
///
/// {@tool dartpad}
/// This sample implements a custom text input field that handles the
/// [DeleteCharacterIntent] intent, as well as a US telephone number input
/// widget that consists of multiple text fields for area code, prefix and line
/// number. When the backspace key is pressed, the phone number input widget
/// sends the focus to the preceding text field when the currently focused
/// field becomes empty.
/// This sample shows how to implement a rudimentary `CopyableText` widget
/// that responds to Ctrl-C by copying its own content to the clipboard.
///
/// if `CopyableText` is to be provided in a package, developers using the
/// widget may want to change how copying is handled. As the author of the
/// package, you can enable that by making the corresponding [Action]
/// overridable. In the second part of the code sample, three `CopyableText`
/// widgets are used to build a verification code widget which overrides the
/// "copy" action by copying the combined numbers from all three `CopyableText`
/// widgets.
///
/// ** See code in examples/api/lib/widgets/actions/action.action_overridable.0.dart **
/// {@end-tool}
...
...
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