Animate resizing a ListView item on tap - flutter

I have a multi-line Text() inside a ListView item.
By default I only want to show 1 line. When the user taps this item i want it to show all lines. I achieve this by setting the maxLines property of the Text-Widget dynamically to 1 or null.
This works great, but the resizing occurs immediatly but I want to animate this transition.
Here is some example code:
class ListPage extends StatelessWidget {
const ListPage({Key key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('List Example'),
),
body: ListView.separated(
itemBuilder: (context, index) {
return ListItem();
},
itemCount: 3,
separatorBuilder: (_, int index) => Divider(),
),
);
}
}
class ListItem extends StatefulWidget {
ListItem({Key key}) : super(key: key);
#override
_ListItemState createState() => _ListItemState();
}
class _ListItemState extends State<ListItem> {
bool _expanded;
#override
void initState() {
_expanded = false;
super.initState();
}
#override
Widget build(BuildContext context) {
return InkWell(
onTap: () {
setState(() {
_expanded = !_expanded;
});
},
child: Text(
'Line1\nLine2\nLine3',
maxLines: _expanded ? null : 1,
softWrap: true,
style: const TextStyle(fontSize: 22),
),
);
}
}
I also already tried using an AnimatedSwitcher like this:
class ListPage extends StatelessWidget {
const ListPage({Key key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('List Example'),
),
body: ListView.separated(
itemBuilder: (context, index) {
return ListItem();
},
itemCount: 3,
separatorBuilder: (_, int index) => Divider(),
),
);
}
}
class ListItem extends StatefulWidget {
ListItem({Key key}) : super(key: key);
#override
_ListItemState createState() => _ListItemState();
}
class _ListItemState extends State<ListItem> {
bool _expanded;
Widget _myAnimatedWidget;
#override
void initState() {
_expanded = false;
_myAnimatedWidget = ExpandableText(key: UniqueKey(), expanded: _expanded);
super.initState();
}
#override
Widget build(BuildContext context) {
return InkWell(
onTap: () {
setState(() {
_expanded = !_expanded;
_myAnimatedWidget =
ExpandableText(key: UniqueKey(), expanded: _expanded);
});
},
child: AnimatedSwitcher(
duration: Duration(milliseconds: 2000),
child: _myAnimatedWidget,
),
);
}
}
class ExpandableText extends StatelessWidget {
const ExpandableText({Key key, this.expanded}) : super(key: key);
final expanded;
#override
Widget build(BuildContext context) {
return Text(
'Line1\nLine2\nLine3',
maxLines: expanded ? null : 1,
softWrap: true,
style: const TextStyle(fontSize: 22),
);
}
}
This animates the Text-Widget but the ListView-Row still resizes immediatly.
What is my mistake? Is the approach of setting the maxLines property maybe wrong for my problem?
Thanks for your help !
Have a great day !

Thanks to Joao's comment I found the right answer:
I just had to wrap my Widget inside the AnimatedSize() widget. That's all :)

Related

Icon change provider index

