From a79ab9fcabefc41710dd9df49a80841e5dc4541f Mon Sep 17 00:00:00 2001 From: Manish Date: Tue, 18 Nov 2025 10:50:50 +0530 Subject: [PATCH] done landscape responsive of all screen --- .../add_payment_request_bottom_sheet.dart | 149 +++++++++++++++--- lib/view/finance/advance_payment_screen.dart | 29 ++-- 2 files changed, 140 insertions(+), 38 deletions(-) diff --git a/lib/model/finance/add_payment_request_bottom_sheet.dart b/lib/model/finance/add_payment_request_bottom_sheet.dart index a23bfcf..7fcd508 100644 --- a/lib/model/finance/add_payment_request_bottom_sheet.dart +++ b/lib/model/finance/add_payment_request_bottom_sheet.dart @@ -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( 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( + optionsBuilder: (textEditingValue) { + final query = textEditingValue.text.toLowerCase(); + return query.isEmpty + ? const Iterable.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)), + ), + ), + ), ), ), ), diff --git a/lib/view/finance/advance_payment_screen.dart b/lib/view/finance/advance_payment_screen.dart index 4a59de8..795c94e 100644 --- a/lib/view/finance/advance_payment_screen.dart +++ b/lib/view/finance/advance_payment_screen.dart @@ -50,6 +50,7 @@ class _AdvancePaymentScreenState extends State @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 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