mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
feat: adds drag-drop support to sidebar pages
1. On mobile it uses ReorderableDelayedDragStartListener (like long press) 2. On desktop it uses ReorderableDragStartListener (instantly)
This commit is contained in:
parent
383925ba55
commit
628e53adc1
@ -27,7 +27,7 @@ import 'app/menu_app.dart';
|
|||||||
import 'app/create_button.dart';
|
import 'app/create_button.dart';
|
||||||
import 'menu_user.dart';
|
import 'menu_user.dart';
|
||||||
|
|
||||||
class HomeMenu extends StatelessWidget {
|
class HomeMenu extends StatefulWidget {
|
||||||
final PublishNotifier<bool> _collapsedNotifier;
|
final PublishNotifier<bool> _collapsedNotifier;
|
||||||
final UserProfile user;
|
final UserProfile user;
|
||||||
final CurrentWorkspaceSetting workspaceSetting;
|
final CurrentWorkspaceSetting workspaceSetting;
|
||||||
@ -40,13 +40,20 @@ class HomeMenu extends StatelessWidget {
|
|||||||
}) : _collapsedNotifier = collapsedNotifier,
|
}) : _collapsedNotifier = collapsedNotifier,
|
||||||
super(key: key);
|
super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<HomeMenu> createState() => _HomeMenuState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _HomeMenuState extends State<HomeMenu> {
|
||||||
|
final List<Widget> _menuItems = List.empty(growable: true);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return MultiBlocProvider(
|
return MultiBlocProvider(
|
||||||
providers: [
|
providers: [
|
||||||
BlocProvider<MenuBloc>(
|
BlocProvider<MenuBloc>(
|
||||||
create: (context) {
|
create: (context) {
|
||||||
final menuBloc = getIt<MenuBloc>(param1: user, param2: workspaceSetting.workspace.id);
|
final menuBloc = getIt<MenuBloc>(param1: widget.user, param2: widget.workspaceSetting.workspace.id);
|
||||||
menuBloc.add(const MenuEvent.initial());
|
menuBloc.add(const MenuEvent.initial());
|
||||||
return menuBloc;
|
return menuBloc;
|
||||||
},
|
},
|
||||||
@ -63,7 +70,7 @@ class HomeMenu extends StatelessWidget {
|
|||||||
BlocListener<MenuBloc, MenuState>(
|
BlocListener<MenuBloc, MenuState>(
|
||||||
listenWhen: (p, c) => p.isCollapse != c.isCollapse,
|
listenWhen: (p, c) => p.isCollapse != c.isCollapse,
|
||||||
listener: (context, state) {
|
listener: (context, state) {
|
||||||
_collapsedNotifier.value = state.isCollapse;
|
widget._collapsedNotifier.value = state.isCollapse;
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
@ -80,7 +87,8 @@ class HomeMenu extends StatelessWidget {
|
|||||||
return Container(
|
return Container(
|
||||||
color: theme.bg1,
|
color: theme.bg1,
|
||||||
child: ChangeNotifierProvider(
|
child: ChangeNotifierProvider(
|
||||||
create: (_) => MenuSharedState(view: workspaceSetting.hasLatestView() ? workspaceSetting.latestView : null),
|
create: (_) =>
|
||||||
|
MenuSharedState(view: widget.workspaceSetting.hasLatestView() ? widget.workspaceSetting.latestView : null),
|
||||||
child: Consumer(builder: (context, MenuSharedState sharedState, child) {
|
child: Consumer(builder: (context, MenuSharedState sharedState, child) {
|
||||||
return Column(
|
return Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
@ -114,27 +122,70 @@ class HomeMenu extends StatelessWidget {
|
|||||||
behavior: const ScrollBehavior().copyWith(scrollbars: false),
|
behavior: const ScrollBehavior().copyWith(scrollbars: false),
|
||||||
child: BlocSelector<MenuBloc, MenuState, List<Widget>>(
|
child: BlocSelector<MenuBloc, MenuState, List<Widget>>(
|
||||||
selector: (state) {
|
selector: (state) {
|
||||||
List<Widget> menuItems = [];
|
// List<Widget> menuItems = [];
|
||||||
menuItems.add(MenuUser(user));
|
// menuItems.add(MenuUser(user));
|
||||||
List<MenuApp> appWidgets =
|
List<MenuApp> appWidgets =
|
||||||
state.apps.foldRight([], (apps, _) => apps.map((app) => MenuApp(app)).toList());
|
state.apps.foldRight([], (apps, _) => apps.map((app) => MenuApp(app)).toList());
|
||||||
menuItems.addAll(appWidgets);
|
|
||||||
return menuItems;
|
for (var app in appWidgets) {
|
||||||
},
|
if (!_menuItems.any((oldElement) => oldElement.key == app.key)) {
|
||||||
builder: (context, menuItems) => ListView.separated(
|
_menuItems.add(app);
|
||||||
itemCount: menuItems.length,
|
|
||||||
separatorBuilder: (context, index) {
|
|
||||||
if (index == 0) {
|
|
||||||
return const VSpace(20);
|
|
||||||
} else {
|
|
||||||
return VSpace(MenuAppSizes.appVPadding);
|
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
physics: StyledScrollPhysics(),
|
// TODO @gaganyadav: fix: concurrent modification exception
|
||||||
itemBuilder: (BuildContext context, int index) {
|
// Unhandled Exception: Concurrent modification during iteration: Instance(length:3) of '_GrowableList'.
|
||||||
return menuItems[index];
|
for (var item in _menuItems) {
|
||||||
},
|
if (!appWidgets.any((oldElement) => oldElement.key == item.key)) {
|
||||||
),
|
_menuItems.remove(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// menuItems.addAll(appWidgets);
|
||||||
|
return _menuItems;
|
||||||
|
},
|
||||||
|
builder: (context, menuItems) {
|
||||||
|
return ReorderableListView.builder(
|
||||||
|
itemCount: menuItems.length,
|
||||||
|
buildDefaultDragHandles: false,
|
||||||
|
header: Padding(
|
||||||
|
padding: EdgeInsets.only(bottom: 20.0 - MenuAppSizes.appVPadding),
|
||||||
|
child: MenuUser(widget.user),
|
||||||
|
),
|
||||||
|
onReorder: (oldIndex, newIndex) {
|
||||||
|
int index = newIndex > oldIndex ? newIndex - 1 : newIndex;
|
||||||
|
|
||||||
|
Widget menu = menuItems.removeAt(oldIndex);
|
||||||
|
menuItems.insert(index, menu);
|
||||||
|
|
||||||
|
final menuBloc = context.read<MenuBloc>();
|
||||||
|
menuBloc.state.apps.forEach((a) {
|
||||||
|
var app = a.removeAt(oldIndex);
|
||||||
|
a.insert(index, app);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
physics: StyledScrollPhysics(),
|
||||||
|
itemBuilder: (BuildContext context, int index) {
|
||||||
|
//? To mimic the ListView.separated behavior, we need to add a padding.
|
||||||
|
// EdgeInsets padding = EdgeInsets.zero;
|
||||||
|
// if (index == 0) {
|
||||||
|
// padding = EdgeInsets.only(bottom: MenuAppSizes.appVPadding / 2);
|
||||||
|
// } else if (index == menuItems.length - 1) {
|
||||||
|
// padding = EdgeInsets.only(top: MenuAppSizes.appVPadding / 2);
|
||||||
|
// } else {
|
||||||
|
// padding = EdgeInsets.symmetric(vertical: MenuAppSizes.appVPadding / 2);
|
||||||
|
// }
|
||||||
|
|
||||||
|
return ReorderableDragStartListener(
|
||||||
|
key: ValueKey(menuItems[index].hashCode),
|
||||||
|
index: index,
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsets.symmetric(vertical: MenuAppSizes.appVPadding / 2),
|
||||||
|
child: menuItems[index],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
Loading…
Reference in New Issue
Block a user