Flutter List, detail page and todo - list

I have a page with a list and a bar that reaches a detail page.
I would like to add a pop on the detail page to retrieve an item and save it to a todo page but I have a problem with my detail page.
With a Stateless, I have no worries but, if I'm not mistaken, I need a Stateful to add a Future, showDialog .. but, I have problems with my indexes... and there, I'm lost ...
Can someone give me a track or an explanation?
Thank you
home.dart
import 'dart:core';
import 'package:flutter/material.dart';
import 'package:test_todo_list/DataList.dart';
import 'package:test_todo_list/detail.dart';
class Home extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Liste Items'),
actions: <Widget>[
IconButton(icon: Icon(Icons.search),
onPressed: () {
showSearch(context: context, delegate: DataSearch(listWords));
})
],
),
body: ListView.separated(
itemCount: listWords.length,
separatorBuilder: (BuildContext context, int i) =>
Divider(color: Colors.grey),
itemBuilder: (context, i) {
return ListTile(
onTap: () {
Navigator.push(
context,MaterialPageRoute(
builder: (context) => Detail(listWordsDetail: listWords[i]),
),
);
},
title: RichText(
textAlign:TextAlign.left,
text: TextSpan(
children:<TextSpan>[
TextSpan(
text:listWords[i].titlelist,
style:Theme.of(context).textTheme.title.merge(TextStyle(color: Colors.blueGrey)),
),
]
)
),
subtitle: Text(listWords[i].definitionlist,
style: Theme.of(context).textTheme.subtitle.merge(
TextStyle(fontStyle: FontStyle.italic, color: Colors.grey)),
),
trailing: Icon(Icons.arrow_forward_ios, color: Colors.grey),
);
},
),
);
}
}
class DataSearch extends SearchDelegate<String> {
final List<ListWords> listWords;
DataSearch(this.listWords);
#override
List<Widget> buildActions(BuildContext context) {
//Actions for app bar
return [IconButton(icon: Icon(Icons.clear), onPressed: () {
query = '';
})];
}
#override
Widget buildLeading(BuildContext context) {
//leading icon on the left of the app bar
return IconButton(
icon: AnimatedIcon(icon: AnimatedIcons.menu_arrow,
progress: transitionAnimation,
),
onPressed: () {
close(context, null);
});
}
#override
Widget buildResults(BuildContext context) {
// show some result based on the selection
final suggestionList = listWords;
return ListView.builder(itemBuilder: (context, index) => ListTile(
title: Text(listWords[index].titlelist),
subtitle: Text(listWords[index].definitionlist),
),
itemCount: suggestionList.length,
);
}
#override
Widget buildSuggestions(BuildContext context) {
// show when someone searches for something
final suggestionList = query.isEmpty
? listWords
: listWords.where((p) => p.titlelist.contains(RegExp(query, caseSensitive: false))).toList();
return ListView.builder(itemBuilder: (context, index) => ListTile(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => Detail(listWordsDetail: suggestionList[index]),
),
);
},
trailing: Icon(Icons.remove_red_eye),
title: RichText(
text: TextSpan(
text: suggestionList[index].titlelist.substring(0, query.length),
style: TextStyle(
color: Colors.red, fontWeight: FontWeight.bold),
children: [
TextSpan(
text: suggestionList[index].titlelist.substring(query.length),
style: TextStyle(color: Colors.grey)),
]),
),
),
itemCount: suggestionList.length,
);
}
}
detail.dart
import 'package:flutter/material.dart';
import 'package:test_todo_list/DataList.dart';
class Detail extends StatefulWidget {
Detail({Key key, #required this.listWordsDetail}) : super(key: key);
final ListWords listWordsDetail;
#override
_DetailState createState() => _DetailState();
}
class _DetailState extends State<Detail> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
brightness: Brightness.dark,
title: const Text('Détails', style: TextStyle(color: Colors.white)),
iconTheme: IconThemeData(color: Colors.white),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(listWordsDetail.titlelist +' (on detail page)',
style:Theme.of(context).textTheme.title.merge(TextStyle(color: Colors.blueGrey)),
),
Text(listWordsDetail.definitionlist,
style: Theme.of(context).textTheme.subtitle.merge(
TextStyle(fontStyle: FontStyle.italic, color: Colors.grey)),
),
Container(
padding: EdgeInsets.all(40.0),
child: GestureDetector(
onTap: () {
},
child: Icon(Icons.add_shopping_cart),
),
)
],
),
)
);
}
}
DataList.dart
List<ListWords> listWords = [
ListWords('oneWord', 'OneWord definition'),
ListWords('twoWord', 'TwoWord definition.'),
ListWords('TreeWord', 'TreeWord definition'),
];
class ListWords {
String titlelist;
String definitionlist;
ListWords(String titlelist, String definitionlist) {
this.titlelist = titlelist;
this.definitionlist = definitionlist;
}
}