Hi I want to change the icon when pressed button.
So I used provider method.
Icon Widget
class LockeryIcon extends StatelessWidget {
final String text;
LockeryIcon({required this.text});
#override
Widget build(BuildContext context) {
return IconButton(
onPressed: () {
Navigator.of(context).pushNamed(SecondView);
print(text);
},
icon: Icon(context.watch<ProviderA>().isIcon),
);
}
}
Listview builder
class Abc extends StatelessWidget {
final List _lock1 = [
'abc 1',
'abc 2',
'abc 3',
];
#override
Widget build(BuildContext context) {
return Scaffold(
body: ListView.builder(
shrinkWrap: true,
itemCount: _lock1.length,
itemBuilder: (context, index) {
return Padding(
padding: const EdgeInsets.all(30.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
LockeryIcon(text: _lock1[index]),
],
),
);
},
),
);
}
}
Main Screen
class MainView extends StatelessWidget {
const MainView({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
body: Abc(),
);
}
Second View
class SecondView extends StatelessWidget {
const SecondView({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
body: TextButton(
onPressed: () {
context.read<LockeryProvider>().change();
Navigator.of(context).pop();
},
child: Text('Done'),
),
);
}
}
Provider
class ProviderA with ChangeNotifier {
IconData _isIcon = Icons.access_time_filled_sharp;
IconData get isIcon => _isIcon;
void change() {
_isIcon = Icons.add_location;
notifyListeners();
}
}
My problem is when I clicked this all the icons are being changed.
Is there a way to pass index to only change the relevant button???
Or my method is not correct?
Please help me on this
Thank you
You have to store an integer in your provider:
class ProviderA with ChangeNotifier {
int _index = -1;
int get isIndex => _index;
void change(int index) {
_index = index;
notifyListeners();
}
}
and check the index in your Icon class like this:
class LockeryIcon extends StatelessWidget {
final String text;
final int listViewIndex;
LockeryIcon({required this.text,required this.listViewIndex});
#override
Widget build(BuildContext context) {
return IconButton(
onPressed: () {
Navigator.of(context).pushNamed(SecondView);
print(text);
},
icon: Icon(context.watch<ProviderA>().isIndex == listViewIndex ? firstIcon:secondIcon),
);
}
}
finally, use the change function in which you press your button.

Flutter: How to switch from one page view to another?

I am creating a flutter app where I have a screen which contains a PageView Builder.There are two other screens which are shown depending on the condition in the PageView Builder(i.e. QuizResult and QuizQuestion).
If the index if equal to the number of quiz questions it will show the Quiz Result Page otherwise it will continue showing the next question on the QuizQuestion Page(Have hardcoded the question for this example).
I want to know what logic can I add in the FlatButton widget onPressed in the QuizResult Page so that I can reset the index of the PageView back to the start and can again show the QuizQuestion Page again?
This is the QuizScreen
class QuizScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: PageView.builder(
physics: const NeverScrollableScrollPhysics(),
controller: state.controller,
scrollDirection: Axis.vertical,
itemBuilder: (BuildContext context, int index) {
if (index == quiz.questions.length) {
return QuizResult();
} else {
return QuizQuestion(question: quiz.questions[index]);
}
},
)
);
}
}
The QuizQuestion Widget looks like this
class QuizQuestion extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(body: Text('Which is the fastest animal?'));
}
}
The QuizResult Widget looks like this
class QuizResult extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(body: FlatButton(onPressed(){ < Logic Here ?? >}, child:Text('PlayAgain')));
}
}
I have used your code to reproduce the issue and then modified it for readability.
All you need is to assign an itemCount. And it needs to be the length of the quiz plus one. We need to add one more page to show the result page.
itemCount: questions.length + 1,
As you already predicted, we need to check the index of the shown page and create a condition based on it.
itemBuilder: (context, index) {
if (index == questions.length) {
return QuizResult(onPressed: onPressed);
}
return QuizQuestion(question: questions[index]);
},
Lastly, you need to jump to the first page using the controller to reset the quiz. The easiest way to do that is: Passing the onPressed function via constructor to QuizResult:
void onPressed() {
controller.jumpToPage(0);
currentPage = 0;
}
Please check the following solution:
main.dart
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) => MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const QuizScreen(),
);
}
class QuizScreen extends StatefulWidget {
const QuizScreen({Key? key}) : super(key: key);
#override
State<QuizScreen> createState() => _QuizScreenState();
}
class _QuizScreenState extends State<QuizScreen> {
final PageController controller = PageController();
int currentPage = 0;
List<String> questions = [
'Which is the fastest animal?',
'Which is the slowest animal?',
'Which is the longest animal?',
];
#override
Widget build(BuildContext context) => Scaffold(
body: SafeArea(
child: Column(
children: [
Expanded(
child: PageView.builder(
physics: const NeverScrollableScrollPhysics(),
controller: controller,
scrollDirection: Axis.vertical,
itemCount: questions.length + 1,
itemBuilder: (context, index) {
if (index == questions.length) {
return QuizResult(onPressed: onPressed);
}
return QuizQuestion(question: questions[index]);
},
),
),
TextButton(
onPressed: () {
if (currentPage == questions.length) return;
controller.jumpToPage(++currentPage);
},
child: const Text('Next'),
)
],
),
),
);
void onPressed() {
controller.jumpToPage(0);
currentPage = 0;
}
}
class QuizQuestion extends StatelessWidget {
const QuizQuestion({Key? key, required this.question}) : super(key: key);
final String question;
#override
Widget build(BuildContext context) => Center(
child: Text(question),
);
}
class QuizResult extends StatelessWidget {
const QuizResult({Key? key, required this.onPressed}) : super(key: key);
final void Function() onPressed;
#override
Widget build(BuildContext context) => Scaffold(
body: Center(
child: TextButton(
onPressed: onPressed,
child: const Text('Play Again'),
),
),
);
}
You can access the modified source code through GitHub.
If you have further questions, please don't hesitate to write in the comments.

