Flutter weird bug with widget function, sometimes in runs 2 times instead of one - flutter

This function have futureBuilder inside and returns another function that returns ListView.
Also I do not want the user to download information from the Internet every time they visit the page, so I put the information downloaded from the Internet into a static variable in class, so i make if else. If this static variable length != 0 , it return me listView instead of make server request with futureBuilder
function that works 2 times instead of one is ListView body
And also this bug created after i added purchases to my application, maybe something wrong there. I don't have any ideas why this happend
this is my complete code
class AddCheckList extends StatefulWidget {
const AddCheckList({Key? key}) : super(key: key);
#override
_AddCheckListState createState() => _AddCheckListState();
}
class _AddCheckListState extends State<AddCheckList> {
String xQueryReqestForCheckListNames = "element CheckListList {for \$a in PACK/OBJECT where (\$a/#inUse = 'True') order by \$a/#name return element CheckList {attribute name {\$a/#name}, attribute sPaid {\$a/#isPaid},attribute oid {\$a/#oid} }}";
String serverLink = "http...";
int addCheckListMethod = 0;
// if addCheckListMethod == 0, then data will download from server and checkLists will be added from server xml data
// if addCheckListMethod == 1, then data will download from assets, and checkLists will be added from assets xml data with getXmlData function
final InAppPurchase _inAppPurchase = InAppPurchase.instance;
final String _productID = '1d7ea644f690ffa';
bool _available = true;
List<ProductDetails> _products = [];
List<PurchaseDetails> _purchases = [];
StreamSubscription<List<PurchaseDetails>>? _subscription;
#override
void initState() {
final Stream<List<PurchaseDetails>> purchaseUpdated = _inAppPurchase.purchaseStream;
_subscription = purchaseUpdated.listen((purchaseDetailsList) {
setState(() {
_purchases.addAll(purchaseDetailsList);
_listenToPurchaseUpdated(purchaseDetailsList);
});
}, onDone: () {
_subscription!.cancel();
}, onError: (error) {
_subscription!.cancel();
});
_initialize();
super.initState();
}
#override
void dispose() {
_subscription!.cancel();
super.dispose();
}
void _initialize() async {
_available = await _inAppPurchase.isAvailable();
List<ProductDetails> products = await _getProducts(
productIds: Set<String>.from(
[_productID],
),
);
setState(() {
_products = products;
});
}
void _listenToPurchaseUpdated(List<PurchaseDetails> purchaseDetailsList) {
purchaseDetailsList.forEach((PurchaseDetails purchaseDetails) async {
switch (purchaseDetails.status) {
case PurchaseStatus.pending:
// _showPendingUI();
break;
case PurchaseStatus.purchased:
case PurchaseStatus.restored:
// bool valid = await _verifyPurchase(purchaseDetails);
// if (!valid) {
// _handleInvalidPurchase(purchaseDetails);
// }
break;
case PurchaseStatus.error:
print(purchaseDetails.error!);
// _handleError(purchaseDetails.error!);
break;
default:
break;
}
if (purchaseDetails.pendingCompletePurchase) {
await _inAppPurchase.completePurchase(purchaseDetails);
}
});
}
Future<List<ProductDetails>> _getProducts({required Set<String> productIds}) async {
ProductDetailsResponse response = await _inAppPurchase.queryProductDetails(productIds);
return response.productDetails;
}
void _subscribe({required ProductDetails product}) {
final PurchaseParam purchaseParam = PurchaseParam(productDetails: product);
_inAppPurchase.buyNonConsumable(
purchaseParam: purchaseParam,
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(padding: EdgeInsets.all(14.0), child: listViweBody(addCheckListMethod, serverLink, xQueryReqestForCheckListNames, _products,_subscribe)),
);
}
}
Widget listView(addCheckListMethod, serverLink, product,_subscribe) {
return ListView.separated(
itemCount: CheckListModel.checkListModelNamesFromServer.length,
itemBuilder: (BuildContext context, int index) {
if (CheckListModel.checkListModelNamesFromServer[index].ispaid == false) {
return InkWell(
onTap: () async {
CheckListModel checkList = CheckListModel('', 0, '', 0, 0, 0, '', [], '');
if (addCheckListMethod == 0) {
String xQueryReqestForCheckList = 'for \$a in PACK/OBJECT where \$a/#name="${CheckListModel.checkListModelNamesFromServer[index].name}" return \$a';
var data = await CheckListModel.getDataFromServer(xQueryReqestForCheckList, serverLink);
CheckListModel.addCheckListFromServer(checkList, data);
} else {
CheckListModel.addCheckList(index, checkList);
}
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text("Добавить описание"),
content: Container(
decoration: BoxDecoration(border: Border.all(color: Color.fromARGB(Desing.colorFromARGBBtn[0], Desing.colorFromARGBBtn[1], Desing.colorFromARGBBtn[2], Desing.colorFromARGBBtn[3]), width: 1), borderRadius: BorderRadius.circular(10)),
child: TextField(
decoration: new InputDecoration.collapsed(hintText: "Описание", border: InputBorder.none),
maxLines: null,
onChanged: (String value) async {
checkList.description = value;
},
),
),
actions: [
TextButton(
onPressed: () {
Navigator.pop(context);
},
child: Text("Отменить"),
),
TextButton(
onPressed: () async {
await checkList.writeToFile(checkList.toJson());
CheckListModel.checkLists.add(checkList);
Navigator.pushNamed(context, '/beforeMainCheckList', arguments: {'index': CheckListModel.checkLists.length - 1});
},
child: Text('Добавить'))
],
);
});
},
child: Container(
decoration: BoxDecoration(border: Border.all(color: Color.fromARGB(Desing.colorFromARGBBtn[0], Desing.colorFromARGBBtn[1], Desing.colorFromARGBBtn[2], Desing.colorFromARGBBtn[3]), width: 1), borderRadius: BorderRadius.circular(10)),
width: 50,
height: 80,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
"${CheckListModel.checkListModelNamesFromServer[index].name}",
style: TextStyle(fontSize: 30),
)
],
),
),
);
} else {
if (product.length != 0) {
return showPurchaseCheckLists(product, index,_subscribe);
} else {
return Center(
child: CircularProgressIndicator(),
);
}
}
},
separatorBuilder: (BuildContext context, int index) {
return Container(
height: 14,
);
});
}
Widget showPurchaseCheckLists(product, index,_subscribe) {
int getCurrentProduct() {
String? checkListModelid = CheckListModel.checkListModelNamesFromServer[index].checkListId?.toLowerCase();
int indexx = 0;
for (int i = 0; i < product.length; i++) {
if (checkListModelid == product[i].id) {
indexx = i;
}
}
return indexx;
}
return InkWell(
child: Container(
decoration: BoxDecoration(border: Border.all(color: Color.fromARGB(Desing.colorFromARGBBtn[0], Desing.colorFromARGBBtn[1], Desing.colorFromARGBBtn[2], Desing.colorFromARGBBtn[3]), width: 1), borderRadius: BorderRadius.circular(10), color: Color.fromARGB(255, 240, 240, 240)),
width: 50,
height: 80,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
"${CheckListModel.checkListModelNamesFromServer[index].name}",
style: TextStyle(fontSize: 25),
),
Text("Купить за ${product[getCurrentProduct()].price}")
],
),
),
onTap: () {
_subscribe(product: product[getCurrentProduct()]);
},
);
}
Widget listViweBody(addCheckListMethod, serverLink, xQueryReqestForCheckListNames, product,_subscribe) {
if (CheckListModel.checkListModelNamesFromServer.length == 0) {
return FutureBuilder(
future: CheckListModel.getDataFromServer(xQueryReqestForCheckListNames, serverLink),
builder: (context, data) {
if (data.connectionState == ConnectionState.done) {
return listView(addCheckListMethod, serverLink, product,_subscribe);
} else {
return Center(
child: CircularProgressIndicator(),
);
}
});
} else {
return listView(addCheckListMethod, serverLink, product,_subscribe);
}
}

