Flutter detail search function

337

So you have to wrap your code with a future builder that will first await your data from Firebase.

Then you have to display any GridView item that fulfill your condition (the string contains what the user has typed, that is here a constant: categorySearched). Additionally you may want to add the lower method to make it case insensitive.

You will use a gridview.builder for that goal.

Then you also need to map each category with the corresponding icon: Map<String, String> imageMap = {'Education': 'educationicon', 'Business': 'businessicon'}; // etc.

Hopefully you should be able to make your code working fully with little tweaks here and there. Let me know if you need more help.

import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';

class LevelCategoryMap {
  final String title;
  final String level;
  final String region;

  LevelCategoryMap(this.title, this.level, this.region);

  Map<String, dynamic> toMap() {
    return {
      'title': title,
      'level': level,
      'description': region
    };
  }

  @override
  String toString() {
    return 'LevelCategoryMap{level: $level, description: $region';
  }
}

class _LevelPageState extends State<LevelPage> {
  final String categorySearched = "fishing";
  String level = 1;

  @override
  Widget build(BuildContext context) {
    final dbCollectionSnapshot = Firestore
        .instance
        .collection("Level$level")
        .where('desc', )
        .snapshots(); // retrieve

    return StreamBuilder<QuerySnapshot>(
        stream: dbCollectionSnapshot,
        builder: (context, snapshot) {
          List<LevelCategoryMap> levelCategory;
          if (!snapshot.hasData || snapshot.data == null) return CircularProgressIndicator();
            snapshot.data.documents.forEach((element) {
              levelCategory.add(LevelCategoryMap(element.documentID, level, element.data['desc']));
            })
            final int resultsLen = levelCategory.length;
            return new Scaffold(
                appBar: AppBar(
                  backgroundColor: Colors.grey,
                  title: Text(widget.level.data["region"]),
                  centerTitle: true,
                ),
                body: ListView(shrinkWrap: true, children: <Widget>[
                  Container(
                    child: ListTile(
                      title: Text(
                        'Current Level ' + widget.level.data["level"].toString(),
                        style: TextStyle(
                            color: widget.level.data["level"] == 5
                                ? Colors.red[900]
                                : widget.level.data["level"] == 4
                                ? Colors.orange[900]
                                : widget.level.data["level"] == 3
                                ? Colors.brown[300]
                                : widget.level.data["level"] == 2
                                ? Colors.blue[300]
                                : widget.level.data["level"] == 1
                                ? Colors.green[300]
                                : Colors.black,
                            fontSize: 25,
                            fontWeight: FontWeight.bold),
                        textAlign: TextAlign.center,
                      ),
                    ),
                  ),

                  Center(
                      child: GridView.builder(
                          itemCount: resultsLen,
                          gridDelegate:
                          SliverGridDelegateWithFixedCrossAxisCount(
                              crossAxisCount: 2),
                          itemBuilder: (context, index) {
                            final String description = levelCategory[index].region;
                            if (description.contains(categorySearched))
                              return myGridItem(context, index, levelCategory[index]);
                            //: ClassifiedThumbnail(connection, capitalize(widget.city), snapshot.data[index]);
                          })),
                ]));
          }

          else
            return CircularProgressIndicator();

        });
  }
}


