Fix cap photo flow to always open review dialog with fallback
This commit is contained in:
@@ -154,10 +154,48 @@ class _MosaicHomePageState extends State<MosaicHomePage> {
|
|||||||
imageQuality: 95,
|
imageQuality: 95,
|
||||||
maxWidth: 1800,
|
maxWidth: 1800,
|
||||||
);
|
);
|
||||||
if (captured == null) return;
|
if (captured == null) {
|
||||||
|
debugPrint('[cap-photo] Capture cancelled by user.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Uint8List bytes;
|
||||||
|
try {
|
||||||
|
bytes = await captured.readAsBytes();
|
||||||
|
} catch (e, st) {
|
||||||
|
debugPrint('[cap-photo] Failed to read captured bytes: $e\n$st');
|
||||||
|
final fallbackImage = img.Image(width: 1, height: 1)
|
||||||
|
..setPixelRgb(0, 0, 255, 152, 0);
|
||||||
|
bytes = Uint8List.fromList(
|
||||||
|
img.encodePng(fallbackImage, level: 1),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> detected;
|
||||||
|
String? detectionWarning;
|
||||||
|
try {
|
||||||
|
detected = await compute(_extractCapFromPhotoIsolate, bytes);
|
||||||
|
} catch (e, st) {
|
||||||
|
debugPrint('[cap-photo] Detection isolate failed: $e\n$st');
|
||||||
|
detectionWarning =
|
||||||
|
'⚠️ Farberkennung ist fehlgeschlagen. Fallback-Farbe wird verwendet; bitte prüfen/korrigieren.';
|
||||||
|
final decoded = img.decodeImage(bytes);
|
||||||
|
final imageW = (decoded?.width ?? 1).toDouble();
|
||||||
|
final imageH = (decoded?.height ?? 1).toDouble();
|
||||||
|
final fallbackColor = Colors.orange.toARGB32();
|
||||||
|
detected = {
|
||||||
|
'dominantColor': fallbackColor,
|
||||||
|
'averageColor': fallbackColor,
|
||||||
|
'usedFallback': true,
|
||||||
|
'circleX': imageW / 2,
|
||||||
|
'circleY': imageH / 2,
|
||||||
|
'circleR': math.min(imageW, imageH) * 0.28,
|
||||||
|
'imageW': imageW,
|
||||||
|
'imageH': imageH,
|
||||||
|
'previewPng': bytes,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
final bytes = await captured.readAsBytes();
|
|
||||||
final detected = await compute(_extractCapFromPhotoIsolate, bytes);
|
|
||||||
if (!mounted) return;
|
if (!mounted) return;
|
||||||
|
|
||||||
Color dominantColor = Color(detected['dominantColor'] as int);
|
Color dominantColor = Color(detected['dominantColor'] as int);
|
||||||
@@ -201,6 +239,7 @@ class _MosaicHomePageState extends State<MosaicHomePage> {
|
|||||||
if (updateDialog) {
|
if (updateDialog) {
|
||||||
setDialogState(() {});
|
setDialogState(() {});
|
||||||
}
|
}
|
||||||
|
try {
|
||||||
final adjusted = await compute(
|
final adjusted = await compute(
|
||||||
_extractCapFromAdjustedCircleIsolate,
|
_extractCapFromAdjustedCircleIsolate,
|
||||||
<String, dynamic>{
|
<String, dynamic>{
|
||||||
@@ -218,6 +257,17 @@ class _MosaicHomePageState extends State<MosaicHomePage> {
|
|||||||
? dominantColor
|
? dominantColor
|
||||||
: averageColor;
|
: averageColor;
|
||||||
_photoCapHexCtrl.text = _colorToHex(selected);
|
_photoCapHexCtrl.text = _colorToHex(selected);
|
||||||
|
} catch (e, st) {
|
||||||
|
debugPrint('[cap-photo] Recalculate failed: $e\n$st');
|
||||||
|
if (localToken != recalcToken) return;
|
||||||
|
detectionWarning =
|
||||||
|
'⚠️ Aktualisierung fehlgeschlagen. Bitte Farbe manuell prüfen.';
|
||||||
|
const fallback = Colors.orange;
|
||||||
|
dominantColor = fallback;
|
||||||
|
averageColor = fallback;
|
||||||
|
selected = fallback;
|
||||||
|
_photoCapHexCtrl.text = _colorToHex(selected);
|
||||||
|
}
|
||||||
if (ctx.mounted) {
|
if (ctx.mounted) {
|
||||||
setDialogState(() {});
|
setDialogState(() {});
|
||||||
}
|
}
|
||||||
@@ -274,6 +324,16 @@ class _MosaicHomePageState extends State<MosaicHomePage> {
|
|||||||
: 'Kreis erkannt. Direkt im Foto ziehen oder mit Pinch/Slider anpassen.',
|
: 'Kreis erkannt. Direkt im Foto ziehen oder mit Pinch/Slider anpassen.',
|
||||||
style: Theme.of(context).textTheme.bodySmall,
|
style: Theme.of(context).textTheme.bodySmall,
|
||||||
),
|
),
|
||||||
|
if (detectionWarning != null) ...[
|
||||||
|
const SizedBox(height: 6),
|
||||||
|
Text(
|
||||||
|
detectionWarning!,
|
||||||
|
style: Theme.of(context).textTheme.bodySmall?.copyWith(
|
||||||
|
color: Theme.of(context).colorScheme.error,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
SegmentedButton<ColorExtractionMode>(
|
SegmentedButton<ColorExtractionMode>(
|
||||||
segments: const [
|
segments: const [
|
||||||
@@ -1094,8 +1154,8 @@ class _CircleAdjustOverlayState extends State<_CircleAdjustOverlay> {
|
|||||||
final x = (local.dx / maxW).clamp(0.0, 1.0);
|
final x = (local.dx / maxW).clamp(0.0, 1.0);
|
||||||
final y = (local.dy / shownH).clamp(0.0, 1.0);
|
final y = (local.dy / shownH).clamp(0.0, 1.0);
|
||||||
final scale = details.scale;
|
final scale = details.scale;
|
||||||
final r = ((_baseRadius ?? widget.circleR) * scale)
|
final r =
|
||||||
.clamp(0.06, 0.49);
|
((_baseRadius ?? widget.circleR) * scale).clamp(0.06, 0.49);
|
||||||
widget.onCircleChanged(x, y, r);
|
widget.onCircleChanged(x, y, r);
|
||||||
},
|
},
|
||||||
onScaleEnd: (_) => _baseRadius = null,
|
onScaleEnd: (_) => _baseRadius = null,
|
||||||
@@ -1125,7 +1185,8 @@ class _CircleOverlayPainter extends CustomPainter {
|
|||||||
final double y;
|
final double y;
|
||||||
final double r;
|
final double r;
|
||||||
|
|
||||||
const _CircleOverlayPainter({required this.x, required this.y, required this.r});
|
const _CircleOverlayPainter(
|
||||||
|
{required this.x, required this.y, required this.r});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void paint(Canvas canvas, Size size) {
|
void paint(Canvas canvas, Size size) {
|
||||||
@@ -1154,8 +1215,10 @@ class _CircleOverlayPainter extends CustomPainter {
|
|||||||
..style = PaintingStyle.stroke
|
..style = PaintingStyle.stroke
|
||||||
..strokeWidth = 1
|
..strokeWidth = 1
|
||||||
..color = Colors.white70;
|
..color = Colors.white70;
|
||||||
canvas.drawLine(Offset(center.dx - 10, center.dy), Offset(center.dx + 10, center.dy), cross);
|
canvas.drawLine(Offset(center.dx - 10, center.dy),
|
||||||
canvas.drawLine(Offset(center.dx, center.dy - 10), Offset(center.dx, center.dy + 10), cross);
|
Offset(center.dx + 10, center.dy), cross);
|
||||||
|
canvas.drawLine(Offset(center.dx, center.dy - 10),
|
||||||
|
Offset(center.dx, center.dy + 10), cross);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|||||||
Reference in New Issue
Block a user