Isses bloc view
This commit is contained in:
parent
e437f99a79
commit
612371b4d9
3 changed files with 136 additions and 9 deletions
|
@ -23,7 +23,7 @@ class IssuesBloc extends Bloc<IssuesEvent, IssueState> {
|
||||||
if (state.hasReachedMax) return;
|
if (state.hasReachedMax) return;
|
||||||
try {
|
try {
|
||||||
if (state.status == IssueStatus.initial) {
|
if (state.status == IssueStatus.initial) {
|
||||||
final issues = await giteaService.getRepoIssues(repoFullname: repoFullName,state: istate,page: 1, limit: 10);
|
final issues = await giteaService.getRepoIssues(owner: repoFullName.split('/')[0],repo: repoFullName.split('/')[1],state: istate,page: 1, limit: 10);
|
||||||
return emit(state.copyWith(
|
return emit(state.copyWith(
|
||||||
status: IssueStatus.success,
|
status: IssueStatus.success,
|
||||||
issues: issues,
|
issues: issues,
|
||||||
|
@ -32,7 +32,7 @@ class IssuesBloc extends Bloc<IssuesEvent, IssueState> {
|
||||||
error_message: null,
|
error_message: null,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
final issues = await giteaService.getRepoIssues(repoFullname: repoFullName,state: istate,page: state.loadedPages+1, limit: 10);
|
final issues = await giteaService.getRepoIssues(owner: repoFullName.split('/')[0],repo: repoFullName.split('/')[1],state: istate,page: state.loadedPages+1, limit: 10);
|
||||||
final issueList = List.of(state.issues);
|
final issueList = List.of(state.issues);
|
||||||
issues.forEach((element) {
|
issues.forEach((element) {
|
||||||
if(issueList.where((selement) => selement.id == element.id).isEmpty) {
|
if(issueList.where((selement) => selement.id == element.id).isEmpty) {
|
||||||
|
|
|
@ -55,12 +55,12 @@ class GiteaService {
|
||||||
throw Exception('error fetching files');
|
throw Exception('error fetching files');
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<List<Issue>> getRepoIssues({required String repoFullname,required String state,int page = 1, int limit = 10}) async{
|
Future<List<Issue>> getRepoIssues({required String owner,required String repo,required String state,int page = 1, int limit = 10}) async{
|
||||||
if(state != "all" || state != "closed" || state != "open") {
|
if(state != "all" && state != "closed" && state != "open") {
|
||||||
throw Exception("Wrong state provided!");
|
throw Exception("Wrong state provided: $state");
|
||||||
}
|
}
|
||||||
var response = await http.get(
|
var response = await http.get(
|
||||||
Uri.https(apiAccess.instance, "api/v1/user/repos/$repoFullname/issues", {
|
Uri.https(apiAccess.instance, "api/v1/repos/$owner/$repo/issues", {
|
||||||
"token": apiAccess.token,
|
"token": apiAccess.token,
|
||||||
"state": state,
|
"state": state,
|
||||||
"page" : page.toString(),
|
"page" : page.toString(),
|
||||||
|
@ -76,7 +76,7 @@ class GiteaService {
|
||||||
result.sort((a,b) => -1*a.updatedAt!.compareTo(b.updatedAt!));
|
result.sort((a,b) => -1*a.updatedAt!.compareTo(b.updatedAt!));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
throw Exception('error fetching posts');
|
throw Exception('error fetching posts: ${response.statusCode}');
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<List<Repository>> getUserRepositories([int page = 1, int limit = 10]) async{
|
Future<List<Repository>> getUserRepositories([int page = 1, int limit = 10]) async{
|
||||||
|
|
|
@ -5,6 +5,8 @@ import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:flutter_markdown/flutter_markdown.dart';
|
import 'package:flutter_markdown/flutter_markdown.dart';
|
||||||
import 'package:gitea_client/cubit/file_list_load_bloc.dart';
|
import 'package:gitea_client/cubit/file_list_load_bloc.dart';
|
||||||
|
import 'package:gitea_client/cubit/issues_bloc.dart';
|
||||||
|
import 'package:gitea_client/model/issues.dart';
|
||||||
import 'package:gitea_client/model/repository.dart';
|
import 'package:gitea_client/model/repository.dart';
|
||||||
import 'package:gitea_client/model/user.dart';
|
import 'package:gitea_client/model/user.dart';
|
||||||
import 'package:gitea_client/service/gitea_service.dart';
|
import 'package:gitea_client/service/gitea_service.dart';
|
||||||
|
@ -308,8 +310,17 @@ class RepoIssues extends StatefulWidget {
|
||||||
}
|
}
|
||||||
|
|
||||||
class _RepoIssues extends State<RepoIssues> {
|
class _RepoIssues extends State<RepoIssues> {
|
||||||
|
final _scrollController = ScrollController();
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_scrollController.addListener(_onScroll);
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
final media = MediaQuery.of(context).size;
|
||||||
return DefaultTabController(
|
return DefaultTabController(
|
||||||
length: 2,
|
length: 2,
|
||||||
child: DefaultTabController(
|
child: DefaultTabController(
|
||||||
|
@ -334,10 +345,90 @@ class _RepoIssues extends State<RepoIssues> {
|
||||||
body: TabBarView(
|
body: TabBarView(
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
Column(
|
Column(
|
||||||
children: const [Text("Open Issues")],
|
children: [
|
||||||
|
Center(
|
||||||
|
child: SizedBox(
|
||||||
|
width: (media.width > 600) ? media.width * 0.5 : media.width * 0.9,
|
||||||
|
height: media.height-kToolbarHeight-kBottomNavigationBarHeight-kTextTabBarHeight-50,
|
||||||
|
child: BlocProvider(
|
||||||
|
create: (context) {
|
||||||
|
return IssuesBloc(GiteaService(apiAccess: widget.user.apiAccess),widget.repo.fullName!,"open")
|
||||||
|
..add(IssuesFetched());
|
||||||
|
},
|
||||||
|
child: BlocBuilder<IssuesBloc, IssueState>(
|
||||||
|
builder: (context, state) {
|
||||||
|
switch (state.status) {
|
||||||
|
case IssueStatus.failure:
|
||||||
|
String error_message = state.error_message!;
|
||||||
|
return Center(child: Text('failed to fetch $error_message'));
|
||||||
|
case IssueStatus.success:
|
||||||
|
if (state.issues.isEmpty) {
|
||||||
|
return const Center(
|
||||||
|
child: Text('No issues found'));
|
||||||
|
}
|
||||||
|
|
||||||
|
return ListView.builder(
|
||||||
|
itemBuilder: (BuildContext context, int index) {
|
||||||
|
return IssuesListItem(
|
||||||
|
issue: state.issues[index],
|
||||||
|
onTap: () {},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
itemCount: state.issues.length,
|
||||||
|
controller: _scrollController,
|
||||||
|
);
|
||||||
|
default:
|
||||||
|
return const Center(child: CircularProgressIndicator());
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
),
|
),
|
||||||
Column(
|
Column(
|
||||||
children: const [Text("Closed Issues")],
|
children: [
|
||||||
|
Center(
|
||||||
|
child: SizedBox(
|
||||||
|
width: (media.width > 600) ? media.width * 0.5 : media.width * 0.9,
|
||||||
|
height: media.height-kToolbarHeight-kBottomNavigationBarHeight-kTextTabBarHeight-50,
|
||||||
|
child: BlocProvider(
|
||||||
|
create: (context) {
|
||||||
|
return IssuesBloc(GiteaService(apiAccess: widget.user.apiAccess),widget.repo.fullName!,"closed")
|
||||||
|
..add(IssuesFetched());
|
||||||
|
},
|
||||||
|
child: BlocBuilder<IssuesBloc, IssueState>(
|
||||||
|
builder: (context, state) {
|
||||||
|
switch (state.status) {
|
||||||
|
case IssueStatus.failure:
|
||||||
|
String error_message = state.error_message!;
|
||||||
|
return Center(child: Text('failed to fetch $error_message'));
|
||||||
|
case IssueStatus.success:
|
||||||
|
if (state.issues.isEmpty) {
|
||||||
|
return const Center(
|
||||||
|
child: Text('No issues found'));
|
||||||
|
}
|
||||||
|
|
||||||
|
return ListView.builder(
|
||||||
|
itemBuilder: (BuildContext context, int index) {
|
||||||
|
return IssuesListItem(
|
||||||
|
issue: state.issues[index],
|
||||||
|
onTap: () {},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
itemCount: state.issues.length,
|
||||||
|
controller: _scrollController,
|
||||||
|
);
|
||||||
|
default:
|
||||||
|
return const Center(child: CircularProgressIndicator());
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
@ -345,6 +436,42 @@ class _RepoIssues extends State<RepoIssues> {
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_scrollController
|
||||||
|
..removeListener(_onScroll)
|
||||||
|
..dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
void _onScroll() {
|
||||||
|
if (_isBottom) context.read<IssuesBloc>().add(IssuesFetched());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool get _isBottom {
|
||||||
|
if (!_scrollController.hasClients) return false;
|
||||||
|
final maxScroll = _scrollController.position.maxScrollExtent;
|
||||||
|
final currentScroll = _scrollController.offset;
|
||||||
|
return currentScroll >= (maxScroll * 0.9);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class IssuesListItem extends StatelessWidget {
|
||||||
|
final Issue issue;
|
||||||
|
final Function onTap;
|
||||||
|
|
||||||
|
const IssuesListItem({Key? key, required this.issue, required this.onTap})
|
||||||
|
: super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return ListTile(
|
||||||
|
leading: Text("#${issue.number!}"),
|
||||||
|
title: Text(issue.title!),
|
||||||
|
onTap: () => {onTap()},
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class RepoPullRequests extends StatefulWidget {
|
class RepoPullRequests extends StatefulWidget {
|
||||||
|
|
Loading…
Reference in a new issue