[flutter]:enable add doc with FlowyOverlay

This commit is contained in:
appflowy 2021-10-11 16:40:08 +08:00
parent 9ddfed5b87
commit 4afbe62475
6 changed files with 128 additions and 97 deletions

View File

@ -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,

View File

@ -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),
);
}
}

View File

@ -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,

View File

@ -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,
),
);
}
}

View File

@ -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({