|
@@ -1,423 +0,0 @@
|
|
|
-
|
|
|
- * @Descripttion:
|
|
|
- * @version:
|
|
|
- * @Author: guanxiaoxin
|
|
|
- * @Date: 2023-10-18 15:34:43
|
|
|
- * @LastEditors: guanxiaoxin
|
|
|
- * @LastEditTime: 2023-10-18 16:23:12
|
|
|
- * @FilePath: \VNoteApp\lib\components\floating_window\floating_button.dart
|
|
|
- */
|
|
|
-import 'dart:async';
|
|
|
-import 'dart:math';
|
|
|
-import 'dart:ui' as ui;
|
|
|
-
|
|
|
-import 'package:flutter/material.dart';
|
|
|
-import 'package:get/get.dart';
|
|
|
-import 'package:vnoteapp/components/floating_window/click_notification.dart';
|
|
|
-import 'package:vnoteapp/components/floating_window/floating_window_shared_data_widget.dart';
|
|
|
-
|
|
|
-class FloatingButton extends StatefulWidget {
|
|
|
- const FloatingButton({super.key});
|
|
|
-
|
|
|
- @override
|
|
|
- _FloatingButtonState createState() => _FloatingButtonState();
|
|
|
-}
|
|
|
-
|
|
|
-class _FloatingButtonState extends State<FloatingButton>
|
|
|
- with TickerProviderStateMixin {
|
|
|
-
|
|
|
- bool isPress = false;
|
|
|
-
|
|
|
-
|
|
|
- AnimationController? _controller;
|
|
|
-
|
|
|
-
|
|
|
- Animation? _animation;
|
|
|
-
|
|
|
- @override
|
|
|
- Widget build(BuildContext context) {
|
|
|
-
|
|
|
- var windowModel = FloatingWindowSharedDataWidget.of(context)!.data;
|
|
|
- return Positioned(
|
|
|
- left: windowModel.left,
|
|
|
- top: windowModel.top,
|
|
|
- child: Listener(
|
|
|
-
|
|
|
- onPointerDown: (details) {
|
|
|
- setState(() {
|
|
|
- isPress = true;
|
|
|
- });
|
|
|
- },
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
- onPointerUp: (e) async {
|
|
|
- setState(() {
|
|
|
- isPress = false;
|
|
|
- });
|
|
|
-
|
|
|
-
|
|
|
- var pixelDetails = MediaQuery.of(context).size;
|
|
|
-
|
|
|
-
|
|
|
- if (windowModel.isLeft &&
|
|
|
- e.position.dx <= 50.0 &&
|
|
|
- windowModel.isEdge) {
|
|
|
- ClickNotification(changeWidget: true).dispatch(context);
|
|
|
- return;
|
|
|
- } else if (!windowModel.isLeft &&
|
|
|
- e.position.dx >= pixelDetails.width - 50.0 &&
|
|
|
- windowModel.isEdge) {
|
|
|
- ClickNotification(changeWidget: true).dispatch(context);
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- if (e.position.dx <= pixelDetails.width / 2) {
|
|
|
-
|
|
|
- _controller = AnimationController(
|
|
|
- vsync: this,
|
|
|
- duration: const Duration(milliseconds: 100));
|
|
|
- _animation =
|
|
|
- Tween(begin: e.position.dx, end: 0.0).animate(_controller!)
|
|
|
- ..addListener(() {
|
|
|
- setState(() {
|
|
|
-
|
|
|
- windowModel.left = _animation!.value;
|
|
|
- });
|
|
|
- });
|
|
|
-
|
|
|
-
|
|
|
- await _controller!.forward();
|
|
|
- _controller!.dispose();
|
|
|
-
|
|
|
-
|
|
|
- setState(() {
|
|
|
- windowModel.isLeft = true;
|
|
|
-
|
|
|
-
|
|
|
- });
|
|
|
- } else {
|
|
|
-
|
|
|
- _controller = AnimationController(
|
|
|
- vsync: this,
|
|
|
- duration: const Duration(milliseconds: 100));
|
|
|
- _animation =
|
|
|
- Tween(begin: e.position.dx, end: pixelDetails.width - 50)
|
|
|
- .animate(_controller!)
|
|
|
- ..addListener(() {
|
|
|
- setState(() {
|
|
|
- windowModel.left = _animation!.value;
|
|
|
-
|
|
|
-
|
|
|
- });
|
|
|
- });
|
|
|
- await _controller!.forward();
|
|
|
-
|
|
|
-
|
|
|
- _controller!.dispose();
|
|
|
-
|
|
|
-
|
|
|
- setState(() {
|
|
|
- windowModel.isLeft = false;
|
|
|
-
|
|
|
-
|
|
|
- });
|
|
|
- }
|
|
|
-
|
|
|
- setState(() {
|
|
|
- windowModel.isEdge = true;
|
|
|
-
|
|
|
-
|
|
|
- });
|
|
|
- },
|
|
|
- child: GestureDetector(
|
|
|
-
|
|
|
- onPanUpdate: (details) {
|
|
|
- var pixelDetails = MediaQuery.of(context).size;
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
- if (windowModel.left + details.delta.dx > 0 &&
|
|
|
- windowModel.left + details.delta.dx < pixelDetails.width - 50) {
|
|
|
- setState(() {
|
|
|
- windowModel.isEdge = false;
|
|
|
- });
|
|
|
- } else {
|
|
|
- setState(() {
|
|
|
- windowModel.isEdge = true;
|
|
|
- });
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- setState(() {
|
|
|
- windowModel.left += details.delta.dx;
|
|
|
- windowModel.top += details.delta.dy;
|
|
|
- });
|
|
|
- },
|
|
|
- child: FutureBuilder(
|
|
|
- future: loadImageByProvider(
|
|
|
- AssetImage(windowModel.dataList[0]['imageUrl'] ?? '')),
|
|
|
- builder: (context, snapshot) => CustomPaint(
|
|
|
- size: const Size(50.0, 50.0),
|
|
|
- painter: FloatingButtonPainter(
|
|
|
- isLeft: windowModel.isLeft,
|
|
|
- isEdge: windowModel.isEdge,
|
|
|
- isPress: isPress,
|
|
|
- buttonImage: Image.asset('assets/images/avatar.png')),
|
|
|
- ),
|
|
|
- ),
|
|
|
- ),
|
|
|
- ),
|
|
|
- );
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- Future<ui.Image> loadImageByProvider(
|
|
|
- ImageProvider provider, {
|
|
|
- ImageConfiguration config = ImageConfiguration.empty,
|
|
|
- }) async {
|
|
|
- Completer<ui.Image> completer = Completer<ui.Image>();
|
|
|
- ImageStreamListener listener;
|
|
|
- ImageStream stream = provider.resolve(config);
|
|
|
- listener = ImageStreamListener((ImageInfo frame, bool sync) {
|
|
|
-
|
|
|
- final ui.Image image = frame.image;
|
|
|
- completer.complete(image);
|
|
|
-
|
|
|
- });
|
|
|
- stream.addListener(listener);
|
|
|
- return completer.future;
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-class FloatingButtonPainter extends CustomPainter {
|
|
|
- FloatingButtonPainter(
|
|
|
- {Key? key,
|
|
|
- required this.isLeft,
|
|
|
- required this.isEdge,
|
|
|
- required this.isPress,
|
|
|
- required this.buttonImage});
|
|
|
-
|
|
|
-
|
|
|
- final bool isLeft;
|
|
|
-
|
|
|
-
|
|
|
- final bool isEdge;
|
|
|
-
|
|
|
-
|
|
|
- final bool isPress;
|
|
|
-
|
|
|
-
|
|
|
- final Image buttonImage;
|
|
|
-
|
|
|
- @override
|
|
|
- void paint(Canvas canvas, Size size) {
|
|
|
-
|
|
|
-
|
|
|
- if (isEdge) {
|
|
|
-
|
|
|
- if (isLeft) {
|
|
|
- paintLeftEdgeButton(canvas, size);
|
|
|
- } else {
|
|
|
- paintRightEdgeButton(canvas, size);
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- } else {
|
|
|
- paintCenterButton(canvas, size);
|
|
|
-
|
|
|
-
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- void paintLeftEdgeButton(Canvas canvas, Size size) {
|
|
|
-
|
|
|
- var paint = Paint()
|
|
|
- ..isAntiAlias = false
|
|
|
- ..style = PaintingStyle.fill
|
|
|
- ..color = const Color.fromRGBO(0xF3, 0xF3, 0xF3, 0.9);
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
- var path = Path()..moveTo(size.width / 2, size.height - 1.5);
|
|
|
- path.lineTo(0.0, size.height - 1.5);
|
|
|
- path.lineTo(0.0, 1.5);
|
|
|
- path.lineTo(size.width / 2, 1.5);
|
|
|
- Rect rect = Rect.fromCircle(
|
|
|
- center: Offset(size.width / 2, size.height / 2), radius: 23.5);
|
|
|
- path.arcTo(rect, pi * 1.5, pi, true);
|
|
|
- canvas.drawPath(path, paint);
|
|
|
-
|
|
|
-
|
|
|
- var edgePath = Path()..moveTo(size.width / 2, size.height);
|
|
|
- edgePath.lineTo(0.0, size.height);
|
|
|
- edgePath.lineTo(0.0, 0.0);
|
|
|
- edgePath.lineTo(size.width / 2, 0.0);
|
|
|
- Rect rect1 = Rect.fromCircle(
|
|
|
- center: Offset(size.width / 2, size.height / 2), radius: 25);
|
|
|
- edgePath.arcTo(rect1, pi * 1.5, pi, true);
|
|
|
-
|
|
|
- paint
|
|
|
- ..isAntiAlias = true
|
|
|
- ..strokeWidth = 0.75
|
|
|
- ..strokeCap = StrokeCap.round
|
|
|
- ..maskFilter = const MaskFilter.blur(BlurStyle.normal, 0.25)
|
|
|
-
|
|
|
-
|
|
|
- ..style = PaintingStyle.stroke
|
|
|
- ..color = const Color.fromRGBO(0xCF, 0xCF, 0xCF, 1);
|
|
|
- canvas.drawPath(edgePath, paint);
|
|
|
-
|
|
|
-
|
|
|
- if (isPress) {
|
|
|
- canvas.drawShadow(
|
|
|
- edgePath, const Color.fromRGBO(0xDA, 0xDA, 0xDA, 0.3), 0, false);
|
|
|
- }
|
|
|
-
|
|
|
- if (buttonImage.isNull) return;
|
|
|
-
|
|
|
-
|
|
|
- paint = Paint();
|
|
|
- canvas.save();
|
|
|
-
|
|
|
-
|
|
|
- RRect imageRRect = RRect.fromRectAndRadius(
|
|
|
- Rect.fromLTWH(size.width / 2 - 17.5, size.width / 2 - 17.5, 35, 35),
|
|
|
- const Radius.circular(17.5));
|
|
|
- canvas.clipRRect(imageRRect);
|
|
|
-
|
|
|
-
|
|
|
- canvas.drawColor(Colors.white, BlendMode.srcOver);
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
- canvas.restore();
|
|
|
-
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- void paintRightEdgeButton(Canvas canvas, Size size) {
|
|
|
- var paint = Paint()
|
|
|
- ..isAntiAlias = false
|
|
|
- ..style = PaintingStyle.fill
|
|
|
- ..color = const Color.fromRGBO(0xF3, 0xF3, 0xF3, 0.9);
|
|
|
-
|
|
|
- var path = Path()..moveTo(size.width / 2, 1.5);
|
|
|
- path.lineTo(size.width, 1.5);
|
|
|
- path.lineTo(size.width, size.height - 1.5);
|
|
|
- path.lineTo(size.width / 2, size.height - 1.5);
|
|
|
-
|
|
|
- Rect rect = Rect.fromCircle(
|
|
|
- center: Offset(size.width / 2, size.height / 2), radius: 23.5);
|
|
|
- path.arcTo(rect, pi * 0.5, pi, true);
|
|
|
-
|
|
|
- canvas.drawPath(path, paint);
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
- var edgePath = Path()..moveTo(size.width / 2, 0.0);
|
|
|
- edgePath.lineTo(size.width, 0.0);
|
|
|
- edgePath.lineTo(size.width, size.height);
|
|
|
- edgePath.lineTo(size.width / 2, size.height);
|
|
|
- Rect edgeRect = Rect.fromCircle(
|
|
|
- center: Offset(size.width / 2, size.height / 2), radius: 25);
|
|
|
- edgePath.arcTo(edgeRect, pi * 0.5, pi, true);
|
|
|
-
|
|
|
- paint
|
|
|
- ..isAntiAlias = true
|
|
|
- ..strokeWidth = 0.75
|
|
|
- ..strokeCap = StrokeCap.round
|
|
|
- ..maskFilter = const MaskFilter.blur(BlurStyle.normal, 0.25)
|
|
|
- ..style = PaintingStyle.stroke
|
|
|
- ..color = const Color.fromRGBO(0xCF, 0xCF, 0xCF, 1);
|
|
|
- canvas.drawPath(edgePath, paint);
|
|
|
-
|
|
|
-
|
|
|
- if (isPress) {
|
|
|
- canvas.drawShadow(
|
|
|
- path, const Color.fromRGBO(0xDA, 0xDA, 0xDA, 0.3), 0, false);
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- if (buttonImage.isNull) return;
|
|
|
-
|
|
|
-
|
|
|
- paint = Paint();
|
|
|
- canvas.save();
|
|
|
-
|
|
|
-
|
|
|
- RRect imageRRect = RRect.fromRectAndRadius(
|
|
|
- Rect.fromLTWH(size.width / 2 - 17.5, size.width / 2 - 17.5, 35, 35),
|
|
|
- const Radius.circular(17.5));
|
|
|
- canvas.clipRRect(imageRRect);
|
|
|
-
|
|
|
-
|
|
|
- canvas.drawColor(Colors.white, BlendMode.srcOver);
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
- canvas.restore();
|
|
|
-
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- void paintCenterButton(Canvas canvas, Size size) {
|
|
|
-
|
|
|
- var paint = Paint()
|
|
|
- ..isAntiAlias = false
|
|
|
- ..style = PaintingStyle.fill
|
|
|
- ..color = const Color.fromRGBO(0xF3, 0xF3, 0xF3, 0.9);
|
|
|
- canvas.drawCircle(Offset(size.width / 2, size.height / 2), 23.5, paint);
|
|
|
-
|
|
|
-
|
|
|
- paint
|
|
|
- ..isAntiAlias = true
|
|
|
- ..style = PaintingStyle.stroke
|
|
|
- ..strokeWidth = 0.75
|
|
|
- ..maskFilter = const MaskFilter.blur(BlurStyle.normal, 0.25)
|
|
|
- ..color = const Color.fromRGBO(0xCF, 0xCF, 0xCF, 1);
|
|
|
- canvas.drawCircle(Offset(size.width / 2, size.height / 2), 25, paint);
|
|
|
-
|
|
|
-
|
|
|
- if (isPress) {
|
|
|
- var circleRect = Rect.fromCircle(
|
|
|
- center: Offset(size.width / 2, size.height / 2), radius: 25);
|
|
|
- var circlePath = Path()..moveTo(size.width / 2, size.height / 2);
|
|
|
- circlePath.arcTo(circleRect, 0, 2 * 3.14, true);
|
|
|
- canvas.drawShadow(
|
|
|
- circlePath, const Color.fromRGBO(0xCF, 0xCF, 0xCF, 0.3), 0.5, false);
|
|
|
- }
|
|
|
-
|
|
|
- if (buttonImage.isNull) return;
|
|
|
-
|
|
|
-
|
|
|
- paint = Paint();
|
|
|
- canvas.save();
|
|
|
-
|
|
|
-
|
|
|
- RRect imageRRect = RRect.fromRectAndRadius(
|
|
|
- Rect.fromLTWH(size.width / 2 - 17.5, size.width / 2 - 17.5, 35, 35),
|
|
|
- const Radius.circular(35));
|
|
|
- canvas.clipRRect(imageRRect);
|
|
|
-
|
|
|
-
|
|
|
- canvas.drawColor(Colors.white, BlendMode.color);
|
|
|
- }
|
|
|
-
|
|
|
- @override
|
|
|
- bool shouldRepaint(covariant CustomPainter oldDelegate) => true;
|
|
|
-}
|