Debug School

rakesh kumar
rakesh kumar

Posted on

Implement a filtering mechanism in Flutter

Input type filter

To add filtering functionality to your KeywordScreen, similar to the previous examples, you'll need to implement a search input field that allows users to filter keywords based on project names or URLs. Below are the specific changes needed:

  1. Add Search Controller and Filtered Keywords List Add these variables in your _KeywordScreenState class:
  TextEditingController _searchController = TextEditingController();
List<Keyword> _filteredKeywords = []; // List to hold filtered keywords
Enter fullscreen mode Exit fullscreen mode
  1. Update the _fetchData Method In the _fetchData method, ensure you initialize _filteredKeywords with the data fetched from the API:
Future<void> _fetchData() async {
    final organizationViewModel = Provider.of<OrganizationViewModel>(context, listen: false);
    final credentials = await _getCredentials();
    final email = credentials['email'];
    final orgSlug = widget.orgSlug;

    // Fetch orgRoleId from secure storage and determine the role
    final secureStorage = FlutterSecureStorage();
    final orgRoleId = await secureStorage.read(key: 'orgRoleId');
    final orgUserId = await secureStorage.read(key: 'orgUserId');
    final orgUserorgId = await secureStorage.read(key: 'orgUserorgId');

    setState(() {
      _userRole = determineUserRole(orgRoleId); // Use the mixin to determine the role
    });

    if (email != null && orgSlug.isNotEmpty) {
      await organizationViewModel.getUserFunction(email, orgSlug);
      await organizationViewModel.getKeyword(email, orgSlug, orgRoleId.toString(), orgUserId.toString(), orgUserorgId.toString());

      _filteredKeywords = organizationViewModel.my_keywords; // Initialize with full data
    }
}
Enter fullscreen mode Exit fullscreen mode
  1. Add the Filter Method Add the _filterKeywords method below your existing methods to filter the keywords based on the search input:
void _filterKeywords(String query) {
    final organizationViewModel = Provider.of<OrganizationViewModel>(context, listen: false);
    final allKeywords = organizationViewModel.my_keywords;

    setState(() {
      _filteredKeywords = allKeywords.where((keyword) {
        final projectNameLower = keyword.projectName?.toLowerCase() ?? '';
        final urlLower = keyword.url?.toLowerCase() ?? '';
        final queryLower = query.toLowerCase();

        return projectNameLower.contains(queryLower) || 
               urlLower.contains(queryLower);
      }).toList();
    });
}
Enter fullscreen mode Exit fullscreen mode
  1. Update the build Method In the build method, add the search input field above the existing list of keywords.

Add the Search TextField
Insert this below the SizedBox(height: 20), line:

Padding(
  padding: const EdgeInsets.all(8.0),
  child: TextField(
    controller: _searchController,
    decoration: InputDecoration(
      labelText: 'Search by Project Name or URL',
      border: OutlineInputBorder(),
      prefixIcon: Icon(Icons.search),
    ),
    onChanged: (value) {
      _filterKeywords(value); // Call filter method on text change
    },
  ),
),
Enter fullscreen mode Exit fullscreen mode

Update the ListView.builder
Replace organizationViewModel.my_keywords.isEmpty with _filteredKeywords.isEmpty and change organizationViewModel.my_keywords.length to _filteredKeywords.length:

Expanded(
  child: _filteredKeywords.isEmpty // Check filtered keywords
      ? Center(
          child: Text('No keywords found for this organization'),
        )
      : ListView.builder(
          itemCount: _filteredKeywords.length,
          itemBuilder: (context, index) {
            final keyword = _filteredKeywords[index];

            return Card(
              // Card content...
            );
          },
        ),
),
Enter fullscreen mode Exit fullscreen mode

Summary of Changes

Search Controller: Added a TextEditingController to manage the search input.
Filtered Keywords List: Introduced a list to hold the filtered keywords based on the search criteria.
Filter Method: Implemented _filterKeywords to filter keywords based on project names or URLs.
Integrated Search Field: Added a TextField for the search input in the UI.
Updated Display Logic: Updated the displayed keywords to reflect the filtered results.

Full code

import 'package:flutter/material.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:provider/provider.dart';
import 'package:wizbrand/Screen/Influencer/createkeyword.dart';
import 'package:wizbrand/Screen/layout/drawer.dart';
import 'package:wizbrand/Screen/layout/rolemixins.dart';
import 'package:wizbrand/model/keyword.dart';
import 'package:wizbrand/view_modal/organization_view_model.dart';

class KeywordScreen extends StatefulWidget {
  final String orgSlug;

  KeywordScreen({required this.orgSlug});

  @override
  _KeywordScreenState createState() => _KeywordScreenState();
}

class _KeywordScreenState extends State<KeywordScreen> with DrawerMixin, RoleMixin {
  String _userRole = ''; // Variable to store the role for AppBar
  TextEditingController _searchController = TextEditingController();
List<Keyword> _filteredKeywords = []; // List to hold filtered keywords
  @override
  void initState() {
    super.initState();
    _fetchData(); // Fetch keyword data when the screen initializes
  }

