I'm using cubit to trigger action (sync to backend) to the current list tile, my problem is that when I trigger the sync, all unsynced tiles get synced, I want to trigger the action on the current tile only. here's the code for the list tile and where I'm using it. work_session_listing_page.dart:
BlocConsumer<WorkSessionListingCubit, WorkSessionListingState>(
listener: (context, state) {
state.whenOrNull(
deleted: () async {
print("SESSION DELETED");
await _animateAndReset();
},
error: (errorMessage) => showSnackBar(context, errorMessage),
);
},
builder: (context, state) {
return state.maybeMap(
orElse: () => _workSessionListingCubit.workSessions.isEmpty
? NoResultsWidget(
text: LocaleKeys.work_list_page_no_results.tr(),
description: LocaleKeys.you_can_create_work_sessions_from_the_home_screen.tr(),
)
: ListView.builder(
itemCount: _workSessionListingCubit.workSessions.length,
itemBuilder: (context, index) {
return SessionListTile(
animationController: _animationController,
session: _workSessionListingCubit.workSessions[index],
workSessionListingCubit: _workSessionListingCubit,
);
},
),
loading: (state) => const Center(
child: CircularProgressIndicator(),
),
);
},
),
session_list_tile.dart:
@override
Widget build(BuildContext context) {
final dateFormat = DateFormat.yMMMMEEEEd();
return BlocListener<ReportCubit, ReportState>(
listener: (context, state) {
state.whenOrNull(
loaded: (reportData) {
if (reportData.sessionPath == widget.session.path)
Navigator.pushNamed(context, WergoRouter.report, arguments: [widget.session, reportData]);
},
);
},
child: BlocListener<TnoReportCubit, TnoReportState>(
listener: (context, state) {
state.whenOrNull(
loaded: (report) {
EasyLoading.dismiss();
if (report.sessionId == widget.session.remoteSessionId)
Navigator.pushNamed(context, WergoRouter.tnoReport, arguments: [report, widget.session]);
},
loading: () {
// code
},
inProgress: (text) {
//more code
},
error: (errorMessage, sessionId) {
// more code
},
);
},
child: BlocProvider.value(
value: _sessionSyncCubit,
child: Container(
margin: EdgeInsets.symmetric(horizontal: 8.w, vertical: 4.h),
padding: EdgeInsets.all(10.sp),
height: 65.h,
decoration: BoxDecoration(
color: DevelColors.cardGray,
borderRadius: BorderRadius.circular(8.r),
),
child: Row(
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(
height: 10,
),
Text(
'${widget.session.firstName} ${widget.session.lastName}',
),
const Spacer(),
Text(
widget.session.workplace,
),
],
),
const Spacer(),
Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Row(
children: [
if (!widget.session.isSynced)
BlocConsumer<UserProfileCubit, UserProfileState>(
listener: (context, state) {
state.whenOrNull(
success: (profile) async =>
_sessionSyncCubit.syncSession(widget.session.copyWith(workerProfileId: profile.id)),
},
builder: (context, state) => state.maybeWhen(
loading: () => Text(
LocaleKeys.creating_worker.tr(),
style: DevelStyles.hintTextStyle12,
),
orElse: () => BlocConsumer<SessionSyncCubit, SessionSyncState>(
bloc: _sessionSyncCubit,
listener: (context, state) {
state.whenOrNull(
synced: () {
Future.delayed(
const Duration(seconds: 1),
() {
setState(() {
opacity = 0;
});
},
);
},
);
},
builder: (context, state) {
return state.maybeWhen(
syncStepUpdated: (step) => Text(
step.toString(),
style: DevelStyles.hintTextStyle12,
),
synced: () {
return AnimatedOpacity(
duration: const Duration(seconds: 1),
opacity: opacity,
child: const Icon(Icons.file_download_done, color: DevelColors.blueConnected),
);
},
orElse: () => GestureDetector(
onTap: () async {
if (context.read<InternetCubit>().hasInternet) {
if (widget.session.workerProfileId == null) {
final user = CreateProfileData.fromWorkSession(widget.session);
await _userProfileCubit.createUserProfile(
user: user,
orgId: _userCubit.user.organization!.id!,
userId: _userCubit.user.id,
);
} else {
_sessionSyncCubit.syncSession(widget.session);
}
} else {
if (mounted)
WergoDialog(
context,
mainButton: TextButton(
style: const ButtonStyle(
splashFactory: NoSplash.splashFactory,
overlayColor: MaterialStatePropertyAll(Colors.transparent),
),
onPressed: () {
Navigator.of(context).pop();
},
child: Text(
LocaleKeys.close.tr(),
style: DevelStyles.actionButtonStyle14.copyWith(
fontWeight: FontWeight.w600,
color: DevelColors.buttonBlue,
fontSize: 14.sp,
),
),
),
title: LocaleKeys.an_error_occured.tr(),
description: LocaleKeys.no_internet_connection.tr(),
header: Lottie.asset(
'assets/lotties/error_sad_face.json',
height: 30.h,
width: 30.h,
controller: _animationController,
onLoaded: (composition) async {
_animationController
..forward()
..repeat();
},
),
).show();
}
},
child: const Icon(
Icons.cloud_off_rounded,
color: DevelColors.hintTextColor,
),
),
);
},
),
),
),
PopupMenuButton(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8.r),
),
padding: EdgeInsets.zero,
onSelected: (value) async {
switch (value) {
case 'report':
context.read<ReportCubit>().getReportData(widget.session);
break;
case 'sync':
if (!widget.session.isSynced) {
final session = widget.session;
if (context.read<InternetCubit>().hasInternet) {
if (widget.session.workerProfileId == null) {
final user = CreateProfileData.fromWorkSession(widget.session);
await _userProfileCubit.createUserProfile(
user: user,
orgId: _userCubit.user.organization!.id!,
userId: _userCubit.user.id,
);
} else {
_sessionSyncCubit.syncSession(
session.copyWith(workerProfileId: widget.session.remoteSessionId));
}
}
}
break;
case 'tno':
if (!widget.session.isSynced) {
final session = widget.session;
if (context.read<InternetCubit>().hasInternet) {
if (widget.session.workerProfileId == null) {
final user = CreateProfileData.fromWorkSession(widget.session);
await _userProfileCubit.createUserProfile(
user: user,
orgId: _userCubit.user.organization!.id!,
userId: _userCubit.user.id,
);
} else {
_sessionSyncCubit.syncSession(
session.copyWith(workerProfileId: widget.session.remoteSessionId));
}
}
}
_tnoReportCubit.getTNOReport(widget.session.remoteSessionId!);
break;
case 'share':
showDialogExportOptionsMenu(
context,
saveToPhoneFunction: () async {
await locator<ExportWorSessionUseCase>()
.call(session: widget.session, exportLocally: true);
if (mounted) Navigator.of(context, rootNavigator: true).pop();
},
shareFunction: () async {
await locator<ExportWorSessionUseCase>().call(session: widget.session);
if (mounted) Navigator.of(context, rootNavigator: true).pop();
},
title: "${LocaleKeys.report_page_pop_up_menu_title.tr()} ZIP",
).show();
break;
case 'delete':
WergoDialog(
context,
mainButton: TextButton(
style: const ButtonStyle(
splashFactory: NoSplash.splashFactory,
overlayColor: MaterialStatePropertyAll(Colors.transparent),
),
onPressed: () async {
await _workSessionListingCubit.deleteSession(widget.session.path);
},
child: Text(
LocaleKeys.delete.tr(),
style: DevelStyles.actionButtonStyle14.copyWith(
fontWeight: FontWeight.w600,
color: DevelColors.redColor,
fontSize: 14.sp,
),
),
),
title: 'worksession is going to be deleted',
description:
"Are you sure to delete the selected work session and all it's data from local device. action can not be reverted",
header: Lottie.asset(
"assets/lotties/deletion.json",
controller: widget.animationController,
height: 40.h,
width: 40.h,
),
secondaryButton: TextButton(
style: const ButtonStyle(
splashFactory: NoSplash.splashFactory,
overlayColor: MaterialStatePropertyAll(Colors.transparent),
),
onPressed: () {
Navigator.pop(context);
},
child: Text(
LocaleKeys.login_cancel_button.tr(),
style: DevelStyles.actionButtonStyle14.copyWith(
fontWeight: FontWeight.w600, color: Colors.black45, fontSize: 14.sp),
),
),
).show();
break;
default:
break;
}
},
itemBuilder: (context) {
return [
const PopupMenuItem(
value: 'report',
child: Text(
"Report",
style: DevelStyles.popUpMenuItemStyle14,
),
),
PopupMenuItem(
value: 'sync',
child: Text(
"Sync Session",
style: !widget.session.isSynced
? DevelStyles.popUpMenuItemStyle14
: DevelStyles.popUpMenuItemStyle14.copyWith(color: Colors.black45),
),
),
const PopupMenuItem(
value: 'tno',
child: Text(
"Static & Dynamic analysis",
style: DevelStyles.popUpMenuItemStyle14,
),
),
const PopupMenuItem(
value: 'share',
child: Text(
"Share",
style: DevelStyles.popUpMenuItemStyle14,
),
),
PopupMenuItem(
value: 'delete',
child: Text(
LocaleKeys.delete.tr(),
style: DevelStyles.popUpDeleteMenuStyle14,
),
),
];
},
),
],
),
const Spacer(),
Text(
dateFormat.format(widget.session.startedAt),
style: const TextStyle(
color: DevelColors.grayTextColor,
fontSize: 13,
),
),
],
),
],
),
),
),
),
);
}
You can move the sync action to the
SessionListTile
widget. This way, each tile will have its sync action.First of all, remove the
BlocListener
fromReportCubit
andTnoReportCubit
, then add a new method inSessionListTile
to handle the sync action:Call this method in the
onTap
callback of theListTile
: