mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
feat: add a pinned icon after page name
This commit is contained in:
parent
1fd34bc58a
commit
a668e0bd09
@ -2,6 +2,7 @@ import 'package:appflowy/generated/flowy_svgs.g.dart';
|
|||||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||||
import 'package:appflowy/workspace/application/sidebar/folder/folder_bloc.dart';
|
import 'package:appflowy/workspace/application/sidebar/folder/folder_bloc.dart';
|
||||||
import 'package:appflowy/workspace/application/tabs/tabs_bloc.dart';
|
import 'package:appflowy/workspace/application/tabs/tabs_bloc.dart';
|
||||||
|
import 'package:appflowy/workspace/application/view/view_ext.dart';
|
||||||
import 'package:appflowy/workspace/presentation/home/menu/sidebar/favorites/favorite_menu_bloc.dart';
|
import 'package:appflowy/workspace/presentation/home/menu/sidebar/favorites/favorite_menu_bloc.dart';
|
||||||
import 'package:appflowy/workspace/presentation/home/menu/sidebar/favorites/favorite_more_actions.dart';
|
import 'package:appflowy/workspace/presentation/home/menu/sidebar/favorites/favorite_more_actions.dart';
|
||||||
import 'package:appflowy/workspace/presentation/home/menu/sidebar/favorites/favorite_pin_action.dart';
|
import 'package:appflowy/workspace/presentation/home/menu/sidebar/favorites/favorite_pin_action.dart';
|
||||||
@ -36,9 +37,6 @@ class FavoriteMenu extends StatelessWidget {
|
|||||||
FavoriteMenuBloc()..add(const FavoriteMenuEvent.initial()),
|
FavoriteMenuBloc()..add(const FavoriteMenuEvent.initial()),
|
||||||
child: BlocBuilder<FavoriteMenuBloc, FavoriteMenuState>(
|
child: BlocBuilder<FavoriteMenuBloc, FavoriteMenuState>(
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
if (state.views.isEmpty) {
|
|
||||||
return const SizedBox.shrink();
|
|
||||||
}
|
|
||||||
return Column(
|
return Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
@ -52,7 +50,10 @@ class FavoriteMenu extends StatelessWidget {
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
const VSpace(12),
|
const VSpace(12),
|
||||||
_buildViews(context, state),
|
_FavoriteGroups(
|
||||||
|
minWidth: minWidth,
|
||||||
|
state: state,
|
||||||
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
@ -60,8 +61,67 @@ class FavoriteMenu extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Widget _buildViews(BuildContext context, FavoriteMenuState state) {
|
class _FavoriteGroupedViews extends StatelessWidget {
|
||||||
|
const _FavoriteGroupedViews({
|
||||||
|
required this.views,
|
||||||
|
});
|
||||||
|
|
||||||
|
final List<ViewPB> views;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: views
|
||||||
|
.map(
|
||||||
|
(e) => ViewItem(
|
||||||
|
key: ValueKey(e.id),
|
||||||
|
view: e,
|
||||||
|
spaceType: FolderSpaceType.favorite,
|
||||||
|
level: 0,
|
||||||
|
onSelected: (_, view) {
|
||||||
|
context.read<TabsBloc>().openPlugin(view);
|
||||||
|
PopoverContainer.maybeOf(context)?.close();
|
||||||
|
},
|
||||||
|
isFeedback: false,
|
||||||
|
isDraggable: false,
|
||||||
|
shouldRenderChildren: false,
|
||||||
|
extendBuilder: (view) => view.isPinned
|
||||||
|
? [
|
||||||
|
const HSpace(4.0),
|
||||||
|
const FlowySvg(
|
||||||
|
FlowySvgs.favorite_pin_s,
|
||||||
|
blendMode: null,
|
||||||
|
),
|
||||||
|
]
|
||||||
|
: [],
|
||||||
|
leftIconBuilder: (_, __) => const HSpace(4.0),
|
||||||
|
rightIconsBuilder: (_, view) => [
|
||||||
|
FavoriteMoreActions(view: view),
|
||||||
|
const HSpace(6.0),
|
||||||
|
FavoritePinAction(view: view),
|
||||||
|
const HSpace(4.0),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.toList(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _FavoriteGroups extends StatelessWidget {
|
||||||
|
const _FavoriteGroups({
|
||||||
|
required this.minWidth,
|
||||||
|
required this.state,
|
||||||
|
});
|
||||||
|
|
||||||
|
final double minWidth;
|
||||||
|
final FavoriteMenuState state;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
final today = _buildGroups(
|
final today = _buildGroups(
|
||||||
context,
|
context,
|
||||||
state.todayViews,
|
state.todayViews,
|
||||||
@ -131,41 +191,11 @@ class FavoriteMenu extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
const VSpace(2),
|
const VSpace(2),
|
||||||
_buildGroupedViews(context, views),
|
_FavoriteGroupedViews(views: views),
|
||||||
const VSpace(8),
|
const VSpace(8),
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildGroupedViews(BuildContext context, List<ViewPB> views) {
|
|
||||||
return Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: views
|
|
||||||
.map(
|
|
||||||
(e) => ViewItem(
|
|
||||||
key: ValueKey(e.id),
|
|
||||||
view: e,
|
|
||||||
spaceType: FolderSpaceType.favorite,
|
|
||||||
level: 0,
|
|
||||||
onSelected: (_, view) {
|
|
||||||
context.read<TabsBloc>().openPlugin(view);
|
|
||||||
PopoverContainer.maybeOf(context)?.close();
|
|
||||||
},
|
|
||||||
isFeedback: false,
|
|
||||||
isDraggable: false,
|
|
||||||
shouldRenderChildren: false,
|
|
||||||
leftIconBuilder: (_, __) => const HSpace(4.0),
|
|
||||||
rightIconsBuilder: (_, view) => [
|
|
||||||
FavoriteMoreActions(view: view),
|
|
||||||
const HSpace(6.0),
|
|
||||||
FavoritePinAction(view: view),
|
|
||||||
const HSpace(4.0),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.toList(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class _FavoriteSearchField extends StatefulWidget {
|
class _FavoriteSearchField extends StatefulWidget {
|
||||||
|
@ -60,6 +60,7 @@ class ViewItem extends StatelessWidget {
|
|||||||
this.rightIconsBuilder,
|
this.rightIconsBuilder,
|
||||||
this.shouldLoadChildViews = true,
|
this.shouldLoadChildViews = true,
|
||||||
this.isExpandedNotifier,
|
this.isExpandedNotifier,
|
||||||
|
this.extendBuilder,
|
||||||
});
|
});
|
||||||
|
|
||||||
final ViewPB view;
|
final ViewPB view;
|
||||||
@ -113,6 +114,8 @@ class ViewItem extends StatelessWidget {
|
|||||||
final bool shouldLoadChildViews;
|
final bool shouldLoadChildViews;
|
||||||
final PropertyValueNotifier<bool>? isExpandedNotifier;
|
final PropertyValueNotifier<bool>? isExpandedNotifier;
|
||||||
|
|
||||||
|
final List<Widget> Function(ViewPB view)? extendBuilder;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return BlocProvider(
|
return BlocProvider(
|
||||||
@ -148,6 +151,7 @@ class ViewItem extends StatelessWidget {
|
|||||||
leftIconBuilder: leftIconBuilder,
|
leftIconBuilder: leftIconBuilder,
|
||||||
rightIconsBuilder: rightIconsBuilder,
|
rightIconsBuilder: rightIconsBuilder,
|
||||||
isExpandedNotifier: isExpandedNotifier,
|
isExpandedNotifier: isExpandedNotifier,
|
||||||
|
extendBuilder: extendBuilder,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@ -181,6 +185,7 @@ class InnerViewItem extends StatefulWidget {
|
|||||||
required this.leftIconBuilder,
|
required this.leftIconBuilder,
|
||||||
required this.rightIconsBuilder,
|
required this.rightIconsBuilder,
|
||||||
this.isExpandedNotifier,
|
this.isExpandedNotifier,
|
||||||
|
required this.extendBuilder,
|
||||||
});
|
});
|
||||||
|
|
||||||
final ViewPB view;
|
final ViewPB view;
|
||||||
@ -210,6 +215,7 @@ class InnerViewItem extends StatefulWidget {
|
|||||||
final ViewItemRightIconsBuilder? rightIconsBuilder;
|
final ViewItemRightIconsBuilder? rightIconsBuilder;
|
||||||
|
|
||||||
final PropertyValueNotifier<bool>? isExpandedNotifier;
|
final PropertyValueNotifier<bool>? isExpandedNotifier;
|
||||||
|
final List<Widget> Function(ViewPB view)? extendBuilder;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<InnerViewItem> createState() => _InnerViewItemState();
|
State<InnerViewItem> createState() => _InnerViewItemState();
|
||||||
@ -247,6 +253,7 @@ class _InnerViewItemState extends State<InnerViewItem> {
|
|||||||
isHovered: widget.isHovered,
|
isHovered: widget.isHovered,
|
||||||
leftIconBuilder: widget.leftIconBuilder,
|
leftIconBuilder: widget.leftIconBuilder,
|
||||||
rightIconsBuilder: widget.rightIconsBuilder,
|
rightIconsBuilder: widget.rightIconsBuilder,
|
||||||
|
extendBuilder: widget.extendBuilder,
|
||||||
);
|
);
|
||||||
|
|
||||||
// if the view is expanded and has child views, render its child views
|
// if the view is expanded and has child views, render its child views
|
||||||
@ -270,6 +277,7 @@ class _InnerViewItemState extends State<InnerViewItem> {
|
|||||||
isHovered: widget.isHovered,
|
isHovered: widget.isHovered,
|
||||||
leftIconBuilder: widget.leftIconBuilder,
|
leftIconBuilder: widget.leftIconBuilder,
|
||||||
rightIconsBuilder: widget.rightIconsBuilder,
|
rightIconsBuilder: widget.rightIconsBuilder,
|
||||||
|
extendBuilder: widget.extendBuilder,
|
||||||
);
|
);
|
||||||
}).toList();
|
}).toList();
|
||||||
|
|
||||||
@ -315,6 +323,7 @@ class _InnerViewItemState extends State<InnerViewItem> {
|
|||||||
isFeedback: true,
|
isFeedback: true,
|
||||||
leftIconBuilder: widget.leftIconBuilder,
|
leftIconBuilder: widget.leftIconBuilder,
|
||||||
rightIconsBuilder: widget.rightIconsBuilder,
|
rightIconsBuilder: widget.rightIconsBuilder,
|
||||||
|
extendBuilder: widget.extendBuilder,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
@ -389,6 +398,7 @@ class SingleInnerViewItem extends StatefulWidget {
|
|||||||
this.isHovered,
|
this.isHovered,
|
||||||
required this.leftIconBuilder,
|
required this.leftIconBuilder,
|
||||||
required this.rightIconsBuilder,
|
required this.rightIconsBuilder,
|
||||||
|
required this.extendBuilder,
|
||||||
});
|
});
|
||||||
|
|
||||||
final ViewPB view;
|
final ViewPB view;
|
||||||
@ -413,6 +423,8 @@ class SingleInnerViewItem extends StatefulWidget {
|
|||||||
final ViewItemLeftIconBuilder? leftIconBuilder;
|
final ViewItemLeftIconBuilder? leftIconBuilder;
|
||||||
final ViewItemRightIconsBuilder? rightIconsBuilder;
|
final ViewItemRightIconsBuilder? rightIconsBuilder;
|
||||||
|
|
||||||
|
final List<Widget> Function(ViewPB view)? extendBuilder;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<SingleInnerViewItem> createState() => _SingleInnerViewItemState();
|
State<SingleInnerViewItem> createState() => _SingleInnerViewItemState();
|
||||||
}
|
}
|
||||||
@ -453,6 +465,10 @@ class _SingleInnerViewItemState extends State<SingleInnerViewItem> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildViewItem(bool onHover, [bool isSelected = false]) {
|
Widget _buildViewItem(bool onHover, [bool isSelected = false]) {
|
||||||
|
final name = FlowyText.regular(
|
||||||
|
widget.view.name,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
);
|
||||||
final children = [
|
final children = [
|
||||||
const HSpace(2),
|
const HSpace(2),
|
||||||
// expand icon or placeholder
|
// expand icon or placeholder
|
||||||
@ -462,12 +478,16 @@ class _SingleInnerViewItemState extends State<SingleInnerViewItem> {
|
|||||||
_buildViewIconButton(),
|
_buildViewIconButton(),
|
||||||
const HSpace(6),
|
const HSpace(6),
|
||||||
// title
|
// title
|
||||||
Expanded(
|
widget.extendBuilder != null
|
||||||
child: FlowyText.regular(
|
? Expanded(
|
||||||
widget.view.name,
|
child: Row(
|
||||||
overflow: TextOverflow.ellipsis,
|
children: [
|
||||||
),
|
name,
|
||||||
),
|
...widget.extendBuilder!(widget.view),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
: Expanded(child: name),
|
||||||
];
|
];
|
||||||
|
|
||||||
// hover action
|
// hover action
|
||||||
|
3
frontend/resources/flowy_icons/16x/favorite_pin.svg
Normal file
3
frontend/resources/flowy_icons/16x/favorite_pin.svg
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M2.64912 1.71521C2.64912 1.43942 2.84766 1.2002 3.16 1.2002H8.855C9.125 1.2002 9.36707 1.40199 9.36707 1.71021C9.36707 1.89847 9.20994 2.20021 8.855 2.20021L8.01019 2.20277L8.00984 4.46598C8.00984 4.53315 8.05692 4.59785 8.10288 4.64382L10.1752 7.02856C10.223 7.07629 10.25 7.14117 10.25 7.20834L10.2495 7.61027C10.25 7.89027 10.025 8.11628 9.75 8.11628L6.51011 8.11753L6.51 11.2002C6.50999 11.4763 6.28614 11.7002 6.01 11.7002H5.99949C5.72355 11.7002 5.49977 11.4761 5.49949 11.2002L5.49613 8.11681L2.255 8.11631C1.96831 8.11631 1.75 7.89027 1.75 7.61027L1.75046 7.20898C1.75048 7.14179 1.77659 7.07678 1.82409 7.02928L3.90196 4.64452C3.94951 4.59697 4.00575 4.53192 4.00575 4.46474L4.00593 2.20171L3.16 2.20021C2.89258 2.20171 2.64912 1.9824 2.64912 1.71521Z" fill="#4DA594"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 891 B |
Loading…
Reference in New Issue
Block a user