mirror of
https://github.com/git-touch/git-touch
synced 2025-03-06 12:17:50 +01:00
feat: add notification page
This commit is contained in:
parent
263913f60b
commit
a051a54549
@ -69,8 +69,8 @@ class _HomePageState extends State<HomePage> {
|
|||||||
if (index >= events.length) {
|
if (index >= events.length) {
|
||||||
// print(events.length);
|
// print(events.length);
|
||||||
if (!isLoading) {
|
if (!isLoading) {
|
||||||
print('index: $index');
|
// print('index: $index');
|
||||||
print('length: ${events.length}');
|
// print('length: ${events.length}');
|
||||||
loadMore();
|
loadMore();
|
||||||
}
|
}
|
||||||
return Text('Loading...');
|
return Text('Loading...');
|
||||||
|
@ -9,21 +9,20 @@ import '../components/event.dart';
|
|||||||
// import 'user.dart';
|
// import 'user.dart';
|
||||||
import '../models/event.dart';
|
import '../models/event.dart';
|
||||||
|
|
||||||
class IosHomeTab extends StatefulWidget {
|
class HomeScreen extends StatefulWidget {
|
||||||
@override
|
@override
|
||||||
createState() {
|
createState() {
|
||||||
return IosHomeTabState();
|
return HomeScreenState();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class IosHomeTabState extends State<IosHomeTab> {
|
class HomeScreenState extends State<HomeScreen> {
|
||||||
int page = 1;
|
int page = 1;
|
||||||
List<Event> events = [];
|
List<Event> events = [];
|
||||||
|
|
||||||
loadFirst() async {
|
loadFirst() async {
|
||||||
events = await fetchEvents();
|
events = await fetchEvents();
|
||||||
print(events);
|
// print(events);
|
||||||
page = 1;
|
|
||||||
return events;
|
return events;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -58,7 +57,7 @@ class IosHomeTabState extends State<IosHomeTab> {
|
|||||||
// },
|
// },
|
||||||
// );
|
// );
|
||||||
widget = ListView.builder(itemBuilder: (context, index) {
|
widget = ListView.builder(itemBuilder: (context, index) {
|
||||||
print(index);
|
// print(index);
|
||||||
try {
|
try {
|
||||||
return EventItem(events[index]);
|
return EventItem(events[index]);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
@ -3,7 +3,6 @@ import 'package:flutter/material.dart';
|
|||||||
import 'home.dart';
|
import 'home.dart';
|
||||||
import 'notification.dart';
|
import 'notification.dart';
|
||||||
import 'profile.dart';
|
import 'profile.dart';
|
||||||
import 'issue.dart';
|
|
||||||
|
|
||||||
class IosHomePage extends StatefulWidget {
|
class IosHomePage extends StatefulWidget {
|
||||||
IosHomePage({Key key, this.title}) : super(key: key);
|
IosHomePage({Key key, this.title}) : super(key: key);
|
||||||
@ -15,58 +14,44 @@ class IosHomePage extends StatefulWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _IosHomePageState extends State<IosHomePage> {
|
class _IosHomePageState extends State<IosHomePage> {
|
||||||
// int _counter = 0;
|
|
||||||
|
|
||||||
// void _incrementCounter() {
|
|
||||||
// setState(() {
|
|
||||||
// _counter++;
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(context) {
|
Widget build(context) {
|
||||||
return CupertinoPageScaffold(
|
return CupertinoPageScaffold(
|
||||||
child: CupertinoTabScaffold(
|
child: CupertinoTabScaffold(
|
||||||
tabBar: CupertinoTabBar(
|
tabBar: CupertinoTabBar(
|
||||||
items: <BottomNavigationBarItem>[
|
items: [
|
||||||
BottomNavigationBarItem(
|
BottomNavigationBarItem(
|
||||||
icon: Icon(CupertinoIcons.home),
|
icon: Icon(Icons.home),
|
||||||
title: Text('Home'),
|
title: Text('Home'),
|
||||||
),
|
),
|
||||||
BottomNavigationBarItem(
|
BottomNavigationBarItem(
|
||||||
icon: Icon(CupertinoIcons.conversation_bubble),
|
icon: Icon(Icons.notifications),
|
||||||
title: Text('Notification'),
|
title: Text('Notification'),
|
||||||
),
|
),
|
||||||
BottomNavigationBarItem(
|
BottomNavigationBarItem(
|
||||||
icon: Icon(CupertinoIcons.profile_circled),
|
icon: Icon(Icons.search),
|
||||||
title: Text('Profile'),
|
title: Text('Search'),
|
||||||
|
),
|
||||||
|
BottomNavigationBarItem(
|
||||||
|
icon: Icon(Icons.person),
|
||||||
|
title: Text('Me'),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
tabBuilder: (context, index) {
|
tabBuilder: (context, index) {
|
||||||
return DefaultTextStyle(
|
return CupertinoTabView(builder: (context) {
|
||||||
style: TextStyle(
|
switch (index) {
|
||||||
// fontFamily: '.SF UI Text',
|
case 0:
|
||||||
// fontSize: 17.0,
|
return HomeScreen();
|
||||||
color: CupertinoColors.black,
|
case 1:
|
||||||
),
|
return NotificationScreen();
|
||||||
child: CupertinoTabView(
|
case 2:
|
||||||
builder: (BuildContext context) {
|
return ProfileScreen();
|
||||||
switch (index) {
|
case 3:
|
||||||
case 0:
|
return ProfileScreen();
|
||||||
return IosHomeTab();
|
default:
|
||||||
break;
|
}
|
||||||
case 1:
|
});
|
||||||
return IosNotificationTab();
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
return IosProfileTab();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
},
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -1,11 +1,73 @@
|
|||||||
// import 'dart:async';
|
import 'dart:async';
|
||||||
// import 'dart:convert';
|
import '../utils.dart';
|
||||||
// import '../utils.dart';
|
|
||||||
import 'package:flutter/cupertino.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
|
@override
|
||||||
Widget build(context) {
|
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)),
|
||||||
|
)),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,9 +3,9 @@
|
|||||||
// import '../utils.dart';
|
// import '../utils.dart';
|
||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
|
|
||||||
class IosProfileTab extends StatelessWidget {
|
class ProfileScreen extends StatelessWidget {
|
||||||
@override
|
@override
|
||||||
Widget build(context) {
|
Widget build(context) {
|
||||||
return Text('Profile');
|
return Text('Profile');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
// import 'dart:io';
|
// import 'dart:io';
|
||||||
// import 'package:graphql_flutter/graphql_flutter.dart';
|
// import 'package:graphql_flutter/graphql_flutter.dart';
|
||||||
import 'android/main.dart';
|
// import 'android/main.dart';
|
||||||
import 'ios/main.dart';
|
import 'ios/main.dart';
|
||||||
// import 'token.dart';
|
// import 'token.dart';
|
||||||
|
|
||||||
@ -25,9 +26,10 @@ class App extends StatelessWidget {
|
|||||||
theme: ThemeData(
|
theme: ThemeData(
|
||||||
primarySwatch: Colors.blue,
|
primarySwatch: Colors.blue,
|
||||||
),
|
),
|
||||||
home: isIos
|
home: DefaultTextStyle(
|
||||||
? IosHomePage(title: 'GitFlux')
|
style: TextStyle(color: CupertinoColors.black),
|
||||||
: AndroidHomePage(title: 'GitFlux'),
|
child: IosHomePage(title: 'GitFlux'),
|
||||||
|
),
|
||||||
routes: {
|
routes: {
|
||||||
// '/notification': (context) => IosNotificationTab(),
|
// '/notification': (context) => IosNotificationTab(),
|
||||||
// '/profile': (context) => IosProfileTab(),
|
// '/profile': (context) => IosProfileTab(),
|
||||||
|
54
lib/models/notification.dart
Normal file
54
lib/models/notification.dart
Normal 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);
|
||||||
|
}
|
61
lib/models/notification.g.dart
Normal file
61
lib/models/notification.g.dart
Normal 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
|
||||||
|
};
|
@ -5,29 +5,40 @@ import 'package:http/http.dart' as http;
|
|||||||
import 'token.dart';
|
import 'token.dart';
|
||||||
import 'models/event.dart';
|
import 'models/event.dart';
|
||||||
import 'models/user.dart';
|
import 'models/user.dart';
|
||||||
|
import 'models/notification.dart';
|
||||||
|
|
||||||
final prefix = 'https://api.github.com';
|
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(
|
final res = await http.get(
|
||||||
prefix + '/users/pd4d10/received_events/public?page=$page',
|
prefix + url,
|
||||||
headers: {HttpHeaders.authorizationHeader: 'token $token'},
|
headers: {HttpHeaders.authorizationHeader: 'token $token'},
|
||||||
);
|
);
|
||||||
|
final data = json.decode(res.body);
|
||||||
|
// if (res.body.startsWith('{')) {
|
||||||
|
// throw data['message'];
|
||||||
|
// }
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
print(res.body);
|
Future<List<Event>> fetchEvents([int page = 1]) async {
|
||||||
List<dynamic> data = json.decode(res.body);
|
List data = await getWithCredentials(
|
||||||
|
'/users/pd4d10/received_events/public?page=$page',
|
||||||
return data.map((item) {
|
);
|
||||||
|
return data.map<Event>((item) {
|
||||||
return Event.fromJson(item);
|
return Event.fromJson(item);
|
||||||
}).toList();
|
}).toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<User> fetchUser(String login) async {
|
Future<User> fetchUser(String login) async {
|
||||||
final res = await http.get(
|
Map<String, dynamic> data = await getWithCredentials('/users/$login');
|
||||||
prefix + '/users/$login',
|
|
||||||
headers: {HttpHeaders.authorizationHeader: 'token $token'},
|
|
||||||
);
|
|
||||||
Map<String, dynamic> data = json.decode(res.body);
|
|
||||||
|
|
||||||
return User.fromJson(data);
|
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();
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user