  Future<void> _fetchData() async {
    final organizationViewModel = Provider.of<OrganizationViewModel>(context, listen: false);
    final credentials = await _getCredentials();
    final email = credentials['email'];
    final orgSlug = widget.orgSlug;
    // Fetch orgRoleId from secure storage and determine the role
    final secureStorage = FlutterSecureStorage();
    final orgRoleId = await secureStorage.read(key: 'orgRoleId');
    final orgUserId = await secureStorage.read(key: 'orgUserId');
    final orgUserorgId = await secureStorage.read(key: 'orgUserorgId');

    setState(() {
      _userRole = determineUserRole(orgRoleId); // Use the mixin to determine the role
    });
     if (email != null && orgSlug.isNotEmpty) {
      await organizationViewModel.getUserFunction(email, orgSlug);
      await organizationViewModel.getKeyword(email, orgSlug, orgRoleId.toString(), orgUserId.toString(), orgUserorgId.toString());

      _filteredKeywords = organizationViewModel.my_keywords; // Initialize with full data
    }
    setState(() {}); // Rebuild the widget after fetching data
  }

  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};
  }

void _filterKeywords(String query) {
    final organizationViewModel = Provider.of<OrganizationViewModel>(context, listen: false);
    final allKeywords = organizationViewModel.my_keywords;

    setState(() {
      _filteredKeywords = allKeywords.where((keyword) {
        final projectNameLower = keyword.projectName?.toLowerCase() ?? '';
        final urlLower = keyword.url?.toLowerCase() ?? '';
        final queryLower = query.toLowerCase();

        return projectNameLower.contains(queryLower) || 
               urlLower.contains(queryLower);
      }).toList();
    });
}
  @override
  Widget build(BuildContext context) {
    final organizationViewModel = Provider.of<OrganizationViewModel>(context);

    return Scaffold(
      appBar: AppBar(
        automaticallyImplyLeading: true,
        backgroundColor: Colors.blue,
        centerTitle: true,
        title: Text(
          'Keywords - $_userRole', // Display role dynamically in the AppBar
          style: TextStyle(color: Colors.white),
        ),
      ),
      drawer: buildDrawer(context, orgSlug: widget.orgSlug),
      body: organizationViewModel.isLoading
          ? Center(child: CircularProgressIndicator())
          : Stack(
              children: [
                buildBaseScreen(
                  body: Padding(
                    padding: const EdgeInsets.all(16.0),
                    child: Column(
                      crossAxisAlignment: CrossAxisAlignment.start,
                      children: [
                        Text(
                          'Keywords',
                          style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
                        ),
                        SizedBox(height: 20),
                        ElevatedButton(
                          onPressed: () {
                            _showCreateKeywordDialog(context);
                          },
                          child: Text('Create New Keyword'),
                        ),
                        SizedBox(height: 20),
                        Padding(
  padding: const EdgeInsets.all(8.0),
  child: TextField(
    controller: _searchController,
    decoration: InputDecoration(
      labelText: 'Search by Project Name or URL',
      border: OutlineInputBorder(),
      prefixIcon: Icon(Icons.search),
    ),
    onChanged: (value) {
      _filterKeywords(value); // Call filter method on text change
    },
  ),
),
                        Expanded(
                          child: _filteredKeywords.isEmpty
                              ? Center(
                                  child: Text('No keywords found for this organization'),
                                )
                              : ListView.builder(
                                  itemCount: _filteredKeywords.length,
          itemBuilder: (context, index) {
            final keyword = _filteredKeywords[index];

                                    return Card(
                                      margin: const EdgeInsets.symmetric(vertical: 8.0),
                                      shape: RoundedRectangleBorder(
                                        borderRadius: BorderRadius.circular(10),
                                        side: BorderSide(color: Colors.grey[300]!),
                                      ),
                                      child: Padding(
                                        padding: const EdgeInsets.all(16.0),
                                        child: Column(
                                          crossAxisAlignment: CrossAxisAlignment.start,
                                          children: [
                                            // Displaying ID
                                            Text(
                                              'Id: ${keyword.id.toString()}',
                                              style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
                                            ),
                                            SizedBox(height: 8),

                                            // Project Name
                                            Text(
                                              'Project Name: ${keyword.projectName ?? ''}',
                                              style: TextStyle(fontSize: 14),
                                            ),
                                            SizedBox(height: 8),

                                            // URL
                                            GestureDetector(
                                              onTap: () {
                                                // Handle URL click if needed
                                              },
                                              child: Text(
                                                'URL: ${keyword.url ?? ''}',
                                                style: TextStyle(color: Colors.blue, decoration: TextDecoration.underline),
                                              ),
                                            ),
                                            SizedBox(height: 8),

                                            // Displaying Keywords as tags
                                            Wrap(
                                              spacing: 6.0,
                                              runSpacing: 6.0,
                                              children: keyword.keyword != null
                                                  ? keyword.keyword!.map((kw) {
                                                      return Container(
                                                        padding: EdgeInsets.symmetric(horizontal: 10, vertical: 5),
                                                        decoration: BoxDecoration(
                                                          color: Colors.purple,
                                                          borderRadius: BorderRadius.circular(20),
                                                        ),
                                                        child: Text(
                                                          kw,
                                                          style: TextStyle(color: Colors.white),
                                                        ),
                                                      );
                                                    }).toList()
                                                  : [],
                                            ),
                                            SizedBox(height: 8),

                                            // Row for edit and delete icons
                                            Row(
                                              mainAxisAlignment: MainAxisAlignment.end,
                                              children: [
                                                IconButton(
                                                  icon: Icon(Icons.edit, color: Colors.blue),
                                                  onPressed: () {
                                                    _showEditKeywordDialog(context, keyword);
                                                  },
                                                  tooltip: 'Edit Keyword',
                                                ),
                                                IconButton(
                                                  icon: Icon(Icons.delete, color: Colors.red),
                                                  onPressed: () {
                                                    _showDeleteKeywordDialog(context, keyword);
                                                  },
                                                  tooltip: 'Delete Keyword',
                                                ),
                                              ],
                                            ),
                                          ],
                                        ),
                                      ),
                                    );
                                  },
                                ),
                        ),
                      ],
                    ),
                  ),
                ),
              ],
            ),
    );
  }

  void _showCreateKeywordDialog(BuildContext context) async {
    final secureStorage = FlutterSecureStorage();
    final orgRoleId = await secureStorage.read(key: 'orgRoleId');
    final orgUserId = await secureStorage.read(key: 'orgUserId');
    final orgUserorgId = await secureStorage.read(key: 'orgUserorgId');

    await showDialog(
      context: context,
      builder: (BuildContext context) {
        return CreateKeywordDialog(
          orgSlug: widget.orgSlug,
          orgRoleId: orgRoleId!,
          orgUserId: orgUserId!,
          orgUserorgId: orgUserorgId!,
        );
      },
    );
  }

void _showEditKeywordDialog(BuildContext context, dynamic keyword) async {
  final secureStorage = FlutterSecureStorage();
  final orgRoleId = await secureStorage.read(key: 'orgRoleId');
  final orgUserId = await secureStorage.read(key: 'orgUserId');
  final orgUserorgId = await secureStorage.read(key: 'orgUserorgId');

  await showDialog(
    context: context,
    builder: (BuildContext context) {
      return CreateKeywordDialog(
        orgSlug: widget.orgSlug,
        orgRoleId: orgRoleId!,
        orgUserId: orgUserId!,
        orgUserorgId: orgUserorgId!,
        keywordId: keyword.id.toString(), // Pass the keyword ID for editing
        existingKeywords: keyword.keyword, // Pass existing keywords for editing
        selectedProjectId: keyword.projectId.toString(), // Pass the selected project ID     
          selectedUrlname: keyword.url, // Pass the selected URL ID
        selectedUrlId: keyword.urlId.toString(), // Pass the selected URL ID
      );
    },
  );
}

  void _showDeleteKeywordDialog(BuildContext context, keyword) async {
    final confirmed = await showDialog(
      context: context,
      builder: (BuildContext context) {
        return AlertDialog(
          title: Text('Delete Keyword'),
          content: Text('Are you sure you want to delete this keyword?'),
          actions: [
            TextButton(
              onPressed: () {
                Navigator.of(context).pop(false); // Cancel action
              },
              child: Text('Cancel'),
            ),
            ElevatedButton(
              onPressed: () {
                Navigator.of(context).pop(true); // Confirm action
              },
              style: ElevatedButton.styleFrom(backgroundColor: Colors.red),
              child: Text('Delete'),
            ),
          ],
        );
      },
    );

   if (confirmed == true) {
      final organizationViewModel = Provider.of<OrganizationViewModel>(context, listen: false);

       await organizationViewModel.deleteKeyword(keyword.id.toString()); // Assuming deleteUrl method takes an ID

      _fetchData(); // Refresh the data after deletion
    }
  }

  Widget buildBaseScreen({required Widget body}) {
    return Container(
      decoration: BoxDecoration(
        color: Colors.white,
      ),
      child: body,
    );
  }
}
Enter fullscreen mode Exit fullscreen mode

Search button type filter

Initialization of Member Data Map

  Map<String, List<WebRatings>> memberDataMap = {};
Enter fullscreen mode Exit fullscreen mode

This line creates a map named memberDataMap where the keys are strings representing team member names (e.g., "Alexa Global") and the values are lists of WebRatings. This map will hold data specific to each team member for later retrieval.

Definition of Team Members:

final List<String> teamMembers = [
"Alexa Global",
      "Alexa USA",
      "Domain",
      "Alexa India",
      "Backlinks",
      "Referring Domain"
];
Enter fullscreen mode Exit fullscreen mode

or

 final List<Map<String, dynamic>> buttons = [
    {'label': 'Subscriber', 'color': Colors.red},
    {'label': 'Facebook', 'color': Colors.purple},
    {'label': 'Followers', 'color': Colors.teal},
    {'label': 'Instagram', 'color': Colors.blue},
  ];
Enter fullscreen mode Exit fullscreen mode

Data Fetching Method:


  Future<void> _fetchData() async {
    final organizationViewModel = Provider.of<OrganizationViewModel>(context, listen: false);
    final credentials = await _getCredentials();
    final email = credentials['email'];
    final orgSlug = widget.orgSlug;
    final secureStorage = FlutterSecureStorage();
    final orgRoleId = await secureStorage.read(key: 'orgRoleId');
    final orgUserId = await secureStorage.read(key: 'orgUserId');
    final orgUserorgId = await secureStorage.read(key: 'orgUserorgId');

    setState(() {
      _userRole = determineUserRole(orgRoleId); // Use the mixin to determine the role
    });

      if (email != null && orgSlug.isNotEmpty) {
      await organizationViewModel.getWebRating(email, orgSlug, orgRoleId.toString(), orgUserId.toString(), orgUserorgId.toString());
      _filteredWebData = organizationViewModel.my_website; // Initialize with full data
   _populateMemberDataMap();// look here
    }
  }
Enter fullscreen mode Exit fullscreen mode

Populating Member Data Map:

void _populateMemberDataMap() {
  // Clear the existing data
  memberDataMap.clear();

  // Loop through the defined team members
  for (var member in teamMembers) {
    // Filter web data based on the project names that match the member
    memberDataMap[member] = _filteredWebData.where((data) {
      // Adjust this logic based on your requirements
      return data.projectName != null && data.projectName!.contains(member);
    }).toList();
  }
}
Enter fullscreen mode Exit fullscreen mode

