import 'dart:io'; import 'package:flutter/material.dart'; import '../../../routing/app_routes.dart'; import '../../../share_intent/pending_share.dart'; import '../../../share_intent/share_intent_listener.dart'; class ShareTargetPage extends StatelessWidget { final PendingShare share; const ShareTargetPage({super.key, required this.share}); static const _imageExtensions = { '.jpg', '.jpeg', '.png', '.gif', '.webp', '.heic', '.heif', '.bmp', }; bool _isImagePath(String path) { final lower = path.toLowerCase(); return _imageExtensions.any(lower.endsWith); } String _appBarTitle() { if (share.hasFiles && share.hasText) return 'Inhalte teilen'; if (share.hasFiles) { return share.filePaths.length == 1 ? '1 Datei teilen' : '${share.filePaths.length} Dateien teilen'; } return 'Inhalt teilen'; } @override Widget build(BuildContext context) => PopScope( onPopInvokedWithResult: (didPop, _) { if (didPop) ShareIntentListener.instance.clear(); }, child: Scaffold( appBar: AppBar(title: Text(_appBarTitle())), body: Column( children: [ Expanded( child: SingleChildScrollView( padding: const EdgeInsets.fromLTRB(16, 16, 16, 8), child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ if (share.hasFiles) _buildFilePreview(context), if (share.hasFiles && share.hasText) const SizedBox(height: 12), if (share.hasText) _buildTextPreview(context), ], ), ), ), const Divider(height: 1), SafeArea( top: false, child: Padding( padding: const EdgeInsets.only(top: 12, bottom: 8), child: Column( children: [ Padding( padding: const EdgeInsets.fromLTRB(16, 4, 16, 12), child: Column( children: [ Icon( Icons.ios_share, size: 44, color: Theme.of(context).colorScheme.primary, ), const SizedBox(height: 8), Text( 'Wo möchtest du teilen?', textAlign: TextAlign.center, style: Theme.of(context).textTheme.titleLarge ?.copyWith(fontWeight: FontWeight.w600), ), ], ), ), ListTile( leading: const Icon(Icons.chat_bubble_outline), title: const Text('An Chat senden'), subtitle: const Text( 'Datei oder Text in einem Talk-Chat teilen', ), trailing: const Icon(Icons.chevron_right), onTap: () => AppRoutes.openShareChatPicker(context, share), ), ListTile( enabled: share.hasFiles, leading: const Icon(Icons.folder_outlined), title: const Text('In Dateien speichern'), subtitle: Text( share.hasFiles ? 'In einen Nextcloud-Ordner hochladen' : 'Nur für Dateien verfügbar', ), trailing: const Icon(Icons.chevron_right), onTap: share.hasFiles ? () => AppRoutes.openShareFolderPicker(context, share) : null, ), ], ), ), ), ], ), ), ); Widget _buildFilePreview(BuildContext context) { if (share.filePaths.length == 1) { final path = share.filePaths.first; final name = path.split(Platform.pathSeparator).last; return ConstrainedBox( constraints: const BoxConstraints(maxHeight: 320), child: Container( decoration: BoxDecoration( color: Theme.of(context).colorScheme.surfaceContainer, borderRadius: BorderRadius.circular(12), ), clipBehavior: Clip.antiAlias, child: _isImagePath(path) ? Image.file( File(path), fit: BoxFit.contain, // Decode at most ~1080px so 50-MP gallery photos don't // balloon the decode buffer just to render at <320px high. cacheWidth: 1080, errorBuilder: (_, _, _) => _fileFallbackLarge(name), ) : _fileFallbackLarge(name), ), ); } return GridView.builder( shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 2, crossAxisSpacing: 10, mainAxisSpacing: 10, ), itemCount: share.filePaths.length, itemBuilder: (context, i) { final path = share.filePaths[i]; final name = path.split(Platform.pathSeparator).last; return Container( decoration: BoxDecoration( color: Theme.of(context).colorScheme.surfaceContainer, borderRadius: BorderRadius.circular(12), ), clipBehavior: Clip.antiAlias, child: _isImagePath(path) ? Image.file( File(path), fit: BoxFit.cover, // Grid tiles are ~half-screen wide; 480px decode is // sharp on 3x displays without blowing up memory when // many files are shared at once. cacheWidth: 480, errorBuilder: (_, _, _) => _fileFallbackLarge(name), ) : _fileFallbackLarge(name), ); }, ); } Widget _buildTextPreview(BuildContext context) => Card( margin: EdgeInsets.zero, child: Padding( padding: const EdgeInsets.all(12), child: Text( share.text!, maxLines: 6, overflow: TextOverflow.ellipsis, ), ), ); Widget _fileFallbackLarge(String name) => Padding( padding: const EdgeInsets.all(16), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ const Icon(Icons.insert_drive_file_outlined, size: 64), const SizedBox(height: 8), Text( name, maxLines: 3, overflow: TextOverflow.ellipsis, textAlign: TextAlign.center, style: const TextStyle(fontSize: 12), ), ], ), ); }