Replace blocked content popup with Instagram-style inline banner
This commit is contained in:
parent
f6c4bb88e0
commit
b5002c1ce4
|
|
@ -39,6 +39,7 @@ class _ComposeScreenState extends ConsumerState<ComposeScreen> {
|
|||
bool _isLoading = false;
|
||||
bool _isUploadingImage = false;
|
||||
String? _errorMessage;
|
||||
String? _blockedMessage;
|
||||
final int _maxCharacters = 500;
|
||||
bool _allowChain = true;
|
||||
bool _isBold = false;
|
||||
|
|
@ -69,6 +70,10 @@ class _ComposeScreenState extends ConsumerState<ComposeScreen> {
|
|||
_bodyController.addListener(() {
|
||||
_charCountNotifier.value = _bodyController.text.length;
|
||||
_handleHashtagSuggestions();
|
||||
// Clear blocked banner when user edits their text
|
||||
if (_blockedMessage != null) {
|
||||
setState(() => _blockedMessage = null);
|
||||
}
|
||||
});
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
if (!mounted) return;
|
||||
|
|
@ -326,7 +331,7 @@ class _ComposeScreenState extends ConsumerState<ComposeScreen> {
|
|||
// Layer 0: Client-side hard blocklist — never even send to server
|
||||
final blockMessage = ContentFilter.instance.check(_bodyController.text.trim());
|
||||
if (blockMessage != null) {
|
||||
await _showBlockedDialog(blockMessage);
|
||||
setState(() => _blockedMessage = blockMessage);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -411,7 +416,7 @@ class _ComposeScreenState extends ConsumerState<ComposeScreen> {
|
|||
final msg = e.toString().replaceAll('Exception: ', '');
|
||||
// Server-side blocklist catch (422 with blocked content message)
|
||||
if (msg.contains("isn't allowed on Sojorn") || msg.contains('not allowed')) {
|
||||
if (mounted) await _showBlockedDialog(msg);
|
||||
if (mounted) setState(() => _blockedMessage = msg);
|
||||
} else {
|
||||
setState(() {
|
||||
_errorMessage = msg;
|
||||
|
|
@ -454,35 +459,60 @@ class _ComposeScreenState extends ConsumerState<ComposeScreen> {
|
|||
return result ?? false;
|
||||
}
|
||||
|
||||
Future<void> _showBlockedDialog(String message) async {
|
||||
await showDialog<void>(
|
||||
context: context,
|
||||
barrierDismissible: false,
|
||||
builder: (context) => AlertDialog(
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)),
|
||||
title: Row(
|
||||
children: [
|
||||
Icon(Icons.block, color: AppTheme.error, size: 24),
|
||||
const SizedBox(width: 8),
|
||||
const Text('Not Allowed'),
|
||||
],
|
||||
),
|
||||
content: Text(
|
||||
message,
|
||||
style: AppTheme.textTheme.bodyMedium,
|
||||
),
|
||||
actions: [
|
||||
ElevatedButton(
|
||||
onPressed: () => Navigator.pop(context),
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: AppTheme.brightNavy,
|
||||
foregroundColor: AppTheme.white,
|
||||
shape: const StadiumBorder(),
|
||||
),
|
||||
child: const Text('Edit My Post'),
|
||||
),
|
||||
],
|
||||
),
|
||||
Widget _buildBlockedBanner() {
|
||||
return AnimatedSize(
|
||||
duration: const Duration(milliseconds: 250),
|
||||
curve: Curves.easeOut,
|
||||
child: _blockedMessage != null
|
||||
? Container(
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: AppTheme.spacingMd,
|
||||
vertical: 12,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFFFEF2F2),
|
||||
border: Border(
|
||||
bottom: BorderSide(
|
||||
color: AppTheme.error.withValues(alpha: 0.2),
|
||||
),
|
||||
),
|
||||
),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Icon(Icons.info_outline, color: AppTheme.error, size: 20),
|
||||
const SizedBox(width: 10),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
_blockedMessage!,
|
||||
style: AppTheme.textTheme.bodySmall?.copyWith(
|
||||
color: const Color(0xFF991B1B),
|
||||
fontWeight: FontWeight.w500,
|
||||
height: 1.4,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
GestureDetector(
|
||||
onTap: () => setState(() => _blockedMessage = null),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(left: 8),
|
||||
child: Icon(
|
||||
Icons.close,
|
||||
size: 16,
|
||||
color: AppTheme.error.withValues(alpha: 0.6),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
: const SizedBox.shrink(),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -515,6 +545,7 @@ class _ComposeScreenState extends ConsumerState<ComposeScreen> {
|
|||
body: SafeArea(
|
||||
child: Column(
|
||||
children: [
|
||||
_buildBlockedBanner(),
|
||||
if (_errorMessage != null)
|
||||
Container(
|
||||
width: double.infinity,
|
||||
|
|
|
|||
Loading…
Reference in a new issue