Building Dynamic Buttons:


  _buildDynamicButtons(), // Dynamic buttons for team members
Enter fullscreen mode Exit fullscreen mode

Building Dynamic Buttons function defination:

Widget _buildDynamicButtons() {
  _populateMemberDataMap(); // Call this to ensure the map is populated before displaying buttons

  return SingleChildScrollView(
    scrollDirection: Axis.horizontal,
    child: Row(
      children: teamMembers.map((memberName) {
        return GestureDetector(
          onTap: () {
            _showDetailsDialog(memberName); // Call to show details dialog
          },
          child: Container(
            padding: EdgeInsets.symmetric(horizontal: 12, vertical: 6),
            margin: EdgeInsets.only(right: 8), // Spacing between buttons
            decoration: BoxDecoration(
              color: Colors.purple,
              borderRadius: BorderRadius.circular(20),
            ),
            child: Text(
              memberName,
              style: TextStyle(color: Colors.white),
            ),
          ),
        );
      }).toList(),
    ),
  );
}
Enter fullscreen mode Exit fullscreen mode

Showing Details Dialog:

void _showDetailsDialog(String memberName) {
  // Filter the data based on the selected member name
  List<WebRatings> filteredData = _filteredWebData.where((data) {
    // Check if the memberName matches any relevant fields in the web data
    switch (memberName) {
      case "Alexa Global":
        return data.globalRank != null; // Ensure that global rank is not null
      case "Alexa USA":
        return data.usaRank != null; // Ensure that USA rank is not null
      case "Domain":
        return data.domain != null; // Ensure that domain is not null
      case "Alexa India":
        return data.indiaRank != null; // Ensure that India rank is not null
      case "Backlinks":
        return data.backlinks != null; // Ensure that backlinks are not null
      case "Referring Domain":
        return data.refer != null; // Ensure that referring domains are not null
      default:
        return false; // No matching case
    }
  }).toList();

  // Create a dialog showing details for the selected member
  showDialog(
    context: context,
    builder: (BuildContext context) {
      return AlertDialog(
        title: Text('$memberName Details'),
        content: Container(
          width: double.maxFinite,
          height: 400, // Adjust the height based on your needs
          child: filteredData.isNotEmpty
              ? ListView.builder(
                  itemCount: filteredData.length,
                  itemBuilder: (context, index) {
                    final data = filteredData[index];
                    return Padding(
                      padding: const EdgeInsets.symmetric(vertical: 4.0),
                      child: Column(
                        crossAxisAlignment: CrossAxisAlignment.start,
                        children: [
                          Text(
                            'Project Name: ${data.projectName ?? 'N/A'}',
                            style: TextStyle(fontSize: 14),
                          ),
                          Text(
                            'Domain Authority: ${data.domain ?? 'N/A'}',
                            style: TextStyle(fontSize: 14),
                          ),
                          Text(
                            'Alexa Global: ${data.globalRank ?? 'N/A'}',
                            style: TextStyle(fontSize: 14),
                          ),
                          Text(
                            'Alexa USA: ${data.usaRank ?? 'N/A'}',
                            style: TextStyle(fontSize: 14),
                          ),
                          Text(
                            'Alexa India: ${data.indiaRank ?? 'N/A'}',
                            style: TextStyle(fontSize: 14),
                          ),
                          Text(
                            'Backlinks: ${data.backlinks ?? 'N/A'}',
                            style: TextStyle(fontSize: 14),
                          ),
                          Text(
                            'Referring Domains: ${data.refer ?? 'N/A'}',
                            style: TextStyle(fontSize: 14),
                          ),
                          Divider(), // Divider between entries for better readability
                        ],
                      ),
                    );
                  },
                )
              : Center(child: Text('No data available for $memberName.')),
        ),
        actions: [
          TextButton(
            onPressed: () {
              Navigator.of(context).pop(); // Close the dialog
            },
            child: Text('Close'),
          ),
        ],
      );
    },
  );
}
Enter fullscreen mode Exit fullscreen mode

output

Image description

Image description

Full code implemention


import 'package:flutter/material.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:provider/provider.dart';
import 'package:wizbrand/Screen/Influencer/createweb.dart';
import 'package:wizbrand/Screen/layout/drawer.dart';
import 'package:wizbrand/Screen/layout/rolemixins.dart';
import 'package:wizbrand/model/webrating.dart';
import 'package:wizbrand/view_modal/organization_view_model.dart';

class WebScreen extends StatefulWidget {
  final String orgSlug;

  WebScreen({required this.orgSlug});

  @override
  _WebScreenState createState() => _WebScreenState();
}

class _WebScreenState extends State<WebScreen> with DrawerMixin, RoleMixin {
  String _userRole = ''; // Variable to store the role for AppBar

