mirror of
				https://gitlab.com/comunic/comunicmobile
				synced 2025-11-03 11:44:18 +00:00 
			
		
		
		
	Can create group conversations
This commit is contained in:
		@@ -1,3 +1,4 @@
 | 
			
		||||
import 'package:comunic/helpers/groups_helper.dart';
 | 
			
		||||
import 'package:comunic/helpers/serialization/conversation_message_serialization_helper.dart';
 | 
			
		||||
import 'package:comunic/helpers/serialization/conversations_serialization_helper.dart';
 | 
			
		||||
import 'package:comunic/helpers/users_helper.dart';
 | 
			
		||||
@@ -238,6 +239,8 @@ class ConversationsHelper {
 | 
			
		||||
        color: map["color"] == null ? null : HexColor(map["color"]),
 | 
			
		||||
        logoURL: map["logo"],
 | 
			
		||||
        groupID: map["group_id"],
 | 
			
		||||
        groupMinMembershipLevel:
 | 
			
		||||
            APIGroupsMembershipLevelsMap[map["group_min_membership_level"]],
 | 
			
		||||
        members: map["members"]
 | 
			
		||||
            .cast<Map<String, dynamic>>()
 | 
			
		||||
            .map(apiToConversationMember)
 | 
			
		||||
 
 | 
			
		||||
@@ -6,6 +6,7 @@ import 'package:comunic/models/advanced_group_info.dart';
 | 
			
		||||
import 'package:comunic/models/api_request.dart';
 | 
			
		||||
import 'package:comunic/models/group.dart';
 | 
			
		||||
import 'package:comunic/models/group_membership.dart';
 | 
			
		||||
import 'package:comunic/models/new_group_conversation.dart';
 | 
			
		||||
import 'package:comunic/utils/api_utils.dart';
 | 
			
		||||
import 'package:comunic/utils/map_utils.dart';
 | 
			
		||||
 | 
			
		||||
@@ -13,7 +14,7 @@ import 'package:comunic/utils/map_utils.dart';
 | 
			
		||||
///
 | 
			
		||||
/// @author Pierre HUBERT
 | 
			
		||||
 | 
			
		||||
const _APIGroupsMembershipLevelsMap = {
 | 
			
		||||
const APIGroupsMembershipLevelsMap = {
 | 
			
		||||
  "administrator": GroupMembershipLevel.ADMINISTRATOR,
 | 
			
		||||
  "moderator": GroupMembershipLevel.MODERATOR,
 | 
			
		||||
  "member": GroupMembershipLevel.MEMBER,
 | 
			
		||||
@@ -326,7 +327,22 @@ class GroupsHelper {
 | 
			
		||||
      await APIRequest.withLogin("groups/update_membership_level")
 | 
			
		||||
          .addInt("groupID", groupID)
 | 
			
		||||
          .addInt("userID", userID)
 | 
			
		||||
          .addString("level", invertMap(_APIGroupsMembershipLevelsMap)[level])
 | 
			
		||||
          .addString("level", invertMap(APIGroupsMembershipLevelsMap)[level])
 | 
			
		||||
          .execWithThrow();
 | 
			
		||||
 | 
			
		||||
  /// Create a new group conversation
 | 
			
		||||
  ///
 | 
			
		||||
  /// Throws in case of failure
 | 
			
		||||
  static Future<void> createGroupConversation(
 | 
			
		||||
          NewGroupConversation conv) async =>
 | 
			
		||||
      await APIRequest.withLogin("groups/create_conversation")
 | 
			
		||||
          .addInt("group_id", conv.groupID)
 | 
			
		||||
          .addString(
 | 
			
		||||
              "min_membership_level",
 | 
			
		||||
              APIGroupsMembershipLevelsMap.entries
 | 
			
		||||
                  .firstWhere((e) => e.value == conv.minMembershipLevel)
 | 
			
		||||
                  .key)
 | 
			
		||||
          .addString("name", conv.name)
 | 
			
		||||
          .execWithThrow();
 | 
			
		||||
 | 
			
		||||
  /// Turn an API entry into a group object
 | 
			
		||||
@@ -336,7 +352,7 @@ class GroupsHelper {
 | 
			
		||||
        name: map["name"],
 | 
			
		||||
        iconURL: map["icon_url"],
 | 
			
		||||
        numberMembers: map["number_members"],
 | 
			
		||||
        membershipLevel: _APIGroupsMembershipLevelsMap[map["membership"]],
 | 
			
		||||
        membershipLevel: APIGroupsMembershipLevelsMap[map["membership"]],
 | 
			
		||||
        visibilityLevel: _APIGroupsVisibilityLevelsMap[map["visibility"]],
 | 
			
		||||
        registrationLevel:
 | 
			
		||||
            _APIGroupsRegistrationLevelsMap[map["registration_level"]],
 | 
			
		||||
@@ -352,7 +368,7 @@ class GroupsHelper {
 | 
			
		||||
        name: map["name"],
 | 
			
		||||
        iconURL: map["icon_url"],
 | 
			
		||||
        numberMembers: map["number_members"],
 | 
			
		||||
        membershipLevel: _APIGroupsMembershipLevelsMap[map["membership"]],
 | 
			
		||||
        membershipLevel: APIGroupsMembershipLevelsMap[map["membership"]],
 | 
			
		||||
        visibilityLevel: _APIGroupsVisibilityLevelsMap[map["visibility"]],
 | 
			
		||||
        registrationLevel:
 | 
			
		||||
            _APIGroupsRegistrationLevelsMap[map["registration_level"]],
 | 
			
		||||
@@ -373,6 +389,6 @@ class GroupsHelper {
 | 
			
		||||
        userID: row["user_id"],
 | 
			
		||||
        groupID: row["group_id"],
 | 
			
		||||
        timeCreate: row["time_create"],
 | 
			
		||||
        level: _APIGroupsMembershipLevelsMap[row["level"]],
 | 
			
		||||
        level: APIGroupsMembershipLevelsMap[row["level"]],
 | 
			
		||||
      );
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -52,6 +52,8 @@ class ServerConfigurationHelper {
 | 
			
		||||
          minLikesLifetime: dataConservationPolicy["min_likes_lifetime"],
 | 
			
		||||
        ),
 | 
			
		||||
        conversationsPolicy: ConversationsPolicy(
 | 
			
		||||
          maxConversationNameLen:
 | 
			
		||||
              conversationsPolicy["max_conversation_name_len"],
 | 
			
		||||
          minMessageLen: conversationsPolicy["min_message_len"],
 | 
			
		||||
          maxMessageLen: conversationsPolicy["max_message_len"],
 | 
			
		||||
          allowedFilesType:
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,5 @@
 | 
			
		||||
import 'package:comunic/enums/likes_type.dart';
 | 
			
		||||
import 'package:comunic/models/conversation.dart';
 | 
			
		||||
import 'package:comunic/models/like_element.dart';
 | 
			
		||||
import 'package:flutter/material.dart';
 | 
			
		||||
 | 
			
		||||
@@ -15,6 +16,7 @@ class AdvancedGroupInfo extends Group implements LikeElement {
 | 
			
		||||
  String url;
 | 
			
		||||
  int likes;
 | 
			
		||||
  bool userLike;
 | 
			
		||||
  List<Conversation> conversations;
 | 
			
		||||
 | 
			
		||||
  AdvancedGroupInfo({
 | 
			
		||||
    @required int id,
 | 
			
		||||
 
 | 
			
		||||
@@ -4,6 +4,8 @@ import 'package:comunic/utils/account_utils.dart';
 | 
			
		||||
import 'package:flutter/material.dart';
 | 
			
		||||
import 'package:meta/meta.dart';
 | 
			
		||||
 | 
			
		||||
import 'group.dart';
 | 
			
		||||
 | 
			
		||||
/// Conversation model
 | 
			
		||||
///
 | 
			
		||||
/// @author Pierre HUBERT
 | 
			
		||||
@@ -17,6 +19,7 @@ class Conversation extends SerializableElement<Conversation> {
 | 
			
		||||
  final Color color;
 | 
			
		||||
  final String logoURL;
 | 
			
		||||
  final int groupID;
 | 
			
		||||
  final GroupMembershipLevel groupMinMembershipLevel;
 | 
			
		||||
  final List<ConversationMember> members;
 | 
			
		||||
  final bool canEveryoneAddMembers;
 | 
			
		||||
  final CallCapabilities callCapabilities;
 | 
			
		||||
@@ -29,6 +32,7 @@ class Conversation extends SerializableElement<Conversation> {
 | 
			
		||||
    @required this.color,
 | 
			
		||||
    @required this.logoURL,
 | 
			
		||||
    @required this.groupID,
 | 
			
		||||
    @required this.groupMinMembershipLevel,
 | 
			
		||||
    @required this.members,
 | 
			
		||||
    @required this.canEveryoneAddMembers,
 | 
			
		||||
    this.callCapabilities = CallCapabilities.NONE,
 | 
			
		||||
@@ -37,6 +41,7 @@ class Conversation extends SerializableElement<Conversation> {
 | 
			
		||||
        assert(lastActivity != null),
 | 
			
		||||
        assert(members != null),
 | 
			
		||||
        assert(canEveryoneAddMembers != null),
 | 
			
		||||
        assert((groupID == null) == (groupMinMembershipLevel == null)),
 | 
			
		||||
        assert(callCapabilities != null),
 | 
			
		||||
        assert(isHavingCall != null);
 | 
			
		||||
 | 
			
		||||
@@ -78,6 +83,9 @@ class Conversation extends SerializableElement<Conversation> {
 | 
			
		||||
        color = map["color"] == null ? null : Color(map["color"]),
 | 
			
		||||
        logoURL = map["logoURL"],
 | 
			
		||||
        groupID = map["groupID"],
 | 
			
		||||
        groupMinMembershipLevel = GroupMembershipLevel.values.firstWhere(
 | 
			
		||||
            (element) => element.toString() == map["groupMinMembershipLevel"],
 | 
			
		||||
            orElse: () => null),
 | 
			
		||||
        lastActivity = map["lastActivity"],
 | 
			
		||||
        members = map["members"]
 | 
			
		||||
            .map((el) => ConversationMember.fromJSON(el))
 | 
			
		||||
@@ -96,6 +104,7 @@ class Conversation extends SerializableElement<Conversation> {
 | 
			
		||||
      "color": color?.value,
 | 
			
		||||
      "logoURL": logoURL,
 | 
			
		||||
      "groupID": groupID,
 | 
			
		||||
      "groupMinMembershipLevel": groupMinMembershipLevel?.toString(),
 | 
			
		||||
      "lastActivity": lastActivity,
 | 
			
		||||
      "members": members.map((e) => e.toJson()).toList(),
 | 
			
		||||
      "canEveryoneAddMembers": canEveryoneAddMembers,
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										21
									
								
								lib/models/new_group_conversation.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								lib/models/new_group_conversation.dart
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,21 @@
 | 
			
		||||
import 'package:comunic/models/group.dart';
 | 
			
		||||
import 'package:flutter/foundation.dart';
 | 
			
		||||
 | 
			
		||||
/// This class contains information about a conversation linked to a group
 | 
			
		||||
/// to create
 | 
			
		||||
///
 | 
			
		||||
/// @author Pierre Hubert
 | 
			
		||||
 | 
			
		||||
class NewGroupConversation {
 | 
			
		||||
  final int groupID;
 | 
			
		||||
  final String name;
 | 
			
		||||
  final GroupMembershipLevel minMembershipLevel;
 | 
			
		||||
 | 
			
		||||
  const NewGroupConversation({
 | 
			
		||||
    @required this.groupID,
 | 
			
		||||
    @required this.name,
 | 
			
		||||
    @required this.minMembershipLevel,
 | 
			
		||||
  })  : assert(groupID != null),
 | 
			
		||||
        assert(name != null),
 | 
			
		||||
        assert(minMembershipLevel != null);
 | 
			
		||||
}
 | 
			
		||||
@@ -58,6 +58,7 @@ class ServerDataConservationPolicy {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class ConversationsPolicy {
 | 
			
		||||
  final int maxConversationNameLen;
 | 
			
		||||
  final int minMessageLen;
 | 
			
		||||
  final int maxMessageLen;
 | 
			
		||||
  final List<String> allowedFilesType;
 | 
			
		||||
@@ -72,6 +73,7 @@ class ConversationsPolicy {
 | 
			
		||||
  final int maxLogoHeight;
 | 
			
		||||
 | 
			
		||||
  const ConversationsPolicy({
 | 
			
		||||
    @required this.maxConversationNameLen,
 | 
			
		||||
    @required this.minMessageLen,
 | 
			
		||||
    @required this.maxMessageLen,
 | 
			
		||||
    @required this.allowedFilesType,
 | 
			
		||||
@@ -84,7 +86,8 @@ class ConversationsPolicy {
 | 
			
		||||
    @required this.maxThumbnailHeight,
 | 
			
		||||
    @required this.maxLogoWidth,
 | 
			
		||||
    @required this.maxLogoHeight,
 | 
			
		||||
  })  : assert(minMessageLen != null),
 | 
			
		||||
  })  : assert(maxConversationNameLen != null),
 | 
			
		||||
        assert(minMessageLen != null),
 | 
			
		||||
        assert(maxMessageLen != null),
 | 
			
		||||
        assert(allowedFilesType != null),
 | 
			
		||||
        assert(filesMaxSize != null),
 | 
			
		||||
 
 | 
			
		||||
@@ -1,8 +1,10 @@
 | 
			
		||||
import 'dart:typed_data';
 | 
			
		||||
 | 
			
		||||
import 'package:comunic/helpers/groups_helper.dart';
 | 
			
		||||
import 'package:comunic/helpers/server_config_helper.dart';
 | 
			
		||||
import 'package:comunic/models/advanced_group_info.dart';
 | 
			
		||||
import 'package:comunic/models/group.dart';
 | 
			
		||||
import 'package:comunic/models/new_group_conversation.dart';
 | 
			
		||||
import 'package:comunic/ui/dialogs/input_user_password_dialog.dart';
 | 
			
		||||
import 'package:comunic/ui/dialogs/multi_choices_dialog.dart';
 | 
			
		||||
import 'package:comunic/ui/dialogs/virtual_directory_dialog.dart';
 | 
			
		||||
@@ -17,6 +19,7 @@ import 'package:comunic/ui/widgets/settings/text_settings_edit_tile.dart';
 | 
			
		||||
import 'package:comunic/utils/files_utils.dart';
 | 
			
		||||
import 'package:comunic/utils/input_utils.dart';
 | 
			
		||||
import 'package:comunic/utils/intl_utils.dart';
 | 
			
		||||
import 'package:comunic/utils/log_utils.dart';
 | 
			
		||||
import 'package:comunic/utils/ui_utils.dart';
 | 
			
		||||
import 'package:flutter/material.dart';
 | 
			
		||||
import 'package:identicon/identicon.dart';
 | 
			
		||||
@@ -85,6 +88,7 @@ class _GroupSettingsScreenState extends SafeState<GroupSettingsScreen> {
 | 
			
		||||
        HeadSpacerSection(),
 | 
			
		||||
        _buildGeneralSection(),
 | 
			
		||||
        _buildAccessRestrictions(),
 | 
			
		||||
        _buildConversationsArea(),
 | 
			
		||||
        _buildGroupLogoArea(),
 | 
			
		||||
        _buildDangerZone(),
 | 
			
		||||
      ],
 | 
			
		||||
@@ -256,6 +260,75 @@ class _GroupSettingsScreenState extends SafeState<GroupSettingsScreen> {
 | 
			
		||||
        ],
 | 
			
		||||
      );
 | 
			
		||||
 | 
			
		||||
  List<MultiChoiceEntry<GroupMembershipLevel>>
 | 
			
		||||
      get _conversationMinMembershipLevel => [
 | 
			
		||||
            MultiChoiceEntry(
 | 
			
		||||
              id: GroupMembershipLevel.ADMINISTRATOR,
 | 
			
		||||
              title: tr("Administrators only"),
 | 
			
		||||
              subtitle: tr(
 | 
			
		||||
                  "Only the administrators of the group can access the conversation"),
 | 
			
		||||
            ),
 | 
			
		||||
            MultiChoiceEntry(
 | 
			
		||||
              id: GroupMembershipLevel.MODERATOR,
 | 
			
		||||
              title: tr("Moderators and administrators"),
 | 
			
		||||
              subtitle: tr(
 | 
			
		||||
                  "Only moderators and administrators of the group can access the conversation"),
 | 
			
		||||
            ),
 | 
			
		||||
            MultiChoiceEntry(
 | 
			
		||||
              id: GroupMembershipLevel.MEMBER,
 | 
			
		||||
              title: tr("All members"),
 | 
			
		||||
              subtitle: tr(
 | 
			
		||||
                  "All the members of the group can access the conversation"),
 | 
			
		||||
            ),
 | 
			
		||||
          ];
 | 
			
		||||
 | 
			
		||||
  SettingsSection _buildConversationsArea() => SettingsSection(
 | 
			
		||||
        title: tr("Group conversations"),
 | 
			
		||||
        tiles: [
 | 
			
		||||
          SettingsTile(
 | 
			
		||||
            title: tr("Create a new conversation"),
 | 
			
		||||
            onPressed: _createNewGroupConversation,
 | 
			
		||||
          ),
 | 
			
		||||
        ],
 | 
			
		||||
      );
 | 
			
		||||
 | 
			
		||||
  void _createNewGroupConversation(BuildContext context) async {
 | 
			
		||||
    try {
 | 
			
		||||
      final name = await askUserString(
 | 
			
		||||
        context: context,
 | 
			
		||||
        title: tr("New conversation name"),
 | 
			
		||||
        message: tr("Please give a name to the new conversation"),
 | 
			
		||||
        defaultValue: "",
 | 
			
		||||
        hint: tr("Name"),
 | 
			
		||||
        minLength: 1,
 | 
			
		||||
        maxLength: ServerConfigurationHelper
 | 
			
		||||
            .config.conversationsPolicy.maxConversationNameLen,
 | 
			
		||||
      );
 | 
			
		||||
 | 
			
		||||
      if (name == null) return;
 | 
			
		||||
 | 
			
		||||
      final visibility = await showMultiChoicesDialog(
 | 
			
		||||
        context: context,
 | 
			
		||||
        choices: _conversationMinMembershipLevel,
 | 
			
		||||
        defaultChoice: GroupMembershipLevel.MEMBER,
 | 
			
		||||
        title: tr("Conversation visibility"),
 | 
			
		||||
      );
 | 
			
		||||
 | 
			
		||||
      if (visibility == null) return;
 | 
			
		||||
 | 
			
		||||
      await GroupsHelper.createGroupConversation(NewGroupConversation(
 | 
			
		||||
        groupID: _groupSettings.id,
 | 
			
		||||
        name: name,
 | 
			
		||||
        minMembershipLevel: visibility,
 | 
			
		||||
      ));
 | 
			
		||||
 | 
			
		||||
      _key.currentState.refresh();
 | 
			
		||||
    } catch (e, s) {
 | 
			
		||||
      logError(e, s);
 | 
			
		||||
      snack(context, tr("Failed to create a conversation!"));
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  Widget _buildGroupLogoArea() {
 | 
			
		||||
    return SettingsSection(
 | 
			
		||||
      title: tr("Group logo"),
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user