Skip to content

Commit d1b682c

Browse files
author
tensor-programming
committed
added filter
1 parent e344c63 commit d1b682c

File tree

6 files changed

+108
-41
lines changed

6 files changed

+108
-41
lines changed

lib/blocs/contribution_bloc.dart

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import 'package:utopian_rocks/model/repository.dart';
44
import 'package:utopian_rocks/model/htmlParser.dart';
55
import 'package:rxdart/rxdart.dart';
66

7+
import 'package:utopian_rocks/utils/utils.dart' as utils;
8+
79
// Contribution buisness logic class
810
class ContributionBloc {
911
final Api api;
@@ -19,19 +21,22 @@ class ContributionBloc {
1921
BehaviorSubject<String>(seedValue: 'pending');
2022
// Stream<String> _log = Stream.empty();
2123

24+
BehaviorSubject<String> _filter = BehaviorSubject<String>(seedValue: 'all');
25+
2226
Stream<List<Contribution>> get results => _results;
23-
Sink<String> get tabname => _tabname;
2427
Stream<String> get voteCount => _voteCount;
2528
Stream<int> get timer => _timer;
2629

27-
// Stream<String> get log => _log;
30+
Sink<String> get tabname => _tabname;
31+
Sink<String> get filter => _filter;
2832

2933
ContributionBloc(this.api, this.parseWebsite) {
3034
_results = _tabname
3135
// Debounce to account for latency
3236
.debounce(Duration(milliseconds: 300))
3337
// Apply the api updateContributions function to tabname stream to get results.
3438
.asyncMap(api.updateContributions)
39+
.asyncMap(applyFilter)
3540
.asBroadcastStream();
3641

3742
_voteCount = Observable.fromFuture(
@@ -41,13 +46,25 @@ class ContributionBloc {
4146
_timer = Observable.periodic(Duration(seconds: 1), (x) => x)
4247
.asyncMap(parseWebsite.getTimer)
4348
.asBroadcastStream();
44-
45-
// _log = Observable(results)
46-
// .withLatestFrom(_tabname.stream, (_, tabname) => 'results for $tabname')
47-
// .asBroadcastStream();
4849
}
4950

5051
void dispose() {
5152
_tabname.close();
53+
_filter.close();
54+
}
55+
56+
Future<List<Contribution>> applyFilter(
57+
List<Contribution> contributions) async {
58+
var filter = await _filter.stream.first ?? 'all';
59+
var tabname = await _tabname.stream.first;
60+
61+
var cons = contributions;
62+
63+
_tabname.add(tabname);
64+
if (filter != 'all') {
65+
cons.removeWhere((c) => c.category != filter);
66+
return cons;
67+
}
68+
return cons;
5269
}
5370
}

lib/blocs/information_bloc.dart

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,11 @@ class InformationBloc {
1818
Stream<GithubReleaseModel> get releases => _releases;
1919

2020
// BLoc that serves package information to the information drawer.
21+
// Bloc gets Github release information only on application start.
2122
InformationBloc(this.packageInfo, this.api) {
2223
_infoStream = Observable.fromFuture(packageInfo).asBroadcastStream();
23-
24-
api.getReleases();
25-
26-
_releases = Observable.fromFuture(api.getReleases())
27-
.debounce(Duration(minutes: 5))
28-
.asBroadcastStream();
24+
// release information is served as a normal stream which can only be subscribed to once.
25+
// This stream also only has one element in it. This is done to stop from overflowing the Github API.
26+
_releases = Observable.fromFuture(api.getReleases()).take(1);
2927
}
3028
}

lib/main.dart

Lines changed: 56 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ import 'package:flutter/material.dart';
33
import 'package:package_info/package_info.dart';
44
import 'package:intl/intl.dart';
55

6+
import 'package:rxdart/rxdart.dart';
7+
68
import 'package:utopian_rocks/components/list_page.dart';
79
import 'package:utopian_rocks/components/drawer.dart';
810

@@ -14,6 +16,7 @@ import 'package:utopian_rocks/blocs/information_bloc.dart';
1416
import 'package:utopian_rocks/providers/information_provider.dart';
1517
import 'package:utopian_rocks/model/htmlParser.dart';
1618
import 'package:utopian_rocks/model/githubApi.dart';
19+
import 'package:utopian_rocks/utils/utils.dart';
1720

1821
void main() => runApp(MyApp());
1922

@@ -43,6 +46,7 @@ class RootApp extends StatelessWidget {
4346
@override
4447
Widget build(BuildContext context) {
4548
final informationBloc = InformationProvider.of(context);
49+
final contributionBloc = ContributionProvider.of(context);
4650
return MaterialApp(
4751
// Remove Debug flag to allow app to be production ready.
4852
debugShowCheckedModeBanner: false,
@@ -78,6 +82,7 @@ class RootApp extends StatelessWidget {
7882
),
7983
],
8084
),
85+
8186
// Add [TabBar] to the [AppBar] to allow the user to navigate from one page to the next.
8287
bottom: TabBar(
8388
tabs: <Widget>[
@@ -98,39 +103,67 @@ class RootApp extends StatelessWidget {
98103
ListPage('pending'),
99104
],
100105
),
101-
bottomNavigationBar: _buildBottonSheet(context),
106+
bottomNavigationBar:
107+
_buildBottonSheet(context, contributionBloc),
102108
endDrawer: InformationDrawer(snapshot),
103109
),
104110
),
105111
),
106112
);
107113
}
108114

