mirror of
https://github.com/git-touch/git-touch
synced 2025-01-31 08:04:51 +01:00
feat: notification filters
This commit is contained in:
parent
fb9fd4cb3a
commit
e16d6c2468
@ -20,32 +20,16 @@ class _HomeState extends State<Home> {
|
||||
return Icon(Icons.notifications);
|
||||
}
|
||||
|
||||
String text = count > 99 ? '99+' : count.toString();
|
||||
// String text = count > 99 ? '99+' : count.toString();
|
||||
|
||||
// https://stackoverflow.com/a/54094844
|
||||
return Stack(children: <Widget>[
|
||||
Icon(Icons.notifications),
|
||||
Positioned(
|
||||
right: 0,
|
||||
child: new Container(
|
||||
padding: EdgeInsets.all(1),
|
||||
decoration: new BoxDecoration(
|
||||
color: Colors.red,
|
||||
borderRadius: BorderRadius.circular(6),
|
||||
),
|
||||
constraints: BoxConstraints(
|
||||
minWidth: 12,
|
||||
minHeight: 12,
|
||||
),
|
||||
child: new Text(
|
||||
'$text',
|
||||
style: new TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 8,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
// https://stackoverflow.com/a/45434404
|
||||
return new Stack(children: <Widget>[
|
||||
new Icon(Icons.notifications),
|
||||
new Positioned(
|
||||
// draw a red marble
|
||||
top: 0.0,
|
||||
right: 0.0,
|
||||
child: new Icon(Icons.brightness_1, size: 8.0, color: Colors.redAccent),
|
||||
)
|
||||
]);
|
||||
}
|
||||
|
@ -76,9 +76,11 @@ class _IssueScreenState extends State<IssueScreen> {
|
||||
itemBuilder: (context, index) => TimelineItem(_items[index], payload),
|
||||
onRefresh: () async {
|
||||
var _payload = await queryIssue(widget.id, widget.owner, widget.name);
|
||||
setState(() {
|
||||
payload = _payload;
|
||||
});
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
payload = _payload;
|
||||
});
|
||||
}
|
||||
},
|
||||
// onLoadMore: () => ,
|
||||
);
|
||||
|
@ -16,11 +16,15 @@ String getItemKey(NotificationPayload item) {
|
||||
}
|
||||
|
||||
Future<Map<String, NotificationGroup>> fetchNotifications(
|
||||
[int page = 1]) async {
|
||||
int index, BuildContext context) async {
|
||||
List items = await getWithCredentials(
|
||||
'/notifications?page=$page&all=true&per_page=100');
|
||||
'/notifications?all=${index == 2}&participating=${index == 1}');
|
||||
var ns = items.map((item) => NotificationPayload.fromJson(item)).toList();
|
||||
|
||||
if (index == 0) {
|
||||
NotificationProvider.of(context).setCount(ns.length);
|
||||
}
|
||||
|
||||
Map<String, NotificationGroup> _groupMap = {};
|
||||
|
||||
ns.forEach((item) {
|
||||
@ -97,7 +101,14 @@ class NotificationScreenState extends State<NotificationScreen> {
|
||||
bool loading = false;
|
||||
Map<String, NotificationGroup> groupMap = {};
|
||||
|
||||
Widget _buildGroupItem(String key, NotificationGroup group) {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_refresh();
|
||||
}
|
||||
|
||||
Widget _buildGroupItem(MapEntry<String, NotificationGroup> entry) {
|
||||
var group = entry.value;
|
||||
var repo = group.repo;
|
||||
return ListGroup(
|
||||
title: Row(
|
||||
@ -126,7 +137,7 @@ class NotificationScreenState extends State<NotificationScreen> {
|
||||
payload: item,
|
||||
markAsRead: () {
|
||||
setState(() {
|
||||
groupMap[key].items[index].unread = false;
|
||||
groupMap[entry.key].items[index].unread = false;
|
||||
});
|
||||
},
|
||||
);
|
||||
@ -134,46 +145,79 @@ class NotificationScreenState extends State<NotificationScreen> {
|
||||
}
|
||||
|
||||
Future<void> _onSwitchTab(BuildContext context, int index) async {
|
||||
// setState(() {
|
||||
// active = index;
|
||||
// loading = true;
|
||||
// });
|
||||
|
||||
var _groupMap = await fetchNotifications();
|
||||
|
||||
// NotificationProvider.of(context).setCount(ns.length);
|
||||
|
||||
setState(() {
|
||||
groupMap = _groupMap;
|
||||
// loading = false;
|
||||
active = index;
|
||||
loading = true;
|
||||
});
|
||||
|
||||
var _groupMap = await fetchNotifications(active, context);
|
||||
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
groupMap = _groupMap;
|
||||
loading = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _refresh() async {
|
||||
print('onrefresh');
|
||||
await _onSwitchTab(context, active);
|
||||
}
|
||||
|
||||
var textMap = {
|
||||
0: 'Unread',
|
||||
1: 'Paticipating',
|
||||
2: 'All',
|
||||
};
|
||||
|
||||
// var iconMap = {
|
||||
// 0: Icon(Icons.inbox),
|
||||
// 1: Icon(Icons.group),
|
||||
// 2: Icon(Icons.mail),
|
||||
// };
|
||||
|
||||
@override
|
||||
Widget build(context) {
|
||||
return RefreshScaffold(
|
||||
title: Text('Notifications'),
|
||||
onRefresh: _refresh,
|
||||
bodyBuilder: () {
|
||||
List<Widget> children = [];
|
||||
children.add(CupertinoSegmentedControl(
|
||||
groupValue: active,
|
||||
onValueChanged: (index) => _onSwitchTab(context, index),
|
||||
children: {
|
||||
0: Text('Unread'),
|
||||
1: Text('Paticipating'),
|
||||
2: Text('All')
|
||||
title: Text(textMap[active]),
|
||||
trailing: GestureDetector(
|
||||
child: Icon(Icons.more_vert, size: 20),
|
||||
onTap: () async {
|
||||
int value = await showCupertinoDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return CupertinoAlertDialog(
|
||||
title: Text('Select filter'),
|
||||
actions: textMap.entries.map((entry) {
|
||||
return CupertinoDialogAction(
|
||||
child: Text(entry.value),
|
||||
onPressed: () {
|
||||
Navigator.pop(context, entry.key);
|
||||
},
|
||||
);
|
||||
}).toList(),
|
||||
);
|
||||
},
|
||||
);
|
||||
_onSwitchTab(context, value);
|
||||
},
|
||||
),
|
||||
actions: <Widget>[
|
||||
PopupMenuButton(
|
||||
onSelected: (value) {
|
||||
_onSwitchTab(context, value);
|
||||
},
|
||||
));
|
||||
children.addAll(groupMap.entries
|
||||
.map((entry) => _buildGroupItem(entry.key, entry.value)));
|
||||
|
||||
return Column(children: children);
|
||||
itemBuilder: (context) {
|
||||
return textMap.entries.map((entry) {
|
||||
return PopupMenuItem(value: entry.key, child: Text(entry.value));
|
||||
}).toList();
|
||||
},
|
||||
)
|
||||
],
|
||||
onRefresh: _refresh,
|
||||
loading: loading,
|
||||
bodyBuilder: () {
|
||||
return Column(children: groupMap.entries.map(_buildGroupItem).toList());
|
||||
},
|
||||
);
|
||||
}
|
||||
|
@ -147,9 +147,11 @@ class _PullRequestScreenState extends State<PullRequestScreen> {
|
||||
onRefresh: () async {
|
||||
var _payload =
|
||||
await queryPullRequest(widget.id, widget.owner, widget.name);
|
||||
setState(() {
|
||||
payload = _payload;
|
||||
});
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
payload = _payload;
|
||||
});
|
||||
}
|
||||
},
|
||||
// onLoadMore: () => ,
|
||||
);
|
||||
|
@ -61,9 +61,11 @@ class _ListScaffoldState extends State<ListScaffold> {
|
||||
} catch (err) {
|
||||
print(err);
|
||||
} finally {
|
||||
setState(() {
|
||||
loading = false;
|
||||
});
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
loading = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -109,10 +109,29 @@ class _NotificationItemState extends State<NotificationItem> {
|
||||
);
|
||||
}
|
||||
|
||||
void _markAsRead() async {
|
||||
if (payload.unread && !loading) {
|
||||
setState(() {
|
||||
loading = true;
|
||||
});
|
||||
try {
|
||||
await patchWithCredentials('/notifications/threads/' + payload.id);
|
||||
widget.markAsRead();
|
||||
} finally {
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
loading = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Link(
|
||||
onTap: () {
|
||||
_markAsRead();
|
||||
Navigator.of(context).push(
|
||||
CupertinoPageRoute(builder: (context) => _buildRoute()),
|
||||
);
|
||||
@ -135,22 +154,7 @@ class _NotificationItemState extends State<NotificationItem> {
|
||||
),
|
||||
Link(
|
||||
child: _buildCheckIcon(),
|
||||
onTap: () async {
|
||||
if (payload.unread && !loading) {
|
||||
setState(() {
|
||||
loading = true;
|
||||
});
|
||||
try {
|
||||
await patchWithCredentials(
|
||||
'/notifications/threads/' + payload.id);
|
||||
widget.markAsRead();
|
||||
} finally {
|
||||
setState(() {
|
||||
loading = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
onTap: _markAsRead,
|
||||
),
|
||||
],
|
||||
),
|
||||
|
@ -7,51 +7,28 @@ import 'loading.dart';
|
||||
typedef RefreshCallback = Future<void> Function();
|
||||
typedef WidgetBuilder = Widget Function();
|
||||
|
||||
class RefreshScaffold extends StatefulWidget {
|
||||
class RefreshScaffold extends StatelessWidget {
|
||||
final Widget title;
|
||||
final WidgetBuilder bodyBuilder;
|
||||
final RefreshCallback onRefresh;
|
||||
final bool loading;
|
||||
final Widget trailing;
|
||||
final List<Widget> actions;
|
||||
|
||||
RefreshScaffold({
|
||||
@required this.title,
|
||||
@required this.bodyBuilder,
|
||||
@required this.onRefresh,
|
||||
@required this.loading,
|
||||
this.trailing,
|
||||
this.actions,
|
||||
});
|
||||
|
||||
@override
|
||||
_RefreshScaffoldState createState() => _RefreshScaffoldState();
|
||||
}
|
||||
|
||||
class _RefreshScaffoldState extends State<RefreshScaffold> {
|
||||
bool loading = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_refresh();
|
||||
}
|
||||
|
||||
Future<void> _refresh() async {
|
||||
print('refresh');
|
||||
setState(() {
|
||||
loading = true;
|
||||
});
|
||||
// try {
|
||||
await widget.onRefresh();
|
||||
// } catch (err) {
|
||||
// print(err);
|
||||
// } finally {
|
||||
setState(() {
|
||||
loading = false;
|
||||
});
|
||||
// }
|
||||
}
|
||||
|
||||
Widget _buildBody(BuildContext context) {
|
||||
Widget _buildBody() {
|
||||
if (loading) {
|
||||
return Loading(more: false);
|
||||
return Loading(more: true);
|
||||
} else {
|
||||
return widget.bodyBuilder();
|
||||
return bodyBuilder();
|
||||
}
|
||||
}
|
||||
|
||||
@ -60,22 +37,26 @@ class _RefreshScaffoldState extends State<RefreshScaffold> {
|
||||
switch (SettingsProvider.of(context).layout) {
|
||||
case LayoutMap.cupertino:
|
||||
return CupertinoPageScaffold(
|
||||
navigationBar: CupertinoNavigationBar(middle: widget.title),
|
||||
navigationBar:
|
||||
CupertinoNavigationBar(middle: title, trailing: trailing),
|
||||
child: SafeArea(
|
||||
child: CustomScrollView(
|
||||
slivers: <Widget>[
|
||||
CupertinoSliverRefreshControl(onRefresh: _refresh),
|
||||
SliverToBoxAdapter(child: _buildBody(context))
|
||||
CupertinoSliverRefreshControl(onRefresh: onRefresh),
|
||||
SliverToBoxAdapter(child: _buildBody())
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
default:
|
||||
return Scaffold(
|
||||
appBar: AppBar(title: widget.title),
|
||||
appBar: AppBar(
|
||||
title: title,
|
||||
actions: actions,
|
||||
),
|
||||
body: RefreshIndicator(
|
||||
onRefresh: _refresh,
|
||||
child: SingleChildScrollView(child: _buildBody(context)),
|
||||
onRefresh: onRefresh,
|
||||
child: SingleChildScrollView(child: _buildBody()),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user