mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2025-04-24 22:57:12 -04:00
fix: hover color highlight with custom widget
This commit is contained in:
parent
5d520d7217
commit
56ced4a76f
8 changed files with 150 additions and 90 deletions
|
@ -1,7 +1,6 @@
|
||||||
import 'package:app_flowy/workspace/presentation/view/view_widget.dart';
|
import 'package:app_flowy/workspace/presentation/view/view_widget.dart';
|
||||||
import 'package:flowy_infra/flowy_logger.dart';
|
import 'package:flowy_infra/flowy_logger.dart';
|
||||||
import 'package:flowy_sdk/protobuf/flowy-workspace/view_create.pb.dart';
|
import 'package:flowy_sdk/protobuf/flowy-workspace/view_create.pb.dart';
|
||||||
import 'package:flowy_infra_ui/style_widget/styled_hover.dart';
|
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:dartz/dartz.dart';
|
import 'package:dartz/dartz.dart';
|
||||||
|
@ -17,22 +16,18 @@ class ViewList extends StatelessWidget {
|
||||||
() => const SizedBox(),
|
() => const SizedBox(),
|
||||||
(views) {
|
(views) {
|
||||||
return Column(
|
return Column(
|
||||||
children: _renderViewWidgets(views),
|
children: _renderViews(views),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Widget> _renderViewWidgets(List<View> views) {
|
List<Widget> _renderViews(List<View> views) {
|
||||||
var targetViews = views.map((view) {
|
var targetViews = views.map((view) {
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.symmetric(vertical: 6),
|
padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 4),
|
||||||
child: StyledHover(
|
child: ViewWidget(
|
||||||
color: Colors.red,
|
view: view,
|
||||||
borderRadius: BorderRadius.circular(8),
|
|
||||||
child: ViewWidget(
|
|
||||||
view: view,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}).toList(growable: false);
|
}).toList(growable: false);
|
||||||
|
|
|
@ -5,6 +5,8 @@ import 'package:app_flowy/workspace/presentation/app/app_widget.dart';
|
||||||
import 'package:flowy_infra_ui/widget/spacing.dart';
|
import 'package:flowy_infra_ui/widget/spacing.dart';
|
||||||
import 'package:flowy_sdk/protobuf/flowy-workspace/view_create.pb.dart';
|
import 'package:flowy_sdk/protobuf/flowy-workspace/view_create.pb.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flowy_infra_ui/style_widget/styled_more.dart';
|
||||||
|
import 'package:flowy_infra_ui/style_widget/styled_hover.dart';
|
||||||
|
|
||||||
class ViewWidget extends StatelessWidget {
|
class ViewWidget extends StatelessWidget {
|
||||||
final View view;
|
final View view;
|
||||||
|
@ -12,32 +14,56 @@ class ViewWidget extends StatelessWidget {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final contentPadding = EdgeInsets.only(
|
|
||||||
left: AppWidgetSize.expandedPadding, top: 5, bottom: 5, right: 5);
|
|
||||||
return InkWell(
|
return InkWell(
|
||||||
onTap: _openView(context),
|
onTap: _openView(context),
|
||||||
child: Padding(
|
child: StyledHover(
|
||||||
padding: contentPadding,
|
color: Colors.grey.shade300,
|
||||||
child: buildContent(),
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
builder: (context, onHover) => _render(context, onHover),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Row buildContent() {
|
Widget _render(BuildContext context, bool onHover) {
|
||||||
return Row(
|
const double width = 20;
|
||||||
children: [
|
List<Widget> children = [
|
||||||
Image(
|
Image(
|
||||||
fit: BoxFit.cover,
|
fit: BoxFit.cover,
|
||||||
width: 20,
|
width: width,
|
||||||
height: 20,
|
height: width,
|
||||||
image: assetImageForViewType(view.viewType)),
|
image: assetImageForViewType(view.viewType)),
|
||||||
const HSpace(6),
|
const HSpace(6),
|
||||||
Text(
|
Text(
|
||||||
view.name,
|
view.name,
|
||||||
textAlign: TextAlign.start,
|
textAlign: TextAlign.start,
|
||||||
style: const TextStyle(fontSize: 15),
|
style: const TextStyle(fontSize: 15),
|
||||||
)
|
),
|
||||||
],
|
];
|
||||||
|
|
||||||
|
if (onHover) {
|
||||||
|
children.add(const Spacer());
|
||||||
|
|
||||||
|
children.add(Align(
|
||||||
|
alignment: Alignment.center,
|
||||||
|
child: StyledMore(
|
||||||
|
width: width,
|
||||||
|
onPressed: () {},
|
||||||
|
),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
final padding = EdgeInsets.only(
|
||||||
|
left: AppWidgetSize.expandedPadding,
|
||||||
|
top: 5,
|
||||||
|
bottom: 5,
|
||||||
|
right: 5,
|
||||||
|
);
|
||||||
|
|
||||||
|
return Padding(
|
||||||
|
padding: padding,
|
||||||
|
child: Flexible(
|
||||||
|
child: Row(children: children),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,8 @@ import 'package:flowy_infra_ui/widget/rounded_button.dart';
|
||||||
import 'package:flowy_infra_ui/widget/spacing.dart';
|
import 'package:flowy_infra_ui/widget/spacing.dart';
|
||||||
import 'package:flowy_sdk/protobuf/flowy-workspace/view_create.pbenum.dart';
|
import 'package:flowy_sdk/protobuf/flowy-workspace/view_create.pbenum.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flowy_infra_ui/style_widget/styled_more.dart';
|
||||||
|
import 'package:flowy_infra_ui/style_widget/styled_text.dart';
|
||||||
|
|
||||||
class HomeTopBar extends StatelessWidget {
|
class HomeTopBar extends StatelessWidget {
|
||||||
final HomeStackView view;
|
final HomeStackView view;
|
||||||
|
@ -50,14 +52,9 @@ class HomeTopBar extends StatelessWidget {
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _renderMoreButton() {
|
Widget _renderMoreButton() {
|
||||||
return SizedBox(
|
return StyledMore(
|
||||||
width: 24,
|
width: 24,
|
||||||
child: IconButton(
|
onPressed: () {},
|
||||||
icon: const Icon(Icons.more_vert),
|
|
||||||
iconSize: 12,
|
|
||||||
alignment: Alignment.center,
|
|
||||||
onPressed: () {},
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -83,12 +80,7 @@ class HomeTitle extends StatelessWidget {
|
||||||
height: 15,
|
height: 15,
|
||||||
image: assetImageForViewType(type)),
|
image: assetImageForViewType(type)),
|
||||||
const HSpace(6),
|
const HSpace(6),
|
||||||
Text(
|
StyledText(title, fontSize: 16),
|
||||||
title,
|
|
||||||
overflow: TextOverflow.fade,
|
|
||||||
softWrap: false,
|
|
||||||
style: const TextStyle(fontSize: 16),
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
|
@ -5,6 +5,7 @@ import 'package:flowy_infra_ui/widget/spacing.dart';
|
||||||
import 'package:flowy_sdk/protobuf/flowy-user/user_detail.pb.dart';
|
import 'package:flowy_sdk/protobuf/flowy-user/user_detail.pb.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
import 'package:flowy_infra_ui/style_widget/styled_text.dart';
|
||||||
|
|
||||||
class MenuUser extends MenuItem {
|
class MenuUser extends MenuItem {
|
||||||
final UserDetail user;
|
final UserDetail user;
|
||||||
|
@ -44,12 +45,7 @@ class MenuUser extends MenuItem {
|
||||||
name = context.read<MenuUserBloc>().state.user.email;
|
name = context.read<MenuUserBloc>().state.user.email;
|
||||||
}
|
}
|
||||||
return Flexible(
|
return Flexible(
|
||||||
child: Text(
|
child: StyledText(name, fontSize: 18),
|
||||||
name,
|
|
||||||
overflow: TextOverflow.fade,
|
|
||||||
softWrap: false,
|
|
||||||
style: const TextStyle(fontSize: 18),
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,59 +1,58 @@
|
||||||
import 'package:flowy_infra_ui/widget/mouse_hover_builder.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flowy_infra/time/duration.dart';
|
import 'package:flowy_infra/time/duration.dart';
|
||||||
|
|
||||||
class StyledHover extends StatelessWidget {
|
typedef HoverBuilder = Widget Function(BuildContext context, bool onHover);
|
||||||
|
|
||||||
|
class StyledHover extends StatefulWidget {
|
||||||
final Color color;
|
final Color color;
|
||||||
final Color borderColor;
|
final Color borderColor;
|
||||||
final double borderWidth;
|
final double borderWidth;
|
||||||
final Widget child;
|
|
||||||
final BorderRadius borderRadius;
|
final BorderRadius borderRadius;
|
||||||
|
final HoverBuilder builder;
|
||||||
|
|
||||||
const StyledHover({
|
const StyledHover({
|
||||||
Key? key,
|
Key? key,
|
||||||
required this.color,
|
required this.color,
|
||||||
required this.child,
|
|
||||||
this.borderColor = Colors.transparent,
|
this.borderColor = Colors.transparent,
|
||||||
this.borderWidth = 0,
|
this.borderWidth = 0,
|
||||||
this.borderRadius = BorderRadius.zero,
|
this.borderRadius = BorderRadius.zero,
|
||||||
|
required this.builder,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<StyledHover> createState() => _StyledHoverState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _StyledHoverState extends State<StyledHover> {
|
||||||
|
bool _onHover = false;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return MouseHoverBuilder(
|
final hoverColor =
|
||||||
builder: (_, isHovered) => AnimatedContainer(
|
_onHover ? widget.color : Theme.of(context).colorScheme.background;
|
||||||
|
|
||||||
|
final hoverBorder = Border.all(
|
||||||
|
color: widget.borderColor,
|
||||||
|
width: widget.borderWidth,
|
||||||
|
);
|
||||||
|
|
||||||
|
final animatedDuration = .1.seconds;
|
||||||
|
|
||||||
|
return MouseRegion(
|
||||||
|
cursor: SystemMouseCursors.click,
|
||||||
|
onEnter: (p) => setOnHover(true),
|
||||||
|
onExit: (p) => setOnHover(false),
|
||||||
|
child: AnimatedContainer(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
border: Border.all(color: borderColor, width: borderWidth),
|
border: hoverBorder,
|
||||||
color: isHovered ? color : Colors.transparent,
|
color: hoverColor,
|
||||||
borderRadius: borderRadius,
|
borderRadius: widget.borderRadius,
|
||||||
),
|
),
|
||||||
duration: .1.seconds,
|
duration: animatedDuration,
|
||||||
child: child,
|
child: widget.builder(context, _onHover),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setOnHover(bool value) => setState(() => _onHover = value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// @override
|
|
||||||
// Widget build(BuildContext context) {
|
|
||||||
// return GestureDetector(
|
|
||||||
// behavior: HitTestBehavior.translucent,
|
|
||||||
// onTap: () {
|
|
||||||
// context
|
|
||||||
// .read<HomeBloc>()
|
|
||||||
// .add(HomeEvent.setEditPannel(CellEditPannelContext()));
|
|
||||||
// },
|
|
||||||
// child: MouseHoverBuilder(
|
|
||||||
// builder: (_, isHovered) => Container(
|
|
||||||
// width: width,
|
|
||||||
// decoration: CellDecoration.box(
|
|
||||||
// color: isHovered ? Colors.red.withOpacity(.1) : Colors.transparent,
|
|
||||||
// ),
|
|
||||||
// padding: EdgeInsets.symmetric(
|
|
||||||
// vertical: GridInsets.vertical, horizontal: GridInsets.horizontal),
|
|
||||||
// child: child,
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// );
|
|
||||||
// }
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class StyledMore extends StatelessWidget {
|
||||||
|
final double width;
|
||||||
|
final double? height;
|
||||||
|
final VoidCallback? onPressed;
|
||||||
|
|
||||||
|
const StyledMore({
|
||||||
|
Key? key,
|
||||||
|
required this.width,
|
||||||
|
this.height,
|
||||||
|
this.onPressed,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return SizedBox(
|
||||||
|
width: width,
|
||||||
|
height: height ?? width,
|
||||||
|
child: IconButton(
|
||||||
|
icon: const Icon(Icons.more_vert),
|
||||||
|
padding: EdgeInsets.zero,
|
||||||
|
iconSize: width / 2,
|
||||||
|
alignment: Alignment.center,
|
||||||
|
onPressed: onPressed,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
import 'package:flutter/widgets.dart';
|
||||||
|
|
||||||
|
class StyledText extends StatelessWidget {
|
||||||
|
final String title;
|
||||||
|
final TextOverflow overflow;
|
||||||
|
final double fontSize;
|
||||||
|
const StyledText(
|
||||||
|
this.title, {
|
||||||
|
Key? key,
|
||||||
|
this.overflow = TextOverflow.fade,
|
||||||
|
this.fontSize = 16,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Text(
|
||||||
|
title,
|
||||||
|
overflow: overflow,
|
||||||
|
softWrap: false,
|
||||||
|
style: TextStyle(fontSize: fontSize),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/rendering.dart';
|
import 'package:flutter/rendering.dart';
|
||||||
|
|
||||||
typedef HoverBuilder = Widget Function(BuildContext context, bool isHovering);
|
typedef HoverBuilder = Widget Function(BuildContext context, bool onHover);
|
||||||
|
|
||||||
class MouseHoverBuilder extends StatefulWidget {
|
class MouseHoverBuilder extends StatefulWidget {
|
||||||
final bool isClickable;
|
final bool isClickable;
|
||||||
|
@ -17,7 +17,7 @@ class MouseHoverBuilder extends StatefulWidget {
|
||||||
}
|
}
|
||||||
|
|
||||||
class _MouseHoverBuilderState extends State<MouseHoverBuilder> {
|
class _MouseHoverBuilderState extends State<MouseHoverBuilder> {
|
||||||
bool isOver = false;
|
bool _onHover = false;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
@ -25,11 +25,11 @@ class _MouseHoverBuilderState extends State<MouseHoverBuilder> {
|
||||||
cursor: widget.isClickable
|
cursor: widget.isClickable
|
||||||
? SystemMouseCursors.click
|
? SystemMouseCursors.click
|
||||||
: SystemMouseCursors.basic,
|
: SystemMouseCursors.basic,
|
||||||
onEnter: (p) => setOver(true),
|
onEnter: (p) => setOnHover(true),
|
||||||
onExit: (p) => setOver(false),
|
onExit: (p) => setOnHover(false),
|
||||||
child: widget.builder(context, isOver),
|
child: widget.builder(context, _onHover),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setOver(bool value) => setState(() => isOver = value);
|
void setOnHover(bool value) => setState(() => _onHover = value);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue