feat : request and request tagging

This commit is contained in:
2025-05-25 16:54:43 +03:30
parent 276c8dd1fe
commit 45778a9866
23 changed files with 655 additions and 145 deletions

View File

@@ -13,6 +13,7 @@ class RAppBar extends StatelessWidget implements PreferredSizeWidget {
final TextStyle? titleTextStyle;
final VoidCallback? onBackPressed;
final List<Widget>? additionalActions;
final int? leadingWidth;
final Widget? leading;
const RAppBar({
@@ -24,8 +25,9 @@ class RAppBar extends StatelessWidget implements PreferredSizeWidget {
this.onBackPressed,
this.additionalActions,
this.leading,
this.hasBack = false,
this.hasBack = true,
this.centerTitle = false,
this.leadingWidth
});
@override
@@ -41,11 +43,13 @@ class RAppBar extends StatelessWidget implements PreferredSizeWidget {
titleTextStyle ??
AppFonts.yekan16.copyWith(color:Colors.white),
title: Text(title),
leadingWidth: leadingWidth?.toDouble(),
leading:leading!=null ? Padding(
padding: const EdgeInsets.only(right: 16),
child: leading,
) : null,
titleSpacing: 8,
actions: [
if (additionalActions != null) ...additionalActions!,
if(hasBack)...{

View File

@@ -1,6 +1,7 @@
import 'package:flutter/material.dart';
import 'package:rasadyar_core/presentation/common/app_color.dart';
import 'package:rasadyar_core/presentation/utils/color_utils.dart';
import '../../common/assets.gen.dart';
class RFab extends StatefulWidget {
@@ -21,10 +22,7 @@ class RFab extends StatefulWidget {
RFab.smallAdd({required VoidCallback? onPressed, Key? key})
: this.small(
onPressed: onPressed,
icon: Assets.vec.addSvg.svg(
width: 20,
height: 20,
),
icon: Assets.vec.addSvg.svg(width: 20, height: 20),
backgroundColor: AppColor.greenNormal,
key: key,
);
@@ -32,10 +30,7 @@ class RFab extends StatefulWidget {
RFab.add({required VoidCallback? onPressed, Key? key})
: this(
onPressed: onPressed,
icon: Assets.vec.addSvg.svg(
width: 20,
height: 20,
),
icon: Assets.vec.addSvg.svg(width: 40, height: 40),
backgroundColor: AppColor.greenNormal,
key: key,
);
@@ -46,10 +41,7 @@ class RFab extends StatefulWidget {
RFab.smallEdit({required VoidCallback? onPressed, Key? key})
: this.small(
onPressed: onPressed,
icon: Assets.vec.addSvg.svg(
width: 20,
height: 20,
),
icon: Assets.vec.addSvg.svg(width: 20, height: 20),
backgroundColor: AppColor.blueNormal,
key: key,
);
@@ -57,10 +49,7 @@ class RFab extends StatefulWidget {
RFab.edit({required VoidCallback? onPressed, Key? key})
: this(
onPressed: onPressed,
icon: Assets.vec.addSvg.svg(
width: 20,
height: 20,
),
icon: Assets.vec.addSvg.svg(width: 20, height: 20),
backgroundColor: AppColor.blueNormal,
key: key,
);
@@ -71,10 +60,7 @@ class RFab extends StatefulWidget {
RFab.smallDelete({required VoidCallback? onPressed, Key? key})
: this.small(
onPressed: onPressed,
icon: Assets.vec.trashSvg.svg(
width: 20,
height: 20,
),
icon: Assets.vec.trashSvg.svg(width: 20, height: 20),
backgroundColor: AppColor.redNormal,
key: key,
);
@@ -82,10 +68,7 @@ class RFab extends StatefulWidget {
RFab.delete({required VoidCallback? onPressed, Key? key})
: this(
onPressed: onPressed,
icon: Assets.vec.trashSvg.svg(
width: 20,
height: 20,
),
icon: Assets.vec.trashSvg.svg(width: 20, height: 20),
backgroundColor: AppColor.redNormal,
key: key,
);
@@ -96,10 +79,7 @@ class RFab extends StatefulWidget {
RFab.smallAction({required VoidCallback? onPressed, Key? key})
: this.small(
onPressed: onPressed,
icon: Assets.vec.scanSvg.svg(
width: 20,
height: 20,
),
icon: Assets.vec.scanSvg.svg(width: 20, height: 20),
backgroundColor: AppColor.blueNormal,
key: key,
);
@@ -107,10 +87,7 @@ class RFab extends StatefulWidget {
RFab.action({required VoidCallback? onPressed, Key? key})
: this(
onPressed: onPressed,
icon: Assets.vec.scanSvg.svg(
width: 20,
height: 20,
),
icon: Assets.vec.scanSvg.svg(width: 20, height: 20),
backgroundColor: AppColor.blueNormal,
key: key,
);
@@ -121,10 +98,7 @@ class RFab extends StatefulWidget {
RFab.smallFilter({required VoidCallback? onPressed, Key? key})
: this.small(
onPressed: onPressed,
icon: Assets.vec.scanSvg.svg(
width: 20,
height: 20,
),
icon: Assets.vec.scanSvg.svg(width: 20, height: 20),
backgroundColor: AppColor.blueNormal,
key: key,
);
@@ -132,10 +106,7 @@ class RFab extends StatefulWidget {
RFab.filter({required VoidCallback? onPressed, Key? key})
: this(
onPressed: onPressed,
icon: Assets.vec.scanSvg.svg(
width: 20,
height: 20,
),
icon: Assets.vec.scanSvg.svg(width: 20, height: 20),
backgroundColor: AppColor.blueNormal,
key: key,
);
@@ -146,10 +117,7 @@ class RFab extends StatefulWidget {
RFab.smallDownload({required VoidCallback? onPressed, Key? key})
: this.small(
onPressed: onPressed,
icon: Assets.vec.downloadSvg.svg(
width: 20,
height: 20,
),
icon: Assets.vec.downloadSvg.svg(width: 20, height: 20),
backgroundColor: AppColor.blueNormal,
key: key,
);
@@ -157,10 +125,7 @@ class RFab extends StatefulWidget {
RFab.download({required VoidCallback? onPressed, Key? key})
: this(
onPressed: onPressed,
icon: Assets.vec.downloadSvg.svg(
width: 20,
height: 20,
),
icon: Assets.vec.downloadSvg.svg(width: 20, height: 20),
backgroundColor: AppColor.blueNormal,
key: key,
);
@@ -171,10 +136,7 @@ class RFab extends StatefulWidget {
RFab.smallExcel({required VoidCallback? onPressed, Key? key})
: this.small(
onPressed: onPressed,
icon: Assets.vec.excelDownloadSvg.svg(
width: 20,
height: 20,
),
icon: Assets.vec.excelDownloadSvg.svg(width: 20, height: 20),
backgroundColor: AppColor.greenDark,
key: key,
);
@@ -182,10 +144,7 @@ class RFab extends StatefulWidget {
RFab.excel({required VoidCallback? onPressed, Key? key})
: this(
onPressed: onPressed,
icon: Assets.vec.excelDownloadSvg.svg(
width: 20,
height: 20,
),
icon: Assets.vec.excelDownloadSvg.svg(width: 20, height: 20),
backgroundColor: AppColor.greenDark,
key: key,
);
@@ -196,10 +155,7 @@ class RFab extends StatefulWidget {
RFab.smallBack({required VoidCallback? onPressed, Key? key})
: this.small(
onPressed: onPressed,
icon: Assets.vec.arrowLeftSvg.svg(
width: 20,
height: 20,
),
icon: Assets.vec.arrowLeftSvg.svg(width: 20, height: 20),
backgroundColor: AppColor.blueNormal,
key: key,
);
@@ -207,10 +163,7 @@ class RFab extends StatefulWidget {
RFab.back({required VoidCallback? onPressed, Key? key})
: this(
onPressed: onPressed,
icon: Assets.vec.arrowLeftSvg.svg(
width: 20,
height: 20,
),
icon: Assets.vec.arrowLeftSvg.svg(width: 20, height: 20),
backgroundColor: AppColor.blueNormal,
key: key,
);

View File

@@ -32,10 +32,10 @@ class ROutlinedElevatedIcon extends StatefulWidget {
Widget? icon;
@override
State<ROutlinedElevatedIcon> createState() => _ROutlinedElevatedStateIcon();
State<ROutlinedElevatedIcon> createState() => _ROutlinedElevatedIconState();
}
class _ROutlinedElevatedStateIcon extends State<ROutlinedElevatedIcon> {
class _ROutlinedElevatedIconState extends State<ROutlinedElevatedIcon> {
@override
Widget build(BuildContext context) {
return OutlinedButton.icon(

View File

@@ -0,0 +1,74 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'draggable_bottom_sheet_controller.dart';
class DraggableBottomSheet2 extends GetView<DraggableBottomSheetController> {
final Color? backgroundColor;
const DraggableBottomSheet2({super.key, this.backgroundColor = Colors.white});
@override
Widget build(BuildContext context) {
WidgetsBinding.instance.addPostFrameCallback((_) {
if (controller.isVisible.value && !controller.isVisible.value) {
controller.show();
}
});
return ObxValue((data) {
return Stack(
children: [
// پس‌زمینه تیره
Positioned.fill(
child: GestureDetector(
onTap: () {},
child: Container(color: Colors.black54),
),
),
// محتوای BottomSheet
AnimatedPositioned(
duration: Duration(milliseconds: 300),
curve: Curves.easeOut,
left: 0,
right: 0,
bottom: 0,
child: GestureDetector(
onVerticalDragUpdate: (details) {
controller.updateHeight(details.primaryDelta);
},
child: Container(
height: 350,
decoration: BoxDecoration(
color: backgroundColor,
borderRadius: BorderRadius.vertical(top: Radius.circular(20)),
boxShadow: [
BoxShadow(
color: Colors.black.withValues(alpha: 0.1),
blurRadius: 10,
),
],
),
child: Column(
children: [
GestureDetector(
onTap: () {},
child: Container(
padding: EdgeInsets.all(10),
child: Icon(Icons.drag_handle),
),
),
Expanded(
child: controller.items[data.value],
),
],
),
),
),
),
],
);
}, controller.currentIndex);
}
}

View File

@@ -129,7 +129,8 @@ import 'draggable_bottom_sheet.dart';
class DraggableBottomSheetController extends GetxController {
final RxBool isVisible = false.obs;
final RxDouble currentHeight = 200.0.obs;
RxList<Widget> items = <Widget>[].obs;
RxInt currentIndex = 0.obs;
late double initialHeight;
late double minHeight;
late double maxHeight;
@@ -158,9 +159,5 @@ class DraggableBottomSheetController extends GetxController {
}
}
@override
void onInit() {
super.onInit();
}
}

View File

@@ -0,0 +1,10 @@
import 'package:flutter/material.dart';
import 'package:latlong2/latlong.dart';
class CustomMarker {
final LatLng point;
final VoidCallback? onTap;
final int? id;
CustomMarker({ this.id, required this.point, this.onTap});
}

View File

@@ -1,6 +1,6 @@
import 'dart:async';
import 'package:flutter/animation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_map/flutter_map.dart';
import 'package:flutter_map_animations/flutter_map_animations.dart';
import 'package:geolocator/geolocator.dart';
@@ -8,13 +8,16 @@ import 'package:get/get.dart';
import 'package:latlong2/latlong.dart';
import 'package:rasadyar_core/utils/logger_utils.dart';
import 'custom_marker.dart';
enum ErrorLocationType { serviceDisabled, permissionDenied, none }
class MapWidgetLogic extends GetxController with GetTickerProviderStateMixin {
Rx<LatLng> currentLocation = LatLng(35.824891, 50.948025).obs;
String tileType = 'https://tile.openstreetmap.org/{z}/{x}/{y}.png';
RxList<LatLng> markers = <LatLng>[].obs;
RxList<CustomMarker> markers = <CustomMarker>[].obs;
RxList<LatLng> allMarkers = <LatLng>[].obs;
Rx<MapController> mapController = MapController().obs;
RxList<ErrorLocationType> errorLocationType = RxList();
@@ -61,6 +64,7 @@ class MapWidgetLogic extends GetxController with GetTickerProviderStateMixin {
@override
void onClose() {
super.onClose();
_debounceTimer?.cancel();
animatedMapController.dispose();
mapController.close();
}
@@ -113,7 +117,9 @@ class MapWidgetLogic extends GetxController with GetTickerProviderStateMixin {
final latLng = LatLng(position.latitude, position.longitude);
currentLocation.value = latLng;
markers.add(latLng);
markers.add(
CustomMarker(id: -1, point: latLng, ),
);
animatedMapController.animateTo(
dest: latLng,
zoom: 18,
@@ -132,7 +138,7 @@ class MapWidgetLogic extends GetxController with GetTickerProviderStateMixin {
'radius': 1000.0,
});
markers.addAll(filtered);
// markers.addAll(filtered);
});
}
@@ -148,4 +154,17 @@ class MapWidgetLogic extends GetxController with GetTickerProviderStateMixin {
.where((marker) => distance(center, marker) <= radiusInMeters)
.toList();
}
void addMarker(CustomMarker marker) {
markers.add(marker);
}
void setMarkers(List<CustomMarker> newMarkers) {
markers.value = newMarkers;
}
void clearMarkers() {
markers.clear();
}
}

View File

@@ -2,7 +2,6 @@ import 'package:flutter/material.dart';
import 'package:flutter_map/flutter_map.dart';
import 'package:geolocator/geolocator.dart';
import 'package:get/get.dart';
import 'package:latlong2/latlong.dart';
import 'package:rasadyar_core/presentation/common/app_color.dart';
import 'package:rasadyar_core/presentation/common/app_fonts.dart';
import 'package:rasadyar_core/presentation/common/assets.gen.dart';
@@ -13,7 +12,16 @@ import 'package:rasadyar_core/presentation/widget/buttons/outline_elevated.dart'
import 'logic.dart';
class MapWidget extends GetView<MapWidgetLogic> {
const MapWidget({super.key});
final VoidCallback? initOnTap;
final Widget? initMarkerWidget;
final Widget markerWidget;
const MapWidget({
this.initOnTap,
this.initMarkerWidget,
required this.markerWidget,
super.key,
});
@override
Widget build(BuildContext context) {
@@ -48,8 +56,7 @@ class MapWidget extends GetView<MapWidgetLogic> {
onPressed: () async {
var res = await Geolocator.openLocationSettings();
if (res) {
var service =
await controller.locationServiceEnabled();
var service = await controller.locationServiceEnabled();
if (service) {
controller.errorLocationType.remove(
ErrorLocationType.serviceDisabled,
@@ -59,7 +66,6 @@ class MapWidget extends GetView<MapWidgetLogic> {
}
},
),
contentPadding: EdgeInsets.all(8),
onWillPop: () async {
return controller.errorLocationType.isEmpty;
@@ -71,9 +77,7 @@ class MapWidget extends GetView<MapWidgetLogic> {
Future.microtask(() {
Get.defaultDialog(
title: 'خطا',
content: const Text(
' دسترسی به سرویس مکان‌یابی غیرفعال است',
),
content: const Text(' دسترسی به سرویس مکان‌یابی غیرفعال است'),
cancel: ROutlinedElevated(
text: 'بررسی مجدد',
width: 120,
@@ -87,9 +91,7 @@ class MapWidget extends GetView<MapWidgetLogic> {
textStyle: AppFonts.yekan16,
width: 120,
onPressed: () async {
var res = await controller.checkPermission(
request: true,
);
var res = await controller.checkPermission(request: true);
if (res) {
controller.errorLocationType.remove(
ErrorLocationType.permissionDenied,
@@ -110,7 +112,10 @@ class MapWidget extends GetView<MapWidgetLogic> {
}
return const SizedBox.shrink();
}, controller.errorLocationType),
_buildMap(), _buildGpsButton(), _buildFilterButton()],
_buildMap(),
_buildGpsButton(),
_buildFilterButton(),
],
);
}
@@ -122,16 +127,30 @@ class MapWidget extends GetView<MapWidgetLogic> {
initialCenter: currentLocation.value,
initialZoom: 18,
onPositionChanged: (camera, hasGesture) {
controller.debouncedUpdateVisibleMarkers(center: camera.center);
if (hasGesture) {
controller.debouncedUpdateVisibleMarkers(center: camera.center);
}
//controller.debouncedUpdateVisibleMarkers(center: camera.center);
},
),
children: [
TileLayer(urlTemplate: controller.tileType),
ObxValue((markers) {
ObxValue((markers) {
return MarkerLayer(
markers:
markers
.map((e) => markerWidget(marker: e, onTap: () {}))
.map(
(e) => Marker(
point: e.point,
child: GestureDetector(
onTap: e.id != -1 ? e.onTap : initOnTap,
child:
e.id != -1
? markerWidget
: initMarkerWidget ?? SizedBox.shrink(),
),
),
)
.toList(),
);
}, controller.markers),
@@ -171,21 +190,18 @@ class MapWidget extends GetView<MapWidgetLogic> {
);
}
Marker markerWidget({required LatLng marker, required VoidCallback onTap}) {
/*Marker markerWidget({required LatLng marker, required VoidCallback onTap}) {
return Marker(
point: marker,
child: GestureDetector(
onTap: onTap,
behavior: HitTestBehavior.opaque,
child: SizedBox(
width: 36,
height: 36,
child:Assets.vec.mapMarkerSvg.svg(
width: 30,
height: 30,
)
width: 36,
height: 36,
child: Assets.vec.mapMarkerSvg.svg(width: 30, height: 30),
),
),
);
}
}*/
}

View File

@@ -6,6 +6,7 @@ export 'buttons/outline_elevated.dart';
export 'buttons/outline_elevated_icon.dart';
export 'buttons/text_button.dart';
export 'draggable_bottom_sheet/draggable_bottom_sheet.dart';
export 'draggable_bottom_sheet/draggable_bottom_sheet2.dart';
export 'draggable_bottom_sheet/draggable_bottom_sheet_controller.dart';
export 'draggable_bottom_sheet/bottom_sheet_manger.dart';
export 'inputs/r_input.dart';