MultiSearch in flutter - flutter

The goal of this project is to use Multisearch to search local JSON data based on an int number inside the string. The search for string content has shown the result, now I'm trying to add a search for number entered by the user that searches by int inside string content, but it returns an error.
null isn't subtype of string.
There is a problem with this search code since it works for both string content and integer number.
import 'dart:convert';
import 'package:ebook_flutter_app/constant.dart';
import 'package:ebook_flutter_app/screens/show_item.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:persistent_bottom_nav_bar/persistent-tab-view.dart';
import '../widgets/showImage.dart';
class SearchScreen extends StatefulWidget {
const SearchScreen({Key? key}) : super(key: key);
#override
SearchScreenState createState() => SearchScreenState();
}
class SearchScreenState extends State<SearchScreen> {
List textValues = [];
List original = [];
static TextEditingController txtQuery = TextEditingController();
void loadData() async {
String jsonStr = await rootBundle.loadString('assets/db/text_value.json');
var json = jsonDecode(jsonStr);
textValues = json;
original = json;
setState(() {});
}
void loadImage() async {
String jsonStr = await rootBundle.loadString('assets/db/image_db.json');
var json = jsonDecode(jsonStr);
textValues = json;
original = json;
print('load Image is running....');
setState(() {});
}
void search(String query) {
if (query.isEmpty) {
textValues = original;
setState(() {});
return;
}
query = query.toLowerCase();
print(query);
List result = [];
textValues.forEach((element) {
var name = element["name"].toString().toLowerCase();
var description = element["description"].toString().toLowerCase();
if (name.contains(query) || description.contains(query)) {
result.add(element);
}
});
textValues = result;
setState(() {});
}
void searchById(String query1) {
if (query1.isEmpty) {
textValues = original;
print('query1 is .....$query1');
setState(() {});
return;
}
print('query1 is $query1');
List result = [];
textValues.forEach((element) {
var id_num = element["id_num"].toString();
var id_img = element["id_img"].toString();
if (id_num.contains(query1) ||
id_img.contains(query1)) {
result.add(element);
print('result is......$result');
}
});
textValues = result;
print('textValues is .....$textValues');
setState(() {});
}
#override
void initState() {
super.initState();
txtQuery.text.contains(r'^[0-3]+$') ? loadImage() : loadData();
print('Init State is Loading....');
}
String StrOrInt(String text) {
if (text.toString().startsWith('1') || text.toString().startsWith('2')) {
return 'int';
} else {
return 'str';
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: CustomAppBar(2),
body: Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
margin: const EdgeInsets.all(10),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
TextFormField(
controller: txtQuery,
onChanged: search,
textDirection: TextDirection.rtl,
decoration: InputDecoration(
hintText: "جست وجو...",
hintTextDirection: TextDirection.rtl,
hintStyle: TextStyle(
color: Colors.black,
fontSize: 18,
fontFamily: 'iran-sans-ds',
decoration: TextDecoration.none,
fontStyle: FontStyle.italic,
),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(4.0)),
focusedBorder: const OutlineInputBorder(
borderSide: BorderSide(color: Colors.black)),
prefixIcon: const Icon(Icons.search),
suffixIcon: IconButton(
icon: const Icon(Icons.clear),
onPressed: () {
txtQuery.text = '';
txtQuery.text.contains(r'^[0-3]+$') ? searchById(txtQuery.text) : search(txtQuery.text);
},
),
),
keyboardType: TextInputType.text,
),
],
),
),
txtQuery.text.isEmpty ? Container() : _listView(textValues)
]),
);
}
}
Widget _listView(text_value) {
return Expanded(
child: ListView.builder(
itemCount: text_value.length,
itemBuilder: (context, index) {
var textVal = text_value[index];
String description = textVal['description'];
String id_num = textVal['id_num'];
String id_img = textVal['id_img'];
print('id_num is ....$id_num' ' id_img is.....$id_img');
return Card(
margin: const EdgeInsets.fromLTRB(8.0, 4.0, 8.0, 4.0),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15.0)),
color: Colors.blue[50],
child: Theme(
data:
Theme.of(context).copyWith(dividerColor: Colors.transparent),
child: InkWell(
onTap: (() => pushNewScreen(
context,
screen: !textVal['id_num'].toString().contains(r'^[0-3]+$')
? ShowItem(
name: textVal['name'],
description: textVal['description'],
)
: ShowImage(
title: textVal['id_num'],
image: Myasset(textVal['id_img']),
),
withNavBar: true, // OPTIONAL VALUE. True by default.
pageTransitionAnimation:
PageTransitionAnimation.slideRight,
)),
child: ExpansionTile(
title: Text(
!textVal['id_num'].toString().contains(r'^[0-3]+$')
? textVal['name']
: textVal['id_num'],
textDirection: TextDirection.rtl,
style:
const TextStyle(fontSize: 20.0, color: Colors.black54),
),
childrenPadding: const EdgeInsets.only(
bottom: 20.0, right: 20.0, left: 20.0, top: 5.0),
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: !textVal['id_num'].toString().contains(r'^[0-3]+$')
? [
const Text(
'بیشتر',
textDirection: TextDirection.rtl,
textAlign: TextAlign.justify,
style: TextStyle(
color: Colors.blue,
fontWeight: FontWeight.bold),
),
Text(
'${description.substring(0, 39)} ...',
textDirection: TextDirection.rtl,
textAlign: TextAlign.justify,
style: TextStyle(color: Colors.black),
),
]
: [Image.asset(Myasset(textVal['id_img']))],
)
],
),
),
),
);
}),
);
}
Below is the last source code which works with string content and returns the result.
import 'dart:convert';
import 'package:ebook_flutter_app/constant.dart';
import 'package:ebook_flutter_app/screens/show_item.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:get/get.dart';
import 'package:persistent_bottom_nav_bar/persistent-tab-view.dart';
class SearchScreen extends StatefulWidget {
const SearchScreen({Key? key}) : super(key: key);
#override
SearchScreenState createState() => SearchScreenState();
}
class SearchScreenState extends State<SearchScreen> {
List textValues = [];
List original = [];
TextEditingController txtQuery = TextEditingController();
void loadData() async {
String jsonStr = await rootBundle.loadString('assets/db/text_value.json');
var json = jsonDecode(jsonStr);
textValues = json;
original = json;
setState(() {});
}
void search(String query) {
if (query.isEmpty) {
textValues = original;
setState(() {});
return;
}
query = query.toLowerCase();
print(query);
List result = [];
textValues.forEach((element) {
var name = element["name"].toString().toLowerCase();
var description = element["description"].toString().toLowerCase();
if (name.contains(query) || description.contains(query)) {
result.add(element);
}
});
textValues = result;
setState(() {});
}
#override
void initState() {
super.initState();
loadData();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: CustomAppBar(2),
body: Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
margin: const EdgeInsets.all(10),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
TextFormField(
controller: txtQuery,
onChanged: search,
textDirection: TextDirection.rtl,
decoration: InputDecoration(
hintText: "جست وجو...",
hintTextDirection: TextDirection.rtl,
hintStyle: TextStyle(
color: Colors.black,
fontSize: 18,
fontFamily: 'iran-sans-ds',
decoration: TextDecoration.none,
fontStyle: FontStyle.italic,
),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(4.0)),
focusedBorder: const OutlineInputBorder(
borderSide: BorderSide(color: Colors.black)),
prefixIcon: const Icon(Icons.search),
suffixIcon: IconButton(
icon: const Icon(Icons.clear),
onPressed: () {
txtQuery.text = '';
search(txtQuery.text);
},
),
),
keyboardType: TextInputType.text,
),
],
),
),
txtQuery.text.isEmpty ? Container() : _listView(textValues)
]),
);
}
}
Widget _listView(text_value) {
return Expanded(
child: ListView.builder(
itemCount: text_value.length,
itemBuilder: (context, index) {
var textVal = text_value[index];
String description = textVal['description'];
return Card(
margin: const EdgeInsets.fromLTRB(8.0, 4.0, 8.0, 4.0),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15.0)),
color: Colors.blue[50],
child: Theme(
data:
Theme.of(context).copyWith(dividerColor: Colors.transparent),
child: InkWell(
onTap: (() => pushNewScreen(
context,
screen: ShowItem(
name: textVal['name'],
description: textVal['description'],
),
withNavBar: true, // OPTIONAL VALUE. True by default.
pageTransitionAnimation:
PageTransitionAnimation.slideRight,
)),
child: ExpansionTile(
title: Text(
textVal['name'],
textDirection: TextDirection.rtl,
style:
const TextStyle(fontSize: 20.0, color: Colors.black54),
),
childrenPadding: const EdgeInsets.only(
bottom: 20.0, right: 20.0, left: 20.0, top: 5.0),
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
const Text(
'بیشتر',
textDirection: TextDirection.rtl,
textAlign: TextAlign.justify,
style: TextStyle(
color: Colors.blue, fontWeight: FontWeight.bold),
),
Text(
'${description.substring(0, 39)} ...',
textDirection: TextDirection.rtl,
textAlign: TextAlign.justify,
style: TextStyle(color: Colors.black),
),
],
)
],
),
),
),
);
}),
);
}

The problem is in the ListView.itemBuilder on the function _listView. The code below assumes textVal contain both image and data and there should be only one type.
itemBuilder: (context, index) {
var textVal = text_value[index];
String description = textVal['description'];
String id_num = textVal['id_num'];
String id_img = textVal['id_img'];
...
To fix it just default the value to something else if null. It's easy with the null-coalescing operator ??. Take a look:
itemBuilder: (context, index) {
var textVal = text_value[index];
String description = textVal['description'] ?? '';
String id_num = textVal['id_num'] ?? '';
String id_img = textVal['id_img'] ?? '';
...

Related

Flutter - ScrollController was used after being disposed

class HomeScreen extends StatefulWidget {
final userName;
HomeScreen(this.userName);
#override
State<HomeScreen> createState() => _HomeScreenState();
}
Future<ClientDashboardModel?>? _meterReadingResponse;
BatchSummaryModel? _batchResponse;
AMRDashboardModel? _amrDashboardResponse;
String _userName = '';
int? qcAssignedReads = 0;
int? qcMrCompleted = 0;
int? qcCompletedReads = 0;
int? qcPendingReads = 0;
int? qcApprovedReads = 0;
int? qcRejectedReads = 0;
bool isFirstTimeCalled = false;
Timer? _timer;
int _currentIndex = 0;
final pages = [
const MDMScreen(),
const AMRDashboard(whichScreen: 0),
const AMRDashboard(whichScreen: 1),
const AMRDashboard(whichScreen: 2)
];
class _HomeScreenState extends State<HomeScreen> {
#override
void initState() {
setUpTimedFetch();
super.initState();
if (widget.userName != null) _userName = (widget.userName!);
}
#override
void dispose() {
isFirstTimeCalled = false;
_timer?.cancel();
super.dispose();
}
void setUpTimedFetch() {
if (!isFirstTimeCalled) {
_meterReadingResponse = _getDashboardData();
}
isFirstTimeCalled = true;
}
Future<ClientDashboardModel?> _getDashboardData() async {
ClientDashboardModel? meterReadingResponse;
SharedPreferences prefs = await SharedPreferences.getInstance();
String token = prefs.getString('token')!;
var responseData = await Dashboard().getClientDashboard(token);
if (responseData.statusCode == 200) {
String data = responseData.body;
var decodedData = jsonDecode(data);
meterReadingResponse = null;
meterReadingResponse = ClientDashboardModel.fromJson(decodedData);
return meterReadingResponse;
}
return null;
}
void logout() async {
SharedPreferences.getInstance().then((value) {
value.remove('token');
value.remove('userName');
});
Navigator.pushReplacement(context, MaterialPageRoute(builder: (context) {
return const LoginScreen();
}));
}
Future<void> _showMyDialog() async {
return showDialog<void>(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return AlertDialog(
title: const Text(Strings.kLogoutLabel),
content: const Text(Strings.kConfirmLogout),
actions: <Widget>[
TextButton(
child: const Text(Strings.kCancelLabel),
onPressed: () {
Navigator.of(context).pop();
},
),
TextButton(
child: const Text(Strings.kOKLabel),
onPressed: () {
Navigator.of(context).pop();
logout();
},
)
],
);
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
bottomNavigationBar: BottomNavigationBar(
type: BottomNavigationBarType.fixed,
currentIndex: _currentIndex,
backgroundColor: const Color(0XFF116AFF),
unselectedItemColor: Colors.white,
selectedLabelStyle: const TextStyle(color: Colors.white),
showUnselectedLabels: false,
onTap: (value) {
setState(() => _currentIndex = value);
},
items: [
BottomNavigationBarItem(
label: 'MDM',
icon: Container(
decoration: BoxDecoration(
color:
_currentIndex == 0 ? Colors.white : Colors.transparent,
shape: BoxShape.circle),
child: const Padding(
padding: EdgeInsets.all(10.0),
child: Icon(Icons.electric_meter_outlined),
),
),
),
BottomNavigationBarItem(
label: 'Site Survey',
icon: Container(
decoration: BoxDecoration(
color:
_currentIndex == 1 ? Colors.white : Colors.transparent,
shape: BoxShape.circle),
child: const Padding(
padding: EdgeInsets.all(10.0),
child: Icon(Icons.location_city_outlined),
),
),
),
BottomNavigationBarItem(
label: 'Meter Replace',
icon: Container(
decoration: BoxDecoration(
color:
_currentIndex == 2 ? Colors.white : Colors.transparent,
shape: BoxShape.circle),
child: const Padding(
padding: EdgeInsets.all(10.0),
child: Icon(Icons.library_books_outlined),
),
),
),
BottomNavigationBarItem(
label: 'TroubleShoot',
icon: Container(
decoration: BoxDecoration(
color:
_currentIndex == 3 ? Colors.white : Colors.transparent,
shape: BoxShape.circle),
child: const Padding(
padding: EdgeInsets.all(10.0),
child: Icon(Icons.info_outline),
),
),
),
],
),
appBar: AppBar(
automaticallyImplyLeading: false,
title: const Text(Strings.kMRDLabel),
actions: [
IconButton(
onPressed: () {
_showMyDialog();
},
icon: const Icon(Icons.power_settings_new))
],
),
body: childView());
}
Widget childView() {
return SingleChildScrollView(
scrollDirection: Axis.vertical,
child: Padding(
padding: const EdgeInsets.all(20.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
Strings.kWelcome2Label,
style: TextStyle(
color: Colors.amber.shade700,
fontSize: 16.0,
fontWeight: FontWeight.w600),
),
Text(
_userName.toTitleCase(),
style: const TextStyle(
color: Colors.black,
fontSize: 16.0,
fontWeight: FontWeight.w400),
)
],
),
const Spacer(),
ClipRRect(
borderRadius: BorderRadius.circular(10),
child: Container(
padding: const EdgeInsets.all(10),
decoration: BoxDecoration(color: Colors.grey.shade200),
child: SvgPicture.asset(
'images/profile.svg',
height: 54.0,
width: 54.0,
),
),
),
],
),
const SizedBox(
height: 30,
),
Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [pages[_currentIndex]],
),
],
),
));
}
}
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:manager/components/dotted_line.dart';
import 'package:manager/model/lookup_cycle.dart';
import 'package:manager/model/mr_report_model.dart';
import 'package:manager/services/dashboard_service.dart';
import 'package:manager/utils/debouncer.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:manager/utils/string_captialize.dart';
class MRPerformance extends StatefulWidget {
const MRPerformance({super.key});
#override
State<MRPerformance> createState() => _MRPerformanceState();
}
bool isFilter = false;
bool isPerformingRequest = false;
int pageNumber = 0;
String _chosenValue = '';
List<MRReportResult> users = [];
Future<List<String>?>? dropDownValue;
ScrollController _scrollController = ScrollController();
final _debouncer = Debouncer(milliseconds: 500);
class _MRPerformanceState extends State<MRPerformance> {
#override
void initState() {
super.initState();
_getMoreData(_chosenValue);
dropDownValue = getAllCategory();
_scrollController.addListener(() {
if (_scrollController.position.pixels ==
_scrollController.position.maxScrollExtent) {
pageNumber++;
_getMoreData(_chosenValue);
}
});
}
Future<List<String>?>? getAllCategory() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
String token = prefs.getString('token')!;
var cycleResponse = await Dashboard().getAllCycle(token);
try {
if (cycleResponse.statusCode == 200) {
List<String> items = [];
var jsonData = json.decode(cycleResponse.body) as List;
List<LookUpCycle> lookupCycle = jsonData
.map<LookUpCycle>((json) => LookUpCycle.fromJson(json))
.toList();
items.add('Select');
for (var element in lookupCycle) {
if (element.name != null) {
items.add(element.name!);
}
}
return items;
}
} catch (ex) {
throw (ex.toString());
}
return null;
}
#override
void dispose() {
super.dispose();
_scrollController.dispose();
}
void _getMoreData(String searchCycle) async {
List<MRReportResult>? resultResponse = [];
if (!isPerformingRequest) {
setState(() {
isPerformingRequest = true;
});
SharedPreferences prefs = await SharedPreferences.getInstance();
String token = prefs.getString('token')!;
debugPrint(token);
var responseData =
await Dashboard().getMRReport(token, pageNumber, 10, searchCycle);
if (responseData.statusCode == 200) {
String data = responseData.body;
var decodedData = jsonDecode(data);
MRReportModel newEntries = MRReportModel.fromJson(decodedData);
if (newEntries.result == null) {
if (newEntries.result!.isEmpty) {
double edge = 50.0;
double offsetFromBottom =
_scrollController.position.maxScrollExtent -
_scrollController.position.pixels;
if (offsetFromBottom < edge) {
_scrollController.animateTo(
_scrollController.offset - (edge - offsetFromBottom),
duration: const Duration(milliseconds: 500),
curve: Curves.easeOut);
}
}
}
setState(() {
users.addAll(newEntries.result!);
isPerformingRequest = false;
});
}
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
resizeToAvoidBottomInset: false,
appBar: AppBar(title: const Text('MR Performance')),
body: filterView());
}
void setFilterState() {
setState(() {
if (isFilter == true) {
isFilter = false;
} else {
isFilter = true;
}
});
}
Widget _buildProgressIndicator() {
return Padding(
padding: const EdgeInsets.all(8.0),
child: Center(
child: Opacity(
opacity: isPerformingRequest ? 1.0 : 0.0,
child: const CircularProgressIndicator(),
),
),
);
}
Widget filterView() {
return Column(
children: [
Row(
children: [
Visibility(
visible: isFilter ? true : false,
child: Flexible(
child: Card(
shape: RoundedRectangleBorder(
side: const BorderSide(color: Color(0XFFDCDCDC)),
borderRadius: BorderRadius.circular(10)),
elevation: 2,
child: Column(
children: [
Row(
children: [
Expanded(
child: TextField(
textInputAction: TextInputAction.search,
decoration: const InputDecoration(
border: InputBorder.none,
prefixIcon: InkWell(
child: Icon(Icons.search),
),
contentPadding: EdgeInsets.all(8.0),
hintText: 'Search ',
),
onChanged: (string) {
_debouncer.run(() {});
},
),
),
],
),
],
),
),
),
),
Visibility(
visible: isFilter ? false : true,
child: Flexible(
child: Card(
elevation: 4,
shape: RoundedRectangleBorder(
side: const BorderSide(color: Color(0XFFDCDCDC)),
borderRadius: BorderRadius.circular(10)),
child: Padding(
padding: const EdgeInsets.only(
left: 10,
),
child: FutureBuilder<List<String>?>(
future: dropDownValue,
builder: (context, snapshot) {
if (snapshot.connectionState ==
ConnectionState.done) {
if (snapshot.hasError) {
return const Text('Something wrong');
} else if (snapshot.hasData) {
var data = snapshot.data!;
return DropdownButtonHideUnderline(
child: DropdownButton<String>(
icon: const Icon(
Icons.expand_more_outlined,
size: 35,
color: Color(0XFF116AFF),
),
borderRadius: BorderRadius.circular(10),
isExpanded: true,
// value: _chosenValue.isNotEmpty ? _chosenValue : null,
elevation: 16,
style: const TextStyle(
color: Colors.black,
fontSize: 14,
fontWeight: FontWeight.w400),
items: data.map((String value) {
return DropdownMenuItem(
value: value, child: Text(value));
}).toList(),
hint: Padding(
padding: const EdgeInsets.all(15),
child: Text(
_chosenValue.isEmpty
? 'Cycle'
: _chosenValue,
style: const TextStyle(
color: Colors.black,
fontSize: 16,
fontWeight: FontWeight.w400),
),
),
onChanged: (String? value) {
setState(() {
if (value != null) {
pageNumber = 0;
users.clear();
if (value == 'Select') {
_chosenValue = '';
} else {
_chosenValue = value;
}
_getMoreData(_chosenValue);
}
});
},
),
);
}
}
return const CircularProgressIndicator();
},
)),
),
),
),
InkWell(
onTap: () => {setFilterState()},
child: Card(
elevation: 4,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10)),
child: Padding(
padding: const EdgeInsets.all(10.0),
child: isFilter
? const Icon(Icons.filter_alt, color: Color(0XFF116AFF))
: const Icon(
Icons.search,
color: Color(0XFF116AFF),
),
),
),
),
],
),
Expanded(
child: ListView.builder(
shrinkWrap: true,
scrollDirection: Axis.vertical,
itemCount: users.length + 1,
controller: _scrollController,
itemBuilder: (BuildContext context, int index) {
if (index == users.length) {
return _buildProgressIndicator();
} else {
return cardView(users, index);
}
}),
),
],
);
}
Widget cardView(List<MRReportResult>? users, int index) {
return Card(
shape: RoundedRectangleBorder(
side: const BorderSide(color: Color(0XFFDCDCDC)),
borderRadius: BorderRadius.circular(10)),
margin: const EdgeInsets.all(8),
child: Padding(
padding: const EdgeInsets.all(10.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Container(
decoration: BoxDecoration(
border: Border.all(
color: Colors.orange,
),
borderRadius: const BorderRadius.all(Radius.circular(20))),
margin: const EdgeInsets.all(10),
padding: const EdgeInsets.all(10),
child: Row(
children: [
Text(
'${users?[index].mRNumber}: ',
style: const TextStyle(
color: Colors.orange,
fontSize: 10,
fontWeight: FontWeight.w600),
),
Text(
'${users?[index].meterReaderName}'.toTitleCase(),
style: const TextStyle(
color: Colors.black,
fontSize: 10,
fontWeight: FontWeight.w400),
),
],
),
),
Padding(
padding: const EdgeInsets.only(left: 20),
child: Row(
children: [
const Text(
'Supervisor: ',
style: TextStyle(
color: Color(0XFF004AC6),
fontSize: 10,
fontWeight: FontWeight.w600),
),
Expanded(
child: Text(
'${users?[index].supervisor}'.toTitleCase(),
overflow: TextOverflow.fade,
style: const TextStyle(
color: Colors.black,
fontSize: 10,
fontWeight: FontWeight.w400),
),
),
],
),
),
const SizedBox(height: 10),
const MySeparator(),
const SizedBox(height: 10),
Padding(
padding: const EdgeInsets.only(left: 30, right: 30),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
Column(
children: [
Text(
'${users?[index].unreadPercenatge}%',
style: const TextStyle(
color: Colors.orange,
fontSize: 10,
fontWeight: FontWeight.w600),
),
const Text(
'Unread',
style: TextStyle(
color: Color(0XFF004AC6),
fontSize: 12,
fontWeight: FontWeight.w400),
)
],
)
],
),
Row(
children: [
Column(
children: [
Text(
'${users?[index].readPercenatge}%',
style: const TextStyle(
color: Colors.green,
fontSize: 10,
fontWeight: FontWeight.w600),
),
const Text(
'Read',
style: TextStyle(
color: Color(0XFF004AC6),
fontSize: 12,
fontWeight: FontWeight.w400),
)
],
)
],
),
Row(
children: [
Column(
children: [
Text(
'${users?[index].plusorMinusTwoReadPercentage}%',
style: const TextStyle(
color: Colors.green,
fontSize: 10,
fontWeight: FontWeight.w600),
),
const Text(
'+/- 2',
style: TextStyle(
color: Color(0XFF004AC6),
fontSize: 12,
fontWeight: FontWeight.w400),
)
],
)
],
),
Row(
children: [
Column(
children: [
Text(
'${users?[index].above32ReadPercentage}%',
style: const TextStyle(
color: Colors.orange,
fontSize: 10,
fontWeight: FontWeight.w600),
),
const Text(
'>32',
style: TextStyle(
color: Color(0XFF004AC6),
fontSize: 12,
fontWeight: FontWeight.w400),
)
],
)
],
),
],
),
),
],
),
),
);
}
}
════════ Exception caught by widgets library ═══════════════════════════════════
The following assertion was thrown building Builder:
A ScrollController was used after being disposed.
Once you have called dispose() on a ScrollController, it can no longer be used.
The relevant error-causing widget was
MaterialApp
lib/main.dart:13
When the exception was thrown, this was the stack
You have declared _getMoreData two times in init(), so remove it before _scrollController as shown below
void initState() {
super.initState();
_getMoreData(_chosenValue);-------------> remove this from here
dropDownValue = getAllCategory();
_scrollController.addListener(() {
if (_scrollController.position.pixels ==
_scrollController.position.maxScrollExtent) {
pageNumber++;
_getMoreData(_chosenValue);
}
});
}
OR
Declare ScrollController _scrollController = ScrollController(); in state class _MRPerformanceState as below code:
class _MRPerformanceState extends State<MRPerformance> {
ScrollController _scrollController = ScrollController();

Flutter - bottomModalSheet can't validate a textfield widget

I have attached a project which is having a bottom modal sheet. Which sheet contains three TextField as name, number and email. So here I have implemented CRUD (Create, read, update and delete) operation and it's fine working. But without validating the TextField it shows in the HomePage. although if I miss to enter name or number still it's passing the data to the homepage card. I have tried many validating options but didn't worked out. If anyone can please help me.
My code:
import 'package:flutter/material.dart';
class HomePage extends StatefulWidget {
const HomePage({super.key});
#override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
List<Map<String, dynamic>> _contacts = [];
bool _isLoading = true;
final bool _validatename = true;
final bool _validatenumber = true;
final bool _validateemail = true;
void _refreshContacts() async {
final data = await Contact.getContacts();
setState(() {
_contacts = data;
_isLoading = false;
});
}
#override
void initState() {
super.initState();
_refreshContacts();
}
final _nameController = TextEditingController();
final _numberController = TextEditingController();
final _emailController = TextEditingController();
final bool _validate = false;
void _showForm(int? id) async {
if (id != null) {
final existingContact = _contacts.firstWhere((element) => element['id'] ==id);
_nameController.text = existingContact['name'];
_numberController.text = existingContact['number'];
_emailController.text = existingContact['email'];
}
showModalBottomSheet(context: context,
elevation: 5,
isScrollControlled: true,
builder: (_) => Container(
padding: EdgeInsets.only(top: 15, left: 15, right: 15, bottom: MediaQuery.of(context).viewInsets.bottom + 120),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.end,
children: [
TextField(
controller: _nameController,
decoration: const InputDecoration(
hintText: "Name",
),
),
const SizedBox(
height: 10.0,
),
TextField(
keyboardType: TextInputType.number,
controller: _numberController,
decoration: const InputDecoration(
hintText: "Numbers",
),
),
const SizedBox(
height: 10.0,
),
TextField(
// keyboardType: TextInputType.emailAddress,
controller: _emailController,
decoration: const InputDecoration(
hintText: "Email Address",
),
),
const SizedBox(
height: 20.0,
),
Row(
children: [
ElevatedButton(
onPressed: () async {
if (id == null) {
await _addContact();
}
if (id != null) {
await _updateContact(id);
}
Navigator.of(context).pop();
_nameController.text = '';
_numberController.text = '';
_emailController.text = '';
},
child: Text(id == null ? 'Create New' : 'Update'),
),
const SizedBox(
width: 10.0,
),
ElevatedButton(onPressed: () async {
_nameController.text = '';
_numberController.text = '';
_emailController.text = '';
}, child: const Text("Clear")),
const SizedBox(
width: 10.0,
),
ElevatedButton(onPressed: (){
Navigator.pop(context);
}, child: const Text("Go Back")),
],
),
]),
));
}
Future<void> _addContact() async {
await Contact.createContact(
_nameController.text, _numberController.text, _emailController.text
);
_refreshContacts();
}
Future<void> _updateContact(int id) async {
await Contact.updateContact(id, _nameController.text, _numberController.text, _emailController.text );
_refreshContacts();
}
void _deleteContact(int id) async {
await Contact.deleteContact(id);
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text("Sccessfully Contact Deleted")));
_refreshContacts();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("Contact App",),
backgroundColor: Colors.blueAccent,
centerTitle: true,
toolbarHeight: 80,
),
body: _isLoading ? const Center(child: CircularProgressIndicator(),) :
ListView.builder(
itemCount: _contacts.length,
itemBuilder: (context, index) =>
Card(
elevation: 5,
shape: const Border(
right: BorderSide(color: Colors.blue, width: 10.0),
),
color: Colors.orange[200],
margin: const EdgeInsets.all(15.0),
child: Material(
elevation: 20.0,
shadowColor: Colors.blueGrey,
child: ListTile(
title: Text(_contacts[index]['name'], style: const TextStyle(fontSize: 22, fontWeight: FontWeight.bold),),
subtitle: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(_contacts[index]['number'], style: const TextStyle(color: Colors.grey, fontSize: 18),),
const SizedBox(
height: 5.0,
),
Text(_contacts[index]['email'], style: const TextStyle(fontSize: 17, color: Colors.black),),
],
),
trailing: SizedBox(
width: 100,
child: Row(
children: [
IconButton(onPressed: () => _showForm(_contacts[index]['id']), icon: const Icon(Icons.edit, color: Colors.blueGrey,)),
IconButton(onPressed: () => _deleteContact(_contacts[index]['id']), icon: const Icon(Icons.delete, color: Colors.red,)),
],
),
),
),
),
),
),
floatingActionButton: FloatingActionButton(
child: const Icon(Icons.add, size: 28,),
onPressed: () => _showForm(null),
),
);
}
}
Above codes are from homepage. I need only the validating part + if anyone can know how to show the each card in another page using page route. Actually this is a contact app. I have tried the new screen to show the full details but couldn't.
You can return when any of the field is empty like
ElevatedButton(
onPressed: () async {
if (_nameController.text.isEmpty ||
_numberController.text.isEmpty ||
_emailController.text.isEmpty) {
return;
}
},
child: Text(id == null ? 'Create New' : 'Update'),
),
But it will be better to use Form widget TextFormFiled with validator . Find more on validation
final _formKey = GlobalKey<FormState>();
showModalBottomSheet(
context: context,
elevation: 5,
isScrollControlled: true,
builder: (_) => Container(
child: Form(
key: _formKey,
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.end,
children: [
TextFormField(
validator: (value) {
if (value == null || value.isEmpty) {
return 'Please enter some text';
}
return null;
},
controller: _nameController,
decoration: const InputDecoration(
hintText: "Name",
),
),
Row(
children: [
ElevatedButton(
onPressed: () async {
final isValided =
_formKey.currentState?.validate();
if (isValided == true) {}
},
child: Text(id == null ? 'Create New' : 'Update'),
),

Flutter - Quantity of all Products returns same value after OnClick

To keep things short:
I have multiple products, where you can increment and decrement their value(qnty) inside the cart and after Submitting, a receipt is generated based on the cart Items.
So the Problem is whenever I try to slide the submit, the qnty of the first product I added to cart is assigned to every product, Like
• Apple: 1
• Mango: 2
• Orange: 6
Above is how it should be like
• Apple: 6
• Mango: 6
• Orange: 6
This is the result I am getting, Note: The Result is from new to old
Secondary issue is that whenever I try to write any value inside the textfield and click submit, the value still doesn't get updated!
The Code consists of 2 files:
Parent File
import 'package:ambica_medico/component/result/productcart.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:flutter_email_sender/flutter_email_sender.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:whatsapp_unilink/whatsapp_unilink.dart';
import '../../component/buttons/c_button.dart';
import '../../constant.dart';
final FirebaseAuth auth = FirebaseAuth.instance;
Stream<QuerySnapshot> getData() => FirebaseFirestore.instance
.collection('Users')
.doc(auth.currentUser?.uid)
.collection('Carts')
.snapshots();
class Cart extends StatefulWidget {
const Cart({Key? key}) : super(key: key);
#override
State<Cart> createState() => _CartState();
}
class _CartState extends State<Cart> {
String _text = '';
callback(newAbc) {
pk = newAbc;
} //Step 5: Callback ready to be passed to the the Procart.
String? product;
String qnty = '';
String? mail;
String? name;
String? address;
String? dln;
String? gst;
late final _getData = getData();
DateTime now = DateTime.now();
Map<String, String> pk = {};
#override
Widget build(BuildContext context) {
return StreamBuilder<dynamic>(
stream: _getData,
builder: (context, snapshot) {
final tilesList = <Widget>[];
if (snapshot.hasData) {
snapshot.data.docs.forEach((value) {
qnty = value.data()['SIB'].toString();
pk = {value.id: qnty}; //Step4: A map which holds every product id and qnty
final productTile = Procart(
pname: value.data()['Product'],
subtitle: value.data()['MRP'],
keyo: value.id,
controller: qnty, sib: value.data()['OSIB'], tis: value.data()['TIS'], callback: callback, //Callback passed!
);
if (_text.isEmpty) {
tilesList.add(productTile);
} else {
if (value
.data()['Product']
.toUpperCase()
.contains(_text.toUpperCase())) {
tilesList.add(productTile);
}
}
// print(pk.values); //Returns 5,1
});
return SafeArea(
child: Scaffold(
resizeToAvoidBottomInset: false,
appBar: AppBar(
leading: Padding(
padding: const EdgeInsets.only(left: 20.0, top: 10),
child: IconButton(
icon: const Icon(
Icons.arrow_back_ios_new_rounded,
color: Colors.black,
size: 20,
),
onPressed: () {
Navigator.pop(context);
},
),
),
backgroundColor: const Color(0xFFf5f3f7),
elevation: 0,
),
body: GestureDetector(
onTap: () => FocusManager.instance.primaryFocus?.unfocus(),
child: Container(
decoration: kImageBackground.copyWith(),
height: MediaQuery.of(context).size.height,
child: Stack(children: [
Column(
children: [
SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.only(
left: 24.0, right: 24.0, top: 40),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisAlignment: MainAxisAlignment.start,
children: [
const Text(
'The Cart',
style: TextStyle(
fontSize: 40,
fontFamily: 'ProductSans',
fontWeight: FontWeight.bold,
color: Colors.black,
),
),
Padding(
padding:
const EdgeInsets.only(top: 50, bottom: 50),
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
color: Colors.white,
boxShadow: const [
BoxShadow(
color: Color(0x261B1B1A),
blurRadius: 50.0,
spreadRadius: 0,
offset: Offset(0.0, 30.0),
),
],
),
height: 70,
child: Center(
child: TextField(
onChanged: (value) {
setState(() {
_text = value;
});
},
keyboardType: TextInputType.text,
decoration: kDecorS.copyWith(
hintText: 'Search Products',
),
style: const TextStyle(
fontFamily: 'ProductSans',
fontSize: 18,
fontWeight: FontWeight.w400,
color: Color(0xff0f1511),
),
),
),
),
),
],
),
),
),
SizedBox(
height: MediaQuery.of(context).size.height * 0.55,
child: ListView(
shrinkWrap: true,
physics: const BouncingScrollPhysics(),
children: tilesList,
),
),
],
),
Positioned(
bottom: 0,
child: SingleChildScrollView(
physics: const NeverScrollableScrollPhysics(),
child: Align(
alignment: Alignment.bottomCenter,
child: Container(
width: MediaQuery.of(context).size.width,
decoration: const BoxDecoration(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(42.0),
topRight: Radius.circular(42.0),
),
color: Colors.white,
),
child: Padding(
padding: const EdgeInsets.only(top: 20),
child: Column(
children: [
const Padding(
padding:
EdgeInsets.only(bottom: 10.0),
child: Center(
child: Text(
'Check and then click below to',
style: TextStyle(
fontSize: 14,
fontFamily: 'ProductSans',
fontWeight: FontWeight.bold,
color: Colors.black,
),
),
),
),
Cbutton(
text: 'Send Order',
onPressed: () async {
String message = "";
DateTime date = DateTime(
now.year, now.month, now.day);
await FirebaseFirestore.instance
.collection('Users')
.doc(auth.currentUser?.uid)
.get()
.then((value) => {
name = value.data()!['name'],
address =
value.data()!['address'],
dln = value.data()!['dln'],
gst = value.data()!['gst'],
});
await snapshot.data.docs
.forEach((value) async {
product = value.data()['Product'];
message += '- $product = ${pk.values} \n';
});
final Email email = Email(
body:
"From:- \n\nName: $name\n\nAddress: $address\n\nDrug License No:- $dln\n\nGST No:- $gst\n\nDate:- $date \n\nDear sir,\nPlease dispatch my following order earliest possible through\n $message \n\nThanks & Regards,\n$name",
subject: 'Order Detail',
recipients: ['calagency03#gmail.com'],
isHTML: false,
);
final link = WhatsAppUnilink(
phoneNumber: '+91 2313210000',
text:
"From:- \n\nName: $name\n\nAddress: $address\n\nDrug License No:- $dln\n\nGST No:- $gst\n\nDate:- $date \n\nDear sir,\nPlease dispatch my following order earliest possible through\n $message \n\nThanks & Regards,\n$name",
);
await FlutterEmailSender.send(email);
final url = Uri.parse('$link');
await launchUrl(url, mode: LaunchMode.externalApplication,);
},
icon: const Icon(
Icons.send_rounded,
color: Colors.black,
size: 20,
),
color: const Color(0xff0f1511),
),
],
),
),
),
),
),
)
]),
),
),
),
);
} else {
return const Center(
child: CircularProgressIndicator(),
);
}
});
}
}
The main logic of printing the receipt for a product is:
await snapshot.data.docs
.forEach((value) async {
product = value.data()['Product'];
message += '- $product = ${pk.values} \n';
});
Child File
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:flutter_slidable/flutter_slidable.dart';
class Procart extends StatefulWidget {
final String pname;
final String subtitle;
final String keyo; // Step1: Product id
final String sib;
final String tis;
final String controller; // Step2: Initial Value/ Qnty
final Function(Map) callback; // Step3: Callback to parents widget in which it passes updated qnty
const Procart(
{Key? key,
required this.pname,
required this.subtitle,
required this.keyo, required this.controller, required this.sib, required this.tis, required this.callback})
: super(key: key);
#override
State<Procart> createState() => _ProcartState();
}
class _ProcartState extends State<Procart> {
final FirebaseAuth auth = FirebaseAuth.instance;
late TextEditingController controller = TextEditingController(text: widget.controller);
Map<String, String> lk = {};
sub() {
setState(() {
controller.text =
(int.parse(controller.text) - 1).toString();
});
}
add() {
setState(() {
controller.text =
(int.parse(controller.text) + 1).toString();
});
}
// #override
// void didUpdateWidget(covariant Procart oldWidget) {
// // TODO: implement didUpdateWidget
// super.didUpdateWidget(oldWidget);
//
//
// }
#override
Widget build(BuildContext context) {
lk = { widget.keyo : controller.text }; // This map is used to store updated value
widget.callback(lk); // send updated value back to parent class but the value still remains 2,2,2 instead of 1,7,2
print(lk.values);
return GestureDetector(
onTap: () => FocusManager.instance.primaryFocus?.unfocus(),
child: Padding(
padding: const EdgeInsets.only(bottom: 10),
child: Slidable(
key: Key(widget.keyo),
endActionPane: ActionPane(motion: const ScrollMotion(), children: [
SlidableAction(
// An action can be bigger than the others.
onPressed: (value) {
FirebaseFirestore.instance
.collection('Users')
.doc(auth.currentUser?.uid)
.collection('Carts')
.doc(widget.keyo)
.delete();
},
backgroundColor: const Color(0xFFD16464),
foregroundColor: Colors.white,
icon: Icons.clear_rounded,
),
]),
child: Padding(
padding: const EdgeInsets.only(left: 28.0, right: 28.0),
child: Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(10)
),
child: Padding(
padding: const EdgeInsets.all(12.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
SizedBox(
width: MediaQuery.of(context).size.width * 0.4,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
widget.pname,
style: const TextStyle(
fontFamily: 'Satoshi',
fontSize: 16,
fontWeight: FontWeight.bold,
color: Color(0xff0f1511),
),
),
Text(
'${widget.subtitle} | ${widget.sib} x ${widget.tis}',
style: const TextStyle(
fontFamily: 'Satoshi',
fontSize: 12,
fontWeight: FontWeight.normal,
color: Color(0xff0f1511),
),
),
],
),
),
Row(
children: [
CircleAvatar(
radius: 16,
backgroundColor: const Color(0xff1b1b1b),
child: IconButton(
iconSize: 13,
icon: const Icon(
Icons.remove,
color: Colors.white,
),
onPressed: () {
if (int.parse(controller.text) >
int.parse(widget.sib)) {
sub();
}
},
),
),
SizedBox(
width: 80,
child: TextFormField(
textAlign: TextAlign.center,
decoration: const InputDecoration(
border: InputBorder.none,
contentPadding: EdgeInsets.only(left: 6, right: 6),
),
controller: controller,
onEditingComplete: () {
controller;
},
keyboardType: TextInputType.number,
style: const TextStyle(
fontFamily: 'Satoshi',
fontSize: 16.0,
fontWeight: FontWeight.bold,
color: Color(0xff0f1511),
),
),
),
CircleAvatar(
radius: 16,
backgroundColor: const Color(0x33bababa),
child: IconButton(
iconSize: 13,
icon: const Icon(
Icons.add,
color: Color(0xff1b1b1b),
),
onPressed: () {
add();
},
),
),
],
),
]),
),
),
))),
);
}
}
For more info I have attached Screenshots below:
A Huge Thank you to anyone who helps me in solving this!
Well, I solved this issue by following the steps below:

Why dark theme isn't working after using provider and using sharedpreferences?

I wanted to add dark theme in my flutter application. So I read this article. I followed every steps but the provider seems not working. And my application is behaving weirdly.
Here is my main.dart file:
import 'package:arithmatic_calculator/dark_theme_provider.dart';
import 'package:arithmatic_calculator/dark_theme_styles.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({Key? key}) : super(key: key);
#override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
static const appTitle = "Simple Calculator";
DarkThemeProvider themeProvider = DarkThemeProvider();
#override
void initState() {
super.initState();
getCurrentAppTheme();
}
void getCurrentAppTheme() async {
themeProvider.darkTheme =
await themeProvider.darkThemePreference.getTheme();
print(themeProvider.darkTheme);
}
#override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (_) {
print("ChangeNotifier: $themeProvider.darkTheme");
return themeProvider;
},
child: MaterialApp(
title: 'Flutter Demo',
debugShowCheckedModeBanner: false,
theme: Styles.themeData(themeProvider.darkTheme, context),
home: Scaffold(
appBar: AppBar(
title: const Text(appTitle),
backgroundColor: Colors.purple,
),
backgroundColor: Colors.white,
body: const CalculatorHomePage()),
),
);
}
}
class CalculatorHomePage extends StatefulWidget {
const CalculatorHomePage({Key? key}) : super(key: key);
#override
State<CalculatorHomePage> createState() => _CalculatorHomePageState();
}
class _CalculatorHomePageState extends State<CalculatorHomePage> {
var num1 = 0, num2 = 0, sum = 0;
final TextEditingController t1 = TextEditingController(text: "0");
final TextEditingController t2 = TextEditingController(text: "0");
void doAddition() {
setState(() {
num1 = int.parse(t1.text);
num2 = int.parse(t2.text);
sum = num1 + num2;
});
}
void doSub() {
setState(() {
num1 = int.parse(t1.text);
num2 = int.parse(t2.text);
sum = num1 - num2;
});
}
void doMul() {
setState(() {
num1 = int.parse(t1.text);
num2 = int.parse(t2.text);
sum = num1 * num2;
});
}
void doDiv() {
setState(() {
num1 = int.parse(t1.text);
num2 = int.parse(t2.text);
sum = num1 ~/ num2;
});
}
void doClear() {
setState(() {
t1.text = "0";
t2.text = "0";
});
}
#override
Widget build(BuildContext context) {
final themeChange = Provider.of<DarkThemeProvider>(context);
return SingleChildScrollView(
padding: const EdgeInsets.all(40.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Checkbox(
value: themeChange.darkTheme,
onChanged: (bool? val) {
setState(() {
themeChange.darkTheme = val!;
print(themeChange.darkTheme);
});
}),
Text(
"Output: $sum",
style: const TextStyle(
fontSize: 20.0,
fontWeight: FontWeight.bold,
color: Colors.purple),
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 16),
child: TextField(
controller: t1,
keyboardType: TextInputType.number,
decoration: const InputDecoration(
border: OutlineInputBorder(), hintText: "Enter number 1"),
),
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 16),
child: TextField(
controller: t2,
keyboardType: TextInputType.number,
decoration: const InputDecoration(
border: OutlineInputBorder(), hintText: "Enter number 2"),
),
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Padding(
padding:
const EdgeInsets.symmetric(horizontal: 8, vertical: 16),
child: MaterialButton(
onPressed: doAddition,
color: Colors.purple,
child: const Text(
"ADD",
style: TextStyle(color: Colors.white),
),
),
),
Padding(
padding:
const EdgeInsets.symmetric(horizontal: 8, vertical: 16),
child: MaterialButton(
onPressed: () {
doSub();
},
color: Colors.purple,
child: const Text(
"SUBTRACT",
style: TextStyle(color: Colors.white),
),
),
),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Padding(
padding:
const EdgeInsets.symmetric(horizontal: 8, vertical: 16),
child: MaterialButton(
onPressed: () {
doDiv();
},
color: Colors.purple,
child: const Text(
"DIVIDE",
style: TextStyle(color: Colors.white),
),
),
),
Padding(
padding:
const EdgeInsets.symmetric(horizontal: 8, vertical: 16),
child: MaterialButton(
onPressed: () {
doMul();
},
color: Colors.purple,
child: const Text(
"MULTIPLY",
style: TextStyle(color: Colors.white),
),
),
),
],
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 16),
child: MaterialButton(
onPressed: () {
doClear();
},
color: Colors.purple,
child: const Text(
"CLEAR",
style: TextStyle(color: Colors.white),
),
),
),
],
),
);
}
}
Here is my dark_theme_provider.dart:
import 'package:arithmatic_calculator/save_theme.dart';
import 'package:flutter/material.dart';
class DarkThemeProvider with ChangeNotifier {
DarkThemePreference darkThemePreference = DarkThemePreference();
bool _darkTheme = false;
bool get darkTheme => _darkTheme;
set darkTheme(bool value) {
_darkTheme = value;
darkThemePreference.setDarkTheme(value);
notifyListeners();
}
}
And here is my save_theme.dart where we used sharedpreferences for saving the current theme.
import 'package:shared_preferences/shared_preferences.dart';
class DarkThemePreference {
static const THEME_STATUS = "THEMESTATUS";
setDarkTheme(bool value) async {
print("Shared Prefs");
SharedPreferences preferences = await SharedPreferences.getInstance();
preferences.setBool(THEME_STATUS, value);
}
Future<bool> getTheme() async {
print("Get theme dhukse");
SharedPreferences preferences = await SharedPreferences.getInstance();
return preferences.getBool(THEME_STATUS) ?? false;
}
}
Can you help me where I am doing wrong? I don't know much about provider.
Your ChangeNotifierProvider will look like this. reference
ChangeNotifierProvider(
create: (_) {
return themeChangeProvider;
},
child: Consumer<DarkThemeProvider>(
builder: (BuildContext context, value, Widget child) {
return MaterialApp(
debugShowCheckedModeBanner: false,
theme: Styles.themeData(themeChangeProvider.darkTheme, context),
home: SplashScreen(),
routes: <String, WidgetBuilder>{
AGENDA: (BuildContext context) => AgendaScreen(),
},
);
},
),);

