This commit is contained in:
jyuesong
2022-01-14 11:07:22 +08:00
parent 84da8495a2
commit 363d89dab2
2 changed files with 229 additions and 56 deletions

148
lib/base/ui/menu.dart Normal file
View File

@@ -0,0 +1,148 @@
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter/cupertino.dart';
import 'package:flutter/widgets.dart';
/// A button in a _ContextMenuSheet.
///
/// A typical use case is to pass a [Text] as the [child] here, but be sure to
/// use [TextOverflow.ellipsis] for the [Text.overflow] field if the text may be
/// long, as without it the text will wrap to the next line.
class QLCupertinoContextMenuAction extends StatefulWidget {
/// Construct a CupertinoContextMenuAction.
const QLCupertinoContextMenuAction({
Key? key,
required this.child,
this.isDefaultAction = false,
this.isDestructiveAction = false,
this.onPressed,
this.trailingIcon,
}) : assert(child != null),
assert(isDefaultAction != null),
assert(isDestructiveAction != null),
super(key: key);
/// The widget that will be placed inside the action.
final Widget child;
/// Indicates whether this action should receive the style of an emphasized,
/// default action.
final bool isDefaultAction;
/// Indicates whether this action should receive the style of a destructive
/// action.
final bool isDestructiveAction;
/// Called when the action is pressed.
final VoidCallback? onPressed;
/// An optional icon to display to the right of the child.
///
/// Will be colored in the same way as the [TextStyle] used for [child] (for
/// example, if using [isDestructiveAction]).
final IconData? trailingIcon;
@override
State<QLCupertinoContextMenuAction> createState() => _QLCupertinoContextMenuActionState();
}
class _QLCupertinoContextMenuActionState extends State<QLCupertinoContextMenuAction> {
static const Color _kBackgroundColor = Color(0xFFEEEEEE);
static const Color _kBackgroundColorPressed = Color(0xFFDDDDDD);
static const double _kButtonHeight = 30.0;
static const TextStyle _kActionSheetActionStyle = TextStyle(
fontFamily: '.SF UI Text',
inherit: false,
fontSize: 14.0,
fontWeight: FontWeight.w400,
color: CupertinoColors.black,
textBaseline: TextBaseline.alphabetic,
);
final GlobalKey _globalKey = GlobalKey();
bool _isPressed = false;
void onTapDown(TapDownDetails details) {
setState(() {
_isPressed = true;
});
}
void onTapUp(TapUpDetails details) {
setState(() {
_isPressed = false;
});
}
void onTapCancel() {
setState(() {
_isPressed = false;
});
}
TextStyle get _textStyle {
if (widget.isDefaultAction) {
return _kActionSheetActionStyle.copyWith(
fontWeight: FontWeight.w600,
);
}
if (widget.isDestructiveAction) {
return _kActionSheetActionStyle.copyWith(
color: CupertinoColors.destructiveRed,
);
}
return _kActionSheetActionStyle;
}
@override
Widget build(BuildContext context) {
return GestureDetector(
key: _globalKey,
onTapDown: onTapDown,
onTapUp: onTapUp,
onTapCancel: onTapCancel,
onTap: widget.onPressed,
behavior: HitTestBehavior.opaque,
child: ConstrainedBox(
constraints: const BoxConstraints(
minHeight: _kButtonHeight,
),
child: Semantics(
button: true,
child: Container(
decoration: BoxDecoration(
color: _isPressed ? _kBackgroundColorPressed : _kBackgroundColor,
border: const Border(
bottom: BorderSide(color: _kBackgroundColorPressed),
),
),
padding: const EdgeInsets.symmetric(
vertical: 10.0,
horizontal: 10.0,
),
child: DefaultTextStyle(
style: _textStyle,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Flexible(
child: widget.child,
),
if (widget.trailingIcon != null)
Icon(
widget.trailingIcon,
color: _textStyle.color,
size: 14,
),
],
),
),
),
),
),
);
}
}

View File

