222 lines
		
	
	
		
			6.7 KiB
		
	
	
	
		
			Dart
		
	
	
	
	
	
			
		
		
	
	
			222 lines
		
	
	
		
			6.7 KiB
		
	
	
	
		
			Dart
		
	
	
	
	
	
import 'package:easy_localization/easy_localization.dart';
 | 
						|
import 'package:flutter/material.dart';
 | 
						|
import 'package:gap/gap.dart';
 | 
						|
import 'package:island/models/post.dart';
 | 
						|
import 'package:island/widgets/content/cloud_files.dart';
 | 
						|
import 'package:material_symbols_icons/symbols.dart';
 | 
						|
import 'package:styled_widget/styled_widget.dart';
 | 
						|
 | 
						|
/// A reusable widget for displaying info banners in compose screens.
 | 
						|
/// Shows editing, reply, and forward information.
 | 
						|
class ComposeInfoBanner extends StatelessWidget {
 | 
						|
  final SnPost? originalPost;
 | 
						|
  final SnPost? replyingTo;
 | 
						|
  final SnPost? forwardingTo;
 | 
						|
  final Function(BuildContext, SnPost)? onReferencePostTap;
 | 
						|
 | 
						|
  const ComposeInfoBanner({
 | 
						|
    super.key,
 | 
						|
    this.originalPost,
 | 
						|
    this.replyingTo,
 | 
						|
    this.forwardingTo,
 | 
						|
    this.onReferencePostTap,
 | 
						|
  });
 | 
						|
 | 
						|
  @override
 | 
						|
  Widget build(BuildContext context) {
 | 
						|
    final effectiveRepliedPost = replyingTo ?? originalPost?.repliedPost;
 | 
						|
    final effectiveForwardedPost = forwardingTo ?? originalPost?.forwardedPost;
 | 
						|
 | 
						|
    // Show editing banner when editing a post
 | 
						|
    if (originalPost != null) {
 | 
						|
      return Column(
 | 
						|
        children: [
 | 
						|
          Container(
 | 
						|
            width: double.infinity,
 | 
						|
            color: Theme.of(context).colorScheme.primaryContainer,
 | 
						|
            child: Row(
 | 
						|
              children: [
 | 
						|
                Icon(
 | 
						|
                  Symbols.edit,
 | 
						|
                  size: 16,
 | 
						|
                  color: Theme.of(context).colorScheme.onPrimaryContainer,
 | 
						|
                ),
 | 
						|
                const Gap(8),
 | 
						|
                Text(
 | 
						|
                  'postEditing'.tr(),
 | 
						|
                  style: Theme.of(context).textTheme.labelMedium?.copyWith(
 | 
						|
                    color: Theme.of(context).colorScheme.onPrimaryContainer,
 | 
						|
                  ),
 | 
						|
                ),
 | 
						|
              ],
 | 
						|
            ).padding(horizontal: 16, vertical: 8),
 | 
						|
          ),
 | 
						|
          // Show reply/forward banners below editing banner if they exist
 | 
						|
          if (effectiveRepliedPost != null)
 | 
						|
            _buildReferenceBanner(
 | 
						|
              context,
 | 
						|
              effectiveRepliedPost,
 | 
						|
              Symbols.reply,
 | 
						|
              'postReplyingTo'.tr(),
 | 
						|
            ),
 | 
						|
          if (effectiveForwardedPost != null)
 | 
						|
            _buildReferenceBanner(
 | 
						|
              context,
 | 
						|
              effectiveForwardedPost,
 | 
						|
              Symbols.forward,
 | 
						|
              'postForwardingTo'.tr(),
 | 
						|
            ),
 | 
						|
        ],
 | 
						|
      );
 | 
						|
    }
 | 
						|
 | 
						|
    // Show banner for replies
 | 
						|
    if (effectiveRepliedPost != null) {
 | 
						|
      return _buildReferenceBanner(
 | 
						|
        context,
 | 
						|
        effectiveRepliedPost,
 | 
						|
        Symbols.reply,
 | 
						|
        'postReplyingTo'.tr(),
 | 
						|
      );
 | 
						|
    }
 | 
						|
 | 
						|
    // Show banner for forwards
 | 
						|
    if (effectiveForwardedPost != null) {
 | 
						|
      return _buildReferenceBanner(
 | 
						|
        context,
 | 
						|
        effectiveForwardedPost,
 | 
						|
        Symbols.forward,
 | 
						|
        'postForwardingTo'.tr(),
 | 
						|
      );
 | 
						|
    }
 | 
						|
 | 
						|
    return const SizedBox.shrink();
 | 
						|
  }
 | 
						|
 | 
						|
  Widget _buildReferenceBanner(
 | 
						|
    BuildContext context,
 | 
						|
    SnPost post,
 | 
						|
    IconData icon,
 | 
						|
    String labelKey,
 | 
						|
  ) {
 | 
						|
    return Container(
 | 
						|
      width: double.infinity,
 | 
						|
      color: Theme.of(context).colorScheme.surfaceContainerHigh,
 | 
						|
      child: Column(
 | 
						|
        crossAxisAlignment: CrossAxisAlignment.start,
 | 
						|
        children: [
 | 
						|
          Row(
 | 
						|
            children: [
 | 
						|
              Icon(icon, size: 16),
 | 
						|
              const Gap(4),
 | 
						|
              Text(labelKey, style: Theme.of(context).textTheme.labelMedium),
 | 
						|
            ],
 | 
						|
          ),
 | 
						|
          const Gap(8),
 | 
						|
          CompactReferencePost(
 | 
						|
            post: post,
 | 
						|
            onTap:
 | 
						|
                onReferencePostTap != null
 | 
						|
                    ? () => onReferencePostTap!(context, post)
 | 
						|
                    : null,
 | 
						|
          ),
 | 
						|
        ],
 | 
						|
      ).padding(all: 16),
 | 
						|
    );
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/// A compact widget for displaying reference posts (replies/forwards).
 | 
						|
class CompactReferencePost extends StatelessWidget {
 | 
						|
  final SnPost post;
 | 
						|
  final VoidCallback? onTap;
 | 
						|
 | 
						|
  const CompactReferencePost({super.key, required this.post, this.onTap});
 | 
						|
 | 
						|
  @override
 | 
						|
  Widget build(BuildContext context) {
 | 
						|
    final theme = Theme.of(context);
 | 
						|
 | 
						|
    return GestureDetector(
 | 
						|
      onTap: onTap,
 | 
						|
      child: Container(
 | 
						|
        padding: const EdgeInsets.all(12),
 | 
						|
        decoration: BoxDecoration(
 | 
						|
          color: theme.colorScheme.surface,
 | 
						|
          borderRadius: BorderRadius.circular(8),
 | 
						|
          border: Border.all(color: theme.colorScheme.outline.withOpacity(0.3)),
 | 
						|
        ),
 | 
						|
        child: Row(
 | 
						|
          children: [
 | 
						|
            ProfilePictureWidget(
 | 
						|
              fileId: post.publisher.picture?.id,
 | 
						|
              radius: 16,
 | 
						|
            ),
 | 
						|
            const Gap(8),
 | 
						|
            Expanded(
 | 
						|
              child: Column(
 | 
						|
                crossAxisAlignment: CrossAxisAlignment.start,
 | 
						|
                children: [
 | 
						|
                  Text(
 | 
						|
                    post.publisher.nick,
 | 
						|
                    style: const TextStyle(
 | 
						|
                      fontWeight: FontWeight.bold,
 | 
						|
                      fontSize: 14,
 | 
						|
                    ),
 | 
						|
                  ),
 | 
						|
                  if (post.title?.isNotEmpty ?? false)
 | 
						|
                    Text(
 | 
						|
                      post.title!,
 | 
						|
                      style: TextStyle(
 | 
						|
                        fontWeight: FontWeight.w500,
 | 
						|
                        fontSize: 13,
 | 
						|
                        color: theme.colorScheme.onSurface,
 | 
						|
                      ),
 | 
						|
                      maxLines: 1,
 | 
						|
                      overflow: TextOverflow.ellipsis,
 | 
						|
                    ),
 | 
						|
                  if (post.content?.isNotEmpty ?? false)
 | 
						|
                    Text(
 | 
						|
                      post.content!,
 | 
						|
                      style: TextStyle(
 | 
						|
                        fontSize: 12,
 | 
						|
                        color: theme.colorScheme.onSurfaceVariant,
 | 
						|
                      ),
 | 
						|
                      maxLines: 2,
 | 
						|
                      overflow: TextOverflow.ellipsis,
 | 
						|
                    ),
 | 
						|
                  if (post.attachments.isNotEmpty)
 | 
						|
                    Row(
 | 
						|
                      mainAxisSize: MainAxisSize.min,
 | 
						|
                      children: [
 | 
						|
                        Icon(
 | 
						|
                          Symbols.attach_file,
 | 
						|
                          size: 12,
 | 
						|
                          color: theme.colorScheme.secondary,
 | 
						|
                        ),
 | 
						|
                        const Gap(4),
 | 
						|
                        Text(
 | 
						|
                          'postHasAttachments'.plural(post.attachments.length),
 | 
						|
                          style: TextStyle(
 | 
						|
                            color: theme.colorScheme.secondary,
 | 
						|
                            fontSize: 11,
 | 
						|
                          ),
 | 
						|
                        ),
 | 
						|
                      ],
 | 
						|
                    ),
 | 
						|
                ],
 | 
						|
              ),
 | 
						|
            ),
 | 
						|
            if (onTap != null)
 | 
						|
              Icon(
 | 
						|
                Symbols.open_in_full,
 | 
						|
                size: 16,
 | 
						|
                color: theme.colorScheme.outline,
 | 
						|
              ),
 | 
						|
          ],
 | 
						|
        ),
 | 
						|
      ),
 | 
						|
    );
 | 
						|
  }
 | 
						|
}
 |