feat : new bottom sheet

This commit is contained in:
2025-07-08 11:10:31 +03:30
parent 639a8dd585
commit bbaeb6c2a5
9 changed files with 429 additions and 299 deletions

View File

@@ -13,7 +13,7 @@ class BaseBottomSheet extends StatelessWidget {
Widget build(BuildContext context) {
return Container(
height: height ?? MediaQuery.of(context).size.height * 0.85,
padding: EdgeInsets.symmetric(vertical: 15, horizontal: 20),
padding: EdgeInsets.symmetric(vertical: 15, horizontal: 10),
decoration: BoxDecoration(
color: bgColor ?? Colors.white,
borderRadius: BorderRadius.only(

View File

@@ -34,6 +34,7 @@ class RTextField extends StatefulWidget {
final FormFieldValidator<String>? validator;
final void Function(String)? onChanged;
final void Function(String)? onSubmitted;
final VoidCallback? onTap;
final List<TextInputFormatter>? inputFormatters;
final Widget? suffix;
@@ -68,6 +69,7 @@ class RTextField extends StatefulWidget {
this.onSubmitted,
this.borderColor,
this.inputFormatters,
this.onTap,
this.suffix,
});
@@ -80,12 +82,12 @@ class RTextField extends StatefulWidget {
bool get _passwordNoBorder => variant == RTextFieldVariant.passwordNoBorder;
InputBorder get _inputBorder => _noBorder || _passwordNoBorder
? InputBorder.none
: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide: BorderSide(color: borderColor ?? AppColor.lightGreyDarkActive, width: 1),
);
InputBorder get _inputBorder => OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide: _noBorder || _passwordNoBorder
? BorderSide.none
: BorderSide(color: borderColor ?? AppColor.darkGreyLight, width: 1),
);
}
class _RTextFieldState extends State<RTextField> {
@@ -142,6 +144,7 @@ class _RTextFieldState extends State<RTextField> {
inputFormatters: widget.inputFormatters,
enabled: widget.enabled,
obscureText: obscure,
onTap: widget.onTap,
onTapOutside: (_) => FocusScope.of(context).unfocus(),
onFieldSubmitted: widget.onSubmitted,
maxLength: widget.maxLength,

View File

@@ -7,6 +7,9 @@ class OverlayDropdownWidget<T> extends StatefulWidget {
final List<T> items;
final T? selectedItem;
final T? initialValue;
final int? height;
final Color? background;
final bool? hasDropIcon;
final Widget Function(T item) itemBuilder;
final Widget Function(T? selected) labelBuilder;
final void Function(T selected)? onChanged;
@@ -21,6 +24,9 @@ class OverlayDropdownWidget<T> extends StatefulWidget {
this.onChanged,
this.selectedItem,
this.contentPadding,
this.height,
this.background,
this.hasDropIcon = true,
});
@override
@@ -58,7 +64,6 @@ class _OverlayDropdownState<T> extends State<OverlayDropdownWidget<T>> {
elevation: 4,
borderRadius: BorderRadius.circular(8),
child: Container(
decoration: BoxDecoration(
color: AppColor.bgLight,
border: Border.all(color: AppColor.darkGreyLight),
@@ -81,7 +86,9 @@ class _OverlayDropdownState<T> extends State<OverlayDropdownWidget<T>> {
_removeOverlay();
},
child: Padding(
padding: widget.contentPadding ?? const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
padding:
widget.contentPadding ??
const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
child: widget.itemBuilder(item),
),
);
@@ -120,19 +127,25 @@ class _OverlayDropdownState<T> extends State<OverlayDropdownWidget<T>> {
_isOpen.value ? _removeOverlay() : _showOverlay();
},
child: Container(
height: 40,
height: widget.height?.toDouble() ?? 40,
width: Get.width,
padding: const EdgeInsets.symmetric(horizontal: 12),
decoration: BoxDecoration(
color: AppColor.bgLight,
color: widget.background ?? AppColor.bgLight,
border: Border.all(color: AppColor.darkGreyLight),
borderRadius: BorderRadius.circular(8),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
widget.labelBuilder(selectedItem),
Icon(_isOpen.value ? CupertinoIcons.chevron_up : CupertinoIcons.chevron_down, size: 14),
Expanded(child: widget.labelBuilder(selectedItem)),
Visibility(
visible: widget.hasDropIcon!,
child: Icon(
_isOpen.value ? CupertinoIcons.chevron_up : CupertinoIcons.chevron_down,
size: 14,
),
),
],
),
),
@@ -140,7 +153,6 @@ class _OverlayDropdownState<T> extends State<OverlayDropdownWidget<T>> {
}
}
class OverlayDropdownWidget2<T> extends StatefulWidget {
final List<T> items;
final T? selectedItem;
@@ -208,65 +220,73 @@ class _OverlayDropdownState2<T> extends State<OverlayDropdownWidget2<T>> {
child: Material(
elevation: 4,
borderRadius: BorderRadius.circular(8),
child: Obx(() => Container(
decoration: BoxDecoration(
color: AppColor.bgLight,
border: Border.all(color: AppColor.darkGreyLight),
borderRadius: BorderRadius.circular(8),
),
constraints: BoxConstraints(maxHeight: 300),
child: Column(
children: [
Padding(
padding: const EdgeInsets.all(8),
child: TextField(
controller: _searchController,
decoration: const InputDecoration(
hintText: 'جستجو...',
isDense: true,
contentPadding: EdgeInsets.symmetric(horizontal: 12, vertical: 8),
border: OutlineInputBorder(),
),
onChanged: (query) {
_filteredItems.value = widget.items
.where((item) =>
widget.itemToString?.call(item).toLowerCase().contains(query.toLowerCase()) ??
false)
.toList();
},
),
),
if (_filteredItems.isEmpty)
const Padding(
padding: EdgeInsets.all(16.0),
child: Text("نتیجه‌ای یافت نشد."),
),
if (_filteredItems.isNotEmpty)
Expanded(
child: ListView(
shrinkWrap: true,
physics: const BouncingScrollPhysics(),
children: _filteredItems.map((item) {
return InkWell(
onTap: () {
widget.onChanged?.call(item);
setState(() {
selectedItem = item;
});
_removeOverlay();
},
child: Padding(
padding: widget.contentPadding ??
const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
child: widget.itemBuilder(item),
),
);
}).toList(),
child: Obx(
() => Container(
decoration: BoxDecoration(
color: AppColor.bgLight,
border: Border.all(color: AppColor.darkGreyLight),
borderRadius: BorderRadius.circular(8),
),
constraints: BoxConstraints(maxHeight: 300),
child: Column(
children: [
Padding(
padding: const EdgeInsets.all(8),
child: TextField(
controller: _searchController,
decoration: const InputDecoration(
hintText: 'جستجو...',
isDense: true,
contentPadding: EdgeInsets.symmetric(horizontal: 12, vertical: 8),
border: OutlineInputBorder(),
),
onChanged: (query) {
_filteredItems.value = widget.items
.where(
(item) =>
widget.itemToString
?.call(item)
.toLowerCase()
.contains(query.toLowerCase()) ??
false,
)
.toList();
},
),
),
],
if (_filteredItems.isEmpty)
const Padding(
padding: EdgeInsets.all(16.0),
child: Text("نتیجه‌ای یافت نشد."),
),
if (_filteredItems.isNotEmpty)
Expanded(
child: ListView(
shrinkWrap: true,
physics: const BouncingScrollPhysics(),
children: _filteredItems.map((item) {
return InkWell(
onTap: () {
widget.onChanged?.call(item);
setState(() {
selectedItem = item;
});
_removeOverlay();
},
child: Padding(
padding:
widget.contentPadding ??
const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
child: widget.itemBuilder(item),
),
);
}).toList(),
),
),
],
),
),
)),
),
),
),
],
@@ -309,13 +329,18 @@ class _OverlayDropdownState2<T> extends State<OverlayDropdownWidget2<T>> {
border: Border.all(color: AppColor.darkGreyLight),
borderRadius: BorderRadius.circular(8),
),
child: Obx(() => Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
widget.labelBuilder(selectedItem),
Icon(_isOpen.value ? CupertinoIcons.chevron_up : CupertinoIcons.chevron_down, size: 14),
],
)),
child: Obx(
() => Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(child: widget.labelBuilder(selectedItem)),
Icon(
_isOpen.value ? CupertinoIcons.chevron_up : CupertinoIcons.chevron_down,
size: 14,
),
],
),
),
),
),
);