forked from lxm_flutter/FlutterUnit
优化 burst_menu
This commit is contained in:
@@ -1,116 +0,0 @@
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
/// create by 张风捷特烈 on 2020/11/17
|
||||
/// contact me by email 1981462002@qq.com
|
||||
/// 说明:
|
||||
|
||||
class BurstFlow extends StatefulWidget {
|
||||
final List<Widget> children;
|
||||
final Widget menu;
|
||||
final double startAngle;
|
||||
|
||||
final double swapAngle;
|
||||
|
||||
BurstFlow({Key key,@required this.children,
|
||||
this.startAngle = 30 + 90.0,
|
||||
this.swapAngle = 120,
|
||||
@required this.menu}) : super(key: key);
|
||||
|
||||
|
||||
@override
|
||||
BurstFlowState createState() => BurstFlowState();
|
||||
}
|
||||
|
||||
class BurstFlowState extends State<BurstFlow>
|
||||
with SingleTickerProviderStateMixin {
|
||||
AnimationController _controller;
|
||||
bool _closed = true;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_controller =
|
||||
AnimationController(duration: Duration(milliseconds: 300), vsync: this)
|
||||
..addStatusListener((status) {
|
||||
if (status == AnimationStatus.completed) {}
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Flow(
|
||||
delegate: _CircleFlowDelegate(_controller,
|
||||
swapAngle: widget.swapAngle, startAngle: widget.startAngle),
|
||||
children: [
|
||||
...widget.children,
|
||||
GestureDetector(onTap: toggle, child: widget.menu)
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
toggle() {
|
||||
if (_closed) {
|
||||
_controller.forward();
|
||||
} else {
|
||||
_controller.reverse();
|
||||
}
|
||||
_closed = !_closed;
|
||||
}
|
||||
}
|
||||
|
||||
class _CircleFlowDelegate extends FlowDelegate {
|
||||
final Animation<double> repaint;
|
||||
|
||||
_CircleFlowDelegate(this.repaint,
|
||||
{this.startAngle = 30 + 90.0, this.swapAngle = 120})
|
||||
: super(repaint: repaint);
|
||||
|
||||
final double startAngle;
|
||||
|
||||
final double swapAngle;
|
||||
|
||||
@override //绘制孩子的方法
|
||||
void paintChildren(FlowPaintingContext context) {
|
||||
double radius = context.size.shortestSide / 2;
|
||||
if (repaint.value > 0.3) {
|
||||
var count = context.childCount - 1;
|
||||
var perRad = swapAngle / 180 * pi / (count - 1);
|
||||
double rotate = startAngle / 180 * pi;
|
||||
for (int i = 0; i < count; i++) {
|
||||
var cSizeX = context.getChildSize(i).width / 2;
|
||||
var cSizeY = context.getChildSize(i).height / 2;
|
||||
|
||||
var offsetX =
|
||||
repaint.value * (radius - cSizeX) * cos(i * perRad + rotate) +
|
||||
radius;
|
||||
var offsetY =
|
||||
repaint.value * (radius - cSizeY) * sin(i * perRad + rotate) +
|
||||
radius;
|
||||
|
||||
context.paintChild(i,
|
||||
transform: Matrix4.translationValues(
|
||||
offsetX - cSizeX, offsetY - cSizeY, 0.0),
|
||||
opacity: repaint.value);
|
||||
}
|
||||
}
|
||||
|
||||
context.paintChild(context.childCount - 1,
|
||||
transform: Matrix4.translationValues(
|
||||
radius - context.getChildSize(context.childCount - 1).width / 2,
|
||||
radius - context.getChildSize(context.childCount - 1).height / 2,
|
||||
0.0));
|
||||
}
|
||||
|
||||
@override
|
||||
bool shouldRepaint(FlowDelegate oldDelegate) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
296
lib/views/components/permanent/burst_menu.dart
Normal file
296
lib/views/components/permanent/burst_menu.dart
Normal file
@@ -0,0 +1,296 @@
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
/// create by 张风捷特烈 on 2020/11/17
|
||||
/// contact me by email 1981462002@qq.com
|
||||
/// 说明:
|
||||
|
||||
enum BurstType {
|
||||
circle,
|
||||
topLeft,
|
||||
bottomLeft,
|
||||
topRight,
|
||||
bottomRight,
|
||||
halfCircle,
|
||||
}
|
||||
|
||||
typedef BurstMenuItemClick = bool Function(int index);
|
||||
|
||||
class BurstMenu extends StatefulWidget {
|
||||
final List<Widget> menus;
|
||||
final Widget center;
|
||||
final double radius;
|
||||
final double startAngle;
|
||||
final double swapAngle;
|
||||
final double hideOpacity;
|
||||
final Duration duration;
|
||||
final BurstType burstType;
|
||||
final Curve curve;
|
||||
final BurstMenuItemClick burstMenuItemClick;
|
||||
|
||||
const BurstMenu({
|
||||
Key key,
|
||||
@required this.menus,
|
||||
@required this.center,
|
||||
this.radius = 100,
|
||||
this.swapAngle = 120,
|
||||
this.startAngle = -60,
|
||||
this.hideOpacity = 0,
|
||||
this.curve = Curves.ease,
|
||||
this.duration = const Duration(milliseconds: 300),
|
||||
this.burstType = BurstType.circle,
|
||||
this.burstMenuItemClick,
|
||||
}) : super(key: key);
|
||||
|
||||
BurstMenu.topLeft({
|
||||
this.menus,
|
||||
this.burstMenuItemClick,
|
||||
this.radius,
|
||||
this.center,
|
||||
this.hideOpacity = 0,
|
||||
this.curve = Curves.ease,
|
||||
this.duration = const Duration(milliseconds: 300),
|
||||
this.burstType = BurstType.topLeft,
|
||||
this.swapAngle = 90,
|
||||
this.startAngle = 0,
|
||||
});
|
||||
|
||||
BurstMenu.bottomLeft({
|
||||
this.menus,
|
||||
this.burstMenuItemClick,
|
||||
this.radius,
|
||||
this.center,
|
||||
this.hideOpacity = 0,
|
||||
this.curve = Curves.ease,
|
||||
this.duration = const Duration(milliseconds: 300),
|
||||
this.burstType = BurstType.bottomLeft,
|
||||
this.swapAngle = 90,
|
||||
this.startAngle = -90,
|
||||
});
|
||||
|
||||
BurstMenu.topRight({
|
||||
this.menus,
|
||||
this.burstMenuItemClick,
|
||||
this.radius,
|
||||
this.center,
|
||||
this.hideOpacity = 0,
|
||||
this.curve = Curves.ease,
|
||||
this.duration = const Duration(milliseconds: 500),
|
||||
this.burstType = BurstType.topRight,
|
||||
this.swapAngle = -90,
|
||||
this.startAngle = 180,
|
||||
});
|
||||
|
||||
BurstMenu.bottomRight({
|
||||
this.menus,
|
||||
this.burstMenuItemClick,
|
||||
this.radius,
|
||||
this.center,
|
||||
this.hideOpacity = 0,
|
||||
this.curve = Curves.ease,
|
||||
this.duration = const Duration(milliseconds: 300),
|
||||
this.burstType = BurstType.bottomRight,
|
||||
this.swapAngle = 90,
|
||||
this.startAngle = 180,
|
||||
});
|
||||
|
||||
@override
|
||||
BurstMenuState createState() => BurstMenuState();
|
||||
}
|
||||
|
||||
class BurstMenuState extends State<BurstMenu>
|
||||
with SingleTickerProviderStateMixin {
|
||||
AnimationController _controller;
|
||||
|
||||
// 是否已关闭
|
||||
bool _closed = true;
|
||||
Animation<double> curveAnim; // 1.定义曲线动画
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_controller = AnimationController(
|
||||
duration: widget.duration,
|
||||
vsync: this,
|
||||
);
|
||||
curveAnim = CurvedAnimation(
|
||||
parent: _controller, curve: widget.curve); //<--2.创建曲线动画
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
width: widget.radius * 2,
|
||||
height: widget.burstType == BurstType.halfCircle
|
||||
? widget.radius
|
||||
: widget.radius * 2,
|
||||
alignment: Alignment.center,
|
||||
child: Flow(
|
||||
delegate: _CircleFlowDelegate(curveAnim,
|
||||
startAngle: widget.startAngle,
|
||||
hideOpacity: widget.hideOpacity,
|
||||
swapAngle: widget.swapAngle,
|
||||
burstType: widget.burstType),
|
||||
children: [
|
||||
...widget.menus.asMap().keys.map((int index) => GestureDetector(
|
||||
onTap: () => _handleItemClick(index),
|
||||
child: widget.menus[index],
|
||||
)),
|
||||
GestureDetector(onTap: toggle, child: widget.center)
|
||||
],
|
||||
));
|
||||
}
|
||||
|
||||
void _handleItemClick(int index) {
|
||||
if (widget.burstMenuItemClick == null) {
|
||||
toggle();
|
||||
return;
|
||||
}
|
||||
bool close = widget.burstMenuItemClick.call(index);
|
||||
if (close) toggle();
|
||||
}
|
||||
|
||||
@override
|
||||
void didUpdateWidget(BurstMenu oldWidget) {
|
||||
super.didUpdateWidget(oldWidget);
|
||||
|
||||
if (widget.duration != oldWidget.duration) {
|
||||
_controller.dispose();
|
||||
_controller = AnimationController(duration: widget.duration, vsync: this);
|
||||
}
|
||||
if (widget.curve != oldWidget.curve ||
|
||||
widget.duration != oldWidget.duration) {
|
||||
curveAnim = CurvedAnimation(parent: _controller, curve: widget.curve);
|
||||
}
|
||||
}
|
||||
|
||||
void toggle() {
|
||||
print("--$_closed------------");
|
||||
|
||||
if (_closed) {
|
||||
_controller.forward();
|
||||
} else {
|
||||
_controller.reverse();
|
||||
}
|
||||
_closed = !_closed;
|
||||
}
|
||||
}
|
||||
|
||||
class _CircleFlowDelegate extends FlowDelegate {
|
||||
// 菜单圆弧的扫描角度
|
||||
final double swapAngle;
|
||||
|
||||
// 菜单圆弧的起始角度
|
||||
final double startAngle;
|
||||
final double hideOpacity;
|
||||
final BurstType burstType;
|
||||
|
||||
final Animation<double> animation;
|
||||
|
||||
_CircleFlowDelegate(
|
||||
this.animation, {
|
||||
this.swapAngle = 120,
|
||||
this.hideOpacity = 0.3,
|
||||
this.startAngle = -60,
|
||||
this.burstType = BurstType.circle,
|
||||
}) : super(repaint: animation);
|
||||
|
||||
//绘制孩子的方法
|
||||
@override
|
||||
void paintChildren(FlowPaintingContext context) {
|
||||
double radius = context.size.shortestSide / 2;
|
||||
final double halfCenterSize =
|
||||
context.getChildSize(context.childCount - 1).width / 2;
|
||||
|
||||
switch (burstType) {
|
||||
case BurstType.circle:
|
||||
paintWithOffset(context, Offset.zero);
|
||||
break;
|
||||
case BurstType.topLeft:
|
||||
Offset centerOffset =
|
||||
Offset(-radius + halfCenterSize, -radius + halfCenterSize);
|
||||
paintWithOffset(context, centerOffset);
|
||||
break;
|
||||
case BurstType.bottomLeft:
|
||||
Offset centerOffset =
|
||||
Offset(-radius + halfCenterSize, radius - halfCenterSize);
|
||||
paintWithOffset(context, centerOffset);
|
||||
break;
|
||||
case BurstType.topRight:
|
||||
Offset centerOffset =
|
||||
Offset(radius - halfCenterSize, -radius + halfCenterSize);
|
||||
paintWithOffset(context, centerOffset);
|
||||
break;
|
||||
case BurstType.bottomRight:
|
||||
Offset centerOffset =
|
||||
Offset(radius - halfCenterSize, radius - halfCenterSize);
|
||||
paintWithOffset(context, centerOffset);
|
||||
break;
|
||||
case BurstType.halfCircle:
|
||||
Offset centerOffset = Offset(radius, radius - halfCenterSize);
|
||||
paintWithOffset(context, centerOffset);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void paintWithOffset(FlowPaintingContext context, Offset centerOffset) {
|
||||
final double radius = context.size.shortestSide / 2;
|
||||
|
||||
final int count = context.childCount - 1;
|
||||
final double perRad = swapAngle / 180 * pi / (count - 1);
|
||||
final double rotate = startAngle / 180 * pi;
|
||||
|
||||
if (animation.value > hideOpacity) {
|
||||
for (int i = 0; i < count; i++) {
|
||||
final double cSizeX = context.getChildSize(i).width / 2;
|
||||
final double cSizeY = context.getChildSize(i).height / 2;
|
||||
|
||||
final double beforeRadius = (radius - cSizeX);
|
||||
final double now = beforeRadius + centerOffset.dy.abs();
|
||||
final swapRadius = (radius - cSizeX) / beforeRadius * now;
|
||||
|
||||
final double offsetX =
|
||||
animation.value * swapRadius * cos(i * perRad + rotate) +
|
||||
radius +
|
||||
centerOffset.dx;
|
||||
final double offsetY =
|
||||
animation.value * swapRadius * sin(i * perRad + rotate) +
|
||||
radius +
|
||||
centerOffset.dy;
|
||||
|
||||
context.paintChild(
|
||||
i,
|
||||
transform: Matrix4.translationValues(
|
||||
offsetX - cSizeX,
|
||||
offsetY - cSizeY,
|
||||
0.0,
|
||||
),
|
||||
opacity: animation.value,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
context.paintChild(
|
||||
context.childCount - 1,
|
||||
transform: Matrix4.translationValues(
|
||||
radius -
|
||||
context.getChildSize(context.childCount - 1).width / 2 +
|
||||
centerOffset.dx,
|
||||
radius -
|
||||
context.getChildSize(context.childCount - 1).height / 2 +
|
||||
centerOffset.dy,
|
||||
0.0,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
bool shouldRepaint(FlowDelegate oldDelegate) => false;
|
||||
}
|
||||
@@ -4,10 +4,7 @@ import 'package:flutter_unit/app/res/toly_icon.dart';
|
||||
import 'package:flutter_unit/app/router/unit_router.dart';
|
||||
import 'package:flutter_unit/blocs/bloc_exp.dart';
|
||||
|
||||
import 'package:flutter_unit/views/components/permanent/feedback_widget.dart';
|
||||
|
||||
|
||||
import '../permanent/burst_flow.dart';
|
||||
import '../permanent/burst_menu.dart';
|
||||
import '../permanent/color_wrapper.dart';
|
||||
|
||||
/// create by 张风捷特烈 on 2020/10/21
|
||||
@@ -84,11 +81,8 @@ class OverlayToolWrapperState extends State<OverlayToolWrapper>
|
||||
final double circleRadius = 80;
|
||||
final double menuSize = 36;
|
||||
|
||||
GlobalKey<BurstFlowState> burstFlowKey = GlobalKey<BurstFlowState>();
|
||||
|
||||
_buildFloating() {
|
||||
Widget _buildFloating() {
|
||||
Color wrapColor = Colors.blue.withOpacity(0.6);
|
||||
|
||||
bool left = offset.dx < 100;
|
||||
|
||||
return Container(
|
||||
@@ -98,96 +92,100 @@ class OverlayToolWrapperState extends State<OverlayToolWrapper>
|
||||
// color: Colors.orangeAccent,
|
||||
child: IconTheme(
|
||||
data: IconTheme.of(context).copyWith(color: Colors.white, size: 18),
|
||||
child: BurstFlow(
|
||||
key: burstFlowKey,
|
||||
startAngle: !left ? 90.0 + 15 : -90 + 15.0,
|
||||
swapAngle: !left ? 180.0 - 15 * 2 : 180.0 - 15 * 2.0,
|
||||
menu: GestureDetector(
|
||||
onPanEnd: _onPanEnd,
|
||||
onPanDown: _onPanDown,
|
||||
onPanUpdate: _updatePosition,
|
||||
child: Opacity(
|
||||
opacity: 0.9,
|
||||
child: Container(
|
||||
width: menuSize,
|
||||
height: menuSize,
|
||||
padding: EdgeInsets.all(2),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.blue,
|
||||
borderRadius: BorderRadius.circular(menuSize / 2)),
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.blue,
|
||||
image: DecorationImage(
|
||||
image: AssetImage('assets/images/icon_head.webp')),
|
||||
borderRadius: BorderRadius.circular(menuSize / 2)),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
children: _buildMenuItems(wrapColor)),
|
||||
child: BurstMenu(
|
||||
startAngle: !left ? 90.0 + 15 : -90 - 15.0 + 180,
|
||||
swapAngle: !left ? 180.0 - 15 * 2 : -(180.0 - 15 * 2),
|
||||
center: _buildCenter(),
|
||||
burstMenuItemClick: _burstMenuItemClick,
|
||||
menus: _buildMenuItems(wrapColor)),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildCenter() => GestureDetector(
|
||||
onPanEnd: _onPanEnd,
|
||||
onPanUpdate: _updatePosition,
|
||||
child: Opacity(
|
||||
opacity: 0.9,
|
||||
child: Container(
|
||||
width: menuSize,
|
||||
height: menuSize,
|
||||
padding: const EdgeInsets.all(2),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.blue,
|
||||
borderRadius: BorderRadius.circular(menuSize / 2)),
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.blue,
|
||||
image: DecorationImage(
|
||||
image: const AssetImage('assets/images/icon_head.webp')),
|
||||
borderRadius: BorderRadius.circular(menuSize / 2)),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
// 构建 菜单 item
|
||||
List<Widget> _buildMenuItems(Color wrapColor) => [
|
||||
FeedbackWidget(
|
||||
onPressed: _doClose,
|
||||
child: Circled(color: wrapColor, child: Icon(Icons.close))),
|
||||
FeedbackWidget(
|
||||
onPressed: _toPoint,
|
||||
child: Circled(
|
||||
color: wrapColor, radius: 15, child: Icon(TolyIcon.icon_bug))),
|
||||
FeedbackWidget(
|
||||
onPressed: _toGalley,
|
||||
child: Circled(
|
||||
color: wrapColor, radius: 15, child: Icon(Icons.palette))),
|
||||
FeedbackWidget(
|
||||
onPressed: _toWidget,
|
||||
child: Circled(color: wrapColor, child: Icon(Icons.widgets))),
|
||||
FeedbackWidget(
|
||||
onPressed: _toSetting,
|
||||
child: Circled(color: wrapColor, child: Icon(Icons.settings))),
|
||||
Circled(color: wrapColor, child: const Icon(Icons.close)),
|
||||
Circled(color: wrapColor, radius: 15, child: const Icon(TolyIcon.icon_bug)),
|
||||
Circled(color: wrapColor, radius: 15, child: const Icon(Icons.palette)),
|
||||
Circled(color: wrapColor, child: const Icon(Icons.widgets)),
|
||||
Circled(color: wrapColor, child: const Icon(Icons.settings)),
|
||||
];
|
||||
|
||||
bool _burstMenuItemClick(int index) {
|
||||
print(index);
|
||||
switch (index) {
|
||||
case 0:
|
||||
_doClose();
|
||||
return true;
|
||||
break;
|
||||
case 1:
|
||||
_toPoint();
|
||||
break;
|
||||
case 2:
|
||||
_toGalley();
|
||||
break;
|
||||
case 3:
|
||||
_toWidget();
|
||||
break;
|
||||
case 4:
|
||||
_toSetting();
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// 处理 菜单 item 点击事件
|
||||
void _toSetting() {
|
||||
Navigator.of(context).pushNamed(UnitRouter.setting);
|
||||
burstFlowKey.currentState.toggle();
|
||||
}
|
||||
|
||||
void _toWidget() {
|
||||
burstFlowKey.currentState.toggle();
|
||||
}
|
||||
void _toWidget() {}
|
||||
|
||||
void _toGalley() {
|
||||
Navigator.of(context).pushNamed(UnitRouter.galley);
|
||||
burstFlowKey.currentState.toggle();
|
||||
}
|
||||
|
||||
void _toPoint() {
|
||||
BlocProvider.of<PointBloc>(context).add(EventLoadPoint());
|
||||
Navigator.of(context).pushNamed(UnitRouter.point);
|
||||
burstFlowKey.currentState.toggle();
|
||||
}
|
||||
|
||||
void _doClose() {
|
||||
if (Navigator.of(context).canPop()) {
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
burstFlowKey.currentState.toggle();
|
||||
}
|
||||
|
||||
double endx;
|
||||
double endX;
|
||||
|
||||
void _onPanEnd(details) {
|
||||
endx = offset.dx;
|
||||
endX = offset.dx;
|
||||
_ctrl.reset();
|
||||
_ctrl.forward();
|
||||
|
||||
// offset = Offset(x, y);
|
||||
// entry.markNeedsBuild();
|
||||
}
|
||||
|
||||
void _listenAnimate() {
|
||||
@@ -197,7 +195,7 @@ class OverlayToolWrapperState extends State<OverlayToolWrapper>
|
||||
// print(offset.dx);
|
||||
if (offset.dx > MediaQuery.of(context).size.width / 2 - circleRadius) {
|
||||
|
||||
double begin = endx;
|
||||
double begin = endX;
|
||||
double end = MediaQuery.of(context).size.width -
|
||||
menuSize / 2 -
|
||||
circleRadius;
|
||||
@@ -205,7 +203,7 @@ class OverlayToolWrapperState extends State<OverlayToolWrapper>
|
||||
px = begin + (end - begin) * t; // x = menuSize / 2 - circleRadius;
|
||||
|
||||
} else {
|
||||
double begin = endx;
|
||||
double begin = endX;
|
||||
double end = menuSize / 2 - circleRadius;
|
||||
double t = _ctrl.value;
|
||||
px = begin + (end - begin) * t; // x = menuSize / 2 - circleRadius;
|
||||
@@ -237,15 +235,14 @@ class OverlayToolWrapperState extends State<OverlayToolWrapper>
|
||||
entry.markNeedsBuild();
|
||||
}
|
||||
|
||||
showFloating() {
|
||||
void showFloating() {
|
||||
if (!show) {
|
||||
Overlay.of(context).insert(entry);
|
||||
show = true;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
hideFloating() {
|
||||
void hideFloating() {
|
||||
if (show) {
|
||||
entry.remove();
|
||||
show = false;
|
||||
@@ -256,6 +253,4 @@ class OverlayToolWrapperState extends State<OverlayToolWrapper>
|
||||
Widget build(BuildContext context) {
|
||||
return widget.child;
|
||||
}
|
||||
|
||||
void _onPanDown(DragDownDetails details) {}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_unit/app/router/unit_router.dart';
|
||||
import 'package:flutter_unit/app/utils/convert.dart';
|
||||
import 'package:flutter_unit/blocs/bloc_exp.dart';
|
||||
import 'package:flutter_unit/model/enums.dart';
|
||||
import 'package:flutter_unit/model/widget_model.dart';
|
||||
import 'package:flutter_unit/views/components/permanent/feedback_widget.dart';
|
||||
import 'package:flutter_unit/views/components/project/default/empty_shower.dart';
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
name: flutter_unit
|
||||
description: A new Flutter application.
|
||||
|
||||
version: 1.5.1
|
||||
version: 1.5.2
|
||||
author: 张风捷特烈 <1981462002@qq.com>
|
||||
homepage: https://juejin.cn/user/149189281194766/posts
|
||||
|
||||
|
||||
Reference in New Issue
Block a user