  TextEditingController _searchController = TextEditingController();
List<WebRatings> _filteredWebData = []; // List to hold filtered web data
   Map<String, List<WebRatings>> memberDataMap = {};
  @override
  void initState() {
    super.initState();
    _fetchData(); // Fetch organization data when the screen initializes
  }

final List<String> teamMembers = [
"Alexa Global",
      "Alexa USA",
      "Domain",
      "Alexa India",
      "Backlinks",
      "Referring Domain"
];
  Future<void> _fetchData() async {
    final organizationViewModel = Provider.of<OrganizationViewModel>(context, listen: false);
    final credentials = await _getCredentials();
    final email = credentials['email'];
    final orgSlug = widget.orgSlug;
    final secureStorage = FlutterSecureStorage();
    final orgRoleId = await secureStorage.read(key: 'orgRoleId');
    final orgUserId = await secureStorage.read(key: 'orgUserId');
    final orgUserorgId = await secureStorage.read(key: 'orgUserorgId');

    setState(() {
      _userRole = determineUserRole(orgRoleId); // Use the mixin to determine the role
    });

      if (email != null && orgSlug.isNotEmpty) {
      await organizationViewModel.getWebRating(email, orgSlug, orgRoleId.toString(), orgUserId.toString(), orgUserorgId.toString());
      _filteredWebData = organizationViewModel.my_website; // Initialize with full data
   _populateMemberDataMap();
    }
  }

void _populateMemberDataMap() {
  // Clear the existing data
  memberDataMap.clear();

  // Loop through the defined team members
  for (var member in teamMembers) {
    // Filter web data based on the project names that match the member
    memberDataMap[member] = _filteredWebData.where((data) {
      // Adjust this logic based on your requirements
      return data.projectName != null && data.projectName!.contains(member);
    }).toList();
  }
}
void _filterWebData(String query) {
    final organizationViewModel = Provider.of<OrganizationViewModel>(context, listen: false);
    final allWebData = organizationViewModel.my_website;

    setState(() {
      _filteredWebData = allWebData.where((webData) {
        final projectNameLower = webData.projectName?.toLowerCase() ?? '';
        final urlLower = webData.domain?.toLowerCase() ?? ''; // Adjust as needed for the URL field
        final queryLower = query.toLowerCase();

        return projectNameLower.contains(queryLower) || 
               urlLower.contains(queryLower);
      }).toList();
    });
}

  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 organizationViewModel = Provider.of<OrganizationViewModel>(context);

    return Scaffold(
      appBar: AppBar(
        automaticallyImplyLeading: true,
        backgroundColor: Colors.blue,
        centerTitle: true,
        title: Text(
          'Web Rankings - $_userRole', // Display role dynamically in the AppBar
          style: TextStyle(color: Colors.white),
        ),
      ),
      drawer: buildDrawer(context, orgSlug: widget.orgSlug),
      body: organizationViewModel.isLoading
          ? Center(child: CircularProgressIndicator()) // Display loading indicator while fetching data
          : Stack(
              children: [
                buildBaseScreen(
                  body: Padding(
                    padding: const EdgeInsets.all(16.0),
                    child: Column(
                      crossAxisAlignment: CrossAxisAlignment.start,
                      children: [
                        Text(
                          'Web Rankings',
                          style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
                        ),
                        SizedBox(height: 20),
                                          Padding(
                    padding: const EdgeInsets.all(8.0),
                    child: TextField(
                      controller: _searchController,
                      decoration: InputDecoration(
                        labelText: 'Search by Project Name or Domain',
                        border: OutlineInputBorder(),
                        prefixIcon: Icon(Icons.search),
                      ),
                      onChanged: (value) {
                        _filterWebData(value); // Call filter method on text change
                      },
                    ),
                  ),
                        ElevatedButton(
                          onPressed: () {
                            _showCreateWebRankingDialog(context);
                          },
                          child: Text('Create New Web Ranking'),
                        ),
                        SizedBox(height: 20),
                         _buildDynamicButtons(), // Dynamic buttons for team members
                        Expanded(
                       child: _filteredWebData.isEmpty // Check filtered web data
                              ? Center(child: Text('No Web ranking found'))
                              : ListView.builder(
                                  itemCount: _filteredWebData.length,
                                itemBuilder: (context, index) {
                                  final webdata = _filteredWebData[index];

                                    return Card(
                                      margin: const EdgeInsets.symmetric(vertical: 8.0),
                                      shape: RoundedRectangleBorder(
                                        borderRadius: BorderRadius.circular(10),
                                        side: BorderSide(color: Colors.grey[300]!),
                                      ),
                                      child: Padding(
                                        padding: const EdgeInsets.all(16.0),
                                        child: Column(
                                          crossAxisAlignment: CrossAxisAlignment.start,
                                          children: [
                                            // ID
                                            Text(
                                              'ID: ${webdata.id ?? 'N/A'}',
                                              style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
                                            ),
                                            SizedBox(height: 8),

                                            // Date
                                            Text(
                                              'Date: ${webdata.createdAt ?? 'N/A'}',
                                              style: TextStyle(fontSize: 14),
                                            ),
                                            SizedBox(height: 8),

                                            // Project Name
                                            Text(
                                              'Project Name: ${webdata.projectName ?? 'No Project Name'}',
                                              style: TextStyle(fontSize: 14),
                                            ),
                                            SizedBox(height: 8),

                                            // Displaying Web Ranking details using Wrap to avoid overflow
                                            Wrap(
                                              spacing: 6.0,
                                              runSpacing: 6.0,
                                              children: [
                                                _buildTag('Domain Authority: ${webdata.domain ?? 'N/A'}'),
                                                _buildTag('Alexa Global: ${webdata.globalRank ?? 'N/A'}'),
                                                _buildTag('Alexa USA: ${webdata.usaRank ?? 'N/A'}'),
                                                _buildTag('Alexa India: ${webdata.indiaRank ?? 'N/A'}'),
                                                _buildTag('Backlinks: ${webdata.backlinks ?? 'N/A'}'),
                                                _buildTag('Referring Domains: ${webdata.refer ?? 'N/A'}'),
                                              ],
                                            ),
                                            SizedBox(height: 8),

                                            // Row for edit and delete icons
                                            Row(
                                              mainAxisAlignment: MainAxisAlignment.end,
                                              children: [
                                                IconButton(
                                                  icon: Icon(Icons.edit, color: Colors.blue),
                                                  onPressed: () {
                                                    _showEditWebRankingDialog(context, webdata);
                                                  },
                                                  tooltip: 'Edit Web Ranking',
                                                ),
                                                IconButton(
                                                  icon: Icon(Icons.delete, color: Colors.red),
                                                  onPressed: () {
                                                    _showDeleteWebRankingDialog(context, webdata);
                                                  },
                                                  tooltip: 'Delete Web Ranking',
                                                ),
                                              ],
                                            ),
                                          ],
                                        ),
                                      ),
                                    );
                                  },
                                ),
                        ),
                      ],
                    ),
                  ),
                ),
              ],
            ),
    );
  }

  // Helper method to build tags
  Widget _buildTag(String text) {
    return Container(
      padding: EdgeInsets.symmetric(horizontal: 10, vertical: 5),
      decoration: BoxDecoration(
        color: Colors.purple,
        borderRadius: BorderRadius.circular(20),
      ),
      child: Text(
        text,
        style: TextStyle(color: Colors.white),
      ),
    );
  }
 // Method to build the dynamic buttons below the search bar
