Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Menu
Open sidebar
Sai Srinivas
gen_rentals
Commits
df116895
Commit
df116895
authored
Oct 18, 2025
by
Sai Srinivas
Browse files
New Screen and api
parent
9462b0ba
Changes
21
Hide whitespace changes
Inline
Side-by-side
android/app/src/main/AndroidManifest.xml
View file @
df116895
...
@@ -2,7 +2,8 @@
...
@@ -2,7 +2,8 @@
<application
<application
android:label=
"Gen Rentals"
android:label=
"Gen Rentals"
android:name=
"${applicationName}"
android:name=
"${applicationName}"
android:icon=
"@mipmap/ic_launcher"
>
android:icon=
"@mipmap/ic_launcher"
android:enableOnBackInvokedCallback=
"true"
>
<!-- Fixed: Removed extra quote and corrected placement -->
<activity
<activity
android:name=
".MainActivity"
android:name=
".MainActivity"
android:exported=
"true"
android:exported=
"true"
...
@@ -17,9 +18,9 @@
...
@@ -17,9 +18,9 @@
while the Flutter UI initializes. After that, this theme continues
while the Flutter UI initializes. After that, this theme continues
to determine the Window background behind the Flutter UI. -->
to determine the Window background behind the Flutter UI. -->
<meta-data
<meta-data
android:name=
"io.flutter.embedding.android.NormalTheme"
android:name=
"io.flutter.embedding.android.NormalTheme"
android:resource=
"@style/NormalTheme"
android:resource=
"@style/NormalTheme"
/>
/>
<intent-filter>
<intent-filter>
<action
android:name=
"android.intent.action.MAIN"
/>
<action
android:name=
"android.intent.action.MAIN"
/>
<category
android:name=
"android.intent.category.LAUNCHER"
/>
<category
android:name=
"android.intent.category.LAUNCHER"
/>
...
@@ -42,4 +43,4 @@
...
@@ -42,4 +43,4 @@
<data
android:mimeType=
"text/plain"
/>
<data
android:mimeType=
"text/plain"
/>
</intent>
</intent>
</queries>
</queries>
</manifest>
</manifest>
\ No newline at end of file
android/gradle.properties
View file @
df116895
org.gradle.jvmargs
=
-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError
org.gradle.jvmargs
=
-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError
android.useAndroidX
=
true
android.useAndroidX
=
true
android.enableJetifier
=
true
android.enableJetifier
=
true
flutter.minSdkVersion
=
23
assets/svg/help_ic.svg
0 → 100644
View file @
df116895
<svg
width=
"38"
height=
"38"
viewBox=
"0 0 38 38"
fill=
"none"
xmlns=
"http://www.w3.org/2000/svg"
>
<path
d=
"M18.9809 37.9618C29.4637 37.9618 37.9618 29.4637 37.9618 18.9809C37.9618 8.49803 29.4637 0 18.9809 0C8.49803 0 0 8.49803 0 18.9809C0 29.4637 8.49803 37.9618 18.9809 37.9618Z"
fill=
"url(#paint0_linear_383_1201)"
/>
<path
d=
"M18.8177 32.4369C17.2122 32.4369 15.8743 31.1325 15.8743 29.5271C15.8743 27.9216 17.2122 26.6172 18.8177 26.6172C20.4231 26.6172 21.761 27.9216 21.761 29.5271C21.761 31.1325 20.4231 32.4369 18.8177 32.4369Z"
fill=
"white"
/>
<path
d=
"M20.7245 22.1017V24.6105H16.0086L15.2058 18.6567C19.186 18.6567 21.9954 17.7872 21.9954 15.2451C21.9954 13.6061 20.7915 12.3018 18.7178 12.3018C17.38 12.3018 15.6404 12.9037 14.102 13.9072L13.4663 9.15762C14.8712 8.18757 17.0789 7.48535 19.1525 7.48535C23.8349 7.48535 27.347 10.6628 27.347 14.8438C27.347 18.8908 24.0024 21.6671 20.7245 22.1017Z"
fill=
"white"
/>
<defs>
<linearGradient
id=
"paint0_linear_383_1201"
x1=
"25.4745"
y1=
"36.8219"
x2=
"12.4873"
y2=
"1.13985"
gradientUnits=
"userSpaceOnUse"
>
<stop
offset=
"0.2486"
stop-color=
"#948BF7"
/>
<stop
offset=
"0.9279"
stop-color=
"#C7CBFF"
/>
</linearGradient>
</defs>
</svg>
lib/Models/DashboardResponse.dart
View file @
df116895
class
DashboardResponse
{
class
DashboardResponse
{
String
?
error
;
String
?
error
;
String
?
mobNum
;
String
?
raname
;
String
?
raname
;
Str
in
g
?
balanceAmount
;
in
t
?
balanceAmount
;
String
?
message
;
String
?
message
;
List
<
Products
>?
product
s
;
List
<
Orders
>?
order
s
;
DashboardResponse
(
DashboardResponse
(
{
this
.
error
,
{
this
.
error
,
this
.
mobNum
,
this
.
raname
,
this
.
raname
,
this
.
balanceAmount
,
this
.
balanceAmount
,
this
.
message
,
this
.
message
,
this
.
product
s
});
this
.
order
s
});
DashboardResponse
.
fromJson
(
Map
<
String
,
dynamic
>
json
)
{
DashboardResponse
.
fromJson
(
Map
<
String
,
dynamic
>
json
)
{
error
=
json
[
'error'
];
error
=
json
[
'error'
];
mobNum
=
json
[
'mob_num'
];
raname
=
json
[
'raname'
];
raname
=
json
[
'raname'
];
balanceAmount
=
json
[
'balance_amount'
];
balanceAmount
=
json
[
'balance_amount'
];
message
=
json
[
'message'
];
message
=
json
[
'message'
];
if
(
json
[
'
product
s'
]
!=
null
)
{
if
(
json
[
'
order
s'
]
!=
null
)
{
products
=
<
Product
s
>[];
orders
=
<
Order
s
>[];
json
[
'
product
s'
].
forEach
((
v
)
{
json
[
'
order
s'
].
forEach
((
v
)
{
product
s
!.
add
(
new
Product
s
.
fromJson
(
v
));
order
s
!.
add
(
new
Order
s
.
fromJson
(
v
));
});
});
}
}
}
}
...
@@ -28,65 +31,62 @@ class DashboardResponse {
...
@@ -28,65 +31,62 @@ class DashboardResponse {
Map
<
String
,
dynamic
>
toJson
()
{
Map
<
String
,
dynamic
>
toJson
()
{
final
Map
<
String
,
dynamic
>
data
=
new
Map
<
String
,
dynamic
>();
final
Map
<
String
,
dynamic
>
data
=
new
Map
<
String
,
dynamic
>();
data
[
'error'
]
=
this
.
error
;
data
[
'error'
]
=
this
.
error
;
data
[
'mob_num'
]
=
this
.
mobNum
;
data
[
'raname'
]
=
this
.
raname
;
data
[
'raname'
]
=
this
.
raname
;
data
[
'balance_amount'
]
=
this
.
balanceAmount
;
data
[
'balance_amount'
]
=
this
.
balanceAmount
;
data
[
'message'
]
=
this
.
message
;
data
[
'message'
]
=
this
.
message
;
if
(
this
.
product
s
!=
null
)
{
if
(
this
.
order
s
!=
null
)
{
data
[
'
product
s'
]
=
this
.
product
s
!.
map
((
v
)
=>
v
.
toJson
()).
toList
();
data
[
'
order
s'
]
=
this
.
order
s
!.
map
((
v
)
=>
v
.
toJson
()).
toList
();
}
}
return
data
;
return
data
;
}
}
}
}
class
Product
s
{
class
Order
s
{
String
?
orderid
;
String
?
orderid
;
String
?
productName
;
String
?
orderNum
;
String
?
productImage
;
String
?
productImage
;
String
?
plan
;
String
?
rentedDate
;
String
?
rentedDate
;
String
?
expiringInColor
;
String
?
expiringInColor
;
String
?
expiringText
;
String
?
expiringText
;
String
?
address
;
bool
?
hasPendingPayment
;
bool
?
hasPendingPayment
;
String
?
pendingPaymentText
;
String
?
pendingPaymentText
;
List
<
String
>?
products
;
Product
s
(
Order
s
(
{
this
.
orderid
,
{
this
.
orderid
,
this
.
productName
,
this
.
orderNum
,
this
.
productImage
,
this
.
productImage
,
this
.
plan
,
this
.
rentedDate
,
this
.
rentedDate
,
this
.
expiringInColor
,
this
.
expiringInColor
,
this
.
expiringText
,
this
.
expiringText
,
this
.
address
,
this
.
hasPendingPayment
,
this
.
hasPendingPayment
,
this
.
pendingPaymentText
});
this
.
pendingPaymentText
,
this
.
products
});
Product
s
.
fromJson
(
Map
<
String
,
dynamic
>
json
)
{
Order
s
.
fromJson
(
Map
<
String
,
dynamic
>
json
)
{
orderid
=
json
[
'orderid'
];
orderid
=
json
[
'orderid'
];
productName
=
json
[
'productName
'
];
orderNum
=
json
[
'order_num
'
];
productImage
=
json
[
'productImage'
];
productImage
=
json
[
'productImage'
];
plan
=
json
[
'plan'
];
rentedDate
=
json
[
'rentedDate'
];
rentedDate
=
json
[
'rentedDate'
];
expiringInColor
=
json
[
'ExpiringInColor'
];
expiringInColor
=
json
[
'ExpiringInColor'
];
expiringText
=
json
[
'expiringText'
];
expiringText
=
json
[
'expiringText'
];
address
=
json
[
'address'
];
hasPendingPayment
=
json
[
'hasPendingPayment'
];
hasPendingPayment
=
json
[
'hasPendingPayment'
];
pendingPaymentText
=
json
[
'pendingPaymentText'
];
pendingPaymentText
=
json
[
'pendingPaymentText'
];
products
=
json
[
'products'
].
cast
<
String
>();
}
}
Map
<
String
,
dynamic
>
toJson
()
{
Map
<
String
,
dynamic
>
toJson
()
{
final
Map
<
String
,
dynamic
>
data
=
new
Map
<
String
,
dynamic
>();
final
Map
<
String
,
dynamic
>
data
=
new
Map
<
String
,
dynamic
>();
data
[
'orderid'
]
=
this
.
orderid
;
data
[
'orderid'
]
=
this
.
orderid
;
data
[
'
productName'
]
=
this
.
productName
;
data
[
'
order_num'
]
=
this
.
orderNum
;
data
[
'productImage'
]
=
this
.
productImage
;
data
[
'productImage'
]
=
this
.
productImage
;
data
[
'plan'
]
=
this
.
plan
;
data
[
'rentedDate'
]
=
this
.
rentedDate
;
data
[
'rentedDate'
]
=
this
.
rentedDate
;
data
[
'ExpiringInColor'
]
=
this
.
expiringInColor
;
data
[
'ExpiringInColor'
]
=
this
.
expiringInColor
;
data
[
'expiringText'
]
=
this
.
expiringText
;
data
[
'expiringText'
]
=
this
.
expiringText
;
data
[
'address'
]
=
this
.
address
;
data
[
'hasPendingPayment'
]
=
this
.
hasPendingPayment
;
data
[
'hasPendingPayment'
]
=
this
.
hasPendingPayment
;
data
[
'pendingPaymentText'
]
=
this
.
pendingPaymentText
;
data
[
'pendingPaymentText'
]
=
this
.
pendingPaymentText
;
data
[
'products'
]
=
this
.
products
;
return
data
;
return
data
;
}
}
}
}
lib/Models/SubscribeOrderDetailsResponse.dart
0 → 100644
View file @
df116895
class
SubscribeOrderDetailsResponse
{
String
?
orderid
;
String
?
orderNum
;
String
?
rentedDate
;
String
?
expiringInColor
;
String
?
expiringText
;
List
<
Products
>?
products
;
String
?
error
;
String
?
message
;
SubscribeOrderDetailsResponse
(
{
this
.
orderid
,
this
.
orderNum
,
this
.
rentedDate
,
this
.
expiringInColor
,
this
.
expiringText
,
this
.
products
,
this
.
error
,
this
.
message
});
SubscribeOrderDetailsResponse
.
fromJson
(
Map
<
String
,
dynamic
>
json
)
{
orderid
=
json
[
'orderid'
];
orderNum
=
json
[
'order_num'
];
rentedDate
=
json
[
'rentedDate'
];
expiringInColor
=
json
[
'ExpiringInColor'
];
expiringText
=
json
[
'expiringText'
];
if
(
json
[
'products'
]
!=
null
)
{
products
=
<
Products
>[];
json
[
'products'
].
forEach
((
v
)
{
products
!.
add
(
new
Products
.
fromJson
(
v
));
});
}
error
=
json
[
'error'
];
message
=
json
[
'message'
];
}
Map
<
String
,
dynamic
>
toJson
()
{
final
Map
<
String
,
dynamic
>
data
=
new
Map
<
String
,
dynamic
>();
data
[
'orderid'
]
=
this
.
orderid
;
data
[
'order_num'
]
=
this
.
orderNum
;
data
[
'rentedDate'
]
=
this
.
rentedDate
;
data
[
'ExpiringInColor'
]
=
this
.
expiringInColor
;
data
[
'expiringText'
]
=
this
.
expiringText
;
if
(
this
.
products
!=
null
)
{
data
[
'products'
]
=
this
.
products
!.
map
((
v
)
=>
v
.
toJson
()).
toList
();
}
data
[
'error'
]
=
this
.
error
;
data
[
'message'
]
=
this
.
message
;
return
data
;
}
}
class
Products
{
String
?
id
;
String
?
idName
;
String
?
prodName
;
String
?
totalPrice
;
String
?
per
;
String
?
dispatchDate
;
String
?
receivedDate
;
Products
(
{
this
.
id
,
this
.
idName
,
this
.
prodName
,
this
.
totalPrice
,
this
.
per
,
this
.
dispatchDate
,
this
.
receivedDate
});
Products
.
fromJson
(
Map
<
String
,
dynamic
>
json
)
{
id
=
json
[
'id'
];
idName
=
json
[
'id_name'
];
prodName
=
json
[
'prod_name'
];
totalPrice
=
json
[
'total_price'
];
per
=
json
[
'per'
];
dispatchDate
=
json
[
'dispatch_date'
];
receivedDate
=
json
[
'received_date'
];
}
Map
<
String
,
dynamic
>
toJson
()
{
final
Map
<
String
,
dynamic
>
data
=
new
Map
<
String
,
dynamic
>();
data
[
'id'
]
=
this
.
id
;
data
[
'id_name'
]
=
this
.
idName
;
data
[
'prod_name'
]
=
this
.
prodName
;
data
[
'total_price'
]
=
this
.
totalPrice
;
data
[
'per'
]
=
this
.
per
;
data
[
'dispatch_date'
]
=
this
.
dispatchDate
;
data
[
'received_date'
]
=
this
.
receivedDate
;
return
data
;
}
}
lib/Models/TransactionsResponse.dart
0 → 100644
View file @
df116895
class
TransactionsResponse
{
int
?
balanceAmount
;
String
?
creditAmount
;
String
?
debitAmount
;
Map
<
String
,
List
<
TransactionItem
>>?
transactions
;
String
?
error
;
String
?
message
;
TransactionsResponse
({
this
.
balanceAmount
,
this
.
creditAmount
,
this
.
debitAmount
,
this
.
transactions
,
this
.
error
,
this
.
message
,
});
TransactionsResponse
.
fromJson
(
Map
<
String
,
dynamic
>
json
)
{
balanceAmount
=
json
[
'balance_amount'
];
creditAmount
=
json
[
'credit_amount'
];
debitAmount
=
json
[
'debit_amount'
];
error
=
json
[
'error'
];
message
=
json
[
'message'
];
if
(
json
[
'transactions'
]
!=
null
)
{
transactions
=
{};
json
[
'transactions'
].
forEach
((
key
,
value
)
{
transactions
![
key
]
=
(
value
as
List
)
.
map
((
v
)
=>
TransactionItem
.
fromJson
(
v
))
.
toList
();
});
}
}
Map
<
String
,
dynamic
>
toJson
()
{
final
Map
<
String
,
dynamic
>
data
=
{};
data
[
'balance_amount'
]
=
balanceAmount
;
data
[
'credit_amount'
]
=
creditAmount
;
data
[
'debit_amount'
]
=
debitAmount
;
data
[
'error'
]
=
error
;
data
[
'message'
]
=
message
;
if
(
transactions
!=
null
)
{
data
[
'transactions'
]
=
transactions
!.
map
((
key
,
value
)
=>
MapEntry
(
key
,
value
.
map
((
v
)
=>
v
.
toJson
()).
toList
()));
}
return
data
;
}
}
class
TransactionItem
{
String
?
paymentId
;
String
?
amount
;
String
?
type
;
String
?
purpose
;
String
?
date
;
TransactionItem
({
this
.
paymentId
,
this
.
amount
,
this
.
type
,
this
.
purpose
,
this
.
date
,
});
TransactionItem
.
fromJson
(
Map
<
String
,
dynamic
>
json
)
{
paymentId
=
json
[
'payment_id'
];
amount
=
json
[
'amount'
];
type
=
json
[
'type'
];
purpose
=
json
[
'purpose'
];
date
=
json
[
'date'
];
}
Map
<
String
,
dynamic
>
toJson
()
{
final
Map
<
String
,
dynamic
>
data
=
{};
data
[
'payment_id'
]
=
paymentId
;
data
[
'amount'
]
=
amount
;
data
[
'type'
]
=
type
;
data
[
'purpose'
]
=
purpose
;
data
[
'date'
]
=
date
;
return
data
;
}
}
lib/Models/orderListResponse.dart
deleted
100644 → 0
View file @
9462b0ba
class
OrderListResponse
{
List
<
Order
>?
order
;
int
?
error
;
String
?
message
;
OrderListResponse
({
this
.
order
,
this
.
error
,
this
.
message
});
OrderListResponse
.
fromJson
(
Map
<
String
,
dynamic
>
json
)
{
if
(
json
[
'order'
]
!=
null
)
{
order
=
<
Order
>[];
json
[
'order'
].
forEach
((
v
)
{
order
!.
add
(
new
Order
.
fromJson
(
v
));
});
}
error
=
json
[
'error'
];
message
=
json
[
'message'
];
}
Map
<
String
,
dynamic
>
toJson
()
{
final
Map
<
String
,
dynamic
>
data
=
new
Map
<
String
,
dynamic
>();
if
(
this
.
order
!=
null
)
{
data
[
'order'
]
=
this
.
order
!.
map
((
v
)
=>
v
.
toJson
()).
toList
();
}
data
[
'error'
]
=
this
.
error
;
data
[
'message'
]
=
this
.
message
;
return
data
;
}
}
class
Order
{
String
?
orderid
;
String
?
datetime
;
String
?
address
;
Order
({
this
.
orderid
,
this
.
datetime
,
this
.
address
});
Order
.
fromJson
(
Map
<
String
,
dynamic
>
json
)
{
orderid
=
json
[
'orderid'
];
datetime
=
json
[
'datetime'
];
address
=
json
[
'address'
];
}
Map
<
String
,
dynamic
>
toJson
()
{
final
Map
<
String
,
dynamic
>
data
=
new
Map
<
String
,
dynamic
>();
data
[
'orderid'
]
=
this
.
orderid
;
data
[
'datetime'
]
=
this
.
datetime
;
data
[
'address'
]
=
this
.
address
;
return
data
;
}
}
lib/Notifier/DashboardProvider.dart
View file @
df116895
...
@@ -15,6 +15,7 @@ class DashboardProvider with ChangeNotifier {
...
@@ -15,6 +15,7 @@ class DashboardProvider with ChangeNotifier {
/// Fetch Dashboard API
/// Fetch Dashboard API
Future
<
void
>
fetchDashboard
({
Future
<
void
>
fetchDashboard
({
required
String
accId
,
required
String
accId
,
required
String
sessionId
,
})
async
{
})
async
{
_isLoading
=
true
;
_isLoading
=
true
;
_errorMessage
=
null
;
_errorMessage
=
null
;
...
@@ -22,7 +23,7 @@ class DashboardProvider with ChangeNotifier {
...
@@ -22,7 +23,7 @@ class DashboardProvider with ChangeNotifier {
try
{
try
{
final
response
=
final
response
=
await
ApiCalling
.
fetchDashboardApi
(
accId
,);
await
ApiCalling
.
fetchDashboardApi
(
accId
,
sessionId
);
if
(
response
!=
null
)
{
if
(
response
!=
null
)
{
_dashboardData
=
response
;
_dashboardData
=
response
;
...
...
lib/Notifier/RentalContactProvider .dart
View file @
df116895
import
'package:flutter/material.dart'
;
import
'package:flutter/material.dart'
;
import
'package:gen_rentals/Services/api_calling.dart'
;
import
'package:gen_rentals/Services/api_calling.dart'
;
import
'package:device_info_plus/device_info_plus.dart'
;
import
'dart:io'
;
class
RentalProvider
extends
ChangeNotifier
{
class
RentalProvider
extends
ChangeNotifier
{
FetchMobileResponse
?
_response
;
FetchMobileResponse
?
_response
;
FetchMobileResponse
?
otpResponse
;
FetchMobileResponse
?
otpResponse
;
bool
_isLoading
=
false
;
bool
_isLoading
=
false
;
FetchMobileResponse
?
get
response
=>
_response
;
FetchMobileResponse
?
get
response
=>
_response
;
bool
get
isLoading
=>
_isLoading
;
bool
get
isLoading
=>
_isLoading
;
bool
isOtpLoading
=
false
;
bool
isOtpLoading
=
false
;
...
@@ -33,7 +36,8 @@ class RentalProvider extends ChangeNotifier {
...
@@ -33,7 +36,8 @@ class RentalProvider extends ChangeNotifier {
notifyListeners
();
notifyListeners
();
try
{
try
{
final
result
=
await
ApiCalling
.
fetchMobileOtpApi
(
mob
,
otp
);
final
deviceDetails
=
await
getDeviceDetails
();
final
result
=
await
ApiCalling
.
fetchMobileOtpApi
(
mob
,
otp
,
deviceDetails
);
otpResponse
=
result
;
otpResponse
=
result
;
}
catch
(
e
)
{
}
catch
(
e
)
{
debugPrint
(
"❌ OTP API Error:
$e
"
);
debugPrint
(
"❌ OTP API Error:
$e
"
);
...
@@ -44,6 +48,41 @@ class RentalProvider extends ChangeNotifier {
...
@@ -44,6 +48,41 @@ class RentalProvider extends ChangeNotifier {
}
}
}
}
Future
<
Map
<
String
,
String
>>
getDeviceDetails
()
async
{
final
deviceInfo
=
DeviceInfoPlugin
();
if
(
Platform
.
isAndroid
)
{
final
androidInfo
=
await
deviceInfo
.
androidInfo
;
return
{
"versionName"
:
androidInfo
.
version
.
release
??
""
,
"versionCode"
:
androidInfo
.
version
.
codename
??
""
,
"osVersion"
:
androidInfo
.
version
.
release
??
""
,
"sdkVersion"
:
androidInfo
.
version
.
sdkInt
.
toString
(),
"device"
:
androidInfo
.
device
??
""
,
"model"
:
androidInfo
.
model
??
""
,
"product"
:
androidInfo
.
product
??
""
,
"manufacturer"
:
androidInfo
.
manufacturer
??
""
,
"brand"
:
androidInfo
.
brand
??
""
,
"user"
:
""
,
"display"
:
androidInfo
.
display
??
""
,
"hardware"
:
androidInfo
.
hardware
??
""
,
"board"
:
androidInfo
.
board
??
""
,
"host"
:
androidInfo
.
host
??
""
,
"serial"
:
androidInfo
.
serialNumber
??
"unknown"
,
"id"
:
androidInfo
.
id
??
""
,
"bootloader"
:
androidInfo
.
bootloader
??
""
,
"cpuAbi1"
:
androidInfo
.
supportedAbis
.
isNotEmpty
?
androidInfo
.
supportedAbis
[
0
]
:
""
,
"cpuAbi2"
:
androidInfo
.
supportedAbis
.
length
>
1
?
androidInfo
.
supportedAbis
[
1
]
:
""
,
"fingerprint"
:
androidInfo
.
fingerprint
??
""
,
};
}
return
{};
}
}
}
...
@@ -52,6 +91,7 @@ class FetchMobileResponse {
...
@@ -52,6 +91,7 @@ class FetchMobileResponse {
String
?
errorMsg
;
String
?
errorMsg
;
String
?
accId
;
String
?
accId
;
String
?
message
;
String
?
message
;
String
?
sessionId
;
FetchMobileResponse
({
this
.
error
,
this
.
errorMsg
});
FetchMobileResponse
({
this
.
error
,
this
.
errorMsg
});
...
@@ -60,6 +100,7 @@ class FetchMobileResponse {
...
@@ -60,6 +100,7 @@ class FetchMobileResponse {
errorMsg
=
json
[
'error_msg'
];
errorMsg
=
json
[
'error_msg'
];
accId
=
json
[
'acc_id'
];
accId
=
json
[
'acc_id'
];
message
=
json
[
'message'
];
message
=
json
[
'message'
];
sessionId
=
json
[
'session_id'
];
}
}
Map
<
String
,
dynamic
>
toJson
()
{
Map
<
String
,
dynamic
>
toJson
()
{
...
@@ -68,7 +109,9 @@ class FetchMobileResponse {
...
@@ -68,7 +109,9 @@ class FetchMobileResponse {
data
[
'error_msg'
]
=
this
.
errorMsg
;
data
[
'error_msg'
]
=
this
.
errorMsg
;
data
[
'acc_id'
]
=
this
.
accId
;
data
[
'acc_id'
]
=
this
.
accId
;
data
[
'message'
]
=
this
.
message
;
data
[
'message'
]
=
this
.
message
;
data
[
'session_id'
]
=
this
.
sessionId
;
return
data
;
return
data
;
}
}
}
}
lib/Notifier/SubscribeOrderDetailsProvider.dart
0 → 100644
View file @
df116895
import
'package:flutter/foundation.dart'
;
import
'package:flutter/material.dart'
;
import
'package:gen_rentals/Services/api_calling.dart'
;
import
'dart:convert'
;
import
'../Models/SubscribeOrderDetailsResponse.dart'
;
class
SubscribeOrderDetailsProvider
with
ChangeNotifier
{
SubscribeOrderDetailsResponse
?
_orderDetails
;
bool
_isLoading
=
false
;
String
_errorMessage
=
''
;
// Getters
SubscribeOrderDetailsResponse
?
get
orderDetails
=>
_orderDetails
;
bool
get
isLoading
=>
_isLoading
;
String
get
errorMessage
=>
_errorMessage
;
/// Fetch Subscribe Order Details
Future
<
void
>
fetchSubscribeOrderDetails
(
String
sessionId
,
String
orderId
,
String
accId
,
)
async
{
_isLoading
=
true
;
_errorMessage
=
''
;
notifyListeners
();
try
{
final
response
=
await
ApiCalling
.
fetchSubsOrderDetailApi
(
sessionId
,
orderId
,
accId
,
);
if
(
response
!=
null
)
{
// Check if error is "0" which means success in your API
if
(
response
.
error
==
"0"
)
{
_orderDetails
=
response
;
_errorMessage
=
''
;
}
// Handle other error cases
else
if
(
response
.
error
!=
null
&&
response
.
error
!.
isNotEmpty
&&
response
.
error
!=
"0"
)
{
_errorMessage
=
response
.
message
??
'An error occurred'
;
_orderDetails
=
null
;
}
// Handle message-based errors
else
if
(
response
.
message
!=
null
&&
response
.
message
!.
isNotEmpty
&&
!
response
.
message
!.
toLowerCase
().
contains
(
'success'
))
{
_errorMessage
=
response
.
message
!;
_orderDetails
=
null
;
}
// Default success case
else
{
_orderDetails
=
response
;
_errorMessage
=
''
;
}
}
else
{
_errorMessage
=
'Failed to load order details'
;
_orderDetails
=
null
;
}
}
catch
(
e
)
{
_errorMessage
=
'An error occurred:
$e
'
;
_orderDetails
=
null
;
debugPrint
(
"❌ Provider Error (fetchSubscribeOrderDetails):
$e
"
);
}
finally
{
_isLoading
=
false
;
notifyListeners
();
}
}
// ... rest of your provider code
}
\ No newline at end of file
lib/Notifier/TransactionsProvider.dart
0 → 100644
View file @
df116895
import
'dart:developer'
;
import
'package:flutter/material.dart'
;
import
'package:gen_rentals/Services/api_calling.dart'
;
import
'../Models/TransactionsResponse.dart'
;
class
TransactionsProvider
with
ChangeNotifier
{
bool
_isLoading
=
false
;
TransactionsResponse
?
_transactionsResponse
;
bool
get
isLoading
=>
_isLoading
;
TransactionsResponse
?
get
transactionsResponse
=>
_transactionsResponse
;
/// For UI convenience
Map
<
String
,
List
<
TransactionItem
>>
get
transactionsByMonth
=>
_transactionsResponse
?.
transactions
??
{};
/// Fetch Rental Transactions API
Future
<
void
>
fetchRentalTransactions
(
String
sessionId
,
String
accId
)
async
{
_isLoading
=
true
;
notifyListeners
();
try
{
final
response
=
await
ApiCalling
.
fetchRentalsTransactionsApi
(
sessionId
,
accId
);
if
(
response
!=
null
&&
response
.
error
==
"0"
)
{
_transactionsResponse
=
response
;
log
(
"✅ Transactions fetched successfully:
${response.transactions?.length ?? 0}
months"
);
}
else
{
log
(
"⚠️ Error in API response:
${response?.message}
"
);
_transactionsResponse
=
null
;
}
}
catch
(
e
)
{
log
(
"❌ Exception in fetchRentalTransactions:
$e
"
);
_transactionsResponse
=
null
;
}
finally
{
_isLoading
=
false
;
notifyListeners
();
}
}
/// Optional: Clear data
void
clearTransactions
()
{
_transactionsResponse
=
null
;
notifyListeners
();
}
}
lib/Screens/DashboardScreen.dart
View file @
df116895
...
@@ -11,7 +11,8 @@ import 'authScreen/LoginScreen.dart';
...
@@ -11,7 +11,8 @@ import 'authScreen/LoginScreen.dart';
class
DashboardScreen
extends
StatefulWidget
{
class
DashboardScreen
extends
StatefulWidget
{
final
String
accId
;
final
String
accId
;
const
DashboardScreen
({
super
.
key
,
required
this
.
accId
});
final
String
sessionId
;
const
DashboardScreen
({
super
.
key
,
required
this
.
accId
,
required
this
.
sessionId
});
@override
@override
State
<
DashboardScreen
>
createState
()
=>
_DashboardScreenState
();
State
<
DashboardScreen
>
createState
()
=>
_DashboardScreenState
();
...
@@ -25,7 +26,7 @@ class _DashboardScreenState extends State<DashboardScreen> {
...
@@ -25,7 +26,7 @@ class _DashboardScreenState extends State<DashboardScreen> {
WidgetsBinding
.
instance
.
addPostFrameCallback
((
_
)
{
WidgetsBinding
.
instance
.
addPostFrameCallback
((
_
)
{
// Only fetch dashboard if accId is valid
// Only fetch dashboard if accId is valid
if
(
widget
.
accId
.
isNotEmpty
&&
widget
.
accId
!=
"null"
)
{
if
(
widget
.
accId
.
isNotEmpty
&&
widget
.
accId
!=
"null"
)
{
Provider
.
of
<
DashboardProvider
>(
context
,
listen:
false
).
fetchDashboard
(
accId:
widget
.
accId
);
Provider
.
of
<
DashboardProvider
>(
context
,
listen:
false
).
fetchDashboard
(
accId:
widget
.
accId
,
sessionId:
widget
.
sessionId
);
}
else
{
}
else
{
// If accId is invalid, navigate back to login
// If accId is invalid, navigate back to login
WidgetsBinding
.
instance
.
addPostFrameCallback
((
_
)
{
WidgetsBinding
.
instance
.
addPostFrameCallback
((
_
)
{
...
@@ -182,9 +183,11 @@ class _DashboardScreenState extends State<DashboardScreen> {
...
@@ -182,9 +183,11 @@ class _DashboardScreenState extends State<DashboardScreen> {
// Main content section
// Main content section
Container
(
Container
(
padding:
const
EdgeInsets
.
symmetric
(
horizontal:
20
),
padding:
const
EdgeInsets
.
symmetric
(
horizontal:
16
),
child:
Column
(
child:
Column
(
children:
[
children:
[
// Balance Amount Card
// Balance Amount Card
Container
(
Container
(
width:
double
.
infinity
,
width:
double
.
infinity
,
...
@@ -222,7 +225,7 @@ class _DashboardScreenState extends State<DashboardScreen> {
...
@@ -222,7 +225,7 @@ class _DashboardScreenState extends State<DashboardScreen> {
children:
[
children:
[
// Use provider data for balance amount - FIXED NULL CHECK
// Use provider data for balance amount - FIXED NULL CHECK
Text
(
Text
(
dashboardData
?.
balanceAmount
??
"0"
,
dashboardData
?.
balanceAmount
.
toString
()
??
"0"
,
style:
const
TextStyle
(
style:
const
TextStyle
(
fontFamily:
"Poppins"
,
fontFamily:
"Poppins"
,
color:
Colors
.
black
,
color:
Colors
.
black
,
...
@@ -260,6 +263,70 @@ class _DashboardScreenState extends State<DashboardScreen> {
...
@@ -260,6 +263,70 @@ class _DashboardScreenState extends State<DashboardScreen> {
const
SizedBox
(
height:
20
),
const
SizedBox
(
height:
20
),
const
SizedBox
(
height:
20
),
// Subscribed Orders
Container
(
width:
double
.
infinity
,
padding:
const
EdgeInsets
.
symmetric
(
horizontal:
2
,
vertical:
10
),
child:
Column
(
crossAxisAlignment:
CrossAxisAlignment
.
start
,
children:
[
// Section Title
Text
(
"Subscribed Orders"
,
style:
TextStyle
(
fontFamily:
"Poppins"
,
color:
Colors
.
grey
.
shade800
,
fontSize:
18
,
fontWeight:
FontWeight
.
w600
,
),
),
const
SizedBox
(
height:
16
),
// Show loading or products list
if
(
dashboardProvider
.
isLoading
&&
dashboardData
==
null
)
const
Center
(
child:
CircularProgressIndicator
(),
)
else
if
(
dashboardData
?.
orders
==
null
||
dashboardData
!.
orders
!.
isEmpty
)
const
Text
(
"No products subscribed"
,
style:
TextStyle
(
fontFamily:
"Poppins"
,
color:
Colors
.
grey
,
fontSize:
14
,
),
)
else
// List of subscribed products from API
Column
(
children:
dashboardData
!.
orders
!.
map
((
product
)
{
return
Column
(
children:
[
InkResponse
(
onTap:
()
{
Navigator
.
push
(
context
,
MaterialPageRoute
(
builder:
(
context
)
=>
ProductsDetailScreen
(
sessionId:
widget
.
sessionId
,
accId:
widget
.
accId
,
orderId:
product
.
orderid
.
toString
(),
)),
);
},
child:
_buildProductItemFromApi
(
product
),
),
const
SizedBox
(
height:
16
),
],
);
}).
toList
(),
),
],
),
),
// Feature cards grid
// Feature cards grid
Container
(
Container
(
width:
double
.
infinity
,
width:
double
.
infinity
,
...
@@ -273,13 +340,13 @@ class _DashboardScreenState extends State<DashboardScreen> {
...
@@ -273,13 +340,13 @@ class _DashboardScreenState extends State<DashboardScreen> {
child:
InkResponse
(
child:
InkResponse
(
onTap:
()
{
onTap:
()
{
Navigator
.
push
(
Navigator
.
push
(
context
,
context
,
MaterialPageRoute
(
builder:
(
context
)
=>
EnquiryScreen
()
MaterialPageRoute
(
builder:
(
context
)
=>
EnquiryScreen
()
)
)
);
);
},
},
child:
Container
(
child:
Container
(
padding:
const
EdgeInsets
.
symmetric
(
horizontal:
15
,
vertical:
10
),
padding:
const
EdgeInsets
.
symmetric
(
horizontal:
15
,
vertical:
8
),
decoration:
BoxDecoration
(
decoration:
BoxDecoration
(
color:
Colors
.
white
,
color:
Colors
.
white
,
borderRadius:
BorderRadius
.
circular
(
12
),
borderRadius:
BorderRadius
.
circular
(
12
),
...
@@ -305,7 +372,7 @@ class _DashboardScreenState extends State<DashboardScreen> {
...
@@ -305,7 +372,7 @@ class _DashboardScreenState extends State<DashboardScreen> {
fontWeight:
FontWeight
.
w400
,
fontWeight:
FontWeight
.
w400
,
),
),
),
),
const
SizedBox
(
height:
8
),
const
SizedBox
(
height:
6
),
Text
(
Text
(
"Submit your enquiry for requirement"
,
"Submit your enquiry for requirement"
,
style:
TextStyle
(
style:
TextStyle
(
...
@@ -417,7 +484,10 @@ class _DashboardScreenState extends State<DashboardScreen> {
...
@@ -417,7 +484,10 @@ class _DashboardScreenState extends State<DashboardScreen> {
onTap:
()
{
onTap:
()
{
Navigator
.
push
(
Navigator
.
push
(
context
,
context
,
MaterialPageRoute
(
builder:
(
context
)
=>
TransactionsScreen
()),
MaterialPageRoute
(
builder:
(
context
)
=>
TransactionsScreen
(
sessionId:
widget
.
sessionId
,
accId:
widget
.
accId
,
)),
);
);
},
},
child:
Container
(
child:
Container
(
...
@@ -487,64 +557,7 @@ class _DashboardScreenState extends State<DashboardScreen> {
...
@@ -487,64 +557,7 @@ class _DashboardScreenState extends State<DashboardScreen> {
],
],
),
),
),
),
const
SizedBox
(
height:
20
),
SizedBox
(
height:
10
,),
// Subscribed Products
Container
(
width:
double
.
infinity
,
padding:
const
EdgeInsets
.
symmetric
(
horizontal:
2
,
vertical:
10
),
child:
Column
(
crossAxisAlignment:
CrossAxisAlignment
.
start
,
children:
[
// Section Title
Text
(
"Subscribed Products"
,
style:
TextStyle
(
fontFamily:
"Poppins"
,
color:
Colors
.
grey
.
shade800
,
fontSize:
18
,
fontWeight:
FontWeight
.
w600
,
),
),
const
SizedBox
(
height:
16
),
// Show loading or products list
if
(
dashboardProvider
.
isLoading
&&
dashboardData
==
null
)
const
Center
(
child:
CircularProgressIndicator
(),
)
else
if
(
dashboardData
?.
products
==
null
||
dashboardData
!.
products
!.
isEmpty
)
const
Text
(
"No products subscribed"
,
style:
TextStyle
(
fontFamily:
"Poppins"
,
color:
Colors
.
grey
,
fontSize:
14
,
),
)
else
// List of subscribed products from API
Column
(
children:
dashboardData
!.
products
!.
map
((
product
)
{
return
Column
(
children:
[
InkResponse
(
onTap:
()
{
Navigator
.
push
(
context
,
MaterialPageRoute
(
builder:
(
context
)
=>
ProductsDetailScreen
()),
);
},
child:
_buildProductItemFromApi
(
product
),
),
const
SizedBox
(
height:
16
),
],
);
}).
toList
(),
),
],
),
)
],
],
),
),
),
),
...
@@ -561,224 +574,267 @@ class _DashboardScreenState extends State<DashboardScreen> {
...
@@ -561,224 +574,267 @@ class _DashboardScreenState extends State<DashboardScreen> {
}
}
// Helper widget for product item from API data
// Helper widget for product item from API data
Widget
_buildProductItemFromApi
(
Products
product
)
{
Widget
_buildProductItemFromApi
(
Orders
product
)
{
return
Stack
(
final
bool
hasPending
=
product
.
hasPendingPayment
==
true
;
children:
[
final
productList
=
product
.
products
??
[];
// Background strip for pending payment
if
(
product
.
hasPendingPayment
==
true
)
return
Container
(
Container
(
margin:
const
EdgeInsets
.
symmetric
(
vertical:
6
),
height:
130
+
50
,
decoration:
BoxDecoration
(
padding:
EdgeInsets
.
zero
,
borderRadius:
BorderRadius
.
circular
(
15
),
decoration:
BoxDecoration
(
boxShadow:
[
color:
Colors
.
red
.
withOpacity
(
0.6
),
BoxShadow
(
borderRadius:
BorderRadius
.
circular
(
15
),
color:
Colors
.
grey
.
withOpacity
(
0.15
),
border:
Border
.
all
(
blurRadius:
6
,
color:
Colors
.
grey
.
shade200
,
offset:
const
Offset
(
0
,
2
),
width:
1
,
),
),
],
),
),
child:
Column
(
child:
Stack
(
children:
[
children:
[
SizedBox
(
height:
144
),
// ===== Red Strip (Behind Card) =====
// Pending payment strip
if
(
hasPending
)
Container
(
Positioned
.
fill
(
width:
double
.
infinity
,
top:
null
,
padding:
const
EdgeInsets
.
symmetric
(
horizontal:
6
,
vertical:
8
),
child:
Align
(
decoration:
BoxDecoration
(
alignment:
Alignment
.
bottomCenter
,
color:
Colors
.
white38
,
child:
Container
(
borderRadius:
const
BorderRadius
.
only
(
height:
45
,
bottomLeft:
Radius
.
circular
(
10
),
decoration:
const
BoxDecoration
(
bottomRight:
Radius
.
circular
(
10
),
color:
Color
(
0xFFFFE2E0
),
borderRadius:
BorderRadius
.
only
(
bottomLeft:
Radius
.
circular
(
15
),
bottomRight:
Radius
.
circular
(
15
),
),
),
),
),
child:
Row
(
child:
Row
(
children:
[
children:
[
Icon
(
const
SizedBox
(
width:
12
),
Icons
.
info_outline
,
const
Icon
(
Icons
.
info_outline
,
color:
Colors
.
red
,
size:
18
),
color:
Colors
.
red
,
size:
18
,
),
const
SizedBox
(
width:
6
),
const
SizedBox
(
width:
6
),
Expanded
(
Expanded
(
child:
Text
(
child:
Text
(
product
.
pendingPaymentText
??
"Payment Pending"
,
product
.
pendingPaymentText
??
style:
TextStyle
(
"Payment Pending. Please Pay before incurring fines."
,
style:
const
TextStyle
(
fontFamily:
"Poppins"
,
fontFamily:
"Poppins"
,
color:
Colors
.
black87
,
color:
Colors
.
red
,
fontSize:
12
,
fontSize:
12
,
fontStyle:
FontStyle
.
normal
,
fontWeight:
FontWeight
.
w400
,
fontWeight:
FontWeight
.
w400
,
),
),
),
),
),
),
const
SizedBox
(
width:
12
),
],
],
),
),
),
),
]
,
)
,
),
),
),
// Main content card
// ===== Main White Card =====
Container
(
Container
(
padding:
const
EdgeInsets
.
symmetric
(
horizontal:
10
,
vertical:
4
),
decoration:
BoxDecoration
(
decoration:
BoxDecoration
(
color:
Colors
.
white
,
color:
Colors
.
white
,
borderRadius:
BorderRadius
.
circular
(
15
),
borderRadius:
BorderRadius
.
circular
(
12
),
border:
Border
.
all
(
color:
Colors
.
grey
.
shade200
,
width:
1
,
),
),
),
padding:
const
EdgeInsets
.
symmetric
(
horizontal:
10
,
vertical:
10
),
child:
Column
(
child:
Column
(
children:
[
crossAxisAlignment:
CrossAxisAlignment
.
start
,
// Main content
children:
[
Row
(
/// Header Row (image, order id, date, badge)
mainAxisAlignment:
MainAxisAlignment
.
spaceBetween
,
Row
(
children:
[
mainAxisAlignment:
MainAxisAlignment
.
spaceBetween
,
Expanded
(
children:
[
flex:
6
,
Row
(
child:
Padding
(
children:
[
padding:
const
EdgeInsets
.
all
(
10
),
Container
(
child:
Column
(
padding:
const
EdgeInsets
.
all
(
14
),
crossAxisAlignment:
CrossAxisAlignment
.
start
,
decoration:
BoxDecoration
(
children:
[
color:
const
Color
(
0xffF2F2F2
),
// Expiring badge
borderRadius:
BorderRadius
.
circular
(
16
),
if
(
product
.
expiringText
!=
null
&&
product
.
expiringText
!.
isNotEmpty
)
Container
(
padding:
const
EdgeInsets
.
symmetric
(
horizontal:
10
,
vertical:
6
),
decoration:
BoxDecoration
(
borderRadius:
BorderRadius
.
circular
(
8
),
gradient:
_getGradientByColor
(
product
.
expiringInColor
),
),
child:
Text
(
product
.
expiringText
!,
style:
const
TextStyle
(
color:
Colors
.
black87
,
fontSize:
12
,
fontStyle:
FontStyle
.
normal
,
fontWeight:
FontWeight
.
w400
,
),
),
),
const
SizedBox
(
height:
8
),
// Product name and plan
Text
(
product
.
productName
??
"Unknown Product"
,
style:
const
TextStyle
(
color:
Colors
.
black
,
fontSize:
16
,
fontStyle:
FontStyle
.
normal
,
fontWeight:
FontWeight
.
w400
,
),
),
),
const
SizedBox
(
height:
4
),
child:
Image
.
network
(
Text
(
product
.
productImage
??
""
,
"Plan"
,
height:
40
,
style:
TextStyle
(
width:
40
,
fontFamily:
"Poppins"
,
fit:
BoxFit
.
contain
,
color:
Colors
.
grey
.
shade600
,
errorBuilder:
(
context
,
error
,
stack
)
=>
fontWeight:
FontWeight
.
w400
,
Image
.
asset
(
'assets/images/gene_png.png'
,
fontStyle:
FontStyle
.
normal
,
height:
40
,
width:
40
),
fontSize:
12
,
height:
1
,
),
),
),
Text
(
),
"₹
${product.plan ?? "0"}
"
,
const
SizedBox
(
width:
8
),
style:
const
TextStyle
(
Column
(
crossAxisAlignment:
CrossAxisAlignment
.
start
,
children:
[
Text
(
"#
${product.orderid ?? "0"}
"
,
style:
const
TextStyle
(
fontFamily:
"Poppins"
,
fontFamily:
"Poppins"
,
color:
Color
(
0xFF008CDE
),
color:
Color
(
0xFF008CDE
),
fontSize:
18
,
fontSize:
16
,
fontStyle:
FontStyle
.
normal
,
fontWeight:
FontWeight
.
w500
,
fontWeight:
FontWeight
.
w500
,
height:
1.2
height:
1.2
,
),
),
Text
(
product
.
rentedDate
??
"Rented date not available"
,
style:
TextStyle
(
fontFamily:
"Poppins"
,
color:
Colors
.
grey
.
shade600
,
fontSize:
12
,
),
),
),
],
),
],
),
// ✅ Gradient expiry badge
if
(
product
.
expiringText
!=
null
&&
product
.
expiringText
!.
isNotEmpty
)
Container
(
padding:
const
EdgeInsets
.
symmetric
(
horizontal:
10
,
vertical:
6
),
decoration:
BoxDecoration
(
gradient:
_getGradientByColor
(
product
.
expiringInColor
),
borderRadius:
BorderRadius
.
circular
(
8
),
),
child:
Text
(
product
.
expiringText
!,
style:
const
TextStyle
(
color:
Colors
.
black87
,
fontSize:
12
,
fontWeight:
FontWeight
.
w500
,
),
),
const
SizedBox
(
height:
3
),
),
),
],
),
// Rented date
const
SizedBox
(
height:
6
),
Text
(
const
Divider
(),
product
.
rentedDate
??
"Rented date not available"
,
style:
TextStyle
(
/// ===== Product List (with +3 More on same line) =====
fontFamily:
"Poppins"
,
Builder
(
color:
Colors
.
grey
.
shade500
,
builder:
(
context
)
{
fontStyle:
FontStyle
.
normal
,
final
visibleItems
=
productList
.
take
(
2
).
toList
();
fontWeight:
FontWeight
.
w400
,
final
remaining
=
productList
.
length
-
visibleItems
.
length
;
fontSize:
12
,
return
Row
(
crossAxisAlignment:
CrossAxisAlignment
.
center
,
mainAxisAlignment:
MainAxisAlignment
.
spaceBetween
,
children:
[
// Left side → Product list (bulleted)
Expanded
(
child:
Column
(
crossAxisAlignment:
CrossAxisAlignment
.
start
,
children:
[
for
(
int
i
=
0
;
i
<
visibleItems
.
length
;
i
++)
Padding
(
padding:
const
EdgeInsets
.
only
(
bottom:
4
),
child:
Row
(
crossAxisAlignment:
CrossAxisAlignment
.
start
,
children:
[
const
SizedBox
(
width:
8
),
const
Text
(
"• "
,
style:
TextStyle
(
color:
Colors
.
black
,
fontSize:
16
),
),
Expanded
(
child:
Text
(
visibleItems
[
i
],
style:
const
TextStyle
(
color:
Colors
.
black
,
fontSize:
16
,
fontWeight:
FontWeight
.
w400
,
),
),
),
],
),
),
],
),
),
// Right side → +x More (vertically centered)
if
(
remaining
>
0
)
Padding
(
padding:
const
EdgeInsets
.
only
(
left:
8
,
right:
4
),
child:
Align
(
alignment:
Alignment
.
center
,
child:
Text
(
"+
$remaining
More"
,
style:
const
TextStyle
(
fontFamily:
"Poppins"
,
color:
Color
(
0xFF008CDE
),
fontSize:
14
,
fontWeight:
FontWeight
.
w500
,
),
),
),
),
),
),
],
],
),
);
)
,
}
,
),
),
Expanded
(
],
flex:
3
,
),
child:
Container
(
padding:
const
EdgeInsets
.
all
(
14
),
decoration:
BoxDecoration
(
color:
const
Color
(
0xffF2F2F2
),
borderRadius:
BorderRadius
.
circular
(
16
),
),
child:
product
.
productImage
!=
null
&&
product
.
productImage
!.
isNotEmpty
?
Image
.
network
(
product
.
productImage
!,
height:
80
,
width:
80
,
fit:
BoxFit
.
contain
,
errorBuilder:
(
context
,
error
,
stackTrace
)
{
return
Image
.
asset
(
'assets/images/gene_png.png'
,
height:
80
,
width:
80
,
fit:
BoxFit
.
contain
,
);
},
)
:
Image
.
asset
(
'assets/images/gene_png.png'
,
height:
80
,
width:
80
,
fit:
BoxFit
.
contain
,
),
),
),
],
),
],
),
),
)
,
]
,
]
,
)
,
);
);
}
}
//
Helper method to get gradient based on color from API
//
Gradient helper
LinearGradient
_getGradientByColor
(
String
?
color
)
{
LinearGradient
_getGradientByColor
(
String
?
color
)
{
switch
(
color
)
{
switch
(
color
)
{
case
"
r
ed"
:
case
"
R
ed"
:
return
const
LinearGradient
(
return
const
LinearGradient
(
colors:
[
Color
(
0xFFFFE0E0
),
Color
(
0xFFFFC0C0
)],
begin:
Alignment
.
topLeft
,
begin:
Alignment
.
topLeft
,
end:
Alignment
.
bottomRight
,
end:
Alignment
.
bottomRight
,
colors:
[
Color
(
0xFFFFDDDD
),
Color
(
0xFFFFB5B5
),
],
);
);
case
"
g
reen"
:
case
"
G
reen"
:
default
:
default
:
return
const
LinearGradient
(
return
const
LinearGradient
(
colors:
[
Color
(
0xFFE9FFDD
),
Color
(
0xFFB5FFD1
)],
begin:
Alignment
.
topLeft
,
begin:
Alignment
.
topLeft
,
end:
Alignment
.
bottomRight
,
end:
Alignment
.
bottomRight
,
colors:
[
Color
(
0xFFE9FFDD
),
Color
(
0xFFB5FFD1
),
],
);
);
}
}
}
}
// Helper method to get gradient based on color from API
// LinearGradient _getGradientByColor(String? color) {
// switch (color) {
// case "red":
// return const LinearGradient(
// begin: Alignment.topLeft,
// end: Alignment.bottomRight,
// colors: [
// Color(0xFFFFDDDD),
// Color(0xFFFFB5B5),
// ],
// );
// case "green":
// default:
// return const LinearGradient(
// begin: Alignment.topLeft,
// end: Alignment.bottomRight,
// colors: [
// Color(0xFFE9FFDD),
// Color(0xFFB5FFD1),
// ],
// );
// }
// }
void
showPaymentBottomSheet
(
BuildContext
context
)
{
void
showPaymentBottomSheet
(
BuildContext
context
)
{
showModalBottomSheet
(
showModalBottomSheet
(
context:
context
,
context:
context
,
...
...
lib/Screens/ProductsDetailScreen.dart
View file @
df116895
import
'dart:convert'
;
import
'package:flutter/material.dart'
;
import
'package:flutter/material.dart'
;
import
'package:flutter_svg/flutter_svg.dart'
;
import
'package:flutter_svg/flutter_svg.dart'
;
import
'package:gen_rentals/Screens/BillDetailListScreen.dart'
;
import
'package:gen_rentals/Screens/BillDetailListScreen.dart'
;
import
'package:gen_rentals/Utility/Reusablewidgets.dart'
;
import
'package:provider/provider.dart'
;
import
'../Models/SubscribeOrderDetailsResponse.dart'
;
import
'../Notifier/SubscribeOrderDetailsProvider.dart'
;
import
'../Utility/AppColors.dart'
;
import
'../Utility/AppColors.dart'
;
import
'HelpScreens/CreateTicketScreen.dart'
;
class
ProductsDetailScreen
extends
StatefulWidget
{
final
String
sessionId
;
final
String
orderId
;
final
String
accId
;
class
ProductsDetailScreen
extends
StatelessWidget
{
const
ProductsDetailScreen
({
const
ProductsDetailScreen
({
super
.
key
});
super
.
key
,
required
this
.
sessionId
,
required
this
.
orderId
,
required
this
.
accId
,
});
@override
@override
Widget
build
(
BuildContext
context
)
{
State
<
ProductsDetailScreen
>
createState
()
=>
_ProductsDetailScreenState
();
double
screenWidth
=
MediaQuery
.
of
(
context
).
size
.
width
;
}
double
screenHeight
=
MediaQuery
.
of
(
context
).
size
.
height
;
double
bottomPadding
=
MediaQuery
.
of
(
context
).
padding
.
bottom
;
return
SafeArea
(
class
_ProductsDetailScreenState
extends
State
<
ProductsDetailScreen
>
{
top:
false
,
child:
Scaffold
(
body:
Container
(
color:
const
Color
(
0xFFF3F3F3
),
height:
screenHeight
,
child:
SingleChildScrollView
(
child:
Column
(
children:
[
// Top background image section
Stack
(
children:
[
// Background image
Container
(
width:
double
.
infinity
,
decoration:
BoxDecoration
(
gradient:
const
LinearGradient
(
begin:
Alignment
.
topCenter
,
end:
Alignment
.
bottomCenter
,
colors:
[
Colors
.
white54
,
Color
(
0xFFF3F3F3
),
],
),
),
child:
Image
.
asset
(
'assets/images/sky_blue_bg.jpg'
,
width:
double
.
infinity
,
height:
400
,
fit:
BoxFit
.
cover
,
),
),
// Content overlay
final
List
<
Map
<
String
,
dynamic
>>
createNewTickets
=
[
Column
(
{
crossAxisAlignment:
CrossAxisAlignment
.
start
,
'title'
:
'Payment Issues'
,
children:
[
'description'
:
'Get help with payment related problems'
,
// Header with profile
'icon'
:
"assets/svg/rupee_coin_ic.svg"
,
Container
(
'color'
:
Color
(
0xFFFFEFBE
),
width:
double
.
infinity
,
},
height:
450
,
{
decoration:
const
BoxDecoration
(
'title'
:
'Bill Related Issues'
,
gradient:
LinearGradient
(
'description'
:
'Resolve bill and invoice matters'
,
begin:
Alignment
.
topCenter
,
'icon'
:
"assets/svg/know_pay.svg"
,
end:
Alignment
.
bottomCenter
,
'color'
:
Color
(
0xFFCEF9FF
),
colors:
[
},
Color
(
0x22FFFFFF
),
{
Color
(
0x33FFFFFF
),
'title'
:
'Other Issues'
,
Color
(
0x88FFFFFF
),
'description'
:
'Any other support you need'
,
Color
(
0xFFF3F3F3
),
'icon'
:
"assets/svg/help_ic.svg"
,
Color
(
0xFFF3F3F3
),
'color'
:
Color
(
0xFFE4E5FF
),
],
},
),
];
),
child:
Column
(
children:
[
const
SizedBox
(
height:
50
),
// Instead of SizedBox(width: 280) - consider using Spacer()
Row
(
mainAxisAlignment:
MainAxisAlignment
.
spaceBetween
,
children:
[
SvgPicture
.
asset
(
"assets/svg/continue_left_ic.svg"
,
height:
50
,
width:
50
,
),
// Removed SizedBox(width: 280)
Container
(
width:
50
,
height:
50
,
decoration:
BoxDecoration
(
color:
Colors
.
white
.
withOpacity
(
0.19
),
shape:
BoxShape
.
circle
,
border:
Border
.
all
(
color:
Colors
.
white
.
withOpacity
(
0.5
),
width:
2
,
),
),
child:
const
Icon
(
Icons
.
person
,
color:
Colors
.
white
,
size:
30
,
),
),
],
),
Column
(
crossAxisAlignment:
CrossAxisAlignment
.
center
,
mainAxisAlignment:
MainAxisAlignment
.
start
,
children:
[
Image
.
asset
(
'assets/images/gen2_img.png'
,
height:
250
,
width:
250
,
),
const
Text
(
"Genesis 85kVA"
,
style:
TextStyle
(
fontFamily:
"Poppins"
,
color:
Colors
.
black
,
fontSize:
30
,
fontWeight:
FontWeight
.
w500
,
),
),
Container
(
padding:
const
EdgeInsets
.
symmetric
(
horizontal:
10
,
vertical:
6
),
decoration:
BoxDecoration
(
borderRadius:
BorderRadius
.
circular
(
8
),
gradient:
const
LinearGradient
(
begin:
Alignment
.
topLeft
,
end:
Alignment
.
bottomRight
,
colors:
[
Color
(
0xFFE9FFDD
),
Color
(
0xFFB5FFD1
),
],
),
),
child:
Text
(
"2 months left"
,
style:
const
TextStyle
(
color:
Colors
.
black87
,
fontSize:
12
,
fontStyle:
FontStyle
.
normal
,
fontWeight:
FontWeight
.
w400
,
),
),
),
SizedBox
(
height:
4
,),
@override
const
Text
(
void
initState
()
{
"Rented on 7th July, 2025"
,
super
.
initState
();
style:
TextStyle
(
// Fetch order details when screen loads
fontFamily:
"Poppins"
,
WidgetsBinding
.
instance
.
addPostFrameCallback
((
_
)
{
color:
Colors
.
grey
,
_loadOrderDetails
();
fontSize:
16
,
});
fontWeight:
FontWeight
.
w400
,
}
),
),
],
),
],
),
),
const
SizedBox
(
height:
10
),
void
_loadOrderDetails
()
{
final
provider
=
Provider
.
of
<
SubscribeOrderDetailsProvider
>(
context
,
listen:
false
);
provider
.
fetchSubscribeOrderDetails
(
widget
.
sessionId
,
widget
.
orderId
,
widget
.
accId
,
);
}
// Main content section
@override
Container
(
Widget
build
(
BuildContext
context
)
{
padding:
const
EdgeInsets
.
symmetric
(
horizontal:
20
),
double
screenHeight
=
MediaQuery
.
of
(
context
).
size
.
height
;
child:
Column
(
double
bottomPadding
=
MediaQuery
.
of
(
context
).
padding
.
bottom
;
children:
[
// Balance Amount Card
Container
(
width:
double
.
infinity
,
padding:
const
EdgeInsets
.
all
(
20
),
decoration:
BoxDecoration
(
color:
Colors
.
white
,
borderRadius:
BorderRadius
.
circular
(
16
),
),
child:
Column
(
crossAxisAlignment:
CrossAxisAlignment
.
start
,
children:
[
InkResponse
(
onTap:
()
{
Navigator
.
push
(
context
,
MaterialPageRoute
(
builder:
(
context
)
=>
BillDetailListScreen
()),
);
},
child:
Row
(
children:
[
const
Text
(
"Balance Amount"
,
style:
TextStyle
(
fontFamily:
"Poppins"
,
color:
AppColors
.
warningText
,
fontSize:
14
,
fontWeight:
FontWeight
.
w400
,
),
),
const
SizedBox
(
width:
4
),
SvgPicture
.
asset
(
"assets/svg/continue_ic.svg"
,
color:
AppColors
.
warningText
,
height:
18
,
width:
18
,
),
],
),
),
const
SizedBox
(
height:
8
),
Row
(
mainAxisAlignment:
MainAxisAlignment
.
spaceBetween
,
children:
[
const
Text
(
"₹24,800"
,
style:
TextStyle
(
fontFamily:
"Poppins"
,
color:
AppColors
.
cardAmountText
,
fontSize:
32
,
fontWeight:
FontWeight
.
w500
,
),
),
InkResponse
(
onTap:
()
=>
showPaymentBottomSheet
(
context
),
child:
Text
(
"Pay Now"
,
style:
TextStyle
(
fontFamily:
"Poppins"
,
color:
AppColors
.
amountText
,
fontSize:
14
,
fontWeight:
FontWeight
.
w500
,
),
),
),
],
),
const
SizedBox
(
height:
2
),
Text
(
"Last Paid on 12th Sep, 2025"
,
style:
TextStyle
(
fontFamily:
"Poppins"
,
color:
AppColors
.
subtitleText
,
fontSize:
12
,
fontWeight:
FontWeight
.
w400
,
// fontStyle: FontStyle.italic,
),
),
SvgPicture
.
asset
(
return
Consumer
<
SubscribeOrderDetailsProvider
>(
"assets/svg/line_ic.svg"
,
builder:
(
context
,
provider
,
child
)
{
color:
AppColors
.
subtitleText
,
return
SafeArea
(
height:
18
,
top:
false
,
width:
18
,
child:
Scaffold
(
),
appBar:
AppBar
(
// After spacer
automaticallyImplyLeading:
false
,
Row
(
backgroundColor:
Colors
.
white
,
mainAxisAlignment:
MainAxisAlignment
.
spaceBetween
,
title:
Row
(
children:
[
children:
[
InkResponse
(
onTap:
()
=>
Navigator
.
pop
(
context
,
true
),
child:
SvgPicture
.
asset
(
"assets/svg/continue_left_ic.svg"
,
height:
25
,
),
),
const
SizedBox
(
width:
10
),
const
Text
(
"Bill List"
,
style:
TextStyle
(
fontSize:
16
,
fontFamily:
"Plus Jakarta Sans"
,
fontWeight:
FontWeight
.
w600
,
color:
Colors
.
black87
,
),
),
],
),
),
body:
_buildBody
(
provider
,
screenHeight
,
bottomPadding
),
),
);
},
);
}
Column
(
Widget
_buildBody
(
SubscribeOrderDetailsProvider
provider
,
double
screenHeight
,
double
bottomPadding
)
{
crossAxisAlignment:
CrossAxisAlignment
.
start
,
if
(
provider
.
isLoading
)
{
children:
[
return
const
Center
(
Text
(
child:
CircularProgressIndicator
(),
"Plan"
,
);
style:
TextStyle
(
}
fontFamily:
"Poppins"
,
color:
AppColors
.
subtitleText
,
fontWeight:
FontWeight
.
w400
,
fontStyle:
FontStyle
.
normal
,
fontSize:
12
,
),
),
Text
(
"₹3600"
,
style:
const
TextStyle
(
fontFamily:
"Poppins"
,
color:
Color
(
0xFF008CDE
),
fontSize:
18
,
fontStyle:
FontStyle
.
normal
,
fontWeight:
FontWeight
.
w500
,
),
),
],
),
Column
(
if
(
provider
.
errorMessage
.
isNotEmpty
)
{
crossAxisAlignment:
CrossAxisAlignment
.
start
,
return
Center
(
children:
[
child:
Column
(
Text
(
mainAxisAlignment:
MainAxisAlignment
.
center
,
"Deposit"
,
children:
[
style:
TextStyle
(
Text
(
fontFamily:
"Poppins"
,
provider
.
errorMessage
,
color:
AppColors
.
subtitleText
,
style:
const
TextStyle
(
fontWeight:
FontWeight
.
w400
,
fontSize:
16
,
fontStyle:
FontStyle
.
normal
,
fontFamily:
"Poppins"
,
fontSize:
12
,
color:
Colors
.
red
,
),
),
),
),
Text
(
const
SizedBox
(
height:
16
),
"₹5483"
,
ElevatedButton
(
style:
const
TextStyle
(
onPressed:
_loadOrderDetails
,
fontFamily:
"Poppins"
,
child:
const
Text
(
'Retry'
),
color:
AppColors
.
cardAmountText
,
),
fontSize:
18
,
],
fontStyle:
FontStyle
.
normal
,
),
fontWeight:
FontWeight
.
w500
,
);
),
}
),
],
),
Column
(
if
(
provider
.
orderDetails
==
null
)
{
crossAxisAlignment:
CrossAxisAlignment
.
start
,
return
const
Center
(
children:
[
child:
Text
(
Text
(
'No order details found'
,
"Tenure"
,
style:
TextStyle
(
style:
TextStyle
(
fontSize:
16
,
fontFamily:
"Poppins"
,
fontFamily:
"Poppins"
,
color:
AppColors
.
subtitleText
,
color:
Colors
.
grey
,
fontWeight:
FontWeight
.
w400
,
),
fontStyle:
FontStyle
.
normal
,
),
fontSize:
12
,
);
),
}
),
Text
(
"6 Months"
,
style:
const
TextStyle
(
fontFamily:
"Poppins"
,
color:
AppColors
.
cardAmountText
,
fontSize:
18
,
fontStyle:
FontStyle
.
normal
,
fontWeight:
FontWeight
.
w500
,
),
),
],
)
],
)
],
),
),
const
SizedBox
(
height:
18
),
final
order
=
provider
.
orderDetails
!;
Container
(
return
Container
(
width:
double
.
infinity
,
color:
const
Color
(
0xFFF3F3F3
),
color:
Colors
.
transparent
,
height:
screenHeight
,
child:
Column
(
child:
SingleChildScrollView
(
crossAxisAlignment:
CrossAxisAlignment
.
start
,
child:
Column
(
children:
[
children:
[
const
SizedBox
(
height:
2
),
// Order header (not in card)
SectionHeading
(
title:
"Generator Overview"
,
padding:
EdgeInsets
.
symmetric
(
vertical:
4
),),
Container
(
Text
(
width:
double
.
infinity
,
"A diesel generator converts fuel into electricity using an engine to drive an alternator. They provide backup power for homes and businesses and serve as primary sources in remote areas."
,
margin:
const
EdgeInsets
.
all
(
16
),
style:
TextStyle
(
padding:
const
EdgeInsets
.
all
(
16
),
fontFamily:
"Poppins"
,
child:
Column
(
color:
AppColors
.
subtitleText
,
crossAxisAlignment:
CrossAxisAlignment
.
center
,
fontWeight:
FontWeight
.
w400
,
children:
[
fontStyle:
FontStyle
.
normal
,
Row
(
fontSize:
12
,
mainAxisAlignment:
MainAxisAlignment
.
center
,
),
children:
[
),
const
Text
(
"# Order ID "
,
style:
TextStyle
(
fontSize:
24
,
fontFamily:
"Poppins"
,
fontWeight:
FontWeight
.
w400
,
color:
Colors
.
black87
,
),
),
Text
(
"#
${order.orderNum ?? order.orderid ?? 'N/A'}
"
,
style:
TextStyle
(
fontSize:
24
,
fontFamily:
"Poppins"
,
fontWeight:
FontWeight
.
w400
,
color:
AppColors
.
amountText
,
),
),
],
),
const
SizedBox
(
height:
8
),
Text
(
order
.
rentedDate
??
'Date not available'
,
style:
const
TextStyle
(
fontSize:
14
,
fontFamily:
"Poppins"
,
fontWeight:
FontWeight
.
w400
,
color:
Colors
.
grey
,
),
),
const
SizedBox
(
height:
14
),
Container
(
padding:
const
EdgeInsets
.
symmetric
(
horizontal:
12
,
vertical:
6
),
decoration:
BoxDecoration
(
color:
_getExpiringColor
(
order
.
expiringInColor
),
borderRadius:
BorderRadius
.
circular
(
16
),
),
child:
Text
(
order
.
expiringText
??
'Expiring info not available'
,
style:
const
TextStyle
(
fontSize:
12
,
fontFamily:
"Poppins"
,
fontWeight:
FontWeight
.
w500
,
color:
Colors
.
white
,
),
),
),
],
),
),
],
// Products section
)
if
(
order
.
products
!=
null
&&
order
.
products
!.
isNotEmpty
)
),
Container
(
const
SizedBox
(
height:
20
),
width:
double
.
infinity
,
margin:
const
EdgeInsets
.
symmetric
(
horizontal:
2
),
padding:
const
EdgeInsets
.
all
(
16
),
child:
Column
(
crossAxisAlignment:
CrossAxisAlignment
.
start
,
children:
[
const
Text
(
"Products"
,
style:
TextStyle
(
fontSize:
18
,
fontFamily:
"Poppins"
,
fontWeight:
FontWeight
.
w600
,
color:
Colors
.
black87
,
),
),
const
SizedBox
(
height:
16
),
// Feature cards grid
// Product list using ListView.builder
Container
(
ListView
.
separated
(
width:
double
.
infinity
,
physics:
const
NeverScrollableScrollPhysics
(),
color:
Colors
.
transparent
,
shrinkWrap:
true
,
child:
Column
(
itemCount:
order
.
products
!.
length
,
children:
[
separatorBuilder:
(
context
,
index
)
=>
const
SizedBox
(
height:
16
),
// First row of feature cards
itemBuilder:
(
context
,
index
)
{
Row
(
return
_buildProductItem
(
order
.
products
![
index
]);
children:
[
},
// Any Requirements Card
),
Expanded
(
child:
_buildFeatureCard
(
title:
"85 kVA"
,
description:
"PRIME POWER"
,
icon:
"assets/svg/power_ic.svg"
,
color:
Colors
.
orange
,
),
),
const
SizedBox
(
width:
16
),
// Subscribed Products Card
Expanded
(
child:
_buildFeatureCard
(
title:
"1500 RPM"
,
description:
"ENGINE SPEED"
,
icon:
"assets/svg/rpm_ic.svg"
,
color:
Colors
.
blue
,
),
),
],
),
const
SizedBox
(
height:
16
),
const
SizedBox
(
height:
16
),
// Divider
const
Divider
(
color:
Color
(
0xFFE5E5E5
),
thickness:
1
,
),
const
SizedBox
(
height:
16
),
// Second row of feature cards
// Help section
Row
(
InkResponse
(
children:
[
onTap:
()
=>
_showReasonBottomSheet
(),
// Have Complaints Card
child:
Row
(
Expanded
(
children:
[
child:
_buildFeatureCard
(
Text
(
title:
"75 dB"
,
"Need help with this order?"
,
description:
"LOW NOISE LEVEL"
,
style:
TextStyle
(
icon:
"assets/svg/noise_ic.svg"
,
fontSize:
14
,
color:
Colors
.
green
,
fontFamily:
"Poppins"
,
),
fontWeight:
FontWeight
.
w500
,
),
color:
Colors
.
grey
,
const
SizedBox
(
width:
16
),
),
// Know Your Payments Card
),
Expanded
(
],
child:
_buildFeatureCard
(
),
title:
"24 Hr"
,
),
description:
"LONGER RUNTIME"
,
const
SizedBox
(
height:
16
),
icon:
"assets/svg/clock_ic.svg"
,
color:
Colors
.
purple
,
),
),
],
),
const
SizedBox
(
height:
20
),
// View Bill button
],
SizedBox
(
),
width:
double
.
infinity
,
),
child:
ElevatedButton
(
],
onPressed:
()
{
Navigator
.
push
(
context
,
MaterialPageRoute
(
builder:
(
context
)
=>
BillDetailListScreen
())
);
// Handle view bill action
FocusScope
.
of
(
context
).
unfocus
();
},
style:
ElevatedButton
.
styleFrom
(
backgroundColor:
AppColors
.
buttonColor
,
foregroundColor:
Colors
.
white
,
padding:
const
EdgeInsets
.
symmetric
(
vertical:
16
),
shape:
RoundedRectangleBorder
(
borderRadius:
BorderRadius
.
circular
(
28
),
),
elevation:
0
,
),
child:
const
Text
(
"View Bill"
,
style:
TextStyle
(
fontSize:
16
,
fontFamily:
"Plus Jakarta Sans"
,
fontWeight:
FontWeight
.
w600
,
),
),
),
),
]
,
)
,
),
),
],
],
),
),
],
)
),
else
),
const
Padding
(
padding:
EdgeInsets
.
all
(
16.0
),
child:
Text
(
'No products found'
,
style:
TextStyle
(
fontSize:
16
,
fontFamily:
"Poppins"
,
color:
Colors
.
grey
,
),
),
),
SizedBox
(
height:
bottomPadding
+
20
),
],
),
),
),
),
);
);
}
}
Widget
_buildProductItem
(
Products
product
)
{
Widget
_buildFeatureCard
({
required
String
title
,
required
String
description
,
required
String
icon
,
required
Color
color
,
})
{
return
Container
(
return
Container
(
padding:
const
EdgeInsets
.
symmetric
(
horizontal:
12
,
vertical:
10
),
padding:
const
EdgeInsets
.
all
(
16
),
decoration:
BoxDecoration
(
decoration:
BoxDecoration
(
color:
Colors
.
grey
.
shade50
,
color:
Colors
.
white
,
borderRadius:
BorderRadius
.
circular
(
12
),
borderRadius:
BorderRadius
.
circular
(
18
),
border:
Border
.
all
(
// border: Border.all(
color:
Colors
.
grey
.
shade200
,
// color: const Color(0xFFE5E5E5),
width:
1
,
// width: 1,
),
// ),
// boxShadow: [
// BoxShadow(
// color: Colors.black.withOpacity(0.05),
// blurRadius: 8,
// offset: const Offset(0, 2),
// ),
// ],
),
),
child:
Column
(
child:
Column
(
crossAxisAlignment:
CrossAxisAlignment
.
center
,
crossAxisAlignment:
CrossAxisAlignment
.
start
,
children:
[
children:
[
// Icon and title row
// Product ID and Name
Container
(
width:
45
,
height:
45
,
decoration:
BoxDecoration
(
color:
color
.
withOpacity
(
0.1
),
borderRadius:
BorderRadius
.
circular
(
12
),
),
child:
Center
(
// Add this Center widget
child:
SvgPicture
.
asset
(
icon
,
height:
25
,
width:
25
,
// Remove fit: BoxFit.none
),
),
),
const
SizedBox
(
height:
4
),
Text
(
Text
(
title
,
product
.
idName
??
product
.
id
??
'N/A'
,
style:
TextStyle
(
style:
const
TextStyle
(
color:
AppColors
.
nearDarkText
,
fontSize:
14
,
fontSize:
14
,
fontWeight:
FontWeight
.
w600
,
fontFamily:
"Poppins"
,
fontWeight:
FontWeight
.
w500
,
color:
Colors
.
grey
,
),
),
),
),
const
SizedBox
(
height:
4
),
const
SizedBox
(
height:
4
),
// Description
Text
(
Text
(
description
,
product
.
prodName
??
'Product name not available'
,
style:
TextStyle
(
style:
const
TextStyle
(
color:
AppColors
.
subtitleText
,
fontSize:
16
,
fontFamily:
"Poppins"
,
fontFamily:
"Poppins"
,
fontWeight:
FontWeight
.
w
4
00
,
fontWeight:
FontWeight
.
w
6
00
,
fontSize:
12
,
color:
Colors
.
black87
,
),
),
),
),
],
const
SizedBox
(
height:
12
),
),
);
// Table-like layout for dates and price
}
Table
(
void
showPaymentBottomSheet
(
BuildContext
context
)
{
columnWidths:
const
{
showModalBottomSheet
(
0
:
FlexColumnWidth
(
2
),
context:
context
,
1
:
FlexColumnWidth
(
1
),
isScrollControlled:
true
,
},
backgroundColor:
Colors
.
transparent
,
children:
[
builder:
(
BuildContext
context
)
{
TableRow
(
return
SafeArea
(
bottom:
true
,
child:
Container
(
decoration:
const
BoxDecoration
(
color:
Colors
.
white
,
borderRadius:
BorderRadius
.
only
(
topLeft:
Radius
.
circular
(
24
),
topRight:
Radius
.
circular
(
24
),
),
),
child:
Padding
(
padding:
const
EdgeInsets
.
symmetric
(
horizontal:
16
,
vertical:
14
),
child:
Column
(
mainAxisSize:
MainAxisSize
.
min
,
crossAxisAlignment:
CrossAxisAlignment
.
start
,
children:
[
children:
[
// Header - Drag handle
TableCell
(
Center
(
child:
Text
(
child:
Container
(
product
.
dispatchDate
!=
null
?
width:
40
,
"Dispatched On
${product.dispatchDate!}
"
:
height:
4
,
"Dispatch date not available"
,
decoration:
BoxDecoration
(
style:
const
TextStyle
(
color:
Colors
.
grey
.
shade300
,
fontSize:
12
,
borderRadius:
BorderRadius
.
circular
(
2
),
fontFamily:
"Poppins"
,
fontWeight:
FontWeight
.
w400
,
color:
Colors
.
grey
,
),
),
),
),
),
),
const
SizedBox
(
height:
20
),
const
TableCell
(
child:
Align
(
// Pay Amount Section
alignment:
Alignment
.
centerRight
,
Row
(
child:
Text
(
mainAxisAlignment:
MainAxisAlignment
.
spaceBetween
,
"Plan"
,
children:
[
style:
TextStyle
(
const
Column
(
fontSize:
12
,
crossAxisAlignment:
CrossAxisAlignment
.
start
,
fontFamily:
"Poppins"
,
children:
[
fontWeight:
FontWeight
.
w500
,
Text
(
color:
Colors
.
black87
,
"Pay"
,
),
style:
TextStyle
(
fontSize:
16
,
fontWeight:
FontWeight
.
w400
,
color:
Color
(
0xFF777777
),
),
),
SizedBox
(
height:
4
),
Text
(
"₹4218"
,
style:
TextStyle
(
fontSize:
24
,
fontWeight:
FontWeight
.
w600
,
color:
Colors
.
black
,
),
),
],
),
// Rent Amount Section
Column
(
crossAxisAlignment:
CrossAxisAlignment
.
end
,
children:
[
const
Text
(
"Rent Amount"
,
style:
TextStyle
(
fontSize:
14
,
fontWeight:
FontWeight
.
w400
,
color:
Color
(
0xFF777777
),
),
),
const
SizedBox
(
height:
4
),
GestureDetector
(
onTap:
()
{
// Handle view bill details
},
child:
Text
(
"View Bill Details"
,
style:
TextStyle
(
fontSize:
14
,
fontWeight:
FontWeight
.
w500
,
color:
Color
(
0xFF008CDE
),
),
),
),
],
),
),
]
,
)
,
),
),
],
const
SizedBox
(
height:
10
),
),
const
Divider
(
height:
1
,
color:
Color
(
0xFFEEEEEE
)),
TableRow
(
const
SizedBox
(
height:
18
),
children:
[
TableCell
(
// Continue Payment Button
child:
Text
(
SizedBox
(
product
.
receivedDate
!=
null
?
width:
double
.
infinity
,
"Received On
${product.receivedDate!}
"
:
child:
ElevatedButton
(
"Receive date not available"
,
onPressed:
()
{
style:
const
TextStyle
(
// Handle continue payment
fontSize:
12
,
},
fontFamily:
"Poppins"
,
style:
ElevatedButton
.
styleFrom
(
fontWeight:
FontWeight
.
w400
,
backgroundColor:
const
Color
(
0xFF008CDE
),
color:
Colors
.
grey
,
foregroundColor:
Colors
.
white
,
disabledBackgroundColor:
const
Color
(
0xFF266E99
),
shape:
RoundedRectangleBorder
(
borderRadius:
BorderRadius
.
circular
(
30
),
),
padding:
const
EdgeInsets
.
symmetric
(
vertical:
16
),
),
),
child:
Padding
(
),
padding:
const
EdgeInsets
.
symmetric
(
horizontal:
22
),
),
child:
Row
(
TableCell
(
mainAxisAlignment:
MainAxisAlignment
.
spaceBetween
,
child:
Align
(
children:
[
alignment:
Alignment
.
centerRight
,
const
Text
(
child:
Text
(
"Continue Payment"
,
product
.
totalPrice
!=
null
?
style:
TextStyle
(
"
${product.totalPrice!}
/
${product.per ?? 'mo'}
"
:
color:
Color
(
0xFFFFFFFF
),
'Price not available'
,
fontSize:
16
,
style:
const
TextStyle
(
),
fontSize:
14
,
),
fontFamily:
"Poppins"
,
SvgPicture
.
asset
(
fontWeight:
FontWeight
.
w600
,
"assets/svg/continue_ic.svg"
,
color:
Colors
.
black87
,
color:
Color
(
0xFFFFFFFF
),
height:
25
,
width:
25
,
),
],
),
),
),
),
),
),
),
),
],
],
),
),
],
),
],
),
);
}
Color
_getExpiringColor
(
String
?
colorString
)
{
if
(
colorString
==
null
||
colorString
.
isEmpty
)
{
return
const
Color
(
0xFFFFEBEB
);
// Default color
}
try
{
// Assuming colorString is in format like "FFFF5757"
return
Color
(
int
.
parse
(
'FF
$colorString
'
,
radix:
16
));
}
catch
(
e
)
{
return
const
Color
(
0xFFFFEFEF
);
// Default color on error
}
}
void
_showReasonBottomSheet
()
{
// Your existing bottom sheet implementation
showModalBottomSheet
(
context:
context
,
backgroundColor:
Colors
.
white
,
shape:
const
RoundedRectangleBorder
(
borderRadius:
BorderRadius
.
only
(
topLeft:
Radius
.
circular
(
20
),
topRight:
Radius
.
circular
(
20
),
),
),
builder:
(
context
)
{
return
Container
(
padding:
const
EdgeInsets
.
symmetric
(
horizontal:
10
,
vertical:
14
),
child:
Column
(
mainAxisSize:
MainAxisSize
.
min
,
crossAxisAlignment:
CrossAxisAlignment
.
start
,
children:
[
const
Text
(
"Select Your Reason"
,
style:
TextStyle
(
fontSize:
18
,
fontFamily:
"Poppins"
,
fontWeight:
FontWeight
.
w600
,
color:
Colors
.
black87
,
),
),
const
SizedBox
(
height:
24
),
GridView
.
builder
(
shrinkWrap:
true
,
physics:
const
NeverScrollableScrollPhysics
(),
gridDelegate:
const
SliverGridDelegateWithFixedCrossAxisCount
(
crossAxisCount:
3
,
crossAxisSpacing:
12
,
mainAxisSpacing:
12
,
childAspectRatio:
0.99
,
),
itemCount:
createNewTickets
.
length
,
itemBuilder:
(
context
,
index
)
{
final
ticket
=
createNewTickets
[
index
];
final
String
title
=
ticket
[
'title'
]
??
'Unknown'
;
final
String
description
=
ticket
[
'description'
]
??
''
;
final
String
icon
=
ticket
[
'icon'
]
??
'assets/svg/help_ic.svg'
;
final
Color
color
=
ticket
[
'color'
]
??
Colors
.
grey
;
return
_buildFeatureCard
(
title:
title
,
description:
description
,
icon:
icon
,
color:
color
,
);
},
),
),
const
SizedBox
(
height:
24
),
],
),
),
);
);
},
},
);
);
}
}
Widget
_buildFeatureCard
({
required
String
title
,
required
String
description
,
required
String
icon
,
required
Color
color
,
})
{
return
GestureDetector
(
onTap:
()
{
Navigator
.
push
(
context
,
MaterialPageRoute
(
builder:
(
context
)
=>
HelpTicketScreen
(
reason:
title
,))
);
},
child:
Container
(
padding:
const
EdgeInsets
.
symmetric
(
horizontal:
2
,
vertical:
1
),
child:
Column
(
crossAxisAlignment:
CrossAxisAlignment
.
center
,
children:
[
// Icon container
Container
(
width:
88
,
height:
88
,
decoration:
BoxDecoration
(
color:
color
.
withOpacity
(
0.7
),
borderRadius:
BorderRadius
.
circular
(
12
),
),
child:
Center
(
child:
SizedBox
(
height:
40
,
width:
40
,
child:
SvgPicture
.
asset
(
icon
,
fit:
BoxFit
.
fitWidth
,
),
),
),
),
const
SizedBox
(
height:
8
),
// Title
SizedBox
(
child:
Text
(
title
,
textAlign:
TextAlign
.
center
,
style:
TextStyle
(
color:
AppColors
.
nearDarkText
,
fontSize:
14
,
fontWeight:
FontWeight
.
w400
,
fontFamily:
"Plus Jakarta Sans"
,
),
),
),
const
SizedBox
(
height:
4
),
],
),
),
);
}
}
}
\ No newline at end of file
lib/Screens/SplashScreen.dart
View file @
df116895
...
@@ -104,13 +104,14 @@ class _SplashScreenState extends State<SplashScreen> with SingleTickerProviderSt
...
@@ -104,13 +104,14 @@ class _SplashScreenState extends State<SplashScreen> with SingleTickerProviderSt
Future
<
void
>
_navigateToDashboard
()
async
{
Future
<
void
>
_navigateToDashboard
()
async
{
final
String
?
savedAccId
=
await
prefs
.
getString
(
"accId"
);
final
String
?
savedAccId
=
await
prefs
.
getString
(
"accId"
);
final
String
?
savedSessionId
=
await
prefs
.
getString
(
"session_id"
);
// Check if accId is not null and not empty
// Check if accId is not null and not empty
if
(
savedAccId
!=
null
&&
savedAccId
.
isNotEmpty
)
{
if
(
savedAccId
!=
null
&&
savedAccId
.
isNotEmpty
)
{
Navigator
.
pushReplacement
(
Navigator
.
pushReplacement
(
context
,
context
,
PageRouteBuilder
(
PageRouteBuilder
(
pageBuilder:
(
_
,
__
,
___
)
=>
DashboardScreen
(
accId:
savedAccId
),
pageBuilder:
(
_
,
__
,
___
)
=>
DashboardScreen
(
accId:
savedAccId
,
sessionId:
savedSessionId
.
toString
(),
),
transitionsBuilder:
(
_
,
animation
,
__
,
child
)
{
transitionsBuilder:
(
_
,
animation
,
__
,
child
)
{
return
FadeTransition
(
return
FadeTransition
(
opacity:
animation
,
opacity:
animation
,
...
...
lib/Screens/TransactionsScreen.dart
View file @
df116895
import
'package:flutter/material.dart'
;
import
'package:flutter/material.dart'
;
import
'package:flutter_svg/flutter_svg.dart'
;
import
'package:flutter_svg/flutter_svg.dart'
;
import
'package:provider/provider.dart'
;
import
'../Notifier/TransactionsProvider.dart'
;
import
'../Utility/AppColors.dart'
;
import
'../Utility/AppColors.dart'
;
class
TransactionsScreen
extends
StatefulWidget
{
class
TransactionsScreen
extends
StatefulWidget
{
const
TransactionsScreen
({
super
.
key
});
final
String
sessionId
;
final
String
accId
;
const
TransactionsScreen
({
super
.
key
,
required
this
.
sessionId
,
required
this
.
accId
,
});
@override
@override
State
<
TransactionsScreen
>
createState
()
=>
_TransactionsScreenState
();
State
<
TransactionsScreen
>
createState
()
=>
_TransactionsScreenState
();
}
}
class
_TransactionsScreenState
extends
State
<
TransactionsScreen
>
{
class
_TransactionsScreenState
extends
State
<
TransactionsScreen
>
{
// Dummy data for transactions
@override
final
List
<
Map
<
String
,
dynamic
>>
transactions
=
[
void
initState
()
{
{
super
.
initState
();
"type"
:
"debit"
,
Future
.
microtask
(()
{
"title"
:
"Payment for June Rent"
,
Provider
.
of
<
TransactionsProvider
>(
context
,
listen:
false
)
"date"
:
"25 Dec 2025"
,
.
fetchRentalTransactions
(
widget
.
sessionId
,
widget
.
accId
);
"amount"
:
"₹5,390.00"
,
});
"ref"
:
"₹1,12,300"
}
},
{
"type"
:
"debit"
,
"title"
:
"Payment for June Rent"
,
"date"
:
"25 Dec 2025"
,
"amount"
:
"₹2,512.00"
,
"ref"
:
"₹26,300"
},
{
"type"
:
"credit"
,
"title"
:
"Refund of Deposit Amount"
,
"date"
:
"25 Dec 2025"
,
"amount"
:
"₹19,790.00"
,
"ref"
:
"₹1,26,300"
},
{
"type"
:
"debit"
,
"title"
:
"Payment for June Rent"
,
"date"
:
"25 Dec 2025"
,
"amount"
:
"₹5,390.00"
,
"ref"
:
"₹1,12,300"
},
{
"type"
:
"debit"
,
"title"
:
"Payment for June Rent"
,
"date"
:
"25 Dec 2025"
,
"amount"
:
"₹2,512.00"
,
"ref"
:
"₹26,300"
},
{
"type"
:
"credit"
,
"title"
:
"Refund of Deposit Amount"
,
"date"
:
"25 Dec 2025"
,
"amount"
:
"₹19,790.00"
,
"ref"
:
"₹1,26,300"
},
];
@override
@override
Widget
build
(
BuildContext
context
)
{
Widget
build
(
BuildContext
context
)
{
final
provider
=
Provider
.
of
<
TransactionsProvider
>(
context
);
final
data
=
provider
.
transactionsResponse
;
return
SafeArea
(
return
SafeArea
(
top:
false
,
top:
false
,
child:
Scaffold
(
child:
Scaffold
(
...
@@ -72,11 +46,11 @@ class _TransactionsScreenState extends State<TransactionsScreen> {
...
@@ -72,11 +46,11 @@ class _TransactionsScreenState extends State<TransactionsScreen> {
onTap:
()
=>
Navigator
.
pop
(
context
,
true
),
onTap:
()
=>
Navigator
.
pop
(
context
,
true
),
child:
SvgPicture
.
asset
(
child:
SvgPicture
.
asset
(
"assets/svg/continue_left_ic.svg"
,
"assets/svg/continue_left_ic.svg"
,
height:
25
height:
25
,
),
),
),
),
const
SizedBox
(
width:
10
),
const
SizedBox
(
width:
10
),
Text
(
const
Text
(
"Transactions"
,
"Transactions"
,
style:
TextStyle
(
style:
TextStyle
(
fontSize:
16
,
fontSize:
16
,
...
@@ -88,208 +62,341 @@ class _TransactionsScreenState extends State<TransactionsScreen> {
...
@@ -88,208 +62,341 @@ class _TransactionsScreenState extends State<TransactionsScreen> {
],
],
),
),
),
),
// Main content
body:
SingleChildScrollView
(
/// ✅ Main Content
padding:
const
EdgeInsets
.
symmetric
(
horizontal:
16
,
vertical:
16
),
body:
provider
.
isLoading
?
const
Center
(
child:
CircularProgressIndicator
())
:
data
==
null
?
const
Center
(
child:
Text
(
"No transactions available"
))
:
SingleChildScrollView
(
padding:
const
EdgeInsets
.
symmetric
(
horizontal:
16
,
vertical:
16
),
child:
Column
(
child:
Column
(
crossAxisAlignment:
CrossAxisAlignment
.
start
,
children:
[
children:
[
SizedBox
(
height:
4
,),
_buildBalanceCard
(
data
),
// Balance Card
const
SizedBox
(
height:
16
),
Container
(
width:
double
.
infinity
,
/// 🗓️ Monthly Grouped Transactions
padding:
const
EdgeInsets
.
symmetric
(
vertical:
24
,
horizontal:
16
),
...
data
.
transactions
!.
entries
.
map
((
entry
)
{
decoration:
BoxDecoration
(
final
month
=
entry
.
key
;
borderRadius:
BorderRadius
.
circular
(
20
),
final
items
=
entry
.
value
;
gradient:
const
LinearGradient
(
return
Column
(
colors:
[
crossAxisAlignment:
CrossAxisAlignment
.
start
,
Color
(
0xFFE9FFEF
),
Color
(
0xFFD6FFDF
),
],
begin:
Alignment
.
topLeft
,
end:
Alignment
.
bottomRight
,
),
),
child:
Column
(
children:
[
children:
[
const
SizedBox
(
height:
12
),
Text
(
Text
(
"₹12,596"
,
month
,
style:
TextStyle
(
style:
const
TextStyle
(
fontSize:
15
,
fontFamily:
"Poppins"
,
fontFamily:
"Poppins"
,
fontWeight:
FontWeight
.
w500
,
fontWeight:
FontWeight
.
w600
,
fontSize:
34
,
color:
Colors
.
black
,
color:
AppColors
.
cardAmountText
,
),
),
),
),
const
SizedBox
(
height:
4
),
const
SizedBox
(
height:
8
),
Text
(
...
items
.
map
((
txn
)
=>
_buildTransactionItem
(
"Balance Amount"
,
type:
txn
.
type
??
""
,
title:
txn
.
purpose
??
"-"
,
date:
txn
.
date
??
""
,
amount:
"₹
${txn.amount ?? "0.00"}
"
,
)),
],
);
}),
],
),
),
),
);
}
/// 💰 Balance Card (Top Section)
Widget
_buildBalanceCard
(
data
)
{
final
balance
=
data
.
balanceAmount
??
"0"
;
final
credit
=
data
.
creditAmount
??
"0"
;
final
debit
=
data
.
debitAmount
??
"0"
;
return
Stack
(
children:
[
Container
(
width:
double
.
infinity
,
padding:
const
EdgeInsets
.
symmetric
(
vertical:
24
,
horizontal:
18
),
decoration:
BoxDecoration
(
gradient:
LinearGradient
(
begin:
Alignment
.
topCenter
,
end:
Alignment
.
bottomCenter
,
colors:
[
Color
(
0xFFF3F3F3
),
Color
(
0xFFB5FFD1
),
],
),
borderRadius:
BorderRadius
.
circular
(
16
),
boxShadow:
[
BoxShadow
(
color:
Colors
.
black
.
withOpacity
(
0.03
),
blurRadius:
8
,
offset:
const
Offset
(
0
,
2
),
)
],
),
child:
Column
(
crossAxisAlignment:
CrossAxisAlignment
.
start
,
children:
[
/// Header
Row
(
mainAxisAlignment:
MainAxisAlignment
.
spaceBetween
,
children:
[
const
Text
(
"Balance Amount"
,
style:
TextStyle
(
fontFamily:
"Poppins"
,
fontSize:
13
,
fontWeight:
FontWeight
.
w500
,
color:
Colors
.
redAccent
,
),
),
TextButton
(
onPressed:
()
{},
child:
const
Text
(
"Pay Now"
,
style:
TextStyle
(
style:
TextStyle
(
fontFamily:
"Poppins"
,
fontFamily:
"Poppins"
,
fontWeight:
FontWeight
.
w400
,
fontWeight:
FontWeight
.
w500
,
fontSize:
14
,
color:
Color
(
0xFF007AFF
),
color:
AppColors
.
cardAmountText
,
),
),
),
),
const
SizedBox
(
height:
10
),
),
Container
(
],
height:
1
,
),
color:
const
Color
(
0xFF777777
).
withOpacity
(
0.3
),
),
const
SizedBox
(
height:
14
),
// Credited / Debited info
Text
(
Row
(
"₹
$balance
"
,
mainAxisAlignment:
MainAxisAlignment
.
spaceEvenly
,
style:
const
TextStyle
(
children:
[
fontFamily:
"Poppins"
,
_buildAmountSummary
(
fontWeight:
FontWeight
.
w600
,
icon:
"assets/svg/cross_down_arrow.svg"
,
fontSize:
30
,
color:
Colors
.
black
,
),
),
const
SizedBox
(
height:
4
),
const
Text
(
"*Make sure to pay before you incur any fines."
,
style:
TextStyle
(
fontFamily:
"Poppins"
,
fontSize:
12
,
color:
Colors
.
grey
,
),
),
const
SizedBox
(
height:
14
),
/// Credit / Debit Row
Row
(
mainAxisAlignment:
MainAxisAlignment
.
spaceEvenly
,
children:
[
// ✅ Bill Paid
Row
(
children:
[
Container
(
height:
46
,
width:
46
,
decoration:
BoxDecoration
(
color:
Colors
.
white
,
color:
Colors
.
white
,
amount:
"₹26,300"
,
borderRadius:
BorderRadius
.
circular
(
22
),
label:
"Credited Amount"
,
),
),
_buildAmountSummary
(
child:
Center
(
icon:
"assets/svg/cross_up_arrow.svg"
,
child:
SvgPicture
.
asset
(
color:
Colors
.
white
,
"assets/svg/cross_down_arrow.svg"
,
amount:
"₹26,300"
,
height:
18
,
label:
"Debited Amount"
,
width:
18
,
fit:
BoxFit
.
contain
,
// Ensures the SVG scales within bounds
),
),
),
],
),
),
],
),
),
const
SizedBox
(
height:
16
),
const
SizedBox
(
width:
10
),
Column
(
crossAxisAlignment:
CrossAxisAlignment
.
start
,
children:
[
Text
(
"₹
$credit
"
,
style:
const
TextStyle
(
fontFamily:
"Poppins"
,
fontWeight:
FontWeight
.
w500
,
fontSize:
13
,
color:
Colors
.
black
,
),
),
Text
(
"Bill Paid"
,
style:
TextStyle
(
fontFamily:
"Poppins"
,
fontSize:
11
,
color:
Colors
.
black54
,
),
),
],
),
],
),
const
SizedBox
(
width:
10
),
// Transaction list
// ❌ Bill Pending
Column
(
Row
(
children:
transactions
.
map
((
t
)
{
children:
[
return
_buildTransactionItem
(
Container
(
type:
t
[
"type"
],
height:
46
,
title:
t
[
"title"
],
width:
46
,
date:
t
[
"date"
],
decoration:
BoxDecoration
(
amount:
t
[
"amount"
],
color:
Colors
.
white
,
ref:
t
[
"ref"
],
borderRadius:
BorderRadius
.
circular
(
22
),
);
),
}).
toList
(),
child:
Center
(
child:
SvgPicture
.
asset
(
"assets/svg/cross_up_arrow.svg"
,
height:
18
,
width:
18
,
fit:
BoxFit
.
contain
,
// Ensures the SVG scales within bounds
),
),
),
const
SizedBox
(
width:
10
),
Column
(
crossAxisAlignment:
CrossAxisAlignment
.
start
,
children:
[
Text
(
"₹
$debit
"
,
style:
const
TextStyle
(
fontFamily:
"Poppins"
,
fontWeight:
FontWeight
.
w500
,
fontSize:
13
,
color:
Colors
.
black
,
),
),
Text
(
"Bill Pending"
,
style:
TextStyle
(
fontFamily:
"Poppins"
,
fontSize:
11
,
color:
Colors
.
black54
,
),
)
],
),
],
),
],
),
),
],
],
),
),
),
),
),
);
}
Widget
_buildAmountSummary
({
/// White overlay card (unchanged)
required
String
icon
,
required
Color
color
,
required
String
amount
,
required
String
label
,
})
{
return
Row
(
children:
[
// Icon and title row
Container
(
Container
(
width:
50
,
width:
double
.
infinity
,
height:
50
,
padding:
const
EdgeInsets
.
all
(
20
)
,
decoration:
BoxDecoration
(
decoration:
BoxDecoration
(
color:
c
olor
.
w
ithOpacity
(
0.9
)
,
color:
C
olor
s
.
w
hite
,
borderRadius:
BorderRadius
.
circular
(
30
),
borderRadius:
BorderRadius
.
circular
(
16
),
),
),
child:
Center
(
// Add this Center widget
child:
Column
(
child:
SvgPicture
.
asset
(
crossAxisAlignment:
CrossAxisAlignment
.
start
,
icon
,
children:
[
height:
20
,
Row
(
width:
20
,
children:
[
// Remove fit: BoxFit.none
const
Text
(
),
"Balance Amount"
,
),
style:
TextStyle
(
),
fontFamily:
"Poppins"
,
const
SizedBox
(
width:
8
),
color:
Color
(
0xFFF00000
),
Column
(
fontSize:
14
,
crossAxisAlignment:
CrossAxisAlignment
.
start
,
fontWeight:
FontWeight
.
w400
,
children:
[
),
Text
(
),
amount
,
const
SizedBox
(
width:
4
),
style:
TextStyle
(
SvgPicture
.
asset
(
fontFamily:
"Poppins"
,
"assets/svg/continue_ic.svg"
,
fontWeight:
FontWeight
.
w400
,
color:
const
Color
(
0xFFF00000
),
fontSize:
14
,
height:
18
,
color:
Colors
.
black
,
width:
18
,
),
],
),
),
),
const
SizedBox
(
height:
8
),
Text
(
Row
(
label
,
mainAxisAlignment:
MainAxisAlignment
.
spaceBetween
,
style:
TextStyle
(
children:
[
fontFamily:
"Poppins"
,
Text
(
fontWeight:
FontWeight
.
w400
,
"₹
$balance
"
,
fontSize:
12
,
style:
const
TextStyle
(
color:
Colors
.
grey
.
shade600
,
fontFamily:
"Poppins"
,
color:
Colors
.
black
,
fontSize:
32
,
fontWeight:
FontWeight
.
w500
,
),
),
InkResponse
(
child:
const
Text
(
"Pay Now"
,
style:
TextStyle
(
fontFamily:
"Poppins"
,
color:
Color
(
0xFF008CDE
),
fontSize:
14
,
fontWeight:
FontWeight
.
w500
,
),
),
),
],
),
),
),
const
SizedBox
(
height:
12
),
],
Text
(
"*Make sure to pay before you incur any fines."
,
style:
TextStyle
(
fontFamily:
"Poppins"
,
color:
Colors
.
grey
.
shade500
,
fontSize:
12
,
fontWeight:
FontWeight
.
w400
,
),
),
],
),
),
),
],
],
);
);
}
}
/// 📋 Transaction Item
Widget
_buildTransactionItem
({
Widget
_buildTransactionItem
({
required
String
type
,
required
String
type
,
required
String
title
,
required
String
title
,
required
String
date
,
required
String
date
,
required
String
amount
,
required
String
amount
,
required
String
ref
,
})
{
})
{
final
isCredit
=
type
==
"credit"
;
final
isCredit
=
type
.
toLowerCase
()
==
"credit"
;
return
Container
(
return
Container
(
margin:
const
EdgeInsets
.
only
(
bottom:
1
2
),
margin:
const
EdgeInsets
.
only
(
bottom:
1
0
),
padding:
const
EdgeInsets
.
symmetric
(
vertical:
1
0
,
horizontal:
14
),
padding:
const
EdgeInsets
.
symmetric
(
vertical:
1
2
,
horizontal:
14
),
decoration:
BoxDecoration
(
decoration:
BoxDecoration
(
color:
Colors
.
white
,
color:
Colors
.
white
,
borderRadius:
BorderRadius
.
circular
(
14
),
borderRadius:
BorderRadius
.
circular
(
14
),
// border: Border.all(color: Colors.grey.shade200, width: 1),
// boxShadow: [
// BoxShadow(
// color: Colors.black.withOpacity(0.02),
// blurRadius: 5,
// offset: const Offset(0, 1),
// ),
// ],
),
),
child:
Row
(
child:
Row
(
children:
[
children:
[
// Icon and title row
CircleAvatar
(
Container
(
radius:
18
,
width:
50
,
backgroundColor:
height:
50
,
isCredit
?
Colors
.
green
.
shade50
:
Colors
.
red
.
shade50
,
decoration:
BoxDecoration
(
child:
SvgPicture
.
asset
(
color:
isCredit
?
Colors
.
green
.
withOpacity
(
0.09
)
:
Colors
.
red
.
withOpacity
(
0.09
),
isCredit
borderRadius:
BorderRadius
.
circular
(
30
),
?
"assets/svg/cross_down_arrow.svg"
),
:
"assets/svg/cross_up_arrow.svg"
,
child:
Center
(
// Add this Center widget
height:
18
,
child:
SvgPicture
.
asset
(
isCredit
?
"assets/svg/cross_down_arrow.svg"
:
"assets/svg/cross_up_arrow.svg"
,
height:
20
,
width:
20
,
// Remove fit: BoxFit.none
),
),
),
),
),
// Container(
// padding: const EdgeInsets.all(8),
// decoration: BoxDecoration(
// color: isCredit
// ? const Color(0xFFE8F9EE)
// : const Color(0xFFFFEBEB),
// shape: BoxShape.circle,
// ),
// child: Icon(
// isCredit ? Icons.arrow_downward_rounded : Icons.arrow_upward_rounded,
// color: isCredit ? Colors.green : Colors.red,
// size: 20,
// ),
// ),
const
SizedBox
(
width:
12
),
const
SizedBox
(
width:
12
),
Expanded
(
Expanded
(
child:
Column
(
child:
Column
(
...
@@ -300,7 +407,6 @@ class _TransactionsScreenState extends State<TransactionsScreen> {
...
@@ -300,7 +407,6 @@ class _TransactionsScreenState extends State<TransactionsScreen> {
overflow:
TextOverflow
.
ellipsis
,
overflow:
TextOverflow
.
ellipsis
,
style:
const
TextStyle
(
style:
const
TextStyle
(
fontFamily:
"Poppins"
,
fontFamily:
"Poppins"
,
fontWeight:
FontWeight
.
w400
,
fontSize:
14
,
fontSize:
14
,
color:
Colors
.
black
,
color:
Colors
.
black
,
),
),
...
@@ -308,51 +414,23 @@ class _TransactionsScreenState extends State<TransactionsScreen> {
...
@@ -308,51 +414,23 @@ class _TransactionsScreenState extends State<TransactionsScreen> {
const
SizedBox
(
height:
4
),
const
SizedBox
(
height:
4
),
Text
(
Text
(
date
,
date
,
style:
TextStyle
(
style:
const
TextStyle
(
fontFamily:
"Poppins"
,
fontFamily:
"Poppins"
,
fontWeight:
FontWeight
.
w400
,
fontSize:
12
,
fontSize:
12
,
color:
Colors
.
grey
.
shade600
,
color:
Colors
.
grey
,
),
),
),
),
],
],
),
),
),
),
const
SizedBox
(
width:
12
),
const
SizedBox
(
width:
12
),
Column
(
Text
(
crossAxisAlignment:
CrossAxisAlignment
.
end
,
amount
,
children:
[
style:
const
TextStyle
(
Text
(
fontFamily:
"Poppins"
,
amount
,
fontSize:
14
,
style:
TextStyle
(
color:
Colors
.
black
,
fontFamily:
"Poppins"
,
),
fontWeight:
FontWeight
.
w400
,
fontSize:
14
,
color:
Colors
.
black
,
),
),
const
SizedBox
(
height:
4
),
Row
(
children:
[
Text
(
ref
,
style:
TextStyle
(
fontFamily:
"Poppins"
,
fontWeight:
FontWeight
.
w400
,
fontSize:
12
,
color:
Colors
.
grey
.
shade600
,
),
),
const
SizedBox
(
width:
4
),
//
SvgPicture
.
asset
(
"assets/svg/rupee_coin_ic.svg"
,
height:
14
,
width:
14
,
// Remove fit: BoxFit.none
),
],
),
],
),
),
],
],
),
),
...
...
lib/Screens/authScreen/OTP_Screen.dart
View file @
df116895
...
@@ -91,12 +91,16 @@ class _OtpScreenState extends State<OtpScreen> {
...
@@ -91,12 +91,16 @@ class _OtpScreenState extends State<OtpScreen> {
// Added null check for accId
// Added null check for accId
if
(
rentalProvider
.
otpResponse
?.
accId
!=
null
)
{
if
(
rentalProvider
.
otpResponse
?.
accId
!=
null
)
{
await
prefs
.
saveString
(
"accId"
,
rentalProvider
.
otpResponse
!.
accId
!);
await
prefs
.
saveString
(
"accId"
,
rentalProvider
.
otpResponse
!.
accId
!);
await
prefs
.
saveString
(
"session_id"
,
rentalProvider
.
otpResponse
!.
sessionId
!);
}
}
// Navigate to dashboard
// Navigate to dashboard
Navigator
.
pushReplacement
(
Navigator
.
pushReplacement
(
context
,
context
,
MaterialPageRoute
(
builder:
(
_
)
=>
DashboardScreen
(
accId:
rentalProvider
.
otpResponse
!.
accId
!,)),
MaterialPageRoute
(
builder:
(
_
)
=>
DashboardScreen
(
accId:
rentalProvider
.
otpResponse
!.
accId
!,
sessionId:
rentalProvider
.
otpResponse
!.
sessionId
!,)
),
);
);
}
else
{
}
else
{
// ❌ Invalid OTP
// ❌ Invalid OTP
...
...
lib/Services/api_URLs.dart
View file @
df116895
/// base Url of api
/// base Url of api
const
baseUrl
=
"https://erp.gengroup.in/ci/app/Inventory/"
;
const
baseUrl
=
"https://erp.gengroup.in/ci/app/Rental/Rental_Home/"
;
const
baseUrl2
=
"https://erp.gengroup.in/ci/app/Rental/"
;
/// tokens url
/// tokens url
const
addFcmTokenUrl
=
"
${baseUrl}
add_fcm_token"
;
const
addFcmTokenUrl
=
"
${baseUrl}
add_fcm_token"
;
/// payments and bills
/// payments and bills
const
addPaymentUrl
=
"
${baseUrl}
add_payment"
;
const
addPaymentUrl
=
"
${baseUrl}
add_payment"
;
const
rentalPaymentDetailsUrl
=
"
${baseUrl}
rental_payment_detail
s"
;
const
transactionsUrl
=
"
${baseUrl}
transaction
s"
;
const
balanceUrl
=
"
${baseUrl}
balance"
;
const
balanceUrl
=
"
${baseUrl}
balance"
;
const
billDetailsUrl
=
"
${baseUrl}
bill_details"
;
const
billDetailsUrl
=
"
${baseUrl}
bill_details"
;
const
billListUrl
=
"
${baseUrl}
bill_list"
;
const
billListUrl
=
"
${baseUrl}
bill_list"
;
...
@@ -21,7 +22,7 @@ const getRentalAccInfoUrl = "${baseUrl}get_rental_acc_info";
...
@@ -21,7 +22,7 @@ const getRentalAccInfoUrl = "${baseUrl}get_rental_acc_info";
const
orderDetailsBillUrl
=
"
${baseUrl}
order_details_bill"
;
const
orderDetailsBillUrl
=
"
${baseUrl}
order_details_bill"
;
const
orderDetailsMainUrl
=
"
${baseUrl}
order_details_main"
;
const
orderDetailsMainUrl
=
"
${baseUrl}
order_details_main"
;
const
orderDetailsProductUrl
=
"
${baseUrl}
order_details_product"
;
const
orderDetailsProductUrl
=
"
${baseUrl}
order_details_product"
;
const
orderListUrl
=
"
${baseUrl}
order_
list
"
;
const
subsOrderDetails
=
"
${baseUrl}
subs_
order_
details
"
;
const
tagOrderUrl
=
"
${baseUrl}
tag_order"
;
const
tagOrderUrl
=
"
${baseUrl}
tag_order"
;
/// tickets
/// tickets
...
@@ -33,6 +34,6 @@ const ticketListUrl = "${baseUrl}ticket_list";
...
@@ -33,6 +34,6 @@ const ticketListUrl = "${baseUrl}ticket_list";
/// dashboard and login
/// dashboard and login
const
fetchMobileUrl
=
"
${baseUrl}
fetch_mobile_number"
;
const
fetchMobileUrl
=
"
${baseUrl2}
Rental_Auth/fetch_mobile_number"
;
const
fetchOtpUrl
=
"
${baseUrl}
login"
;
const
fetchOtpUrl
=
"
${baseUrl2}
Rental_Auth/login"
;
const
dashboardUrl
=
"
${baseUrl}
dashboard"
;
const
dashboardUrl
=
"
${baseUrl2}
Rental_Home/dashboard"
;
\ No newline at end of file
\ No newline at end of file
lib/Services/api_calling.dart
View file @
df116895
...
@@ -7,11 +7,12 @@ import 'package:gen_rentals/Models/billProductResponse.dart';
...
@@ -7,11 +7,12 @@ import 'package:gen_rentals/Models/billProductResponse.dart';
import
'package:gen_rentals/Models/orderDetailsBillResponse.dart'
;
import
'package:gen_rentals/Models/orderDetailsBillResponse.dart'
;
import
'package:gen_rentals/Models/orderDetailsMainResponse.dart'
;
import
'package:gen_rentals/Models/orderDetailsMainResponse.dart'
;
import
'package:gen_rentals/Models/orderDetailsProductResponse.dart'
;
import
'package:gen_rentals/Models/orderDetailsProductResponse.dart'
;
import
'package:gen_rentals/Models/
orderList
Response.dart'
;
import
'package:gen_rentals/Models/
SubscribeOrderDetails
Response.dart'
;
import
'package:gen_rentals/Models/ticketListResponse.dart'
;
import
'package:gen_rentals/Models/ticketListResponse.dart'
;
import
'package:gen_rentals/Notifier/billDetailsResponse.dart'
;
import
'package:gen_rentals/Notifier/billDetailsResponse.dart'
;
import
'../Models/DashboardResponse.dart'
;
import
'../Models/DashboardResponse.dart'
;
import
'../Models/RentalPaymentDetailsResponse.dart'
;
import
'../Models/RentalPaymentDetailsResponse.dart'
;
import
'../Models/TransactionsResponse.dart'
;
import
'../Models/rentalAccountResponse.dart'
;
import
'../Models/rentalAccountResponse.dart'
;
import
'../Models/rentalContactResponse.dart'
;
import
'../Models/rentalContactResponse.dart'
;
import
'../Notifier/RentalContactProvider .dart'
;
import
'../Notifier/RentalContactProvider .dart'
;
...
@@ -47,13 +48,15 @@ class ApiCalling {
...
@@ -47,13 +48,15 @@ class ApiCalling {
static
Future
<
FetchMobileResponse
?>
fetchMobileOtpApi
(
static
Future
<
FetchMobileResponse
?>
fetchMobileOtpApi
(
String
mob
,
String
mob
,
String
otp
String
otp
,
Map
<
String
,
String
>
deviceDetails
)
async
{
)
async
{
debugPrint
(
"############################### Api calling "
);
debugPrint
(
"############################### Api calling "
);
try
{
try
{
Map
<
String
,
String
>
data
=
{
Map
<
String
,
String
>
data
=
{
"mob"
:
mob
,
"mob"
:
mob
,
"otp"
:
otp
,
"otp"
:
otp
,
"device_details"
:
deviceDetails
.
toString
(),
};
};
final
res
=
await
post
(
data
,
fetchOtpUrl
,
{});
final
res
=
await
post
(
data
,
fetchOtpUrl
,
{});
...
@@ -204,23 +207,24 @@ class ApiCalling {
...
@@ -204,23 +207,24 @@ class ApiCalling {
}
}
}
}
/// Fetch
Order List
/// Fetch
Subscribe Order Details
static
Future
<
OrderList
Response
?>
fetchOrder
List
Api
(
static
Future
<
SubscribeOrderDetails
Response
?>
fetch
Subs
Order
Detail
Api
(
String
sessionId
,
String
sessionId
,
String
emp
Id
,
String
order
Id
,
String
accId
,
String
accId
,
)
async
{
)
async
{
try
{
try
{
Map
<
String
,
String
>
data
=
{
Map
<
String
,
String
>
data
=
{
"session_id"
:
sessionId
,
"session_id"
:
sessionId
,
"
emp
_id"
:
emp
Id
,
"
order
_id"
:
order
Id
,
"acc_id"
:
accId
,
"acc_id"
:
accId
,
};
};
final
res
=
await
post
(
data
,
orderListUrl
,
{});
final
res
=
await
post
(
data
,
subsOrderDetails
,
{});
debugPrint
(
"Subscribe order details Response:
${res?.body}
"
);
if
(
res
!=
null
)
{
if
(
res
!=
null
)
{
return
OrderList
Response
.
fromJson
(
jsonDecode
(
res
.
body
));
return
SubscribeOrderDetails
Response
.
fromJson
(
jsonDecode
(
res
.
body
));
}
else
{
}
else
{
debugPrint
(
"Null Response"
);
debugPrint
(
"Null Response"
);
return
null
;
return
null
;
...
@@ -286,23 +290,21 @@ class ApiCalling {
...
@@ -286,23 +290,21 @@ class ApiCalling {
}
}
}
}
/// Fetch Rental
Payment Details
/// Fetch Rental
Transaction
static
Future
<
RentalPaymentDetail
sResponse
?>
fetchRental
PaymentDetail
sApi
(
static
Future
<
Transaction
sResponse
?>
fetchRental
sTransaction
sApi
(
String
sessionId
,
String
sessionId
,
String
empId
,
String
accId
,
String
billId
,
)
async
{
)
async
{
try
{
try
{
Map
<
String
,
String
>
data
=
{
Map
<
String
,
String
>
data
=
{
"session_id"
:
sessionId
,
"session_id"
:
sessionId
,
"emp_id"
:
empId
,
"acc_id"
:
accId
,
"bill_id"
:
billId
,
};
};
final
res
=
await
post
(
data
,
rentalPaymentDetail
sUrl
,
{});
final
res
=
await
post
(
data
,
transaction
sUrl
,
{});
if
(
res
!=
null
)
{
if
(
res
!=
null
)
{
return
RentalPaymentDetail
sResponse
.
fromJson
(
jsonDecode
(
res
.
body
));
return
Transaction
sResponse
.
fromJson
(
jsonDecode
(
res
.
body
));
}
else
{
}
else
{
debugPrint
(
"Null Response"
);
debugPrint
(
"Null Response"
);
return
null
;
return
null
;
...
@@ -535,11 +537,13 @@ class ApiCalling {
...
@@ -535,11 +537,13 @@ class ApiCalling {
/// Fetch Dashboard
/// Fetch Dashboard
static
Future
<
DashboardResponse
?>
fetchDashboardApi
(
static
Future
<
DashboardResponse
?>
fetchDashboardApi
(
String
accId
,
String
accId
,
String
sessionId
,
)
async
{
)
async
{
debugPrint
(
"Dashboard Api called ##############"
);
debugPrint
(
"Dashboard Api called ##############"
);
try
{
try
{
Map
<
String
,
String
>
data
=
{
Map
<
String
,
String
>
data
=
{
"acc_id"
:
accId
,
"acc_id"
:
accId
,
"session_id"
:
sessionId
,
};
};
debugPrint
(
"Account Id :
$accId
"
);
debugPrint
(
"Account Id :
$accId
"
);
...
...
lib/main.dart
View file @
df116895
import
'package:flutter/material.dart'
;
import
'package:flutter/material.dart'
;
import
'package:gen_rentals/Notifier/DashboardProvider.dart'
;
import
'package:gen_rentals/Notifier/DashboardProvider.dart'
;
import
'package:gen_rentals/Notifier/TransactionsProvider.dart'
;
import
'package:gen_rentals/Screens/SplashScreen.dart'
;
import
'package:gen_rentals/Screens/SplashScreen.dart'
;
import
'package:provider/provider.dart'
;
import
'package:provider/provider.dart'
;
import
'Notifier/RentalContactProvider .dart'
;
import
'Notifier/RentalContactProvider .dart'
;
import
'Notifier/SubscribeOrderDetailsProvider.dart'
;
import
'Notifier/theme_provider.dart'
;
import
'Notifier/theme_provider.dart'
;
import
'Screens/authScreen/LoginScreen.dart'
;
import
'Screens/authScreen/LoginScreen.dart'
;
...
@@ -28,6 +30,8 @@ class MyApp extends StatelessWidget {
...
@@ -28,6 +30,8 @@ class MyApp extends StatelessWidget {
ChangeNotifierProvider
<
DashboardProvider
>(
create:
(
_
)
=>
DashboardProvider
()),
ChangeNotifierProvider
<
DashboardProvider
>(
create:
(
_
)
=>
DashboardProvider
()),
ChangeNotifierProvider
<
RentalProvider
>(
create:
(
_
)
=>
RentalProvider
(),),
ChangeNotifierProvider
<
RentalProvider
>(
create:
(
_
)
=>
RentalProvider
(),),
ChangeNotifierProvider
<
ThemeProvider
>(
create:
(
_
)
=>
ThemeProvider
(),),
ChangeNotifierProvider
<
ThemeProvider
>(
create:
(
_
)
=>
ThemeProvider
(),),
ChangeNotifierProvider
(
create:
(
_
)
=>
SubscribeOrderDetailsProvider
()),
ChangeNotifierProvider
(
create:
(
_
)
=>
TransactionsProvider
()),
],
],
child:
Consumer
<
ThemeProvider
>(
child:
Consumer
<
ThemeProvider
>(
builder:
(
context
,
themeProvider
,
child
)
{
builder:
(
context
,
themeProvider
,
child
)
{
...
...
pubspec.lock
View file @
df116895
...
@@ -129,6 +129,22 @@ packages:
...
@@ -129,6 +129,22 @@ packages:
url: "https://pub.dev"
url: "https://pub.dev"
source: hosted
source: hosted
version: "0.7.11"
version: "0.7.11"
device_info_plus:
dependency: "direct dev"
description:
name: device_info_plus
sha256: a7fd703482b391a87d60b6061d04dfdeab07826b96f9abd8f5ed98068acc0074
url: "https://pub.dev"
source: hosted
version: "10.1.2"
device_info_plus_platform_interface:
dependency: transitive
description:
name: device_info_plus_platform_interface
sha256: e1ea89119e34903dca74b883d0dd78eb762814f97fb6c76f35e9ff74d261a18f
url: "https://pub.dev"
source: hosted
version: "7.0.3"
fake_async:
fake_async:
dependency: transitive
dependency: transitive
description:
description:
...
@@ -781,6 +797,14 @@ packages:
...
@@ -781,6 +797,14 @@ packages:
url: "https://pub.dev"
url: "https://pub.dev"
source: hosted
source: hosted
version: "5.13.0"
version: "5.13.0"
win32_registry:
dependency: transitive
description:
name: win32_registry
sha256: "21ec76dfc731550fd3e2ce7a33a9ea90b828fdf19a5c3bcf556fa992cfa99852"
url: "https://pub.dev"
source: hosted
version: "1.1.5"
xdg_directories:
xdg_directories:
dependency: transitive
dependency: transitive
description:
description:
...
...
Prev
1
2
Next
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment