Change value inside list view builder using provider - flutter

I have shopping app want to create Wishlist ,I did many things correctly,just when I want to check one product all products checked ,also when I want increase or decrease number of product all products quantity change as shown in image below ,my code :
Provider :
class ProductProvider with ChangeNotifier {
List<Product> products = [];
bool isAdded = false;
int count = 0;
void chane_add_color() {
isAdded = !isAdded;
notifyListeners();
}
void add_count() {
count++;
notifyListeners();
}
void rem_count() {
if (count > 0) {
count--;
}
notifyListeners();
}
}
my list tile left trailing :
trailing: Consumer<ProductProvider>(
builder: (context, prod, child) {
return Wrap(
spacing: 35,
children: <Widget>[
Column(
children: [
InkWell(
onTap: prod.add_count,
child: Icon(Icons.add, color: Colors.green)),
Text('${prod.count}'),
InkWell(
onTap: prod.rem_count,
child: Icon(Icons.remove, color: Colors.red)),
],
),
IconButton(
onPressed: prod.chane_add_color,
icon: Icon(Icons.favorite,
color: prod.isAdded ? Colors.red : Colors.grey),
),
],
);
}),
the result :
I guess it need a list for counter ,but don't know how to do
is there any suggestion ?

This is notifier class:
class ProductModel extends ChangeNotifier {
List<Map<String, dynamic>> _products = [
{'product': 'mercedes', 'count': 0, 'isFavorite': false},
{'product': 'audi', 'count': 0, 'isFavorite': false},
{'product': 'bmw', 'count': 0, 'isFavorite': false},
{'product': 'volvo', 'count': 0, 'isFavorite': false}
];
List<Map<String, dynamic>> get products => _products;
ProductModel();
ProductModel.instance();
addFavorite({int index}) {
_products[index]['isFavorite'] = !_products[index]['isFavorite'];
notifyListeners();
}
incrementCounter({int index}) {
_products[index]['count'] += 1;
notifyListeners();
}
}
This is your widget:
class ProductView extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: ChangeNotifierProvider<ProductModel>(
create: (context) => ProductModel.instance(),
child: Consumer<ProductModel>(
builder: (context, viewModel, child) {
return ListView.builder(
itemCount: viewModel.products.length,
itemBuilder: (context, index) {
return ListTile(
leading: FlatButton(
child: Text('${viewModel.products[index]['count']} +'),
onPressed: () {
viewModel.incrementCounter(index: index);
},
),
title: Text(viewModel.products[index]['product']),
trailing: IconButton(
icon: Icon(
Icons.favorite,
color: viewModel.products[index]['isFavorite']
? Colors.red
: Colors.grey,
),
onPressed: () {
viewModel.addFavorite(index: index);
},
),
);
},
);
},
),
),
);
}
}

Related

Is there a way to make new pages without manually creating classes for it? flutter