Widget _buildDynamicButtons() {
  _populateMemberDataMap(); // Call this to ensure the map is populated before displaying buttons

  return SingleChildScrollView(
    scrollDirection: Axis.horizontal,
    child: Row(
      children: teamMembers.map((memberName) {
        return GestureDetector(
          onTap: () {
            _showDetailsDialog(memberName); // Call to show details dialog
          },
          child: Container(
            padding: EdgeInsets.symmetric(horizontal: 12, vertical: 6),
            margin: EdgeInsets.only(right: 8), // Spacing between buttons
            decoration: BoxDecoration(
              color: Colors.purple,
              borderRadius: BorderRadius.circular(20),
            ),
            child: Text(
              memberName,
              style: TextStyle(color: Colors.white),
            ),
          ),
        );
      }).toList(),
    ),
  );
}

// Method to show details dialog for a selected project
void _showDetailsDialog(String memberName) {
  // Filter the data based on the selected member name
  List<WebRatings> filteredData = _filteredWebData.where((data) {
    // Check if the memberName matches any relevant fields in the web data
    switch (memberName) {
      case "Alexa Global":
        return data.globalRank != null; // Ensure that global rank is not null
      case "Alexa USA":
        return data.usaRank != null; // Ensure that USA rank is not null
      case "Domain":
        return data.domain != null; // Ensure that domain is not null
      case "Alexa India":
        return data.indiaRank != null; // Ensure that India rank is not null
      case "Backlinks":
        return data.backlinks != null; // Ensure that backlinks are not null
      case "Referring Domain":
        return data.refer != null; // Ensure that referring domains are not null
      default:
        return false; // No matching case
    }
  }).toList();

  // Create a dialog showing details for the selected member
  showDialog(
    context: context,
    builder: (BuildContext context) {
      return AlertDialog(
        title: Text('$memberName Details'),
        content: Container(
          width: double.maxFinite,
          height: 400, // Adjust the height based on your needs
          child: filteredData.isNotEmpty
              ? ListView.builder(
                  itemCount: filteredData.length,
                  itemBuilder: (context, index) {
                    final data = filteredData[index];
                    return Padding(
                      padding: const EdgeInsets.symmetric(vertical: 4.0),
                      child: Column(
                        crossAxisAlignment: CrossAxisAlignment.start,
                        children: [
                          Text(
                            'Project Name: ${data.projectName ?? 'N/A'}',
                            style: TextStyle(fontSize: 14),
                          ),
                          Text(
                            'Domain Authority: ${data.domain ?? 'N/A'}',
                            style: TextStyle(fontSize: 14),
                          ),
                          Text(
                            'Alexa Global: ${data.globalRank ?? 'N/A'}',
                            style: TextStyle(fontSize: 14),
                          ),
                          Text(
                            'Alexa USA: ${data.usaRank ?? 'N/A'}',
                            style: TextStyle(fontSize: 14),
                          ),
                          Text(
                            'Alexa India: ${data.indiaRank ?? 'N/A'}',
                            style: TextStyle(fontSize: 14),
                          ),
                          Text(
                            'Backlinks: ${data.backlinks ?? 'N/A'}',
                            style: TextStyle(fontSize: 14),
                          ),
                          Text(
                            'Referring Domains: ${data.refer ?? 'N/A'}',
                            style: TextStyle(fontSize: 14),
                          ),
                          Divider(), // Divider between entries for better readability
                        ],
                      ),
                    );
                  },
                )
              : Center(child: Text('No data available for $memberName.')),
        ),
        actions: [
          TextButton(
            onPressed: () {
              Navigator.of(context).pop(); // Close the dialog
            },
            child: Text('Close'),
          ),
        ],
      );
    },
  );
}
  // Method to show details dialog for a selected project

  // Method to display a dialog for creating a Web Ranking entry
  void _showCreateWebRankingDialog(BuildContext context) async {
    final secureStorage = FlutterSecureStorage();
    final orgRoleId = await secureStorage.read(key: 'orgRoleId');
    final orgUserId = await secureStorage.read(key: 'orgUserId');
    final orgUserorgId = await secureStorage.read(key: 'orgUserorgId');

    await showDialog(
      context: context,
      builder: (BuildContext context) {
        return CreateWebDialog(
          orgSlug: widget.orgSlug,
          orgRoleId: orgRoleId!,
          orgUserId: orgUserId!,
          orgUserorgId: orgUserorgId!,
        ); // Passing the orgSlug
      },
    );
  }

