Commit 97cb09f8 authored by Sai Srinivas's avatar Sai Srinivas
Browse files

Profile and some more changes

parent b8c2cae9
......@@ -5,6 +5,7 @@ import 'package:flutter_svg/flutter_svg.dart';
import 'package:provider/provider.dart';
import '../../Notifier/HelpAndEnquiryProvider.dart';
import '../../Utility/AppColors.dart';
import '../../Utility/FullScreenImageViewer.dart';
import '../../Utility/Reusablewidgets.dart';
import 'package:image_picker/image_picker.dart';
......@@ -84,17 +85,17 @@ class _TicketChatScreenState extends State<TicketChatScreen> {
const Spacer(),
Container(
padding:
const EdgeInsets.symmetric(horizontal: 10, vertical: 6),
const EdgeInsets.symmetric(horizontal: 12, vertical: 6),
decoration: BoxDecoration(
color: status ? Colors.green.shade50 : Colors.red.shade50,
borderRadius: BorderRadius.circular(16),
color: status ? Color(0xFFD7FFD2) : Color(0xFFFFEBEB),
borderRadius: BorderRadius.circular(6),
),
child: Text(
widget.status,
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w400,
color: status ? Colors.green : Colors.red,
color: status ? Colors.black87 : Colors.red,
),
),
),
......@@ -134,6 +135,7 @@ class _TicketChatScreenState extends State<TicketChatScreen> {
),
),
),
if(widget.status != "Closed")
Container(
width: double.infinity,
padding: const EdgeInsets.all(16),
......@@ -243,17 +245,6 @@ class _TicketChatScreenState extends State<TicketChatScreen> {
),
),
const SizedBox(height: 6),
Text(
message,
style: const TextStyle(
fontSize: 14,
fontStyle: FontStyle.normal,
fontWeight: FontWeight.w400,
color: Colors.black87,
height: 1.5,
),
),
const SizedBox(height: 8),
// 🔹 Image container section
if (images.isNotEmpty)
......@@ -268,6 +259,19 @@ class _TicketChatScreenState extends State<TicketChatScreen> {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ClipRRect(
borderRadius: BorderRadius.circular(12),
child: GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (_) => FullScreenImageViewer(
imageUrl: images[index],
),
),
);
},
child: ClipRRect(
borderRadius: BorderRadius.circular(12),
child: Image.network(
images[index],
......@@ -279,12 +283,14 @@ class _TicketChatScreenState extends State<TicketChatScreen> {
width: 100,
height: 80,
color: Colors.grey.shade200,
child: const Icon(Icons.broken_image,
color: Colors.grey),
child: const Icon(Icons.broken_image, color: Colors.grey),
);
},
),
),
),
),
if (imageName.length > index)
Padding(
padding: const EdgeInsets.only(top: 4.0),
......@@ -304,6 +310,19 @@ class _TicketChatScreenState extends State<TicketChatScreen> {
),
),
Text(
message,
style: const TextStyle(
fontSize: 14,
fontStyle: FontStyle.normal,
fontWeight: FontWeight.w400,
color: Colors.black87,
height: 1.5,
),
),
const SizedBox(height: 8),
// Divider line
Container(
height: 1,
......
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:gen_rentals/Screens/BillDetailListScreen.dart';
import 'package:gen_rentals/Screens/BillScreens/BillDetailListScreen.dart';
import 'package:gen_rentals/Utility/Reusablewidgets.dart';
import 'package:provider/provider.dart';
import '../Models/SubscribeOrderDetailsResponse.dart';
......@@ -108,9 +108,14 @@ class _ProductsDetailScreenState extends State<ProductsDetailScreen> {
width: double.infinity,
child: ElevatedButton(
onPressed: () {
final order = provider.orderDetails!;
Navigator.push(
context,
MaterialPageRoute(builder: (context) => BillDetailListScreen())
MaterialPageRoute(builder: (context) => BillDetailListScreen(
sessionId: widget.sessionId,
orderId: order.orderid.toString(),
accId: widget.accId,
))
);
// Handle view bill action
FocusScope.of(context).unfocus();
......@@ -193,65 +198,58 @@ class _ProductsDetailScreenState extends State<ProductsDetailScreen> {
children: [
SizedBox(height: 1,),
// Order header (not in card)
Container(
Padding(
padding: const EdgeInsets.all(14),
child: Container(
width: double.infinity,
margin: const EdgeInsets.all(0),
padding: const EdgeInsets.all(0),
padding: EdgeInsets.symmetric(horizontal: 0, vertical: 16),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(2),
borderRadius: BorderRadius.circular(22),
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [
Color(0xDDFFFFFF),
Color(0xFFFFFFFF),
Color(0xAAFFFFFF),
Color(0x88FFFFFF),
Color(0x66FFFFFF),
Color(0x44FFFFFF),
Color(0x11FFFFFF),
Color(0xFFFFFFFF),
]
)
),
child: Padding(
padding: const EdgeInsets.all(18),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
"Order ID ",
style: TextStyle(
fontSize: 24,
fontFamily: "Poppins",
fontWeight: FontWeight.w400,
color: Colors.black87,
),
SizedBox(height: 2,),
Container(
padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 6),
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.topRight,
colors: [
Color(0xffD4EFFF),
// Color(0xFFFFFFFF),
Color(0xFFFFFFFF),
]
)
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Column(
children: [
Text(
"#${order.orderNum ?? order.orderid ?? 'N/A'}",
"Order ID #${order.orderNum ?? order.orderid ?? 'N/A'}",
style: TextStyle(
fontSize: 24,
fontSize: 14,
fontFamily: "Poppins",
fontWeight: FontWeight.w400,
color: AppColors.amountText,
),
),
],
),
const SizedBox(height: 12),
//
Text(
"Duration",
style: TextStyle(
fontSize: 12,
fontFamily: "Poppins",
fontWeight: FontWeight.w400,
color: Colors.black87,
),
),
const SizedBox(height: 2),
SizedBox(height: 4,),
Text(
"${order.fromDate} - ${order.toDate ?? 'Duration unavailable'}",
style: TextStyle(
......@@ -261,7 +259,8 @@ class _ProductsDetailScreenState extends State<ProductsDetailScreen> {
color: AppColors.subtitleText,
),
),
const SizedBox(height: 12),
],
),
Container(
padding: const EdgeInsets.symmetric(
horizontal: 10, vertical: 6),
......@@ -279,7 +278,26 @@ class _ProductsDetailScreenState extends State<ProductsDetailScreen> {
),
),
),
const SizedBox(height: 14),
],
),
),
const SizedBox(height: 12),
//
Padding(
padding: EdgeInsets.symmetric(horizontal: 14, vertical: 4),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Address",
style: TextStyle(
fontSize: 12,
fontFamily: "Poppins",
fontWeight: FontWeight.w400,
color: Colors.black87,
),
),
const SizedBox(height: 8),
//
Text(
order.accName ?? ' A/c not available',
......@@ -299,7 +317,10 @@ class _ProductsDetailScreenState extends State<ProductsDetailScreen> {
fontWeight: FontWeight.w400,
color: AppColors.subtitleText,
),
textAlign: TextAlign.center,
textAlign: TextAlign.start,
),
],
),
),
],
),
......@@ -539,14 +560,14 @@ class _ProductsDetailScreenState extends State<ProductsDetailScreen> {
switch (color) {
case "Red":
return const LinearGradient(
colors: [Color(0xFFFFE0E0), Color(0xFFFFC0C0)],
colors: [Color(0xFFFFEBEB), Color(0xFFFFEBEB)],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
);
case "Green":
default:
return const LinearGradient(
colors: [Color(0xFFE9FFDD), Color(0xFFB5FFD1)],
colors: [Color(0xFFE5FFE2), Color(0xFFE5FFE2)],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
);
......
This diff is collapsed.
......@@ -3,10 +3,10 @@ import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:gen_rentals/Screens/BillDetailListScreen.dart';
import 'package:gen_rentals/Screens/BillScreens/BillDetailListScreen.dart';
import 'package:gen_rentals/Screens/DashboardScreen.dart';
import 'package:gen_rentals/Screens/ProductsDetailScreen.dart';
import 'package:gen_rentals/Screens/TransactionsScreen.dart';
import 'package:gen_rentals/Screens/TransactionScreens/TransactionsScreen.dart';
import '../Utility/CustomSnackbar.dart';
import '../Utility/SharedpreferencesService.dart';
import 'authScreen/LoginScreen.dart';
......
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:gen_rentals/Utility/AppColors.dart';
enum BillStatusType { paid, pending }
class BillStatusToast extends StatelessWidget {
final BillStatusType type;
final String amount;
final String orderId;
final String date;
final String product;
final String productPrice;
final String total;
final VoidCallback onDownload;
final VoidCallback? onPayNow;
const BillStatusToast({
super.key,
required this.type,
required this.amount,
required this.orderId,
required this.date,
required this.product,
required this.productPrice,
required this.total,
required this.onDownload,
this.onPayNow,
});
@override
Widget build(BuildContext context) {
final isPaid = type == BillStatusType.paid;
return Dialog(
insetPadding: const EdgeInsets.all(16),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)),
child: Padding(
padding: const EdgeInsets.all(20),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
// ✅ or ❌ icon
Container(
decoration: BoxDecoration(
color: isPaid
? Colors.green.withOpacity(0.1)
: Colors.red.withOpacity(0.1),
shape: BoxShape.circle,
),
padding: const EdgeInsets.all(12),
child: Icon(
isPaid ? Icons.check_circle : Icons.access_time_filled,
color: isPaid ? Colors.green : Colors.red,
size: 40,
),
),
const SizedBox(height: 12),
Text(
isPaid ? "Payment Receipt" : "Bill Pending",
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.w600,
fontFamily: "Plus Jakarta Sans",
),
),
const SizedBox(height: 6),
Text(
"₹$amount",
style: const TextStyle(
fontSize: 28,
fontWeight: FontWeight.w700,
color: Colors.black,
),
),
const SizedBox(height: 18),
// Details
const Divider(thickness: 1),
Align(
alignment: Alignment.centerLeft,
child: Text(
"Payment Details",
style: TextStyle(
fontSize: 15,
color: Colors.grey[700],
fontWeight: FontWeight.w500,
),
),
),
const SizedBox(height: 10),
_detailRow("Order ID", "#$orderId", true),
_detailRow("Date", date, false),
if (isPaid) _detailRow("Payment Mode", "UPI", false),
const SizedBox(height: 10),
const Divider(thickness: 1),
Align(
alignment: Alignment.centerLeft,
child: Text(
"Products",
style: TextStyle(
fontSize: 15,
color: Colors.grey[700],
fontWeight: FontWeight.w500,
),
),
),
const SizedBox(height: 10),
_detailRow(product, "₹${productPrice}", false),
const SizedBox(height: 10),
const Divider(thickness: 1),
_detailRow("Total", "₹$total", true),
const SizedBox(height: 20),
// Bottom buttons
if (isPaid)
SizedBox(
width: double.infinity,
child: ElevatedButton.icon(
onPressed: onDownload,
icon: const Icon(Icons.download, color: Colors.white),
label: const Text(
"Download Receipt",
style: TextStyle(
fontSize: 16,
fontFamily: "Plus Jakarta Sans",
fontWeight: FontWeight.w600,
color: Colors.white,
),
),
style: ElevatedButton.styleFrom(
backgroundColor: AppColors.amountText,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(50),
),
padding: const EdgeInsets.symmetric(vertical: 14),
),
),
)
else
Row(
children: [
Expanded(
child: OutlinedButton.icon(
onPressed: onDownload,
icon: const Icon(Icons.download, color: Colors.black),
label: const Text(
"Download",
style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.w600,
),
),
style: OutlinedButton.styleFrom(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(50),
),
side: const BorderSide(color: Colors.black26),
padding: const EdgeInsets.symmetric(vertical: 14),
),
),
),
const SizedBox(width: 10),
Expanded(
child: ElevatedButton(
onPressed: onPayNow,
style: ElevatedButton.styleFrom(
backgroundColor: AppColors.amountText,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(50),
),
padding: const EdgeInsets.symmetric(vertical: 14),
),
child: const Text(
"Pay Now",
style: TextStyle(
fontSize: 16,
fontFamily: "Plus Jakarta Sans",
fontWeight: FontWeight.w600,
color: Colors.white,
),
),
),
),
],
),
],
),
),
);
}
Widget _detailRow(String title, String value, bool highlight) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 4),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(title,
style: const TextStyle(
fontSize: 14,
color: Colors.black54,
)),
Text(
value,
style: TextStyle(
fontSize: 14,
fontWeight: highlight ? FontWeight.w600 : FontWeight.w500,
color: highlight ? Colors.black : Colors.black87,
),
),
],
),
);
}
}
......@@ -2,9 +2,11 @@ import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:provider/provider.dart';
import '../Notifier/TransactionsProvider.dart';
import '../Utility/AppColors.dart';
import 'DashboardScreen.dart';
import '../../Notifier/TransactionsProvider.dart';
import '../../Utility/AppColors.dart';
import '../../Utility/CustomSnackbar.dart';
import '../DashboardScreen.dart';
import 'BillStatusToast.dart';
class TransactionsScreen extends StatefulWidget {
final String sessionId;
......@@ -95,12 +97,74 @@ class _TransactionsScreenState extends State<TransactionsScreen> {
color: Colors.black,
),
),
const SizedBox(height: 8),
...items.map((txn) => _buildTransactionItem(
SizedBox(height: 8),
...items.map((txn) => InkResponse(
onTap: () async {
// Step 1: Fetch receipt details
await provider.fetchPaymentReceiptDetails(
widget.sessionId,
widget.accId,
txn.paymentId.toString(),
);
// Step 2: If found, show the toast dialog
if (provider.receiptDetails != null) {
final receipt = provider.receiptDetails!;
showDialog(
context: context,
builder: (_) => BillStatusToast(
type: BillStatusType.paid,
amount: receipt.cAmount ?? "0",
orderId: receipt.billId ?? "",
date: receipt.prDate ?? "",
product: receipt.narration ?? "N/A",
productPrice: receipt.dAmount ?? "",
total: receipt.cAmount ?? "0",
/// Use provider for Download
onDownload: () async {
Navigator.pop(context); // Close toast before downloading
await provider.downloadPaymentReceipt(
context,
widget.sessionId,
receipt.id ?? "",
widget.accId,
);
},
/// Handle Pay Now
onPayNow: () {
Navigator.pop(context);
// Navigate to payment screen or trigger payment flow
// Navigator.push(
// context,
// MaterialPageRoute(
// builder: (_) => PaymentScreen(
// accId: widget.accId,
// sessionId: widget.sessionId,
// ledgerId: receipt.id ?? "",
// ),
// ),
// );
},
),
);
} else {
CustomSnackBar.showError(
context: context,
message: "Unable to fetch receipt details",
);
}
},
child: _buildTransactionItem(
type: txn.type ?? "",
title: txn.purpose ?? "-",
date: txn.date ?? "",
amount: "₹${txn.amount ?? "0.00"}",
),
)),
],
);
......@@ -418,7 +482,8 @@ class _TransactionsScreenState extends State<TransactionsScreen> {
return PaymentBottomSheetContent(
payTotal: payTotal,
payBill: payBill,
flag: false,
billFlag: false,
partFlag: true,
);
},
);
......
......@@ -207,11 +207,11 @@ class _OtpScreenState extends State<OtpScreen> {
filled: true,
fillColor: Colors.white,
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(50),
borderRadius: BorderRadius.circular(60),
borderSide: BorderSide(color: Colors.grey.withOpacity(0.5), width: 1),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(50),
borderRadius: BorderRadius.circular(60),
borderSide: const BorderSide(color: Color(0xFF008CDE), width: 2),
),
),
......
......@@ -11,7 +11,9 @@ const transactionsUrl = "${baseUrl}transactions";
const balanceUrl = "${baseUrl}balance";
const billDetailsUrl = "${baseUrl}bill_details";
const billListUrl = "${baseUrl}bill_list";
const billProductUrl = "${baseUrl}bill_product";
const downloadBillUrl = "${baseUrl}download_bill";
const paymentReceiptDetailsUrl = "${baseUrl}payment_receipt_details";
const downloadReceiptUrl = "${baseUrl}download_receipt";
/// info
const checkInOutSubmitUrl = "${baseUrl}check_in_out_submit";
......@@ -37,3 +39,4 @@ const ticketListUrl = "${baseUrl}ticket_list";
const fetchMobileUrl = "${baseUrl2}Rental_Auth/fetch_mobile_number";
const fetchOtpUrl = "${baseUrl2}Rental_Auth/login";
const dashboardUrl = "${baseUrl2}Rental_Home/dashboard";
const logoutUrl = "${baseUrl2}Rental_Auth/logout";
\ No newline at end of file
import 'dart:convert';
import 'dart:io';
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:gen_rentals/Models/CommonResponse.dart';
import 'package:gen_rentals/Models/HelpAndEnquiryModels/TicketChatDisplayResponse.dart';
import 'package:gen_rentals/Models/billListResponse.dart';
import 'package:gen_rentals/Models/BillsModels/billListResponse.dart';
import 'package:gen_rentals/Models/TransactionModels/PaymentReceiptDetailsResponse.dart';
import 'package:gen_rentals/Models/billProductResponse.dart';
import 'package:gen_rentals/Models/orderDetailsBillResponse.dart';
import 'package:gen_rentals/Models/orderDetailsMainResponse.dart';
import 'package:gen_rentals/Models/orderDetailsProductResponse.dart';
import 'package:gen_rentals/Models/SubscribeOrderDetailsResponse.dart';
import 'package:gen_rentals/Models/HelpAndEnquiryModels/ticketListResponse.dart';
import 'package:gen_rentals/Notifier/billDetailsResponse.dart';
import '../Models/BillsModels/BillDetailsResponse.dart';
import '../Models/DashboardResponse.dart';
import '../Models/RentalPaymentDetailsResponse.dart';
import '../Models/TransactionsResponse.dart';
import '../Models/TransactionModels/TransactionsResponse.dart';
import '../Models/orderDetailsBillResponse.dart';
import '../Models/rentalAccountResponse.dart';
import '../Models/rentalContactResponse.dart';
import '../Notifier/RentalContactProvider .dart';
import 'api_URLs.dart';
import 'api_post_request.dart';
import 'package:http/http.dart' as http show MultipartFile;
class ApiCalling {
......@@ -74,6 +74,31 @@ class ApiCalling {
}
}
static Future<CommonResponse?> logoutApi(
String accId,
String sessionId,
Map<String, String> deviceDetails
) async {
debugPrint("############################### Api calling ");
try {
Map<String, String> data = {
"acc_id": accId,
"session_id": sessionId,
};
final res = await post(data, fetchOtpUrl, {});
if (res != null) {
return CommonResponse.fromJson(jsonDecode(res.body));
} else {
debugPrint("Null Response");
return null;
}
} catch (e) {
debugPrint("❌ API Error: $e");
return null;
}
}
/// Fetch Rental Account Info
static Future<RentalAccountResponse?> fetchRentalAccountInfoApi(
......@@ -103,13 +128,13 @@ class ApiCalling {
/// Fetch Bill List
static Future<BillListResponse?> fetchBillListApi(
String sessionId,
String empId,
String orderId,
String accId,
) async {
try {
Map<String, String> data = {
"session_id": sessionId,
"emp_id": empId,
"order_id": orderId,
"acc_id": accId,
};
......@@ -130,13 +155,13 @@ class ApiCalling {
/// Fetch Bill Details
static Future<BillDetailsResponse?> fetchBillDetailsApi(
String sessionId,
String empId,
String accId,
String billId,
) async {
try {
Map<String, String> data = {
"session_id": sessionId,
"emp_id": empId,
"acc_id": accId,
"bill_id": billId,
};
......@@ -155,8 +180,8 @@ class ApiCalling {
}
/// Fetch Bill Product
static Future<BillProductResponse?> fetchBillProductApi(
/// Bill Download api
static Future<CommonResponse?> billDownloadApi(
String sessionId,
String empId,
String accId,
......@@ -164,51 +189,82 @@ class ApiCalling {
try {
Map<String, String> data = {
"session_id": sessionId,
"emp_id": empId,
"bill_id": empId,
"acc_id": accId,
};
final res = await post(data, downloadBillUrl, {});
if (res != null) {
return CommonResponse.fromJson(jsonDecode(res.body));
} else {
debugPrint("Null Response");
return null;
}
} catch (e) {
debugPrint("❌ API Error (billDownload): $e");
return null;
}
}
/// Payment Receipt Details api
static Future<PaymentReceiptDetailsResponse?> fetchPaymentReceiptDetailsApi(
String sessionId,
String accId,
String ledgerId,
) async {
try {
Map<String, String> data = {
"session_id": sessionId,
"acc_id": accId,
"ledger_id": ledgerId,
};
final res = await post(data, billProductUrl, {});
final res = await post(data, paymentReceiptDetailsUrl, {});
debugPrint("TR Response ${res?.body}");
if (res != null) {
return BillProductResponse.fromJson(jsonDecode(res.body));
return PaymentReceiptDetailsResponse.fromJson(jsonDecode(res.body));
} else {
debugPrint("Null Response");
return null;
}
} catch (e) {
debugPrint("❌ API Error (fetchBillProduct): $e");
debugPrint("❌ API Error (paymentReceiptDetails): $e");
return null;
}
}
/// Fetch Order Detail Bill
static Future<OrderDetailsBillResponse?> fetchOrderDetailBillApi(
/// Payment Receipt DownloadApi
static Future<CommonResponse?> paymentReceiptDownloadApi(
String sessionId,
String empId,
String orderId,
String ledgerId,
String accId,
) async {
try {
Map<String, String> data = {
"session_id": sessionId,
"emp_id": empId,
"ord_id": orderId,
"ledger_id": ledgerId,
"acc_id": accId,
};
final res = await post(data, orderDetailsBillUrl, {});
final res = await post(data, downloadReceiptUrl, {});
debugPrint("DownloadApi Response${res}");
if (res != null) {
return OrderDetailsBillResponse.fromJson(jsonDecode(res.body));
return CommonResponse.fromJson(jsonDecode(res.body));
} else {
debugPrint("Null Response");
return null;
}
} catch (e) {
debugPrint("❌ API Error (fetchOrderDetailBill): $e");
debugPrint("❌ API Error (billDownload): $e");
return null;
}
}
/// Fetch Subscribe Order Details
static Future<SubscribeOrderDetailsResponse?> fetchSubsOrderDetailApi(
String sessionId,
......@@ -371,15 +427,42 @@ class ApiCalling {
return null;
}
}
//
// static Future<addTicketResponse?> addTicketAPI(
// type, description, List<http.MultipartFile> newList) async {
// if (await CheckHeaderValidity()) {
// try {
// Map<String, String> data = {
// 'type': type.toString(),
// 'description': description.toString(),
// //ticket_image
// };
// // print("Add ticket ${data}");
// final header = await HeaderValues();
// final res = await PostMultipleImagesNew(
// data, addTicketsUrl, header, newList);
// if (res != null) {
// return addTicketResponse.fromJson(jsonDecode(res));
// } else {
// return null;
// }
// } catch (e) {
// debugPrint('hello bev=bug $e ');
// return null;
// }
// } else {
// return addTicketResponse(error: "401");
// }
// }
/// Send Message Chat Api
/// Send Message Chat Api
static Future<CommonResponse?> addMessageApi(
String sessionId,
String accId,
String ticketId,
String msgText,
List<File>? images,
List<http.MultipartFile>? images,
) async {
try {
Map<String, String> body = {
......@@ -394,13 +477,15 @@ class ApiCalling {
// Add any other headers you need (auth tokens, etc.)
};
final res = await postMessageWithImages(
debugPrint("Data to addTicketApi${body}");
final res = await PostMultipleImagesNew(
body,
addMessageUrl, // Your API endpoint
headers,
images ?? [], // Pass empty list if no images
);
debugPrint("Response from addMessageApi ${res}");
if (res != null) {
return CommonResponse.fromJson(jsonDecode(res));
} else {
......@@ -420,6 +505,7 @@ class ApiCalling {
String type,
String description,
String orderId,
String otherReason,
List<File>? images,
) async {
......@@ -430,7 +516,7 @@ class ApiCalling {
"type": type,
"des": description,
"order_id": orderId,
"other_reason": otherReason,
};
Map<String, String> headers = {
......
......@@ -181,20 +181,50 @@ Future<String?> postImageNew(
//hotel_image
//other_image
Future<String?> PostMultipleImagesNew(
// Future<String?> PostMultipleImagesNew(
// Map<String, String> body,
// String urlLink,
// Map<String, String> headers,
// List<http.MultipartFile> newList,
// List<http.MultipartFile> newList1,
// List<http.MultipartFile> newList2,
// ) async {
// try {
// var req = http.MultipartRequest('POST', Uri.parse(urlLink));
// req.headers.addAll(headers);
// req.files.addAll(newList);
// req.files.addAll(newList1);
// req.files.addAll(newList2);
// req.fields.addAll(body);
//
// var res = await req.send();
// final resBody = await res.stream.bytesToString();
//
// if (res.statusCode >= 200 && res.statusCode < 300) {
// print("**** $resBody .... $res");
// return resBody;
// } else {
// print("error: ${res.reasonPhrase}");
// return null;
// }
// } catch (e) {
// debugPrint(e.toString());
// return null;
// }
// }
Future<String?> PostMultipleImagesNew2(
Map<String, String> body,
String urlLink,
Map<String, String> headers,
List<http.MultipartFile> newList,
List<http.MultipartFile> newList1,
List<http.MultipartFile> newList2,
) async {
try {
var req = http.MultipartRequest('POST', Uri.parse(urlLink));
req.headers.addAll(headers);
req.files.addAll(newList);
req.files.addAll(newList1);
req.files.addAll(newList2);
req.fields.addAll(body);
var res = await req.send();
......@@ -213,18 +243,16 @@ Future<String?> PostMultipleImagesNew(
}
}
Future<String?> PostMultipleImagesNew2(
Future<String?> PostMultipleImages(
Map<String, String> body,
String urlLink,
Map<String, String> headers,
List<http.MultipartFile> newList,
List<http.MultipartFile> newList1,
) async {
try {
var req = http.MultipartRequest('POST', Uri.parse(urlLink));
req.headers.addAll(headers);
req.files.addAll(newList);
req.files.addAll(newList1);
req.fields.addAll(body);
var res = await req.send();
......@@ -242,13 +270,11 @@ Future<String?> PostMultipleImagesNew2(
return null;
}
}
Future<String?> PostMultipleImages(
Future<String?> PostMultipleImagesNew(
Map<String, String> body,
String urlLink,
Map<String, String> headers,
List<http.MultipartFile> newList,
) async {
List<http.MultipartFile> newList) async {
try {
var req = http.MultipartRequest('POST', Uri.parse(urlLink));
req.headers.addAll(headers);
......@@ -271,6 +297,7 @@ Future<String?> PostMultipleImages(
}
}
/// Send message with multiple images
Future<String?> postMessageWithImages(
Map<String, String> body,
......
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:photo_view/photo_view.dart';
class FullScreenImageViewer extends StatefulWidget {
final String imageUrl;
const FullScreenImageViewer({super.key, required this.imageUrl});
@override
State<FullScreenImageViewer> createState() => _FullScreenImageViewerState();
}
class _FullScreenImageViewerState extends State<FullScreenImageViewer> {
PhotoViewController controller = PhotoViewController();
PhotoViewScaleStateController scaleStateController = PhotoViewScaleStateController();
bool _showControls = true;
@override
void initState() {
super.initState();
// Auto-hide controls after 3 seconds
Future.delayed(const Duration(seconds: 3), () {
if (mounted) {
setState(() {
_showControls = false;
});
}
});
}
void _toggleControls() {
setState(() {
_showControls = !_showControls;
});
}
void _resetImage() {
controller.reset();
scaleStateController.reset();
}
void _rotateImage() {
final double currentRotation = controller.rotation;
controller.rotation = currentRotation + 90.0;
}
@override
Widget build(BuildContext context) {
return SafeArea(
top: false,
child: Scaffold(
backgroundColor: Color(0xFFFFFFFF),
body: Stack(
children: [
// Main Photo View
GestureDetector(
onTap: _toggleControls,
child: PhotoView(
imageProvider: NetworkImage(widget.imageUrl),
controller: controller,
scaleStateController: scaleStateController,
backgroundDecoration: const BoxDecoration(
color: Color(0xFF444444),
),
minScale: PhotoViewComputedScale.contained * 0.8,
maxScale: PhotoViewComputedScale.covered * 4,
initialScale: PhotoViewComputedScale.contained,
basePosition: Alignment.center,
filterQuality: FilterQuality.high,
enableRotation: true,
gestureDetectorBehavior: HitTestBehavior.opaque,
loadingBuilder: (context, event) => Center(
child: Container(
width: 40,
height: 40,
child: const CircularProgressIndicator(
color: Colors.white,
strokeWidth: 2,
),
),
),
errorBuilder: (context, error, stackTrace) => Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Icon(
Icons.error_outline,
color: Colors.white,
size: 50,
),
const SizedBox(height: 16),
Text(
'Failed to load image',
style: TextStyle(
color: Colors.white.withOpacity(0.8),
fontSize: 16,
),
),
],
),
),
),
),
// Controls Overlay
if (_showControls) ...[
// Top Bar
Positioned(
top: MediaQuery.of(context).padding.top,
left: 0,
right: 0,
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [
Colors.black.withOpacity(0.7),
Colors.black.withOpacity(0.3),
Colors.transparent,
],
),
),
child: Row(
children: [
// Close Button
GestureDetector(
onTap: () => Navigator.pop(context),
child: Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: Colors.black.withOpacity(0.5),
shape: BoxShape.circle,
),
child: const Icon(
Icons.close,
color: Colors.white,
size: 24,
),
),
),
const Spacer(),
// Reset Button
GestureDetector(
onTap: _resetImage,
child: Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: Colors.black.withOpacity(0.5),
shape: BoxShape.circle,
),
child: const Icon(
Icons.refresh,
color: Colors.white,
size: 24,
),
),
),
const SizedBox(width: 12),
// Rotate Button
GestureDetector(
onTap: _rotateImage,
child: Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: Colors.black.withOpacity(0.5),
shape: BoxShape.circle,
),
child: const Icon(
Icons.rotate_90_degrees_ccw,
color: Colors.white,
size: 24,
),
),
),
],
),
),
),
// Bottom Info Bar
Positioned(
bottom: 0,
left: 0,
right: 0,
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 20),
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.bottomCenter,
end: Alignment.topCenter,
colors: [
Colors.black.withOpacity(0.7),
Colors.black.withOpacity(0.3),
Colors.transparent,
],
),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Zoom Instructions
Row(
children: [
_buildInstructionIcon(Icons.touch_app, "Double tap to zoom"),
const SizedBox(width: 16),
_buildInstructionIcon(Icons.pan_tool, "Pan to move"),
const SizedBox(width: 16),
_buildInstructionIcon(Icons.rotate_right, "Pinch to rotate"),
],
),
const SizedBox(height: 12),
// Image Info
Text(
"Image Preview",
style: TextStyle(
color: Colors.white.withOpacity(0.9),
fontSize: 14,
fontWeight: FontWeight.w500,
),
),
],
),
),
),
],
// Double Tap Zoom Hint (appears briefly)
Positioned(
bottom: MediaQuery.of(context).padding.bottom + 100,
left: 0,
right: 0,
child: AnimatedOpacity(
opacity: _showControls ? 1.0 : 0.0,
duration: const Duration(milliseconds: 300),
child: const Center(
child: Text(
"Double tap to zoom",
style: TextStyle(
color: Colors.white,
fontSize: 14,
fontWeight: FontWeight.w400,
),
),
),
),
),
],
),
// Bottom Navigation Bar with additional controls
bottomNavigationBar: _showControls
? Container(
height: 60,
decoration: BoxDecoration(
color: Colors.black.withOpacity(0.7),
borderRadius: const BorderRadius.only(
topLeft: Radius.circular(12),
topRight: Radius.circular(12),
),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
// Zoom In
IconButton(
onPressed: () {
final double currentScale = controller.scale ?? 1.0;
controller.scale = currentScale * 1.5;
},
icon: const Icon(Icons.zoom_in, color: Colors.white),
tooltip: "Zoom In",
),
// Zoom Out
IconButton(
onPressed: () {
final double currentScale = controller.scale ?? 1.0;
controller.scale = currentScale / 1.5;
},
icon: const Icon(Icons.zoom_out, color: Colors.white),
tooltip: "Zoom Out",
),
// Reset
IconButton(
onPressed: _resetImage,
icon: const Icon(Icons.fit_screen, color: Colors.white),
tooltip: "Reset",
),
// Rotate
IconButton(
onPressed: _rotateImage,
icon: const Icon(Icons.rotate_90_degrees_ccw, color: Colors.white),
tooltip: "Rotate 90°",
),
],
),
)
: null,
),
);
}
Widget _buildInstructionIcon(IconData icon, String text) {
return Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(icon, color: Colors.white.withOpacity(0.7), size: 16),
const SizedBox(width: 4),
Text(
text,
style: TextStyle(
color: Colors.white.withOpacity(0.7),
fontSize: 12,
),
),
],
);
}
@override
void dispose() {
controller.dispose();
scaleStateController.dispose();
super.dispose();
}
}
\ No newline at end of file
import 'package:flutter/material.dart';
import 'package:gen_rentals/Notifier/BillProvider.dart';
import 'package:gen_rentals/Notifier/DashboardProvider.dart';
import 'package:gen_rentals/Notifier/HelpAndEnquiryProvider.dart';
import 'package:gen_rentals/Notifier/TransactionsProvider.dart';
......@@ -34,6 +35,7 @@ class MyApp extends StatelessWidget {
ChangeNotifierProvider(create: (_) => SubscribeOrderDetailsProvider()),
ChangeNotifierProvider(create: (_) => TransactionsProvider()),
ChangeNotifierProvider(create: (_) => HelpAndEnquiryProvider()),
ChangeNotifierProvider(create: (_) => BillProvider()),
],
child: Consumer<ThemeProvider>(
builder: (context, themeProvider, child) {
......@@ -41,24 +43,7 @@ class MyApp extends StatelessWidget {
debugShowCheckedModeBanner: false,
title: 'Gen Rentals',
theme: ThemeData(
brightness: themeProvider.isDark ? Brightness.dark : Brightness.light,
fontFamily: 'Poppins',
textTheme: const TextTheme(
bodyMedium: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w400,
height: 1.5,
letterSpacing: -0.12,
),
titleMedium: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
),
labelLarge: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w700,
),
),
fontFamily: 'PoppinsRegular',
),
home: const SplashScreen(),
);
......
......@@ -157,10 +157,10 @@ packages:
dependency: transitive
description:
name: fake_async
sha256: "6a95e56b2449df2273fd8c45a662d6947ce1ebb7aafe80e550a3f68297f3cacc"
sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44"
url: "https://pub.dev"
source: hosted
version: "1.3.2"
version: "1.3.3"
ffi:
dependency: transitive
description:
......@@ -412,26 +412,26 @@ packages:
dependency: transitive
description:
name: leak_tracker
sha256: c35baad643ba394b40aac41080300150a4f08fd0fd6a10378f8f7c6bc161acec
sha256: "33e2e26bdd85a0112ec15400c8cbffea70d0f9c3407491f672a2fad47915e2de"
url: "https://pub.dev"
source: hosted
version: "10.0.8"
version: "11.0.2"
leak_tracker_flutter_testing:
dependency: transitive
description:
name: leak_tracker_flutter_testing
sha256: f8b613e7e6a13ec79cfdc0e97638fddb3ab848452eff057653abd3edba760573
sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1"
url: "https://pub.dev"
source: hosted
version: "3.0.9"
version: "3.0.10"
leak_tracker_testing:
dependency: transitive
description:
name: leak_tracker_testing
sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3"
sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1"
url: "https://pub.dev"
source: hosted
version: "3.0.1"
version: "3.0.2"
lints:
dependency: transitive
description:
......@@ -504,6 +504,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.1.0"
open_filex:
dependency: "direct dev"
description:
name: open_filex
sha256: "9976da61b6a72302cf3b1efbce259200cd40232643a467aac7370addf94d6900"
url: "https://pub.dev"
source: hosted
version: "4.7.0"
package_info_plus:
dependency: "direct dev"
description:
......@@ -537,7 +545,7 @@ packages:
source: hosted
version: "1.1.0"
path_provider:
dependency: transitive
dependency: "direct dev"
description:
name: path_provider
sha256: "50c5dd5b6e1aaf6fb3a78b33f6aa3afca52bf903a8a5298f53101fdaee55bbcd"
......@@ -640,6 +648,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "6.1.0"
photo_view:
dependency: "direct dev"
description:
name: photo_view
sha256: "8036802a00bae2a78fc197af8a158e3e2f7b500561ed23b4c458107685e645bb"
url: "https://pub.dev"
source: hosted
version: "0.14.0"
platform:
dependency: transitive
description:
......@@ -841,10 +857,10 @@ packages:
dependency: transitive
description:
name: test_api
sha256: fb31f383e2ee25fbbfe06b40fe21e1e458d14080e3c67e7ba0acfde4df4e0bbd
sha256: "522f00f556e73044315fa4585ec3270f1808a4b186c936e612cab0b565ff1e00"
url: "https://pub.dev"
source: hosted
version: "0.7.4"
version: "0.7.6"
typed_data:
dependency: transitive
description:
......@@ -889,10 +905,10 @@ packages:
dependency: transitive
description:
name: vector_math
sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803"
sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b
url: "https://pub.dev"
source: hosted
version: "2.1.4"
version: "2.2.0"
vm_service:
dependency: transitive
description:
......@@ -942,5 +958,5 @@ packages:
source: hosted
version: "6.5.0"
sdks:
dart: ">=3.7.2 <4.0.0"
dart: ">=3.8.0-0 <4.0.0"
flutter: ">=3.29.0"
......@@ -60,6 +60,9 @@ dev_dependencies:
firebase_core: ^4.1.1
device_info_plus: ^10.0.0
image_picker: ^1.0.4
path_provider: ^2.1.4
open_filex: ^4.4.0
photo_view: ^0.14.0
#flutter_local_notifications: ^17.2.0
......@@ -94,18 +97,24 @@ flutter:
# list giving the asset and other descriptors for the font. For
# example:
fonts:
- family: Poppins
# - family: Trajan Pro
- family: PoppinsRegular
fonts:
- asset: assets/fonts/Poppins/Poppins-Regular.ttf
style: normal
- family: PoppinsMedium
fonts:
- asset: assets/fonts/Poppins/Poppins-Medium.ttf
weight: 500
style: normal
- family: PoppinsBold
fonts:
- asset: assets/fonts/Poppins/Poppins-Bold.ttf
weight: 700
# - family: Trajan Pro
# fonts:
# - asset: fonts/TrajanPro.ttf
# - asset: fonts/TrajanPro_Bold.ttf
# weight: 700
style: normal
#
# For details regarding fonts from package dependencies,
# see https://flutter.dev/to/font-from-package
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment