prototypeItem added to ReorderableList and ReorderableListView (#81604)
prototypeItem added to ReorderableList and ReorderableListView along with tests
This commit is contained in:
parent
2d89ebb929
commit
f9905fc43c
@ -77,6 +77,7 @@ class ReorderableListView extends StatefulWidget {
|
|||||||
required List<Widget> children,
|
required List<Widget> children,
|
||||||
required this.onReorder,
|
required this.onReorder,
|
||||||
this.itemExtent,
|
this.itemExtent,
|
||||||
|
this.prototypeItem,
|
||||||
this.proxyDecorator,
|
this.proxyDecorator,
|
||||||
this.buildDefaultDragHandles = true,
|
this.buildDefaultDragHandles = true,
|
||||||
this.padding,
|
this.padding,
|
||||||
@ -96,6 +97,10 @@ class ReorderableListView extends StatefulWidget {
|
|||||||
}) : assert(scrollDirection != null),
|
}) : assert(scrollDirection != null),
|
||||||
assert(onReorder != null),
|
assert(onReorder != null),
|
||||||
assert(children != null),
|
assert(children != null),
|
||||||
|
assert(
|
||||||
|
itemExtent == null || prototypeItem == null,
|
||||||
|
'You can only pass itemExtent or prototypeItem, not both',
|
||||||
|
),
|
||||||
assert(
|
assert(
|
||||||
children.every((Widget w) => w.key != null),
|
children.every((Widget w) => w.key != null),
|
||||||
'All children of this widget must have a key.',
|
'All children of this widget must have a key.',
|
||||||
@ -170,6 +175,7 @@ class ReorderableListView extends StatefulWidget {
|
|||||||
required this.itemCount,
|
required this.itemCount,
|
||||||
required this.onReorder,
|
required this.onReorder,
|
||||||
this.itemExtent,
|
this.itemExtent,
|
||||||
|
this.prototypeItem,
|
||||||
this.proxyDecorator,
|
this.proxyDecorator,
|
||||||
this.buildDefaultDragHandles = true,
|
this.buildDefaultDragHandles = true,
|
||||||
this.padding,
|
this.padding,
|
||||||
@ -189,6 +195,10 @@ class ReorderableListView extends StatefulWidget {
|
|||||||
}) : assert(scrollDirection != null),
|
}) : assert(scrollDirection != null),
|
||||||
assert(itemCount >= 0),
|
assert(itemCount >= 0),
|
||||||
assert(onReorder != null),
|
assert(onReorder != null),
|
||||||
|
assert(
|
||||||
|
itemExtent == null || prototypeItem == null,
|
||||||
|
'You can only pass itemExtent or prototypeItem, not both',
|
||||||
|
),
|
||||||
assert(buildDefaultDragHandles != null),
|
assert(buildDefaultDragHandles != null),
|
||||||
super(key: key);
|
super(key: key);
|
||||||
|
|
||||||
@ -328,6 +338,9 @@ class ReorderableListView extends StatefulWidget {
|
|||||||
/// {@macro flutter.widgets.list_view.itemExtent}
|
/// {@macro flutter.widgets.list_view.itemExtent}
|
||||||
final double? itemExtent;
|
final double? itemExtent;
|
||||||
|
|
||||||
|
/// {@macro flutter.widgets.list_view.prototypeItem}
|
||||||
|
final Widget? prototypeItem;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_ReorderableListViewState createState() => _ReorderableListViewState();
|
_ReorderableListViewState createState() => _ReorderableListViewState();
|
||||||
}
|
}
|
||||||
@ -551,6 +564,7 @@ class _ReorderableListViewState extends State<ReorderableListView> {
|
|||||||
sliver: SliverReorderableList(
|
sliver: SliverReorderableList(
|
||||||
itemBuilder: _itemBuilder,
|
itemBuilder: _itemBuilder,
|
||||||
itemExtent: widget.itemExtent,
|
itemExtent: widget.itemExtent,
|
||||||
|
prototypeItem: widget.prototypeItem,
|
||||||
itemCount: widget.itemCount,
|
itemCount: widget.itemCount,
|
||||||
onReorder: widget.onReorder,
|
onReorder: widget.onReorder,
|
||||||
proxyDecorator: widget.proxyDecorator ?? _proxyDecorator,
|
proxyDecorator: widget.proxyDecorator ?? _proxyDecorator,
|
||||||
|
@ -18,6 +18,7 @@ import 'scroll_position.dart';
|
|||||||
import 'scroll_view.dart';
|
import 'scroll_view.dart';
|
||||||
import 'scrollable.dart';
|
import 'scrollable.dart';
|
||||||
import 'sliver.dart';
|
import 'sliver.dart';
|
||||||
|
import 'sliver_prototype_extent_list.dart';
|
||||||
import 'ticker_provider.dart';
|
import 'ticker_provider.dart';
|
||||||
import 'transitions.dart';
|
import 'transitions.dart';
|
||||||
|
|
||||||
@ -113,6 +114,7 @@ class ReorderableList extends StatefulWidget {
|
|||||||
required this.itemCount,
|
required this.itemCount,
|
||||||
required this.onReorder,
|
required this.onReorder,
|
||||||
this.itemExtent,
|
this.itemExtent,
|
||||||
|
this.prototypeItem,
|
||||||
this.proxyDecorator,
|
this.proxyDecorator,
|
||||||
this.padding,
|
this.padding,
|
||||||
this.scrollDirection = Axis.vertical,
|
this.scrollDirection = Axis.vertical,
|
||||||
@ -128,6 +130,10 @@ class ReorderableList extends StatefulWidget {
|
|||||||
this.restorationId,
|
this.restorationId,
|
||||||
this.clipBehavior = Clip.hardEdge,
|
this.clipBehavior = Clip.hardEdge,
|
||||||
}) : assert(itemCount >= 0),
|
}) : assert(itemCount >= 0),
|
||||||
|
assert(
|
||||||
|
itemExtent == null || prototypeItem == null,
|
||||||
|
'You can only pass itemExtent or prototypeItem, not both',
|
||||||
|
),
|
||||||
super(key: key);
|
super(key: key);
|
||||||
|
|
||||||
/// {@template flutter.widgets.reorderable_list.itemBuilder}
|
/// {@template flutter.widgets.reorderable_list.itemBuilder}
|
||||||
@ -215,6 +221,9 @@ class ReorderableList extends StatefulWidget {
|
|||||||
/// {@macro flutter.widgets.list_view.itemExtent}
|
/// {@macro flutter.widgets.list_view.itemExtent}
|
||||||
final double? itemExtent;
|
final double? itemExtent;
|
||||||
|
|
||||||
|
/// {@macro flutter.widgets.list_view.prototypeItem}
|
||||||
|
final Widget? prototypeItem;
|
||||||
|
|
||||||
/// The state from the closest instance of this class that encloses the given
|
/// The state from the closest instance of this class that encloses the given
|
||||||
/// context.
|
/// context.
|
||||||
///
|
///
|
||||||
@ -342,6 +351,7 @@ class ReorderableListState extends State<ReorderableList> {
|
|||||||
sliver: SliverReorderableList(
|
sliver: SliverReorderableList(
|
||||||
key: _sliverReorderableListKey,
|
key: _sliverReorderableListKey,
|
||||||
itemExtent: widget.itemExtent,
|
itemExtent: widget.itemExtent,
|
||||||
|
prototypeItem: widget.prototypeItem,
|
||||||
itemBuilder: widget.itemBuilder,
|
itemBuilder: widget.itemBuilder,
|
||||||
itemCount: widget.itemCount,
|
itemCount: widget.itemCount,
|
||||||
onReorder: widget.onReorder,
|
onReorder: widget.onReorder,
|
||||||
@ -386,8 +396,13 @@ class SliverReorderableList extends StatefulWidget {
|
|||||||
required this.itemCount,
|
required this.itemCount,
|
||||||
required this.onReorder,
|
required this.onReorder,
|
||||||
this.itemExtent,
|
this.itemExtent,
|
||||||
|
this.prototypeItem,
|
||||||
this.proxyDecorator,
|
this.proxyDecorator,
|
||||||
}) : assert(itemCount >= 0),
|
}) : assert(itemCount >= 0),
|
||||||
|
assert(
|
||||||
|
itemExtent == null || prototypeItem == null,
|
||||||
|
'You can only pass itemExtent or prototypeItem, not both',
|
||||||
|
),
|
||||||
super(key: key);
|
super(key: key);
|
||||||
|
|
||||||
/// {@macro flutter.widgets.reorderable_list.itemBuilder}
|
/// {@macro flutter.widgets.reorderable_list.itemBuilder}
|
||||||
@ -405,6 +420,9 @@ class SliverReorderableList extends StatefulWidget {
|
|||||||
/// {@macro flutter.widgets.list_view.itemExtent}
|
/// {@macro flutter.widgets.list_view.itemExtent}
|
||||||
final double? itemExtent;
|
final double? itemExtent;
|
||||||
|
|
||||||
|
/// {@macro flutter.widgets.list_view.prototypeItem}
|
||||||
|
final Widget? prototypeItem;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
SliverReorderableListState createState() => SliverReorderableListState();
|
SliverReorderableListState createState() => SliverReorderableListState();
|
||||||
|
|
||||||
@ -841,12 +859,18 @@ class SliverReorderableListState extends State<SliverReorderableList> with Ticke
|
|||||||
// list extent stable we add a dummy entry to the end.
|
// list extent stable we add a dummy entry to the end.
|
||||||
childCount: widget.itemCount + (_dragInfo != null ? 1 : 0),
|
childCount: widget.itemCount + (_dragInfo != null ? 1 : 0),
|
||||||
);
|
);
|
||||||
return widget.itemExtent != null
|
if (widget.itemExtent != null) {
|
||||||
? SliverFixedExtentList(
|
return SliverFixedExtentList(
|
||||||
itemExtent: widget.itemExtent!,
|
delegate: childrenDelegate,
|
||||||
delegate: childrenDelegate,
|
itemExtent: widget.itemExtent!,
|
||||||
)
|
);
|
||||||
: SliverList(delegate: childrenDelegate);
|
} else if (widget.prototypeItem != null) {
|
||||||
|
return SliverPrototypeExtentList(
|
||||||
|
delegate: childrenDelegate,
|
||||||
|
prototypeItem: widget.prototypeItem!,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return SliverList(delegate: childrenDelegate);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1490,11 +1490,12 @@ class ListView extends BoxScrollView {
|
|||||||
/// * [SliverFixedExtentList], the sliver used internally when this property
|
/// * [SliverFixedExtentList], the sliver used internally when this property
|
||||||
/// is provided. It constrains its box children to have a specific given
|
/// is provided. It constrains its box children to have a specific given
|
||||||
/// extent along the main axis.
|
/// extent along the main axis.
|
||||||
/// {@endtemplate}
|
|
||||||
/// * The [prototypeItem] property, which allows forcing the children's
|
/// * The [prototypeItem] property, which allows forcing the children's
|
||||||
/// extent to be the same as the given widget.
|
/// extent to be the same as the given widget.
|
||||||
|
/// {@endtemplate}
|
||||||
final double? itemExtent;
|
final double? itemExtent;
|
||||||
|
|
||||||
|
/// {@template flutter.widgets.list_view.prototypeItem}
|
||||||
/// If non-null, forces the children to have the same extent as the given
|
/// If non-null, forces the children to have the same extent as the given
|
||||||
/// widget in the scroll direction.
|
/// widget in the scroll direction.
|
||||||
///
|
///
|
||||||
@ -1510,6 +1511,7 @@ class ListView extends BoxScrollView {
|
|||||||
/// extent as a prototype item along the main axis.
|
/// extent as a prototype item along the main axis.
|
||||||
/// * The [itemExtent] property, which allows forcing the children's extent
|
/// * The [itemExtent] property, which allows forcing the children's extent
|
||||||
/// to a given value.
|
/// to a given value.
|
||||||
|
/// {@endtemplate}
|
||||||
final Widget? prototypeItem;
|
final Widget? prototypeItem;
|
||||||
|
|
||||||
/// A delegate that provides the children for the [ListView].
|
/// A delegate that provides the children for the [ListView].
|
||||||
|
@ -1506,6 +1506,35 @@ void main() {
|
|||||||
expect(exception.toString(), contains('ReorderableListView widgets require an Overlay widget ancestor'));
|
expect(exception.toString(), contains('ReorderableListView widgets require an Overlay widget ancestor'));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
testWidgets('ReorderableListView asserts on both non-null itemExtent and prototypeItem', (WidgetTester tester) async {
|
||||||
|
expect(() => ReorderableListView(
|
||||||
|
children: const <Widget>[],
|
||||||
|
itemExtent: 30,
|
||||||
|
prototypeItem: const SizedBox(),
|
||||||
|
onReorder: (int fromIndex, int toIndex) { },
|
||||||
|
), throwsAssertionError);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('ReorderableListView.builder asserts on both non-null itemExtent and prototypeItem', (WidgetTester tester) async {
|
||||||
|
final List<int> numbers = <int>[0,1,2];
|
||||||
|
expect(() => ReorderableListView.builder(
|
||||||
|
itemBuilder: (BuildContext context, int index) {
|
||||||
|
return SizedBox(
|
||||||
|
key: ValueKey<int>(numbers[index]),
|
||||||
|
height: 20 + numbers[index] * 10,
|
||||||
|
child: ReorderableDragStartListener(
|
||||||
|
index: index,
|
||||||
|
child: Text(numbers[index].toString()),
|
||||||
|
)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
itemCount: numbers.length,
|
||||||
|
itemExtent: 30,
|
||||||
|
prototypeItem: const SizedBox(),
|
||||||
|
onReorder: (int fromIndex, int toIndex) { },
|
||||||
|
), throwsAssertionError);
|
||||||
|
});
|
||||||
|
|
||||||
testWidgets('if itemExtent is non-null, children have same extent in the scroll direction', (WidgetTester tester) async {
|
testWidgets('if itemExtent is non-null, children have same extent in the scroll direction', (WidgetTester tester) async {
|
||||||
final List<int> numbers = <int>[0,1,2];
|
final List<int> numbers = <int>[0,1,2];
|
||||||
|
|
||||||
@ -1528,13 +1557,49 @@ void main() {
|
|||||||
},
|
},
|
||||||
itemCount: numbers.length,
|
itemCount: numbers.length,
|
||||||
itemExtent: 30,
|
itemExtent: 30,
|
||||||
onReorder: (int fromIndex, int toIndex) {
|
onReorder: (int fromIndex, int toIndex) { },
|
||||||
if (fromIndex < toIndex) {
|
);
|
||||||
toIndex--;
|
},
|
||||||
}
|
),
|
||||||
final int value = numbers.removeAt(fromIndex);
|
),
|
||||||
numbers.insert(toIndex, value);
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
final double item0Height = tester.getSize(find.text('0').hitTestable()).height;
|
||||||
|
final double item1Height = tester.getSize(find.text('1').hitTestable()).height;
|
||||||
|
final double item2Height = tester.getSize(find.text('2').hitTestable()).height;
|
||||||
|
|
||||||
|
expect(item0Height, 30.0);
|
||||||
|
expect(item1Height, 30.0);
|
||||||
|
expect(item2Height, 30.0);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('if prototypeItem is non-null, children have same extent in the scroll direction', (WidgetTester tester) async {
|
||||||
|
final List<int> numbers = <int>[0,1,2];
|
||||||
|
|
||||||
|
await tester.pumpWidget(
|
||||||
|
MaterialApp(
|
||||||
|
home: Scaffold(
|
||||||
|
body: StatefulBuilder(
|
||||||
|
builder: (BuildContext context, StateSetter setState) {
|
||||||
|
return ReorderableListView.builder(
|
||||||
|
itemBuilder: (BuildContext context, int index) {
|
||||||
|
return SizedBox(
|
||||||
|
key: ValueKey<int>(numbers[index]),
|
||||||
|
// children with different heights
|
||||||
|
height: 20 + numbers[index] * 10,
|
||||||
|
child: ReorderableDragStartListener(
|
||||||
|
index: index,
|
||||||
|
child: Text(numbers[index].toString()),
|
||||||
|
)
|
||||||
|
);
|
||||||
},
|
},
|
||||||
|
itemCount: numbers.length,
|
||||||
|
prototypeItem: const SizedBox(
|
||||||
|
height: 30,
|
||||||
|
child: Text('3'),
|
||||||
|
),
|
||||||
|
onReorder: (int oldIndex, int newIndex) { },
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
@ -268,6 +268,46 @@ void main() {
|
|||||||
expect(getItemFadeTransition(), findsNothing);
|
expect(getItemFadeTransition(), findsNothing);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
testWidgets('ReorderableList asserts on both non-null itemExtent and prototypeItem', (WidgetTester tester) async {
|
||||||
|
final List<int> numbers = <int>[0,1,2];
|
||||||
|
expect(() => ReorderableList(
|
||||||
|
itemBuilder: (BuildContext context, int index) {
|
||||||
|
return SizedBox(
|
||||||
|
key: ValueKey<int>(numbers[index]),
|
||||||
|
height: 20 + numbers[index] * 10,
|
||||||
|
child: ReorderableDragStartListener(
|
||||||
|
index: index,
|
||||||
|
child: Text(numbers[index].toString()),
|
||||||
|
)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
itemCount: numbers.length,
|
||||||
|
itemExtent: 30,
|
||||||
|
prototypeItem: const SizedBox(),
|
||||||
|
onReorder: (int fromIndex, int toIndex) { },
|
||||||
|
), throwsAssertionError);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('SliverReorderableList asserts on both non-null itemExtent and prototypeItem', (WidgetTester tester) async {
|
||||||
|
final List<int> numbers = <int>[0,1,2];
|
||||||
|
expect(() => SliverReorderableList(
|
||||||
|
itemBuilder: (BuildContext context, int index) {
|
||||||
|
return SizedBox(
|
||||||
|
key: ValueKey<int>(numbers[index]),
|
||||||
|
height: 20 + numbers[index] * 10,
|
||||||
|
child: ReorderableDragStartListener(
|
||||||
|
index: index,
|
||||||
|
child: Text(numbers[index].toString()),
|
||||||
|
)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
itemCount: numbers.length,
|
||||||
|
itemExtent: 30,
|
||||||
|
prototypeItem: const SizedBox(),
|
||||||
|
onReorder: (int fromIndex, int toIndex) { },
|
||||||
|
), throwsAssertionError);
|
||||||
|
});
|
||||||
|
|
||||||
testWidgets('if itemExtent is non-null, children have same extent in the scroll direction', (WidgetTester tester) async {
|
testWidgets('if itemExtent is non-null, children have same extent in the scroll direction', (WidgetTester tester) async {
|
||||||
final List<int> numbers = <int>[0,1,2];
|
final List<int> numbers = <int>[0,1,2];
|
||||||
|
|
||||||
@ -312,6 +352,48 @@ void main() {
|
|||||||
expect(item1Height, 30.0);
|
expect(item1Height, 30.0);
|
||||||
expect(item2Height, 30.0);
|
expect(item2Height, 30.0);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
testWidgets('if prototypeItem is non-null, children have same extent in the scroll direction', (WidgetTester tester) async {
|
||||||
|
final List<int> numbers = <int>[0,1,2];
|
||||||
|
|
||||||
|
await tester.pumpWidget(
|
||||||
|
MaterialApp(
|
||||||
|
home: Scaffold(
|
||||||
|
body: StatefulBuilder(
|
||||||
|
builder: (BuildContext context, StateSetter setState) {
|
||||||
|
return ReorderableList(
|
||||||
|
itemBuilder: (BuildContext context, int index) {
|
||||||
|
return SizedBox(
|
||||||
|
key: ValueKey<int>(numbers[index]),
|
||||||
|
// children with different heights
|
||||||
|
height: 20 + numbers[index] * 10,
|
||||||
|
child: ReorderableDragStartListener(
|
||||||
|
index: index,
|
||||||
|
child: Text(numbers[index].toString()),
|
||||||
|
)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
itemCount: numbers.length,
|
||||||
|
prototypeItem: const SizedBox(
|
||||||
|
height: 30,
|
||||||
|
child: Text('3'),
|
||||||
|
),
|
||||||
|
onReorder: (int oldIndex, int newIndex) { },
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
final double item0Height = tester.getSize(find.text('0').hitTestable()).height;
|
||||||
|
final double item1Height = tester.getSize(find.text('1').hitTestable()).height;
|
||||||
|
final double item2Height = tester.getSize(find.text('2').hitTestable()).height;
|
||||||
|
|
||||||
|
expect(item0Height, 30.0);
|
||||||
|
expect(item1Height, 30.0);
|
||||||
|
expect(item2Height, 30.0);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
class TestList extends StatefulWidget {
|
class TestList extends StatefulWidget {
|
||||||
|
@ -1233,7 +1233,7 @@ void main() {
|
|||||||
expect(finder, findsOneWidget);
|
expect(finder, findsOneWidget);
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('ListView asserts on both non-null itemExtent and prototypeItem', (WidgetTester tester) async {
|
testWidgets('ListView asserts on both non-null itemExtent and prototypeItem', (WidgetTester tester) async {
|
||||||
expect(() => ListView(
|
expect(() => ListView(
|
||||||
itemExtent: 100,
|
itemExtent: 100,
|
||||||
prototypeItem: const SizedBox(),
|
prototypeItem: const SizedBox(),
|
||||||
@ -1372,4 +1372,45 @@ void main() {
|
|||||||
expect(item1Height, 30.0);
|
expect(item1Height, 30.0);
|
||||||
expect(item2Height, 30.0);
|
expect(item2Height, 30.0);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
testWidgets('if prototypeItem is non-null, children have same extent in the scroll direction', (WidgetTester tester) async {
|
||||||
|
final List<int> numbers = <int>[0,1,2];
|
||||||
|
|
||||||
|
await tester.pumpWidget(
|
||||||
|
MaterialApp(
|
||||||
|
home: Scaffold(
|
||||||
|
body: StatefulBuilder(
|
||||||
|
builder: (BuildContext context, StateSetter setState) {
|
||||||
|
return ListView.builder(
|
||||||
|
itemBuilder: (BuildContext context, int index) {
|
||||||
|
return SizedBox(
|
||||||
|
key: ValueKey<int>(numbers[index]),
|
||||||
|
// children with different heights
|
||||||
|
height: 20 + numbers[index] * 10,
|
||||||
|
child: ReorderableDragStartListener(
|
||||||
|
index: index,
|
||||||
|
child: Text(numbers[index].toString()),
|
||||||
|
)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
itemCount: numbers.length,
|
||||||
|
prototypeItem: const SizedBox(
|
||||||
|
height: 30,
|
||||||
|
child: Text('3'),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
final double item0Height = tester.getSize(find.text('0').hitTestable()).height;
|
||||||
|
final double item1Height = tester.getSize(find.text('1').hitTestable()).height;
|
||||||
|
final double item2Height = tester.getSize(find.text('2').hitTestable()).height;
|
||||||
|
|
||||||
|
expect(item0Height, 30.0);
|
||||||
|
expect(item1Height, 30.0);
|
||||||
|
expect(item2Height, 30.0);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user