From aee8a91c13956997d0df25a230a7f7057407608b Mon Sep 17 00:00:00 2001 From: Badr Kouki Date: Sat, 23 Aug 2025 09:49:06 +0100 Subject: [PATCH 1/2] fix #163: add safearea flag to show or hide safearea --- lib/bottom_picker.dart | 501 +++++++++++++++++++++-------------------- 1 file changed, 254 insertions(+), 247 deletions(-) diff --git a/lib/bottom_picker.dart b/lib/bottom_picker.dart index e6c658d..be634c8 100644 --- a/lib/bottom_picker.dart +++ b/lib/bottom_picker.dart @@ -78,6 +78,7 @@ class BottomPicker extends StatefulWidget { this.closeOnSubmit = true, this.headerBuilder, this.diameterRatio = 1.1, + this.useSafeArea = false, }) { dateOrder = null; onRangeDateSubmitPressed = null; @@ -134,6 +135,7 @@ class BottomPicker extends StatefulWidget { this.headerBuilder, this.calendarDays = CupertinoDatePickerWidget.fullWeek, this.diameterRatio = 1.1, + this.useSafeArea = false, }) { datePickerMode = CupertinoDatePickerMode.date; bottomPickerType = BottomPickerType.dateTime; @@ -167,6 +169,7 @@ class BottomPicker extends StatefulWidget { this.itemExtent = 35.0, this.diameterRatio = 1.1, this.headerBuilder, + this.useSafeArea = false, }) { datePickerMode = CupertinoDatePickerMode.date; bottomPickerType = BottomPickerType.year; @@ -220,6 +223,7 @@ class BottomPicker extends StatefulWidget { this.headerBuilder, this.calendarDays = CupertinoDatePickerWidget.fullWeek, this.diameterRatio = 1.1, + this.useSafeArea = false, }) { datePickerMode = CupertinoDatePickerMode.monthYear; bottomPickerType = BottomPickerType.dateTime; @@ -278,6 +282,7 @@ class BottomPicker extends StatefulWidget { this.calendarDays = CupertinoDatePickerWidget.fullWeek, this.diameterRatio = 1.1, this.hourPredicate, + this.useSafeArea = false, }) { datePickerMode = CupertinoDatePickerMode.dateAndTime; bottomPickerType = BottomPickerType.dateTime; @@ -332,6 +337,7 @@ class BottomPicker extends StatefulWidget { this.headerBuilder, this.calendarDays = CupertinoDatePickerWidget.fullWeek, this.diameterRatio = 1.1, + this.useSafeArea = false, }) { datePickerMode = CupertinoDatePickerMode.time; bottomPickerType = BottomPickerType.time; @@ -386,6 +392,7 @@ class BottomPicker extends StatefulWidget { this.headerBuilder, this.calendarDays = CupertinoDatePickerWidget.fullWeek, this.diameterRatio = 1.1, + this.useSafeArea = false, }) { dateOrder = null; onRangeDateSubmitPressed = null; @@ -441,6 +448,7 @@ class BottomPicker extends StatefulWidget { this.headerBuilder, this.calendarDays = CupertinoDatePickerWidget.fullWeek, this.diameterRatio = 1.1, + this.useSafeArea = false, }) { datePickerMode = CupertinoDatePickerMode.date; bottomPickerType = BottomPickerType.rangeDate; @@ -512,6 +520,7 @@ class BottomPicker extends StatefulWidget { this.headerBuilder, this.calendarDays = CupertinoDatePickerWidget.fullWeek, this.diameterRatio = 1.1, + this.useSafeArea = false, }) { datePickerMode = CupertinoDatePickerMode.time; bottomPickerType = BottomPickerType.rangeTime; @@ -815,11 +824,13 @@ class BottomPicker extends StatefulWidget { /// A predicate that can be used to select which hours are selectable. SelectableHourPredicate? hourPredicate; + final bool useSafeArea; + ///display the bottom picker popup ///[context] the app context to display the popup void show(BuildContext context) { showModalBottomSheet( - useSafeArea: true, + useSafeArea: useSafeArea, context: context, isDismissible: dismissable, enableDrag: false, @@ -906,258 +917,254 @@ class BottomPickerState extends State { @override Widget build(BuildContext context) { - return SafeArea( - child: Container( - height: widget.height ?? context.bottomPickerHeight, - decoration: BoxDecoration( - color: widget.backgroundColor, - borderRadius: const BorderRadius.only( - topRight: Radius.circular(20), - topLeft: Radius.circular(20), - ), + if (widget.useSafeArea) { + return SafeArea( + child: _bottomPickerWidget(context), + ); + } + return _bottomPickerWidget(context); + } + + Container _bottomPickerWidget(BuildContext context) { + return Container( + height: widget.height ?? context.bottomPickerHeight, + decoration: BoxDecoration( + color: widget.backgroundColor, + borderRadius: const BorderRadius.only( + topRight: Radius.circular(20), + topLeft: Radius.circular(20), ), - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Column( - children: [ - Padding( - padding: const EdgeInsets.symmetric( - horizontal: 20, - ), - child: Directionality( - textDirection: widget.layoutOrientation ?? TextDirection.ltr, - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Padding( - padding: widget.headerBuilder == null - ? widget.titlePadding ?? const EdgeInsets.all(0) - : EdgeInsets.zero, - child: Row( - children: [ - if (widget.headerBuilder != null) - Expanded( - child: widget.headerBuilder!( - context, - ), + ), + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Column( + children: [ + Padding( + padding: const EdgeInsets.symmetric( + horizontal: 20, + ), + child: Directionality( + textDirection: widget.layoutOrientation ?? TextDirection.ltr, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Padding( + padding: widget.headerBuilder == null + ? widget.titlePadding ?? const EdgeInsets.all(0) + : EdgeInsets.zero, + child: Row( + children: [ + if (widget.headerBuilder != null) + Expanded( + child: widget.headerBuilder!( + context, ), - if (widget.headerBuilder == null && - widget.pickerTitle != null) - Expanded(child: widget.pickerTitle!), - if (widget.headerBuilder == null && - (widget.displayCloseIcon ?? true)) - widget.closeWidget ?? - CloseIcon( - onPress: _closeBottomPicker, - iconColor: widget.closeIconColor, - closeIconSize: widget.closeIconSize, - ), - ], - ), + ), + if (widget.headerBuilder == null && + widget.pickerTitle != null) + Expanded(child: widget.pickerTitle!), + if (widget.headerBuilder == null && + (widget.displayCloseIcon ?? true)) + widget.closeWidget ?? + CloseIcon( + onPress: _closeBottomPicker, + iconColor: widget.closeIconColor, + closeIconSize: widget.closeIconSize, + ), + ], ), - if (widget.headerBuilder == null && - widget.pickerDescription != null) - widget.pickerDescription!, - ], - ), + ), + if (widget.headerBuilder == null && + widget.pickerDescription != null) + widget.pickerDescription!, + ], ), ), - Expanded( - child: widget.bottomPickerType == BottomPickerType.simple - ? SimplePicker( - items: widget.items!, - onChange: (int index) { - selectedItemIndex = index; - widget.onChange?.call(index); - }, - selectedItemIndex: widget.selectedItemIndex, - textStyle: widget.pickerTextStyle, - itemExtent: widget.itemExtent, - selectionOverlay: widget.selectionOverlay, - pickerThemeData: widget.pickerThemeData, - diameterRatio: widget.diameterRatio, - ) - : widget.bottomPickerType == BottomPickerType.timer - ? TimePicker( - mode: widget.timerPickerMode!, - minuteInterval: widget.minuteInterval, - textStyle: widget.pickerTextStyle, - itemExtent: widget.itemExtent, - initialDuration: widget.initialTimerDuration, - onChange: (p0) { - widget.onChange?.call(p0); - selectedTimerDuration = p0; - }, - secondInterval: widget.timerSecondsInterval, - pickerThemeData: widget.pickerThemeData, - ) - : widget.bottomPickerType == BottomPickerType.time - ? DatePicker( - initialDateTime: widget.initialTime.toDateTime, - minuteInterval: widget.minuteInterval, - maxDateTime: widget.maxTime.toDateTime, - minDateTime: widget.minTime.toDateTime, - mode: widget.datePickerMode, - onDateChanged: (DateTime date) { - selectedDateTime = date; - widget.onChange?.call(date); - }, - use24hFormat: widget.use24hFormat, - dateOrder: widget.dateOrder, - textStyle: widget.pickerTextStyle, - itemExtent: widget.itemExtent, - showTimeSeparator: widget.showTimeSeparator, - pickerThemeData: widget.pickerThemeData, - ) - : widget.bottomPickerType == - BottomPickerType.dateTime - ? DatePicker( - initialDateTime: widget.initialDateTime, - minuteInterval: widget.minuteInterval, - maxDateTime: widget.maxDateTime, - minDateTime: widget.minDateTime, - mode: widget.datePickerMode, - onDateChanged: (DateTime date) { - selectedDateTime = date; - widget.onChange?.call(date); - }, - use24hFormat: widget.use24hFormat, - dateOrder: widget.dateOrder, - textStyle: widget.pickerTextStyle, - itemExtent: widget.itemExtent, - showTimeSeparator: widget.showTimeSeparator, - pickerThemeData: widget.pickerThemeData, - hourPredicate: widget.hourPredicate, - ) - : widget.bottomPickerType == - BottomPickerType.year - ? BottomYearDatePicker( - initialDateTime: widget.initialDateTime, - maxDateTime: widget.maxDateTime, - minDateTime: widget.minDateTime, - onDateChanged: (DateTime date) { - selectedDateTime = date; - widget.onChange?.call(date); - }, - itemExtent: widget.itemExtent, - pickerThemeData: widget.pickerThemeData, - ) - : widget.bottomPickerType == - BottomPickerType.rangeTime - ? RangePicker( - mode: CupertinoDatePickerMode.time, - use24hFormat: widget.use24hFormat, - initialFirstDateTime: - widget.initialFirstTime, - initialSecondDateTime: - widget.initialSecondTime, - maxFirstDate: widget.maxFirstTime, - minFirstDateTime: - widget.minFirstTime, - maxSecondDate: widget.maxSecondTime, - minSecondDateTime: - widget.minSecondTime, - onFirstDateChanged: - (DateTime date) { - selectedFirstDateTime = date; - }, - onSecondDateChanged: - (DateTime date) { - selectedSecondDateTime = date; - }, - dateOrder: widget.dateOrder, - textStyle: widget.pickerTextStyle, - minuteInterval: - widget.minuteInterval, - itemExtent: widget.itemExtent, - showTimeSeperator: - widget.showTimeSeparator, - pickerThemeData: - widget.pickerThemeData, - ) - : RangePicker( - mode: CupertinoDatePickerMode.date, - use24hFormat: widget.use24hFormat, - initialFirstDateTime: - widget.initialFirstDate, - initialSecondDateTime: - widget.initialSecondDate, - maxFirstDate: widget.maxFirstDate, - minFirstDateTime: - widget.minFirstDate, - maxSecondDate: widget.maxSecondDate, - minSecondDateTime: - widget.minSecondDate, - onFirstDateChanged: - (DateTime date) { - selectedFirstDateTime = date; - }, - onSecondDateChanged: - (DateTime date) { - selectedSecondDateTime = date; - }, - dateOrder: widget.dateOrder, - textStyle: widget.pickerTextStyle, - itemExtent: widget.itemExtent, - showTimeSeperator: - widget.showTimeSeparator, - pickerThemeData: - widget.pickerThemeData, - ), - ), - if (widget.displaySubmitButton) - Padding( - padding: const EdgeInsets.symmetric( - vertical: 20, - ), - child: Row( - mainAxisAlignment: widget.buttonAlignment, - children: [ - BottomPickerButton( - onClick: () { - if (widget.bottomPickerType == - BottomPickerType.rangeDate) { - widget.onRangeDateSubmitPressed?.call( - selectedFirstDateTime, - selectedSecondDateTime, - ); - } else if (widget.bottomPickerType == - BottomPickerType.rangeTime) { - widget.onRangeTimeSubmitPressed?.call( - selectedFirstDateTime, - selectedSecondDateTime, - ); - } else if (widget.bottomPickerType == - BottomPickerType.dateTime || - widget.bottomPickerType == - BottomPickerType.time || - widget.bottomPickerType == - BottomPickerType.year) { - widget.onSubmit?.call(selectedDateTime); - } else if (widget.bottomPickerType == - BottomPickerType.timer) { - widget.onSubmit?.call(selectedTimerDuration); - } else { - widget.onSubmit?.call(selectedItemIndex); - } - - if (widget.closeOnSubmit ?? false) { - Navigator.pop(context); - } - }, - gradients: widget.gradientColors, - theme: widget.bottomPickerTheme, - buttonPadding: widget.buttonPadding, - buttonWidth: widget.buttonWidth, - solidColor: widget.buttonSingleColor, - buttonChild: widget.buttonContent, - style: widget.buttonStyle, - ), - ], - ), + ), + Expanded( + child: widget.bottomPickerType == BottomPickerType.simple + ? SimplePicker( + items: widget.items!, + onChange: (int index) { + selectedItemIndex = index; + widget.onChange?.call(index); + }, + selectedItemIndex: widget.selectedItemIndex, + textStyle: widget.pickerTextStyle, + itemExtent: widget.itemExtent, + selectionOverlay: widget.selectionOverlay, + pickerThemeData: widget.pickerThemeData, + diameterRatio: widget.diameterRatio, + ) + : widget.bottomPickerType == BottomPickerType.timer + ? TimePicker( + mode: widget.timerPickerMode!, + minuteInterval: widget.minuteInterval, + textStyle: widget.pickerTextStyle, + itemExtent: widget.itemExtent, + initialDuration: widget.initialTimerDuration, + onChange: (p0) { + widget.onChange?.call(p0); + selectedTimerDuration = p0; + }, + secondInterval: widget.timerSecondsInterval, + pickerThemeData: widget.pickerThemeData, + ) + : widget.bottomPickerType == BottomPickerType.time + ? DatePicker( + initialDateTime: widget.initialTime.toDateTime, + minuteInterval: widget.minuteInterval, + maxDateTime: widget.maxTime.toDateTime, + minDateTime: widget.minTime.toDateTime, + mode: widget.datePickerMode, + onDateChanged: (DateTime date) { + selectedDateTime = date; + widget.onChange?.call(date); + }, + use24hFormat: widget.use24hFormat, + dateOrder: widget.dateOrder, + textStyle: widget.pickerTextStyle, + itemExtent: widget.itemExtent, + showTimeSeparator: widget.showTimeSeparator, + pickerThemeData: widget.pickerThemeData, + ) + : widget.bottomPickerType == BottomPickerType.dateTime + ? DatePicker( + initialDateTime: widget.initialDateTime, + minuteInterval: widget.minuteInterval, + maxDateTime: widget.maxDateTime, + minDateTime: widget.minDateTime, + mode: widget.datePickerMode, + onDateChanged: (DateTime date) { + selectedDateTime = date; + widget.onChange?.call(date); + }, + use24hFormat: widget.use24hFormat, + dateOrder: widget.dateOrder, + textStyle: widget.pickerTextStyle, + itemExtent: widget.itemExtent, + showTimeSeparator: widget.showTimeSeparator, + pickerThemeData: widget.pickerThemeData, + hourPredicate: widget.hourPredicate, + ) + : widget.bottomPickerType == BottomPickerType.year + ? BottomYearDatePicker( + initialDateTime: widget.initialDateTime, + maxDateTime: widget.maxDateTime, + minDateTime: widget.minDateTime, + onDateChanged: (DateTime date) { + selectedDateTime = date; + widget.onChange?.call(date); + }, + itemExtent: widget.itemExtent, + pickerThemeData: widget.pickerThemeData, + ) + : widget.bottomPickerType == + BottomPickerType.rangeTime + ? RangePicker( + mode: CupertinoDatePickerMode.time, + use24hFormat: widget.use24hFormat, + initialFirstDateTime: + widget.initialFirstTime, + initialSecondDateTime: + widget.initialSecondTime, + maxFirstDate: widget.maxFirstTime, + minFirstDateTime: widget.minFirstTime, + maxSecondDate: widget.maxSecondTime, + minSecondDateTime: + widget.minSecondTime, + onFirstDateChanged: (DateTime date) { + selectedFirstDateTime = date; + }, + onSecondDateChanged: (DateTime date) { + selectedSecondDateTime = date; + }, + dateOrder: widget.dateOrder, + textStyle: widget.pickerTextStyle, + minuteInterval: widget.minuteInterval, + itemExtent: widget.itemExtent, + showTimeSeperator: + widget.showTimeSeparator, + pickerThemeData: + widget.pickerThemeData, + ) + : RangePicker( + mode: CupertinoDatePickerMode.date, + use24hFormat: widget.use24hFormat, + initialFirstDateTime: + widget.initialFirstDate, + initialSecondDateTime: + widget.initialSecondDate, + maxFirstDate: widget.maxFirstDate, + minFirstDateTime: widget.minFirstDate, + maxSecondDate: widget.maxSecondDate, + minSecondDateTime: + widget.minSecondDate, + onFirstDateChanged: (DateTime date) { + selectedFirstDateTime = date; + }, + onSecondDateChanged: (DateTime date) { + selectedSecondDateTime = date; + }, + dateOrder: widget.dateOrder, + textStyle: widget.pickerTextStyle, + itemExtent: widget.itemExtent, + showTimeSeperator: + widget.showTimeSeparator, + pickerThemeData: + widget.pickerThemeData, + ), + ), + if (widget.displaySubmitButton) + Padding( + padding: const EdgeInsets.symmetric( + vertical: 20, ), - ], - ), + child: Row( + mainAxisAlignment: widget.buttonAlignment, + children: [ + BottomPickerButton( + onClick: () { + if (widget.bottomPickerType == + BottomPickerType.rangeDate) { + widget.onRangeDateSubmitPressed?.call( + selectedFirstDateTime, + selectedSecondDateTime, + ); + } else if (widget.bottomPickerType == + BottomPickerType.rangeTime) { + widget.onRangeTimeSubmitPressed?.call( + selectedFirstDateTime, + selectedSecondDateTime, + ); + } else if (widget.bottomPickerType == + BottomPickerType.dateTime || + widget.bottomPickerType == BottomPickerType.time || + widget.bottomPickerType == BottomPickerType.year) { + widget.onSubmit?.call(selectedDateTime); + } else if (widget.bottomPickerType == + BottomPickerType.timer) { + widget.onSubmit?.call(selectedTimerDuration); + } else { + widget.onSubmit?.call(selectedItemIndex); + } + + if (widget.closeOnSubmit ?? false) { + Navigator.pop(context); + } + }, + gradients: widget.gradientColors, + theme: widget.bottomPickerTheme, + buttonPadding: widget.buttonPadding, + buttonWidth: widget.buttonWidth, + solidColor: widget.buttonSingleColor, + buttonChild: widget.buttonContent, + style: widget.buttonStyle, + ), + ], + ), + ), + ], ), ), ); From 75d5cf47849056058e05b728254bee340bc231df Mon Sep 17 00:00:00 2001 From: Badr Kouki Date: Sat, 23 Aug 2025 09:55:44 +0100 Subject: [PATCH 2/2] docs: update package documentation and changelog --- CHANGELOG.md | 12 ++++++------ README.md | 3 +++ lib/bottom_picker.dart | 1 + pubspec.yaml | 2 +- 4 files changed, 11 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6f0063d..d5486e4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## [4.1.1] - 23/08/2025 + +**Bug Fix** + +- add SafeArea flag to show or hide safe area widget from bottom picker widget tree and bottom sheet. [ISSUE#163](https://github.com/koukibadr/Bottom-Picker/issues/163) + ## [4.1.0] - 09/08/2025 **Features** @@ -89,12 +95,6 @@ - enable `minutesInterval` feature for range time picker. -## [2.11.0] - 01/02/2025 - -**Changes:** - -- enable `minutesInterval` feature for range time picker. - ## [2.10.1] - 21/01/2025 **Changes:** diff --git a/README.md b/README.md index 3ffe198..fb40d14 100644 --- a/README.md +++ b/README.md @@ -302,6 +302,9 @@ dependencies: /// A predicate that can be used to select which hours are selectable. SelectableHourPredicate? hourPredicate; + + /// Indicates whether to use SafeArea to avoid content overflow. + final bool useSafeArea; ```` ## Examples diff --git a/lib/bottom_picker.dart b/lib/bottom_picker.dart index be634c8..5f80e5f 100644 --- a/lib/bottom_picker.dart +++ b/lib/bottom_picker.dart @@ -824,6 +824,7 @@ class BottomPicker extends StatefulWidget { /// A predicate that can be used to select which hours are selectable. SelectableHourPredicate? hourPredicate; + /// Indicates whether to use SafeArea to avoid content overflow. final bool useSafeArea; ///display the bottom picker popup diff --git a/pubspec.yaml b/pubspec.yaml index fd60ddf..30d31c7 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: bottom_picker description: An easy way that let you create a bottom item picker or date & time picker with minmum parameters -version: 4.1.0 +version: 4.1.1 homepage: 'https://github.com/koukibadr/Bottom-Picker' environment: sdk: '>=2.19.0 <4.0.0'