109-
Widget _buildBottonSheet(BuildContext context) {
110-
final contributionBloc = ContributionProvider.of(context);
111-
115+
Widget _buildBottonSheet(
116+
BuildContext context,
117+
ContributionBloc contributionBloc,
118+
) {
112119
return StreamBuilder(
113120
stream: contributionBloc.voteCount,
114121
builder: (context, votecountSnapshot) => BottomAppBar(
115-
color: Color(0xff26A69A),
116-
child: Row(
117-
children: [
118-
StreamBuilder(
119-
stream: contributionBloc.timer,
120-
builder: (context, timerSnapshot) {
121-
return Text(
122-
'Next Vote Cycle: ${DateFormat.Hms().format(DateTime(0, 0, 0, 0, 0, timerSnapshot.data ?? 0))} ',
123-
style: TextStyle(fontWeight: FontWeight.w700),
124-
);
125-
}),
126-
Text(
127-
'Vote Power: ${double.parse(votecountSnapshot.data ?? '0.0').toStringAsPrecision(4)}',
128-
style: TextStyle(fontWeight: FontWeight.w700),
122+
color: Color(0xff26A69A),
123+
child: Row(
124+
children: [
125+
StreamBuilder(
126+
stream: contributionBloc.timer,
127+
builder: (context, timerSnapshot) {
128+
return Text(
129+
'Next Vote Cycle: ${DateFormat.Hms().format(DateTime(0, 0, 0, 0, 0, timerSnapshot.data ?? 0))} ',
130+
style: TextStyle(fontWeight: FontWeight.w700),
131+
);
132+
}),
133+
Text(
134+
'Vote Power: ${double.parse(votecountSnapshot.data ?? '0.0').toStringAsPrecision(4)}',
135+
style: TextStyle(fontWeight: FontWeight.w700),
136+
),
137+
_generateMenu(categories, contributionBloc),
138+
],
139+
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
140+
crossAxisAlignment: CrossAxisAlignment.center,
141+
)));
142+
}
143+
144+
Widget _generateMenu(
145+
List<String> categories,
146+
ContributionBloc bloc,
147+
) {
148+
return PopupMenuButton<String>(
149+
tooltip: 'Filter Contribution Categories',
150+
onSelected: (category) => bloc.filter.add(category),
151+
itemBuilder: (context) => categories
152+
.map((cate) => PopupMenuItem(
153+
height: 40.0,
154+
value: cate,
155+
child: ListTile(
156+
leading: Icon(
157+
IconData(
158+
icons[cate],
159+
fontFamily: 'Utopicons',
160+
),
161+
color: colors[cate],
129162
),
130-
],
131-
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
132-
crossAxisAlignment: CrossAxisAlignment.center,
133-
),
134-
));
163+
title: Text(cate),
164+
),
165+
))
166+
.toList(),
167+
);
135168
}
136169
}

lib/model/githubApi.dart

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,10 @@ class GithubApi {
1111
'https://api.github.com/repos/tensor-programming/utopian-rocks-mobile/releases';
1212

1313
Future<GithubReleaseModel> getReleases() async {
14-
List<GithubReleaseModel> items = [];
15-
16-
Response res = await _client.get(Uri.parse(_url));
17-
List map = json.decode(res.body);
18-
var x = map.map((gh) => GithubReleaseModel.fromJson(gh)).toList();
14+
String resBody =
15+
await _client.get(Uri.parse(_url)).then((Response res) => res.body);
16+
List ghJson = json.decode(resBody);
17+
var x = ghJson.map((gh) => GithubReleaseModel.fromJson(gh)).toList();
1918
return x.first;
2019
}
2120
}

lib/model/model.dart

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,9 @@ class Contribution {
2828
Contribution.fromJson(Map json)
2929
: author = json['author'] as String,
3030
// Remove any -task categories
31-
category = (json['category'] as String).replaceFirst('-task', ''),
31+
category = (json['category'] as String)
32+
.replaceFirst('-task', '')
33+
.replaceFirst("task-", ''),
3234
moderator = json['moderator'] as String,
3335
// Shorten Repository url for UI page.
3436
repository = (json['repository'] as String)

lib/utils/utils.dart

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,21 @@
11
import 'package:flutter/material.dart';
22

3+
const categories = [
4+
'ideas',
5+
'development',
6+
'bug-hunting',
7+
'translations',
8+
'graphics',
9+
'analysis',
10+
'documentation',
11+
'tutorials',
12+
'video-tutorials',
13+
'copywriting',
14+
'blog',
15+
'social',
16+
'all',
17+
];
18+
319
// a list of the Utopian Color hexidecimal codes.
420
const colors = <String, Color>{
521
'ideas': Color(0xFF4DD39F),
@@ -14,6 +30,7 @@ const colors = <String, Color>{
1430
'copywriting': Color(0xFF007f80),
1531
'blog': Color(0xff0275d8),
1632
'social': Color(0xff7bc0f5),
33+
'all': Color(0xff3237c9),
1734
};
1835

1936
// A list of the Utopian Icon font codes.
@@ -30,6 +47,7 @@ const icons = <String, int>{
3047
'copywriting': 0x0044,
3148
'blog': 0x0042,
3249
'social': 0x004c,
50+
'all': 0x004e
3351
};
3452

3553
// Vote wieghts for Utopian vote based on Category

0 commit comments

Comments
 (0)