126 lines
3.4 KiB
Dart
126 lines
3.4 KiB
Dart
// Author: fruit.com.cn
|
|
|
|
import 'package:flutter/material.dart';
|
|
|
|
import '../../../core/data/models/interaction.dart';
|
|
import '../../../l10n/app_localizations.dart';
|
|
|
|
const int _maxDescriptionLength = 300;
|
|
|
|
/// 举报弹窗收集的结果。
|
|
class ReportDialogResult {
|
|
const ReportDialogResult({
|
|
required this.reason,
|
|
required this.description,
|
|
});
|
|
|
|
final ReportReason reason;
|
|
final String description;
|
|
}
|
|
|
|
/// 打开举报原因单选弹窗;取消时返回 null。
|
|
Future<ReportDialogResult?> showReportDialog(
|
|
BuildContext context, {
|
|
required String title,
|
|
}) => showDialog<ReportDialogResult>(
|
|
context: context,
|
|
builder: (_) => _ReportDialog(title: title),
|
|
);
|
|
|
|
class _ReportDialog extends StatefulWidget {
|
|
const _ReportDialog({required this.title});
|
|
|
|
final String title;
|
|
|
|
@override
|
|
State<_ReportDialog> createState() => _ReportDialogState();
|
|
}
|
|
|
|
class _ReportDialogState extends State<_ReportDialog> {
|
|
final _description = TextEditingController();
|
|
ReportReason _reason = ReportReason.spam;
|
|
|
|
@override
|
|
void dispose() {
|
|
_description.dispose();
|
|
super.dispose();
|
|
}
|
|
|
|
void _submit() {
|
|
Navigator.of(context).pop(
|
|
ReportDialogResult(
|
|
reason: _reason,
|
|
description: _description.text.trim(),
|
|
),
|
|
);
|
|
}
|
|
|
|
String _reasonLabel(AppLocalizations l10n, ReportReason reason) =>
|
|
switch (reason) {
|
|
ReportReason.spam => l10n.reportReasonSpam,
|
|
ReportReason.abuse => l10n.reportReasonAbuse,
|
|
ReportReason.porn => l10n.reportReasonPorn,
|
|
ReportReason.ad => l10n.reportReasonAd,
|
|
ReportReason.other => l10n.reportReasonOther,
|
|
};
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final l10n = AppLocalizations.of(context)!;
|
|
return AlertDialog(
|
|
title: Text(widget.title),
|
|
content: SingleChildScrollView(
|
|
child: Column(
|
|
mainAxisSize: MainAxisSize.min,
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Text(l10n.reportReason),
|
|
RadioGroup<ReportReason>(
|
|
groupValue: _reason,
|
|
onChanged: (value) {
|
|
if (value == null) return;
|
|
setState(() => _reason = value);
|
|
},
|
|
child: Column(
|
|
children: [
|
|
for (final reason in ReportReason.values)
|
|
RadioListTile<ReportReason>(
|
|
key: Key('report-reason-${reason.apiValue}'),
|
|
value: reason,
|
|
contentPadding: EdgeInsets.zero,
|
|
dense: true,
|
|
title: Text(_reasonLabel(l10n, reason)),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
const SizedBox(height: 8),
|
|
TextField(
|
|
key: const Key('report-description'),
|
|
controller: _description,
|
|
maxLength: _maxDescriptionLength,
|
|
maxLines: 3,
|
|
minLines: 2,
|
|
decoration: InputDecoration(
|
|
hintText: l10n.reportDescriptionHint,
|
|
border: const OutlineInputBorder(),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
actions: [
|
|
TextButton(
|
|
onPressed: () => Navigator.of(context).pop(),
|
|
child: Text(l10n.cancel),
|
|
),
|
|
FilledButton(
|
|
key: const Key('report-submit'),
|
|
onPressed: _submit,
|
|
child: Text(l10n.reportSubmit),
|
|
),
|
|
],
|
|
);
|
|
}
|
|
}
|