diff --git a/assets/icons/gps.svg b/assets/icons/gps.svg
new file mode 100644
index 0000000..de896a0
--- /dev/null
+++ b/assets/icons/gps.svg
@@ -0,0 +1,3 @@
+
diff --git a/assets/vec/gps.svg.vec b/assets/vec/gps.svg.vec
new file mode 100644
index 0000000..4508f5d
Binary files /dev/null and b/assets/vec/gps.svg.vec differ
diff --git a/features/supervision/lib/presentation/filter/logic.dart b/features/supervision/lib/presentation/filter/logic.dart
index 168fbaa..521ed9c 100644
--- a/features/supervision/lib/presentation/filter/logic.dart
+++ b/features/supervision/lib/presentation/filter/logic.dart
@@ -1,22 +1,32 @@
import 'dart:async';
-import 'dart:developer';
+import 'package:flutter/animation.dart';
+import 'package:flutter_map/flutter_map.dart';
+import 'package:flutter_map_animations/flutter_map_animations.dart';
import 'package:geolocator/geolocator.dart';
-import 'package:get/get.dart';
import 'package:latlong2/latlong.dart';
+import 'package:rasadyar_core/core.dart';
import 'package:supervision/data/utils/marker_generator.dart';
-class SupervisionFilterLogic extends GetxController {
+enum BottomSheetStep { filter, markerSelected, markerDetails }
+
+class SupervisionFilterLogic extends GetxController
+ with GetTickerProviderStateMixin {
Rx currentLocation = LatLng(35.824891, 50.948025).obs;
RxList allMarkers = [].obs;
RxList markers = [].obs;
Timer? _debounceTimer;
+ RxBool isLoading = false.obs;
+ RxInt filterIndex = 0.obs;
+ RxInt showIndex = 0.obs;
+ Rx bottomSheetStep = BottomSheetStep.filter.obs;
+ Rx mapController = MapController().obs;
+ late final AnimatedMapController animatedMapController;
-
- RxBool isSelected = false.obs;
+ late Rx sheetController;
Future determineCurrentPosition() async {
bool serviceEnabled;
@@ -45,6 +55,12 @@ class SupervisionFilterLogic extends GetxController {
final latLng = LatLng(position.latitude, position.longitude);
currentLocation.value = latLng;
markers.add(latLng);
+ animatedMapController.animateTo(
+ dest: latLng,
+ zoom: 18,
+ curve: Curves.easeInOut,
+ duration: const Duration(seconds: 1),
+ );
}
void debouncedUpdateVisibleMarkers({required LatLng center}) {
@@ -77,13 +93,50 @@ class SupervisionFilterLogic extends GetxController {
Future generatedMarkers() async {
final generatedMarkers = await generateLocationsUsingCompute(100000);
allMarkers.value = generatedMarkers;
+ }
+ @override
+ void onInit() {
+ super.onInit();
+ animatedMapController = AnimatedMapController(
+ vsync: this,
+ duration: const Duration(milliseconds: 500),
+ curve: Curves.easeInOut,
+ cancelPreviousAnimations: true,
+ );
+ sheetController =
+ DraggableBottomSheetController(
+ initialVisibility: false,
+ initialHeight: 300,
+ minHeight: 50,
+ maxHeight: 600,
+ ).obs;
+
+ bottomSheetStep.listen((data) {
+ if (data == BottomSheetStep.filter) {
+ sheetController =
+ DraggableBottomSheetController(
+ initialVisibility: false,
+ initialHeight: 300,
+ minHeight: 50,
+ maxHeight: 600,
+ ).obs;
+ } else if (data == BottomSheetStep.markerSelected) {
+ sheetController =
+ DraggableBottomSheetController(
+ initialVisibility: true,
+ initialHeight: 150,
+ minHeight: 50,
+ maxHeight: 150,
+ ).obs;
+ sheetController.refresh();
+ }
+ });
}
@override
void onReady() {
super.onReady();
-
determineCurrentPosition();
generatedMarkers();
}
diff --git a/features/supervision/lib/presentation/filter/view.dart b/features/supervision/lib/presentation/filter/view.dart
index 1d0b6ac..034b0e5 100644
--- a/features/supervision/lib/presentation/filter/view.dart
+++ b/features/supervision/lib/presentation/filter/view.dart
@@ -24,6 +24,7 @@ class SupervisionFilterPage extends GetView {
children: [
ObxValue((currentLocation) {
return FlutterMap(
+ mapController: controller.animatedMapController.mapController,
options: MapOptions(
initialCenter: currentLocation.value,
initialZoom: 18,
@@ -45,10 +46,18 @@ class SupervisionFilterPage extends GetView {
.map(
(marker) => Marker(
point: marker,
- child: const Icon(
- Icons.location_on,
- color: Colors.red,
- size: 30,
+
+ child: IconButton(
+ onPressed: () {
+ controller.bottomSheetStep.value =
+ BottomSheetStep.markerSelected;
+
+ },
+ icon: Icon(
+ Icons.location_on,
+ color: Colors.red,
+ size: 30,
+ ),
),
),
)
@@ -59,116 +68,274 @@ class SupervisionFilterPage extends GetView {
);
}, controller.currentLocation),
+ Positioned(
+ right: 10,
+ bottom: 150,
+ child: ObxValue((data) {
+ return RFab.small(
+ backgroundColor: AppColor.greenNormal,
+ isLoading: data.value,
+ icon: vecWidget(Assets.vecGpsSvg),
+ onPressed: () {
+ controller.isLoading.value = true;
+ controller.determineCurrentPosition().then(
+ (value) =>
+ controller.isLoading.value = !controller.isLoading.value,
+ );
+ },
+ );
+ }, controller.isLoading),
+ ),
Positioned(
right: 10,
bottom: 100,
- child: RFab.smallAdd(
+ child: RFab.small(
+ backgroundColor: AppColor.blueNormal,
+ icon: vecWidget(Assets.vecFilterSvg, width: 24, height: 24),
onPressed: () {
- controller.isSelected.value = !controller.isSelected.value;
+ controller.sheetController.value.toggle();
},
),
),
-
Positioned(
bottom: 0,
left: 0,
right: 0,
- child: ObxValue((isSelected) {
- return DraggableBottomSheet(isVisible: isSelected.value);
- }, controller.isSelected),
+ child: ObxValue((data) {
+ return DraggableBottomSheet(
+ controller: data.value,
+ child: ObxValue((data) {
+ if (data.value == BottomSheetStep.filter) {
+ return filterWidget();
+ } else if (data.value == BottomSheetStep.markerSelected) {
+ return const SizedBox(
+ height: 150,
+ child: Center(child: Text('Marker Selected')),
+ );
+ } else {
+ return const SizedBox(
+ height: 150,
+ child: Center(child: Text('Noting')),
+ );
+ }
+ }, controller.bottomSheetStep),
+ );
+ }, controller.sheetController),
),
],
);
}
-}
-class DraggableBottomSheet extends StatefulWidget {
- final bool isVisible;
- final double initialHeight;
- final double minHeight;
- final double maxHeight;
-
- const DraggableBottomSheet({
- super.key,
- required this.isVisible,
- this.initialHeight = 200,
- this.minHeight = 0,
- this.maxHeight = 700,
- });
-
- @override
- State createState() => _DraggableBottomSheetState();
-}
-
-class _DraggableBottomSheetState extends State {
- late double _sheetHeight;
- bool isWidgetVisible = false;
-
- @override
- void initState() {
- super.initState();
- _sheetHeight = widget.initialHeight;
- isWidgetVisible = widget.isVisible;
- }
-
- void _onVerticalDragUpdate(DragUpdateDetails details) {
- setState(() {
- _sheetHeight -= details.delta.dy;
- _sheetHeight = _sheetHeight.clamp(widget.minHeight, widget.maxHeight);
- });
- }
-
- @override
- void didUpdateWidget(covariant DraggableBottomSheet oldWidget) {
- if (_sheetHeight <= oldWidget.initialHeight) {
- setState(() {
- isWidgetVisible = !isWidgetVisible;
- });
- }
-
- super.didUpdateWidget(oldWidget);
- }
-
- @override
- Widget build(BuildContext context) {
- return AnimatedPositioned(
- duration: const Duration(milliseconds: 300),
- curve: Curves.easeOut,
- bottom: widget.isVisible ? 0 : -widget.maxHeight,
- left: 0,
- right: 0,
- child: GestureDetector(
- onVerticalDragUpdate: _onVerticalDragUpdate,
- child: Container(
- height: _sheetHeight,
- decoration: const BoxDecoration(
- color: Colors.white,
- borderRadius: BorderRadius.vertical(top: Radius.circular(50)),
- ),
- child: Column(
+ Padding filterWidget() {
+ return Padding(
+ padding: const EdgeInsets.all(20.0),
+ child: Column(
+ spacing: 16,
+ children: [
+ Row(
+ mainAxisAlignment: MainAxisAlignment.spaceAround,
+ spacing: 16,
children: [
- const SizedBox(height: 10),
Container(
- width: 40,
- height: 5,
+ width: 100,
+ height: 64,
+ clipBehavior: Clip.antiAlias,
decoration: BoxDecoration(
- color: Colors.grey[400],
- borderRadius: BorderRadius.circular(5),
+ color: AppColor.blueLight,
+ borderRadius: BorderRadius.circular(8),
+ border: Border.all(width: 1, color: AppColor.blackLightHover),
+ ),
+ child: Column(
+ mainAxisAlignment: MainAxisAlignment.center,
+ spacing: 4,
+ children: [
+ Text('دامداران', style: AppFonts.yekan10),
+ Text('183 عدد', style: AppFonts.yekan13Bold),
+ ],
),
),
- const SizedBox(height: 10),
- Expanded(
- child: ListView.builder(
- itemCount: 15,
- itemBuilder:
- (context, index) =>
- ListTile(title: Text('Item ${index + 1}')),
+ Container(
+ width: 100,
+ height: 64,
+ clipBehavior: Clip.antiAlias,
+ decoration: BoxDecoration(
+ color: AppColor.greenLight,
+ borderRadius: BorderRadius.circular(8),
+ border: Border.all(width: 1, color: AppColor.blackLightHover),
+ ),
+ child: Column(
+ mainAxisAlignment: MainAxisAlignment.center,
+ spacing: 4,
+ children: [
+ Text('مرغداران', style: AppFonts.yekan10),
+ Text('183 عدد', style: AppFonts.yekan13Bold),
+ ],
+ ),
+ ),
+ Container(
+ width: 100,
+ height: 64,
+ clipBehavior: Clip.antiAlias,
+ decoration: BoxDecoration(
+ color: AppColor.blueLight,
+ borderRadius: BorderRadius.circular(8),
+ border: Border.all(width: 1, color: AppColor.blackLightHover),
+ ),
+ child: Column(
+ mainAxisAlignment: MainAxisAlignment.center,
+ spacing: 4,
+ children: [
+ Text('اصناف', style: AppFonts.yekan10),
+ Text('183 عدد', style: AppFonts.yekan13Bold),
+ ],
),
),
],
),
- ),
+
+ Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ spacing: 12,
+ children: [
+ Text(
+ 'فیلتر نمایش',
+ textAlign: TextAlign.center,
+ style: AppFonts.yekan13.copyWith(color: AppColor.blueNormal),
+ ),
+ ObxValue((data) {
+ return Row(
+ mainAxisAlignment: MainAxisAlignment.start,
+ crossAxisAlignment: CrossAxisAlignment.center,
+ spacing: 8,
+ children: [
+ customChip(
+ isSelected: data.value == 0,
+ onTap: (data) {
+ controller.filterIndex.value = data;
+ },
+ index: 0,
+ title: 'دامداران',
+ ),
+ customChip(
+ isSelected: data.value == 1,
+ title: 'مرغداران',
+ onTap: (data) {
+ controller.filterIndex.value = data;
+ },
+ index: 1,
+ ),
+ customChip(
+ isSelected: data.value == 2,
+ title: 'اصناف',
+ onTap: (data) {
+ controller.filterIndex.value = data;
+ },
+ index: 2,
+ ),
+ ],
+ );
+ }, controller.filterIndex),
+ ],
+ ),
+
+ Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ spacing: 12,
+ children: [
+ Text(
+ 'نمایش',
+ textAlign: TextAlign.center,
+ style: AppFonts.yekan13.copyWith(color: AppColor.blueNormal),
+ ),
+ ObxValue((data) {
+ return SingleChildScrollView(
+ scrollDirection: Axis.horizontal,
+ child: Row(
+ mainAxisAlignment: MainAxisAlignment.start,
+ crossAxisAlignment: CrossAxisAlignment.center,
+ spacing: 8,
+ children: [
+ customChip(
+ isSelected: data.value == 0,
+ title: 'نمایش همه',
+ onTap: (data) {
+ controller.showIndex.value = data;
+ },
+ index: 0,
+ ),
+ customChip(
+ isSelected: data.value == 1,
+ title: 'دارای تراکنش',
+ onTap: (data) {
+ controller.showIndex.value = data;
+ },
+ index: 1,
+ ),
+ customChip(
+ isSelected: data.value == 2,
+ title: 'بازرسی شده ها',
+ onTap: (data) {
+ controller.showIndex.value = data;
+ },
+ index: 2,
+ ),
+ customChip(
+ isSelected: data.value == 3,
+ title: 'بازرسی نشده ها',
+ onTap: (data) {
+ controller.showIndex.value = data;
+ },
+ index: 3,
+ ),
+ customChip(
+ isSelected: data.value == 4,
+ title: 'متخلفین',
+ onTap: (data) {
+ controller.showIndex.value = data;
+ },
+ index: 4,
+ ),
+ ],
+ ),
+ );
+ }, controller.showIndex),
+ ],
+ ),
+ ],
),
);
}
}
+
+Widget customChip({
+ bool isSelected = false,
+ required String title,
+ required int index,
+ required Function(int) onTap,
+}) {
+ return GestureDetector(
+ onTap: () {
+ onTap.call(index);
+ },
+ child: Container(
+ padding: EdgeInsets.symmetric(horizontal: 20, vertical: 10),
+ clipBehavior: Clip.antiAlias,
+ decoration: BoxDecoration(
+ color: isSelected ? AppColor.blueNormal : AppColor.whiteGreyNormal,
+ borderRadius: BorderRadius.circular(8),
+ border:
+ isSelected
+ ? Border.fromBorderSide(BorderSide.none)
+ : Border.all(width: 0.25, color: const Color(0xFFB0B0B0)),
+ ),
+ child: Text(
+ title,
+ textAlign: TextAlign.center,
+ style:
+ isSelected
+ ? AppFonts.yekan10.copyWith(color: AppColor.whiteLight)
+ : AppFonts.yekan10,
+ ),
+ ),
+ );
+}
diff --git a/features/supervision/pubspec.lock b/features/supervision/pubspec.lock
index 05a3d7f..3ee017f 100644
--- a/features/supervision/pubspec.lock
+++ b/features/supervision/pubspec.lock
@@ -102,6 +102,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "8.1.1"
+ flutter_map_animations:
+ dependency: "direct main"
+ description:
+ name: flutter_map_animations
+ sha256: bf583863561861aaaf4854ae7ed8940d79bea7d32918bf7a85d309b25235a09e
+ url: "https://pub.dev"
+ source: hosted
+ version: "0.9.0"
flutter_svg:
dependency: transitive
description:
diff --git a/features/supervision/pubspec.yaml b/features/supervision/pubspec.yaml
index bc13c6f..7dd0679 100644
--- a/features/supervision/pubspec.yaml
+++ b/features/supervision/pubspec.yaml
@@ -12,6 +12,7 @@ dependencies:
rasadyar_core:
path: ./../../packages/core
flutter_map: ^8.1.1
+ flutter_map_animations: ^0.9.0
location: ^8.0.0
latlong2: ^0.9.1
geolocator: ^13.0.4
diff --git a/lib/presentation/common/assets.dart b/lib/presentation/common/assets.dart
index 705ebe1..4e91d17 100644
--- a/lib/presentation/common/assets.dart
+++ b/lib/presentation/common/assets.dart
@@ -9,6 +9,7 @@ class Assets {
static const String iconsDownload = 'assets/icons/download.svg';
static const String iconsEdit = 'assets/icons/edit.svg';
static const String iconsFilter = 'assets/icons/filter.svg';
+ static const String iconsGps = 'assets/icons/gps.svg';
static const String iconsKey = 'assets/icons/key.svg';
static const String iconsMap = 'assets/icons/map.svg';
static const String iconsMapMarker = 'assets/icons/map_marker.svg';
@@ -25,6 +26,7 @@ class Assets {
static const String vecDownloadSvg = 'assets/vec/download.svg.vec';
static const String vecEditSvg = 'assets/vec/edit.svg.vec';
static const String vecFilterSvg = 'assets/vec/filter.svg.vec';
+ static const String vecGpsSvg = 'assets/vec/gps.svg.vec';
static const String vecKeySvg = 'assets/vec/key.svg.vec';
static const String vecMapMarkerSvg = 'assets/vec/map_marker.svg.vec';
static const String vecMapSvg = 'assets/vec/map.svg.vec';
diff --git a/packages/core/lib/presentation/common/assets.dart b/packages/core/lib/presentation/common/assets.dart
index 705ebe1..4e91d17 100644
--- a/packages/core/lib/presentation/common/assets.dart
+++ b/packages/core/lib/presentation/common/assets.dart
@@ -9,6 +9,7 @@ class Assets {
static const String iconsDownload = 'assets/icons/download.svg';
static const String iconsEdit = 'assets/icons/edit.svg';
static const String iconsFilter = 'assets/icons/filter.svg';
+ static const String iconsGps = 'assets/icons/gps.svg';
static const String iconsKey = 'assets/icons/key.svg';
static const String iconsMap = 'assets/icons/map.svg';
static const String iconsMapMarker = 'assets/icons/map_marker.svg';
@@ -25,6 +26,7 @@ class Assets {
static const String vecDownloadSvg = 'assets/vec/download.svg.vec';
static const String vecEditSvg = 'assets/vec/edit.svg.vec';
static const String vecFilterSvg = 'assets/vec/filter.svg.vec';
+ static const String vecGpsSvg = 'assets/vec/gps.svg.vec';
static const String vecKeySvg = 'assets/vec/key.svg.vec';
static const String vecMapMarkerSvg = 'assets/vec/map_marker.svg.vec';
static const String vecMapSvg = 'assets/vec/map.svg.vec';
diff --git a/packages/core/lib/presentation/widget/buttons/fab.dart b/packages/core/lib/presentation/widget/buttons/fab.dart
index c7c768e..3dfe651 100644
--- a/packages/core/lib/presentation/widget/buttons/fab.dart
+++ b/packages/core/lib/presentation/widget/buttons/fab.dart
@@ -5,16 +5,15 @@ import 'package:rasadyar_core/presentation/utils/color_utils.dart';
import 'package:rasadyar_core/presentation/widget/vec_widget.dart';
class RFab extends StatefulWidget {
-
-
final VoidCallback? onPressed;
Color? foregroundColor;
Color? backgroundColor;
Color? disabledForegroundColor;
Color? disabledBackgroundColor;
- double? radius;
+ double radius;
ShapeBorder? shapeBorder;
Widget? icon;
+ bool isLoading;
@override
State createState() => _RFabState();
@@ -177,6 +176,7 @@ class RFab extends StatefulWidget {
required this.icon,
required this.backgroundColor,
super.key,
+ this.isLoading = false,
}) : radius = 40.0,
foregroundColor = Colors.white;
@@ -184,6 +184,7 @@ class RFab extends StatefulWidget {
required this.onPressed,
required this.icon,
required this.backgroundColor,
+ this.isLoading = false,
super.key,
}) : radius = 56.0,
foregroundColor = Colors.white;
@@ -195,7 +196,7 @@ class _RFabState extends State {
@override
Widget build(BuildContext context) {
return ElevatedButton(
- onPressed: widget.onPressed,
+ onPressed: widget.isLoading == false ? widget.onPressed : null,
style: ButtonStyle(
side: WidgetStateProperty.all(BorderSide.none),
backgroundColor: WidgetStateProperty.resolveWith((states) {
@@ -226,7 +227,19 @@ class _RFabState extends State {
),
padding: WidgetStatePropertyAll(EdgeInsets.zero),
),
- child: widget.icon,
+ child:
+ widget.isLoading
+ ? SizedBox(
+ height: widget.radius / 2,
+ width: widget.radius / 2,
+ child: CircularProgressIndicator(
+ strokeWidth: 2.5,
+ valueColor: AlwaysStoppedAnimation(
+ widget.foregroundColor ?? Colors.white,
+ ),
+ ),
+ )
+ : widget.icon,
);
}
}
diff --git a/packages/core/lib/presentation/widget/draggable_bottom_sheet/draggable_bottom_sheet.dart b/packages/core/lib/presentation/widget/draggable_bottom_sheet/draggable_bottom_sheet.dart
new file mode 100644
index 0000000..b61941c
--- /dev/null
+++ b/packages/core/lib/presentation/widget/draggable_bottom_sheet/draggable_bottom_sheet.dart
@@ -0,0 +1,95 @@
+import 'package:flutter/cupertino.dart';
+import 'package:flutter/material.dart';
+import 'package:get/get.dart';
+import 'package:rasadyar_core/presentation/widget/draggable_bottom_sheet/draggable_bottom_sheet_controller.dart';
+
+class DraggableBottomSheet extends StatelessWidget {
+ final DraggableBottomSheetController? controller;
+ final bool isVisible;
+ final double initialHeight;
+ final double minHeight;
+ final double maxHeight;
+ final Widget? child;
+
+ const DraggableBottomSheet({
+ super.key,
+ this.controller,
+ this.isVisible = false,
+ this.initialHeight = 200,
+ this.minHeight = 0,
+ this.maxHeight = 700,
+ this.child,
+ });
+
+ @override
+ Widget build(BuildContext context) {
+ // If no controller is passed, create one locally
+ final DraggableBottomSheetController bottomSheetController =
+ controller ??
+ Get.put(
+ DraggableBottomSheetController(
+ initialVisibility: false, // always start hidden
+ initialHeight: initialHeight,
+ minHeight: minHeight,
+ maxHeight: maxHeight,
+ ),
+ tag: 'local_$hashCode',
+ );
+
+ // Optionally show after first frame if isVisible is true
+ WidgetsBinding.instance.addPostFrameCallback((_) {
+ if (isVisible && !bottomSheetController.isVisible.value) {
+ bottomSheetController.show();
+ }
+ });
+
+ return ObxValue(
+ (data) => AnimatedPositioned(
+ duration: const Duration(milliseconds: 300),
+ curve: Curves.easeOut,
+ bottom: bottomSheetController.isVisible.value ? 0 : -maxHeight,
+ left: 0,
+ right: 0,
+ child: GestureDetector(
+ onVerticalDragUpdate: (DragUpdateDetails details) {
+ bottomSheetController.updateHeight(details.delta.dy);
+ },
+ child: Container(
+ height: data.value,
+ decoration: const BoxDecoration(
+ color: Colors.white,
+ borderRadius: BorderRadius.vertical(top: Radius.circular(50)),
+ ),
+ child: Column(
+ children: [
+ const SizedBox(height: 10),
+
+ /* Container(
+ width: 40,
+ height: 5,
+ decoration: BoxDecoration(
+ color: Colors.grey[400],
+ borderRadius: BorderRadius.circular(5),
+ ),
+ ),*/
+ GestureDetector(
+ onTap: () {
+ bottomSheetController.hide();
+ },
+ behavior: HitTestBehavior.opaque,
+ child: Row(
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [const Icon(CupertinoIcons.chevron_down)],
+ ),
+ ),
+ const SizedBox(height: 10),
+ Expanded(child: child ?? SizedBox.shrink()),
+ ],
+ ),
+ ),
+ ),
+ ),
+ bottomSheetController.currentHeight,
+ );
+ }
+}
diff --git a/packages/core/lib/presentation/widget/draggable_bottom_sheet/draggable_bottom_sheet_controller.dart b/packages/core/lib/presentation/widget/draggable_bottom_sheet/draggable_bottom_sheet_controller.dart
new file mode 100644
index 0000000..eedebc8
--- /dev/null
+++ b/packages/core/lib/presentation/widget/draggable_bottom_sheet/draggable_bottom_sheet_controller.dart
@@ -0,0 +1,76 @@
+import 'package:flutter/foundation.dart';
+import 'package:get/get.dart';
+
+
+class DraggableBottomSheetController extends GetxController {
+ // Observable variables
+ final RxBool isVisible = false.obs;
+ final RxDouble currentHeight = 200.0.obs;
+
+ // Configuration values
+ final double initialHeight;
+ final double minHeight;
+ final double maxHeight;
+
+ DraggableBottomSheetController({
+ bool initialVisibility = false,
+ this.initialHeight = 200,
+ this.minHeight = 0,
+ this.maxHeight = 700,
+ }) {
+ isVisible.value = initialVisibility;
+ currentHeight.value = initialHeight;
+ }
+
+ // Show the bottom sheet
+ void show() {
+ if (!isVisible.value) {
+ isVisible.value = true;
+ currentHeight.value = initialHeight;
+ }
+ }
+
+ // Hide the bottom sheet
+ void hide() {
+ if (isVisible.value) {
+ isVisible.value = false;
+ }
+ }
+
+ // Toggle visibility
+ void toggle() {
+ isVisible.value = !isVisible.value;
+ if (isVisible.value) {
+ currentHeight.value = initialHeight;
+ }
+ }
+
+ // Set a specific height for the bottom sheet
+ void setHeight(double height) {
+ final clampedHeight = height.clamp(minHeight, maxHeight);
+ if (currentHeight.value != clampedHeight) {
+ currentHeight.value = clampedHeight;
+ }
+ }
+
+ // Update height (usually called during drag)
+ void updateHeight(double delta) {
+ final newHeight = currentHeight.value - delta;
+ if(newHeight < minHeight) {
+ hide();
+ return;
+ }
+ currentHeight.value = newHeight.clamp(minHeight, maxHeight);
+ }
+
+ // Expand to maximum height
+ void expandFully() {
+ currentHeight.value = maxHeight;
+ isVisible.value = true;
+ }
+
+ // Collapse to minimum height
+ void collapse() {
+ currentHeight.value = minHeight;
+ }
+}
\ No newline at end of file
diff --git a/packages/core/lib/presentation/widget/widget.dart b/packages/core/lib/presentation/widget/widget.dart
index 2e060ee..076a534 100644
--- a/packages/core/lib/presentation/widget/widget.dart
+++ b/packages/core/lib/presentation/widget/widget.dart
@@ -1,2 +1,4 @@
export 'vec_widget.dart';
export 'bottom_navigation/bottom_navigation_1.dart';
+export 'draggable_bottom_sheet/draggable_bottom_sheet.dart';
+export 'draggable_bottom_sheet/draggable_bottom_sheet_controller.dart';
diff --git a/pubspec.lock b/pubspec.lock
index c5b9b9f..ef4da26 100644
--- a/pubspec.lock
+++ b/pubspec.lock
@@ -246,6 +246,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "8.1.1"
+ flutter_map_animations:
+ dependency: transitive
+ description:
+ name: flutter_map_animations
+ sha256: bf583863561861aaaf4854ae7ed8940d79bea7d32918bf7a85d309b25235a09e
+ url: "https://pub.dev"
+ source: hosted
+ version: "0.9.0"
flutter_svg:
dependency: "direct main"
description: