mirror of
https://gitlab.com/comunic/comunicmobile
synced 2025-07-01 14:13:29 +00:00
Compare commits
14 Commits
Author | SHA1 | Date | |
---|---|---|---|
e969c85188 | |||
de8b4f7fb4 | |||
f624971717 | |||
49a1098a28 | |||
64bbce2084 | |||
504be2e5ef | |||
79ed8e934e | |||
1bd7840be6 | |||
e80232931e | |||
20b19d0a4a | |||
ec16984b8a | |||
80a1c4e0c4 | |||
512b058d34 | |||
73f20a543d |
@ -340,6 +340,7 @@
|
||||
"Failed to remove conversation logo!": "Erreur lors de la suppression du logo de la conversation !",
|
||||
"Failed to remove member!": "Echec de la suppression d'un membre !",
|
||||
"Failed to send a file!": "Erreur lors de l'envoi d'un fichier !",
|
||||
"Failed to send report!": "Erreur lors de l'envoi du signalement !",
|
||||
"Failed to start recording!": "Erreur lors du lancement de l'enregistrement !",
|
||||
"Failed to toggle admin status of user!": "Echec du changement du status administrateur d'un membre !",
|
||||
"Failed to update conversation settings!": "Echec de la mise à jour des paramètres de la conversation !",
|
||||
@ -500,6 +501,7 @@
|
||||
"Please check back soon!": "Revenez plus tard finir la configuration de l'application !",
|
||||
"Please choose new account image visibility level:": "Veuillez choisir un nouveau niveau de visibilité pour votre image de compte :",
|
||||
"Please choose now the Forez group you want to join...": "Veuillez maintenant choisir le groupe #Forez que vous souhaitez rejoindre...",
|
||||
"Please choose the reason of your report:": "Veuillez indiquer la raison de votre signalement",
|
||||
"Please click on the day you will be in the plain, so that everyone gets informed ! ;)": "Veuillez cliquer sur les jours où vous serez présent dans la plaine du Forez, que tout le monde soit au courant ;)",
|
||||
"Please enter message content: ": "Veuillez entrer le contenu du message :",
|
||||
"Please enter new message content:": "Veuillez entrer le contenu du nouveau message :",
|
||||
@ -534,6 +536,7 @@
|
||||
"Question 1": "Question 1",
|
||||
"Question 2": "Question 2",
|
||||
"Ready": "Prêt",
|
||||
"Reason of report": "Raison du signalement",
|
||||
"Receive notifications for the conversations you follow.": "Recevoir des notifications push pour les conversations que vous suivez",
|
||||
"Record audio": "Faire un enregistrement audio",
|
||||
"Recording...": "Enregistrement...",
|
||||
@ -543,6 +546,8 @@
|
||||
"Remove": "Supprimer",
|
||||
"Remove selected image": "Supprimer l'image sélectionnée",
|
||||
"Replace image": "Remplacer l'image",
|
||||
"Report abuse": "Signaler un abus",
|
||||
"Report successfully saved. Thank you for your contribution!": "Le report a bien été pris en compte. Merci pour votre contribution !",
|
||||
"Request membership": "Demander de rejoindre le groupe",
|
||||
"Requested": "En attente",
|
||||
"Respond to survey": "Répondre au sondage",
|
||||
@ -642,8 +647,11 @@
|
||||
"You can search the people you know and ask them to become your friends!": "Vous pouvez rechercher vos connaissances et les demander en amis !",
|
||||
"You can search the people you know and ask them to become your friends!\\n\\nThis will help you to reach them to exchange information!": "Vous pouvez rechercher vos connaissances et les demander en amis, pour entrer facilement en contact avec elles !",
|
||||
"You can use this virtual directory.": "Vous pouvez utiliser ce répertoire virtuel.",
|
||||
"You do not have any conversation yet!": "Vous n'avez pas encore de conversation !",
|
||||
"You do not have any friend yet!": "Vous n'avez pas encore d'amis sur Comunic !",
|
||||
"You do not have any notification now.": "Vous n'avez pas de notification pour l'intant.",
|
||||
"You do not have any unread conversation yet...": "Vous n'avez aucune conversation non lue pour le moment...",
|
||||
"You have already sent a report for this resource!": "Vous avez déjà soumis un signalement pour cette ressource !",
|
||||
"You must accept the Terms Of Service to continue.": "Vous devez accepter les Conditions d'utilisation pour continuer.",
|
||||
"You security questions have been successfully updated!": "Vos questions de sécurité ont été mises avec succès !",
|
||||
"You will need to restart the application to apply changes": "Vous aurez besoin de redémarrer l'application pour appliquer les changements",
|
||||
|
28
lib/enums/report_target_type.dart
Normal file
28
lib/enums/report_target_type.dart
Normal 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";
|
||||
}
|
||||
}
|
||||
}
|
38
lib/helpers/report_helper.dart
Normal file
38
lib/helpers/report_helper.dart
Normal file
@ -0,0 +1,38 @@
|
||||
import 'package:comunic/enums/report_target_type.dart';
|
||||
import 'package:comunic/models/api_request.dart';
|
||||
import 'package:comunic/models/report_target.dart';
|
||||
import 'package:comunic/models/server_config.dart';
|
||||
|
||||
/// Reports Helper
|
||||
///
|
||||
/// @author Pierre Hubert
|
||||
|
||||
enum ReportResult {
|
||||
Success,
|
||||
ErrorAlreadyReported,
|
||||
Error,
|
||||
}
|
||||
|
||||
class ReportHelper {
|
||||
/// Send a new report to the server
|
||||
static Future<ReportResult> sendReport({
|
||||
required ReportCause cause,
|
||||
required ReportTarget target,
|
||||
required String comment,
|
||||
}) async {
|
||||
final response = await APIRequest.withLogin("reports/create", args: {
|
||||
"cause": cause.id,
|
||||
"target_type": target.type.apiId,
|
||||
"target_id": target.id.toString(),
|
||||
"comment": comment
|
||||
}).exec();
|
||||
|
||||
if (response.isOK) return ReportResult.Success;
|
||||
|
||||
print("Failed to send report: ${response.content}");
|
||||
|
||||
if (response.code == 409) return ReportResult.ErrorAlreadyReported;
|
||||
|
||||
return ReportResult.Error;
|
||||
}
|
||||
}
|
@ -23,77 +23,88 @@ class ServerConfigurationHelper {
|
||||
final dataConservationPolicy = response["data_conservation_policy"];
|
||||
final conversationsPolicy = response["conversations_policy"];
|
||||
final accountInformationPolicy = response["account_info_policy"];
|
||||
final reportPolicy = response["report_policy"];
|
||||
|
||||
_config = ServerConfig(
|
||||
minSupportedMobileVersion:
|
||||
Version.parse(response["min_supported_mobile_version"]),
|
||||
termsURL: response["terms_url"],
|
||||
privacyPolicyURL: response["privacy_policy_url"],
|
||||
contactEmail: response["contact_email"],
|
||||
playStoreURL: response["play_store_url"],
|
||||
androidDirectDownloadURL: response["android_direct_download_url"],
|
||||
banner: banner == null
|
||||
? null
|
||||
: Banner(
|
||||
enabled: banner["enabled"],
|
||||
expire: banner["expire"],
|
||||
nature: BannerNatureExt.fromStr(banner["nature"]),
|
||||
message: Map<String, dynamic>.from(banner["message"])
|
||||
.map((key, value) => MapEntry(key, value.toString())),
|
||||
link: banner["link"]),
|
||||
notificationsPolicy: NotificationsPolicy(
|
||||
hasFirebase: pushNotificationsPolicy["has_firebase"],
|
||||
hasIndependent: pushNotificationsPolicy["has_independent"],
|
||||
),
|
||||
passwordPolicy: PasswordPolicy(
|
||||
allowMailInPassword: passwordPolicy["allow_email_in_password"],
|
||||
allowNameInPassword: passwordPolicy["allow_name_in_password"],
|
||||
minPasswordLength: passwordPolicy["min_password_length"],
|
||||
minNumberUpperCaseLetters:
|
||||
passwordPolicy["min_number_upper_case_letters"],
|
||||
minNumberLowerCaseLetters:
|
||||
passwordPolicy["min_number_lower_case_letters"],
|
||||
minNumberDigits: passwordPolicy["min_number_digits"],
|
||||
minNumberSpecialCharacters:
|
||||
passwordPolicy["min_number_special_characters"],
|
||||
minCategoriesPresence: passwordPolicy["min_categories_presence"],
|
||||
),
|
||||
dataConservationPolicy: ServerDataConservationPolicy(
|
||||
minInactiveAccountLifetime:
|
||||
dataConservationPolicy["min_inactive_account_lifetime"],
|
||||
minNotificationLifetime:
|
||||
dataConservationPolicy["min_notification_lifetime"],
|
||||
minCommentsLifetime: dataConservationPolicy["min_comments_lifetime"],
|
||||
minPostsLifetime: dataConservationPolicy["min_posts_lifetime"],
|
||||
minConversationMessagesLifetime:
|
||||
dataConservationPolicy["min_conversation_messages_lifetime"],
|
||||
minLikesLifetime: dataConservationPolicy["min_likes_lifetime"],
|
||||
),
|
||||
conversationsPolicy: ConversationsPolicy(
|
||||
maxConversationNameLen:
|
||||
conversationsPolicy["max_conversation_name_len"],
|
||||
minMessageLen: conversationsPolicy["min_message_len"],
|
||||
maxMessageLen: conversationsPolicy["max_message_len"],
|
||||
allowedFilesType:
|
||||
conversationsPolicy["allowed_files_type"].cast<String>(),
|
||||
filesMaxSize: conversationsPolicy["files_max_size"],
|
||||
writingEventInterval: conversationsPolicy["writing_event_interval"],
|
||||
writingEventLifetime: conversationsPolicy["writing_event_lifetime"],
|
||||
maxMessageImageWidth: conversationsPolicy["max_message_image_width"],
|
||||
maxMessageImageHeight: conversationsPolicy["max_message_image_height"],
|
||||
maxThumbnailWidth: conversationsPolicy["max_thumbnail_width"],
|
||||
maxThumbnailHeight: conversationsPolicy["max_thumbnail_height"],
|
||||
maxLogoWidth: conversationsPolicy["max_logo_width"],
|
||||
maxLogoHeight: conversationsPolicy["max_logo_height"],
|
||||
),
|
||||
accountInformationPolicy: AccountInformationPolicy(
|
||||
minFirstNameLength: accountInformationPolicy["min_first_name_length"],
|
||||
maxFirstNameLength: accountInformationPolicy["max_first_name_length"],
|
||||
minLastNameLength: accountInformationPolicy["min_last_name_length"],
|
||||
maxLastNameLength: accountInformationPolicy["max_last_name_length"],
|
||||
maxLocationLength: accountInformationPolicy["max_location_length"],
|
||||
),
|
||||
);
|
||||
minSupportedMobileVersion:
|
||||
Version.parse(response["min_supported_mobile_version"]),
|
||||
termsURL: response["terms_url"],
|
||||
privacyPolicyURL: response["privacy_policy_url"],
|
||||
contactEmail: response["contact_email"],
|
||||
playStoreURL: response["play_store_url"],
|
||||
androidDirectDownloadURL: response["android_direct_download_url"],
|
||||
banner: banner == null
|
||||
? null
|
||||
: Banner(
|
||||
enabled: banner["enabled"],
|
||||
expire: banner["expire"],
|
||||
nature: BannerNatureExt.fromStr(banner["nature"]),
|
||||
message: Map<String, dynamic>.from(banner["message"])
|
||||
.map((key, value) => MapEntry(key, value.toString())),
|
||||
link: banner["link"]),
|
||||
notificationsPolicy: NotificationsPolicy(
|
||||
hasFirebase: pushNotificationsPolicy["has_firebase"],
|
||||
hasIndependent: pushNotificationsPolicy["has_independent"],
|
||||
),
|
||||
passwordPolicy: PasswordPolicy(
|
||||
allowMailInPassword: passwordPolicy["allow_email_in_password"],
|
||||
allowNameInPassword: passwordPolicy["allow_name_in_password"],
|
||||
minPasswordLength: passwordPolicy["min_password_length"],
|
||||
minNumberUpperCaseLetters:
|
||||
passwordPolicy["min_number_upper_case_letters"],
|
||||
minNumberLowerCaseLetters:
|
||||
passwordPolicy["min_number_lower_case_letters"],
|
||||
minNumberDigits: passwordPolicy["min_number_digits"],
|
||||
minNumberSpecialCharacters:
|
||||
passwordPolicy["min_number_special_characters"],
|
||||
minCategoriesPresence: passwordPolicy["min_categories_presence"],
|
||||
),
|
||||
dataConservationPolicy: ServerDataConservationPolicy(
|
||||
minInactiveAccountLifetime:
|
||||
dataConservationPolicy["min_inactive_account_lifetime"],
|
||||
minNotificationLifetime:
|
||||
dataConservationPolicy["min_notification_lifetime"],
|
||||
minCommentsLifetime: dataConservationPolicy["min_comments_lifetime"],
|
||||
minPostsLifetime: dataConservationPolicy["min_posts_lifetime"],
|
||||
minConversationMessagesLifetime:
|
||||
dataConservationPolicy["min_conversation_messages_lifetime"],
|
||||
minLikesLifetime: dataConservationPolicy["min_likes_lifetime"],
|
||||
),
|
||||
conversationsPolicy: ConversationsPolicy(
|
||||
maxConversationNameLen:
|
||||
conversationsPolicy["max_conversation_name_len"],
|
||||
minMessageLen: conversationsPolicy["min_message_len"],
|
||||
maxMessageLen: conversationsPolicy["max_message_len"],
|
||||
allowedFilesType:
|
||||
conversationsPolicy["allowed_files_type"].cast<String>(),
|
||||
filesMaxSize: conversationsPolicy["files_max_size"],
|
||||
writingEventInterval: conversationsPolicy["writing_event_interval"],
|
||||
writingEventLifetime: conversationsPolicy["writing_event_lifetime"],
|
||||
maxMessageImageWidth: conversationsPolicy["max_message_image_width"],
|
||||
maxMessageImageHeight:
|
||||
conversationsPolicy["max_message_image_height"],
|
||||
maxThumbnailWidth: conversationsPolicy["max_thumbnail_width"],
|
||||
maxThumbnailHeight: conversationsPolicy["max_thumbnail_height"],
|
||||
maxLogoWidth: conversationsPolicy["max_logo_width"],
|
||||
maxLogoHeight: conversationsPolicy["max_logo_height"],
|
||||
),
|
||||
accountInformationPolicy: AccountInformationPolicy(
|
||||
minFirstNameLength: accountInformationPolicy["min_first_name_length"],
|
||||
maxFirstNameLength: accountInformationPolicy["max_first_name_length"],
|
||||
minLastNameLength: accountInformationPolicy["min_last_name_length"],
|
||||
maxLastNameLength: accountInformationPolicy["max_last_name_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
|
||||
@ -109,4 +120,4 @@ class ServerConfigurationHelper {
|
||||
/// Shortcut for server configuration
|
||||
ServerConfig? get srvConfig => ServerConfigurationHelper.config;
|
||||
|
||||
bool get showBanner => srvConfig!.banner != null && srvConfig!.banner!.visible;
|
||||
bool get showBanner => srvConfig!.banner != null && srvConfig!.banner!.visible;
|
||||
|
@ -6,6 +6,7 @@ import 'package:comunic/lists/comments_list.dart';
|
||||
import 'package:comunic/models/displayed_content.dart';
|
||||
import 'package:comunic/models/like_element.dart';
|
||||
import 'package:comunic/models/survey.dart';
|
||||
import 'package:comunic/utils/account_utils.dart' as account;
|
||||
|
||||
/// Single post information
|
||||
///
|
||||
@ -76,6 +77,8 @@ class Post implements LikeElement {
|
||||
access == UserAccessLevels.FULL ||
|
||||
access == UserAccessLevels.INTERMEDIATE;
|
||||
|
||||
bool get isOwner => userID == account.userID();
|
||||
|
||||
@override
|
||||
LikesType get likeType => LikesType.POST;
|
||||
}
|
||||
|
8
lib/models/report_target.dart
Normal file
8
lib/models/report_target.dart
Normal file
@ -0,0 +1,8 @@
|
||||
import 'package:comunic/enums/report_target_type.dart';
|
||||
|
||||
class ReportTarget {
|
||||
final ReportTargetType type;
|
||||
final int id;
|
||||
|
||||
const ReportTarget(this.type, this.id);
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
import 'package:comunic/utils/date_utils.dart';
|
||||
import 'package:comunic/utils/intl_utils.dart';
|
||||
import 'package:version/version.dart';
|
||||
|
||||
/// Server static configuration
|
||||
@ -137,6 +138,23 @@ class Banner {
|
||||
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 {
|
||||
final Version minSupportedMobileVersion;
|
||||
final String termsURL;
|
||||
@ -150,6 +168,7 @@ class ServerConfig {
|
||||
final ServerDataConservationPolicy dataConservationPolicy;
|
||||
final ConversationsPolicy conversationsPolicy;
|
||||
final AccountInformationPolicy accountInformationPolicy;
|
||||
final ReportPolicy? reportPolicy;
|
||||
|
||||
const ServerConfig({
|
||||
required this.minSupportedMobileVersion,
|
||||
@ -164,5 +183,8 @@ class ServerConfig {
|
||||
required this.dataConservationPolicy,
|
||||
required this.conversationsPolicy,
|
||||
required this.accountInformationPolicy,
|
||||
required this.reportPolicy,
|
||||
});
|
||||
|
||||
bool get isReportingEnabled => this.reportPolicy != null;
|
||||
}
|
||||
|
140
lib/ui/dialogs/report_dialog.dart
Normal file
140
lib/ui/dialogs/report_dialog.dart
Normal file
@ -0,0 +1,140 @@
|
||||
import 'package:comunic/helpers/report_helper.dart';
|
||||
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/dialogs/alert_dialog.dart';
|
||||
import 'package:comunic/ui/routes/main_route/main_route.dart';
|
||||
import 'package:comunic/ui/widgets/comunic_back_button_widget.dart';
|
||||
import 'package:comunic/ui/widgets/safe_state.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 {
|
||||
MainController.of(ctx)!.push(
|
||||
_ReportDialog(target: target),
|
||||
canShowAsDialog: true,
|
||||
hideNavBar: true,
|
||||
);
|
||||
}
|
||||
|
||||
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 SafeState<_ReportDialog> {
|
||||
var _cause = srvConfig!.reportPolicy!.causes.length - 1;
|
||||
var _status = _Status.ChooseCause;
|
||||
final _commentController = TextEditingController();
|
||||
|
||||
List<ReportCause> get _causes => srvConfig!.reportPolicy!.causes;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
leading: ComunicBackButton(),
|
||||
title: Text(tr("Report abuse")!),
|
||||
actions: _status == _Status.Sending
|
||||
? []
|
||||
: [
|
||||
IconButton(
|
||||
onPressed: _goNextStep,
|
||||
icon: Icon(Icons.check),
|
||||
),
|
||||
]),
|
||||
body: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: _buildContent(),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
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:")!),
|
||||
SizedBox(height: 15),
|
||||
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,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
if (_status == _Status.GiveComment) {
|
||||
return Column(
|
||||
children: [
|
||||
Text("You can optionally describe the reason of your report:"),
|
||||
SizedBox(height: 15),
|
||||
TextField(
|
||||
controller: _commentController,
|
||||
decoration: InputDecoration(hintText: tr("Reason of report")),
|
||||
minLines: 5,
|
||||
maxLines: 5,
|
||||
maxLength: srvConfig!.reportPolicy!.maxCommentLength,
|
||||
)
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
throw Exception("Unknown status!");
|
||||
}
|
||||
|
||||
void _goNextStep() async {
|
||||
if (_status == _Status.ChooseCause) {
|
||||
setState(() => _status = _Status.GiveComment);
|
||||
return;
|
||||
}
|
||||
|
||||
// Send report
|
||||
try {
|
||||
setState(() => _status = _Status.Sending);
|
||||
|
||||
final result = await ReportHelper.sendReport(
|
||||
cause: _causes[_cause],
|
||||
target: widget.target,
|
||||
comment: _commentController.value.text,
|
||||
);
|
||||
|
||||
// In case of success
|
||||
if (result == ReportResult.Success) {
|
||||
await alert(context,
|
||||
tr("Report successfully saved. Thank you for your contribution!"));
|
||||
MainController.of(context)!.popPage();
|
||||
} else if (result == ReportResult.ErrorAlreadyReported) {
|
||||
await alert(
|
||||
context, tr("You have already sent a report for this resource!"));
|
||||
MainController.of(context)!.popPage();
|
||||
} else {
|
||||
await alert(context, tr("Failed to send report!"));
|
||||
}
|
||||
} catch (e, s) {
|
||||
print("$e $s");
|
||||
alert(context, tr("Failed to send report!"));
|
||||
} finally {
|
||||
setState(() => _status = _Status.GiveComment);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,4 +1,8 @@
|
||||
import 'package:comunic/enums/report_target_type.dart';
|
||||
import 'package:comunic/models/advanced_group_info.dart';
|
||||
import 'package:comunic/models/group.dart';
|
||||
import 'package:comunic/models/report_target.dart';
|
||||
import 'package:comunic/ui/dialogs/report_dialog.dart';
|
||||
import 'package:comunic/ui/routes/main_route/main_route.dart';
|
||||
import 'package:comunic/ui/screens/group_sections/about_group_section.dart';
|
||||
import 'package:comunic/ui/screens/group_sections/forez_presence_section.dart';
|
||||
@ -65,7 +69,10 @@ class _AuthorizedGroupPageScreenState
|
||||
|
||||
// About the group
|
||||
_GroupPageTab(
|
||||
widget: (c) => AboutGroupSection(group: _group),
|
||||
widget: (c) => AboutGroupSection(
|
||||
group: _group,
|
||||
onReportGroup: _reportGroup,
|
||||
),
|
||||
label: tr("About")!,
|
||||
),
|
||||
|
||||
@ -197,6 +204,10 @@ class _AuthorizedGroupPageScreenState
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// Report group
|
||||
void _reportGroup(Group g) => showReportDialog(
|
||||
ctx: context, target: ReportTarget(ReportTargetType.Group, g.id));
|
||||
}
|
||||
|
||||
class _GroupPageTab {
|
||||
|
@ -1,5 +1,6 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:comunic/enums/report_target_type.dart';
|
||||
import 'package:comunic/helpers/conversations_helper.dart';
|
||||
import 'package:comunic/helpers/events_helper.dart';
|
||||
import 'package:comunic/helpers/server_config_helper.dart';
|
||||
@ -11,7 +12,9 @@ import 'package:comunic/models/config.dart';
|
||||
import 'package:comunic/models/conversation.dart';
|
||||
import 'package:comunic/models/conversation_message.dart';
|
||||
import 'package:comunic/models/new_conversation_message.dart';
|
||||
import 'package:comunic/models/report_target.dart';
|
||||
import 'package:comunic/ui/dialogs/pick_file_dialog.dart';
|
||||
import 'package:comunic/ui/dialogs/report_dialog.dart';
|
||||
import 'package:comunic/ui/routes/main_route/main_route.dart';
|
||||
import 'package:comunic/ui/tiles/conversation_message_tile.dart';
|
||||
import 'package:comunic/ui/tiles/server_conversation_message_tile.dart';
|
||||
@ -504,6 +507,7 @@ class _ConversationScreenState extends SafeState<ConversationScreen> {
|
||||
onRequestMessageStats: _requestMessageStats,
|
||||
onRequestMessageUpdate: _updateMessage,
|
||||
onRequestMessageDelete: _deleteMessage,
|
||||
onReportMessage: _reportMessage,
|
||||
);
|
||||
|
||||
Widget _buildDateWidget(DateTime dt) => Center(
|
||||
@ -753,4 +757,9 @@ class _ConversationScreenState extends SafeState<ConversationScreen> {
|
||||
if (!await _conversationsHelper.deleteMessage(message.id))
|
||||
showSimpleSnack(context, tr("Could not delete conversation message!")!);
|
||||
}
|
||||
|
||||
/// Report message
|
||||
void _reportMessage(ConversationMessage msg) => showReportDialog(
|
||||
ctx: context,
|
||||
target: ReportTarget(ReportTargetType.ConversationMessage, msg.id!));
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:comunic/enums/load_error_level.dart';
|
||||
import 'package:comunic/enums/report_target_type.dart';
|
||||
import 'package:comunic/helpers/conversations_helper.dart';
|
||||
import 'package:comunic/helpers/events_helper.dart';
|
||||
import 'package:comunic/helpers/groups_helper.dart';
|
||||
@ -9,6 +10,8 @@ import 'package:comunic/lists/conversations_list.dart';
|
||||
import 'package:comunic/lists/groups_list.dart';
|
||||
import 'package:comunic/lists/users_list.dart';
|
||||
import 'package:comunic/models/conversation.dart';
|
||||
import 'package:comunic/models/report_target.dart';
|
||||
import 'package:comunic/ui/dialogs/report_dialog.dart';
|
||||
import 'package:comunic/ui/routes/main_route/main_route.dart';
|
||||
import 'package:comunic/ui/screens/create_conversation_screen.dart';
|
||||
import 'package:comunic/ui/tiles/conversation_tile.dart';
|
||||
@ -160,6 +163,11 @@ class _ConversationScreenState extends SafeState<ConversationsListScreen> {
|
||||
_loadConversationsList(false);
|
||||
}
|
||||
|
||||
/// Handle conversation report request
|
||||
void _reportConversation(Conversation conversation) => showReportDialog(
|
||||
ctx: context,
|
||||
target: ReportTarget(ReportTargetType.Conversation, conversation.id!));
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (_error == LoadErrorLevel.MAJOR) return _buildErrorCard();
|
||||
@ -201,6 +209,7 @@ class _ConversationScreenState extends SafeState<ConversationsListScreen> {
|
||||
},
|
||||
onRequestUpdate: _updateConversation,
|
||||
onRequestLeave: _requestLeaveConversation,
|
||||
onReport: _reportConversation,
|
||||
);
|
||||
},
|
||||
itemCount: max(_list!.length, 1),
|
||||
|
@ -1,10 +1,13 @@
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:comunic/enums/report_target_type.dart';
|
||||
import 'package:comunic/helpers/friends_helper.dart';
|
||||
import 'package:comunic/helpers/users_helper.dart';
|
||||
import 'package:comunic/lists/friends_list.dart';
|
||||
import 'package:comunic/lists/users_list.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/pending_friend_tile.dart';
|
||||
import 'package:comunic/ui/widgets/safe_state.dart';
|
||||
@ -151,11 +154,13 @@ class _FriendsListScreenState extends SafeState<FriendsListScreen> {
|
||||
onOpenPrivateConversation: _openPrivateConversation,
|
||||
onSetFollowing: _setFollowingFriend,
|
||||
onRequestDelete: _deleteFriend,
|
||||
onReportFriend: _reportFriend,
|
||||
)
|
||||
: PendingFriendTile(
|
||||
friend: _friendsList![i],
|
||||
user: _usersInfo.getUser(_friendsList![i].id),
|
||||
onRespond: _respondRequest,
|
||||
onReport: _reportFriend,
|
||||
);
|
||||
}),
|
||||
),
|
||||
@ -216,6 +221,10 @@ class _FriendsListScreenState extends SafeState<FriendsListScreen> {
|
||||
_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]
|
||||
Future<void> _openPrivateConversation(Friend friend) async {
|
||||
await openPrivateConversation(context, friend.id);
|
||||
|
@ -1,3 +1,4 @@
|
||||
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/utils/date_utils.dart';
|
||||
@ -11,10 +12,12 @@ import 'package:url_launcher/url_launcher.dart';
|
||||
|
||||
class AboutGroupSection extends StatelessWidget {
|
||||
final AdvancedGroupInfo group;
|
||||
final Function(Group) onReportGroup;
|
||||
|
||||
const AboutGroupSection({
|
||||
Key? key,
|
||||
required this.group,
|
||||
required this.onReportGroup,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
@ -103,6 +106,15 @@ class AboutGroupSection extends StatelessWidget {
|
||||
subtitle: Text(tr("Forez special features enabled")!),
|
||||
)
|
||||
: Container(),
|
||||
// Report group
|
||||
srvConfig!.isReportingEnabled
|
||||
? ListTile(
|
||||
textColor: Colors.red,
|
||||
leading: Icon(Icons.flag, color: Colors.red),
|
||||
title: Text(tr("Report abuse")!),
|
||||
onTap: () => onReportGroup(group),
|
||||
)
|
||||
: Container(),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
@ -1,6 +1,10 @@
|
||||
import 'package:comunic/enums/report_target_type.dart';
|
||||
import 'package:comunic/helpers/groups_helper.dart';
|
||||
import 'package:comunic/helpers/server_config_helper.dart';
|
||||
import 'package:comunic/lists/groups_list.dart';
|
||||
import 'package:comunic/models/group.dart';
|
||||
import 'package:comunic/models/report_target.dart';
|
||||
import 'package:comunic/ui/dialogs/report_dialog.dart';
|
||||
import 'package:comunic/ui/routes/main_route/main_route.dart';
|
||||
import 'package:comunic/ui/widgets/group_icon_widget.dart';
|
||||
import 'package:comunic/ui/widgets/group_membership_widget.dart';
|
||||
@ -70,9 +74,26 @@ class _GroupsListScreenState extends SafeState<GroupsListScreen> {
|
||||
group: g,
|
||||
onUpdated: () => _refreshIndicatorKey.currentState!.show(),
|
||||
),
|
||||
trailing: IconButton(
|
||||
icon: Icon(Icons.delete),
|
||||
onPressed: () => _deleteGroup(g)),
|
||||
trailing: IntrinsicWidth(
|
||||
child: Row(
|
||||
children: [
|
||||
// Remove membership
|
||||
IconButton(
|
||||
icon: Icon(Icons.delete),
|
||||
onPressed: () => _deleteGroup(g)),
|
||||
|
||||
// Report button
|
||||
srvConfig!.isReportingEnabled && !g.isAtLeastMember
|
||||
? IconButton(
|
||||
onPressed: () => _reportGroup(g),
|
||||
icon: Icon(
|
||||
Icons.flag,
|
||||
),
|
||||
)
|
||||
: Container()
|
||||
],
|
||||
),
|
||||
),
|
||||
onTap: () => MainController.of(context)!.openGroup(g.id),
|
||||
))
|
||||
.toList(),
|
||||
@ -122,6 +143,10 @@ class _GroupsListScreenState extends SafeState<GroupsListScreen> {
|
||||
_refreshIndicatorKey.currentState!.show();
|
||||
}
|
||||
|
||||
/// Report a group
|
||||
void _reportGroup(Group g) => showReportDialog(
|
||||
ctx: context, target: ReportTarget(ReportTargetType.Group, g.id));
|
||||
|
||||
/// Add a group
|
||||
void _createGroup() async {
|
||||
try {
|
||||
|
@ -20,8 +20,7 @@ enum _PageStatus { LOADING, ERROR, READY }
|
||||
class UserPageScreen extends StatefulWidget {
|
||||
final int userID;
|
||||
|
||||
const UserPageScreen({Key? key, required this.userID})
|
||||
: super(key: key);
|
||||
const UserPageScreen({Key? key, required this.userID}) : super(key: key);
|
||||
|
||||
@override
|
||||
_UserPageScreenState createState() => _UserPageScreenState();
|
||||
@ -33,7 +32,7 @@ class _UserPageScreenState extends SafeState<UserPageScreen> {
|
||||
|
||||
// Objects members
|
||||
_PageStatus _status = _PageStatus.LOADING;
|
||||
AdvancedUserInfo? _userInfo;
|
||||
AdvancedUserInfo? _userInfo;
|
||||
FriendStatus? _frienshipStatus;
|
||||
final _refreshIndicatorKey = GlobalKey<RefreshIndicatorState>();
|
||||
|
||||
@ -42,7 +41,7 @@ class _UserPageScreenState extends SafeState<UserPageScreen> {
|
||||
@override
|
||||
void didChangeDependencies() {
|
||||
super.didChangeDependencies();
|
||||
if(_userInfo?.id != widget.userID)
|
||||
if (_userInfo?.id == widget.userID) return;
|
||||
_getUserInfo();
|
||||
}
|
||||
|
||||
|
@ -1,8 +1,12 @@
|
||||
import 'package:comunic/enums/report_target_type.dart';
|
||||
import 'package:comunic/enums/user_page_visibility.dart';
|
||||
import 'package:comunic/helpers/friends_helper.dart';
|
||||
import 'package:comunic/helpers/server_config_helper.dart';
|
||||
import 'package:comunic/models/advanced_user_info.dart';
|
||||
import 'package:comunic/models/displayed_content.dart';
|
||||
import 'package:comunic/models/friend_status.dart';
|
||||
import 'package:comunic/models/report_target.dart';
|
||||
import 'package:comunic/ui/dialogs/report_dialog.dart';
|
||||
import 'package:comunic/ui/widgets/FrienshipStatusWidget.dart';
|
||||
import 'package:comunic/ui/widgets/async_screen_widget.dart';
|
||||
import 'package:comunic/ui/widgets/text_widget.dart';
|
||||
@ -21,7 +25,7 @@ class AboutUserSection extends StatefulWidget {
|
||||
const AboutUserSection({
|
||||
Key? key,
|
||||
required this.user,
|
||||
}) : super(key: key);
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
_AboutUserSectionState createState() => _AboutUserSectionState();
|
||||
@ -129,6 +133,21 @@ class _AboutUserSectionState extends State<AboutUserSection> {
|
||||
? tr("Public page")!
|
||||
: tr("Private page")!)),
|
||||
),
|
||||
|
||||
// Report user
|
||||
!widget.user.isCurrentUser && srvConfig!.isReportingEnabled
|
||||
? ListTile(
|
||||
textColor: Colors.red,
|
||||
leading: Icon(Icons.flag, color: Colors.red),
|
||||
title: Text(tr("Report abuse")!),
|
||||
onTap: _reportAbuse,
|
||||
)
|
||||
: Container(),
|
||||
],
|
||||
);
|
||||
|
||||
/// Report user
|
||||
void _reportAbuse() => showReportDialog(
|
||||
ctx: context,
|
||||
target: ReportTarget(ReportTargetType.User, widget.user.id));
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
import 'package:comunic/helpers/server_config_helper.dart';
|
||||
import 'package:comunic/models/friend.dart';
|
||||
import 'package:comunic/models/user.dart';
|
||||
import 'package:comunic/ui/widgets/account_image_widget.dart';
|
||||
@ -10,11 +11,17 @@ import 'package:flutter/material.dart';
|
||||
///
|
||||
/// @author Pierre HUBERT
|
||||
|
||||
enum _FriendMenuChoices { REMOVE, TOGGLE_FOLLOWING, PRIVATE_CONVERSATION }
|
||||
enum _FriendMenuChoices {
|
||||
REMOVE,
|
||||
TOGGLE_FOLLOWING,
|
||||
PRIVATE_CONVERSATION,
|
||||
REPORT
|
||||
}
|
||||
|
||||
typedef OnRequestDeleteFriend = void Function(Friend);
|
||||
typedef OnSetFollowing = void Function(Friend, bool);
|
||||
typedef OnOpenPrivateConversation = void Function(Friend);
|
||||
typedef OnReportFriend = void Function(Friend);
|
||||
|
||||
class AcceptedFriendTile extends StatelessWidget {
|
||||
final Friend friend;
|
||||
@ -22,6 +29,7 @@ class AcceptedFriendTile extends StatelessWidget {
|
||||
final OnRequestDeleteFriend onRequestDelete;
|
||||
final OnSetFollowing onSetFollowing;
|
||||
final OnOpenPrivateConversation onOpenPrivateConversation;
|
||||
final OnReportFriend onReportFriend;
|
||||
|
||||
const AcceptedFriendTile({
|
||||
Key? key,
|
||||
@ -30,6 +38,7 @@ class AcceptedFriendTile extends StatelessWidget {
|
||||
required this.onRequestDelete,
|
||||
required this.onSetFollowing,
|
||||
required this.onOpenPrivateConversation,
|
||||
required this.onReportFriend,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
@ -75,7 +84,15 @@ class AcceptedFriendTile extends StatelessWidget {
|
||||
child: Text(tr("Remove")!),
|
||||
value: _FriendMenuChoices.REMOVE,
|
||||
),
|
||||
],
|
||||
]..addAll(srvConfig!.isReportingEnabled
|
||||
? [
|
||||
// Report user
|
||||
PopupMenuItem(
|
||||
child: Text(tr("Report abuse")!),
|
||||
value: _FriendMenuChoices.REPORT,
|
||||
),
|
||||
]
|
||||
: []),
|
||||
onSelected: _selectedMenuOption,
|
||||
),
|
||||
);
|
||||
@ -97,6 +114,10 @@ class AcceptedFriendTile extends StatelessWidget {
|
||||
case _FriendMenuChoices.REMOVE:
|
||||
onRequestDelete(friend);
|
||||
break;
|
||||
|
||||
case _FriendMenuChoices.REPORT:
|
||||
onReportFriend(friend);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
import 'package:comunic/helpers/server_config_helper.dart';
|
||||
import 'package:comunic/models/comment.dart';
|
||||
import 'package:comunic/models/user.dart';
|
||||
import 'package:comunic/ui/widgets/account_image_widget.dart';
|
||||
@ -13,13 +14,14 @@ import 'package:flutter/material.dart';
|
||||
///
|
||||
/// @author Pierre HUBERT
|
||||
|
||||
enum _CommentAction { DELETE, UPDATE }
|
||||
enum _CommentAction { DELETE, UPDATE, REPORT }
|
||||
|
||||
class CommentTile extends StatelessWidget {
|
||||
final Comment comment;
|
||||
final User user;
|
||||
final void Function(Comment) onUpdateComment;
|
||||
final void Function(Comment) onDeleteComment;
|
||||
final void Function(Comment) onReportComment;
|
||||
|
||||
const CommentTile({
|
||||
Key? key,
|
||||
@ -27,6 +29,7 @@ class CommentTile extends StatelessWidget {
|
||||
required this.user,
|
||||
required this.onUpdateComment,
|
||||
required this.onDeleteComment,
|
||||
required this.onReportComment,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
@ -37,34 +40,13 @@ class CommentTile extends StatelessWidget {
|
||||
user.displayName,
|
||||
),
|
||||
subtitle: _buildCommentContent(),
|
||||
trailing: Text(
|
||||
diffTimeFromNowToStr(comment.timeSent)!,
|
||||
style: TextStyle(fontSize: 10.0),
|
||||
),
|
||||
trailing: _buildTrailing(),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildAccountImageWidget() {
|
||||
return PopupMenuButton<_CommentAction>(
|
||||
child: AccountImageWidget(
|
||||
user: user,
|
||||
),
|
||||
onSelected: _selectedMenuOption,
|
||||
itemBuilder: (c) => [
|
||||
// Update comment content
|
||||
PopupMenuItem(
|
||||
enabled: comment.isOwner,
|
||||
child: Text(tr("Update")!),
|
||||
value: _CommentAction.UPDATE,
|
||||
),
|
||||
|
||||
// Delete comment
|
||||
PopupMenuItem(
|
||||
enabled: comment.isOwner,
|
||||
child: Text(tr("Delete")!),
|
||||
value: _CommentAction.DELETE,
|
||||
),
|
||||
],
|
||||
return AccountImageWidget(
|
||||
user: user,
|
||||
);
|
||||
}
|
||||
|
||||
@ -101,6 +83,49 @@ class CommentTile extends StatelessWidget {
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildTrailing() {
|
||||
return IntrinsicWidth(
|
||||
child: Row(
|
||||
children: [
|
||||
Text(
|
||||
diffTimeFromNowToStr(comment.timeSent)!,
|
||||
style: TextStyle(fontSize: 10.0),
|
||||
),
|
||||
SizedBox(width: 5),
|
||||
PopupMenuButton<_CommentAction>(
|
||||
padding: EdgeInsets.all(0),
|
||||
child: InkWell(
|
||||
child: Icon(Icons.adaptive.more, size: 20),
|
||||
),
|
||||
onSelected: _selectedMenuOption,
|
||||
itemBuilder: (c) => [
|
||||
// Update comment content
|
||||
PopupMenuItem(
|
||||
enabled: comment.isOwner,
|
||||
child: Text(tr("Update")!),
|
||||
value: _CommentAction.UPDATE,
|
||||
),
|
||||
|
||||
// Delete comment
|
||||
PopupMenuItem(
|
||||
enabled: comment.isOwner,
|
||||
child: Text(tr("Delete")!),
|
||||
value: _CommentAction.DELETE,
|
||||
),
|
||||
]..addAll(srvConfig!.isReportingEnabled && !comment.isOwner
|
||||
? [
|
||||
PopupMenuItem(
|
||||
child: Text(tr("Report abuse")!),
|
||||
value: _CommentAction.REPORT,
|
||||
)
|
||||
]
|
||||
: []),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// A menu option has been selected
|
||||
void _selectedMenuOption(_CommentAction value) {
|
||||
switch (value) {
|
||||
@ -113,6 +138,11 @@ class CommentTile extends StatelessWidget {
|
||||
case _CommentAction.DELETE:
|
||||
onDeleteComment(comment);
|
||||
break;
|
||||
|
||||
// Report comment
|
||||
case _CommentAction.REPORT:
|
||||
onReportComment(comment);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
import 'package:comunic/helpers/server_config_helper.dart';
|
||||
import 'package:comunic/models/conversation_message.dart';
|
||||
import 'package:comunic/models/user.dart';
|
||||
import 'package:comunic/ui/widgets/conversation_file_tile.dart';
|
||||
@ -17,6 +18,7 @@ enum _MenuChoices {
|
||||
DELETE,
|
||||
REQUEST_UPDATE_CONTENT,
|
||||
GET_STATS,
|
||||
REPORT
|
||||
}
|
||||
|
||||
typedef OnRequestMessageStats = void Function(ConversationMessage);
|
||||
@ -29,6 +31,7 @@ class ConversationMessageTile extends StatelessWidget {
|
||||
final OnRequestMessageStats onRequestMessageStats;
|
||||
final OnRequestMessageUpdate onRequestMessageUpdate;
|
||||
final OnRequestMessageDelete onRequestMessageDelete;
|
||||
final Function(ConversationMessage) onReportMessage;
|
||||
|
||||
const ConversationMessageTile({
|
||||
Key? key,
|
||||
@ -37,6 +40,7 @@ class ConversationMessageTile extends StatelessWidget {
|
||||
required this.onRequestMessageStats,
|
||||
required this.onRequestMessageUpdate,
|
||||
required this.onRequestMessageDelete,
|
||||
required this.onReportMessage,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
@ -90,6 +94,14 @@ class ConversationMessageTile extends StatelessWidget {
|
||||
value: _MenuChoices.DELETE,
|
||||
child: Text(tr("Delete")!),
|
||||
),
|
||||
|
||||
// Report the message
|
||||
PopupMenuItem(
|
||||
enabled:
|
||||
srvConfig!.isReportingEnabled && !message.isOwner,
|
||||
value: _MenuChoices.REPORT,
|
||||
child: Text(tr("Report abuse")!),
|
||||
),
|
||||
]..removeWhere((element) => !element.enabled),
|
||||
),
|
||||
)
|
||||
@ -133,6 +145,10 @@ class ConversationMessageTile extends StatelessWidget {
|
||||
case _MenuChoices.DELETE:
|
||||
onRequestMessageDelete(message);
|
||||
break;
|
||||
|
||||
case _MenuChoices.REPORT:
|
||||
onReportMessage(message);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
import 'package:comunic/helpers/conversations_helper.dart';
|
||||
import 'package:comunic/helpers/server_config_helper.dart';
|
||||
import 'package:comunic/lists/groups_list.dart';
|
||||
import 'package:comunic/lists/users_list.dart';
|
||||
import 'package:comunic/models/config.dart';
|
||||
@ -18,7 +19,7 @@ typedef OpenConversationCallback = void Function(Conversation);
|
||||
typedef RequestLeaveConversationCallback = void Function(Conversation);
|
||||
typedef RequestUpdateConversationCallback = void Function(Conversation);
|
||||
|
||||
enum _PopupMenuChoices { UPDATE, LEAVE }
|
||||
enum _PopupMenuChoices { UPDATE, LEAVE, REPORT }
|
||||
|
||||
class ConversationTile extends StatelessWidget {
|
||||
final Conversation conversation;
|
||||
@ -27,6 +28,7 @@ class ConversationTile extends StatelessWidget {
|
||||
final OpenConversationCallback onOpen;
|
||||
final RequestUpdateConversationCallback onRequestUpdate;
|
||||
final RequestLeaveConversationCallback onRequestLeave;
|
||||
final Function(Conversation) onReport;
|
||||
|
||||
const ConversationTile({
|
||||
Key? key,
|
||||
@ -36,7 +38,8 @@ class ConversationTile extends StatelessWidget {
|
||||
required this.onOpen,
|
||||
required this.onRequestUpdate,
|
||||
required this.onRequestLeave,
|
||||
}) : super(key: key);
|
||||
required this.onReport,
|
||||
}) : super(key: key);
|
||||
|
||||
_buildSubInformation(IconData icon, String content) {
|
||||
return Row(
|
||||
@ -116,18 +119,26 @@ class ConversationTile extends StatelessWidget {
|
||||
|
||||
onLongPressOpenMenu: (position) {
|
||||
showMenu<_PopupMenuChoices>(
|
||||
context: context,
|
||||
position: position,
|
||||
items: [
|
||||
PopupMenuItem(
|
||||
child: Text(tr("Update")!),
|
||||
value: _PopupMenuChoices.UPDATE,
|
||||
),
|
||||
PopupMenuItem(
|
||||
child: Text(tr("Leave")!),
|
||||
value: _PopupMenuChoices.LEAVE,
|
||||
)
|
||||
]).then(_conversationMenuCallback);
|
||||
context: context,
|
||||
position: position,
|
||||
items: [
|
||||
PopupMenuItem(
|
||||
child: Text(tr("Update")!),
|
||||
value: _PopupMenuChoices.UPDATE,
|
||||
),
|
||||
PopupMenuItem(
|
||||
child: Text(tr("Leave")!),
|
||||
value: _PopupMenuChoices.LEAVE,
|
||||
)
|
||||
]..addAll(srvConfig!.isReportingEnabled
|
||||
? [
|
||||
PopupMenuItem(
|
||||
child: Text(tr("Report abuse")!),
|
||||
value: _PopupMenuChoices.REPORT,
|
||||
)
|
||||
]
|
||||
: []))
|
||||
.then(_conversationMenuCallback);
|
||||
},
|
||||
);
|
||||
|
||||
@ -158,7 +169,11 @@ class ConversationTile extends StatelessWidget {
|
||||
onRequestLeave(conversation);
|
||||
break;
|
||||
|
||||
default:
|
||||
case _PopupMenuChoices.REPORT:
|
||||
onReport(conversation);
|
||||
break;
|
||||
|
||||
case null:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,7 @@
|
||||
import 'package:comunic/helpers/server_config_helper.dart';
|
||||
import 'package:comunic/models/friend.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/utils/intl_utils.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
@ -14,13 +16,15 @@ class PendingFriendTile extends StatelessWidget {
|
||||
final Friend friend;
|
||||
final User user;
|
||||
final RespondFriendshipRequestCallback onRespond;
|
||||
final OnReportFriend onReport;
|
||||
|
||||
const PendingFriendTile(
|
||||
{Key? key,
|
||||
required this.friend,
|
||||
required this.user,
|
||||
required this.onRespond})
|
||||
: super(key: key);
|
||||
const PendingFriendTile({
|
||||
Key? key,
|
||||
required this.friend,
|
||||
required this.user,
|
||||
required this.onRespond,
|
||||
required this.onReport,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@ -56,7 +60,19 @@ class PendingFriendTile extends StatelessWidget {
|
||||
style: ButtonStyle(
|
||||
backgroundColor: MaterialStateProperty.all(Colors.red)),
|
||||
onPressed: () => onRespond(friend, false),
|
||||
)
|
||||
),
|
||||
|
||||
// Report button
|
||||
srvConfig!.isReportingEnabled
|
||||
? IconButton(
|
||||
visualDensity: VisualDensity.compact,
|
||||
onPressed: () => onReport(friend),
|
||||
icon: Icon(
|
||||
Icons.flag,
|
||||
size: 15.0,
|
||||
),
|
||||
)
|
||||
: Container()
|
||||
],
|
||||
),
|
||||
),
|
||||
|
@ -2,15 +2,19 @@ import 'dart:math';
|
||||
|
||||
import 'package:comunic/enums/post_kind.dart';
|
||||
import 'package:comunic/enums/post_visibility_level.dart';
|
||||
import 'package:comunic/enums/report_target_type.dart';
|
||||
import 'package:comunic/helpers/comments_helper.dart';
|
||||
import 'package:comunic/helpers/posts_helper.dart';
|
||||
import 'package:comunic/helpers/server_config_helper.dart';
|
||||
import 'package:comunic/lists/groups_list.dart';
|
||||
import 'package:comunic/lists/users_list.dart';
|
||||
import 'package:comunic/models/comment.dart';
|
||||
import 'package:comunic/models/new_comment.dart';
|
||||
import 'package:comunic/models/post.dart';
|
||||
import 'package:comunic/models/report_target.dart';
|
||||
import 'package:comunic/models/user.dart';
|
||||
import 'package:comunic/ui/dialogs/post_visibility_picker_dialog.dart';
|
||||
import 'package:comunic/ui/dialogs/report_dialog.dart';
|
||||
import 'package:comunic/ui/tiles/comment_tile.dart';
|
||||
import 'package:comunic/ui/widgets/account_image_widget.dart';
|
||||
import 'package:comunic/ui/widgets/countdown_widget.dart';
|
||||
@ -41,7 +45,7 @@ const TextStyle _userNameStyle = TextStyle(
|
||||
fontSize: 16.0);
|
||||
|
||||
/// Post actions
|
||||
enum _PostActions { DELETE, UPDATE_CONTENT }
|
||||
enum _PostActions { DELETE, UPDATE_CONTENT, REPORT }
|
||||
|
||||
class PostTile extends StatefulWidget {
|
||||
final Post post;
|
||||
@ -152,7 +156,14 @@ class _PostTileState extends State<PostTile> {
|
||||
value: _PostActions.DELETE,
|
||||
enabled: widget.post.canDelete,
|
||||
),
|
||||
],
|
||||
]..addAll(srvConfig!.isReportingEnabled && !widget.post.isOwner
|
||||
? [
|
||||
PopupMenuItem(
|
||||
child: Text(tr("Report abuse")!),
|
||||
value: _PostActions.REPORT,
|
||||
)
|
||||
]
|
||||
: []),
|
||||
onSelected: _selectedPostMenuAction,
|
||||
)
|
||||
],
|
||||
@ -356,6 +367,7 @@ class _PostTileState extends State<PostTile> {
|
||||
user: widget.usersInfo.getUser(comment.userID),
|
||||
onUpdateComment: _updateCommentContent,
|
||||
onDeleteComment: _deleteComment,
|
||||
onReportComment: _reportComment,
|
||||
);
|
||||
},
|
||||
);
|
||||
@ -549,6 +561,10 @@ class _PostTileState extends State<PostTile> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Process a report request
|
||||
void _reportComment(Comment comment) => showReportDialog(
|
||||
ctx: context, target: ReportTarget(ReportTargetType.Comment, comment.id));
|
||||
|
||||
/// Method called each time the user has selected an option
|
||||
void _selectedPostMenuAction(_PostActions value) {
|
||||
switch (value) {
|
||||
@ -561,6 +577,11 @@ class _PostTileState extends State<PostTile> {
|
||||
case _PostActions.DELETE:
|
||||
confirmDelete();
|
||||
break;
|
||||
|
||||
// Report content
|
||||
case _PostActions.REPORT:
|
||||
reportContent();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -620,4 +641,9 @@ class _PostTileState extends State<PostTile> {
|
||||
|
||||
widget.onDeletedPost(widget.post);
|
||||
}
|
||||
|
||||
/// Report post
|
||||
void reportContent() async => await showReportDialog(
|
||||
ctx: context,
|
||||
target: ReportTarget(ReportTargetType.Post, widget.post.id));
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ description: Comunic client
|
||||
# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
|
||||
# Read more about iOS versioning at
|
||||
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
||||
version: 1.1.11+18
|
||||
version: 1.1.12+19
|
||||
|
||||
environment:
|
||||
sdk: '>=2.12.0 <3.0.0'
|
||||
|
Reference in New Issue
Block a user