Report abuse

This commit is contained in:
LittleSheep 2024-09-21 22:10:59 +08:00
parent befc647b03
commit 91a32e6736
7 changed files with 211 additions and 75 deletions

View File

@ -440,5 +440,10 @@
"termRelated": "Related Terms", "termRelated": "Related Terms",
"appDetails": "App Details", "appDetails": "App Details",
"projectWebsite": "Project Website", "projectWebsite": "Project Website",
"iAmNotRobot": "I'm not a Robot" "iAmNotRobot": "I'm not a Robot",
"report": "Report",
"reportAbuse": "Report abuse",
"reportAbuseResource": "Resource identifier",
"reportAbuseReason": "Report reason",
"reportSubmitted": "Report submitted, thank you for your contribution. We will send a notification about the result of the report within 24 hours for you."
} }

View File

@ -436,5 +436,10 @@
"termRelated": "相关条款", "termRelated": "相关条款",
"projectWebsite": "项目网站", "projectWebsite": "项目网站",
"appDetails": "应用详情", "appDetails": "应用详情",
"iAmNotRobot": "我不是机器人" "iAmNotRobot": "我不是机器人",
"report": "举报",
"reportAbuse": "举报滥用",
"reportAbuseResource": "举报的资源",
"reportAbuseReason": "举报的原因",
"reportSubmitted": "举报已提交,感谢你的贡献。我们将通过通知在 24 小时内通知该举报的处理结果。"
} }

View File

@ -41,30 +41,21 @@ class _BootstrapperShellState extends State<BootstrapperShell> {
final Completer _bootCompleter = Completer(); final Completer _bootCompleter = Completer();
late final List<({String label, Future<void> Function() action})> _periods = [ Future<void> _checkForUpdate() async {
(
label: 'bsLoadingTheme',
action: () async {
await context.read<ThemeSwitcher>().restoreTheme();
},
),
(
label: 'bsCheckForUpdate',
action: () async {
if (PlatformInfo.isWeb) return; if (PlatformInfo.isWeb) return;
try { try {
final prefs = await SharedPreferences.getInstance(); final prefs = await SharedPreferences.getInstance();
final info = await PackageInfo.fromPlatform(); final info = await PackageInfo.fromPlatform();
final localVersionString = '${info.version}+${info.buildNumber}'; final localVersionString = '${info.version}+${info.buildNumber}';
final resp = await GetConnect().get( final resp = await GetConnect(
timeout: const Duration(seconds: 60),
).get(
'https://git.solsynth.dev/api/v1/repos/hydrogen/solian/tags?page=1&limit=1', 'https://git.solsynth.dev/api/v1/repos/hydrogen/solian/tags?page=1&limit=1',
); );
final remoteVersionString = final remoteVersionString =
(resp.body as List).firstOrNull?['name'] ?? '0.0.0+0'; (resp.body as List).firstOrNull?['name'] ?? '0.0.0+0';
final remoteVersion = final remoteVersion = Version.parse(remoteVersionString.split('+').first);
Version.parse(remoteVersionString.split('+').first); final localVersion = Version.parse(localVersionString.split('+').first);
final localVersion =
Version.parse(localVersionString.split('+').first);
final remoteBuildNumber = final remoteBuildNumber =
int.tryParse(remoteVersionString.split('+').last) ?? 0; int.tryParse(remoteVersionString.split('+').last) ?? 0;
final localBuildNumber = final localBuildNumber =
@ -74,11 +65,6 @@ class _BootstrapperShellState extends State<BootstrapperShell> {
(remoteVersion == localVersion && (remoteVersion == localVersion &&
remoteBuildNumber > localBuildNumber) || remoteBuildNumber > localBuildNumber) ||
(remoteVersionString != localVersionString && strictUpdate)) { (remoteVersionString != localVersionString && strictUpdate)) {
setState(() {
_isErrored = true;
_subtitle = 'bsCheckForUpdateDesc'.tr;
});
if (PlatformInfo.isAndroid) { if (PlatformInfo.isAndroid) {
context context
.showConfirmDialog( .showConfirmDialog(
@ -100,10 +86,10 @@ class _BootstrapperShellState extends State<BootstrapperShell> {
} }
}); });
} else { } else {
setState(() { context.showInfoDialog(
_isErrored = true; 'updateAvailable'.tr,
_subtitle = 'bsCheckForUpdateDesc'.tr; 'bsCheckForUpdateDesc'.tr,
}); );
} }
} else if (remoteVersionString != localVersionString) { } else if (remoteVersionString != localVersionString) {
_bootCompleter.future.then((_) { _bootCompleter.future.then((_) {
@ -115,6 +101,13 @@ class _BootstrapperShellState extends State<BootstrapperShell> {
} catch (e) { } catch (e) {
context.showErrorDialog('Unable to check update: $e'); context.showErrorDialog('Unable to check update: $e');
} }
}
late final List<({String label, Future<void> Function() action})> _periods = [
(
label: 'bsLoadingTheme',
action: () async {
await context.read<ThemeSwitcher>().restoreTheme();
}, },
), ),
( (
@ -214,6 +207,7 @@ class _BootstrapperShellState extends State<BootstrapperShell> {
void initState() { void initState() {
super.initState(); super.initState();
_runPeriods(); _runPeriods();
_checkForUpdate();
} }
@override @override

View File

@ -146,7 +146,10 @@ class _SignUpScreenState extends State<SignUpScreen> {
const Gap(8), const Gap(8),
CheckboxListTile( CheckboxListTile(
value: _isTermAccepted, value: _isTermAccepted,
title: Text('termAccept'.tr), title: Text(
'termAccept'.tr,
style: const TextStyle(height: 1.2),
).paddingOnly(bottom: 4),
shape: const RoundedRectangleBorder( shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all( borderRadius: BorderRadius.all(
Radius.circular(8), Radius.circular(8),

View File

@ -74,9 +74,13 @@ class LinkExpansion extends StatelessWidget {
), ),
).paddingOnly(right: 8), ).paddingOnly(right: 8),
if (snapshot.data!.siteName != null) if (snapshot.data!.siteName != null)
Text( Expanded(
child: Text(
snapshot.data!.siteName!, snapshot.data!.siteName!,
style: Theme.of(context).textTheme.labelLarge, style: Theme.of(context).textTheme.labelLarge,
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
), ),
], ],
).paddingOnly( ).paddingOnly(

View File

@ -12,6 +12,7 @@ import 'package:solian/platform.dart';
import 'package:solian/providers/auth.dart'; import 'package:solian/providers/auth.dart';
import 'package:solian/router.dart'; import 'package:solian/router.dart';
import 'package:solian/screens/posts/post_editor.dart'; import 'package:solian/screens/posts/post_editor.dart';
import 'package:solian/widgets/reports/abuse_report.dart';
class PostAction extends StatefulWidget { class PostAction extends StatefulWidget {
final Post item; final Post item;
@ -149,6 +150,23 @@ class _PostActionState extends State<PostAction> {
Navigator.pop(context); Navigator.pop(context);
}, },
), ),
ListTile(
contentPadding: const EdgeInsets.symmetric(horizontal: 24),
leading: const Icon(Icons.report),
title: Text('report'.tr),
onTap: () {
showDialog(
context: context,
builder: (context) => AbuseReportDialog(
resourceId: 'post:${widget.item.id}',
),
).then((status) {
if (status == true) {
Navigator.pop(context);
}
});
},
),
if (!widget.noReact) if (!widget.noReact)
ListTile( ListTile(
contentPadding: const EdgeInsets.symmetric(horizontal: 24), contentPadding: const EdgeInsets.symmetric(horizontal: 24),

View File

@ -0,0 +1,107 @@
import 'package:flutter/material.dart';
import 'package:gap/gap.dart';
import 'package:get/get.dart';
import 'package:solian/exceptions/request.dart';
import 'package:solian/exts.dart';
import 'package:solian/providers/auth.dart';
class AbuseReportDialog extends StatefulWidget {
final String? resourceId;
const AbuseReportDialog({super.key, this.resourceId});
@override
State<AbuseReportDialog> createState() => _AbuseReportDialogState();
}
class _AbuseReportDialogState extends State<AbuseReportDialog> {
final TextEditingController _resourceController = TextEditingController();
final TextEditingController _reasonController = TextEditingController();
bool _isBusy = false;
Future<void> _submit() async {
final auth = Get.find<AuthProvider>();
if (!auth.isAuthorized.value) return;
final client = await auth.configureClient('id');
setState(() => _isBusy = true);
final resp = await client.post('/reports/abuse', {
'resource': _resourceController.text,
'reason': _reasonController.text,
});
setState(() => _isBusy = false);
if (resp.statusCode != 200) {
context.showErrorDialog(RequestException(resp));
} else {
context.showSnackbar('reportSubmitted'.tr);
Navigator.pop(context, true);
}
}
@override
void initState() {
if (widget.resourceId != null) {
_resourceController.text = widget.resourceId!;
}
super.initState();
}
@override
void dispose() {
_resourceController.dispose();
_reasonController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return AlertDialog(
title: Text('reportAbuse'.tr),
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
const Gap(4),
TextField(
controller: _resourceController,
decoration: InputDecoration(
border: const OutlineInputBorder(),
labelText: 'reportAbuseResource'.tr,
enabled: widget.resourceId == null,
isDense: true,
),
),
const Gap(12),
TextField(
controller: _reasonController,
textInputAction: TextInputAction.newline,
minLines: 1,
maxLines: 3,
decoration: InputDecoration(
border: const OutlineInputBorder(),
labelText: 'reportAbuseReason'.tr,
isDense: true,
),
),
],
),
actions: [
TextButton(
onPressed: _isBusy
? null
: () {
Navigator.pop(context);
},
child: Text('cancel'.tr),
),
TextButton(
onPressed: _isBusy ? null : () => _submit(),
child: Text('okay'.tr),
),
],
);
}
}