diff --git a/.github/workflows/auto-merge.yml b/.github/workflows/auto-merge.yml index 3554b67aad..b2300d33f6 100644 --- a/.github/workflows/auto-merge.yml +++ b/.github/workflows/auto-merge.yml @@ -10,4 +10,4 @@ jobs: - uses: actions/checkout@v2 - uses: ahmadnassri/action-dependabot-auto-merge@v2 with: - github-token: ${{ secrets.GITHUB_TOKEN }} + github-token: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file diff --git a/.github/workflows/autoupdate.yaml b/.github/workflows/autoupdate.yml similarity index 87% rename from .github/workflows/autoupdate.yaml rename to .github/workflows/autoupdate.yml index 93e4b5952a..7db5e7a1e9 100644 --- a/.github/workflows/autoupdate.yaml +++ b/.github/workflows/autoupdate.yml @@ -14,4 +14,4 @@ jobs: steps: - uses: docker://chinthakagodawita/autoupdate-action:v1 env: - GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}' + GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}' \ No newline at end of file diff --git a/.github/workflows/pr_reminders.yml b/.github/workflows/pr_remiders.yml similarity index 88% rename from .github/workflows/pr_reminders.yml rename to .github/workflows/pr_remiders.yml index d9e08f3394..14de61c653 100644 --- a/.github/workflows/pr_reminders.yml +++ b/.github/workflows/pr_remiders.yml @@ -16,4 +16,4 @@ jobs: with: webhook-url: ${{ secrets.SLACK_PR_REMINDER_WEBHOOK_URL }} provider: 'slack' # Required (slack, rocket or msteams) - channel: '#project-blt-prs' # Optional, eg: #general + channel: '#project-blt-prs' # Optional, eg: #general \ No newline at end of file diff --git a/lib/src/models/company_model.dart b/lib/src/models/company_model.dart index 39fc20cafb..cef31a74ef 100644 --- a/lib/src/models/company_model.dart +++ b/lib/src/models/company_model.dart @@ -7,11 +7,14 @@ class Company { String? email; String? url; String? hexcolor; - final int openIssues; - final int closedIssues; + String? twitter; + String? facebook; + int? openIssues; + int? closedIssues; final DateTime lastModified; final String logoLink; final String topTester; + bool? isActive; Company( this.id, @@ -24,6 +27,9 @@ class Company { this.lastModified, this.logoLink, this.topTester, + this.twitter, + this.facebook, + this.isActive, ); Color? get valueColor { @@ -45,14 +51,21 @@ class Company { parsedJson["email"] ?? null, parsedJson["url"] ?? null, parsedJson["color"] ?? null, - parsedJson["open"], - parsedJson["closed"], + parsedJson["open"] ?? 0, + parsedJson["closed"] ?? 0, DateTime.parse(parsedJson["modified"]), parsedJson["logo"].toString(), - parsedJson["top"], + parsedJson["top"] ?? "", + parsedJson["twitter"], + parsedJson["facebook"], + parsedJson["isActive"], ); } + static List fromSnapshot(List json) { + return json.map((data) => Company.fromJson(data)).toList(); + } + void setMoreInfo( int id, String mail, diff --git a/lib/src/pages/auth/forgot.dart b/lib/src/pages/auth/forgot.dart index c2fc8cb9c4..773d5b74b1 100644 --- a/lib/src/pages/auth/forgot.dart +++ b/lib/src/pages/auth/forgot.dart @@ -1,5 +1,4 @@ import 'package:blt/src/pages/pages_import.dart'; -import 'package:flutter/material.dart'; /// Page for initiating the process for recovering /// a user's account password. diff --git a/lib/src/pages/auth/login.dart b/lib/src/pages/auth/login.dart index a4a67d2474..c1531c07b3 100644 --- a/lib/src/pages/auth/login.dart +++ b/lib/src/pages/auth/login.dart @@ -1,5 +1,4 @@ import 'package:blt/src/pages/pages_import.dart'; -import 'package:flutter/material.dart'; /// The login page for the app. class LoginPage extends StatefulWidget { diff --git a/lib/src/pages/auth/signup.dart b/lib/src/pages/auth/signup.dart index 3cd7cbf3ff..cbf180ab1c 100644 --- a/lib/src/pages/auth/signup.dart +++ b/lib/src/pages/auth/signup.dart @@ -1,5 +1,4 @@ import 'package:blt/src/pages/pages_import.dart'; -import 'package:flutter/material.dart'; /// The signup page for the app. class SignUpPage extends StatefulWidget { diff --git a/lib/src/pages/companies/company_details_and_issues.dart b/lib/src/pages/companies/company_details_and_issues.dart new file mode 100644 index 0000000000..020b0a98ba --- /dev/null +++ b/lib/src/pages/companies/company_details_and_issues.dart @@ -0,0 +1,461 @@ +import 'package:blt/src/pages/home/home_imports.dart'; + +class CompanyDetailWithIssues extends ConsumerStatefulWidget { + const CompanyDetailWithIssues({super.key, required this.company}); + final Company company; + + @override + CompanyDetailWithIssuesState createState() => CompanyDetailWithIssuesState(); +} + +// ScrollController _scrollController = new ScrollController(); + +class CompanyDetailWithIssuesState + extends ConsumerState + with TickerProviderStateMixin { + late AnimationController animationController; + late String paginatedUrl; + late Color companyColor; + late List openIssues, closedIssues; + bool loading = true; + + static const TextStyle optionStyle = + TextStyle(fontSize: 30, fontWeight: FontWeight.bold); + + @override + void initState() { + // paginatedUrl = IssueEndPoints.issues; + companyColor = Color(0xFFDC4654); + + animationController = + AnimationController(duration: new Duration(seconds: 2), vsync: this); + animationController.repeat(); + + // _scrollController.addListener(() async { + // if (_scrollController.position.pixels == + // _scrollController.position.maxScrollExtent) { + // loadMoreIssues(); + // } + // }); + getIssuesByStatus(); + super.initState(); + } + + void getIssuesByStatus() async { + setState(() { + loading = true; + }); + IssueData? response = + await IssueApiClient.getIssueByStatus("open", widget.company.url!); + openIssues = response!.issueList ?? []; + print(openIssues.length); + response = + await IssueApiClient.getIssueByStatus("closed", widget.company.url!); + closedIssues = response!.issueList ?? []; + print(closedIssues.length); + setState(() { + loading = false; + }); + } + + @override + void dispose() { + animationController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + final isDarkMode = Theme.of(context).brightness == Brightness.dark; + final Size size = MediaQuery.of(context).size; + final Company company = widget.company; + + return Scaffold( + backgroundColor: isDarkMode + ? Color.fromRGBO(34, 22, 23, 1) + : Theme.of(context).canvasColor, + appBar: AppBar( + backgroundColor: companyColor, + leading: IconButton( + icon: Icon( + Icons.arrow_back_ios_new_rounded, + color: Colors.white, + ), + onPressed: () { + Navigator.of(context).pop(); + }, + ), + title: Text( + company.companyName, + style: TextStyle( + color: Colors.white, + fontSize: 20, + ), + ), + ), + body: RefreshIndicator( + onRefresh: () async { + getIssuesByStatus(); + }, + child: SingleChildScrollView( + physics: const BouncingScrollPhysics(), + child: Padding( + padding: EdgeInsets.symmetric(horizontal: 20).copyWith(top: 12), + child: + Column(mainAxisAlignment: MainAxisAlignment.start, children: [ + ClipRRect( + borderRadius: BorderRadius.circular(12), + child: SizedBox( + // width: size.width * 0.89, + height: size.height * 0.17, + child: Image.network( + company.logoLink, + fit: BoxFit.contain, + ), + ), + ), + SizedBox(height: 8), + Text( + company.companyName, + style: GoogleFonts.ubuntu( + textStyle: TextStyle( + color: Color(0xFF737373), + fontSize: 18, + ), + ), + ), + SizedBox(height: 8), + if (company.email != "") ...[ + Text( + company.email!, + style: GoogleFonts.ubuntu( + textStyle: TextStyle( + color: Color(0xFF737373), + fontSize: 16, + ), + ), + ), + SizedBox(height: 8), + ], + Container( + width: double.infinity, + height: 50, + child: Builder(builder: (context) { + return TextButton( + child: Text( + "Subscribe", + style: GoogleFonts.ubuntu( + textStyle: TextStyle( + color: Colors.white, + fontSize: 20, + ), + ), + ), + style: ButtonStyle( + shape: WidgetStateProperty.all( + RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8.0), + ), + ), + backgroundColor: WidgetStateProperty.all( + isDarkMode + ? Color.fromRGBO(126, 33, 58, 1) + : Color(0xFFDC4654), + ), + ), + onPressed: () async {}, + ); + }), + ), + SizedBox(height: 10), + + // Open Issues list + Container( + padding: EdgeInsets.fromLTRB(0, 0, 0, 12), + color: Theme.of(context).canvasColor, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + "Open Issues", + style: GoogleFonts.ubuntu( + textStyle: TextStyle( + color: Color(0xFFDC4654), + fontSize: 16, + fontWeight: FontWeight.bold, + ), + ), + ), + IconButton( + icon: Icon( + Icons.arrow_forward_ios_rounded, + color: Color(0xFFDC4654), + ), + onPressed: () { + Navigator.pushNamed( + context, + RouteManager.openIssues, + arguments: company, + ); + }, + ), + ]), + Text( + "Check all the open issues from ${company.companyName}!", + style: GoogleFonts.aBeeZee( + textStyle: TextStyle( + color: Color(0xFF737373), + ), + ), + ), + if (!loading) + Container( + // height: 0.3 * size.height, + padding: const EdgeInsets.fromLTRB(0, 20, 0, 10), + child: InkWell( + onTap: () { + Navigator.pushNamed( + context, + RouteManager.closedIssues, + arguments: company, + ); + }, + child: ListView.builder( + padding: EdgeInsets.zero, + physics: NeverScrollableScrollPhysics(), + itemCount: + (openIssues.length < 3 ? openIssues.length : 3), + shrinkWrap: true, + itemBuilder: (context, index) { + return ListTile( + shape: RoundedRectangleBorder( + borderRadius: index == 0 + ? BorderRadius.only( + topLeft: Radius.circular(10), + topRight: Radius.circular(15), + ) + : index == 2 + ? BorderRadius.only( + bottomLeft: Radius.circular(10), + bottomRight: Radius.circular(10), + ) + : BorderRadius.only( + topLeft: Radius.circular(0), + ), + ), + tileColor: index == 2 + ? Color(0xFFC9AE5D).withOpacity(0.42) + : index == 1 + ? Color(0xFFADD8E6).withOpacity(0.42) + : index == 0 + ? Color(0xFFFFD700) + .withOpacity(0.42) + : Colors.white, + // leading: buildAvatar(leaderList[index].image), + title: Text( + openIssues[index].title, + style: GoogleFonts.ubuntu( + textStyle: TextStyle( + color: isDarkMode + ? Colors.white + : Color(0xFFDC4654), + ), + ), + maxLines: 6, + ), + subtitle: Text( + "${openIssues[index].created!.day}/${openIssues[index].created!.month}/${openIssues[index].created!.year}", + style: GoogleFonts.aBeeZee( + textStyle: TextStyle( + color: isDarkMode + ? Colors.grey[400] + : Color(0xFF737373), + fontSize: 12, + ), + ), + ), + trailing: Text( + "# " + (index + 1).toString(), + style: GoogleFonts.ubuntu( + textStyle: TextStyle( + color: isDarkMode + ? Colors.grey[400] + : Color(0xFF737373), + fontSize: 15, + fontWeight: FontWeight.bold, + ), + ), + ), + ); + }, + ), + ), + ), + if (loading) + Center( + child: CircularProgressIndicator( + valueColor: animationController.drive( + ColorTween( + begin: Colors.blueAccent, + end: Colors.red, + ), + ), + ), + ), + + SizedBox(height: 10), + // Closed Issues list + Container( + padding: EdgeInsets.fromLTRB(0, 0, 0, 12), + color: Theme.of(context).canvasColor, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + "Closed Issues", + style: GoogleFonts.ubuntu( + textStyle: TextStyle( + color: Color(0xFFDC4654), + fontSize: 16, + fontWeight: FontWeight.bold, + ), + ), + ), + IconButton( + icon: Icon( + Icons.arrow_forward_ios_rounded, + color: Color(0xFFDC4654), + ), + onPressed: () { + Navigator.pushNamed( + context, + RouteManager.closedIssues, + arguments: company, + ); + }, + ), + ]), + Text( + "Check all the closed issues from ${company.companyName}!", + style: GoogleFonts.aBeeZee( + textStyle: TextStyle( + color: Color(0xFF737373), + ), + ), + ), + if (!loading) + Container( + // height: 0.3 * size.height, + padding: const EdgeInsets.fromLTRB(0, 20, 0, 10), + child: InkWell( + onTap: () { + Navigator.pushNamed( + context, + RouteManager.monthlyLeaderboardPage, + ); + }, + child: ListView.builder( + padding: EdgeInsets.zero, + physics: NeverScrollableScrollPhysics(), + itemCount: (closedIssues.length < 3 + ? closedIssues.length + : 3), + shrinkWrap: true, + itemBuilder: (context, index) { + return ListTile( + shape: RoundedRectangleBorder( + borderRadius: index == 0 + ? BorderRadius.only( + topLeft: Radius.circular(10), + topRight: Radius.circular(15), + ) + : index == 2 + ? BorderRadius.only( + bottomLeft: + Radius.circular(10), + bottomRight: + Radius.circular(10), + ) + : BorderRadius.only( + topLeft: Radius.circular(0), + ), + ), + tileColor: index == 2 + ? Color(0xFFC9AE5D).withOpacity(0.42) + : index == 1 + ? Color(0xFFADD8E6) + .withOpacity(0.42) + : index == 0 + ? Color(0xFFFFD700) + .withOpacity(0.42) + : Colors.white, + // leading: buildAvatar(leaderList[index].image), + title: Text( + closedIssues[index].title, + style: GoogleFonts.ubuntu( + textStyle: TextStyle( + color: isDarkMode + ? Colors.white + : Color(0xFFDC4654), + ), + ), + maxLines: 6, + ), + subtitle: Text( + "${closedIssues[index].created!.day}/${closedIssues[index].created!.month}/${closedIssues[index].created!.year}", + style: GoogleFonts.aBeeZee( + textStyle: TextStyle( + color: isDarkMode + ? Colors.grey[400] + : Color(0xFF737373), + fontSize: 12, + ), + ), + ), + trailing: Text( + "# " + (index + 1).toString(), + style: GoogleFonts.ubuntu( + textStyle: TextStyle( + color: isDarkMode + ? Colors.grey[400] + : Color(0xFF737373), + fontSize: 15, + fontWeight: FontWeight.bold, + ), + ), + ), + ); + }, + ), + ), + ), + if (loading) + Center( + child: CircularProgressIndicator( + valueColor: animationController.drive( + ColorTween( + begin: Colors.blueAccent, + end: Colors.red, + ), + ), + ), + ), + ], + ), + ), + ], + ), + ), + ]), + ), + ), + ), + ); + } +} diff --git a/lib/src/pages/companies/company_list_page.dart b/lib/src/pages/companies/company_list_page.dart new file mode 100644 index 0000000000..beff10f97b --- /dev/null +++ b/lib/src/pages/companies/company_list_page.dart @@ -0,0 +1,238 @@ +import 'package:blt/src/pages/home/home_imports.dart'; + +class CompanyListPage extends ConsumerStatefulWidget { + const CompanyListPage({super.key}); + + @override + CompanyListPageState createState() => CompanyListPageState(); +} + +ScrollController _scrollController = new ScrollController(); + +class CompanyListPageState extends ConsumerState + with TickerProviderStateMixin { + late AnimationController animationController; + late String paginatedUrl; + late Color companyColor; + + static const TextStyle optionStyle = + TextStyle(fontSize: 30, fontWeight: FontWeight.bold); + + @override + void initState() { + paginatedUrl = IssueEndPoints.issues; + companyColor = Color(0xFFDC4654); + + animationController = + AnimationController(duration: new Duration(seconds: 2), vsync: this); + animationController.repeat(); + + // _scrollController.addListener(() async { + // if (_scrollController.position.pixels == + // _scrollController.position.maxScrollExtent) { + // loadMoreIssues(); + // } + // }); + super.initState(); + } + + @override + void dispose() { + animationController.dispose(); + super.dispose(); + } + + // void loadMoreIssues() { + // // paginatedUrl = ref.watch(companyListProvider.notifier).nxtUrl!; + // ref.watch(companiesListProvider.notifier); + // } + + @override + Widget build(BuildContext context) { + final isDarkMode = Theme.of(context).brightness == Brightness.dark; + final Size size = MediaQuery.of(context).size; + final issueState = ref.watch(companiesListProvider); + + return Scaffold( + backgroundColor: isDarkMode + ? Color.fromRGBO(34, 22, 23, 1) + : Theme.of(context).canvasColor, + appBar: AppBar( + backgroundColor: companyColor, + leading: IconButton( + icon: Icon( + Icons.arrow_back_ios_new_rounded, + color: Colors.white, + ), + onPressed: () { + Navigator.of(context).pop(); + }, + ), + title: Text( + "Companies", + style: TextStyle( + color: Colors.white, + fontSize: 20, + ), + ), + ), + body: RefreshIndicator( + onRefresh: () async { + ref.read(companiesListProvider.notifier).refreshCompanyList(); + }, + child: SingleChildScrollView( + physics: const BouncingScrollPhysics(), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + padding: EdgeInsets.symmetric(horizontal: 20), + width: size.width, + color: isDarkMode + ? Color.fromRGBO(34, 22, 23, 1) + : Theme.of(context).canvasColor, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + padding: EdgeInsets.fromLTRB(0, 12, 0, 12), + child: Text( + "Companies", + style: GoogleFonts.ubuntu( + textStyle: TextStyle( + color: Color(0xFF737373), + fontSize: 25, + ), + ), + ), + ), + Container( + padding: EdgeInsets.fromLTRB(0, 0, 0, 16), + child: Text( + "Check out the list of awesome companies out here. Maybe try to fix there issues too?", + style: GoogleFonts.aBeeZee( + textStyle: TextStyle( + color: Color(0xFF737373), + ), + ), + ), + ), + ], + ), + ), + Container( + // height: size.height * 0.8, + padding: EdgeInsets.symmetric(horizontal: 20), + child: issueState!.when( + data: (List? companyList) { + if (companyList!.isEmpty) { + return Center( + child: Text( + "${AppLocalizations.of(context)!.notManyBugs}:) \n ${AppLocalizations.of(context)!.yay}", + textAlign: TextAlign.center, + ), + ); + } else { + return ListView.separated( + controller: _scrollController, + itemCount: companyList.length, + shrinkWrap: true, + physics: NeverScrollableScrollPhysics(), + itemBuilder: (context, index) { + final company = companyList[index]; + return CompanyListElement( + company: company, + ); + }, + separatorBuilder: (BuildContext context, int index) { + return SizedBox(height: 10); + }, + ); + } + }, + error: (Object error, StackTrace? stackTrace) { + return Center( + child: Text( + AppLocalizations.of(context)!.somethingWentWrong, + style: TextStyle(fontSize: 18), + ), + ); + }, + loading: () { + return Center( + child: CircularProgressIndicator( + valueColor: animationController.drive( + ColorTween( + begin: Colors.blueAccent, + end: Colors.red, + ), + ), + ), + ); + }, + ), + ), + ], + ), + ), + ), + ); + } +} + +class CompanyListElement extends StatelessWidget { + const CompanyListElement({super.key, required this.company}); + final Company company; + + @override + Widget build(BuildContext context) { + final Size size = MediaQuery.of(context).size; + return GestureDetector( + onTap: () { + Navigator.of(context).pushNamed( + RouteManager.companyDetailPageWithIssues, + arguments: company, + ); + }, + child: Container( + width: size.width * 0.9, + decoration: BoxDecoration( + color: Colors.grey[350], + borderRadius: BorderRadius.circular(10), + ), + child: Padding( + padding: const EdgeInsets.all(16.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + ClipRRect( + borderRadius: BorderRadius.circular(10), + child: SizedBox( + height: 80, + width: 120, + child: Image.network( + company.logoLink, + fit: BoxFit.cover, + alignment: Alignment.center, + ), + ), + ), + SizedBox(height: 8), + Text( + company.companyName, + style: GoogleFonts.ubuntu( + textStyle: TextStyle( + color: Color.fromARGB(255, 95, 95, 95), + fontSize: 18, + fontWeight: FontWeight.bold, + ), + ), + ) + ], + ), + ), + ), + ); + } +} diff --git a/lib/src/pages/company_details.dart b/lib/src/pages/company_details.dart index 0d0df81b95..e7ed8fc70f 100644 --- a/lib/src/pages/company_details.dart +++ b/lib/src/pages/company_details.dart @@ -1,5 +1,4 @@ import 'package:blt/src/pages/pages_import.dart'; -import 'package:flutter/material.dart'; /// Popup page for viewing company details when a company /// is clicked on the Company Scoreboard page. @@ -62,7 +61,7 @@ class _CompanyDetailPageState extends State { ), child: Center( child: Text( - widget.company.openIssues > 0 + widget.company.openIssues! > 0 ? AppLocalizations.of(context)!.unableToGetInfo : AppLocalizations.of(context)!.noOpenIssues, style: GoogleFonts.aBeeZee( @@ -86,7 +85,7 @@ class _CompanyDetailPageState extends State { ), child: Center( child: Text( - widget.company.closedIssues > 0 + widget.company.closedIssues! > 0 ? AppLocalizations.of(context)!.unableToGetInfo : AppLocalizations.of(context)!.noOpenIssues, style: GoogleFonts.aBeeZee( diff --git a/lib/src/pages/drawer/about.dart b/lib/src/pages/drawer/about.dart index 012ad6b1c0..f7129d5044 100644 --- a/lib/src/pages/drawer/about.dart +++ b/lib/src/pages/drawer/about.dart @@ -1,4 +1,3 @@ -import 'package:flutter/material.dart'; import 'package:blt/src/pages/pages_import.dart'; /// Page for describing the BLT project. diff --git a/lib/src/pages/drawer/change_password.dart b/lib/src/pages/drawer/change_password.dart index a855ace99b..00cefe1b2f 100644 --- a/lib/src/pages/drawer/change_password.dart +++ b/lib/src/pages/drawer/change_password.dart @@ -1,4 +1,3 @@ -import 'package:flutter/material.dart'; import '../pages_import.dart'; /// The change password page for the app. diff --git a/lib/src/pages/drawer/company_dashboard.dart b/lib/src/pages/drawer/company_dashboard.dart index ae172f3356..8981bcb1f3 100644 --- a/lib/src/pages/drawer/company_dashboard.dart +++ b/lib/src/pages/drawer/company_dashboard.dart @@ -1,4 +1,3 @@ -import 'package:flutter/material.dart'; import '../pages_import.dart'; class CompanyDashBoardPage extends ConsumerStatefulWidget { diff --git a/lib/src/pages/drawer/legal.dart b/lib/src/pages/drawer/legal.dart index ac3ce4e0ff..5014ec07d3 100644 --- a/lib/src/pages/drawer/legal.dart +++ b/lib/src/pages/drawer/legal.dart @@ -1,4 +1,3 @@ -import 'package:flutter/material.dart'; import '../pages_import.dart'; /// Page stating the legal Terms and Conditions and Privacy diff --git a/lib/src/pages/drawer/referral.dart b/lib/src/pages/drawer/referral.dart index dccfec578c..248fcc907f 100644 --- a/lib/src/pages/drawer/referral.dart +++ b/lib/src/pages/drawer/referral.dart @@ -1,5 +1,4 @@ import 'package:blt/src/pages/pages_import.dart'; -import 'package:flutter/material.dart'; /// Page for allowing users to send referrals to their friends. class ReferralPage extends StatefulWidget { diff --git a/lib/src/pages/drawer/social.dart b/lib/src/pages/drawer/social.dart index 3bbb8b7792..e09bf3958c 100644 --- a/lib/src/pages/drawer/social.dart +++ b/lib/src/pages/drawer/social.dart @@ -1,6 +1,4 @@ import 'package:blt/src/pages/pages_import.dart'; -import 'package:flutter/material.dart'; -//import 'package:flutter_inappwebview/flutter_inappwebview.dart'; class SocialPage extends ConsumerStatefulWidget { const SocialPage({Key? key}) : super(key: key); diff --git a/lib/src/pages/error.dart b/lib/src/pages/error.dart index 493ac4a6aa..8b876c4b8b 100644 --- a/lib/src/pages/error.dart +++ b/lib/src/pages/error.dart @@ -1,5 +1,4 @@ import 'package:blt/src/pages/pages_import.dart'; -import 'package:flutter/material.dart'; /// This page is thrown in case when a Navigation exception occurs. class ErrorPage extends StatelessWidget { diff --git a/lib/src/pages/home/feed.dart b/lib/src/pages/home/feed.dart index 65a552f690..d939d9c867 100644 --- a/lib/src/pages/home/feed.dart +++ b/lib/src/pages/home/feed.dart @@ -1,6 +1,4 @@ import 'package:blt/src/pages/pages_import.dart'; -import 'package:flutter/material.dart'; - /// Page for showing social activity of BLT, new issues, /// top premium subscribers. diff --git a/lib/src/pages/home/home.dart b/lib/src/pages/home/home.dart index 7d7a6b0df3..408282f46a 100644 --- a/lib/src/pages/home/home.dart +++ b/lib/src/pages/home/home.dart @@ -313,6 +313,19 @@ class _HomeState extends ConsumerState { // Then close the drawer }, ), + ListTile( + title: Text("Companies"), + onTap: () { + Navigator.pushNamed( + context, + RouteManager.companiesListPage, + ); + + // Update the state of the app + // ... + // Then close the drawer + }, + ), ListTile( title: Text(AppLocalizations.of(context)!.companyDashboard), onTap: () { diff --git a/lib/src/pages/home/home_imports.dart b/lib/src/pages/home/home_imports.dart index d51214b79b..80f5a0a394 100644 --- a/lib/src/pages/home/home_imports.dart +++ b/lib/src/pages/home/home_imports.dart @@ -38,3 +38,5 @@ export 'package:url_launcher/url_launcher.dart'; export 'package:flutter_markdown/flutter_markdown.dart'; export 'package:pasteboard/pasteboard.dart'; export 'package:flutter_gen/gen_l10n/app_localizations.dart'; +export 'package:blt/src/providers/companies/company_list_provider.dart'; +export 'package:blt/src/providers/providers_imports.dart'; diff --git a/lib/src/pages/home/issues.dart b/lib/src/pages/home/issues.dart index 832b50f7be..3ea7410bc9 100644 --- a/lib/src/pages/home/issues.dart +++ b/lib/src/pages/home/issues.dart @@ -1,5 +1,4 @@ import 'package:blt/src/pages/home/home_imports.dart'; -import 'package:flutter/material.dart'; /// Issues page for viewing all the issues posted via the website and app. class IssuesPage extends ConsumerStatefulWidget { diff --git a/lib/src/pages/home/leaderboard.dart b/lib/src/pages/home/leaderboard.dart index 52d78a174e..5a47a9a552 100644 --- a/lib/src/pages/home/leaderboard.dart +++ b/lib/src/pages/home/leaderboard.dart @@ -1,5 +1,4 @@ import 'package:blt/src/pages/home/home_imports.dart'; -import 'package:flutter/material.dart'; /// The Leaderboards dashboard page, contains the Global, /// Monthly leaderboard, and Company Scoreboard. diff --git a/lib/src/pages/home/profile.dart b/lib/src/pages/home/profile.dart index d9dfb681ce..0f6e034059 100644 --- a/lib/src/pages/home/profile.dart +++ b/lib/src/pages/home/profile.dart @@ -1,5 +1,4 @@ import 'package:blt/src/pages/home/home_imports.dart'; -import 'package:flutter/material.dart'; /// Page that displays the stats of a user registered on BLT, /// shows dummy data for Guest login. diff --git a/lib/src/pages/home/report_bug.dart b/lib/src/pages/home/report_bug.dart index 603f54d13e..8b1e618d82 100644 --- a/lib/src/pages/home/report_bug.dart +++ b/lib/src/pages/home/report_bug.dart @@ -1,5 +1,4 @@ import 'package:blt/src/pages/home/home_imports.dart'; -import 'package:flutter/material.dart'; /// Report Bug and Start Bug Hunt Page, namesake, used for /// posting bugs, companies and individuals diff --git a/lib/src/pages/home/start_hunt.dart b/lib/src/pages/home/start_hunt.dart index e57f87d8a1..88ba87e0b6 100644 --- a/lib/src/pages/home/start_hunt.dart +++ b/lib/src/pages/home/start_hunt.dart @@ -1,5 +1,4 @@ import 'dart:typed_data'; -import 'package:flutter/material.dart'; import 'package:blt/src/pages/home/home_imports.dart'; import 'package:path_provider/path_provider.dart'; diff --git a/lib/src/pages/issues/closed_issues.dart b/lib/src/pages/issues/closed_issues.dart new file mode 100644 index 0000000000..854f672b84 --- /dev/null +++ b/lib/src/pages/issues/closed_issues.dart @@ -0,0 +1,192 @@ +import 'package:blt/src/pages/home/home_imports.dart'; + +/// Issues page for viewing all the Closed issues for a company posted via the website and app. +class ClosedIssuesPage extends ConsumerStatefulWidget { + const ClosedIssuesPage({required this.company, Key? key}); + final Company company; + + @override + ClosedIssuesPageState createState() => ClosedIssuesPageState(); +} + +ScrollController _scrollController = new ScrollController(); + +class ClosedIssuesPageState extends ConsumerState + with TickerProviderStateMixin { + late AnimationController animationController; + + late var closedIssuesListProvider = StateNotifierProvider< + IssueByStatusListProvider, AsyncValue?>?>((ref) { + return IssueByStatusListProvider( + ref.read, 'closed', widget.company.url ?? ""); + }); + // late String paginatedUrl; + + static const TextStyle optionStyle = + TextStyle(fontSize: 30, fontWeight: FontWeight.bold); + + @override + void initState() { + // paginatedUrl = + // IssueEndPoints.issues + "/?status=open&domain=${widget.company.url}"; + + animationController = + AnimationController(duration: new Duration(seconds: 2), vsync: this); + animationController.repeat(); + + _scrollController.addListener(() async { + if (_scrollController.position.pixels == + _scrollController.position.maxScrollExtent) { + loadMoreIssues(); + } + }); + super.initState(); + } + + @override + void dispose() { + animationController.dispose(); + super.dispose(); + } + + void loadMoreIssues() { + // paginatedUrl = ref + // .watch( + // closedIssuesListProvider({"url": widget.company.url ?? ""}).notifier) + // .nxtUrl!; + ref + .watch(closedIssuesListProvider.notifier) + .getMoreIssues("closed", widget.company.url ?? ""); + } + + @override + Widget build(BuildContext context) { + final Size size = MediaQuery.of(context).size; + + final issueState = ref.watch(closedIssuesListProvider); + final isDarkMode = Theme.of(context).brightness == Brightness.dark; + + return Scaffold( + backgroundColor: isDarkMode + ? Color.fromRGBO(34, 22, 23, 1) + : Theme.of(context).canvasColor, + appBar: AppBar( + backgroundColor: Color(0xFFDC4654), + leading: IconButton( + icon: Icon( + Icons.arrow_back_ios_new_rounded, + color: Colors.white, + ), + onPressed: () { + Navigator.of(context).pop(); + }, + ), + title: Text( + "Closed Issues", + style: TextStyle( + color: Colors.white, + fontSize: 20, + ), + ), + ), + body: RefreshIndicator( + onRefresh: () async { + ref.read(closedIssuesListProvider.notifier).refreshIssueList(); + }, + child: SingleChildScrollView( + physics: const BouncingScrollPhysics(), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + padding: EdgeInsets.symmetric(horizontal: 20), + width: size.width, + color: isDarkMode + ? Color.fromRGBO(34, 22, 23, 1) + : Theme.of(context).canvasColor, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + padding: EdgeInsets.fromLTRB(0, 12, 0, 12), + child: Text( + "Closed Issues", + style: GoogleFonts.ubuntu( + textStyle: TextStyle( + color: Color(0xFF737373), + fontSize: 25, + ), + ), + ), + ), + Container( + padding: EdgeInsets.fromLTRB(0, 0, 0, 16), + child: Text( + "Check out the closed issues found and reported by ${widget.company.companyName}. Maybe find a fix too?", + style: GoogleFonts.aBeeZee( + textStyle: TextStyle( + color: Color(0xFF737373), + ), + ), + ), + ), + ], + ), + ), + Container( + height: size.height * 0.8, + padding: EdgeInsets.symmetric(horizontal: 20), + child: issueState!.when( + data: (List? issueList) { + if (issueList!.isEmpty) { + return Center( + child: Text( + "${AppLocalizations.of(context)!.notManyBugs}:) \n ${AppLocalizations.of(context)!.yay}", + textAlign: TextAlign.center, + ), + ); + } else { + return ListView.builder( + controller: _scrollController, + itemCount: issueList.length, + itemBuilder: (context, index) { + final currentIssue = issueList[index]; + if (currentIssue.screenshotsLink!.isEmpty) { + return Container(); + } + return IssueCard( + issue: currentIssue, + ); + }, + ); + } + }, + error: (Object error, StackTrace? stackTrace) { + return Center( + child: Text( + AppLocalizations.of(context)!.somethingWentWrong, + style: TextStyle(fontSize: 18), + ), + ); + }, + loading: () { + return Center( + child: CircularProgressIndicator( + valueColor: animationController.drive( + ColorTween( + begin: Colors.blueAccent, + end: Colors.red, + ), + ), + ), + ); + }, + ), + ), + ], + ), + ), + ), + ); + } +} diff --git a/lib/src/pages/issues/open_issues.dart b/lib/src/pages/issues/open_issues.dart new file mode 100644 index 0000000000..9068dc2530 --- /dev/null +++ b/lib/src/pages/issues/open_issues.dart @@ -0,0 +1,192 @@ +import 'package:blt/src/pages/home/home_imports.dart'; + +/// Issues page for viewing all the open issues for a company posted via the website and app. +class OpenIssuesPage extends ConsumerStatefulWidget { + const OpenIssuesPage({required this.company, Key? key}); + final Company company; + + @override + OpenIssuesPageState createState() => OpenIssuesPageState(); +} + +ScrollController _scrollController = new ScrollController(); + +class OpenIssuesPageState extends ConsumerState + with TickerProviderStateMixin { + late AnimationController animationController; + + late var openIssuesListProvider = StateNotifierProvider< + IssueByStatusListProvider, AsyncValue?>?>((ref) { + return IssueByStatusListProvider( + ref.read, 'open', widget.company.url ?? ""); + }); + // late String paginatedUrl; + + static const TextStyle optionStyle = + TextStyle(fontSize: 30, fontWeight: FontWeight.bold); + + @override + void initState() { + // paginatedUrl = + // IssueEndPoints.issues + "/?status=open&domain=${widget.company.url}"; + + animationController = + AnimationController(duration: new Duration(seconds: 2), vsync: this); + animationController.repeat(); + + _scrollController.addListener(() async { + if (_scrollController.position.pixels == + _scrollController.position.maxScrollExtent) { + loadMoreIssues(); + } + }); + super.initState(); + } + + @override + void dispose() { + animationController.dispose(); + super.dispose(); + } + + void loadMoreIssues() { + // paginatedUrl = ref + // .watch( + // openIssuesListProvider({"url": widget.company.url ?? ""}).notifier) + // .nxtUrl!; + ref + .watch(openIssuesListProvider.notifier) + .getMoreIssues("open", widget.company.url ?? ""); + } + + @override + Widget build(BuildContext context) { + final Size size = MediaQuery.of(context).size; + + final issueState = ref.watch(openIssuesListProvider); + final isDarkMode = Theme.of(context).brightness == Brightness.dark; + + return Scaffold( + backgroundColor: isDarkMode + ? Color.fromRGBO(34, 22, 23, 1) + : Theme.of(context).canvasColor, + appBar: AppBar( + backgroundColor: Color(0xFFDC4654), + leading: IconButton( + icon: Icon( + Icons.arrow_back_ios_new_rounded, + color: Colors.white, + ), + onPressed: () { + Navigator.of(context).pop(); + }, + ), + title: Text( + "Open Issues", + style: TextStyle( + color: Colors.white, + fontSize: 20, + ), + ), + ), + body: RefreshIndicator( + onRefresh: () async { + ref.read(openIssuesListProvider.notifier).refreshIssueList(); + }, + child: SingleChildScrollView( + physics: const BouncingScrollPhysics(), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + padding: EdgeInsets.symmetric(horizontal: 20), + width: size.width, + color: isDarkMode + ? Color.fromRGBO(34, 22, 23, 1) + : Theme.of(context).canvasColor, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + padding: EdgeInsets.fromLTRB(0, 12, 0, 12), + child: Text( + "Open Issues", + style: GoogleFonts.ubuntu( + textStyle: TextStyle( + color: Color(0xFF737373), + fontSize: 25, + ), + ), + ), + ), + Container( + padding: EdgeInsets.fromLTRB(0, 0, 0, 16), + child: Text( + "Check out the open issues found and reported by ${widget.company.companyName}. Maybe find a fix too?", + style: GoogleFonts.aBeeZee( + textStyle: TextStyle( + color: Color(0xFF737373), + ), + ), + ), + ), + ], + ), + ), + Container( + height: size.height * 0.8, + padding: EdgeInsets.symmetric(horizontal: 20), + child: issueState!.when( + data: (List? issueList) { + if (issueList!.isEmpty) { + return Center( + child: Text( + "${AppLocalizations.of(context)!.notManyBugs}:) \n ${AppLocalizations.of(context)!.yay}", + textAlign: TextAlign.center, + ), + ); + } else { + return ListView.builder( + controller: _scrollController, + itemCount: issueList.length, + itemBuilder: (context, index) { + final currentIssue = issueList[index]; + if (currentIssue.screenshotsLink!.isEmpty) { + return Container(); + } + return IssueCard( + issue: currentIssue, + ); + }, + ); + } + }, + error: (Object error, StackTrace? stackTrace) { + return Center( + child: Text( + AppLocalizations.of(context)!.somethingWentWrong, + style: TextStyle(fontSize: 18), + ), + ); + }, + loading: () { + return Center( + child: CircularProgressIndicator( + valueColor: animationController.drive( + ColorTween( + begin: Colors.blueAccent, + end: Colors.red, + ), + ), + ), + ); + }, + ), + ), + ], + ), + ), + ), + ); + } +} diff --git a/lib/src/pages/onboarding_main_page.dart b/lib/src/pages/onboarding_main_page.dart index f03036b08d..38b6fec24f 100644 --- a/lib/src/pages/onboarding_main_page.dart +++ b/lib/src/pages/onboarding_main_page.dart @@ -1,5 +1,4 @@ import 'package:blt/src/pages/pages_import.dart'; -import 'package:flutter/material.dart'; class OnboardingMainPage extends ConsumerStatefulWidget { @override diff --git a/lib/src/pages/pages_import.dart b/lib/src/pages/pages_import.dart index 7f8916ed8c..06eece408a 100644 --- a/lib/src/pages/pages_import.dart +++ b/lib/src/pages/pages_import.dart @@ -34,3 +34,4 @@ export 'package:blt/src/global/variables.dart'; export 'package:blt/src/pages/welcome.dart'; export 'package:flutter_gen/gen_l10n/app_localizations.dart'; export 'package:blt/src/providers/language_provider.dart'; +export 'package:flutter/material.dart'; diff --git a/lib/src/pages/welcome.dart b/lib/src/pages/welcome.dart index 6ee6c40e50..6c9c5b2e73 100644 --- a/lib/src/pages/welcome.dart +++ b/lib/src/pages/welcome.dart @@ -1,5 +1,4 @@ import 'package:blt/src/pages/pages_import.dart'; -import 'package:flutter/material.dart'; import 'package:flutter/scheduler.dart'; /// The Landing page for unauthenticated users, or if a diff --git a/lib/src/providers/companies/company_list_provider.dart b/lib/src/providers/companies/company_list_provider.dart new file mode 100644 index 0000000000..d341999888 --- /dev/null +++ b/lib/src/providers/companies/company_list_provider.dart @@ -0,0 +1,39 @@ +import 'package:blt/src/components/components_import.dart'; +import 'package:blt/src/models/company_model.dart'; +import 'package:blt/src/util/api/company_api.dart'; + +final companiesListProvider = + StateNotifierProvider?>?>( + (ref) { + return CompanyListNotifier(ref.read); + }, +); + +class CompanyListNotifier extends StateNotifier?>?> { + final Reader read; + AsyncValue?>? previousState; + + CompanyListNotifier(this.read, [AsyncValue>? companyList]) + : super(companyList ?? const AsyncValue.loading()) { + _retrieveCompaniesList(); + } + + Future _retrieveCompaniesList() async { + try { + final List? companyData = + await CompanyApiClient.getListOfCompanies("/company/"); + state = AsyncValue.data(companyData); + } catch (e) { + AsyncValue.error(e); + } + } + + Future refreshCompanyList() async { + state = const AsyncValue.loading(); + try { + await _retrieveCompaniesList(); + } catch (e) { + AsyncValue.error(e); + } + } +} diff --git a/lib/src/providers/issuelist_provider.dart b/lib/src/providers/issuelist_provider.dart index c5b86103c9..009b8b642e 100644 --- a/lib/src/providers/issuelist_provider.dart +++ b/lib/src/providers/issuelist_provider.dart @@ -79,3 +79,68 @@ class IssueListProvider extends StateNotifier?>?> { _resetState(); } } + +class IssueByStatusListProvider + extends StateNotifier?>?> { + final Reader read; + final String status; + final String? url; + String? nxtUrl; + AsyncValue?>? previousState; + + IssueByStatusListProvider(this.read, this.status, this.url, + [AsyncValue>? issueList]) + : super(issueList ?? const AsyncValue.loading()) { + _retrieveIssueList(); + } + + Future _retrieveIssueList() async { + try { + final IssueData? issueData = + await IssueApiClient.getIssueByStatus(status, url ?? ""); + state = AsyncValue.data(issueData?.issueList ?? []); + print("Retrieved: ${state?.asData?.value}"); + } catch (e) { + state = AsyncValue.error(e); + } + } + + Future> getMoreIssues(String status, String? url) async { + List issues = []; + _cacheState(); + try { + final IssueData? issueData = + await IssueApiClient.getIssueByStatus(status, url ?? ""); + issues = issueData?.issueList ?? []; + } catch (e) { + _handleException(e); + throw e; + } + return issues; + } + + Future refreshIssueList() async { + state = const AsyncValue.loading(); + try { + await _retrieveIssueList(); + } catch (e) { + AsyncValue.error(e); + } + } + + void _cacheState() { + previousState = state; + } + + void _resetState() { + if (previousState != null) { + state = previousState; + previousState = null; + } + } + + void _handleException(e) { + print(e); + _resetState(); + } +} diff --git a/lib/src/routes/routes_import.dart b/lib/src/routes/routes_import.dart index a7ec5ac9f1..7aa0013727 100644 --- a/lib/src/routes/routes_import.dart +++ b/lib/src/routes/routes_import.dart @@ -19,3 +19,7 @@ export '../pages/leaderboards/global_leaderboard.dart'; export '../pages/issues/issue_detail.dart'; export '../pages/leaderboards/monthly_leaderboard.dart'; export '../pages/drawer/social.dart'; +export 'package:blt/src/pages/companies/company_details_and_issues.dart'; +export 'package:blt/src/pages/companies/company_list_page.dart'; +export 'package:blt/src/pages/issues/closed_issues.dart'; +export 'package:blt/src/pages/issues/open_issues.dart'; diff --git a/lib/src/routes/routing.dart b/lib/src/routes/routing.dart index ec017a04b3..ac2d210ba0 100644 --- a/lib/src/routes/routing.dart +++ b/lib/src/routes/routing.dart @@ -12,14 +12,18 @@ class RouteManager { static String currentRoute = "/loginSignup"; static const String legalPage = "/legal"; static const String aboutPage = "/about"; + static const String companiesListPage = "/companies"; static const String companyDashboardPage = "/companyDashboard"; static const String referralPage = "/refer"; static const String globalLeaderboardPage = "/globalBoard"; static const String monthlyLeaderboardPage = "/monthlyBoard"; static const String companyScoreboardPage = "/companyBoard"; static const String companyDetailPage = "/companyDetail"; + static const String companyDetailPageWithIssues = "/companyWithIssues"; static const String issueDetailPage = "/issueDetail"; static const String changePassword = "/changePassword"; + static const String openIssues = "/openIssues"; + static const String closedIssues = "/closedIssues"; /// Route generator, finds a requested route or throws the /// error page in case of route not found. @@ -362,6 +366,92 @@ class RouteManager { transitionDuration: const Duration(milliseconds: 750), ); + case companiesListPage: + return PageRouteBuilder( + pageBuilder: (context, animation, secondaryAnimation) => + const CompanyListPage(), + transitionsBuilder: (context, animation, secondaryAnimation, child) { + const begin = Offset(1.0, 0); + const end = Offset.zero; + const curve = Curves.ease; + + var tween = + Tween(begin: begin, end: end).chain(CurveTween(curve: curve)); + + return SlideTransition( + position: animation.drive(tween), + child: child, + ); + }, + transitionDuration: const Duration(milliseconds: 750), + ); + + case companyDetailPageWithIssues: + return PageRouteBuilder( + pageBuilder: (context, animation, secondaryAnimation) => + CompanyDetailWithIssues( + company: arguments as Company, + ), + transitionsBuilder: (context, animation, secondaryAnimation, child) { + const begin = Offset(1.0, 0); + const end = Offset.zero; + const curve = Curves.ease; + + var tween = + Tween(begin: begin, end: end).chain(CurveTween(curve: curve)); + + return SlideTransition( + position: animation.drive(tween), + child: child, + ); + }, + transitionDuration: const Duration(milliseconds: 750), + ); + + case openIssues: + return PageRouteBuilder( + pageBuilder: (context, animation, secondaryAnimation) => + OpenIssuesPage( + company: arguments as Company, + ), + transitionsBuilder: (context, animation, secondaryAnimation, child) { + const begin = Offset(1.0, 0); + const end = Offset.zero; + const curve = Curves.ease; + + var tween = + Tween(begin: begin, end: end).chain(CurveTween(curve: curve)); + + return SlideTransition( + position: animation.drive(tween), + child: child, + ); + }, + transitionDuration: const Duration(milliseconds: 750), + ); + + case closedIssues: + return PageRouteBuilder( + pageBuilder: (context, animation, secondaryAnimation) => + ClosedIssuesPage( + company: arguments as Company, + ), + transitionsBuilder: (context, animation, secondaryAnimation, child) { + const begin = Offset(1.0, 0); + const end = Offset.zero; + const curve = Curves.ease; + + var tween = + Tween(begin: begin, end: end).chain(CurveTween(curve: curve)); + + return SlideTransition( + position: animation.drive(tween), + child: child, + ); + }, + transitionDuration: const Duration(milliseconds: 750), + ); + default: return PageRouteBuilder( pageBuilder: (context, animation, secondaryAnimation) => ErrorPage(), diff --git a/lib/src/util/api/company_api.dart b/lib/src/util/api/company_api.dart index bad053b5d9..a966d5914f 100644 --- a/lib/src/util/api/company_api.dart +++ b/lib/src/util/api/company_api.dart @@ -6,6 +6,20 @@ import 'package:http/http.dart' as http; class CompanyApiClient { CompanyApiClient._(); + static Future> getListOfCompanies(String endpoint) async { + String searchUrl = GeneralEndPoints.apiBaseUrl + endpoint; + print(searchUrl); + List companiesList = []; + try { + var response = await http.get(Uri.parse(searchUrl)); + var decodedResponse = jsonDecode(utf8.decode(response.bodyBytes)); + companiesList = Company.fromSnapshot(decodedResponse["results"]); + } catch (e) { + print(e); + } + return companiesList; + } + /// Search a company by keyword, /// returns the first matching result. static Future getCompanyByKeyWord( diff --git a/lib/src/util/api/issues_api.dart b/lib/src/util/api/issues_api.dart index 370d1ae7b9..d17a63594e 100644 --- a/lib/src/util/api/issues_api.dart +++ b/lib/src/util/api/issues_api.dart @@ -232,4 +232,32 @@ class IssueApiClient { static Future getUserIssueById() async {} static Future searchUserIssueByKeyWord() async {} + + static Future getIssueByStatus(String status, String url) async { + http.Response? response; + IssueData? issueData; + List? issueList; + try { + String searchUrl = GeneralEndPoints.apiBaseUrl + + "/api/v1/issues/" + + "?status=$status&domain=$url"; + response = await http.get(Uri.parse(searchUrl)); + if (response.statusCode == 200) { + issueList = []; + var decodedResponse = jsonDecode(utf8.decode(response.bodyBytes)); + decodedResponse["results"].forEach((element) { + issueList!.add(Issue.fromJson(element)); + }); + issueData = IssueData( + count: decodedResponse["count"], + nextQuery: decodedResponse["next"], + previousQuery: decodedResponse["previous"], + issueList: issueList, + ); + } + } catch (e) { + print(e); + } + return issueData; + } }