Search and select item in listview using flutter

I am searching in ListView and I am getting search result in flitered list but when I am selecting the searched item in listview and clear the searchbox in the original list my selected item is deselected.
My original list is "rest" list in the code and filtered list is "filteredList used in code.
Help me to solve my issue as I am new to flutter.
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:http/http.dart' as http;
import 'package:shared_preferences/shared_preferences.dart';
String stringValue="default";
String Currentdate;
const lightGrey = Color(0xff858585);
const darkGrey = Color(0xff404042);
const orange = Color(0xffff8500);
const blue = Color(0xff2f5597);
const skyblue=Color(0xffF1F5F9);
const darkblue=Color(0xffD4E7F9);
class AttendencePage2 extends StatefulWidget {
final String centernametext,batchname,date,centerid,batchid,accesstoken;
AttendencePage2(this.centernametext,this.batchname,this.date,this.centerid,this.batchid,this.accesstoken);
#override
State<StatefulWidget> createState() {
// TODO: implement createState
return _AttendencePage2();
}
}
class _AttendencePage2 extends State<AttendencePage2> {
int i;
String str_accesstoken;
List rest;
List<Autogenerated> list= List<Autogenerated>();
List filteredlist;
TextEditingController controller = new TextEditingController();
bool isSelected = false;
List<int> indexList = new List();
bool longPressFlag = false;
void longPress() {
setState(() {
if (indexList.isEmpty) {
longPressFlag = false;
} else {
longPressFlag = true;
}
});
}
var mycolor=Colors.white;
bool checkVal = false;
bool checkVal2=false;
#override
void initState() {
super.initState();
getStringValuesSF();
StudentListRequest();
}
#override
Widget build(BuildContext context) {
// for (var i = 0; i < 50; i++) {
// indexList.add(Element(isSelected: false));
// }
SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle(
systemNavigationBarColor: Colors.white, // navigation bar color
statusBarColor: Colors.black, // status bar color
));
return MaterialApp(
home: Scaffold(
appBar: AppBar(
centerTitle: true,
backgroundColor: orange,
title: Text('ATTENDENCE'),
),body:
Stack(
children: <Widget>[
Container(
color: Colors.white,
),
Container(
color: skyblue,
width: double.infinity,
height: 65,
padding: EdgeInsets.only(right: 20,left: 20,top: 10,bottom: 10),
child:Row(
children: <Widget>[
Container(
child:Column(children: <Widget>[
Text("Center Name",style: TextStyle(color: lightGrey,fontSize: 17)),
Container(
margin: EdgeInsets.only(top:5),
child:Text(widget.centernametext.toUpperCase(),style: TextStyle(color: Colors.black,fontSize: 13)),
),
],)
//child:
),
Spacer(),
Container(
child:Column(children: <Widget>[
Text("Batch",style: TextStyle(color: lightGrey,fontSize: 17),textAlign: TextAlign.left,),
Container(
margin: EdgeInsets.only(top:5),
child:Text(widget.batchname,style: TextStyle(color: Colors.black,fontSize: 13)),),
],)
),
Spacer(),
Container(
child:Column(children: <Widget>[
Text("Date",style: TextStyle(color: lightGrey,fontSize: 17)),
Container(
margin: EdgeInsets.only(top:5),
child:Text(widget.date,style: TextStyle(color: Colors.black,fontSize: 13)),
),
],)
),
Container(
margin: EdgeInsets.only(left: 10),
child: Image.asset('assets/grey_edit.png',width: 20,height: 25),
),
],
)
),
_searchBar(),
Container(
color: skyblue,
width: double.infinity,
height: 50,
margin: EdgeInsets.only(top:155,left: 10,right: 10),
padding: EdgeInsets.only(right: 20,left: 0,top: 10,bottom: 10),
child:Row(
children: <Widget>[
Container(
child: Checkbox(
value: checkVal,
onChanged: (bool value) {
setState(() {
checkVal = value;
if(checkVal==true){
isSelected=true;
}else{
isSelected=false;
}
});
} ),
),
Container(margin: EdgeInsets.only(top:5),
child:Column(children: <Widget>[
Text("Name",style: TextStyle(color: lightGrey,fontSize: 15)),
],)
),
Spacer(),
Container(margin: EdgeInsets.only(top:5),
child:Column(children: <Widget>[
Text(" ",style: TextStyle(color: lightGrey,fontSize: 15),textAlign: TextAlign.left,),
],)
),
Spacer(),
Container(margin: EdgeInsets.only(top:5),
child:Column(children: <Widget>[
Text("Level ",style: TextStyle(color: lightGrey,fontSize: 15)),
],)
),
Spacer(),
Container(margin: EdgeInsets.only(top:5),
child:Column(children: <Widget>[
Text("No. of class",style: TextStyle(color: lightGrey,fontSize: 15)),
],)
),
Spacer(),
Container(margin: EdgeInsets.only(top:5),
child:Column(children: <Widget>[
Text("Attend",style: TextStyle(color: lightGrey,fontSize: 15)),
],)
),
],
)
),
Container(
margin: EdgeInsets.only(top:205,left: 10,right: 10),
decoration: BoxDecoration(
border: Border.all(color: darkblue)
),
child: ListView.builder(
//addAutomaticKeepAlives: true,
itemCount: filteredlist==null?0:filteredlist.length,
// padding: const EdgeInsets.all(2.0),
itemBuilder: (context, index) {
return new CustomWidget(
selected:isSelected,
rest:filteredlist,
index: index,
longPressEnabled: longPressFlag,
callback: () {
longPress();
},
);
})
)])));
}
_searchBar() {
return Container(
child:Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
width: 350,
height: 40,
margin: EdgeInsets.only(left:20,top:90),
child:TextField(
decoration: InputDecoration(
contentPadding: EdgeInsets.fromLTRB(20.0, 15.0, 20.0, 15.0),
prefixIcon: new Padding(
padding: const EdgeInsets.only( top: 13, left: 0, right: 5, bottom: 13),
child: new SizedBox(
height: 2,
child: Image.asset('assets/search.png'),
),
),
labelText: "Search by name",
labelStyle: TextStyle(
color: lightGrey,
fontSize: 15
),
border: OutlineInputBorder( borderSide: BorderSide(color: lightGrey, width: 0.5),
borderRadius: BorderRadius.circular(5.0)),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: orange, width: 0.5),
borderRadius: BorderRadius.circular(5.0)
)),
controller: controller,
onChanged: (string){setState(() {
filteredlist=rest.where((f){
var dataName=f['student']['name'].toString().toLowerCase();
var dataName2=f['course']['level_no'].toString().toLowerCase();
return dataName.contains(string)||dataName2.contains(string);
}).toList();
}
);
},
)
),
],
)
);
}
Future<List<Autogenerated>> StudentListRequest() async {
String as=widget.accesstoken.toString();
var url = 'http://demo.neurapses.com:3032/students?center=5ca5ba30e0adb9c1839aa0d2&batch=5ca5c81597f8a03368df072c';
var response = await http.get(url,
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer $as'
},
);
final int statusCode = response.statusCode;
if (statusCode < 200 || statusCode > 400 || json == null) {
throw new Exception("Error while fetching data");
} else {
setState(() {
var data = json.decode(response.body);
rest = data['docs'];
for(var rest in rest)
{
list.add(Autogenerated.fromJson(rest));
}
filteredlist=rest;
});
return list;
}
}
getStringValuesSF() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
str_accesstoken = prefs.getString('accesstoken');
}
}
class Autogenerated {
List<Docs> docs;
Autogenerated({this.docs});
Autogenerated.fromJson(Map<String, dynamic> json) {
if (json['docs'] != null) {
docs = new List<Docs>();
json['docs'].forEach((v) {
docs.add(new Docs.fromJson(v));
});
}
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
if (this.docs != null) {
data['docs'] = this.docs.map((v) => v.toJson()).toList();
}
return data;
}
}
class Docs {
Student student;
Docs(
{
this.student,
});
Docs.fromJson(Map<String, dynamic> json) {
student =
json['student'] != null ? new Student.fromJson(json['student']) : null;
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
if (this.student != null) {
data['student'] = this.student.toJson();
}
return data;
}
}
class Student {
String name;
Student(
{
this.name,
});
Student.fromJson(Map<String, dynamic> json) {
name = json['name'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['name'] = this.name;
return data;
}
}
class CustomWidget extends StatefulWidget {
final int index;
final bool longPressEnabled;
final VoidCallback callback;
final List rest;
bool selected;
CustomWidget({Key key, this.selected, this.rest, this.index, this.longPressEnabled, this.callback}) : super(key: key);
#override
_CustomWidgetState createState() => new _CustomWidgetState();
}
class _CustomWidgetState extends State<CustomWidget> {
final skyblue=Color(0xffF1F5F9);
#override
Widget build(BuildContext context) {
return new GestureDetector(
onLongPress: () {
widget.callback();
},
onTap: () {
if (widget.longPressEnabled) {
widget.callback();
}
},
child:Container(
margin: new EdgeInsets.only(top:5.0),
color: widget.selected ? Colors.grey[300]:Colors.white,
child:Row(children: <Widget>[
Flexible(
fit:FlexFit.loose,
child: ListTile(
contentPadding: EdgeInsets.only(left: 0.0, right: 0.0),
title:
Container(
child:Column(children: <Widget>[
Row(
children: <Widget>[
Container(
child: Checkbox(
onChanged: (val) {
setState(() {
widget.selected = !widget.selected;
});
},
value: widget.selected,
),
),
Container(
child:Container(width:80,child:Text(widget.rest[widget.index]['student']['name'], style: TextStyle(color: Colors
.black, fontSize: 13),
)),
),
Spacer(),
Container(
child: Text(widget.rest[widget.index]['course']['level_no'], style: TextStyle(color: Colors
.black, fontSize: 13),)
),
Spacer(),
Container(
child: Text(
"", style: TextStyle(color: Colors.black,
fontSize: 13),)
),
Spacer(),
Container(
child: Text("", style: TextStyle(color: Colors
.black, fontSize: 13),)
),
],
),
Container(
color: darkblue,
height: 0.7,
width: double.infinity,
),
]),
// onLongPress: toggleSelection,
))
)],),
));
}
}
Add Search Bar
TextField(
controller: editingController,
decoration: InputDecoration(
labelText: "Search",
hintText: "Search",
prefixIcon: Icon(Icons.search),
border: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(25.0)))),
),
Code for UI showing a search bar and ListView with 1000 items
import 'package:flutter/material.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Flutter Demo',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: new MyHomePage(title: 'ListView with Search'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => new _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
TextEditingController editingController = TextEditingController();
final duplicateItems = List<String>.generate(10000, (i) => "Item $i");
var items = List<String>();
#override
void initState() {
items.addAll(duplicateItems);
super.initState();
}
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text(widget.title),
),
body: Container(
child: Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.all(8.0),
child: TextField(
onChanged: (value) {
},
controller: editingController,
decoration: InputDecoration(
labelText: "Search",
hintText: "Search",
prefixIcon: Icon(Icons.search),
border: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(25.0)))),
),
),
Expanded(
child: ListView.builder(
shrinkWrap: true,
itemCount: items.length,
itemBuilder: (context, index) {
return ListTile(
title: Text('${items[index]}'),
);
},
),
),
],
),
),
);
}
}