After searching on the web, by chance, I found this solution that I can not explain but it's working...
import 'package:flutter/material.dart';
import 'package:test_todo_list/DataList.dart';
import 'package:test_todo_list/todo_list.dart';
class Detail extends StatefulWidget {
const Detail({Key key, this.listWordsDetail}) : super (key: key);
final ListWords listWordsDetail;
#override
_DetailState createState() => _DetailState();
}
class _DetailState extends State<Detail> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
brightness: Brightness.dark,
title: const Text('Détails', style: TextStyle(color: Colors.white)),
iconTheme: IconThemeData(color: Colors.white),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(widget.listWordsDetail.titlelist),
Text(widget.listWordsDetail.definitionlist),
Container(
padding: EdgeInsets.all(40.0),
child: GestureDetector(
onTap: () {
//open Dialog addTodoList()
},
child: Icon(Icons.add_shopping_cart),
),
)
],
),
)
);
}
Future<Null> addTodoList() async {
showDialog(context: context);
//... à construire
}
}

Related

flutter : value not passed to the previous screen and is shown null while using constructor

Basically, I have two classes Register and AddUser. I want to navigate value from the AddUser page to the RegisterPage but I am not getting any values despite using the constructor and getting null value while debugging.
User First lands on the Register page where there is floatingAction button and it navigates to the AddUser Page. After providing the input , on clicking save button, it navigates back to the Register page where user will get the list of input.
**Register**
class Register extends StatefulWidget {
late String? names;
Register({required this.names});
#override
_RegisterState createState() => _RegisterState(names);
}
class _RegisterState extends State<Register> {
late String? names;
_RegisterState(this.names);
List<UserModel> getUserModel() {
return [
UserModel(
name: widget.names??'',
)
];
}
// final user = UserSimplePreferences.getUser();
#override
void initState() {
// TODO: implement initState
super.initState();
}
#override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Padding(
padding: const EdgeInsets.only(top: 10, bottom: 10),
child: Text('Seleccione una categoría:',
textAlign: TextAlign.center,
style: TextStyle(color: Colors.black)
),
),
Expanded(
child: ListView.builder(
itemCount: getUserModel().length,
itemBuilder: (BuildContext ctx, int index) {
return Container(
margin: EdgeInsets.all(20),
height: 150,
child: Stack(
children: [
Text(getUserModel()[index].name)
],
)
);
},
),
),
FloatingActionButton(
backgroundColor: Colors.indigo[900],
onPressed: () {
print(names);
Navigator.push(
context,
MaterialPageRoute(builder: (_) {
return AddUser(idUser: '',);
}),
);
},
child: Icon(Icons.add, color: Colors.white),
),
]
);
}
}
**AddUser**
class AddUser extends StatefulWidget {
final String? idUser;
const AddUser({required this.idUser});
#override
_AddUserState createState() => _AddUserState();
}
class _AddUserState extends State<AddUser> {
final formKey = GlobalKey<FormState>();
TextEditingController saaaaa = new TextEditingController();
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) => Scaffold(
appBar: AppBar(
automaticallyImplyLeading: false,
title: Text(
'Please Enter Your Details',
textAlign: TextAlign.center,
)),
body: SafeArea(
child: ListView(
padding: EdgeInsets.all(16),
children: [
buildName(),
const SizedBox(height: 12),
],
),
),
);
Widget buildName() => buildTitle(
title: 'Name',
child: TextFormField(
controller: saaaaa,
//initialValue: name,
decoration: InputDecoration(
border: OutlineInputBorder(),
hintText: 'Your Name',
),
onChanged: (namer) => setState(() => namer = saaaaa.text),
),
);
Widget buildButton() => ButtonWidget(
text: 'Save',
onClicked: () async {
setState(() async {
Register(names : saaaaa.text );
Navigator.pop(context);
});
});
Widget buildTitle({
required String title,
required Widget child,
}) =>
Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Text(
title,
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 18),
),
const SizedBox(height: 8),
child,
],
);
}
You can achive this things by then callback in navigator and pass your value when you pop add screen.
Please replace your code with below code
Register
class Register extends StatefulWidget {
#override
_RegisterState createState() => _RegisterState();
}
class _RegisterState extends State<Register> {
List<UserModel> userList = [];
// final user = UserSimplePreferences.getUser();
#override
void initState() {
// TODO: implement initState
super.initState();
}
#override
Widget build(BuildContext context) {
return Column(crossAxisAlignment: CrossAxisAlignment.stretch, children: [
Padding(
padding: const EdgeInsets.only(top: 10, bottom: 10),
child: Text('Seleccione una categoría:',
textAlign: TextAlign.center, style: TextStyle(color: Colors.black)),
),
Expanded(
child: ListView.builder(
itemCount: userList.length,
itemBuilder: (BuildContext ctx, int index) {
return Container(
margin: EdgeInsets.all(20),
height: 150,
child: Stack(
children: [Text(userList[index].name)],
));
},
),
),
FloatingActionButton(
backgroundColor: Colors.indigo[900],
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (_) {
return AddUser(
idUser: '',
);
}),
).then((value) {
if (value != null) {
userList.add(UserModel(name: value));
setState(() {});
}
});
},
child: Icon(Icons.add, color: Colors.white),
),
]);
}
}
**AddUser**
class AddUser extends StatefulWidget {
final String? idUser;
const AddUser({required this.idUser});
#override
_AddUserState createState() => _AddUserState();
}
class _AddUserState extends State<AddUser> {
final formKey = GlobalKey<FormState>();
TextEditingController saaaaa = new TextEditingController();
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) => Scaffold(
appBar: AppBar(
automaticallyImplyLeading: false,
title: Text(
'Please Enter Your Details',
textAlign: TextAlign.center,
)),
body: SafeArea(
child: ListView(
padding: EdgeInsets.all(16),
children: [
buildName(),
buildButton(),
const SizedBox(height: 12),
],
),
),
);
Widget buildName() => buildTitle(
title: 'Name',
child: TextFormField(
controller: saaaaa,
//initialValue: name,
decoration: InputDecoration(
border: OutlineInputBorder(),
hintText: 'Your Name',
),
onChanged: (namer) => setState(() => namer = saaaaa.text),
),
);
Widget buildButton() => ButtonWidget(
text: 'Save',
onClicked: () async {
setState(() async {
// Register(names : saaaaa.text );
Navigator.pop(context, saaaaa.text);
});
});
Widget buildTitle({
required String title,
required Widget child,
}) =>
Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Text(
title,
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 18),
),
const SizedBox(height: 8),
child,
],
);
}
This may help and work for you
Register screen
FloatingActionButton(
backgroundColor: Colors.indigo[900],
onPressed: () async {
print(names);
var result = await Navigator.push(
context,
MaterialPageRoute(
builder: (BuildContext context) => AddUser(idUser: '')));
print(result);
names = result;
setState((){});
},
child: const Icon(Icons.add, color: Colors.white),
)
Add screen
Widget buildButton() => MaterialButton(
child: Text('Save'),
onPressed: () {
Navigator.pop(context, saaaaa.text);
});
I guess here after you can take and store in list in register page and then list down the names
You can achieve this thing by using a callback function
add Callback function to your AddUser class and on save button just call your call back function like below:
class AddUser extends StatefulWidget {
final String? idUser;
// add this to your register class
final Function(String) addedUser;
const AddUser({required this.idUser,required this.addedUser});
#override
_AddUserState createState() => _AddUserState();
}
class _AddUserState extends State<AddUser> {
final formKey = GlobalKey<FormState>();
TextEditingController saaaaa = new TextEditingController();
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) => Scaffold(
appBar: AppBar(
automaticallyImplyLeading: false,
title: Text(
'Please Enter Your Details',
textAlign: TextAlign.center,
)),
body: SafeArea(
child: ListView(
padding: EdgeInsets.all(16),
children: [
buildName(),
const SizedBox(height: 12),
],
),
),
);
Widget buildButton() => ButtonWidget(
text: 'Save',
onClicked: () async {
setState(() async {
/// Just call addedUser like this
widget.addedUser(saaaaa.text);
Navigator.pop(context);
});
});
}
Simply where you are calling AddUser in Register Screen, add addedUser in the constructor of AddUser
import 'package:flutter/material.dart';
class Register extends StatefulWidget {
late String? names;
Register({required this.names});
#override
_RegisterState createState() => _RegisterState(names);
}
class _RegisterState extends State<Register> {
late String? names;
_RegisterState(this.names);
#override
Widget build(BuildContext context) {
FloatingActionButton(
backgroundColor: Colors.indigo[900],
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (_) {
//just add parameter to your AddUser constructor
return AddUser(idUser: '',addedUser:(value){
///In this value variable you get the value of user you added on addUser page///
print(value);
});
}),
);
},
child: Icon(Icons.add, color: Colors.white),
),
]
);
}
}

