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
d5a10340
Unverified
Commit
d5a10340
authored
May 24, 2018
by
Michael Goderbauer
Committed by
GitHub
May 24, 2018
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Expandable Search (#17629)
parent
711174a9
Changes
66
Show whitespace changes
Inline
Side-by-side
Showing
66 changed files
with
1412 additions
and
57 deletions
+1412
-57
material.dart
examples/flutter_gallery/lib/demo/material/material.dart
+1
-0
search_demo.dart
examples/flutter_gallery/lib/demo/material/search_demo.dart
+287
-0
demos.dart
examples/flutter_gallery/lib/gallery/demos.dart
+8
-0
material.dart
packages/flutter/lib/material.dart
+1
-0
material_localizations.dart
...ages/flutter/lib/src/material/material_localizations.dart
+7
-0
search.dart
packages/flutter/lib/src/material/search.dart
+442
-0
localizations_test.dart
packages/flutter/test/material/localizations_test.dart
+1
-0
search_test.dart
packages/flutter/test/material/search_test.dart
+519
-0
localizations.dart
...ges/flutter_localizations/lib/src/l10n/localizations.dart
+26
-0
material_ar.arb
packages/flutter_localizations/lib/src/l10n/material_ar.arb
+2
-1
material_de.arb
packages/flutter_localizations/lib/src/l10n/material_de.arb
+2
-1
material_de_CH.arb
...ges/flutter_localizations/lib/src/l10n/material_de_CH.arb
+2
-1
material_en.arb
packages/flutter_localizations/lib/src/l10n/material_en.arb
+6
-1
material_en_AU.arb
...ges/flutter_localizations/lib/src/l10n/material_en_AU.arb
+2
-1
material_en_CA.arb
...ges/flutter_localizations/lib/src/l10n/material_en_CA.arb
+2
-1
material_en_GB.arb
...ges/flutter_localizations/lib/src/l10n/material_en_GB.arb
+2
-1
material_en_IE.arb
...ges/flutter_localizations/lib/src/l10n/material_en_IE.arb
+2
-1
material_en_IN.arb
...ges/flutter_localizations/lib/src/l10n/material_en_IN.arb
+2
-1
material_en_SG.arb
...ges/flutter_localizations/lib/src/l10n/material_en_SG.arb
+2
-1
material_en_ZA.arb
...ges/flutter_localizations/lib/src/l10n/material_en_ZA.arb
+2
-1
material_es.arb
packages/flutter_localizations/lib/src/l10n/material_es.arb
+2
-1
material_es_419.arb
...es/flutter_localizations/lib/src/l10n/material_es_419.arb
+2
-1
material_es_AR.arb
...ges/flutter_localizations/lib/src/l10n/material_es_AR.arb
+2
-1
material_es_BO.arb
...ges/flutter_localizations/lib/src/l10n/material_es_BO.arb
+2
-1
material_es_CL.arb
...ges/flutter_localizations/lib/src/l10n/material_es_CL.arb
+2
-1
material_es_CO.arb
...ges/flutter_localizations/lib/src/l10n/material_es_CO.arb
+2
-1
material_es_CR.arb
...ges/flutter_localizations/lib/src/l10n/material_es_CR.arb
+2
-1
material_es_DO.arb
...ges/flutter_localizations/lib/src/l10n/material_es_DO.arb
+2
-1
material_es_EC.arb
...ges/flutter_localizations/lib/src/l10n/material_es_EC.arb
+2
-1
material_es_GT.arb
...ges/flutter_localizations/lib/src/l10n/material_es_GT.arb
+2
-1
material_es_HN.arb
...ges/flutter_localizations/lib/src/l10n/material_es_HN.arb
+2
-1
material_es_MX.arb
...ges/flutter_localizations/lib/src/l10n/material_es_MX.arb
+2
-1
material_es_NI.arb
...ges/flutter_localizations/lib/src/l10n/material_es_NI.arb
+2
-1
material_es_PA.arb
...ges/flutter_localizations/lib/src/l10n/material_es_PA.arb
+2
-1
material_es_PE.arb
...ges/flutter_localizations/lib/src/l10n/material_es_PE.arb
+2
-1
material_es_PR.arb
...ges/flutter_localizations/lib/src/l10n/material_es_PR.arb
+2
-1
material_es_PY.arb
...ges/flutter_localizations/lib/src/l10n/material_es_PY.arb
+2
-1
material_es_SV.arb
...ges/flutter_localizations/lib/src/l10n/material_es_SV.arb
+2
-1
material_es_US.arb
...ges/flutter_localizations/lib/src/l10n/material_es_US.arb
+2
-1
material_es_UY.arb
...ges/flutter_localizations/lib/src/l10n/material_es_UY.arb
+2
-1
material_es_VE.arb
...ges/flutter_localizations/lib/src/l10n/material_es_VE.arb
+2
-1
material_fa.arb
packages/flutter_localizations/lib/src/l10n/material_fa.arb
+2
-1
material_fr.arb
packages/flutter_localizations/lib/src/l10n/material_fr.arb
+2
-1
material_gsw.arb
packages/flutter_localizations/lib/src/l10n/material_gsw.arb
+2
-1
material_he.arb
packages/flutter_localizations/lib/src/l10n/material_he.arb
+2
-1
material_id.arb
packages/flutter_localizations/lib/src/l10n/material_id.arb
+2
-1
material_it.arb
packages/flutter_localizations/lib/src/l10n/material_it.arb
+2
-1
material_ja.arb
packages/flutter_localizations/lib/src/l10n/material_ja.arb
+2
-1
material_ko.arb
packages/flutter_localizations/lib/src/l10n/material_ko.arb
+2
-1
material_ms.arb
packages/flutter_localizations/lib/src/l10n/material_ms.arb
+2
-1
material_nb.arb
packages/flutter_localizations/lib/src/l10n/material_nb.arb
+2
-1
material_nl.arb
packages/flutter_localizations/lib/src/l10n/material_nl.arb
+2
-1
material_pl.arb
packages/flutter_localizations/lib/src/l10n/material_pl.arb
+2
-1
material_ps.arb
packages/flutter_localizations/lib/src/l10n/material_ps.arb
+2
-1
material_pt.arb
packages/flutter_localizations/lib/src/l10n/material_pt.arb
+2
-1
material_pt_PT.arb
...ges/flutter_localizations/lib/src/l10n/material_pt_PT.arb
+2
-1
material_ro.arb
packages/flutter_localizations/lib/src/l10n/material_ro.arb
+2
-1
material_ru.arb
packages/flutter_localizations/lib/src/l10n/material_ru.arb
+2
-1
material_th.arb
packages/flutter_localizations/lib/src/l10n/material_th.arb
+2
-1
material_tr.arb
packages/flutter_localizations/lib/src/l10n/material_tr.arb
+2
-1
material_ur.arb
packages/flutter_localizations/lib/src/l10n/material_ur.arb
+2
-1
material_vi.arb
packages/flutter_localizations/lib/src/l10n/material_vi.arb
+2
-1
material_zh.arb
packages/flutter_localizations/lib/src/l10n/material_zh.arb
+2
-1
material_zh_HK.arb
...ges/flutter_localizations/lib/src/l10n/material_zh_HK.arb
+2
-1
material_zh_TW.arb
...ges/flutter_localizations/lib/src/l10n/material_zh_TW.arb
+2
-1
material_localizations.dart
...flutter_localizations/lib/src/material_localizations.dart
+4
-1
No files found.
examples/flutter_gallery/lib/demo/material/material.dart
View file @
d5a10340
...
...
@@ -24,6 +24,7 @@ export 'page_selector_demo.dart';
export
'persistent_bottom_sheet_demo.dart'
;
export
'progress_indicator_demo.dart'
;
export
'scrollable_tabs_demo.dart'
;
export
'search_demo.dart'
;
export
'selection_controls_demo.dart'
;
export
'slider_demo.dart'
;
export
'snack_bar_demo.dart'
;
...
...
examples/flutter_gallery/lib/demo/material/search_demo.dart
0 → 100644
View file @
d5a10340
// Copyright 2018 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:flutter/material.dart'
;
class
SearchDemo
extends
StatefulWidget
{
static
const
String
routeName
=
'/material/search'
;
@override
_SearchDemoState
createState
()
=>
new
_SearchDemoState
();
}
class
_SearchDemoState
extends
State
<
SearchDemo
>
{
final
_SearchDemoSearchDelegate
_delegate
=
new
_SearchDemoSearchDelegate
();
final
GlobalKey
<
ScaffoldState
>
_scaffoldKey
=
new
GlobalKey
<
ScaffoldState
>();
int
_lastIntegerSelected
;
@override
Widget
build
(
BuildContext
context
)
{
return
new
Scaffold
(
key:
_scaffoldKey
,
appBar:
new
AppBar
(
leading:
new
IconButton
(
tooltip:
'Navigation menu'
,
icon:
new
AnimatedIcon
(
icon:
AnimatedIcons
.
menu_arrow
,
color:
Colors
.
white
,
progress:
_delegate
.
transitionAnimation
,
),
onPressed:
()
{
_scaffoldKey
.
currentState
.
openDrawer
();
},
),
title:
const
Text
(
'Numbers'
),
actions:
<
Widget
>[
new
IconButton
(
tooltip:
'Search'
,
icon:
const
Icon
(
Icons
.
search
),
onPressed:
()
async
{
final
int
selected
=
await
showSearch
<
int
>(
context:
context
,
delegate:
_delegate
,
);
if
(
selected
!=
null
&&
selected
!=
_lastIntegerSelected
)
{
setState
(()
{
_lastIntegerSelected
=
selected
;
});
}
},
),
new
IconButton
(
tooltip:
'More (not implemented)'
,
icon:
const
Icon
(
Icons
.
more_vert
),
onPressed:
()
{},
),
],
),
body:
new
Center
(
child:
new
Column
(
mainAxisAlignment:
MainAxisAlignment
.
center
,
children:
<
Widget
>[
new
MergeSemantics
(
child:
new
Column
(
mainAxisAlignment:
MainAxisAlignment
.
center
,
children:
<
Widget
>[
new
Row
(
mainAxisAlignment:
MainAxisAlignment
.
center
,
children:
const
<
Widget
>[
const
Text
(
'Press the '
),
const
Tooltip
(
message:
'search'
,
child:
const
Icon
(
Icons
.
search
,
size:
18.0
,
),
),
const
Text
(
' icon in the AppBar'
),
],
),
const
Text
(
'and search for an integer between 0 and 100,000.'
),
],
),
),
const
SizedBox
(
height:
64.0
),
new
Text
(
'Last selected integer:
${_lastIntegerSelected ?? 'NONE' }
.'
)
],
),
),
floatingActionButton:
new
FloatingActionButton
.
extended
(
tooltip:
'Back'
,
// Tests depend on this label to exit the demo.
onPressed:
()
{
Navigator
.
of
(
context
).
pop
();
},
label:
const
Text
(
'Close demo'
),
icon:
const
Icon
(
Icons
.
close
),
),
drawer:
new
Drawer
(
child:
new
Column
(
children:
<
Widget
>[
const
UserAccountsDrawerHeader
(
accountName:
const
Text
(
'Zach Widget'
),
accountEmail:
const
Text
(
'zach.widget@example.com'
),
currentAccountPicture:
const
CircleAvatar
(
backgroundImage:
const
AssetImage
(
'shrine/vendors/zach.jpg'
,
package:
'flutter_gallery_assets'
,
),
),
margin:
EdgeInsets
.
zero
,
),
new
MediaQuery
.
removePadding
(
context:
context
,
// DrawerHeader consumes top MediaQuery padding.
removeTop:
true
,
child:
const
ListTile
(
leading:
const
Icon
(
Icons
.
payment
),
title:
const
Text
(
'Placeholder'
),
),
),
],
),
),
);
}
}
class
_SearchDemoSearchDelegate
extends
SearchDelegate
<
int
>
{
final
List
<
int
>
_data
=
new
List
<
int
>.
generate
(
100001
,
(
int
i
)
=>
i
).
reversed
.
toList
();
final
List
<
int
>
_history
=
<
int
>[
42607
,
85604
,
66374
,
44
,
174
];
@override
Widget
buildLeading
(
BuildContext
context
)
{
return
new
IconButton
(
tooltip:
'Back'
,
icon:
new
AnimatedIcon
(
icon:
AnimatedIcons
.
menu_arrow
,
progress:
transitionAnimation
,
),
onPressed:
()
{
close
(
context
,
null
);
},
);
}
@override
Widget
buildSuggestions
(
BuildContext
context
)
{
final
Iterable
<
int
>
suggestions
=
query
.
isEmpty
?
_history
:
_data
.
where
((
int
i
)
=>
'
$i
'
.
startsWith
(
query
));
return
new
_SuggestionList
(
query:
query
,
suggestions:
suggestions
.
map
((
int
i
)
=>
'
$i
'
).
toList
(),
onSelected:
(
String
suggestion
)
{
query
=
suggestion
;
showResults
(
context
);
},
);
}
@override
Widget
buildResults
(
BuildContext
context
)
{
final
int
searched
=
int
.
tryParse
(
query
);
if
(
searched
==
null
||
!
_data
.
contains
(
searched
))
{
return
new
Center
(
child:
new
Text
(
'"
$query
"
\n
is not a valid integer between 0 and 100,000.
\n
Try again.'
,
textAlign:
TextAlign
.
center
,
),
);
}
return
new
ListView
(
children:
<
Widget
>[
new
_ResultCard
(
title:
'This integer'
,
integer:
searched
,
searchDelegate:
this
,
),
new
_ResultCard
(
title:
'Next integer'
,
integer:
searched
+
1
,
searchDelegate:
this
,
),
new
_ResultCard
(
title:
'Previous integer'
,
integer:
searched
-
1
,
searchDelegate:
this
,
),
],
);
}
@override
List
<
Widget
>
buildActions
(
BuildContext
context
)
{
return
<
Widget
>[
query
.
isEmpty
?
new
IconButton
(
tooltip:
'Voice Search'
,
icon:
const
Icon
(
Icons
.
mic
),
onPressed:
()
{
query
=
'TODO: implement voice input'
;
},
)
:
new
IconButton
(
tooltip:
'Clear'
,
icon:
const
Icon
(
Icons
.
clear
),
onPressed:
()
{
query
=
''
;
showSuggestions
(
context
);
},
)
];
}
}
class
_ResultCard
extends
StatelessWidget
{
const
_ResultCard
({
this
.
integer
,
this
.
title
,
this
.
searchDelegate
});
final
int
integer
;
final
String
title
;
final
SearchDelegate
<
int
>
searchDelegate
;
@override
Widget
build
(
BuildContext
context
)
{
final
ThemeData
theme
=
Theme
.
of
(
context
);
return
new
GestureDetector
(
onTap:
()
{
searchDelegate
.
close
(
context
,
integer
);
},
child:
new
Card
(
child:
new
Padding
(
padding:
const
EdgeInsets
.
all
(
8.0
),
child:
new
Column
(
children:
<
Widget
>[
new
Text
(
title
),
new
Text
(
'
$integer
'
,
style:
theme
.
textTheme
.
headline
.
copyWith
(
fontSize:
72.0
),
),
],
),
),
),
);
}
}
class
_SuggestionList
extends
StatelessWidget
{
const
_SuggestionList
({
this
.
suggestions
,
this
.
query
,
this
.
onSelected
});
final
List
<
String
>
suggestions
;
final
String
query
;
final
ValueChanged
<
String
>
onSelected
;
@override
Widget
build
(
BuildContext
context
)
{
final
ThemeData
theme
=
Theme
.
of
(
context
);
return
new
ListView
.
builder
(
itemCount:
suggestions
.
length
,
itemBuilder:
(
BuildContext
context
,
int
i
)
{
final
String
suggestion
=
suggestions
[
i
];
return
new
ListTile
(
leading:
query
.
isEmpty
?
const
Icon
(
Icons
.
history
)
:
const
Icon
(
null
),
title:
new
RichText
(
text:
new
TextSpan
(
text:
suggestion
.
substring
(
0
,
query
.
length
),
style:
theme
.
textTheme
.
subhead
.
copyWith
(
fontWeight:
FontWeight
.
bold
),
children:
<
TextSpan
>[
new
TextSpan
(
text:
suggestion
.
substring
(
query
.
length
),
style:
theme
.
textTheme
.
subhead
,
),
],
),
),
onTap:
()
{
onSelected
(
suggestion
);
},
);
},
);
}
}
examples/flutter_gallery/lib/gallery/demos.dart
View file @
d5a10340
...
...
@@ -313,6 +313,14 @@ List<GalleryDemo> _buildGalleryDemos() {
routeName:
OverscrollDemo
.
routeName
,
buildRoute:
(
BuildContext
context
)
=>
const
OverscrollDemo
(),
),
new
GalleryDemo
(
title:
'Search'
,
subtitle:
'Expandable search'
,
icon:
Icons
.
search
,
category:
_kMaterialComponents
,
routeName:
SearchDemo
.
routeName
,
buildRoute:
(
BuildContext
context
)
=>
new
SearchDemo
(),
),
new
GalleryDemo
(
title:
'Selection controls'
,
subtitle:
'Checkboxes, radio buttons, and switches'
,
...
...
packages/flutter/lib/material.dart
View file @
d5a10340
...
...
@@ -78,6 +78,7 @@ export 'src/material/raised_button.dart';
export
'src/material/refresh_indicator.dart'
;
export
'src/material/scaffold.dart'
;
export
'src/material/scrollbar.dart'
;
export
'src/material/search.dart'
;
export
'src/material/shadows.dart'
;
export
'src/material/slider.dart'
;
export
'src/material/slider_theme.dart'
;
...
...
packages/flutter/lib/src/material/material_localizations.dart
View file @
d5a10340
...
...
@@ -160,6 +160,10 @@ abstract class MaterialLocalizations {
/// alert dialog widget is opened.
String
get
alertDialogLabel
;
/// Label indicating that a text field is a search field. This will be used
/// as a hint text in the text field.
String
get
searchFieldLabel
;
/// The format used to lay out the time picker.
///
/// The documentation for [TimeOfDayFormat] enum values provides details on
...
...
@@ -537,6 +541,9 @@ class DefaultMaterialLocalizations implements MaterialLocalizations {
@override
String
get
alertDialogLabel
=>
'Alert'
;
@override
String
get
searchFieldLabel
=>
'Search'
;
@override
String
aboutListTileTitle
(
String
applicationName
)
=>
'About
$applicationName
'
;
...
...
packages/flutter/lib/src/material/search.dart
0 → 100644
View file @
d5a10340
// Copyright 2018 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
'package:flutter/widgets.dart'
;
import
'app_bar.dart'
;
import
'colors.dart'
;
import
'input_border.dart'
;
import
'input_decorator.dart'
;
import
'material_localizations.dart'
;
import
'scaffold.dart'
;
import
'text_field.dart'
;
import
'theme.dart'
;
/// Shows a full screen search page and returns the search result selected by
/// the user when the page is closed.
///
/// The search page consists of an app bar with a search field and a body which
/// can either show suggested search queries or the search results.
///
/// The appearance of the search page is determined by the provided
/// `delegate`. The initial query string is given by `query`, which defaults
/// to the empty string. When `query` is set to null, `delegate.query` will
/// be used as the initial query.
///
/// The method returns the selected search result, which can be set in the
/// [SearchDelegate.close] call.
///
/// A given [SearchDelegate] can only be associated with one active [showSearch]
/// call. Call [SearchDelegate.close] before re-using the same delegate instance
/// for another [showSearch] call.
///
/// The transition to the search page triggered by this method looks best if the
/// screen triggering the transition contains an [AppBar] at the top and the
/// transition is called from an [IconButton] that's part of [AppBar.actions].
/// The animation provided by [SearchDelegate.transitionAnimation] can be used
/// to trigger additional animations in the underlying page while the search
/// page fades in or out. This is commonly used to animate an [AnimatedIcon] in
/// the [AppBar.leading] position e.g. from the hamburger menu to the back arrow
/// used to exit the search page.
///
/// See also:
///
/// * [SearchDelegate] to define the content of the search page.
Future
<
T
>
showSearch
<
T
>({
@required
BuildContext
context
,
@required
SearchDelegate
<
T
>
delegate
,
String
query:
''
,
})
{
assert
(
delegate
!=
null
);
assert
(
context
!=
null
);
assert
(
delegate
.
_result
==
null
||
delegate
.
_result
.
isCompleted
);
delegate
.
_result
=
new
Completer
<
T
>();
delegate
.
query
=
query
??
delegate
.
query
;
delegate
.
_currentBody
=
_SearchBody
.
suggestions
;
Navigator
.
of
(
context
).
push
(
new
_SearchPageRoute
<
T
>(
delegate:
delegate
,
));
return
delegate
.
_result
.
future
;
}
/// Delegate for [showSearch] to define the content of the search page.
///
/// The search page always shows an [AppBar] at the top where users can
/// enter their search queries. The buttons shown before and after the search
/// query text field can be customized via [SearchDelegate.leading] and
/// [SearchDelegate.actions].
///
/// The body below the [AppBar] can either show suggested queries (returned by
/// [SearchDelegate.buildSuggestions]) or - once the user submits a search - the
/// results of the search as returned by [SearchDelegate.buildResults].
///
/// [SearchDelegate.query] always contains the current query entered by the user
/// and should be used to build the suggestions and results.
///
/// The results can be brought on screen by calling [SearchDelegate.showResults]
/// and you can go back to showing the suggestions by calling
/// [SearchDelegate.showSuggestions].
///
/// Once the user has selected a search result, [SearchDelegate.close] should be
/// called to remove the search page from the top of the navigation stack and
/// to notify the caller of [showSearch] about the selected search result.
///
/// A given [SearchDelegate] can only be associated with one active [showSearch]
/// call. Call [SearchDelegate.close] before re-using the same delegate instance
/// for another [showSearch] call.
abstract
class
SearchDelegate
<
T
>
{
/// Suggestions shown in the body of the search page while the user types a
/// query into the search field.
///
/// The delegate method is called whenever the content of [query] changes.
/// The suggestions should be based on the current [query] string. If the query
/// string is empty, it is good practice to show suggested queries based on
/// past queries or the current context.
///
/// Usually, this method will return a [ListView] with one [ListTile] per
/// suggestion. When [ListTile.onTap] is called, [query] should be updated
/// with the corresponding suggestion and the results page should be shown
/// by calling [showResults].
Widget
buildSuggestions
(
BuildContext
context
);
/// The results shown after the user submits a search from the search page.
///
/// The current value of [query] can be used to determine what the user
/// searched for.
///
/// Typically, this method returns a [ListView] with the search results.
/// When the user taps on a particular search result, [close] should be called
/// with the selected result as argument. This will close the search page and
/// communicate the result back to the initial caller of [showSearch].
Widget
buildResults
(
BuildContext
context
);
/// A widget to display before the current query in the [AppBar].
///
/// Typically an [IconButton] configured with a [BackButtonIcon] that exits
/// the search with [close]. One can also use an [AnimatedIcon] driven by
/// [transitionAnimation], which animates from e.g. a hamburger menu to the
/// back button as the search overlay fades in.
///
/// Returns null if no widget should be shown.
///
/// See also:
///
/// * [AppBar.leading], the intended use for the return value of this method.
Widget
buildLeading
(
BuildContext
context
);
/// Widgets to display after the search query in the [AppBar].
///
/// If the [query] is not empty, this should typically contain a button to
/// clear the query and show the suggestions again (via [showSuggestions]) if
/// the results are currently shown.
///
/// Returns null if no widget should be shown
///
/// See also:
///
/// * [AppBar.actions], the intended use for the return value of this method.
List
<
Widget
>
buildActions
(
BuildContext
context
);
/// The theme used to style the [AppBar].
///
/// By default, a white theme is used.
///
/// See also:
///
/// * [AppBar.backgroundColor], which is set to [ThemeData.primaryColor].
/// * [Appbar.iconTheme], which is set to [ThemeData.primaryIconTheme].
/// * [AppBar.textTheme], which is set to [ThemeData.primaryTextTheme].
/// * [AppBar.brightness], which is set to [ThemeData.primaryColorBrightness].
ThemeData
appBarTheme
(
BuildContext
context
)
{
assert
(
context
!=
null
);
final
ThemeData
theme
=
Theme
.
of
(
context
);
assert
(
theme
!=
null
);
return
theme
.
copyWith
(
primaryColor:
Colors
.
white
,
primaryIconTheme:
theme
.
primaryIconTheme
.
copyWith
(
color:
Colors
.
grey
),
primaryColorBrightness:
Brightness
.
light
,
primaryTextTheme:
theme
.
textTheme
,
);
}
/// The current query string shown in the [Appbar].
///
/// The user manipulates this string via the keyboard.
///
/// If the user taps on a suggestion provided by [buildSuggestions] this
/// string should be updated to that suggestion via the setter.
String
get
query
=>
_queryTextController
.
text
;
set
query
(
String
value
)
{
assert
(
query
!=
null
);
_queryTextController
.
text
=
value
;
}
/// Transition from the suggestions returned by [buildSuggestions] to the
/// [query] results returned by [buildResults].
///
/// If the user taps on a suggestion provided by [buildSuggestions] the
/// screen should typically transition to the page showing the search
/// results for the suggested query. This transition can be triggered
/// by calling this method.
///
/// See also:
///
/// * [showSuggestions] to show the search suggestions again.
void
showResults
(
BuildContext
context
)
{
_focusNode
.
unfocus
();
_currentBody
=
_SearchBody
.
results
;
}
/// Transition from showing the results returned by [buildResults] to showing
/// the suggestions returned by [buildSuggestions].
///
/// Calling this method will also put the input focus back into the search
/// field of the ApBar.
///
/// If the results are currently shown this method can be used to go back
/// to showing the search suggestions.
///
/// See also:
///
/// * [showResults] to show the search results.
void
showSuggestions
(
BuildContext
context
)
{
FocusScope
.
of
(
context
).
requestFocus
(
_focusNode
);
_currentBody
=
_SearchBody
.
suggestions
;
}
/// Closes the search page and returns to the underlying route.
///
/// The value provided for `result` is used as the return value of the call
/// to [showSearch] that launched the search initially.
void
close
(
BuildContext
context
,
T
result
)
{
_currentBody
=
null
;
_focusNode
.
unfocus
();
_result
.
complete
(
result
);
Navigator
.
of
(
context
)
..
popUntil
((
Route
<
dynamic
>
route
)
=>
route
==
_route
)
..
pop
(
result
);
}
/// [Animation] triggered when the search pages fades in or out.
///
/// This animation is commonly used to animate [AnimatedIcon]s of
/// [IconButton]s returned by [buildLeading] or [buildActions]. It can also be
/// used to animate [IconButton]s contained within the route below the search
/// page.
Animation
<
double
>
get
transitionAnimation
=>
_proxyAnimation
;
final
FocusNode
_focusNode
=
new
FocusNode
();
final
TextEditingController
_queryTextController
=
new
TextEditingController
();
final
ProxyAnimation
_proxyAnimation
=
new
ProxyAnimation
(
kAlwaysDismissedAnimation
);
final
ValueNotifier
<
_SearchBody
>
_currentBodyNotifier
=
new
ValueNotifier
<
_SearchBody
>(
null
);
_SearchBody
get
_currentBody
=>
_currentBodyNotifier
.
value
;
set
_currentBody
(
_SearchBody
value
)
{
_currentBodyNotifier
.
value
=
value
;
}
Completer
<
T
>
_result
;
_SearchPageRoute
<
T
>
_route
;
}
/// Describes the body that is currently shown under the [AppBar] in the
/// search page.
enum
_SearchBody
{
/// Suggested queries are shown in the body.
///
/// The suggested queries are generated by [SearchDelegate.buildSuggestions].
suggestions
,
/// Search results are currently shown in the body.
///
/// The search results are generated by [SearchDelegate.buildResults].
results
,
}
class
_SearchPageRoute
<
T
>
extends
PageRoute
<
void
>
{
_SearchPageRoute
({
@required
this
.
delegate
,
})
:
assert
(
delegate
!=
null
)
{
assert
(
delegate
.
_route
==
null
,
'The
${delegate.runtimeType}
instance is currently used by another active '
'search. Please close that search by calling close() on the SearchDelegate '
'before openening another search with the same delegate instance.'
,
);
delegate
.
_route
=
this
;
}
final
SearchDelegate
<
T
>
delegate
;
@override
Color
get
barrierColor
=>
null
;
@override
String
get
barrierLabel
=>
null
;
@override
Duration
get
transitionDuration
=>
const
Duration
(
milliseconds:
300
);
@override
bool
get
maintainState
=>
false
;
@override
Widget
buildTransitions
(
BuildContext
context
,
Animation
<
double
>
animation
,
Animation
<
double
>
secondaryAnimation
,
Widget
child
,
)
{
return
new
FadeTransition
(
opacity:
animation
,
child:
child
,
);
}
@override
Animation
<
double
>
createAnimation
()
{
final
Animation
<
double
>
animation
=
super
.
createAnimation
();
delegate
.
_proxyAnimation
.
parent
=
animation
;
return
animation
;
}
@override
Widget
buildPage
(
BuildContext
context
,
Animation
<
double
>
animation
,
Animation
<
double
>
secondaryAnimation
,
)
{
return
new
_SearchPage
<
T
>(
delegate:
delegate
,
animation:
animation
,
);
}
@override
void
didComplete
(
void
result
)
{
super
.
didComplete
(
result
);
assert
(
delegate
.
_route
==
this
);
delegate
.
_route
=
null
;
}
}
class
_SearchPage
<
T
>
extends
StatefulWidget
{
const
_SearchPage
({
this
.
delegate
,
this
.
animation
,
});
final
SearchDelegate
<
T
>
delegate
;
final
Animation
<
double
>
animation
;
@override
State
<
StatefulWidget
>
createState
()
=>
new
_SearchPageState
<
T
>();
}
class
_SearchPageState
<
T
>
extends
State
<
_SearchPage
<
T
>>
{
@override
void
initState
()
{
super
.
initState
();
queryTextController
.
addListener
(
_onQueryChanged
);
widget
.
animation
.
addStatusListener
(
_onAnimationStatusChanged
);
widget
.
delegate
.
_currentBodyNotifier
.
addListener
(
_onSearchBodyChanged
);
widget
.
delegate
.
_focusNode
.
addListener
(
_onFocusChanged
);
}
@override
void
dispose
()
{
super
.
dispose
();
queryTextController
.
removeListener
(
_onQueryChanged
);
widget
.
animation
.
removeStatusListener
(
_onAnimationStatusChanged
);
widget
.
delegate
.
_currentBodyNotifier
.
removeListener
(
_onSearchBodyChanged
);
widget
.
delegate
.
_focusNode
.
removeListener
(
_onFocusChanged
);
}
void
_onAnimationStatusChanged
(
AnimationStatus
status
)
{
if
(
status
!=
AnimationStatus
.
completed
)
{
return
;
}
widget
.
animation
.
removeStatusListener
(
_onAnimationStatusChanged
);
if
(
widget
.
delegate
.
_currentBody
==
_SearchBody
.
suggestions
)
{
FocusScope
.
of
(
context
).
requestFocus
(
widget
.
delegate
.
_focusNode
);
}
}
void
_onFocusChanged
()
{
if
(
widget
.
delegate
.
_focusNode
.
hasFocus
&&
widget
.
delegate
.
_currentBody
!=
_SearchBody
.
suggestions
)
{
widget
.
delegate
.
showSuggestions
(
context
);
}
}
void
_onQueryChanged
()
{
setState
(()
{
// rebuild ourselves because query changed.
});
}
void
_onSearchBodyChanged
()
{
setState
(()
{
// rebuild ourselves because search body changed.
});
}
@override
Widget
build
(
BuildContext
context
)
{
final
ThemeData
theme
=
widget
.
delegate
.
appBarTheme
(
context
);
Widget
body
;
switch
(
widget
.
delegate
.
_currentBody
)
{
case
_SearchBody
.
suggestions
:
body
=
new
KeyedSubtree
(
key:
const
ValueKey
<
_SearchBody
>(
_SearchBody
.
suggestions
),
child:
widget
.
delegate
.
buildSuggestions
(
context
),
);
break
;
case
_SearchBody
.
results
:
body
=
new
KeyedSubtree
(
key:
const
ValueKey
<
_SearchBody
>(
_SearchBody
.
results
),
child:
widget
.
delegate
.
buildResults
(
context
),
);
break
;
}
return
new
Scaffold
(
appBar:
new
AppBar
(
backgroundColor:
theme
.
primaryColor
,
iconTheme:
theme
.
primaryIconTheme
,
textTheme:
theme
.
primaryTextTheme
,
brightness:
theme
.
primaryColorBrightness
,
leading:
widget
.
delegate
.
buildLeading
(
context
),
// TODO(goderbauer): Show the search key (instead of enter) on keyboard, https://github.com/flutter/flutter/issues/17525
title:
new
TextField
(
controller:
queryTextController
,
focusNode:
widget
.
delegate
.
_focusNode
,
style:
theme
.
textTheme
.
title
,
onSubmitted:
(
String
_
)
{
widget
.
delegate
.
showResults
(
context
);
},
decoration:
new
InputDecoration
(
border:
InputBorder
.
none
,
hintText:
MaterialLocalizations
.
of
(
context
).
searchFieldLabel
,
),
),
actions:
widget
.
delegate
.
buildActions
(
context
),
),
body:
new
AnimatedSwitcher
(
duration:
const
Duration
(
milliseconds:
300
),
child:
body
,
),
);
}
TextEditingController
get
queryTextController
=>
widget
.
delegate
.
_queryTextController
;
}
packages/flutter/test/material/localizations_test.dart
View file @
d5a10340
...
...
@@ -34,6 +34,7 @@ void main() {
expect
(
localizations
.
popupMenuLabel
,
isNotNull
);
expect
(
localizations
.
dialogLabel
,
isNotNull
);
expect
(
localizations
.
alertDialogLabel
,
isNotNull
);
expect
(
localizations
.
searchFieldLabel
,
isNotNull
);
expect
(
localizations
.
aboutListTileTitle
(
'FOO'
),
isNotNull
);
expect
(
localizations
.
aboutListTileTitle
(
'FOO'
),
contains
(
'FOO'
));
...
...
packages/flutter/test/material/search_test.dart
0 → 100644
View file @
d5a10340
// Copyright 2018 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:flutter/material.dart'
;
import
'package:flutter_test/flutter_test.dart'
;
void
main
(
)
{
testWidgets
(
'Can open and close search'
,
(
WidgetTester
tester
)
async
{
final
_TestSearchDelegate
delegate
=
new
_TestSearchDelegate
();
final
List
<
String
>
selectedResults
=
<
String
>[];
await
tester
.
pumpWidget
(
new
TestHomePage
(
delegate:
delegate
,
results:
selectedResults
,
));
// We are on the homepage
expect
(
find
.
text
(
'HomeBody'
),
findsOneWidget
);
expect
(
find
.
text
(
'HomeTitle'
),
findsOneWidget
);
expect
(
find
.
text
(
'Suggestions'
),
findsNothing
);
// Open search
await
tester
.
tap
(
find
.
byTooltip
(
'Search'
));
await
tester
.
pumpAndSettle
();
expect
(
find
.
text
(
'HomeBody'
),
findsNothing
);
expect
(
find
.
text
(
'HomeTitle'
),
findsNothing
);
expect
(
find
.
text
(
'Suggestions'
),
findsOneWidget
);
expect
(
selectedResults
,
hasLength
(
0
));
final
TextField
textField
=
tester
.
widget
(
find
.
byType
(
TextField
));
expect
(
textField
.
focusNode
.
hasFocus
,
isTrue
);
// Close search
await
tester
.
tap
(
find
.
byTooltip
(
'Back'
));
await
tester
.
pumpAndSettle
();
expect
(
find
.
text
(
'HomeBody'
),
findsOneWidget
);
expect
(
find
.
text
(
'HomeTitle'
),
findsOneWidget
);
expect
(
find
.
text
(
'Suggestions'
),
findsNothing
);
expect
(
selectedResults
,
<
String
>[
'Result'
]);
});
testWidgets
(
'Requests suggestions'
,
(
WidgetTester
tester
)
async
{
final
_TestSearchDelegate
delegate
=
new
_TestSearchDelegate
();
await
tester
.
pumpWidget
(
new
TestHomePage
(
delegate:
delegate
,
));
await
tester
.
tap
(
find
.
byTooltip
(
'Search'
));
await
tester
.
pumpAndSettle
();
expect
(
delegate
.
query
,
''
);
expect
(
delegate
.
querysForSuggestions
.
last
,
''
);
expect
(
delegate
.
querysForResults
,
hasLength
(
0
));
// Type W o w into search field
delegate
.
querysForSuggestions
.
clear
();
await
tester
.
enterText
(
find
.
byType
(
TextField
),
'W'
);
await
tester
.
pumpAndSettle
();
expect
(
delegate
.
query
,
'W'
);
await
tester
.
enterText
(
find
.
byType
(
TextField
),
'Wo'
);
await
tester
.
pumpAndSettle
();
expect
(
delegate
.
query
,
'Wo'
);
await
tester
.
enterText
(
find
.
byType
(
TextField
),
'Wow'
);
await
tester
.
pumpAndSettle
();
expect
(
delegate
.
query
,
'Wow'
);
expect
(
delegate
.
querysForSuggestions
,
<
String
>[
'W'
,
'Wo'
,
'Wow'
]);
expect
(
delegate
.
querysForResults
,
hasLength
(
0
));
});
testWidgets
(
'Shows Results and closes search'
,
(
WidgetTester
tester
)
async
{
final
_TestSearchDelegate
delegate
=
new
_TestSearchDelegate
();
final
List
<
String
>
selectedResults
=
<
String
>[];
await
tester
.
pumpWidget
(
new
TestHomePage
(
delegate:
delegate
,
results:
selectedResults
,
));
await
tester
.
tap
(
find
.
byTooltip
(
'Search'
));
await
tester
.
pumpAndSettle
();
await
tester
.
enterText
(
find
.
byType
(
TextField
),
'Wow'
);
await
tester
.
pumpAndSettle
();
await
tester
.
tap
(
find
.
text
(
'Suggestions'
));
await
tester
.
pumpAndSettle
();
// We are on the results page for Wow
expect
(
find
.
text
(
'HomeBody'
),
findsNothing
);
expect
(
find
.
text
(
'HomeTitle'
),
findsNothing
);
expect
(
find
.
text
(
'Suggestions'
),
findsNothing
);
expect
(
find
.
text
(
'Results'
),
findsOneWidget
);
final
TextField
textField
=
tester
.
widget
(
find
.
byType
(
TextField
));
expect
(
textField
.
focusNode
.
hasFocus
,
isFalse
);
expect
(
delegate
.
querysForResults
,
<
String
>[
'Wow'
]);
// Close search
await
tester
.
tap
(
find
.
byTooltip
(
'Back'
));
await
tester
.
pumpAndSettle
();
expect
(
find
.
text
(
'HomeBody'
),
findsOneWidget
);
expect
(
find
.
text
(
'HomeTitle'
),
findsOneWidget
);
expect
(
find
.
text
(
'Suggestions'
),
findsNothing
);
expect
(
find
.
text
(
'Results'
),
findsNothing
);
expect
(
selectedResults
,
<
String
>[
'Result'
]);
});
testWidgets
(
'Can switch between results and suggestions'
,
(
WidgetTester
tester
)
async
{
final
_TestSearchDelegate
delegate
=
new
_TestSearchDelegate
();
await
tester
.
pumpWidget
(
new
TestHomePage
(
delegate:
delegate
,
));
await
tester
.
tap
(
find
.
byTooltip
(
'Search'
));
await
tester
.
pumpAndSettle
();
// Showing suggestions
expect
(
find
.
text
(
'Suggestions'
),
findsOneWidget
);
expect
(
find
.
text
(
'Results'
),
findsNothing
);
// Typing query Wow
delegate
.
querysForSuggestions
.
clear
();
await
tester
.
enterText
(
find
.
byType
(
TextField
),
'Wow'
);
await
tester
.
pumpAndSettle
();
expect
(
delegate
.
query
,
'Wow'
);
expect
(
delegate
.
querysForSuggestions
,
<
String
>[
'Wow'
]);
expect
(
delegate
.
querysForResults
,
hasLength
(
0
));
await
tester
.
tap
(
find
.
text
(
'Suggestions'
));
await
tester
.
pumpAndSettle
();
// Showing Results
expect
(
find
.
text
(
'Suggestions'
),
findsNothing
);
expect
(
find
.
text
(
'Results'
),
findsOneWidget
);
expect
(
delegate
.
query
,
'Wow'
);
expect
(
delegate
.
querysForSuggestions
,
<
String
>[
'Wow'
]);
expect
(
delegate
.
querysForResults
,
<
String
>[
'Wow'
]);
TextField
textField
=
tester
.
widget
(
find
.
byType
(
TextField
));
expect
(
textField
.
focusNode
.
hasFocus
,
isFalse
);
// Taping search field to go back to suggestions
await
tester
.
tap
(
find
.
byType
(
TextField
));
await
tester
.
pumpAndSettle
();
textField
=
tester
.
widget
(
find
.
byType
(
TextField
));
expect
(
textField
.
focusNode
.
hasFocus
,
isTrue
);
expect
(
find
.
text
(
'Suggestions'
),
findsOneWidget
);
expect
(
find
.
text
(
'Results'
),
findsNothing
);
expect
(
delegate
.
querysForSuggestions
,
<
String
>[
'Wow'
,
'Wow'
]);
expect
(
delegate
.
querysForResults
,
<
String
>[
'Wow'
]);
await
tester
.
enterText
(
find
.
byType
(
TextField
),
'Foo'
);
await
tester
.
pumpAndSettle
();
expect
(
delegate
.
query
,
'Foo'
);
expect
(
delegate
.
querysForSuggestions
,
<
String
>[
'Wow'
,
'Wow'
,
'Foo'
]);
expect
(
delegate
.
querysForResults
,
<
String
>[
'Wow'
]);
// Go to results again
await
tester
.
tap
(
find
.
text
(
'Suggestions'
));
await
tester
.
pumpAndSettle
();
expect
(
find
.
text
(
'Suggestions'
),
findsNothing
);
expect
(
find
.
text
(
'Results'
),
findsOneWidget
);
expect
(
delegate
.
query
,
'Foo'
);
expect
(
delegate
.
querysForSuggestions
,
<
String
>[
'Wow'
,
'Wow'
,
'Foo'
]);
expect
(
delegate
.
querysForResults
,
<
String
>[
'Wow'
,
'Foo'
]);
textField
=
tester
.
widget
(
find
.
byType
(
TextField
));
expect
(
textField
.
focusNode
.
hasFocus
,
isFalse
);
});
testWidgets
(
'Fresh search allways starts with empty query'
,
(
WidgetTester
tester
)
async
{
final
_TestSearchDelegate
delegate
=
new
_TestSearchDelegate
();
await
tester
.
pumpWidget
(
new
TestHomePage
(
delegate:
delegate
,
));
await
tester
.
tap
(
find
.
byTooltip
(
'Search'
));
await
tester
.
pumpAndSettle
();
expect
(
delegate
.
query
,
''
);
delegate
.
query
=
'Foo'
;
await
tester
.
tap
(
find
.
byTooltip
(
'Back'
));
await
tester
.
pumpAndSettle
();
await
tester
.
tap
(
find
.
byTooltip
(
'Search'
));
await
tester
.
pumpAndSettle
();
expect
(
delegate
.
query
,
''
);
});
testWidgets
(
'Initial queries are honored'
,
(
WidgetTester
tester
)
async
{
final
_TestSearchDelegate
delegate
=
new
_TestSearchDelegate
();
expect
(
delegate
.
query
,
''
);
await
tester
.
pumpWidget
(
new
TestHomePage
(
delegate:
delegate
,
passInInitialQuery:
true
,
initialQuery:
'Foo'
,
));
await
tester
.
tap
(
find
.
byTooltip
(
'Search'
));
await
tester
.
pumpAndSettle
();
expect
(
delegate
.
query
,
'Foo'
);
});
testWidgets
(
'Initial query null re-used previous query'
,
(
WidgetTester
tester
)
async
{
final
_TestSearchDelegate
delegate
=
new
_TestSearchDelegate
();
delegate
.
query
=
'Foo'
;
await
tester
.
pumpWidget
(
new
TestHomePage
(
delegate:
delegate
,
passInInitialQuery:
true
,
initialQuery:
null
,
));
await
tester
.
tap
(
find
.
byTooltip
(
'Search'
));
await
tester
.
pumpAndSettle
();
expect
(
delegate
.
query
,
'Foo'
);
});
testWidgets
(
'Changing query shows up in search field'
,
(
WidgetTester
tester
)
async
{
final
_TestSearchDelegate
delegate
=
new
_TestSearchDelegate
();
await
tester
.
pumpWidget
(
new
TestHomePage
(
delegate:
delegate
,
passInInitialQuery:
true
,
initialQuery:
null
,
));
await
tester
.
tap
(
find
.
byTooltip
(
'Search'
));
await
tester
.
pumpAndSettle
();
delegate
.
query
=
'Foo'
;
expect
(
find
.
text
(
'Foo'
),
findsOneWidget
);
expect
(
find
.
text
(
'Bar'
),
findsNothing
);
delegate
.
query
=
'Bar'
;
expect
(
find
.
text
(
'Foo'
),
findsNothing
);
expect
(
find
.
text
(
'Bar'
),
findsOneWidget
);
});
testWidgets
(
'transitionAnimation runs while search fades in/out'
,
(
WidgetTester
tester
)
async
{
final
_TestSearchDelegate
delegate
=
new
_TestSearchDelegate
();
await
tester
.
pumpWidget
(
new
TestHomePage
(
delegate:
delegate
,
passInInitialQuery:
true
,
initialQuery:
null
,
));
// runs while search fades in
expect
(
delegate
.
transitionAnimation
.
status
,
AnimationStatus
.
dismissed
);
await
tester
.
tap
(
find
.
byTooltip
(
'Search'
));
expect
(
delegate
.
transitionAnimation
.
status
,
AnimationStatus
.
forward
);
await
tester
.
pumpAndSettle
();
expect
(
delegate
.
transitionAnimation
.
status
,
AnimationStatus
.
completed
);
// does not run while switching to results
await
tester
.
tap
(
find
.
text
(
'Suggestions'
));
expect
(
delegate
.
transitionAnimation
.
status
,
AnimationStatus
.
completed
);
await
tester
.
pumpAndSettle
();
expect
(
delegate
.
transitionAnimation
.
status
,
AnimationStatus
.
completed
);
// runs while search fades out
await
tester
.
tap
(
find
.
byTooltip
(
'Back'
));
expect
(
delegate
.
transitionAnimation
.
status
,
AnimationStatus
.
reverse
);
await
tester
.
pumpAndSettle
();
expect
(
delegate
.
transitionAnimation
.
status
,
AnimationStatus
.
dismissed
);
});
testWidgets
(
'Closing nested search returns to search'
,
(
WidgetTester
tester
)
async
{
final
List
<
String
>
nestedSearchResults
=
<
String
>[];
final
_TestSearchDelegate
nestedSearchDelegate
=
new
_TestSearchDelegate
(
suggestions:
'Nested Suggestions'
,
result:
'Nested Result'
,
);
final
List
<
String
>
selectedResults
=
<
String
>[];
final
_TestSearchDelegate
delegate
=
new
_TestSearchDelegate
(
actions:
<
Widget
>[
new
Builder
(
builder:
(
BuildContext
context
)
{
return
new
IconButton
(
tooltip:
'Nested Search'
,
icon:
const
Icon
(
Icons
.
search
),
onPressed:
()
async
{
final
String
result
=
await
showSearch
(
context:
context
,
delegate:
nestedSearchDelegate
,
);
nestedSearchResults
.
add
(
result
);
},
);
},
)
],
);
await
tester
.
pumpWidget
(
new
TestHomePage
(
delegate:
delegate
,
results:
selectedResults
,
));
expect
(
find
.
text
(
'HomeBody'
),
findsOneWidget
);
await
tester
.
tap
(
find
.
byTooltip
(
'Search'
));
await
tester
.
pumpAndSettle
();
expect
(
find
.
text
(
'HomeBody'
),
findsNothing
);
expect
(
find
.
text
(
'Suggestions'
),
findsOneWidget
);
expect
(
find
.
text
(
'Nested Suggestions'
),
findsNothing
);
await
tester
.
tap
(
find
.
byTooltip
(
'Nested Search'
));
await
tester
.
pumpAndSettle
();
expect
(
find
.
text
(
'HomeBody'
),
findsNothing
);
expect
(
find
.
text
(
'Suggestions'
),
findsNothing
);
expect
(
find
.
text
(
'Nested Suggestions'
),
findsOneWidget
);
await
tester
.
tap
(
find
.
byTooltip
(
'Back'
));
await
tester
.
pumpAndSettle
();
expect
(
nestedSearchResults
,
<
String
>[
'Nested Result'
]);
expect
(
find
.
text
(
'HomeBody'
),
findsNothing
);
expect
(
find
.
text
(
'Suggestions'
),
findsOneWidget
);
expect
(
find
.
text
(
'Nested Suggestions'
),
findsNothing
);
await
tester
.
tap
(
find
.
byTooltip
(
'Back'
));
await
tester
.
pumpAndSettle
();
expect
(
find
.
text
(
'HomeBody'
),
findsOneWidget
);
expect
(
find
.
text
(
'Suggestions'
),
findsNothing
);
expect
(
find
.
text
(
'Nested Suggestions'
),
findsNothing
);
expect
(
selectedResults
,
<
String
>[
'Result'
]);
});
testWidgets
(
'Closing search with nested search shown goes back to underlying route'
,
(
WidgetTester
tester
)
async
{
_TestSearchDelegate
delegate
;
final
List
<
String
>
nestedSearchResults
=
<
String
>[];
final
_TestSearchDelegate
nestedSearchDelegate
=
new
_TestSearchDelegate
(
suggestions:
'Nested Suggestions'
,
result:
'Nested Result'
,
actions:
<
Widget
>[
new
Builder
(
builder:
(
BuildContext
context
)
{
return
new
IconButton
(
tooltip:
'Close Search'
,
icon:
const
Icon
(
Icons
.
close
),
onPressed:
()
async
{
delegate
.
close
(
context
,
'Result Foo'
);
},
);
},
)
],
);
final
List
<
String
>
selectedResults
=
<
String
>[];
delegate
=
new
_TestSearchDelegate
(
actions:
<
Widget
>[
new
Builder
(
builder:
(
BuildContext
context
)
{
return
new
IconButton
(
tooltip:
'Nested Search'
,
icon:
const
Icon
(
Icons
.
search
),
onPressed:
()
async
{
final
String
result
=
await
showSearch
(
context:
context
,
delegate:
nestedSearchDelegate
,
);
nestedSearchResults
.
add
(
result
);
},
);
},
)
],
);
await
tester
.
pumpWidget
(
new
TestHomePage
(
delegate:
delegate
,
results:
selectedResults
,
));
expect
(
find
.
text
(
'HomeBody'
),
findsOneWidget
);
await
tester
.
tap
(
find
.
byTooltip
(
'Search'
));
await
tester
.
pumpAndSettle
();
expect
(
find
.
text
(
'HomeBody'
),
findsNothing
);
expect
(
find
.
text
(
'Suggestions'
),
findsOneWidget
);
expect
(
find
.
text
(
'Nested Suggestions'
),
findsNothing
);
await
tester
.
tap
(
find
.
byTooltip
(
'Nested Search'
));
await
tester
.
pumpAndSettle
();
expect
(
find
.
text
(
'HomeBody'
),
findsNothing
);
expect
(
find
.
text
(
'Suggestions'
),
findsNothing
);
expect
(
find
.
text
(
'Nested Suggestions'
),
findsOneWidget
);
await
tester
.
tap
(
find
.
byTooltip
(
'Close Search'
));
await
tester
.
pumpAndSettle
();
expect
(
find
.
text
(
'HomeBody'
),
findsOneWidget
);
expect
(
find
.
text
(
'Suggestions'
),
findsNothing
);
expect
(
find
.
text
(
'Nested Suggestions'
),
findsNothing
);
expect
(
nestedSearchResults
,
hasLength
(
0
));
expect
(
selectedResults
,
<
String
>[
'Result Foo'
]);
});
}
class
TestHomePage
extends
StatelessWidget
{
const
TestHomePage
({
this
.
results
,
this
.
delegate
,
this
.
passInInitialQuery
:
false
,
this
.
initialQuery
,
});
final
List
<
String
>
results
;
final
SearchDelegate
<
String
>
delegate
;
final
bool
passInInitialQuery
;
final
String
initialQuery
;
@override
Widget
build
(
BuildContext
context
)
{
return
new
MaterialApp
(
home:
Builder
(
builder:
(
BuildContext
context
)
{
return
new
Scaffold
(
appBar:
new
AppBar
(
title:
const
Text
(
'HomeTitle'
),
actions:
<
Widget
>[
new
IconButton
(
tooltip:
'Search'
,
icon:
const
Icon
(
Icons
.
search
),
onPressed:
()
async
{
String
selectedResult
;
if
(
passInInitialQuery
)
{
selectedResult
=
await
showSearch
<
String
>(
context:
context
,
delegate:
delegate
,
query:
initialQuery
,
);
}
else
{
selectedResult
=
await
showSearch
<
String
>(
context:
context
,
delegate:
delegate
,
);
}
results
?.
add
(
selectedResult
);
},
),
],
),
body:
const
Text
(
'HomeBody'
),
);
}),
);
}
}
class
_TestSearchDelegate
extends
SearchDelegate
<
String
>
{
_TestSearchDelegate
({
this
.
suggestions
:
'Suggestions'
,
this
.
result
:
'Result'
,
this
.
actions
:
const
<
Widget
>[],
});
final
String
suggestions
;
final
String
result
;
final
List
<
Widget
>
actions
;
@override
Widget
buildLeading
(
BuildContext
context
)
{
return
new
IconButton
(
tooltip:
'Back'
,
icon:
const
Icon
(
Icons
.
arrow_back
),
onPressed:
()
{
close
(
context
,
result
);
},
);
}
final
List
<
String
>
querysForSuggestions
=
<
String
>[];
final
List
<
String
>
querysForResults
=
<
String
>[];
@override
Widget
buildSuggestions
(
BuildContext
context
)
{
querysForSuggestions
.
add
(
query
);
return
new
MaterialButton
(
onPressed:
()
{
showResults
(
context
);
},
child:
new
Text
(
suggestions
),
);
}
@override
Widget
buildResults
(
BuildContext
context
)
{
querysForResults
.
add
(
query
);
return
const
Text
(
'Results'
);
}
@override
List
<
Widget
>
buildActions
(
BuildContext
context
)
{
return
actions
;
}
}
packages/flutter_localizations/lib/src/l10n/localizations.dart
View file @
d5a10340
...
...
@@ -64,6 +64,7 @@ class TranslationBundle {
String
get
popupMenuLabel
=>
parent
?.
popupMenuLabel
;
String
get
dialogLabel
=>
parent
?.
dialogLabel
;
String
get
alertDialogLabel
=>
parent
?.
alertDialogLabel
;
String
get
searchFieldLabel
=>
parent
?.
searchFieldLabel
;
}
// ignore: camel_case_types
...
...
@@ -113,6 +114,7 @@ class _Bundle_ar extends TranslationBundle {
@override
String
get
popupMenuLabel
=>
r'قائمة منبثقة'
;
@override
String
get
dialogLabel
=>
r'مربع حوار'
;
@override
String
get
alertDialogLabel
=>
r'مربع حوار التنبيه'
;
@override
String
get
searchFieldLabel
=>
r'بحث'
;
}
// ignore: camel_case_types
...
...
@@ -159,6 +161,7 @@ class _Bundle_de extends TranslationBundle {
@override
String
get
popupMenuLabel
=>
r'Pop-up-Menü'
;
@override
String
get
dialogLabel
=>
r'Dialogfeld'
;
@override
String
get
alertDialogLabel
=>
r'Aufmerksam'
;
@override
String
get
searchFieldLabel
=>
r'Suchen'
;
}
// ignore: camel_case_types
...
...
@@ -205,6 +208,7 @@ class _Bundle_en extends TranslationBundle {
@override
String
get
popupMenuLabel
=>
r'Popup menu'
;
@override
String
get
dialogLabel
=>
r'Dialog'
;
@override
String
get
alertDialogLabel
=>
r'Alert'
;
@override
String
get
searchFieldLabel
=>
r'Search'
;
}
// ignore: camel_case_types
...
...
@@ -251,6 +255,7 @@ class _Bundle_es extends TranslationBundle {
@override
String
get
popupMenuLabel
=>
r'Menú emergente'
;
@override
String
get
dialogLabel
=>
r'Cuadro de diálogo'
;
@override
String
get
alertDialogLabel
=>
r'Alerta'
;
@override
String
get
searchFieldLabel
=>
r'Buscar'
;
}
// ignore: camel_case_types
...
...
@@ -296,6 +301,7 @@ class _Bundle_fa extends TranslationBundle {
@override
String
get
popupMenuLabel
=>
r'منوی بازشو'
;
@override
String
get
dialogLabel
=>
r'کادر گفتگو'
;
@override
String
get
alertDialogLabel
=>
r'هشدار'
;
@override
String
get
searchFieldLabel
=>
r'جستجو کردن'
;
}
// ignore: camel_case_types
...
...
@@ -342,6 +348,7 @@ class _Bundle_fr extends TranslationBundle {
@override
String
get
popupMenuLabel
=>
r'Menu contextuel'
;
@override
String
get
dialogLabel
=>
r'Boîte de dialogue'
;
@override
String
get
alertDialogLabel
=>
r'Alerte'
;
@override
String
get
searchFieldLabel
=>
r'Chercher'
;
}
// ignore: camel_case_types
...
...
@@ -387,6 +394,7 @@ class _Bundle_gsw extends TranslationBundle {
@override
String
get
popupMenuLabel
=>
r'Pop-up-Menü'
;
@override
String
get
dialogLabel
=>
r'Dialogfeld'
;
@override
String
get
alertDialogLabel
=>
r'Aufmerksam'
;
@override
String
get
searchFieldLabel
=>
r'Suchen'
;
}
// ignore: camel_case_types
...
...
@@ -434,6 +442,7 @@ class _Bundle_he extends TranslationBundle {
@override
String
get
popupMenuLabel
=>
r'תפריט קופץ'
;
@override
String
get
dialogLabel
=>
r'תיבת דו-שיח'
;
@override
String
get
alertDialogLabel
=>
r'עֵרָנִי'
;
@override
String
get
searchFieldLabel
=>
r'לחפש'
;
}
// ignore: camel_case_types
...
...
@@ -479,6 +488,7 @@ class _Bundle_id extends TranslationBundle {
@override
String
get
popupMenuLabel
=>
r'Menu pop-up'
;
@override
String
get
dialogLabel
=>
r'Dialog'
;
@override
String
get
alertDialogLabel
=>
r'Waspada'
;
@override
String
get
searchFieldLabel
=>
r'Pencarian'
;
}
// ignore: camel_case_types
...
...
@@ -524,6 +534,7 @@ class _Bundle_it extends TranslationBundle {
@override
String
get
popupMenuLabel
=>
r'Menu popup'
;
@override
String
get
dialogLabel
=>
r'Finestra di dialogo'
;
@override
String
get
alertDialogLabel
=>
r'Mettere in guardia'
;
@override
String
get
searchFieldLabel
=>
r'Ricerca'
;
}
// ignore: camel_case_types
...
...
@@ -569,6 +580,7 @@ class _Bundle_ja extends TranslationBundle {
@override
String
get
popupMenuLabel
=>
r'ポップアップ メニュー'
;
@override
String
get
dialogLabel
=>
r'ダイアログ'
;
@override
String
get
alertDialogLabel
=>
r'アラート'
;
@override
String
get
searchFieldLabel
=>
r'サーチ'
;
}
// ignore: camel_case_types
...
...
@@ -614,6 +626,7 @@ class _Bundle_ko extends TranslationBundle {
@override
String
get
popupMenuLabel
=>
r'팝업 메뉴'
;
@override
String
get
dialogLabel
=>
r'대화상자'
;
@override
String
get
alertDialogLabel
=>
r'경보'
;
@override
String
get
searchFieldLabel
=>
r'수색'
;
}
// ignore: camel_case_types
...
...
@@ -660,6 +673,7 @@ class _Bundle_ms extends TranslationBundle {
@override
String
get
popupMenuLabel
=>
r'Menu pop timbul'
;
@override
String
get
dialogLabel
=>
r'Dialog'
;
@override
String
get
alertDialogLabel
=>
r'Amaran'
;
@override
String
get
searchFieldLabel
=>
r'Carian'
;
}
// ignore: camel_case_types
...
...
@@ -705,6 +719,7 @@ class _Bundle_nb extends TranslationBundle {
@override
String
get
popupMenuLabel
=>
r'Forgrunnsmeny'
;
@override
String
get
dialogLabel
=>
r'Dialogboks'
;
@override
String
get
alertDialogLabel
=>
r'Varsling'
;
@override
String
get
searchFieldLabel
=>
r'Søke'
;
}
// ignore: camel_case_types
...
...
@@ -750,6 +765,7 @@ class _Bundle_nl extends TranslationBundle {
@override
String
get
popupMenuLabel
=>
r'Pop-upmenu'
;
@override
String
get
dialogLabel
=>
r'Dialoogvenster'
;
@override
String
get
alertDialogLabel
=>
r'Alarm'
;
@override
String
get
searchFieldLabel
=>
r'Zoeken'
;
}
// ignore: camel_case_types
...
...
@@ -797,6 +813,7 @@ class _Bundle_pl extends TranslationBundle {
@override
String
get
popupMenuLabel
=>
r'Wyskakujące menu'
;
@override
String
get
dialogLabel
=>
r'Okno dialogowe'
;
@override
String
get
alertDialogLabel
=>
r'Alarm'
;
@override
String
get
searchFieldLabel
=>
r'Szukaj'
;
}
// ignore: camel_case_types
...
...
@@ -839,6 +856,7 @@ class _Bundle_ps extends TranslationBundle {
@override
String
get
popupMenuLabel
=>
r'د پاپ اپ مینو'
;
@override
String
get
dialogLabel
=>
r'خبرې اترې'
;
@override
String
get
alertDialogLabel
=>
r'خبرتیا'
;
@override
String
get
searchFieldLabel
=>
r'لټون'
;
}
// ignore: camel_case_types
...
...
@@ -884,6 +902,7 @@ class _Bundle_pt extends TranslationBundle {
@override
String
get
popupMenuLabel
=>
r'Menu pop-up'
;
@override
String
get
dialogLabel
=>
r'Caixa de diálogo'
;
@override
String
get
alertDialogLabel
=>
r'Alerta'
;
@override
String
get
searchFieldLabel
=>
r'Pesquisa'
;
}
// ignore: camel_case_types
...
...
@@ -931,6 +950,7 @@ class _Bundle_ro extends TranslationBundle {
@override
String
get
popupMenuLabel
=>
r'Meniu pop-up'
;
@override
String
get
dialogLabel
=>
r'Casetă de dialog'
;
@override
String
get
alertDialogLabel
=>
r'Alerta'
;
@override
String
get
searchFieldLabel
=>
r'Căutare'
;
}
// ignore: camel_case_types
...
...
@@ -979,6 +999,7 @@ class _Bundle_ru extends TranslationBundle {
@override
String
get
popupMenuLabel
=>
r'Всплывающее меню'
;
@override
String
get
dialogLabel
=>
r'Диалоговое окно'
;
@override
String
get
alertDialogLabel
=>
r'бдительный'
;
@override
String
get
searchFieldLabel
=>
r'Поиск'
;
}
// ignore: camel_case_types
...
...
@@ -1024,6 +1045,7 @@ class _Bundle_th extends TranslationBundle {
@override
String
get
popupMenuLabel
=>
r'เมนูป๊อปอัป'
;
@override
String
get
dialogLabel
=>
r'กล่องโต้ตอบ'
;
@override
String
get
alertDialogLabel
=>
r'เตือนภัย'
;
@override
String
get
searchFieldLabel
=>
r'ค้นหา'
;
}
// ignore: camel_case_types
...
...
@@ -1069,6 +1091,7 @@ class _Bundle_tr extends TranslationBundle {
@override
String
get
popupMenuLabel
=>
r'Popup menü'
;
@override
String
get
dialogLabel
=>
r'İletişim kutusu'
;
@override
String
get
alertDialogLabel
=>
r'Alarm'
;
@override
String
get
searchFieldLabel
=>
r'Arama'
;
}
// ignore: camel_case_types
...
...
@@ -1114,6 +1137,7 @@ class _Bundle_ur extends TranslationBundle {
@override
String
get
popupMenuLabel
=>
r'پاپ اپ مینو'
;
@override
String
get
dialogLabel
=>
r'ڈائیلاگ'
;
@override
String
get
alertDialogLabel
=>
r'انتباہ'
;
@override
String
get
searchFieldLabel
=>
r'تلاش کریں'
;
}
// ignore: camel_case_types
...
...
@@ -1159,6 +1183,7 @@ class _Bundle_vi extends TranslationBundle {
@override
String
get
popupMenuLabel
=>
r'Menu bật lên'
;
@override
String
get
dialogLabel
=>
r'Hộp thoại'
;
@override
String
get
alertDialogLabel
=>
r'Hộp thoại'
;
@override
String
get
searchFieldLabel
=>
r'Tìm kiếm'
;
}
// ignore: camel_case_types
...
...
@@ -1204,6 +1229,7 @@ class _Bundle_zh extends TranslationBundle {
@override
String
get
popupMenuLabel
=>
r'弹出菜单'
;
@override
String
get
dialogLabel
=>
r'对话框'
;
@override
String
get
alertDialogLabel
=>
r'警报'
;
@override
String
get
searchFieldLabel
=>
r'搜索'
;
}
// ignore: camel_case_types
...
...
packages/flutter_localizations/lib/src/l10n/material_ar.arb
View file @
d5a10340
...
...
@@ -42,5 +42,6 @@
"drawerLabel"
:
"قائمة تنقل"
,
"popupMenuLabel"
:
"قائمة منبثقة"
,
"dialogLabel"
:
"مربع حوار"
,
"alertDialogLabel"
:
"مربع حوار التنبيه"
"alertDialogLabel"
:
"مربع حوار التنبيه"
,
"searchFieldLabel"
:
"بحث"
}
packages/flutter_localizations/lib/src/l10n/material_de.arb
View file @
d5a10340
...
...
@@ -39,5 +39,6 @@
"drawerLabel"
:
"Navigationsmenü"
,
"popupMenuLabel"
:
"Pop-up-Menü"
,
"dialogLabel"
:
"Dialogfeld"
,
"alertDialogLabel"
:
"Aufmerksam"
"alertDialogLabel"
:
"Aufmerksam"
,
"searchFieldLabel"
:
"Suchen"
}
packages/flutter_localizations/lib/src/l10n/material_de_CH.arb
View file @
d5a10340
...
...
@@ -38,5 +38,6 @@
"drawerLabel"
:
"Navigationsmenü"
,
"popupMenuLabel"
:
"Pop-up-Menü"
,
"dialogLabel"
:
"Dialogfeld"
,
"alertDialogLabel"
:
"Aufmerksam"
"alertDialogLabel"
:
"Aufmerksam"
,
"searchFieldLabel"
:
"Suchen"
}
packages/flutter_localizations/lib/src/l10n/material_en.arb
View file @
d5a10340
...
...
@@ -199,5 +199,10 @@
"alertDialogLabel"
:
"Alert"
,
"@dialogLabel"
:
{
"description"
:
"The audio announcement made when an AlertDialog is opened."
},
"searchFieldLabel"
:
"Search"
,
"@dialogLabel"
:
{
"description"
:
"Label indicating that a text field is a search field. This will be used as a hint text in the text field."
}
}
packages/flutter_localizations/lib/src/l10n/material_en_AU.arb
View file @
d5a10340
...
...
@@ -38,5 +38,6 @@
"drawerLabel"
:
"Navigation menu"
,
"popupMenuLabel"
:
"Pop-up menu"
,
"dialogLabel"
:
"Dialogue"
,
"alertDialogLabel"
:
"Alert"
"alertDialogLabel"
:
"Alert"
,
"searchFieldLabel"
:
"Search"
}
packages/flutter_localizations/lib/src/l10n/material_en_CA.arb
View file @
d5a10340
...
...
@@ -38,5 +38,6 @@
"drawerLabel"
:
"Navigation menu"
,
"popupMenuLabel"
:
"Pop-up menu"
,
"dialogLabel"
:
"Dialogue"
,
"alertDialogLabel"
:
"Alert"
"alertDialogLabel"
:
"Alert"
,
"searchFieldLabel"
:
"Search"
}
packages/flutter_localizations/lib/src/l10n/material_en_GB.arb
View file @
d5a10340
...
...
@@ -38,5 +38,6 @@
"drawerLabel"
:
"Navigation menu"
,
"popupMenuLabel"
:
"Pop-up menu"
,
"dialogLabel"
:
"Dialogue"
,
"alertDialogLabel"
:
"Alert"
"alertDialogLabel"
:
"Alert"
,
"searchFieldLabel"
:
"Search"
}
packages/flutter_localizations/lib/src/l10n/material_en_IE.arb
View file @
d5a10340
...
...
@@ -38,5 +38,6 @@
"drawerLabel"
:
"Navigation menu"
,
"popupMenuLabel"
:
"Pop-up menu"
,
"dialogLabel"
:
"Dialogue"
,
"alertDialogLabel"
:
"Alert"
"alertDialogLabel"
:
"Alert"
,
"searchFieldLabel"
:
"Search"
}
packages/flutter_localizations/lib/src/l10n/material_en_IN.arb
View file @
d5a10340
...
...
@@ -38,5 +38,6 @@
"drawerLabel"
:
"Navigation menu"
,
"popupMenuLabel"
:
"Pop-up menu"
,
"dialogLabel"
:
"Dialogue"
,
"alertDialogLabel"
:
"Alert"
"alertDialogLabel"
:
"Alert"
,
"searchFieldLabel"
:
"Search"
}
packages/flutter_localizations/lib/src/l10n/material_en_SG.arb
View file @
d5a10340
...
...
@@ -38,5 +38,6 @@
"drawerLabel"
:
"Navigation menu"
,
"popupMenuLabel"
:
"Pop-up menu"
,
"dialogLabel"
:
"Dialogue"
,
"alertDialogLabel"
:
"Alert"
"alertDialogLabel"
:
"Alert"
,
"searchFieldLabel"
:
"Search"
}
packages/flutter_localizations/lib/src/l10n/material_en_ZA.arb
View file @
d5a10340
...
...
@@ -38,5 +38,6 @@
"drawerLabel"
:
"Navigation menu"
,
"popupMenuLabel"
:
"Pop-up menu"
,
"dialogLabel"
:
"Dialogue"
,
"alertDialogLabel"
:
"Alert"
"alertDialogLabel"
:
"Alert"
,
"searchFieldLabel"
:
"Search"
}
packages/flutter_localizations/lib/src/l10n/material_es.arb
View file @
d5a10340
...
...
@@ -39,5 +39,6 @@
"drawerLabel"
:
"Menú de navegación"
,
"popupMenuLabel"
:
"Menú emergente"
,
"dialogLabel"
:
"Cuadro de diálogo"
,
"alertDialogLabel"
:
"Alerta"
"alertDialogLabel"
:
"Alerta"
,
"searchFieldLabel"
:
"Buscar"
}
packages/flutter_localizations/lib/src/l10n/material_es_419.arb
View file @
d5a10340
...
...
@@ -38,5 +38,6 @@
"drawerLabel"
:
"Menú de navegación"
,
"popupMenuLabel"
:
"Menú emergente"
,
"dialogLabel"
:
"Diálogo"
,
"alertDialogLabel"
:
"Alerta"
"alertDialogLabel"
:
"Alerta"
,
"searchFieldLabel"
:
"Buscar"
}
packages/flutter_localizations/lib/src/l10n/material_es_AR.arb
View file @
d5a10340
...
...
@@ -38,5 +38,6 @@
"drawerLabel"
:
"Menú de navegación"
,
"popupMenuLabel"
:
"Menú emergente"
,
"dialogLabel"
:
"Diálogo"
,
"alertDialogLabel"
:
"Alerta"
"alertDialogLabel"
:
"Alerta"
,
"searchFieldLabel"
:
"Buscar"
}
packages/flutter_localizations/lib/src/l10n/material_es_BO.arb
View file @
d5a10340
...
...
@@ -38,5 +38,6 @@
"drawerLabel"
:
"Menú de navegación"
,
"popupMenuLabel"
:
"Menú emergente"
,
"dialogLabel"
:
"Diálogo"
,
"alertDialogLabel"
:
"Alerta"
"alertDialogLabel"
:
"Alerta"
,
"searchFieldLabel"
:
"Buscar"
}
packages/flutter_localizations/lib/src/l10n/material_es_CL.arb
View file @
d5a10340
...
...
@@ -38,5 +38,6 @@
"drawerLabel"
:
"Menú de navegación"
,
"popupMenuLabel"
:
"Menú emergente"
,
"dialogLabel"
:
"Diálogo"
,
"alertDialogLabel"
:
"Alerta"
"alertDialogLabel"
:
"Alerta"
,
"searchFieldLabel"
:
"Buscar"
}
packages/flutter_localizations/lib/src/l10n/material_es_CO.arb
View file @
d5a10340
...
...
@@ -38,5 +38,6 @@
"drawerLabel"
:
"Menú de navegación"
,
"popupMenuLabel"
:
"Menú emergente"
,
"dialogLabel"
:
"Diálogo"
,
"alertDialogLabel"
:
"Alerta"
"alertDialogLabel"
:
"Alerta"
,
"searchFieldLabel"
:
"Buscar"
}
packages/flutter_localizations/lib/src/l10n/material_es_CR.arb
View file @
d5a10340
...
...
@@ -38,5 +38,6 @@
"drawerLabel"
:
"Menú de navegación"
,
"popupMenuLabel"
:
"Menú emergente"
,
"dialogLabel"
:
"Diálogo"
,
"alertDialogLabel"
:
"Alerta"
"alertDialogLabel"
:
"Alerta"
,
"searchFieldLabel"
:
"Buscar"
}
packages/flutter_localizations/lib/src/l10n/material_es_DO.arb
View file @
d5a10340
...
...
@@ -38,5 +38,6 @@
"drawerLabel"
:
"Menú de navegación"
,
"popupMenuLabel"
:
"Menú emergente"
,
"dialogLabel"
:
"Diálogo"
,
"alertDialogLabel"
:
"Alerta"
"alertDialogLabel"
:
"Alerta"
,
"searchFieldLabel"
:
"Buscar"
}
packages/flutter_localizations/lib/src/l10n/material_es_EC.arb
View file @
d5a10340
...
...
@@ -38,5 +38,6 @@
"drawerLabel"
:
"Menú de navegación"
,
"popupMenuLabel"
:
"Menú emergente"
,
"dialogLabel"
:
"Diálogo"
,
"alertDialogLabel"
:
"Alerta"
"alertDialogLabel"
:
"Alerta"
,
"searchFieldLabel"
:
"Buscar"
}
packages/flutter_localizations/lib/src/l10n/material_es_GT.arb
View file @
d5a10340
...
...
@@ -38,5 +38,6 @@
"drawerLabel"
:
"Menú de navegación"
,
"popupMenuLabel"
:
"Menú emergente"
,
"dialogLabel"
:
"Diálogo"
,
"alertDialogLabel"
:
"Alerta"
"alertDialogLabel"
:
"Alerta"
,
"searchFieldLabel"
:
"Buscar"
}
packages/flutter_localizations/lib/src/l10n/material_es_HN.arb
View file @
d5a10340
...
...
@@ -38,5 +38,6 @@
"drawerLabel"
:
"Menú de navegación"
,
"popupMenuLabel"
:
"Menú emergente"
,
"dialogLabel"
:
"Diálogo"
,
"alertDialogLabel"
:
"Alerta"
"alertDialogLabel"
:
"Alerta"
,
"searchFieldLabel"
:
"Buscar"
}
packages/flutter_localizations/lib/src/l10n/material_es_MX.arb
View file @
d5a10340
...
...
@@ -38,5 +38,6 @@
"drawerLabel"
:
"Menú de navegación"
,
"popupMenuLabel"
:
"Menú emergente"
,
"dialogLabel"
:
"Diálogo"
,
"alertDialogLabel"
:
"Alerta"
"alertDialogLabel"
:
"Alerta"
,
"searchFieldLabel"
:
"Buscar"
}
packages/flutter_localizations/lib/src/l10n/material_es_NI.arb
View file @
d5a10340
...
...
@@ -38,5 +38,6 @@
"drawerLabel"
:
"Menú de navegación"
,
"popupMenuLabel"
:
"Menú emergente"
,
"dialogLabel"
:
"Diálogo"
,
"alertDialogLabel"
:
"Alerta"
"alertDialogLabel"
:
"Alerta"
,
"searchFieldLabel"
:
"Buscar"
}
packages/flutter_localizations/lib/src/l10n/material_es_PA.arb
View file @
d5a10340
...
...
@@ -38,5 +38,6 @@
"drawerLabel"
:
"Menú de navegación"
,
"popupMenuLabel"
:
"Menú emergente"
,
"dialogLabel"
:
"Diálogo"
,
"alertDialogLabel"
:
"Alerta"
"alertDialogLabel"
:
"Alerta"
,
"searchFieldLabel"
:
"Buscar"
}
packages/flutter_localizations/lib/src/l10n/material_es_PE.arb
View file @
d5a10340
...
...
@@ -38,5 +38,6 @@
"drawerLabel"
:
"Menú de navegación"
,
"popupMenuLabel"
:
"Menú emergente"
,
"dialogLabel"
:
"Diálogo"
,
"alertDialogLabel"
:
"Alerta"
"alertDialogLabel"
:
"Alerta"
,
"searchFieldLabel"
:
"Buscar"
}
packages/flutter_localizations/lib/src/l10n/material_es_PR.arb
View file @
d5a10340
...
...
@@ -38,5 +38,6 @@
"drawerLabel"
:
"Menú de navegación"
,
"popupMenuLabel"
:
"Menú emergente"
,
"dialogLabel"
:
"Diálogo"
,
"alertDialogLabel"
:
"Alerta"
"alertDialogLabel"
:
"Alerta"
,
"searchFieldLabel"
:
"Buscar"
}
packages/flutter_localizations/lib/src/l10n/material_es_PY.arb
View file @
d5a10340
...
...
@@ -38,5 +38,6 @@
"drawerLabel"
:
"Menú de navegación"
,
"popupMenuLabel"
:
"Menú emergente"
,
"dialogLabel"
:
"Diálogo"
,
"alertDialogLabel"
:
"Alerta"
"alertDialogLabel"
:
"Alerta"
,
"searchFieldLabel"
:
"Buscar"
}
packages/flutter_localizations/lib/src/l10n/material_es_SV.arb
View file @
d5a10340
...
...
@@ -38,5 +38,6 @@
"drawerLabel"
:
"Menú de navegación"
,
"popupMenuLabel"
:
"Menú emergente"
,
"dialogLabel"
:
"Diálogo"
,
"alertDialogLabel"
:
"Alerta"
"alertDialogLabel"
:
"Alerta"
,
"searchFieldLabel"
:
"Buscar"
}
packages/flutter_localizations/lib/src/l10n/material_es_US.arb
View file @
d5a10340
...
...
@@ -38,5 +38,6 @@
"drawerLabel"
:
"Menú de navegación"
,
"popupMenuLabel"
:
"Menú emergente"
,
"dialogLabel"
:
"Diálogo"
,
"alertDialogLabel"
:
"Alerta"
"alertDialogLabel"
:
"Alerta"
,
"searchFieldLabel"
:
"Buscar"
}
packages/flutter_localizations/lib/src/l10n/material_es_UY.arb
View file @
d5a10340
...
...
@@ -38,5 +38,6 @@
"drawerLabel"
:
"Menú de navegación"
,
"popupMenuLabel"
:
"Menú emergente"
,
"dialogLabel"
:
"Diálogo"
,
"alertDialogLabel"
:
"Alerta"
"alertDialogLabel"
:
"Alerta"
,
"searchFieldLabel"
:
"Buscar"
}
packages/flutter_localizations/lib/src/l10n/material_es_VE.arb
View file @
d5a10340
...
...
@@ -38,5 +38,6 @@
"drawerLabel"
:
"Menú de navegación"
,
"popupMenuLabel"
:
"Menú emergente"
,
"dialogLabel"
:
"Diálogo"
,
"alertDialogLabel"
:
"Alerta"
"alertDialogLabel"
:
"Alerta"
,
"searchFieldLabel"
:
"Buscar"
}
packages/flutter_localizations/lib/src/l10n/material_fa.arb
View file @
d5a10340
...
...
@@ -38,5 +38,6 @@
"drawerLabel"
:
"منوی پیمایش"
,
"popupMenuLabel"
:
"منوی بازشو"
,
"dialogLabel"
:
"کادر گفتگو"
,
"alertDialogLabel"
:
"هشدار"
"alertDialogLabel"
:
"هشدار"
,
"searchFieldLabel"
:
"جستجو کردن"
}
packages/flutter_localizations/lib/src/l10n/material_fr.arb
View file @
d5a10340
...
...
@@ -39,5 +39,6 @@
"drawerLabel"
:
"Menu de navigation"
,
"popupMenuLabel"
:
"Menu contextuel"
,
"dialogLabel"
:
"Boîte de dialogue"
,
"alertDialogLabel"
:
"Alerte"
"alertDialogLabel"
:
"Alerte"
,
"searchFieldLabel"
:
"Chercher"
}
packages/flutter_localizations/lib/src/l10n/material_gsw.arb
View file @
d5a10340
...
...
@@ -38,5 +38,6 @@
"drawerLabel"
:
"Navigationsmenü"
,
"popupMenuLabel"
:
"Pop-up-Menü"
,
"dialogLabel"
:
"Dialogfeld"
,
"alertDialogLabel"
:
"Aufmerksam"
"alertDialogLabel"
:
"Aufmerksam"
,
"searchFieldLabel"
:
"Suchen"
}
packages/flutter_localizations/lib/src/l10n/material_he.arb
View file @
d5a10340
...
...
@@ -40,5 +40,6 @@
"drawerLabel"
:
"תפריט ניווט"
,
"popupMenuLabel"
:
"תפריט קופץ"
,
"dialogLabel"
:
"תיבת דו-שיח"
,
"alertDialogLabel"
:
"עֵרָנִי"
"alertDialogLabel"
:
"עֵרָנִי"
,
"searchFieldLabel"
:
"לחפש"
}
packages/flutter_localizations/lib/src/l10n/material_id.arb
View file @
d5a10340
...
...
@@ -38,5 +38,6 @@
"drawerLabel"
:
"Menu navigasi"
,
"popupMenuLabel"
:
"Menu pop-up"
,
"dialogLabel"
:
"Dialog"
,
"alertDialogLabel"
:
"Waspada"
"alertDialogLabel"
:
"Waspada"
,
"searchFieldLabel"
:
"Pencarian"
}
packages/flutter_localizations/lib/src/l10n/material_it.arb
View file @
d5a10340
...
...
@@ -38,5 +38,6 @@
"drawerLabel"
:
"Menu di navigazione"
,
"popupMenuLabel"
:
"Menu popup"
,
"dialogLabel"
:
"Finestra di dialogo"
,
"alertDialogLabel"
:
"Mettere in guardia"
"alertDialogLabel"
:
"Mettere in guardia"
,
"searchFieldLabel"
:
"Ricerca"
}
packages/flutter_localizations/lib/src/l10n/material_ja.arb
View file @
d5a10340
...
...
@@ -38,5 +38,6 @@
"drawerLabel"
:
"ナビゲーション メニュー"
,
"popupMenuLabel"
:
"ポップアップ メニュー"
,
"dialogLabel"
:
"ダイアログ"
,
"alertDialogLabel"
:
"アラート"
"alertDialogLabel"
:
"アラート"
,
"searchFieldLabel"
:
"サーチ"
}
packages/flutter_localizations/lib/src/l10n/material_ko.arb
View file @
d5a10340
...
...
@@ -38,5 +38,6 @@
"drawerLabel"
:
"탐색 메뉴"
,
"popupMenuLabel"
:
"팝업 메뉴"
,
"dialogLabel"
:
"대화상자"
,
"alertDialogLabel"
:
"경보"
"alertDialogLabel"
:
"경보"
,
"searchFieldLabel"
:
"수색"
}
packages/flutter_localizations/lib/src/l10n/material_ms.arb
View file @
d5a10340
...
...
@@ -39,5 +39,6 @@
"drawerLabel"
:
"Menu navigasi"
,
"popupMenuLabel"
:
"Menu pop timbul"
,
"dialogLabel"
:
"Dialog"
,
"alertDialogLabel"
:
"Amaran"
"alertDialogLabel"
:
"Amaran"
,
"searchFieldLabel"
:
"Carian"
}
packages/flutter_localizations/lib/src/l10n/material_nb.arb
View file @
d5a10340
...
...
@@ -38,5 +38,6 @@
"drawerLabel"
:
"Navigasjonsmeny"
,
"popupMenuLabel"
:
"Forgrunnsmeny"
,
"dialogLabel"
:
"Dialogboks"
,
"alertDialogLabel"
:
"Varsling"
"alertDialogLabel"
:
"Varsling"
,
"searchFieldLabel"
:
"Søke"
}
packages/flutter_localizations/lib/src/l10n/material_nl.arb
View file @
d5a10340
...
...
@@ -38,5 +38,6 @@
"drawerLabel"
:
"Navigatiemenu"
,
"popupMenuLabel"
:
"Pop-upmenu"
,
"dialogLabel"
:
"Dialoogvenster"
,
"alertDialogLabel"
:
"Alarm"
"alertDialogLabel"
:
"Alarm"
,
"searchFieldLabel"
:
"Zoeken"
}
packages/flutter_localizations/lib/src/l10n/material_pl.arb
View file @
d5a10340
...
...
@@ -40,5 +40,6 @@
"drawerLabel"
:
"Menu nawigacyjne"
,
"popupMenuLabel"
:
"Wyskakujące menu"
,
"dialogLabel"
:
"Okno dialogowe"
,
"alertDialogLabel"
:
"Alarm"
"alertDialogLabel"
:
"Alarm"
,
"searchFieldLabel"
:
"Szukaj"
}
packages/flutter_localizations/lib/src/l10n/material_ps.arb
View file @
d5a10340
...
...
@@ -37,5 +37,6 @@
"drawerLabel"
:
"د نیویگیشن مینو"
,
"popupMenuLabel"
:
"د پاپ اپ مینو"
,
"dialogLabel"
:
"خبرې اترې"
,
"alertDialogLabel"
:
"خبرتیا"
"alertDialogLabel"
:
"خبرتیا"
,
"searchFieldLabel"
:
"لټون"
}
packages/flutter_localizations/lib/src/l10n/material_pt.arb
View file @
d5a10340
...
...
@@ -40,5 +40,6 @@
"drawerLabel"
:
"Menu de navegação"
,
"popupMenuLabel"
:
"Menu pop-up"
,
"dialogLabel"
:
"Caixa de diálogo"
,
"alertDialogLabel"
:
"Alerta"
"alertDialogLabel"
:
"Alerta"
,
"searchFieldLabel"
:
"Pesquisa"
}
packages/flutter_localizations/lib/src/l10n/material_pt_PT.arb
View file @
d5a10340
...
...
@@ -38,5 +38,6 @@
"drawerLabel"
:
"Menu de navegação"
,
"popupMenuLabel"
:
"Menu pop-up"
,
"dialogLabel"
:
"Caixa de diálogo"
,
"alertDialogLabel"
:
"Alerta"
"alertDialogLabel"
:
"Alerta"
,
"searchFieldLabel"
:
"Pesquisa"
}
packages/flutter_localizations/lib/src/l10n/material_ro.arb
View file @
d5a10340
...
...
@@ -40,5 +40,6 @@
"drawerLabel"
:
"Meniu de navigare"
,
"popupMenuLabel"
:
"Meniu pop-up"
,
"dialogLabel"
:
"Casetă de dialog"
,
"alertDialogLabel"
:
"Alerta"
"alertDialogLabel"
:
"Alerta"
,
"searchFieldLabel"
:
"Căutare"
}
packages/flutter_localizations/lib/src/l10n/material_ru.arb
View file @
d5a10340
...
...
@@ -41,5 +41,6 @@
"drawerLabel"
:
"Меню навигации"
,
"popupMenuLabel"
:
"Всплывающее меню"
,
"dialogLabel"
:
"Диалоговое окно"
,
"alertDialogLabel"
:
"бдительный"
"alertDialogLabel"
:
"бдительный"
,
"searchFieldLabel"
:
"Поиск"
}
packages/flutter_localizations/lib/src/l10n/material_th.arb
View file @
d5a10340
...
...
@@ -38,5 +38,6 @@
"drawerLabel"
:
"เมนูการนำทาง"
,
"popupMenuLabel"
:
"เมนูป๊อปอัป"
,
"dialogLabel"
:
"กล่องโต้ตอบ"
,
"alertDialogLabel"
:
"เตือนภัย"
"alertDialogLabel"
:
"เตือนภัย"
,
"searchFieldLabel"
:
"ค้นหา"
}
packages/flutter_localizations/lib/src/l10n/material_tr.arb
View file @
d5a10340
...
...
@@ -38,5 +38,6 @@
"drawerLabel"
:
"Gezinme menüsü"
,
"popupMenuLabel"
:
"Popup menü"
,
"dialogLabel"
:
"İletişim kutusu"
,
"alertDialogLabel"
:
"Alarm"
"alertDialogLabel"
:
"Alarm"
,
"searchFieldLabel"
:
"Arama"
}
packages/flutter_localizations/lib/src/l10n/material_ur.arb
View file @
d5a10340
...
...
@@ -38,5 +38,6 @@
"drawerLabel"
:
"نیویگیشن مینو"
,
"popupMenuLabel"
:
"پاپ اپ مینو"
,
"dialogLabel"
:
"ڈائیلاگ"
,
"alertDialogLabel"
:
"انتباہ"
"alertDialogLabel"
:
"انتباہ"
,
"searchFieldLabel"
:
"تلاش کریں"
}
packages/flutter_localizations/lib/src/l10n/material_vi.arb
View file @
d5a10340
...
...
@@ -38,5 +38,6 @@
"drawerLabel"
:
"Menu di chuyển"
,
"popupMenuLabel"
:
"Menu bật lên"
,
"dialogLabel"
:
"Hộp thoại"
,
"alertDialogLabel"
:
"Hộp thoại"
"alertDialogLabel"
:
"Hộp thoại"
,
"searchFieldLabel"
:
"Tìm kiếm"
}
packages/flutter_localizations/lib/src/l10n/material_zh.arb
View file @
d5a10340
...
...
@@ -38,5 +38,6 @@
"drawerLabel"
:
"导航菜单"
,
"popupMenuLabel"
:
"弹出菜单"
,
"dialogLabel"
:
"对话框"
,
"alertDialogLabel"
:
"警报"
"alertDialogLabel"
:
"警报"
,
"searchFieldLabel"
:
"搜索"
}
packages/flutter_localizations/lib/src/l10n/material_zh_HK.arb
View file @
d5a10340
...
...
@@ -38,5 +38,6 @@
"drawerLabel"
:
"導覽選單"
,
"popupMenuLabel"
:
"彈出式選單"
,
"dialogLabel"
:
"對話方塊"
,
"alertDialogLabel"
:
"警报"
"alertDialogLabel"
:
"警报"
,
"searchFieldLabel"
:
"搜索"
}
packages/flutter_localizations/lib/src/l10n/material_zh_TW.arb
View file @
d5a10340
...
...
@@ -38,5 +38,6 @@
"drawerLabel"
:
"導覽選單"
,
"popupMenuLabel"
:
"彈出式選單"
,
"dialogLabel"
:
"對話方塊"
,
"alertDialogLabel"
:
"警报"
"alertDialogLabel"
:
"警报"
,
"searchFieldLabel"
:
"搜索"
}
packages/flutter_localizations/lib/src/material_localizations.dart
View file @
d5a10340
...
...
@@ -16,7 +16,7 @@ import 'widgets_localizations.dart';
// Watch out: the supported locales list in the doc comment below must be kept
// in sync with the list we test, see test/translations_test.dart, and of course
// the ac
ut
al list of supported locales in _MaterialLocalizationsDelegate.
// the ac
tu
al list of supported locales in _MaterialLocalizationsDelegate.
/// Localized strings for the material widgets.
///
...
...
@@ -268,6 +268,9 @@ class GlobalMaterialLocalizations implements MaterialLocalizations {
@override
String
get
alertDialogLabel
=>
_translationBundle
.
alertDialogLabel
;
@override
String
get
searchFieldLabel
=>
_translationBundle
.
searchFieldLabel
;
@override
String
aboutListTileTitle
(
String
applicationName
)
{
final
String
text
=
_translationBundle
.
aboutListTileTitle
;
...
...
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