void _showEditWebRankingDialog(BuildContext context, dynamic webData) async {
  final secureStorage = FlutterSecureStorage();
  final orgRoleId = await secureStorage.read(key: 'orgRoleId');
  final orgUserId = await secureStorage.read(key: 'orgUserId');
  final orgUserorgId = await secureStorage.read(key: 'orgUserorgId');

  await showDialog(
    context: context,
    builder: (BuildContext context) {
      return CreateWebDialog(
        orgSlug: widget.orgSlug,
        orgRoleId: orgRoleId!,
        orgUserId: orgUserId!,
        orgUserorgId: orgUserorgId!,
        webid: webData.id.toString(),
        projectId: webData.projectId.toString(),
        projectName: webData.projectName,
        domain: webData.domain,
        globalRank: webData.globalRank?.toString(),
        usaRank: webData.usaRank?.toString(),
        indiaRank: webData.indiaRank?.toString(),
        backlinks: webData.backlinks?.toString(),
        referringDomains: webData.refer?.toString(),
      );
    },
  );
}

  // Method to display a dialog for deleting a Web Ranking entry
  void _showDeleteWebRankingDialog(BuildContext context, dynamic webdata) async {
    final confirmed = await showDialog(
      context: context,
      builder: (BuildContext context) {
        return AlertDialog(
          title: Text('Delete Web Ranking'),
          content: Text('Are you sure you want to delete this web ranking entry?'),
          actions: [
            TextButton(
              onPressed: () {
                Navigator.of(context).pop(false); // Cancel action
              },
              child: Text('Cancel'),
            ),
            ElevatedButton(
              onPressed: () {
                Navigator.of(context).pop(true); // Confirm action
              },
              style: ElevatedButton.styleFrom(backgroundColor: Colors.red),
              child: Text('Delete'),
            ),
          ],
        );
      },
    );

    if (confirmed == true) {
      final organizationViewModel = Provider.of<OrganizationViewModel>(context, listen: false);
       await organizationViewModel.deleteWeb(webdata.id.toString()); // Assuming deleteCompetitor method takes an ID
      _fetchData(); // Refresh the data after deletion
    }
  }

  Widget buildBaseScreen({required Widget body}) {
    return Container(
      decoration: BoxDecoration(
        color: Colors.white,
      ),
      child: body,
    );
  }
}
Enter fullscreen mode Exit fullscreen mode

Search button with different button color type filter

To add dynamic labels and colors to your buttons, you can modify your current code to incorporate a list of maps containing button properties such as label and color. Here's how you can integrate this into your existing setup:

  1. Define the buttons list: We'll use a list of maps to define the labels and colors for your buttons.
final List<Map<String, dynamic>> buttons = [
  {'label': 'Alexa Global', 'color': Colors.red},
  {'label': 'Alexa USA', 'color': Colors.purple},
  {'label': 'Domain', 'color': Colors.teal},
  {'label': 'Alexa India', 'color': Colors.blue},
  {'label': 'Backlinks', 'color': Colors.orange},
  {'label': 'Referring Domain', 'color': Colors.green},
];
Enter fullscreen mode Exit fullscreen mode
  1. Modify the _buildDynamicButtons function: Instead of mapping through teamMembers, we will loop through the buttons list and use the label and color values for each button.
Widget _buildDynamicButtons() {
  _populateMemberDataMap(); // Ensure the map is populated before displaying buttons

  return SingleChildScrollView(
    scrollDirection: Axis.horizontal,
    child: Row(
      children: buttons.map((button) {
        return GestureDetector(
          onTap: () {
            _showDetailsDialog(button['label']); // Use the label to show details
          },
          child: Container(
            padding: EdgeInsets.symmetric(horizontal: 12, vertical: 6),
            margin: EdgeInsets.only(right: 8), // Spacing between buttons
            decoration: BoxDecoration(
              color: button['color'], // Set the button color dynamically
              borderRadius: BorderRadius.circular(20),
            ),
            child: Text(
              button['label'], // Display the button label
              style: TextStyle(color: Colors.white),
            ),
          ),
        );
      }).toList(),
    ),
  );
}
Enter fullscreen mode Exit fullscreen mode
  1. Update _showDetailsDialog to handle the dynamic labels: Make sure the dialog shows the correct data for the dynamic buttons. You already have this logic in place based on the memberName.