Widget myGridItem(context, index, LevelCategoryMap myLevelCategory) {
  Map<String, String> imageMap = {'Education': 'educationicon', 'Business': 'businessicon'}; // etc.

  return ListTile(
    title: Container(
        decoration: BoxDecoration(
          borderRadius: BorderRadius.circular(30),
          color: Colors.grey,
        ),
        child: InkWell(
          enableFeedback: true,
          child: Image.asset('assets/images/' + imageMap[myLevelCategory.title]  + '.png'),
          onTap: () => {
            Navigator.of(context).push(MaterialPageRoute(
                builder: (context) => CategoryPage(
                    text1: myLevelCategory.title, // I assume level is the name with education
                    text2: myLevelCategory.region,
                    text3: myLevelCategory.level)))
          },
          splashColor: Colors.white,
          borderRadius: BorderRadius.circular(20),
        )),
    subtitle: Text(myLevelCategory.title,
        style: TextStyle(
          color: Colors.white,
          fontSize: 10,
        ),
        textAlign: TextAlign.center),
  );

This will work with firebase. However note that you are downloading everything are doing the work on the mobile. In your case it's not a big deal since you only have 10 categories with only text. However if you wanted to make a search-based query in firebase you would have to use a third party service as stated here: https://firebase.google.com/docs/firestore/solutions/search

Share:
337
PKirby
Author by

PKirby

Come to the geek side, we have π

Updated on December 21, 2022

Comments

  • PKirby
    PKirby over 1 year

    I currently have a flutter app which displays clickable images within a gridview.

    Categories

    After selecting an image, it takes you to a detailed page which provides more info on the selected category:

    Category Detail

    I now need to build search functionality which would filter based on the Category Detail. So if I search for "Fishing", the gridview filters displaying "Agriculture" and whatever other Category detail contains that word.

    I currently use Firebase to return the Category detail whenever a user selects the Category so I assume that the search would have to be linked to my firebase?

    I've tried looking for answers on the web but none caters for my specific requirement.

    UPDATE Included Gridview Page Code:

    class _LevelPageState extends State<LevelPage> {
      @override
      Widget build(BuildContext context) {
        return new Scaffold(
            appBar: AppBar(
              backgroundColor: Colors.grey,
              title: Text(widget.level.data["region"]),
              centerTitle: true,
            ),
            body: ListView(shrinkWrap: true, children: <Widget>[
              Container(
                child: ListTile(
                  title: Text(
                    'Current Level ' + widget.level.data["level"].toString(),
                    style: TextStyle(
                         color: widget.level.data["level"] == 5
                             ? Colors.red[900]
                             : widget.level.data["level"] == 4
                                 ? Colors.orange[900]
                                 : widget.level.data["level"] == 3
                                     ? Colors.brown[300]
                                     : widget.level.data["level"] == 2
                                         ? Colors.blue[300]
                                         : widget.level.data["level"] == 1
                                             ? Colors.green[300]
                                             : Colors.black,
                        fontSize: 25,
                        fontWeight: FontWeight.bold),
                    textAlign: TextAlign.center,
                  ),
                ),
              ),
              Container(
                height: (MediaQuery.of(context).size.height),
                padding: EdgeInsets.all(10),
                child: GridView.count(
                  shrinkWrap: true,
                  physics: ScrollPhysics(),
                  mainAxisSpacing: 40,
                  crossAxisSpacing: 20,
                  crossAxisCount: 3,
                  childAspectRatio: MediaQuery.of(context).size.height / 400,
                  children: <Widget>[
                    ListTile(
                      title: Container(
                          decoration: BoxDecoration(
                            borderRadius: BorderRadius.circular(30),
                            color: Colors.grey,
                          ),
                          child: InkWell(
                            enableFeedback: true,
                            child: Image.asset('assets/images/mediaicon.png'),
                            onTap: () => {
                              Navigator.of(context).push(MaterialPageRoute(
                                  builder: (context) => CategoryPage(
                                      text1: 'Media',
                                      text2: widget.level.data["region"].toString(),
                                      text3:
                                          widget.level.data["level"].toString())))
                            },
                            splashColor: Colors.white,
                            borderRadius: BorderRadius.circular(20),
                          )),
                      subtitle: Text('Media',
                          style: TextStyle(
                            color: Colors.white,
                            fontSize: 10,
                          ),
                          textAlign: TextAlign.center),
                    ),
                    ListTile(
                      title: Container(
                          decoration: BoxDecoration(
                            borderRadius: BorderRadius.circular(30),
                            color: Colors.grey,
                          ),
                          child: InkWell(
                            enableFeedback: true,
                            child: Image.asset('assets/images/mobileanditicon.png'),
                            onTap: () => {
                              Navigator.of(context).push(MaterialPageRoute(
                                  builder: (context) => CategoryPage(
                                      text1: 'Info and Comms',
                                      text2: widget.level.data["region"].toString(),
                                      text3:
                                          widget.level.data["level"].toString())))
                            },
                            splashColor: Colors.white,
                            borderRadius: BorderRadius.circular(20),
                          )),
                      subtitle: Text('Info and Comms',
                          style: TextStyle(
                            color: Colors.white,
                            fontSize: 10,
                          ),
                          textAlign: TextAlign.center),
                    ),
                    ListTile(
                      title: Container(
                          decoration: BoxDecoration(
                            borderRadius: BorderRadius.circular(30),
                            color: Colors.grey,
                          ),
                          child: InkWell(
                            enableFeedback: true,
                            child: Image.asset('assets/images/utilitiesicon.png'),
                            onTap: () => {
                              Navigator.of(context).push(MaterialPageRoute(
                                  builder: (context) => CategoryPage(
                                      text1: 'Utilities',
                                      text2: widget.level.data["region"].toString(),
                                      text3:
                                          widget.level.data["level"].toString())))
                            }, 
                            splashColor: Colors.white,
                            borderRadius: BorderRadius.circular(20),
                          )),
                      subtitle: Text('Utilities',
                          style: TextStyle(
                            color: Colors.white,
                            fontSize: 10,
                          ),
                          textAlign: TextAlign.center),
                    ),
                    ListTile(
                      title: Container(
                          decoration: BoxDecoration(
                            borderRadius: BorderRadius.circular(30),
                            color: Colors.grey,
                          ),
                          child: InkWell(
                            enableFeedback: true,
                            child: Image.asset('assets/images/educationicon.png'),
                            onTap: () => {
                              Navigator.of(context).push(MaterialPageRoute(
                                  builder: (context) => CategoryPage(
                                      text1: 'Education',
                                      text2: widget.level.data["region"].toString(),
                                      text3:
                                          widget.level.data["level"].toString())))
                            },
                            splashColor: Colors.white,
                            borderRadius: BorderRadius.circular(20),
                          )),
                      subtitle: Text('Education',
                          style: TextStyle(
                            color: Colors.white,
                            fontSize: 10,
                          ),
                          textAlign: TextAlign.center),
                    ),
                    ListTile(
                      title: Container(
                          decoration: BoxDecoration(
                            borderRadius: BorderRadius.circular(30),
                            color: Colors.grey,
                          ),
                          child: InkWell(
                            enableFeedback: true,
                            child: Image.asset('assets/images/repairsicon.png'),
                            onTap: () => {
                              Navigator.of(context).push(MaterialPageRoute(
                                  builder: (context) => CategoryPage(
                                      text1: 'Repairs',
                                      text2: widget.level.data["region"].toString(),
                                      text3:
                                          widget.level.data["level"].toString())))
                            },
                            splashColor: Colors.white,
                            borderRadius: BorderRadius.circular(20),
                          )),
                      subtitle: Text('Repairs',
                          style: TextStyle(
                            color: Colors.white,
                            fontSize: 10,
                          ),
                          textAlign: TextAlign.center),
                    ),
                    ListTile(
                      title: Container(
                          decoration: BoxDecoration(
                            borderRadius: BorderRadius.circular(30),
                            color: Colors.grey,
                          ),
                          child: InkWell(
                            enableFeedback: true,
                            child:
                                Image.asset('assets/images/domestichelpicon.png'),
                            onTap: () => {
                              Navigator.of(context).push(MaterialPageRoute(
                                  builder: (context) => CategoryPage(
                                      text1: 'Domestic Help',
                                      text2: widget.level.data["region"].toString(),
                                      text3:
                                          widget.level.data["level"].toString())))
                            },
                            splashColor: Colors.white,
                            borderRadius: BorderRadius.circular(20),
                          )),
                      subtitle: Text('Domestic Help',
                          style: TextStyle(
                            color: Colors.white,
                            fontSize: 10,
                          ),
                          textAlign: TextAlign.center),
                    ),
                  ],
                ),
              ),
            ]));
      }
    }
    

    I have adjusted the above code to only include 6 of the gridview images to shorten the code.

    Data Structure on Firebase : Firebase Data Structure

  • PKirby
    PKirby almost 4 years
    Thanks for your answer. I am geeting a "Undefined name 'FirebaseDatabase'. Try correcting the name to one that is defined, or defining the name." on 'final dbRef = FirebaseDatabase.instance.reference().child("levelcategory")‌​;'
  • Antonin GAVREL
    Antonin GAVREL almost 4 years
    Yes it depends on how you defined names of your data in your firebase database. I am using PostgresQL so I camt help you much on this part, you can google 'future flutter firebase tutorial" if you have never done it to get started and hopefully you will be able to have your code working
  • PKirby
    PKirby almost 4 years
    Thanks, I've replace it with 'widget.level.data["level"];' but now getting a 'NoSuchMethodError" - "Class 'int' has no instance getter 'once'. Receiver: 3 Tried calling: once"
  • PKirby
    PKirby almost 4 years
    I've added my firebase data structure if that would help? .. I am a bit lost as to where to go from here...