diff --git a/assets/icons/App Screen-1.svg b/assets/icons/App Screen-1.svg new file mode 100644 index 0000000..f63acf2 --- /dev/null +++ b/assets/icons/App Screen-1.svg @@ -0,0 +1,5368 @@ + + + + + + diff --git a/assets/icons/App Screen-2.svg b/assets/icons/App Screen-2.svg new file mode 100644 index 0000000..8906180 --- /dev/null +++ b/assets/icons/App Screen-2.svg @@ -0,0 +1,4086 @@ + + + + + + diff --git a/assets/icons/App Screen-3.svg b/assets/icons/App Screen-3.svg new file mode 100644 index 0000000..6ef4c6a --- /dev/null +++ b/assets/icons/App Screen-3.svg @@ -0,0 +1,4551 @@ + + + + + + diff --git a/lib/core/apis/apis.dart b/lib/core/apis/apis.dart index 53d7679..fce54ab 100644 --- a/lib/core/apis/apis.dart +++ b/lib/core/apis/apis.dart @@ -23,4 +23,5 @@ class EndPoint { static String favorite = 'favorite'; static String editCard(int id) => 'card/$id'; static String search = 'card'; + static String rate = 'rate'; } diff --git a/lib/core/routing/routing_manager.dart b/lib/core/routing/routing_manager.dart index cf5211e..2c414e6 100644 --- a/lib/core/routing/routing_manager.dart +++ b/lib/core/routing/routing_manager.dart @@ -161,11 +161,11 @@ class RoutingManager { ), GetPage( name: RouteName.feedback, - page: () => const FeedbackScreen(), + page: () => FeedbackScreen(), ), GetPage( name: RouteName.reviewForm, - page: () => const ReviewFormScreen(), + page: () => ReviewFormScreen(), ), GetPage( name: RouteName.imageView, diff --git a/lib/features/account/presentation_layer/screens/account.dart b/lib/features/account/presentation_layer/screens/account.dart index ff9580b..8a6b395 100644 --- a/lib/features/account/presentation_layer/screens/account.dart +++ b/lib/features/account/presentation_layer/screens/account.dart @@ -163,30 +163,30 @@ class AccountScreen extends StatelessWidget { // ).paddingOnly(bottom: 0), // ], // ), - AccountWidget( - icon: "my cards.svg", - title: "my_cards".tr, - ).onTap(() async { - if (authController.isGuest.value) { - Get.defaultDialog( - title: '', - content: Column( - children: [ - BoldTextWidget('you_have_to_sign_in'.tr), - const SizedBox( - height: 20, - ), - ButtonWidget( - onTap: () { - RoutingManager.off(RouteName.login); - }, - title: 'sign_in'.tr) - ], - )); - return; - } - RoutingManager.to(RouteName.myCards); - }), + // AccountWidget( + // icon: "my cards.svg", + // title: "my_cards".tr, + // ).onTap(() async { + // if (authController.isGuest.value) { + // Get.defaultDialog( + // title: '', + // content: Column( + // children: [ + // BoldTextWidget('you_have_to_sign_in'.tr), + // const SizedBox( + // height: 20, + // ), + // ButtonWidget( + // onTap: () { + // RoutingManager.off(RouteName.login); + // }, + // title: 'sign_in'.tr) + // ], + // )); + // return; + // } + // RoutingManager.to(RouteName.myCards); + // }), AccountWidget( icon: "about us.svg", title: "about_us".tr, diff --git a/lib/features/card/business_logic_layer/card_controller.dart b/lib/features/card/business_logic_layer/card_controller.dart index c8dee75..9d8770c 100644 --- a/lib/features/card/business_logic_layer/card_controller.dart +++ b/lib/features/card/business_logic_layer/card_controller.dart @@ -10,6 +10,8 @@ import 'package:taafee_mobile/features/card/data_layer/model/add_card.dart'; import 'package:taafee_mobile/features/card/data_layer/model/card_images.dart'; import 'package:taafee_mobile/features/card/data_layer/model/card_model.dart'; import 'package:taafee_mobile/features/card/data_layer/model/edit_card.dart'; +import 'package:taafee_mobile/features/card/data_layer/model/feedback.dart'; +import 'package:taafee_mobile/features/card/data_layer/model/rate.dart'; import 'package:taafee_mobile/features/card/data_layer/source/card_service.dart'; import 'package:rx_future/rx_future.dart'; @@ -244,4 +246,19 @@ class CardController extends GetxController { void changeCurrentIndex(int index) { currentIndex.value = index; } + + RateModel rateModel = RateModel.zero(); + RxFuture sendRatingState = RxFuture(null); + Future sendRating() async { + await sendRatingState.observe((p0) async { + await cardService.sendRating(rateModel); + }); + } + + RxFuture> feedbackState = RxFuture([]); + Future getFeedback(int cardId) async { + await feedbackState.observe((p0) async { + return await cardService.getFeedback(cardId); + }); + } } diff --git a/lib/features/card/data_layer/model/card_model.dart b/lib/features/card/data_layer/model/card_model.dart index 5d3d81a..78e8c23 100644 --- a/lib/features/card/data_layer/model/card_model.dart +++ b/lib/features/card/data_layer/model/card_model.dart @@ -1,3 +1,4 @@ +import 'package:taafee_mobile/features/card/data_layer/model/work_schedules.dart'; import 'package:taafee_mobile/features/home/data_layer/model/city.dart'; import 'card_images.dart'; @@ -17,6 +18,11 @@ class CardModel { String additionalData; List cardImages; bool isFav; + int price; + String lat; + String lan; + WorkScheduleModel? workScheduleModel; + int avgRating; CardModel( {required this.id, @@ -31,22 +37,33 @@ class CardModel { required this.website, required this.additionalData, required this.cardImages, - required this.isFav}); + required this.isFav, + required this.price, + required this.lat, + required this.lan, + this.workScheduleModel, + required this.avgRating}); factory CardModel.fromJson(Map json) => CardModel( - id: json["id"], - name: json["name"], - cityModel: CityModel.fromJson(json["city"]), - address: json["address"], - postalCode: json["postal_code"], - phoneNumber: json["phone_number1"], - services: json["services"], - categoryId: json["category_id"] ?? json['category']['id'], - user: User.fromJson(json["user"]), - website: json["website"], - additionalData: json["additional_data"], - cardImages: CardImages.fromJsonList(json), - isFav: json["isFav"] == 1 ? true : false); + id: json["id"], + name: json["name"], + cityModel: CityModel.fromJson(json["city"]), + address: json["address"], + postalCode: json["postal_code"], + phoneNumber: json["phone_number1"], + services: json["services"], + categoryId: json["category_id"] ?? json['category']['id'], + user: User.fromJson(json["user"]), + website: json["website"], + additionalData: json["additional_data"], + cardImages: CardImages.fromJsonList(json), + isFav: json["isFav"] == 1 ? true : false, + price: json["price"], + lan: json["lan"], + lat: json["lat"], + workScheduleModel: json["work_schedules"] == null ? null : WorkScheduleModel.fromJson(json), + avgRating: json["avg_rating"], + ); static List fromJsonList(Map json) { List cards = []; diff --git a/lib/features/card/data_layer/model/feedback.dart b/lib/features/card/data_layer/model/feedback.dart new file mode 100644 index 0000000..104e492 --- /dev/null +++ b/lib/features/card/data_layer/model/feedback.dart @@ -0,0 +1,35 @@ +import 'package:taafee_mobile/features/auth/data_layer/model/user.dart'; + +class FeedbackModel { + int id; + int stars; + String feedback; + User user; + int cardId; + + FeedbackModel({ + required this.id, + required this.stars, + required this.feedback, + required this.user, + required this.cardId, + }); + + factory FeedbackModel.fromJson(Map json) => FeedbackModel( + id: json["id"], + stars: json["stars"], + feedback: json["feedback"].toString(), + user: User.fromJson(json["user"]), + cardId: json["card_id"], + ); + + static List fromJsonList(Map json) { + List feedback = []; + json["data"].forEach( + (element) => feedback.add( + FeedbackModel.fromJson(element), + ), + ); + return feedback; + } +} diff --git a/lib/features/card/data_layer/model/rate.dart b/lib/features/card/data_layer/model/rate.dart new file mode 100644 index 0000000..5ead8ca --- /dev/null +++ b/lib/features/card/data_layer/model/rate.dart @@ -0,0 +1,15 @@ +class RateModel { + int cardId; + double stars; + String? feedback; + + RateModel({required this.cardId, required this.stars, this.feedback}); + + factory RateModel.zero() => RateModel(cardId: 0, stars: 0); + + Map toJson() => { + 'card_id': cardId, + 'stars': stars * 2, + if (feedback != null) 'feedback': feedback, + }; +} diff --git a/lib/features/card/data_layer/model/work_schedules.dart b/lib/features/card/data_layer/model/work_schedules.dart new file mode 100644 index 0000000..5712046 --- /dev/null +++ b/lib/features/card/data_layer/model/work_schedules.dart @@ -0,0 +1,65 @@ +class WorkScheduleModel { + List days; + WorkScheduleModel({ + required this.days, + }); + + factory WorkScheduleModel.fromJson(Map json) { + List days = []; + json["work_schedules"].forEach((key, value) { + days.add( + Day( + day: key, + workTime: workTimeModel.fromJsonList(value), + ), + ); + }); + return WorkScheduleModel(days: days); + } +} + +class Day { + String day; + List workTime; + Day({ + required this.day, + required this.workTime, + }); + factory Day.zero() => Day( + day: "", + workTime: [], + ); +} + +class workTimeModel { + String name; + String startTime; + String endTime; + workTimeModel({ + required this.name, + required this.startTime, + required this.endTime, + }); + + factory workTimeModel.fromJson(Map json) => workTimeModel( + name: json["name"], + startTime: json["start"], + endTime: json["end"], + ); + + static List fromJsonList(List json) { + List days = []; + for (var day in json) { + days.add( + workTimeModel.fromJson(day), + ); + } + + // json[key].forEach( + // (element) => days.add( + // workTimeModel.fromJson(element), + // ), + // ); + return days; + } +} diff --git a/lib/features/card/data_layer/model/working_time.dart b/lib/features/card/data_layer/model/working_time.dart index 8d6f005..66e86c1 100644 --- a/lib/features/card/data_layer/model/working_time.dart +++ b/lib/features/card/data_layer/model/working_time.dart @@ -1,11 +1,11 @@ -class WorkingTimeModel { - String type; - String startTime; - String endTime; +// class WorkingTimeModel { +// String type; +// String startTime; +// String endTime; - WorkingTimeModel({ - required this.type, - required this.startTime, - required this.endTime, - }); -} +// WorkingTimeModel({ +// required this.type, +// required this.startTime, +// required this.endTime, +// }); +// } diff --git a/lib/features/card/data_layer/source/card_service.dart b/lib/features/card/data_layer/source/card_service.dart index e0b8114..c5a551c 100644 --- a/lib/features/card/data_layer/source/card_service.dart +++ b/lib/features/card/data_layer/source/card_service.dart @@ -8,6 +8,8 @@ import 'package:taafee_mobile/core/local_storage/local_storage.dart'; import 'package:taafee_mobile/core/network/http.dart'; import 'package:taafee_mobile/features/card/data_layer/model/add_card.dart'; import 'package:taafee_mobile/features/card/data_layer/model/card_images.dart'; +import 'package:taafee_mobile/features/card/data_layer/model/feedback.dart'; +import 'package:taafee_mobile/features/card/data_layer/model/rate.dart'; import '../model/card_model.dart'; import '../model/edit_card.dart'; @@ -15,33 +17,25 @@ import '../model/edit_card.dart'; class CardService { LocalStorage localStorage = LocalStorage(); Future addCard(AddCardModel addCardModel) async { - Request request = Request(EndPoint.card, RequestMethod.post, - body: addCardModel.toJson(), isFormData: true, authorized: true); + Request request = + Request(EndPoint.card, RequestMethod.post, body: addCardModel.toJson(), isFormData: true, authorized: true); //no need to use variable await request.sendRequest(); } - Future> getCards( - {int? page, - int? categoryId, - void Function(Object)? onConnectionError}) async { + Future> getCards({int? page, int? categoryId, void Function(Object)? onConnectionError}) async { Request request = Request(EndPoint.card, RequestMethod.get, authorized: true, cacheable: true, - queryParams: { - "page": page, - if (categoryId != null) 'category_id': categoryId - }); + queryParams: {"page": page, if (categoryId != null) 'category_id': categoryId}); - Map response = - await request.sendRequest(onConnectionError: onConnectionError); + Map response = await request.sendRequest(onConnectionError: onConnectionError); return CardModel.fromJsonList(response); } Future showCard({required int cardId}) async { - Request request = Request('${EndPoint.card}/$cardId', RequestMethod.get, - authorized: true); + Request request = Request('${EndPoint.card}/$cardId', RequestMethod.get, authorized: true); Map response = await request.sendRequest(); return CardModel.fromJson(response['data']); } @@ -71,15 +65,11 @@ class CardService { await request.sendRequest(); } - Future> getMyCards(int userId, - {int? page, void Function(Object)? onConnectionError}) async { + Future> getMyCards(int userId, {int? page, void Function(Object)? onConnectionError}) async { Request request = Request(EndPoint.card, RequestMethod.get, - cacheable: true, - authorized: true, - queryParams: {"user_id": userId, 'page': page}); + cacheable: true, authorized: true, queryParams: {"user_id": userId, 'page': page}); - Map response = - await request.sendRequest(onConnectionError: onConnectionError); + Map response = await request.sendRequest(onConnectionError: onConnectionError); return CardModel.fromJsonList(response); } @@ -148,4 +138,23 @@ class CardService { )); return Uint8List.fromList(response.data); } + + Future sendRating(RateModel rateModel) async { + Request request = Request(EndPoint.rate, RequestMethod.post, authorized: true, body: rateModel.toJson()); + + Map response = await request.sendRequest(); + } + + Future> getFeedback(int cardId) async { + Request request = Request( + EndPoint.rate, + RequestMethod.get, + authorized: true, + queryParams: { + "card_id": cardId, + }, + ); + Map response = await request.sendRequest(); + return FeedbackModel.fromJsonList(response); + } } diff --git a/lib/features/card/presentation_layer/screens/card_details.dart b/lib/features/card/presentation_layer/screens/card_details.dart index 959ddcb..5a9ba7b 100644 --- a/lib/features/card/presentation_layer/screens/card_details.dart +++ b/lib/features/card/presentation_layer/screens/card_details.dart @@ -142,13 +142,15 @@ class CardDetailsScreen extends StatelessWidget { radius: 60, backgroundColor: AppColors.secondaryColor, ), - const Positioned( + Positioned( top: 15, child: CircleAvatar( radius: 50, - backgroundImage: AssetImage( - "assets/images/Ellipse 8.png", - ), + backgroundImage: cardModel.user.avatarImage == null + ? const AssetImage( + "assets/images/default_user_avatar.png", + ) + : NetworkImage(cardModel.user.avatarImage!) as ImageProvider, ), ), ], @@ -162,16 +164,20 @@ class CardDetailsScreen extends StatelessWidget { child: ListViewWidget( physics: const BouncingScrollPhysics(), scrollDirection: Axis.horizontal, - itemCount: 4, + itemCount: cardModel.cardImages.length, childBuilder: (index) { if (index == 3) { - return const ImageWidget( + return ImageWidget( numberOfImages: 5, + cardImages: cardModel.cardImages[index], ).onTap(() { RoutingManager.to(RouteName.imageView); }); } - return const ImageWidget(numberOfImages: 1); + return ImageWidget( + numberOfImages: 1, + cardImages: cardModel.cardImages[index], + ); }, ), ), @@ -184,11 +190,15 @@ class CardDetailsScreen extends StatelessWidget { const SizedBox( height: 20, ), - WorkingTimeWidget(), + WorkingTimeWidget( + workScheduleModel: cardModel.workScheduleModel, + ), const SizedBox( height: 20, ), - RateWidget(), + RateWidget( + cardModel: cardModel, + ), const SizedBox( height: 20, ), @@ -200,21 +210,13 @@ class CardDetailsScreen extends StatelessWidget { // ), child: FlutterMap( options: MapOptions( - center: const location.LatLng(51.509364, -0.128928), + center: location.LatLng(double.parse(cardModel.lat), double.parse(cardModel.lan)), ), children: [ TileLayer( urlTemplate: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png', userAgentPackageName: 'com.example.app', ), - // RichAttributionWidget( - // attributions: [ - // TextSourceAttribution( - // 'OpenStreetMap contributors', - // onTap: () => launchUrl(Uri.parse('https://openstreetmap.org/copyright')), - // ), - // ], - // ), ], ), ), @@ -243,161 +245,28 @@ class CardDetailsScreen extends StatelessWidget { const SizedBox( height: 20, ), - // Row( - // children: [ - // ButtonWidget( - // color: AppColors.callColor, - // haveIcon: true, - // onTap: () async { - // await UrlLauncherService.makePhoneCall(cardModel.phoneNumber); - // }, - // title: "call_owner".tr, - // textColor: Colors.white, - // child: SvgPicture.asset( - // "assets/icons/phone.svg", - // colorFilter: const ColorFilter.mode(Colors.white, BlendMode.srcIn), - // ), - // ).paddingSymmetric(horizontal: 4).expanded(Responsive.isTablet() ? 1 : 5), - // ButtonWidget( - // color: AppColors.emailColor, - // haveIcon: true, - // onTap: () async { - // await UrlLauncherService.sendEmail(cardModel.user.email); - // }, - // title: "email".tr, - // textColor: Colors.white, - // child: SvgPicture.asset("assets/icons/Email.svg"), - // ).paddingSymmetric(horizontal: 4).expanded(Responsive.isTablet() ? 1 : 5), - // if (Responsive.isTablet()) - // Visibility( - // visible: chatController.chatUser.id != cardModel.user.chatUserId, - // child: Obx(() { - // return ButtonWidget( - // isLoading: chatController.createRoomState.loading, - // textColor: Colors.white, - // color: AppColors.messageColor, - // haveIcon: true, - // onTap: () { - // if (chatController.connectionState.value == SocketConnectionState.connected) { - // chatController.createRoom( - // chatUserId: cardModel.user.chatUserId, - // onSuccess: (room) { - // RoutingManager.to(RouteName.chatDetails, arguments: { - // "room": room, - // }); - // }); - // } else { - // Toast.showToast('you_have_no_internet_connection.'.tr); - // } - // }, - // title: "start_conversation".tr, - // fontSize: 13, - // child: SvgPicture.asset("assets/icons/message.svg"), - // ).expanded(Responsive.isTablet() ? 1 : 5); - // }), - // ), - // if (Responsive.isTablet()) - // Obx(() { - // return Visibility( - // visible: homeController.user.value!.id != cardModel.user.id, - // child: (homeController.currentCardAppointment.value != null) - // ? ButtonWidget( - // haveIcon: true, - // onTap: () { - // appointmentDialog(context); - // }, - // fontSize: 13, - // color: AppColors.secondaryColor, - // title: 'you_have_an_appointment'.tr, - // child: const Icon( - // Icons.schedule, - // color: Colors.white, - // ), - // ).paddingSymmetric(horizontal: 4).expanded(Responsive.isTablet() ? 1 : 5) - // : ButtonWidget( - // onTap: () { - // cardController.getAvailableAppointments(); - // appointmentSchedulingDialog(context); - // }, - // haveIcon: true, - // fontSize: 12, - // title: 'schedule_an_appointment'.tr, - // color: AppColors.secondaryColor, - // child: const Icon( - // Icons.schedule, - // color: Colors.white, - // ), - // ).paddingSymmetric(horizontal: 4).expanded(Responsive.isTablet() ? 1 : 5), - // ); - // }), - // ], - // ).paddingSymmetric(vertical: Responsive.isTablet() ? 20 : 4, horizontal: Responsive.isTablet() ? 40 : 10), - // if (!Responsive.isTablet()) - // Obx(() { - // return Row( - // children: [ - // Obx(() { - // return Visibility( - // visible: homeController.user.value!.id != cardModel.user.id, - // child: (homeController.currentCardAppointment.value != null) - // ? ButtonWidget( - // haveIcon: true, - // onTap: () { - // appointmentDialog(context); - // }, - // fontSize: 12, - // color: AppColors.secondaryColor, - // title: 'you_have_an_appointment'.tr, - // child: const Icon( - // Icons.schedule, - // color: Colors.white, - // ), - // ).paddingSymmetric(horizontal: 4).expanded(Responsive.isTablet() ? 1 : 5) - // : ButtonWidget( - // onTap: () { - // cardController.getAvailableAppointments(); - // appointmentSchedulingDialog(context); - // }, - // haveIcon: true, - // fontSize: 12, - // title: 'schedule_an_appointment'.tr, - // color: AppColors.secondaryColor, - // child: const Icon( - // Icons.schedule, - // color: Colors.white, - // ), - // ).paddingSymmetric(horizontal: 4).expanded(Responsive.isTablet() ? 1 : 5), - // ); - // }), - // Visibility( - // visible: chatController.chatUser.id != cardModel.user.chatUserId, - // child: ButtonWidget( - // isLoading: chatController.createRoomState.loading, - // textColor: Colors.white, - // color: AppColors.messageColor, - // haveIcon: true, - // onTap: () { - // if (chatController.connectionState.value == SocketConnectionState.connected) { - // chatController.createRoom( - // chatUserId: cardModel.user.chatUserId, - // onSuccess: (room) { - // RoutingManager.to(RouteName.chatDetails, arguments: {"room": room}); - // }); - // } else { - // Toast.showToast('you_have_no_internet_connection'.tr); - // } - // }, - // title: "start_conversation".tr, - // fontSize: 12, - // child: SvgPicture.asset("assets/icons/message.svg"), - // ).paddingSymmetric(horizontal: 4).expanded(Responsive.isTablet() ? 1 : 5), - // ), - // ], - // ).paddingSymmetric(vertical: Responsive.isTablet() ? 20 : 4, horizontal: Responsive.isTablet() ? 40 : 10); - // }), - // const SizedBox( - // height: 60, - // ), + Container( + width: Get.width * .89, + height: 200, + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(10), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const RegularTextWidget( + "Insurance companies", + color: Colors.grey, + fontSize: 14, + ).paddingSymmetric(horizontal: 30), + RegularTextWidget(cardModel.additionalData).paddingSymmetric(horizontal: 10, vertical: 5) + ], + ), + ), + const SizedBox( + height: 20, + ), ], ).paddingSymmetric(horizontal: Responsive.isTablet() ? 20 : 0)), ).makeSafeArea(); diff --git a/lib/features/card/presentation_layer/screens/feedback.dart b/lib/features/card/presentation_layer/screens/feedback.dart index e5d5869..1051dbd 100644 --- a/lib/features/card/presentation_layer/screens/feedback.dart +++ b/lib/features/card/presentation_layer/screens/feedback.dart @@ -3,10 +3,13 @@ import 'package:get/get.dart'; import 'package:taafee_mobile/common/extensions/widget_extension.dart'; import 'package:taafee_mobile/common/widgets/header_screen.dart'; import 'package:taafee_mobile/common/widgets/listview.dart'; +import 'package:taafee_mobile/common/widgets/rx_viewer.dart'; +import 'package:taafee_mobile/features/card/business_logic_layer/card_controller.dart'; import 'package:taafee_mobile/features/card/presentation_layer/widgets/feedback_widget.dart'; class FeedbackScreen extends StatelessWidget { - const FeedbackScreen({super.key}); + final CardController cardController = Get.find(); + FeedbackScreen({super.key}); @override Widget build(BuildContext context) { @@ -16,13 +19,18 @@ class FeedbackScreen extends StatelessWidget { HeaderScreen( "Feedback", ).paddingOnly(top: 20), - SizedBox( - width: Get.width, - child: ListViewWidget( - itemCount: 10, - childBuilder: (index) { - return const FeedbackWidget(); - }), + RxViewer( + rxFuture: cardController.feedbackState, + child: () => SizedBox( + width: Get.width, + child: ListViewWidget( + itemCount: cardController.feedbackState.result.length, + childBuilder: (index) { + return FeedbackWidget( + feedbackModel: cardController.feedbackState.result[index], + ); + }), + ), ) ], ), diff --git a/lib/features/card/presentation_layer/screens/review_form.dart b/lib/features/card/presentation_layer/screens/review_form.dart index bb20143..4a2f4e2 100644 --- a/lib/features/card/presentation_layer/screens/review_form.dart +++ b/lib/features/card/presentation_layer/screens/review_form.dart @@ -7,11 +7,13 @@ import 'package:taafee_mobile/common/widgets/button.dart'; import 'package:taafee_mobile/common/widgets/header_screen.dart'; import 'package:taafee_mobile/common/widgets/text.dart'; import 'package:taafee_mobile/common/widgets/textfiled.dart'; +import 'package:taafee_mobile/features/card/business_logic_layer/card_controller.dart'; import '../../../../core/routing/routing_manager.dart'; class ReviewFormScreen extends StatelessWidget { - const ReviewFormScreen({super.key}); + final CardController cardController = Get.find(); + ReviewFormScreen({super.key}); @override Widget build(BuildContext context) { @@ -45,7 +47,7 @@ class ReviewFormScreen extends StatelessWidget { minRating: 1, itemSize: 40, direction: Axis.horizontal, - allowHalfRating: false, + allowHalfRating: true, glow: false, itemCount: 5, // glowColor: , @@ -54,13 +56,17 @@ class ReviewFormScreen extends StatelessWidget { Icons.star_rounded, color: Colors.amber, ), - onRatingUpdate: (rating) {}, + onRatingUpdate: (rating) { + cardController.rateModel.stars = rating; + }, ), ), TextFieldWidget( maxLines: 7, textInputAction: TextInputAction.newline, - onChange: (value) {}, + onChange: (value) { + cardController.rateModel.feedback = value; + }, keyboardType: TextInputType.multiline, label: "", validate: (value) { @@ -68,13 +74,17 @@ class ReviewFormScreen extends StatelessWidget { }, height: Get.height * .3, ).paddingOnly(top: 30), - ButtonWidget( - onTap: () { - RoutingManager.back(); - }, - title: "Done", - width: Get.width * .3, - ).center() + Obx(() { + return ButtonWidget( + isLoading: cardController.sendRatingState.loading, + onTap: () async { + await cardController.sendRating(); + RoutingManager.back(); + }, + title: "Done", + width: Get.width * .3, + ).center(); + }) ], ).paddingSymmetric(horizontal: 30, vertical: 20), ], diff --git a/lib/features/card/presentation_layer/widgets/card.dart b/lib/features/card/presentation_layer/widgets/card.dart index 6f78597..e86bf3f 100644 --- a/lib/features/card/presentation_layer/widgets/card.dart +++ b/lib/features/card/presentation_layer/widgets/card.dart @@ -23,7 +23,7 @@ class CardWidget extends StatelessWidget { width: Get.width, height: 175, child: Container( - margin: const EdgeInsets.symmetric(horizontal: 20, vertical: 10), + margin: const EdgeInsets.symmetric(horizontal: 0, vertical: 10), decoration: BoxDecoration( borderRadius: BorderRadius.circular(4), ), diff --git a/lib/features/card/presentation_layer/widgets/consultation_price.dart b/lib/features/card/presentation_layer/widgets/consultation_price.dart index 5980a88..0dd2574 100644 --- a/lib/features/card/presentation_layer/widgets/consultation_price.dart +++ b/lib/features/card/presentation_layer/widgets/consultation_price.dart @@ -37,7 +37,7 @@ class ConsultationPriceWidget extends StatelessWidget { color: Colors.grey, ), BoldTextWidget( - "400 SP".tr, + "${cardModel.price} SP".tr, fontSize: 20, color: Colors.grey, ), diff --git a/lib/features/card/presentation_layer/widgets/feedback_widget.dart b/lib/features/card/presentation_layer/widgets/feedback_widget.dart index 45c7b77..ec0644f 100644 --- a/lib/features/card/presentation_layer/widgets/feedback_widget.dart +++ b/lib/features/card/presentation_layer/widgets/feedback_widget.dart @@ -1,24 +1,28 @@ import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:taafee_mobile/common/widgets/text.dart'; +import 'package:taafee_mobile/features/card/data_layer/model/feedback.dart'; class FeedbackWidget extends StatelessWidget { - const FeedbackWidget({super.key}); + final FeedbackModel feedbackModel; + const FeedbackWidget({super.key, required this.feedbackModel}); @override Widget build(BuildContext context) { - return const Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - RegularTextWidget( - "Zakoor", - fontSize: 16, - ), - RegularTextWidget( - "ggggggggggggggggggg", - fontSize: 14, - ), - ], - ).paddingSymmetric(horizontal: 20, vertical: 8); + return feedbackModel.feedback != "null" + ? Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + RegularTextWidget( + "${feedbackModel.user.firstName} ${feedbackModel.user.lastName}", + fontSize: 16, + ), + RegularTextWidget( + feedbackModel.feedback, + fontSize: 14, + ), + ], + ).paddingSymmetric(horizontal: 20, vertical: 8) + : Container(); } } diff --git a/lib/features/card/presentation_layer/widgets/image.dart b/lib/features/card/presentation_layer/widgets/image.dart index e8cb3b8..53cdb13 100644 --- a/lib/features/card/presentation_layer/widgets/image.dart +++ b/lib/features/card/presentation_layer/widgets/image.dart @@ -1,14 +1,16 @@ +import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; +import 'package:taafee_mobile/common/const/const.dart'; import 'package:taafee_mobile/common/extensions/widget_extension.dart'; import 'package:taafee_mobile/common/widgets/text.dart'; +import 'package:taafee_mobile/features/card/data_layer/model/card_images.dart'; +import 'package:taafee_mobile/features/card/data_layer/model/card_model.dart'; class ImageWidget extends StatelessWidget { final int numberOfImages; - const ImageWidget({ - super.key, - required this.numberOfImages, - }); + final CardImages cardImages; + const ImageWidget({super.key, required this.numberOfImages, required this.cardImages}); @override Widget build(BuildContext context) { @@ -18,8 +20,9 @@ class ImageWidget extends StatelessWidget { height: Get.width * .2, decoration: BoxDecoration( borderRadius: BorderRadius.circular(10), - image: const DecorationImage( - image: AssetImage("assets/images/download.jpg"), + image: DecorationImage( + image: CachedNetworkImageProvider(Domain.domain + cardImages.url.substring(6)), + // image: AssetImage("assets/images/download.jpg"), fit: BoxFit.cover, ), ), diff --git a/lib/features/card/presentation_layer/widgets/rate.dart b/lib/features/card/presentation_layer/widgets/rate.dart index 4e7444e..9bb8bac 100644 --- a/lib/features/card/presentation_layer/widgets/rate.dart +++ b/lib/features/card/presentation_layer/widgets/rate.dart @@ -8,6 +8,7 @@ import 'package:taafee_mobile/common/widgets/button.dart'; import 'package:taafee_mobile/common/widgets/text.dart'; import 'package:taafee_mobile/core/routing/routing_manager.dart'; import 'package:taafee_mobile/features/card/business_logic_layer/card_controller.dart'; +import 'package:taafee_mobile/features/card/data_layer/model/card_model.dart'; import 'package:taafee_mobile/features/card/presentation_layer/widgets/star.dart'; import 'package:taafee_mobile/features/card/presentation_layer/widgets/view_ratings.dart'; @@ -15,14 +16,15 @@ import '../../../../common/const/const.dart'; import '../../../../common/widgets/textfiled.dart'; class RateWidget extends StatelessWidget { + final CardModel cardModel; final CardController cardController = Get.find(); - RateWidget({super.key}); + RateWidget({super.key, required this.cardModel}); @override Widget build(BuildContext context) { return Container( width: Get.width * .89, - height: 150, + height: 200, decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(10), @@ -34,6 +36,7 @@ class RateWidget extends StatelessWidget { children: [ const RegularTextWidget("Rates"), Container( + margin: const EdgeInsets.only(top: 5), alignment: Alignment.center, width: 100, height: 25, @@ -46,199 +49,20 @@ class RateWidget extends StatelessWidget { color: Colors.white, ), ).onTap(() { + cardController.rateModel.cardId = cardModel.id; RoutingManager.to(RouteName.reviewForm); }), ], ).paddingSymmetric(horizontal: 20, vertical: 5), - const ViewRatingsWidget(), + ViewRatingsWidget( + cardModel: cardModel, + ), ], ), - - // child: Column( - // children: [ - // Row( - // mainAxisAlignment: MainAxisAlignment.spaceBetween, - // children: [ - // Row( - // children: [ - // RegularTextWidget("Number of users who rate this : ".tr), - // RegularTextWidget("10".tr), - // ], - // ), - // Container( - // alignment: Alignment.center, - // width: 100, - // height: 25, - // decoration: BoxDecoration( - // color: AppColors.primeColor, - // borderRadius: BorderRadius.circular(25), - // ), - // child: RegularTextWidget( - // "Rate Now".tr, - // color: Colors.white, - // ), - // ).onTap(() { - // dialog(); - // cardController.currentIndex(0); - // }) - // ], - // ), - // Row( - // mainAxisAlignment: MainAxisAlignment.spaceBetween, - // children: [ - // Column( - // children: [ - // const Stack( - // alignment: Alignment.center, - // children: [ - // StarWidget(maxRating: 1, starSize: 60, readOnly: true), - // RegularTextWidget( - // "2.5", - // color: Colors.black, - // ), - // ], - // ), - // RegularTextWidget("Waiting".tr), - // ], - // ), - // Column( - // children: [ - // const Stack( - // alignment: Alignment.center, - // children: [ - // StarWidget(maxRating: 1, starSize: 60, readOnly: true), - // RegularTextWidget( - // "2.5", - // color: Colors.black, - // ), - // ], - // ), - // RegularTextWidget("Performance".tr), - // ], - // ), - // Column( - // children: [ - // const Stack( - // alignment: Alignment.center, - // children: [ - // StarWidget(maxRating: 1, starSize: 60, readOnly: true), - // RegularTextWidget( - // "2.5", - // color: Colors.black, - // ), - // ], - // ), - // RegularTextWidget("Price".tr), - // ], - // ) - // ], - // ).paddingOnly(top: 10).paddingSymmetric(horizontal: 20), - // ], - // ).paddingSymmetric(horizontal: 10, vertical: 10), - ).onTap(() { + ).onTap(() async { + cardController.getFeedback(cardModel.id); RoutingManager.to(RouteName.feedback); log("message"); }); } - - final PageController pageController = PageController(); - final List rate = [ - "waiting?", - "Performance?", - "Price?", - "Feedback", - ]; - final List stars = [ - const StarWidget(maxRating: 5, starSize: 30, readOnly: false), - const StarWidget(maxRating: 5, starSize: 30, readOnly: false), - const StarWidget(maxRating: 5, starSize: 30, readOnly: false), - - Container( - alignment: Alignment.topCenter, - width: Get.width * .5, - height: 55, - child: TextFormField( - onChanged: (value) {}, - maxLines: 4, - textInputAction: TextInputAction.newline, - keyboardType: TextInputType.multiline, - ), - ), - // TextFieldWidget( - // keyboardType: TextInputType.multiline, - // label: "", - // onChange: (value) {}, - // maxLines: 5, - // textInputAction: TextInputAction.newline, - // validate: (p0) { - // return null; - // }, - // ), - ]; - void dialog() { - Get.defaultDialog( - onWillPop: () async { - cardController.currentIndex(0); - return true; - }, - confirm: Obx(() { - return Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - RegularTextWidget( - "back".tr, - color: Colors.black, - ).onTap(() { - if (cardController.currentIndex.value == 0) { - RoutingManager.back(); - } - pageController.animateToPage(cardController.currentIndex.value - 1, - duration: const Duration(milliseconds: 250), curve: Curves.easeIn); - }), - ButtonWidget( - width: 80, - onTap: () { - if (cardController.currentIndex.value == 3) { - RoutingManager.back(); - } - pageController.animateToPage(cardController.currentIndex.value + 1, - duration: const Duration(milliseconds: 250), curve: Curves.easeIn); - }, - title: cardController.currentIndex.value == 3 ? "OK".tr : "Next".tr), - ], - ).paddingSymmetric(horizontal: 20); - }), - backgroundColor: Colors.white, - title: "", - middleText: "", - content: SizedBox( - width: Get.width * .5, - height: Get.height * .15, - child: PageView.builder( - physics: const BouncingScrollPhysics(), - controller: pageController, - onPageChanged: (value) { - cardController.changeCurrentIndex(value); - }, - itemCount: 4, - itemBuilder: (BuildContext context, index) { - return Column( - children: [ - BoldTextWidget(rate[index].tr).paddingOnly(bottom: 30), - - stars[index], - // SizedBox( - // width: Get.width * .8, - // child: RegularTextWidget( - // textAlign: TextAlign.center, - // text[index].tr, - // color: Colors.black, - // ), - // ) - ], - ); - }, - ), - )); - } } diff --git a/lib/features/card/presentation_layer/widgets/star.dart b/lib/features/card/presentation_layer/widgets/star.dart index 80df950..3b5044d 100644 --- a/lib/features/card/presentation_layer/widgets/star.dart +++ b/lib/features/card/presentation_layer/widgets/star.dart @@ -1,41 +1,41 @@ -import 'package:animated_rating_stars/animated_rating_stars.dart'; -import 'package:flutter/material.dart'; +// import 'package:animated_rating_stars/animated_rating_stars.dart'; +// import 'package:flutter/material.dart'; -class StarWidget extends StatelessWidget { - final double maxRating; - final double starSize; - final bool readOnly; - const StarWidget({ - super.key, - required this.maxRating, - required this.starSize, - required this.readOnly, - }); +// class StarWidget extends StatelessWidget { +// final double maxRating; +// final double starSize; +// final bool readOnly; +// const StarWidget({ +// super.key, +// required this.maxRating, +// required this.starSize, +// required this.readOnly, +// }); - @override - Widget build(BuildContext context) { - return AnimatedRatingStars( - initialRating: 1, - minRating: 0, - maxRating: maxRating, - filledColor: Colors.amber, - emptyColor: Colors.grey, - filledIcon: Icons.star_border_rounded, - halfFilledIcon: Icons.star_half_rounded, - emptyIcon: Icons.star_border_rounded, - onChanged: (double rating) { - // Handle the rating change here - print('Rating: $rating'); - }, - displayRatingValue: true, - interactiveTooltips: true, - customFilledIcon: Icons.star_border_rounded, - customHalfFilledIcon: Icons.star_half_rounded, - customEmptyIcon: Icons.star_border_rounded, - starSize: starSize, - animationDuration: const Duration(milliseconds: 300), - animationCurve: Curves.easeInOut, - readOnly: readOnly, - ); - } -} +// @override +// Widget build(BuildContext context) { +// return AnimatedRatingStars( +// initialRating: 1, +// minRating: 0, +// maxRating: maxRating, +// filledColor: Colors.amber, +// emptyColor: Colors.grey, +// filledIcon: Icons.star_border_rounded, +// halfFilledIcon: Icons.star_half_rounded, +// emptyIcon: Icons.star_border_rounded, +// onChanged: (double rating) { +// // Handle the rating change here +// print('Rating: $rating'); +// }, +// displayRatingValue: true, +// interactiveTooltips: true, +// customFilledIcon: Icons.star_border_rounded, +// customHalfFilledIcon: Icons.star_half_rounded, +// customEmptyIcon: Icons.star_border_rounded, +// starSize: starSize, +// animationDuration: const Duration(milliseconds: 300), +// animationCurve: Curves.easeInOut, +// readOnly: readOnly, +// ); +// } +// } diff --git a/lib/features/card/presentation_layer/widgets/view_ratings.dart b/lib/features/card/presentation_layer/widgets/view_ratings.dart index 2967fac..35e9ec9 100644 --- a/lib/features/card/presentation_layer/widgets/view_ratings.dart +++ b/lib/features/card/presentation_layer/widgets/view_ratings.dart @@ -5,9 +5,11 @@ import 'package:percent_indicator/linear_percent_indicator.dart'; import 'package:taafee_mobile/common/const/const.dart'; import 'package:taafee_mobile/common/widgets/listview.dart'; import 'package:taafee_mobile/common/widgets/text.dart'; +import 'package:taafee_mobile/features/card/data_layer/model/card_model.dart'; class ViewRatingsWidget extends StatelessWidget { - const ViewRatingsWidget({super.key}); + final CardModel cardModel; + const ViewRatingsWidget({super.key, required this.cardModel}); @override Widget build(BuildContext context) { @@ -23,15 +25,15 @@ class ViewRatingsWidget extends StatelessWidget { color: AppColors.primeColor, shape: BoxShape.circle, ), - child: const BoldTextWidget( - "5.0", + child: BoldTextWidget( + (cardModel.avgRating / 2).toString(), fontSize: 24, color: Colors.white, ), ), RatingBar.builder( itemSize: 15, - initialRating: 3.5, + initialRating: cardModel.avgRating / 2, minRating: 1, direction: Axis.horizontal, allowHalfRating: true, diff --git a/lib/features/card/presentation_layer/widgets/wording_time.dart b/lib/features/card/presentation_layer/widgets/wording_time.dart index a4ed41b..12f531b 100644 --- a/lib/features/card/presentation_layer/widgets/wording_time.dart +++ b/lib/features/card/presentation_layer/widgets/wording_time.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:get/get.dart'; +import 'package:taafee_mobile/features/card/data_layer/model/work_schedules.dart'; import 'package:taafee_mobile/features/card/data_layer/model/working_time.dart'; import '../../../../common/const/const.dart'; @@ -7,77 +8,66 @@ import '../../../../common/widgets/listview.dart'; import '../../../../common/widgets/text.dart'; class WorkingTimeWidget extends StatelessWidget { - final List list = [ - WorkingTimeModel(type: "Sunday", startTime: "8:00", endTime: "10:00"), - WorkingTimeModel(type: "Monday", startTime: "8:00", endTime: "10:00"), - WorkingTimeModel(type: "Sunday", startTime: "8:00", endTime: "10:00"), - ]; - WorkingTimeWidget({super.key}); + WorkScheduleModel? workScheduleModel; + WorkingTimeWidget({super.key, this.workScheduleModel}); @override Widget build(BuildContext context) { - return Container( - width: Get.width * .89, - height: 270, - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(10), - ), - child: Stack( - children: [ - const BoldTextWidget( - "working time", - color: Colors.grey, - ).paddingSymmetric(horizontal: 20), - ListViewWidget( - physics: const BouncingScrollPhysics(), - itemCount: 8, - scrollDirection: Axis.horizontal, - childBuilder: (index) { - return Column( - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - const RegularTextWidget("8:00"), - Expanded( - child: Container( - width: 1, - color: AppColors.dividerColor, - ), - ), - ], - ).paddingSymmetric(horizontal: 10); - }).paddingOnly(top: 25), - SizedBox( + return workScheduleModel != null + ? Container( + width: Get.width * .89, + // height: 270, + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(10), + ), + child: SizedBox( width: Get.width * .89, child: ListViewWidget( - itemCount: list.length, + itemCount: workScheduleModel!.days.length, + physics: const BouncingScrollPhysics(), childBuilder: (index) { - return SizedBox( - width: Get.width * .89, - height: 42, - child: ListViewWidget( - padding: const EdgeInsets.only(top: 20), - scrollDirection: Axis.horizontal, - itemCount: list.length, - childBuilder: (index) { - return Container( - alignment: Alignment.center, - margin: const EdgeInsets.symmetric(horizontal: 10), - width: 100, - decoration: BoxDecoration( - color: AppColors.secondaryColor, - borderRadius: BorderRadius.circular(25), - ), - child: RegularTextWidget( - list[index].type, - color: Colors.white, - ), - ); - }), + return Row( + children: [ + SizedBox( + width: 90, + child: BoldTextWidget(workScheduleModel!.days[index].day), + ).paddingSymmetric(horizontal: 12), + Expanded( + child: SizedBox( + height: 50, + child: ListViewWidget( + physics: const BouncingScrollPhysics(), + scrollDirection: Axis.horizontal, + itemCount: workScheduleModel!.days[index].workTime.length, + childBuilder: (i) { + return Container( + alignment: Alignment.center, + width: 125, + decoration: BoxDecoration( + color: workScheduleModel!.days[index].workTime[i].name == "عطلة" + ? Colors.grey + : AppColors.secondaryColor, + borderRadius: BorderRadius.circular(10), + ), + margin: const EdgeInsets.symmetric(horizontal: 0, vertical: 10), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + RegularTextWidget(workScheduleModel!.days[index].workTime[i].startTime), + RegularTextWidget(workScheduleModel!.days[index].workTime[i].name), + RegularTextWidget(workScheduleModel!.days[index].workTime[i].endTime), + ], + ).paddingSymmetric(horizontal: 10), + ); + }), + ), + ) + ], ); }), - ).paddingOnly(top: 30) - ], - )); + ), + ) + : Container(); } }