void _showDetailsDialog(String memberName) {
  List<WebRatings> filteredData = _filteredWebData.where((data) {
    switch (memberName) {
      case "Alexa Global":
        return data.globalRank != null;
      case "Alexa USA":
        return data.usaRank != null;
      case "Domain":
        return data.domain != null;
      case "Alexa India":
        return data.indiaRank != null;
      case "Backlinks":
        return data.backlinks != null;
      case "Referring Domain":
        return data.refer != null;
      default:
        return false;
    }
  }).toList();

  showDialog(
    context: context,
    builder: (BuildContext context) {
      return AlertDialog(
        title: Text('$memberName Details'),
        content: Container(
          width: double.maxFinite,
          height: 400, // Adjust the height as needed
          child: filteredData.isNotEmpty
              ? ListView.builder(
                  itemCount: filteredData.length,
                  itemBuilder: (context, index) {
                    final data = filteredData[index];
                    return Padding(
                      padding: const EdgeInsets.symmetric(vertical: 4.0),
                      child: Column(
                        crossAxisAlignment: CrossAxisAlignment.start,
                        children: [
                          Text('Project Name: ${data.projectName ?? 'N/A'}', style: TextStyle(fontSize: 14)),
                          Text('Domain Authority: ${data.domain ?? 'N/A'}', style: TextStyle(fontSize: 14)),
                          Text('Alexa Global: ${data.globalRank ?? 'N/A'}', style: TextStyle(fontSize: 14)),
                          Text('Alexa USA: ${data.usaRank ?? 'N/A'}', style: TextStyle(fontSize: 14)),
                          Text('Alexa India: ${data.indiaRank ?? 'N/A'}', style: TextStyle(fontSize: 14)),
                          Text('Backlinks: ${data.backlinks ?? 'N/A'}', style: TextStyle(fontSize: 14)),
                          Text('Referring Domains: ${data.refer ?? 'N/A'}', style: TextStyle(fontSize: 14)),
                          Divider(),
                        ],
                      ),
                    );
                  },
                )
              : Center(child: Text('No data available for $memberName.')),
        ),
        actions: [
          TextButton(
            onPressed: () {
              Navigator.of(context).pop(); // Close the dialog
            },
            child: Text('Close'),
          ),
        ],
      );
    },
  );
}
Enter fullscreen mode Exit fullscreen mode

Full Code Implementation:
Here is the complete code, integrating the list of dynamic buttons with labels and colors:

// List of dynamic buttons with labels and colors
final List<Map<String, dynamic>> buttons = [
  {'label': 'Alexa Global', 'color': Colors.red},
  {'label': 'Alexa USA', 'color': Colors.purple},
  {'label': 'Domain', 'color': Colors.teal},
  {'label': 'Alexa India', 'color': Colors.blue},
  {'label': 'Backlinks', 'color': Colors.orange},
  {'label': 'Referring Domain', 'color': Colors.green},
];

// Building Dynamic Buttons
Widget _buildDynamicButtons() {
  _populateMemberDataMap(); // Ensure the map is populated before displaying buttons

  return SingleChildScrollView(
    scrollDirection: Axis.horizontal,
    child: Row(
      children: buttons.map((button) {
        return GestureDetector(
          onTap: () {
            _showDetailsDialog(button['label']); // Use the label to show details
          },
          child: Container(
            padding: EdgeInsets.symmetric(horizontal: 12, vertical: 6),
            margin: EdgeInsets.only(right: 8), // Spacing between buttons
            decoration: BoxDecoration(
              color: button['color'], // Set the button color dynamically
              borderRadius: BorderRadius.circular(20),
            ),
            child: Text(
              button['label'], // Display the button label
              style: TextStyle(color: Colors.white),
            ),
          ),
        );
      }).toList(),
    ),
  );
}

// Populating Member Data Map
void _populateMemberDataMap() {
  memberDataMap.clear();
  for (var member in teamMembers) {
    memberDataMap[member] = _filteredWebData.where((data) {
      return data.projectName != null && data.projectName!.contains(member);
    }).toList();
  }
}

// Showing Details Dialog
void _showDetailsDialog(String memberName) {
  List<WebRatings> filteredData = _filteredWebData.where((data) {
    switch (memberName) {
      case "Alexa Global":
        return data.globalRank != null;
      case "Alexa USA":
        return data.usaRank != null;
      case "Domain":
        return data.domain != null;
      case "Alexa India":
        return data.indiaRank != null;
      case "Backlinks":
        return data.backlinks != null;
      case "Referring Domain":
        return data.refer != null;
      default:
        return false;
    }
  }).toList();

  showDialog(
    context: context,
    builder: (BuildContext context) {
      return AlertDialog(
        title: Text('$memberName Details'),
        content: Container(
          width: double.maxFinite,
          height: 400,
          child: filteredData.isNotEmpty
              ? ListView.builder(
                  itemCount: filteredData.length,
                  itemBuilder: (context, index) {
                    final data = filteredData[index];
                    return Padding(
                      padding: const EdgeInsets.symmetric(vertical: 4.0),
                      child: Column(
                        crossAxisAlignment: CrossAxisAlignment.start,
                        children: [
                          Text('Project Name: ${data.projectName ?? 'N/A'}', style: TextStyle(fontSize: 14)),
                          Text('Domain Authority: ${data.domain ?? 'N/A'}', style: TextStyle(fontSize: 14)),
                          Text('Alexa Global: ${data.globalRank ?? 'N/A'}', style: TextStyle(fontSize: 14)),
                          Text('Alexa USA: ${data.usaRank ?? 'N/A'}', style: TextStyle(fontSize: 14)),
                          Text('Alexa India: ${data.indiaRank ?? 'N/A'}', style: TextStyle(fontSize: 14)),
                          Text('Backlinks: ${data.backlinks ?? 'N/A'}', style: TextStyle(fontSize: 14)),
                          Text('Referring Domains: ${data.refer ?? 'N/A'}', style: TextStyle(fontSize: 14)),
                          Divider(),
                        ],
                      ),
                    );
                  },
                )
              : Center(child: Text('No data available for $memberName.')),
        ),
        actions: [
          TextButton(
            onPressed: () {
              Navigator.of(context).pop(); // Close the dialog
            },
            child: Text('Close'),
          ),
        ],
      );
    },
  );
}
Enter fullscreen mode Exit fullscreen mode

This approach allows you to create dynamic buttons with different labels and colors, while the logic for showing filtered data remains intact.

Top comments (0)