maheshj01 / searchfield

A highly customizable simple and easy to use flutter Widget to add a searchfield to your Flutter Application.This Widget allows you to search and select from list of suggestions.
MIT License
84 stars 63 forks source link

Selected suggestion doesn't update when the list changes #168

Closed twfungi closed 2 months ago

twfungi commented 2 months ago

Describe the bug The selected suggestion doesn't match the text in the TextEdit when I remove one item (or shift the order) in the suggestion list.

To Reproduce Steps to reproduce the behavior:

  1. Click on any item(other than the first one) in the suggestion list
  2. Error: text in the TextEdit doesn't match the selected item (the index remains the the same)

[X] By clicking this checkbox, I confirm I am using the latest version of the package found on pub.dev/searchfield

Expected behavior Text in the TextEdit should match the item in the suggestion list if there is one, or no item is selected if there's no match.

Actual behavior text in the TextEdit doesn't match the selected item (the index remains the the same)

Screenshots

Screenshot 2024-09-05 at 9 12 08 PM
import 'package:flutter/material.dart';
import 'package:searchfield/searchfield.dart';
import 'dart:developer' as d;

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});
  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final focus = FocusNode();
  final _controller = TextEditingController();
  var suggestions = <String>[
    "OPtion1",
    "OPtion2",
    "OPtion3",
    "OPtion4",
    "OPtion5",
    "OPtion6",
    "OPtion7",
    "OPtion8",
    "OPtion9",
    "OPtion10"
  ];

  @override
  void initState() {
    super.initState();
    suggestions = getSuggestions();
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    Widget searchChild(x) => Padding(
          padding: const EdgeInsets.symmetric(vertical: 4.0, horizontal: 12),
          child: Text(x, style: Theme.of(context).textTheme.bodyMedium!),
        );

    SuggestionDecoration suggestionDecoration = SuggestionDecoration(
      elevation: 16.0,
      color: Colors.white54,
      borderRadius: BorderRadius.circular(24),
    );

    return Scaffold(
        appBar: AppBar(centerTitle: true, automaticallyImplyLeading: true, title: const Text('test')),
        body: GestureDetector(
            onTap: () {
              FocusScope.of(context).unfocus();
            },
            child: SizedBox(
                height: double.infinity,
                width: double.infinity,
                child: Column(
                  children: [
                    SizedBox(
                        width: 400,
                        child: SearchField(
                          controller: _controller,
                          onSearchTextChanged: (query) {
                            List<String> filter;
                            query = query.trim();
                            if (query.isEmpty) {
                              filter = suggestions = getSuggestions();
                            } else {
                              filter = suggestions
                                  .where((element) => element.toLowerCase().contains(query.toLowerCase()))
                                  .toList();
                            }
                            return filter.map((e) => SearchFieldListItem<String>(e, child: searchChild(e))).toList();
                          },
                          onSubmit: (str) async {
                            d.log('[onSubmit] $str');
                            saveSuggestion(str.trim());
                          },
                          initialValue: null,
                          onTap: () async {
                            suggestions = getSuggestions();
                            setState(() {});
                          },
                          showEmpty: false,
                          emptyWidget: Container(
                              decoration: suggestionDecoration, height: 200, child: const Center(child: Text('Empty'))),
                          key: const Key('searchfield'),
                          searchStyle: Theme.of(context).textTheme.bodyMedium!,
                          dynamicHeight: true,
                          maxSuggestionBoxHeight: 300,
                          scrollbarDecoration: ScrollbarDecoration(minThumbLength: 30, thickness: 10),
                          onTapOutside: null,
                          suggestionDirection: SuggestionDirection.down,
                          suggestionStyle: Theme.of(context).textTheme.bodyMedium!,
                          searchInputDecoration: InputDecoration(
                            prefixIcon: const Icon(Icons.search),
                            fillColor: Colors.white38,
                            suffixIcon: IconButton(
                              onPressed: _controller.clear,
                              icon: const Icon(Icons.clear),
                            ),
                            focusedBorder: OutlineInputBorder(
                              borderRadius: BorderRadius.circular(24),
                              borderSide: const BorderSide(
                                width: 1,
                                color: Colors.grey,
                                style: BorderStyle.solid,
                              ),
                            ),
                            border: OutlineInputBorder(
                              borderRadius: BorderRadius.circular(24),
                              borderSide: const BorderSide(
                                width: 1,
                                color: Colors.black,
                                style: BorderStyle.solid,
                              ),
                            ),
                            filled: true,
                            contentPadding: const EdgeInsets.symmetric(
                              horizontal: 20,
                            ),
                          ),
                          suggestionsDecoration: suggestionDecoration,
                          suggestions:
                              suggestions.map((e) => SearchFieldListItem<String>(e, child: searchChild(e))).toList(),
                          focusNode: focus,
                          suggestionState: Suggestion.expand,
                          onSuggestionTap: (SearchFieldListItem<String> x) {
                            focus.unfocus();
                            d.log('[onSuggestionTap] selected ${x.searchKey}');
                            saveSuggestion(x.searchKey);
                          },
                        )),
                  ],
                ))));
  }

  List<String> getSuggestions() {
    return suggestions;
  }

  void saveSuggestion(String item) {
    if (item.isNotEmpty) {
      suggestions.removeWhere((e) => e == item);
      suggestions.insert(0, item);
      if (suggestions.length > 10) {
        suggestions.removeLast();
      }
    }
  }
}

maheshj01 commented 2 months ago

Hi @twfungi, I am able to reproduce the issue, I will investigate and get back to you on this.

Thanks

maheshj01 commented 2 months ago

released in v1.1.1