adds new filter

This commit is contained in:
otsmr 2026-01-25 16:46:41 +01:00
parent fb93d0c9ec
commit 42a81b9309
5 changed files with 47 additions and 21 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4 KiB

View file

@ -5,6 +5,7 @@ import 'package:twonly/src/views/camera/camera_preview_components/painters/face_
enum FaceFilterType { enum FaceFilterType {
none, none,
dogBrown, dogBrown,
beardUpperLipGreen,
beardUpperLip, beardUpperLip,
} }
@ -27,7 +28,9 @@ extension FaceFilterTypeExtension on FaceFilterType {
case FaceFilterType.dogBrown: case FaceFilterType.dogBrown:
return DogFilterPainter.getPreview(); return DogFilterPainter.getPreview();
case FaceFilterType.beardUpperLip: case FaceFilterType.beardUpperLip:
return BeardFilterPainter.getPreview(); return BeardFilterPainter.getPreview(this);
case FaceFilterType.beardUpperLipGreen:
return BeardFilterPainter.getPreview(this);
} }
} }
} }

View file

@ -397,20 +397,25 @@ class MainCameraController {
cameraController != null) { cameraController != null) {
if (faces.isNotEmpty) { if (faces.isNotEmpty) {
CustomPainter? painter; CustomPainter? painter;
if (_currentFilterType == FaceFilterType.dogBrown) { switch (_currentFilterType) {
case FaceFilterType.dogBrown:
painter = DogFilterPainter( painter = DogFilterPainter(
faces, faces,
inputImage.metadata!.size, inputImage.metadata!.size,
inputImage.metadata!.rotation, inputImage.metadata!.rotation,
cameraController!.description.lensDirection, cameraController!.description.lensDirection,
); );
} else if (_currentFilterType == FaceFilterType.beardUpperLip) { case FaceFilterType.beardUpperLip:
case FaceFilterType.beardUpperLipGreen:
painter = BeardFilterPainter( painter = BeardFilterPainter(
_currentFilterType,
faces, faces,
inputImage.metadata!.size, inputImage.metadata!.size,
inputImage.metadata!.rotation, inputImage.metadata!.rotation,
cameraController!.description.lensDirection, cameraController!.description.lensDirection,
); );
case FaceFilterType.none:
break;
} }
if (painter != null) { if (painter != null) {

View file

@ -6,27 +6,45 @@ import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:google_mlkit_face_detection/google_mlkit_face_detection.dart'; import 'package:google_mlkit_face_detection/google_mlkit_face_detection.dart';
import 'package:twonly/src/utils/log.dart'; import 'package:twonly/src/utils/log.dart';
import 'package:twonly/src/views/camera/camera_preview_components/face_filters.dart';
import 'package:twonly/src/views/camera/camera_preview_components/painters/coordinates_translator.dart'; import 'package:twonly/src/views/camera/camera_preview_components/painters/coordinates_translator.dart';
import 'package:twonly/src/views/camera/camera_preview_components/painters/face_filters/face_filter_painter.dart'; import 'package:twonly/src/views/camera/camera_preview_components/painters/face_filters/face_filter_painter.dart';
class BeardFilterPainter extends FaceFilterPainter { class BeardFilterPainter extends FaceFilterPainter {
BeardFilterPainter( BeardFilterPainter(
FaceFilterType beardType,
super.faces, super.faces,
super.imageSize, super.imageSize,
super.rotation, super.rotation,
super.cameraLensDirection, super.cameraLensDirection,
) { ) {
_loadAssets(); _loadAssets(beardType);
} }
static FaceFilterType? _lastLoadedBeardType;
static ui.Image? _beardImage; static ui.Image? _beardImage;
static bool _loading = false; static bool _loading = false;
static Future<void> _loadAssets() async { static String getAssetPath(FaceFilterType beardType) {
if (_loading || _beardImage != null) return; switch (beardType) {
case FaceFilterType.beardUpperLip:
return 'assets/filters/beard_upper_lip.webp';
case FaceFilterType.beardUpperLipGreen:
return 'assets/filters/beard_upper_lip_green.webp';
case FaceFilterType.dogBrown:
case FaceFilterType.none:
return '';
}
}
static Future<void> _loadAssets(FaceFilterType beardType) async {
if ((_loading || _beardImage != null) &&
_lastLoadedBeardType == beardType) {
return;
}
_loading = true; _loading = true;
try { try {
_beardImage = await _loadImage('assets/filters/beard_upper_lip.webp'); _beardImage = await _loadImage(getAssetPath(beardType));
} catch (e) { } catch (e) {
Log.error('Failed to load filter assets: $e'); Log.error('Failed to load filter assets: $e');
} finally { } finally {
@ -161,12 +179,12 @@ class BeardFilterPainter extends FaceFilterPainter {
..restore(); ..restore();
} }
static Widget getPreview() { static Widget getPreview(FaceFilterType beardType) {
return Preview( return Preview(
child: Padding( child: Padding(
padding: const EdgeInsets.all(8), padding: const EdgeInsets.all(8),
child: Image.asset( child: Image.asset(
'assets/filters/beard_upper_lip.webp', getAssetPath(beardType),
fit: BoxFit.contain, fit: BoxFit.contain,
), ),
), ),