I have an empty page lets call it "class list" which the user can create a new "class" in the listview by clicking a button and giving it a name and when you click on that "class" it opens a new page with that name on the app bar, lets call this new page the "students lists", now you can create another list in it, and I used hive to store the data.
now the problem is when you create a list of students in the "student list" page when you come back and go to "class lists" and click on another "class", the student list you created earlier will appear for every "class" page.
the reason for this is because I have created a class(the syntax) for student list page and it will show for every "class".
since its the user who creates "classes" and I haven't putted any limitation on it, I cant create infinite classes(the syntax) for the pages created so what can I do?
class list page
inside class 1
inside class 2
here is the codes:
the "list class" codes:
import 'package:attendance/data/database.dart';
import 'package:flutter/material.dart';
import 'package:flutter_speed_dial/flutter_speed_dial.dart';
import 'package:attendance/insideList.dart';
import 'package:hive_flutter/hive_flutter.dart';
class lists extends StatefulWidget {
const lists({super.key});
#override
State<lists> createState() => _listsState();
}
class _listsState extends State<lists> {
final _myBox = Hive.box('mybox');
ListDataBase db = ListDataBase();
late TextEditingController _textController;
#override
void initState() {
if (_myBox.get("NAMES") == null) {
db.InitialData();
} else {
db.LoadData();
}
super.initState();
_textController = TextEditingController();
}
#override
void dispose() {
_textController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
db.Items.sort();
return Scaffold(
body: db.Items.length > 0
? ListView.separated(
itemCount: db.Items.length,
itemBuilder: (_, index) {
return ListTile(
leading: const Icon(Icons.school),
trailing: const Icon(Icons.arrow_forward),
title: Center(child: Text(db.Items[index])),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: ((context) =>
InsideList(db.Items[index]))));
},
onLongPress: (() async {
await showDialog(
context: context,
builder: ((context) {
return AlertDialog(
title: const Text(
"Are you sure you want to delete this class?",
style: TextStyle(fontSize: 15),
),
actions: [
TextButton(
child: Text("cancel"),
onPressed: (() {
Navigator.pop(context);
})),
TextButton(
child: Text('Delete'),
onPressed: () {
setState(() {
db.Items.removeAt(index);
db.UpdateDataBase();
Navigator.pop(context);
});
},
),
],
);
}));
}),
);
},
separatorBuilder: (BuildContext context, int index) =>
const Divider(
color: Colors.black,
),
)
: const Center(
child: Text("You currently have no classes. Add from below."),
),
floatingActionButton: SpeedDial(
animatedIcon: AnimatedIcons.menu_arrow,
spacing: 6,
spaceBetweenChildren: 6,
backgroundColor: const Color.fromARGB(255, 22, 37, 50),
foregroundColor: const Color.fromARGB(255, 255, 255, 255),
children: [
SpeedDialChild(
child: const Icon(Icons.school),
label: "add class",
onTap: () async {
final result = await showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: const Text('Add a new class'),
content: TextField(
controller: _textController,
autofocus: true,
decoration: const InputDecoration(
hintText: "Enter the name of the class."),
),
actions: [
TextButton(
child: Text('Cancel'),
onPressed: () {
Navigator.pop(context);
},
),
TextButton(
child: Text('Add'),
onPressed: () {
Navigator.pop(context, _textController.text);
db.UpdateDataBase();
_textController.clear();
},
),
],
);
},
);
if (result != null) {
result as String;
setState(() {
db.Items.add(result);
});
}
},
)
],
),
);
}
}
the student page codes:
import 'package:attendance/data/StudentsDatabase.dart';
import 'package:flutter/material.dart';
import 'package:flutter_speed_dial/flutter_speed_dial.dart';
import 'package:hive_flutter/hive_flutter.dart';
class InsideList extends StatefulWidget {
final String name;
InsideList(this.name);
#override
State<InsideList> createState() => _InsideListState();
}
class _InsideListState extends State<InsideList> {
final _myBox = Hive.box('mybox2');
StudentsDatabase db = StudentsDatabase();
late TextEditingController _textController;
#override
void initState() {
if (_myBox.get("NAMES") == null) {
db.InitialData();
} else {
db.LoadData();
}
super.initState();
_textController = TextEditingController();
}
void _selectRadio(int index, int? val) {
setState(() {
db.SelectedRadio[index] = val ?? 0;
});
}
#override
void dispose() {
_textController.dispose();
super.dispose();
}
Widget build(BuildContext context) {
db.Students.sort();
return Scaffold(
appBar: AppBar(
title: Text(widget.name),
centerTitle: true,
backgroundColor: const Color.fromARGB(255, 22, 37, 50),
toolbarHeight: 65,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(
bottom: Radius.circular(30),
),
),
),
body: db.Students.length > 0
? ListView.separated(
itemCount: db.Students.length,
itemBuilder: (_, index) {
return ListTile(
leading: const Icon(Icons.person),
trailing: FittedBox(
fit: BoxFit.fill,
child: Row(
children: [
Radio(
activeColor: Colors.green,
value: 0,
groupValue: db.SelectedRadio[index],
onChanged: (val) {
_selectRadio(index, val);
db.UpdateDataBase();
}),
Radio(
activeColor: Colors.red,
value: 1,
groupValue: db.SelectedRadio[index],
onChanged: (val) {
_selectRadio(index, val);
db.UpdateDataBase();
}),
],
),
),
title: Center(child: Text(db.Students[index])),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: ((context) =>
InsideList(db.Students[index]))));
},
onLongPress: (() async {
await showDialog(
context: context,
builder: ((context) {
return AlertDialog(
title: const Text(
"Are you sure you want to delete this student?",
style: TextStyle(fontSize: 15),
),
actions: [
TextButton(
child: Text("cancel"),
onPressed: (() {
Navigator.pop(context);
})),
TextButton(
child: Text('Delete'),
onPressed: () {
setState(() {
db.Students.removeAt(index);
db.UpdateDataBase();
Navigator.pop(context);
});
},
),
],
);
}));
}),
);
},
separatorBuilder: (BuildContext context, int index) =>
const Divider(
color: Colors.black,
),
)
: const Center(
child: Text("You currently have no students. Add from below."),
),
floatingActionButton: SpeedDial(
animatedIcon: AnimatedIcons.menu_arrow,
spacing: 6,
spaceBetweenChildren: 6,
backgroundColor: const Color.fromARGB(255, 22, 37, 50),
foregroundColor: const Color.fromARGB(255, 255, 255, 255),
children: [
SpeedDialChild(
child: const Icon(Icons.group_add),
label: "add student",
onTap: () async {
final result = await showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: const Text('Add a new student'),
content: TextField(
controller: _textController,
autofocus: true,
decoration: const InputDecoration(
hintText: "Enter the name of the student."),
),
actions: [
TextButton(
child: Text('Cancel'),
onPressed: () {
Navigator.pop(context);
},
),
TextButton(
child: Text('Add'),
onPressed: () {
Navigator.pop(context, _textController.text);
db.UpdateDataBase();
_textController.clear();
},
),
],
);
},
);
if (result != null) {
result as String;
setState(() {
db.Students.add(result);
db.SelectedRadio.add(0);
});
}
},
),
],
),
);
}
}
From what i am understanding, You will need to connect the student list with every single class separately. To show a quick example.
List<ClassRoom> firstPageList = [];
class ClassRoom {
ClassRoom({required this.name});
final String name;
List<Student> students = [];
}
class Student {
Student({required this.studentName});
final String studentName;
}
Kinda like this. Then when a new ClassRoom class added to the list, Show the name on the list. And pass that ClassRoom to the next page.
And on the next page, Use that ClassRoom instance, and add all the students inside the list of that ClassRoom.
Now for every page you will have a different class and for every class, you will have it's seperate Student.
After that, all you need to do is, handle the states of every class properly. And setup a way to store them properly.

