done landscape responsive of all screen

This commit is contained in:
Manish 2025-11-18 10:50:50 +05:30
parent c005d2574c
commit a79ab9fcab
2 changed files with 140 additions and 38 deletions

View File

@ -78,6 +78,7 @@ class _PaymentRequestBottomSheetState extends State<_PaymentRequestBottomSheet>
'name': data["projectName"],
};
controller.selectedPayee.value = data["payee"] ?? "";
controller.isAdvancePayment.value = data["isAdvancePayment"] ?? false;
@ -142,7 +143,38 @@ class _PaymentRequestBottomSheetState extends State<_PaymentRequestBottomSheet>
} else {
success = await controller.submitPaymentRequest();
}
return Obx(() => SafeArea(
child: Form(
key: _formKey,
child: BaseBottomSheet(
title: widget.isEdit
? "Edit Payment Request"
: "Create Payment Request",
isSubmitting: controller.isSubmitting.value,
onCancel: Get.back,
submitText: "Save as Draft",
onSubmit: () async {
if (_formKey.currentState!.validate() &&
_validateSelections()) {
bool success = false;
if (widget.isEdit && widget.existingData != null) {
final requestId =
widget.existingData!['id']?.toString() ?? '';
if (requestId.isNotEmpty) {
success = await controller.submitEditedPaymentRequest(
requestId: requestId);
} else {
_showError("Invalid Payment Request ID");
return;
}
} else {
success = await controller.submitPaymentRequest();
}
if (success) {
Get.back();
widget.onUpdated?.call();
if (success) {
Get.back();
widget.onUpdated?.call();
@ -157,6 +189,23 @@ class _PaymentRequestBottomSheetState extends State<_PaymentRequestBottomSheet>
}
}
},
child: SingleChildScrollView(
padding: const EdgeInsets.only(bottom: 20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
_buildDropdown(
showAppSnackbar(
title: "Success",
message: widget.isEdit
? "Payment request updated successfully!"
: "Payment request created successfully!",
type: SnackbarType.success,
);
}
}
},
child: SingleChildScrollView(
padding: const EdgeInsets.only(bottom: 20),
child: Column(
@ -174,6 +223,10 @@ class _PaymentRequestBottomSheetState extends State<_PaymentRequestBottomSheet>
key: _projectDropdownKey,
),
_gap(),
_buildDropdown(
key: _projectDropdownKey,
),
_gap(),
_buildDropdown(
"Expense Category",
Icons.category_outlined,
@ -208,7 +261,7 @@ class _PaymentRequestBottomSheetState extends State<_PaymentRequestBottomSheet>
? null
: "Enter valid amount"),
_gap(),
_buildPayeeField(),
_buildPayeeAutocompleteField(),
_gap(),
_buildDropdown(
"Currency",
@ -230,6 +283,19 @@ class _PaymentRequestBottomSheetState extends State<_PaymentRequestBottomSheet>
_buildAttachmentsSection(),
MySpacing.height(30),
],
),
key: _currencyDropdownKey,
),
_gap(),
_buildTextField("Description", Icons.description_outlined,
controller.descriptionController,
hint: "Enter description",
maxLines: 3,
validator: Validators.requiredField),
_gap(),
_buildAttachmentsSection(),
MySpacing.height(30),
],
),
),
),
@ -297,6 +363,7 @@ class _PaymentRequestBottomSheetState extends State<_PaymentRequestBottomSheet>
final label = entry.value;
final value = i == 0;
return Expanded(
child: RadioListTile<bool>(
contentPadding: EdgeInsets.zero,
@ -353,27 +420,67 @@ class _PaymentRequestBottomSheetState extends State<_PaymentRequestBottomSheet>
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SectionTitle(
icon: Icons.person_outline,
title: "Payee",
requiredField: true,
),
MySpacing.height(6),
GestureDetector(
onTap: _showPayeeSelector,
child: TileContainer(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Obx(() => Text(
controller.selectedPayee.value?.name ?? "Select Payee",
style: const TextStyle(fontSize: 15),
overflow: TextOverflow.ellipsis,
)),
SectionTitle(
icon: Icons.person_outline, title: "Payee", requiredField: true),
const SizedBox(height: 6),
Autocomplete<String>(
optionsBuilder: (textEditingValue) {
final query = textEditingValue.text.toLowerCase();
return query.isEmpty
? const Iterable<String>.empty()
: controller.payees
.where((p) => p.toLowerCase().contains(query));
},
displayStringForOption: (option) => option,
fieldViewBuilder:
(context, fieldController, focusNode, onFieldSubmitted) {
WidgetsBinding.instance.addPostFrameCallback((_) {
if (fieldController.text != controller.selectedPayee.value) {
fieldController.text = controller.selectedPayee.value;
fieldController.selection = TextSelection.fromPosition(
TextPosition(offset: fieldController.text.length));
}
});
return TextFormField(
controller: fieldController,
focusNode: focusNode,
decoration: InputDecoration(
hintText: "Type or select payee",
filled: true,
fillColor: Colors.grey.shade100,
contentPadding:
const EdgeInsets.symmetric(horizontal: 12, vertical: 14),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide: BorderSide(color: Colors.grey.shade300),
),
const Icon(Icons.arrow_drop_down, size: 22),
],
),
validator: (v) =>
v == null || v.trim().isEmpty ? "Please enter payee" : null,
onChanged: (val) => controller.selectedPayee.value = val,
);
},
onSelected: (selection) => controller.selectedPayee.value = selection,
optionsViewBuilder: (context, onSelected, options) => Material(
color: Colors.white,
elevation: 4,
borderRadius: BorderRadius.circular(8),
child: ConstrainedBox(
constraints: const BoxConstraints(maxHeight: 200, minWidth: 300),
child: ListView.builder(
padding: EdgeInsets.zero,
itemCount: options.length,
itemBuilder: (_, index) => InkWell(
onTap: () => onSelected(options.elementAt(index)),
child: Container(
padding: const EdgeInsets.symmetric(
vertical: 10, horizontal: 12),
child: Text(options.elementAt(index),
style: const TextStyle(fontSize: 14)),
),
),
),
),
),
),

View File

@ -50,6 +50,7 @@ class _AdvancePaymentScreenState extends State<AdvancePaymentScreen>
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: const Color(0xFFF5F5F5),
backgroundColor: const Color(0xFFF5F5F5),
appBar: _buildAppBar(),
body: SafeArea(
@ -58,25 +59,19 @@ class _AdvancePaymentScreenState extends State<AdvancePaymentScreen>
final bool isLandscape =
constraints.maxWidth > constraints.maxHeight;
return RefreshIndicator(
onRefresh: () async {
final emp = controller.selectedEmployee.value;
if (emp != null) {
await controller.fetchAdvancePayments(emp.id.toString());
}
},
color: Colors.white,
backgroundColor: contentTheme.primary,
strokeWidth: 2.5,
displacement: 60,
child: GestureDetector(
behavior: HitTestBehavior.translucent,
onTap: () {
FocusScopeNode currentFocus = FocusScope.of(context);
if (!currentFocus.hasPrimaryFocus) {
currentFocus.unfocus();
return GestureDetector(
onTap: () => FocusScope.of(context).unfocus(),
child: RefreshIndicator(
onRefresh: () async {
final emp = controller.selectedEmployee.value;
if (emp != null) {
await controller.fetchAdvancePayments(emp.id.toString());
}
},
color: Colors.white,
backgroundColor: contentTheme.primary,
strokeWidth: 2.5,
displacement: 60,
// ---------------- PORTRAIT (UNCHANGED) ----------------
child: !isLandscape