List data Disappears after pressing back Flutter

Whenever I add an item to my least it adds to the list at the current state but when I reopen after pop context the item is no more there
*How can I have the items in list permanently *enter image description hereenter image description hereenter image description hereenter image description hereenter image description here
class Prabesh extends StatefulWidget {
#override
_PrabeshState createState() => _PrabeshState();
}
class _PrabeshState extends State<Prabesh> {
final List users = [
'Ram',
'Shyam',
'Hari',
'Paudel',
'Pandey',
'Sashwat',
'Kismat',
];
// ondlt(Key key) {
// for (int i = 0; i <= users.length; i++) {
// var a = users.elementAt(i);
// if (key == a.key) {
// users.removeAt(i);
// }
// }
// }
void onClk() {
myDialog(BuildContext, context);
}
final myUser = TextEditingController();
myDialog(BuildContext, context) {
showDialog(
barrierDismissible: false,
context: context,
builder: (context) {
return AlertDialog(
title: Text('Add a user'),
content: TextFormField(
controller: myUser,
maxLength: 20,
decoration: InputDecoration(
hintText: 'Enter Username',
),
),
actions: [
ElevatedButton(
onPressed: () => Navigator.pop(context),
child: Text('Cancel')),
ElevatedButton(
onPressed: () {
setState(() {
if (myUser.text.isEmpty) {
return Navigator.pop(context);
} else {
users.add(myUser.text);
return Navigator.pop(context);
}
});
},
child: Text('Add'),
),
],
);
});
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Prabesh'),
leading: BackButton(
onPressed: () => Navigator.pop(context),
),
),
body: ListView.builder(
itemCount: users.length,
itemBuilder: (context, index) {
return Card(
elevation: 10,
child: ListTile(
// key: Key(users[index]),
//onLongPress: () => ondlt(key),
onTap: () {},
title: Text(users[index]),
trailing: Icon(Icons.menu),
leading: CircleAvatar(
child: Text(users[index].substring(0, 1)),
),
),
);
},
),
floatingActionButton: FloatingActionButton(
onPressed: () => onClk(),
child: Icon(Icons.add),
),
),
);
}
}
You must save your data locally or on an online database.
For saving data on mobile storage you can use this package.
But for saving data on an online database you can use Firebase or you must develop a web server.