how to increase the size of the window with the search result in flutter?

I have a page code written in an android studio. On this page, I display a list of objects, as well as a widget to search for these objects. When I clicked on the search widget,my list of objects is shrinking, and it is almost invisible (it is at the top). Can this be fixed somehow so that it can be seen on the whole page ??
import 'package:flutter/material.dart';
import 'package:flutter_app_seals/model/post/form_unseals.dart';
import 'package:flutter_app_seals/model/post/form_seals.dart';
import 'package:flutter_app_seals/model/setting/globalvar.dart' as global;
import 'dart:async';
import 'dart:io';
import 'dart:convert';
void main() => runApp(JsonParseObjectSts_UN());
class JsonParseObjectSts_UN extends StatefulWidget {
JsonParseObjectSts_UN() : super();
#override
_JsonParseObjectsState createState() => _JsonParseObjectsState();
}
class _JsonParseObjectsState extends State <StatefulWidget> {
List<UserDetails> _searchResult = [];
List<UserDetails> _userDetails = [];
TextEditingController controller = new TextEditingController();
final String url = global.urlVar ;
// Get json result and convert it to model. Then add
Future<Null> getUserDetails() async {
HttpClient client = new HttpClient();
client.badCertificateCallback = ((X509Certificate cert, String host, int port) => true);
final request = await client
.getUrl(Uri.parse(url))
.timeout(Duration(seconds: 5));
HttpClientResponse response = await request.close();
var responseBody = await response.transform(utf8.decoder).join();
final responseJson = json.decode(responseBody);
setState(() {
for (Map user in responseJson) {
_userDetails.add(UserDetails.fromJson(user));
}
});
}
#override
void initState() {
super.initState();
getUserDetails();
}
Widget _buildUsersList() {
return new ListView.builder(
itemCount: _userDetails.length,
itemBuilder: (context, index) {
return new Card(
color: (_userDetails[index].sealed == "Так") ? Colors.redAccent : Colors.greenAccent,
margin: EdgeInsets.symmetric(vertical: 7),
child: ListTile(
title: Text(
_userDetails[index].name,
style: TextStyle(fontSize: 25),
),
subtitle: Text("Запломбований:${_userDetails[index].sealed}"),
leading: Icon(
Icons.home_outlined,
size: 30,
color: Colors.black87,
),
onTap: () =>
{
if ('Так' == _userDetails[index].sealed) {
global.nameObj = _userDetails[index].name,
global.sealsNumb = _userDetails[index].seal_number,
global.typesOp = 'Так',
Navigator.push(
context,
MaterialPageRoute(builder: (context) => Unseals()),
)
}
else{
{
global.nameObj = _userDetails[index].name,
global.typesOp = 'Ні',
Navigator.push(
context,
MaterialPageRoute(builder: (context) => Form_seals()),
)
}
}
}
),
);
},
);
}
Widget _buildSearchResults() {
return new ListView.builder(
itemCount: _searchResult.length,
itemBuilder: (context, i) {
return new Card(
color: (_searchResult[i].sealed == "Так") ? Colors.redAccent : Colors.greenAccent,
margin: EdgeInsets.symmetric(vertical: 7),
child: ListTile(
title: Text(
_searchResult[i].name,
style: TextStyle(fontSize: 25),
),
subtitle: Text("Запломбований:${_searchResult[i].sealed}"),
leading: Icon(
Icons.home_outlined,
size: 30,
color: Colors.black87,
),
onTap: () =>
{
if ('Так' == _searchResult[i].sealed) {
global.nameObj = _searchResult[i].name,
global.sealsNumb = _searchResult[i].seal_number,
global.typesOp = 'Так',
Navigator.push(
context,
MaterialPageRoute(builder: (context) => Unseals()),
)
}
else{
{
global.nameObj = _searchResult[i].name,
global.typesOp = 'Ні',
Navigator.push(
context,
MaterialPageRoute(builder: (context) => Form_seals()),
)
}
}
}
),
);
},
);
}
Widget _buildSearchBox() {
return new Padding(
padding: EdgeInsets.all(7.0),
child: new Card(
child: new ListTile(
leading: new Icon(Icons.search),
title: new TextField(
controller: controller,
decoration: new InputDecoration(
hintText: 'Пошук', border: InputBorder.none),
onChanged: onSearchTextChanged,
),
trailing: new IconButton(
icon: new Icon(Icons.cancel),
onPressed: () {
controller.clear();
onSearchTextChanged('');
},
),
),
),
);
}
Widget _buildBody() {
return new Scaffold(
body:Container(
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [Colors.blue, Colors.white],
begin: Alignment.topCenter,
end: Alignment.bottomCenter),
),
child:Column(
children: <Widget>[
new Expanded( flex: 1, child: _buildSearchBox()),
new Expanded(flex:8,
child: _searchResult.length != 0 || controller.text.isNotEmpty
? _buildSearchResults()
: _buildUsersList()),
],
),
),
);
}
#override
Widget build(BuildContext context) {
return new Scaffold(
body: _buildBody()
);
}
onSearchTextChanged(String text) async {
_searchResult.clear();
if (text.isEmpty) {
setState(() {});
return;
}
_userDetails.forEach((userDetail) {
if (userDetail.name.contains(text) ) _searchResult.add(userDetail);
});
setState(() {});
}
}
class UserDetails {
final String name, seal_number,sealed;
UserDetails({this.name, this.sealed, this.seal_number});
factory UserDetails.fromJson(Map<String, dynamic> json) {
return new UserDetails(
sealed: json['sealed'],
name: json['name'],
seal_number: json['seal_number'],
);
}
}
My page:
My page with search:
I have looked at your code several times, I just noticed a small error.
For the results of your searches, you try to display the "List" of searches in a ListView.builder, which is in a column in the parent container does not have a defined height.
Solution: Set a height for the main container and the problem will be solved

Flutter List View Data Duplication when I do setState and pagination with StreamBuilder

I am implementation the list data from API to show in list view. There I am using Streambuiler and pull to refresh library for scrolling changes. I set the new data from API to local list inside StreamBuilder. Every time when I made setState for state changes. The StreamBuilder rebuild and setting data again. Then my list was duplicated, I do not know yet what's wrong with my code. I am developing the App with flutter recently. Please check my code what is wrong in there. 🙏🙏🙏
class OrderListScreen extends StatefulWidget {
#override
_OrderListScreenState createState() => _OrderListScreenState();
}
class _OrderListScreenState extends State<OrderListScreen> {
String showingFromDate, showingToDate;
OrderBloc _orderBloc;
OrderListOb _orderListOb = OrderListOb();
int paginationPage = 0;
DateTime fromDate, toDate;
List<Orders> _orderList = [];
var _refreshController = RefreshController();
#override
void initState() {
super.initState();
_orderBloc = OrderBloc();
initDate();
fetchAPI();
}
#override
void dispose() {
super.dispose();
_orderBloc.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: defaultAppBar("Order List Screen", showBackArrow: false),
body: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
textView("From Date", isBold: true),
textView("To Date", isBold: true),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
ActionChip(
padding: EdgeInsets.all(4.0),
avatar: Icon(
Icons.calendar_today_sharp,
color: Colors.white,
size: 18,
),
backgroundColor: PRIMARY_COLOR,
label: textView(showingFromDate, textColor: Colors.white),
onPressed: () {
_selectDate(context, isFromDate: true);
},
),
ActionChip(
padding: EdgeInsets.all(4.0),
avatar: Icon(
Icons.calendar_today_sharp,
color: Colors.white,
size: 18,
),
backgroundColor: PRIMARY_COLOR,
label: textView(showingToDate, textColor: Colors.white),
onPressed: () {
_selectDate(context, isFromDate: false);
},
),
],
),
StreamBuilder(
stream: _orderBloc.orderListStream(),
initialData:
BaseResponse(data: null, message: MsgState.loading),
builder: (BuildContext context, AsyncSnapshot snapshot) {
BaseResponse ob = snapshot.data;
if (ob.message == MsgState.loading) {
return Center(
child: Container(
child: CircularProgressIndicator(),
),
);
} else if (ob.message == MsgState.data ) {
_orderListOb = OrderListOb();
_orderListOb = ob.data;
_orderList.addAll(_orderListOb.result.orders);
return buildListView();
} else {
return handleErrorWidget(ob.data);
}
},
),
],
),
));
}
Widget buildListView() {
return Container(
height: 450,
child: SmartRefresher(
enablePullUp: _orderListOb.result.orders.length > 9,
enablePullDown: true,
onRefresh: () {
print("Pull To Refresh");
},
onLoading: () {
paginationPage = _orderListOb.result.pagination.nextId;
fetchAPI(); //Do pagination
},
controller: _refreshController,
child: ListView.builder(
shrinkWrap: true,
physics: ClampingScrollPhysics(),
itemCount: _orderList.length,
itemBuilder: (BuildContext context, int index) {
return InkWell(
onTap: () {
context.navigateName("order_detail", data: {
'isAcceptOrder': true,
'order_id': _orderList[index].id
});
},
child: orderItemWidget(_orderList[index],
isAcceptedOrder: false));
}),
),
);
}
void fetchAPI() {
_orderBloc.getOrderList(
serviceId: ServiceTypes.AIRCON_SERVICE.value,
fromDate: DateUtil.requestDateFormat(fromDate.toString()),
toDate: DateUtil.requestDateFormat(toDate.toString()),
page: paginationPage);
}
void initDate() {
showingFromDate = DateUtil.covertDate(DateUtil.getCurrentDate().toString());
showingToDate = DateUtil.covertDate(DateUtil.getCurrentDate().toString());
fromDate = DateUtil.getCurrentDate();
toDate = DateUtil.getCurrentDate();
}
void resetData() {
print("Clear");
paginationPage = 0;
_orderList.clear();
}
_selectDate(BuildContext context, {bool isFromDate = true}) async {
final DateTime picked = await showDatePicker(
context: context,
initialDate: isFromDate ? fromDate : toDate, // Refer step 1
firstDate: DateTime(2000),
lastDate: DateTime(2025),
);
if (picked != null)
setState(() {
if (isFromDate) {
showingFromDate = DateUtil.covertDate(picked.toString());
fromDate = picked;
} else {
showingToDate = DateUtil.covertDate(picked.toString());
toDate = picked;
}
resetData();
fetchAPI();
});
}
}
The problem is that you're doing _orderList.addAll(_orderListOb.result.orders); . Instead, you should clean the list before or just _orderList=_orderListOb.result.orders;
Check for existence the value before adding to list, if list doesnt contain the value then add like this:
if(!_orderList.contains(_orderListOb.result.orders))
_orderList.addAll(_orderListOb.result.orders);
I hope it will work!

Search with filter card (data from api) for Flutter

I have a code with the help of which I take the data through the Get method and use this data in the cards. I highlight the cards with color depending on their condition. The problem is that I can't add a search by (item.name). But I can't do it. I found some examples but couldn't add them to my code. I will be grateful for your help. Here is my code:
import 'package:flutter/material.dart';
import 'package:flutter_app_seals/model/object_main/ObjectListGet.dart';
import 'package:flutter_app_seals/model/object_main/ServicesObjectMain.dart';
import 'package:flutter_app_seals/model/post/form_unseals.dart';
import 'package:flutter_app_seals/model/post/form_seals.dart';
import 'package:flutter_app_seals/model/setting/globalvar.dart' as global;
class JsonParseObjectSts extends StatefulWidget {
//
JsonParseObjectSts() : super();
#override
_JsonParseObjectsState createState() => _JsonParseObjectsState();
}
class _JsonParseObjectsState extends State <StatefulWidget> {
Widget build(BuildContext context) {
var futureBuilder = new FutureBuilder< List<ObjectListMain>>(
future: ServicesObjectMain.getObjectMain(),
builder: (context, snapshot)
{
// Data is loading, you should show progress indicator to a user
if (!snapshot.hasData) {
return Center(
child: CircularProgressIndicator(),
);
}
// Data is loaded, handle it
return ListView.builder(
physics: BouncingScrollPhysics(),
padding: EdgeInsets.all(40),
itemCount: snapshot.data.length,
itemBuilder: (_, index) {
final item = snapshot.data[index];
return Card(
color: (item.sealed == "Так") ? Colors.redAccent : Colors.greenAccent,
margin: EdgeInsets.symmetric(vertical: 7),
child: ListTile(
title: Text(
item.name,
style: TextStyle(fontSize: 30),
),
subtitle: Text("Запломбований:${item.sealed}"),
leading: Icon(
Icons.home_outlined,
size: 40,
color: Colors.black87,
),
onTap: () =>
{
if ('Так' == item.sealed) {
global.nameObj = item.name,
global.sealsNumb = item.seal_number,
global.typesOp = 'Так',
Navigator.push(
context,
MaterialPageRoute(builder: (context) => Unseals()),
)
}
else{
{
global.nameObj = item.name,
global.typesOp = 'Ні',
Navigator.push(
context,
MaterialPageRoute(builder: (context) => Form_seals()),
)
}
}
}
),
);
},
);
}
);
return new Scaffold(
body:Container(
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [Colors.blue, Colors.white],
begin: Alignment.topCenter,
end: Alignment.bottomCenter),
),
child: futureBuilder
),
);
}
}
And scrin :
Also I tried one more way, but in it there is a problem, the data which I take away from api they are duplicated. Duplicate when I go to this page or when I delete text from the search widget.
import 'package:flutter/material.dart';
import 'package:flutter_app_seals/model/post/form_unseals.dart';
import 'package:flutter_app_seals/model/post/form_seals.dart';
import 'package:flutter_app_seals/model/setting/globalvar.dart' as global;
import 'dart:async';
import 'dart:convert';
import 'package:http/http.dart' as http;
class JsonParseObjectSts extends StatefulWidget {
#override
_JsonParseObjectsState createState() => _JsonParseObjectsState();
}
class _JsonParseObjectsState extends State <StatefulWidget> {
TextEditingController controller = new TextEditingController();
// Get json result and convert it to model. Then add
Future<Null> getUserDetails() async {
final response = await http.get(url);
final responseJson = json.decode(response.body);
setState(() {
for (Map user in responseJson) {
_userDetails.add(UserDetails.fromJson(user));
}
});
}
#override
void initState() {
super.initState();
getUserDetails();
}
#override
Widget build(BuildContext context) {
return new Scaffold(
body: new Column(
children: <Widget>[
new Container(
color: Theme.of(context).primaryColor,
child: new Padding(
padding: const EdgeInsets.all(8.0),
child: new Card(
child: new ListTile(
leading: new Icon(Icons.search),
title: new TextField(
controller: controller,
decoration: new InputDecoration(
hintText: 'Пошук', border: InputBorder.none),
onChanged: onSearchTextChanged,
),
trailing: new IconButton(icon: new Icon(Icons.cancel), onPressed: () {
controller.clear();
onSearchTextChanged('');
},),
),
),
),
),
new Expanded(
child: _searchResult.length != 0 || controller.text.isNotEmpty
? new ListView.builder(
itemCount: _searchResult.length,
itemBuilder: (context, i) {
return new Card(
color: (_searchResult[i].sealed == "Так") ? Colors.redAccent : Colors.greenAccent,
margin: EdgeInsets.symmetric(vertical: 7),
child: ListTile(
title: Text(
_searchResult[i].name,
style: TextStyle(fontSize: 30),
),
subtitle: Text("Запломбований:${_searchResult[i].sealed}"),
leading: Icon(
Icons.home_outlined,
size: 40,
color: Colors.black87,
),
onTap: () =>
{
if ('Так' == _searchResult[i].sealed) {
global.nameObj = _searchResult[i].name,
global.sealsNumb = _searchResult[i].seal_number,
global.typesOp = 'Так',
Navigator.push(
context,
MaterialPageRoute(builder: (context) => Unseals()),
)
}
else{
{
global.nameObj = _searchResult[i].name,
global.typesOp = 'Ні',
Navigator.push(
context,
MaterialPageRoute(builder: (context) => Form_seals()),
)
}
}
}
),
);
},
)
: new ListView.builder(
itemCount: _userDetails.length,
itemBuilder: (context, index) {
return new Card(
color: (_userDetails[index].sealed == "Так") ? Colors.redAccent : Colors.greenAccent,
margin: EdgeInsets.symmetric(vertical: 7),
child: ListTile(
title: Text(
_userDetails[index].name,
style: TextStyle(fontSize: 30),
),
subtitle: Text("Запломбований:${_userDetails[index].sealed}"),
leading: Icon(
Icons.home_outlined,
size: 40,
color: Colors.black87,
),
onTap: () =>
{
if ('Так' == _userDetails[index].sealed) {
global.nameObj = _userDetails[index].name,
global.sealsNumb = _userDetails[index].seal_number,
global.typesOp = 'Так',
Navigator.push(
context,
MaterialPageRoute(builder: (context) => Unseals()),
)
}
else{
{
global.nameObj = _userDetails[index].name,
global.typesOp = 'Ні',
Navigator.push(
context,
MaterialPageRoute(builder: (context) => Form_seals()),
)
}
}
}
),
);
},
),
),
],
),
);
}
onSearchTextChanged(String text) async {
_searchResult.clear();
if (text.isEmpty) {
setState(() {});
return ;
}
_userDetails.forEach((userDetail) {
if (userDetail.name.contains(text) || userDetail.name.contains(text))
_searchResult.add(userDetail);
});
setState(() {});
}
}
List<UserDetails> _searchResult = [];
List<UserDetails> _userDetails = [];
final String url = global.urlVar + '/object_status' + '?data_area=' + global.dataArea;
class UserDetails {
final String name, seal_number,sealed;
UserDetails({this.name, this.sealed, this.seal_number});
factory UserDetails.fromJson(Map<String, dynamic> json) {
return new UserDetails(
sealed: json['sealed'],
name: json['name'],
seal_number: json['seal_number'],
);
}
}

