mirror of
				https://gitlab.com/comunic/comunicmobile
				synced 2025-11-04 04:04:18 +00:00 
			
		
		
		
	Use WebSocket to update likes
This commit is contained in:
		@@ -1,5 +1,5 @@
 | 
			
		||||
import 'package:comunic/enums/likes_type.dart';
 | 
			
		||||
import 'package:comunic/models/api_request.dart';
 | 
			
		||||
import 'package:comunic/helpers/websocket_helper.dart';
 | 
			
		||||
import 'package:meta/meta.dart';
 | 
			
		||||
 | 
			
		||||
/// Likes helper
 | 
			
		||||
@@ -15,21 +15,15 @@ const LikesAPIMap = {
 | 
			
		||||
 | 
			
		||||
class LikesHelper {
 | 
			
		||||
  /// Update liking status of an element
 | 
			
		||||
  Future<bool> setLiking({
 | 
			
		||||
  Future<void> setLiking({
 | 
			
		||||
    @required LikesType type,
 | 
			
		||||
    @required bool like,
 | 
			
		||||
    @required int id,
 | 
			
		||||
  }) async {
 | 
			
		||||
    return (await APIRequest(
 | 
			
		||||
          uri: "likes/update",
 | 
			
		||||
          needLogin: true,
 | 
			
		||||
          args: {
 | 
			
		||||
            "type": LikesAPIMap[type],
 | 
			
		||||
            "like": like.toString(),
 | 
			
		||||
            "id": id.toString(),
 | 
			
		||||
          },
 | 
			
		||||
        ).exec())
 | 
			
		||||
            .code ==
 | 
			
		||||
        200;
 | 
			
		||||
    return (await ws("likes/update", {
 | 
			
		||||
      "type": LikesAPIMap[type],
 | 
			
		||||
      "like": like.toString(),
 | 
			
		||||
      "id": id.toString(),
 | 
			
		||||
    }));
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,3 +1,4 @@
 | 
			
		||||
import 'dart:async';
 | 
			
		||||
import 'dart:convert';
 | 
			
		||||
 | 
			
		||||
import 'package:comunic/helpers/events_helper.dart';
 | 
			
		||||
@@ -13,6 +14,10 @@ import 'package:web_socket_channel/web_socket_channel.dart';
 | 
			
		||||
class WebSocketHelper {
 | 
			
		||||
  static WebSocketChannel _ws;
 | 
			
		||||
 | 
			
		||||
  static int _counter = 0;
 | 
			
		||||
 | 
			
		||||
  static final _requests = Map<String, Completer<dynamic>>();
 | 
			
		||||
 | 
			
		||||
  /// Check out whether we are currently connected to WebSocket or not
 | 
			
		||||
  static bool isConnected() {
 | 
			
		||||
    return _ws != null && _ws.closeCode == null;
 | 
			
		||||
@@ -57,11 +62,36 @@ class WebSocketHelper {
 | 
			
		||||
      // Notify when the channel is closed
 | 
			
		||||
      onDone: () {
 | 
			
		||||
        print("WS Channel closed");
 | 
			
		||||
 | 
			
		||||
        // Clear Futures queue
 | 
			
		||||
        _requests.clear();
 | 
			
		||||
 | 
			
		||||
        EventsHelper.emit(WSClosedEvent());
 | 
			
		||||
      },
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /// Send a new message
 | 
			
		||||
  ///
 | 
			
		||||
  /// This method might throw an [Exception] in case of failure
 | 
			
		||||
  static Future<dynamic> sendMessage(String title, dynamic data) {
 | 
			
		||||
    if (!isConnected())
 | 
			
		||||
      throw Exception("WS: Trying to send message but websocket is closed!");
 | 
			
		||||
 | 
			
		||||
    final completer = Completer();
 | 
			
		||||
 | 
			
		||||
    final id = "freq-${_counter++}";
 | 
			
		||||
 | 
			
		||||
    final msg = WsMessage(id: id, title: title, data: data).toJSON();
 | 
			
		||||
 | 
			
		||||
    print("WS Send message: $msg");
 | 
			
		||||
 | 
			
		||||
    _ws.sink.add(msg);
 | 
			
		||||
 | 
			
		||||
    _requests[id] = completer;
 | 
			
		||||
    return completer.future;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /// Process incoming message
 | 
			
		||||
  static _processMessage(String msgStr) {
 | 
			
		||||
    try {
 | 
			
		||||
@@ -70,7 +100,7 @@ class WebSocketHelper {
 | 
			
		||||
      if (!msg.hasId)
 | 
			
		||||
        _processUnattendedMessage(msg);
 | 
			
		||||
      else
 | 
			
		||||
        throw Exception("Do not know how to process attended message!");
 | 
			
		||||
        _respondRequests(msg);
 | 
			
		||||
    } catch (e, stack) {
 | 
			
		||||
      print("WS could not process message: $e");
 | 
			
		||||
      print(stack);
 | 
			
		||||
@@ -94,4 +124,25 @@ class WebSocketHelper {
 | 
			
		||||
        throw Exception("Unknown message type: ${msg.title}");
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /// Process responses to requests
 | 
			
		||||
  static _respondRequests(WsMessage msg) {
 | 
			
		||||
    if (!_requests.containsKey(msg.id))
 | 
			
		||||
      throw Exception(
 | 
			
		||||
          "Could not find request ${msg.id} in the requests queue!");
 | 
			
		||||
 | 
			
		||||
    final completer = _requests.remove(msg.id);
 | 
			
		||||
 | 
			
		||||
    // Handles errors
 | 
			
		||||
    if (msg.title != "success") {
 | 
			
		||||
      completer.completeError(Exception("Could not process request!"));
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    completer.complete(msg.data);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Helper function
 | 
			
		||||
Future<dynamic> ws(String title, dynamic data) =>
 | 
			
		||||
    WebSocketHelper.sendMessage(title, data);
 | 
			
		||||
 
 | 
			
		||||
@@ -1,3 +1,5 @@
 | 
			
		||||
import 'dart:convert';
 | 
			
		||||
 | 
			
		||||
import 'package:flutter/widgets.dart';
 | 
			
		||||
 | 
			
		||||
/// WebSocket message
 | 
			
		||||
@@ -14,12 +16,21 @@ class WsMessage {
 | 
			
		||||
    @required this.title,
 | 
			
		||||
    @required this.data,
 | 
			
		||||
  })  : assert(id != null),
 | 
			
		||||
        assert(title != null);
 | 
			
		||||
        assert(title != null),
 | 
			
		||||
        assert(title.length > 0);
 | 
			
		||||
 | 
			
		||||
  /// 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"]);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /// Turn a message into a JSON object to send it to the API
 | 
			
		||||
  String toJSON() =>
 | 
			
		||||
      jsonEncode({
 | 
			
		||||
        "id": id,
 | 
			
		||||
        "title": title,
 | 
			
		||||
        "data": data,
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
  bool get hasId => this.id != null && this.id.isNotEmpty;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -71,13 +71,16 @@ class _LikeWidgetState extends SafeState<LikeWidget> {
 | 
			
		||||
  /// Toggle like status
 | 
			
		||||
  void _toggleLike() async {
 | 
			
		||||
    // As like are not really important, we ignore failures
 | 
			
		||||
    if (await LikesHelper()
 | 
			
		||||
        .setLiking(type: elem.likeType, like: !elem.userLike, id: elem.id)) {
 | 
			
		||||
    try {
 | 
			
		||||
      await LikesHelper()
 | 
			
		||||
          .setLiking(type: elem.likeType, like: !elem.userLike, id: elem.id);
 | 
			
		||||
      setState(() {
 | 
			
		||||
        elem.userLike = !elem.userLike;
 | 
			
		||||
 | 
			
		||||
        elem.likes += elem.userLike ? 1 : -1;
 | 
			
		||||
      });
 | 
			
		||||
    } catch (e, stack) {
 | 
			
		||||
      print("$e\n$stack");
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user