[flutter]: config ui of menu view

This commit is contained in:
appflowy 2021-10-10 11:16:27 +08:00
parent ece353b6b1
commit 03182a51b0
28 changed files with 132 additions and 145 deletions

View file

@ -17,5 +17,6 @@
"editor.wordWrapColumn": 120, "editor.wordWrapColumn": 120,
"editor.minimap.maxColumn": 140, "editor.minimap.maxColumn": 140,
"prettier.printWidth": 140, "prettier.printWidth": 140,
"editor.wordWrap": "wordWrapColumn" "editor.wordWrap": "wordWrapColumn",
"dart.lineLength": 120
} }

View file

@ -1,6 +0,0 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M6 5L3 8L6 11" stroke="#333333" stroke-linecap="round" stroke-linejoin="round"/>
<rect width="4" height="1" rx="0.5" transform="matrix(-1 0 0 1 13 5)" fill="#333333"/>
<rect width="6" height="1" rx="0.5" transform="matrix(-1 0 0 1 13 7.5)" fill="#333333"/>
<rect width="4" height="1" rx="0.5" transform="matrix(-1 0 0 1 13 10)" fill="#333333"/>
</svg>

Before

Width:  |  Height:  |  Size: 457 B

View file

Before

Width:  |  Height:  |  Size: 516 B

After

Width:  |  Height:  |  Size: 516 B

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 495 B

After

Width:  |  Height:  |  Size: 495 B

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 286 B

After

Width:  |  Height:  |  Size: 286 B

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 449 B

After

Width:  |  Height:  |  Size: 449 B

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 525 B

After

Width:  |  Height:  |  Size: 525 B

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 512 B

After

Width:  |  Height:  |  Size: 512 B

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 394 B

After

Width:  |  Height:  |  Size: 394 B

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 579 B

After

Width:  |  Height:  |  Size: 579 B

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 905 B

After

Width:  |  Height:  |  Size: 905 B

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 433 B

After

Width:  |  Height:  |  Size: 433 B

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 387 B

After

Width:  |  Height:  |  Size: 387 B

Before After
Before After

View file

