mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
[flutter]:enable add doc with FlowyOverlay
This commit is contained in:
parent
9ddfed5b87
commit
4afbe62475
@ -20,6 +20,8 @@ class AppWidgetTask extends LaunchTask {
|
||||
}
|
||||
}
|
||||
|
||||
final GlobalKey<FlowyOverlayState> _key = GlobalKey<FlowyOverlayState>();
|
||||
|
||||
class ApplicationWidget extends StatelessWidget {
|
||||
final Widget child;
|
||||
const ApplicationWidget({
|
||||
@ -36,10 +38,11 @@ class ApplicationWidget extends StatelessWidget {
|
||||
setWindowFrame(const Rect.fromLTRB(0, 0, launchWidth, launchWidth / ratio));
|
||||
|
||||
final theme = AppTheme.fromType(ThemeType.light);
|
||||
FlowyOverlayConfig config = FlowyOverlayConfig(barrierColor: theme.bg3.withOpacity(0.3));
|
||||
return Provider.value(
|
||||
value: theme,
|
||||
child: MaterialApp(
|
||||
builder: overlayManagerBuilder(),
|
||||
builder: overlayManagerBuilder(config: config),
|
||||
debugShowCheckedModeBanner: false,
|
||||
theme: theme.themeData,
|
||||
navigatorKey: AppGlobals.rootNavKey,
|
||||
|
@ -1,16 +1,19 @@
|
||||
import 'package:app_flowy/workspace/application/app/app_bloc.dart';
|
||||
import 'package:expandable/expandable.dart';
|
||||
import 'package:flowy_infra/flowy_icon_data_icons.dart';
|
||||
import 'package:flowy_infra/image.dart';
|
||||
import 'package:flowy_infra/theme.dart';
|
||||
import 'package:flowy_infra_ui/flowy_infra_ui.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/flowy_icon_data_icons.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:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:styled_widget/styled_widget.dart';
|
||||
|
||||
import 'package:app_flowy/workspace/application/app/app_bloc.dart';
|
||||
|
||||
import 'menu_app.dart';
|
||||
|
||||
class MenuAppHeader extends StatelessWidget {
|
||||
@ -55,37 +58,88 @@ class MenuAppHeader extends StatelessWidget {
|
||||
fontSize: 12,
|
||||
),
|
||||
)),
|
||||
|
||||
ViewAddButton(
|
||||
onPressed: () {
|
||||
debugPrint('add view');
|
||||
// FlowyOverlay.of(context)
|
||||
// .insert(widget: Text('test'), identifier: 'identifier');
|
||||
DisclosureButton(
|
||||
onSelected: (viewType) {
|
||||
context.read<AppBloc>().add(AppEvent.createView("New view", "", viewType));
|
||||
},
|
||||
).padding(right: MenuAppSizes.expandedIconPadding),
|
||||
// PopupMenuButton(
|
||||
// iconSize: 16,
|
||||
// tooltip: 'create new view',
|
||||
// icon: svg("home/add"),
|
||||
// padding: EdgeInsets.zero,
|
||||
// onSelected: (viewType) => _createView(viewType as ViewType, context),
|
||||
// itemBuilder: (context) => menuItemBuilder())
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
List<PopupMenuEntry> menuItemBuilder() {
|
||||
return ViewType.values.where((element) => element != ViewType.Blank).map((ty) {
|
||||
return PopupMenuItem<ViewType>(
|
||||
value: ty,
|
||||
child: Row(
|
||||
children: <Widget>[Text(ty.name)],
|
||||
));
|
||||
}).toList();
|
||||
}
|
||||
class DisclosureButton extends StatelessWidget {
|
||||
final Function(ViewType) onSelected;
|
||||
const DisclosureButton({
|
||||
Key? key,
|
||||
required this.onSelected,
|
||||
}) : super(key: key);
|
||||
|
||||
void _createView(ViewType viewType, BuildContext context) {
|
||||
context.read<AppBloc>().add(AppEvent.createView("New view", "", viewType));
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return FlowyIconButton(
|
||||
width: 16,
|
||||
onPressed: () {
|
||||
DisclosureButtonActionList(
|
||||
anchorContext: context,
|
||||
onSelected: onSelected,
|
||||
).show(context);
|
||||
},
|
||||
icon: svg("home/add"),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class DisclosureButtonActionList {
|
||||
final Function(ViewType) onSelected;
|
||||
final BuildContext anchorContext;
|
||||
final String _identifier = 'DisclosureButtonActionList';
|
||||
|
||||
const DisclosureButtonActionList({required this.anchorContext, required this.onSelected});
|
||||
|
||||
void show(BuildContext buildContext) {
|
||||
final items = ViewType.values.where((element) => element != ViewType.Blank).map((ty) {
|
||||
return CreateItem(
|
||||
viewType: ty,
|
||||
onSelected: (viewType) {
|
||||
FlowyOverlay.of(buildContext).remove(_identifier);
|
||||
onSelected(viewType);
|
||||
});
|
||||
}).toList();
|
||||
|
||||
ListOverlay.showWithAnchor(
|
||||
buildContext,
|
||||
identifier: _identifier,
|
||||
itemCount: items.length,
|
||||
itemBuilder: (context, index) => items[index],
|
||||
anchorContext: anchorContext,
|
||||
anchorDirection: AnchorDirection.bottomRight,
|
||||
maxWidth: 120,
|
||||
maxHeight: 80,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class CreateItem extends StatelessWidget {
|
||||
final ViewType viewType;
|
||||
final Function(ViewType) onSelected;
|
||||
const CreateItem({
|
||||
Key? key,
|
||||
required this.viewType,
|
||||
required this.onSelected,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GestureDetector(
|
||||
onTap: () {
|
||||
onSelected(viewType);
|
||||
},
|
||||
child: FlowyText.medium(
|
||||
viewType.name,
|
||||
fontSize: 12,
|
||||
).padding(horizontal: 10, vertical: 10),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
// ignore_for_file: unused_element
|
||||
|
||||
import 'package:dartz/dartz.dart' show Tuple3;
|
||||
import 'package:flowy_infra_ui/src/flowy_overlay/overlay_layout_delegate.dart';
|
||||
import 'package:flowy_infra_ui/src/flowy_overlay/layout.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
/// Specifies how overlay are anchored to the SourceWidget
|
||||
@ -55,13 +55,21 @@ enum OnBackBehavior {
|
||||
dismiss,
|
||||
}
|
||||
|
||||
class FlowyOverlayConfig {
|
||||
final Color barrierColor;
|
||||
|
||||
FlowyOverlayConfig({required this.barrierColor});
|
||||
|
||||
const FlowyOverlayConfig.defualt() : barrierColor = Colors.transparent;
|
||||
}
|
||||
|
||||
final GlobalKey<FlowyOverlayState> _key = GlobalKey<FlowyOverlayState>();
|
||||
|
||||
/// Invoke this method in app generation process
|
||||
TransitionBuilder overlayManagerBuilder() {
|
||||
TransitionBuilder overlayManagerBuilder({FlowyOverlayConfig config = const FlowyOverlayConfig.defualt()}) {
|
||||
return (context, child) {
|
||||
assert(child != null, 'Child can\'t be null.');
|
||||
return FlowyOverlay(key: _key, child: child!);
|
||||
return FlowyOverlay(key: _key, child: child!, config: config);
|
||||
};
|
||||
}
|
||||
|
||||
@ -70,50 +78,33 @@ abstract class FlowyOverlayDelegate {
|
||||
}
|
||||
|
||||
class FlowyOverlay extends StatefulWidget {
|
||||
const FlowyOverlay({
|
||||
Key? key,
|
||||
required this.child,
|
||||
this.barrierColor = Colors.transparent,
|
||||
}) : super(key: key);
|
||||
const FlowyOverlay({Key? key, required this.child, required this.config}) : super(key: key);
|
||||
|
||||
final Widget child;
|
||||
|
||||
final Color? barrierColor;
|
||||
|
||||
static FlowyOverlayState of(
|
||||
BuildContext context, {
|
||||
bool rootOverlay = false,
|
||||
}) {
|
||||
FlowyOverlayState? overlayManager;
|
||||
if (rootOverlay) {
|
||||
overlayManager = context.findRootAncestorStateOfType<FlowyOverlayState>() ?? overlayManager;
|
||||
} else {
|
||||
overlayManager = overlayManager ?? context.findAncestorStateOfType<FlowyOverlayState>();
|
||||
}
|
||||
final FlowyOverlayConfig config;
|
||||
|
||||
static FlowyOverlayState of(BuildContext context, {bool rootOverlay = false}) {
|
||||
FlowyOverlayState? state = maybeOf(context, rootOverlay: rootOverlay);
|
||||
assert(() {
|
||||
if (overlayManager == null) {
|
||||
if (state == null) {
|
||||
throw FlutterError(
|
||||
'Can\'t find overlay manager in current context, please check if already wrapped by overlay manager.',
|
||||
);
|
||||
}
|
||||
return true;
|
||||
}());
|
||||
return overlayManager!;
|
||||
return state!;
|
||||
}
|
||||
|
||||
static FlowyOverlayState? maybeOf(
|
||||
BuildContext context, {
|
||||
bool rootOverlay = false,
|
||||
}) {
|
||||
FlowyOverlayState? overlayManager;
|
||||
static FlowyOverlayState? maybeOf(BuildContext context, {bool rootOverlay = false}) {
|
||||
FlowyOverlayState? state;
|
||||
if (rootOverlay) {
|
||||
overlayManager = context.findRootAncestorStateOfType<FlowyOverlayState>() ?? overlayManager;
|
||||
state = context.findRootAncestorStateOfType<FlowyOverlayState>();
|
||||
} else {
|
||||
overlayManager = overlayManager ?? context.findAncestorStateOfType<FlowyOverlayState>();
|
||||
state = context.findAncestorStateOfType<FlowyOverlayState>();
|
||||
}
|
||||
|
||||
return overlayManager;
|
||||
return state;
|
||||
}
|
||||
|
||||
@override
|
||||
@ -239,8 +230,7 @@ class FlowyOverlayState extends State<FlowyOverlay> {
|
||||
overlay = CustomSingleChildLayout(
|
||||
delegate: OverlayLayoutDelegate(
|
||||
anchorRect: anchorRect,
|
||||
anchorDirection:
|
||||
shouldAnchor ? anchorDirection ?? AnchorDirection.rightWithTopAligned : AnchorDirection.custom,
|
||||
anchorDirection: anchorDirection ?? AnchorDirection.rightWithTopAligned,
|
||||
overlapBehaviour: overlapBehaviour ?? OverlapBehaviour.stretch,
|
||||
),
|
||||
child: widget,
|
||||
@ -259,7 +249,7 @@ class FlowyOverlayState extends State<FlowyOverlay> {
|
||||
widget.child,
|
||||
if (overlays.isNotEmpty)
|
||||
Container(
|
||||
color: widget.barrierColor,
|
||||
color: widget.config.barrierColor,
|
||||
child: GestureDetector(
|
||||
behavior: HitTestBehavior.opaque,
|
||||
onTap: _handleTapOnBackground,
|
||||
|
@ -17,6 +17,26 @@ class ListOverlay extends StatelessWidget {
|
||||
final double maxWidth;
|
||||
final double maxHeight;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
constraints: BoxConstraints.tight(Size(maxWidth, maxHeight)),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: const BorderRadius.all(Radius.circular(6)),
|
||||
boxShadow: [
|
||||
BoxShadow(color: Colors.black.withOpacity(0.1), spreadRadius: 1, blurRadius: 20.0),
|
||||
],
|
||||
),
|
||||
child: ListView.builder(
|
||||
shrinkWrap: true,
|
||||
itemBuilder: itemBuilder,
|
||||
itemCount: itemCount,
|
||||
controller: controller,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
static void showWithAnchor(
|
||||
BuildContext context, {
|
||||
required String identifier,
|
||||
@ -77,23 +97,4 @@ class ListOverlay extends StatelessWidget {
|
||||
overlapBehaviour: overlapBehaviour,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
constraints: BoxConstraints.tight(Size(maxWidth, maxHeight)),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: const BorderRadius.all(Radius.circular(6)),
|
||||
boxShadow: [
|
||||
BoxShadow(color: Colors.black.withOpacity(0.1), spreadRadius: 1, blurRadius: 20.0),
|
||||
],
|
||||
),
|
||||
child: ListView.builder(
|
||||
shrinkWrap: true,
|
||||
itemBuilder: itemBuilder,
|
||||
itemCount: itemCount,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -48,23 +48,6 @@ class FlowyDropdownButton extends StatelessWidget {
|
||||
}
|
||||
}
|
||||
|
||||
class ViewAddButton extends StatelessWidget {
|
||||
final VoidCallback? onPressed;
|
||||
const ViewAddButton({
|
||||
Key? key,
|
||||
this.onPressed,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return FlowyIconButton(
|
||||
width: 16,
|
||||
onPressed: onPressed,
|
||||
icon: svg("home/add"),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class ViewMoreButton extends StatelessWidget {
|
||||
final VoidCallback? onPressed;
|
||||
const ViewMoreButton({
|
||||
|
Loading…
Reference in New Issue
Block a user