onEnd in CountdownTimer with bool

I tried to set a bool to true when my CountdownTimer() from the package flutter_countdown_timer: 1.5.0 is finished. But it changes all my CountdownTimer from my ListView. I think I must to use a List but I don't know how to use that. I am a beginner, be indulgent please. This is my code :
main.dart
import 'package:flutter/material.dart';
import 'package:flutter_countdown_timer/flutter_countdown_timer.dart';
import './data.dart';
import './favorite_screen.dart';
import './home_list.dart';
class Home extends StatefulWidget {
#override
_HomeState createState() => _HomeState();
}
class Item {
final String title;
final String description;
final String imageURL;
final int countdown;
final int id;
final bool boole;
Item({
this.title,
this.description,
this.imageURL,
this.countdown,
this.id,
this.boole,
});
}
class _HomeState extends State<Home> {
List<Item> savedItems = new List<Item>();
//List<bool> addFavorite = List<bool>();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Home'),
actions: [
IconButton(
icon: Icon(Icons.favorite_border),
onPressed: () => pushToFavorite(context))
],
),
body: ListView.builder(
itemCount: itemData.length,
itemBuilder: (context, index) {
bool isSaved = savedItems.contains(itemData[index]);
return Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
TextObject(
itemData[index].title, itemData[index].description),
TimerWidget(itemData[index].countdown),
Spacer(),
Container(
padding: const EdgeInsets.only(left: 8.0, top: 8.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Padding(
padding: const EdgeInsets.all(7.0),
child: GestureDetector(
child: Icon(
isSaved
? Icons.favorite
: Icons.favorite_border,
color: isSaved ? Colors.red : null,
size: 32,
),
onTap: () {
setState(() {
if (isSaved) {
savedItems.remove(itemData[index]);
isSaved = false;
} else {
savedItems.add(itemData[index]);
isSaved = true;
}
});
},
),
),
])),
],
),
)
],
);
}));
}
Future pushToFavorite(BuildContext context) {
return Navigator.of(context).push(MaterialPageRoute(
builder: (context) => Favorite(favoriteItem: savedItems)));
}
}
timerWidget.dart
import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart';
import 'package:flutter_countdown_timer/flutter_countdown_timer.dart';
class TextObject extends StatelessWidget {
final String title;
final String description;
const TextObject(this.title, this.description);
#override
Widget build(BuildContext context) {
return Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Spacer(),
//Titre
Container(
padding: const EdgeInsets.only(top: 15.0),
child: FittedBox(
child: Text(
title,
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
),
),
),
//Decription
Container(
padding: const EdgeInsets.only(left: 10.0, top: 15.0),
child: Text(
description,
style: TextStyle(fontSize: 18, fontWeight: FontWeight.normal),
),
),
Spacer(),
],
);
}
}
class TimerWidget extends StatefulWidget {
final int date;
const TimerWidget(
this.date,
);
#override
_TimerWidgetState createState() => _TimerWidgetState();
}
class _TimerWidgetState extends State<TimerWidget> {
bool finished = false;
#override
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.only(top: 10.0),
child: finished == false ? CountdownTimer(
daysSymbol: new Text("j "),
hoursSymbol: new Text(" : "),
minSymbol: new Text(" : "),
secSymbol: new Text(""),
endTime: widget.date,
textStyle: TextStyle(
fontSize: 14,
fontWeight: FontWeight.bold,
color: Colors.black,
),
onEnd: () {
setState(() {
finished = true;
});
},
) : Text('It is finished'));
}
}
Thanks !

