import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:photo_view/photo_view.dart'; class FullScreenImageViewer extends StatefulWidget { final String imageUrl; const FullScreenImageViewer({super.key, required this.imageUrl}); @override State createState() => _FullScreenImageViewerState(); } class _FullScreenImageViewerState extends State { PhotoViewController controller = PhotoViewController(); PhotoViewScaleStateController scaleStateController = PhotoViewScaleStateController(); bool _showControls = true; @override void initState() { super.initState(); // Auto-hide controls after 3 seconds Future.delayed(const Duration(seconds: 3), () { if (mounted) { setState(() { _showControls = false; }); } }); } void _toggleControls() { setState(() { _showControls = !_showControls; }); } void _resetImage() { controller.reset(); scaleStateController.reset(); } void _rotateImage() { final double currentRotation = controller.rotation; controller.rotation = currentRotation + 90.0; } @override Widget build(BuildContext context) { return SafeArea( top: false, child: Scaffold( backgroundColor: Color(0xFFFFFFFF), body: Stack( children: [ // Main Photo View GestureDetector( onTap: _toggleControls, child: PhotoView( imageProvider: NetworkImage(widget.imageUrl), controller: controller, scaleStateController: scaleStateController, backgroundDecoration: const BoxDecoration( color: Color(0xFF444444), ), minScale: PhotoViewComputedScale.contained * 0.8, maxScale: PhotoViewComputedScale.covered * 4, initialScale: PhotoViewComputedScale.contained, basePosition: Alignment.center, filterQuality: FilterQuality.high, enableRotation: true, gestureDetectorBehavior: HitTestBehavior.opaque, loadingBuilder: (context, event) => Center( child: Container( width: 40, height: 40, child: const CircularProgressIndicator( color: Colors.white, strokeWidth: 2, ), ), ), errorBuilder: (context, error, stackTrace) => Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ const Icon( Icons.error_outline, color: Colors.white, size: 50, ), const SizedBox(height: 16), Text( 'Failed to load image', style: TextStyle( color: Colors.white.withOpacity(0.8), fontSize: 16, ), ), ], ), ), ), ), // Controls Overlay if (_showControls) ...[ // Top Bar Positioned( top: MediaQuery.of(context).padding.top, left: 0, right: 0, child: Container( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), decoration: BoxDecoration( gradient: LinearGradient( begin: Alignment.topCenter, end: Alignment.bottomCenter, colors: [ Colors.black.withOpacity(0.7), Colors.black.withOpacity(0.3), Colors.transparent, ], ), ), child: Row( children: [ // Close Button GestureDetector( onTap: () => Navigator.pop(context), child: Container( padding: const EdgeInsets.all(8), decoration: BoxDecoration( color: Colors.black.withOpacity(0.5), shape: BoxShape.circle, ), child: const Icon( Icons.close, color: Colors.white, size: 24, ), ), ), const Spacer(), // Reset Button GestureDetector( onTap: _resetImage, child: Container( padding: const EdgeInsets.all(8), decoration: BoxDecoration( color: Colors.black.withOpacity(0.5), shape: BoxShape.circle, ), child: const Icon( Icons.refresh, color: Colors.white, size: 24, ), ), ), const SizedBox(width: 12), // Rotate Button GestureDetector( onTap: _rotateImage, child: Container( padding: const EdgeInsets.all(8), decoration: BoxDecoration( color: Colors.black.withOpacity(0.5), shape: BoxShape.circle, ), child: const Icon( Icons.rotate_90_degrees_ccw, color: Colors.white, size: 24, ), ), ), ], ), ), ), // Bottom Info Bar Positioned( bottom: 0, left: 0, right: 0, child: Container( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 20), decoration: BoxDecoration( gradient: LinearGradient( begin: Alignment.bottomCenter, end: Alignment.topCenter, colors: [ Colors.black.withOpacity(0.7), Colors.black.withOpacity(0.3), Colors.transparent, ], ), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Zoom Instructions Row( children: [ _buildInstructionIcon(Icons.touch_app, "Double tap to zoom"), const SizedBox(width: 16), _buildInstructionIcon(Icons.pan_tool, "Pan to move"), const SizedBox(width: 16), _buildInstructionIcon(Icons.rotate_right, "Pinch to rotate"), ], ), const SizedBox(height: 12), // Image Info Text( "Image Preview", style: TextStyle( color: Colors.white.withOpacity(0.9), fontSize: 14, fontWeight: FontWeight.w500, ), ), ], ), ), ), ], // Double Tap Zoom Hint (appears briefly) Positioned( bottom: MediaQuery.of(context).padding.bottom + 100, left: 0, right: 0, child: AnimatedOpacity( opacity: _showControls ? 1.0 : 0.0, duration: const Duration(milliseconds: 300), child: const Center( child: Text( "Double tap to zoom", style: TextStyle( color: Colors.white, fontSize: 14, fontWeight: FontWeight.w400, ), ), ), ), ), ], ), // Bottom Navigation Bar with additional controls bottomNavigationBar: _showControls ? Container( height: 60, decoration: BoxDecoration( color: Colors.black.withOpacity(0.7), borderRadius: const BorderRadius.only( topLeft: Radius.circular(12), topRight: Radius.circular(12), ), ), child: Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ // Zoom In IconButton( onPressed: () { final double currentScale = controller.scale ?? 1.0; controller.scale = currentScale * 1.5; }, icon: const Icon(Icons.zoom_in, color: Colors.white), tooltip: "Zoom In", ), // Zoom Out IconButton( onPressed: () { final double currentScale = controller.scale ?? 1.0; controller.scale = currentScale / 1.5; }, icon: const Icon(Icons.zoom_out, color: Colors.white), tooltip: "Zoom Out", ), // Reset IconButton( onPressed: _resetImage, icon: const Icon(Icons.fit_screen, color: Colors.white), tooltip: "Reset", ), // Rotate IconButton( onPressed: _rotateImage, icon: const Icon(Icons.rotate_90_degrees_ccw, color: Colors.white), tooltip: "Rotate 90°", ), ], ), ) : null, ), ); } Widget _buildInstructionIcon(IconData icon, String text) { return Row( mainAxisSize: MainAxisSize.min, children: [ Icon(icon, color: Colors.white.withOpacity(0.7), size: 16), const SizedBox(width: 4), Text( text, style: TextStyle( color: Colors.white.withOpacity(0.7), fontSize: 12, ), ), ], ); } @override void dispose() { controller.dispose(); scaleStateController.dispose(); super.dispose(); } }