feat: add input validation to search, update agent card layout, and extend ProfileFormField with input constraints
This commit is contained in:
@@ -1598,9 +1598,13 @@ class _SpecializationCardWidgetState extends State<_SpecializationCardWidget> {
|
||||
: widget.card.values.take(_initialCount).toList();
|
||||
final hasMore = widget.card.values.length > _initialCount;
|
||||
|
||||
// Consistent minimum height across all cards so the layout stays uniform
|
||||
// regardless of how many values each card has (icon + title + up to 3
|
||||
// rows + show more button fits comfortably).
|
||||
return Container(
|
||||
width: 298,
|
||||
padding: const EdgeInsets.symmetric(vertical: 16),
|
||||
constraints: const BoxConstraints(minHeight: 240),
|
||||
padding: const EdgeInsets.symmetric(vertical: 16, horizontal: 12),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(15),
|
||||
@@ -1611,11 +1615,13 @@ class _SpecializationCardWidgetState extends State<_SpecializationCardWidget> {
|
||||
),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
Icon(_icon, size: 32, color: AppColors.accentOrange),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
widget.card.name,
|
||||
textAlign: TextAlign.center,
|
||||
style: const TextStyle(
|
||||
fontFamily: 'Fractul',
|
||||
fontSize: 14,
|
||||
|
||||
@@ -187,6 +187,7 @@ class _AgentSearchScreenState extends ConsumerState<AgentSearchScreen> {
|
||||
),
|
||||
),
|
||||
onSubmitted: (value) {
|
||||
if (value.trim().isEmpty) return;
|
||||
ref.read(searchAgentsProvider.notifier).search(value);
|
||||
},
|
||||
),
|
||||
@@ -196,13 +197,24 @@ class _AgentSearchScreenState extends ConsumerState<AgentSearchScreen> {
|
||||
const SizedBox(width: 0),
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
ref
|
||||
.read(searchAgentsProvider.notifier)
|
||||
.search(_searchController.text);
|
||||
final query = _searchController.text.trim();
|
||||
if (query.isEmpty) {
|
||||
// No input — don't trigger a refresh
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(
|
||||
content: Text('Please enter a keyword'),
|
||||
behavior: SnackBarBehavior.floating,
|
||||
duration: Duration(seconds: 2),
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
ref.read(searchAgentsProvider.notifier).search(query);
|
||||
},
|
||||
child: Container(
|
||||
width: 62,
|
||||
height: 42,
|
||||
alignment: Alignment.center,
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.accentOrange,
|
||||
border: Border.all(
|
||||
@@ -211,12 +223,10 @@ class _AgentSearchScreenState extends ConsumerState<AgentSearchScreen> {
|
||||
),
|
||||
borderRadius: BorderRadius.circular(7),
|
||||
),
|
||||
child: Center(
|
||||
child: SvgPicture.string(
|
||||
'<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M15.5 14h-.79l-.28-.27A6.471 6.471 0 0 0 16 9.5 6.5 6.5 0 1 0 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z" fill="white"/></svg>',
|
||||
width: 24,
|
||||
height: 24,
|
||||
),
|
||||
child: const Icon(
|
||||
Icons.search,
|
||||
color: Colors.white,
|
||||
size: 24,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:real_estate_mobile/core/constants/app_colors.dart';
|
||||
|
||||
class ProfileFormField extends StatelessWidget {
|
||||
@@ -10,6 +11,8 @@ class ProfileFormField extends StatelessWidget {
|
||||
final TextCapitalization textCapitalization;
|
||||
final bool obscureText;
|
||||
final Widget? suffixIcon;
|
||||
final List<TextInputFormatter>? inputFormatters;
|
||||
final int? maxLength;
|
||||
|
||||
const ProfileFormField({
|
||||
super.key,
|
||||
@@ -21,6 +24,8 @@ class ProfileFormField extends StatelessWidget {
|
||||
this.textCapitalization = TextCapitalization.words,
|
||||
this.obscureText = false,
|
||||
this.suffixIcon,
|
||||
this.inputFormatters,
|
||||
this.maxLength,
|
||||
});
|
||||
|
||||
@override
|
||||
@@ -53,6 +58,8 @@ class ProfileFormField extends StatelessWidget {
|
||||
keyboardType: keyboardType,
|
||||
textCapitalization: textCapitalization,
|
||||
obscureText: obscureText,
|
||||
inputFormatters: inputFormatters,
|
||||
maxLength: maxLength,
|
||||
textAlignVertical: TextAlignVertical.center,
|
||||
style: const TextStyle(
|
||||
fontFamily: 'SourceSerif4',
|
||||
@@ -62,6 +69,7 @@ class ProfileFormField extends StatelessWidget {
|
||||
),
|
||||
decoration: InputDecoration(
|
||||
isDense: true,
|
||||
counterText: '',
|
||||
contentPadding:
|
||||
const EdgeInsets.symmetric(horizontal: 12, vertical: 10),
|
||||
border: border,
|
||||
|
||||
Reference in New Issue
Block a user