@ -4,7 +4,6 @@ import 'package:flowy_infra/image.dart';
import 'package:flowy_infra/theme.dart'; import 'package:flowy_infra/theme.dart';
import 'package:flowy_infra_ui/style_widget/text.dart'; import 'package:flowy_infra_ui/style_widget/text.dart';
import 'package:flowy_infra_ui/widget/spacing.dart'; import 'package:flowy_infra_ui/widget/spacing.dart';
import 'package:flowy_infra_ui/style_widget/text_button.dart';
import 'package:flowy_infra/flowy_icon_data_icons.dart'; import 'package:flowy_infra/flowy_icon_data_icons.dart';
import 'package:flowy_sdk/protobuf/flowy-workspace/app_create.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-workspace/app_create.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-workspace/view_create.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-workspace/view_create.pb.dart';
@ -23,65 +22,61 @@ class AppHeader extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final theme = context.watch<AppTheme>(); final theme = context.watch<AppTheme>();
return Row( return SizedBox(
mainAxisAlignment: MainAxisAlignment.start, height: 20,
crossAxisAlignment: CrossAxisAlignment.center, child: Row(
children: [ mainAxisAlignment: MainAxisAlignment.start,
InkWell( crossAxisAlignment: CrossAxisAlignment.center,
onTap: () { children: [
ExpandableController.of(context, InkWell(
rebuildOnChange: false, required: true) onTap: () {
?.toggle(); ExpandableController.of(context, rebuildOnChange: false, required: true)?.toggle();
}, },
child: ExpandableIcon( child: ExpandableIcon(
theme: ExpandableThemeData( theme: ExpandableThemeData(
expandIcon: FlowyIconData.drop_down_show, expandIcon: FlowyIconData.drop_down_show,
collapseIcon: FlowyIconData.drop_down_hide, collapseIcon: FlowyIconData.drop_down_hide,
iconColor: theme.shader1, iconColor: theme.shader1,
iconSize: AppPageSize.expandedIconSize, iconSize: AppPageSize.expandedIconSize,
iconPadding: EdgeInsets.zero, iconPadding: EdgeInsets.zero,
hasIcon: false, hasIcon: false,
),
), ),
), ),
), HSpace(AppPageSize.expandedIconRightSpace),
HSpace(AppPageSize.expandedIconRightSpace), Expanded(
Expanded( child: GestureDetector(
child: GestureDetector( onTapDown: (_) {
onTapDown: (_) { ExpandableController.of(context, rebuildOnChange: false, required: true)?.toggle();
ExpandableController.of(context, },
rebuildOnChange: false, required: true) child: FlowyText.medium(
?.toggle(); app.name,
}, fontSize: 12,
child: FlowyText( ),
app.name, )),
fontSize: 12,
),
)),
// FlowyIconButton( // FlowyIconButton(
// icon: const Icon(Icons.add), // icon: const Icon(Icons.add),
// onPressed: () { // onPressed: () {
// debugPrint('add view'); // debugPrint('add view');
// FlowyOverlay.of(context) // FlowyOverlay.of(context)
// .insert(widget: Text('test'), identifier: 'identifier'); // .insert(widget: Text('test'), identifier: 'identifier');
// }, // },
// ), // ),
PopupMenuButton( PopupMenuButton(
iconSize: 16, iconSize: 16,
tooltip: 'create new view', tooltip: 'create new view',
icon: svg("home/add"), icon: svg("home/add"),
padding: EdgeInsets.zero, padding: EdgeInsets.zero,
onSelected: (viewType) => onSelected: (viewType) => _createView(viewType as ViewType, context),
_createView(viewType as ViewType, context), itemBuilder: (context) => menuItemBuilder())
itemBuilder: (context) => menuItemBuilder()) ],
], ),
); );
} }
List<PopupMenuEntry> menuItemBuilder() { List<PopupMenuEntry> menuItemBuilder() {
return ViewType.values return ViewType.values.where((element) => element != ViewType.Blank).map((ty) {
.where((element) => element != ViewType.Blank)
.map((ty) {
return PopupMenuItem<ViewType>( return PopupMenuItem<ViewType>(
value: ty, value: ty,
child: Row( child: Row(

View file

@ -15,11 +15,10 @@ import 'package:styled_widget/styled_widget.dart';
import 'app_header.dart'; import 'app_header.dart';
class AppPageSize { class AppPageSize {
static double expandedIconSize = 20; static double expandedIconSize = 16;
static double expandedIconRightSpace = 6; static double expandedIconRightSpace = 6;
static double scale = 1; static double scale = 1;
static double get expandedPadding => static double get expandedPadding => expandedIconSize * scale + expandedIconRightSpace;
expandedIconSize * scale + expandedIconRightSpace;
} }
class ViewListData extends ChangeNotifier { class ViewListData extends ChangeNotifier {

View file

@ -67,7 +67,7 @@ class ViewListPage extends StatelessWidget {
); );
return Padding( return Padding(
padding: const EdgeInsets.symmetric(vertical: 2), padding: const EdgeInsets.symmetric(vertical: 4),
child: viewWidget, child: viewWidget,
); );
}).toList(growable: false); }).toList(growable: false);

View file

@ -1,5 +1,5 @@
class HomeSizes { class HomeSizes {
static double get menuTopBarHeight => 60; static double get menuTopBarHeight => 48;
static double get menuAddButtonHeight => 60; static double get menuAddButtonHeight => 60;
static double get topBarHeight => 60; static double get topBarHeight => 60;
static double get editPannelTopBarHeight => 60; static double get editPannelTopBarHeight => 60;

View file

@ -1,10 +1,13 @@
import 'package:flowy_infra/theme.dart';
import 'package:flowy_infra_ui/style_widget/hover.dart'; import 'package:flowy_infra_ui/style_widget/hover.dart';
import 'package:flowy_infra_ui/style_widget/icon_button.dart'; import 'package:flowy_infra_ui/style_widget/icon_button.dart';
import 'package:flowy_infra_ui/style_widget/text.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:app_flowy/workspace/domain/image.dart'; import 'package:app_flowy/workspace/domain/image.dart';
import 'package:app_flowy/workspace/presentation/app/app_page.dart'; import 'package:app_flowy/workspace/presentation/app/app_page.dart';
import 'package:provider/provider.dart';
import 'package:styled_widget/styled_widget.dart'; import 'package:styled_widget/styled_widget.dart';
class ViewWidgetContext { class ViewWidgetContext {
@ -21,16 +24,13 @@ class ViewPage extends StatelessWidget {
final ViewWidgetContext viewCtx; final ViewWidgetContext viewCtx;
final bool isSelected; final bool isSelected;
final OpenViewCallback onOpen; final OpenViewCallback onOpen;
ViewPage( ViewPage({Key? key, required this.viewCtx, required this.onOpen, required this.isSelected})
{Key? key,
required this.viewCtx,
required this.onOpen,
required this.isSelected})
: super(key: viewCtx.valueKey()); : super(key: viewCtx.valueKey());
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final config = HoverDisplayConfig(hoverColor: Colors.grey.shade200); final theme = context.watch<AppTheme>();
final config = HoverDisplayConfig(hoverColor: theme.bg3);
return InkWell( return InkWell(
onTap: _openView(context), onTap: _openView(context),
child: FlowyHover( child: FlowyHover(
@ -40,30 +40,37 @@ class ViewPage extends StatelessWidget {
); );
} }
Widget _render( Widget _render(BuildContext context, bool onHover, HoverDisplayConfig config) {
BuildContext context, bool onHover, HoverDisplayConfig config) {
const double width = 22;
List<Widget> children = [ List<Widget> children = [
SizedBox( SizedBox(
width: width, width: 16,
height: width, height: 16,
child: svgForViewType(viewCtx.view.viewType)), child: svgForViewType(viewCtx.view.viewType),
),
const HSpace(6), const HSpace(6),
Text( FlowyText.regular(
viewCtx.view.name, viewCtx.view.name,
textAlign: TextAlign.start, fontSize: 12,
style: const TextStyle(fontSize: 15),
), ),
]; ];
if (onHover) { if (onHover) {
_addedHover(children, width); children.add(const Spacer());
children.add(ViewMoreButton(
width: 16,
onPressed: () {
debugPrint('show view setting');
},
));
} }
Widget widget = Row(children: children).padding( Widget widget = Container(
vertical: 5, child: Row(children: children).padding(
left: AppPageSize.expandedPadding, left: AppPageSize.expandedPadding,
right: 5, right: 12,
),
height: 24,
alignment: Alignment.centerLeft,
); );
if (isSelected) { if (isSelected) {
@ -76,17 +83,4 @@ class ViewPage extends StatelessWidget {
Function() _openView(BuildContext context) { Function() _openView(BuildContext context) {
return () => onOpen(viewCtx.view); return () => onOpen(viewCtx.view);
} }
void _addedHover(List<Widget> children, double hoverWidth) {
children.add(const Spacer());
children.add(Align(
alignment: Alignment.center,
child: FlowyMoreButton(
width: hoverWidth,
onPressed: () {
debugPrint('show view setting');
},
),
));
}
} }

View file

@ -51,7 +51,7 @@ class HomeTopBar extends StatelessWidget {
} }
Widget _renderMoreButton() { Widget _renderMoreButton() {
return FlowyMoreButton( return ViewMoreButton(
width: 24, width: 24,
onPressed: () { onPressed: () {
debugPrint('show more'); debugPrint('show more');
@ -79,11 +79,7 @@ class HomeTitle extends StatelessWidget {
return Flexible( return Flexible(
child: Row( child: Row(
children: [ children: [
Image( Image(fit: BoxFit.scaleDown, width: 15, height: 15, image: assetImageForViewType(type)),
fit: BoxFit.scaleDown,
width: 15,
height: 15,
image: assetImageForViewType(type)),
const HSpace(6), const HSpace(6),
FlowyText(title, fontSize: 16), FlowyText(title, fontSize: 16),
], ],

View file

@ -23,8 +23,7 @@ class MenuList extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return ExpandableTheme( return ExpandableTheme(
data: ExpandableThemeData( data: ExpandableThemeData(useInkWell: true, animationDuration: Durations.medium),
useInkWell: true, animationDuration: Durations.medium),
child: Expanded( child: Expanded(
child: ListView.separated( child: ListView.separated(
itemCount: menuItems.length, itemCount: menuItems.length,
@ -32,7 +31,7 @@ class MenuList extends StatelessWidget {
if (index == 0) { if (index == 0) {
return const VSpace(29); return const VSpace(29);
} else { } else {
return const VSpace(9); return const VSpace(24);
} }
}, },
physics: const BouncingScrollPhysics(), physics: const BouncingScrollPhysics(),

View file

@ -3,6 +3,7 @@ import 'package:app_flowy/workspace/presentation/widgets/menu/menu_top_bar.dart'
import 'package:dartz/dartz.dart'; import 'package:dartz/dartz.dart';
import 'package:flowy_infra/size.dart'; import 'package:flowy_infra/size.dart';
import 'package:flowy_infra_ui/widget/error_page.dart'; import 'package:flowy_infra_ui/widget/error_page.dart';
import 'package:flowy_infra_ui/widget/spacing.dart';
import 'package:flowy_sdk/protobuf/flowy-user/user_profile.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-user/user_profile.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-workspace/app_create.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-workspace/app_create.pb.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@ -38,13 +39,10 @@ class HomeMenu extends StatelessWidget {
return MultiBlocProvider( return MultiBlocProvider(
providers: [ providers: [
BlocProvider<MenuBloc>( BlocProvider<MenuBloc>(
create: (context) => create: (context) => getIt<MenuBloc>(param1: user, param2: workspaceId)..add(const MenuEvent.initial())),
getIt<MenuBloc>(param1: user, param2: workspaceId)
..add(const MenuEvent.initial())),
BlocProvider( BlocProvider(
create: (context) => create: (context) =>
getIt<MenuWatchBloc>(param1: user, param2: workspaceId) getIt<MenuWatchBloc>(param1: user, param2: workspaceId)..add(const MenuWatchEvent.started())),
..add(const MenuWatchEvent.started())),
], ],
child: MultiBlocListener( child: MultiBlocListener(
listeners: [ listeners: [
@ -76,6 +74,7 @@ class HomeMenu extends StatelessWidget {
mainAxisAlignment: MainAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start,
children: [ children: [
_renderTopBar(context), _renderTopBar(context),
const VSpace(32),
_renderMenuList(context), _renderMenuList(context),
], ],
).padding(horizontal: Insets.l), ).padding(horizontal: Insets.l),
@ -104,16 +103,12 @@ class HomeMenu extends StatelessWidget {
Widget _renderNewAppButton(BuildContext context) { Widget _renderNewAppButton(BuildContext context) {
return NewAppButton( return NewAppButton(
press: (appName) => press: (appName) => context.read<MenuBloc>().add(MenuEvent.createApp(appName, desc: "")),
context.read<MenuBloc>().add(MenuEvent.createApp(appName, desc: "")),
); );
} }
Widget _renderTopBar(BuildContext context) { Widget _renderTopBar(BuildContext context) {
return SizedBox( return const MenuTopBar();
height: HomeSizes.menuTopBarHeight,
child: const MenuTopBar(),
);
} }
List<MenuItem> menuItemsWithApps(Option<List<App>> someApps) { List<MenuItem> menuItemsWithApps(Option<List<App>> someApps) {

View file

@ -9,19 +9,21 @@ class MenuTopBar extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return BlocBuilder<MenuBloc, MenuState>( return BlocBuilder<MenuBloc, MenuState>(
builder: (context, state) { builder: (context, state) {
return Row( return SizedBox(
children: [ height: 48,
svgWithSize("flowy_logo_with_text", const Size(92, 17)), child: Row(
const Spacer(), children: [
IconButton( svgWithSize("flowy_logo_with_text", const Size(92, 17)),
iconSize: 16, const Spacer(),
icon: svg("home/hide_menu"), IconButton(
alignment: Alignment.centerRight, iconSize: 16,
padding: EdgeInsets.zero, icon: svg("home/hide_menu"),
onPressed: () => alignment: Alignment.centerRight,
context.read<MenuBloc>().add(const MenuEvent.collapse()), padding: EdgeInsets.zero,
), onPressed: () => context.read<MenuBloc>().add(const MenuEvent.collapse()),
], ),
],
),
); );
}, },
); );

View file

@ -23,17 +23,14 @@ class _FlowyHoverState extends State<FlowyHover> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final hoverColor = _onHover final hoverColor = _onHover ? widget.config.hoverColor : Theme.of(context).colorScheme.background;
? widget.config.hoverColor
: Theme.of(context).colorScheme.background;
final config = widget.config.copyWith(hoverColor: hoverColor); final config = widget.config.copyWith(hoverColor: hoverColor);
return MouseRegion( return MouseRegion(
cursor: SystemMouseCursors.click, cursor: SystemMouseCursors.click,
onEnter: (p) => setOnHover(true), onEnter: (p) => setOnHover(true),
onExit: (p) => setOnHover(false), onExit: (p) => setOnHover(false),
child: FlowyHoverBackground( child: FlowyHoverBackground(config: config, child: widget.builder(context, _onHover)),
config: config, child: widget.builder(context, _onHover)),
); );
} }
@ -49,15 +46,16 @@ class HoverDisplayConfig {
const HoverDisplayConfig( const HoverDisplayConfig(
{this.borderColor = Colors.transparent, {this.borderColor = Colors.transparent,
this.borderWidth = 0, this.borderWidth = 0,
this.borderRadius = const BorderRadius.all(Radius.circular(8)), this.borderRadius = const BorderRadius.all(Radius.circular(6)),
this.hoverColor}); this.hoverColor});
HoverDisplayConfig copyWith({Color? hoverColor}) { HoverDisplayConfig copyWith({Color? hoverColor}) {
return HoverDisplayConfig( return HoverDisplayConfig(
borderColor: borderColor, borderColor: borderColor,
borderWidth: borderWidth, borderWidth: borderWidth,
borderRadius: borderRadius, borderRadius: borderRadius,
hoverColor: hoverColor); hoverColor: hoverColor,
);
} }
} }

View file

@ -1,3 +1,4 @@
import 'package:flowy_infra/image.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
class FlowyIconButton extends StatelessWidget { class FlowyIconButton extends StatelessWidget {
@ -32,12 +33,12 @@ class FlowyIconButton extends StatelessWidget {
} }
} }
class FlowyMoreButton extends StatelessWidget { class ViewMoreButton extends StatelessWidget {
final double width; final double width;
final double? height; final double? height;
final VoidCallback? onPressed; final VoidCallback? onPressed;
const FlowyMoreButton({ const ViewMoreButton({
Key? key, Key? key,
this.height, this.height,
this.onPressed, this.onPressed,
@ -49,7 +50,7 @@ class FlowyMoreButton extends StatelessWidget {
return FlowyIconButton( return FlowyIconButton(
width: width, width: width,
height: height, height: height,
icon: const Icon(Icons.more_vert), icon: svg("editor/details"),
onPressed: onPressed, onPressed: onPressed,
); );
} }

View file

@ -6,13 +6,25 @@ class FlowyText extends StatelessWidget {
final String title; final String title;
final TextOverflow overflow; final TextOverflow overflow;
final double fontSize; final double fontSize;
final FontWeight fontWeight;
const FlowyText( const FlowyText(
this.title, { this.title, {
Key? key, Key? key,
this.overflow = TextOverflow.ellipsis, this.overflow = TextOverflow.ellipsis,
this.fontSize = 16, this.fontSize = 16,
this.fontWeight = FontWeight.w500,
}) : super(key: key); }) : super(key: key);
const FlowyText.medium(this.title, {Key? key, this.fontSize = 16, TextOverflow? overflow})
: fontWeight = FontWeight.w500,
overflow = overflow ?? TextOverflow.ellipsis,
super(key: key);
const FlowyText.regular(this.title, {Key? key, this.fontSize = 16, TextOverflow? overflow})
: fontWeight = FontWeight.w400,
overflow = overflow ?? TextOverflow.ellipsis,
super(key: key);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final theme = context.watch<AppTheme>(); final theme = context.watch<AppTheme>();
@ -21,7 +33,7 @@ class FlowyText extends StatelessWidget {
softWrap: false, softWrap: false,
style: TextStyle( style: TextStyle(
color: theme.shader1, color: theme.shader1,
fontWeight: FontWeight.w500, fontWeight: fontWeight,
fontSize: fontSize + 2, fontSize: fontSize + 2,
)); ));
} }

View file

@ -98,6 +98,7 @@ flutter:
assets: assets:
- assets/images/ - assets/images/
- assets/images/home/ - assets/images/home/
- assets/images/editor/
# - images/a_dot_ham.jpeg # - images/a_dot_ham.jpeg
# An image asset can refer to one or more resolution-specific "variants", see # An image asset can refer to one or more resolution-specific "variants", see