Related

flutter - wait for camera access granted

I have a flutter app that opens the camera preview with a FutureBuilder. When the app opens for the first time, the app asks for permission. (This is triggered automatically). When I press ok I get a red screen:
I need to wait for the response, and why is dispose called?
I checked this: https://pub.dev/packages/permission_handler
and tested this:
if (await Permission.contacts.request().isGranted) {
// Either the permission was already granted before or the user just granted it.
}
But I got false and was never asked to approve anything. In contrast to the description.
Any ideas?
Here is the code:
import 'dart:io';
import 'package:camera/camera.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:name/Model/FileIO/file_io.dart';
import 'package:name/Views/main_view.dart';
import 'package:name/main.dart';
class CameraView extends StatefulWidget {
const CameraView({Key? key}) : super(key: key);
#override
State<CameraView> createState() {
return _CameraViewState();
}
}
class _CameraViewState extends State<CameraView> with WidgetsBindingObserver {
CameraController? controller;
late Future<void> _initializeController;
List<CameraDescription> rearCameras = List.empty(growable: true);
int _currentCameraIndex = 0;
#override
void initState() {
SystemChrome.setPreferredOrientations([
DeviceOrientation.landscapeRight,
DeviceOrientation.landscapeLeft,
DeviceOrientation.portraitUp
]);
_ambiguate(WidgetsBinding.instance)?.addObserver(this);
for (var description in cameras) {
if (description.lensDirection == CameraLensDirection.back) {
rearCameras.add(description);
}
}
onNewCameraSelected(rearCameras[_currentCameraIndex]);
super.initState();
}
#override
void dispose() {
_ambiguate(WidgetsBinding.instance)?.removeObserver(this);
SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);
super.dispose();
}
#override
void didChangeAppLifecycleState(AppLifecycleState state) {
final CameraController? cameraController = controller;
if (cameraController == null || cameraController.value.isInitialized) {
return;
}
if (state == AppLifecycleState.inactive) {
cameraController.dispose();
}
if (state == AppLifecycleState.resumed) {
onNewCameraSelected(rearCameras[_currentCameraIndex]);
}
}
Future<void> onNewCameraSelected(CameraDescription description) async {
if (controller != null) {
await controller!.dispose();
}
final CameraController cameraController = CameraController(
description,
ResolutionPreset.max,
enableAudio: false,
imageFormatGroup: ImageFormatGroup.jpeg,
);
controller = cameraController;
cameraController.addListener(() {
if (mounted) {
setState(() {});
}
if (cameraController.value.hasError) {
showInSnackbar(
"Camera error: ${cameraController.value.errorDescription}");
}
});
try {
_initializeController = cameraController.initialize();
} on CameraException catch (e) {
print('Error initializing camera: $e');
}
if (mounted) {
setState(() {});
}
}
Future<void> _onCameraSwitch() async {
if (controller == null) {
return;
}
_currentCameraIndex = (_currentCameraIndex + 1) % rearCameras.length;
final CameraDescription cameraDescription =
rearCameras[_currentCameraIndex];
onNewCameraSelected(cameraDescription);
}
void showInSnackbar(String message) {
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(content: Text(message)));
}
bool isRecording() {
return controller != null && controller!.value.isRecordingVideo;
}
Widget _cameraPreviewWidget(DeviceOrientation orientation) {
if (controller != null) {
final size = MediaQuery.of(context).size;
final deviceRatio = size.width / size.height;
controller!.lockCaptureOrientation(orientation);
return Center(
child: AspectRatio(
aspectRatio: deviceRatio,
child: CameraPreview(controller!),
),
);
}
return const Text("Camera not ready or available");
}
Widget _captureRowWidget() {
final CameraController? cameraController = controller;
return Container(
color: const Color.fromARGB(50, 255, 255, 255),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
IconButton(
icon: const Icon(Icons.videocam),
color: Colors.blue,
onPressed: cameraController != null &&
cameraController.value.isInitialized &&
!cameraController.value.isRecordingVideo
? onVideoRecordButtonPressed
: null,
),
IconButton(
onPressed: isRecording() ? onStopRecordingButtonPressed : null,
icon: const Icon(Icons.stop),
),
TextButton(
onPressed: _onCameraSwitch, child: const Text("Switch Camera"))
],
),
);
}
void onVideoRecordButtonPressed() {
startVideoRecording().then((_) => {
if (mounted) {setState(() {})}
});
}
void onStopRecordingButtonPressed() {
stopVideoRecording().then((video) async {
if (video != null) {
final path = await localPath;
final file = File('$path/video/${timestamp() + ".mp4"}');
await file.create(recursive: true);
video.saveTo(file.path);
}
});
}
Future<void> startVideoRecording() async {
final CameraController? cameraController = controller;
if (cameraController == null || !cameraController.value.isInitialized) {
showInSnackbar("Error: Camera unavailable");
return;
}
if (cameraController.value.isRecordingVideo) {
return;
}
try {
await cameraController.startVideoRecording();
} on CameraException catch (e) {
_showCameraException(e);
return;
}
}
Future<XFile?> stopVideoRecording() async {
final CameraController? cameraController = controller;
if (cameraController == null || !cameraController.value.isInitialized) {
return null;
}
try {
return cameraController.stopVideoRecording();
} on CameraException catch (e) {
_showCameraException(e);
return null;
}
}
OrientationBuilder getBody() {
return OrientationBuilder(
builder: (context, orientation) {
var deviceOrientation = DeviceOrientation.landscapeLeft;
if (orientation == Orientation.portrait) {
deviceOrientation = DeviceOrientation.portraitUp;
}
return Stack(
children: [
_cameraPreviewWidget(deviceOrientation),
Positioned(
bottom: 2,
left: 2,
right: 2,
child: _captureRowWidget(),
),
],
);
},
);
}
void _showCameraException(CameraException e) {
_logError(e.code, e.description);
showInSnackbar('Error: ${e.code}\n${e.description}');
}
void _navigateBack() {
Navigator.pushAndRemoveUntil(
context,
MaterialPageRoute(
builder: (context) {
return const MainView();
},
),
(Route<dynamic> route) => false,
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("Video Recorder"),
leading: GestureDetector(
onTap: () {
_navigateBack();
},
child: const Icon(
Icons.arrow_back, // add custom icons also
),
),
),
body: SafeArea(
child: FutureBuilder<void>(
future: _initializeController,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
return getBody();
} else {
return const Center(child: CircularProgressIndicator());
}
}),
),
);
}
T? _ambiguate<T>(T? value) => value;
void _logError(String code, String? message) {
if (message != null) {
print('Error: $code\nError Message: $message');
} else {
print('Error: $code');
}
}
String timestamp() {
return DateTime.now().microsecondsSinceEpoch.toString();
}
}
I do double check after grant permission, and if it still not granted it will show a dialog to open setting menu
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:camera/camera.dart';
import 'package:permission_handler/permission_handler.dart';
enum CaptureMode { IDENTITY, SELFIE }
class CameraCapture extends StatefulWidget {
Function onCaptured;
CaptureMode captureMode;
CameraCapture({required this.onCaptured, required this.captureMode});
#override
State<CameraCapture> createState() => _CameraCaptureState();
}
class _CameraCaptureState extends State<CameraCapture> {
List<CameraDescription>? cameras;
CameraController? cameraController;
bool isPopupPermissionShow = false;
_openSettingDialog(BuildContext context) => AlertDialog(
title: const Text("Camera permission not granted"),
content: SingleChildScrollView(
child: ListBody(
children: [
GestureDetector(
child: const Text("Open Setting"),
onTap: () async {
Navigator.pop(context, null);
cameraController?.dispose();
await openAppSettings();
setState(() {});
},
),
const Padding(padding: EdgeInsets.all(10)),
GestureDetector(
child: const Text("Cancel"),
onTap: () async {
Navigator.pop(context, null);
return;
},
),
],
),
),
);
checkPermission(BuildContext context) async {
try {
bool isCameraGranted = await Permission.camera.request().isGranted;
if (!isCameraGranted) {
if (!isPopupPermissionShow) {
isPopupPermissionShow = true;
await showDialog(
context: context,
builder: (BuildContext context) {
return _openSettingDialog(context);
});
}
isPopupPermissionShow = false;
}
} catch (e) {
debugPrint("camera error: " + e.toString());
}
}
Future<bool> setupCamera(BuildContext context) async {
if (cameras == null) {
cameras = await availableCameras();
}
if (cameraController == null || !(cameraController!.value.isInitialized)) {
if (cameras != null && cameras!.length > 0) {
cameraController = CameraController(
(widget.captureMode == CaptureMode.IDENTITY)
? cameras!.first
: cameras![1],
ResolutionPreset.medium);
try {
await cameraController?.initialize();
} catch (e) {
bool isCameraGranted = await Permission.camera.request().isGranted;
if (!isCameraGranted) {
checkPermission(context);
} else {
debugPrint("camera error " + (e.toString()));
}
}
} else {
bool isCameraGranted = await Permission.camera.request().isGranted;
if (!isCameraGranted) {
checkPermission(context);
} else {
debugPrint("camera not available");
}
}
}
return false;
}
#override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: null,
child: Scaffold(
backgroundColor: Colors.black,
resizeToAvoidBottomInset: false,
appBar: AppBar(
leading: IconButton(
icon: Icon(Icons.close, color: Colors.black),
onPressed: () {
cameraController?.dispose();
widget.onCaptured("cancel");
}),
),
body: Stack(
children: [
FutureBuilder(
future: setupCamera(context),
builder: (_, snapshot) {
return (snapshot.connectionState == ConnectionState.done)
? CameraPreview(
cameraController!,
)
: Container(
// child: LoadingProgress(),
width: double.infinity,
height: double.infinity,
color: Colors.black,
);
}),
Container(
width: double.infinity,
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
//put camera mask here
children: [
Container(
padding: EdgeInsets.only(
top: 16, left: 32, right: 32, bottom: 32),
child: _shutterButton(() async {
final image = await cameraController?.takePicture();
String imgPath = (image?.path ?? "");
cameraController?.dispose();
}),
),
],
),
),
],
),
),
);
}
_shutterButton(Function onShot) => Stack(
alignment: Alignment.center,
children: [
Container(
width: 60,
height: 60,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(40), color: Colors.white),
),
Container(
width: 50,
height: 50,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(40), color: Colors.black),
),
InkWell(
onTap: () {
onShot();
},
borderRadius: BorderRadius.circular(40),
child: Container(
width: 40,
height: 40,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(40), color: Colors.white),
),
),
],
);
}
I found the error, it was an incorrect if-statement.
#override
void didChangeAppLifecycleState(AppLifecycleState state) {
final CameraController? cameraController = controller;
if (cameraController == null || !cameraController.value.isInitialized) <-- the ! is missing in the OP {
return;
}
if (state == AppLifecycleState.inactive) {
cameraController.dispose();
}
if (state == AppLifecycleState.resumed) {
onNewCameraSelected(rearCameras[_currentCameraIndex]);
}
}

