Merge pull request #272 from krawieck/feature/report
This commit is contained in:
commit
8f34591111
|
@ -7,8 +7,8 @@ part of 'config_store.dart';
|
|||
// **************************************************************************
|
||||
|
||||
ConfigStore _$ConfigStoreFromJson(Map<String, dynamic> json) => ConfigStore()
|
||||
..theme = _$enumDecodeNullable(_$ThemeModeEnumMap, json['theme']) ??
|
||||
ThemeMode.system
|
||||
..theme =
|
||||
$enumDecodeNullable(_$ThemeModeEnumMap, json['theme']) ?? ThemeMode.system
|
||||
..amoledDarkMode = json['amoledDarkMode'] as bool? ?? false
|
||||
..locale = LocaleSerde.fromJson(json['locale'] as String?)
|
||||
..showAvatars = json['showAvatars'] as bool? ?? true
|
||||
|
@ -28,43 +28,6 @@ Map<String, dynamic> _$ConfigStoreToJson(ConfigStore instance) =>
|
|||
'defaultListingType': instance.defaultListingType,
|
||||
};
|
||||
|
||||
K _$enumDecode<K, V>(
|
||||
Map<K, V> enumValues,
|
||||
Object? source, {
|
||||
K? unknownValue,
|
||||
}) {
|
||||
if (source == null) {
|
||||
throw ArgumentError(
|
||||
'A value must be provided. Supported values: '
|
||||
'${enumValues.values.join(', ')}',
|
||||
);
|
||||
}
|
||||
|
||||
return enumValues.entries.singleWhere(
|
||||
(e) => e.value == source,
|
||||
orElse: () {
|
||||
if (unknownValue == null) {
|
||||
throw ArgumentError(
|
||||
'`$source` is not one of the supported values: '
|
||||
'${enumValues.values.join(', ')}',
|
||||
);
|
||||
}
|
||||
return MapEntry(unknownValue, enumValues.values.first);
|
||||
},
|
||||
).key;
|
||||
}
|
||||
|
||||
K? _$enumDecodeNullable<K, V>(
|
||||
Map<K, V> enumValues,
|
||||
dynamic source, {
|
||||
K? unknownValue,
|
||||
}) {
|
||||
if (source == null) {
|
||||
return null;
|
||||
}
|
||||
return _$enumDecode<K, V>(enumValues, source, unknownValue: unknownValue);
|
||||
}
|
||||
|
||||
const _$ThemeModeEnumMap = {
|
||||
ThemeMode.system: 'system',
|
||||
ThemeMode.light: 'light',
|
||||
|
|
|
@ -85,6 +85,11 @@ ThemeData _themeFactory({bool dark = false, bool amoled = false}) {
|
|||
),
|
||||
),
|
||||
),
|
||||
dialogTheme: DialogTheme(
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -102,11 +102,15 @@ class CommentWidget extends StatelessWidget {
|
|||
asyncStore: context.read<CommentStore>().deletingState,
|
||||
child: AsyncStoreListener(
|
||||
asyncStore: context.read<CommentStore>().savingState,
|
||||
child: AsyncStoreListener<CommentReportView>(
|
||||
asyncStore: context.read<CommentStore>().reportingState,
|
||||
successMessageBuilder: (context, data) => 'Comment reported',
|
||||
child: const _CommentWidget(),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ import '../../util/observer_consumers.dart';
|
|||
import '../../util/share.dart';
|
||||
import '../bottom_modal.dart';
|
||||
import '../markdown_mode_icon.dart';
|
||||
import '../report_dialog.dart';
|
||||
import '../tile_action.dart';
|
||||
import '../write_comment.dart';
|
||||
import 'comment.dart';
|
||||
|
@ -155,6 +156,23 @@ class _CommentMoreMenuPopup extends HookWidget {
|
|||
store.block(token);
|
||||
}),
|
||||
),
|
||||
ListTile(
|
||||
leading: store.reportingState.isLoading
|
||||
? const CircularProgressIndicator.adaptive()
|
||||
: const Icon(Icons.flag),
|
||||
title: const Text('Report'),
|
||||
onTap: store.reportingState.isLoading
|
||||
? null
|
||||
: () {
|
||||
Navigator.of(context).pop();
|
||||
loggedInAction((token) async {
|
||||
final reason = await ReportDialog.show(context);
|
||||
if (reason != null) {
|
||||
await store.report(token, reason);
|
||||
}
|
||||
})();
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
leading: const Icon(Icons.info_outline),
|
||||
title: const Text('Nerd stuff'),
|
||||
|
|
|
@ -36,6 +36,7 @@ abstract class _CommentStore with Store {
|
|||
final markPersonMentionAsReadState = AsyncStore<PersonMentionView>();
|
||||
final markAsReadState = AsyncStore<FullCommentView>();
|
||||
final blockingState = AsyncStore<BlockedPerson>();
|
||||
final reportingState = AsyncStore<CommentReportView>();
|
||||
|
||||
@computed
|
||||
bool get isMine =>
|
||||
|
@ -76,6 +77,20 @@ abstract class _CommentStore with Store {
|
|||
collapsed = !collapsed;
|
||||
}
|
||||
|
||||
@action
|
||||
Future<void> report(Jwt token, String reason) async {
|
||||
if (reason.trim().isEmpty) throw ArgumentError('reason must not be empty');
|
||||
|
||||
await reportingState.runLemmy(
|
||||
comment.instanceHost,
|
||||
CreateCommentReport(
|
||||
commentId: comment.comment.id,
|
||||
reason: reason,
|
||||
auth: token.raw,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@action
|
||||
Future<void> delete(Jwt token) async {
|
||||
final result = await deletingState.runLemmy(
|
||||
|
|
|
@ -88,6 +88,13 @@ mixin _$CommentStore on _CommentStore, Store {
|
|||
});
|
||||
}
|
||||
|
||||
final _$reportAsyncAction = AsyncAction('_CommentStore.report');
|
||||
|
||||
@override
|
||||
Future<void> report(Jwt token, String reason) {
|
||||
return _$reportAsyncAction.run(() => super.report(token, reason));
|
||||
}
|
||||
|
||||
final _$deleteAsyncAction = AsyncAction('_CommentStore.delete');
|
||||
|
||||
@override
|
||||
|
|
|
@ -41,9 +41,13 @@ class PostTile extends StatelessWidget {
|
|||
final name = state.personView.person.preferredName;
|
||||
return state.blocked ? '$name blocked' : '$name unblocked';
|
||||
},
|
||||
child: AsyncStoreListener<PostReportView>(
|
||||
asyncStore: context.read<PostStore>().reportingState,
|
||||
successMessageBuilder: (context, data) => 'Post reported',
|
||||
child: const _Post(),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
|
|
|
@ -12,6 +12,7 @@ import '../../util/icons.dart';
|
|||
import '../../util/observer_consumers.dart';
|
||||
import '../bottom_modal.dart';
|
||||
import '../info_table_popup.dart';
|
||||
import '../report_dialog.dart';
|
||||
import 'post_store.dart';
|
||||
|
||||
class PostMoreMenuButton extends StatelessWidget {
|
||||
|
@ -121,6 +122,23 @@ class PostMoreMenu extends HookWidget {
|
|||
);
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
leading: store.reportingState.isLoading
|
||||
? const CircularProgressIndicator.adaptive()
|
||||
: const Icon(Icons.flag),
|
||||
title: const Text('Report'),
|
||||
onTap: store.reportingState.isLoading
|
||||
? null
|
||||
: () {
|
||||
Navigator.of(context).pop();
|
||||
loggedInAction((token) async {
|
||||
final reason = await ReportDialog.show(context);
|
||||
if (reason != null) {
|
||||
await store.report(token, reason);
|
||||
}
|
||||
})();
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
leading: const Icon(Icons.info_outline),
|
||||
title: const Text('Nerd stuff'),
|
||||
|
|
|
@ -14,6 +14,7 @@ abstract class _PostStore with Store {
|
|||
final votingState = AsyncStore<PostView>();
|
||||
final savingState = AsyncStore<PostView>();
|
||||
final userBlockingState = AsyncStore<BlockedPerson>();
|
||||
final reportingState = AsyncStore<PostReportView>();
|
||||
|
||||
@observable
|
||||
PostView postView;
|
||||
|
@ -55,6 +56,20 @@ abstract class _PostStore with Store {
|
|||
if (result != null) postView = result;
|
||||
}
|
||||
|
||||
@action
|
||||
Future<void> report(Jwt token, String reason) async {
|
||||
if (reason.trim().isEmpty) throw ArgumentError('reason must not be empty');
|
||||
|
||||
await reportingState.runLemmy(
|
||||
postView.instanceHost,
|
||||
CreatePostReport(
|
||||
postId: postView.post.id,
|
||||
reason: reason,
|
||||
auth: token.raw,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@action
|
||||
Future<void> blockUser(Jwt token) async {
|
||||
final result = await userBlockingState.runLemmy(
|
||||
|
|
|
@ -45,6 +45,13 @@ mixin _$PostStore on _PostStore, Store {
|
|||
return _$saveAsyncAction.run(() => super.save(token));
|
||||
}
|
||||
|
||||
final _$reportAsyncAction = AsyncAction('_PostStore.report');
|
||||
|
||||
@override
|
||||
Future<void> report(Jwt token, String reason) {
|
||||
return _$reportAsyncAction.run(() => super.report(token, reason));
|
||||
}
|
||||
|
||||
final _$blockUserAsyncAction = AsyncAction('_PostStore.blockUser');
|
||||
|
||||
@override
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
|
||||
class ReportDialog extends HookWidget {
|
||||
const ReportDialog();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final controller = useListenable(useTextEditingController());
|
||||
|
||||
return AlertDialog(
|
||||
title: const Text('Report'),
|
||||
content: TextField(
|
||||
autofocus: true,
|
||||
controller: controller,
|
||||
decoration: const InputDecoration(
|
||||
label: Text('reason'),
|
||||
),
|
||||
minLines: 1,
|
||||
maxLines: 3,
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
child: const Text('cancel'),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: controller.text.trim().isEmpty
|
||||
? null
|
||||
: () => Navigator.of(context).pop(controller.text.trim()),
|
||||
child: const Text('report'),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
static Future<String?> show(BuildContext context) async =>
|
||||
showDialog(context: context, builder: (context) => const ReportDialog());
|
||||
}
|
10
pubspec.lock
10
pubspec.lock
|
@ -300,7 +300,7 @@ packages:
|
|||
name: freezed_annotation
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.14.3"
|
||||
version: "0.15.0"
|
||||
frontend_server_client:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -412,14 +412,14 @@ packages:
|
|||
name: json_annotation
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "4.1.0"
|
||||
version: "4.3.0"
|
||||
json_serializable:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: json_serializable
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "5.0.0"
|
||||
version: "6.0.1"
|
||||
keyboard_dismisser:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -440,7 +440,7 @@ packages:
|
|||
name: lemmy_api_client
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.16.0"
|
||||
version: "0.17.0"
|
||||
logging:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -790,7 +790,7 @@ packages:
|
|||
name: source_helper
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.2.1"
|
||||
version: "1.3.0"
|
||||
source_span:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
|
@ -49,12 +49,12 @@ dependencies:
|
|||
# utils
|
||||
timeago: ^3.0.2
|
||||
fuzzy: ^0.4.0-nullsafety.0
|
||||
lemmy_api_client: ^0.16.0
|
||||
lemmy_api_client: ^0.17.0
|
||||
intl: ^0.17.0
|
||||
matrix4_transform: ^2.0.0
|
||||
json_annotation: ^4.1.0
|
||||
json_annotation: ^4.3.0
|
||||
keyboard_dismisser: ^2.0.0
|
||||
freezed_annotation: ^0.14.3
|
||||
freezed_annotation: ^0.15.0
|
||||
logging: ^1.0.1
|
||||
|
||||
flutter:
|
||||
|
@ -70,7 +70,7 @@ dev_dependencies:
|
|||
flutter_test:
|
||||
sdk: flutter
|
||||
flutter_launcher_icons: ^0.9.2
|
||||
json_serializable: ^5.0.0
|
||||
json_serializable: ^6.0.0
|
||||
build_runner: ^2.1.2
|
||||
mobx_codegen: ^2.0.2
|
||||
freezed: ^0.14.1+2
|
||||
|
|
Loading…
Reference in New Issue