Flutter - How to connect void to build widget?

I am trying to get a new historyTile() to be called to the Scaffold() each second. I am unsure how to make the void function connect.
Any advice and feedback is appreciated!
Code:
class activityTab extends StatefulWidget {
const activityTab({Key? key}) : super(key: key);
#override
State<activityTab> createState() => _activityTabState();
}
class _activityTabState extends State<activityTab> {
#override
void historyTile() {
final now = DateTime.now();
String tileTime = DateFormat.yMMMMd().add_jm().format(now);
ListView.builder(
shrinkWrap: true,
itemBuilder: (context, index) {
return ListTile(
leading: Icon(Icons.backup_outlined),
title: Text('Synced my_script.pdf with the cloud.'),
subtitle: Text('${tileTime}'),
tileColor: Colors.greenAccent,
);
}
);
}
#override
void initState() {
super.initState();
Timer.periodic(Duration(seconds: 1), (Timer t) => historyTile());
}
#override
Widget build(BuildContext context) {
return Scaffold(
body:
Container(
child: SingleChildScrollView(
child: historyTile(); // ERROR HERE
),
),
);
}
}
You can try creating periodic streams with a Stream Builder widget. If not, the simplest method is to put your widget in scaffold and try calling the setState function periodically with a 1-second timer.
In the StreamBuilder example you should change the widget a bit. Sending the parameter you want to update to the widget from outside will add a little more flexibility to you.
return Scaffold(
body: StreamBuilder<String>(
stream: Stream.periodic(const Duration(seconds: 1), (x) {
// Your Action Here
final now = DateTime.now();
return DateFormat.yMMMMd().add_jm().format(now);
}),
builder: (context, snapshot) {
String param = "";
if (snapshot.hasData) param = snapshot.data!;
return _historyTile(txt = param);
}
),
);
Or you could use your widget in Scaffold Body and periodically set the widgets state in timer callback.
class _activityTabState extends State<activityTab> {
String tileTime = "";
...
Timer.periodic(Duration(seconds: 1), () {
setState(() {
final now = DateTime.now();
tileTime = DateFormat.yMMMMd().add_jm().format(now);
});
};
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
child: SingleChildScrollView(
child: historyTile(tileName);
),
),
);
}
or just
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
child: SingleChildScrollView(
child: ListTile(
leading: Icon(Icons.backup_outlined),
title: Text('Synced my_script.pdf with the cloud.'),
subtitle: Text('$tileTime'),
tileColor: Colors.greenAccent,
),
),
),
);
}
Create your historyTile widget as a custom widget
class HistoryTile extends StatefulWidget {
const HistoryTile({Key? key, required this.txt}) : super(key: key);
final String txt;
#override
State<HistoryTile> createState() => _HistoryTileState();
}
class _HistoryTileState extends State<HistoryTile> {
#override
Widget build(BuildContext context) {
return ListTile(
leading: Icon(Icons.backup_outlined),
title: Text('Synced my_script.pdf with the cloud.'),
subtitle: Text(widget.txt),
tileColor: Colors.greenAccent,
);
}
}
there is some issues in you ListView.Builder. You do not put itemCount there. And you need to use setState in timer. So codes are below. Please check.
class activityTab extends StatefulWidget {
const activityTab({Key? key}) : super(key: key);
#override
State<activityTab> createState() => _activityTabState();
}
class _activityTabState extends State<activityTab> {
String _now;
Timer _everySecond;
#override
historyTile() {
final now = DateTime.now();
String tileTime = DateFormat.yMMMMd().add_jms().format(now);
return ListView.builder(
shrinkWrap: true,
itemCount: 1,
itemBuilder: (context, index) {
return ListTile(
leading: Icon(Icons.backup_outlined),
title: Text('Synced my_script.pdf with the cloud.'),
subtitle: Text('${tileTime}'),
tileColor: Colors.greenAccent,
);
});
}
void _timer() {
Future.delayed(Duration(seconds: 1)).then((_) {
setState(() {
_timer();
});
});
}
#override
void initState() {
super.initState();
_timer();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
height: 500,
child: SingleChildScrollView(
child: historyTile(),
),
),
);
}
}