How can i save my data in list that it can be used in entire lifecycle of application in flutter?

In my flutter application i am using mvp with clean architecture and my server return 5 items when it hit api, and when i scroll more it again hit api and get next 5 items. And i am saving these items in a list so that i can not call api again and again for already fetched items and this list was used in listview.builder. I had used bottom navigation bar and when i move from product items tab to any other tab and from there came to products items it again fetch products from api and thats not what i want. I want to show that list which was already fetched by that list in products list tab whenever i return back.
Video of my problem.
import 'dart:async';
import 'package:bakery_application/Bloc/TECartBloc.dart';
import 'package:bakery_application/Singleton/CartManager.dart';
import 'package:bakery_application/data/dataSource/product/remote/ProductRemoteDataSource.dart';
import 'package:bakery_application/data/model/responseDTO/ProductResponseDTO.dart';
import 'package:bakery_application/data/model/responseDTO/models/products.dart';
import 'package:bakery_application/data/model/responseDTO/models/productsList.dart';
import 'package:bakery_application/domain/repository/product/ProductRepo.dart';
import 'package:bakery_application/ui/productdetailscreeen/ProductDetailScreen.dart';
import 'package:bakery_application/ui/productscreen/IProductPresenter.dart';
import 'package:bakery_application/ui/productscreen/IProductView.dart';
import 'package:connectivity/connectivity.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:bakery_application/localmodels/ProductModel.dart';
import 'package:bakery_application/widgets/TEProductIncrementor.dart';
import 'package:modal_progress_hud/modal_progress_hud.dart';
import 'package:provider/provider.dart';
import 'ProductPresenter.dart';
class ProductScreen extends StatefulWidget {
Key key;
List<Products> myList = new List<Products>();
int _pageNumber = 1;
ProductScreen({
this.key,
}) : super(key: key);
#override
_ProductScreenState createState() => _ProductScreenState();
}
class _ProductScreenState extends State<ProductScreen> implements IProductView {
_ProductScreenState() {
productPresenter = ProductPresenter(
this,
ProductRepo(
ProductRemoteDataSource(),
),
);
}
bool circularindicator = false;
Color circularColor;
double circularOpacity;
IProductPresenter productPresenter;
AsyncSnapshot snapshotList;
var _connectionStatus = 'Unknown';
Connectivity connectivity;
StreamSubscription<ConnectivityResult> subscription;
ScrollController _scrollController = ScrollController();
bool cupertinoProgress;
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(
backgroundColor: Colors.orange,
automaticallyImplyLeading: false,
title: Text(
'Product',
style: TextStyle(color: Colors.white),
),
),
body:
StreamBuilder(
stream: productPresenter.getProducts,
builder: (context, AsyncSnapshot<ProductsList> snapshot) {
if (snapshot.hasData) {
return productListView(widget.myList);
} else if (snapshot.hasError) {
return Text(snapshot.error.toString());
}
return Center(
child: Container(
child: CircularProgressIndicator(),
),
);
},
),
);
}
Future<Null> refreshList() async {
await Future.delayed(Duration(seconds: 2));
setState(() {});
return null;
}
Widget productListView(List snapshot) {
return RefreshIndicator(
onRefresh: refreshList,
child:
ListView.builder(
key: widget.key,
controller: _scrollController,
shrinkWrap: true,
scrollDirection: Axis.vertical,
itemBuilder: (BuildContext context, int index) {
if(index+1 == widget.myList.length) {
CupertinoActivityIndicator();
}
var plist = widget.myList[index];
return GestureDetector(
onTap: () => Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ProductDetailScreen(
product: plist,
),
),
),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
width: 120,
height: 130,
child: Image(
image: NetworkImage(plist.image),
),
),
Container(
child: Flexible(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Text(
plist.name,
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 16,
),
),
Text(
plist.description,
softWrap: true,
textAlign: TextAlign.left,
),
SizedBox(
height: 7,
),
Row(
children: <Widget>[
Text(plist.price.toString(),
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 20,
)),
Spacer(),
Text(plist.brand),
],
),
TEProductIncrementor(
product: plist,
),
//TODO reverse it alse
],
),
),
),
),
],
),
Row(
children: <Widget>[
Expanded(
child: Divider(
color: Colors.grey.shade300,
),
),
],
)
],
),
),
);
},
itemCount: widget.myList.length,
),
);
}
productlist(BuildContext context, int index
}
#override
hideProgress(ProductsList response) {
setState(() {
// Here you can write your code for open new view
cupertinoProgress=false;
});
for (var c in response.products) {
widget.myList.add(c);
}
}
#override
showError(String error) {
// TODO: implement showError
return null;
}
#override
showProgress() {
print('Successful');
setState(() {
cupertinoProgress=true;
});
}
#override
void initState() {
super.initState();
connectivity = new Connectivity();
print('Init state called');
print('Init state called');
print('Init state called');
subscription =
connectivity.onConnectivityChanged.listen((ConnectivityResult result) {
_connectionStatus = result.toString();
print(_connectionStatus);
if (result == ConnectivityResult.wifi ||
result == ConnectivityResult.mobile) {
widget.myList.isEmpty
? productPresenter.fetchProducts(widget._pageNumber.toString())
:
widget._pageNumber = widget._pageNumber + 1;
productPresenter.fetchProducts(widget._pageNumber.toString(),);
_scrollController.addListener(() {
if (_scrollController.position.pixels ==
_scrollController.position.maxScrollExtent) {
widget._pageNumber = widget._pageNumber + 1;
print(widget._pageNumber);
productPresenter.fetchProducts(widget._pageNumber.toString(),);
}
});
} else {
showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: Center(
child: Container(
child: Icon(
Icons.add_alert,
color: Colors.orange,
size: 20,
),
),
),
content: Text('Check your internet'),
actions: <Widget>[
new FlatButton(
child: new Text('Ok'),
onPressed: () {
Navigator.of(context).pop();
},
),
],
);
},
);
}
});
}
#override
void dispose() {
subscription.cancel();
super.dispose();
}
getMoreData() async {
}
}
The main problem you're facing is that each time the user scrolls of the tab you're in and returns to it, the app re-fetches the data again.
You can use IndexedStack to make the data only loads once, for that you can edit your code to be this way.
class BaseScreenState extends State<BaseScreen> {
List<Widget> _pages = [Page1(), Page2(), Page3()];
#override
Widget build(BuildContext context) {
return Scaffold(
body: IndexedStack(
index: currentIndex,
children: _pages,
),
);
}
}

