feat: add notification page

This commit is contained in:
Rongjian Zhang 2019-01-22 23:39:44 +08:00
parent 263913f60b
commit a051a54549
9 changed files with 242 additions and 68 deletions

View File

@ -69,8 +69,8 @@ class _HomePageState extends State<HomePage> {
if (index >= events.length) {
// print(events.length);
if (!isLoading) {
print('index: $index');
print('length: ${events.length}');
// print('index: $index');
// print('length: ${events.length}');
loadMore();
}
return Text('Loading...');

View File

@ -9,21 +9,20 @@ import '../components/event.dart';
// import 'user.dart';
import '../models/event.dart';
class IosHomeTab extends StatefulWidget {
class HomeScreen extends StatefulWidget {
@override
createState() {
return IosHomeTabState();
return HomeScreenState();
}
}
class IosHomeTabState extends State<IosHomeTab> {
class HomeScreenState extends State<HomeScreen> {
int page = 1;
List<Event> events = [];
loadFirst() async {
events = await fetchEvents();
print(events);
page = 1;
// print(events);
return events;
}
@ -58,7 +57,7 @@ class IosHomeTabState extends State<IosHomeTab> {
// },
// );
widget = ListView.builder(itemBuilder: (context, index) {
print(index);
// print(index);
try {
return EventItem(events[index]);
} catch (err) {

View File

@ -3,7 +3,6 @@ import 'package:flutter/material.dart';
import 'home.dart';
import 'notification.dart';
import 'profile.dart';
import 'issue.dart';
class IosHomePage extends StatefulWidget {
IosHomePage({Key key, this.title}) : super(key: key);
@ -15,58 +14,44 @@ class IosHomePage extends StatefulWidget {
}
class _IosHomePageState extends State<IosHomePage> {
// int _counter = 0;
// void _incrementCounter() {
// setState(() {
// _counter++;
// });
// }
@override
Widget build(context) {
return CupertinoPageScaffold(
child: CupertinoTabScaffold(
tabBar: CupertinoTabBar(
items: <BottomNavigationBarItem>[
items: [
BottomNavigationBarItem(
icon: Icon(CupertinoIcons.home),
icon: Icon(Icons.home),
title: Text('Home'),
),
BottomNavigationBarItem(
icon: Icon(CupertinoIcons.conversation_bubble),
icon: Icon(Icons.notifications),
title: Text('Notification'),
),
BottomNavigationBarItem(
icon: Icon(CupertinoIcons.profile_circled),
title: Text('Profile'),
icon: Icon(Icons.search),
title: Text('Search'),
),
BottomNavigationBarItem(
icon: Icon(Icons.person),
title: Text('Me'),
),
],
),
tabBuilder: (context, index) {
return DefaultTextStyle(
style: TextStyle(
// fontFamily: '.SF UI Text',
// fontSize: 17.0,
color: CupertinoColors.black,
),
child: CupertinoTabView(
builder: (BuildContext context) {
switch (index) {
case 0:
return IosHomeTab();
break;
case 1:
return IosNotificationTab();
break;
case 2:
return IosProfileTab();
break;
default:
}
},
),
);
return CupertinoTabView(builder: (context) {
switch (index) {
case 0:
return HomeScreen();
case 1:
return NotificationScreen();
case 2:
return ProfileScreen();
case 3:
return ProfileScreen();
default:
}
});
},
),
);

View File

@ -1,11 +1,73 @@
// import 'dart:async';
// import 'dart:convert';
// import '../utils.dart';
import 'dart:async';
import '../utils.dart';
import 'package:flutter/cupertino.dart';
import '../models/notification.dart';
class NotificationScreen extends StatefulWidget {
@override
NotificationScreenState createState() => NotificationScreenState();
}
class NotificationScreenState extends State<NotificationScreen> {
int tabIndex = 0;
bool loading = false;
List<NotificationItem> items = [];
initState() {
super.initState();
initFetch();
}
initFetch() async {
items = await fetchNotifications('all');
setState(() {});
}
@override
void dispose() {
// TODO: implement dispose
super.dispose();
print('dispose');
}
_onChange(int value) async {
setState(() {
loading = true;
tabIndex = value;
});
items = await fetchNotifications('all');
setState(() {
loading = false;
});
}
class IosNotificationTab extends StatelessWidget {
@override
Widget build(context) {
return Text('Notification');
return SafeArea(
child: Column(
children: <Widget>[
CupertinoSegmentedControl(
groupValue: tabIndex,
onValueChanged: _onChange,
children: {
0: Text('Unread'),
1: Text('Paticipating'),
2: Text('All')
},
),
Flexible(
child: loading
? CupertinoActivityIndicator()
: ListView.builder(
itemCount: items.length,
itemBuilder: (context, index) => RichText(
text: TextSpan(
text: items[index].id,
style: TextStyle(color: CupertinoColors.black)),
)),
)
],
),
);
}
}

View File

@ -3,9 +3,9 @@
// import '../utils.dart';
import 'package:flutter/cupertino.dart';
class IosProfileTab extends StatelessWidget {
class ProfileScreen extends StatelessWidget {
@override
Widget build(context) {
return Text('Profile');
return Text('Profile');
}
}

View File

@ -1,7 +1,8 @@
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
// import 'dart:io';
// import 'package:graphql_flutter/graphql_flutter.dart';
import 'android/main.dart';
// import 'android/main.dart';
import 'ios/main.dart';
// import 'token.dart';
@ -25,9 +26,10 @@ class App extends StatelessWidget {
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: isIos
? IosHomePage(title: 'GitFlux')
: AndroidHomePage(title: 'GitFlux'),
home: DefaultTextStyle(
style: TextStyle(color: CupertinoColors.black),
child: IosHomePage(title: 'GitFlux'),
),
routes: {
// '/notification': (context) => IosNotificationTab(),
// '/profile': (context) => IosProfileTab(),

View File

@ -0,0 +1,54 @@
import 'package:json_annotation/json_annotation.dart';
part 'notification.g.dart';
@JsonSerializable()
class Subject {
Subject(this.title, this.type);
String title;
String type;
factory Subject.fromJson(Map<String, dynamic> json) =>
_$SubjectFromJson(json);
Map<String, dynamic> toJson() => _$SubjectToJson(this);
}
@JsonSerializable()
class Owner {
Owner(this.login, this.avatarUrl);
String login;
String avatarUrl;
factory Owner.fromJson(Map<String, dynamic> json) => _$OwnerFromJson(json);
Map<String, dynamic> toJson() => _$OwnerToJson(this);
}
@JsonSerializable()
class Repository {
Repository(this.fullName, this.type, this.onwer);
String fullName;
String type;
Owner onwer;
factory Repository.fromJson(Map<String, dynamic> json) =>
_$RepositoryFromJson(json);
Map<String, dynamic> toJson() => _$RepositoryToJson(this);
}
@JsonSerializable()
class NotificationItem {
NotificationItem(this.id, this.type, this.actor, this.repository);
String id;
String type;
Subject actor;
Repository repository;
Map<String, dynamic> payload;
factory NotificationItem.fromJson(Map<String, dynamic> json) =>
_$NotificationItemFromJson(json);
Map<String, dynamic> toJson() => _$NotificationItemToJson(this);
}

View File

@ -0,0 +1,61 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'notification.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
Subject _$SubjectFromJson(Map<String, dynamic> json) {
return Subject(json['title'] as String, json['type'] as String);
}
Map<String, dynamic> _$SubjectToJson(Subject instance) =>
<String, dynamic>{'title': instance.title, 'type': instance.type};
Owner _$OwnerFromJson(Map<String, dynamic> json) {
return Owner(json['login'] as String, json['avatar_url'] as String);
}
Map<String, dynamic> _$OwnerToJson(Owner instance) => <String, dynamic>{
'login': instance.login,
'avatar_url': instance.avatarUrl
};
Repository _$RepositoryFromJson(Map<String, dynamic> json) {
return Repository(
json['full_name'] as String,
json['type'] as String,
json['onwer'] == null
? null
: Owner.fromJson(json['onwer'] as Map<String, dynamic>));
}
Map<String, dynamic> _$RepositoryToJson(Repository instance) =>
<String, dynamic>{
'full_name': instance.fullName,
'type': instance.type,
'onwer': instance.onwer
};
NotificationItem _$NotificationItemFromJson(Map<String, dynamic> json) {
return NotificationItem(
json['id'] as String,
json['type'] 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>))
..payload = json['payload'] as Map<String, dynamic>;
}
Map<String, dynamic> _$NotificationItemToJson(NotificationItem instance) =>
<String, dynamic>{
'id': instance.id,
'type': instance.type,
'actor': instance.actor,
'repository': instance.repository,
'payload': instance.payload
};

View File

@ -5,29 +5,40 @@ import 'package:http/http.dart' as http;
import 'token.dart';
import 'models/event.dart';
import 'models/user.dart';
import 'models/notification.dart';
final prefix = 'https://api.github.com';
Future<List<Event>> fetchEvents([int page = 1]) async {
Future<dynamic> getWithCredentials(String url) async {
final res = await http.get(
prefix + '/users/pd4d10/received_events/public?page=$page',
prefix + url,
headers: {HttpHeaders.authorizationHeader: 'token $token'},
);
final data = json.decode(res.body);
// if (res.body.startsWith('{')) {
// throw data['message'];
// }
return data;
}
print(res.body);
List<dynamic> data = json.decode(res.body);
return data.map((item) {
Future<List<Event>> fetchEvents([int page = 1]) async {
List data = await getWithCredentials(
'/users/pd4d10/received_events/public?page=$page',
);
return data.map<Event>((item) {
return Event.fromJson(item);
}).toList();
}
Future<User> fetchUser(String login) async {
final res = await http.get(
prefix + '/users/$login',
headers: {HttpHeaders.authorizationHeader: 'token $token'},
);
Map<String, dynamic> data = json.decode(res.body);
Map<String, dynamic> data = await getWithCredentials('/users/$login');
return User.fromJson(data);
}
Future<List<NotificationItem>> fetchNotifications(String type) async {
List data = await getWithCredentials('/notifications?$type=true');
print(data);
return data
.map<NotificationItem>((item) => NotificationItem.fromJson(item))
.toList();
}