Exporting a Flutter List to CSV file

I have this screen which lists the items of a class into ListView. What I would want is to have the button (FloatingActionButton in the code) that would export that list to a CSV file. I have the code of what I think it should look, but my issue is that I don't know how to use onPressed on the button in order to export, for now it is null, but it should call the getCSV() function with something in it. Here's the code:
class MailListAdmin extends StatefulWidget {
#override
_MailListAdminState createState() => _MailListAdminState();
}
class _MailListAdminState extends State<MailListAdmin> {
List<String> list = [];
List<Email> finalExport;
#override
void initState() {
super.initState();
DatabaseProvider.db.getMail().then(
(mailList) {
BlocProvider.of<MailBloc>(context).add(SetMail(mailList));
},
);
}
getCsv(List<Email> mailList) async {
List<List<dynamic>> rows = List<List<dynamic>>();
for (int i = 0; i < mailList.length; i++) {
List<dynamic> row = List();
row.add(mailList[i].id);
row.add(mailList[i].email);
rows.add(row);
setState(() {
mailList = finalExport;
});
print(rows);
}
await SimplePermissions.requestPermission(Permission.WriteExternalStorage);
bool checkPermission = await SimplePermissions.checkPermission(
Permission.WriteExternalStorage);
if (checkPermission) {
String dir =
(await getExternalStorageDirectory()).absolute.path + "/documents";
String file = "$dir";
File f = new File(file + "filename.csv");
String csv = const ListToCsvConverter().convert(rows);
f.writeAsString(csv);
}
}
//-------------------------------------
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.blueGrey[900],
title: Text('Newsletter Users'),
actions: [
Padding(
padding: EdgeInsets.only(right: 20.0),
child: Badge(
child: Text('Copied ' + list.length.toString()),
showBadge: false)),
],
),
body: Container(
child: BlocConsumer<MailBloc, List<Email>>(
builder: (context, mailList) {
return ListView.separated(
itemCount: mailList.length,
itemBuilder: (BuildContext context, int index) {
Email mail = mailList[index];
return Card(
child: ListTile(
leading: GestureDetector(
child: Icon(Icons.copy),
onTap: () {
FlutterClipboard.copy(mail.email);
print('Copied ${mail.email}!');
Scaffold.of(context).showSnackBar(SnackBar(
backgroundColor: Colors.grey[600],
duration: Duration(milliseconds: 1000),
content: Text(
'${mail.email} Copied To Clipboard!',
style: TextStyle(fontSize: 20.0),
),
));
list.add(mail.email);
setState(() {
list.length.toString();
});
print(mail.email);
print(list);
}),
trailing: Icon(Icons.delete),
onTap: () {
DatabaseProvider.db.deleteMail(mail.id).then((_) {
BlocProvider.of<MailBloc>(context).add(
DeleteMail(index),
);
});
list.remove(mail.email);
print(list);
setState(() {
list.length.toString();
});
},
title: Text(
mail.email,
style: TextStyle(fontSize: 20.0),
),
),
);
},
separatorBuilder: (BuildContext context, int index) =>
Divider(color: Colors.black),
);
},
listener: (BuildContext context, mailList) {},
),
),
floatingActionButton: FloatingActionButton(
child: Text('Export'),
onPressed: () =>
null, //im not sure how to add the mailList to getCsv(???)
),
);
}
}
Check the export button, where I am not sure how to activate it with getCSV function. Also, how would I access the saved CSV file after it is saved (where would it be saved in the device?)
Try the following steps:
Create a new list in the class.
Assign it to the mail list from the BlocConsumer.
Then use the list in onPressed by passing it to getCsv method.
The Implementation
theEmails is the new list.
class _MailListAdminState extends State<MailListAdmin> {
List<String> list = [];
List<Email> finalExport;
#override
void initState() {
super.initState();
DatabaseProvider.db.getMail().then(
(mailList) {
BlocProvider.of<MailBloc>(context).add(SetMail(mailList));
},
);
}
List<Email> theEmails = [];
getCsv(List<Email> mailList) async {
List<List<dynamic>> rows = List<List<dynamic>>();
for (int i = 0; i < mailList.length; i++) {
List<dynamic> row = List();
row.add(mailList[i].id);
row.add(mailList[i].email);
rows.add(row);
setState(() {
mailList = finalExport;
});
print(rows);
}
await SimplePermissions.requestPermission(Permission.WriteExternalStorage);
bool checkPermission = await SimplePermissions.checkPermission(
Permission.WriteExternalStorage);
if (checkPermission) {
String dir =
(await getExternalStorageDirectory()).absolute.path + "/documents";
String file = "$dir";
File f = new File(file + "filename.csv");
String csv = const ListToCsvConverter().convert(rows);
f.writeAsString(csv);
}
}
//-------------------------------------
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.blueGrey[900],
title: Text('Newsletter Users'),
actions: [
Padding(
padding: EdgeInsets.only(right: 20.0),
child: Badge(
child: Text('Copied ' + list.length.toString()),
showBadge: false)),
],
),
body: Container(
child: BlocConsumer<MailBloc, List<Email>>(
builder: (context, mailList) {
theEmails = mailList;
return ListView.separated(
itemCount: mailList.length,
itemBuilder: (BuildContext context, int index) {
Email mail = mailList[index];
return Card(
child: ListTile(
leading: GestureDetector(
child: Icon(Icons.copy),
onTap: () {
FlutterClipboard.copy(mail.email);
print('Copied ${mail.email}!');
Scaffold.of(context).showSnackBar(SnackBar(
backgroundColor: Colors.grey[600],
duration: Duration(milliseconds: 1000),
content: Text(
'${mail.email} Copied To Clipboard!',
style: TextStyle(fontSize: 20.0),
),
));
list.add(mail.email);
setState(() {
list.length.toString();
});
print(mail.email);
print(list);
}),
trailing: Icon(Icons.delete),
onTap: () {
DatabaseProvider.db.deleteMail(mail.id).then((_) {
BlocProvider.of<MailBloc>(context).add(
DeleteMail(index),
);
});
list.remove(mail.email);
print(list);
setState(() {
list.length.toString();
});
},
title: Text(
mail.email,
style: TextStyle(fontSize: 20.0),
),
),
);
},
separatorBuilder: (BuildContext context, int index) =>
Divider(color: Colors.black),
);
},
listener: (BuildContext context, mailList) {},
),
),
floatingActionButton: FloatingActionButton(
child: Text('Export'),
onPressed: (){
getCsv(theEmails);
}, //im not sure how to add the mailList to getCsv(???)
),
);
}
}