mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
fix: v0.6.2 issues (#5654)
* fix: remove create button in move to menu * fix: add loading indicator when duplicating space * fix: sidebar header expand icon status * fix: text within select tag overflow * fix: callout block icon align issue * feat: sync the space icon when creating a space * fix: duplicated hover views * fix: cover image doesn't update
This commit is contained in:
parent
50f5be3e75
commit
c78f23e1c0
@ -1,8 +1,8 @@
|
|||||||
import 'package:appflowy/plugins/database/grid/presentation/layout/sizes.dart';
|
|
||||||
import 'package:appflowy/plugins/database/widgets/row/cells/cell_container.dart';
|
|
||||||
import 'package:appflowy/plugins/database/widgets/cell_editor/extension.dart';
|
|
||||||
import 'package:appflowy/plugins/database/application/cell/bloc/select_option_cell_bloc.dart';
|
import 'package:appflowy/plugins/database/application/cell/bloc/select_option_cell_bloc.dart';
|
||||||
|
import 'package:appflowy/plugins/database/grid/presentation/layout/sizes.dart';
|
||||||
|
import 'package:appflowy/plugins/database/widgets/cell_editor/extension.dart';
|
||||||
import 'package:appflowy/plugins/database/widgets/cell_editor/select_option_cell_editor.dart';
|
import 'package:appflowy/plugins/database/widgets/cell_editor/select_option_cell_editor.dart';
|
||||||
|
import 'package:appflowy/plugins/database/widgets/row/cells/cell_container.dart';
|
||||||
import 'package:appflowy_backend/protobuf/flowy-database2/protobuf.dart';
|
import 'package:appflowy_backend/protobuf/flowy-database2/protobuf.dart';
|
||||||
import 'package:appflowy_popover/appflowy_popover.dart';
|
import 'package:appflowy_popover/appflowy_popover.dart';
|
||||||
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
||||||
@ -56,7 +56,7 @@ class DesktopGridSelectOptionCellSkin extends IEditableSelectOptionCellSkin {
|
|||||||
child: SelectOptionTag(
|
child: SelectOptionTag(
|
||||||
option: option,
|
option: option,
|
||||||
padding: const EdgeInsets.symmetric(
|
padding: const EdgeInsets.symmetric(
|
||||||
vertical: 1,
|
vertical: 4,
|
||||||
horizontal: 8,
|
horizontal: 8,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||||
import 'package:appflowy/plugins/database/widgets/row/cells/cell_container.dart';
|
|
||||||
import 'package:appflowy/plugins/database/widgets/cell_editor/extension.dart';
|
|
||||||
import 'package:appflowy/plugins/database/application/cell/bloc/select_option_cell_bloc.dart';
|
import 'package:appflowy/plugins/database/application/cell/bloc/select_option_cell_bloc.dart';
|
||||||
|
import 'package:appflowy/plugins/database/widgets/cell_editor/extension.dart';
|
||||||
import 'package:appflowy/plugins/database/widgets/cell_editor/select_option_cell_editor.dart';
|
import 'package:appflowy/plugins/database/widgets/cell_editor/select_option_cell_editor.dart';
|
||||||
|
import 'package:appflowy/plugins/database/widgets/row/cells/cell_container.dart';
|
||||||
import 'package:appflowy_backend/protobuf/flowy-database2/protobuf.dart';
|
import 'package:appflowy_backend/protobuf/flowy-database2/protobuf.dart';
|
||||||
import 'package:appflowy_popover/appflowy_popover.dart';
|
import 'package:appflowy_popover/appflowy_popover.dart';
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
@ -67,7 +67,7 @@ class DesktopRowDetailSelectOptionCellSkin
|
|||||||
return SelectOptionTag(
|
return SelectOptionTag(
|
||||||
option: option,
|
option: option,
|
||||||
padding: const EdgeInsets.symmetric(
|
padding: const EdgeInsets.symmetric(
|
||||||
vertical: 1,
|
vertical: 4,
|
||||||
horizontal: 8,
|
horizontal: 8,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -96,7 +96,6 @@ class SelectOptionTag extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
|
|
||||||
return Container(
|
return Container(
|
||||||
height: 20,
|
|
||||||
padding: onRemove == null ? padding : padding.copyWith(right: 2.0),
|
padding: onRemove == null ? padding : padding.copyWith(right: 2.0),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: optionColor,
|
color: optionColor,
|
||||||
|
@ -1,10 +1,6 @@
|
|||||||
import 'dart:collection';
|
import 'dart:collection';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:flutter/foundation.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter/services.dart';
|
|
||||||
|
|
||||||
import 'package:appflowy/generated/flowy_svgs.g.dart';
|
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/plugins/database/application/cell/bloc/select_option_cell_editor_bloc.dart';
|
import 'package:appflowy/plugins/database/application/cell/bloc/select_option_cell_editor_bloc.dart';
|
||||||
@ -14,12 +10,14 @@ import 'package:appflowy_popover/appflowy_popover.dart';
|
|||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:flowy_infra/theme_extension.dart';
|
import 'package:flowy_infra/theme_extension.dart';
|
||||||
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
|
||||||
import '../../grid/presentation/layout/sizes.dart';
|
import '../../grid/presentation/layout/sizes.dart';
|
||||||
import '../../grid/presentation/widgets/common/type_option_separator.dart';
|
import '../../grid/presentation/widgets/common/type_option_separator.dart';
|
||||||
import '../field/type_option_editor/select/select_option_editor.dart';
|
import '../field/type_option_editor/select/select_option_editor.dart';
|
||||||
|
|
||||||
import 'extension.dart';
|
import 'extension.dart';
|
||||||
import 'select_option_text_field.dart';
|
import 'select_option_text_field.dart';
|
||||||
|
|
||||||
@ -476,11 +474,11 @@ class SelectOptionTagCell extends StatelessWidget {
|
|||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.symmetric(
|
padding: const EdgeInsets.symmetric(
|
||||||
horizontal: 6.0,
|
horizontal: 6.0,
|
||||||
vertical: 4.0,
|
|
||||||
),
|
),
|
||||||
child: SelectOptionTag(
|
child: SelectOptionTag(
|
||||||
option: option,
|
option: option,
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 8),
|
padding:
|
||||||
|
const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -132,7 +132,10 @@ class _SelectOptionTextFieldState extends State<SelectOptionTextField> {
|
|||||||
(option) => SelectOptionTag(
|
(option) => SelectOptionTag(
|
||||||
option: option,
|
option: option,
|
||||||
onRemove: (option) => widget.onRemove(option),
|
onRemove: (option) => widget.onRemove(option),
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 1),
|
padding: const EdgeInsets.symmetric(
|
||||||
|
horizontal: 8,
|
||||||
|
vertical: 4,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.toList();
|
.toList();
|
||||||
|
@ -8,7 +8,6 @@ import 'package:appflowy/plugins/document/application/document_data_pb_extension
|
|||||||
import 'package:appflowy/plugins/document/application/document_listener.dart';
|
import 'package:appflowy/plugins/document/application/document_listener.dart';
|
||||||
import 'package:appflowy/plugins/document/application/document_service.dart';
|
import 'package:appflowy/plugins/document/application/document_service.dart';
|
||||||
import 'package:appflowy/plugins/document/application/editor_transaction_adapter.dart';
|
import 'package:appflowy/plugins/document/application/editor_transaction_adapter.dart';
|
||||||
import 'package:appflowy/plugins/document/presentation/editor_plugins/migration/editor_migration.dart';
|
|
||||||
import 'package:appflowy/plugins/trash/application/trash_service.dart';
|
import 'package:appflowy/plugins/trash/application/trash_service.dart';
|
||||||
import 'package:appflowy/shared/feature_flags.dart';
|
import 'package:appflowy/shared/feature_flags.dart';
|
||||||
import 'package:appflowy/startup/startup.dart';
|
import 'package:appflowy/startup/startup.dart';
|
||||||
@ -19,7 +18,6 @@ import 'package:appflowy/util/color_to_hex_string.dart';
|
|||||||
import 'package:appflowy/util/debounce.dart';
|
import 'package:appflowy/util/debounce.dart';
|
||||||
import 'package:appflowy/util/throttle.dart';
|
import 'package:appflowy/util/throttle.dart';
|
||||||
import 'package:appflowy/workspace/application/view/view_listener.dart';
|
import 'package:appflowy/workspace/application/view/view_listener.dart';
|
||||||
import 'package:appflowy/workspace/application/view/view_service.dart';
|
|
||||||
import 'package:appflowy_backend/protobuf/flowy-document/entities.pb.dart';
|
import 'package:appflowy_backend/protobuf/flowy-document/entities.pb.dart';
|
||||||
import 'package:appflowy_backend/protobuf/flowy-document/protobuf.dart';
|
import 'package:appflowy_backend/protobuf/flowy-document/protobuf.dart';
|
||||||
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
|
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
|
||||||
@ -118,11 +116,6 @@ class DocumentBloc extends Bloc<DocumentEvent, DocumentState> {
|
|||||||
final result = await _fetchDocumentState();
|
final result = await _fetchDocumentState();
|
||||||
_onViewChanged();
|
_onViewChanged();
|
||||||
_onDocumentChanged();
|
_onDocumentChanged();
|
||||||
result.onSuccess((s) {
|
|
||||||
if (s != null) {
|
|
||||||
_migrateCover(s);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
final newState = await result.fold(
|
final newState = await result.fold(
|
||||||
(s) async {
|
(s) async {
|
||||||
final userProfilePB =
|
final userProfilePB =
|
||||||
@ -390,14 +383,6 @@ class DocumentBloc extends Bloc<DocumentEvent, DocumentState> {
|
|||||||
metadata: jsonEncode(metadata.toJson()),
|
metadata: jsonEncode(metadata.toJson()),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// from version 0.5.5, the cover is stored in the view.ext
|
|
||||||
Future<void> _migrateCover(EditorState editorState) async {
|
|
||||||
final view = await ViewBackendService.getView(documentId);
|
|
||||||
view.onSuccess((s) {
|
|
||||||
return EditorMigration.migrateCoverIfNeeded(s, editorState);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@freezed
|
@freezed
|
||||||
|
@ -196,6 +196,7 @@ class _CalloutBlockComponentWidgetState
|
|||||||
), // force to refresh the popover state
|
), // force to refresh the popover state
|
||||||
title: '',
|
title: '',
|
||||||
emoji: emoji,
|
emoji: emoji,
|
||||||
|
emojiSize: 16.0,
|
||||||
onSubmitted: (emoji, controller) {
|
onSubmitted: (emoji, controller) {
|
||||||
setEmoji(emoji);
|
setEmoji(emoji);
|
||||||
controller?.close();
|
controller?.close();
|
||||||
@ -204,7 +205,7 @@ class _CalloutBlockComponentWidgetState
|
|||||||
),
|
),
|
||||||
Flexible(
|
Flexible(
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.symmetric(vertical: 8.0),
|
padding: const EdgeInsets.symmetric(vertical: 6.0),
|
||||||
child: buildCalloutBlockComponent(context, textDirection),
|
child: buildCalloutBlockComponent(context, textDirection),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -91,6 +91,7 @@ class _DocumentCoverWidgetState extends State<DocumentCoverWidget> {
|
|||||||
|
|
||||||
String viewIcon = '';
|
String viewIcon = '';
|
||||||
PageStyleCover? cover;
|
PageStyleCover? cover;
|
||||||
|
late ViewPB view;
|
||||||
late final ViewListener viewListener;
|
late final ViewListener viewListener;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -99,6 +100,7 @@ class _DocumentCoverWidgetState extends State<DocumentCoverWidget> {
|
|||||||
final value = widget.view.icon.value;
|
final value = widget.view.icon.value;
|
||||||
viewIcon = value.isNotEmpty ? value : icon ?? '';
|
viewIcon = value.isNotEmpty ? value : icon ?? '';
|
||||||
cover = widget.view.cover;
|
cover = widget.view.cover;
|
||||||
|
view = widget.view;
|
||||||
widget.node.addListener(_reload);
|
widget.node.addListener(_reload);
|
||||||
viewListener = ViewListener(
|
viewListener = ViewListener(
|
||||||
viewId: widget.view.id,
|
viewId: widget.view.id,
|
||||||
@ -107,6 +109,7 @@ class _DocumentCoverWidgetState extends State<DocumentCoverWidget> {
|
|||||||
setState(() {
|
setState(() {
|
||||||
viewIcon = p0.icon.value;
|
viewIcon = p0.icon.value;
|
||||||
cover = p0.cover;
|
cover = p0.cover;
|
||||||
|
view = p0;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@ -137,7 +140,7 @@ class _DocumentCoverWidgetState extends State<DocumentCoverWidget> {
|
|||||||
),
|
),
|
||||||
if (hasCover)
|
if (hasCover)
|
||||||
DocumentCover(
|
DocumentCover(
|
||||||
view: widget.view,
|
view: view,
|
||||||
editorState: widget.editorState,
|
editorState: widget.editorState,
|
||||||
node: widget.node,
|
node: widget.node,
|
||||||
coverType: coverType,
|
coverType: coverType,
|
||||||
@ -204,7 +207,7 @@ class _DocumentCoverWidgetState extends State<DocumentCoverWidget> {
|
|||||||
// compatible with version > 0.5.5.
|
// compatible with version > 0.5.5.
|
||||||
EditorMigration.migrateCoverIfNeeded(
|
EditorMigration.migrateCoverIfNeeded(
|
||||||
widget.view,
|
widget.view,
|
||||||
widget.editorState,
|
attributes,
|
||||||
overwrite: true,
|
overwrite: true,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -164,18 +164,17 @@ class EditorMigration {
|
|||||||
// Now, the cover is stored in the view.ext.
|
// Now, the cover is stored in the view.ext.
|
||||||
static void migrateCoverIfNeeded(
|
static void migrateCoverIfNeeded(
|
||||||
ViewPB view,
|
ViewPB view,
|
||||||
EditorState editorState, {
|
Attributes attributes, {
|
||||||
bool overwrite = false,
|
bool overwrite = false,
|
||||||
}) async {
|
}) async {
|
||||||
if (view.extra.isNotEmpty && !overwrite) {
|
if (view.extra.isNotEmpty && !overwrite) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final root = editorState.document.root;
|
|
||||||
final coverType = CoverType.fromString(
|
final coverType = CoverType.fromString(
|
||||||
root.attributes[DocumentHeaderBlockKeys.coverType],
|
attributes[DocumentHeaderBlockKeys.coverType],
|
||||||
);
|
);
|
||||||
final coverDetails = root.attributes[DocumentHeaderBlockKeys.coverDetails];
|
final coverDetails = attributes[DocumentHeaderBlockKeys.coverDetails];
|
||||||
|
|
||||||
Map extra = {};
|
Map extra = {};
|
||||||
|
|
||||||
|
@ -297,11 +297,16 @@ class SpaceBloc extends Bloc<SpaceEvent, SpaceState> {
|
|||||||
if (currentSpace == null) {
|
if (currentSpace == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
emit(state.copyWith(isDuplicatingSpace: true));
|
||||||
|
|
||||||
final newSpace = await _duplicateSpace(currentSpace);
|
final newSpace = await _duplicateSpace(currentSpace);
|
||||||
// open the duplicated space
|
// open the duplicated space
|
||||||
if (newSpace != null) {
|
if (newSpace != null) {
|
||||||
|
add(const SpaceEvent.didReceiveSpaceUpdate());
|
||||||
add(SpaceEvent.open(newSpace));
|
add(SpaceEvent.open(newSpace));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
emit(state.copyWith(isDuplicatingSpace: false));
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
@ -346,25 +351,22 @@ class SpaceBloc extends Bloc<SpaceEvent, SpaceState> {
|
|||||||
SpacePermission.private => ViewSectionPB.Private,
|
SpacePermission.private => ViewSectionPB.Private,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
final extra = {
|
||||||
|
ViewExtKeys.isSpaceKey: true,
|
||||||
|
ViewExtKeys.spaceIconKey: icon,
|
||||||
|
ViewExtKeys.spaceIconColorKey: iconColor,
|
||||||
|
ViewExtKeys.spacePermissionKey: permission.index,
|
||||||
|
ViewExtKeys.spaceCreatedAtKey: DateTime.now().millisecondsSinceEpoch,
|
||||||
|
};
|
||||||
final result = await _workspaceService.createView(
|
final result = await _workspaceService.createView(
|
||||||
name: name,
|
name: name,
|
||||||
viewSection: section,
|
viewSection: section,
|
||||||
setAsCurrent: false,
|
setAsCurrent: true,
|
||||||
viewId: viewId,
|
viewId: viewId,
|
||||||
|
extra: jsonEncode(extra),
|
||||||
);
|
);
|
||||||
return await result.fold((space) async {
|
return await result.fold((space) async {
|
||||||
Log.info('Space created: $space');
|
Log.info('Space created: $space');
|
||||||
final extra = {
|
|
||||||
ViewExtKeys.isSpaceKey: true,
|
|
||||||
ViewExtKeys.spaceIconKey: icon,
|
|
||||||
ViewExtKeys.spaceIconColorKey: iconColor,
|
|
||||||
ViewExtKeys.spacePermissionKey: permission.index,
|
|
||||||
ViewExtKeys.spaceCreatedAtKey: DateTime.now().millisecondsSinceEpoch,
|
|
||||||
};
|
|
||||||
await ViewBackendService.updateView(
|
|
||||||
viewId: space.id,
|
|
||||||
extra: jsonEncode(extra),
|
|
||||||
);
|
|
||||||
return space;
|
return space;
|
||||||
}, (error) {
|
}, (error) {
|
||||||
Log.error('Failed to create space: $error');
|
Log.error('Failed to create space: $error');
|
||||||
@ -620,19 +622,17 @@ class SpaceBloc extends Bloc<SpaceEvent, SpaceState> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (final view in space.childViews) {
|
for (final view in space.childViews) {
|
||||||
unawaited(
|
await ViewBackendService.duplicate(
|
||||||
ViewBackendService.duplicate(
|
view: view,
|
||||||
view: view,
|
openAfterDuplicate: true,
|
||||||
openAfterDuplicate: true,
|
includeChildren: true,
|
||||||
includeChildren: true,
|
parentViewId: newSpace.id,
|
||||||
parentViewId: newSpace.id,
|
suffix: '',
|
||||||
suffix: '',
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Log.info('Space duplicated: $newSpace');
|
Log.info('Space duplicated: $newSpace');
|
||||||
add(const SpaceEvent.didReceiveSpaceUpdate());
|
|
||||||
return newSpace;
|
return newSpace;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -688,6 +688,7 @@ class SpaceState with _$SpaceState {
|
|||||||
@Default(null) ViewPB? lastCreatedPage,
|
@Default(null) ViewPB? lastCreatedPage,
|
||||||
FlowyResult<void, FlowyError>? createPageResult,
|
FlowyResult<void, FlowyError>? createPageResult,
|
||||||
@Default(false) bool shouldShowUpgradeDialog,
|
@Default(false) bool shouldShowUpgradeDialog,
|
||||||
|
@Default(false) bool isDuplicatingSpace,
|
||||||
}) = _SpaceState;
|
}) = _SpaceState;
|
||||||
|
|
||||||
factory SpaceState.initial() => const SpaceState();
|
factory SpaceState.initial() => const SpaceState();
|
||||||
|
@ -133,13 +133,13 @@ extension ViewExtension on ViewPB {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FlowySvg get spaceIconSvg {
|
FlowySvg? get spaceIconSvg {
|
||||||
try {
|
try {
|
||||||
final ext = jsonDecode(extra);
|
final ext = jsonDecode(extra);
|
||||||
final icon = ext[ViewExtKeys.spaceIconKey];
|
final icon = ext[ViewExtKeys.spaceIconKey];
|
||||||
final color = ext[ViewExtKeys.spaceIconColorKey];
|
final color = ext[ViewExtKeys.spaceIconColorKey];
|
||||||
if (icon == null || color == null) {
|
if (icon == null || color == null) {
|
||||||
return const FlowySvg(FlowySvgs.space_icon_s, blendMode: null);
|
return null;
|
||||||
}
|
}
|
||||||
return FlowySvg(
|
return FlowySvg(
|
||||||
FlowySvgData('assets/flowy_icons/16x/$icon.svg'),
|
FlowySvgData('assets/flowy_icons/16x/$icon.svg'),
|
||||||
@ -147,7 +147,7 @@ extension ViewExtension on ViewPB {
|
|||||||
blendMode: BlendMode.srcOut,
|
blendMode: BlendMode.srcOut,
|
||||||
);
|
);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return const FlowySvg(FlowySvgs.space_icon_s, blendMode: null);
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,6 +19,7 @@ class WorkspaceService {
|
|||||||
ViewLayoutPB? layout,
|
ViewLayoutPB? layout,
|
||||||
bool? setAsCurrent,
|
bool? setAsCurrent,
|
||||||
String? viewId,
|
String? viewId,
|
||||||
|
String? extra,
|
||||||
}) {
|
}) {
|
||||||
final payload = CreateViewPayloadPB.create()
|
final payload = CreateViewPayloadPB.create()
|
||||||
..parentViewId = workspaceId
|
..parentViewId = workspaceId
|
||||||
@ -42,6 +43,10 @@ class WorkspaceService {
|
|||||||
payload.viewId = viewId;
|
payload.viewId = viewId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (extra != null) {
|
||||||
|
payload.extra = extra;
|
||||||
|
}
|
||||||
|
|
||||||
return FolderEventCreateView(payload).send();
|
return FolderEventCreateView(payload).send();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -117,6 +117,7 @@ class _MovePageMenuState extends State<MovePageMenu> {
|
|||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
SpacePopup(
|
SpacePopup(
|
||||||
|
showCreateButton: false,
|
||||||
child: CurrentSpace(
|
child: CurrentSpace(
|
||||||
space: space,
|
space: space,
|
||||||
),
|
),
|
||||||
|
@ -5,6 +5,7 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:appflowy/generated/flowy_svgs.g.dart';
|
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/plugins/blank/blank.dart';
|
import 'package:appflowy/plugins/blank/blank.dart';
|
||||||
|
import 'package:appflowy/plugins/document/presentation/editor_plugins/openai/widgets/loading.dart';
|
||||||
import 'package:appflowy/shared/feature_flags.dart';
|
import 'package:appflowy/shared/feature_flags.dart';
|
||||||
import 'package:appflowy/startup/startup.dart';
|
import 'package:appflowy/startup/startup.dart';
|
||||||
import 'package:appflowy/workspace/application/action_navigation/action_navigation_bloc.dart';
|
import 'package:appflowy/workspace/application/action_navigation/action_navigation_bloc.dart';
|
||||||
@ -38,6 +39,8 @@ 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:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
|
||||||
|
Loading? _duplicateSpaceLoading;
|
||||||
|
|
||||||
/// Home Sidebar is the left side bar of the home page.
|
/// Home Sidebar is the left side bar of the home page.
|
||||||
///
|
///
|
||||||
/// in the sidebar, we have:
|
/// in the sidebar, we have:
|
||||||
@ -136,7 +139,8 @@ class HomeSideBar extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
BlocListener<SpaceBloc, SpaceState>(
|
BlocListener<SpaceBloc, SpaceState>(
|
||||||
listenWhen: (p, c) =>
|
listenWhen: (p, c) =>
|
||||||
p.lastCreatedPage?.id != c.lastCreatedPage?.id,
|
p.lastCreatedPage?.id != c.lastCreatedPage?.id ||
|
||||||
|
p.isDuplicatingSpace != c.isDuplicatingSpace,
|
||||||
listener: (context, state) {
|
listener: (context, state) {
|
||||||
final page = state.lastCreatedPage;
|
final page = state.lastCreatedPage;
|
||||||
if (page == null || page.id.isEmpty) {
|
if (page == null || page.id.isEmpty) {
|
||||||
@ -153,6 +157,14 @@ class HomeSideBar extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (state.isDuplicatingSpace) {
|
||||||
|
_duplicateSpaceLoading ??= Loading(context);
|
||||||
|
_duplicateSpaceLoading?.start();
|
||||||
|
} else if (_duplicateSpaceLoading != null) {
|
||||||
|
_duplicateSpaceLoading?.stop();
|
||||||
|
_duplicateSpaceLoading = null;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
BlocListener<ActionNavigationBloc, ActionNavigationState>(
|
BlocListener<ActionNavigationBloc, ActionNavigationState>(
|
||||||
|
@ -277,9 +277,11 @@ class DeleteSpacePopup extends StatelessWidget {
|
|||||||
class SpacePopup extends StatelessWidget {
|
class SpacePopup extends StatelessWidget {
|
||||||
const SpacePopup({
|
const SpacePopup({
|
||||||
super.key,
|
super.key,
|
||||||
|
required this.showCreateButton,
|
||||||
required this.child,
|
required this.child,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
final bool showCreateButton;
|
||||||
final Widget child;
|
final Widget child;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -293,7 +295,9 @@ class SpacePopup extends StatelessWidget {
|
|||||||
offset: const Offset(0, 4),
|
offset: const Offset(0, 4),
|
||||||
popupBuilder: (_) => BlocProvider.value(
|
popupBuilder: (_) => BlocProvider.value(
|
||||||
value: context.read<SpaceBloc>(),
|
value: context.read<SpaceBloc>(),
|
||||||
child: const SidebarSpaceMenu(),
|
child: SidebarSpaceMenu(
|
||||||
|
showCreateButton: showCreateButton,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
child: FlowyButton(
|
child: FlowyButton(
|
||||||
useIntrinsicWidth: true,
|
useIntrinsicWidth: true,
|
||||||
@ -333,8 +337,10 @@ class CurrentSpace extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
const HSpace(4.0),
|
const HSpace(4.0),
|
||||||
const FlowySvg(
|
FlowySvg(
|
||||||
FlowySvgs.workspace_drop_down_menu_show_s,
|
context.read<SpaceBloc>().state.isExpanded
|
||||||
|
? FlowySvgs.workspace_drop_down_menu_show_s
|
||||||
|
: FlowySvgs.workspace_drop_down_menu_hide_s,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
@ -89,6 +89,7 @@ class _SidebarSpaceHeaderState extends State<SidebarSpaceHeader> {
|
|||||||
bottom: 3,
|
bottom: 3,
|
||||||
right: isHovered.value || onEditing ? 88 : 0,
|
right: isHovered.value || onEditing ? 88 : 0,
|
||||||
child: SpacePopup(
|
child: SpacePopup(
|
||||||
|
showCreateButton: true,
|
||||||
child: _buildChild(),
|
child: _buildChild(),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -14,7 +14,12 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
|
||||||
class SidebarSpaceMenu extends StatelessWidget {
|
class SidebarSpaceMenu extends StatelessWidget {
|
||||||
const SidebarSpaceMenu({super.key});
|
const SidebarSpaceMenu({
|
||||||
|
super.key,
|
||||||
|
required this.showCreateButton,
|
||||||
|
});
|
||||||
|
|
||||||
|
final bool showCreateButton;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@ -32,16 +37,18 @@ class SidebarSpaceMenu extends StatelessWidget {
|
|||||||
isSelected: state.currentSpace?.id == space.id,
|
isSelected: state.currentSpace?.id == space.id,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const Padding(
|
if (showCreateButton) ...[
|
||||||
padding: EdgeInsets.symmetric(vertical: 8.0),
|
const Padding(
|
||||||
child: Divider(
|
padding: EdgeInsets.symmetric(vertical: 8.0),
|
||||||
height: 0.5,
|
child: Divider(
|
||||||
|
height: 0.5,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
const SizedBox(
|
||||||
const SizedBox(
|
height: HomeSpaceViewSizes.viewHeight,
|
||||||
height: HomeSpaceViewSizes.viewHeight,
|
child: _CreateSpaceButton(),
|
||||||
child: _CreateSpaceButton(),
|
),
|
||||||
),
|
],
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
@ -257,26 +257,33 @@ class _InnerViewItemState extends State<InnerViewItem> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
Widget child = SingleInnerViewItem(
|
Widget child = ValueListenableBuilder(
|
||||||
view: widget.view,
|
valueListenable: getIt<MenuSharedState>().notifier,
|
||||||
parentView: widget.parentView,
|
builder: (context, value, _) {
|
||||||
level: widget.level,
|
final isSelected = value?.id == widget.view.id;
|
||||||
showActions: widget.showActions,
|
return SingleInnerViewItem(
|
||||||
spaceType: widget.spaceType,
|
view: widget.view,
|
||||||
onSelected: widget.onSelected,
|
parentView: widget.parentView,
|
||||||
onTertiarySelected: widget.onTertiarySelected,
|
level: widget.level,
|
||||||
isExpanded: widget.isExpanded,
|
showActions: widget.showActions,
|
||||||
isDraggable: widget.isDraggable,
|
spaceType: widget.spaceType,
|
||||||
leftPadding: widget.leftPadding,
|
onSelected: widget.onSelected,
|
||||||
isFeedback: widget.isFeedback,
|
onTertiarySelected: widget.onTertiarySelected,
|
||||||
height: widget.height,
|
isExpanded: widget.isExpanded,
|
||||||
isPlaceholder: widget.isPlaceholder,
|
isDraggable: widget.isDraggable,
|
||||||
isHovered: widget.isHovered,
|
leftPadding: widget.leftPadding,
|
||||||
leftIconBuilder: widget.leftIconBuilder,
|
isFeedback: widget.isFeedback,
|
||||||
rightIconsBuilder: widget.rightIconsBuilder,
|
height: widget.height,
|
||||||
extendBuilder: widget.extendBuilder,
|
isPlaceholder: widget.isPlaceholder,
|
||||||
disableSelectedStatus: widget.disableSelectedStatus,
|
isHovered: widget.isHovered,
|
||||||
shouldIgnoreView: widget.shouldIgnoreView,
|
leftIconBuilder: widget.leftIconBuilder,
|
||||||
|
rightIconsBuilder: widget.rightIconsBuilder,
|
||||||
|
extendBuilder: widget.extendBuilder,
|
||||||
|
disableSelectedStatus: widget.disableSelectedStatus,
|
||||||
|
shouldIgnoreView: widget.shouldIgnoreView,
|
||||||
|
isSelected: isSelected,
|
||||||
|
);
|
||||||
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
// 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
|
||||||
@ -403,6 +410,7 @@ class SingleInnerViewItem extends StatefulWidget {
|
|||||||
required this.extendBuilder,
|
required this.extendBuilder,
|
||||||
required this.disableSelectedStatus,
|
required this.disableSelectedStatus,
|
||||||
required this.shouldIgnoreView,
|
required this.shouldIgnoreView,
|
||||||
|
required this.isSelected,
|
||||||
});
|
});
|
||||||
|
|
||||||
final ViewPB view;
|
final ViewPB view;
|
||||||
@ -430,6 +438,7 @@ class SingleInnerViewItem extends StatefulWidget {
|
|||||||
|
|
||||||
final List<Widget> Function(ViewPB view)? extendBuilder;
|
final List<Widget> Function(ViewPB view)? extendBuilder;
|
||||||
final bool Function(ViewPB view)? shouldIgnoreView;
|
final bool Function(ViewPB view)? shouldIgnoreView;
|
||||||
|
final bool isSelected;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<SingleInnerViewItem> createState() => _SingleInnerViewItemState();
|
State<SingleInnerViewItem> createState() => _SingleInnerViewItemState();
|
||||||
@ -441,8 +450,8 @@ class _SingleInnerViewItemState extends State<SingleInnerViewItem> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
var isSelected =
|
var isSelected = widget.isSelected;
|
||||||
getIt<MenuSharedState>().latestOpenView?.id == widget.view.id;
|
|
||||||
if (widget.disableSelectedStatus == true) {
|
if (widget.disableSelectedStatus == true) {
|
||||||
isSelected = false;
|
isSelected = false;
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,7 @@ impl EventIntegrationTest {
|
|||||||
index: None,
|
index: None,
|
||||||
section: None,
|
section: None,
|
||||||
view_id: None,
|
view_id: None,
|
||||||
|
extra: None,
|
||||||
};
|
};
|
||||||
EventBuilder::new(self.clone())
|
EventBuilder::new(self.clone())
|
||||||
.event(FolderEvent::CreateView)
|
.event(FolderEvent::CreateView)
|
||||||
|
@ -46,6 +46,7 @@ impl EventIntegrationTest {
|
|||||||
index: None,
|
index: None,
|
||||||
section: None,
|
section: None,
|
||||||
view_id: None,
|
view_id: None,
|
||||||
|
extra: None,
|
||||||
};
|
};
|
||||||
EventBuilder::new(self.clone())
|
EventBuilder::new(self.clone())
|
||||||
.event(FolderEvent::CreateView)
|
.event(FolderEvent::CreateView)
|
||||||
@ -78,6 +79,7 @@ impl EventIntegrationTest {
|
|||||||
index: None,
|
index: None,
|
||||||
section: None,
|
section: None,
|
||||||
view_id: None,
|
view_id: None,
|
||||||
|
extra: None,
|
||||||
};
|
};
|
||||||
EventBuilder::new(self.clone())
|
EventBuilder::new(self.clone())
|
||||||
.event(FolderEvent::CreateView)
|
.event(FolderEvent::CreateView)
|
||||||
@ -105,6 +107,7 @@ impl EventIntegrationTest {
|
|||||||
index: None,
|
index: None,
|
||||||
section: None,
|
section: None,
|
||||||
view_id: None,
|
view_id: None,
|
||||||
|
extra: None,
|
||||||
};
|
};
|
||||||
EventBuilder::new(self.clone())
|
EventBuilder::new(self.clone())
|
||||||
.event(FolderEvent::CreateView)
|
.event(FolderEvent::CreateView)
|
||||||
|
@ -66,6 +66,7 @@ impl DocumentEventTest {
|
|||||||
index: None,
|
index: None,
|
||||||
section: None,
|
section: None,
|
||||||
view_id: None,
|
view_id: None,
|
||||||
|
extra: None,
|
||||||
};
|
};
|
||||||
EventBuilder::new(core.clone())
|
EventBuilder::new(core.clone())
|
||||||
.event(FolderEvent::CreateView)
|
.event(FolderEvent::CreateView)
|
||||||
|
@ -43,6 +43,7 @@ impl EventIntegrationTest {
|
|||||||
index: None,
|
index: None,
|
||||||
section: None,
|
section: None,
|
||||||
view_id: None,
|
view_id: None,
|
||||||
|
extra: None,
|
||||||
};
|
};
|
||||||
let view = EventBuilder::new(self.clone())
|
let view = EventBuilder::new(self.clone())
|
||||||
.event(FolderEvent::CreateView)
|
.event(FolderEvent::CreateView)
|
||||||
|
@ -238,6 +238,7 @@ impl EventIntegrationTest {
|
|||||||
index: None,
|
index: None,
|
||||||
section: None,
|
section: None,
|
||||||
view_id: None,
|
view_id: None,
|
||||||
|
extra: None,
|
||||||
};
|
};
|
||||||
EventBuilder::new(self.clone())
|
EventBuilder::new(self.clone())
|
||||||
.event(FolderEvent::CreateView)
|
.event(FolderEvent::CreateView)
|
||||||
@ -302,6 +303,7 @@ impl ViewTest {
|
|||||||
index: None,
|
index: None,
|
||||||
section: None,
|
section: None,
|
||||||
view_id: None,
|
view_id: None,
|
||||||
|
extra: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
let view = EventBuilder::new(sdk.clone())
|
let view = EventBuilder::new(sdk.clone())
|
||||||
|
@ -253,6 +253,7 @@ pub async fn create_view(
|
|||||||
index: None,
|
index: None,
|
||||||
section: None,
|
section: None,
|
||||||
view_id: None,
|
view_id: None,
|
||||||
|
extra: None,
|
||||||
};
|
};
|
||||||
EventBuilder::new(sdk.clone())
|
EventBuilder::new(sdk.clone())
|
||||||
.event(CreateView)
|
.event(CreateView)
|
||||||
|
@ -261,6 +261,11 @@ pub struct CreateViewPayloadPB {
|
|||||||
|
|
||||||
#[pb(index = 11, one_of)]
|
#[pb(index = 11, one_of)]
|
||||||
pub view_id: Option<String>,
|
pub view_id: Option<String>,
|
||||||
|
|
||||||
|
// The extra data of the view.
|
||||||
|
// Refer to the extra field in the collab
|
||||||
|
#[pb(index = 12, one_of)]
|
||||||
|
pub extra: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Eq, PartialEq, Hash, Debug, ProtoBuf_Enum, Clone, Default)]
|
#[derive(Eq, PartialEq, Hash, Debug, ProtoBuf_Enum, Clone, Default)]
|
||||||
@ -335,7 +340,7 @@ impl TryInto<CreateViewParams> for CreateViewPayloadPB {
|
|||||||
index: self.index,
|
index: self.index,
|
||||||
section: self.section,
|
section: self.section,
|
||||||
icon: None,
|
icon: None,
|
||||||
extra: None,
|
extra: self.extra,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user