flutter lazyload loading page twice

so im trying to build a lazyload, from my backend i already made per page 5 items. but i dont understand why when i try in flutter the first page is always loaded twice?
for example if i scroll up to page 5, the order of the page will be 1,1,2,3,4 then when i try to refresh, it will show page 5, refresh again then it will show page 1, any idea why?
class ProgressScreen extends StatefulWidget {
#override
_ProgressScreenState createState() => _ProgressScreenState();
}
class _ProgressScreenState extends State<ProgressScreen> {
late MainProgressStore _mainProgressStore;
late UserStore _userStore;
int currentPage = 1;
late int totalPages;
#override
void initState() {
super.initState();
}
#override
void didChangeDependencies() {
super.didChangeDependencies();
// initializing stores
_mainProgressStore = Provider.of<MainProgressStore>(context);
_userStore = Provider.of<UserStore>(context);
if (!_userStore.loading) {
_userStore.getUser();
}
if (!_mainProgressStore.loading) {
_mainProgressStore.postMainProgress(
'loading', 'all', 'desc', 3, 0, currentPage);
}
}
List<Datum> mainProgress = [];
final RefreshController refreshController =
RefreshController(initialRefresh: true);
Future<bool> getmainProgress({bool isRefresh = false}) async {
if (isRefresh) {
currentPage = 1;
} else {
if (currentPage >= totalPages) {
refreshController.loadNoData();
return false;
}
}
final response = await _mainProgressStore.postMainProgress(
'loading', 'all', 'desc', 3, 0, currentPage);
if (_mainProgressStore.success == true) {
final result = _mainProgressStore.mainProgress!.mainProgress;
if (isRefresh) {
mainProgress = result.response;
} else {
mainProgress.addAll(result.response);
}
currentPage++;
totalPages = 10;
print(result.response);
setState(() {});
return true;
} else {
return false;
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppNavBar(),
drawer: DrawerNavBar(userStore: _userStore),
body: _buildMainContent(),
);
}
Widget _buildMainContent() {
return Observer(
builder: (context) {
return _mainProgressStore.success
? _buildRefresh(_mainProgressStore)
: CustomProgressIndicatorWidget();
},
);
}
Widget _buildRefresh(_mainProgressStore) {
return Platform.isIOS
? _buildIOSList(_mainProgressStore)
: _refreshView(_mainProgressStore);
}
Widget _refreshView(_mainProgressStore) {
return SmartRefresher(
controller: refreshController,
enablePullUp: true,
onRefresh: () async {
final result = await getmainProgress(isRefresh: true);
if (result) {
refreshController.refreshCompleted();
} else {
refreshController.refreshFailed();
}
},
onLoading: () async {
final result = await getmainProgress();
if (result) {
refreshController.loadComplete();
} else {
refreshController.loadFailed();
}
},
child: _buildBody(_mainProgressStore));
}
Widget _buildIOSList(_mainProgressStore) {
return Container(
child: CustomScrollView(
slivers: [
CupertinoSliverRefreshControl(
onRefresh: () async {
_mainProgressStore.getHomepage(currentPage);
},
),
SliverList(
delegate: SliverChildBuilderDelegate((context, index) {
return _buildBody(_mainProgressStore);
}, childCount: _mainProgressStore.response.length))
],
),
);
}
Widget _buildBody(_mainProgressStore) {
return SingleChildScrollView(
child: Column(children: <Widget>[
Align(
alignment: Alignment.centerLeft,
child: Container(
padding: EdgeInsets.only(
top: DeviceUtils.getScaledHeight(context, 0.03),
left: DeviceUtils.getScaledWidth(context, 0.06),
bottom: DeviceUtils.getScaledHeight(context, 0.03)),
child: Text(
'MY ORDERS',
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: DeviceUtils.getScaledWidth(context, 0.035),
color: Colors.black),
),
),
),
SearchProgress(
currentPage: currentPage, mainProgressStore: _mainProgressStore),
OrderInfo(
progressData: mainProgress, mainProgressStore: _mainProgressStore),
]));
}
}

