feat: mobile filter sending/recv

This commit is contained in:
bwees
2026-01-25 15:27:05 -06:00
parent 2e4cfa80a9
commit ae9bb0aa80
5 changed files with 303 additions and 106 deletions

View File

@@ -1,52 +1,278 @@
import 'package:flutter/material.dart';
const List<ColorFilter> filters = [
class EditFilter {
final String name;
final double rrBias;
final double rgBias;
final double rbBias;
final double grBias;
final double ggBias;
final double gbBias;
final double brBias;
final double bgBias;
final double bbBias;
final double rOffset;
final double gOffset;
final double bOffset;
const EditFilter({
required this.name,
required this.rrBias,
required this.rgBias,
required this.rbBias,
required this.grBias,
required this.ggBias,
required this.gbBias,
required this.brBias,
required this.bgBias,
required this.bbBias,
required this.rOffset,
required this.gOffset,
required this.bOffset,
});
bool get isIdentity =>
rrBias == 1 &&
rgBias == 0 &&
rbBias == 0 &&
grBias == 0 &&
ggBias == 1 &&
gbBias == 0 &&
brBias == 0 &&
bgBias == 0 &&
bbBias == 1 &&
rOffset == 0 &&
gOffset == 0 &&
bOffset == 0;
factory EditFilter.fromMatrix(List<double> matrix, String name) {
if (matrix.length != 20) {
throw ArgumentError('Color filter matrix must have 20 elements');
}
return EditFilter(
name: name,
rrBias: matrix[0],
rgBias: matrix[1],
rbBias: matrix[2],
grBias: matrix[5],
ggBias: matrix[6],
gbBias: matrix[7],
brBias: matrix[10],
bgBias: matrix[11],
bbBias: matrix[12],
rOffset: matrix[4],
gOffset: matrix[9],
bOffset: matrix[14],
);
}
factory EditFilter.fromDtoParams(Map<String, dynamic> params, String name) {
print(params);
return EditFilter(
name: name,
rrBias: (params['rrBias'] as num).toDouble(),
rgBias: (params['rgBias'] as num).toDouble(),
rbBias: (params['rbBias'] as num).toDouble(),
grBias: (params['grBias'] as num).toDouble(),
ggBias: (params['ggBias'] as num).toDouble(),
gbBias: (params['gbBias'] as num).toDouble(),
brBias: (params['brBias'] as num).toDouble(),
bgBias: (params['bgBias'] as num).toDouble(),
bbBias: (params['bbBias'] as num).toDouble(),
rOffset: (params['rOffset'] as num).toDouble(),
gOffset: (params['gOffset'] as num).toDouble(),
bOffset: (params['bOffset'] as num).toDouble(),
);
}
ColorFilter get colorFilter {
final colorMatrix = <double>[
rrBias,
rgBias,
rbBias,
0,
rOffset,
grBias,
ggBias,
gbBias,
0,
gOffset,
brBias,
bgBias,
bbBias,
0,
bOffset,
0,
0,
0,
1,
0,
];
return ColorFilter.matrix(colorMatrix);
}
Map<String, dynamic> get dtoParameters {
return {
"rrBias": rrBias,
"rgBias": rgBias,
"rbBias": rbBias,
"grBias": grBias,
"ggBias": ggBias,
"gbBias": gbBias,
"brBias": brBias,
"bgBias": bgBias,
"bbBias": bbBias,
"rOffset": rOffset,
"gOffset": gOffset,
"bOffset": bOffset,
};
}
@override
bool operator ==(Object other) {
if (identical(this, other)) return true;
if (other is! EditFilter) return false;
return rrBias == other.rrBias &&
rgBias == other.rgBias &&
rbBias == other.rbBias &&
grBias == other.grBias &&
ggBias == other.ggBias &&
gbBias == other.gbBias &&
brBias == other.brBias &&
bgBias == other.bgBias &&
bbBias == other.bbBias &&
rOffset == other.rOffset &&
gOffset == other.gOffset &&
bOffset == other.bOffset;
}
@override
int get hashCode =>
name.hashCode ^
rrBias.hashCode ^
rgBias.hashCode ^
rbBias.hashCode ^
grBias.hashCode ^
ggBias.hashCode ^
gbBias.hashCode ^
brBias.hashCode ^
bgBias.hashCode ^
bbBias.hashCode ^
rOffset.hashCode ^
gOffset.hashCode ^
bOffset.hashCode;
}
final List<EditFilter> filters = [
//Original
ColorFilter.matrix([1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0]),
EditFilter.fromMatrix([1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0], "Original"),
//Vintage
ColorFilter.matrix([0.8, 0.1, 0.1, 0, 20, 0.1, 0.8, 0.1, 0, 20, 0.1, 0.1, 0.8, 0, 20, 0, 0, 0, 1, 0]),
EditFilter.fromMatrix([0.8, 0.1, 0.1, 0, 20, 0.1, 0.8, 0.1, 0, 20, 0.1, 0.1, 0.8, 0, 20, 0, 0, 0, 1, 0], "Vintage"),
//Mood
ColorFilter.matrix([1.2, 0.1, 0.1, 0, 10, 0.1, 1, 0.1, 0, 10, 0.1, 0.1, 1, 0, 10, 0, 0, 0, 1, 0]),
EditFilter.fromMatrix([1.2, 0.1, 0.1, 0, 10, 0.1, 1, 0.1, 0, 10, 0.1, 0.1, 1, 0, 10, 0, 0, 0, 1, 0], "Mood"),
//Crisp
ColorFilter.matrix([1.2, 0, 0, 0, 0, 0, 1.2, 0, 0, 0, 0, 0, 1.2, 0, 0, 0, 0, 0, 1, 0]),
EditFilter.fromMatrix([1.2, 0, 0, 0, 0, 0, 1.2, 0, 0, 0, 0, 0, 1.2, 0, 0, 0, 0, 0, 1, 0], "Crisp"),
//Cool
ColorFilter.matrix([0.9, 0, 0.2, 0, 0, 0, 1, 0.1, 0, 0, 0.1, 0, 1.2, 0, 0, 0, 0, 0, 1, 0]),
EditFilter.fromMatrix([0.9, 0, 0.2, 0, 0, 0, 1, 0.1, 0, 0, 0.1, 0, 1.2, 0, 0, 0, 0, 0, 1, 0], "Cool"),
//Blush
ColorFilter.matrix([1.1, 0.1, 0.1, 0, 10, 0.1, 1, 0.1, 0, 10, 0.1, 0.1, 1, 0, 5, 0, 0, 0, 1, 0]),
EditFilter.fromMatrix([1.1, 0.1, 0.1, 0, 10, 0.1, 1, 0.1, 0, 10, 0.1, 0.1, 1, 0, 5, 0, 0, 0, 1, 0], "Blush"),
//Sunkissed
ColorFilter.matrix([1.3, 0, 0.1, 0, 15, 0, 1.1, 0.1, 0, 10, 0, 0, 0.9, 0, 5, 0, 0, 0, 1, 0]),
EditFilter.fromMatrix([1.3, 0, 0.1, 0, 15, 0, 1.1, 0.1, 0, 10, 0, 0, 0.9, 0, 5, 0, 0, 0, 1, 0], "Sunkissed"),
//Fresh
ColorFilter.matrix([1.2, 0, 0, 0, 20, 0, 1.2, 0, 0, 20, 0, 0, 1.1, 0, 20, 0, 0, 0, 1, 0]),
EditFilter.fromMatrix([1.2, 0, 0, 0, 20, 0, 1.2, 0, 0, 20, 0, 0, 1.1, 0, 20, 0, 0, 0, 1, 0], "Fresh"),
//Classic
ColorFilter.matrix([1.1, 0, -0.1, 0, 10, -0.1, 1.1, 0.1, 0, 5, 0, -0.1, 1.1, 0, 0, 0, 0, 0, 1, 0]),
EditFilter.fromMatrix([1.1, 0, -0.1, 0, 10, -0.1, 1.1, 0.1, 0, 5, 0, -0.1, 1.1, 0, 0, 0, 0, 0, 1, 0], "Classic"),
//Lomo-ish
ColorFilter.matrix([1.5, 0, 0.1, 0, 0, 0, 1.45, 0, 0, 0, 0.1, 0, 1.3, 0, 0, 0, 0, 0, 1, 0]),
EditFilter.fromMatrix([1.5, 0, 0.1, 0, 0, 0, 1.45, 0, 0, 0, 0.1, 0, 1.3, 0, 0, 0, 0, 0, 1, 0], "Lomo-ish"),
//Nashville
ColorFilter.matrix([1.2, 0.15, -0.15, 0, 15, 0.1, 1.1, 0.1, 0, 10, -0.05, 0.2, 1.25, 0, 5, 0, 0, 0, 1, 0]),
EditFilter.fromMatrix([
1.2,
0.15,
-0.15,
0,
15,
0.1,
1.1,
0.1,
0,
10,
-0.05,
0.2,
1.25,
0,
5,
0,
0,
0,
1,
0,
], "Nashville"),
//Valencia
ColorFilter.matrix([1.15, 0.1, 0.1, 0, 20, 0.1, 1.1, 0, 0, 10, 0.1, 0.1, 1.2, 0, 5, 0, 0, 0, 1, 0]),
EditFilter.fromMatrix([1.15, 0.1, 0.1, 0, 20, 0.1, 1.1, 0, 0, 10, 0.1, 0.1, 1.2, 0, 5, 0, 0, 0, 1, 0], "Valencia"),
//Clarendon
ColorFilter.matrix([1.2, 0, 0, 0, 10, 0, 1.25, 0, 0, 10, 0, 0, 1.3, 0, 10, 0, 0, 0, 1, 0]),
EditFilter.fromMatrix([1.2, 0, 0, 0, 10, 0, 1.25, 0, 0, 10, 0, 0, 1.3, 0, 10, 0, 0, 0, 1, 0], "Clarendon"),
//Moon
ColorFilter.matrix([0.33, 0.33, 0.33, 0, 0, 0.33, 0.33, 0.33, 0, 0, 0.33, 0.33, 0.33, 0, 0, 0, 0, 0, 1, 0]),
EditFilter.fromMatrix([
0.33,
0.33,
0.33,
0,
0,
0.33,
0.33,
0.33,
0,
0,
0.33,
0.33,
0.33,
0,
0,
0,
0,
0,
1,
0,
], "Moon"),
//Willow
ColorFilter.matrix([0.5, 0.5, 0.5, 0, 20, 0.5, 0.5, 0.5, 0, 20, 0.5, 0.5, 0.5, 0, 20, 0, 0, 0, 1, 0]),
EditFilter.fromMatrix([0.5, 0.5, 0.5, 0, 20, 0.5, 0.5, 0.5, 0, 20, 0.5, 0.5, 0.5, 0, 20, 0, 0, 0, 1, 0], "Willow"),
//Kodak
ColorFilter.matrix([1.3, 0.1, -0.1, 0, 10, 0, 1.25, 0.1, 0, 10, 0, -0.1, 1.1, 0, 5, 0, 0, 0, 1, 0]),
//Frost
ColorFilter.matrix([0.8, 0.2, 0.1, 0, 0, 0.2, 1.1, 0.1, 0, 0, 0.1, 0.1, 1.2, 0, 10, 0, 0, 0, 1, 0]),
//Night Vision
ColorFilter.matrix([0.1, 0.95, 0.2, 0, 0, 0.1, 1.5, 0.1, 0, 0, 0.2, 0.7, 0, 0, 0, 0, 0, 0, 1, 0]),
EditFilter.fromMatrix([1.3, 0.1, -0.1, 0, 10, 0, 1.25, 0.1, 0, 10, 0, -0.1, 1.1, 0, 5, 0, 0, 0, 1, 0], "Kodak"),
//Sunset
ColorFilter.matrix([1.5, 0.2, 0, 0, 0, 0.1, 0.9, 0.1, 0, 0, -0.1, -0.2, 1.3, 0, 0, 0, 0, 0, 1, 0]),
EditFilter.fromMatrix([1.5, 0.2, 0, 0, 0, 0.1, 0.9, 0.1, 0, 0, -0.1, -0.2, 1.3, 0, 0, 0, 0, 0, 1, 0], "Sunset"),
//Noir
ColorFilter.matrix([1.3, -0.3, 0.1, 0, 0, -0.1, 1.2, -0.1, 0, 0, 0.1, -0.2, 1.3, 0, 0, 0, 0, 0, 1, 0]),
EditFilter.fromMatrix([1.3, -0.3, 0.1, 0, 0, -0.1, 1.2, -0.1, 0, 0, 0.1, -0.2, 1.3, 0, 0, 0, 0, 0, 1, 0], "Noir"),
//Dreamy
ColorFilter.matrix([1.1, 0.1, 0.1, 0, 0, 0.1, 1.1, 0.1, 0, 0, 0.1, 0.1, 1.1, 0, 15, 0, 0, 0, 1, 0]),
EditFilter.fromMatrix([1.1, 0.1, 0.1, 0, 0, 0.1, 1.1, 0.1, 0, 0, 0.1, 0.1, 1.1, 0, 15, 0, 0, 0, 1, 0], "Dreamy"),
//Sepia
ColorFilter.matrix([0.393, 0.769, 0.189, 0, 0, 0.349, 0.686, 0.168, 0, 0, 0.272, 0.534, 0.131, 0, 0, 0, 0, 0, 1, 0]),
EditFilter.fromMatrix([
0.393,
0.769,
0.189,
0,
0,
0.349,
0.686,
0.168,
0,
0,
0.272,
0.534,
0.131,
0,
0,
0,
0,
0,
1,
0,
], "Sepia"),
//Radium
ColorFilter.matrix([
EditFilter.fromMatrix([
1.438,
-0.062,
-0.062,
@@ -67,9 +293,9 @@ const List<ColorFilter> filters = [
0,
1,
0,
]),
], "Radium"),
//Aqua
ColorFilter.matrix([
EditFilter.fromMatrix([
0.2126,
0.7152,
0.0722,
@@ -90,59 +316,23 @@ const List<ColorFilter> filters = [
0,
1,
0,
]),
], "Aqua"),
//Purple Haze
ColorFilter.matrix([1.3, 0, 1.2, 0, 0, 0, 1.1, 0, 0, 0, 0.2, 0, 1.3, 0, 0, 0, 0, 0, 1, 0]),
EditFilter.fromMatrix([1.3, 0, 1.2, 0, 0, 0, 1.1, 0, 0, 0, 0.2, 0, 1.3, 0, 0, 0, 0, 0, 1, 0], "Purple Haze"),
//Lemonade
ColorFilter.matrix([1.2, 0.1, 0, 0, 0, 0, 1.1, 0.2, 0, 0, 0.1, 0, 0.7, 0, 0, 0, 0, 0, 1, 0]),
EditFilter.fromMatrix([1.2, 0.1, 0, 0, 0, 0, 1.1, 0.2, 0, 0, 0.1, 0, 0.7, 0, 0, 0, 0, 0, 1, 0], "Lemonade"),
//Caramel
ColorFilter.matrix([1.6, 0.2, 0, 0, 0, 0.1, 1.3, 0.1, 0, 0, 0, 0.1, 0.9, 0, 0, 0, 0, 0, 1, 0]),
EditFilter.fromMatrix([1.6, 0.2, 0, 0, 0, 0.1, 1.3, 0.1, 0, 0, 0, 0.1, 0.9, 0, 0, 0, 0, 0, 1, 0], "Caramel"),
//Peachy
ColorFilter.matrix([1.3, 0.5, 0, 0, 0, 0.2, 1.1, 0.3, 0, 0, 0.1, 0.1, 1.2, 0, 0, 0, 0, 0, 1, 0]),
EditFilter.fromMatrix([1.3, 0.5, 0, 0, 0, 0.2, 1.1, 0.3, 0, 0, 0.1, 0.1, 1.2, 0, 0, 0, 0, 0, 1, 0], "Peachy"),
//Neon
ColorFilter.matrix([1, 0, 1, 0, 0, 0, 2, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 1, 0]),
EditFilter.fromMatrix([1, 0, 1, 0, 0, 0, 2, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 1, 0], "Neon"),
//Cold Morning
ColorFilter.matrix([0.9, 0.1, 0.2, 0, 0, 0, 1, 0.1, 0, 0, 0.1, 0, 1.2, 0, 0, 0, 0, 0, 1, 0]),
EditFilter.fromMatrix([0.9, 0.1, 0.2, 0, 0, 0, 1, 0.1, 0, 0, 0.1, 0, 1.2, 0, 0, 0, 0, 0, 1, 0], "Cold Morning"),
//Lush
ColorFilter.matrix([0.9, 0.2, 0, 0, 0, 0, 1.2, 0, 0, 0, 0, 0, 1.1, 0, 0, 0, 0, 0, 1, 0]),
EditFilter.fromMatrix([0.9, 0.2, 0, 0, 0, 0, 1.2, 0, 0, 0, 0, 0, 1.1, 0, 0, 0, 0, 0, 1, 0], "Lush"),
//Urban Neon
ColorFilter.matrix([1.1, 0, 0.3, 0, 0, 0, 0.9, 0.3, 0, 0, 0.3, 0.1, 1.2, 0, 0, 0, 0, 0, 1, 0]),
EditFilter.fromMatrix([1.1, 0, 0.3, 0, 0, 0, 0.9, 0.3, 0, 0, 0.3, 0.1, 1.2, 0, 0, 0, 0, 0, 1, 0], "Urban Neon"),
//Monochrome
ColorFilter.matrix([0.6, 0.2, 0.2, 0, 0, 0.2, 0.6, 0.2, 0, 0, 0.2, 0.2, 0.7, 0, 0, 0, 0, 0, 1, 0]),
];
const List<String> filterNames = [
'Original',
'Vintage',
'Mood',
'Crisp',
'Cool',
'Blush',
'Sunkissed',
'Fresh',
'Classic',
'Lomo-ish',
'Nashville',
'Valencia',
'Clarendon',
'Moon',
'Willow',
'Kodak',
'Frost',
'Night Vision',
'Sunset',
'Noir',
'Dreamy',
'Sepia',
'Radium',
'Aqua',
'Purple Haze',
'Lemonade',
'Caramel',
'Peachy',
'Neon',
'Cold Morning',
'Lush',
'Urban Neon',
'Monochrome',
EditFilter.fromMatrix([0.6, 0.2, 0.2, 0, 0, 0.2, 0.6, 0.2, 0, 0, 0.2, 0.2, 0.7, 0, 0, 0, 0, 0, 1, 0], "Monochrome"),
];

View File

@@ -1,6 +1,6 @@
import "package:openapi/api.dart" as api show AssetEditAction;
enum AssetEditAction { rotate, crop, mirror, other }
enum AssetEditAction { rotate, crop, mirror, filter, other }
extension AssetEditActionExtension on AssetEditAction {
api.AssetEditAction? toDto() {
@@ -8,6 +8,7 @@ extension AssetEditActionExtension on AssetEditAction {
AssetEditAction.rotate => api.AssetEditAction.rotate,
AssetEditAction.crop => api.AssetEditAction.crop,
AssetEditAction.mirror => api.AssetEditAction.mirror,
AssetEditAction.filter => api.AssetEditAction.filter,
AssetEditAction.other => null,
};
}

View File

@@ -810,6 +810,7 @@ extension on api.AssetEditAction {
api.AssetEditAction.crop => AssetEditAction.crop,
api.AssetEditAction.rotate => AssetEditAction.rotate,
api.AssetEditAction.mirror => AssetEditAction.mirror,
api.AssetEditAction.filter => AssetEditAction.filter,
_ => AssetEditAction.other,
};
}

View File

@@ -23,7 +23,7 @@ class FilterImagePage extends HookWidget {
@override
Widget build(BuildContext context) {
final colorFilter = useState<ColorFilter>(filters[0]);
final colorFilter = useState<EditFilter>(filters[0]);
final selectedFilterIndex = useState<int>(0);
Future<ui.Image> createFilteredImage(ui.Image inputImage, ColorFilter filter) {
@@ -42,12 +42,12 @@ class FilterImagePage extends HookWidget {
return completer.future;
}
void applyFilter(ColorFilter filter, int index) {
void applyFilter(EditFilter filter, int index) {
colorFilter.value = filter;
selectedFilterIndex.value = index;
}
Future<Image> applyFilterAndConvert(ColorFilter filter) async {
Future<Image> applyFilterAndConvert(EditFilter filter) async {
final completer = Completer<ui.Image>();
image.image
.resolve(ImageConfiguration.empty)
@@ -58,7 +58,7 @@ class FilterImagePage extends HookWidget {
);
final uiImage = await completer.future;
final filteredUiImage = await createFilteredImage(uiImage, filter);
final filteredUiImage = await createFilteredImage(uiImage, filter.colorFilter);
final byteData = await filteredUiImage.toByteData(format: ui.ImageByteFormat.png);
final pngBytes = byteData!.buffer.asUint8List();
@@ -86,7 +86,7 @@ class FilterImagePage extends HookWidget {
SizedBox(
height: context.height * 0.7,
child: Center(
child: ColorFiltered(colorFilter: colorFilter.value, child: image),
child: ColorFiltered(colorFilter: colorFilter.value.colorFilter, child: image),
),
),
SizedBox(
@@ -99,7 +99,7 @@ class FilterImagePage extends HookWidget {
padding: const EdgeInsets.symmetric(horizontal: 8.0),
child: _FilterButton(
image: image,
label: filterNames[index],
label: filters[index].name,
filter: filters[index],
isSelected: selectedFilterIndex.value == index,
onTap: () => applyFilter(filters[index], index),
@@ -117,7 +117,7 @@ class FilterImagePage extends HookWidget {
class _FilterButton extends StatelessWidget {
final Image image;
final String label;
final ColorFilter filter;
final EditFilter filter;
final bool isSelected;
final VoidCallback onTap;
@@ -145,7 +145,7 @@ class _FilterButton extends StatelessWidget {
child: ClipRRect(
borderRadius: const BorderRadius.all(Radius.circular(10)),
child: ColorFiltered(
colorFilter: filter,
colorFilter: filter.colorFilter,
child: FittedBox(fit: BoxFit.cover, child: image),
),
),

View File

@@ -49,7 +49,7 @@ class _DriftEditImagePageState extends ConsumerState<DriftEditImagePage> with Ti
int _rotationAngle = 0;
bool _flipHorizontal = false;
bool _flipVertical = false;
ColorFilter? _colorFilter;
EditFilter? _filter;
double? _aspectRatio;
late final originalWidth = widget.exifInfo.isFlipped ? widget.exifInfo.height : widget.exifInfo.width;
@@ -74,6 +74,12 @@ class _DriftEditImagePageState extends ConsumerState<DriftEditImagePage> with Ti
final (rotationAngle, flipHorizontal, flipVertical) = normalizeTransformEdits(widget.edits);
final existingFilter = widget.edits.firstWhereOrNull((edit) => edit.action == AssetEditAction.filter);
if (existingFilter != null) {
final parsedFilter = EditFilter.fromDtoParams(existingFilter.parameters, 'Custom');
_filter = filters.firstWhereOrNull((filter) => filter == parsedFilter);
}
// dont animate to initial rotation
_rotationAnimationDuration = const Duration(milliseconds: 0);
_rotationAngle = rotationAngle.toInt();
@@ -122,6 +128,10 @@ class _DriftEditImagePageState extends ConsumerState<DriftEditImagePage> with Ti
);
}
if (_filter != null && !_filter!.isIdentity) {
edits.add(AssetEdit(action: AssetEditAction.filter, parameters: _filter!.dtoParameters));
}
try {
final completer = ref.read(websocketProvider.notifier).waitForEvent("AssetEditReadyV1", (dynamic data) {
final eventData = data as Map<String, dynamic>;
@@ -208,9 +218,9 @@ class _DriftEditImagePageState extends ConsumerState<DriftEditImagePage> with Ti
});
}
void _applyFilter(ColorFilter? filter) {
void _applyFilter(EditFilter? filter) {
setState(() {
_colorFilter = filter;
_filter = filter;
});
}
@@ -222,7 +232,7 @@ class _DriftEditImagePageState extends ConsumerState<DriftEditImagePage> with Ti
_rotationAngle = 0;
_flipHorizontal = false;
_flipVertical = false;
_colorFilter = null;
_filter = null;
_aspectRatio = null;
});
}
@@ -231,7 +241,7 @@ class _DriftEditImagePageState extends ConsumerState<DriftEditImagePage> with Ti
final isCropped = cropController.crop != const Rect.fromLTRB(0, 0, 1, 1);
final isRotated = (_rotationAngle % 360 + 360) % 360 != 0;
final isFlipped = _flipHorizontal || _flipVertical;
final isFiltered = _colorFilter != null;
final isFiltered = _filter != null && !_filter!.isIdentity;
return isCropped || isRotated || isFlipped || isFiltered;
}
@@ -292,7 +302,10 @@ class _DriftEditImagePageState extends ConsumerState<DriftEditImagePage> with Ti
controller: cropController,
image: widget.image,
gridColor: Colors.white,
overlayPainter: MatrixAdjustmentPainter(image: data.data!, filter: _colorFilter),
overlayPainter: MatrixAdjustmentPainter(
image: data.data!,
filter: _filter?.colorFilter,
),
);
},
),
@@ -334,7 +347,7 @@ class _DriftEditImagePageState extends ConsumerState<DriftEditImagePage> with Ti
aspectRatio: _aspectRatio,
),
secondChild: _FilterControls(
currentFilter: _colorFilter,
currentFilter: _filter,
previewImage: widget.image,
onApplyFilter: _applyFilter,
),
@@ -540,9 +553,9 @@ class _TransformControls extends StatelessWidget {
}
class _FilterControls extends StatelessWidget {
final ColorFilter? currentFilter;
final EditFilter? currentFilter;
final Image previewImage;
final void Function(ColorFilter?) onApplyFilter;
final void Function(EditFilter?) onApplyFilter;
const _FilterControls({required this.currentFilter, required this.previewImage, required this.onApplyFilter});
@@ -555,14 +568,13 @@ class _FilterControls extends StatelessWidget {
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Row(
children: filters.mapIndexed((i, filter) {
children: filters.map((filter) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 8.0),
child: _FilterButton(
image: previewImage,
label: filterNames[i],
filter: filter,
isSelected: currentFilter == filters[i],
isSelected: currentFilter == filter,
onTap: () => onApplyFilter(filter),
),
);
@@ -576,18 +588,11 @@ class _FilterControls extends StatelessWidget {
class _FilterButton extends StatelessWidget {
final Image image;
final String label;
final ColorFilter filter;
final EditFilter filter;
final bool isSelected;
final VoidCallback onTap;
const _FilterButton({
required this.image,
required this.label,
required this.filter,
required this.isSelected,
required this.onTap,
});
const _FilterButton({required this.image, required this.filter, required this.isSelected, required this.onTap});
@override
Widget build(BuildContext context) {
@@ -605,14 +610,14 @@ class _FilterButton extends StatelessWidget {
child: ClipRRect(
borderRadius: BorderRadius.all(isSelected ? const Radius.circular(9) : const Radius.circular(12)),
child: ColorFiltered(
colorFilter: filter,
colorFilter: filter.colorFilter,
child: Image(image: image.image, fit: BoxFit.cover),
),
),
),
),
const SizedBox(height: 10),
Text(label, style: context.themeData.textTheme.bodyMedium),
Text(filter.name, style: context.themeData.textTheme.bodyMedium),
],
);
}