From 56ced4a76f16ee3269cd3cf34bebffb47527556d Mon Sep 17 00:00:00 2001 From: appflowy Date: Tue, 27 Jul 2021 11:54:59 +0800 Subject: [PATCH] fix: hover color highlight with custom widget --- .../workspace/presentation/app/view_list.dart | 15 ++-- .../presentation/view/view_widget.dart | 66 ++++++++++++------ .../presentation/widgets/home_top_bar.dart | 18 ++--- .../presentation/widgets/menu/menu_user.dart | 8 +-- .../lib/style_widget/styled_hover.dart | 69 +++++++++---------- .../lib/style_widget/styled_more.dart | 29 ++++++++ .../lib/style_widget/styled_text.dart | 23 +++++++ .../lib/widget/mouse_hover_builder.dart | 12 ++-- 8 files changed, 150 insertions(+), 90 deletions(-) create mode 100644 app_flowy/packages/flowy_infra_ui/lib/style_widget/styled_more.dart create mode 100644 app_flowy/packages/flowy_infra_ui/lib/style_widget/styled_text.dart diff --git a/app_flowy/lib/workspace/presentation/app/view_list.dart b/app_flowy/lib/workspace/presentation/app/view_list.dart index 030a4bb22e..c1f104db20 100644 --- a/app_flowy/lib/workspace/presentation/app/view_list.dart +++ b/app_flowy/lib/workspace/presentation/app/view_list.dart @@ -1,7 +1,6 @@ import 'package:app_flowy/workspace/presentation/view/view_widget.dart'; import 'package:flowy_infra/flowy_logger.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/material.dart'; import 'package:dartz/dartz.dart'; @@ -17,22 +16,18 @@ class ViewList extends StatelessWidget { () => const SizedBox(), (views) { return Column( - children: _renderViewWidgets(views), + children: _renderViews(views), ); }, ); } - List _renderViewWidgets(List views) { + List _renderViews(List views) { var targetViews = views.map((view) { return Padding( - padding: const EdgeInsets.symmetric(vertical: 6), - child: StyledHover( - color: Colors.red, - borderRadius: BorderRadius.circular(8), - child: ViewWidget( - view: view, - ), + padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 4), + child: ViewWidget( + view: view, ), ); }).toList(growable: false); diff --git a/app_flowy/lib/workspace/presentation/view/view_widget.dart b/app_flowy/lib/workspace/presentation/view/view_widget.dart index 0b75e406f9..227923fc2c 100644 --- a/app_flowy/lib/workspace/presentation/view/view_widget.dart +++ b/app_flowy/lib/workspace/presentation/view/view_widget.dart @@ -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_sdk/protobuf/flowy-workspace/view_create.pb.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 { final View view; @@ -12,32 +14,56 @@ class ViewWidget extends StatelessWidget { @override Widget build(BuildContext context) { - final contentPadding = EdgeInsets.only( - left: AppWidgetSize.expandedPadding, top: 5, bottom: 5, right: 5); return InkWell( onTap: _openView(context), - child: Padding( - padding: contentPadding, - child: buildContent(), + child: StyledHover( + color: Colors.grey.shade300, + borderRadius: BorderRadius.circular(8), + builder: (context, onHover) => _render(context, onHover), ), ); } - Row buildContent() { - return Row( - children: [ - Image( - fit: BoxFit.cover, - width: 20, - height: 20, - image: assetImageForViewType(view.viewType)), - const HSpace(6), - Text( - view.name, - textAlign: TextAlign.start, - style: const TextStyle(fontSize: 15), - ) - ], + Widget _render(BuildContext context, bool onHover) { + const double width = 20; + List children = [ + Image( + fit: BoxFit.cover, + width: width, + height: width, + image: assetImageForViewType(view.viewType)), + const HSpace(6), + Text( + view.name, + textAlign: TextAlign.start, + 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), + ), ); } diff --git a/app_flowy/lib/workspace/presentation/widgets/home_top_bar.dart b/app_flowy/lib/workspace/presentation/widgets/home_top_bar.dart index 1b43b14a5a..9a51434d4f 100644 --- a/app_flowy/lib/workspace/presentation/widgets/home_top_bar.dart +++ b/app_flowy/lib/workspace/presentation/widgets/home_top_bar.dart @@ -5,6 +5,8 @@ import 'package:flowy_infra_ui/widget/rounded_button.dart'; import 'package:flowy_infra_ui/widget/spacing.dart'; import 'package:flowy_sdk/protobuf/flowy-workspace/view_create.pbenum.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 { final HomeStackView view; @@ -50,14 +52,9 @@ class HomeTopBar extends StatelessWidget { } Widget _renderMoreButton() { - return SizedBox( + return StyledMore( 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, image: assetImageForViewType(type)), const HSpace(6), - Text( - title, - overflow: TextOverflow.fade, - softWrap: false, - style: const TextStyle(fontSize: 16), - ), + StyledText(title, fontSize: 16), ], ), ); diff --git a/app_flowy/lib/workspace/presentation/widgets/menu/menu_user.dart b/app_flowy/lib/workspace/presentation/widgets/menu/menu_user.dart index 31fabb8bf5..83ad37c5fd 100644 --- a/app_flowy/lib/workspace/presentation/widgets/menu/menu_user.dart +++ b/app_flowy/lib/workspace/presentation/widgets/menu/menu_user.dart @@ -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:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flowy_infra_ui/style_widget/styled_text.dart'; class MenuUser extends MenuItem { final UserDetail user; @@ -44,12 +45,7 @@ class MenuUser extends MenuItem { name = context.read().state.user.email; } return Flexible( - child: Text( - name, - overflow: TextOverflow.fade, - softWrap: false, - style: const TextStyle(fontSize: 18), - ), + child: StyledText(name, fontSize: 18), ); } diff --git a/app_flowy/packages/flowy_infra_ui/lib/style_widget/styled_hover.dart b/app_flowy/packages/flowy_infra_ui/lib/style_widget/styled_hover.dart index 64001583af..ff33ac7cae 100644 --- a/app_flowy/packages/flowy_infra_ui/lib/style_widget/styled_hover.dart +++ b/app_flowy/packages/flowy_infra_ui/lib/style_widget/styled_hover.dart @@ -1,59 +1,58 @@ -import 'package:flowy_infra_ui/widget/mouse_hover_builder.dart'; import 'package:flutter/material.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 borderColor; final double borderWidth; - final Widget child; final BorderRadius borderRadius; + final HoverBuilder builder; const StyledHover({ Key? key, required this.color, - required this.child, this.borderColor = Colors.transparent, this.borderWidth = 0, this.borderRadius = BorderRadius.zero, + required this.builder, }) : super(key: key); + @override + State createState() => _StyledHoverState(); +} + +class _StyledHoverState extends State { + bool _onHover = false; + @override Widget build(BuildContext context) { - return MouseHoverBuilder( - builder: (_, isHovered) => AnimatedContainer( + final hoverColor = + _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( - border: Border.all(color: borderColor, width: borderWidth), - color: isHovered ? color : Colors.transparent, - borderRadius: borderRadius, + border: hoverBorder, + color: hoverColor, + borderRadius: widget.borderRadius, ), - duration: .1.seconds, - child: child, + duration: animatedDuration, + 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() -// .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, -// ), -// ), -// ); -// } \ No newline at end of file diff --git a/app_flowy/packages/flowy_infra_ui/lib/style_widget/styled_more.dart b/app_flowy/packages/flowy_infra_ui/lib/style_widget/styled_more.dart new file mode 100644 index 0000000000..a101a439ef --- /dev/null +++ b/app_flowy/packages/flowy_infra_ui/lib/style_widget/styled_more.dart @@ -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, + ), + ); + } +} diff --git a/app_flowy/packages/flowy_infra_ui/lib/style_widget/styled_text.dart b/app_flowy/packages/flowy_infra_ui/lib/style_widget/styled_text.dart new file mode 100644 index 0000000000..1fe439ca4a --- /dev/null +++ b/app_flowy/packages/flowy_infra_ui/lib/style_widget/styled_text.dart @@ -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), + ); + } +} diff --git a/app_flowy/packages/flowy_infra_ui/lib/widget/mouse_hover_builder.dart b/app_flowy/packages/flowy_infra_ui/lib/widget/mouse_hover_builder.dart index f04df5a689..317545635b 100644 --- a/app_flowy/packages/flowy_infra_ui/lib/widget/mouse_hover_builder.dart +++ b/app_flowy/packages/flowy_infra_ui/lib/widget/mouse_hover_builder.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.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 { final bool isClickable; @@ -17,7 +17,7 @@ class MouseHoverBuilder extends StatefulWidget { } class _MouseHoverBuilderState extends State { - bool isOver = false; + bool _onHover = false; @override Widget build(BuildContext context) { @@ -25,11 +25,11 @@ class _MouseHoverBuilderState extends State { cursor: widget.isClickable ? SystemMouseCursors.click : SystemMouseCursors.basic, - onEnter: (p) => setOver(true), - onExit: (p) => setOver(false), - child: widget.builder(context, isOver), + onEnter: (p) => setOnHover(true), + onExit: (p) => setOnHover(false), + child: widget.builder(context, _onHover), ); } - void setOver(bool value) => setState(() => isOver = value); + void setOnHover(bool value) => setState(() => _onHover = value); }