mirror of
https://gitlab.com/comunic/comunicmobile
synced 2024-12-26 04:48:51 +00:00
Use Websocket to update number of unread notifications
This commit is contained in:
parent
36f89a9a53
commit
1b13a90615
@ -9,6 +9,13 @@ import 'package:event_bus/event_bus.dart';
|
||||
/// Main WebSocket closed
|
||||
class WSClosedEvent {}
|
||||
|
||||
/// New number of notifications
|
||||
class NewNumberNotifsEvent {
|
||||
final int newNum;
|
||||
|
||||
NewNumberNotifsEvent(this.newNum);
|
||||
}
|
||||
|
||||
class EventsHelper {
|
||||
static EventBus _mgr = EventBus();
|
||||
|
||||
|
@ -1,6 +1,9 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:comunic/helpers/events_helper.dart';
|
||||
import 'package:comunic/models/api_request.dart';
|
||||
import 'package:comunic/models/config.dart';
|
||||
import 'package:comunic/models/ws_message.dart';
|
||||
import 'package:web_socket_channel/web_socket_channel.dart';
|
||||
|
||||
/// User web socket helper
|
||||
@ -40,7 +43,10 @@ class WebSocketHelper {
|
||||
|
||||
_ws.stream.listen(
|
||||
// When we got data
|
||||
(onData) => print("WS New data: $onData"),
|
||||
(data) {
|
||||
print("WS New data: $data");
|
||||
_processMessage(data.toString());
|
||||
},
|
||||
|
||||
// Print errors on console
|
||||
onError: (e, stack) {
|
||||
@ -55,4 +61,31 @@ class WebSocketHelper {
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/// Process incoming message
|
||||
static _processMessage(String msgStr) {
|
||||
try {
|
||||
final msg = WsMessage.fromJSON(jsonDecode(msgStr));
|
||||
|
||||
if (!msg.hasId)
|
||||
_processUnattendedMessage(msg);
|
||||
else
|
||||
throw Exception("Do not know how to process attended message!");
|
||||
} catch (e, stack) {
|
||||
print("WS could not process message: $e");
|
||||
print(stack);
|
||||
}
|
||||
}
|
||||
|
||||
/// Process an unattended message
|
||||
static _processUnattendedMessage(WsMessage msg) {
|
||||
switch (msg.title) {
|
||||
case "number_notifs":
|
||||
EventsHelper.emit(NewNumberNotifsEvent(msg.data));
|
||||
break;
|
||||
|
||||
default:
|
||||
throw Exception("Unknown message type: ${msg.title}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,8 +3,8 @@
|
||||
/// @author Pierre Hubert
|
||||
|
||||
class CountUnreadNotifications {
|
||||
final int notifications;
|
||||
final int conversations;
|
||||
int notifications;
|
||||
int conversations;
|
||||
|
||||
CountUnreadNotifications({
|
||||
this.notifications,
|
||||
|
25
lib/models/ws_message.dart
Normal file
25
lib/models/ws_message.dart
Normal file
@ -0,0 +1,25 @@
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
/// WebSocket message
|
||||
///
|
||||
/// @author Pierre Hubert
|
||||
|
||||
class WsMessage {
|
||||
final String id;
|
||||
final String title;
|
||||
final dynamic data;
|
||||
|
||||
const WsMessage({
|
||||
@required this.id,
|
||||
@required this.title,
|
||||
@required this.data,
|
||||
}) : assert(id != null),
|
||||
assert(title != null);
|
||||
|
||||
/// Construct a message from a JSON document (messages coming from the server)
|
||||
static WsMessage fromJSON(final Map<dynamic, dynamic> m) {
|
||||
return WsMessage(id: m["id"], title: m["title"], data: m["data"]);
|
||||
}
|
||||
|
||||
bool get hasId => this.id != null && this.id.isNotEmpty;
|
||||
}
|
@ -1,3 +1,4 @@
|
||||
import 'package:comunic/helpers/events_helper.dart';
|
||||
import 'package:comunic/helpers/notifications_helper.dart';
|
||||
import 'package:comunic/models/count_unread_notifications.dart';
|
||||
import 'package:comunic/ui/widgets/safe_state.dart';
|
||||
@ -113,8 +114,7 @@ class ComunicAppBar extends StatefulWidget implements PreferredSizeWidget {
|
||||
final OnSelectMenuAction onTap;
|
||||
final BarCallbackActions selectedAction;
|
||||
|
||||
const ComunicAppBar(
|
||||
{Key key, @required this.onTap, @required this.selectedAction})
|
||||
const ComunicAppBar({Key key, @required this.onTap, @required this.selectedAction})
|
||||
: assert(onTap != null),
|
||||
super(key: key);
|
||||
|
||||
@ -126,12 +126,17 @@ class ComunicAppBar extends StatefulWidget implements PreferredSizeWidget {
|
||||
}
|
||||
|
||||
class _ComunicAppBarState extends SafeState<ComunicAppBar> {
|
||||
CountUnreadNotifications _unreadNotifications;
|
||||
var _unreadNotifications =
|
||||
CountUnreadNotifications(notifications: 0, conversations: 0);
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
_refreshCountUnread();
|
||||
super.initState();
|
||||
|
||||
// Listen to notifications number update
|
||||
this.listenChangeState<NewNumberNotifsEvent>(
|
||||
(d) => _unreadNotifications.notifications = d.newNum);
|
||||
}
|
||||
|
||||
void _refreshCountUnread() async {
|
||||
@ -171,7 +176,7 @@ class _ComunicAppBarState extends SafeState<ComunicAppBar> {
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: List.generate(
|
||||
_menuItems.length,
|
||||
(i) => _MenuItemWidget(
|
||||
(i) => _MenuItemWidget(
|
||||
item: _menuItems[i],
|
||||
onTap: widget.onTap,
|
||||
isSelected: _menuItems[i].action == widget.selectedAction,
|
||||
@ -212,9 +217,9 @@ class _MenuItemWidget extends StatelessWidget {
|
||||
color: isSelected ? _secondaryColor() : _primaryColor(),
|
||||
child: !item.isMenu
|
||||
? InkWell(
|
||||
child: _buildIconContainer(),
|
||||
onTap: () => onTap(item.action),
|
||||
)
|
||||
child: _buildIconContainer(),
|
||||
onTap: () => onTap(item.action),
|
||||
)
|
||||
: _buildContextMenuPopupButton(),
|
||||
),
|
||||
);
|
||||
@ -235,15 +240,15 @@ class _MenuItemWidget extends StatelessWidget {
|
||||
newNotice == 0
|
||||
? Container()
|
||||
: Material(
|
||||
color: Colors.red,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(2.0),
|
||||
child: Text(" $newNotice ",
|
||||
style: TextStyle(color: Colors.white)),
|
||||
),
|
||||
borderRadius: BorderRadius.all(
|
||||
Radius.circular(50.0),
|
||||
)),
|
||||
color: Colors.red,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(2.0),
|
||||
child: Text(" $newNotice ",
|
||||
style: TextStyle(color: Colors.white)),
|
||||
),
|
||||
borderRadius: BorderRadius.all(
|
||||
Radius.circular(50.0),
|
||||
)),
|
||||
Spacer(flex: 2),
|
||||
],
|
||||
);
|
||||
@ -255,9 +260,9 @@ class _MenuItemWidget extends StatelessWidget {
|
||||
child: _buildIconContainer(),
|
||||
itemBuilder: (i) => _menuActionsItem
|
||||
.map((f) => PopupMenuItem(
|
||||
child: Text(f.label),
|
||||
value: f.action,
|
||||
))
|
||||
child: Text(f.label),
|
||||
value: f.action,
|
||||
))
|
||||
.toList(),
|
||||
onSelected: onTap,
|
||||
);
|
||||
|
@ -8,7 +8,6 @@ import 'package:flutter/material.dart';
|
||||
/// @author Pierre HUBERT
|
||||
|
||||
abstract class SafeState<T extends StatefulWidget> extends State<T> {
|
||||
|
||||
final _subscriptions = List<StreamSubscription>();
|
||||
|
||||
@override
|
||||
@ -21,8 +20,7 @@ abstract class SafeState<T extends StatefulWidget> extends State<T> {
|
||||
|
||||
@override
|
||||
void setState(fn) {
|
||||
if(mounted)
|
||||
super.setState(fn);
|
||||
if (mounted) super.setState(fn);
|
||||
}
|
||||
|
||||
/// Register to a new subscription
|
||||
@ -30,4 +28,14 @@ abstract class SafeState<T extends StatefulWidget> extends State<T> {
|
||||
void listen<T>(void onEvent(T event)) {
|
||||
_subscriptions.add(EventsHelper.on<T>(onEvent));
|
||||
}
|
||||
}
|
||||
|
||||
/// Register to a new subscription
|
||||
///
|
||||
/// Callback will we called inside of setState
|
||||
@protected
|
||||
void listenChangeState<T>(void onEvent(T event)) {
|
||||
_subscriptions.add(EventsHelper.on<T>((d) {
|
||||
setState(() => onEvent(d));
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user