mirror of
				https://gitlab.com/comunic/comunicmobile
				synced 2025-11-04 04:04:18 +00:00 
			
		
		
		
	Can update a conversation
This commit is contained in:
		@@ -8,7 +8,6 @@ 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/conversation_settings.dart';
 | 
			
		||||
import 'package:comunic/models/new_conversation_message.dart';
 | 
			
		||||
import 'package:comunic/utils/account_utils.dart';
 | 
			
		||||
import 'package:meta/meta.dart';
 | 
			
		||||
@@ -28,7 +27,7 @@ class ConversationsHelper {
 | 
			
		||||
  /// Create a new conversation
 | 
			
		||||
  ///
 | 
			
		||||
  /// Return the ID of the newly created conversation or -1 in case of failure
 | 
			
		||||
  Future<int> createConversation(ConversationSettings settings) async {
 | 
			
		||||
  Future<int> createConversation(Conversation settings) async {
 | 
			
		||||
    final response =
 | 
			
		||||
        await APIRequest(uri: "conversations/create", needLogin: true, args: {
 | 
			
		||||
      "name": settings.hasName ? settings.name : "false",
 | 
			
		||||
@@ -41,6 +40,27 @@ class ConversationsHelper {
 | 
			
		||||
    return response.getObject()["conversationID"];
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /// Update an existing conversation
 | 
			
		||||
  ///
 | 
			
		||||
  /// Returns a boolean depending of the success of the operation
 | 
			
		||||
  Future<bool> updateConversation(Conversation settings) async {
 | 
			
		||||
    final request =
 | 
			
		||||
        APIRequest(uri: "conversations/updateSettings", needLogin: true, args: {
 | 
			
		||||
      "conversationID": settings.id.toString(),
 | 
			
		||||
      "following": settings.following ? "true" : "false"
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    // Update all conversation settings, if possible
 | 
			
		||||
    if(settings.isOwner) {
 | 
			
		||||
      request.addString("name", settings.hasName ? settings.name : "false");
 | 
			
		||||
      request.addString("members", settings.members.join(","));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    final response = await request.exec();
 | 
			
		||||
 | 
			
		||||
    return response.code == 200;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /// Download the list of conversations from the server
 | 
			
		||||
  Future<ConversationsList> downloadList() async {
 | 
			
		||||
    final response =
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,6 @@
 | 
			
		||||
import 'package:comunic/helpers/database/database_contract.dart';
 | 
			
		||||
import 'package:comunic/models/cache_model.dart';
 | 
			
		||||
import 'package:comunic/utils/account_utils.dart';
 | 
			
		||||
import 'package:comunic/utils/list_utils.dart';
 | 
			
		||||
import 'package:meta/meta.dart';
 | 
			
		||||
 | 
			
		||||
@@ -34,6 +35,10 @@ class Conversation extends CacheModel implements Comparable {
 | 
			
		||||
  /// Check out whether a conversation has a fixed name or not
 | 
			
		||||
  bool get hasName => this.name != null;
 | 
			
		||||
 | 
			
		||||
  /// Check out whether current user of the application is the owner of it or
 | 
			
		||||
  /// not
 | 
			
		||||
  bool get isOwner => this.ownerID == userID();
 | 
			
		||||
 | 
			
		||||
  Conversation.fromMap(Map<String, dynamic> map)
 | 
			
		||||
      : ownerID = map[ConversationTableContract.C_OWNER_ID],
 | 
			
		||||
        lastActive = map[ConversationTableContract.C_LAST_ACTIVE],
 | 
			
		||||
 
 | 
			
		||||
@@ -1,27 +0,0 @@
 | 
			
		||||
import 'package:meta/meta.dart';
 | 
			
		||||
 | 
			
		||||
/// Conversation settings model
 | 
			
		||||
///
 | 
			
		||||
/// Use this model to create / update a conversation
 | 
			
		||||
///
 | 
			
		||||
/// @author Pierre HUBERT
 | 
			
		||||
 | 
			
		||||
class ConversationSettings {
 | 
			
		||||
  /// Set the ID to 0 if not required
 | 
			
		||||
  final int id;
 | 
			
		||||
  final String name;
 | 
			
		||||
  final bool following;
 | 
			
		||||
  final List<int> members;
 | 
			
		||||
 | 
			
		||||
  ConversationSettings({
 | 
			
		||||
    @required this.id,
 | 
			
		||||
    @required this.name,
 | 
			
		||||
    @required this.following,
 | 
			
		||||
    @required this.members,
 | 
			
		||||
  })  : assert(members != null && members.length > 0),
 | 
			
		||||
        assert(following != null);
 | 
			
		||||
 | 
			
		||||
  bool get hasName => name != null && name.length > 0;
 | 
			
		||||
 | 
			
		||||
  bool get hasId => id != null && id > 0;
 | 
			
		||||
}
 | 
			
		||||
@@ -1,5 +1,6 @@
 | 
			
		||||
import 'package:comunic/helpers/conversations_helper.dart';
 | 
			
		||||
import 'package:comunic/models/conversation.dart';
 | 
			
		||||
import 'package:comunic/ui/routes/update_conversation_route.dart';
 | 
			
		||||
import 'package:comunic/ui/screens/conversation_screen.dart';
 | 
			
		||||
import 'package:comunic/utils/intl_utils.dart';
 | 
			
		||||
import 'package:comunic/utils/ui_utils.dart';
 | 
			
		||||
@@ -53,6 +54,14 @@ class _ConversationRouteState extends State<ConversationRoute> {
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void _openSettings() {
 | 
			
		||||
    Navigator.of(context).push(MaterialPageRoute(builder: (b) {
 | 
			
		||||
      return UpdateConversationRoute(
 | 
			
		||||
        conversationID: widget.conversationID,
 | 
			
		||||
      );
 | 
			
		||||
    }));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  Widget _buildRouteBody() {
 | 
			
		||||
    //Handle errors
 | 
			
		||||
    if (_error != null && _error)
 | 
			
		||||
@@ -86,6 +95,12 @@ class _ConversationRouteState extends State<ConversationRoute> {
 | 
			
		||||
        title: Text(
 | 
			
		||||
          _conversationName == null ? tr("Loading") : _conversationName,
 | 
			
		||||
        ),
 | 
			
		||||
        actions: <Widget>[
 | 
			
		||||
          IconButton(
 | 
			
		||||
            icon: Icon(Icons.settings),
 | 
			
		||||
            onPressed: _openSettings,
 | 
			
		||||
          )
 | 
			
		||||
        ],
 | 
			
		||||
      ),
 | 
			
		||||
      body: _buildRouteBody(),
 | 
			
		||||
    );
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										91
									
								
								lib/ui/routes/update_conversation_route.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										91
									
								
								lib/ui/routes/update_conversation_route.dart
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,91 @@
 | 
			
		||||
import 'package:comunic/helpers/conversations_helper.dart';
 | 
			
		||||
import 'package:comunic/helpers/users_helper.dart';
 | 
			
		||||
import 'package:comunic/lists/users_list.dart';
 | 
			
		||||
import 'package:comunic/models/conversation.dart';
 | 
			
		||||
import 'package:comunic/ui/screens/update_conversation_screen.dart';
 | 
			
		||||
import 'package:comunic/utils/intl_utils.dart';
 | 
			
		||||
import 'package:comunic/utils/ui_utils.dart';
 | 
			
		||||
import 'package:flutter/material.dart';
 | 
			
		||||
 | 
			
		||||
/// Update a conversation route
 | 
			
		||||
///
 | 
			
		||||
/// @author Pierre HUBERT
 | 
			
		||||
 | 
			
		||||
class UpdateConversationRoute extends StatefulWidget {
 | 
			
		||||
  final int conversationID;
 | 
			
		||||
 | 
			
		||||
  const UpdateConversationRoute({Key key, this.conversationID})
 | 
			
		||||
      : assert(conversationID != null),
 | 
			
		||||
        super(key: key);
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  State<StatefulWidget> createState() => _UpdateConversationRoute();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class _UpdateConversationRoute extends State<UpdateConversationRoute> {
 | 
			
		||||
  Conversation _conversation;
 | 
			
		||||
  UsersList _membersInfo;
 | 
			
		||||
  bool _error = false;
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  void didChangeDependencies() {
 | 
			
		||||
    super.didChangeDependencies();
 | 
			
		||||
    _loadConversation();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void setError(bool e) => setState(() {
 | 
			
		||||
        _error = e;
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
  /// Load information about the being updated conversation
 | 
			
		||||
  Future<void> _loadConversation() async {
 | 
			
		||||
    setError(false);
 | 
			
		||||
 | 
			
		||||
    final conversation = await ConversationsHelper()
 | 
			
		||||
        .getSingle(widget.conversationID, force: true);
 | 
			
		||||
 | 
			
		||||
    if (conversation == null) return setError(true);
 | 
			
		||||
 | 
			
		||||
    //Load information about the members of the conversation
 | 
			
		||||
    _membersInfo = await UsersHelper().getUsersInfo(conversation.members);
 | 
			
		||||
 | 
			
		||||
    if (_membersInfo == null) return setError(true);
 | 
			
		||||
 | 
			
		||||
    setState(() {
 | 
			
		||||
      _conversation = conversation;
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /// Build the body of this widget
 | 
			
		||||
  Widget _buildBody() {
 | 
			
		||||
    if (_error)
 | 
			
		||||
      return buildErrorCard(
 | 
			
		||||
          tr("Could not load information about the conversation"),
 | 
			
		||||
          actions: [
 | 
			
		||||
            FlatButton(
 | 
			
		||||
              onPressed: _loadConversation,
 | 
			
		||||
              child: Text(
 | 
			
		||||
                tr("Retry").toUpperCase(),
 | 
			
		||||
                style: TextStyle(color: Colors.white),
 | 
			
		||||
              ),
 | 
			
		||||
            )
 | 
			
		||||
          ]);
 | 
			
		||||
 | 
			
		||||
    if (_conversation == null) return buildLoadingPage();
 | 
			
		||||
 | 
			
		||||
    return UpdateConversationScreen(
 | 
			
		||||
      initialUsers: _membersInfo,
 | 
			
		||||
      initialSettings: _conversation,
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  Widget build(BuildContext context) {
 | 
			
		||||
    return Scaffold(
 | 
			
		||||
      appBar: AppBar(
 | 
			
		||||
        title: Text(tr("Update a conversation")),
 | 
			
		||||
      ),
 | 
			
		||||
      body: _buildBody(),
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
import 'package:comunic/helpers/conversations_helper.dart';
 | 
			
		||||
import 'package:comunic/lists/users_list.dart';
 | 
			
		||||
import 'package:comunic/models/conversation_settings.dart';
 | 
			
		||||
import 'package:comunic/models/conversation.dart';
 | 
			
		||||
import 'package:comunic/ui/routes/conversation_route.dart';
 | 
			
		||||
import 'package:comunic/ui/tiles/simple_user_tile.dart';
 | 
			
		||||
import 'package:comunic/ui/widgets/pick_user_widget.dart';
 | 
			
		||||
@@ -14,6 +14,15 @@ import 'package:flutter/material.dart';
 | 
			
		||||
enum _MembersMenuChoices { REMOVE }
 | 
			
		||||
 | 
			
		||||
class UpdateConversationScreen extends StatefulWidget {
 | 
			
		||||
  final Conversation initialSettings;
 | 
			
		||||
  final UsersList initialUsers;
 | 
			
		||||
 | 
			
		||||
  const UpdateConversationScreen({
 | 
			
		||||
    Key key,
 | 
			
		||||
    this.initialSettings,
 | 
			
		||||
    this.initialUsers,
 | 
			
		||||
  }) : super(key: key);
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  State<StatefulWidget> createState() => _UpdateConversationScreen();
 | 
			
		||||
}
 | 
			
		||||
@@ -23,6 +32,22 @@ class _UpdateConversationScreen extends State<UpdateConversationScreen> {
 | 
			
		||||
  UsersList _members = UsersList();
 | 
			
		||||
  bool _followConversation = true;
 | 
			
		||||
 | 
			
		||||
  get isUpdating => widget.initialSettings != null;
 | 
			
		||||
 | 
			
		||||
  get isOwner => !isUpdating || widget.initialSettings.isOwner;
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  void initState() {
 | 
			
		||||
    super.initState();
 | 
			
		||||
 | 
			
		||||
    // Check if we are updating an existing conversation
 | 
			
		||||
    if (widget.initialSettings != null) {
 | 
			
		||||
      _nameController.text = widget.initialSettings.name;
 | 
			
		||||
      _members = widget.initialUsers;
 | 
			
		||||
      _followConversation = widget.initialSettings.following;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  Widget build(BuildContext context) {
 | 
			
		||||
    return Container(
 | 
			
		||||
@@ -33,8 +58,10 @@ class _UpdateConversationScreen extends State<UpdateConversationScreen> {
 | 
			
		||||
          TextField(
 | 
			
		||||
            controller: _nameController,
 | 
			
		||||
            decoration: InputDecoration(
 | 
			
		||||
                labelText: tr("Conversation name (optionnal)"),
 | 
			
		||||
                alignLabelWithHint: true),
 | 
			
		||||
              labelText: tr("Conversation name (optionnal)"),
 | 
			
		||||
              alignLabelWithHint: true,
 | 
			
		||||
              enabled: isOwner,
 | 
			
		||||
            ),
 | 
			
		||||
          ),
 | 
			
		||||
 | 
			
		||||
          // Add a member to the conversation
 | 
			
		||||
@@ -42,6 +69,7 @@ class _UpdateConversationScreen extends State<UpdateConversationScreen> {
 | 
			
		||||
            resetOnChoose: true,
 | 
			
		||||
            keepFocusOnChoose: true,
 | 
			
		||||
            label: tr("Add member"),
 | 
			
		||||
            enabled: isOwner,
 | 
			
		||||
            onSelectUser: (user) => setState(() {
 | 
			
		||||
                  if (!_members.contains(user)) _members.add(user);
 | 
			
		||||
                }),
 | 
			
		||||
@@ -57,17 +85,19 @@ class _UpdateConversationScreen extends State<UpdateConversationScreen> {
 | 
			
		||||
                      itemBuilder: (b, i) {
 | 
			
		||||
                        return SimpleUserTile(
 | 
			
		||||
                          user: _members[i],
 | 
			
		||||
                          trailing: PopupMenuButton<_MembersMenuChoices>(
 | 
			
		||||
                            onSelected: (choice) =>
 | 
			
		||||
                                _membersMenuItemSelected(i, choice),
 | 
			
		||||
                            itemBuilder: (c) =>
 | 
			
		||||
                                <PopupMenuEntry<_MembersMenuChoices>>[
 | 
			
		||||
                                  PopupMenuItem(
 | 
			
		||||
                                    child: Text(tr("Remove")),
 | 
			
		||||
                                    value: _MembersMenuChoices.REMOVE,
 | 
			
		||||
                                  )
 | 
			
		||||
                                ],
 | 
			
		||||
                          ),
 | 
			
		||||
                          trailing: isOwner
 | 
			
		||||
                              ? PopupMenuButton<_MembersMenuChoices>(
 | 
			
		||||
                                  onSelected: (choice) =>
 | 
			
		||||
                                      _membersMenuItemSelected(i, choice),
 | 
			
		||||
                                  itemBuilder: (c) =>
 | 
			
		||||
                                      <PopupMenuEntry<_MembersMenuChoices>>[
 | 
			
		||||
                                        PopupMenuItem(
 | 
			
		||||
                                          child: Text(tr("Remove")),
 | 
			
		||||
                                          value: _MembersMenuChoices.REMOVE,
 | 
			
		||||
                                        )
 | 
			
		||||
                                      ],
 | 
			
		||||
                                )
 | 
			
		||||
                              : null,
 | 
			
		||||
                        );
 | 
			
		||||
                      },
 | 
			
		||||
                    ),
 | 
			
		||||
@@ -90,7 +120,9 @@ class _UpdateConversationScreen extends State<UpdateConversationScreen> {
 | 
			
		||||
          // Submit button
 | 
			
		||||
          RaisedButton(
 | 
			
		||||
            onPressed: _members.length < 1 ? null : _submitForm,
 | 
			
		||||
            child: Text(tr("Create the conversation")),
 | 
			
		||||
            child: Text(isUpdating
 | 
			
		||||
                ? tr("Update the conversation")
 | 
			
		||||
                : tr("Create the conversation")),
 | 
			
		||||
          )
 | 
			
		||||
        ],
 | 
			
		||||
      ),
 | 
			
		||||
@@ -109,24 +141,40 @@ class _UpdateConversationScreen extends State<UpdateConversationScreen> {
 | 
			
		||||
 | 
			
		||||
  /// Submit the conversation
 | 
			
		||||
  Future<void> _submitForm() async {
 | 
			
		||||
    final settings = ConversationSettings(
 | 
			
		||||
      id: 0,
 | 
			
		||||
      name: _nameController.text,
 | 
			
		||||
      following: _followConversation,
 | 
			
		||||
      members: _members.usersID,
 | 
			
		||||
    );
 | 
			
		||||
    final settings = Conversation(
 | 
			
		||||
        id: isUpdating ? widget.initialSettings.id : 0,
 | 
			
		||||
        name: _nameController.text,
 | 
			
		||||
        following: _followConversation,
 | 
			
		||||
        members: _members.usersID,
 | 
			
		||||
 | 
			
		||||
        // Give random value to these fields as they are ignored here
 | 
			
		||||
        lastActive: 0,
 | 
			
		||||
        ownerID: 0,
 | 
			
		||||
        sawLastMessage: true);
 | 
			
		||||
 | 
			
		||||
    // Create the conversation
 | 
			
		||||
    final conversationID = await ConversationsHelper().createConversation(settings);
 | 
			
		||||
    var conversationID = settings.id;
 | 
			
		||||
    bool error = false;
 | 
			
		||||
    if (isUpdating)
 | 
			
		||||
      error = !(await ConversationsHelper().updateConversation(settings));
 | 
			
		||||
    else {
 | 
			
		||||
      conversationID = await ConversationsHelper().createConversation(settings);
 | 
			
		||||
      if (conversationID < 1) error = true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Check for errors
 | 
			
		||||
    if(conversationID < 1)
 | 
			
		||||
      return Scaffold.of(context).showSnackBar(
 | 
			
		||||
          SnackBar(content: Text(tr("Could not create the conversation!")), duration: Duration(seconds: 1),));
 | 
			
		||||
    if (error)
 | 
			
		||||
      return Scaffold.of(context).showSnackBar(SnackBar(
 | 
			
		||||
        content: Text(isUpdating
 | 
			
		||||
            ? tr("Could not update the conversation!")
 | 
			
		||||
            : tr("Could not create the conversation!")),
 | 
			
		||||
        duration: Duration(seconds: 1),
 | 
			
		||||
      ));
 | 
			
		||||
 | 
			
		||||
    // Open the conversation
 | 
			
		||||
    Navigator.of(context).pushReplacement(MaterialPageRoute(
 | 
			
		||||
      builder: (c) => ConversationRoute(conversationID: conversationID,)
 | 
			
		||||
    ));
 | 
			
		||||
        builder: (c) => ConversationRoute(
 | 
			
		||||
              conversationID: conversationID,
 | 
			
		||||
            )));
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -18,13 +18,15 @@ class PickUserWidget extends StatefulWidget {
 | 
			
		||||
  final String label;
 | 
			
		||||
  final bool resetOnChoose;
 | 
			
		||||
  final bool keepFocusOnChoose;
 | 
			
		||||
  final bool enabled;
 | 
			
		||||
 | 
			
		||||
  const PickUserWidget(
 | 
			
		||||
      {Key key,
 | 
			
		||||
      @required this.onSelectUser,
 | 
			
		||||
      @required this.label,
 | 
			
		||||
      this.resetOnChoose = false,
 | 
			
		||||
      this.keepFocusOnChoose = false})
 | 
			
		||||
      this.keepFocusOnChoose = false,
 | 
			
		||||
      this.enabled = true})
 | 
			
		||||
      : assert(onSelectUser != null),
 | 
			
		||||
        assert(label != null),
 | 
			
		||||
        assert(resetOnChoose != null),
 | 
			
		||||
@@ -66,6 +68,7 @@ class _PickUserWidgetState extends State<PickUserWidget> {
 | 
			
		||||
      focusNode: _focusNode,
 | 
			
		||||
      onChanged: (s) => _updateSuggestions(),
 | 
			
		||||
      controller: _controller,
 | 
			
		||||
      enabled: widget.enabled,
 | 
			
		||||
      decoration: InputDecoration(
 | 
			
		||||
        labelText: widget.label,
 | 
			
		||||
        alignLabelWithHint: true,
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user