feat: notification screen
This commit is contained in:
parent
3c83804b3d
commit
9043322201
|
@ -26,11 +26,12 @@ class HomeScreenState extends State<HomeScreen> {
|
|||
|
||||
@override
|
||||
Widget build(context) {
|
||||
// Navigator.of(context).pushNamed('/user');
|
||||
final eventBloc = EventProvider.of(context);
|
||||
|
||||
return CupertinoPageScaffold(
|
||||
navigationBar: CupertinoNavigationBar(
|
||||
middle: Text('Home'),
|
||||
middle: Text("GitFlux"),
|
||||
),
|
||||
child: StreamBuilder<List<Event>>(
|
||||
stream: eventBloc.events,
|
||||
|
|
|
@ -17,7 +17,11 @@ class IosHomePage extends StatefulWidget {
|
|||
class _IosHomePageState extends State<IosHomePage> {
|
||||
@override
|
||||
Widget build(context) {
|
||||
return CupertinoPageScaffold(
|
||||
return CupertinoTheme(
|
||||
data: CupertinoThemeData(
|
||||
// brightness: Brightness.dark,
|
||||
// barBackgroundColor: Color.fromRGBO(0x24, 0x29, 0x2e, 1),
|
||||
),
|
||||
child: CupertinoTabScaffold(
|
||||
tabBar: CupertinoTabBar(
|
||||
items: [
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import '../models/notification.dart';
|
||||
import '../providers/notification.dart';
|
||||
import 'package:git_flux/screens/repo.dart';
|
||||
|
||||
class NotificationScreen extends StatefulWidget {
|
||||
@override
|
||||
|
@ -13,69 +15,115 @@ class NotificationScreenState extends State<NotificationScreen> {
|
|||
// initFetch();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
super.dispose();
|
||||
print('dispose');
|
||||
Widget _buildItem(BuildContext context, NotificationItem item) {
|
||||
return GestureDetector(
|
||||
onTap: () {
|
||||
Navigator.of(context).push(CupertinoPageRoute(
|
||||
title: 'test', builder: (context) => RepoScreen()));
|
||||
},
|
||||
child: Container(
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
Icon(Icons.info_outline),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Text(item.subject.title),
|
||||
Text(item.updatedAt)
|
||||
],
|
||||
),
|
||||
),
|
||||
Icon(Icons.arrow_forward_ios)
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildGroupItem(NotificationGroup group) {
|
||||
return Container(
|
||||
padding: EdgeInsets.all(10),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: <Widget>[
|
||||
Container(
|
||||
color: CupertinoColors.extraLightBackgroundGray,
|
||||
child: Text(
|
||||
group.fullName,
|
||||
style: TextStyle(color: CupertinoColors.black),
|
||||
),
|
||||
),
|
||||
ListView.builder(
|
||||
shrinkWrap: true,
|
||||
itemCount: group.items.length,
|
||||
itemBuilder: (context, index) =>
|
||||
_buildItem(context, group.items[index]),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(context) {
|
||||
NotificationBloc bloc = NotificationProvider.of(context);
|
||||
TextStyle _textStyle = DefaultTextStyle.of(context).style;
|
||||
|
||||
return SafeArea(
|
||||
return CupertinoPageScaffold(
|
||||
navigationBar: CupertinoNavigationBar(
|
||||
middle: StreamBuilder<int>(
|
||||
stream: bloc.active,
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.data == null) {
|
||||
return Text("loading...");
|
||||
}
|
||||
return SizedBox.expand(
|
||||
child: DefaultTextStyle(
|
||||
style: _textStyle,
|
||||
child: CupertinoSegmentedControl(
|
||||
groupValue: snapshot.data,
|
||||
onValueChanged: (int index) {
|
||||
bloc.activeUpdate.add(index);
|
||||
},
|
||||
children: {
|
||||
0: Text('Unread'),
|
||||
1: Text('Paticipating'),
|
||||
2: Text('All')
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
StreamBuilder<int>(
|
||||
stream: bloc.active,
|
||||
StreamBuilder<bool>(
|
||||
stream: bloc.loading,
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.data == null) {
|
||||
return Text("loading...");
|
||||
}
|
||||
return Flexible(
|
||||
child: snapshot.data == null || snapshot.data
|
||||
? CupertinoActivityIndicator()
|
||||
: StreamBuilder<List<NotificationGroup>>(
|
||||
stream: bloc.items,
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.data == null) {
|
||||
return Text('loading...');
|
||||
}
|
||||
|
||||
return CupertinoSegmentedControl(
|
||||
groupValue: snapshot.data,
|
||||
onValueChanged: (int index) {
|
||||
bloc.activeUpdate.add(index);
|
||||
},
|
||||
children: {
|
||||
0: Text('Unread'),
|
||||
1: Text('Paticipating'),
|
||||
2: Text('All')
|
||||
},
|
||||
List<NotificationGroup> groups = snapshot.data;
|
||||
|
||||
return ListView.builder(
|
||||
itemCount: groups.length,
|
||||
itemBuilder: (context, i) =>
|
||||
_buildGroupItem(groups[i]),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
StreamBuilder<bool>(
|
||||
stream: bloc.loading,
|
||||
builder: (context, snapshot) {
|
||||
return Flexible(
|
||||
child: snapshot.data == null || snapshot.data
|
||||
? CupertinoActivityIndicator()
|
||||
: StreamBuilder<List<NotificationItem>>(
|
||||
stream: bloc.items,
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.data == null) {
|
||||
return Text('loading...');
|
||||
}
|
||||
|
||||
return ListView.builder(
|
||||
itemCount: snapshot.data.length,
|
||||
itemBuilder: (context, index) {
|
||||
return RichText(
|
||||
text: TextSpan(
|
||||
text: snapshot
|
||||
.data[index].repository.fullName,
|
||||
style:
|
||||
TextStyle(color: CupertinoColors.black),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
|
|
@ -4,6 +4,6 @@ import '../widgets/user.dart';
|
|||
class ProfileScreen extends StatelessWidget {
|
||||
@override
|
||||
Widget build(context) {
|
||||
return UserScreen('pd4d10');
|
||||
return UserWidget('pd4d10');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
// import 'package:uri/uri.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'ios/main.dart';
|
||||
import 'providers/event.dart';
|
||||
import 'providers/notification.dart';
|
||||
import 'providers/search.dart';
|
||||
import 'package:git_flux/providers/event.dart';
|
||||
import 'package:git_flux/providers/notification.dart';
|
||||
import 'package:git_flux/providers/search.dart';
|
||||
import 'package:git_flux/ios/main.dart';
|
||||
// import 'package:git_flux/screens/user.dart';
|
||||
// import 'package:git_flux/screens/repo.dart';
|
||||
|
||||
class App extends StatelessWidget {
|
||||
final isIos = true;
|
||||
|
@ -22,18 +25,15 @@ class App extends StatelessWidget {
|
|||
child: EventProvider(
|
||||
bloc: eventBloc,
|
||||
child: MaterialApp(
|
||||
title: 'GitFlux',
|
||||
theme: ThemeData(
|
||||
primarySwatch: Colors.blue,
|
||||
),
|
||||
home: DefaultTextStyle(
|
||||
style: TextStyle(color: CupertinoColors.black),
|
||||
child: IosHomePage(title: 'GitFlux'),
|
||||
),
|
||||
routes: {
|
||||
// '/notification': (context) => IosNotificationTab(),
|
||||
// '/profile': (context) => IosProfileTab(),
|
||||
},
|
||||
// theme: ThemeData(
|
||||
// textTheme: TextTheme(
|
||||
// title: TextStyle(color: Colors.red),
|
||||
// ),
|
||||
// ),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
|
|
@ -40,12 +40,15 @@ class Repository {
|
|||
|
||||
@JsonSerializable()
|
||||
class NotificationItem {
|
||||
NotificationItem(this.id, this.type, this.actor, this.repository);
|
||||
NotificationItem(this.id, this.type, this.updatedAt, this.actor,
|
||||
this.repository, this.subject);
|
||||
|
||||
String id;
|
||||
String type;
|
||||
String updatedAt;
|
||||
Subject actor;
|
||||
Repository repository;
|
||||
Subject subject;
|
||||
Map<String, dynamic> payload;
|
||||
|
||||
factory NotificationItem.fromJson(Map<String, dynamic> json) =>
|
||||
|
|
|
@ -42,12 +42,16 @@ NotificationItem _$NotificationItemFromJson(Map<String, dynamic> json) {
|
|||
return NotificationItem(
|
||||
json['id'] as String,
|
||||
json['type'] as String,
|
||||
json['updated_at'] as String,
|
||||
json['actor'] == null
|
||||
? null
|
||||
: Subject.fromJson(json['actor'] as Map<String, dynamic>),
|
||||
json['repository'] == null
|
||||
? null
|
||||
: Repository.fromJson(json['repository'] as Map<String, dynamic>))
|
||||
: Repository.fromJson(json['repository'] as Map<String, dynamic>),
|
||||
json['subject'] == null
|
||||
? null
|
||||
: Subject.fromJson(json['subject'] as Map<String, dynamic>))
|
||||
..payload = json['payload'] as Map<String, dynamic>;
|
||||
}
|
||||
|
||||
|
@ -55,7 +59,9 @@ Map<String, dynamic> _$NotificationItemToJson(NotificationItem instance) =>
|
|||
<String, dynamic>{
|
||||
'id': instance.id,
|
||||
'type': instance.type,
|
||||
'updated_at': instance.updatedAt,
|
||||
'actor': instance.actor,
|
||||
'repository': instance.repository,
|
||||
'subject': instance.subject,
|
||||
'payload': instance.payload
|
||||
};
|
||||
|
|
|
@ -4,7 +4,14 @@ import 'package:rxdart/rxdart.dart';
|
|||
import '../utils.dart';
|
||||
import '../models/notification.dart';
|
||||
|
||||
Future<List<NotificationItem>> fetchNotifications([int index = 0]) async {
|
||||
class NotificationGroup {
|
||||
String fullName;
|
||||
List<NotificationItem> items = [];
|
||||
|
||||
NotificationGroup(this.fullName);
|
||||
}
|
||||
|
||||
Future<List<NotificationGroup>> fetchNotifications([int index = 0]) async {
|
||||
String search = '';
|
||||
if (index == 1) {
|
||||
search = '?paticipating=true';
|
||||
|
@ -12,18 +19,24 @@ Future<List<NotificationItem>> fetchNotifications([int index = 0]) async {
|
|||
search = '?all=true';
|
||||
}
|
||||
List data = await getWithCredentials('/notifications$search');
|
||||
// print(data.length);
|
||||
return data
|
||||
.map<NotificationItem>((item) => NotificationItem.fromJson(item))
|
||||
.toList();
|
||||
Map<String, NotificationGroup> groupMap = {};
|
||||
data.forEach((item) {
|
||||
String repo = item['repository']['full_name'];
|
||||
if (groupMap[repo] == null) {
|
||||
groupMap[repo] = NotificationGroup(repo);
|
||||
}
|
||||
|
||||
groupMap[repo].items.add(NotificationItem.fromJson(item));
|
||||
});
|
||||
return groupMap.values.toList();
|
||||
}
|
||||
|
||||
class NotificationBloc {
|
||||
final _items = BehaviorSubject<List<NotificationItem>>(seedValue: []);
|
||||
final _groups = BehaviorSubject<List<NotificationGroup>>(seedValue: []);
|
||||
final _active = BehaviorSubject(seedValue: 0);
|
||||
final _loading = BehaviorSubject(seedValue: false);
|
||||
|
||||
Stream<List<NotificationItem>> get items => _items.stream;
|
||||
Stream<List<NotificationGroup>> get items => _groups.stream;
|
||||
Stream<int> get active => _active.stream;
|
||||
Stream<bool> get loading => _loading.stream;
|
||||
|
||||
|
@ -32,7 +45,7 @@ class NotificationBloc {
|
|||
NotificationBloc() {
|
||||
_active.stream.listen((int index) async {
|
||||
_loading.add(true);
|
||||
_items.add(await fetchNotifications(index));
|
||||
_groups.add(await fetchNotifications(index));
|
||||
_loading.add(false);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
import 'package:flutter/cupertino.dart';
|
||||
|
||||
class RepoScreen extends StatelessWidget {
|
||||
@override
|
||||
Widget build(context) {
|
||||
return CupertinoPageScaffold(
|
||||
navigationBar: CupertinoNavigationBar(
|
||||
middle: Text("repo"),
|
||||
),
|
||||
child: Text("repo"),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
import 'package:flutter/cupertino.dart';
|
||||
import '../widgets/user.dart';
|
||||
|
||||
class UserScreen extends StatelessWidget {
|
||||
@override
|
||||
Widget build(context) {
|
||||
return UserWidget('pd4d10');
|
||||
}
|
||||
}
|
|
@ -32,15 +32,15 @@ Future queryUser(String login) async {
|
|||
final GlobalKey<RefreshIndicatorState> _refreshIndicatorKey =
|
||||
new GlobalKey<RefreshIndicatorState>();
|
||||
|
||||
class UserScreen extends StatefulWidget {
|
||||
class UserWidget extends StatefulWidget {
|
||||
final String login;
|
||||
|
||||
UserScreen(this.login);
|
||||
UserWidget(this.login);
|
||||
|
||||
_UserScreenState createState() => _UserScreenState();
|
||||
_UserWidgetState createState() => _UserWidgetState();
|
||||
}
|
||||
|
||||
class _UserScreenState extends State<UserScreen> {
|
||||
class _UserWidgetState extends State<UserWidget> {
|
||||
var user = null;
|
||||
|
||||
@override
|
||||
|
@ -57,50 +57,51 @@ class _UserScreenState extends State<UserScreen> {
|
|||
Widget build(BuildContext context) {
|
||||
return SafeArea(
|
||||
child: RefreshIndicator(
|
||||
key: _refreshIndicatorKey,
|
||||
onRefresh: () async {
|
||||
var _user = await queryUser(widget.login);
|
||||
setState(() {
|
||||
user = _user;
|
||||
});
|
||||
},
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
Container(
|
||||
margin: EdgeInsets.symmetric(vertical: 20.0),
|
||||
child: ClipOval(
|
||||
child: Image.network(
|
||||
user['avatarUrl'],
|
||||
fit: BoxFit.fill,
|
||||
width: 64,
|
||||
height: 64,
|
||||
),
|
||||
key: _refreshIndicatorKey,
|
||||
onRefresh: () async {
|
||||
var _user = await queryUser(widget.login);
|
||||
setState(() {
|
||||
user = _user;
|
||||
});
|
||||
},
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
Container(
|
||||
margin: EdgeInsets.symmetric(vertical: 20.0),
|
||||
child: ClipOval(
|
||||
child: Image.network(
|
||||
user['avatarUrl'],
|
||||
fit: BoxFit.fill,
|
||||
width: 64,
|
||||
height: 64,
|
||||
),
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: <Widget>[
|
||||
GestureDetector(
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
Text(user['followers']['totalCount'].toString()),
|
||||
Text('Followers'),
|
||||
],
|
||||
),
|
||||
onTap: () {
|
||||
// print(1);
|
||||
},
|
||||
),
|
||||
Column(
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: <Widget>[
|
||||
GestureDetector(
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
Text(user['following']['totalCount'].toString()),
|
||||
Text('Following')
|
||||
Text(user['followers']['totalCount'].toString()),
|
||||
Text('Followers'),
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
],
|
||||
)),
|
||||
),
|
||||
onTap: () {
|
||||
// print(1);
|
||||
},
|
||||
),
|
||||
Column(
|
||||
children: <Widget>[
|
||||
Text(user['following']['totalCount'].toString()),
|
||||
Text('Following')
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ dependencies:
|
|||
cupertino_icons: ^0.1.2
|
||||
http: ^0.11.3
|
||||
rxdart: ^0.20.0
|
||||
uri: ^0.11.3
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
|
|
Loading…
Reference in New Issue