twonly-app/lib/src/components/image_editor/layers/draw_layer.dart
2025-02-04 22:42:18 +01:00

204 lines
6.1 KiB
Dart

import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:hand_signature/signature.dart';
import 'package:screenshot/screenshot.dart';
import 'package:twonly/src/components/image_editor/action_button.dart';
import 'package:twonly/src/components/image_editor/data/layer.dart';
import 'package:twonly/src/utils/misc.dart';
class DrawLayer extends StatefulWidget {
final DrawLayerData layerData;
final VoidCallback? onUpdate;
const DrawLayer({
super.key,
required this.layerData,
this.onUpdate,
});
@override
createState() => _DrawLayerState();
}
class _DrawLayerState extends State<DrawLayer> {
Color pickerColor = Colors.white, currentColor = Colors.white;
var screenshotController = ScreenshotController();
List<CubicPath> undoList = [];
bool skipNextEvent = false;
@override
void initState() {
widget.layerData.control.addListener(() {
if (widget.layerData.control.hasActivePath) return;
if (skipNextEvent) {
skipNextEvent = false;
return;
}
undoList = [];
setState(() {});
});
super.initState();
}
double _sliderValue = 0.0;
final colors = [
Colors.white,
Colors.red,
Colors.orange,
Colors.yellow,
Colors.green,
Colors.indigo,
Colors.blue,
Colors.black,
];
Color _getColorFromSliderValue(double value) {
// Calculate the index based on the slider value
int index = (value * (colors.length - 1)).floor();
int nextIndex = (index + 1).clamp(0, colors.length - 1);
// Calculate the interpolation factor
double factor = value * (colors.length - 1) - index;
// Interpolate between the two colors
return Color.lerp(colors[index], colors[nextIndex], factor)!;
}
void _onSliderChanged(double value) {
setState(() {
_sliderValue = value;
currentColor = _getColorFromSliderValue(value);
});
}
@override
Widget build(BuildContext context) {
return Stack(
fit: StackFit.expand,
children: [
Positioned.fill(
child: Container(
decoration: BoxDecoration(
color: Colors.transparent,
),
child: Screenshot(
controller: screenshotController,
child: HandSignature(
control: widget.layerData.control,
color: currentColor,
width: 1.0,
maxWidth: 7.0,
type: SignatureDrawType.shape,
),
),
),
),
if (widget.layerData.isEditing && widget.layerData.showCustomButtons)
Positioned(
top: 5,
left: 5,
right: 50,
child: Row(
children: [
ActionButton(
FontAwesomeIcons.check,
tooltipText: context.lang.imageEditorDrawOk,
onPressed: () async {
widget.layerData.isEditing = false;
},
),
Expanded(child: Container()),
ActionButton(
FontAwesomeIcons.arrowRotateLeft,
tooltipText: context.lang.undo,
color: widget.layerData.control.paths.isNotEmpty
? Colors.white
: Colors.white.withAlpha(80),
onPressed: () {
if (widget.layerData.control.paths.isEmpty) return;
skipNextEvent = true;
undoList.add(widget.layerData.control.paths.last);
widget.layerData.control.stepBack();
setState(() {});
},
),
ActionButton(
tooltipText: context.lang.redo,
FontAwesomeIcons.arrowRotateRight,
color: undoList.isNotEmpty
? Colors.white
: Colors.white.withAlpha(80),
onPressed: () {
if (undoList.isEmpty) return;
widget.layerData.control.paths.add(undoList.removeLast());
setState(() {});
},
),
],
),
),
if (widget.layerData.isEditing && widget.layerData.showCustomButtons)
Positioned(
right: 20,
top: 50,
child: Stack(
children: <Widget>[
Container(
height: 240,
width: 40,
color: Colors.transparent,
),
SizedBox(
height: 240,
width: 40,
child: Center(
child: Container(
alignment: Alignment.center,
width: 10,
height: 195,
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: colors,
stops: List.generate(colors.length,
(index) => index / (colors.length - 1)),
),
borderRadius: BorderRadius.circular(10),
),
),
),
),
Positioned.fill(
child: RotatedBox(
quarterTurns: 1,
child: Slider(
value: _sliderValue,
thumbColor: currentColor,
activeColor: Colors.transparent,
inactiveColor: Colors.transparent,
onChanged: _onSliderChanged,
min: 0.0,
max: 1.0,
divisions: 100,
),
),
),
],
),
),
if (!widget.layerData.isEditing)
Positioned.fill(
child: Container(
color: Colors.transparent,
))
],
);
}
}