1
0
mirror of https://gitlab.com/comunic/comunicmobile synced 2024-11-24 22:09:21 +00:00

Start to build report dialog

This commit is contained in:
Pierre HUBERT 2022-03-18 17:54:19 +01:00
parent 512b058d34
commit 80a1c4e0c4
8 changed files with 274 additions and 79 deletions

View File

@ -0,0 +1,28 @@
/// What kind of content that can be reported
enum ReportTargetType {
Post,
Comment,
Conversation,
ConversationMessage,
User,
Group
}
extension ReportTargetExt on ReportTargetType {
String get apiId {
switch (this) {
case ReportTargetType.Post:
return "post";
case ReportTargetType.Comment:
return "comment";
case ReportTargetType.Conversation:
return "conversation";
case ReportTargetType.ConversationMessage:
return "conversation_message";
case ReportTargetType.User:
return "user";
case ReportTargetType.Group:
return "group";
}
}
}

View File

@ -23,6 +23,7 @@ class ServerConfigurationHelper {
final dataConservationPolicy = response["data_conservation_policy"]; final dataConservationPolicy = response["data_conservation_policy"];
final conversationsPolicy = response["conversations_policy"]; final conversationsPolicy = response["conversations_policy"];
final accountInformationPolicy = response["account_info_policy"]; final accountInformationPolicy = response["account_info_policy"];
final reportPolicy = response["report_policy"];
_config = ServerConfig( _config = ServerConfig(
minSupportedMobileVersion: minSupportedMobileVersion:
@ -80,7 +81,8 @@ class ServerConfigurationHelper {
writingEventInterval: conversationsPolicy["writing_event_interval"], writingEventInterval: conversationsPolicy["writing_event_interval"],
writingEventLifetime: conversationsPolicy["writing_event_lifetime"], writingEventLifetime: conversationsPolicy["writing_event_lifetime"],
maxMessageImageWidth: conversationsPolicy["max_message_image_width"], maxMessageImageWidth: conversationsPolicy["max_message_image_width"],
maxMessageImageHeight: conversationsPolicy["max_message_image_height"], maxMessageImageHeight:
conversationsPolicy["max_message_image_height"],
maxThumbnailWidth: conversationsPolicy["max_thumbnail_width"], maxThumbnailWidth: conversationsPolicy["max_thumbnail_width"],
maxThumbnailHeight: conversationsPolicy["max_thumbnail_height"], maxThumbnailHeight: conversationsPolicy["max_thumbnail_height"],
maxLogoWidth: conversationsPolicy["max_logo_width"], maxLogoWidth: conversationsPolicy["max_logo_width"],
@ -93,7 +95,16 @@ class ServerConfigurationHelper {
maxLastNameLength: accountInformationPolicy["max_last_name_length"], maxLastNameLength: accountInformationPolicy["max_last_name_length"],
maxLocationLength: accountInformationPolicy["max_location_length"], maxLocationLength: accountInformationPolicy["max_location_length"],
), ),
); reportPolicy: reportPolicy == null
? null
: ReportPolicy(
causes: List.from(reportPolicy["causes"]
.map((cause) => ReportCause(
id: cause["id"],
label: new Map<String, String>.from(cause["label"])))
.toList()),
maxCommentLength: reportPolicy["max_comment_length"],
));
} }
/// Get current server configuration, throwing if it is not loaded yet /// Get current server configuration, throwing if it is not loaded yet

View File

@ -0,0 +1,8 @@
import 'package:comunic/enums/report_target_type.dart';
class ReportTarget {
final ReportTargetType type;
final int targetId;
const ReportTarget(this.type, this.targetId);
}

View File

@ -1,4 +1,5 @@
import 'package:comunic/utils/date_utils.dart'; import 'package:comunic/utils/date_utils.dart';
import 'package:comunic/utils/intl_utils.dart';
import 'package:version/version.dart'; import 'package:version/version.dart';
/// Server static configuration /// Server static configuration
@ -137,6 +138,23 @@ class Banner {
bool get visible => enabled && (expire == null || expire! > time()); bool get visible => enabled && (expire == null || expire! > time());
} }
class ReportCause {
final String id;
final Map<String, String> label;
const ReportCause({required this.id, required this.label});
String get localeLabel =>
label.containsKey(shortLang) ? label[shortLang]! : label["en"]!;
}
class ReportPolicy {
final List<ReportCause> causes;
final int maxCommentLength;
const ReportPolicy({required this.causes, required this.maxCommentLength});
}
class ServerConfig { class ServerConfig {
final Version minSupportedMobileVersion; final Version minSupportedMobileVersion;
final String termsURL; final String termsURL;
@ -150,6 +168,7 @@ class ServerConfig {
final ServerDataConservationPolicy dataConservationPolicy; final ServerDataConservationPolicy dataConservationPolicy;
final ConversationsPolicy conversationsPolicy; final ConversationsPolicy conversationsPolicy;
final AccountInformationPolicy accountInformationPolicy; final AccountInformationPolicy accountInformationPolicy;
final ReportPolicy? reportPolicy;
const ServerConfig({ const ServerConfig({
required this.minSupportedMobileVersion, required this.minSupportedMobileVersion,
@ -164,5 +183,8 @@ class ServerConfig {
required this.dataConservationPolicy, required this.dataConservationPolicy,
required this.conversationsPolicy, required this.conversationsPolicy,
required this.accountInformationPolicy, required this.accountInformationPolicy,
required this.reportPolicy,
}); });
bool get isReportingEnabled => this.reportPolicy != null;
} }

View File

@ -0,0 +1,80 @@
import 'package:comunic/helpers/server_config_helper.dart';
import 'package:comunic/models/report_target.dart';
import 'package:comunic/models/server_config.dart';
import 'package:comunic/ui/widgets/dialogs/cancel_dialog_button.dart';
import 'package:comunic/utils/intl_utils.dart';
import 'package:flutter/material.dart';
enum _Status { ChooseCause, GiveComment, Sending }
/// Show a dialog to report some content
Future<void> showReportDialog({
required BuildContext ctx,
required ReportTarget target,
}) async {
await showDialog(
context: ctx,
builder: (ctx) => _ReportDialog(
target: target,
));
}
class _ReportDialog extends StatefulWidget {
final ReportTarget target;
const _ReportDialog({Key? key, required this.target}) : super(key: key);
@override
State<_ReportDialog> createState() => _ReportDialogState();
}
class _ReportDialogState extends State<_ReportDialog> {
var _cause = srvConfig!.reportPolicy!.causes.length - 1;
var _status = _Status.ChooseCause;
List<ReportCause> get _causes => srvConfig!.reportPolicy!.causes;
@override
Widget build(BuildContext context) {
return AlertDialog(
title: Text(tr("Report abuse")!),
content: Container(width: 100, height: 200, child: _buildContent()),
actions: _status == _Status.Sending
? []
: [
CancelDialogButton(),
MaterialButton(
onPressed: null,
child: Text(
(_status == _Status.ChooseCause ? tr("Next")! : tr("Send")!)
.toUpperCase()),
)
],
);
}
Widget _buildContent() {
if (_status == _Status.Sending)
return Center(child: CircularProgressIndicator());
if (_status == _Status.ChooseCause)
return Column(
children: [
Text(tr("Please choose the reason of your report (you can scroll to access all reasons):")!),
Expanded(
child: ListView.builder(
itemBuilder: (c, i) => RadioListTile(
dense: false,
title: Text(_causes[i].localeLabel),
value: i,
groupValue: _cause,
onChanged: (_i) => setState(() => _cause = i)),
itemCount: _causes.length,
),
),
],
);
throw Exception("todo");
}
}

View File

@ -1,10 +1,13 @@
import 'dart:math'; import 'dart:math';
import 'package:comunic/enums/report_target_type.dart';
import 'package:comunic/helpers/friends_helper.dart'; import 'package:comunic/helpers/friends_helper.dart';
import 'package:comunic/helpers/users_helper.dart'; import 'package:comunic/helpers/users_helper.dart';
import 'package:comunic/lists/friends_list.dart'; import 'package:comunic/lists/friends_list.dart';
import 'package:comunic/lists/users_list.dart'; import 'package:comunic/lists/users_list.dart';
import 'package:comunic/models/friend.dart'; import 'package:comunic/models/friend.dart';
import 'package:comunic/models/report_target.dart';
import 'package:comunic/ui/dialogs/report_dialog.dart';
import 'package:comunic/ui/tiles/accepted_friend_tile.dart'; import 'package:comunic/ui/tiles/accepted_friend_tile.dart';
import 'package:comunic/ui/tiles/pending_friend_tile.dart'; import 'package:comunic/ui/tiles/pending_friend_tile.dart';
import 'package:comunic/ui/widgets/safe_state.dart'; import 'package:comunic/ui/widgets/safe_state.dart';
@ -151,11 +154,13 @@ class _FriendsListScreenState extends SafeState<FriendsListScreen> {
onOpenPrivateConversation: _openPrivateConversation, onOpenPrivateConversation: _openPrivateConversation,
onSetFollowing: _setFollowingFriend, onSetFollowing: _setFollowingFriend,
onRequestDelete: _deleteFriend, onRequestDelete: _deleteFriend,
onReportFriend: _reportFriend,
) )
: PendingFriendTile( : PendingFriendTile(
friend: _friendsList![i], friend: _friendsList![i],
user: _usersInfo.getUser(_friendsList![i].id), user: _usersInfo.getUser(_friendsList![i].id),
onRespond: _respondRequest, onRespond: _respondRequest,
onReport: _reportFriend,
); );
}), }),
), ),
@ -216,6 +221,10 @@ class _FriendsListScreenState extends SafeState<FriendsListScreen> {
_refreshList(); _refreshList();
} }
/// Report a friend
Future<void> _reportFriend(Friend friend) async => await showReportDialog(
ctx: context, target: ReportTarget(ReportTargetType.User, friend.id));
/// Open a private conversation for a given [friend] /// Open a private conversation for a given [friend]
Future<void> _openPrivateConversation(Friend friend) async { Future<void> _openPrivateConversation(Friend friend) async {
await openPrivateConversation(context, friend.id); await openPrivateConversation(context, friend.id);

View File

@ -1,3 +1,4 @@
import 'package:comunic/helpers/server_config_helper.dart';
import 'package:comunic/models/friend.dart'; import 'package:comunic/models/friend.dart';
import 'package:comunic/models/user.dart'; import 'package:comunic/models/user.dart';
import 'package:comunic/ui/widgets/account_image_widget.dart'; import 'package:comunic/ui/widgets/account_image_widget.dart';
@ -10,11 +11,17 @@ import 'package:flutter/material.dart';
/// ///
/// @author Pierre HUBERT /// @author Pierre HUBERT
enum _FriendMenuChoices { REMOVE, TOGGLE_FOLLOWING, PRIVATE_CONVERSATION } enum _FriendMenuChoices {
REMOVE,
TOGGLE_FOLLOWING,
PRIVATE_CONVERSATION,
REPORT
}
typedef OnRequestDeleteFriend = void Function(Friend); typedef OnRequestDeleteFriend = void Function(Friend);
typedef OnSetFollowing = void Function(Friend, bool); typedef OnSetFollowing = void Function(Friend, bool);
typedef OnOpenPrivateConversation = void Function(Friend); typedef OnOpenPrivateConversation = void Function(Friend);
typedef OnReportFriend = void Function(Friend);
class AcceptedFriendTile extends StatelessWidget { class AcceptedFriendTile extends StatelessWidget {
final Friend friend; final Friend friend;
@ -22,6 +29,7 @@ class AcceptedFriendTile extends StatelessWidget {
final OnRequestDeleteFriend onRequestDelete; final OnRequestDeleteFriend onRequestDelete;
final OnSetFollowing onSetFollowing; final OnSetFollowing onSetFollowing;
final OnOpenPrivateConversation onOpenPrivateConversation; final OnOpenPrivateConversation onOpenPrivateConversation;
final OnReportFriend onReportFriend;
const AcceptedFriendTile({ const AcceptedFriendTile({
Key? key, Key? key,
@ -30,6 +38,7 @@ class AcceptedFriendTile extends StatelessWidget {
required this.onRequestDelete, required this.onRequestDelete,
required this.onSetFollowing, required this.onSetFollowing,
required this.onOpenPrivateConversation, required this.onOpenPrivateConversation,
required this.onReportFriend,
}) : super(key: key); }) : super(key: key);
@override @override
@ -75,7 +84,15 @@ class AcceptedFriendTile extends StatelessWidget {
child: Text(tr("Remove")!), child: Text(tr("Remove")!),
value: _FriendMenuChoices.REMOVE, value: _FriendMenuChoices.REMOVE,
), ),
], ]..addAll(srvConfig!.isReportingEnabled
? [
// Report user
PopupMenuItem(
child: Text(tr("Report abuse")!),
value: _FriendMenuChoices.REPORT,
),
]
: []),
onSelected: _selectedMenuOption, onSelected: _selectedMenuOption,
), ),
); );
@ -97,6 +114,10 @@ class AcceptedFriendTile extends StatelessWidget {
case _FriendMenuChoices.REMOVE: case _FriendMenuChoices.REMOVE:
onRequestDelete(friend); onRequestDelete(friend);
break; break;
case _FriendMenuChoices.REPORT:
onReportFriend(friend);
break;
} }
} }
} }

View File

@ -1,5 +1,7 @@
import 'package:comunic/helpers/server_config_helper.dart';
import 'package:comunic/models/friend.dart'; import 'package:comunic/models/friend.dart';
import 'package:comunic/models/user.dart'; import 'package:comunic/models/user.dart';
import 'package:comunic/ui/tiles/accepted_friend_tile.dart';
import 'package:comunic/ui/widgets/account_image_widget.dart'; import 'package:comunic/ui/widgets/account_image_widget.dart';
import 'package:comunic/utils/intl_utils.dart'; import 'package:comunic/utils/intl_utils.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@ -14,13 +16,15 @@ class PendingFriendTile extends StatelessWidget {
final Friend friend; final Friend friend;
final User user; final User user;
final RespondFriendshipRequestCallback onRespond; final RespondFriendshipRequestCallback onRespond;
final OnReportFriend onReport;
const PendingFriendTile( const PendingFriendTile({
{Key? key, Key? key,
required this.friend, required this.friend,
required this.user, required this.user,
required this.onRespond}) required this.onRespond,
: super(key: key); required this.onReport,
}) : super(key: key);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -56,7 +60,19 @@ class PendingFriendTile extends StatelessWidget {
style: ButtonStyle( style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(Colors.red)), backgroundColor: MaterialStateProperty.all(Colors.red)),
onPressed: () => onRespond(friend, false), onPressed: () => onRespond(friend, false),
),
// Report button
srvConfig!.isReportingEnabled
? IconButton(
visualDensity: VisualDensity.compact,
onPressed: () => onReport(friend),
icon: Icon(
Icons.flag,
size: 15.0,
),
) )
: Container()
], ],
), ),
), ),