import 'dart:typed_data'; import 'package:crop_your_image/crop_your_image.dart'; import 'package:flutter/material.dart'; import 'app_progress_indicator.dart'; /// Full-screen 1:1 cropper. Pure-Flutter so it inherits the app theme and /// MediaQuery insets (no UCrop / native Activity needed). Returns the /// cropped JPEG/PNG bytes via Navigator pop, or `null` on cancel. class AvatarCropPage extends StatefulWidget { final Uint8List imageBytes; const AvatarCropPage({required this.imageBytes, super.key}); @override State createState() => _AvatarCropPageState(); } class _AvatarCropPageState extends State { final _controller = CropController(); bool _busy = false; void _confirm() { if (_busy) return; setState(() => _busy = true); _controller.crop(); } @override Widget build(BuildContext context) { final theme = Theme.of(context); return Scaffold( backgroundColor: theme.colorScheme.surface, appBar: AppBar( title: const Text('Zuschneiden'), leading: IconButton( icon: const Icon(Icons.close), tooltip: 'Abbrechen', onPressed: _busy ? null : () => Navigator.of(context).pop(), ), actions: [ IconButton( icon: _busy ? Padding( padding: const EdgeInsets.all(10), child: AppProgressIndicator.small( color: theme.colorScheme.onSurface, ), ) : const Icon(Icons.check), tooltip: 'Bestätigen', onPressed: _busy ? null : _confirm, ), ], ), body: SafeArea( // Pinch-Zoom (interactive: true) lässt zwei-Finger-Gesten direkt am // Bildschirmrand starten und triggert dann die Android-Zurückgeste. // Crop-Rahmen mit Eck-Dots reicht für Avatar-Auswahl völlig aus. child: Crop( image: widget.imageBytes, controller: _controller, aspectRatio: 1.0, interactive: false, baseColor: theme.colorScheme.surface, maskColor: Colors.black.withValues(alpha: 0.6), cornerDotBuilder: (size, _) => DotControl(color: theme.colorScheme.primary), onCropped: (result) { if (!mounted) return; switch (result) { case CropSuccess(:final croppedImage): Navigator.of(context).pop(croppedImage); case CropFailure(): setState(() => _busy = false); ScaffoldMessenger.of(context).showSnackBar( const SnackBar( content: Text('Bild konnte nicht zugeschnitten werden'), ), ); } }, ), ), ); } }