Flutter Scroll view to focused widget on a column

I'm developing an app for Android TV, and use DPAD navigation.
I have multiple widgets inside a column. when i navigate to a widget which is outside the view, the widget/view is not moving to reflect the selected widget.
// ignore_for_file: avoid_print
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart';
import 'package:provider/provider.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
static const String _title = 'Flutter Code Sample';
#override
Widget build(BuildContext context) {
return MaterialApp(
title: _title,
home: Scaffold(
appBar: AppBar(title: const Text(_title)),
body: const MyStatelessWidget(),
),
);
}
}
class MyStatelessWidget extends StatelessWidget {
const MyStatelessWidget({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
final TextTheme textTheme = Theme.of(context).textTheme;
return DefaultTextStyle(
style: textTheme.headline4!,
child: ChangeNotifierProvider<SampleNotifier>(
create: (context) => SampleNotifier(), child: const CardHolder()),
);
}
}
class CardHolder extends StatefulWidget {
const CardHolder({Key? key}) : super(key: key);
#override
_CardHolderState createState() => _CardHolderState();
}
class _CardHolderState extends State<CardHolder> {
late FocusNode _focusNode;
late FocusAttachment _focusAttachment;
#override
void initState() {
super.initState();
_focusNode = FocusNode(debugLabel: "traversal_node");
_focusAttachment = _focusNode.attach(context, onKey: _handleKeyPress);
_focusNode.requestFocus();
}
#override
Widget build(BuildContext context) {
_focusAttachment.reparent();
return Focus(
focusNode: _focusNode,
autofocus: true,
onKey: _handleKeyPress,
child: Consumer<SampleNotifier>(
builder: (context, models, child) {
int listSize = Provider.of<SampleNotifier>(context).listSize;
return SingleChildScrollView(
child: SampleRow(cat: "Test", models: models.modelList),
);
},
),
);
}
KeyEventResult _handleKeyPress(FocusNode node, RawKeyEvent event) {
if (event is RawKeyDownEvent) {
print("t:FocusNode: ${node.debugLabel} event: ${event.logicalKey}");
if (event.logicalKey == LogicalKeyboardKey.arrowRight) {
Provider.of<SampleNotifier>(context, listen: false).moveRight();
return KeyEventResult.handled;
} else if (event.logicalKey == LogicalKeyboardKey.arrowLeft) {
Provider.of<SampleNotifier>(context, listen: false).moveLeft();
return KeyEventResult.handled;
}
}
// debugDumpFocusTree();
return KeyEventResult.ignored;
}
}
class SampleCard extends StatefulWidget {
final int number;
final SampleModel model;
final bool focused;
const SampleCard(
{required this.number,
required this.focused,
required this.model,
Key? key})
: super(key: key);
#override
_SampleCardState createState() => _SampleCardState();
}
class _SampleCardState extends State<SampleCard> {
late Color _color;
#override
void initState() {
super.initState();
_color = Colors.red.shade900;
}
#override
void dispose() {
super.dispose();
}
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 10),
child: widget.focused
? Container(
width: 150,
height: 300,
color: Colors.white,
child: Center(
child: Text(
"${widget.model.text} ${widget.model.num}",
style: TextStyle(color: _color),
),
),
)
: Container(
width: 150,
height: 300,
color: Colors.black,
child: Center(
child: Text(
"${widget.model.text} ${widget.model.num}",
style: TextStyle(color: _color),
),
),
),
);
}
}
class SampleRow extends StatelessWidget {
final String cat;
final List<SampleModel> models;
SampleRow({Key? key, required this.cat, required this.models}) : super(key: key);
#override
Widget build(BuildContext context) {
final int selectedIndex =
Provider.of<SampleNotifier>(context).selectedIndex;
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Padding(
padding: EdgeInsets.only(left: 16, bottom: 8),
),
models.isNotEmpty
? SizedBox(
height: 200,
child: ListView.custom(
padding: const EdgeInsets.all(8),
scrollDirection: Axis.horizontal,
childrenDelegate: SliverChildBuilderDelegate(
(context, index) => Padding(
padding: const EdgeInsets.symmetric(horizontal: 8),
child: SampleCard(
focused: index == selectedIndex,
model: models[index],
number: index,
),
),
childCount: models.length,
findChildIndexCallback: _findChildIndex,
),
),
)
: SizedBox(
height: 200,
child: Container(
color: Colors.teal,
),
)
],
);
}
int _findChildIndex(Key key) => models.indexWhere((model) =>
"$cat-${model.text}_${model.num}" == (key as ValueKey<String>).value);
}
class SampleNotifier extends ChangeNotifier {
final List<SampleModel> _models = [
SampleModel(0, "zero"),
SampleModel(1, "one"),
SampleModel(2, "two"),
SampleModel(3, "three"),
SampleModel(4, "four"),
SampleModel(5, "five"),
SampleModel(6, "six"),
SampleModel(7, "seven"),
SampleModel(8, "eight"),
SampleModel(9, "nine"),
SampleModel(10, "ten")
];
int _selectedIndex = 0;
List<SampleModel> get modelList => _models;
int get selectedIndex => _selectedIndex;
int get listSize => _models.length;
void moveRight() {
if (_selectedIndex < _models.length - 1) {
_selectedIndex = _selectedIndex + 1;
}
notifyListeners();
}
void moveLeft() {
if (_selectedIndex > 0) {
_selectedIndex = _selectedIndex - 1;
}
notifyListeners();
}
}
class SampleModel {
int num;
String text;
SampleModel(this.num, this.text);
}
I need a way to move/scroll the widget into view. Is there any way to do this, using the DPAD navigation on android tv
Here is the gist
You could use the scrollable_positioned_list package.
Instead of a ListView.custom which scrolls based on pixels, this widgets its based on index:
final ItemScrollController itemScrollController = ItemScrollController();
ScrollablePositionedList.builder(
itemCount: 500,
itemBuilder: (context, index) => Text('Item $index'),
itemScrollController: itemScrollController,
itemPositionsListener: itemPositionsListener,
);
So you could maintain an index of the current scroll position and on DPAD press just :
itemScrollController.jumpTo(index: currentItem);
setState((){currentItem++;})