type '_Type' is not a subtype of type 'String'

So i am a beginner in flutter and am trying to learn via tutorials, so here I am trying to make todo app using sqflite and everything is perfect and no error is shown in the editor but on clicking floating action button in notelist file it shows this error-
The following _TypeError was thrown building Builder:
type '_Type' is not a subtype of type 'String'
heres my main.dart file
void main() {
runApp(MaterialApp(
home: NoteList(),
));
}
here notelist
class NoteList extends StatefulWidget {
const NoteList({Key? key}) : super(key: key);
#override
_NoteListState createState() => _NoteListState();
}
class _NoteListState extends State<NoteList> {
int count = 0;
DatabaseHelper databaseHelper = DatabaseHelper();
late List<Note> noteList;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Note List'),
),
body: getNoteListView(),
floatingActionButton: FloatingActionButton(
onPressed: () {
debugPrint('fab clicked');
navigateToDetail(Note('', '', 2 ,''),'Add Note');
},
child: Icon(Icons.add),
),
);
}
ListView getNoteListView(){
return ListView.builder(
itemCount: count,
itemBuilder: (context, index){
return Card(
color: Colors.white,
elevation: 2.0,
child: ListTile(
leading: CircleAvatar(
backgroundColor: getPriorityColor(this.noteList[index].priority),
child: getPriorityIcon(this.noteList[index].priority),
),
title: Text(this.noteList[index].title!,),
subtitle: Text(this.noteList[index].date!),
trailing: IconButton(onPressed: (){
_delete(context, noteList[index]);
},
icon: Icon(Icons.delete),
),
onTap: (){
debugPrint('tapped');
navigateToDetail(noteList[index],'Edit Note');
},
),
);
}
);
}
void navigateToDetail(Note note, String title) async{
bool result = await Navigator.push(context, MaterialPageRoute(builder: (context) {
return NoteDetail(appBarTitle: Title, note: note);
}));
if (result == true) {
updateListView();
}
}
// Returns the priority color
Color getPriorityColor(int? priority) {
switch (priority) {
case 1:
return Colors.red;
break;
case 2:
return Colors.yellow;
break;
default:
return Colors.yellow;
}
}
// Returns the priority icon
Icon getPriorityIcon(int? priority) {
switch (priority) {
case 1:
return Icon(Icons.play_arrow);
break;
case 2:
return Icon(Icons.keyboard_arrow_right);
break;
default:
return Icon(Icons.keyboard_arrow_right);
}
}
void _delete(BuildContext context, Note note) async {
int? result = await databaseHelper.deleteNote(note.id);
if (result != 0) {
_showSnackBar(context, 'Note Deleted Successfully');
updateListView();
}
}
void _showSnackBar(BuildContext context, String message) {
final snackBar = SnackBar(content: Text(message));
Scaffold.of(context).showSnackBar(snackBar);
}
void updateListView() {
final Future<Database> dbFuture = databaseHelper.initializeDatabase();
dbFuture.then((database) {
Future<List<Note>> noteListFuture = databaseHelper.getNoteList();
noteListFuture.then((noteList) {
setState(() {
this.noteList = noteList;
this.count = noteList.length;
});
});
});
}
}
and heres notedetail file
class NoteDetail extends StatefulWidget {
final Note note;
final appBarTitle;
NoteDetail( {Key? key,required this.appBarTitle, required this.note}) : super(key: key);
#override
_NoteDetailState createState() => _NoteDetailState(this.note, this.appBarTitle);
}
class _NoteDetailState extends State<NoteDetail> {
static var _priorities = ['High', 'Low'];
DatabaseHelper helper = DatabaseHelper();
TextEditingController titleController = TextEditingController();
TextEditingController descController = TextEditingController();
String appBarTitle;
Note note;
_NoteDetailState(this.note , this.appBarTitle);
#override
Widget build(BuildContext context) {
titleController.text = note.title!;
descController.text = note.description!;
return Scaffold(
appBar: AppBar(
title: Text(appBarTitle),
),
body: Container(
padding: EdgeInsets.all(10),
child: ListView(
children: [
ListTile(
title: DropdownButton(
items: _priorities.map((dropDownStringItem) {
return DropdownMenuItem (
value: dropDownStringItem,
child: Text(dropDownStringItem),
);
}).toList(),
value: getPriorityAsString(note.priority),
onChanged: (valueSelectedByUser) {
setState(() {
debugPrint('User selected $valueSelectedByUser');
updatePriorityAsInt(valueSelectedByUser);
});
}
),
),
SizedBox(height: 10,),
Container(
child: TextField(
controller: titleController,
onChanged: (value) {
debugPrint('something changed in the title textfield ');
updateTitle();
},
decoration: InputDecoration(
labelText: 'Title',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(5.0),
)
),
),
),
SizedBox(height: 10,),
Container(
child: TextField(
controller: descController,
onChanged: (value) {
debugPrint('something changed in the description textfield ');
updateDescription();
},
decoration: InputDecoration(
labelText: 'Description',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(5.0),
)
),
),
),
Container(
padding: EdgeInsets.all(10),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
width: 120,
height: 50,
padding: EdgeInsets.all(5),
child: ElevatedButton(onPressed: (){
debugPrint('add button clicked');
_save();
}, child: Text('Save',
style: TextStyle(
fontSize: 18
),
)
),
),
Container(
width: 120,
height: 50,
padding: EdgeInsets.all(5),
child: ElevatedButton(onPressed: (){
_delete();
debugPrint('Delete button clicked');
}, child: Text('Delete',
style: TextStyle(
fontSize: 18
),)),
),
],
),
)
],
),
),
);
}
// Convert int priority to String priority and display it to user in DropDown
String getPriorityAsString(int? value) {
String priority = '';
switch (value) {
case 1:
priority = _priorities[0]; // 'High'
break;
case 2:
priority = _priorities[1]; // 'Low'
break;
}
return priority;
}
// Convert the String priority in the form of integer before saving it to Database
void updatePriorityAsInt(var value) {
switch (value) {
case 'High':
note.priority = 1;
break;
case 'Low':
note.priority = 2;
break;
}
}
// Update the title of Note object
void updateTitle(){
note.title = titleController.text;
}
// Update the description of Note object
void updateDescription() {
note.description = descController.text;
}
void _delete() async {
moveToLastScreen();
// Case 1: If user is trying to delete the NEW NOTE i.e. he has come to
// the detail page by pressing the FAB of NoteList page.
if (note.id == null) {
_showAlertDialog('Status', 'No Note was deleted');
return;
}
// Case 2: User is trying to delete the old note that already has a valid ID.
int? result = await helper.deleteNote(note.id);
if (result != 0) {
_showAlertDialog('Status', 'Note Deleted Successfully');
} else {
_showAlertDialog('Status', 'Error Occured while Deleting Note');
}
}
void moveToLastScreen() {
Navigator.pop(context, true);
}
void _showAlertDialog(String title, String message) {
AlertDialog alertDialog = AlertDialog(
title: Text(title),
content: Text(message),
);
showDialog(
context: context,
builder: (_) => alertDialog
);
}
// Save data to database
void _save() async {
moveToLastScreen();
note.date = DateFormat.yMMMd().format(DateTime.now());
int? result;
if (note.id != null) { // Case 1: Update operation
result = await helper.updateNote(note);
} else { // Case 2: Insert Operation
result = await helper.insertNote(note);
}
if (result != 0) { // Success
_showAlertDialog('Status', 'Note Saved Successfully');
} else { // Failure
_showAlertDialog('Status', 'Problem Saving Note');
}
}
}
This looks like a spelling mistake.
void navigateToDetail(Note note, String title) async{
...
// change Title into title
return NoteDetail(appBarTitle: title, note: note);
...

ImagePicker with Bloc - Flutter

How to add a stream with a picture(ImagePicker) in the bloc architecture, which can be selected from the phone, what should the widget look like?
My example is without validation whether it is to be included?
How should I work in a bloc along with the avatar photo?
I do not know how to approach it and what steps would be taken when it comes to both validation of such a photo, if possible, and the use of stream with bloc, any help is very welcome.
class ProfileView extends StatefulWidget {
const ProfileView({Key? key}) : super(key: key);
#override
_ProfileViewState createState() => _ProfileViewState();
static Route route() {
return MaterialPageRoute<void>(builder: (_) => ProfileView());
}
}
class _ProfileViewState extends State<ProfileView> {
final bloc = Bloc();
#override
Widget build(BuildContext context) {
return Scaffold(
body: _profilePage(context),
);
}
Widget _profilePage(BuildContext context) {
return ColorfulSafeArea(
color: orange,
child: Center(
child: Column(
children: [
_changeAvatarButton(context),
SizedBox(height: 15),
_usernameTile(),
SizedBox(height: 5),
_cityTile(),
SizedBox(height: 60),
],
),
),
);
// });
}
// Profile avatar
Widget _avatar() {
return CircleAvatar(
radius: 83,
backgroundColor: orange,
child: CircleAvatar(
backgroundColor: Colors.white,
radius: 80,
child: Icon(personIcon, size: 60, color: orange),
),
);
}
Widget _changeAvatarButton(BuildContext context) {
return Column(
children: [
CircleAvatar(
radius: 83,
backgroundColor: orange,
child: _image == null
? _avatar()
: ClipRRect(
borderRadius: BorderRadius.circular(83),
child: Image.file(
_image!,
height: 160,
// Change the size up or down accordingly border radius
width: 160,
// Change the size up or down accordingly border radius
fit: BoxFit.cover,
)),
),
CustomButtonText(
onPressed: () {
_showPicker(context);
},
title: changePhoto,
textColor: teal),
],
);
}
File? _image;
final picker = ImagePicker();
Future getImage() async {
final pickedFile = await picker.getImage(
source: ImageSource.gallery, maxWidth: 1800, maxHeight: 1800);
setState(() {
if (pickedFile != null) {
_image = File(pickedFile.path);
} else {
print(getImageText);
}
});
}
Future getCameraImage() async {
final pickedFile = await picker.getImage(
source: ImageSource.camera,
maxWidth: 1800,
maxHeight: 1800,
);
setState(() {
if (pickedFile != null) {
_image = File(pickedFile.path);
} else {
print(getImageText);
}
});
}
void _showPicker(BuildContext context) {
showModalBottomSheet<void>(
context: context,
builder: (BuildContext bc) {
return SafeArea(
child: Container(
child: Wrap(
children: <Widget>[
ListTile(
leading: Icon(photoIcon),
title: Text(showPickerPhoto),
onTap: () async {
await getImage();
Navigator.of(context).pop();
}),
ListTile(
leading: Icon(cameraIcon),
title: Text(showPickerCamera),
onTap: () async {
await getCameraImage();
Navigator.of(context).pop();
},
),
],
),
),
);
});
}
Widget _usernameTile() {
return StreamBuilder(
stream: bloc.name,
builder: (context, snapshot) {
return CustomTextField(
title: 'Name',
obscureText: false,
colour: Colors.black,
keyboardType: TextInputType.name,
labelText: labelTextUsername,
onChanged: bloc.changeName,
errorText: snapshot.error != null ? 'invalid name' : null
// onChanged: (newValue) {
// bloc.changeName(newValue);
// },
);
});
}
Widget _cityTile() {
return StreamBuilder(
stream: bloc.city,
builder: (context, snapshot) {
return CustomTextField(
title: 'City',
obscureText: false,
colour: Colors.black,
keyboardType: TextInputType.name,
labelText: labelTextCity,
onChanged: bloc.changeCity,
errorText: snapshot.error != null ? 'invalid city' : null
);
});}
}
Validators looks in this way:
class Validators {
static final RegExp _nameRegExp = RegExp(
r'^(?=.*[a-z])[A-Za-z ]{3,}$',
);
final validateName =
StreamTransformer<String, String>.fromHandlers(handleData: (name, sink) {
if (name.contains(_nameRegExp)) {
sink.add(name);
} else {
sink.addError('Enter a valid name');
}
});
static final RegExp _cityRegExp = RegExp(
r'^[a-zA-Z]+(?:[\s-][a-zA-Z]+)*$',
);
final validateCity =
StreamTransformer<String, String>.fromHandlers(handleData: (city, sink) {
if (city.contains(_cityRegExp)) {
sink.add(city);
} else {
sink.addError('Enter a valid city');
}
});
static final RegExp _avatarRegExp = RegExp(
r'/.*\.(gif|jpe?g|bmp|png)$/igm',
);
final validateAvatar =
StreamTransformer<String, String>.fromHandlers(handleData: (avatar, sink) {
if (avatar.contains(_avatarRegExp)) {
sink.add(avatar);
} else {
sink.addError('Enter a valid avatar photo');
}
});
}
and Bloc:
import 'dart:async';
import 'dart:io';
import 'validators.dart';
class Bloc extends Validators {
//instances
//
final _avatarPath = StreamController<File>();
final _name = StreamController<String>();
final _city = StreamController<String>();
//add data stream
Stream<File> get avatarPath => _avatarPath.stream;
Stream<String> get name => _name.stream.transform(validateName);
Stream<String> get city => _city.stream.transform(validateCity);
// change data
Function(File) get changeAvatarPath => _avatarPath.sink.add;
Function(String) get changeName => _name.sink.add;
Function(String) get changeCity => _city.sink.add;
//for cleanup
void dispose() {
_avatarPath.close();
_name.close();
_city.close();
}
}
// bloc.changeName---> bloc.nameController.sin.add
final bloc = new Bloc();

how to refresh state on Navigator.Pop or Push in flutter

Here I have two pages first is called BSP_signup_terms page and the second is Bsp_Service_page. when I am on BSP_signup_terms on that page I have to select some checkbox based on the selected checkbox it will show me some data. but problem is that it will show me the complete data but when I get back to the BSP_signup_terms from Bsp_signup_page and I am changing the checkbox and then again when I am pressing next button it will not change the result it same as the previous result.
Here is the Image of Output Page
In this image I've attached both screen output when I am selecting only one checkbox it will render some value in service page and when I am back to the Terms and Condition page and select one more checkbox then it will not updating service page
Here is the code I've tried.
BSP_Signup_Terms_Page
class BspLicensedSignupTermsPage extends StatefulWidget {
static const String routeName = "/bspLicensedSignupTerms";
final BspSignupCommonModel bspSignupCommonModel;
BspLicensedSignupTermsPage({
Key key,
#required this.bspSignupCommonModel,
}) : super(key: key);
#override
_BspLicensedSignupTermsPageState createState() =>
_BspLicensedSignupTermsPageState();
}
class _BspLicensedSignupTermsPageState
extends State<BspLicensedSignupTermsPage> {
#override
void initState() {
super.initState();
}
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
bool _isWalkIn = false;
bool _isHome = false;
bool _isOnDemand = false;
Widget _buildselectcheckbox() {
return Text(
AppConstantsValue.appConst['bsplicensedsignupterms']['selectcheck']
['translation'],
);
}
// Walkin
_onCustomerWalkin(value) {
setState(() {
_isWalkIn = value;
});
}
Widget _buildCustomerWalkIn() {
return TudoConditionWidget(
text: AppConstantsValue.appConst['bsplicensedsignupterms']
['CustomerWalkIn']['translation'],
onChanged: (value) {
print(value);
_onCustomerWalkin(value);
},
validate: false,
);
}
// Home
_onCustomerInHome(value) {
setState(() {
_isHome = value;
});
}
Widget _buildCustomerInHome() {
return TudoConditionWidget(
text: AppConstantsValue.appConst['bsplicensedsignupterms']
['CustomerInHome']['translation'],
onChanged: (value) {
_onCustomerInHome(value);
},
validate: false,
);
}
Widget _buildCustomerInHomeHelp() {
return Text(
AppConstantsValue.appConst['bsplicensedsignupterms']['businesscheckhelp']
['translation'],
);
}
// On Demand
_onCustomerOnDemand(value) {
setState(() {
_isOnDemand = value;
});
}
Widget _buildBusinessOnDemand() {
return TudoConditionWidget(
text: AppConstantsValue.appConst['bsplicensedsignupterms']
['BusinessOnDemand']['translation'],
onChanged: (value) {
_onCustomerOnDemand(value);
},
validate: false,
);
}
Widget _buildBusinessOnDemandHelp() {
return Text(AppConstantsValue.appConst['bsplicensedsignupterms']
['businessprovidehelp']['translation']);
}
#override
Widget build(BuildContext context) {
final appBar = AppBar(
title: Text("Bsp Licensed Signup Terms and Condition"),
leading: IconButton(
icon: Icon(Icons.arrow_back_ios),
onPressed: () {
NavigationHelper.navigatetoBack(context);
},
),
centerTitle: true,
);
final bottomNavigationBar = Container(
height: 56,
//margin: EdgeInsets.symmetric(vertical: 24, horizontal: 12),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
new FlatButton.icon(
icon: Icon(Icons.close),
label: Text('Clear'),
color: Colors.redAccent,
textColor: Colors.black,
padding: EdgeInsets.symmetric(vertical: 10, horizontal: 30),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(7),
),
onPressed: () {
_formKey.currentState.reset();
},
),
new FlatButton.icon(
icon: Icon(FontAwesomeIcons.arrowCircleRight),
label: Text('Next'),
color: colorStyles["primary"],
textColor: Colors.white,
padding: EdgeInsets.symmetric(vertical: 10, horizontal: 30),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(7),
),
onPressed: () {
if (_formKey.currentState.validate()) {
if (_isHome == false &&
_isOnDemand == false &&
_isWalkIn == false) {
showDialog(
barrierDismissible: false,
context: context,
builder: (context) => ShowErrorDialog(
title: Text('Select Service'),
content: Text(
'Please select atleast one service type to proceed next',
),
));
} else {
BspSignupCommonModel model = widget.bspSignupCommonModel;
model.isWalkin = _isWalkIn;
model.isHome = _isHome;
model.isOnDemand = _isOnDemand;
print(model.toJson());
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
BspServicePage(bspSignupCommonModel: model),
),
);
}
}
},
),
],
),
);
return new Scaffold(
appBar: appBar,
bottomNavigationBar: bottomNavigationBar,
body: Container(
height: double.infinity,
width: double.infinity,
child: Stack(
children: <Widget>[
SingleChildScrollView(
child: SafeArea(
child: Form(
autovalidate: true,
key: _formKey,
child: Scrollbar(
child: SingleChildScrollView(
dragStartBehavior: DragStartBehavior.down,
padding: const EdgeInsets.symmetric(horizontal: 10.0),
child: new Container(
decoration: BoxDecoration(
borderRadius: new BorderRadius.circular(25)),
child: new Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
_buildselectcheckbox(),
_buildCustomerWalkIn(),
_buildCustomerInHome(),
_buildCustomerInHomeHelp(),
_buildBusinessOnDemand(),
_buildBusinessOnDemandHelp(),
],
),
),
),
),
),
),
),
],
),
),
);
}
}
BSP_Service_Page
class BspServicePage extends StatefulWidget {
static const String routeName = "/bspService";
final BspSignupCommonModel bspSignupCommonModel;
BspServicePage({
Key key,
#required this.bspSignupCommonModel,
}) : super(key: key);
#override
_BspServicePageState createState() => _BspServicePageState();
}
class _BspServicePageState extends State<BspServicePage> {
List<int> servicesIds = [];
Map<String, bool> selection = {};
List<BspServices.Service> selectedServices = [];
SearchBarController _controller = new SearchBarController();
String _searchText = '';
bool refreshservices = true;
#override
void initState() {
super.initState();
}
void _showErrorDialog(String message) {
showDialog(
barrierDismissible: false,
context: context,
builder: (context) => ShowErrorDialog(
title: Text('An Error Occurred!'),
content: Text(message),
),
);
}
void refresh() {
setState(() {
refreshservices = !refreshservices;
});
}
#override
Widget build(BuildContext context) {
var _bspServiceBloc = new BspServiceBloc();
final appBar = SearchBar(
controller: _controller,
onQueryChanged: (String query) {
print('Search Query $query');
setState(() {
_searchText = query;
});
},
defaultBar: AppBar(
centerTitle: true,
leading: IconButton(
icon: Icon(Icons.arrow_back_ios),
onPressed: () {
refresh();
NavigationHelper.navigatetoBack(context);
}),
title: Text('Select Services'),
),
);
final bottomNavigationBar = Container(
height: 56,
// margin: EdgeInsets.symmetric(vertical: 24, horizontal: 12),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
new FlatButton.icon(
icon: Icon(Icons.close),
label: Text('Clear'),
color: Colors.redAccent,
textColor: Colors.black,
padding: EdgeInsets.symmetric(vertical: 10, horizontal: 30),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(7),
),
onPressed: () {
print('reseting the state');
setState(() {
selection = {};
servicesIds = [];
});
},
),
new FlatButton.icon(
icon: Icon(FontAwesomeIcons.arrowCircleRight),
label: Text('Next'),
color: colorStyles["primary"],
textColor: Colors.white,
padding: EdgeInsets.symmetric(vertical: 10, horizontal: 30),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(7),
),
onPressed: () {
BspSignupCommonModel model = widget.bspSignupCommonModel;
model.servicesIds = servicesIds;
model.services = selectedServices;
print('servicesIds at the next button');
print(servicesIds);
print(model.toJson());
if (servicesIds.length == 0) {
_showErrorDialog(
'You need to select at least one service to proceed next!');
} else {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => BusinessProfilePage(
bspSignupCommonModel: model,
),
),
);
}
},
),
],
),
);
return new Scaffold(
appBar: appBar,
bottomNavigationBar: bottomNavigationBar,
body: new BspServiceScreen(
bspServiceBloc: _bspServiceBloc,
bspSignupCommonModel: widget.bspSignupCommonModel,
servicesIds: servicesIds,
selection: selection,
searchQuery: _searchText,
selectedServices: selectedServices,
refresh: refresh,
),
);
}
}
Bsp_service_screen
class BspServiceScreen extends StatefulWidget {
final BspServiceBloc _bspServiceBloc;
final String searchQuery;
final List<int> servicesIds;
final Map<String, bool> selection;
final BspSignupCommonModel bspSignupCommonModel;
final List<BspServices.Service> selectedServices;
final Function refresh;
const BspServiceScreen({
Key key,
#required BspServiceBloc bspServiceBloc,
#required this.bspSignupCommonModel,
#required this.servicesIds,
#required this.selection,
#required this.selectedServices,
#required this.refresh,
this.searchQuery,
}) : _bspServiceBloc = bspServiceBloc,
super(key: key);
#override
BspServiceScreenState createState() {
return new BspServiceScreenState(_bspServiceBloc);
}
}
class BspServiceScreenState extends State<BspServiceScreen> {
final BspServiceBloc _bspServiceBloc;
BspServiceScreenState(this._bspServiceBloc);
// Map<String, bool> _selection = {};
#override
void initState() {
super.initState();
bool isHome = widget.bspSignupCommonModel.isHome;
bool isWalkIn = widget.bspSignupCommonModel.isWalkin;
bool isOnDemand = widget.bspSignupCommonModel.isOnDemand;
this._bspServiceBloc.dispatch(LoadBspServiceEvent(
countryId: 1,
isHome: isHome,
isOnDemand: isOnDemand,
isWalkin: isWalkIn,
));
}
#override
void dispose() {
super.dispose();
}
#override
Widget build(BuildContext context) {
return BlocBuilder<BspServiceBloc, BspServiceState>(
bloc: widget._bspServiceBloc,
builder: (
BuildContext context,
BspServiceState currentState,
) {
if (currentState is UnBspServiceState) {
return Center(child: CircularProgressIndicator());
}
if (currentState is ErrorBspServiceState) {
return new Container(
child: new Center(
child: new Text(currentState.errorMessage ?? 'Error'),
),
);
}
if (currentState is InBspServiceState) {
// print(
// 'in bsp service state, ${currentState.bspServices.servicesByCountry.length}');
if (currentState.bspServices.servicesByCountry.length == 0) {
return Container(
child: Center(
child: Text("No Services available for this combination"),
),
);
} else {
return new Container(
child:
_renderServices(currentState.bspServices.servicesByCountry),
);
}
}
return Container();
},
);
}
List<ServicesByCountry> finalList = new List();
ListView _renderServices(List<ServicesByCountry> lovCountryServices) {
WidgetsBinding.instance.addPostFrameCallback((_) {
if (widget.searchQuery != '') {
finalList.clear();
lovCountryServices.forEach((ServicesByCountry data) {
if (data.name
.toLowerCase()
.contains(widget.searchQuery.toLowerCase())) {
setState(() {
finalList.add(data);
});
} else {
data.services.forEach((ServiceList.Service services) {
if (services.name
.toLowerCase()
.contains(widget.searchQuery.toLowerCase())) {
setState(() {
finalList.add(data);
});
}
});
}
});
} else {
setState(() {
finalList.clear();
finalList.addAll(lovCountryServices);
});
}
});
return ListView.builder(
shrinkWrap: true,
padding: const EdgeInsets.all(8.0),
itemCount: finalList.length,
itemBuilder: (BuildContext context, int index) {
ServicesByCountry item = finalList[index];
List itemsList = item.services;
return ExpansionTile(
title: Text(item.name),
children: List.generate(itemsList.length, (i) {
widget.selection[itemsList[i].name] =
widget.selection[itemsList[i].name] ?? itemsList[i].isSelected;
return CheckboxListTile(
title: Text(itemsList[i].name),
value: widget.selection[itemsList[i].name],
onChanged: (val) {
setState(() {
widget.selection[itemsList[i].name] = val;
if (val) {
widget.servicesIds.add(itemsList[i].id);
List<BspServices.Service> services =
widget.selectedServices.where((service) {
return service.mainCategory == item.name;
}).toList();
SubCategory subService = new SubCategory(
id: itemsList[i].id,
name: itemsList[i].name,
);
List<SubCategory> subCategories = [];
if (services.length == 0) {
subCategories.add(subService);
widget.selectedServices.add(
new BspServices.Service(
mainCategory: item.name,
mainCategoryId: item.id,
subCategory: subCategories,
),
);
} else {
print('services in else');
print(services[0].subCategory);
subCategories = services[0].subCategory;
subCategories.add(subService);
}
} else {
widget.servicesIds.removeWhere((service) {
return service == itemsList[i].id;
});
List<BspServices.Service> services =
widget.selectedServices.where((service) {
return service.mainCategory == item.name;
}).toList();
services[0].subCategory.removeWhere((subService) {
return subService.id == itemsList[i].id;
});
}
});
print('widget.servicesIds after set state');
print(widget.servicesIds);
},
);
}),
);
},
);
}
}
You can use setState() after return to the first page:
Navigator.push(context, MaterialPageRoute(builder: (context) => Page2())).then((value) {
setState(() {
// refresh state
});
});
Please try below code:-
First you add one method async method:-
void redirectToNextScreen() async {
final Route route = MaterialPageRoute(
builder: (context) => BspServicePage(bspSignupCommonModel: model));
final result = await Navigator.push(mContext, route);
try {
if (result != null) {
if (result) {
//Return callback here.
}
}
} catch (e) {
print(e.toString());
}
}
Then Next you can call this method in "BSP_Signup_Terms_Page" on Next button Pressed event.
Second you can add below line in "BspServicePage" screen Next and Cancel Events.
Navigator.pop(mContext, true); //true means refresh back page and false means not refresh.