mirror of
				https://gitlab.com/comunic/comunicmobile
				synced 2025-11-04 04:04:18 +00:00 
			
		
		
		
	Can send images in conversations
This commit is contained in:
		@@ -1,11 +1,10 @@
 | 
			
		||||
import 'dart:convert';
 | 
			
		||||
import 'dart:io';
 | 
			
		||||
 | 
			
		||||
import 'package:comunic/helpers/account_credentials_helper.dart';
 | 
			
		||||
import 'package:comunic/models/api_request.dart';
 | 
			
		||||
import 'package:comunic/models/api_response.dart';
 | 
			
		||||
import 'package:comunic/models/config.dart';
 | 
			
		||||
import 'package:http/http.dart' as http;
 | 
			
		||||
import 'package:dio/dio.dart';
 | 
			
		||||
 | 
			
		||||
/// API Helper
 | 
			
		||||
///
 | 
			
		||||
@@ -16,7 +15,7 @@ class APIHelper {
 | 
			
		||||
  ///
 | 
			
		||||
  /// This method should never throw but the response code of the [APIResponse]
 | 
			
		||||
  /// should be verified before accessing response content
 | 
			
		||||
  Future<APIResponse> exec(APIRequest request) async {
 | 
			
		||||
  Future<APIResponse> exec(APIRequest request, {bool multipart = false}) async {
 | 
			
		||||
    try {
 | 
			
		||||
      //Add API tokens
 | 
			
		||||
      request.addString("serviceName", config().serviceName);
 | 
			
		||||
@@ -38,20 +37,39 @@ class APIHelper {
 | 
			
		||||
      else
 | 
			
		||||
        url = Uri.https(config().apiServerName, path);
 | 
			
		||||
 | 
			
		||||
      final response = await http.post(
 | 
			
		||||
      final data = FormData.from(request.args);
 | 
			
		||||
 | 
			
		||||
      // Process files (if required)
 | 
			
		||||
      if (multipart)
 | 
			
		||||
        request.files.forEach(
 | 
			
		||||
            (k, v) => data.add(k, UploadFileInfo(v, v.path.split("/").last)));
 | 
			
		||||
 | 
			
		||||
      // Execute the request
 | 
			
		||||
      final response = await Dio().post(
 | 
			
		||||
        url.toString(),
 | 
			
		||||
        body: request.args,
 | 
			
		||||
        encoding: utf8
 | 
			
		||||
        data: data,
 | 
			
		||||
        options: Options(
 | 
			
		||||
          receiveDataWhenStatusError: true,
 | 
			
		||||
          validateStatus: (s) => true,
 | 
			
		||||
          responseType: ResponseType.plain,
 | 
			
		||||
        ),
 | 
			
		||||
      );
 | 
			
		||||
 | 
			
		||||
      if (response.statusCode != HttpStatus.ok)
 | 
			
		||||
        return APIResponse(response.statusCode, null);
 | 
			
		||||
 | 
			
		||||
      return APIResponse(response.statusCode, utf8.decode(response.bodyBytes));
 | 
			
		||||
      return APIResponse(response.statusCode, response.data);
 | 
			
		||||
    } on Exception catch (e) {
 | 
			
		||||
      print(e.toString());
 | 
			
		||||
      print("Could not execute a request!");
 | 
			
		||||
      return APIResponse(-1, null);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /// Same as exec, but also allows to send files
 | 
			
		||||
  ///
 | 
			
		||||
  /// Warning ! Currently the response body to such requests is always null !
 | 
			
		||||
  Future<APIResponse> execWithFiles(APIRequest request) async {
 | 
			
		||||
    return await exec(request, multipart: true);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -4,6 +4,7 @@ import 'package:comunic/lists/conversation_messages_list.dart';
 | 
			
		||||
import 'package:comunic/lists/conversations_list.dart';
 | 
			
		||||
import 'package:comunic/lists/users_list.dart';
 | 
			
		||||
import 'package:comunic/models/api_request.dart';
 | 
			
		||||
import 'package:comunic/models/api_response.dart';
 | 
			
		||||
import 'package:comunic/models/conversation.dart';
 | 
			
		||||
import 'package:comunic/models/conversation_message.dart';
 | 
			
		||||
import 'package:comunic/models/new_conversation_message.dart';
 | 
			
		||||
@@ -162,14 +163,25 @@ class ConversationsHelper {
 | 
			
		||||
 | 
			
		||||
  /// Send a new message to the server
 | 
			
		||||
  Future<SendMessageResult> sendMessage(NewConversationMessage message) async {
 | 
			
		||||
    final response = await APIRequest(
 | 
			
		||||
    final request = APIRequest(
 | 
			
		||||
      uri: "conversations/sendMessage",
 | 
			
		||||
      needLogin: true,
 | 
			
		||||
      args: {
 | 
			
		||||
        "conversationID": message.conversationID.toString(),
 | 
			
		||||
        "message": message.message
 | 
			
		||||
        "message": message.hasMessage ? message.message : ""
 | 
			
		||||
      },
 | 
			
		||||
    ).exec();
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    //Check for image
 | 
			
		||||
    if(message.hasImage)
 | 
			
		||||
      request.addFile("image", message.image);
 | 
			
		||||
 | 
			
		||||
    //Send the message
 | 
			
		||||
    APIResponse response;
 | 
			
		||||
    if(!message.hasImage)
 | 
			
		||||
      response = await request.exec();
 | 
			
		||||
    else
 | 
			
		||||
      response = await request.execWithFiles();
 | 
			
		||||
 | 
			
		||||
    if(response.code == 401)
 | 
			
		||||
      return SendMessageResult.MESSAGE_REJECTED;
 | 
			
		||||
 
 | 
			
		||||
@@ -1,3 +1,5 @@
 | 
			
		||||
import 'dart:io';
 | 
			
		||||
 | 
			
		||||
import 'package:comunic/helpers/api_helper.dart';
 | 
			
		||||
import 'package:comunic/models/api_response.dart';
 | 
			
		||||
import 'package:meta/meta.dart';
 | 
			
		||||
@@ -12,6 +14,7 @@ class APIRequest {
 | 
			
		||||
  final String uri;
 | 
			
		||||
  final bool needLogin;
 | 
			
		||||
  Map<String, String> args;
 | 
			
		||||
  Map<String, File> files = Map();
 | 
			
		||||
 | 
			
		||||
  APIRequest({@required this.uri, this.needLogin = false, this.args})
 | 
			
		||||
      : assert(uri != null),
 | 
			
		||||
@@ -26,6 +29,11 @@ class APIRequest {
 | 
			
		||||
  void addBool(String name, bool value) =>
 | 
			
		||||
      args[name] = value ? "true" : "false";
 | 
			
		||||
 | 
			
		||||
  void addFile(String name, File file) => files[name] = file;
 | 
			
		||||
 | 
			
		||||
  /// Execute the request
 | 
			
		||||
  Future<APIResponse> exec() async => APIHelper().exec(this);
 | 
			
		||||
 | 
			
		||||
  /// Execute the request with files
 | 
			
		||||
  Future<APIResponse> execWithFiles() async => APIHelper().execWithFiles(this);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,3 +1,5 @@
 | 
			
		||||
import 'dart:io';
 | 
			
		||||
 | 
			
		||||
import 'package:meta/meta.dart';
 | 
			
		||||
 | 
			
		||||
/// New conversation message model
 | 
			
		||||
@@ -9,9 +11,15 @@ import 'package:meta/meta.dart';
 | 
			
		||||
class NewConversationMessage {
 | 
			
		||||
  final int conversationID;
 | 
			
		||||
  final String message;
 | 
			
		||||
  final File image;
 | 
			
		||||
 | 
			
		||||
  NewConversationMessage({
 | 
			
		||||
    @required this.conversationID,
 | 
			
		||||
    @required this.message,
 | 
			
		||||
  }) : assert(conversationID != null);
 | 
			
		||||
    this.image
 | 
			
		||||
  })  : assert(conversationID != null),
 | 
			
		||||
        assert(image != null || message != null);
 | 
			
		||||
 | 
			
		||||
  bool get hasMessage => message != null;
 | 
			
		||||
  bool get hasImage => image != null;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -86,15 +86,36 @@ class _ConversationScreenState extends State<ConversationScreen> {
 | 
			
		||||
  /// Pick and send an image
 | 
			
		||||
  Future<void> _sendImage(BuildContext context) async {
 | 
			
		||||
    final image = await pickImage(context);
 | 
			
		||||
 | 
			
		||||
    if (image == null) return null;
 | 
			
		||||
 | 
			
		||||
    _submitMessage(
 | 
			
		||||
      context,
 | 
			
		||||
      NewConversationMessage(
 | 
			
		||||
        conversationID: widget.conversationID,
 | 
			
		||||
        message: null,
 | 
			
		||||
        image: image,
 | 
			
		||||
      ),
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /// Send a new message
 | 
			
		||||
  Future<void> _submitMessage(BuildContext context, String content) async {
 | 
			
		||||
  /// Send a new text message
 | 
			
		||||
  Future<void> _submitTextMessage(BuildContext context, String content) async {
 | 
			
		||||
    _submitMessage(
 | 
			
		||||
      context,
 | 
			
		||||
      NewConversationMessage(
 | 
			
		||||
        conversationID: widget.conversationID,
 | 
			
		||||
        message: content,
 | 
			
		||||
      ),
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /// Submit a new message
 | 
			
		||||
  Future<void> _submitMessage(
 | 
			
		||||
      BuildContext context, NewConversationMessage message) async {
 | 
			
		||||
    //Send the message
 | 
			
		||||
    _setSending(true);
 | 
			
		||||
    final result = await _conversationsHelper.sendMessage(
 | 
			
		||||
        NewConversationMessage(
 | 
			
		||||
            conversationID: widget.conversationID, message: content));
 | 
			
		||||
    final result = await _conversationsHelper.sendMessage(message);
 | 
			
		||||
    _setSending(false);
 | 
			
		||||
 | 
			
		||||
    //Check the result of the operation
 | 
			
		||||
@@ -148,14 +169,14 @@ class _ConversationScreenState extends State<ConversationScreen> {
 | 
			
		||||
        children: <Widget>[
 | 
			
		||||
          // Image area
 | 
			
		||||
          new Container(
 | 
			
		||||
              margin: new EdgeInsets.symmetric(horizontal: 4.0),
 | 
			
		||||
              child: new IconButton(
 | 
			
		||||
                  icon: new Icon(
 | 
			
		||||
                    Icons.photo_camera,
 | 
			
		||||
                    color: Theme.of(context).accentColor,
 | 
			
		||||
                  ),
 | 
			
		||||
                  onPressed: () => _sendImage(context)),
 | 
			
		||||
            ),
 | 
			
		||||
            margin: new EdgeInsets.symmetric(horizontal: 4.0),
 | 
			
		||||
            child: new IconButton(
 | 
			
		||||
                icon: new Icon(
 | 
			
		||||
                  Icons.photo_camera,
 | 
			
		||||
                  color: Theme.of(context).accentColor,
 | 
			
		||||
                ),
 | 
			
		||||
                onPressed: () => _sendImage(context)),
 | 
			
		||||
          ),
 | 
			
		||||
 | 
			
		||||
          // Message area
 | 
			
		||||
          new Flexible(
 | 
			
		||||
@@ -166,8 +187,9 @@ class _ConversationScreenState extends State<ConversationScreen> {
 | 
			
		||||
                  _isMessageValid = messageText.length > 4;
 | 
			
		||||
                });
 | 
			
		||||
              },
 | 
			
		||||
              onSubmitted:
 | 
			
		||||
                  _isMessageValid ? (s) => _submitMessage(context, s) : null,
 | 
			
		||||
              onSubmitted: _isMessageValid
 | 
			
		||||
                  ? (s) => _submitTextMessage(context, s)
 | 
			
		||||
                  : null,
 | 
			
		||||
              decoration:
 | 
			
		||||
                  new InputDecoration.collapsed(hintText: tr("Send a message")),
 | 
			
		||||
            ),
 | 
			
		||||
@@ -184,7 +206,8 @@ class _ConversationScreenState extends State<ConversationScreen> {
 | 
			
		||||
                    : Theme.of(context).disabledColor,
 | 
			
		||||
              ),
 | 
			
		||||
              onPressed: !_isSendingMessage && _isMessageValid
 | 
			
		||||
                  ? () => _submitMessage(context, _textEditingController.text)
 | 
			
		||||
                  ? () =>
 | 
			
		||||
                      _submitTextMessage(context, _textEditingController.text)
 | 
			
		||||
                  : null,
 | 
			
		||||
            ),
 | 
			
		||||
          ),
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user