Synchronization of list view and detail view

I have an app with simple functionality. After authentication user see the page with ListView widget which is populated with help of StreamBuilder widget and BLoC. Click on ListView row opens details page with set of detail widgets (TextField. Now I need to change my GUI design for tables. As we have more space I decided to display details near the list view, i.e. when user clicks on ListView item no new page opened but details are displayed on the right side of ListView. I need the idea how to synchronize the detail view widget with selected item in list view widget. I figured out that I can use somehow ValueNotifier/ValueListenableBuilder but I can't gather my thoughts together. I need some ideas, please.
please use this package responsive_scaffold https://pub.dev/packages/responsive_scaffold
On mobile it shows a list and pushes to details and on tablet it shows the List and the selected item.
example code
import 'package:flutter/material.dart';
import 'package:responsive_scaffold/responsive_scaffold.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
var _scaffoldKey = new GlobalKey<ScaffoldState>();
#override
Widget build(BuildContext context) {
return MaterialApp(
home: ResponsiveListScaffold.builder(
scaffoldKey: _scaffoldKey,
detailBuilder: (BuildContext context, int index, bool tablet) {
return DetailsScreen(
// appBar: AppBar(
// elevation: 0.0,
// title: Text("Details"),
// actions: [
// IconButton(
// icon: Icon(Icons.share),
// onPressed: () {},
// ),
// IconButton(
// icon: Icon(Icons.delete),
// onPressed: () {
// if (!tablet) Navigator.of(context).pop();
// },
// ),
// ],
// ),
body: Scaffold(
appBar: AppBar(
elevation: 0.0,
title: Text("Details"),
automaticallyImplyLeading: !tablet,
actions: [
IconButton(
icon: Icon(Icons.share),
onPressed: () {},
),
IconButton(
icon: Icon(Icons.delete),
onPressed: () {
if (!tablet) Navigator.of(context).pop();
},
),
],
),
bottomNavigationBar: BottomAppBar(
elevation: 0.0,
child: Container(
child: IconButton(
icon: Icon(Icons.share),
onPressed: () {},
),
),
),
body: Container(
child: Center(
child: Text("Item: $index"),
),
),
),
);
},
nullItems: Center(child: CircularProgressIndicator()),
emptyItems: Center(child: Text("No Items Found")),
slivers: <Widget>[
SliverAppBar(
title: Text("App Bar"),
),
],
itemCount: 100,
itemBuilder: (BuildContext context, int index) {
return ListTile(
leading: Text(index.toString()),
);
},
bottomNavigationBar: BottomAppBar(
elevation: 0.0,
child: Container(
child: IconButton(
icon: Icon(Icons.share),
onPressed: () {},
),
),
),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: () {
_scaffoldKey.currentState.showSnackBar(SnackBar(
content: Text("Snackbar!"),
));
},
),
),
);
}
}