How to set focus to TextField in ListView

I have a ListView that has a TextField widget in its children. Listview's items can be changed dynamically. When I press the "Add row" button, a new row should be added and the textfield belongs to newly added row should be focused (keyboard should be shown.) How can I achieve this?
Here is my sample code:
import 'package:flutter/material.dart';
class MainPage extends StatefulWidget {
MainPage({Key key}) : super(key: key);
_MainPageState createState() => _MainPageState();
}
class _MainPageState extends State<MainPage> {
List<String> list = ['one', 'two', 'three', 'four', 'five', 'six', 'seven'];
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('NoteList App'),
),
body: Column(children: <Widget>[
Expanded(child: _buildList(context)),
FlatButton(
onPressed: () {
setState(() {
list.add('new');
});
},
child: Text('Add row'))
]));
}
Widget _buildList(BuildContext context) {
return ListView.builder(
itemCount: list.length,
padding: const EdgeInsets.only(top: 1.0),
itemBuilder: (context, index) {
return ListItem(textContent: list[index]);
},
);
}
}
class ListItem extends StatelessWidget {
var _txt = TextEditingController();
final String textContent;
ListItem({Key key, this.textContent}) : super(key: key) {
_txt.text = textContent ?? '';
}
#override
Widget build(BuildContext context) {
return TextField(
controller: _txt,
textInputAction: TextInputAction.go,
);
}
}
You can copy paste run full code below
You can define an Item class and put FocusNode in it
then use FocusScope.of(context).requestFocus
code snippet
class Item {
String textContent;
FocusNode myFocusNode;
TextEditingController myController;
Item(this.textContent, this.myFocusNode, this.myController);
}
List<Item> list = [
Item('one', FocusNode(), TextEditingController()),
Item('two', FocusNode(), TextEditingController()),
Item('three', FocusNode(), TextEditingController()),
Item('four', FocusNode(), TextEditingController())
];
onPressed: () {
setState(() {
list.add(Item('new', FocusNode(), TextEditingController()));
});
WidgetsBinding.instance.addPostFrameCallback((_) {
FocusScope.of(context)
.requestFocus(list[list.length - 1].myFocusNode);
});
},
working demo
full code
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class Item {
String textContent;
FocusNode myFocusNode;
TextEditingController myController;
Item(this.textContent, this.myFocusNode, this.myController);
}
class MainPage extends StatefulWidget {
MainPage({Key key}) : super(key: key);
_MainPageState createState() => _MainPageState();
}
List<Item> list = [
Item('one', FocusNode(), TextEditingController()),
Item('two', FocusNode(), TextEditingController()),
Item('three', FocusNode(), TextEditingController()),
Item('four', FocusNode(), TextEditingController())
];
class _MainPageState extends State<MainPage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('NoteList App'),
),
body: Column(children: <Widget>[
Expanded(child: _buildList(context)),
FlatButton(
onPressed: () {
setState(() {
list.add(Item('new', FocusNode(), TextEditingController()));
});
WidgetsBinding.instance.addPostFrameCallback((_) {
FocusScope.of(context)
.requestFocus(list[list.length - 1].myFocusNode);
});
},
child: Text('Add row'))
]));
}
Widget _buildList(BuildContext context) {
return ListView.builder(
itemCount: list.length,
padding: const EdgeInsets.only(top: 1.0),
itemBuilder: (context, index) {
return ListItem(index: index);
},
);
}
#override
void dispose() {
list.forEach((element) {
element.myFocusNode.dispose();
element.myController.dispose();
});
super.dispose();
}
}
class ListItem extends StatefulWidget {
final int index;
ListItem({Key key, this.index}) : super(key: key);
#override
_ListItemState createState() => _ListItemState();
}
class _ListItemState extends State<ListItem> {
#override
void initState() {
super.initState();
list[widget.index].myController.text = list[widget.index].textContent;
}
#override
Widget build(BuildContext context) {
return TextField(
focusNode: list[widget.index].myFocusNode,
controller: list[widget.index].myController,
textInputAction: TextInputAction.go,
);
}
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MainPage(),
);
}
}