Compare commits
3 Commits
4a9ccc7c7a
...
efddaf50f2
Author | SHA1 | Date | |
---|---|---|---|
efddaf50f2 | |||
d4aaf61091 | |||
fa346b528e |
@ -387,5 +387,14 @@
|
|||||||
"articleWrittenAt": "Written at {}",
|
"articleWrittenAt": "Written at {}",
|
||||||
"articleEditedAt": "Edited at {}",
|
"articleEditedAt": "Edited at {}",
|
||||||
"attachmentSaved": "Saved to album",
|
"attachmentSaved": "Saved to album",
|
||||||
"openInAlbum": "Open in album"
|
"openInAlbum": "Open in album",
|
||||||
|
"postAbuseReport": "Report Post",
|
||||||
|
"postAbuseReportDescription": "Report posts that violate our user agreement and community guidelines to help us improve the content on Solar Network. Please describe how this post violates the relevant rules. Do not include any sensitive information. We will process your report within 24 hours.",
|
||||||
|
"abuseReport": "Abuse Report",
|
||||||
|
"abuseReportDescription": "Report any resources that violate our user agreement and community guidelines to help us improve the content on Solar Network. Please describe the location of the resource (provide resource ID as best as possible) and how this violates the relevant rules. Do not include any sensitive information. We will process your report within 24 hours.",
|
||||||
|
"abuseReportActionDescription": "Report abuse usage behavior.",
|
||||||
|
"abuseReportResource": "Resource Location / ID",
|
||||||
|
"abuseReportReason": "Reason",
|
||||||
|
"abuseReportSubmitted": "Report submitted, thank you for your contribution.",
|
||||||
|
"submit": "Submit"
|
||||||
}
|
}
|
||||||
|
@ -377,7 +377,7 @@
|
|||||||
"accountJoinedAt": "加入于 {}",
|
"accountJoinedAt": "加入于 {}",
|
||||||
"accountBirthday": "出生于 {}",
|
"accountBirthday": "出生于 {}",
|
||||||
"accountBadge": "徽章",
|
"accountBadge": "徽章",
|
||||||
"badgeCompanyStaff": "索尔辛茨士大夫 · Staff",
|
"badgeCompanyStaff": "索尔辛茨士大夫 · 员工",
|
||||||
"badgeSiteMigration": "Solar Network 原住民",
|
"badgeSiteMigration": "Solar Network 原住民",
|
||||||
"accountStatus": "状态",
|
"accountStatus": "状态",
|
||||||
"accountStatusOnline": "在线",
|
"accountStatusOnline": "在线",
|
||||||
@ -387,5 +387,14 @@
|
|||||||
"articleWrittenAt": "发表于 {}",
|
"articleWrittenAt": "发表于 {}",
|
||||||
"articleEditedAt": "编辑于 {}",
|
"articleEditedAt": "编辑于 {}",
|
||||||
"attachmentSaved": "已保存到相册",
|
"attachmentSaved": "已保存到相册",
|
||||||
"openInAlbum": "在相册中打开"
|
"openInAlbum": "在相册中打开",
|
||||||
|
"postAbuseReport": "检举帖子",
|
||||||
|
"postAbuseReportDescription": "检举不符合我们用户协议以及社区准则的帖子,来帮助我们更好的维护 Solar Network 上的内容。请在下面描述该帖子如何违反我么的相关规定。请勿填写任何敏感信息。我们将会在 24 小时内处理您的检举。",
|
||||||
|
"abuseReport": "检举",
|
||||||
|
"abuseReportDescription": "检举不符合我们用户协议以及社区准则的任何资源,来帮助我们更好的维护 Solar Network 上的内容。请在下面描述资源的位置(提供资源 ID 为佳)以及如何违反我么的相关规定。请勿填写任何敏感信息。我们将会在 24 小时内处理您的检举。",
|
||||||
|
"abuseReportActionDescription": "检举不合规行为。",
|
||||||
|
"abuseReportResource": "资源位置 / ID",
|
||||||
|
"abuseReportReason": "检举原因",
|
||||||
|
"abuseReportSubmitted": "检举已提交,感谢你的贡献。",
|
||||||
|
"submit": "提交"
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ import 'package:go_router/go_router.dart';
|
|||||||
import 'package:material_symbols_icons/symbols.dart';
|
import 'package:material_symbols_icons/symbols.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import 'package:styled_widget/styled_widget.dart';
|
import 'package:styled_widget/styled_widget.dart';
|
||||||
|
import 'package:surface/providers/sn_network.dart';
|
||||||
import 'package:surface/providers/userinfo.dart';
|
import 'package:surface/providers/userinfo.dart';
|
||||||
import 'package:surface/widgets/account/account_image.dart';
|
import 'package:surface/widgets/account/account_image.dart';
|
||||||
import 'package:surface/widgets/app_bar_leading.dart';
|
import 'package:surface/widgets/app_bar_leading.dart';
|
||||||
@ -104,6 +105,23 @@ class _AuthorizedAccountScreen extends StatelessWidget {
|
|||||||
GoRouter.of(context).pushNamed('accountPublishers');
|
GoRouter.of(context).pushNamed('accountPublishers');
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
ListTile(
|
||||||
|
title: Text('abuseReport').tr(),
|
||||||
|
subtitle: Text('abuseReportActionDescription').tr(),
|
||||||
|
contentPadding: const EdgeInsets.symmetric(horizontal: 24),
|
||||||
|
leading: const Icon(Symbols.flag),
|
||||||
|
trailing: const Icon(Symbols.chevron_right),
|
||||||
|
onTap: () {
|
||||||
|
showDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (context) => _AbuseReportDialog(),
|
||||||
|
).then((value) {
|
||||||
|
if (value == true && context.mounted) {
|
||||||
|
context.showSnackbar('abuseReportSubmitted'.tr());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
),
|
||||||
ListTile(
|
ListTile(
|
||||||
title: Text('accountLogout').tr(),
|
title: Text('accountLogout').tr(),
|
||||||
subtitle: Text('accountLogoutSubtitle').tr(),
|
subtitle: Text('accountLogoutSubtitle').tr(),
|
||||||
@ -183,3 +201,89 @@ class _UnauthorizedAccountScreen extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class _AbuseReportDialog extends StatefulWidget {
|
||||||
|
const _AbuseReportDialog({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<_AbuseReportDialog> createState() => _AbuseReportDialogState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _AbuseReportDialogState extends State<_AbuseReportDialog> {
|
||||||
|
bool _isBusy = false;
|
||||||
|
|
||||||
|
final _resourceController = TextEditingController();
|
||||||
|
final _reasonController = TextEditingController();
|
||||||
|
|
||||||
|
@override
|
||||||
|
dispose() {
|
||||||
|
_resourceController.dispose();
|
||||||
|
_reasonController.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _performAction() async {
|
||||||
|
setState(() => _isBusy = true);
|
||||||
|
try {
|
||||||
|
final sn = context.read<SnNetworkProvider>();
|
||||||
|
await sn.client.request(
|
||||||
|
'/cgi/id/reports/abuse',
|
||||||
|
data: {
|
||||||
|
'resource': _resourceController.text,
|
||||||
|
'reason': _reasonController.text,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
if (!mounted) return;
|
||||||
|
Navigator.pop(context, true);
|
||||||
|
} catch (err) {
|
||||||
|
if (!mounted) return;
|
||||||
|
context.showErrorDialog(err);
|
||||||
|
} finally {
|
||||||
|
setState(() => _isBusy = false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return AlertDialog(
|
||||||
|
title: Text('abuseReport'.tr()),
|
||||||
|
content: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text('abuseReportDescription'.tr()),
|
||||||
|
const Gap(12),
|
||||||
|
TextField(
|
||||||
|
controller: _resourceController,
|
||||||
|
maxLength: null,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
border: const UnderlineInputBorder(),
|
||||||
|
labelText: 'abuseReportResource'.tr(),
|
||||||
|
),
|
||||||
|
onTapOutside: (_) => FocusManager.instance.primaryFocus?.unfocus(),
|
||||||
|
),
|
||||||
|
const Gap(4),
|
||||||
|
TextField(
|
||||||
|
controller: _reasonController,
|
||||||
|
maxLength: null,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
border: const UnderlineInputBorder(),
|
||||||
|
labelText: 'abuseReportReason'.tr(),
|
||||||
|
),
|
||||||
|
onTapOutside: (_) => FocusManager.instance.primaryFocus?.unfocus(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
actions: [
|
||||||
|
TextButton(
|
||||||
|
onPressed: _isBusy ? null : () => Navigator.pop(context),
|
||||||
|
child: Text('dialogDismiss').tr(),
|
||||||
|
),
|
||||||
|
TextButton(
|
||||||
|
onPressed: _isBusy ? null : _performAction,
|
||||||
|
child: Text('submit').tr(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -6,6 +6,7 @@ import 'package:gap/gap.dart';
|
|||||||
import 'package:google_fonts/google_fonts.dart';
|
import 'package:google_fonts/google_fonts.dart';
|
||||||
import 'package:material_symbols_icons/symbols.dart';
|
import 'package:material_symbols_icons/symbols.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:relative_time/relative_time.dart';
|
||||||
import 'package:styled_widget/styled_widget.dart';
|
import 'package:styled_widget/styled_widget.dart';
|
||||||
import 'package:surface/providers/sn_network.dart';
|
import 'package:surface/providers/sn_network.dart';
|
||||||
import 'package:surface/types/account.dart';
|
import 'package:surface/types/account.dart';
|
||||||
@ -28,14 +29,14 @@ const Map<String, (String, IconData, Color)> kBadgesMeta = {
|
|||||||
|
|
||||||
class UserScreen extends StatefulWidget {
|
class UserScreen extends StatefulWidget {
|
||||||
final String name;
|
final String name;
|
||||||
|
|
||||||
const UserScreen({super.key, required this.name});
|
const UserScreen({super.key, required this.name});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<UserScreen> createState() => _UserScreenState();
|
State<UserScreen> createState() => _UserScreenState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _UserScreenState extends State<UserScreen>
|
class _UserScreenState extends State<UserScreen> with SingleTickerProviderStateMixin {
|
||||||
with SingleTickerProviderStateMixin {
|
|
||||||
late final ScrollController _scrollController = ScrollController();
|
late final ScrollController _scrollController = ScrollController();
|
||||||
|
|
||||||
SnAccount? _account;
|
SnAccount? _account;
|
||||||
@ -75,14 +76,12 @@ class _UserScreenState extends State<UserScreen>
|
|||||||
double _appBarBlur = 0.0;
|
double _appBarBlur = 0.0;
|
||||||
|
|
||||||
late final _appBarWidth = MediaQuery.of(context).size.width;
|
late final _appBarWidth = MediaQuery.of(context).size.width;
|
||||||
late final _appBarHeight =
|
late final _appBarHeight = (_appBarWidth * kBannerAspectRatio).roundToDouble();
|
||||||
(_appBarWidth * kBannerAspectRatio).roundToDouble();
|
|
||||||
|
|
||||||
void _updateAppBarBlur() {
|
void _updateAppBarBlur() {
|
||||||
if (_scrollController.offset > _appBarHeight) return;
|
if (_scrollController.offset > _appBarHeight) return;
|
||||||
setState(() {
|
setState(() {
|
||||||
_appBarBlur =
|
_appBarBlur = (_scrollController.offset / _appBarHeight * 10).clamp(0.0, 10.0);
|
||||||
(_scrollController.offset / _appBarHeight * 10).clamp(0.0, 10.0);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -218,9 +217,7 @@ class _UserScreenState extends State<UserScreen>
|
|||||||
Symbols.circle,
|
Symbols.circle,
|
||||||
fill: 1,
|
fill: 1,
|
||||||
size: 16,
|
size: 16,
|
||||||
color: (_status?.isOnline ?? false)
|
color: (_status?.isOnline ?? false) ? Colors.green : Colors.grey,
|
||||||
? Colors.green
|
|
||||||
: Colors.grey,
|
|
||||||
).padding(all: 4),
|
).padding(all: 4),
|
||||||
const Gap(8),
|
const Gap(8),
|
||||||
Text(
|
Text(
|
||||||
@ -230,19 +227,55 @@ class _UserScreenState extends State<UserScreen>
|
|||||||
: 'accountStatusOffline'.tr()
|
: 'accountStatusOffline'.tr()
|
||||||
: 'loading'.tr(),
|
: 'loading'.tr(),
|
||||||
),
|
),
|
||||||
|
if (_status != null && !_status!.isOnline && _status!.lastSeenAt != null)
|
||||||
|
Text(
|
||||||
|
'accountStatusLastSeen'.tr(args: [
|
||||||
|
_status!.lastSeenAt != null
|
||||||
|
? RelativeTime(context).format(
|
||||||
|
_status!.lastSeenAt!.toLocal(),
|
||||||
|
)
|
||||||
|
: 'unknown',
|
||||||
|
]),
|
||||||
|
).padding(left: 6).opacity(0.75),
|
||||||
],
|
],
|
||||||
).padding(vertical: 8, horizontal: 12),
|
).padding(vertical: 8, horizontal: 12),
|
||||||
),
|
),
|
||||||
const Gap(8),
|
const Gap(8),
|
||||||
|
Wrap(
|
||||||
|
children: _account!.badges
|
||||||
|
.map(
|
||||||
|
(ele) => Tooltip(
|
||||||
|
richMessage: TextSpan(
|
||||||
|
children: [
|
||||||
|
TextSpan(text: kBadgesMeta[ele.type]?.$1.tr() ?? 'unknown'.tr()),
|
||||||
|
if (ele.metadata['title'] != null)
|
||||||
|
TextSpan(
|
||||||
|
text: '\n${ele.metadata['title']}',
|
||||||
|
style: const TextStyle(fontWeight: FontWeight.bold),
|
||||||
|
),
|
||||||
|
TextSpan(text: '\n'),
|
||||||
|
TextSpan(
|
||||||
|
text: DateFormat.yMEd().format(ele.createdAt),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
child: Icon(
|
||||||
|
kBadgesMeta[ele.type]?.$2 ?? Symbols.question_mark,
|
||||||
|
color: kBadgesMeta[ele.type]?.$3,
|
||||||
|
fill: 1,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.toList(),
|
||||||
|
).padding(horizontal: 8),
|
||||||
|
const Gap(8),
|
||||||
Column(
|
Column(
|
||||||
children: [
|
children: [
|
||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
const Icon(Symbols.calendar_add_on),
|
const Icon(Symbols.calendar_add_on),
|
||||||
const Gap(8),
|
const Gap(8),
|
||||||
Text('publisherJoinedAt').tr(args: [
|
Text('publisherJoinedAt').tr(args: [DateFormat('y/M/d').format(_account!.createdAt)]),
|
||||||
DateFormat('y/M/d').format(_account!.createdAt)
|
|
||||||
]),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
Row(
|
Row(
|
||||||
@ -279,11 +312,7 @@ class _UserScreenState extends State<UserScreen>
|
|||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text('accountBadge')
|
Text('accountBadge').bold().fontSize(17).tr().padding(horizontal: 20, bottom: 4),
|
||||||
.bold()
|
|
||||||
.fontSize(17)
|
|
||||||
.tr()
|
|
||||||
.padding(horizontal: 20, bottom: 4),
|
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: 80,
|
height: 80,
|
||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
@ -297,8 +326,7 @@ class _UserScreenState extends State<UserScreen>
|
|||||||
child: Card(
|
child: Card(
|
||||||
child: ListTile(
|
child: ListTile(
|
||||||
leading: Icon(
|
leading: Icon(
|
||||||
kBadgesMeta[badge.type]?.$2 ??
|
kBadgesMeta[badge.type]?.$2 ?? Symbols.question_mark,
|
||||||
Symbols.question_mark,
|
|
||||||
color: kBadgesMeta[badge.type]?.$3,
|
color: kBadgesMeta[badge.type]?.$3,
|
||||||
fill: 1,
|
fill: 1,
|
||||||
),
|
),
|
||||||
@ -308,8 +336,7 @@ class _UserScreenState extends State<UserScreen>
|
|||||||
subtitle: badge.metadata['title'] != null
|
subtitle: badge.metadata['title'] != null
|
||||||
? Text(badge.metadata['title'])
|
? Text(badge.metadata['title'])
|
||||||
: Text(
|
: Text(
|
||||||
DateFormat('y/M/d')
|
DateFormat('y/M/d').format(badge.createdAt),
|
||||||
.format(badge.createdAt),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -73,7 +73,6 @@ class MarkdownTextContent extends StatelessWidget {
|
|||||||
extensionSet: markdown.ExtensionSet(
|
extensionSet: markdown.ExtensionSet(
|
||||||
<markdown.BlockSyntax>[
|
<markdown.BlockSyntax>[
|
||||||
markdown.CodeBlockSyntax(),
|
markdown.CodeBlockSyntax(),
|
||||||
...markdown.ExtensionSet.commonMark.blockSyntaxes,
|
|
||||||
...markdown.ExtensionSet.gitHubFlavored.blockSyntaxes,
|
...markdown.ExtensionSet.gitHubFlavored.blockSyntaxes,
|
||||||
],
|
],
|
||||||
<markdown.InlineSyntax>[
|
<markdown.InlineSyntax>[
|
||||||
@ -82,7 +81,6 @@ class MarkdownTextContent extends StatelessWidget {
|
|||||||
markdown.AutolinkSyntax(),
|
markdown.AutolinkSyntax(),
|
||||||
markdown.AutolinkExtensionSyntax(),
|
markdown.AutolinkExtensionSyntax(),
|
||||||
markdown.CodeSyntax(),
|
markdown.CodeSyntax(),
|
||||||
...markdown.ExtensionSet.commonMark.inlineSyntaxes,
|
|
||||||
...markdown.ExtensionSet.gitHubFlavored.inlineSyntaxes
|
...markdown.ExtensionSet.gitHubFlavored.inlineSyntaxes
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@ -93,7 +91,7 @@ class MarkdownTextContent extends StatelessWidget {
|
|||||||
final segments = uri.split('/');
|
final segments = uri.split('/');
|
||||||
switch (segments[0]) {
|
switch (segments[0]) {
|
||||||
default:
|
default:
|
||||||
GoRouter.of(context).push(uri);
|
GoRouter.of(context).push('/$uri');
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -188,7 +186,7 @@ class _UserNameCardInlineSyntax extends markdown.InlineSyntax {
|
|||||||
final alias = match[0]!;
|
final alias = match[0]!;
|
||||||
final anchor = markdown.Element.text('a', alias)
|
final anchor = markdown.Element.text('a', alias)
|
||||||
..attributes['href'] = Uri.encodeFull(
|
..attributes['href'] = Uri.encodeFull(
|
||||||
'solink://users/${alias.substring(1)}',
|
'solink://account/${alias.substring(1)}',
|
||||||
);
|
);
|
||||||
parser.addNode(anchor);
|
parser.addNode(anchor);
|
||||||
|
|
||||||
|
@ -569,6 +569,18 @@ class _PostContentHeader extends StatelessWidget {
|
|||||||
Text('report').tr(),
|
Text('report').tr(),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
onTap: () {
|
||||||
|
showDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (context) => _PostAbuseReportDialog(
|
||||||
|
data: data,
|
||||||
|
),
|
||||||
|
).then((value) {
|
||||||
|
if (value == true && context.mounted) {
|
||||||
|
context.showSnackbar('abuseReportSubmitted'.tr());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@ -724,3 +736,79 @@ class _PostTruncatedHint extends StatelessWidget {
|
|||||||
).opacity(0.75);
|
).opacity(0.75);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class _PostAbuseReportDialog extends StatefulWidget {
|
||||||
|
final SnPost data;
|
||||||
|
|
||||||
|
const _PostAbuseReportDialog({super.key, required this.data});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<_PostAbuseReportDialog> createState() => _PostAbuseReportDialogState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _PostAbuseReportDialogState extends State<_PostAbuseReportDialog> {
|
||||||
|
bool _isBusy = false;
|
||||||
|
|
||||||
|
final _reasonController = TextEditingController();
|
||||||
|
|
||||||
|
@override
|
||||||
|
dispose() {
|
||||||
|
_reasonController.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _performAction() async {
|
||||||
|
setState(() => _isBusy = true);
|
||||||
|
try {
|
||||||
|
final sn = context.read<SnNetworkProvider>();
|
||||||
|
await sn.client.request(
|
||||||
|
'/cgi/id/reports/abuse',
|
||||||
|
data: {
|
||||||
|
'resource': 'post:${widget.data.id}',
|
||||||
|
'reason': _reasonController.text,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
if (!mounted) return;
|
||||||
|
Navigator.pop(context, true);
|
||||||
|
} catch (err) {
|
||||||
|
if (!mounted) return;
|
||||||
|
context.showErrorDialog(err);
|
||||||
|
} finally {
|
||||||
|
setState(() => _isBusy = false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return AlertDialog(
|
||||||
|
title: Text('postAbuseReport'.tr()),
|
||||||
|
content: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text('postAbuseReportDescription'.tr()),
|
||||||
|
const Gap(12),
|
||||||
|
TextField(
|
||||||
|
controller: _reasonController,
|
||||||
|
maxLength: null,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
border: const UnderlineInputBorder(),
|
||||||
|
labelText: 'abuseReportReason'.tr(),
|
||||||
|
),
|
||||||
|
onTapOutside: (_) => FocusManager.instance.primaryFocus?.unfocus(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
actions: [
|
||||||
|
TextButton(
|
||||||
|
onPressed: _isBusy ? null : () => Navigator.pop(context),
|
||||||
|
child: Text('dialogDismiss').tr(),
|
||||||
|
),
|
||||||
|
TextButton(
|
||||||
|
onPressed: _isBusy ? null : _performAction,
|
||||||
|
child: Text('submit').tr(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user