import 'dart:io'; import 'package:connectivity_plus/connectivity_plus.dart'; import 'package:dropdown_button2/dropdown_button2.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_svg/svg.dart'; import 'package:provider/provider.dart'; import 'package:intl/intl.dart'; import '../../Utils/app_colors.dart'; import '../../Utils/commonServices.dart'; import '../../Utils/commonWidgets.dart'; import '../../Utils/dropdownTheme.dart'; class AddBillScreen extends StatefulWidget { final String pageTitleName; const AddBillScreen({super.key, required this.pageTitleName}); @override State createState() => _AddBillScreenState(); } class _AddBillScreenState extends State { Dropdowntheme ddtheme = Dropdowntheme(); List focusNodes = List.generate(8, (index) => FocusNode()); Map _source = {ConnectivityResult.mobile: true}; final MyConnectivity _connectivity = MyConnectivity.instance; TextEditingController placeController = TextEditingController(); TextEditingController dateController = TextEditingController(); TextEditingController noteController = TextEditingController(); String? selectedDAAmount; String? selectedTourType; List> travelExpenses = [ {"title": "Bike", "amount": "1800", "icon": "assets/svg/ic_bike.svg"}, {"title": "Taxi", "amount": "300", "icon": "assets/svg/ic_taxi.svg"}, ]; List> hotelExpenses = [ {"title": "Hotel Sharada", "amount": "1800", "icon": "assets/svg/ic_hotel.svg"}, {"title": "Hotel Nikitan", "amount": "1800", "icon": "assets/svg/ic_hotel.svg"}, ]; List> otherExpenses = [ {"title": "Book", "amount": "1800", "icon": "assets/svg/ic_book.svg"}, ]; @override void initState() { super.initState(); _connectivity.initialise(); _connectivity.myStream.listen((source) { setState(() => _source = source); }); } @override void dispose() { placeController.dispose(); dateController.dispose(); noteController.dispose(); focusNodes.map((e) => e.dispose()); _connectivity.disposeStream(); super.dispose(); } Future _onBackPressed(BuildContext context) async { Navigator.pop(context, true); return true; } @override Widget build(BuildContext context) { switch (_source.keys.toList()[0]) { case ConnectivityResult.mobile: case ConnectivityResult.wifi: connection = 'Online'; break; case ConnectivityResult.none: default: connection = 'Offline'; } return (connection == "Online") ? Platform.isAndroid ? WillPopScope( onWillPop: () => _onBackPressed(context), child: SafeArea( top: false, bottom: true, child: _scaffold(context), ), ) : _scaffold(context) : NoNetwork(context); } Widget _scaffold(BuildContext context) { return Scaffold( resizeToAvoidBottomInset: true, backgroundColor: AppColors.scaffold_bg_color, appBar: appbarNew(context, widget.pageTitleName, 0xFFFFFFFF), body: SingleChildScrollView( child: Container( padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 12), margin: const EdgeInsets.all(12), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(20), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ /// Place of Visit TextWidget(context, "Place of Visit"), textFieldNew(context, placeController, "Enter Place"), /// DA Amount TextWidget(context, "DA Amount"), dropDownField(context, "Select DA Amount", ["100", "200", "300"], selectedDAAmount, (val) { setState(() => selectedDAAmount = val); }), /// Tour Type TextWidget(context, "Tour Type"), dropDownField(context, "Select Tour", ["Business", "Personal"], selectedTourType, (val) { setState(() => selectedTourType = val); }), /// Tour Date TextWidget(context, "Tour Date"), GestureDetector( onTap: () async { DateTime? picked = await showDatePicker( context: context, initialDate: DateTime.now(), firstDate: DateTime(2022), lastDate: DateTime(2100), ); if (picked != null) { dateController.text = DateFormat("dd MMM yyyy").format(picked); setState(() {}); } }, child: textFieldNew(context, dateController, "Enter Date", enabled: false), ), /// Note TextWidget(context, "Note"), textFieldNew(context, noteController, "Write Note", maxLines: 3), const SizedBox(height: 16), /// Travel Expenses sectionHeader("Travel Expenses", onAddTap: () { // TODO: Add Travel Expense }), expenseList(travelExpenses), /// Hotel Expenses sectionHeader("Hotel Expenses", onAddTap: () { // TODO: Add Hotel Expense }), expenseList(hotelExpenses), /// Other Expenses sectionHeader("Other Expenses", onAddTap: () { // TODO: Add Other Expense }), expenseList(otherExpenses), const SizedBox(height: 80), ], ), ), ), floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat, bottomNavigationBar: InkResponse( onTap: () { // TODO: Submit API Call }, child: Container( height: 45, alignment: Alignment.center, margin: const EdgeInsets.symmetric(horizontal: 10, vertical: 15), padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 5), decoration: BoxDecoration( color: AppColors.app_blue, borderRadius: BorderRadius.circular(15), ), child: const Text( "Submit", style: TextStyle( fontSize: 15, fontFamily: "JakartaMedium", color: Colors.white, ), ), ), ), ); } /// --- Custom Widgets Below --- Widget textFieldNew(BuildContext context, TextEditingController controller, String hint, {bool enabled = true, int maxLines = 1}) { return Container( margin: const EdgeInsets.only(bottom: 12), decoration: BoxDecoration( color: AppColors.text_field_color, borderRadius: BorderRadius.circular(14), ), child: TextFormField( controller: controller, enabled: enabled, maxLines: maxLines, decoration: _inputDecoration(hint) ), ); } Widget dropDownField(BuildContext context, String hint, List items, String? value, Function(String?) onChanged) { return Container( margin: const EdgeInsets.only(bottom: 12), padding: const EdgeInsets.symmetric(horizontal: 12), decoration: BoxDecoration( color: AppColors.text_field_color, borderRadius: BorderRadius.circular(14), ), child: DropdownButtonHideUnderline( child: DropdownButton2( isExpanded: true, hint: Text(hint, style: const TextStyle(fontSize: 14, color: Colors.grey)), value: value, items: items.map((e) => DropdownMenuItem(value: e, child: Text(e))).toList(), onChanged: onChanged, iconStyleData: ddtheme.iconStyleData, // menuItemStyleData: ddtheme.menuItemStyleData, dropdownStyleData: ddtheme.dropdownStyleData, ), ), ); } Widget sectionHeader(String title, {VoidCallback? onAddTap}) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(title, style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w600)), const SizedBox(height: 6), Container( height: 45, decoration: BoxDecoration( border: Border.all(color: Colors.grey.shade400, width: 0.7, style: BorderStyle.solid), borderRadius: BorderRadius.circular(12), ), child: InkWell( onTap: onAddTap, child: Center( child: Row( mainAxisAlignment: MainAxisAlignment.center, children: const [ Icon(Icons.add, color: Colors.blue), SizedBox(width: 6), Text("Add Expenses", style: TextStyle(color: Colors.blue, fontSize: 14)), ], ), ), ), ), const SizedBox(height: 10), ], ); } Widget expenseList(List> items) { return Container( height: 84, margin: const EdgeInsets.only(bottom: 12), child: ListView.builder( scrollDirection: Axis.horizontal, itemCount: items.length, itemBuilder: (context, index) { final exp = items[index]; return Container( width: 120, margin: const EdgeInsets.only(right: 10), padding: const EdgeInsets.all(10), decoration: BoxDecoration( color: const Color(0xFFE6F6FF), borderRadius: BorderRadius.circular(12), ), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ SvgPicture.asset(exp["icon"] ?? "assets/svg/ic_default.svg", height: 22), const SizedBox(height: 6), Text(exp["title"] ?? "-", style: const TextStyle(fontSize: 13, fontWeight: FontWeight.w500)), Text("₹${exp["amount"]}", style: const TextStyle(fontSize: 12, color: Colors.blue)), ], ), ); }, ), ); } InputDecoration _inputDecoration(String hint) { return InputDecoration( hintText: hint, hintStyle: TextStyle( fontSize: 14, fontFamily: "Plus Jakarta Sans", fontStyle: FontStyle.normal, fontWeight: FontWeight.w400, color: Color(0xFFB4BEC0), ), filled: true, fillColor: Colors.grey.shade100, enabledBorder: InputBorder.none, disabledBorder: InputBorder.none, focusedBorder: InputBorder.none, ); } }