import 'dart:io'; import 'package:cached_network_image/cached_network_image.dart'; import 'package:file_picker/file_picker.dart'; import 'package:flutter/material.dart'; import 'package:flutter_file_dialog/flutter_file_dialog.dart'; import 'package:path/path.dart' as p; import 'package:path_provider/path_provider.dart'; import '../globals.dart'; import '../models/media_attachment.dart'; import '../services/auth_service.dart'; import '../utils/snackbar_builder.dart'; class ImageViewerScreen extends StatefulWidget { final List attachments; final int initialIndex; const ImageViewerScreen({ super.key, required this.attachments, int this.initialIndex = 0, }); @override State createState() => _ImageViewerScreenState(); } class _ImageViewerScreenState extends State { var index = 0; @override void initState() { index = widget.initialIndex; } Future saveImage( BuildContext context, MediaAttachment attachment, ) async { buildSnackbar(context, 'Downloading full image to save locally'); final appsDir = await getApplicationDocumentsDirectory(); final filename = p.basename(attachment.fullFileUri.path); final bytesResult = await getIt() .currentClient .value .getFileBytes(attachment.uri); if (bytesResult.isFailure && mounted) { buildSnackbar(context, 'Error getting full size version of file: ${bytesResult.error}'); return; } if (Platform.isAndroid || Platform.isIOS) { final params = SaveFileDialogParams( data: bytesResult.value, fileName: filename, ); await FlutterFileDialog.saveFile(params: params); } else { final location = await FilePicker.platform.saveFile( dialogTitle: 'Save Image', fileName: filename, initialDirectory: appsDir.path, ); if (location != null) { await File(location).writeAsBytes(bytesResult.value); } } } @override Widget build(BuildContext context) { print('Index: $index'); final attachment = widget.attachments[index]; return Scaffold( appBar: AppBar( actions: [ IconButton( onPressed: () => saveImage(context, attachment), icon: const Icon(Icons.download)) ], ), body: SafeArea( child: Listener( onPointerMove: (details) { final velocity = details.delta.dx ?? 0.0; print('Velocity: $velocity'); if (velocity > 0 && index > 0) { setState(() { index--; }); } if (velocity < 0 && index < widget.attachments.length - 1) { setState(() { index++; }); } }, child: buildCoreViewer(attachment)), ), ); } Widget buildCoreViewer(MediaAttachment attachment) { final width = MediaQuery.of(context).size.width; final height = MediaQuery.of(context).size.height; return Column( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ SizedBox( width: width, height: 0.8 * height, child: InteractiveViewer( maxScale: 10.0, scaleFactor: 400, child: CachedNetworkImage(imageUrl: attachment.uri.toString()), ), ), Expanded( child: SingleChildScrollView( child: Padding( padding: const EdgeInsets.all(8.0), child: Text(attachment.description), ), ), ), ], ); } }