fix: hover color highlight with custom widget

This commit is contained in:
appflowy 2021-07-27 11:54:59 +08:00
parent 5d520d7217
commit 56ced4a76f
8 changed files with 150 additions and 90 deletions

View file

@ -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,23 +16,19 @@ 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(
color: Colors.red,
borderRadius: BorderRadius.circular(8),
child: ViewWidget( child: ViewWidget(
view: view, view: view,
), ),
),
); );
}).toList(growable: false); }).toList(growable: false);
return targetViews; return targetViews;

View file

@ -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),
),
); );
} }

View file

@ -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(
icon: const Icon(Icons.more_vert),
iconSize: 12,
alignment: Alignment.center,
onPressed: () {}, 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),
),
], ],
), ),
); );

View file

@ -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),
),
); );
} }

View file

@ -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,
// ),
// ),
// );
// }

View file

@ -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,
),
);
}
}

View file

@ -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),
);
}
}

View file

@ -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);
} }