diff --git a/lib/programs screen/girl_script.dart b/lib/programs screen/girl_script.dart index b27d766..4dcef93 100644 --- a/lib/programs screen/girl_script.dart +++ b/lib/programs screen/girl_script.dart @@ -1,70 +1,112 @@ import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; +import 'package:multi_select_flutter/dialog/multi_select_dialog_field.dart'; +import 'package:multi_select_flutter/util/multi_select_item.dart'; import 'package:opso/modals/book_mark_model.dart'; import 'package:opso/modals/gssoc_project_modal.dart'; - -import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:opso/widgets/gssoc_project_widget.dart'; import 'package:opso/widgets/year_button.dart'; - import '../widgets/SearchandFilterWidget.dart'; + class GSSOCScreen extends StatefulWidget { const GSSOCScreen({super.key}); + @override State createState() => _GSSOCScreenState(); } + class _GSSOCScreenState extends State { - String currectPage = "/girl_script_summer_of_code"; + String currentPage = "/girl_script_summer_of_code"; String currentProject = "Girl Script Summer of Code"; List gssoc2024 = []; List gssoc2023 = []; - bool isBookmarked = true; List gssoc2022 = []; List gssoc2021 = []; + List allOrganizations = []; + List allLanguages = []; + List selectedOrganizations = ['All']; + List selectedLanguages = ['All']; int selectedYear = 2024; - String selectedOrg = "All"; + bool isBookmarked = true; List projectList = []; Future? getProjectFunction; + Future initializeProjectLists() async { - String response = - await rootBundle.loadString('assets/projects/gssoc/gssoc2024.json'); - var jsonList = await json.decode(response); - for (var data in jsonList) { - gssoc2024.add(GssocProjectModal.getDataFromJson(data)); - } - projectList = List.from(gssoc2024); - response = - await rootBundle.loadString('assets/projects/gssoc/gssoc2023.json'); - jsonList = await json.decode(response); - for (var data in jsonList) { - gssoc2023.add(GssocProjectModal.getDataFromJson(data)); - } - response = - await rootBundle.loadString('assets/projects/gssoc/gssoc2022.json'); - jsonList = await json.decode(response); - for (var data in jsonList) { - gssoc2022.add(GssocProjectModal.getDataFromJson(data)); - } - response = - await rootBundle.loadString('assets/projects/gssoc/gssoc2021.json'); - jsonList = await json.decode(response); - for (var data in jsonList) { - gssoc2021.add(GssocProjectModal.getDataFromJson(data)); - } + await _loadProjects('assets/projects/gssoc/gssoc2024.json', gssoc2024); + await _loadProjects('assets/projects/gssoc/gssoc2023.json', gssoc2023); + await _loadProjects('assets/projects/gssoc/gssoc2022.json', gssoc2022); + await _loadProjects('assets/projects/gssoc/gssoc2021.json', gssoc2021); + + + // Populate all unique organizations and languages + allOrganizations = _extractUniqueValues((project) => project.hostedBy); + allLanguages = languages; + projectList = List.from(gssoc2024); // Default year + } + + + List languages = [ + 'All', + 'Js', + 'Python', + 'React', + 'Angular', + 'Bootstrap', + 'Firebase', + 'Node', + 'MongoDb', + 'Express', + 'Next', + 'CSS', + 'HTML', + 'JavaScript', + 'Flutter', + 'Dart' + ]; + + + Future _loadProjects(String path, List list) async { + String response = await rootBundle.loadString(path); + var jsonList = json.decode(response) as List; + list.addAll(jsonList.map((data) => GssocProjectModal.getDataFromJson(data)).toList()); + } + + + List _extractUniqueValues(String Function(GssocProjectModal) extractor) { + return { + 'All', + ...gssoc2024.map(extractor), + ...gssoc2023.map(extractor), + ...gssoc2022.map(extractor), + ...gssoc2021.map(extractor), + }.toList(); + } + + + List _extractUniqueLanguages(List Function(GssocProjectModal) extractor) { + final allLanguages = [ + for (var project in gssoc2024) ...extractor(project), + for (var project in gssoc2023) ...extractor(project), + for (var project in gssoc2022) ...extractor(project), + for (var project in gssoc2021) ...extractor(project), + ]; + return ['All', ...allLanguages.toSet()]; } + @override void initState() { - getProjectFunction = initializeProjectLists(); super.initState(); + getProjectFunction = initializeProjectLists(); _checkBookmarkStatus(); } + Future _checkBookmarkStatus() async { bool bookmarkStatus = await HandleBookmark.isBookmarked(currentProject); setState(() { @@ -72,350 +114,279 @@ class _GSSOCScreenState extends State { }); } - void searchTag(String searchTag) { - projectList = projectList - .where((element) => element.techstack.contains(searchTag)) - .toList(); + + void filterProjects() { + // Filter projects by year first + projectList = _getProjectsByYear(); + + + // Filter projects by selected languages + if (!selectedLanguages.contains('All')) { + projectList = projectList.where((project) => + selectedLanguages.every((language) => project.techstack.contains(language)) + ).toList(); + } + + + // Update the list of organizations based on the filtered projects by language + _updateOrganizationList(); + + + // Filter projects by selected organizations + if (!selectedOrganizations.contains('All')) { + projectList = projectList.where((project) => selectedOrganizations.contains(project.hostedBy)).toList(); + } + + + // Ensure state is updated to reflect changes setState(() {}); } - void search(String searchText) { - if (searchText.isEmpty) { - switch (selectedYear) { - case 2021: - projectList = gssoc2021; - break; - case 2022: - projectList = gssoc2022; - break; - case 2023: - projectList = gssoc2023; - break; - case 2024: - projectList = gssoc2024; - break; - } - setState(() {}); - return; - } - projectList = projectList - .where( - (element) => - element.name.toLowerCase().contains(searchText.toLowerCase()) || - element.techstack.contains(searchText) || - element.hostedBy.toLowerCase().contains(searchText.toLowerCase()), - ) + + + + void _updateOrganizationList() { + allOrganizations = _extractUniqueValues((project) => project.hostedBy) + .where((organization) => projectList.any((project) => project.hostedBy == organization)) .toList(); - setState(() {}); + allOrganizations.insert(0, 'All'); } + + List _getProjectsByYear() { + switch (selectedYear) { + case 2021: + return gssoc2021; + case 2022: + return gssoc2022; + case 2023: + return gssoc2023; + case 2024: + return gssoc2024; + default: + return []; + } + } + + Future _refresh() async { + await initializeProjectLists(); setState(() { - initializeProjectLists(); selectedYear = 2024; + selectedOrganizations = ['All']; + selectedLanguages = ['All']; }); } + @override Widget build(BuildContext context) { - ScreenUtil.init(context); - // var height = MediaQuery.sizeOf(context).height; - // var width = MediaQuery.sizeOf(context).width; - List languages = [ - 'All', - 'Js', - 'Python', - 'React', - 'Angular', - 'Bootstrap', - 'Firebase', - 'Node', - 'MongoDb', - 'Express', - 'Next', - 'CSS', - 'HTML', - 'JavaScript', - 'Flutter', - 'Dart' - ]; + var height = MediaQuery.of(context).size.height; + var width = MediaQuery.of(context).size.width; + + return RefreshIndicator( - onRefresh: _refresh, - child: Scaffold( - appBar: AppBar(title: const Text('GSSoC'), actions: [ - IconButton( - icon: (isBookmarked) - ? const Icon(Icons.bookmark_add_rounded) - : const Icon(Icons.bookmark_add_outlined), - onPressed: () { - setState(() { - isBookmarked = !isBookmarked; - }); - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text( - isBookmarked ? 'Bookmark added' : 'Bookmark removed'), - duration: const Duration( - seconds: 2), // Adjust the duration as needed + onRefresh: _refresh, + child: Scaffold( + appBar: AppBar(title: const Text('GSSoC'), actions: [ + IconButton( + icon: (isBookmarked) + ? const Icon(Icons.bookmark_add_rounded) + : const Icon(Icons.bookmark_add_outlined), + onPressed: () { + setState(() { + isBookmarked = !isBookmarked; + }); + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text(isBookmarked ? 'Bookmark added' : 'Bookmark removed'), + duration: const Duration(seconds: 2), + ), + ); + if (isBookmarked) { + HandleBookmark.addBookmark(currentProject, currentPage); + } else { + HandleBookmark.deleteBookmark(currentProject); + } + }, + ) + ]), + body: FutureBuilder( + future: getProjectFunction, + builder: (context, snapshot) { + if (snapshot.connectionState == ConnectionState.waiting) { + return const Center(child: CircularProgressIndicator()); + } else if (snapshot.connectionState == ConnectionState.done) { + return SingleChildScrollView( + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 48, vertical: 8), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + _buildSearchBar(), + const SizedBox(height: 20), + _buildYearButtons(), + const SizedBox(height: 20), + _buildMultiSelectField( + items: allLanguages, + selectedValues: selectedLanguages, + title: "Select Languages", + buttonText: "Filter by Language", + onConfirm: (results) { + setState(() { + selectedLanguages = results.isNotEmpty ? results : ['All']; + print(selectedLanguages); + filterProjects(); + }); + }, + ), + const SizedBox(height: 20), + const SizedBox(height: 20), + _buildProjectList(height, width), + ], ), - ); - if (isBookmarked) { - print("Adding"); - HandleBookmark.addBookmark(currentProject, currectPage); - } else { - print("Deleting"); - HandleBookmark.deleteBookmark(currentProject); - } - }, - ) - ]), - body: FutureBuilder( - future: getProjectFunction, - builder: (context, snapshot) { - if (snapshot.connectionState == ConnectionState.waiting) { - return const Center(child: CircularProgressIndicator()); - } else if (snapshot.connectionState == ConnectionState.done) { - return (ScreenUtil().orientation == Orientation.portrait) - ? Padding( - padding: EdgeInsets.symmetric( - horizontal: ScreenUtil().setWidth(46), - vertical: ScreenUtil().setHeight(16)), - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - searchbar(), - const SizedBox(height: 20), - yearFilterWidget(), - // const SizedBox(height: 20), - // SizedBox( - // height: 50, - // child: ElevatedButton( - // onPressed: () {}, - // style: ElevatedButton.styleFrom( - // shape: const RoundedRectangleBorder( - // borderRadius: BorderRadius.zero, - // ), - // backgroundColor: const Color.fromARGB( - // 255, 253, 214, 115), // Set button color - // padding: const EdgeInsets.symmetric( - // vertical: 10.0, horizontal: 20.0), - // ), - // child: const Text( - // 'View Projects', - // style: TextStyle(color: Colors.white, fontSize: 18), - // ), - // ), - // ), - SizedBox( - height: ScreenUtil().setHeight(20), - ), - - languageFilterWidget(languages), - - projectsListView(), - ], - ), - ) - : Padding( - padding: const EdgeInsets.symmetric( - vertical: 8.0, - horizontal: 16.0, - ), - child: Row( - children: [ - Expanded( - child: SingleChildScrollView( - child: Column( - mainAxisAlignment: - MainAxisAlignment.spaceBetween, - children: [ - SizedBox( - width: ScreenUtil().screenWidth * 0.4, - child: searchbar(), - ), - const SizedBox(height: 20), - yearFilterWidget(), - languageFilterWidget(languages), - ], - ), - ), - ), - const SizedBox(width: 20), - projectsListView(), - ], - ), - ); - } else { - return const Center(child: Text("Some error occured")); - } - }), - )); + ), + ); + } else { + return const Center(child: Text("Some error occurred")); + } + }, + ), + ), + ); } - Row languageFilterWidget(List languages) { - return Row( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - Text( - 'Filter by Language:', - style: TextStyle( - fontWeight: FontWeight.w400, - fontSize: ScreenUtil().setSp( - (ScreenUtil().orientation == Orientation.portrait) ? 14 : 8)), + + Widget _buildSearchBar() { + return TextFormField( + decoration: InputDecoration( + filled: true, + hintText: 'Search', + suffixIcon: const Icon(Icons.search), + enabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(10), + borderSide: const BorderSide(color: Color(0xFFEEEEEE)), ), - Padding( - padding: EdgeInsets.all(ScreenUtil().setHeight(8)), - child: DropdownWidget( - items: languages, - hintText: 'Language', - onChanged: (newValue) { - setState(() { - switch (selectedYear) { - case 2021: - projectList = gssoc2021; - break; - case 2022: - projectList = gssoc2022; - break; - case 2023: - projectList = gssoc2023; - break; - case 2024: - projectList = gssoc2024; - break; - } - searchTag(newValue); - }); - // Perform filtering based on selectedLanguage - }, - ), - ) - ], + focusedBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(10), + borderSide: const BorderSide(color: Color(0xFFEEEEEE)), + ), + disabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(10), + borderSide: const BorderSide(color: Color(0xFFEEEEEE)), + ), + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(10), + borderSide: const BorderSide(color: Color(0xFFEEEEEE)), + ), + contentPadding: const EdgeInsets.symmetric(vertical: 12.0, horizontal: 20.0), + ), + onFieldSubmitted: (value) { + setState(() { + projectList = _getProjectsByYear() + .where((project) => project.name.toLowerCase().contains(value.toLowerCase())) + .toList(); + }); + }, + onChanged: (value) { + if (value.isEmpty) { + setState(() { + projectList = _getProjectsByYear(); + }); + } + }, ); } - SizedBox yearFilterWidget() { + + Widget _buildYearButtons() { return SizedBox( - height: ScreenUtil().screenHeight * - ((ScreenUtil().orientation == Orientation.portrait) ? 0.2 : 0.4), - width: ScreenUtil().screenWidth * 0.4, + height: MediaQuery.sizeOf(context).height * 0.2, child: GridView( physics: const NeverScrollableScrollPhysics(), gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: 2, childAspectRatio: 1.5 / 0.6, + crossAxisCount: 2, crossAxisSpacing: 15, mainAxisSpacing: 15, ), children: [ YearButton( year: "2021", - isEnabled: selectedYear == 2021 ? true : false, + isEnabled: selectedYear == 2021, onTap: () { setState(() { - projectList = gssoc2021; selectedYear = 2021; + filterProjects(); }); }, - backgroundColor: selectedYear == 2021 - ? Colors.white - : const Color.fromRGBO(255, 183, 77, 1), + backgroundColor: selectedYear == 2021 ? Colors.white : const Color.fromRGBO(255, 183, 77, 1), ), YearButton( year: "2022", - isEnabled: selectedYear == 2022 ? true : false, + isEnabled: selectedYear == 2022, onTap: () { setState(() { - projectList = gssoc2022; selectedYear = 2022; + filterProjects(); }); }, - backgroundColor: selectedYear == 2022 - ? Colors.white - : const Color.fromRGBO(255, 183, 77, 1), + backgroundColor: selectedYear == 2022 ? Colors.white : const Color.fromRGBO(255, 183, 77, 1), ), YearButton( year: "2023", - isEnabled: selectedYear == 2023 ? true : false, + isEnabled: selectedYear == 2023, onTap: () { setState(() { - projectList = gssoc2023; selectedYear = 2023; + filterProjects(); }); }, - backgroundColor: selectedYear == 2023 - ? Colors.white - : const Color.fromRGBO(255, 183, 77, 1), + backgroundColor: selectedYear == 2023 ? Colors.white : const Color.fromRGBO(255, 183, 77, 1), ), YearButton( - isEnabled: selectedYear == 2024 ? true : false, year: "2024", + isEnabled: selectedYear == 2024, onTap: () { setState(() { - projectList = gssoc2024; selectedYear = 2024; + filterProjects(); }); }, - backgroundColor: selectedYear == 2024 - ? Colors.white - : const Color.fromRGBO(255, 183, 77, 1), + backgroundColor: selectedYear == 2024 ? Colors.white : const Color.fromRGBO(255, 183, 77, 1), ), ], ), ); } - TextFormField searchbar() { - return TextFormField( - decoration: InputDecoration( - filled: true, - // fillColor: const Color(0xFFEEEEEE), - hintText: 'Search', - suffixIcon: const Icon(Icons.search), - enabledBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(10), - borderSide: const BorderSide( - color: Color(0xFFEEEEEE), - ), - ), - focusedBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(10), - borderSide: const BorderSide( - color: Color(0xFFEEEEEE), - ), - ), - disabledBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(10), - borderSide: const BorderSide( - color: Color(0xFFEEEEEE), - ), - ), - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(10), - borderSide: const BorderSide( - color: Color(0xFFEEEEEE), - ), - ), - contentPadding: EdgeInsets.symmetric( - vertical: ScreenUtil().setHeight(12), - horizontal: ScreenUtil().setWidth(20)), + + Widget _buildMultiSelectField({ + required List items, + required List selectedValues, + required String title, + required String buttonText, + required void Function(List) onConfirm, + }) { + bool isDarkMode = Theme.of(context).brightness == Brightness.dark; + return MultiSelectDialogField( + backgroundColor: isDarkMode ? Colors.grey.shade100 : Colors.white, + items: items.map((e) => MultiSelectItem(e, e)).toList(), + initialValue: selectedValues, + title: Text(title,style: TextStyle(color: isDarkMode ? Colors.black : Colors.black)), + buttonText: Text(buttonText), + onConfirm: onConfirm, + decoration: BoxDecoration( + border: Border.all(color: Colors.grey), + borderRadius: BorderRadius.circular(10), ), - onFieldSubmitted: (value) { - print("value is $value"); - search(value.trim()); - }, - onChanged: (value) { - if (value.isEmpty) { - search(value); - } - }, ); } - Expanded projectsListView() { - return Expanded( - // width: width, + + Widget _buildProjectList(double height, double width) { + return Container( + height: height, // Set a specific height here child: ListView.builder( itemCount: projectList.length, itemBuilder: (BuildContext context, int index) { @@ -424,8 +395,8 @@ class _GSSOCScreenState extends State { child: GssocProjectWidget( index: index + 1, modal: projectList[index], - height: ScreenUtil().screenHeight * 0.2, - width: ScreenUtil().screenWidth, + height: height * 0.2, + width: width, ), ); }, @@ -433,3 +404,4 @@ class _GSSOCScreenState extends State { ); } } + diff --git a/lib/programs screen/google_season_of_docs_screen.dart b/lib/programs screen/google_season_of_docs_screen.dart index c8c7a5a..8c66f0a 100644 --- a/lib/programs screen/google_season_of_docs_screen.dart +++ b/lib/programs screen/google_season_of_docs_screen.dart @@ -1,8 +1,7 @@ import 'dart:convert'; - -import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; +import 'package:multi_select_flutter/multi_select_flutter.dart'; import 'package:opso/modals/book_mark_model.dart'; import 'package:opso/modals/gsod/gsod_modal_new.dart'; import 'package:opso/modals/gsod/gsod_modal_old.dart'; @@ -10,13 +9,21 @@ import 'package:opso/widgets/gsod/gsod_project_widget_new.dart'; import 'package:opso/widgets/gsod/gsod_project_widget_old.dart'; import 'package:opso/widgets/year_button.dart'; + + + class GoogleSeasonOfDocsScreen extends StatefulWidget { @override State createState() => _GoogleSeasonOfDocsScreenState(); } + + + class _GoogleSeasonOfDocsScreenState extends State { + List selectedOrganizations = []; + List selectedProposals = ['All']; String currentProgram = "Google Season of Docs"; bool isBookmarked = true; String currentPage = "/google_season_of_docs"; @@ -25,51 +32,70 @@ class _GoogleSeasonOfDocsScreenState extends State { List gsod2021 = []; List gsod2020 = []; List gsod2019 = []; - bool flag = true; int selectedYear = 2023; + + + List projectList = []; + List allProjectList =[]; Future? getProjectFunction; + + + Future initializeProjectLists() async { String response = - await rootBundle.loadString('assets/projects/gsod/gsod2023.json'); + await rootBundle.loadString('assets/projects/gsod/gsod2023.json'); var jsonList = await json.decode(response); for (var data in jsonList) { gsod2023.add(GsodModalNew.fromMap(data)); } - print(gsod2023.length); projectList = List.from(gsod2023); + allProjectList = List.from(gsod2023); + + response = - await rootBundle.loadString('assets/projects/gsod/gsod2022.json'); + await rootBundle.loadString('assets/projects/gsod/gsod2022.json'); jsonList = await json.decode(response); - for (var data in jsonList) { - print(data["organization_name"]); gsod2022.add(GsodModalNew.fromMap(data)); } + + + response = - await rootBundle.loadString('assets/projects/gsod/gsod2021.json'); + await rootBundle.loadString('assets/projects/gsod/gsod2021.json'); jsonList = await json.decode(response); - for (var data in jsonList) { gsod2021.add(GsodModalNew.fromMap(data)); } + + + + response = - await rootBundle.loadString('assets/projects/gsod/gsod2020.json'); + await rootBundle.loadString('assets/projects/gsod/gsod2020.json'); jsonList = await json.decode(response); for (var data in jsonList) { gsod2020.add(GsodModalOld.fromMap(data)); } + + + + response = - await rootBundle.loadString('assets/projects/gsod/gsod2019.json'); + await rootBundle.loadString('assets/projects/gsod/gsod2019.json'); jsonList = await json.decode(response); for (var data in jsonList) { gsod2019.add(GsodModalOld.fromMap(data)); } } + + + @override void initState() { getProjectFunction = initializeProjectLists(); @@ -77,6 +103,9 @@ class _GoogleSeasonOfDocsScreenState extends State { super.initState(); } + + + Future _checkBookmarkStatus() async { bool bookmarkStatus = await HandleBookmark.isBookmarked(currentProgram); setState(() { @@ -84,95 +113,163 @@ class _GoogleSeasonOfDocsScreenState extends State { }); } + + + void search(String searchText) { if (searchText.isEmpty) { - switch (selectedYear) { - case 2021: - projectList = gsod2021; - break; - case 2022: - projectList = gsod2022; - break; - case 2023: - projectList = gsod2023; - break; - case 20202: - projectList = gsod2020; - break; - case 2019: - projectList = gsod2019; - break; - } - setState(() {}); + resetProjectsByLanguage(); return; } if (selectedYear > 2020) { projectList = projectList .where( (element) => - element.organizationName - .toLowerCase() - .contains(searchText.toLowerCase()) || - element.budget - .toLowerCase() - .contains(searchText.toLowerCase()) || - element.acceptedProjectProposal - .toLowerCase() - .contains(searchText.toLowerCase()) || - element.caseStudy - .toLowerCase() - .contains(searchText.toLowerCase()) || - element.docsPage - .toLowerCase() - .contains(searchText.toLowerCase()), - ) + element.organizationName + .toLowerCase() + .contains(searchText.toLowerCase()) || + element.budget + .toLowerCase() + .contains(searchText.toLowerCase()) || + element.acceptedProjectProposal + .toLowerCase() + .contains(searchText.toLowerCase()) || + element.caseStudy + .toLowerCase() + .contains(searchText.toLowerCase()) || + element.docsPage.toLowerCase().contains(searchText.toLowerCase()), + ) .toList(); } else { projectList = projectList .where( (element) => - element.organization - .toLowerCase() - .contains(searchText.toLowerCase()) || - element.technicalWriter - .toLowerCase() - .contains(searchText.toLowerCase()) || - element.mentor - .toLowerCase() - .contains(searchText.toLowerCase()) || - element.project - .toLowerCase() - .contains(searchText.toLowerCase()) || - element.originalProjectProposal - .toLowerCase() - .contains(searchText.toLowerCase()) || - element.report.toLowerCase().contains(searchText.toLowerCase()), - ) + element.organization.toLowerCase().contains(searchText.toLowerCase()) || + element.technicalWriter.toLowerCase().contains(searchText.toLowerCase()) || + element.mentor.toLowerCase().contains(searchText.toLowerCase()) || + element.project.toLowerCase().contains(searchText.toLowerCase()) || + element.originalProjectProposal.toLowerCase().contains(searchText.toLowerCase()) || + element.report.toLowerCase().contains(searchText.toLowerCase()), + ) .toList(); } - setState(() {}); + + + + setState(() { + _resetValueIfNotValid(); + }); } + + + Future _refresh() async { - // Fetch data for the next year based on the currently selected year setState(() { initializeProjectLists(); + selectedOrganizations = ['All']; + selectedProposals = ['All']; selectedYear = 2023; - if (selectedYear > 2023) - selectedYear = 2019; // Reset to the beginning if it exceeds 2023 + if (selectedYear > 2023) selectedYear = 2019; // Reset to the beginning if it exceeds 2023 + }); + } + + + + + void resetProjectsByLanguage() { + switch (selectedYear) { + case 2019: + projectList = gsod2019; + allProjectList = gsod2019; + break; + case 2020: + projectList = gsod2020; + allProjectList = gsod2020; + break; + case 2021: + projectList = gsod2021; + allProjectList = gsod2021; + break; + case 2022: + projectList = gsod2022; + allProjectList = gsod2022; + break; + case 2023: + projectList = gsod2023; + allProjectList = gsod2023; + break; + case 2024: + projectList = gsod2023; + allProjectList = gsod2023; + break; + } + filterProjects(); + } + + + + + void filterProjects() { + var filteredProjects = List.from(projectList); + print("!@# $selectedOrganizations"); + + + // Filter by organizations + if (!selectedOrganizations.contains('All')) { + filteredProjects = filteredProjects.where((project) { + return selectedOrganizations.every((org) => project.organizationName.contains(org)); + }).toList(); + } else { + filteredProjects = gsod2023; + } + + + // Filter by proposals + if (!selectedProposals.contains('All')) { + filteredProjects = filteredProjects.where((project) { + return selectedProposals.contains(project.acceptedProjectProposal); + }).toList(); + } + + + setState(() { + projectList = filteredProjects; + /*_resetValueIfNotValid();*/ }); } + + + + + + void _resetValueIfNotValid() { + // Reset selectedOrganizations if they are not valid + var validOrganizations = projectList.map((project) => project.organizationName).toSet(); + selectedOrganizations = selectedOrganizations.where((org) => validOrganizations.contains(org) || org == 'All').toList(); + /* if (selectedOrganizations.isEmpty) { + selectedOrganizations = ['All']; + }*/ + + + + + } + + + + @override Widget build(BuildContext context) { - // var height = MediaQuery.sizeOf(context).height; - // var width = MediaQuery.sizeOf(context).width; - ScreenUtil.init(context); + bool isDarkMode = Theme.of(context).brightness == Brightness.dark; + var height = MediaQuery.sizeOf(context).height; + var width = MediaQuery.sizeOf(context).width; return RefreshIndicator( onRefresh: _refresh, child: Scaffold( - appBar: AppBar(title: const Text('OpSo'), actions: [ + appBar: AppBar(title: const Text('GSoD'), actions: [ IconButton( icon: (isBookmarked) ? const Icon(Icons.bookmark_add_rounded) @@ -183,39 +280,34 @@ class _GoogleSeasonOfDocsScreenState extends State { }); ScaffoldMessenger.of(context).showSnackBar( SnackBar( - content: Text( - isBookmarked ? 'Bookmark added' : 'Bookmark removed'), - duration: const Duration( - seconds: 2), // Adjust the duration as needed + content: Text(isBookmarked ? 'Bookmark added' : 'Bookmark removed'), + duration: const Duration(seconds: 2), // Adjust the duration as needed ), ); if (isBookmarked) { - print("Adding"); HandleBookmark.addBookmark(currentProgram, currentPage); } else { - print("Deleting"); HandleBookmark.deleteBookmark(currentProgram); } }, ) ]), body: FutureBuilder( - future: getProjectFunction, - builder: (context, snapshot) { - if (snapshot.connectionState == ConnectionState.waiting) { - return const Center(child: CircularProgressIndicator()); - } else if (snapshot.connectionState == ConnectionState.done) { - return Padding( - padding: EdgeInsets.symmetric( - horizontal: ScreenUtil().setWidth(46), - vertical: ScreenUtil().setHeight(16)), + future: getProjectFunction, + builder: (context, snapshot) { + if (snapshot.connectionState == ConnectionState.waiting) { + return const Center(child: CircularProgressIndicator()); + } else if (snapshot.connectionState == ConnectionState.done) { + return SingleChildScrollView( + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 46, vertical: 16), child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, + mainAxisSize: MainAxisSize.min, children: [ TextFormField( decoration: InputDecoration( filled: true, - // fillColor: const Color(0xFFEEEEEE), hintText: 'Search', suffixIcon: const Icon(Icons.search), enabledBorder: OutlineInputBorder( @@ -242,12 +334,10 @@ class _GoogleSeasonOfDocsScreenState extends State { color: Color(0xFFEEEEEE), ), ), - contentPadding: EdgeInsets.symmetric( - vertical: ScreenUtil().setHeight(12), - horizontal: ScreenUtil().setWidth(40)), + contentPadding: const EdgeInsets.symmetric( + vertical: 12.0, horizontal: 20.0), ), onFieldSubmitted: (value) { - print("value is $value"); search(value.trim()); }, onChanged: (value) { @@ -256,16 +346,15 @@ class _GoogleSeasonOfDocsScreenState extends State { } }, ), - SizedBox(height: ScreenUtil().setHeight(20)), + const SizedBox(height: 20), Container( constraints: BoxConstraints( - maxHeight: ScreenUtil().screenHeight * 0.3, + maxHeight: height * 0.3, ), - width: ScreenUtil().screenWidth, + width: width, child: GridView( physics: const NeverScrollableScrollPhysics(), - gridDelegate: - const SliverGridDelegateWithFixedCrossAxisCount( + gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 2, childAspectRatio: 1.5 / 0.6, crossAxisSpacing: 15, @@ -274,11 +363,12 @@ class _GoogleSeasonOfDocsScreenState extends State { children: [ YearButton( year: "2019", - isEnabled: selectedYear == 2019 ? true : false, + isEnabled: selectedYear == 2019, onTap: () { setState(() { projectList = gsod2019; selectedYear = 2019; + _resetValueIfNotValid(); }); }, backgroundColor: selectedYear == 2019 @@ -287,11 +377,12 @@ class _GoogleSeasonOfDocsScreenState extends State { ), YearButton( year: "2020", - isEnabled: selectedYear == 2020 ? true : false, + isEnabled: selectedYear == 2020, onTap: () { setState(() { projectList = gsod2020; selectedYear = 2020; + _resetValueIfNotValid(); }); }, backgroundColor: selectedYear == 2020 @@ -300,11 +391,12 @@ class _GoogleSeasonOfDocsScreenState extends State { ), YearButton( year: "2021", - isEnabled: selectedYear == 2021 ? true : false, + isEnabled: selectedYear == 2021, onTap: () { setState(() { projectList = gsod2021; selectedYear = 2021; + _resetValueIfNotValid(); }); }, backgroundColor: selectedYear == 2021 @@ -313,11 +405,12 @@ class _GoogleSeasonOfDocsScreenState extends State { ), YearButton( year: "2022", - isEnabled: selectedYear == 2022 ? true : false, + isEnabled: selectedYear == 2022, onTap: () { setState(() { projectList = gsod2022; selectedYear = 2022; + _resetValueIfNotValid(); }); }, backgroundColor: selectedYear == 2022 @@ -326,11 +419,12 @@ class _GoogleSeasonOfDocsScreenState extends State { ), YearButton( year: "2023", - isEnabled: selectedYear == 2023 ? true : false, + isEnabled: selectedYear == 2023, onTap: () { setState(() { projectList = gsod2023; selectedYear = 2023; + _resetValueIfNotValid(); }); }, backgroundColor: selectedYear == 2023 @@ -340,62 +434,110 @@ class _GoogleSeasonOfDocsScreenState extends State { ], ), ), - // const SizedBox(height: 20), - // SizedBox( - // height: 50, - // child: ElevatedButton( - // onPressed: () {}, - // style: ElevatedButton.styleFrom( - // shape: const RoundedRectangleBorder( - // borderRadius: BorderRadius.zero, - // ), - // backgroundColor: const Color.fromARGB( - // 255, 253, 214, 115), // Set button color - // padding: const EdgeInsets.symmetric( - // vertical: 10.0, horizontal: 20.0), - // ), - // child: const Text( - // 'View Projects', - // style: TextStyle(color: Colors.white, fontSize: 18), - // ), - // ), - // ), - const SizedBox( - height: 20, + const SizedBox(height: 20), + _buildMultiSelectField( + items: [ + 'All', + ...projectList + .map((project) => project.organizationName) + .toSet(), + ], + selectedValues: selectedOrganizations, + title: "Select Organizations", + buttonText: "Filter by Organization", + onConfirm: (results) { + setState(() { + selectedOrganizations = results.isNotEmpty ? results : ['All']; + print("this is selected organization $selectedOrganizations"); + filterProjects(); + }); + }, ), - Expanded( - // width: width, - child: ListView.builder( - itemCount: projectList.length, - itemBuilder: (BuildContext context, int index) { - return Padding( - padding: const EdgeInsets.symmetric(vertical: 10), - child: selectedYear <= 2020 - ? GsodProjectWidgetOld( - index: index + 1, - modal: projectList[index], - height: ScreenUtil().screenHeight * 0.2, - width: ScreenUtil().screenWidth, - ) - : GsodProjectWidgetNew( - index: index + 1, - modal: projectList[index], - height: ScreenUtil().screenHeight * 0.2, - width: ScreenUtil().screenWidth, - ), - ); - }, + + const SizedBox(height: 20), + const SizedBox(height: 20), + projectList.isNotEmpty + ? ListView.builder( + shrinkWrap: true, + physics: NeverScrollableScrollPhysics(), + itemCount: projectList.length, + itemBuilder: (BuildContext context, int index) { + return Padding( + padding: const EdgeInsets.symmetric(vertical: 10), + child: selectedYear <= 2020 + ? GsodProjectWidgetOld( + index: index + 1, + modal: projectList[index], + height: height * 0.2, + width: width, + ) + : GsodProjectWidgetNew( + index: index + 1, + modal: projectList[index], + height: height * 0.2, + width: width, + ), + ); + }, + ) + : Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text('No projects available.'), + SizedBox(height: 20), + ElevatedButton( + onPressed: () { + // Call the refresh function + _refresh(); + }, + child: Text('Refresh'), + ), + ], ), ), + + ], ), - ); - } else { - return const Center(child: Text("Some error occured")); - } - }), + ), + ); + } else { + return const Center(child: Text("Some error occurred")); + } + }, + ), ), ); } + Widget _buildMultiSelectField({ + required List items, + required List selectedValues, + required String title, + required String buttonText, + required void Function(List) onConfirm, + }) { + bool isDarkMode = Theme.of(context).brightness == Brightness.dark; + return MultiSelectDialogField( + backgroundColor: isDarkMode ? Colors.grey.shade100 : Colors.white, + items: items.map((e) => MultiSelectItem(e, e)).toList(), + initialValue: selectedValues, + title: Text( + title, + style: TextStyle(color: isDarkMode ? Colors.black : Colors.black), + ), + buttonText: Text(buttonText), + onConfirm: onConfirm, + decoration: BoxDecoration( + border: Border.all(color: Colors.grey), + borderRadius: BorderRadius.circular(10), + ), + ); + } + + } + + + diff --git a/lib/programs screen/google_summer_of_code_screen.dart b/lib/programs screen/google_summer_of_code_screen.dart index ff97c20..770fc11 100644 --- a/lib/programs screen/google_summer_of_code_screen.dart +++ b/lib/programs screen/google_summer_of_code_screen.dart @@ -2,34 +2,36 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:opso/widgets/gsoc/GsocProjectWidget.dart'; import 'package:url_launcher/url_launcher.dart'; +import 'package:multi_select_flutter/multi_select_flutter.dart'; import '../modals/GSoC/Gsoc.dart'; -import 'package:flutter_screenutil/flutter_screenutil.dart'; - -import '../modals/book_mark_model.dart'; import '../services/ApiService.dart'; import '../widgets/SearchandFilterWidget.dart'; import '../widgets/year_button.dart'; + + + class GoogleSummerOfCodeScreen extends StatefulWidget { @override State createState() => _GoogleSummerOfCodeScreenState(); } + + + class _GoogleSummerOfCodeScreenState extends State { + bool _isRefreshing = false; + String selectedOrg = ''; // Ensure this is defined List gsoc2024 = []; List gsoc2023 = []; List gsoc2022 = []; List gsoc2021 = []; - String currectPage = "/google_summer_of_code"; - String currentProject = "Google Summer of Code"; - bool isBookmarked = true; int selectedYear = 2024; - List languages = [ 'js', 'python', - 'React', + 'django', 'Angular', 'Bootstrap', 'Firebase', @@ -39,27 +41,28 @@ class _GoogleSummerOfCodeScreenState extends State { 'Next', 'css', 'html', - 'javaScript', + 'javascript', 'flutter', 'Dart' ]; List orgList = []; + List selectedLanguages = []; + List allOrganizations = []; + List selectedOrganizations = []; late Future _dataFetchFuture; - final GlobalKey _listKey = GlobalKey(); + + + @override void initState() { super.initState(); + _refresh(); _dataFetchFuture = getProjectData(); - _checkBookmarkStatus(); } - Future _checkBookmarkStatus() async { - bool bookmarkStatus = await HandleBookmark.isBookmarked(currentProject); - setState(() { - isBookmarked = bookmarkStatus; - }); - } + + Future getProjectData() async { ApiService apiService = ApiService(); @@ -69,65 +72,72 @@ class _GoogleSummerOfCodeScreenState extends State { Gsoc orgData2023 = await apiService.getOrgByYear('2023'); Gsoc orgData2024 = await apiService.getOrgByYear('2024'); + + + setState(() { gsoc2021 = orgData2021.organizations ?? []; gsoc2022 = orgData2022.organizations ?? []; gsoc2023 = orgData2023.organizations ?? []; gsoc2024 = orgData2024.organizations ?? []; orgList = gsoc2024; // Default to the latest year + allOrganizations = [...orgList.map((org) => org.name!).toSet()]; }); - _populateAnimatedList(orgList); } catch (e) { print('Error: $e'); } } - void _clearAnimatedList() { - for (var i = orgList.length - 1; i >= 0; i--) { - _listKey.currentState?.removeItem( - i, - (context, animation) => SizedBox.shrink(), - duration: Duration.zero, - ); - } - } - void _populateAnimatedList(List organizations) { - for (var i = 0; i < organizations.length; i++) { - _listKey.currentState?.insertItem(i); + + + void filterProjects() { + orgList = _getOrganizationsByYear(selectedYear); + if(selectedLanguages.length>=2){ + selectedLanguages.removeAt(0); + } + if(selectedOrganizations.length>=2){ + selectedOrganizations.removeAt(0); + } + if (!selectedLanguages.contains('All')) { + orgList = orgList.where((project) => + selectedLanguages.every((language) => project.technologies?.contains(language) == true) + ).toList(); } - } - void searchTag(String searchTag) { - setState(() { - _clearAnimatedList(); - orgList = _getOrganizationsByYear(selectedYear) - .where((element) => - element.technologies?.contains(searchTag) == true || - element.topics?.contains(searchTag) == true) + + + + + + if (!selectedOrganizations.contains('All')) { + orgList = orgList + .where((project) => selectedOrganizations.contains(project.name)) .toList(); - _populateAnimatedList(orgList); - }); - } + } - void search(String searchText) { - setState(() { - _clearAnimatedList(); - if (searchText.isEmpty) { - orgList = _getOrganizationsByYear(selectedYear); - } else { - orgList = _getOrganizationsByYear(selectedYear) - .where((element) => - element.name - ?.toLowerCase() - .contains(searchText.toLowerCase()) == - true) - .toList(); - } - _populateAnimatedList(orgList); - }); + + + + // Update organization filter based on selected languages + allOrganizations = [ + ..._getOrganizationsByYear(selectedYear) + .where((org) => + selectedLanguages.contains('All') || + org.technologies?.any(selectedLanguages.contains) == true) + .map((org) => org.name!) + .toSet() + ]; + + + + + setState(() {}); } + + + List _getOrganizationsByYear(int year) { switch (year) { case 2021: @@ -143,52 +153,61 @@ class _GoogleSummerOfCodeScreenState extends State { } } + + + Future _refresh() async { setState(() { - _dataFetchFuture = getProjectData(); + _isRefreshing = true; + }); + await getProjectData(); + setState(() { selectedYear = 2024; + selectedLanguages = ['All']; + selectedOrganizations = ['All']; + filterProjects(); + _isRefreshing = false; + }); + } + + + + + // Add this method to the _GoogleSummerOfCodeScreenState class + void search(String searchText) { + setState(() { + selectedOrg = 'All'; // Reset selectedOrg to avoid mismatch + if (searchText.isEmpty) { + orgList = _getOrganizationsByYear(selectedYear); + } else { + orgList = _getOrganizationsByYear(selectedYear) + .where((element) => + element.name + ?.toLowerCase() + .contains(searchText.toLowerCase()) == + true) + .toList(); + } }); } + + + @override Widget build(BuildContext context) { - // var height = MediaQuery.of(context).size.height; - // var width = MediaQuery.of(context).size.width; + var height = MediaQuery.of(context).size.height; + var width = MediaQuery.of(context).size.width; + + - ScreenUtil.init( - context, - ); return RefreshIndicator( onRefresh: _refresh, child: Scaffold( - appBar: AppBar(title: const Text('Google Summer of Code'), actions: [ - IconButton( - icon: (isBookmarked) - ? const Icon(Icons.bookmark_add_rounded) - : const Icon(Icons.bookmark_add_outlined), - onPressed: () { - setState(() { - isBookmarked = !isBookmarked; - }); - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text( - isBookmarked ? 'Bookmark added' : 'Bookmark removed'), - duration: const Duration( - seconds: 2), // Adjust the duration as needed - ), - ); - if (isBookmarked) { - print("Adding"); - HandleBookmark.addBookmark(currentProject, currectPage); - } else { - print("Deleting"); - HandleBookmark.deleteBookmark(currentProject); - } - }, - ) - ]), + appBar: AppBar( + title: Text('Google Summer of Code'), + ), body: FutureBuilder( future: _dataFetchFuture, builder: (context, snapshot) { @@ -197,173 +216,210 @@ class _GoogleSummerOfCodeScreenState extends State { } else if (snapshot.hasError) { return Center(child: Text('Error: ${snapshot.error}')); } else { - return Padding( - padding: EdgeInsets.symmetric( - horizontal: ScreenUtil().setWidth(46), - vertical: ScreenUtil().setHeight(16)), - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - TextFormField( - decoration: InputDecoration( - filled: true, - hintText: 'Search', - suffixIcon: const Icon(Icons.search), - enabledBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(10), - borderSide: const BorderSide( - color: Color(0xFFEEEEEE), + return SingleChildScrollView( + child: Padding( + padding: + const EdgeInsets.symmetric(horizontal: 46, vertical: 16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + TextFormField( + decoration: InputDecoration( + filled: true, + hintText: 'Search', + suffixIcon: const Icon(Icons.search), + enabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(10), + borderSide: const BorderSide( + color: Color(0xFFEEEEEE), + ), ), - ), - focusedBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(10), - borderSide: const BorderSide( - color: Color(0xFFEEEEEE), + focusedBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(10), + borderSide: const BorderSide( + color: Color(0xFFEEEEEE), + ), ), - ), - disabledBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(10), - borderSide: const BorderSide( - color: Color(0xFFEEEEEE), + disabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(10), + borderSide: const BorderSide( + color: Color(0xFFEEEEEE), + ), ), - ), - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(10), - borderSide: const BorderSide( - color: Color(0xFFEEEEEE), + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(10), + borderSide: const BorderSide( + color: Color(0xFFEEEEEE), + ), ), + contentPadding: const EdgeInsets.symmetric( + vertical: 12.0, horizontal: 20.0), ), - contentPadding: EdgeInsets.symmetric( - vertical: ScreenUtil().setWidth(12), - horizontal: ScreenUtil().setHeight(20)), + onFieldSubmitted: (value) { + search(value.trim()); + }, + onChanged: (value) { + if (value.isEmpty) { + search(value); + } + }, ), - onFieldSubmitted: (value) { - search(value.trim()); - }, - onChanged: (value) { - if (value.isEmpty) { - search(value); - } - }, - ), - SizedBox(height: ScreenUtil().setHeight(20)), - SizedBox( - height: ScreenUtil().screenHeight * 0.2, - width: ScreenUtil().screenWidth, - child: GridView( - physics: const NeverScrollableScrollPhysics(), - gridDelegate: - const SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: 2, - childAspectRatio: 1.5 / 0.6, - crossAxisSpacing: 15, - mainAxisSpacing: 15, - ), - children: [ - YearButton( - year: "2021", - isEnabled: selectedYear == 2021, - onTap: () { - setState(() { - selectedYear = 2021; - _clearAnimatedList(); - orgList = gsoc2021; - }); - _populateAnimatedList(gsoc2021); - }, - backgroundColor: selectedYear == 2021 - ? Colors.white - : const Color.fromRGBO(255, 183, 77, 1), - ), - YearButton( - year: "2022", - isEnabled: selectedYear == 2022, - onTap: () { - setState(() { - selectedYear = 2022; - _clearAnimatedList(); - orgList = gsoc2022; - }); - _populateAnimatedList(gsoc2022); - }, - backgroundColor: selectedYear == 2022 - ? Colors.white - : const Color.fromRGBO(255, 183, 77, 1), + const SizedBox(height: 20), + SizedBox( + height: height * 0.2, + width: width, + child: GridView( + physics: const NeverScrollableScrollPhysics(), + gridDelegate: + const SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 2, + childAspectRatio: 1.5 / 0.6, + crossAxisSpacing: 15, + mainAxisSpacing: 15, ), - YearButton( - year: "2023", - isEnabled: selectedYear == 2023, - onTap: () { - setState(() { - selectedYear = 2023; - _clearAnimatedList(); - orgList = gsoc2023; - }); - _populateAnimatedList(gsoc2023); - }, - backgroundColor: selectedYear == 2023 - ? Colors.white - : const Color.fromRGBO(255, 183, 77, 1), + children: [ + YearButton( + year: "2021", + isEnabled: selectedYear == 2021, + onTap: () { + setState(() { + selectedYear = 2021; + selectedLanguages = []; + selectedOrganizations = []; + filterProjects(); + }); + }, + backgroundColor: selectedYear == 2021 + ? Colors.white + : const Color.fromRGBO(255, 183, 77, 1), + ), + YearButton( + year: "2022", + isEnabled: selectedYear == 2022, + onTap: () { + setState(() { + selectedYear = 2022; + selectedLanguages = []; + selectedOrganizations = []; + filterProjects(); + }); + }, + backgroundColor: selectedYear == 2022 + ? Colors.white + : const Color.fromRGBO(255, 183, 77, 1), + ), + YearButton( + year: "2023", + isEnabled: selectedYear == 2023, + onTap: () { + setState(() { + selectedYear = 2023; + selectedLanguages = []; + selectedOrganizations = []; + filterProjects(); + }); + }, + backgroundColor: selectedYear == 2023 + ? Colors.white + : const Color.fromRGBO(255, 183, 77, 1), + ), + YearButton( + isEnabled: selectedYear == 2024, + year: "2024", + onTap: () { + setState(() { + selectedYear = 2024; + selectedLanguages = []; + selectedOrganizations = []; + filterProjects(); + }); + }, + backgroundColor: selectedYear == 2024 + ? Colors.white + : const Color.fromRGBO(255, 183, 77, 1), + ), + ], + ), + ), + const SizedBox(height: 20), + _buildMultiSelectField( + items: languages, + selectedValues: selectedLanguages, + title: "Select Languages", + buttonText: "Filter by Language", + onConfirm: (results) { + setState(() { + selectedLanguages = + results.isNotEmpty ? results : []; + print(selectedLanguages); + filterProjects(); + }); + }, + ), + const SizedBox(height: 20), + orgList.isEmpty + ? _isRefreshing + ? Column( + children: const [ + Center( + child: Column( + children: [ + CircularProgressIndicator(), + SizedBox(height: 10), + Text('Refreshing...'), + ], + ) ), - YearButton( - isEnabled: selectedYear == 2024, - year: "2024", - onTap: () { - setState(() { - selectedYear = 2024; - _clearAnimatedList(); - orgList = gsoc2024; - }); - _populateAnimatedList(gsoc2024); + SizedBox(height: 20), + ], + ) + : Column( + children: [ + const Center(child: Text('No projects found')), + const SizedBox(height: 20), + TextButton( + onPressed: () { + _refresh(); }, - backgroundColor: selectedYear == 2024 - ? Colors.white - : const Color.fromRGBO(255, 183, 77, 1), + child: const Text('Refresh'), ), ], - ), - ), - Row( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - const Text( - 'Filter by Language:', - style: TextStyle(fontWeight: FontWeight.w400), - ), - Padding( - padding: EdgeInsets.all(ScreenUtil().setWidth(8)), - child: Row( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - DropdownWidget( - items: languages, - hintText: 'Language', - onChanged: (newValue) { - searchTag(newValue); - }, + ) + : Container( + height: height, + child: ListView.builder( + itemCount: orgList.length, + itemBuilder: (context, index) { + return Padding( + padding: const EdgeInsets.symmetric(vertical: 10), + child: Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(20), + boxShadow: [ + BoxShadow( + color: Colors.grey.withOpacity(0.5), + spreadRadius: 2, + blurRadius: 5, + offset: Offset(0, 3), // changes position of shadow + ), + ], + ), + child: GsocProjectWidget( + index: index + 1, + modal: orgList[index], + height: height * 0.2, + width: width, + ), ), - ], - ), - ) - ], - ), - Expanded( - child: AnimatedList( - key: _listKey, - initialItemCount: orgList.length, - itemBuilder: (context, index, animation) { - return _buildAnimatedItem( - context, - index, - animation, - ScreenUtil().screenHeight, - ScreenUtil().screenWidth); - }, + ); + }, + ), ), - ), - ], + + + ], + ), ), ); } @@ -373,44 +429,41 @@ class _GoogleSummerOfCodeScreenState extends State { ); } - Widget _buildAnimatedItem(BuildContext context, int index, - Animation animation, double height, double width) { - return SizeTransition( - sizeFactor: animation, - axis: Axis.vertical, - child: Padding( - padding: const EdgeInsets.symmetric(vertical: 10), - child: Container( - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(20), - boxShadow: [ - BoxShadow( - color: Colors.grey.withOpacity(0.5), - spreadRadius: 2, - blurRadius: 5, - offset: Offset(0, 3), // changes position of shadow - ), - ], - ), - child: Column( - children: [ - GsocProjectWidget( - index: index + 1, - modal: orgList[index], - height: height * 0.2, - width: width, - ), - ], - ), - ), + + + + Widget _buildMultiSelectField({ + required List items, + required List selectedValues, + required String title, + required String buttonText, + required void Function(List) onConfirm, + }) { + bool isDarkMode = Theme.of(context).brightness == Brightness.dark; + return MultiSelectDialogField( + backgroundColor: isDarkMode ? Colors.grey.shade100 : Colors.white, + items: items.map((e) => MultiSelectItem(e, e)).toList(), + initialValue: selectedValues, + title: Text(title, + style: TextStyle(color: isDarkMode ? Colors.black : Colors.black)), + buttonText: Text(buttonText), + onConfirm: onConfirm, + decoration: BoxDecoration( + border: Border.all(color: Colors.grey), + borderRadius: BorderRadius.circular(10), ), ); } } + + + void main() { runApp(MaterialApp( home: GoogleSummerOfCodeScreen(), )); } + + + diff --git a/pubspec.lock b/pubspec.lock index 65f4ec1..994a129 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -260,26 +260,26 @@ packages: dependency: transitive description: name: leak_tracker - sha256: "7f0df31977cb2c0b88585095d168e689669a2cc9b97c309665e3386f3e9d341a" + sha256: "78eb209deea09858f5269f5a5b02be4049535f568c07b275096836f01ea323fa" url: "https://pub.dev" source: hosted - version: "10.0.4" + version: "10.0.0" leak_tracker_flutter_testing: dependency: transitive description: name: leak_tracker_flutter_testing - sha256: "06e98f569d004c1315b991ded39924b21af84cf14cc94791b8aea337d25b57f8" + sha256: b46c5e37c19120a8a01918cfaf293547f47269f7cb4b0058f21531c2465d6ef0 url: "https://pub.dev" source: hosted - version: "3.0.3" + version: "2.0.1" leak_tracker_testing: dependency: transitive description: name: leak_tracker_testing - sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" + sha256: a597f72a664dbd293f3bfc51f9ba69816f84dcd403cdac7066cb3f6003f3ab47 url: "https://pub.dev" source: hosted - version: "3.0.1" + version: "2.0.1" lints: dependency: transitive description: @@ -308,10 +308,18 @@ packages: dependency: transitive description: name: meta - sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136" + sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04 + url: "https://pub.dev" + source: hosted + version: "1.11.0" + multi_select_flutter: + dependency: "direct main" + description: + name: multi_select_flutter + sha256: "503857b415d390d29159df8a9d92d83c6aac17aaf1c307fb7bcfc77d097d20ed" url: "https://pub.dev" source: hosted - version: "1.12.0" + version: "4.1.3" path: dependency: transitive description: @@ -481,10 +489,10 @@ packages: dependency: transitive description: name: test_api - sha256: "9955ae474176f7ac8ee4e989dadfb411a58c30415bcfb648fa04b2b8a03afa7f" + sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b" url: "https://pub.dev" source: hosted - version: "0.7.0" + version: "0.6.1" timeline_tile: dependency: "direct main" description: @@ -601,10 +609,10 @@ packages: dependency: transitive description: name: vm_service - sha256: "3923c89304b715fb1eb6423f017651664a03bf5f4b29983627c4da791f74a4ec" + sha256: b3d56ff4341b8f182b96aceb2fa20e3dcb336b9f867bc0eafc0de10f1048e957 url: "https://pub.dev" source: hosted - version: "14.2.1" + version: "13.0.0" web: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 3c0f1f4..f3c4496 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -42,7 +42,7 @@ dependencies: timeline_tile: ^2.0.0 flutter_svg: ^2.0.10+1 flutter_screenutil: ^5.9.1 - + multi_select_flutter: ^4.1.3 dev_dependencies: awesome_notifications: ^0.9.3+1 flutter_launcher_icons: ^0.13.1