update ui logic to replace scaffold
This commit is contained in:
@@ -300,19 +300,24 @@ class BrowserScreen extends HookConsumerWidget {
|
|||||||
[],
|
[],
|
||||||
);
|
);
|
||||||
|
|
||||||
final sheetController = useState<PersistentBottomSheetController?>(null);
|
|
||||||
|
|
||||||
final pointerMoveEventsController = useStreamController<Offset>();
|
final pointerMoveEventsController = useStreamController<Offset>();
|
||||||
|
|
||||||
|
// Watch sheet state for rendering in Stack
|
||||||
|
final displayedSheet = ref.watch(bottomSheetControllerProvider);
|
||||||
|
final sheetDisplayed = displayedSheet != null;
|
||||||
|
|
||||||
// Compute visibility states for toolbars
|
// Compute visibility states for toolbars
|
||||||
final appBarVisible = useValueListenable(displayAppBar);
|
final appBarVisible = useValueListenable(displayAppBar);
|
||||||
final topDismissed = ref.watch(tabBarDismissableControllerProvider);
|
final topDismissed = ref.watch(tabBarDismissableControllerProvider);
|
||||||
|
|
||||||
// Toolbar is visible when: sheet is shown OR (not fullscreen AND app bar visible)
|
// Toolbar is visible when: sheet is shown OR (not fullscreen AND app bar visible)
|
||||||
final topToolbarVisible =
|
final topToolbarVisible =
|
||||||
sheetController.value != null || (!tabInFullScreen && !topDismissed);
|
sheetDisplayed || (!tabInFullScreen && !topDismissed);
|
||||||
final bottomToolbarVisible =
|
final bottomToolbarVisible =
|
||||||
sheetController.value != null || (!tabInFullScreen && appBarVisible);
|
sheetDisplayed || (!tabInFullScreen && appBarVisible);
|
||||||
|
|
||||||
|
// Calculate relative safe area for sheet max size
|
||||||
|
final relativeSafeArea = MediaQuery.of(context).relativeSafeArea();
|
||||||
|
|
||||||
// Calculate bottom toolbar size for FAB positioning
|
// Calculate bottom toolbar size for FAB positioning
|
||||||
final bottomAppBarSize = BrowserBottomAppBar(
|
final bottomAppBarSize = BrowserBottomAppBar(
|
||||||
@@ -340,15 +345,28 @@ class BrowserScreen extends HookConsumerWidget {
|
|||||||
Positioned.fill(
|
Positioned.fill(
|
||||||
child: _Browser(
|
child: _Browser(
|
||||||
overlayController: overlayController,
|
overlayController: overlayController,
|
||||||
sheetController: sheetController,
|
|
||||||
displayAppBar: displayAppBar,
|
displayAppBar: displayAppBar,
|
||||||
tabInFullScreen: tabInFullScreen,
|
tabInFullScreen: tabInFullScreen,
|
||||||
pointerMoveEventSink: pointerMoveEventsController.sink,
|
pointerMoveEventSink: pointerMoveEventsController.sink,
|
||||||
bottomAppBarSize: bottomAppBarSize,
|
sheetDisplayed: sheetDisplayed,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
// Layer 1: Bottom Toolbar (overlay, slides in/out)
|
// Layer 1: Sheet (when displayed) - positioned above toolbar
|
||||||
|
if (sheetDisplayed)
|
||||||
|
Positioned(
|
||||||
|
left: 0,
|
||||||
|
right: 0,
|
||||||
|
top: 0,
|
||||||
|
bottom: bottomAppBarSize.height,
|
||||||
|
child: _SheetContainer(
|
||||||
|
displayedSheet: displayedSheet,
|
||||||
|
relativeSafeArea: relativeSafeArea,
|
||||||
|
bottomAppBarSize: bottomAppBarSize,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
// Layer 2: Bottom Toolbar (overlay, slides in/out) - above sheet
|
||||||
Positioned(
|
Positioned(
|
||||||
left: 0,
|
left: 0,
|
||||||
right: 0,
|
right: 0,
|
||||||
@@ -367,7 +385,7 @@ class BrowserScreen extends HookConsumerWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
// Layer 2: Top Toolbar (overlay, slides in/out) - only when position is top
|
// Layer 3: Top Toolbar (overlay, slides in/out) - only when position is top
|
||||||
if (tabBarPosition == TabBarPosition.top)
|
if (tabBarPosition == TabBarPosition.top)
|
||||||
Positioned(
|
Positioned(
|
||||||
left: 0,
|
left: 0,
|
||||||
@@ -387,10 +405,14 @@ class BrowserScreen extends HookConsumerWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
// Layer 3: FAB (positioned above bottom toolbar)
|
// Layer 4: FAB (animates position with toolbar visibility)
|
||||||
Positioned(
|
AnimatedPositioned(
|
||||||
|
duration: _AnimatedToolbar._kAnimationDuration,
|
||||||
|
curve: Curves.easeInOutQuart,
|
||||||
right: 16,
|
right: 16,
|
||||||
bottom: bottomAppBarSize.height + 16,
|
bottom: bottomToolbarVisible
|
||||||
|
? bottomAppBarSize.height + 16
|
||||||
|
: 16 + MediaQuery.of(context).padding.bottom,
|
||||||
child: const BrowserFab(),
|
child: const BrowserFab(),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@@ -401,24 +423,80 @@ class BrowserScreen extends HookConsumerWidget {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Container widget for bottom sheets - renders in Stack for proper layering.
|
||||||
|
class _SheetContainer extends HookConsumerWidget {
|
||||||
|
final Sheet displayedSheet;
|
||||||
|
final double relativeSafeArea;
|
||||||
|
final Size bottomAppBarSize;
|
||||||
|
|
||||||
|
const _SheetContainer({
|
||||||
|
required this.displayedSheet,
|
||||||
|
required this.relativeSafeArea,
|
||||||
|
required this.bottomAppBarSize,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
bool dismissOnThreshold(DraggableScrollableNotification notification) {
|
||||||
|
if (notification.extent <= 0.1) {
|
||||||
|
logger.i('Dismissing sheet, reached min extend');
|
||||||
|
ref.read(bottomSheetControllerProvider.notifier).requestDismiss();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return GestureDetector(
|
||||||
|
onTap: () {
|
||||||
|
// Dismiss sheet when tapping outside
|
||||||
|
ref.read(bottomSheetControllerProvider.notifier).requestDismiss();
|
||||||
|
},
|
||||||
|
child: Container(
|
||||||
|
color: Colors.black54, // Scrim
|
||||||
|
child: GestureDetector(
|
||||||
|
onTap: () {}, // Prevent tap from propagating to parent
|
||||||
|
child: Align(
|
||||||
|
alignment: Alignment.bottomCenter,
|
||||||
|
child: switch (displayedSheet) {
|
||||||
|
ViewTabsSheet() =>
|
||||||
|
NotificationListener<DraggableScrollableNotification>(
|
||||||
|
key: UniqueKey(),
|
||||||
|
onNotification: dismissOnThreshold,
|
||||||
|
child: _ViewTabsSheet(maxChildSize: relativeSafeArea),
|
||||||
|
),
|
||||||
|
final EditUrlSheet parameter =>
|
||||||
|
NotificationListener<DraggableScrollableNotification>(
|
||||||
|
key: UniqueKey(),
|
||||||
|
onNotification: dismissOnThreshold,
|
||||||
|
child: _ViewUrlSheet(
|
||||||
|
initialTabState: parameter.tabState,
|
||||||
|
maxChildSize: relativeSafeArea,
|
||||||
|
bottomAppBarSize: bottomAppBarSize,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class _Browser extends HookConsumerWidget {
|
class _Browser extends HookConsumerWidget {
|
||||||
Duration get _backButtonPressTimeout => const Duration(seconds: 2);
|
Duration get _backButtonPressTimeout => const Duration(seconds: 2);
|
||||||
|
|
||||||
final OverlayPortalController overlayController;
|
final OverlayPortalController overlayController;
|
||||||
final ValueNotifier<PersistentBottomSheetController?> sheetController;
|
|
||||||
final ValueNotifier<bool> displayAppBar;
|
final ValueNotifier<bool> displayAppBar;
|
||||||
final StreamSink<Offset> pointerMoveEventSink;
|
final StreamSink<Offset> pointerMoveEventSink;
|
||||||
final Size bottomAppBarSize;
|
|
||||||
|
|
||||||
final bool tabInFullScreen;
|
final bool tabInFullScreen;
|
||||||
|
final bool sheetDisplayed;
|
||||||
|
|
||||||
const _Browser({
|
const _Browser({
|
||||||
required this.overlayController,
|
required this.overlayController,
|
||||||
required this.sheetController,
|
|
||||||
required this.displayAppBar,
|
required this.displayAppBar,
|
||||||
required this.tabInFullScreen,
|
required this.tabInFullScreen,
|
||||||
required this.pointerMoveEventSink,
|
required this.pointerMoveEventSink,
|
||||||
required this.bottomAppBarSize,
|
required this.sheetDisplayed,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -427,88 +505,6 @@ class _Browser extends HookConsumerWidget {
|
|||||||
|
|
||||||
final overlayBuilder = ref.watch(overlayControllerProvider);
|
final overlayBuilder = ref.watch(overlayControllerProvider);
|
||||||
|
|
||||||
ref.listen(bottomSheetControllerProvider, (previous, next) {
|
|
||||||
if (!context.mounted) {
|
|
||||||
logger.e('Cannot show sheet, context not mounted');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
|
||||||
if (!context.mounted) {
|
|
||||||
logger.e('Cannot show sheet, context not mounted (post frame)');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Close existing sheet
|
|
||||||
if (sheetController.value != null) {
|
|
||||||
try {
|
|
||||||
final existingController = sheetController.value!;
|
|
||||||
sheetController.value = null;
|
|
||||||
existingController.close();
|
|
||||||
} catch (e) {
|
|
||||||
logger.e('Error closing existing sheet', error: e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Show new sheet
|
|
||||||
if (next != null) {
|
|
||||||
try {
|
|
||||||
final relativeSafeArea = MediaQuery.of(context).relativeSafeArea();
|
|
||||||
|
|
||||||
final controller = Scaffold.of(context).showBottomSheet((context) {
|
|
||||||
logger.i(
|
|
||||||
'Building bottom sheet, relativeSafeArea: $relativeSafeArea, mounted: ${context.mounted}',
|
|
||||||
);
|
|
||||||
|
|
||||||
bool dismissOnThreshold(
|
|
||||||
DraggableScrollableNotification notification,
|
|
||||||
) {
|
|
||||||
if (notification.extent <= 0.1) {
|
|
||||||
logger.i('Dismissing sheet, reached min extend');
|
|
||||||
ref
|
|
||||||
.read(bottomSheetControllerProvider.notifier)
|
|
||||||
.requestDismiss();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
final sheet = switch (next) {
|
|
||||||
ViewTabsSheet() =>
|
|
||||||
NotificationListener<DraggableScrollableNotification>(
|
|
||||||
key: UniqueKey(),
|
|
||||||
onNotification: dismissOnThreshold,
|
|
||||||
child: _ViewTabsSheet(maxChildSize: relativeSafeArea),
|
|
||||||
),
|
|
||||||
final EditUrlSheet parameter =>
|
|
||||||
NotificationListener<DraggableScrollableNotification>(
|
|
||||||
key: UniqueKey(),
|
|
||||||
onNotification: dismissOnThreshold,
|
|
||||||
child: _ViewUrlSheet(
|
|
||||||
initialTabState: parameter.tabState,
|
|
||||||
maxChildSize: relativeSafeArea,
|
|
||||||
bottomAppBarSize: bottomAppBarSize,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
};
|
|
||||||
|
|
||||||
return sheet;
|
|
||||||
});
|
|
||||||
|
|
||||||
unawaited(
|
|
||||||
controller.closed.whenComplete(() {
|
|
||||||
ref.read(bottomSheetControllerProvider.notifier).closed(next);
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
sheetController.value = controller;
|
|
||||||
} catch (e) {
|
|
||||||
debugPrint('Failed to show bottom sheet: $e');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
return DragTarget<TabDragData>(
|
return DragTarget<TabDragData>(
|
||||||
onMove: (details) {
|
onMove: (details) {
|
||||||
ref
|
ref
|
||||||
@@ -538,7 +534,7 @@ class _Browser extends HookConsumerWidget {
|
|||||||
return overlayBuilder!.call(context);
|
return overlayBuilder!.call(context);
|
||||||
},
|
},
|
||||||
child: Listener(
|
child: Listener(
|
||||||
onPointerDown: sheetController.value != null
|
onPointerDown: sheetDisplayed
|
||||||
? (_) {
|
? (_) {
|
||||||
ref
|
ref
|
||||||
.read(bottomSheetControllerProvider.notifier)
|
.read(bottomSheetControllerProvider.notifier)
|
||||||
@@ -683,7 +679,8 @@ class _BrowserView extends StatelessWidget {
|
|||||||
SafeArea(
|
SafeArea(
|
||||||
top: !isFullscreen,
|
top: !isFullscreen,
|
||||||
right: !isFullscreen,
|
right: !isFullscreen,
|
||||||
bottom: !isFullscreen,
|
// Bottom SafeArea is handled by the overlay toolbar (BottomAppBar)
|
||||||
|
bottom: false,
|
||||||
left: !isFullscreen,
|
left: !isFullscreen,
|
||||||
child: Stack(
|
child: Stack(
|
||||||
children: [
|
children: [
|
||||||
|
|||||||
+6
-19
@@ -443,31 +443,18 @@ class TabViewHeader extends HookConsumerWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (context.mounted) {
|
if (context.mounted) {
|
||||||
ScaffoldMessenger.of(
|
ui_helper.showInfoMessage(
|
||||||
context,
|
context,
|
||||||
).showSnackBar(
|
shouldReopenTabs
|
||||||
SnackBar(
|
? 'Container data cleared successfully'
|
||||||
content: Text(
|
: 'Container data cleared. ${tabs.length} tab(s) closed.',
|
||||||
shouldReopenTabs
|
|
||||||
? 'Container data cleared successfully'
|
|
||||||
: 'Container data cleared. ${tabs.length} tab(s) closed.',
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (context.mounted) {
|
if (context.mounted) {
|
||||||
ScaffoldMessenger.of(
|
ui_helper.showErrorMessage(
|
||||||
context,
|
context,
|
||||||
).showSnackBar(
|
'Error clearing data: $e',
|
||||||
SnackBar(
|
|
||||||
content: Text(
|
|
||||||
'Error clearing data: $e',
|
|
||||||
),
|
|
||||||
backgroundColor: Theme.of(
|
|
||||||
context,
|
|
||||||
).colorScheme.error,
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import 'package:weblibre/core/filesystem.dart';
|
|||||||
import 'package:weblibre/domain/entities/profile.dart';
|
import 'package:weblibre/domain/entities/profile.dart';
|
||||||
import 'package:weblibre/features/user/domain/repositories/profile.dart';
|
import 'package:weblibre/features/user/domain/repositories/profile.dart';
|
||||||
import 'package:weblibre/utils/exit_app.dart';
|
import 'package:weblibre/utils/exit_app.dart';
|
||||||
|
import 'package:weblibre/utils/ui_helper.dart' as ui_helper;
|
||||||
|
|
||||||
/// Handles the profile switching flow with confirmation dialog and cache clearing options.
|
/// Handles the profile switching flow with confirmation dialog and cache clearing options.
|
||||||
///
|
///
|
||||||
@@ -43,9 +44,7 @@ Future<void> handleSwitchProfile(
|
|||||||
// Don't allow switching to the already active profile
|
// Don't allow switching to the already active profile
|
||||||
if (isSelected) {
|
if (isSelected) {
|
||||||
if (context.mounted) {
|
if (context.mounted) {
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ui_helper.showInfoMessage(context, 'This profile is already active');
|
||||||
const SnackBar(content: Text('This profile is already active')),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,21 +22,47 @@ import 'package:nullability/nullability.dart';
|
|||||||
import 'package:url_launcher/url_launcher.dart';
|
import 'package:url_launcher/url_launcher.dart';
|
||||||
import 'package:weblibre/utils/clipboard.dart';
|
import 'package:weblibre/utils/clipboard.dart';
|
||||||
|
|
||||||
|
/// Default bottom margin for floating snackbars to position above toolbar.
|
||||||
|
/// This accounts for the typical browser toolbar height.
|
||||||
|
const _kSnackBarBottomMargin = 72.0;
|
||||||
|
|
||||||
|
/// Creates a floating snackbar with proper margin for overlay toolbar layout.
|
||||||
|
SnackBar _createFloatingSnackBar({
|
||||||
|
required Widget content,
|
||||||
|
Color? backgroundColor,
|
||||||
|
SnackBarAction? action,
|
||||||
|
Duration duration = const Duration(seconds: 4),
|
||||||
|
bool persist = false,
|
||||||
|
}) {
|
||||||
|
return SnackBar(
|
||||||
|
content: content,
|
||||||
|
backgroundColor: backgroundColor,
|
||||||
|
action: action,
|
||||||
|
duration: duration,
|
||||||
|
persist: persist,
|
||||||
|
behavior: SnackBarBehavior.floating,
|
||||||
|
margin: const EdgeInsets.only(
|
||||||
|
left: 16,
|
||||||
|
right: 16,
|
||||||
|
bottom: _kSnackBarBottomMargin,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
void showErrorMessage(BuildContext context, String message) {
|
void showErrorMessage(BuildContext context, String message) {
|
||||||
final snackBar = SnackBar(
|
final snackBar = _createFloatingSnackBar(
|
||||||
content: Text(
|
content: Text(
|
||||||
message,
|
message,
|
||||||
style: TextStyle(color: Theme.of(context).colorScheme.error),
|
style: TextStyle(color: Theme.of(context).colorScheme.error),
|
||||||
),
|
),
|
||||||
backgroundColor: Theme.of(context).colorScheme.onError,
|
backgroundColor: Theme.of(context).colorScheme.onError,
|
||||||
persist: false,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
ScaffoldMessenger.of(context).showSnackBar(snackBar);
|
ScaffoldMessenger.of(context).showSnackBar(snackBar);
|
||||||
}
|
}
|
||||||
|
|
||||||
void showInfoMessage(BuildContext context, String message) {
|
void showInfoMessage(BuildContext context, String message) {
|
||||||
final snackBar = SnackBar(content: Text(message), persist: false);
|
final snackBar = _createFloatingSnackBar(content: Text(message));
|
||||||
|
|
||||||
ScaffoldMessenger.of(context).showSnackBar(snackBar);
|
ScaffoldMessenger.of(context).showSnackBar(snackBar);
|
||||||
}
|
}
|
||||||
@@ -46,12 +72,11 @@ void showTabBackButtonMessage(
|
|||||||
int tabCount,
|
int tabCount,
|
||||||
Duration duration,
|
Duration duration,
|
||||||
) {
|
) {
|
||||||
final snackbar = SnackBar(
|
final snackbar = _createFloatingSnackBar(
|
||||||
content: (tabCount > 1)
|
content: (tabCount > 1)
|
||||||
? const Text('Navigate BACK again to close current tab')
|
? const Text('Navigate BACK again to close current tab')
|
||||||
: const Text('Navigate BACK again to exit app'),
|
: const Text('Navigate BACK again to exit app'),
|
||||||
duration: duration,
|
duration: duration,
|
||||||
persist: false,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
ScaffoldMessenger.of(context)
|
ScaffoldMessenger.of(context)
|
||||||
@@ -70,13 +95,12 @@ void showTabOpenedMessage(
|
|||||||
null => 'New tab opened in background',
|
null => 'New tab opened in background',
|
||||||
};
|
};
|
||||||
|
|
||||||
final snackBar = SnackBar(
|
final snackBar = _createFloatingSnackBar(
|
||||||
content: Text(message),
|
content: Text(message),
|
||||||
action: onShow.mapNotNull(
|
action: onShow.mapNotNull(
|
||||||
(onPressed) => SnackBarAction(label: 'Show', onPressed: onPressed),
|
(onPressed) => SnackBarAction(label: 'Show', onPressed: onPressed),
|
||||||
),
|
),
|
||||||
duration: duration,
|
duration: duration,
|
||||||
persist: false,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
ScaffoldMessenger.of(context).showSnackBar(snackBar);
|
ScaffoldMessenger.of(context).showSnackBar(snackBar);
|
||||||
@@ -90,7 +114,7 @@ Future<void> showSuggestNewTabMessage(
|
|||||||
final clipboardUrl = await tryGetUriFromClipboard();
|
final clipboardUrl = await tryGetUriFromClipboard();
|
||||||
|
|
||||||
if (clipboardUrl != null) {
|
if (clipboardUrl != null) {
|
||||||
final snackBar = SnackBar(
|
final snackBar = _createFloatingSnackBar(
|
||||||
content: const Text('Want to open link from clipboard?'),
|
content: const Text('Want to open link from clipboard?'),
|
||||||
action: SnackBarAction(
|
action: SnackBarAction(
|
||||||
label: 'Open',
|
label: 'Open',
|
||||||
@@ -99,7 +123,6 @@ Future<void> showSuggestNewTabMessage(
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
duration: duration,
|
duration: duration,
|
||||||
persist: false,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
if (context.mounted) {
|
if (context.mounted) {
|
||||||
@@ -121,13 +144,12 @@ void showTabSwitchMessage(
|
|||||||
null => 'New tab opened',
|
null => 'New tab opened',
|
||||||
};
|
};
|
||||||
|
|
||||||
final snackBar = SnackBar(
|
final snackBar = _createFloatingSnackBar(
|
||||||
content: Text(message),
|
content: Text(message),
|
||||||
action: onSwitch.mapNotNull(
|
action: onSwitch.mapNotNull(
|
||||||
(onPressed) => SnackBarAction(label: 'Switch', onPressed: onPressed),
|
(onPressed) => SnackBarAction(label: 'Switch', onPressed: onPressed),
|
||||||
),
|
),
|
||||||
duration: duration,
|
duration: duration,
|
||||||
persist: false,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
ScaffoldMessenger.of(context).showSnackBar(snackBar);
|
ScaffoldMessenger.of(context).showSnackBar(snackBar);
|
||||||
@@ -165,13 +187,12 @@ void showTabUndoClose(
|
|||||||
}) {
|
}) {
|
||||||
ScaffoldMessenger.of(context).clearSnackBars();
|
ScaffoldMessenger.of(context).clearSnackBars();
|
||||||
|
|
||||||
final snackBar = SnackBar(
|
final snackBar = _createFloatingSnackBar(
|
||||||
content: (count > 1)
|
content: (count > 1)
|
||||||
? Text('$count Tabs closed')
|
? Text('$count Tabs closed')
|
||||||
: const Text('Tab closed'),
|
: const Text('Tab closed'),
|
||||||
action: SnackBarAction(label: 'Undo', onPressed: onUndo),
|
action: SnackBarAction(label: 'Undo', onPressed: onUndo),
|
||||||
duration: duration,
|
duration: duration,
|
||||||
persist: false,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
ScaffoldMessenger.of(context).showSnackBar(snackBar);
|
ScaffoldMessenger.of(context).showSnackBar(snackBar);
|
||||||
|
|||||||
Reference in New Issue
Block a user