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
9608a64d
Unverified
Commit
9608a64d
authored
Oct 16, 2021
by
Kate Lovett
Committed by
GitHub
Oct 16, 2021
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Revert "Remove BottomNavigationBarItem.title deprecation" (#91930)
parent
99c8dd56
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
90 additions
and
71 deletions
+90
-71
bottom_tab_bar.dart
packages/flutter/lib/src/cupertino/bottom_tab_bar.dart
+1
-0
bottom_navigation_bar.dart
packages/flutter/lib/src/material/bottom_navigation_bar.dart
+5
-4
bottom_navigation_bar_theme.dart
...flutter/lib/src/material/bottom_navigation_bar_theme.dart
+2
-2
bottom_navigation_bar_item.dart
...s/flutter/lib/src/widgets/bottom_navigation_bar_item.dart
+15
-0
bottom_tab_bar_test.dart
packages/flutter/test/cupertino/bottom_tab_bar_test.dart
+1
-1
bottom_navigation_bar_test.dart
...ges/flutter/test/material/bottom_navigation_bar_test.dart
+66
-64
No files found.
packages/flutter/lib/src/cupertino/bottom_tab_bar.dart
View file @
9608a64d
...
...
@@ -254,6 +254,7 @@ class CupertinoTabBar extends StatelessWidget implements PreferredSizeWidget {
Expanded
(
child:
Center
(
child:
active
?
item
.
activeIcon
:
item
.
icon
),
),
if
(
item
.
title
!=
null
)
item
.
title
!,
if
(
item
.
label
!=
null
)
Text
(
item
.
label
!),
];
}
...
...
packages/flutter/lib/src/material/bottom_navigation_bar.dart
View file @
9608a64d
...
...
@@ -185,8 +185,9 @@ class BottomNavigationBar extends StatefulWidget {
})
:
assert
(
items
!=
null
),
assert
(
items
.
length
>=
2
),
assert
(
items
.
every
((
BottomNavigationBarItem
item
)
=>
item
.
title
!=
null
)
||
items
.
every
((
BottomNavigationBarItem
item
)
=>
item
.
label
!=
null
),
'Every item must have a non-null label'
,
'Every item must have a non-null
title or
label'
,
),
assert
(
0
<=
currentIndex
&&
currentIndex
<
items
.
length
),
assert
(
elevation
==
null
||
elevation
>=
0.0
),
...
...
@@ -246,13 +247,13 @@ class BottomNavigationBar extends StatefulWidget {
final
double
iconSize
;
/// The color of the selected [BottomNavigationBarItem.icon] and
/// [BottomNavigationBarItem.
label
].
/// [BottomNavigationBarItem.
title
].
///
/// If null then the [ThemeData.primaryColor] is used.
final
Color
?
selectedItemColor
;
/// The color of the unselected [BottomNavigationBarItem.icon] and
/// [BottomNavigationBarItem.
label
]s.
/// [BottomNavigationBarItem.
title
]s.
///
/// If null then the [ThemeData.unselectedWidgetColor]'s color is used.
final
Color
?
unselectedItemColor
;
...
...
@@ -691,7 +692,7 @@ class _Label extends StatelessWidget {
),
),
alignment:
Alignment
.
bottomCenter
,
child:
Text
(
item
.
label
!),
child:
item
.
title
??
Text
(
item
.
label
!),
),
);
...
...
packages/flutter/lib/src/material/bottom_navigation_bar_theme.dart
View file @
9608a64d
...
...
@@ -78,13 +78,13 @@ class BottomNavigationBarThemeData with Diagnosticable {
final
IconThemeData
?
unselectedIconTheme
;
/// The color of the selected [BottomNavigationBarItem.icon] and
/// [BottomNavigationBarItem.
label
].
/// [BottomNavigationBarItem.
title
].
///
/// See [BottomNavigationBar.selectedItemColor].
final
Color
?
selectedItemColor
;
/// The color of the unselected [BottomNavigationBarItem.icon] and
/// [BottomNavigationBarItem.
label
]s.
/// [BottomNavigationBarItem.
title
]s.
///
/// See [BottomNavigationBar.unselectedItemColor].
final
Color
?
unselectedItemColor
;
...
...
packages/flutter/lib/src/widgets/bottom_navigation_bar_item.dart
View file @
9608a64d
...
...
@@ -24,11 +24,17 @@ class BottomNavigationBarItem {
/// The argument [icon] should not be null and the argument [label] should not be null when used in a Material Design's [BottomNavigationBar].
const
BottomNavigationBarItem
({
required
this
.
icon
,
@Deprecated
(
'Use "label" instead, as it allows for an improved text-scaling experience. '
'This feature was deprecated after v1.19.0.'
,
)
this
.
title
,
this
.
label
,
Widget
?
activeIcon
,
this
.
backgroundColor
,
this
.
tooltip
,
})
:
activeIcon
=
activeIcon
??
icon
,
assert
(
label
==
null
||
title
==
null
),
assert
(
icon
!=
null
);
/// The icon of the item.
...
...
@@ -61,6 +67,15 @@ class BottomNavigationBarItem {
/// * [BottomNavigationBarItem.icon], for a description of how to pair icons.
final
Widget
activeIcon
;
/// The title of the item. If the title is not provided only the icon will be shown when not used in a Material Design [BottomNavigationBar].
///
/// This field is deprecated, use [label] instead.
@Deprecated
(
'Use "label" instead, as it allows for an improved text-scaling experience. '
'This feature was deprecated after v1.19.0.'
,
)
final
Widget
?
title
;
/// The text label for this [BottomNavigationBarItem].
///
/// This will be used to create a [Text] widget to put in the bottom navigation bar.
...
...
packages/flutter/test/cupertino/bottom_tab_bar_test.dart
View file @
9608a64d
...
...
@@ -429,7 +429,7 @@ Future<void> main() async {
semantics
.
dispose
();
});
testWidgets
(
'
Label
of items should be nullable'
,
(
WidgetTester
tester
)
async
{
testWidgets
(
'
Title
of items should be nullable'
,
(
WidgetTester
tester
)
async
{
final
MemoryImage
iconProvider
=
MemoryImage
(
Uint8List
.
fromList
(
kTransparentImage
));
final
List
<
int
>
itemsTapped
=
<
int
>[];
...
...
packages/flutter/test/material/bottom_navigation_bar_test.dart
View file @
9608a64d
...
...
@@ -28,11 +28,11 @@ void main() {
items:
const
<
BottomNavigationBarItem
>[
BottomNavigationBarItem
(
icon:
Icon
(
Icons
.
ac_unit
),
label:
'AC'
,
title:
Text
(
'AC'
)
,
),
BottomNavigationBarItem
(
icon:
Icon
(
Icons
.
access_alarm
),
label:
'Alarm'
,
title:
Text
(
'Alarm'
)
,
),
],
onTap:
(
int
index
)
{
...
...
@@ -1031,11 +1031,11 @@ void main() {
bottomNavigationBar:
BottomNavigationBar
(
items:
const
<
BottomNavigationBarItem
>[
BottomNavigationBarItem
(
label:
'A'
,
title:
Text
(
'A'
)
,
icon:
Icon
(
Icons
.
ac_unit
),
),
BottomNavigationBarItem
(
label:
'B'
,
title:
Text
(
'B'
)
,
icon:
Icon
(
Icons
.
battery_alert
),
),
],
...
...
@@ -1046,7 +1046,7 @@ void main() {
);
final
RenderBox
box
=
tester
.
renderObject
(
find
.
byType
(
BottomNavigationBar
));
expect
(
box
.
size
.
height
,
equals
(
5
6.0
));
expect
(
box
.
size
.
height
,
equals
(
6
6.0
));
});
testWidgets
(
'BottomNavigationBar does not grow with textScaleFactor when labels are provided'
,
(
WidgetTester
tester
)
async
{
...
...
@@ -1216,9 +1216,9 @@ void main() {
expect
(
find
.
byTooltip
(
'C'
),
findsNothing
);
});
testWidgets
(
'BottomNavigationBar limits width of tiles with long
label
s'
,
(
WidgetTester
tester
)
async
{
final
String
longTextA
=
List
<
String
>.
generate
(
100
,
(
int
index
)
=>
'A'
).
toString
(
);
final
String
longTextB
=
List
<
String
>.
generate
(
100
,
(
int
index
)
=>
'B'
).
toString
(
);
testWidgets
(
'BottomNavigationBar limits width of tiles with long
title
s'
,
(
WidgetTester
tester
)
async
{
final
Text
longTextA
=
Text
(
''
.
padLeft
(
100
,
'A'
)
);
final
Text
longTextB
=
Text
(
''
.
padLeft
(
100
,
'B'
)
);
await
tester
.
pumpWidget
(
MaterialApp
(
...
...
@@ -1226,11 +1226,11 @@ void main() {
bottomNavigationBar:
BottomNavigationBar
(
items:
<
BottomNavigationBarItem
>[
BottomNavigationBarItem
(
label
:
longTextA
,
title
:
longTextA
,
icon:
const
Icon
(
Icons
.
ac_unit
),
),
BottomNavigationBarItem
(
label
:
longTextB
,
title
:
longTextB
,
icon:
const
Icon
(
Icons
.
battery_alert
),
),
],
...
...
@@ -1242,9 +1242,9 @@ void main() {
final
RenderBox
box
=
tester
.
renderObject
(
find
.
byType
(
BottomNavigationBar
));
expect
(
box
.
size
.
height
,
equals
(
kBottomNavigationBarHeight
));
final
RenderBox
itemBoxA
=
tester
.
renderObject
(
find
.
text
(
longTextA
));
final
RenderBox
itemBoxA
=
tester
.
renderObject
(
find
.
text
(
longTextA
.
data
!
));
expect
(
itemBoxA
.
size
,
equals
(
const
Size
(
400.0
,
14.0
)));
final
RenderBox
itemBoxB
=
tester
.
renderObject
(
find
.
text
(
longTextB
));
final
RenderBox
itemBoxB
=
tester
.
renderObject
(
find
.
text
(
longTextB
.
data
!
));
expect
(
itemBoxB
.
size
,
equals
(
const
Size
(
400.0
,
14.0
)));
});
...
...
@@ -1379,15 +1379,15 @@ void main() {
items:
const
<
BottomNavigationBarItem
>[
BottomNavigationBarItem
(
icon:
Icon
(
Icons
.
ac_unit
),
label:
'AC'
,
title:
Text
(
'AC'
)
,
),
BottomNavigationBarItem
(
icon:
Icon
(
Icons
.
access_alarm
),
label:
'Alarm'
,
title:
Text
(
'Alarm'
)
,
),
BottomNavigationBarItem
(
icon:
Icon
(
Icons
.
hot_tub
),
label:
'Hot Tub'
,
title:
Text
(
'Hot Tub'
)
,
),
],
),
...
...
@@ -1433,15 +1433,15 @@ void main() {
items:
const
<
BottomNavigationBarItem
>[
BottomNavigationBarItem
(
icon:
Icon
(
Icons
.
ac_unit
),
label:
'AC'
,
title:
Text
(
'AC'
)
,
),
BottomNavigationBarItem
(
icon:
Icon
(
Icons
.
access_alarm
),
label:
'Alarm'
,
title:
Text
(
'Alarm'
)
,
),
BottomNavigationBarItem
(
icon:
Icon
(
Icons
.
hot_tub
),
label:
'Hot Tub'
,
title:
Text
(
'Hot Tub'
)
,
),
],
),
...
...
@@ -1626,7 +1626,7 @@ void main() {
}
});
testWidgets
(
'BottomNavigationBar item
label
should not be nullable'
,
(
WidgetTester
tester
)
async
{
testWidgets
(
'BottomNavigationBar item
title
should not be nullable'
,
(
WidgetTester
tester
)
async
{
expect
(()
{
MaterialApp
(
home:
Scaffold
(
...
...
@@ -1732,11 +1732,11 @@ void main() {
items:
const
<
BottomNavigationBarItem
>[
BottomNavigationBarItem
(
icon:
Icon
(
Icons
.
ac_unit
),
label:
'Red'
,
title:
Text
(
'Red'
)
,
),
BottomNavigationBarItem
(
icon:
Icon
(
Icons
.
access_alarm
),
label:
'Green'
,
title:
Text
(
'Green'
)
,
),
],
),
...
...
@@ -1775,11 +1775,11 @@ void main() {
items:
const
<
BottomNavigationBarItem
>[
BottomNavigationBarItem
(
icon:
Icon
(
Icons
.
ac_unit
),
label:
'Red'
,
title:
Text
(
'Red'
)
,
),
BottomNavigationBarItem
(
icon:
Icon
(
Icons
.
access_alarm
),
label:
'Green'
,
title:
Text
(
'Green'
)
,
),
],
),
...
...
@@ -1817,8 +1817,8 @@ void main() {
child:
BottomNavigationBar
(
mouseCursor:
SystemMouseCursors
.
text
,
items:
const
<
BottomNavigationBarItem
>[
BottomNavigationBarItem
(
icon:
Icon
(
Icons
.
ac_unit
),
label:
'AC'
),
BottomNavigationBarItem
(
icon:
Icon
(
Icons
.
access_alarm
),
label:
'Alarm'
),
BottomNavigationBarItem
(
icon:
Icon
(
Icons
.
ac_unit
),
title:
Text
(
'AC'
)
),
BottomNavigationBarItem
(
icon:
Icon
(
Icons
.
access_alarm
),
title:
Text
(
'Alarm'
)
),
],
),
),
...
...
@@ -1842,8 +1842,8 @@ void main() {
cursor:
SystemMouseCursors
.
forbidden
,
child:
BottomNavigationBar
(
items:
const
<
BottomNavigationBarItem
>[
BottomNavigationBarItem
(
icon:
Icon
(
Icons
.
ac_unit
),
label:
'AC'
),
BottomNavigationBarItem
(
icon:
Icon
(
Icons
.
access_alarm
),
label:
'Alarm'
),
BottomNavigationBarItem
(
icon:
Icon
(
Icons
.
ac_unit
),
title:
Text
(
'AC'
)
),
BottomNavigationBarItem
(
icon:
Icon
(
Icons
.
access_alarm
),
title:
Text
(
'Alarm'
)
),
],
),
),
...
...
@@ -1875,8 +1875,8 @@ void main() {
child:
BottomNavigationBar
(
enableFeedback:
enableFeedback
,
items:
const
<
BottomNavigationBarItem
>[
BottomNavigationBarItem
(
icon:
Icon
(
Icons
.
ac_unit
),
label:
'AC'
),
BottomNavigationBarItem
(
icon:
Icon
(
Icons
.
access_alarm
),
label:
'Alarm'
),
BottomNavigationBarItem
(
icon:
Icon
(
Icons
.
ac_unit
),
title:
Text
(
'AC'
)
),
BottomNavigationBarItem
(
icon:
Icon
(
Icons
.
access_alarm
),
title:
Text
(
'Alarm'
)
),
],
),
),
...
...
@@ -2015,7 +2015,9 @@ void main() {
testWidgets
(
'BottomNavigationBar default layout'
,
(
WidgetTester
tester
)
async
{
final
Key
icon0
=
UniqueKey
();
final
Key
title0
=
UniqueKey
();
final
Key
icon1
=
UniqueKey
();
final
Key
title1
=
UniqueKey
();
await
tester
.
pumpWidget
(
MaterialApp
(
...
...
@@ -2026,11 +2028,11 @@ void main() {
items:
<
BottomNavigationBarItem
>[
BottomNavigationBarItem
(
icon:
SizedBox
(
key:
icon0
,
width:
200
,
height:
10
),
label:
'Title0'
,
title:
SizedBox
(
key:
title0
,
width:
200
,
height:
10
)
,
),
BottomNavigationBarItem
(
icon:
SizedBox
(
key:
icon1
,
width:
200
,
height:
10
),
label:
'Title1'
,
title:
SizedBox
(
key:
title1
,
width:
200
,
height:
10
)
,
),
],
),
...
...
@@ -2045,24 +2047,25 @@ void main() {
// The height of the navigation bar is kBottomNavigationBarHeight = 56
// The top of the navigation bar is 600 - 56 = 544
// The top and bottom of the selected item is defined by its centered icon/label column:
// top = 544
+ ((56 - (10 + 10)) / 2)
= 562
// top = 544
- (56 - (10 + 10)) / 2
= 562
// bottom = top + 10 + 10 = 582
expect
(
tester
.
getRect
(
find
.
byKey
(
icon0
)).
top
,
560.0
);
expect
(
tester
.
getRect
(
find
.
text
(
'Title0'
)).
bottom
,
584.0
);
// The items are padded horizontally according to
// MainAxisAlignment.spaceAround. Left/right padding is:
// 800 - (200 * 2) / 4 = 100
// The layout of the unselected item's label is slightly different; not
// checking that here.
expect
(
tester
.
getRect
(
find
.
text
(
'Title0'
)),
const
Rect
.
fromLTRB
(
158.0
,
570.0
,
242.0
,
584.0
));
expect
(
tester
.
getRect
(
find
.
byKey
(
icon0
)),
const
Rect
.
fromLTRB
(
100.0
,
560.0
,
300.0
,
570.0
));
expect
(
tester
.
getRect
(
find
.
byKey
(
icon1
)),
const
Rect
.
fromLTRB
(
500.0
,
560.0
,
700.0
,
570.0
));
expect
(
tester
.
getRect
(
find
.
byKey
(
icon0
)).
top
,
562
);
expect
(
tester
.
getRect
(
find
.
byKey
(
title0
)).
bottom
,
582
);
// The items are horizontal padded according to
// MainAxisAlignment.spaceBetween Left/right padding is 800 - (200
// * 4) / 4 = 100. The layout of the unselected item's title is
// slightly different; not checking that here.
expect
(
tester
.
getRect
(
find
.
byKey
(
title0
)),
const
Rect
.
fromLTRB
(
100
,
572
,
300
,
582
));
expect
(
tester
.
getRect
(
find
.
byKey
(
icon0
)),
const
Rect
.
fromLTRB
(
100
,
562
,
300
,
572
));
expect
(
tester
.
getRect
(
find
.
byKey
(
icon1
)),
const
Rect
.
fromLTRB
(
500
,
562
,
700
,
572
));
});
testWidgets
(
'BottomNavigationBar centered landscape layout'
,
(
WidgetTester
tester
)
async
{
final
Key
icon0
=
UniqueKey
();
final
Key
title0
=
UniqueKey
();
final
Key
icon1
=
UniqueKey
();
final
Key
title1
=
UniqueKey
();
await
tester
.
pumpWidget
(
MaterialApp
(
...
...
@@ -2074,11 +2077,11 @@ void main() {
items:
<
BottomNavigationBarItem
>[
BottomNavigationBarItem
(
icon:
SizedBox
(
key:
icon0
,
width:
200
,
height:
10
),
label:
'Title0'
,
title:
SizedBox
(
key:
title0
,
width:
200
,
height:
10
)
,
),
BottomNavigationBarItem
(
icon:
SizedBox
(
key:
icon1
,
width:
200
,
height:
10
),
label:
'Title1'
,
title:
SizedBox
(
key:
title1
,
width:
200
,
height:
10
)
,
),
],
),
...
...
@@ -2091,23 +2094,22 @@ void main() {
expect
(
tester
.
getSize
(
find
.
byType
(
BottomNavigationBar
)),
const
Size
(
800
,
kBottomNavigationBarHeight
));
expect
(
tester
.
getRect
(
find
.
byType
(
BottomNavigationBar
)),
const
Rect
.
fromLTRB
(
0
,
600
-
kBottomNavigationBarHeight
,
800
,
600
));
// The items are laid out as in the default case, within width
=
600
// The items are laid out as in the default case, within width
=
600
// (the "portrait" width) and the result is centered with the
// landscape width = 800.
// So item 0's left edges are:
// ((800 - 600) / 2) + ((600 - 400) / 4) = 150.
// Item 1's right edge is:
// 800 - 150 = 650
// The layout of the unselected item's label is slightly different; not
// checking that here.
expect
(
tester
.
getRect
(
find
.
text
(
'Title0'
)),
const
Rect
.
fromLTRB
(
208.0
,
570.0
,
292.0
,
584.0
));
expect
(
tester
.
getRect
(
find
.
byKey
(
icon0
)),
const
Rect
.
fromLTRB
(
150.0
,
560.0
,
350.0
,
570.0
));
expect
(
tester
.
getRect
(
find
.
byKey
(
icon1
)),
const
Rect
.
fromLTRB
(
450.0
,
560.0
,
650.0
,
570.0
));
// landscape width=800. So item 0's left edges are (800 - 600) / 2 +
// (600 - 400) / 4 = 150. Item 1's right edge is 800 - 150 =
// 650. The layout of the unselected item's title is slightly
// different; not checking that here.
expect
(
tester
.
getRect
(
find
.
byKey
(
title0
)),
const
Rect
.
fromLTRB
(
150.0
,
572.0
,
350.0
,
582.0
));
expect
(
tester
.
getRect
(
find
.
byKey
(
icon0
)),
const
Rect
.
fromLTRB
(
150
,
562
,
350
,
572
));
expect
(
tester
.
getRect
(
find
.
byKey
(
icon1
)),
const
Rect
.
fromLTRB
(
450
,
562
,
650
,
572
));
});
testWidgets
(
'BottomNavigationBar linear landscape layout'
,
(
WidgetTester
tester
)
async
{
final
Key
icon0
=
UniqueKey
();
final
Key
title0
=
UniqueKey
();
final
Key
icon1
=
UniqueKey
();
final
Key
title1
=
UniqueKey
();
await
tester
.
pumpWidget
(
MaterialApp
(
...
...
@@ -2119,11 +2121,11 @@ void main() {
items:
<
BottomNavigationBarItem
>[
BottomNavigationBarItem
(
icon:
SizedBox
(
key:
icon0
,
width:
100
,
height:
20
),
label:
'Title0'
,
title:
SizedBox
(
key:
title0
,
width:
100
,
height:
20
)
,
),
BottomNavigationBarItem
(
icon:
SizedBox
(
key:
icon1
,
width:
100
,
height:
20
),
label:
'Title1'
,
title:
SizedBox
(
key:
title1
,
width:
100
,
height:
20
)
,
),
],
),
...
...
@@ -2137,12 +2139,12 @@ void main() {
expect
(
tester
.
getRect
(
find
.
byType
(
BottomNavigationBar
)),
const
Rect
.
fromLTRB
(
0
,
600
-
kBottomNavigationBarHeight
,
800
,
600
));
// The items are laid out as in the default case except each
// item's icon/
label
is arranged in a row, with 8 pixels in
// between the icon and
label
. The layout of the unselected
// item's
label
is slightly different; not checking that here.
expect
(
tester
.
getRect
(
find
.
text
(
'Title0'
)),
const
Rect
.
fromLTRB
(
212.0
,
565.0
,
296.0
,
579.0
));
expect
(
tester
.
getRect
(
find
.
byKey
(
icon0
)),
const
Rect
.
fromLTRB
(
104.0
,
562.0
,
204.0
,
582.0
));
expect
(
tester
.
getRect
(
find
.
byKey
(
icon1
)),
const
Rect
.
fromLTRB
(
504.0
,
562.0
,
604.0
,
582.0
));
// item's icon/
title
is arranged in a row, with 8 pixels in
// between the icon and
title
. The layout of the unselected
// item's
title
is slightly different; not checking that here.
expect
(
tester
.
getRect
(
find
.
byKey
(
title0
)),
const
Rect
.
fromLTRB
(
204
,
562
,
304
,
582
));
expect
(
tester
.
getRect
(
find
.
byKey
(
icon0
)),
const
Rect
.
fromLTRB
(
96
,
562
,
196
,
582
));
expect
(
tester
.
getRect
(
find
.
byKey
(
icon1
)),
const
Rect
.
fromLTRB
(
496
,
562
,
596
,
582
));
});
}
...
...
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