feat: add news filter

This commit is contained in:
Rongjian Zhang 2019-03-10 16:09:26 +08:00
parent 55af7463f1
commit 049f44b5f4
6 changed files with 96 additions and 49 deletions

View File

@ -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);

View File

@ -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,

View File

@ -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);
},
),
],
);
},
);
}

View File

@ -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),

View File

@ -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),
);
}
}

View File

@ -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);