// * Shared widget for text input fields with database integration // * Features: // * - Customizable text input field // * - Database value suggestions // * - Required field validation // * - Default value support // * - Visual feedback for validation state // * - Dropdown for previous entries import 'package:fforte/enums/databases.dart'; import 'package:fforte/methods/excursion_db_helper.dart'; import 'package:fforte/methods/place_db_helper.dart'; import 'package:flutter/material.dart'; import 'package:shared_preferences/shared_preferences.dart'; /// Widget for managing text input with database integration /// Provides suggestions from previous entries and validation class VarTextField extends StatefulWidget { /// Controller for the text input final TextEditingController textController; /// Localized label/hint text final String localization; /// Database type (place or excursion) final DatabasesEnum dbDesignation; /// Database field name final String dbName; /// Default value key for preferences final String? defaultValue; /// Whether the field is required final bool required; const VarTextField({ super.key, required this.textController, required this.localization, required this.dbName, required this.required, required this.dbDesignation, this.defaultValue, }); @override State createState() => _VarTextFieldState(); } /// State class for the variable text field widget class _VarTextFieldState extends State { /// List of previous values from database List dbVar = []; @override void initState() { super.initState(); // Load default value if field is empty if (widget.textController.text == "" && widget.defaultValue != null) { _loadPref(); } // Load previous values from database _loadData().then((e) => dbVar = e); } /// Load previous values from the appropriate database /// @return Future[List[String]] List of previous values Future> _loadData() async { List> entries = []; List> templatesEntries = []; // Get entries from appropriate database if (widget.dbDesignation == DatabasesEnum.place) { entries = await PlaceDBHelper().getAllMainEntries(); templatesEntries = await PlaceDBHelper().getAllTemplates(); } else if (widget.dbDesignation == DatabasesEnum.excursion) { entries = await ExcursionDBHelper().getAllMainEntries(); templatesEntries = await ExcursionDBHelper().getAllTemplates(); } List erg = []; // Extract values for this field from entries for (var element in entries) { for (var key in element.keys) { if (key == widget.dbName && element[key].toString() != "") { erg.add(element[key].toString()); } } } // Extract values from templates for (var element in templatesEntries) { for (var key in element.keys) { if (key == widget.dbName && element[key].toString() != "") { erg.add(element[key].toString()); } } } return erg; } /// Load default value from preferences void _loadPref() { Future.delayed(Duration.zero, () async { SharedPreferences prefs = await SharedPreferences.getInstance(); String bLand = prefs.getString(widget.defaultValue!) ?? ""; setState(() { widget.textController.text = bLand; }); }); } @override Widget build(BuildContext context) { return Row( children: [ // Text input field Expanded( flex: 5, child: TextField( controller: widget.textController, keyboardType: TextInputType.multiline, maxLines: null, onChanged: (value) { setState(() { widget.textController.text = value; }); }, decoration: InputDecoration( hintText: widget.localization, // Border color based on required status and value enabledBorder: widget.required ? (widget.textController.text.isEmpty ? const UnderlineInputBorder( borderSide: BorderSide(color: Colors.red), ) : const UnderlineInputBorder( borderSide: BorderSide(color: Colors.green), )) : const UnderlineInputBorder( borderSide: BorderSide(color: Colors.grey), ), focusedBorder: widget.required ? (widget.textController.text.isEmpty ? const UnderlineInputBorder( borderSide: BorderSide(color: Colors.red), ) : const UnderlineInputBorder( borderSide: BorderSide(color: Colors.green), )) : const UnderlineInputBorder( borderSide: BorderSide(color: Colors.grey), ), ), ), ), const Expanded(child: SizedBox(width: 15)), // Dropdown for previous values Expanded( flex: 1, child: Align( alignment: Alignment.bottomLeft, child: PopupMenuButton( onSelected: (String value) { setState(() { widget.textController.text = value; }); }, itemBuilder: (BuildContext context) { return dbVar.map((String item) { return PopupMenuItem(value: item, child: Text(item)); }).toList(); }, child: const Icon(Icons.arrow_drop_down), ), ), ), ], ); } }