BASE: Update Icons & Name Of The App.

This commit is contained in:
2025-12-04 10:23:59 +05:00
parent b04050384d
commit e602782edd
228 changed files with 34364 additions and 7905 deletions

View File

@@ -11,7 +11,7 @@ import 'package:customer/themes/app_them_data.dart';
import 'package:customer/themes/round_button_fill.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:get/get.dart' hide Trans;
class FavouriteOndemandScreen extends StatelessWidget {
const FavouriteOndemandScreen({super.key});
@@ -24,7 +24,8 @@ class FavouriteOndemandScreen extends StatelessWidget {
init: FavouriteOndemmandController(),
builder: (controller) {
return Scaffold(
backgroundColor: isDark ? AppThemeData.surfaceDark : AppThemeData.surface,
backgroundColor:
isDark ? AppThemeData.surfaceDark : AppThemeData.surface,
appBar: AppBar(
automaticallyImplyLeading: false,
backgroundColor: AppThemeData.onDemand300,
@@ -33,7 +34,15 @@ class FavouriteOndemandScreen extends StatelessWidget {
child: Row(
children: [
const SizedBox(width: 10),
Text("Favourite Services".tr(), style: TextStyle(fontFamily: AppThemeData.semiBold, color: isDark ? AppThemeData.grey900 : AppThemeData.grey900, fontSize: 20)),
Text(
"Favourite Services".tr(),
style: TextStyle(
fontFamily: AppThemeData.semiBold,
color:
isDark ? AppThemeData.grey900 : AppThemeData.grey900,
fontSize: 20,
),
),
],
),
),
@@ -50,12 +59,30 @@ class FavouriteOndemandScreen extends StatelessWidget {
children: [
Image.asset("assets/images/login.gif", height: 120),
const SizedBox(height: 12),
Text("Please Log In to Continue".tr(), style: TextStyle(color: isDark ? AppThemeData.grey100 : AppThemeData.grey800, fontSize: 22, fontFamily: AppThemeData.semiBold)),
Text(
"Please Log In to Continue".tr(),
style: TextStyle(
color:
isDark
? AppThemeData.grey100
: AppThemeData.grey800,
fontSize: 22,
fontFamily: AppThemeData.semiBold,
),
),
const SizedBox(height: 5),
Text(
"Youre not logged in. Please sign in to access your account and explore all features.".tr(),
"Youre not logged in. Please sign in to access your account and explore all features."
.tr(),
textAlign: TextAlign.center,
style: TextStyle(color: isDark ? AppThemeData.grey50 : AppThemeData.grey500, fontSize: 16, fontFamily: AppThemeData.bold),
style: TextStyle(
color:
isDark
? AppThemeData.grey50
: AppThemeData.grey500,
fontSize: 16,
fontFamily: AppThemeData.bold,
),
),
const SizedBox(height: 20),
RoundedButtonFill(
@@ -72,10 +99,15 @@ class FavouriteOndemandScreen extends StatelessWidget {
),
)
: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 10),
padding: const EdgeInsets.symmetric(
horizontal: 16,
vertical: 10,
),
child:
controller.lstFav.isEmpty
? Constant.showEmptyView(message: "Favourite Service not found.".tr())
? Constant.showEmptyView(
message: "Favourite Service not found.".tr(),
)
: ListView.builder(
shrinkWrap: true,
padding: EdgeInsets.zero,
@@ -83,86 +115,231 @@ class FavouriteOndemandScreen extends StatelessWidget {
physics: const BouncingScrollPhysics(),
itemCount: controller.lstFav.length,
itemBuilder: (context, index) {
return FutureBuilder<List<ProviderServiceModel>>(
future: FireStoreUtils.getCurrentProviderService(controller.lstFav[index]),
return FutureBuilder<
List<ProviderServiceModel>
>(
future:
FireStoreUtils.getCurrentProviderService(
controller.lstFav[index],
),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const Center(child: CircularProgressIndicator());
if (snapshot.connectionState ==
ConnectionState.waiting) {
return const Center(
child: CircularProgressIndicator(),
);
}
if (!snapshot.hasData || snapshot.data == null || snapshot.data!.isEmpty) {
if (!snapshot.hasData ||
snapshot.data == null ||
snapshot.data!.isEmpty) {
return const SizedBox(); // or a placeholder widget
}
final provider = snapshot.data!.first; // safer way than [0]
final provider =
snapshot
.data!
.first; // safer way than [0]
return GestureDetector(
onTap: () {
Get.to(() => OnDemandDetailsScreen(), arguments: {'providerModel': provider});
Get.to(
() => OnDemandDetailsScreen(),
arguments: {
'providerModel': provider,
},
);
},
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 5),
padding: const EdgeInsets.symmetric(
vertical: 5,
),
child: Container(
height: MediaQuery.of(context).size.height * 0.16,
height:
MediaQuery.of(
context,
).size.height *
0.16,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
border: Border.all(color: isDark ? AppThemeData.grey500 : Colors.grey.shade100, width: 1),
color: isDark ? AppThemeData.grey900 : Colors.white,
borderRadius: BorderRadius.circular(
10,
),
border: Border.all(
color:
isDark
? AppThemeData.grey500
: Colors.grey.shade100,
width: 1,
),
color:
isDark
? AppThemeData.grey900
: Colors.white,
),
child: Row(
children: [
ClipRRect(
borderRadius: const BorderRadius.only(bottomLeft: Radius.circular(10), topLeft: Radius.circular(10)),
borderRadius:
const BorderRadius.only(
bottomLeft:
Radius.circular(10),
topLeft: Radius.circular(
10,
),
),
child: CachedNetworkImage(
imageUrl: provider.photos.isNotEmpty ? provider.photos.first : Constant.placeHolderImage,
height: MediaQuery.of(context).size.height * 0.16,
imageUrl:
provider.photos.isNotEmpty
? provider
.photos
.first
: Constant
.placeHolderImage,
height:
MediaQuery.of(
context,
).size.height *
0.16,
width: 110,
fit: BoxFit.cover,
placeholder: (context, url) => Center(child: CircularProgressIndicator.adaptive(valueColor: AlwaysStoppedAnimation(AppThemeData.primary300))),
errorWidget: (context, url, error) => Image.network(Constant.placeHolderImage, fit: BoxFit.cover),
placeholder:
(context, url) => Center(
child: CircularProgressIndicator.adaptive(
valueColor:
AlwaysStoppedAnimation(
AppThemeData
.primary300,
),
),
),
errorWidget:
(
context,
url,
error,
) => Image.network(
Constant
.placeHolderImage,
fit: BoxFit.cover,
),
),
),
Expanded(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 10),
padding:
const EdgeInsets.symmetric(
horizontal: 16,
vertical: 10,
),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment:
MainAxisAlignment
.spaceBetween,
crossAxisAlignment:
CrossAxisAlignment
.start,
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.start,
crossAxisAlignment:
CrossAxisAlignment
.start,
children: [
Expanded(
child: Text(
provider.title ?? "",
provider.title ??
"",
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold, color: isDark ? Colors.white : Colors.black),
overflow:
TextOverflow
.ellipsis,
style: TextStyle(
fontSize: 18,
fontWeight:
FontWeight
.bold,
color:
isDark
? Colors
.white
: Colors
.black,
),
),
),
Obx(
() => GestureDetector(
onTap: () => controller.toggleFavourite(provider),
onTap:
() => controller
.toggleFavourite(
provider,
),
child: Icon(
controller.lstFav.where((element) => element.service_id == provider.id).isNotEmpty ? Icons.favorite : Icons.favorite_border,
controller
.lstFav
.where(
(
element,
) =>
element.service_id ==
provider.id,
)
.isNotEmpty
? Icons
.favorite
: Icons
.favorite_border,
size: 24,
color:
controller.lstFav.where((element) => element.service_id == provider.id).isNotEmpty
? AppThemeData.primary300
: (isDark ? Colors.white38 : Colors.black38),
controller
.lstFav
.where(
(
element,
) =>
element.service_id ==
provider.id,
)
.isNotEmpty
? AppThemeData
.primary300
: (isDark
? Colors.white38
: Colors.black38),
),
),
),
],
),
FutureBuilder<CategoryModel?>(
future: controller.getCategory(provider.categoryId ?? ""),
FutureBuilder<
CategoryModel?
>(
future: controller
.getCategory(
provider.categoryId ??
"",
),
builder: (ctx, snap) {
if (!snap.hasData) return const SizedBox();
return Text(snap.data?.title ?? "", style: TextStyle(fontSize: 14, color: isDark ? Colors.white : Colors.black));
if (!snap.hasData)
return const SizedBox();
return Text(
snap.data?.title ??
"",
style: TextStyle(
fontSize: 14,
color:
isDark
? Colors
.white
: Colors
.black,
),
);
},
),
_buildPrice(provider, isDark: isDark),
_buildPrice(
provider,
isDark: isDark,
),
_buildRating(provider),
],
),
@@ -176,79 +353,231 @@ class FavouriteOndemandScreen extends StatelessWidget {
},
);
FutureBuilder<List<ProviderServiceModel>>(
future: FireStoreUtils.getCurrentProviderService(controller.lstFav[index]),
future:
FireStoreUtils.getCurrentProviderService(
controller.lstFav[index],
),
builder: (context, snapshot) {
return snapshot.data != null
? GestureDetector(
onTap: () {
Get.to(() => OnDemandDetailsScreen(), arguments: {'providerModel': snapshot.data![0]});
Get.to(
() => OnDemandDetailsScreen(),
arguments: {
'providerModel':
snapshot.data![0],
},
);
},
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 5),
padding: const EdgeInsets.symmetric(
vertical: 5,
),
child: Container(
height: MediaQuery.of(context).size.height * 0.16,
height:
MediaQuery.of(
context,
).size.height *
0.16,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
border: Border.all(color: isDark ? AppThemeData.grey500 : Colors.grey.shade100, width: 1),
color: isDark ? AppThemeData.grey900 : Colors.white,
borderRadius:
BorderRadius.circular(10),
border: Border.all(
color:
isDark
? AppThemeData.grey500
: Colors
.grey
.shade100,
width: 1,
),
color:
isDark
? AppThemeData.grey900
: Colors.white,
),
child: Row(
children: [
ClipRRect(
borderRadius: const BorderRadius.only(bottomLeft: Radius.circular(10), topLeft: Radius.circular(10)),
borderRadius:
const BorderRadius.only(
bottomLeft:
Radius.circular(
10,
),
topLeft:
Radius.circular(
10,
),
),
child: CachedNetworkImage(
imageUrl: snapshot.data![0].photos.isNotEmpty ? snapshot.data![0].photos[0] : Constant.placeHolderImage,
height: MediaQuery.of(context).size.height * 0.16,
imageUrl:
snapshot
.data![0]
.photos
.isNotEmpty
? snapshot
.data![0]
.photos[0]
: Constant
.placeHolderImage,
height:
MediaQuery.of(
context,
).size.height *
0.16,
width: 110,
fit: BoxFit.cover,
placeholder: (context, url) => Center(child: CircularProgressIndicator.adaptive(valueColor: AlwaysStoppedAnimation(AppThemeData.primary300))),
errorWidget: (context, url, error) => Image.network(Constant.placeHolderImage, fit: BoxFit.cover),
placeholder:
(
context,
url,
) => Center(
child: CircularProgressIndicator.adaptive(
valueColor:
AlwaysStoppedAnimation(
AppThemeData
.primary300,
),
),
),
errorWidget:
(
context,
url,
error,
) => Image.network(
Constant
.placeHolderImage,
fit: BoxFit.cover,
),
),
),
Expanded(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 10),
padding:
const EdgeInsets.symmetric(
horizontal: 16,
vertical: 10,
),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment:
MainAxisAlignment
.spaceBetween,
crossAxisAlignment:
CrossAxisAlignment
.start,
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.start,
crossAxisAlignment:
CrossAxisAlignment
.start,
children: [
Expanded(
child: Text(
snapshot.data![0].title ?? "",
snapshot
.data![0]
.title ??
"",
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold, color: isDark ? Colors.white : Colors.black),
overflow:
TextOverflow
.ellipsis,
style: TextStyle(
fontSize:
18,
fontWeight:
FontWeight
.bold,
color:
isDark
? Colors.white
: Colors.black,
),
),
),
Obx(
() => GestureDetector(
onTap: () => controller.toggleFavourite(snapshot.data![0]),
onTap:
() => controller.toggleFavourite(
snapshot
.data![0],
),
child: Icon(
controller.lstFav.where((element) => element.service_id == snapshot.data![0].id).isNotEmpty
? Icons.favorite
: Icons.favorite_border,
controller
.lstFav
.where(
(
element,
) =>
element.service_id ==
snapshot.data![0].id,
)
.isNotEmpty
? Icons
.favorite
: Icons
.favorite_border,
size: 24,
color:
controller.lstFav.where((element) => element.service_id == snapshot.data![0].id).isNotEmpty
controller.lstFav
.where(
(
element,
) =>
element.service_id ==
snapshot.data![0].id,
)
.isNotEmpty
? AppThemeData.primary300
: (isDark ? Colors.white38 : Colors.black38),
: (isDark
? Colors.white38
: Colors.black38),
),
),
),
],
),
FutureBuilder<CategoryModel?>(
future: controller.getCategory(snapshot.data![0].categoryId ?? ""),
builder: (ctx, snap) {
if (!snap.hasData) return const SizedBox();
return Text(snap.data?.title ?? "", style: TextStyle(fontSize: 14, color: isDark ? Colors.white : Colors.black));
FutureBuilder<
CategoryModel?
>(
future: controller
.getCategory(
snapshot
.data![0]
.categoryId ??
"",
),
builder: (
ctx,
snap,
) {
if (!snap.hasData)
return const SizedBox();
return Text(
snap
.data
?.title ??
"",
style: TextStyle(
fontSize: 14,
color:
isDark
? Colors
.white
: Colors
.black,
),
);
},
),
_buildPrice(snapshot.data![0], isDark: isDark),
_buildRating(snapshot.data![0]),
_buildPrice(
snapshot.data![0],
isDark: isDark,
),
_buildRating(
snapshot.data![0],
),
],
),
),
@@ -272,20 +601,38 @@ class FavouriteOndemandScreen extends StatelessWidget {
Widget _buildPrice(ProviderServiceModel provider, {bool isDark = false}) {
if (provider.disPrice == "" || provider.disPrice == "0") {
return Text(
provider.priceUnit == 'Fixed' ? Constant.amountShow(amount: provider.price) : '${Constant.amountShow(amount: provider.price ?? "0")}/${'hr'.tr()}',
style: TextStyle(fontSize: 14, fontWeight: FontWeight.bold, color: isDark ? Colors.white : AppThemeData.primary300),
provider.priceUnit == 'Fixed'
? Constant.amountShow(amount: provider.price)
: '${Constant.amountShow(amount: provider.price ?? "0")}/${'hr'.tr()}',
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.bold,
color: isDark ? Colors.white : AppThemeData.primary300,
),
);
} else {
return Row(
children: [
Text(
provider.priceUnit == 'Fixed' ? Constant.amountShow(amount: provider.disPrice ?? '0') : '${Constant.amountShow(amount: provider.disPrice)}/${'hr'.tr()}',
style: TextStyle(fontSize: 14, fontWeight: FontWeight.bold, color: isDark ? Colors.white : AppThemeData.primary300),
provider.priceUnit == 'Fixed'
? Constant.amountShow(amount: provider.disPrice ?? '0')
: '${Constant.amountShow(amount: provider.disPrice)}/${'hr'.tr()}',
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.bold,
color: isDark ? Colors.white : AppThemeData.primary300,
),
),
const SizedBox(width: 5),
Text(
provider.priceUnit == 'Fixed' ? Constant.amountShow(amount: provider.price) : '${Constant.amountShow(amount: provider.price ?? "0")}/${'hr'.tr()}',
style: const TextStyle(fontSize: 12, color: Colors.grey, decoration: TextDecoration.lineThrough),
provider.priceUnit == 'Fixed'
? Constant.amountShow(amount: provider.price)
: '${Constant.amountShow(amount: provider.price ?? "0")}/${'hr'.tr()}',
style: const TextStyle(
fontSize: 12,
color: Colors.grey,
decoration: TextDecoration.lineThrough,
),
),
],
);
@@ -298,14 +645,24 @@ class FavouriteOndemandScreen extends StatelessWidget {
rating = (provider.reviewsSum ?? 0) / (provider.reviewsCount ?? 1);
}
return Container(
decoration: BoxDecoration(color: AppThemeData.warning400, borderRadius: BorderRadius.circular(16)),
decoration: BoxDecoration(
color: AppThemeData.warning400,
borderRadius: BorderRadius.circular(16),
),
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 5),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
const Icon(Icons.star, size: 16, color: Colors.white),
const SizedBox(width: 3),
Text(rating.toStringAsFixed(1), style: const TextStyle(letterSpacing: 0.5, fontSize: 12, color: Colors.white)),
Text(
rating.toStringAsFixed(1),
style: const TextStyle(
letterSpacing: 0.5,
fontSize: 12,
color: Colors.white,
),
),
],
),
);

View File

@@ -1,7 +1,7 @@
import 'package:cached_network_image/cached_network_image.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:get/get.dart' hide Trans;
import 'package:intl/intl.dart';
import '../../constant/constant.dart';
import '../../controllers/my_booking_on_demand_controller.dart';
@@ -24,13 +24,24 @@ class MyBookingOnDemandScreen extends StatelessWidget {
builder: (controller) {
return DefaultTabController(
length: controller.tabTitles.length,
initialIndex: controller.tabTitles.indexOf(controller.selectedTab.value),
initialIndex: controller.tabTitles.indexOf(
controller.selectedTab.value,
),
child: Scaffold(
appBar: AppBar(
automaticallyImplyLeading: false,
backgroundColor: AppThemeData.primary300,
centerTitle: false,
title: Padding(padding: const EdgeInsets.only(bottom: 10), child: Text("Booking History".tr(), style: AppThemeData.boldTextStyle(fontSize: 18, color: AppThemeData.grey900))),
title: Padding(
padding: const EdgeInsets.only(bottom: 10),
child: Text(
"Booking History".tr(),
style: AppThemeData.boldTextStyle(
fontSize: 18,
color: AppThemeData.grey900,
),
),
),
bottom: PreferredSize(
preferredSize: const Size.fromHeight(48),
child: TabBar(
@@ -41,8 +52,15 @@ class MyBookingOnDemandScreen extends StatelessWidget {
labelColor: AppThemeData.grey900,
unselectedLabelColor: AppThemeData.grey900,
labelStyle: AppThemeData.boldTextStyle(fontSize: 16),
unselectedLabelStyle: AppThemeData.mediumTextStyle(fontSize: 16),
tabs: controller.tabTitles.map((title) => Tab(child: Center(child: Text(title)))).toList(),
unselectedLabelStyle: AppThemeData.mediumTextStyle(
fontSize: 16,
),
tabs:
controller.tabTitles
.map(
(title) => Tab(child: Center(child: Text(title))),
)
.toList(),
),
),
),
@@ -55,78 +73,217 @@ class MyBookingOnDemandScreen extends StatelessWidget {
final orders = controller.getOrdersForTab(title);
if (orders.isEmpty) {
return Center(child: Text("No ride found".tr(), style: AppThemeData.mediumTextStyle(color: isDark ? AppThemeData.greyDark900 : AppThemeData.grey900)));
return Center(
child: Text(
"No ride found".tr(),
style: AppThemeData.mediumTextStyle(
color:
isDark
? AppThemeData.greyDark900
: AppThemeData.grey900,
),
),
);
}
return ListView.builder(
padding: const EdgeInsets.all(16),
itemCount: orders.length,
itemBuilder: (context, index) {
OnProviderOrderModel onProviderOrder = orders[index];
WorkerModel? worker = controller.getWorker(onProviderOrder.workerId);
OnProviderOrderModel onProviderOrder =
orders[index];
WorkerModel? worker = controller.getWorker(
onProviderOrder.workerId,
);
return InkWell(
onTap: () {
Get.to(() => OnDemandOrderDetailsScreen(), arguments: onProviderOrder);
Get.to(
() => OnDemandOrderDetailsScreen(),
arguments: onProviderOrder,
);
},
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 5, vertical: 5),
padding: const EdgeInsets.symmetric(
horizontal: 5,
vertical: 5,
),
margin: const EdgeInsets.only(bottom: 15),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
border: Border.all(color: isDark ? AppThemeData.grey500 : Colors.grey.shade100, width: 1),
color: isDark ? AppThemeData.grey500 : Colors.white,
border: Border.all(
color:
isDark
? AppThemeData.grey500
: Colors.grey.shade100,
width: 1,
),
color:
isDark
? AppThemeData.grey500
: Colors.white,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Row(
children: [
Padding(
padding: const EdgeInsets.symmetric(horizontal: 10),
padding:
const EdgeInsets.symmetric(
horizontal: 10,
),
child: CachedNetworkImage(
imageUrl: onProviderOrder.provider.photos.first,
imageUrl:
onProviderOrder
.provider
.photos
.first,
height: 80,
width: 80,
imageBuilder:
(context, imageProvider) =>
Container(decoration: BoxDecoration(borderRadius: BorderRadius.circular(10), image: DecorationImage(image: imageProvider, fit: BoxFit.cover))),
placeholder: (context, url) => Center(child: CircularProgressIndicator.adaptive(valueColor: AlwaysStoppedAnimation(AppThemeData.primary300))),
(
context,
imageProvider,
) => Container(
decoration: BoxDecoration(
borderRadius:
BorderRadius.circular(
10,
),
image: DecorationImage(
image: imageProvider,
fit: BoxFit.cover,
),
),
),
placeholder:
(context, url) => Center(
child: CircularProgressIndicator.adaptive(
valueColor:
AlwaysStoppedAnimation(
AppThemeData
.primary300,
),
),
),
errorWidget:
(context, url, error) => ClipRRect(
borderRadius: BorderRadius.circular(10),
child: Image.network(Constant.placeHolderImage, fit: BoxFit.cover, cacheHeight: 80, cacheWidth: 80),
(
context,
url,
error,
) => ClipRRect(
borderRadius:
BorderRadius.circular(
10,
),
child: Image.network(
Constant
.placeHolderImage,
fit: BoxFit.cover,
cacheHeight: 80,
cacheWidth: 80,
),
),
fit: BoxFit.cover,
),
),
Expanded(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 20),
padding:
const EdgeInsets.symmetric(
horizontal: 20,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Container(
padding: const EdgeInsets.symmetric(vertical: 6, horizontal: 12),
decoration: BoxDecoration(color: AppThemeData.info50, border: Border.all(color: AppThemeData.info300), borderRadius: BorderRadius.circular(12)),
child: Text(onProviderOrder.status, style: AppThemeData.boldTextStyle(fontSize: 14, color: AppThemeData.info500)),
),
Padding(
padding: const EdgeInsets.only(top: 6),
padding:
const EdgeInsets.symmetric(
vertical: 6,
horizontal: 12,
),
decoration: BoxDecoration(
color:
AppThemeData.info50,
border: Border.all(
color:
AppThemeData
.info300,
),
borderRadius:
BorderRadius.circular(
12,
),
),
child: Text(
onProviderOrder.provider.title.toString(),
style: AppThemeData.semiBoldTextStyle(fontSize: 16, color: isDark ? AppThemeData.greyDark900 : AppThemeData.grey900),
onProviderOrder.status,
style:
AppThemeData.boldTextStyle(
fontSize: 14,
color:
AppThemeData
.info500,
),
),
),
Padding(
padding:
const EdgeInsets.only(
top: 6,
),
child: Text(
onProviderOrder
.provider
.title
.toString(),
style: AppThemeData.semiBoldTextStyle(
fontSize: 16,
color:
isDark
? AppThemeData
.greyDark900
: AppThemeData
.grey900,
),
),
),
Padding(
padding:
const EdgeInsets.only(
top: 6,
),
child: buildPriceText(
onProviderOrder,
),
),
Padding(padding: const EdgeInsets.only(top: 6), child: buildPriceText(onProviderOrder)),
const SizedBox(height: 6),
if (onProviderOrder.status != Constant.orderCompleted &&
onProviderOrder.status != Constant.orderCancelled &&
onProviderOrder.otp != null &&
onProviderOrder.otp!.isNotEmpty)
if (onProviderOrder
.status !=
Constant
.orderCompleted &&
onProviderOrder
.status !=
Constant
.orderCancelled &&
onProviderOrder.otp !=
null &&
onProviderOrder
.otp!
.isNotEmpty)
Text(
"${'OTP :'.tr()} ${onProviderOrder.otp}",
style: AppThemeData.mediumTextStyle(fontSize: 14, color: isDark ? AppThemeData.greyDark900 : AppThemeData.grey900),
style: AppThemeData.mediumTextStyle(
fontSize: 14,
color:
isDark
? AppThemeData
.greyDark900
: AppThemeData
.grey900,
),
),
],
),
@@ -136,7 +293,12 @@ class MyBookingOnDemandScreen extends StatelessWidget {
),
/// Bottom Details (Date, Provider, Worker)
buildBottomDetails(context, onProviderOrder, isDark, worker),
buildBottomDetails(
context,
onProviderOrder,
isDark,
worker,
),
],
),
),
@@ -152,37 +314,81 @@ class MyBookingOnDemandScreen extends StatelessWidget {
}
Widget buildPriceText(OnProviderOrderModel order) {
final hasDiscount = order.provider.disPrice != "" && order.provider.disPrice != "0";
final price = hasDiscount ? order.provider.disPrice.toString() : order.provider.price.toString();
final hasDiscount =
order.provider.disPrice != "" && order.provider.disPrice != "0";
final price =
hasDiscount
? order.provider.disPrice.toString()
: order.provider.price.toString();
return Text(
order.provider.priceUnit == 'Fixed' ? Constant.amountShow(amount: price) : "${Constant.amountShow(amount: price)}/${'hr'.tr()}",
style: AppThemeData.mediumTextStyle(fontSize: 16, color: AppThemeData.primary300),
order.provider.priceUnit == 'Fixed'
? Constant.amountShow(amount: price)
: "${Constant.amountShow(amount: price)}/${'hr'.tr()}",
style: AppThemeData.mediumTextStyle(
fontSize: 16,
color: AppThemeData.primary300,
),
);
}
Widget buildBottomDetails(BuildContext context, OnProviderOrderModel order, bool isDark, WorkerModel? worker) {
Widget buildBottomDetails(
BuildContext context,
OnProviderOrderModel order,
bool isDark,
WorkerModel? worker,
) {
return Container(
margin: const EdgeInsets.symmetric(horizontal: 10, vertical: 10),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
border: Border.all(color: isDark ? AppThemeData.grey400 : AppThemeData.grey100, width: 1),
border: Border.all(
color: isDark ? AppThemeData.grey400 : AppThemeData.grey100,
width: 1,
),
color: isDark ? AppThemeData.greyDark100 : AppThemeData.grey100,
),
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 10),
child: Column(
children: [
detailRow("Date & Time", DateFormat('dd-MMM-yyyy hh:mm a').format(order.scheduleDateTime!.toDate()), isDark),
detailRow(
"Date & Time",
DateFormat(
'dd-MMM-yyyy hh:mm a',
).format(order.scheduleDateTime!.toDate()),
isDark,
),
const Divider(thickness: 1),
detailRow("Provider", order.provider.authorName.toString(), isDark),
if (order.provider.priceUnit == "Hourly") ...[
if (order.startTime != null) ...[const Divider(thickness: 1), detailRow("Start Time", DateFormat('dd-MMM-yyyy hh:mm a').format(order.startTime!.toDate()), isDark)],
if (order.endTime != null) ...[const Divider(thickness: 1), detailRow("End Time", DateFormat('dd-MMM-yyyy hh:mm a').format(order.endTime!.toDate()), isDark)],
if (order.startTime != null) ...[
const Divider(thickness: 1),
detailRow(
"Start Time",
DateFormat(
'dd-MMM-yyyy hh:mm a',
).format(order.startTime!.toDate()),
isDark,
),
],
if (order.endTime != null) ...[
const Divider(thickness: 1),
detailRow(
"End Time",
DateFormat(
'dd-MMM-yyyy hh:mm a',
).format(order.endTime!.toDate()),
isDark,
),
],
],
if (worker != null) ...[const Divider(thickness: 1), detailRow("Worker", worker.fullName().toString(), isDark)],
if (worker != null) ...[
const Divider(thickness: 1),
detailRow("Worker", worker.fullName().toString(), isDark),
],
],
),
),
@@ -195,8 +401,20 @@ class MyBookingOnDemandScreen extends StatelessWidget {
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(label.tr(), style: AppThemeData.mediumTextStyle(fontSize: 14, color: isDark ? AppThemeData.greyDark900 : AppThemeData.grey900)),
Text(value.tr(), style: AppThemeData.regularTextStyle(fontSize: 14, color: isDark ? AppThemeData.greyDark900 : AppThemeData.grey900)),
Text(
label.tr(),
style: AppThemeData.mediumTextStyle(
fontSize: 14,
color: isDark ? AppThemeData.greyDark900 : AppThemeData.grey900,
),
),
Text(
value.tr(),
style: AppThemeData.regularTextStyle(
fontSize: 14,
color: isDark ? AppThemeData.greyDark900 : AppThemeData.grey900,
),
),
],
),
);

View File

@@ -4,7 +4,7 @@ import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:geocoding/geocoding.dart';
import 'package:geolocator/geolocator.dart';
import 'package:get/get.dart';
import 'package:get/get.dart' hide Trans;
import '../../constant/constant.dart';
import '../../controllers/theme_controller.dart';
import '../../controllers/on_demand_booking_controller.dart';
@@ -42,12 +42,30 @@ class OnDemandBookingScreen extends StatelessWidget {
child: Container(
height: 42,
width: 42,
decoration: BoxDecoration(shape: BoxShape.circle, color: AppThemeData.grey50),
child: Center(child: Padding(padding: const EdgeInsets.only(left: 5), child: Icon(Icons.arrow_back_ios, color: AppThemeData.grey900, size: 20))),
decoration: BoxDecoration(
shape: BoxShape.circle,
color: AppThemeData.grey50,
),
child: Center(
child: Padding(
padding: const EdgeInsets.only(left: 5),
child: Icon(
Icons.arrow_back_ios,
color: AppThemeData.grey900,
size: 20,
),
),
),
),
),
const SizedBox(width: 10),
Text("Book Service".tr(), style: AppThemeData.boldTextStyle(fontSize: 18, color: AppThemeData.grey900)),
Text(
"Book Service".tr(),
style: AppThemeData.boldTextStyle(
fontSize: 18,
color: AppThemeData.grey900,
),
),
],
),
),
@@ -58,13 +76,28 @@ class OnDemandBookingScreen extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Services Section
Text("Services".tr(), style: AppThemeData.semiBoldTextStyle(fontSize: 18, color: isDark ? AppThemeData.greyDark900 : AppThemeData.grey900)),
Text(
"Services".tr(),
style: AppThemeData.semiBoldTextStyle(
fontSize: 18,
color:
isDark
? AppThemeData.greyDark900
: AppThemeData.grey900,
),
),
const SizedBox(height: 10),
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
border: Border.all(color: isDark ? AppThemeData.greyDark400 : AppThemeData.grey100),
color: isDark ? AppThemeData.greyDark50 : AppThemeData.grey50,
border: Border.all(
color:
isDark
? AppThemeData.greyDark400
: AppThemeData.grey100,
),
color:
isDark ? AppThemeData.greyDark50 : AppThemeData.grey50,
),
padding: const EdgeInsets.all(8),
child: Row(
@@ -73,18 +106,60 @@ class OnDemandBookingScreen extends StatelessWidget {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(controller.provider.value?.title ?? '', style: AppThemeData.mediumTextStyle(fontSize: 16, color: isDark ? AppThemeData.greyDark900 : AppThemeData.grey900)),
Text(
controller.provider.value?.title ?? '',
style: AppThemeData.mediumTextStyle(
fontSize: 16,
color:
isDark
? AppThemeData.greyDark900
: AppThemeData.grey900,
),
),
const SizedBox(height: 5),
Text(controller.categoryTitle.value, style: AppThemeData.mediumTextStyle(fontSize: 14, color: isDark ? AppThemeData.greyDark900 : AppThemeData.grey900)),
if (controller.provider.value?.priceUnit == "Fixed") ...[
Text(
controller.categoryTitle.value,
style: AppThemeData.mediumTextStyle(
fontSize: 14,
color:
isDark
? AppThemeData.greyDark900
: AppThemeData.grey900,
),
),
if (controller.provider.value?.priceUnit ==
"Fixed") ...[
const SizedBox(height: 20),
Row(
children: [
GestureDetector(onTap: controller.decrementQuantity, child: Icon(Icons.remove_circle_outline, color: AppThemeData.primary300, size: 30)),
GestureDetector(
onTap: controller.decrementQuantity,
child: Icon(
Icons.remove_circle_outline,
color: AppThemeData.primary300,
size: 30,
),
),
const SizedBox(width: 10),
Text('${controller.quantity.value}', style: AppThemeData.mediumTextStyle(fontSize: 18, color: isDark ? AppThemeData.greyDark900 : AppThemeData.grey900)),
Text(
'${controller.quantity.value}',
style: AppThemeData.mediumTextStyle(
fontSize: 18,
color:
isDark
? AppThemeData.greyDark900
: AppThemeData.grey900,
),
),
const SizedBox(width: 10),
GestureDetector(onTap: controller.incrementQuantity, child: Icon(Icons.add_circle_outline, color: AppThemeData.primary300, size: 30)),
GestureDetector(
onTap: controller.incrementQuantity,
child: Icon(
Icons.add_circle_outline,
color: AppThemeData.primary300,
size: 30,
),
),
],
),
],
@@ -98,7 +173,15 @@ class OnDemandBookingScreen extends StatelessWidget {
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
color: Colors.grey.shade300,
image: controller.provider.value!.photos.isNotEmpty ? DecorationImage(image: NetworkImage(controller.provider.value?.photos.first), fit: BoxFit.cover) : null,
image:
controller.provider.value!.photos.isNotEmpty
? DecorationImage(
image: NetworkImage(
controller.provider.value?.photos.first,
),
fit: BoxFit.cover,
)
: null,
),
),
],
@@ -109,8 +192,14 @@ class OnDemandBookingScreen extends StatelessWidget {
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
border: Border.all(color: isDark ? AppThemeData.greyDark400 : AppThemeData.grey100),
color: isDark ? AppThemeData.greyDark50 : AppThemeData.grey50,
border: Border.all(
color:
isDark
? AppThemeData.greyDark400
: AppThemeData.grey100,
),
color:
isDark ? AppThemeData.greyDark50 : AppThemeData.grey50,
),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
@@ -119,7 +208,16 @@ class OnDemandBookingScreen extends StatelessWidget {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text("Address".tr(), style: AppThemeData.semiBoldTextStyle(fontSize: 18, color: isDark ? AppThemeData.greyDark900 : AppThemeData.grey900)),
Text(
"Address".tr(),
style: AppThemeData.semiBoldTextStyle(
fontSize: 18,
color:
isDark
? AppThemeData.greyDark900
: AppThemeData.grey900,
),
),
SizedBox(height: 5),
InkWell(
onTap: () async {
@@ -127,20 +225,32 @@ class OnDemandBookingScreen extends StatelessWidget {
Get.to(AddressListScreen())!.then((value) {
if (value != null) {
ShippingAddress shippingAddress = value;
if (Constant.checkZoneCheck(shippingAddress.location!.latitude ?? 0.0, shippingAddress.location!.longitude ?? 0.0)) {
controller.selectedAddress.value = shippingAddress;
if (Constant.checkZoneCheck(
shippingAddress.location!.latitude ??
0.0,
shippingAddress.location!.longitude ??
0.0,
)) {
controller.selectedAddress.value =
shippingAddress;
controller.calculatePrice();
} else {
ShowToastDialog.showToast("Service not available in this area".tr());
ShowToastDialog.showToast(
"Service not available in this area"
.tr(),
);
}
}
});
} else {
Constant.checkPermission(
onTap: () async {
ShowToastDialog.showLoader("Please wait...".tr());
ShowToastDialog.showLoader(
"Please wait...".tr(),
);
ShippingAddress shippingAddress = ShippingAddress();
ShippingAddress shippingAddress =
ShippingAddress();
try {
await Geolocator.requestPermission();
@@ -148,43 +258,81 @@ class OnDemandBookingScreen extends StatelessWidget {
ShowToastDialog.closeLoader();
if (Constant.selectedMapType == 'osm') {
final result = await Get.to(() => MapPickerPage());
final result = await Get.to(
() => MapPickerPage(),
);
if (result != null) {
final firstPlace = result;
final lat = firstPlace.coordinates.latitude;
final lng = firstPlace.coordinates.longitude;
final lat =
firstPlace.coordinates.latitude;
final lng =
firstPlace
.coordinates
.longitude;
final address = firstPlace.address;
shippingAddress.addressAs = "Home";
shippingAddress.locality = address.toString();
shippingAddress.location = UserLocation(latitude: lat, longitude: lng);
shippingAddress.locality =
address.toString();
shippingAddress
.location = UserLocation(
latitude: lat,
longitude: lng,
);
controller.selectedAddress.value = shippingAddress;
controller.selectedAddress.value =
shippingAddress;
Get.back();
}
} else {
Get.to(LocationPickerScreen())!.then((value) async {
Get.to(LocationPickerScreen())!.then((
value,
) async {
if (value != null) {
SelectedLocationModel selectedLocationModel = value;
SelectedLocationModel
selectedLocationModel = value;
shippingAddress.addressAs = "Home";
shippingAddress.location = UserLocation(latitude: selectedLocationModel.latLng!.latitude, longitude: selectedLocationModel.latLng!.longitude);
shippingAddress.locality = "Picked from Map";
shippingAddress.addressAs =
"Home";
shippingAddress
.location = UserLocation(
latitude:
selectedLocationModel
.latLng!
.latitude,
longitude:
selectedLocationModel
.latLng!
.longitude,
);
shippingAddress.locality =
"Picked from Map";
controller.selectedAddress.value = shippingAddress;
controller.selectedAddress.value =
shippingAddress;
}
});
}
} catch (e) {
await placemarkFromCoordinates(19.228825, 72.854118).then((valuePlaceMaker) {
Placemark placeMark = valuePlaceMaker[0];
shippingAddress.location = UserLocation(latitude: 19.228825, longitude: 72.854118);
await placemarkFromCoordinates(
19.228825,
72.854118,
).then((valuePlaceMaker) {
Placemark placeMark =
valuePlaceMaker[0];
shippingAddress
.location = UserLocation(
latitude: 19.228825,
longitude: 72.854118,
);
String currentLocation =
"${placeMark.name}, ${placeMark.subLocality}, ${placeMark.locality}, ${placeMark.administrativeArea}, ${placeMark.postalCode}, ${placeMark.country}";
shippingAddress.locality = currentLocation;
shippingAddress.locality =
currentLocation;
});
controller.selectedAddress.value = shippingAddress;
controller.selectedAddress.value =
shippingAddress;
ShowToastDialog.closeLoader();
}
},
@@ -193,10 +341,17 @@ class OnDemandBookingScreen extends StatelessWidget {
}
},
child: Text(
controller.selectedAddress.value.getFullAddress(),
controller.selectedAddress.value
.getFullAddress(),
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: AppThemeData.mediumTextStyle(fontSize: 16, color: isDark ? AppThemeData.greyDark900 : AppThemeData.grey900),
style: AppThemeData.mediumTextStyle(
fontSize: 16,
color:
isDark
? AppThemeData.greyDark900
: AppThemeData.grey900,
),
),
),
],
@@ -206,7 +361,12 @@ class OnDemandBookingScreen extends StatelessWidget {
),
),
const SizedBox(height: 15),
TextFieldWidget(title: "Description".tr(), hintText: "Enter Description".tr(), controller: controller.descriptionController.value, maxLine: 5),
TextFieldWidget(
title: "Description".tr(),
hintText: "Enter Description".tr(),
controller: controller.descriptionController.value,
maxLine: 5,
),
const SizedBox(height: 10),
GestureDetector(
onTap: () {
@@ -220,13 +380,36 @@ class OnDemandBookingScreen extends StatelessWidget {
buttonSingleColor: AppThemeData.primary300,
buttonPadding: 10,
buttonWidth: 70,
pickerTitle: Text("", style: AppThemeData.mediumTextStyle(fontSize: 14, color: isDark ? AppThemeData.greyDark900 : AppThemeData.grey900)),
backgroundColor: isDark ? AppThemeData.greyDark50 : AppThemeData.grey50,
pickerTextStyle: AppThemeData.mediumTextStyle(fontSize: 14, color: isDark ? AppThemeData.greyDark900 : AppThemeData.grey900),
pickerTitle: Text(
"",
style: AppThemeData.mediumTextStyle(
fontSize: 14,
color:
isDark
? AppThemeData.greyDark900
: AppThemeData.grey900,
),
),
backgroundColor:
isDark
? AppThemeData.greyDark50
: AppThemeData.grey50,
pickerTextStyle: AppThemeData.mediumTextStyle(
fontSize: 14,
color:
isDark
? AppThemeData.greyDark900
: AppThemeData.grey900,
),
closeIconColor: isDark ? Colors.white : Colors.black,
).show(context);
},
child: TextFieldWidget(title: "Booking Date & Slot".tr(), hintText: "Choose Date and Time".tr(), controller: controller.dateTimeController.value, enable: false),
child: TextFieldWidget(
title: "Booking Date & Slot".tr(),
hintText: "Choose Date and Time".tr(),
controller: controller.dateTimeController.value,
enable: false,
),
),
const SizedBox(height: 15),
controller.provider.value?.priceUnit == "Fixed"
@@ -241,7 +424,14 @@ class OnDemandBookingScreen extends StatelessWidget {
scrollDirection: Axis.horizontal,
itemBuilder: (context, index) {
final coupon = controller.couponList[index];
return GestureDetector(onTap: () => controller.applyCoupon(coupon), child: buildOfferItem(controller, index, isDark));
return GestureDetector(
onTap: () => controller.applyCoupon(coupon),
child: buildOfferItem(
controller,
index,
isDark,
),
);
},
),
)
@@ -249,7 +439,16 @@ class OnDemandBookingScreen extends StatelessWidget {
buildPromoCode(controller, isDark),
Padding(
padding: EdgeInsets.symmetric(vertical: 10),
child: Text("Price Detail".tr(), style: AppThemeData.semiBoldTextStyle(fontSize: 16, color: isDark ? AppThemeData.greyDark900 : AppThemeData.grey900)),
child: Text(
"Price Detail".tr(),
style: AppThemeData.semiBoldTextStyle(
fontSize: 16,
color:
isDark
? AppThemeData.greyDark900
: AppThemeData.grey900,
),
),
),
priceTotalRow(controller, isDark),
],
@@ -260,14 +459,23 @@ class OnDemandBookingScreen extends StatelessWidget {
),
bottomNavigationBar: Padding(
padding: const EdgeInsets.all(20.0),
child: RoundedButtonFill(title: "Confirm".tr(), color: AppThemeData.primary300, textColor: AppThemeData.grey50, onPress: () => controller.confirmBooking(context)),
child: RoundedButtonFill(
title: "Confirm".tr(),
color: AppThemeData.primary300,
textColor: AppThemeData.grey50,
onPress: () => controller.confirmBooking(context),
),
),
);
},
);
}
Widget buildOfferItem(OnDemandBookingController controller, int index, bool isDark) {
Widget buildOfferItem(
OnDemandBookingController controller,
int index,
bool isDark,
) {
return Obx(() {
final coupon = controller.couponList[index];
@@ -275,7 +483,11 @@ class OnDemandBookingScreen extends StatelessWidget {
margin: const EdgeInsets.fromLTRB(7, 10, 7, 10),
height: 85,
child: DottedBorder(
options: RoundedRectDottedBorderOptions(strokeWidth: 1, radius: const Radius.circular(10), color: AppThemeData.primary300),
options: RoundedRectDottedBorderOptions(
strokeWidth: 1,
radius: const Radius.circular(10),
color: AppThemeData.primary300,
),
child: Padding(
padding: const EdgeInsets.fromLTRB(12, 5, 12, 0),
child: Column(
@@ -284,13 +496,26 @@ class OnDemandBookingScreen extends StatelessWidget {
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Image(image: AssetImage('assets/images/offer_icon.png'), height: 25, width: 25),
const Image(
image: AssetImage('assets/images/offer_icon.png'),
height: 25,
width: 25,
),
const SizedBox(width: 10),
Container(
margin: const EdgeInsets.only(top: 3),
child: Text(
coupon.discountType == "Fix Price" ? "${Constant.amountShow(amount: coupon.discount.toString())} ${'OFF'.tr()}" : "${coupon.discount} ${'% Off'.tr()}",
style: TextStyle(fontWeight: FontWeight.bold, letterSpacing: 0.7, color: isDark ? AppThemeData.greyDark900 : AppThemeData.grey900),
coupon.discountType == "Fix Price"
? "${Constant.amountShow(amount: coupon.discount.toString())} ${'OFF'.tr()}"
: "${coupon.discount} ${'% Off'.tr()}",
style: TextStyle(
fontWeight: FontWeight.bold,
letterSpacing: 0.7,
color:
isDark
? AppThemeData.greyDark900
: AppThemeData.grey900,
),
),
),
],
@@ -299,11 +524,36 @@ class OnDemandBookingScreen extends StatelessWidget {
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(coupon.code ?? '', style: const TextStyle(fontSize: 16, fontWeight: FontWeight.normal, letterSpacing: 0.5, color: Colors.orange)),
Container(margin: const EdgeInsets.only(left: 15, right: 15, top: 3), width: 1, color: AppThemeData.grey50),
Text(
"valid till ".tr() + controller.getDate(coupon.expiresAt!.toDate().toString()),
style: TextStyle(letterSpacing: 0.5, color: isDark ? AppThemeData.greyDark900 : AppThemeData.grey900),
coupon.code ?? '',
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.normal,
letterSpacing: 0.5,
color: Colors.orange,
),
),
Container(
margin: const EdgeInsets.only(
left: 15,
right: 15,
top: 3,
),
width: 1,
color: AppThemeData.grey50,
),
Text(
"valid till ".tr() +
controller.getDate(
coupon.expiresAt!.toDate().toString(),
),
style: TextStyle(
letterSpacing: 0.5,
color:
isDark
? AppThemeData.greyDark900
: AppThemeData.grey900,
),
),
],
),
@@ -321,7 +571,9 @@ class OnDemandBookingScreen extends StatelessWidget {
margin: const EdgeInsets.only(top: 10, bottom: 13),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
border: Border.all(color: isDark ? AppThemeData.greyDark400 : AppThemeData.grey100),
border: Border.all(
color: isDark ? AppThemeData.greyDark400 : AppThemeData.grey100,
),
color: isDark ? AppThemeData.greyDark50 : AppThemeData.grey50,
),
child: Padding(
@@ -332,17 +584,37 @@ class OnDemandBookingScreen extends StatelessWidget {
Expanded(
child: Row(
children: [
Image.asset("assets/images/reedem.png", height: 50, width: 50),
Image.asset(
"assets/images/reedem.png",
height: 50,
width: 50,
),
const SizedBox(width: 10),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text("Promo Code".tr(), style: AppThemeData.mediumTextStyle(fontSize: 18, color: isDark ? AppThemeData.greyDark900 : AppThemeData.grey900), overflow: TextOverflow.ellipsis),
Text(
"Promo Code".tr(),
style: AppThemeData.mediumTextStyle(
fontSize: 18,
color:
isDark
? AppThemeData.greyDark900
: AppThemeData.grey900,
),
overflow: TextOverflow.ellipsis,
),
const SizedBox(height: 5),
Text(
"Apply promo code".tr(),
style: AppThemeData.mediumTextStyle(fontSize: 15, color: isDark ? AppThemeData.greyDark900 : AppThemeData.grey900),
style: AppThemeData.mediumTextStyle(
fontSize: 15,
color:
isDark
? AppThemeData.greyDark900
: AppThemeData.grey900,
),
overflow: TextOverflow.ellipsis,
),
],
@@ -353,7 +625,13 @@ class OnDemandBookingScreen extends StatelessWidget {
),
FloatingActionButton(
onPressed: () {
Get.bottomSheet(promoCodeSheet(controller, isDark), isScrollControlled: true, isDismissible: true, backgroundColor: Colors.transparent, enableDrag: true);
Get.bottomSheet(
promoCodeSheet(controller, isDark),
isScrollControlled: true,
isDismissible: true,
backgroundColor: Colors.transparent,
enableDrag: true,
);
},
mini: true,
backgroundColor: Colors.blueGrey.shade50,
@@ -371,7 +649,10 @@ class OnDemandBookingScreen extends StatelessWidget {
return Container(
padding: EdgeInsets.only(bottom: Get.height / 4.3, left: 25, right: 25),
height: Get.height * 0.88,
decoration: BoxDecoration(color: Colors.transparent, border: Border.all(style: BorderStyle.none)),
decoration: BoxDecoration(
color: Colors.transparent,
border: Border.all(style: BorderStyle.none),
),
child: Column(
children: [
InkWell(
@@ -379,14 +660,21 @@ class OnDemandBookingScreen extends StatelessWidget {
child: Container(
height: 45,
decoration: BoxDecoration(
border: Border.all(color: isDark ? AppThemeData.greyDark400 : AppThemeData.grey100, width: 0.3),
border: Border.all(
color:
isDark ? AppThemeData.greyDark400 : AppThemeData.grey100,
width: 0.3,
),
color: isDark ? AppThemeData.greyDark50 : AppThemeData.grey50,
shape: BoxShape.circle,
),
child: Center(
child: Icon(
Icons.close,
color: isDark ? AppThemeData.greyDark900 : AppThemeData.grey900, // ✅ visible color
color:
isDark
? AppThemeData.greyDark900
: AppThemeData.grey900, // ✅ visible color
size: 28,
),
),
@@ -395,40 +683,93 @@ class OnDemandBookingScreen extends StatelessWidget {
const SizedBox(height: 25),
Expanded(
child: Container(
decoration: BoxDecoration(borderRadius: BorderRadius.circular(10), color: isDark ? AppThemeData.greyDark50 : AppThemeData.grey50),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
color: isDark ? AppThemeData.greyDark50 : AppThemeData.grey50,
),
alignment: Alignment.center,
child: SingleChildScrollView(
child: Column(
children: [
Container(padding: const EdgeInsets.only(top: 30), child: const Image(image: AssetImage('assets/images/redeem_coupon.png'), width: 100)),
Container(
padding: const EdgeInsets.only(top: 20),
child: Text('Redeem Your Coupons'.tr(), style: AppThemeData.mediumTextStyle(color: isDark ? AppThemeData.greyDark900 : AppThemeData.grey900, fontSize: 16)),
),
Center(
child: Container(
padding: const EdgeInsets.only(top: 10, left: 22, right: 22),
child: Text("Voucher or Coupon code".tr(), style: AppThemeData.mediumTextStyle(color: isDark ? AppThemeData.greyDark900 : AppThemeData.grey900)),
padding: const EdgeInsets.only(top: 30),
child: const Image(
image: AssetImage('assets/images/redeem_coupon.png'),
width: 100,
),
),
Container(
padding: const EdgeInsets.only(left: 20, right: 20, top: 20),
padding: const EdgeInsets.only(top: 20),
child: Text(
'Redeem Your Coupons'.tr(),
style: AppThemeData.mediumTextStyle(
color:
isDark
? AppThemeData.greyDark900
: AppThemeData.grey900,
fontSize: 16,
),
),
),
Center(
child: Container(
padding: const EdgeInsets.only(
top: 10,
left: 22,
right: 22,
),
child: Text(
"Voucher or Coupon code".tr(),
style: AppThemeData.mediumTextStyle(
color:
isDark
? AppThemeData.greyDark900
: AppThemeData.grey900,
),
),
),
),
Container(
padding: const EdgeInsets.only(
left: 20,
right: 20,
top: 20,
),
child: DottedBorder(
options: RoundedRectDottedBorderOptions(strokeWidth: 1, radius: const Radius.circular(12), color: AppThemeData.primary300),
options: RoundedRectDottedBorderOptions(
strokeWidth: 1,
radius: const Radius.circular(12),
color: AppThemeData.primary300,
),
child: ClipRRect(
borderRadius: const BorderRadius.all(Radius.circular(12)),
borderRadius: const BorderRadius.all(
Radius.circular(12),
),
child: Container(
padding: const EdgeInsets.all(20),
color: isDark ? AppThemeData.greyDark50 : AppThemeData.grey50,
color:
isDark
? AppThemeData.greyDark50
: AppThemeData.grey50,
alignment: Alignment.center,
child: TextFormField(
textAlign: TextAlign.center,
style: AppThemeData.mediumTextStyle(color: isDark ? AppThemeData.greyDark900 : AppThemeData.grey900),
style: AppThemeData.mediumTextStyle(
color:
isDark
? AppThemeData.greyDark900
: AppThemeData.grey900,
),
controller: controller.couponTextController.value,
decoration: InputDecoration(
border: InputBorder.none,
hintText: "Write Coupon Code".tr(),
hintStyle: AppThemeData.mediumTextStyle(color: isDark ? AppThemeData.greyDark400 : AppThemeData.grey400),
hintStyle: AppThemeData.mediumTextStyle(
color:
isDark
? AppThemeData.greyDark400
: AppThemeData.grey400,
),
),
),
),
@@ -436,21 +777,34 @@ class OnDemandBookingScreen extends StatelessWidget {
),
),
Padding(
padding: const EdgeInsets.only(top: 30, bottom: 30, left: 15, right: 15),
padding: const EdgeInsets.only(
top: 30,
bottom: 30,
left: 15,
right: 15,
),
child: RoundedButtonFill(
title: "REDEEM NOW".tr(),
color: AppThemeData.primary300,
textColor: AppThemeData.grey50,
onPress: () {
final inputCode = controller.couponTextController.value.text.trim().toLowerCase();
final inputCode =
controller.couponTextController.value.text
.trim()
.toLowerCase();
final matchingCoupon = controller.couponList.firstWhereOrNull((c) => c.code?.toLowerCase() == inputCode);
final matchingCoupon = controller.couponList
.firstWhereOrNull(
(c) => c.code?.toLowerCase() == inputCode,
);
if (matchingCoupon != null) {
controller.applyCoupon(matchingCoupon);
Get.back();
} else {
ShowToastDialog.showToast("Applied coupon not valid.".tr());
ShowToastDialog.showToast(
"Applied coupon not valid.".tr(),
);
}
},
),
@@ -470,14 +824,22 @@ class OnDemandBookingScreen extends StatelessWidget {
return Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
border: Border.all(color: isDark ? AppThemeData.greyDark400 : AppThemeData.grey100),
border: Border.all(
color: isDark ? AppThemeData.greyDark400 : AppThemeData.grey100,
),
color: isDark ? AppThemeData.greyDark50 : AppThemeData.grey50,
),
child: Column(
children: [
const SizedBox(height: 5),
rowText("Price".tr(), Constant.amountShow(amount: controller.price.value.toString()), isDark),
controller.discountAmount.value != 0 ? const Divider() : const SizedBox(),
rowText(
"Price".tr(),
Constant.amountShow(amount: controller.price.value.toString()),
isDark,
),
controller.discountAmount.value != 0
? const Divider()
: const SizedBox(),
controller.discountAmount.value != 0
? Padding(
padding: const EdgeInsets.symmetric(horizontal: 10),
@@ -490,19 +852,39 @@ class OnDemandBookingScreen extends StatelessWidget {
children: [
Text(
"${"Discount".tr()} ${controller.discountType.value == 'Percentage' || controller.discountType.value == 'Percent' ? "(${controller.discountLabel.value}%)" : "(${Constant.amountShow(amount: controller.discountLabel.value)})"}",
style: TextStyle(color: isDark ? AppThemeData.greyDark900 : AppThemeData.grey900),
style: TextStyle(
color:
isDark
? AppThemeData.greyDark900
: AppThemeData.grey900,
),
),
Text(
controller.offerCode.value,
style: TextStyle(
color:
isDark
? AppThemeData.greyDark900
: AppThemeData.grey900,
),
),
Text(controller.offerCode.value, style: TextStyle(color: isDark ? AppThemeData.greyDark900 : AppThemeData.grey900)),
],
),
),
Text("(-${Constant.amountShow(amount: controller.discountAmount.value.toString())})", style: const TextStyle(color: Colors.red)),
Text(
"(-${Constant.amountShow(amount: controller.discountAmount.value.toString())})",
style: const TextStyle(color: Colors.red),
),
],
),
)
: const SizedBox(),
const Divider(),
rowText("SubTotal".tr(), Constant.amountShow(amount: controller.subTotal.value.toString()), isDark),
rowText(
"SubTotal".tr(),
Constant.amountShow(amount: controller.subTotal.value.toString()),
isDark,
),
const Divider(),
ListView.builder(
itemCount: Constant.taxList.length,
@@ -513,19 +895,39 @@ class OnDemandBookingScreen extends StatelessWidget {
return Column(
children: [
Padding(
padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 10),
padding: const EdgeInsets.symmetric(
vertical: 8,
horizontal: 10,
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Text(
"${taxModel.title} (${taxModel.type == "fix" ? Constant.amountShow(amount: taxModel.tax) : "${taxModel.tax}%"})",
style: AppThemeData.mediumTextStyle(color: isDark ? AppThemeData.greyDark900 : AppThemeData.grey900),
style: AppThemeData.mediumTextStyle(
color:
isDark
? AppThemeData.greyDark900
: AppThemeData.grey900,
),
),
),
Text(
Constant.amountShow(amount: Constant.getTaxValue(amount: controller.subTotal.value.toString(), taxModel: taxModel).toString()),
style: AppThemeData.mediumTextStyle(color: isDark ? AppThemeData.greyDark900 : AppThemeData.grey900),
Constant.amountShow(
amount:
Constant.getTaxValue(
amount:
controller.subTotal.value.toString(),
taxModel: taxModel,
).toString(),
),
style: AppThemeData.mediumTextStyle(
color:
isDark
? AppThemeData.greyDark900
: AppThemeData.grey900,
),
),
],
),
@@ -535,7 +937,13 @@ class OnDemandBookingScreen extends StatelessWidget {
);
},
),
rowText("Total Amount".tr(), Constant.amountShow(amount: controller.totalAmount.value.toString()), isDark),
rowText(
"Total Amount".tr(),
Constant.amountShow(
amount: controller.totalAmount.value.toString(),
),
isDark,
),
const SizedBox(height: 5),
],
),
@@ -549,8 +957,18 @@ class OnDemandBookingScreen extends StatelessWidget {
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(title.tr(), style: AppThemeData.mediumTextStyle(color: isDark ? AppThemeData.greyDark900 : AppThemeData.grey900)),
Text(value.tr(), style: AppThemeData.mediumTextStyle(color: isDark ? AppThemeData.greyDark900 : AppThemeData.grey900)),
Text(
title.tr(),
style: AppThemeData.mediumTextStyle(
color: isDark ? AppThemeData.greyDark900 : AppThemeData.grey900,
),
),
Text(
value.tr(),
style: AppThemeData.mediumTextStyle(
color: isDark ? AppThemeData.greyDark900 : AppThemeData.grey900,
),
),
],
),
);

View File

@@ -2,7 +2,7 @@ import 'package:cached_network_image/cached_network_image.dart';
import 'package:customer/screen_ui/on_demand_service/view_category_service_screen.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:get/get.dart' hide Trans;
import '../../constant/constant.dart';
import '../../controllers/on_demand_category_controller.dart';
import '../../controllers/theme_controller.dart';
@@ -33,8 +33,20 @@ class OnDemandCategoryScreen extends StatelessWidget {
child: Container(
height: 42,
width: 42,
decoration: BoxDecoration(shape: BoxShape.circle, color: AppThemeData.grey50),
child: Center(child: Padding(padding: const EdgeInsets.only(left: 5), child: Icon(Icons.arrow_back_ios, color: AppThemeData.grey900, size: 20))),
decoration: BoxDecoration(
shape: BoxShape.circle,
color: AppThemeData.grey50,
),
child: Center(
child: Padding(
padding: const EdgeInsets.only(left: 5),
child: Icon(
Icons.arrow_back_ios,
color: AppThemeData.grey900,
size: 20,
),
),
),
),
),
const SizedBox(width: 10),
@@ -42,12 +54,22 @@ class OnDemandCategoryScreen extends StatelessWidget {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text("Explore services".tr(), style: AppThemeData.boldTextStyle(fontSize: 18, color: AppThemeData.grey900)),
Text(
"Explore services tailored for you—quick, easy, and personalized.".tr(),
"Explore services".tr(),
style: AppThemeData.boldTextStyle(
fontSize: 18,
color: AppThemeData.grey900,
),
),
Text(
"Explore services tailored for you—quick, easy, and personalized."
.tr(),
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: AppThemeData.boldTextStyle(fontSize: 14, color: AppThemeData.grey900),
style: AppThemeData.boldTextStyle(
fontSize: 14,
color: AppThemeData.grey900,
),
),
],
),
@@ -60,7 +82,10 @@ class OnDemandCategoryScreen extends StatelessWidget {
controller.isLoading.value
? Constant.loader()
: Padding(
padding: const EdgeInsets.symmetric(vertical: 20, horizontal: 15),
padding: const EdgeInsets.symmetric(
vertical: 20,
horizontal: 15,
),
child: SingleChildScrollView(
child: Column(
children: [
@@ -71,9 +96,17 @@ class OnDemandCategoryScreen extends StatelessWidget {
itemCount: controller.categories.length,
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3),
gridDelegate:
const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
),
itemBuilder: (context, index) {
return categoriesCell(context, controller.categories[index], index, isDark);
return categoriesCell(
context,
controller.categories[index],
index,
isDark,
);
},
),
],
@@ -85,16 +118,42 @@ class OnDemandCategoryScreen extends StatelessWidget {
);
}
Widget categoriesCell(BuildContext context, CategoryModel category, int index, bool isDark) {
Widget categoriesCell(
BuildContext context,
CategoryModel category,
int index,
bool isDark,
) {
return GestureDetector(
onTap: () {
Get.to(() => ViewCategoryServiceListScreen(), arguments: {'categoryId': category.id, 'categoryTitle': category.title});
Get.to(
() => ViewCategoryServiceListScreen(),
arguments: {
'categoryId': category.id,
'categoryTitle': category.title,
},
);
},
child: Column(
children: [
ClipRRect(borderRadius: BorderRadius.circular(12), child: CachedNetworkImage(imageUrl: category.image ?? "", height: 60, width: 60, fit: BoxFit.cover)),
ClipRRect(
borderRadius: BorderRadius.circular(12),
child: CachedNetworkImage(
imageUrl: category.image ?? "",
height: 60,
width: 60,
fit: BoxFit.cover,
),
),
const SizedBox(height: 5),
Text(category.title ?? "", style: AppThemeData.semiBoldTextStyle(fontSize: 12, color: isDark ? AppThemeData.greyDark900 : AppThemeData.grey900), textAlign: TextAlign.center),
Text(
category.title ?? "",
style: AppThemeData.semiBoldTextStyle(
fontSize: 12,
color: isDark ? AppThemeData.greyDark900 : AppThemeData.grey900,
),
textAlign: TextAlign.center,
),
],
),
);

View File

@@ -5,8 +5,7 @@ import 'package:customer/themes/app_them_data.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:get/get.dart';
import 'package:get/get.dart' hide Trans;
import '../../controllers/on_demand_dashboard_controller.dart';
class OnDemandDashboardScreen extends StatelessWidget {
@@ -27,12 +26,19 @@ class OnDemandDashboardScreen extends StatelessWidget {
showUnselectedLabels: true,
showSelectedLabels: true,
selectedFontSize: 12,
selectedLabelStyle: const TextStyle(fontFamily: AppThemeData.bold),
unselectedLabelStyle: const TextStyle(fontFamily: AppThemeData.bold),
selectedLabelStyle: const TextStyle(
fontFamily: AppThemeData.bold,
),
unselectedLabelStyle: const TextStyle(
fontFamily: AppThemeData.bold,
),
currentIndex: controller.selectedIndex.value,
backgroundColor: isDark ? AppThemeData.grey900 : AppThemeData.grey50,
selectedItemColor: isDark ? AppThemeData.primary300 : AppThemeData.primary300,
unselectedItemColor: isDark ? AppThemeData.grey300 : AppThemeData.grey600,
backgroundColor:
isDark ? AppThemeData.grey900 : AppThemeData.grey50,
selectedItemColor:
isDark ? AppThemeData.primary300 : AppThemeData.primary300,
unselectedItemColor:
isDark ? AppThemeData.grey300 : AppThemeData.grey600,
onTap: (int index) {
if (index == 0) {
Get.put(CabDashboardController());
@@ -42,18 +48,72 @@ class OnDemandDashboardScreen extends StatelessWidget {
items:
Constant.walletSetting == false
? [
navigationBarItem(isDark, index: 0, assetIcon: "assets/icons/ic_home_cab.svg", label: 'Home'.tr(), controller: controller),
navigationBarItem(isDark, index: 1, assetIcon: "assets/icons/ic_fav.svg", label: 'Favourites'.tr(), controller: controller),
navigationBarItem(isDark, index: 2, assetIcon: "assets/icons/ic_booking_cab.svg", label: 'My Bookings'.tr(), controller: controller),
navigationBarItem(isDark, index: 3, assetIcon: "assets/icons/ic_profile.svg", label: 'Profile'.tr(), controller: controller),
navigationBarItem(
isDark,
index: 0,
assetIcon: "assets/icons/ic_home_cab.svg",
label: 'Home'.tr(),
controller: controller,
),
navigationBarItem(
isDark,
index: 1,
assetIcon: "assets/icons/ic_fav.svg",
label: 'Favourites'.tr(),
controller: controller,
),
navigationBarItem(
isDark,
index: 2,
assetIcon: "assets/icons/ic_booking_cab.svg",
label: 'My Bookings'.tr(),
controller: controller,
),
navigationBarItem(
isDark,
index: 3,
assetIcon: "assets/icons/ic_profile.svg",
label: 'Profile'.tr(),
controller: controller,
),
]
: [
navigationBarItem(isDark, index: 0, assetIcon: "assets/icons/ic_home_cab.svg", label: 'Home'.tr(), controller: controller),
navigationBarItem(isDark, index: 1, assetIcon: "assets/icons/ic_fav.svg", label: 'Favourites'.tr(), controller: controller),
navigationBarItem(
isDark,
index: 0,
assetIcon: "assets/icons/ic_home_cab.svg",
label: 'Home'.tr(),
controller: controller,
),
navigationBarItem(
isDark,
index: 1,
assetIcon: "assets/icons/ic_fav.svg",
label: 'Favourites'.tr(),
controller: controller,
),
navigationBarItem(isDark, index: 2, assetIcon: "assets/icons/ic_booking_cab.svg", label: 'My Bookings'.tr(), controller: controller),
navigationBarItem(isDark, index: 3, assetIcon: "assets/icons/ic_wallet_cab.svg", label: 'Wallet'.tr(), controller: controller),
navigationBarItem(isDark, index: 4, assetIcon: "assets/icons/ic_profile.svg", label: 'Profile'.tr(), controller: controller),
navigationBarItem(
isDark,
index: 2,
assetIcon: "assets/icons/ic_booking_cab.svg",
label: 'My Bookings'.tr(),
controller: controller,
),
navigationBarItem(
isDark,
index: 3,
assetIcon: "assets/icons/ic_wallet_cab.svg",
label: 'Wallet'.tr(),
controller: controller,
),
navigationBarItem(
isDark,
index: 4,
assetIcon: "assets/icons/ic_profile.svg",
label: 'Profile'.tr(),
controller: controller,
),
],
),
);
@@ -62,7 +122,13 @@ class OnDemandDashboardScreen extends StatelessWidget {
});
}
BottomNavigationBarItem navigationBarItem(isDark, {required int index, required String label, required String assetIcon, required OnDemandDashboardController controller}) {
BottomNavigationBarItem navigationBarItem(
isDark, {
required int index,
required String label,
required String assetIcon,
required OnDemandDashboardController controller,
}) {
return BottomNavigationBarItem(
icon: Padding(
padding: const EdgeInsets.symmetric(vertical: 5),

View File

@@ -4,7 +4,7 @@ import 'package:customer/screen_ui/on_demand_service/provider_screen.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_rating_bar/flutter_rating_bar.dart';
import 'package:get/get.dart';
import 'package:get/get.dart' hide Trans;
import 'package:intl/intl.dart';
import '../../controllers/theme_controller.dart';
import '../../models/provider_serivce_model.dart';
@@ -25,7 +25,13 @@ class OnDemandDetailsScreen extends StatelessWidget {
init: OnDemandDetailsController(),
builder: (controller) {
return Scaffold(
body: buildSliverScrollView(context, controller, controller.provider, controller.userModel, isDark),
body: buildSliverScrollView(
context,
controller,
controller.provider,
controller.userModel,
isDark,
),
bottomNavigationBar:
controller.isOpen.value == false
? SizedBox()
@@ -43,9 +49,20 @@ class OnDemandDetailsScreen extends StatelessWidget {
if (Constant.userModel == null) {
Get.offAll(const LoginScreen());
} else {
print("providerModel ::::::::${controller.provider.title ?? 'No provider'}");
print("categoryTitle ::::::: ${controller.categoryTitle.value}");
Get.to(() => OnDemandBookingScreen(), arguments: {'providerModel': controller.provider, 'categoryTitle': controller.categoryTitle.value});
print(
"providerModel ::::::::${controller.provider.title ?? 'No provider'}",
);
print(
"categoryTitle ::::::: ${controller.categoryTitle.value}",
);
Get.to(
() => OnDemandBookingScreen(),
arguments: {
'providerModel': controller.provider,
'categoryTitle':
controller.categoryTitle.value,
},
);
}
},
),
@@ -57,7 +74,13 @@ class OnDemandDetailsScreen extends StatelessWidget {
);
}
SingleChildScrollView buildSliverScrollView(BuildContext context, OnDemandDetailsController controller, ProviderServiceModel provider, user, isDark) {
SingleChildScrollView buildSliverScrollView(
BuildContext context,
OnDemandDetailsController controller,
ProviderServiceModel provider,
user,
isDark,
) {
final width = MediaQuery.of(context).size.width;
final height = MediaQuery.of(context).size.height;
@@ -68,21 +91,54 @@ class OnDemandDetailsScreen extends StatelessWidget {
Stack(
children: [
CachedNetworkImage(
imageUrl: provider.photos.isNotEmpty ? provider.photos.first : "",
placeholder: (context, url) => Center(child: CircularProgressIndicator(valueColor: AlwaysStoppedAnimation(AppThemeData.primary300))),
errorWidget: (context, url, error) => Image.network(Constant.placeHolderImage, fit: BoxFit.fitWidth),
imageUrl:
provider.photos.isNotEmpty ? provider.photos.first : "",
placeholder:
(context, url) => Center(
child: CircularProgressIndicator(
valueColor: AlwaysStoppedAnimation(
AppThemeData.primary300,
),
),
),
errorWidget:
(context, url, error) => Image.network(
Constant.placeHolderImage,
fit: BoxFit.fitWidth,
),
fit: BoxFit.fitWidth,
width: width,
height: height * 0.45,
),
Positioned(top: height * 0.05, left: width * 0.03, child: _circleButton(context, icon: Icons.arrow_back, onTap: () => Get.back())),
Positioned(
top: height * 0.05,
left: width * 0.03,
child: _circleButton(
context,
icon: Icons.arrow_back,
onTap: () => Get.back(),
),
),
Positioned(
top: height * 0.05,
right: width * 0.03,
child: Container(
decoration: BoxDecoration(borderRadius: BorderRadius.circular(40), color: controller.isOpen.value ? Colors.green : Colors.red),
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 10),
child: Text(controller.isOpen.value ? "Open".tr() : "Close".tr(), style: const TextStyle(fontWeight: FontWeight.bold, color: Colors.white, fontSize: 14)),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(40),
color: controller.isOpen.value ? Colors.green : Colors.red,
),
padding: const EdgeInsets.symmetric(
horizontal: 16,
vertical: 10,
),
child: Text(
controller.isOpen.value ? "Open".tr() : "Close".tr(),
style: const TextStyle(
fontWeight: FontWeight.bold,
color: Colors.white,
fontSize: 14,
),
),
),
),
],
@@ -105,27 +161,66 @@ class OnDemandDetailsScreen extends StatelessWidget {
Expanded(
child: Text(
provider.title.toString(),
style: TextStyle(fontSize: 20, fontFamily: AppThemeData.regular, fontWeight: FontWeight.bold, color: isDark ? Colors.white : Colors.black),
style: TextStyle(
fontSize: 20,
fontFamily: AppThemeData.regular,
fontWeight: FontWeight.bold,
color: isDark ? Colors.white : Colors.black,
),
),
),
Row(
children: [
provider.disPrice == "" || provider.disPrice == "0"
? Text(
provider.priceUnit == 'Fixed' ? Constant.amountShow(amount: provider.price ?? '0') : '${Constant.amountShow(amount: provider.price ?? '0')}/${'hr'.tr()}',
style: TextStyle(fontSize: 18, fontFamily: AppThemeData.regular, fontWeight: FontWeight.bold, color: isDark ? Colors.white : AppThemeData.primary300),
provider.priceUnit == 'Fixed'
? Constant.amountShow(
amount: provider.price ?? '0',
)
: '${Constant.amountShow(amount: provider.price ?? '0')}/${'hr'.tr()}',
style: TextStyle(
fontSize: 18,
fontFamily: AppThemeData.regular,
fontWeight: FontWeight.bold,
color:
isDark
? Colors.white
: AppThemeData.primary300,
),
)
: Row(
children: [
Text(
provider.priceUnit == 'Fixed' ? Constant.amountShow(amount: provider.disPrice ?? '0') : '${Constant.amountShow(amount: provider.disPrice ?? '0')}/${'hr'.tr()}',
style: TextStyle(fontSize: 18, fontFamily: AppThemeData.regular, fontWeight: FontWeight.bold, color: isDark ? Colors.white : AppThemeData.primary300),
provider.priceUnit == 'Fixed'
? Constant.amountShow(
amount: provider.disPrice ?? '0',
)
: '${Constant.amountShow(amount: provider.disPrice ?? '0')}/${'hr'.tr()}',
style: TextStyle(
fontSize: 18,
fontFamily: AppThemeData.regular,
fontWeight: FontWeight.bold,
color:
isDark
? Colors.white
: AppThemeData.primary300,
),
),
Padding(
padding: const EdgeInsets.only(left: 8.0),
child: Text(
provider.priceUnit == 'Fixed' ? Constant.amountShow(amount: provider.price ?? '0') : '${Constant.amountShow(amount: provider.price ?? '0')}/${'hr'.tr()}',
style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 18, color: Colors.grey, decoration: TextDecoration.lineThrough),
provider.priceUnit == 'Fixed'
? Constant.amountShow(
amount: provider.price ?? '0',
)
: '${Constant.amountShow(amount: provider.price ?? '0')}/${'hr'.tr()}',
style: const TextStyle(
fontWeight: FontWeight.bold,
fontSize: 18,
color: Colors.grey,
decoration:
TextDecoration.lineThrough,
),
),
),
],
@@ -139,23 +234,51 @@ class OnDemandDetailsScreen extends StatelessWidget {
Expanded(
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 5),
child: Text(categoryTitle, style: TextStyle(fontSize: 14, fontFamily: AppThemeData.regular, fontWeight: FontWeight.w400, color: isDark ? Colors.white : Colors.black)),
child: Text(
categoryTitle,
style: TextStyle(
fontSize: 14,
fontFamily: AppThemeData.regular,
fontWeight: FontWeight.w400,
color: isDark ? Colors.white : Colors.black,
),
),
),
),
Padding(
padding: const EdgeInsets.only(left: 8.0),
child: Row(
children: [
const Icon(Icons.star, size: 16, color: AppThemeData.warning400),
const Icon(
Icons.star,
size: 16,
color: AppThemeData.warning400,
),
const SizedBox(width: 3),
Text(
provider.reviewsCount != 0 ? ((provider.reviewsSum ?? 0.0) / (provider.reviewsCount ?? 0.0)).toStringAsFixed(1) : '0',
style: const TextStyle(letterSpacing: 0.5, fontSize: 16, fontFamily: AppThemeData.regular, fontWeight: FontWeight.w500, color: AppThemeData.warning400),
provider.reviewsCount != 0
? ((provider.reviewsSum ?? 0.0) /
(provider.reviewsCount ?? 0.0))
.toStringAsFixed(1)
: '0',
style: const TextStyle(
letterSpacing: 0.5,
fontSize: 16,
fontFamily: AppThemeData.regular,
fontWeight: FontWeight.w500,
color: AppThemeData.warning400,
),
),
const SizedBox(width: 10),
Text(
"(${provider.reviewsCount} ${'Reviews'.tr()})",
style: TextStyle(letterSpacing: 0.5, fontSize: 16, fontFamily: AppThemeData.regular, fontWeight: FontWeight.w500, color: isDark ? Colors.white : Colors.black),
style: TextStyle(
letterSpacing: 0.5,
fontSize: 16,
fontFamily: AppThemeData.regular,
fontWeight: FontWeight.w500,
color: isDark ? Colors.white : Colors.black,
),
),
],
),
@@ -168,18 +291,40 @@ class OnDemandDetailsScreen extends StatelessWidget {
children: [
subCategoryTitle.isNotEmpty
? Container(
decoration: BoxDecoration(borderRadius: BorderRadius.circular(10), color: AppThemeData.primary300.withOpacity(0.20)),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
color: AppThemeData.primary300.withOpacity(
0.20,
),
),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 10),
child: Text(subCategoryTitle, style: TextStyle(fontSize: 14, fontWeight: FontWeight.bold, fontFamily: AppThemeData.regular, color: AppThemeData.primary300)),
padding: const EdgeInsets.symmetric(
horizontal: 16,
vertical: 10,
),
child: Text(
subCategoryTitle,
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.bold,
fontFamily: AppThemeData.regular,
color: AppThemeData.primary300,
),
),
),
)
: Container(),
const SizedBox(width: 10),
Container(
decoration: BoxDecoration(borderRadius: BorderRadius.circular(10), color: Colors.green.withOpacity(0.20)),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
color: Colors.green.withOpacity(0.20),
),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 10),
padding: const EdgeInsets.symmetric(
horizontal: 16,
vertical: 10,
),
child: InkWell(
onTap: () {
showModalBottomSheet(
@@ -188,10 +333,22 @@ class OnDemandDetailsScreen extends StatelessWidget {
context: context,
backgroundColor: Colors.transparent,
enableDrag: true,
builder: (context) => showTiming(context, controller, isDark),
builder:
(context) => showTiming(
context,
controller,
isDark,
),
);
},
child: Text("View Timing".tr(), style: const TextStyle(fontWeight: FontWeight.bold, color: Colors.green, letterSpacing: 0.5)),
child: Text(
"View Timing".tr(),
style: const TextStyle(
fontWeight: FontWeight.bold,
color: Colors.green,
letterSpacing: 0.5,
),
),
),
),
),
@@ -201,14 +358,22 @@ class OnDemandDetailsScreen extends StatelessWidget {
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Icon(Icons.location_on_outlined, color: isDark ? Colors.white : Colors.black, size: 20),
Icon(
Icons.location_on_outlined,
color: isDark ? Colors.white : Colors.black,
size: 20,
),
const SizedBox(width: 5),
Expanded(
child: Text(
provider.address.toString(),
maxLines: 2,
overflow: TextOverflow.ellipsis,
style: TextStyle(fontFamily: AppThemeData.regular, fontWeight: FontWeight.w400, color: isDark ? Colors.white : Colors.black),
style: TextStyle(
fontFamily: AppThemeData.regular,
fontWeight: FontWeight.w400,
color: isDark ? Colors.white : Colors.black,
),
),
),
],
@@ -219,7 +384,11 @@ class OnDemandDetailsScreen extends StatelessWidget {
_tabBar(controller),
Obx(() {
if (controller.tabString.value == "About") {
return aboutTabViewWidget(controller, controller.provider, isDark);
return aboutTabViewWidget(
controller,
controller.provider,
isDark,
);
} else if (controller.tabString.value == "Gallery") {
return galleryTabViewWidget(controller);
} else {
@@ -237,14 +406,35 @@ class OnDemandDetailsScreen extends StatelessWidget {
);
}
Widget _circleButton(BuildContext context, {required IconData icon, required VoidCallback onTap}) {
Widget _circleButton(
BuildContext context, {
required IconData icon,
required VoidCallback onTap,
}) {
return ClipOval(
child: Container(color: Colors.black.withOpacity(0.7), child: InkWell(onTap: onTap, child: Padding(padding: const EdgeInsets.all(8.0), child: Icon(icon, size: 30, color: Colors.white)))),
child: Container(
color: Colors.black.withOpacity(0.7),
child: InkWell(
onTap: onTap,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Icon(icon, size: 30, color: Colors.white),
),
),
),
);
}
Widget _tabBar(OnDemandDetailsController controller) {
return Obx(() => Row(children: [_tabItem("About", controller), _tabItem("Gallery", controller), _tabItem("Review", controller)]));
return Obx(
() => Row(
children: [
_tabItem("About", controller),
_tabItem("Gallery", controller),
_tabItem("Review", controller),
],
),
);
}
Widget _tabItem(String title, OnDemandDetailsController controller) {
@@ -253,33 +443,67 @@ class OnDemandDetailsScreen extends StatelessWidget {
child: Container(
margin: const EdgeInsets.only(right: 10),
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 10),
decoration: BoxDecoration(color: controller.tabString.value == title ? AppThemeData.primary300 : Colors.grey.shade200, borderRadius: BorderRadius.circular(10)),
child: Text(title.tr(), style: TextStyle(fontWeight: FontWeight.bold, color: controller.tabString.value == title ? Colors.white : Colors.black)),
decoration: BoxDecoration(
color:
controller.tabString.value == title
? AppThemeData.primary300
: Colors.grey.shade200,
borderRadius: BorderRadius.circular(10),
),
child: Text(
title.tr(),
style: TextStyle(
fontWeight: FontWeight.bold,
color:
controller.tabString.value == title
? Colors.white
: Colors.black,
),
),
),
);
}
Widget aboutTabViewWidget(OnDemandDetailsController controller, ProviderServiceModel providerModel, bool isDark) {
Widget aboutTabViewWidget(
OnDemandDetailsController controller,
ProviderServiceModel providerModel,
bool isDark,
) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 10),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text((providerModel.description ?? '').tr(), style: TextStyle(color: isDark ? Colors.white : Colors.black, fontSize: 14, fontFamily: AppThemeData.regular, fontWeight: FontWeight.w500)),
Text(
(providerModel.description ?? '').tr(),
style: TextStyle(
color: isDark ? Colors.white : Colors.black,
fontSize: 14,
fontFamily: AppThemeData.regular,
fontWeight: FontWeight.w500,
),
),
const SizedBox(height: 10),
Obx(() {
final user = controller.userModel.value;
if (user == null) return const SizedBox();
return InkWell(
onTap: () {
Get.to(() => ProviderScreen(), arguments: {'providerId': user.id});
Get.to(
() => ProviderScreen(),
arguments: {'providerId': user.id},
);
},
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 2),
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
border: Border.all(color: isDark ? AppThemeData.grey500 : Colors.grey.shade100, width: 1),
border: Border.all(
color:
isDark ? AppThemeData.grey500 : Colors.grey.shade100,
width: 1,
),
color: isDark ? AppThemeData.grey500 : Colors.white,
),
child: Padding(
@@ -289,30 +513,86 @@ class OnDemandDetailsScreen extends StatelessWidget {
Expanded(
child: Row(
children: [
CircleAvatar(radius: 30, backgroundImage: NetworkImage(user.profilePictureURL?.isNotEmpty == true ? user.profilePictureURL! : Constant.placeHolderImage)),
CircleAvatar(
radius: 30,
backgroundImage: NetworkImage(
user.profilePictureURL?.isNotEmpty == true
? user.profilePictureURL!
: Constant.placeHolderImage,
),
),
const SizedBox(width: 10),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(user.fullName(), style: TextStyle(color: isDark ? Colors.white : Colors.black, fontFamily: AppThemeData.regular, fontSize: 14, fontWeight: FontWeight.bold)),
Text(
user.fullName(),
style: TextStyle(
color:
isDark
? Colors.white
: Colors.black,
fontFamily: AppThemeData.regular,
fontSize: 14,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 5),
Text(user.email ?? '', style: TextStyle(color: isDark ? Colors.white : Colors.black, fontFamily: AppThemeData.regular, fontSize: 14)),
Text(
user.email ?? '',
style: TextStyle(
color:
isDark
? Colors.white
: Colors.black,
fontFamily: AppThemeData.regular,
fontSize: 14,
),
),
const SizedBox(height: 10),
// Rating Box
Container(
decoration: BoxDecoration(color: AppThemeData.warning400, borderRadius: BorderRadius.circular(16)),
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 5),
decoration: BoxDecoration(
color: AppThemeData.warning400,
borderRadius: BorderRadius.circular(16),
),
padding: const EdgeInsets.symmetric(
horizontal: 10,
vertical: 5,
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
const Icon(Icons.star, size: 16, color: Colors.white),
const Icon(
Icons.star,
size: 16,
color: Colors.white,
),
const SizedBox(width: 3),
Text(
double.parse(user.reviewsCount.toString()) != 0
? (double.parse(user.reviewsSum.toString()) / double.parse(user.reviewsCount.toString())).toStringAsFixed(1)
double.parse(
user.reviewsCount
.toString(),
) !=
0
? (double.parse(
user.reviewsSum
.toString(),
) /
double.parse(
user.reviewsCount
.toString(),
))
.toStringAsFixed(1)
: '0',
style: const TextStyle(letterSpacing: 0.5, fontSize: 12, fontFamily: AppThemeData.regular, fontWeight: FontWeight.w500, color: Colors.white),
style: const TextStyle(
letterSpacing: 0.5,
fontSize: 12,
fontFamily: AppThemeData.regular,
fontWeight: FontWeight.w500,
color: Colors.white,
),
),
],
),
@@ -348,7 +628,12 @@ class OnDemandDetailsScreen extends StatelessWidget {
shrinkWrap: true,
padding: EdgeInsets.zero,
physics: const NeverScrollableScrollPhysics(),
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2, mainAxisSpacing: 0, crossAxisSpacing: 8, mainAxisExtent: 180),
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
mainAxisSpacing: 0,
crossAxisSpacing: 8,
mainAxisExtent: 180,
),
itemBuilder: (context, index) {
final imageUrl = photos[index];
return Padding(
@@ -359,9 +644,29 @@ class OnDemandDetailsScreen extends StatelessWidget {
imageUrl: imageUrl,
height: 60,
width: 60,
imageBuilder: (context, imageProvider) => Container(decoration: BoxDecoration(borderRadius: BorderRadius.circular(10), image: DecorationImage(image: imageProvider, fit: BoxFit.cover))),
placeholder: (context, url) => Center(child: CircularProgressIndicator.adaptive(valueColor: AlwaysStoppedAnimation(AppThemeData.primary300))),
errorWidget: (context, url, error) => Image.network(Constant.placeHolderImage, fit: BoxFit.cover),
imageBuilder:
(context, imageProvider) => Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
image: DecorationImage(
image: imageProvider,
fit: BoxFit.cover,
),
),
),
placeholder:
(context, url) => Center(
child: CircularProgressIndicator.adaptive(
valueColor: AlwaysStoppedAnimation(
AppThemeData.primary300,
),
),
),
errorWidget:
(context, url, error) => Image.network(
Constant.placeHolderImage,
fit: BoxFit.cover,
),
fit: BoxFit.cover,
),
),
@@ -370,11 +675,24 @@ class OnDemandDetailsScreen extends StatelessWidget {
);
}
Widget reviewTabViewWidget(OnDemandDetailsController controller, bool isDark) {
Widget reviewTabViewWidget(
OnDemandDetailsController controller,
bool isDark,
) {
final reviews = controller.ratingService;
if (reviews.isEmpty) {
return SizedBox(height: 200, child: Center(child: Text("No review Found".tr(), style: AppThemeData.mediumTextStyle(color: isDark ? AppThemeData.greyDark900 : AppThemeData.grey900))));
return SizedBox(
height: 200,
child: Center(
child: Text(
"No review Found".tr(),
style: AppThemeData.mediumTextStyle(
color: isDark ? AppThemeData.greyDark900 : AppThemeData.grey900,
),
),
),
);
}
return ListView.builder(
@@ -390,8 +708,17 @@ class OnDemandDetailsScreen extends StatelessWidget {
clipBehavior: Clip.antiAlias,
decoration: ShapeDecoration(
color: isDark ? AppThemeData.grey700 : AppThemeData.grey50,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
shadows: const [BoxShadow(color: Color(0x0A000000), blurRadius: 32, offset: Offset(0, 0), spreadRadius: 0)],
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
shadows: const [
BoxShadow(
color: Color(0x0A000000),
blurRadius: 32,
offset: Offset(0, 0),
spreadRadius: 0,
),
],
),
child: Padding(
padding: const EdgeInsets.all(8.0),
@@ -401,26 +728,58 @@ class OnDemandDetailsScreen extends StatelessWidget {
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(review.uname ?? '', style: TextStyle(fontSize: 16, letterSpacing: 1, fontWeight: FontWeight.w600, color: isDark ? AppThemeData.greyDark900 : AppThemeData.grey900)),
Text(
review.createdAt != null ? DateFormat('dd MMM').format(review.createdAt!.toDate()) : '',
style: TextStyle(fontSize: 12, color: isDark ? AppThemeData.greyDark900 : AppThemeData.grey900),
review.uname ?? '',
style: TextStyle(
fontSize: 16,
letterSpacing: 1,
fontWeight: FontWeight.w600,
color:
isDark
? AppThemeData.greyDark900
: AppThemeData.grey900,
),
),
Text(
review.createdAt != null
? DateFormat(
'dd MMM',
).format(review.createdAt!.toDate())
: '',
style: TextStyle(
fontSize: 12,
color:
isDark
? AppThemeData.greyDark900
: AppThemeData.grey900,
),
),
],
),
const SizedBox(height: 4),
RatingBar.builder(
initialRating: double.tryParse(review.rating.toString()) ?? 0,
initialRating:
double.tryParse(review.rating.toString()) ?? 0,
direction: Axis.horizontal,
itemSize: 20,
ignoreGestures: true,
itemPadding: const EdgeInsets.symmetric(horizontal: 4.0),
itemBuilder: (context, _) => Icon(Icons.star, color: AppThemeData.primary300),
itemBuilder:
(context, _) =>
Icon(Icons.star, color: AppThemeData.primary300),
onRatingUpdate: (rate) {},
),
const Divider(),
const SizedBox(height: 5),
Text(review.comment ?? '', style: TextStyle(color: isDark ? AppThemeData.greyDark900 : AppThemeData.grey900)),
Text(
review.comment ?? '',
style: TextStyle(
color:
isDark
? AppThemeData.greyDark900
: AppThemeData.grey900,
),
),
],
),
),
@@ -430,31 +789,71 @@ class OnDemandDetailsScreen extends StatelessWidget {
);
}
Widget showTiming(BuildContext context, OnDemandDetailsController controller, bool isDark) {
Widget showTiming(
BuildContext context,
OnDemandDetailsController controller,
bool isDark,
) {
final provider = controller.provider;
return Container(
decoration: BoxDecoration(color: isDark ? AppThemeData.grey300 : Colors.white, borderRadius: const BorderRadius.only(topLeft: Radius.circular(20), topRight: Radius.circular(20))),
decoration: BoxDecoration(
color: isDark ? AppThemeData.grey300 : Colors.white,
borderRadius: const BorderRadius.only(
topLeft: Radius.circular(20),
topRight: Radius.circular(20),
),
),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Padding(
padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 16),
child: Text("Service Timing".tr(), style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold, fontFamily: AppThemeData.regular, color: AppThemeData.primary300)),
child: Text(
"Service Timing".tr(),
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
fontFamily: AppThemeData.regular,
color: AppThemeData.primary300,
),
),
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 16),
child: Row(
children: [
Expanded(child: _timeCard(context, "Start Time : ".tr(), provider.startTime.toString(), isDark)),
Expanded(
child: _timeCard(
context,
"Start Time : ".tr(),
provider.startTime.toString(),
isDark,
),
),
const SizedBox(width: 10),
Expanded(child: _timeCard(context, "End Time : ".tr(), provider.endTime.toString(), isDark)),
Expanded(
child: _timeCard(
context,
"End Time : ".tr(),
provider.endTime.toString(),
isDark,
),
),
],
),
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 16),
child: Text("Service Days".tr(), style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold, fontFamily: AppThemeData.regular, color: AppThemeData.primary300)),
child: Text(
"Service Days".tr(),
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
fontFamily: AppThemeData.regular,
color: AppThemeData.primary300,
),
),
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
@@ -466,10 +865,30 @@ class OnDemandDetailsScreen extends StatelessWidget {
.map(
(day) => Card(
elevation: 2,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(6), side: BorderSide(color: isDark ? const Color(0XFF3c3a2e) : const Color(0XFFC3C5D1), width: 1)),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(6),
side: BorderSide(
color:
isDark
? const Color(0XFF3c3a2e)
: const Color(0XFFC3C5D1),
width: 1,
),
),
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 7, horizontal: 20),
child: Text(day, style: TextStyle(color: isDark ? const Color(0XFFa5a292) : const Color(0XFF5A5D6D))),
padding: const EdgeInsets.symmetric(
vertical: 7,
horizontal: 20,
),
child: Text(
day,
style: TextStyle(
color:
isDark
? const Color(0XFFa5a292)
: const Color(0XFF5A5D6D),
),
),
),
),
)
@@ -482,16 +901,39 @@ class OnDemandDetailsScreen extends StatelessWidget {
);
}
Widget _timeCard(BuildContext context, String title, String value, bool isDark) {
Widget _timeCard(
BuildContext context,
String title,
String value,
bool isDark,
) {
return Card(
elevation: 2,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(6), side: BorderSide(color: isDark ? const Color(0XFF3c3a2e) : const Color(0XFFC3C5D1), width: 1)),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(6),
side: BorderSide(
color: isDark ? const Color(0XFF3c3a2e) : const Color(0XFFC3C5D1),
width: 1,
),
),
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 7, horizontal: 20),
child: Row(
children: [
Text(title, style: TextStyle(color: isDark ? const Color(0XFFa5a292) : const Color(0XFF5A5D6D))),
Text(value, style: TextStyle(color: isDark ? const Color(0XFFa5a292) : const Color(0XFF5A5D6D))),
Text(
title,
style: TextStyle(
color:
isDark ? const Color(0XFFa5a292) : const Color(0XFF5A5D6D),
),
),
Text(
value,
style: TextStyle(
color:
isDark ? const Color(0XFFa5a292) : const Color(0XFF5A5D6D),
),
),
],
),
),

View File

@@ -20,7 +20,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
import 'package:geocoding/geocoding.dart';
import 'package:geolocator/geolocator.dart';
import 'package:get/get.dart';
import 'package:get/get.dart' hide Trans;
import '../../controllers/on_demand_home_controller.dart';
import '../../models/category_model.dart';
import '../../models/provider_serivce_model.dart';
@@ -51,8 +51,20 @@ class OnDemandHomeScreen extends StatelessWidget {
child: Container(
height: 42,
width: 42,
decoration: const BoxDecoration(shape: BoxShape.circle, color: AppThemeData.grey50),
child: const Center(child: Padding(padding: EdgeInsets.only(left: 5), child: Icon(Icons.arrow_back_ios, color: AppThemeData.grey900, size: 20))),
decoration: const BoxDecoration(
shape: BoxShape.circle,
color: AppThemeData.grey50,
),
child: const Center(
child: Padding(
padding: EdgeInsets.only(left: 5),
child: Icon(
Icons.arrow_back_ios,
color: AppThemeData.grey900,
size: 20,
),
),
),
),
),
const SizedBox(width: 10),
@@ -61,8 +73,23 @@ class OnDemandHomeScreen extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Constant.userModel == null
? InkWell(onTap: () => Get.offAll(const LoginScreen()), child: Text("Login".tr(), style: AppThemeData.boldTextStyle(color: AppThemeData.grey900, fontSize: 12)))
: Text(Constant.userModel!.fullName(), style: AppThemeData.boldTextStyle(color: AppThemeData.grey900, fontSize: 12)),
? InkWell(
onTap: () => Get.offAll(const LoginScreen()),
child: Text(
"Login".tr(),
style: AppThemeData.boldTextStyle(
color: AppThemeData.grey900,
fontSize: 12,
),
),
)
: Text(
Constant.userModel!.fullName(),
style: AppThemeData.boldTextStyle(
color: AppThemeData.grey900,
fontSize: 12,
),
),
InkWell(
onTap: () async {
if (Constant.userModel != null) {
@@ -76,10 +103,13 @@ class OnDemandHomeScreen extends StatelessWidget {
} else {
Constant.checkPermission(
onTap: () async {
ShowToastDialog.showLoader("Please wait...".tr());
ShowToastDialog.showLoader(
"Please wait...".tr(),
);
// ✅ declare it once here!
ShippingAddress shippingAddress = ShippingAddress();
ShippingAddress shippingAddress =
ShippingAddress();
try {
await Geolocator.requestPermission();
@@ -87,41 +117,72 @@ class OnDemandHomeScreen extends StatelessWidget {
ShowToastDialog.closeLoader();
if (Constant.selectedMapType == 'osm') {
final result = await Get.to(() => MapPickerPage());
final result = await Get.to(
() => MapPickerPage(),
);
if (result != null) {
final firstPlace = result;
final lat = firstPlace.coordinates.latitude;
final lng = firstPlace.coordinates.longitude;
final lat =
firstPlace.coordinates.latitude;
final lng =
firstPlace.coordinates.longitude;
final address = firstPlace.address;
shippingAddress.addressAs = "Home";
shippingAddress.locality = address.toString();
shippingAddress.location = UserLocation(latitude: lat, longitude: lng);
Constant.selectedLocation = shippingAddress;
shippingAddress.locality =
address.toString();
shippingAddress.location = UserLocation(
latitude: lat,
longitude: lng,
);
Constant.selectedLocation =
shippingAddress;
controller.getData();
Get.back();
}
} else {
Get.to(LocationPickerScreen())!.then((value) async {
Get.to(LocationPickerScreen())!.then((
value,
) async {
if (value != null) {
SelectedLocationModel selectedLocationModel = value;
SelectedLocationModel
selectedLocationModel = value;
shippingAddress.addressAs = "Home";
shippingAddress.location = UserLocation(latitude: selectedLocationModel.latLng!.latitude, longitude: selectedLocationModel.latLng!.longitude);
shippingAddress.locality = "Picked from Map"; // You can reverse-geocode
shippingAddress
.location = UserLocation(
latitude:
selectedLocationModel
.latLng!
.latitude,
longitude:
selectedLocationModel
.latLng!
.longitude,
);
shippingAddress.locality =
"Picked from Map"; // You can reverse-geocode
Constant.selectedLocation = shippingAddress;
Constant.selectedLocation =
shippingAddress;
controller.getData();
}
});
}
} catch (e) {
await placemarkFromCoordinates(19.228825, 72.854118).then((valuePlaceMaker) {
await placemarkFromCoordinates(
19.228825,
72.854118,
).then((valuePlaceMaker) {
Placemark placeMark = valuePlaceMaker[0];
shippingAddress.location = UserLocation(latitude: 19.228825, longitude: 72.854118);
shippingAddress.location = UserLocation(
latitude: 19.228825,
longitude: 72.854118,
);
String currentLocation =
"${placeMark.name}, ${placeMark.subLocality}, ${placeMark.locality}, ${placeMark.administrativeArea}, ${placeMark.postalCode}, ${placeMark.country}";
shippingAddress.locality = currentLocation;
shippingAddress.locality =
currentLocation;
});
Constant.selectedLocation = shippingAddress;
@@ -139,10 +200,21 @@ class OnDemandHomeScreen extends StatelessWidget {
TextSpan(
children: [
TextSpan(
text: Constant.selectedLocation.getFullAddress(),
style: TextStyle(fontFamily: AppThemeData.medium, overflow: TextOverflow.ellipsis, color: AppThemeData.grey900, fontSize: 14),
text:
Constant.selectedLocation
.getFullAddress(),
style: TextStyle(
fontFamily: AppThemeData.medium,
overflow: TextOverflow.ellipsis,
color: AppThemeData.grey900,
fontSize: 14,
),
),
WidgetSpan(
child: SvgPicture.asset(
"assets/icons/ic_down.svg",
),
),
WidgetSpan(child: SvgPicture.asset("assets/icons/ic_down.svg")),
],
),
),
@@ -157,7 +229,8 @@ class OnDemandHomeScreen extends StatelessWidget {
body:
controller.isLoading.value
? Constant.loader()
: Constant.isZoneAvailable == false || controller.providerList.isEmpty
: Constant.isZoneAvailable == false ||
controller.providerList.isEmpty
? Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Column(
@@ -166,12 +239,30 @@ class OnDemandHomeScreen extends StatelessWidget {
children: [
Image.asset("assets/images/location.gif", height: 120),
const SizedBox(height: 12),
Text("No Store Found in Your Area".tr(), style: TextStyle(color: isDark ? AppThemeData.grey100 : AppThemeData.grey800, fontSize: 22, fontFamily: AppThemeData.semiBold)),
Text(
"No Store Found in Your Area".tr(),
style: TextStyle(
color:
isDark
? AppThemeData.grey100
: AppThemeData.grey800,
fontSize: 22,
fontFamily: AppThemeData.semiBold,
),
),
const SizedBox(height: 5),
Text(
"Currently, there are no available store in your zone. Try changing your location to find nearby options.".tr(),
"Currently, there are no available store in your zone. Try changing your location to find nearby options."
.tr(),
textAlign: TextAlign.center,
style: TextStyle(color: isDark ? AppThemeData.grey50 : AppThemeData.grey500, fontSize: 16, fontFamily: AppThemeData.bold),
style: TextStyle(
color:
isDark
? AppThemeData.grey50
: AppThemeData.grey500,
fontSize: 16,
fontFamily: AppThemeData.bold,
),
),
const SizedBox(height: 20),
RoundedButtonFill(
@@ -188,7 +279,10 @@ class OnDemandHomeScreen extends StatelessWidget {
),
)
: Padding(
padding: const EdgeInsets.symmetric(vertical: 20, horizontal: 15),
padding: const EdgeInsets.symmetric(
vertical: 20,
horizontal: 15,
),
child: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
@@ -199,42 +293,95 @@ class OnDemandHomeScreen extends StatelessWidget {
height: MediaQuery.of(context).size.height * 0.12,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
border: Border.all(color: isDark ? AppThemeData.greyDark600 : AppThemeData.greyDark600, width: 1),
color: isDark ? AppThemeData.greyDark50 : AppThemeData.grey50,
border: Border.all(
color:
isDark
? AppThemeData.greyDark600
: AppThemeData.greyDark600,
width: 1,
),
color:
isDark
? AppThemeData.greyDark50
: AppThemeData.grey50,
),
child:
controller.categories.isEmpty
? Constant.showEmptyView(message: "No Categories".tr())
? Constant.showEmptyView(
message: "No Categories".tr(),
)
: Padding(
padding: const EdgeInsets.symmetric(vertical: 10),
padding: const EdgeInsets.symmetric(
vertical: 10,
),
child: Row(
children: [
Expanded(
child: ListView.builder(
itemCount: controller.categories.length > 3 ? 3 : controller.categories.length,
itemCount:
controller.categories.length >
3
? 3
: controller
.categories
.length,
scrollDirection: Axis.horizontal,
itemBuilder: (context, index) {
final category = controller.categories[index];
final category =
controller
.categories[index];
return InkWell(
onTap: () {
Get.to(() => ViewCategoryServiceListScreen(), arguments: {'categoryId': category.id, 'categoryTitle': category.title});
Get.to(
() =>
ViewCategoryServiceListScreen(),
arguments: {
'categoryId':
category.id,
'categoryTitle':
category.title,
},
);
},
child: CategoryView(category: category, index: index, isDark: isDark),
child: CategoryView(
category: category,
index: index,
isDark: isDark,
),
);
},
),
),
if (controller.categories.length > 3)
Padding(
padding: const EdgeInsets.symmetric(horizontal: 10),
padding:
const EdgeInsets.symmetric(
horizontal: 10,
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
InkWell(
onTap: () {
Get.to(() => const OnDemandCategoryScreen());
Get.to(
() =>
const OnDemandCategoryScreen(),
);
},
child: ClipOval(child: Container(width: 50, height: 50, color: AppThemeData.grey200, child: const Center(child: Icon(Icons.chevron_right)))),
child: ClipOval(
child: Container(
width: 50,
height: 50,
color:
AppThemeData
.grey200,
child: const Center(
child: Icon(
Icons.chevron_right,
),
),
),
),
),
const SizedBox(height: 5),
SizedBox(
@@ -242,9 +389,17 @@ class OnDemandHomeScreen extends StatelessWidget {
child: Center(
child: Text(
"View All".tr(),
textAlign: TextAlign.center,
textAlign:
TextAlign.center,
maxLines: 1,
style: AppThemeData.semiBoldTextStyle(color: isDark ? AppThemeData.greyDark900 : AppThemeData.grey900),
style: AppThemeData.semiBoldTextStyle(
color:
isDark
? AppThemeData
.greyDark900
: AppThemeData
.grey900,
),
),
),
),
@@ -262,14 +417,28 @@ class OnDemandHomeScreen extends StatelessWidget {
Expanded(
child: Text(
"Most Popular services".tr(),
style: TextStyle(color: isDark ? Colors.white : Colors.black, fontSize: 18, fontFamily: AppThemeData.regular, fontWeight: FontWeight.w600),
style: TextStyle(
color:
isDark ? Colors.white : Colors.black,
fontSize: 18,
fontFamily: AppThemeData.regular,
fontWeight: FontWeight.w600,
),
),
),
InkWell(
onTap: () {
Get.to(() => ViewAllPopularServiceScreen());
},
child: Text("View all".tr(), style: TextStyle(color: AppThemeData.primary300, fontSize: 14, fontFamily: AppThemeData.regular, fontWeight: FontWeight.w600)),
child: Text(
"View all".tr(),
style: TextStyle(
color: AppThemeData.primary300,
fontSize: 14,
fontFamily: AppThemeData.regular,
fontWeight: FontWeight.w600,
),
),
),
],
),
@@ -280,9 +449,16 @@ class OnDemandHomeScreen extends StatelessWidget {
shrinkWrap: true,
padding: EdgeInsets.zero,
physics: const NeverScrollableScrollPhysics(),
itemCount: controller.providerList.length >= 6 ? 6 : controller.providerList.length,
itemCount:
controller.providerList.length >= 6
? 6
: controller.providerList.length,
itemBuilder: (_, index) {
return ServiceView(provider: controller.providerList[index], controller: controller, isDark: isDark);
return ServiceView(
provider: controller.providerList[index],
controller: controller,
isDark: isDark,
);
},
),
],
@@ -334,7 +510,13 @@ class BannerView extends StatelessWidget {
final banner = bannerList[index];
return ClipRRect(
borderRadius: BorderRadius.circular(15),
child: SizedBox(width: MediaQuery.of(context).size.width * 0.8, child: NetworkImageWidget(imageUrl: banner.photo ?? '', fit: BoxFit.cover)),
child: SizedBox(
width: MediaQuery.of(context).size.width * 0.8,
child: NetworkImageWidget(
imageUrl: banner.photo ?? '',
fit: BoxFit.cover,
),
),
);
},
),
@@ -344,7 +526,18 @@ class BannerView extends StatelessWidget {
return Row(
children: List.generate(bannerList.length, (index) {
bool isSelected = currentPage.value == index;
return Expanded(child: Container(height: 4, decoration: BoxDecoration(color: isSelected ? AppThemeData.grey300 : AppThemeData.grey100, borderRadius: BorderRadius.circular(5))));
return Expanded(
child: Container(
height: 4,
decoration: BoxDecoration(
color:
isSelected
? AppThemeData.grey300
: AppThemeData.grey100,
borderRadius: BorderRadius.circular(5),
),
),
);
}),
);
}),
@@ -358,7 +551,12 @@ class CategoryView extends StatelessWidget {
final int index;
final bool isDark;
const CategoryView({super.key, required this.category, required this.index, required this.isDark});
const CategoryView({
super.key,
required this.category,
required this.index,
required this.isDark,
});
@override
Widget build(BuildContext context) {
@@ -370,11 +568,21 @@ class CategoryView extends StatelessWidget {
Container(
height: 55,
width: 55,
decoration: BoxDecoration(color: Constant.colorList[index % Constant.colorList.length], borderRadius: BorderRadius.circular(50)),
decoration: BoxDecoration(
color: Constant.colorList[index % Constant.colorList.length],
borderRadius: BorderRadius.circular(50),
),
child: ClipOval(
child: Padding(
padding: const EdgeInsets.all(14.0),
child: CachedNetworkImage(imageUrl: category.image.toString(), errorWidget: (_, __, ___) => Image.network(Constant.placeHolderImage, fit: BoxFit.cover)),
child: CachedNetworkImage(
imageUrl: category.image.toString(),
errorWidget:
(_, __, ___) => Image.network(
Constant.placeHolderImage,
fit: BoxFit.cover,
),
),
),
),
),
@@ -382,7 +590,15 @@ class CategoryView extends StatelessWidget {
SizedBox(
width: 70,
child: Center(
child: Text(category.title ?? "", textAlign: TextAlign.center, maxLines: 1, style: AppThemeData.semiBoldTextStyle(color: isDark ? AppThemeData.greyDark900 : AppThemeData.grey900)),
child: Text(
category.title ?? "",
textAlign: TextAlign.center,
maxLines: 1,
style: AppThemeData.semiBoldTextStyle(
color:
isDark ? AppThemeData.greyDark900 : AppThemeData.grey900,
),
),
),
),
],
@@ -396,40 +612,70 @@ class ServiceView extends StatelessWidget {
final bool isDark;
final OnDemandHomeController? controller;
const ServiceView({super.key, required this.provider, this.isDark = false, this.controller});
const ServiceView({
super.key,
required this.provider,
this.isDark = false,
this.controller,
});
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
Get.to(() => OnDemandDetailsScreen(), arguments: {'providerModel': provider});
Get.to(
() => OnDemandDetailsScreen(),
arguments: {'providerModel': provider},
);
},
child: Container(
margin: const EdgeInsets.symmetric(vertical: 5),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
border: Border.all(color: isDark ? AppThemeData.grey500 : Colors.grey.shade200),
border: Border.all(
color: isDark ? AppThemeData.grey500 : Colors.grey.shade200,
),
color: isDark ? AppThemeData.grey900 : Colors.white,
),
child: Row(
children: [
// --- Left Image ---
ClipRRect(
borderRadius: const BorderRadius.only(topLeft: Radius.circular(10), bottomLeft: Radius.circular(10)),
borderRadius: const BorderRadius.only(
topLeft: Radius.circular(10),
bottomLeft: Radius.circular(10),
),
child: CachedNetworkImage(
imageUrl: provider.photos.isNotEmpty ? provider.photos[0] : Constant.placeHolderImage,
imageUrl:
provider.photos.isNotEmpty
? provider.photos[0]
: Constant.placeHolderImage,
width: 110,
height: MediaQuery.of(context).size.height * 0.16,
fit: BoxFit.cover,
placeholder: (context, url) => Center(child: CircularProgressIndicator.adaptive(valueColor: AlwaysStoppedAnimation(AppThemeData.primary300))),
errorWidget: (context, url, error) => Image.network(Constant.placeHolderImage, fit: BoxFit.cover),
placeholder:
(context, url) => Center(
child: CircularProgressIndicator.adaptive(
valueColor: AlwaysStoppedAnimation(
AppThemeData.primary300,
),
),
),
errorWidget:
(context, url, error) => Image.network(
Constant.placeHolderImage,
fit: BoxFit.cover,
),
),
),
// --- Right Content ---
Expanded(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10),
padding: const EdgeInsets.symmetric(
horizontal: 12,
vertical: 10,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
@@ -442,17 +688,40 @@ class ServiceView extends StatelessWidget {
provider.title ?? "",
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold, color: isDark ? Colors.white : Colors.black),
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
color: isDark ? Colors.white : Colors.black,
),
),
),
if (controller != null)
Obx(
() => GestureDetector(
onTap: () => controller!.toggleFavourite(provider),
onTap:
() => controller!.toggleFavourite(provider),
child: Icon(
controller!.lstFav.where((element) => element.service_id == provider.id).isNotEmpty ? Icons.favorite : Icons.favorite_border,
controller!.lstFav
.where(
(element) =>
element.service_id == provider.id,
)
.isNotEmpty
? Icons.favorite
: Icons.favorite_border,
size: 24,
color: controller!.lstFav.where((element) => element.service_id == provider.id).isNotEmpty ? AppThemeData.primary300 : (isDark ? Colors.white38 : Colors.black38),
color:
controller!.lstFav
.where(
(element) =>
element.service_id ==
provider.id,
)
.isNotEmpty
? AppThemeData.primary300
: (isDark
? Colors.white38
: Colors.black38),
),
),
),
@@ -464,10 +733,18 @@ class ServiceView extends StatelessWidget {
// Category
if (controller != null)
FutureBuilder<CategoryModel?>(
future: controller!.getCategory(provider.categoryId ?? ""),
future: controller!.getCategory(
provider.categoryId ?? "",
),
builder: (ctx, snap) {
if (!snap.hasData) return const SizedBox.shrink();
return Text(snap.data?.title ?? "", style: TextStyle(fontSize: 13, color: isDark ? Colors.white70 : Colors.black54));
return Text(
snap.data?.title ?? "",
style: TextStyle(
fontSize: 13,
color: isDark ? Colors.white70 : Colors.black54,
),
);
},
),
@@ -493,21 +770,39 @@ class ServiceView extends StatelessWidget {
Widget _buildPrice() {
if (provider.disPrice == "" || provider.disPrice == "0") {
return Text(
provider.priceUnit == 'Fixed' ? Constant.amountShow(amount: provider.price) : '${Constant.amountShow(amount: provider.price ?? "0")}/${'hr'.tr()}',
style: TextStyle(fontSize: 14, fontWeight: FontWeight.bold, color: isDark ? Colors.white : AppThemeData.primary300),
provider.priceUnit == 'Fixed'
? Constant.amountShow(amount: provider.price)
: '${Constant.amountShow(amount: provider.price ?? "0")}/${'hr'.tr()}',
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.bold,
color: isDark ? Colors.white : AppThemeData.primary300,
),
);
} else {
return Row(
children: [
Text(
provider.priceUnit == 'Fixed' ? Constant.amountShow(amount: provider.disPrice ?? '0') : '${Constant.amountShow(amount: provider.disPrice)}/${'hr'.tr()}',
style: TextStyle(fontSize: 14, fontWeight: FontWeight.bold, color: isDark ? Colors.white : AppThemeData.primary300),
provider.priceUnit == 'Fixed'
? Constant.amountShow(amount: provider.disPrice ?? '0')
: '${Constant.amountShow(amount: provider.disPrice)}/${'hr'.tr()}',
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.bold,
color: isDark ? Colors.white : AppThemeData.primary300,
),
),
const SizedBox(width: 6),
Flexible(
child: Text(
provider.priceUnit == 'Fixed' ? Constant.amountShow(amount: provider.price) : '${Constant.amountShow(amount: provider.price ?? "0")}/hr',
style: const TextStyle(fontSize: 12, color: Colors.grey, decoration: TextDecoration.lineThrough),
provider.priceUnit == 'Fixed'
? Constant.amountShow(amount: provider.price)
: '${Constant.amountShow(amount: provider.price ?? "0")}/hr',
style: const TextStyle(
fontSize: 12,
color: Colors.grey,
decoration: TextDecoration.lineThrough,
),
overflow: TextOverflow.ellipsis,
),
),
@@ -522,11 +817,21 @@ class ServiceView extends StatelessWidget {
rating = (provider.reviewsSum ?? 0) / (provider.reviewsCount ?? 1);
}
return Container(
decoration: BoxDecoration(color: AppThemeData.warning400, borderRadius: BorderRadius.circular(12)),
decoration: BoxDecoration(
color: AppThemeData.warning400,
borderRadius: BorderRadius.circular(12),
),
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [const Icon(Icons.star, size: 14, color: Colors.white), const SizedBox(width: 3), Text(rating.toStringAsFixed(1), style: const TextStyle(fontSize: 12, color: Colors.white))],
children: [
const Icon(Icons.star, size: 14, color: Colors.white),
const SizedBox(width: 3),
Text(
rating.toStringAsFixed(1),
style: const TextStyle(fontSize: 12, color: Colors.white),
),
],
),
);
}

View File

@@ -1,7 +1,7 @@
import 'package:customer/constant/constant.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:get/get.dart' hide Trans;
import '../../controllers/0n_demand_payment_controller.dart';
import '../../controllers/theme_controller.dart';
import '../../payment/createRazorPayOrderModel.dart';
@@ -35,12 +35,30 @@ class OnDemandPaymentScreen extends StatelessWidget {
child: Container(
height: 42,
width: 42,
decoration: BoxDecoration(shape: BoxShape.circle, color: AppThemeData.grey50),
child: Center(child: Padding(padding: const EdgeInsets.only(left: 5), child: Icon(Icons.arrow_back_ios, color: AppThemeData.grey900, size: 20))),
decoration: BoxDecoration(
shape: BoxShape.circle,
color: AppThemeData.grey50,
),
child: Center(
child: Padding(
padding: const EdgeInsets.only(left: 5),
child: Icon(
Icons.arrow_back_ios,
color: AppThemeData.grey900,
size: 20,
),
),
),
),
),
const SizedBox(width: 10),
Text("Select Payment Method".tr(), style: AppThemeData.boldTextStyle(fontSize: 18, color: AppThemeData.grey900)),
Text(
"Select Payment Method".tr(),
style: AppThemeData.boldTextStyle(
fontSize: 18,
color: AppThemeData.grey900,
),
),
],
),
),
@@ -49,45 +67,106 @@ class OnDemandPaymentScreen extends StatelessWidget {
controller.isLoading.value
? Constant.loader()
: Container(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 20),
decoration: BoxDecoration(color: isDark ? AppThemeData.greyDark200 : Colors.white),
padding: const EdgeInsets.symmetric(
horizontal: 16,
vertical: 20,
),
decoration: BoxDecoration(
color: isDark ? AppThemeData.greyDark200 : Colors.white,
),
child: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text("Preferred Payment".tr(), textAlign: TextAlign.start, style: AppThemeData.boldTextStyle(fontSize: 15, color: isDark ? AppThemeData.greyDark500 : AppThemeData.grey500)),
Text(
"Preferred Payment".tr(),
textAlign: TextAlign.start,
style: AppThemeData.boldTextStyle(
fontSize: 15,
color:
isDark
? AppThemeData.greyDark500
: AppThemeData.grey500,
),
),
const SizedBox(height: 10),
if (controller.walletSettingModel.value.isEnabled == true || controller.cashOnDeliverySettingModel.value.isEnabled == true)
if (controller.walletSettingModel.value.isEnabled ==
true ||
controller
.cashOnDeliverySettingModel
.value
.isEnabled ==
true)
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15),
color: isDark ? AppThemeData.greyDark50 : AppThemeData.grey50,
border: Border.all(color: isDark ? AppThemeData.greyDark200 : AppThemeData.grey200),
color:
isDark
? AppThemeData.greyDark50
: AppThemeData.grey50,
border: Border.all(
color:
isDark
? AppThemeData.greyDark200
: AppThemeData.grey200,
),
),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: [
Visibility(
visible: controller.walletSettingModel.value.isEnabled == true,
child: cardDecoration(controller, PaymentGateway.wallet, isDark, "assets/images/ic_wallet.png"),
visible:
controller
.walletSettingModel
.value
.isEnabled ==
true,
child: cardDecoration(
controller,
PaymentGateway.wallet,
isDark,
"assets/images/ic_wallet.png",
),
),
Visibility(
visible: controller.cashOnDeliverySettingModel.value.isEnabled == true,
child: cardDecoration(controller, PaymentGateway.cod, isDark, "assets/images/ic_cash.png"),
visible:
controller
.cashOnDeliverySettingModel
.value
.isEnabled ==
true,
child: cardDecoration(
controller,
PaymentGateway.cod,
isDark,
"assets/images/ic_cash.png",
),
),
],
),
),
),
if (controller.walletSettingModel.value.isEnabled == true || controller.cashOnDeliverySettingModel.value.isEnabled == true)
if (controller.walletSettingModel.value.isEnabled ==
true ||
controller
.cashOnDeliverySettingModel
.value
.isEnabled ==
true)
Column(
children: [
const SizedBox(height: 10),
Text(
"Other Payment Options".tr(),
textAlign: TextAlign.start,
style: AppThemeData.boldTextStyle(fontSize: 15, color: isDark ? AppThemeData.greyDark500 : AppThemeData.grey500),
style: AppThemeData.boldTextStyle(
fontSize: 15,
color:
isDark
? AppThemeData.greyDark500
: AppThemeData.grey500,
),
),
const SizedBox(height: 10),
],
@@ -95,38 +174,155 @@ class OnDemandPaymentScreen extends StatelessWidget {
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15),
color: isDark ? AppThemeData.greyDark50 : AppThemeData.grey50,
border: Border.all(color: isDark ? AppThemeData.greyDark200 : AppThemeData.grey200),
color:
isDark
? AppThemeData.greyDark50
: AppThemeData.grey50,
border: Border.all(
color:
isDark
? AppThemeData.greyDark200
: AppThemeData.grey200,
),
),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: [
Visibility(visible: controller.stripeModel.value.isEnabled == true, child: cardDecoration(controller, PaymentGateway.stripe, isDark, "assets/images/stripe.png")),
Visibility(visible: controller.payPalModel.value.isEnabled == true, child: cardDecoration(controller, PaymentGateway.paypal, isDark, "assets/images/paypal.png")),
Visibility(
visible: controller.payStackModel.value.isEnable == true,
child: cardDecoration(controller, PaymentGateway.payStack, isDark, "assets/images/paystack.png"),
visible:
controller
.stripeModel
.value
.isEnabled ==
true,
child: cardDecoration(
controller,
PaymentGateway.stripe,
isDark,
"assets/images/stripe.png",
),
),
Visibility(
visible: controller.mercadoPagoModel.value.isEnabled == true,
child: cardDecoration(controller, PaymentGateway.mercadoPago, isDark, "assets/images/mercado-pago.png"),
visible:
controller
.payPalModel
.value
.isEnabled ==
true,
child: cardDecoration(
controller,
PaymentGateway.paypal,
isDark,
"assets/images/paypal.png",
),
),
Visibility(
visible: controller.flutterWaveModel.value.isEnable == true,
child: cardDecoration(controller, PaymentGateway.flutterWave, isDark, "assets/images/flutterwave_logo.png"),
visible:
controller
.payStackModel
.value
.isEnable ==
true,
child: cardDecoration(
controller,
PaymentGateway.payStack,
isDark,
"assets/images/paystack.png",
),
),
Visibility(visible: controller.payFastModel.value.isEnable == true, child: cardDecoration(controller, PaymentGateway.payFast, isDark, "assets/images/payfast.png")),
Visibility(
visible: controller.razorPayModel.value.isEnabled == true,
child: cardDecoration(controller, PaymentGateway.razorpay, isDark, "assets/images/razorpay.png"),
visible:
controller
.mercadoPagoModel
.value
.isEnabled ==
true,
child: cardDecoration(
controller,
PaymentGateway.mercadoPago,
isDark,
"assets/images/mercado-pago.png",
),
),
Visibility(visible: controller.midTransModel.value.enable == true, child: cardDecoration(controller, PaymentGateway.midTrans, isDark, "assets/images/midtrans.png")),
Visibility(
visible: controller.orangeMoneyModel.value.enable == true,
child: cardDecoration(controller, PaymentGateway.orangeMoney, isDark, "assets/images/orange_money.png"),
visible:
controller
.flutterWaveModel
.value
.isEnable ==
true,
child: cardDecoration(
controller,
PaymentGateway.flutterWave,
isDark,
"assets/images/flutterwave_logo.png",
),
),
Visibility(
visible:
controller
.payFastModel
.value
.isEnable ==
true,
child: cardDecoration(
controller,
PaymentGateway.payFast,
isDark,
"assets/images/payfast.png",
),
),
Visibility(
visible:
controller
.razorPayModel
.value
.isEnabled ==
true,
child: cardDecoration(
controller,
PaymentGateway.razorpay,
isDark,
"assets/images/razorpay.png",
),
),
Visibility(
visible:
controller.midTransModel.value.enable ==
true,
child: cardDecoration(
controller,
PaymentGateway.midTrans,
isDark,
"assets/images/midtrans.png",
),
),
Visibility(
visible:
controller
.orangeMoneyModel
.value
.enable ==
true,
child: cardDecoration(
controller,
PaymentGateway.orangeMoney,
isDark,
"assets/images/orange_money.png",
),
),
Visibility(
visible:
controller.xenditModel.value.enable ==
true,
child: cardDecoration(
controller,
PaymentGateway.xendit,
isDark,
"assets/images/xendit.png",
),
),
Visibility(visible: controller.xenditModel.value.enable == true, child: cardDecoration(controller, PaymentGateway.xendit, isDark, "assets/images/xendit.png")),
],
),
),
@@ -137,55 +333,151 @@ class OnDemandPaymentScreen extends StatelessWidget {
color: AppThemeData.primary300,
textColor: AppThemeData.grey900,
onPress: () async {
print("getTotalAmount :::::::: ${"${controller.totalAmount.value}"}");
print(
"getTotalAmount :::::::: ${"${controller.totalAmount.value}"}",
);
if (controller.isOrderPlaced.value == false) {
controller.isOrderPlaced.value = true;
if (controller.selectedPaymentMethod.value == PaymentGateway.stripe.name) {
controller.stripeMakePayment(amount: "${controller.totalAmount.value}");
} else if (controller.selectedPaymentMethod.value == PaymentGateway.paypal.name) {
controller.paypalPaymentSheet("${controller.totalAmount.value}", context);
} else if (controller.selectedPaymentMethod.value == PaymentGateway.payStack.name) {
controller.payStackPayment("${controller.totalAmount.value}");
} else if (controller.selectedPaymentMethod.value == PaymentGateway.mercadoPago.name) {
controller.mercadoPagoMakePayment(context: context, amount: "${controller.totalAmount.value}");
} else if (controller.selectedPaymentMethod.value == PaymentGateway.flutterWave.name) {
controller.flutterWaveInitiatePayment(context: context, amount: "${controller.totalAmount.value}");
} else if (controller.selectedPaymentMethod.value == PaymentGateway.payFast.name) {
controller.payFastPayment(context: context, amount: "${controller.totalAmount.value}");
} else if (controller.selectedPaymentMethod.value == PaymentGateway.wallet.name) {
double totalAmount = double.parse("${controller.totalAmount.value}");
double walletAmount = double.tryParse(Constant.userModel?.walletAmount?.toString() ?? "0") ?? 0;
if (controller.selectedPaymentMethod.value ==
PaymentGateway.stripe.name) {
controller.stripeMakePayment(
amount: "${controller.totalAmount.value}",
);
} else if (controller
.selectedPaymentMethod
.value ==
PaymentGateway.paypal.name) {
controller.paypalPaymentSheet(
"${controller.totalAmount.value}",
context,
);
} else if (controller
.selectedPaymentMethod
.value ==
PaymentGateway.payStack.name) {
controller.payStackPayment(
"${controller.totalAmount.value}",
);
} else if (controller
.selectedPaymentMethod
.value ==
PaymentGateway.mercadoPago.name) {
controller.mercadoPagoMakePayment(
context: context,
amount: "${controller.totalAmount.value}",
);
} else if (controller
.selectedPaymentMethod
.value ==
PaymentGateway.flutterWave.name) {
controller.flutterWaveInitiatePayment(
context: context,
amount: "${controller.totalAmount.value}",
);
} else if (controller
.selectedPaymentMethod
.value ==
PaymentGateway.payFast.name) {
controller.payFastPayment(
context: context,
amount: "${controller.totalAmount.value}",
);
} else if (controller
.selectedPaymentMethod
.value ==
PaymentGateway.wallet.name) {
double totalAmount = double.parse(
"${controller.totalAmount.value}",
);
double walletAmount =
double.tryParse(
Constant.userModel?.walletAmount
?.toString() ??
"0",
) ??
0;
if (walletAmount == 0) {
ShowToastDialog.showToast("Wallet balance is 0. Please recharge wallet.".tr());
ShowToastDialog.showToast(
"Wallet balance is 0. Please recharge wallet."
.tr(),
);
} else if (walletAmount < totalAmount) {
ShowToastDialog.showToast("Insufficient wallet balance. Please add funds.".tr());
ShowToastDialog.showToast(
"Insufficient wallet balance. Please add funds."
.tr(),
);
} else {
controller.placeOrder();
}
} else if (controller.selectedPaymentMethod.value == PaymentGateway.cod.name) {
} else if (controller
.selectedPaymentMethod
.value ==
PaymentGateway.cod.name) {
controller.placeOrder();
} else if (controller.selectedPaymentMethod.value == PaymentGateway.wallet.name) {
} else if (controller
.selectedPaymentMethod
.value ==
PaymentGateway.wallet.name) {
controller.placeOrder();
} else if (controller.selectedPaymentMethod.value == PaymentGateway.midTrans.name) {
controller.midtransMakePayment(context: context, amount: "${controller.totalAmount.value}");
} else if (controller.selectedPaymentMethod.value == PaymentGateway.orangeMoney.name) {
controller.orangeMakePayment(context: context, amount: "${controller.totalAmount.value}");
} else if (controller.selectedPaymentMethod.value == PaymentGateway.xendit.name) {
controller.xenditPayment(context, "${controller.totalAmount.value}");
} else if (controller.selectedPaymentMethod.value == PaymentGateway.razorpay.name) {
RazorPayController().createOrderRazorPay(amount: double.parse("${controller.totalAmount.value}"), razorpayModel: controller.razorPayModel.value).then((value) {
if (value == null) {
Get.back();
ShowToastDialog.showToast("Something went wrong, please contact admin.".tr());
} else {
CreateRazorPayOrderModel result = value;
controller.openCheckout(amount: "${controller.totalAmount.value}", orderId: result.id);
}
});
} else if (controller
.selectedPaymentMethod
.value ==
PaymentGateway.midTrans.name) {
controller.midtransMakePayment(
context: context,
amount: "${controller.totalAmount.value}",
);
} else if (controller
.selectedPaymentMethod
.value ==
PaymentGateway.orangeMoney.name) {
controller.orangeMakePayment(
context: context,
amount: "${controller.totalAmount.value}",
);
} else if (controller
.selectedPaymentMethod
.value ==
PaymentGateway.xendit.name) {
controller.xenditPayment(
context,
"${controller.totalAmount.value}",
);
} else if (controller
.selectedPaymentMethod
.value ==
PaymentGateway.razorpay.name) {
RazorPayController()
.createOrderRazorPay(
amount: double.parse(
"${controller.totalAmount.value}",
),
razorpayModel:
controller.razorPayModel.value,
)
.then((value) {
if (value == null) {
Get.back();
ShowToastDialog.showToast(
"Something went wrong, please contact admin."
.tr(),
);
} else {
CreateRazorPayOrderModel result =
value;
controller.openCheckout(
amount:
"${controller.totalAmount.value}",
orderId: result.id,
);
}
});
} else {
controller.isOrderPlaced.value = false;
ShowToastDialog.showToast("Please select payment method".tr());
ShowToastDialog.showToast(
"Please select payment method".tr(),
);
}
controller.isOrderPlaced.value = false;
}
@@ -215,8 +507,21 @@ class OnDemandPaymentScreen extends StatelessWidget {
Container(
width: 50,
height: 50,
decoration: ShapeDecoration(shape: RoundedRectangleBorder(side: const BorderSide(width: 1, color: Color(0xFFE5E7EB)), borderRadius: BorderRadius.circular(8))),
child: Padding(padding: EdgeInsets.all(value.name == "payFast" ? 0 : 8.0), child: Image.asset(image)),
decoration: ShapeDecoration(
shape: RoundedRectangleBorder(
side: const BorderSide(
width: 1,
color: Color(0xFFE5E7EB),
),
borderRadius: BorderRadius.circular(8),
),
),
child: Padding(
padding: EdgeInsets.all(
value.name == "payFast" ? 0 : 8.0,
),
child: Image.asset(image),
),
),
const SizedBox(width: 10),
value.name == "wallet"
@@ -227,12 +532,30 @@ class OnDemandPaymentScreen extends StatelessWidget {
Text(
value.name.capitalizeString(),
textAlign: TextAlign.start,
style: AppThemeData.semiBoldTextStyle(fontSize: 16, color: isDark ? AppThemeData.grey50 : AppThemeData.grey900),
style: AppThemeData.semiBoldTextStyle(
fontSize: 16,
color:
isDark
? AppThemeData.grey50
: AppThemeData.grey900,
),
),
Text(
Constant.amountShow(amount: Constant.userModel?.walletAmount == null ? '0.0' : Constant.userModel?.walletAmount.toString()),
Constant.amountShow(
amount:
Constant.userModel?.walletAmount == null
? '0.0'
: Constant.userModel?.walletAmount
.toString(),
),
textAlign: TextAlign.start,
style: AppThemeData.semiBoldTextStyle(fontSize: 14, color: isDark ? AppThemeData.primary300 : AppThemeData.primary300),
style: AppThemeData.semiBoldTextStyle(
fontSize: 14,
color:
isDark
? AppThemeData.primary300
: AppThemeData.primary300,
),
),
],
),
@@ -241,14 +564,23 @@ class OnDemandPaymentScreen extends StatelessWidget {
child: Text(
value.name.capitalizeString(),
textAlign: TextAlign.start,
style: AppThemeData.semiBoldTextStyle(fontSize: 16, color: isDark ? AppThemeData.grey50 : AppThemeData.grey900),
style: AppThemeData.semiBoldTextStyle(
fontSize: 16,
color:
isDark
? AppThemeData.grey50
: AppThemeData.grey900,
),
),
),
const Expanded(child: SizedBox()),
Radio(
value: value.name,
groupValue: controller.selectedPaymentMethod.value,
activeColor: isDark ? AppThemeData.primary300 : AppThemeData.primary300,
activeColor:
isDark
? AppThemeData.primary300
: AppThemeData.primary300,
onChanged: (value) {
controller.selectedPaymentMethod.value = value.toString();
},

View File

@@ -1,7 +1,7 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_rating_bar/flutter_rating_bar.dart';
import 'package:get/get.dart';
import 'package:get/get.dart' hide Trans;
import '../../constant/constant.dart';
import '../../controllers/on_demand_review_controller.dart';
import '../../controllers/theme_controller.dart';
@@ -34,61 +34,139 @@ class OnDemandReviewScreen extends StatelessWidget {
child: Container(
height: 42,
width: 42,
decoration: BoxDecoration(shape: BoxShape.circle, color: AppThemeData.grey50),
child: Center(child: Padding(padding: const EdgeInsets.only(left: 5), child: Icon(Icons.arrow_back_ios, color: AppThemeData.grey900, size: 20))),
decoration: BoxDecoration(
shape: BoxShape.circle,
color: AppThemeData.grey50,
),
child: Center(
child: Padding(
padding: const EdgeInsets.only(left: 5),
child: Icon(
Icons.arrow_back_ios,
color: AppThemeData.grey900,
size: 20,
),
),
),
),
),
const SizedBox(width: 10),
Text(controller.ratingModel.value != null ? "Update Review".tr() : "Add Review".tr(), style: AppThemeData.boldTextStyle(fontSize: 18, color: AppThemeData.grey900)),
Text(
controller.ratingModel.value != null
? "Update Review".tr()
: "Add Review".tr(),
style: AppThemeData.boldTextStyle(
fontSize: 18,
color: AppThemeData.grey900,
),
),
],
),
),
),
body: Obx(
() =>
(controller.reviewFor.value == "Worker" && controller.workerModel.value == null) || (controller.reviewFor.value == "Provider" && controller.provider.value == null)
(controller.reviewFor.value == "Worker" &&
controller.workerModel.value == null) ||
(controller.reviewFor.value == "Provider" &&
controller.provider.value == null)
? Constant.loader()
: Padding(
padding: const EdgeInsets.only(top: 50.0),
child: Stack(
children: [
Padding(
padding: const EdgeInsets.only(left: 20, right: 20, top: 42, bottom: 20),
padding: const EdgeInsets.only(
left: 20,
right: 20,
top: 42,
bottom: 20,
),
child: Card(
elevation: 2,
color: isDark ? AppThemeData.greyDark50 : AppThemeData.grey50,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
color:
isDark
? AppThemeData.greyDark50
: AppThemeData.grey50,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
child: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.only(top: 65),
child: Column(
children: [
Text('Rate for'.tr(), style: AppThemeData.mediumTextStyle(fontSize: 18, color: isDark ? AppThemeData.greyDark900 : AppThemeData.grey900)),
Text(
controller.reviewFor.value == "Provider" ? controller.order.value!.provider.authorName ?? "" : controller.workerModel.value!.fullName(),
style: AppThemeData.mediumTextStyle(fontSize: 18, color: isDark ? AppThemeData.greyDark900 : AppThemeData.grey900),
'Rate for'.tr(),
style: AppThemeData.mediumTextStyle(
fontSize: 18,
color:
isDark
? AppThemeData.greyDark900
: AppThemeData.grey900,
),
),
Text(
controller.reviewFor.value == "Provider"
? controller
.order
.value!
.provider
.authorName ??
""
: controller.workerModel.value!
.fullName(),
style: AppThemeData.mediumTextStyle(
fontSize: 18,
color:
isDark
? AppThemeData.greyDark900
: AppThemeData.grey900,
),
),
Padding(
padding: const EdgeInsets.only(top: 10),
child: RatingBar.builder(
initialRating: controller.ratings.value,
initialRating:
controller.ratings.value,
minRating: 1,
direction: Axis.horizontal,
allowHalfRating: true,
itemCount: 5,
itemPadding: const EdgeInsets.symmetric(horizontal: 4.0),
itemBuilder: (context, _) => const Icon(Icons.star, color: Colors.amber),
unratedColor: isDark ? AppThemeData.greyDark400 : AppThemeData.grey400,
itemPadding:
const EdgeInsets.symmetric(
horizontal: 4.0,
),
itemBuilder:
(context, _) => const Icon(
Icons.star,
color: Colors.amber,
),
unratedColor:
isDark
? AppThemeData.greyDark400
: AppThemeData.grey400,
onRatingUpdate: (rating) {
controller.ratings.value = rating;
},
),
),
Padding(padding: EdgeInsets.all(20.0), child: TextFieldWidget(hintText: "Type comment....".tr(), controller: controller.comment, maxLine: 5)),
Padding(
padding: EdgeInsets.all(20.0),
child: TextFieldWidget(
hintText: "Type comment....".tr(),
controller: controller.comment,
maxLine: 5,
),
),
Padding(
padding: const EdgeInsets.all(20.0),
child: RoundedButtonFill(
title: controller.ratingModel.value != null ? "Update Review".tr() : "Add Review".tr(),
title:
controller.ratingModel.value !=
null
? "Update Review".tr()
: "Add Review".tr(),
color: AppThemeData.primary300,
textColor: AppThemeData.grey50,
onPress: controller.submitReview,
@@ -105,7 +183,19 @@ class OnDemandReviewScreen extends StatelessWidget {
child: ClipRRect(
borderRadius: BorderRadius.circular(50),
child: NetworkImageWidget(
imageUrl: controller.reviewFor.value == "Provider" ? controller.order.value?.provider.authorProfilePic ?? '' : controller.workerModel.value?.profilePictureURL ?? '',
imageUrl:
controller.reviewFor.value == "Provider"
? controller
.order
.value
?.provider
.authorProfilePic ??
''
: controller
.workerModel
.value
?.profilePictureURL ??
'',
fit: BoxFit.cover,
height: 100,
width: 100,

View File

@@ -10,8 +10,7 @@ import 'package:customer/widget/firebase_pagination/src/fireStore_pagination.dar
import 'package:customer/widget/firebase_pagination/src/models/view_type.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:get/get.dart' hide Trans;
import '../../../controllers/theme_controller.dart';
import '../../../service/fire_store_utils.dart';
import '../../../themes/show_toast_dialog.dart';
@@ -25,10 +24,19 @@ class ProviderInboxScreen extends StatelessWidget {
final isDark = themeController.isDark.value;
return Scaffold(
appBar: AppBar(
backgroundColor: isDark ? AppThemeData.surfaceDark : AppThemeData.surface,
backgroundColor:
isDark ? AppThemeData.surfaceDark : AppThemeData.surface,
centerTitle: false,
titleSpacing: 0,
title: Text("Provider Inbox".tr(), textAlign: TextAlign.start, style: TextStyle(fontFamily: AppThemeData.medium, fontSize: 16, color: isDark ? AppThemeData.grey50 : AppThemeData.grey900)),
title: Text(
"Provider Inbox".tr(),
textAlign: TextAlign.start,
style: TextStyle(
fontFamily: AppThemeData.medium,
fontSize: 16,
color: isDark ? AppThemeData.grey50 : AppThemeData.grey900,
),
),
),
body: FirestorePagination(
//item builder type is compulsory.
@@ -40,8 +48,12 @@ class ProviderInboxScreen extends StatelessWidget {
onTap: () async {
ShowToastDialog.showLoader("Please wait...".tr());
UserModel? customer = await FireStoreUtils.getUserProfile(inboxModel.customerId.toString());
UserModel? restaurantUser = await FireStoreUtils.getUserProfile(inboxModel.restaurantId.toString());
UserModel? customer = await FireStoreUtils.getUserProfile(
inboxModel.customerId.toString(),
);
UserModel? restaurantUser = await FireStoreUtils.getUserProfile(
inboxModel.restaurantId.toString(),
);
ShowToastDialog.closeLoader();
Get.to(
@@ -62,15 +74,23 @@ class ProviderInboxScreen extends StatelessWidget {
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 5),
child: Container(
decoration: ShapeDecoration(color: isDark ? AppThemeData.grey900 : AppThemeData.grey50, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8))),
decoration: ShapeDecoration(
color: isDark ? AppThemeData.grey900 : AppThemeData.grey50,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
children: [
ClipRRect(
borderRadius: const BorderRadius.all(Radius.circular(10)),
borderRadius: const BorderRadius.all(
Radius.circular(10),
),
child: NetworkImageWidget(
imageUrl: inboxModel.restaurantProfileImage.toString(),
imageUrl:
inboxModel.restaurantProfileImage.toString(),
fit: BoxFit.cover,
height: Responsive.height(6, context),
width: Responsive.width(12, context),
@@ -87,13 +107,29 @@ class ProviderInboxScreen extends StatelessWidget {
child: Text(
"${inboxModel.restaurantName}",
textAlign: TextAlign.start,
style: TextStyle(fontFamily: AppThemeData.semiBold, fontSize: 16, color: isDark ? AppThemeData.grey100 : AppThemeData.grey800),
style: TextStyle(
fontFamily: AppThemeData.semiBold,
fontSize: 16,
color:
isDark
? AppThemeData.grey100
: AppThemeData.grey800,
),
),
),
Text(
Constant.timestampToDate(inboxModel.createdAt!),
Constant.timestampToDate(
inboxModel.createdAt!,
),
textAlign: TextAlign.start,
style: TextStyle(fontFamily: AppThemeData.regular, fontSize: 16, color: isDark ? AppThemeData.grey400 : AppThemeData.grey500),
style: TextStyle(
fontFamily: AppThemeData.regular,
fontSize: 16,
color:
isDark
? AppThemeData.grey400
: AppThemeData.grey500,
),
),
],
),
@@ -101,7 +137,14 @@ class ProviderInboxScreen extends StatelessWidget {
Text(
"${inboxModel.lastMessage}",
textAlign: TextAlign.start,
style: TextStyle(fontFamily: AppThemeData.medium, fontSize: 14, color: isDark ? AppThemeData.grey200 : AppThemeData.grey700),
style: TextStyle(
fontFamily: AppThemeData.medium,
fontSize: 14,
color:
isDark
? AppThemeData.grey200
: AppThemeData.grey700,
),
),
],
),
@@ -116,7 +159,10 @@ class ProviderInboxScreen extends StatelessWidget {
shrinkWrap: true,
onEmpty: Constant.showEmptyView(message: "No Conversion found".tr()),
// orderBy is compulsory to enable pagination
query: FirebaseFirestore.instance.collection('chat_provider').where("customerId", isEqualTo: FireStoreUtils.getCurrentUid()).orderBy('createdAt', descending: true),
query: FirebaseFirestore.instance
.collection('chat_provider')
.where("customerId", isEqualTo: FireStoreUtils.getCurrentUid())
.orderBy('createdAt', descending: true),
//Change types customerId
viewType: ViewType.list,
initialLoader: Constant.loader(),

View File

@@ -3,7 +3,7 @@ import 'package:customer/screen_ui/on_demand_service/on_demand_home_screen.dart'
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:get/get.dart';
import 'package:get/get.dart' hide Trans;
import '../../controllers/provider_controller.dart';
import '../../controllers/theme_controller.dart';
import '../../models/provider_serivce_model.dart';
@@ -26,58 +26,114 @@ class ProviderScreen extends StatelessWidget {
controller.isLoading.value
? Center(child: Constant.loader())
: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 50),
padding: const EdgeInsets.symmetric(
horizontal: 16,
vertical: 50,
),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Center(
child:
(controller.userModel.value?.profilePictureURL ?? "").isNotEmpty
? CircleAvatar(backgroundImage: NetworkImage(controller.userModel.value?.profilePictureURL ?? ''), radius: 50.0)
: CircleAvatar(backgroundImage: NetworkImage(Constant.placeHolderImage), radius: 50.0),
(controller.userModel.value?.profilePictureURL ??
"")
.isNotEmpty
? CircleAvatar(
backgroundImage: NetworkImage(
controller
.userModel
.value
?.profilePictureURL ??
'',
),
radius: 50.0,
)
: CircleAvatar(
backgroundImage: NetworkImage(
Constant.placeHolderImage,
),
radius: 50.0,
),
),
const SizedBox(height: 10),
Text(
controller.userModel.value?.fullName() ?? '',
style: TextStyle(color: isDark ? Colors.white : Colors.black, fontFamily: AppThemeData.regular, fontSize: 20, fontWeight: FontWeight.w900),
style: TextStyle(
color: isDark ? Colors.white : Colors.black,
fontFamily: AppThemeData.regular,
fontSize: 20,
fontWeight: FontWeight.w900,
),
),
const SizedBox(height: 5),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
SvgPicture.asset("assets/icons/ic_mail.svg", color: isDark ? Colors.white : Colors.black),
SvgPicture.asset(
"assets/icons/ic_mail.svg",
color: isDark ? Colors.white : Colors.black,
),
const SizedBox(width: 6),
Text(
controller.userModel.value?.email ?? '',
style: TextStyle(color: isDark ? Colors.white : Colors.black, fontFamily: AppThemeData.regular, fontSize: 14, fontWeight: FontWeight.w500),
style: TextStyle(
color: isDark ? Colors.white : Colors.black,
fontFamily: AppThemeData.regular,
fontSize: 14,
fontWeight: FontWeight.w500,
),
),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
SvgPicture.asset("assets/icons/ic_mobile.svg", color: isDark ? Colors.white : Colors.black),
SvgPicture.asset(
"assets/icons/ic_mobile.svg",
color: isDark ? Colors.white : Colors.black,
),
const SizedBox(width: 6),
Text(
controller.userModel.value?.phoneNumber ?? '',
style: TextStyle(color: isDark ? Colors.white : Colors.black, fontFamily: AppThemeData.regular, fontSize: 14, fontWeight: FontWeight.w500),
style: TextStyle(
color: isDark ? Colors.white : Colors.black,
fontFamily: AppThemeData.regular,
fontSize: 14,
fontWeight: FontWeight.w500,
),
),
],
),
const SizedBox(height: 10),
Container(
decoration: const BoxDecoration(color: AppThemeData.warning400, borderRadius: BorderRadius.all(Radius.circular(16))),
decoration: const BoxDecoration(
color: AppThemeData.warning400,
borderRadius: BorderRadius.all(Radius.circular(16)),
),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 5),
padding: const EdgeInsets.symmetric(
horizontal: 10,
vertical: 5,
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
const Icon(Icons.star, size: 16, color: Colors.white),
const Icon(
Icons.star,
size: 16,
color: Colors.white,
),
const SizedBox(width: 3),
Text(
_getRating(controller),
style: const TextStyle(letterSpacing: 0.5, fontSize: 12, fontFamily: AppThemeData.regular, fontWeight: FontWeight.w500, color: Colors.white),
style: const TextStyle(
letterSpacing: 0.5,
fontSize: 12,
fontFamily: AppThemeData.regular,
fontWeight: FontWeight.w500,
color: Colors.white,
),
),
],
),
@@ -93,8 +149,14 @@ class ProviderScreen extends StatelessWidget {
itemCount: controller.providerList.length,
padding: EdgeInsets.zero,
itemBuilder: (context, index) {
ProviderServiceModel data = controller.providerList[index];
return ServiceView(provider: data, isDark: isDark, controller: controller.onDemandHomeController.value);
ProviderServiceModel data =
controller.providerList[index];
return ServiceView(
provider: data,
isDark: isDark,
controller:
controller.onDemandHomeController.value,
);
},
),
),
@@ -107,8 +169,16 @@ class ProviderScreen extends StatelessWidget {
}
String _getRating(ProviderController controller) {
final reviewsCount = double.tryParse(controller.userModel.value?.reviewsCount?.toString() ?? "0") ?? 0;
final reviewsSum = double.tryParse(controller.userModel.value?.reviewsSum?.toString() ?? "0") ?? 0;
final reviewsCount =
double.tryParse(
controller.userModel.value?.reviewsCount?.toString() ?? "0",
) ??
0;
final reviewsSum =
double.tryParse(
controller.userModel.value?.reviewsSum?.toString() ?? "0",
) ??
0;
if (reviewsCount == 0) return "0";
final avg = reviewsSum / reviewsCount;

View File

@@ -1,7 +1,7 @@
import 'package:customer/screen_ui/on_demand_service/on_demand_home_screen.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:get/get.dart' hide Trans;
import '../../constant/constant.dart';
import '../../controllers/theme_controller.dart';
import '../../controllers/view_all_popular_service_controller.dart';
@@ -32,12 +32,30 @@ class ViewAllPopularServiceScreen extends StatelessWidget {
child: Container(
height: 42,
width: 42,
decoration: BoxDecoration(shape: BoxShape.circle, color: AppThemeData.grey50),
child: Center(child: Padding(padding: const EdgeInsets.only(left: 5), child: Icon(Icons.arrow_back_ios, color: AppThemeData.grey900, size: 20))),
decoration: BoxDecoration(
shape: BoxShape.circle,
color: AppThemeData.grey50,
),
child: Center(
child: Padding(
padding: const EdgeInsets.only(left: 5),
child: Icon(
Icons.arrow_back_ios,
color: AppThemeData.grey900,
size: 20,
),
),
),
),
),
const SizedBox(width: 10),
Text("All Services".tr(), style: AppThemeData.boldTextStyle(fontSize: 18, color: AppThemeData.grey900)),
Text(
"All Services".tr(),
style: AppThemeData.boldTextStyle(
fontSize: 18,
color: AppThemeData.grey900,
),
),
],
),
),
@@ -46,13 +64,29 @@ class ViewAllPopularServiceScreen extends StatelessWidget {
controller.isLoading.value
? Constant.loader()
: Padding(
padding: const EdgeInsets.symmetric(vertical: 20, horizontal: 15),
padding: const EdgeInsets.symmetric(
vertical: 20,
horizontal: 15,
),
child: Column(
children: [
TextFieldWidget(hintText: "Search Service".tr(), controller: controller.searchTextFiledController.value, onchange: (value) => controller.getFilterData(value.toString())),
TextFieldWidget(
hintText: "Search Service".tr(),
controller:
controller.searchTextFiledController.value,
onchange:
(value) =>
controller.getFilterData(value.toString()),
),
const SizedBox(height: 15),
controller.providerList.isEmpty
? Expanded(child: Center(child: Constant.showEmptyView(message: "No service Found".tr())))
? Expanded(
child: Center(
child: Constant.showEmptyView(
message: "No service Found".tr(),
),
),
)
: Expanded(
child: ListView.builder(
itemCount: controller.providerList.length,
@@ -60,8 +94,14 @@ class ViewAllPopularServiceScreen extends StatelessWidget {
padding: EdgeInsets.zero,
scrollDirection: Axis.vertical,
itemBuilder: (context, index) {
ProviderServiceModel data = controller.providerList[index];
return ServiceView(provider: data, isDark: isDark, controller: controller.onDemandHomeController.value);
ProviderServiceModel data =
controller.providerList[index];
return ServiceView(
provider: data,
isDark: isDark,
controller:
controller.onDemandHomeController.value,
);
},
),
),

View File

@@ -1,6 +1,6 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:get/get.dart' hide Trans;
import '../../constant/constant.dart';
import '../../controllers/theme_controller.dart';
import '../../controllers/view_category_service_controller.dart';
@@ -32,12 +32,30 @@ class ViewCategoryServiceListScreen extends StatelessWidget {
child: Container(
height: 42,
width: 42,
decoration: BoxDecoration(shape: BoxShape.circle, color: AppThemeData.grey50),
child: Center(child: Padding(padding: const EdgeInsets.only(left: 5), child: Icon(Icons.arrow_back_ios, color: AppThemeData.grey900, size: 20))),
decoration: BoxDecoration(
shape: BoxShape.circle,
color: AppThemeData.grey50,
),
child: Center(
child: Padding(
padding: const EdgeInsets.only(left: 5),
child: Icon(
Icons.arrow_back_ios,
color: AppThemeData.grey900,
size: 20,
),
),
),
),
),
const SizedBox(width: 10),
Text(controller.categoryTitle.value, style: AppThemeData.boldTextStyle(fontSize: 18, color: AppThemeData.grey900)),
Text(
controller.categoryTitle.value,
style: AppThemeData.boldTextStyle(
fontSize: 18,
color: AppThemeData.grey900,
),
),
],
),
),
@@ -48,14 +66,22 @@ class ViewCategoryServiceListScreen extends StatelessWidget {
: controller.providerList.isEmpty
? Constant.showEmptyView(message: "No Service Found".tr())
: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 10),
padding: const EdgeInsets.symmetric(
horizontal: 16,
vertical: 10,
),
child: ListView.builder(
itemCount: controller.providerList.length,
shrinkWrap: true,
padding: EdgeInsets.zero,
itemBuilder: (context, index) {
ProviderServiceModel providerModel = controller.providerList[index];
return ServiceView(isDark: isDark, provider: providerModel, controller: controller.onDemandHomeController.value);
ProviderServiceModel providerModel =
controller.providerList[index];
return ServiceView(
isDark: isDark,
provider: providerModel,
controller: controller.onDemandHomeController.value,
);
},
),
),

View File

@@ -10,8 +10,7 @@ import 'package:customer/widget/firebase_pagination/src/fireStore_pagination.dar
import 'package:customer/widget/firebase_pagination/src/models/view_type.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:get/get.dart' hide Trans;
import '../../../controllers/theme_controller.dart';
import '../../../service/fire_store_utils.dart';
import '../../../themes/show_toast_dialog.dart';
@@ -25,10 +24,19 @@ class WorkerInboxScreen extends StatelessWidget {
final isDark = themeController.isDark.value;
return Scaffold(
appBar: AppBar(
backgroundColor: isDark ? AppThemeData.surfaceDark : AppThemeData.surface,
backgroundColor:
isDark ? AppThemeData.surfaceDark : AppThemeData.surface,
centerTitle: false,
titleSpacing: 0,
title: Text("Worker Inbox".tr(), textAlign: TextAlign.start, style: TextStyle(fontFamily: AppThemeData.medium, fontSize: 16, color: isDark ? AppThemeData.grey50 : AppThemeData.grey900)),
title: Text(
"Worker Inbox".tr(),
textAlign: TextAlign.start,
style: TextStyle(
fontFamily: AppThemeData.medium,
fontSize: 16,
color: isDark ? AppThemeData.grey50 : AppThemeData.grey900,
),
),
),
body: FirestorePagination(
//item builder type is compulsory.
@@ -40,11 +48,17 @@ class WorkerInboxScreen extends StatelessWidget {
onTap: () async {
ShowToastDialog.showLoader("Please wait...".tr());
UserModel? customer = await FireStoreUtils.getUserProfile(inboxModel.customerId.toString());
UserModel? restaurantUser = await FireStoreUtils.getUserProfile(inboxModel.restaurantId.toString());
UserModel? customer = await FireStoreUtils.getUserProfile(
inboxModel.customerId.toString(),
);
UserModel? restaurantUser = await FireStoreUtils.getUserProfile(
inboxModel.restaurantId.toString(),
);
ShowToastDialog.closeLoader();
print("customerId: ${inboxModel.customerId}, restaurantId: ${inboxModel.restaurantId}");
print(
"customerId: ${inboxModel.customerId}, restaurantId: ${inboxModel.restaurantId}",
);
Get.to(
const ChatScreen(),
arguments: {
@@ -63,15 +77,23 @@ class WorkerInboxScreen extends StatelessWidget {
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 5),
child: Container(
decoration: ShapeDecoration(color: isDark ? AppThemeData.grey900 : AppThemeData.grey50, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8))),
decoration: ShapeDecoration(
color: isDark ? AppThemeData.grey900 : AppThemeData.grey50,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
children: [
ClipRRect(
borderRadius: const BorderRadius.all(Radius.circular(10)),
borderRadius: const BorderRadius.all(
Radius.circular(10),
),
child: NetworkImageWidget(
imageUrl: inboxModel.restaurantProfileImage.toString(),
imageUrl:
inboxModel.restaurantProfileImage.toString(),
fit: BoxFit.cover,
height: Responsive.height(6, context),
width: Responsive.width(12, context),
@@ -88,13 +110,29 @@ class WorkerInboxScreen extends StatelessWidget {
child: Text(
"${inboxModel.restaurantName}",
textAlign: TextAlign.start,
style: TextStyle(fontFamily: AppThemeData.semiBold, fontSize: 16, color: isDark ? AppThemeData.grey100 : AppThemeData.grey800),
style: TextStyle(
fontFamily: AppThemeData.semiBold,
fontSize: 16,
color:
isDark
? AppThemeData.grey100
: AppThemeData.grey800,
),
),
),
Text(
Constant.timestampToDate(inboxModel.createdAt!),
Constant.timestampToDate(
inboxModel.createdAt!,
),
textAlign: TextAlign.start,
style: TextStyle(fontFamily: AppThemeData.regular, fontSize: 16, color: isDark ? AppThemeData.grey400 : AppThemeData.grey500),
style: TextStyle(
fontFamily: AppThemeData.regular,
fontSize: 16,
color:
isDark
? AppThemeData.grey400
: AppThemeData.grey500,
),
),
],
),
@@ -102,7 +140,14 @@ class WorkerInboxScreen extends StatelessWidget {
Text(
"${inboxModel.lastMessage}",
textAlign: TextAlign.start,
style: TextStyle(fontFamily: AppThemeData.medium, fontSize: 14, color: isDark ? AppThemeData.grey200 : AppThemeData.grey700),
style: TextStyle(
fontFamily: AppThemeData.medium,
fontSize: 14,
color:
isDark
? AppThemeData.grey200
: AppThemeData.grey700,
),
),
],
),
@@ -117,7 +162,10 @@ class WorkerInboxScreen extends StatelessWidget {
shrinkWrap: true,
onEmpty: Constant.showEmptyView(message: "No Conversion found".tr()),
// orderBy is compulsory to enable pagination
query: FirebaseFirestore.instance.collection('chat_worker').where("customerId", isEqualTo: FireStoreUtils.getCurrentUid()).orderBy('createdAt', descending: true),
query: FirebaseFirestore.instance
.collection('chat_worker')
.where("customerId", isEqualTo: FireStoreUtils.getCurrentUid())
.orderBy('createdAt', descending: true),
//Change types customerId
viewType: ViewType.list,
initialLoader: Constant.loader(),