Debug School

rakesh kumar
rakesh kumar

Posted on

How search functionality works in flutter using MVMM

Declare variable

 TextEditingController _searchController = TextEditingController();
  String _selectedFilter = 'Select Filter By';
Enter fullscreen mode Exit fullscreen mode

Add input field

   Padding(
            padding: const EdgeInsets.all(8.0),
            child: TextField(
              controller: _searchController,
              decoration: InputDecoration(
                labelText: 'Search by name, country, state, city or social site',
                border: OutlineInputBorder(),
              ),
              onChanged: (value) {
                setState(() {});
              },
            ),
          ),
Enter fullscreen mode Exit fullscreen mode

Apply search functionality logic

  Widget build(BuildContext context) {
    final influencerViewModel = Provider.of<InfluencerViewModel>(context);
    print("Available influencerViewModel: ${influencerViewModel.influencers.map((c) => c.socialPrice).toList()}");

    List<SearchInfluencer> filteredInfluencers = influencerViewModel.influencers.where((influencer) {
      bool matchesSearch = influencer.userName != null &&
          influencer.userName!.toLowerCase().contains(_searchController.text.toLowerCase());
      bool matchesCountry = influencer.countryName != null &&
          influencer.countryName!.toLowerCase().contains(_searchController.text.toLowerCase());
      bool matchesState = influencer.stateName != null &&
          influencer.stateName!.toLowerCase().contains(_searchController.text.toLowerCase());
      bool matchesCity = influencer.cityName != null &&
          influencer.cityName!.toLowerCase().contains(_searchController.text.toLowerCase());

      Map<String, dynamic>? socialPrices;
      try {
        socialPrices = jsonDecode(influencer.socialPrice ?? '{}');
      } catch (e) {
        print('Error decoding socialPrice: $e');
      }

      bool matchesSocialSite = socialPrices != null &&
          socialPrices.keys.any((key) => key.toLowerCase().contains(_searchController.text.toLowerCase()));

      return matchesSearch || matchesCountry || matchesState || matchesCity || matchesSocialSite;
    }).toList();
Enter fullscreen mode Exit fullscreen mode

After search functionality renders data

 Expanded(
            child: influencerViewModel.isLoading
                ? const Center(child: CircularProgressIndicator())
                : filteredInfluencers.isEmpty
                    ? const Center(child: Text('No influencers found'))
                    : ListView.builder(
                        itemCount: filteredInfluencers.length,
                        itemBuilder: (context, index) {
                          final influencer = filteredInfluencers[index];
                          Map<String, dynamic>? socialPrices;
                          try {
                            socialPrices = jsonDecode(influencer.socialPrice ?? '{}');
                          } catch (e) {
                            print('Error decoding socialPrice: $e');
                          }

                          return Padding(
                            padding: const EdgeInsets.symmetric(vertical: 8.0, horizontal: 16.0),
                            child: Card(
                              elevation: 4,
                              shape: RoundedRectangleBorder(
                                borderRadius: BorderRadius.circular(8.0),
                              ),
                              child: Column(
                                children: [
                                  ListTile(
                                    contentPadding: EdgeInsets.all(4.0),
                                    leading: CircleAvatar(
                                      backgroundImage: AssetImage('assets/avatar.png'), // Replace with the path to your avatar image
                                      radius: 20,
                                    ),
                                    title: Text(
                                      influencer.userName ?? "No Name",
                                      style: TextStyle(fontWeight: FontWeight.bold),
                                    ),
                                    subtitle: Text(
                                      '${influencer.countryName ?? "No Country"} / ${influencer.stateName ?? "No State"} / ${influencer.cityName ?? "No City"}',
                                      style: TextStyle(color: Colors.black54),
                                    ),
                                  ),
                                  socialPrices != null
                                      ? Padding(
                                          padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
                                          child: Wrap(
                                            spacing: 10.0,
                                            runSpacing: 5.0,
                                            children: socialPrices.entries.map((entry) {
                                              return SizedBox(
                                                width: (MediaQuery.of(context).size.width - 100) / 3,
                                                child: Chip(
                                                  label: Text('${entry.key}: ${entry.value}'),
                                                ),
                                              );
                                            }).toList(),
                                          ),
                                        )
                                      : Padding(
                                          padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
                                          child: Text('No social data'),
                                        ),
                                ],
                              ),
                            ),
                          );
                        },
                      ),
          ),
Enter fullscreen mode Exit fullscreen mode

Full code

import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter_application_1/Screen/layout/mixins.dart';
import 'package:provider/provider.dart';
import 'package:flutter_application_1/Screen/Influencer/locationfilter.dart';
import 'package:flutter_application_1/Screen/Influencer/socialsitefilter.dart';
import 'package:flutter_application_1/model/search_influencer.dart';
import 'package:flutter_application_1/view_modal/influencer_view_model.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';

class InfluencerScreen extends StatefulWidget {
  const InfluencerScreen({super.key});

  @override
  State<InfluencerScreen> createState() => _InfluencerScreenState();
}

class _InfluencerScreenState extends State<InfluencerScreen> with NavigationMixin {
  TextEditingController _searchController = TextEditingController();
  String _selectedFilter = 'Select Filter By';

  @override
  void initState() {
    super.initState();
    Future.microtask(() async {
      Provider.of<InfluencerViewModel>(context, listen: false).fetchInfluencers();

      Map<String, String?> credentials = await _getCredentials();
      String? email = credentials['email'];
      String? password = credentials['password'];

      if (email != null && password != null) {
        print('Email: $email');
        print('Password: $password');
      } else {
        print('No credentials found');
      }
    });
  }

  Future<Map<String, String?>> _getCredentials() async {
    final secureStorage = FlutterSecureStorage();
    String? email = await secureStorage.read(key: 'email');
    String? password = await secureStorage.read(key: 'password');
    return {'email': email, 'password': password};
  }

  @override
  Widget build(BuildContext context) {
    final influencerViewModel = Provider.of<InfluencerViewModel>(context);
    print("Available influencerViewModel: ${influencerViewModel.influencers.map((c) => c.socialPrice).toList()}");

    List<SearchInfluencer> filteredInfluencers = influencerViewModel.influencers.where((influencer) {
      bool matchesSearch = influencer.userName != null &&
          influencer.userName!.toLowerCase().contains(_searchController.text.toLowerCase());
      bool matchesCountry = influencer.countryName != null &&
          influencer.countryName!.toLowerCase().contains(_searchController.text.toLowerCase());
      bool matchesState = influencer.stateName != null &&
          influencer.stateName!.toLowerCase().contains(_searchController.text.toLowerCase());
      bool matchesCity = influencer.cityName != null &&
          influencer.cityName!.toLowerCase().contains(_searchController.text.toLowerCase());

      Map<String, dynamic>? socialPrices;
      try {
        socialPrices = jsonDecode(influencer.socialPrice ?? '{}');
      } catch (e) {
        print('Error decoding socialPrice: $e');
      }

      bool matchesSocialSite = socialPrices != null &&
          socialPrices.keys.any((key) => key.toLowerCase().contains(_searchController.text.toLowerCase()));

      return matchesSearch || matchesCountry || matchesState || matchesCity || matchesSocialSite;
    }).toList();

    return buildBaseScreen(
      currentIndex: 0, // Set the appropriate index for the bottom nav bar
      title: 'Influencers',
      body: Column(
        children: [
          Padding(
            padding: const EdgeInsets.all(8.0),
            child: TextField(
              controller: _searchController,
              decoration: InputDecoration(
                labelText: 'Search by name, country, state, city or social site',
                border: OutlineInputBorder(),
              ),
              onChanged: (value) {
                setState(() {});
              },
            ),
          ),
          Padding(
            padding: const EdgeInsets.all(8.0),
            child: DropdownButton<String>(
              isExpanded: true,
              value: _selectedFilter,
              onChanged: (newValue) {
                setState(() {
                  _selectedFilter = newValue!;
                });
                if (_selectedFilter == 'Location') {
                  Navigator.push(
                    context,
                    MaterialPageRoute(builder: (context) => LocationFilterScreen()),
                  );
                } else if (_selectedFilter == 'Social_site') {
                  Navigator.push(
                    context,
                    MaterialPageRoute(builder: (context) => TagFilterScreen()),
                  );
                }
              },
              items: ['Select Filter By', 'Location', 'Social_site'].map((filter) {
                return DropdownMenuItem<String>(
                  value: filter,
                  child: Text(filter),
                );
              }).toList(),
            ),
          ),
          Expanded(
            child: influencerViewModel.isLoading
                ? const Center(child: CircularProgressIndicator())
                : filteredInfluencers.isEmpty
                    ? const Center(child: Text('No influencers found'))
                    : ListView.builder(
                        itemCount: filteredInfluencers.length,
                        itemBuilder: (context, index) {
                          final influencer = filteredInfluencers[index];
                          Map<String, dynamic>? socialPrices;
                          try {
                            socialPrices = jsonDecode(influencer.socialPrice ?? '{}');
                          } catch (e) {
                            print('Error decoding socialPrice: $e');
                          }

                          return Padding(
                            padding: const EdgeInsets.symmetric(vertical: 8.0, horizontal: 16.0),
                            child: Card(
                              elevation: 4,
                              shape: RoundedRectangleBorder(
                                borderRadius: BorderRadius.circular(8.0),
                              ),
                              child: Column(
                                children: [
                                  ListTile(
                                    contentPadding: EdgeInsets.all(4.0),
                                    leading: CircleAvatar(
                                      backgroundImage: AssetImage('assets/avatar.png'), // Replace with the path to your avatar image
                                      radius: 20,
                                    ),
                                    title: Text(
                                      influencer.userName ?? "No Name",
                                      style: TextStyle(fontWeight: FontWeight.bold),
                                    ),
                                    subtitle: Text(
                                      '${influencer.countryName ?? "No Country"} / ${influencer.stateName ?? "No State"} / ${influencer.cityName ?? "No City"}',
                                      style: TextStyle(color: Colors.black54),
                                    ),
                                  ),
                                  socialPrices != null
                                      ? Padding(
                                          padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
                                          child: Wrap(
                                            spacing: 10.0,
                                            runSpacing: 5.0,
                                            children: socialPrices.entries.map((entry) {
                                              return SizedBox(
                                                width: (MediaQuery.of(context).size.width - 100) / 3,
                                                child: Chip(
                                                  label: Text('${entry.key}: ${entry.value}'),
                                                ),
                                              );
                                            }).toList(),
                                          ),
                                        )
                                      : Padding(
                                          padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
                                          child: Text('No social data'),
                                        ),
                                ],
                              ),
                            ),
                          );
                        },
                      ),
          ),
        ],
      ),
    );
  }

  @override
  void dispose() {
    _searchController.dispose();
    super.dispose();
  }
}
Enter fullscreen mode Exit fullscreen mode

Image description

Another Way

Declare variable

 TextEditingController _searchController = TextEditingController();
  String _selectedFilter = 'Select Filter By';
Enter fullscreen mode Exit fullscreen mode

Add input field

   Padding(
            padding: const EdgeInsets.all(8.0),
            child: TextField(
              controller: _searchController,
              decoration: InputDecoration(
                labelText: 'Search by name, country, state, city or social site',
                border: OutlineInputBorder(),
              ),
              onChanged: (value) {
                setState(() {});
              },
            ),
          ),
Enter fullscreen mode Exit fullscreen mode

Apply search functionality logic

   List<SearchInfluencer> filteredInfluencers = influencerViewModel.influencers.where((influencer) {
      bool matchesSearch = (influencer.userName != null &&
              influencer.userName!.toLowerCase().contains(_searchController.text.toLowerCase())) ||
          (influencer.countryName != null &&
              influencer.countryName!.toLowerCase().contains(_searchController.text.toLowerCase())) ||
          (influencer.stateName != null &&
              influencer.stateName!.toLowerCase().contains(_searchController.text.toLowerCase())) ||
          (influencer.cityName != null &&
              influencer.cityName!.toLowerCase().contains(_searchController.text.toLowerCase())) ||
          (influencer.socialPrice != null && 
              influencer.socialPrice!.toLowerCase().contains(_searchController.text.toLowerCase()));
      return matchesSearch;
    }).toList();
Enter fullscreen mode Exit fullscreen mode

Renders data

 Expanded(
            child: influencerViewModel.isLoading
                ? const Center(child: CircularProgressIndicator())
                : filteredInfluencers.isEmpty
                    ? const Center(child: Text('No influencers found'))
                    : ListView.builder(
                        itemCount: filteredInfluencers.length,
                        itemBuilder: (context, index) {
                          final influencer = filteredInfluencers[index];
                          Map<String, dynamic>? socialPrices;
                          try {
                            socialPrices = jsonDecode(influencer.socialPrice ?? '{}');
                          } catch (e) {
                            print('Error decoding socialPrice: $e');
                          }
                          return Padding(
                            padding: const EdgeInsets.symmetric(vertical: 8.0, horizontal: 16.0),
                            child: Card(
                              elevation: 4,
                              shape: RoundedRectangleBorder(
                                borderRadius: BorderRadius.circular(8.0),
                              ),
                              child: Column(
                                children: [
                                  ListTile(
                                    contentPadding: EdgeInsets.all(4.0),
                                    leading: CircleAvatar(
                                      backgroundImage: AssetImage('assets/avatar.png'), // Replace with the path to your avatar image
                                      radius: 20,
                                    ),
                                    title: Text(
                                      influencer.userName ?? "No Name",
                                      style: TextStyle(fontWeight: FontWeight.bold),
                                    ),
                                  ),
                                  Padding(
                                    padding: const EdgeInsets.symmetric(horizontal: 4.0, vertical: 2.0),
                                    child: Text(
                                      '${influencer.countryName ?? "No Country"} / ${influencer.stateName ?? "No State"} / ${influencer.cityName ?? "No City"}',
                                      style: TextStyle(color: Colors.black54),
                                    ),
                                  ),
                                  socialPrices != null
                                      ? Padding(
                                          padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
                                          child: Wrap(
                                            spacing: 10.0,
                                            runSpacing: 5.0,
                                            children: socialPrices.entries.map((entry) {
                                              return SizedBox(
                                                width: (MediaQuery.of(context).size.width - 100) / 3,
                                                child: Chip(
                                                  label: Text('${entry.key}: ${entry.value}'),
                                                ),
                                              );
                                            }).toList(),
                                          ),
                                        )
                                      : Padding(
                                          padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
                                          child: Text('No social data'),
                                        ),
                                ],
                              ),
                            ),
                          );
                        },
                      ),
          ),
Enter fullscreen mode Exit fullscreen mode

Top comments (0)