dismissById static method
Dismisses a specific modal by its ID (PRIMARY DISMISSAL METHOD)
This is the recommended way to dismiss modals. It searches through all modals (dialogs, bottom sheets, and queued snackbars) for a matching ID and dismisses only that specific modal, leaving all other modals untouched.
The method uses the appropriate type-specific dismissal logic internally, ensuring proper cleanup and preservation of other active modals.
Parameters:
id: The ID of the modal to dismiss (as specified inModal.show()orModal.showSnackbar())onDismissed: Optional callback executed after the modal is dismissed
Returns true if a modal with the given ID was found and dismissed,
false if no modal with that ID was found.
Example:
// Show a bottom sheet with an ID
Modal.show(
id: 'settings_sheet',
type: ModalType.bottomSheet,
child: SettingsSheet(),
);
// Later, dismiss it by ID
await Modal.dismissById('settings_sheet');
// Works with snackbars too
Modal.showSnackbar(text: 'Message', id: 'my_snack');
await Modal.dismissById('my_snack');
Implementation
static Future<bool> dismissById(String id,
{VoidCallback? onDismissed}) async {
if (_showDebugPrints) {
debugPrint('Modal.dismissById called: id=$id');
}
// Check if this ID matches the active dialog
if (Modal.isDialogActive && _dialogController.state != null) {
final dialog = _dialogController.state!;
if (dialog.id == id || dialog.uniqueId == id) {
if (_showDebugPrints) {
debugPrint(
'Modal.dismissById: found dialog with ID=$id. Dismissing...');
}
await dismissDialog(onDismissed: onDismissed);
return true;
}
}
// Check if this ID matches the active sheet
if (Modal.isSheetActive && _sheetController.state != null) {
final sheet = _sheetController.state!;
if (sheet.id == id || sheet.uniqueId == id) {
if (_showDebugPrints) {
debugPrint(
'Modal.dismissById: found bottom sheet with ID=$id. Dismissing...');
}
await dismissBottomSheet(onDismissed: onDismissed);
return true;
}
}
// Check if this ID matches the active side sheet
if (Modal.isSideSheetActive && _sideSheetController.state != null) {
final sheet = _sideSheetController.state!;
if (sheet.id == id || sheet.uniqueId == id) {
if (_showDebugPrints) {
debugPrint(
'Modal.dismissById: found side sheet with ID=$id. Dismissing...');
}
await dismissSideSheet(onDismissed: onDismissed);
return true;
}
}
// Search for and remove from snackbar queue
final currentQueueMap = _snackbarQueueNotifier.state;
bool found = false;
for (final position in currentQueueMap.keys.toList()) {
if (found) break;
final queueAtPosition = currentQueueMap[position]!;
// Search using both id and uniqueId for flexibility
final matchIndex = queueAtPosition.indexWhere(
(content) => content.id == id || content.uniqueId == id,
);
if (matchIndex >= 0) {
found = true;
final snackbar = queueAtPosition[matchIndex];
if (_showDebugPrints) {
debugPrint(
'Modal.dismissById: found snackbar with ID=$id (uniqueId=${snackbar.uniqueId}) at position=$position. Removing...');
}
// Check if this is the currently active snackbar
final isActiveSnackbar =
_snackbarController.state?.uniqueId == snackbar.uniqueId;
// If this was the active snackbar, handle transition
if (isActiveSnackbar) {
// Try to use the snackbar's internal controller for dismiss animation
final controller = _getSnackbarController(snackbar.uniqueId);
if (controller != null && controller.isAttached) {
// Use imperative dismiss via controller
if (_showDebugPrints) {
debugPrint(
'Modal.dismissById: Using controller to dismiss snackbar ${snackbar.uniqueId}');
}
final completer = Completer<void>();
controller.playDismissAnimation(
direction: '',
onComplete: () {
// Remove from queue after animation completes
_removeSnackbarAfterDismiss(
position, snackbar.uniqueId, onDismissed);
if (!completer.isCompleted) {
completer.complete();
}
},
);
// Wait for animation to complete
await completer.future;
} else {
// Fallback: Use the old reactive approach
if (_showDebugPrints) {
debugPrint(
'Modal.dismissById: Controller not found, using fallback for snackbar ${snackbar.uniqueId}');
}
_setSnackbarDismissing(snackbar.uniqueId, true);
await Future.delayed(0.3.sec, () {
_removeSnackbarAfterDismiss(
position, snackbar.uniqueId, onDismissed);
});
}
} else {
// Not the active snackbar, remove immediately
final updatedQueue = List<_ModalContent>.from(queueAtPosition);
updatedQueue.removeAt(matchIndex);
final updatedQueueMap =
Map<Alignment, List<_ModalContent>>.from(currentQueueMap);
if (updatedQueue.isEmpty) {
updatedQueueMap.remove(position);
} else {
updatedQueueMap[position] = updatedQueue;
}
_snackbarQueueNotifier.state = updatedQueueMap;
// Unregister from modal registry
final updatedRegistry =
Map<String, ModalType>.from(_modalRegistry.state);
updatedRegistry.remove(snackbar.uniqueId);
_modalRegistry.state = updatedRegistry;
onDismissed?.call();
snackbar.onDismissed?.call();
}
if (_showDebugPrints) {
debugPrint('Modal.dismissById: successfully dismissed ID=$id');
}
return true;
}
}
if (_showDebugPrints) {
debugPrint(
'Modal.dismissById: ID=$id not found in any active modal or snackbar queue');
}
return false;
}