mirror of
https://github.com/git-touch/git-touch
synced 2025-02-20 13:30:38 +01:00
feat: add news filter
This commit is contained in:
parent
55af7463f1
commit
049f44b5f4
@ -10,6 +10,7 @@ import 'package:flutter/material.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
// import '../utils/utils.dart';
|
||||
import '../utils/constants.dart';
|
||||
import '../utils/utils.dart';
|
||||
import '../models/account.dart';
|
||||
|
||||
class PlatformType {
|
||||
@ -17,12 +18,6 @@ class PlatformType {
|
||||
static const gitlab = 'gitlab';
|
||||
}
|
||||
|
||||
class StorageKeys {
|
||||
static const account = 'account';
|
||||
static const github = 'github';
|
||||
static const theme = 'theme';
|
||||
}
|
||||
|
||||
// abstract class Model<T> {
|
||||
// Future<T> query(BuildContext context) {
|
||||
// var settings = SettingsProvider.of(context);
|
||||
|
@ -17,23 +17,21 @@ class ListPayload<T, K> {
|
||||
// This is a scaffold for infinite scroll screens
|
||||
class ListScaffold<T, K> extends StatefulWidget {
|
||||
final Widget title;
|
||||
// final IconData trailingIconData;
|
||||
// final Function trailingOnTap;
|
||||
final Widget Function({Function({bool force}) refresh}) trailingBuiler;
|
||||
final Widget Function(T payload) itemBuilder;
|
||||
final Future<ListPayload<T, K>> Function() onRefresh;
|
||||
final Future<ListPayload<T, K>> Function(K cursor) onLoadMore;
|
||||
|
||||
ListScaffold({
|
||||
@required this.title,
|
||||
// this.trailingIconData,
|
||||
// this.trailingOnTap,
|
||||
@required this.itemBuilder,
|
||||
@required this.onRefresh,
|
||||
@required this.onLoadMore,
|
||||
this.trailingBuiler,
|
||||
});
|
||||
|
||||
@override
|
||||
_ListScaffoldState createState() => _ListScaffoldState();
|
||||
_ListScaffoldState<T, K> createState() => _ListScaffoldState();
|
||||
}
|
||||
|
||||
class _ListScaffoldState<T, K> extends State<ListScaffold<T, K>> {
|
||||
@ -62,11 +60,20 @@ class _ListScaffoldState<T, K> extends State<ListScaffold<T, K>> {
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> _refresh() async {
|
||||
// print('list scaffold refresh');
|
||||
@override
|
||||
void dispose() {
|
||||
_controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
Future<void> _refresh({bool force = false}) async {
|
||||
print('list scaffold refresh');
|
||||
setState(() {
|
||||
error = '';
|
||||
loading = true;
|
||||
if (force) {
|
||||
items = [];
|
||||
}
|
||||
});
|
||||
try {
|
||||
var _payload = await widget.onRefresh();
|
||||
@ -96,7 +103,8 @@ class _ListScaffoldState<T, K> extends State<ListScaffold<T, K>> {
|
||||
cursor = _payload.cursor;
|
||||
hasMore = _payload.hasMore;
|
||||
} catch (err) {
|
||||
print(err);
|
||||
error = err.toString();
|
||||
throw err;
|
||||
} finally {
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
@ -154,6 +162,7 @@ class _ListScaffoldState<T, K> extends State<ListScaffold<T, K>> {
|
||||
return EmptyWidget();
|
||||
} else {
|
||||
return ListView.builder(
|
||||
// shrinkWrap: true,
|
||||
controller: _controller,
|
||||
itemCount: 2 * items.length + 1,
|
||||
itemBuilder: _buildItem,
|
||||
@ -176,15 +185,9 @@ class _ListScaffoldState<T, K> extends State<ListScaffold<T, K>> {
|
||||
return CupertinoPageScaffold(
|
||||
navigationBar: CupertinoNavigationBar(
|
||||
middle: widget.title,
|
||||
// trailing: Link(
|
||||
// child: Icon(
|
||||
// widget.trailingIconData,
|
||||
// size: 24,
|
||||
// color: Colors.blueAccent,
|
||||
// ),
|
||||
// beforeRedirect: widget.trailingOnTap,
|
||||
// bgColor: Colors.transparent,
|
||||
// ),
|
||||
trailing: widget.trailingBuiler == null
|
||||
? null
|
||||
: widget.trailingBuiler(refresh: _refresh),
|
||||
),
|
||||
child: SafeArea(
|
||||
child: CustomScrollView(
|
||||
@ -197,14 +200,9 @@ class _ListScaffoldState<T, K> extends State<ListScaffold<T, K>> {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: widget.title,
|
||||
// actions: widget.trailingIconData == null
|
||||
// ? []
|
||||
// : <Widget>[
|
||||
// IconButton(
|
||||
// icon: Icon(widget.trailingIconData),
|
||||
// onPressed: widget.trailingOnTap,
|
||||
// )
|
||||
// ],
|
||||
actions: widget.trailingBuiler == null
|
||||
? null
|
||||
: [widget.trailingBuiler(refresh: _refresh)],
|
||||
),
|
||||
body: RefreshIndicator(
|
||||
onRefresh: _refresh,
|
||||
|
@ -4,6 +4,16 @@ import '../scaffolds/list.dart';
|
||||
import '../widgets/event_item.dart';
|
||||
import '../providers/settings.dart';
|
||||
import '../utils/utils.dart';
|
||||
import '../widgets/action.dart';
|
||||
|
||||
class NewsFilter {
|
||||
static const all = 'all';
|
||||
|
||||
/// The same as GitHub dashboard
|
||||
///
|
||||
/// Exclude issue and pull request events
|
||||
static const github = 'github';
|
||||
}
|
||||
|
||||
class NewsScreen extends StatefulWidget {
|
||||
@override
|
||||
@ -11,34 +21,69 @@ class NewsScreen extends StatefulWidget {
|
||||
}
|
||||
|
||||
class NewsScreenState extends State<NewsScreen> {
|
||||
Future<List<EventPayload>> fetchEvents(int page) async {
|
||||
String filter = NewsFilter.github;
|
||||
|
||||
Future<ListPayload<EventPayload, int>> fetchEvents([int page = 1]) async {
|
||||
var settings = SettingsProvider.of(context);
|
||||
var login = settings.activeLogin;
|
||||
List data = await settings.getWithCredentials(
|
||||
'/users/$login/received_events?page=$page&per_page=$pageSize');
|
||||
// print(data);
|
||||
return data
|
||||
print(data.length);
|
||||
var hasMore = data.length == pageSize;
|
||||
var events = data
|
||||
.map<EventPayload>((item) => EventPayload.fromJson(item))
|
||||
.where(testEvents)
|
||||
.toList();
|
||||
|
||||
return ListPayload(
|
||||
cursor: page + 1,
|
||||
hasMore: hasMore,
|
||||
items: events,
|
||||
);
|
||||
}
|
||||
|
||||
bool testEvents(EventPayload event) {
|
||||
switch (filter) {
|
||||
case NewsFilter.github:
|
||||
return ![
|
||||
'IssueCommentEvent',
|
||||
'IssuesEvent',
|
||||
'PullRequestEvent',
|
||||
'PullRequestReviewEvent',
|
||||
'PullRequestReviewCommentEvent',
|
||||
].contains(event.type);
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(context) {
|
||||
// FIXME: can't add generic type here. Don't know why
|
||||
// type '(Event) => EventItem' is not a subtype of type '(dynamic) => Widget'
|
||||
return ListScaffold(
|
||||
return ListScaffold<EventPayload, int>(
|
||||
title: Text('News'),
|
||||
itemBuilder: (payload) => EventItem(payload),
|
||||
onRefresh: () async {
|
||||
var page = 1;
|
||||
var items = await fetchEvents(page);
|
||||
return ListPayload(
|
||||
cursor: page + 1, hasMore: items.length == pageSize, items: items);
|
||||
},
|
||||
onLoadMore: (page) async {
|
||||
var items = await fetchEvents(page);
|
||||
return ListPayload(
|
||||
cursor: page + 1, hasMore: items.length == pageSize, items: items);
|
||||
onRefresh: fetchEvents,
|
||||
onLoadMore: (page) => fetchEvents(page),
|
||||
trailingBuiler: ({refresh}) {
|
||||
return ActionButton(
|
||||
title: 'Filter',
|
||||
actions: [
|
||||
Action(
|
||||
text: 'Show all items',
|
||||
onPress: () {
|
||||
filter = NewsFilter.all;
|
||||
refresh(force: true);
|
||||
},
|
||||
),
|
||||
Action(
|
||||
text: 'Only GitHub items',
|
||||
onPress: () {
|
||||
filter = NewsFilter.github;
|
||||
refresh(force: true);
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
@ -218,7 +218,9 @@ $key: pullRequest(number: ${item.number}) {
|
||||
title: _buildTitle(),
|
||||
bottom: TabBar(
|
||||
onTap: _onSwitchTab,
|
||||
tabs: textMap.entries.map((entry) => Tab(text: entry.value)).toList(),
|
||||
tabs: textMap.entries
|
||||
.map((entry) => Tab(text: entry.value.toUpperCase()))
|
||||
.toList(),
|
||||
),
|
||||
// trailing: GestureDetector(
|
||||
// child: Icon(Icons.more_vert, size: 20),
|
||||
|
@ -54,7 +54,7 @@ class _ReposScreenState extends State<ReposScreen> {
|
||||
title: Text('$login\'s $title'),
|
||||
onRefresh: () => _queryRepos(),
|
||||
onLoadMore: (cursor) => _queryRepos(cursor),
|
||||
itemBuilder: (payload) => RepoItem(payload),
|
||||
itemBuilder: (payload) => RepoItem(payload, showOwner: false),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,13 @@ import '../screens/repo.dart';
|
||||
export 'package:flutter_vector_icons/flutter_vector_icons.dart';
|
||||
export 'timeago.dart';
|
||||
|
||||
class StorageKeys {
|
||||
static const account = 'account';
|
||||
static const github = 'github';
|
||||
static const theme = 'theme';
|
||||
static const newsFilter = 'news.filter';
|
||||
}
|
||||
|
||||
Color convertColor(String cssHex) {
|
||||
if (cssHex.startsWith('#')) {
|
||||
cssHex = cssHex.substring(1);
|
||||
|
Loading…
x
Reference in New Issue
Block a user