@@ -6,6 +6,7 @@ import 'package:qinglong_app/base/base_state_widget.dart';
import 'package:qinglong_app/base/routes.dart'; import 'package:qinglong_app/base/routes.dart';
import 'package:qinglong_app/base/theme.dart'; import 'package:qinglong_app/base/theme.dart';
import 'package:qinglong_app/base/ui/abs_underline_tabindicator.dart'; import 'package:qinglong_app/base/ui/abs_underline_tabindicator.dart';
import 'package:qinglong_app/base/ui/menu.dart';
import 'package:qinglong_app/module/task/intime_log/intime_log_page.dart'; import 'package:qinglong_app/module/task/intime_log/intime_log_page.dart';
import 'package:qinglong_app/module/task/task_bean.dart'; import 'package:qinglong_app/module/task/task_bean.dart';
import 'package:qinglong_app/module/task/task_viewmodel.dart'; import 'package:qinglong_app/module/task/task_viewmodel.dart';
@@ -89,7 +90,7 @@ class _TaskPageState extends State<TaskPage> {
// return searchCell(ref); // return searchCell(ref);
// } // }
TaskBean item = list[index ]; TaskBean item = list[index];
if ((item.name == null || item.name!.contains(_searchKey ?? "")) || (item.command == null || item.command!.contains(_searchKey ?? ""))) { if ((item.name == null || item.name!.contains(_searchKey ?? "")) || (item.command == null || item.command!.contains(_searchKey ?? ""))) {
return TaskItemCell(item, ref); return TaskItemCell(item, ref);
@@ -148,58 +149,82 @@ class TaskItemCell extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Column( return CupertinoContextMenu(
mainAxisSize: MainAxisSize.min, actions: [
crossAxisAlignment: CrossAxisAlignment.start, QLCupertinoContextMenuAction(
children: [ child: Text(
Slidable( bean.status! == 1 ? "运行" : "停止运行",
enabled: false,
key: const ValueKey(0),
startActionPane: ActionPane(
motion: const ScrollMotion(),
extentRatio: 0.3,
dragDismissible: false,
children: [
SlidableAction(
flex: 1,
icon: bean.status == 0 ? CupertinoIcons.stop_circle : CupertinoIcons.memories,
foregroundColor: Colors.white,
backgroundColor: const Color(0xFF0F77FE),
onPressed: (BuildContext context) {
if (bean.status == 0) {
stopCron(context, ref);
} else {
startCron(context, ref);
}
},
),
SlidableAction(
flex: 1,
backgroundColor: Colors.green,
foregroundColor: Colors.white,
icon: CupertinoIcons.clock_fill,
onPressed: (BuildContext context) {
logCron(context, ref);
},
),
],
), ),
endActionPane: ActionPane( trailingIcon: bean.status! == 1 ? CupertinoIcons.memories : CupertinoIcons.stop_circle,
motion: const ScrollMotion(), onPressed: () {
extentRatio: 0.15, Navigator.of(context).pop();
children: [ startCron(context, ref);
SlidableAction( },
backgroundColor: Colors.cyan, ),
flex: 1, QLCupertinoContextMenuAction(
onPressed: (_) { child: Text("查看日志"),
more(context, ref); onPressed: () {
}, Navigator.of(context).pop();
foregroundColor: Colors.white, logCron(context, ref);
icon: CupertinoIcons.ellipsis, },
trailingIcon: CupertinoIcons.clock,
),
QLCupertinoContextMenuAction(
child: const Text("编辑"),
onPressed: () {
Navigator.of(context).pop();
Navigator.of(context).pushNamed(Routes.route_AddTask, arguments: bean);
},
trailingIcon: CupertinoIcons.pencil_outline,
),
QLCupertinoContextMenuAction(
child: Text(bean.isPinned! == 0 ? "置顶" : "取消置顶"),
onPressed: () {
Navigator.of(context).pop();
pinTask();
},
trailingIcon: bean.isPinned! == 0 ? CupertinoIcons.pin : CupertinoIcons.pin_slash,
),
QLCupertinoContextMenuAction(
child: Text(bean.isDisabled! == 0 ? "禁用" : "启用"),
onPressed: () {
Navigator.of(context).pop();
enableTask();
},
isDestructiveAction: true,
trailingIcon: bean.isDisabled! == 0 ? Icons.dnd_forwardslash : Icons.check_circle_outline_sharp,
),
QLCupertinoContextMenuAction(
child: const Text("删除"),
onPressed: () {
Navigator.of(context).pop();
delTask(context, ref);
},
isDestructiveAction: true,
trailingIcon: CupertinoIcons.delete,
),
],
previewBuilder: (context, anima, child) {
return IntrinsicWidth(
child: Material(
color: Colors.transparent,
child: Text(
bean.name ?? "",
maxLines: 1,
style: TextStyle(
overflow: TextOverflow.ellipsis,
color: bean.isDisabled == 1 ? const Color(0xffF85152) : ref.watch(themeProvider).themeColor.taskTitleColor(),
fontSize: 18,
), ),
], ),
), ),
child: Container( );
},
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
color: bean.isPinned == 1 ? ref.watch(themeProvider).themeColor.pinColor() : Colors.transparent, color: bean.isPinned == 1 ? ref.watch(themeProvider).themeColor.pinColor() : Colors.transparent,
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(
horizontal: 15, horizontal: 15,
@@ -261,12 +286,12 @@ class TaskItemCell extends StatelessWidget {
], ],
), ),
), ),
), const Divider(
const Divider( height: 1,
height: 1, indent: 15,
indent: 15, ),
), ],
], ),
); );
} }