mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
Merge branch 'main' into workspace-invite
This commit is contained in:
commit
d0c647203c
@ -1,5 +1,7 @@
|
|||||||
|
import 'package:appflowy/plugins/database/calendar/presentation/calendar_event_editor.dart';
|
||||||
import 'package:appflowy_backend/protobuf/flowy-database2/setting_entities.pbenum.dart';
|
import 'package:appflowy_backend/protobuf/flowy-database2/setting_entities.pbenum.dart';
|
||||||
import 'package:appflowy_backend/protobuf/flowy-folder/view.pbenum.dart';
|
import 'package:appflowy_backend/protobuf/flowy-folder/view.pbenum.dart';
|
||||||
|
import 'package:flowy_infra_ui/style_widget/icon_button.dart';
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
import 'package:integration_test/integration_test.dart';
|
import 'package:integration_test/integration_test.dart';
|
||||||
|
|
||||||
@ -147,6 +149,49 @@ void main() {
|
|||||||
tester.assertNumberOfEventsOnSpecificDay(1, DateTime.now());
|
tester.assertNumberOfEventsOnSpecificDay(1, DateTime.now());
|
||||||
});
|
});
|
||||||
|
|
||||||
|
testWidgets('create and duplicate calendar event', (tester) async {
|
||||||
|
const customTitle = "EventTitleCustom";
|
||||||
|
|
||||||
|
await tester.initializeAppFlowy();
|
||||||
|
await tester.tapGoButton();
|
||||||
|
|
||||||
|
// Create the calendar view
|
||||||
|
await tester.createNewPageWithNameUnderParent(
|
||||||
|
layout: ViewLayoutPB.Calendar,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Scroll until today's date cell is visible
|
||||||
|
await tester.scrollToToday();
|
||||||
|
|
||||||
|
// Hover over today's calendar cell
|
||||||
|
await tester.hoverOnTodayCalendarCell(
|
||||||
|
// Tap on create new event button
|
||||||
|
onHover: () async => tester.tapAddCalendarEventButton(),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Make sure that the event editor popup is shown
|
||||||
|
tester.assertEventEditorOpen();
|
||||||
|
|
||||||
|
tester.assertNumberOfEventsInCalendar(1);
|
||||||
|
|
||||||
|
// Change the title of the event
|
||||||
|
await tester.editEventTitle(customTitle);
|
||||||
|
|
||||||
|
// Duplicate event
|
||||||
|
final duplicateBtnFinder = find
|
||||||
|
.descendant(
|
||||||
|
of: find.byType(CalendarEventEditor),
|
||||||
|
matching: find.byType(
|
||||||
|
FlowyIconButton,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.first;
|
||||||
|
await tester.tap(duplicateBtnFinder);
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
|
tester.assertNumberOfEventsInCalendar(2, title: customTitle);
|
||||||
|
});
|
||||||
|
|
||||||
testWidgets('rescheduling events', (tester) async {
|
testWidgets('rescheduling events', (tester) async {
|
||||||
await tester.initializeAppFlowy();
|
await tester.initializeAppFlowy();
|
||||||
await tester.tapGoButton();
|
await tester.tapGoButton();
|
||||||
|
@ -64,6 +64,20 @@ class CalendarBloc extends Bloc<CalendarEvent, CalendarState> {
|
|||||||
createEvent: (DateTime date) async {
|
createEvent: (DateTime date) async {
|
||||||
await _createEvent(date);
|
await _createEvent(date);
|
||||||
},
|
},
|
||||||
|
duplicateEvent: (String viewId, String rowId) async {
|
||||||
|
final result = await RowBackendService.duplicateRow(viewId, rowId);
|
||||||
|
result.fold(
|
||||||
|
(_) => null,
|
||||||
|
(e) => Log.error('Failed to duplicate event: $e', e),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
deleteEvent: (String viewId, String rowId) async {
|
||||||
|
final result = await RowBackendService.deleteRow(viewId, rowId);
|
||||||
|
result.fold(
|
||||||
|
(_) => null,
|
||||||
|
(e) => Log.error('Failed to delete event: $e', e),
|
||||||
|
);
|
||||||
|
},
|
||||||
newEventPopupDisplayed: () {
|
newEventPopupDisplayed: () {
|
||||||
emit(state.copyWith(editingEvent: null));
|
emit(state.copyWith(editingEvent: null));
|
||||||
},
|
},
|
||||||
@ -407,6 +421,12 @@ class CalendarEvent with _$CalendarEvent {
|
|||||||
|
|
||||||
const factory CalendarEvent.didReceiveDatabaseUpdate(DatabasePB database) =
|
const factory CalendarEvent.didReceiveDatabaseUpdate(DatabasePB database) =
|
||||||
_ReceiveDatabaseUpdate;
|
_ReceiveDatabaseUpdate;
|
||||||
|
|
||||||
|
const factory CalendarEvent.duplicateEvent(String viewId, String rowId) =
|
||||||
|
_DuplicateEvent;
|
||||||
|
|
||||||
|
const factory CalendarEvent.deleteEvent(String viewId, String rowId) =
|
||||||
|
_DeleteEvent;
|
||||||
}
|
}
|
||||||
|
|
||||||
@freezed
|
@freezed
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
import 'package:appflowy/mobile/presentation/database/card/card_detail/mobile_card_detail_screen.dart';
|
import 'package:appflowy/mobile/presentation/database/card/card_detail/mobile_card_detail_screen.dart';
|
||||||
import 'package:appflowy/plugins/database/application/database_controller.dart';
|
import 'package:appflowy/plugins/database/application/database_controller.dart';
|
||||||
import 'package:appflowy/plugins/database/application/row/row_cache.dart';
|
import 'package:appflowy/plugins/database/application/row/row_cache.dart';
|
||||||
@ -9,11 +11,11 @@ import 'package:appflowy_popover/appflowy_popover.dart';
|
|||||||
import 'package:flowy_infra/size.dart';
|
import 'package:flowy_infra/size.dart';
|
||||||
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
||||||
import 'package:flowy_infra_ui/style_widget/hover.dart';
|
import 'package:flowy_infra_ui/style_widget/hover.dart';
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
|
|
||||||
import '../application/calendar_bloc.dart';
|
import '../application/calendar_bloc.dart';
|
||||||
|
|
||||||
import 'calendar_event_editor.dart';
|
import 'calendar_event_editor.dart';
|
||||||
|
|
||||||
class EventCard extends StatefulWidget {
|
class EventCard extends StatefulWidget {
|
||||||
@ -144,15 +146,18 @@ class _EventCardState extends State<EventCard> {
|
|||||||
asBarrier: true,
|
asBarrier: true,
|
||||||
margin: EdgeInsets.zero,
|
margin: EdgeInsets.zero,
|
||||||
offset: const Offset(10.0, 0),
|
offset: const Offset(10.0, 0),
|
||||||
popupBuilder: (BuildContext popoverContext) {
|
popupBuilder: (_) {
|
||||||
final settings = context.watch<CalendarBloc>().state.settings;
|
final settings = context.watch<CalendarBloc>().state.settings;
|
||||||
if (settings == null) {
|
if (settings == null) {
|
||||||
return const SizedBox.shrink();
|
return const SizedBox.shrink();
|
||||||
}
|
}
|
||||||
return CalendarEventEditor(
|
return BlocProvider.value(
|
||||||
databaseController: widget.databaseController,
|
value: context.read<CalendarBloc>(),
|
||||||
rowMeta: widget.event.event.rowMeta,
|
child: CalendarEventEditor(
|
||||||
layoutSettings: settings,
|
databaseController: widget.databaseController,
|
||||||
|
rowMeta: widget.event.event.rowMeta,
|
||||||
|
layoutSettings: settings,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
child: Container(
|
child: Container(
|
||||||
|
@ -1,25 +1,25 @@
|
|||||||
|
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/database/application/cell/bloc/text_cell_bloc.dart';
|
||||||
import 'package:appflowy/plugins/database/application/cell/cell_controller.dart';
|
import 'package:appflowy/plugins/database/application/cell/cell_controller.dart';
|
||||||
import 'package:appflowy/plugins/database/application/database_controller.dart';
|
import 'package:appflowy/plugins/database/application/database_controller.dart';
|
||||||
import 'package:appflowy/plugins/database/application/field/field_controller.dart';
|
import 'package:appflowy/plugins/database/application/field/field_controller.dart';
|
||||||
import 'package:appflowy/plugins/database/application/row/row_controller.dart';
|
import 'package:appflowy/plugins/database/application/row/row_controller.dart';
|
||||||
import 'package:appflowy/plugins/database/application/row/row_service.dart';
|
import 'package:appflowy/plugins/database/calendar/application/calendar_bloc.dart';
|
||||||
import 'package:appflowy/plugins/database/calendar/application/calendar_event_editor_bloc.dart';
|
import 'package:appflowy/plugins/database/calendar/application/calendar_event_editor_bloc.dart';
|
||||||
|
import 'package:appflowy/plugins/database/widgets/cell/editable_cell_builder.dart';
|
||||||
import 'package:appflowy/plugins/database/widgets/cell/editable_cell_skeleton/text.dart';
|
import 'package:appflowy/plugins/database/widgets/cell/editable_cell_skeleton/text.dart';
|
||||||
import 'package:appflowy/plugins/database/widgets/row/accessory/cell_accessory.dart';
|
import 'package:appflowy/plugins/database/widgets/row/accessory/cell_accessory.dart';
|
||||||
import 'package:appflowy/plugins/database/widgets/cell/editable_cell_builder.dart';
|
|
||||||
import 'package:appflowy/plugins/database/widgets/row/cells/cell_container.dart';
|
import 'package:appflowy/plugins/database/widgets/row/cells/cell_container.dart';
|
||||||
import 'package:appflowy/plugins/database/application/cell/bloc/text_cell_bloc.dart';
|
|
||||||
import 'package:appflowy/plugins/database/widgets/row/row_detail.dart';
|
import 'package:appflowy/plugins/database/widgets/row/row_detail.dart';
|
||||||
import 'package:appflowy/util/field_type_extension.dart';
|
import 'package:appflowy/util/field_type_extension.dart';
|
||||||
import 'package:appflowy_backend/log.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:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
|
||||||
class CalendarEventEditor extends StatelessWidget {
|
class CalendarEventEditor extends StatelessWidget {
|
||||||
@ -86,17 +86,28 @@ class EventEditorControls extends StatelessWidget {
|
|||||||
child: Row(
|
child: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.end,
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
children: [
|
children: [
|
||||||
|
FlowyIconButton(
|
||||||
|
width: 20,
|
||||||
|
icon: const FlowySvg(FlowySvgs.m_duplicate_s),
|
||||||
|
iconColorOnHover: Theme.of(context).colorScheme.onSecondary,
|
||||||
|
onPressed: () => context.read<CalendarBloc>().add(
|
||||||
|
CalendarEvent.duplicateEvent(
|
||||||
|
rowController.viewId,
|
||||||
|
rowController.rowId,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const HSpace(8.0),
|
||||||
FlowyIconButton(
|
FlowyIconButton(
|
||||||
width: 20,
|
width: 20,
|
||||||
icon: const FlowySvg(FlowySvgs.delete_s),
|
icon: const FlowySvg(FlowySvgs.delete_s),
|
||||||
iconColorOnHover: Theme.of(context).colorScheme.onSecondary,
|
iconColorOnHover: Theme.of(context).colorScheme.onSecondary,
|
||||||
onPressed: () async {
|
onPressed: () => context.read<CalendarBloc>().add(
|
||||||
final result = await RowBackendService.deleteRow(
|
CalendarEvent.deleteEvent(
|
||||||
rowController.viewId,
|
rowController.viewId,
|
||||||
rowController.rowId,
|
rowController.rowId,
|
||||||
);
|
),
|
||||||
result.fold((l) => null, (err) => Log.error(err));
|
),
|
||||||
},
|
|
||||||
),
|
),
|
||||||
const HSpace(8.0),
|
const HSpace(8.0),
|
||||||
FlowyIconButton(
|
FlowyIconButton(
|
||||||
@ -107,12 +118,10 @@ class EventEditorControls extends StatelessWidget {
|
|||||||
PopoverContainer.of(context).close();
|
PopoverContainer.of(context).close();
|
||||||
FlowyOverlay.show(
|
FlowyOverlay.show(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (BuildContext context) {
|
builder: (_) => RowDetailPage(
|
||||||
return RowDetailPage(
|
databaseController: databaseController,
|
||||||
databaseController: databaseController,
|
rowController: rowController,
|
||||||
rowController: rowController,
|
),
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
@ -81,9 +81,9 @@ class _AppFlowyEditorPageState extends State<AppFlowyEditorPage> {
|
|||||||
InlinePageReferenceService(
|
InlinePageReferenceService(
|
||||||
currentViewId: documentBloc.view.id,
|
currentViewId: documentBloc.view.id,
|
||||||
limitResults: 5,
|
limitResults: 5,
|
||||||
).inlinePageReferenceDelegate,
|
),
|
||||||
DateReferenceService(context).dateReferenceDelegate,
|
DateReferenceService(context),
|
||||||
ReminderReferenceService(context).reminderReferenceDelegate,
|
ReminderReferenceService(context),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -32,13 +32,13 @@ Future<void> showLinkToPageMenu(
|
|||||||
customTitle: titleFromPageType(pageType),
|
customTitle: titleFromPageType(pageType),
|
||||||
insertPage: pageType != ViewLayoutPB.Document,
|
insertPage: pageType != ViewLayoutPB.Document,
|
||||||
limitResults: 15,
|
limitResults: 15,
|
||||||
).inlinePageReferenceDelegate,
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
final List<InlineActionsResult> initialResults = [];
|
final List<InlineActionsResult> initialResults = [];
|
||||||
for (final handler in service.handlers) {
|
for (final handler in service.handlers) {
|
||||||
final group = await handler();
|
final group = await handler.search(null);
|
||||||
|
|
||||||
if (group.results.isNotEmpty) {
|
if (group.results.isNotEmpty) {
|
||||||
initialResults.add(group);
|
initialResults.add(group);
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
import 'package:appflowy/plugins/inline_actions/handlers/inline_page_reference.dart';
|
import 'package:appflowy/plugins/inline_actions/handlers/inline_page_reference.dart';
|
||||||
import 'package:appflowy/plugins/inline_actions/inline_actions_menu.dart';
|
import 'package:appflowy/plugins/inline_actions/inline_actions_menu.dart';
|
||||||
import 'package:appflowy/plugins/inline_actions/inline_actions_result.dart';
|
import 'package:appflowy/plugins/inline_actions/inline_actions_result.dart';
|
||||||
import 'package:appflowy/plugins/inline_actions/inline_actions_service.dart';
|
import 'package:appflowy/plugins/inline_actions/inline_actions_service.dart';
|
||||||
import 'package:appflowy_editor/appflowy_editor.dart';
|
import 'package:appflowy_editor/appflowy_editor.dart';
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
const _bracketChar = '[';
|
const _bracketChar = '[';
|
||||||
const _plusChar = '+';
|
const _plusChar = '+';
|
||||||
@ -89,7 +90,7 @@ Future<bool> inlinePageReferenceCommandHandler(
|
|||||||
InlinePageReferenceService(
|
InlinePageReferenceService(
|
||||||
currentViewId: currentViewId,
|
currentViewId: currentViewId,
|
||||||
limitResults: 10,
|
limitResults: 10,
|
||||||
).inlinePageReferenceDelegate,
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -97,7 +98,7 @@ Future<bool> inlinePageReferenceCommandHandler(
|
|||||||
|
|
||||||
final List<InlineActionsResult> initialResults = [];
|
final List<InlineActionsResult> initialResults = [];
|
||||||
for (final handler in service.handlers) {
|
for (final handler in service.handlers) {
|
||||||
final group = await handler();
|
final group = await handler.search(null);
|
||||||
|
|
||||||
if (group.results.isNotEmpty) {
|
if (group.results.isNotEmpty) {
|
||||||
initialResults.add(group);
|
initialResults.add(group);
|
||||||
|
@ -1,17 +1,19 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
import 'package:appflowy/date/date_service.dart';
|
import 'package:appflowy/date/date_service.dart';
|
||||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||||
import 'package:appflowy/plugins/document/presentation/editor_plugins/base/string_extension.dart';
|
import 'package:appflowy/plugins/document/presentation/editor_plugins/base/string_extension.dart';
|
||||||
import 'package:appflowy/plugins/document/presentation/editor_plugins/mention/mention_block.dart';
|
import 'package:appflowy/plugins/document/presentation/editor_plugins/mention/mention_block.dart';
|
||||||
import 'package:appflowy/plugins/inline_actions/inline_actions_result.dart';
|
import 'package:appflowy/plugins/inline_actions/inline_actions_result.dart';
|
||||||
|
import 'package:appflowy/plugins/inline_actions/service_handler.dart';
|
||||||
import 'package:appflowy_editor/appflowy_editor.dart';
|
import 'package:appflowy_editor/appflowy_editor.dart';
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
final _keywords = [
|
final _keywords = [
|
||||||
LocaleKeys.inlineActions_date.tr().toLowerCase(),
|
LocaleKeys.inlineActions_date.tr().toLowerCase(),
|
||||||
];
|
];
|
||||||
|
|
||||||
class DateReferenceService {
|
class DateReferenceService extends InlineActionsDelegate {
|
||||||
DateReferenceService(this.context) {
|
DateReferenceService(this.context) {
|
||||||
// Initialize locale
|
// Initialize locale
|
||||||
_locale = context.locale.toLanguageTag();
|
_locale = context.locale.toLanguageTag();
|
||||||
@ -27,7 +29,8 @@ class DateReferenceService {
|
|||||||
|
|
||||||
List<InlineActionsMenuItem> options = [];
|
List<InlineActionsMenuItem> options = [];
|
||||||
|
|
||||||
Future<InlineActionsResult> dateReferenceDelegate([
|
@override
|
||||||
|
Future<InlineActionsResult> search([
|
||||||
String? search,
|
String? search,
|
||||||
]) async {
|
]) async {
|
||||||
// Checks if Locale has changed since last
|
// Checks if Locale has changed since last
|
||||||
|
@ -9,16 +9,23 @@ import 'package:appflowy/plugins/document/presentation/editor_plugins/mention/me
|
|||||||
import 'package:appflowy/plugins/document/presentation/editor_plugins/mention/mention_page_block.dart';
|
import 'package:appflowy/plugins/document/presentation/editor_plugins/mention/mention_page_block.dart';
|
||||||
import 'package:appflowy/plugins/inline_actions/inline_actions_menu.dart';
|
import 'package:appflowy/plugins/inline_actions/inline_actions_menu.dart';
|
||||||
import 'package:appflowy/plugins/inline_actions/inline_actions_result.dart';
|
import 'package:appflowy/plugins/inline_actions/inline_actions_result.dart';
|
||||||
|
import 'package:appflowy/plugins/inline_actions/service_handler.dart';
|
||||||
|
import 'package:appflowy/startup/startup.dart';
|
||||||
|
import 'package:appflowy/user/application/auth/auth_service.dart';
|
||||||
import 'package:appflowy/workspace/application/view/view_ext.dart';
|
import 'package:appflowy/workspace/application/view/view_ext.dart';
|
||||||
import 'package:appflowy/workspace/application/view/view_service.dart';
|
import 'package:appflowy/workspace/application/view/view_service.dart';
|
||||||
|
import 'package:appflowy/workspace/application/workspace/workspace_listener.dart';
|
||||||
|
import 'package:appflowy_backend/dispatch/dispatch.dart';
|
||||||
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
|
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
|
||||||
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
|
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
|
||||||
|
import 'package:appflowy_backend/protobuf/flowy-folder/workspace.pb.dart';
|
||||||
|
import 'package:appflowy_backend/protobuf/flowy-user/user_profile.pb.dart';
|
||||||
import 'package:appflowy_editor/appflowy_editor.dart';
|
import 'package:appflowy_editor/appflowy_editor.dart';
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:flowy_infra_ui/widget/dialog/styled_dialogs.dart';
|
import 'package:flowy_infra_ui/widget/dialog/styled_dialogs.dart';
|
||||||
import 'package:flowy_infra_ui/widget/error_page.dart';
|
import 'package:flowy_infra_ui/widget/error_page.dart';
|
||||||
|
|
||||||
class InlinePageReferenceService {
|
class InlinePageReferenceService extends InlineActionsDelegate {
|
||||||
InlinePageReferenceService({
|
InlinePageReferenceService({
|
||||||
required this.currentViewId,
|
required this.currentViewId,
|
||||||
this.viewLayout,
|
this.viewLayout,
|
||||||
@ -51,12 +58,67 @@ class InlinePageReferenceService {
|
|||||||
List<InlineActionsMenuItem> _items = [];
|
List<InlineActionsMenuItem> _items = [];
|
||||||
List<InlineActionsMenuItem> _filtered = [];
|
List<InlineActionsMenuItem> _filtered = [];
|
||||||
|
|
||||||
|
UserProfilePB? _user;
|
||||||
|
String? _workspaceId;
|
||||||
|
WorkspaceListener? _listener;
|
||||||
|
|
||||||
Future<void> init() async {
|
Future<void> init() async {
|
||||||
_items = await _generatePageItems(currentViewId, viewLayout);
|
_items = await _generatePageItems(currentViewId, viewLayout);
|
||||||
_filtered = limitResults > 0 ? _items.take(limitResults).toList() : _items;
|
_filtered = limitResults > 0 ? _items.take(limitResults).toList() : _items;
|
||||||
|
|
||||||
|
await _initWorkspaceListener();
|
||||||
|
|
||||||
_initCompleter.complete();
|
_initCompleter.complete();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> _initWorkspaceListener() async {
|
||||||
|
final snapshot = await Future.wait([
|
||||||
|
FolderEventGetCurrentWorkspaceSetting().send(),
|
||||||
|
getIt<AuthService>().getUser(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
final (workspaceSettings, userProfile) = (snapshot.first, snapshot.last);
|
||||||
|
_workspaceId = workspaceSettings.fold(
|
||||||
|
(s) => (s as WorkspaceSettingPB).workspaceId,
|
||||||
|
(e) => null,
|
||||||
|
);
|
||||||
|
|
||||||
|
_user = userProfile.fold((s) => s as UserProfilePB, (e) => null);
|
||||||
|
|
||||||
|
if (_user != null && _workspaceId != null) {
|
||||||
|
_listener = WorkspaceListener(
|
||||||
|
user: _user!,
|
||||||
|
workspaceId: _workspaceId!,
|
||||||
|
);
|
||||||
|
_listener!.start(
|
||||||
|
appsChanged: (_) async {
|
||||||
|
_items = await _generatePageItems(currentViewId, viewLayout);
|
||||||
|
_filtered =
|
||||||
|
limitResults > 0 ? _items.take(limitResults).toList() : _items;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<InlineActionsResult> search([
|
||||||
|
String? search,
|
||||||
|
]) async {
|
||||||
|
_filtered = await _filterItems(search);
|
||||||
|
|
||||||
|
return InlineActionsResult(
|
||||||
|
title: customTitle?.isNotEmpty == true
|
||||||
|
? customTitle!
|
||||||
|
: LocaleKeys.inlineActions_pageReference.tr(),
|
||||||
|
results: _filtered,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> dispose() async {
|
||||||
|
await _listener?.stop();
|
||||||
|
}
|
||||||
|
|
||||||
Future<List<InlineActionsMenuItem>> _filterItems(String? search) async {
|
Future<List<InlineActionsMenuItem>> _filterItems(String? search) async {
|
||||||
await _initCompleter.future;
|
await _initCompleter.future;
|
||||||
|
|
||||||
@ -76,19 +138,6 @@ class InlinePageReferenceService {
|
|||||||
: items.toList();
|
: items.toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<InlineActionsResult> inlinePageReferenceDelegate([
|
|
||||||
String? search,
|
|
||||||
]) async {
|
|
||||||
_filtered = await _filterItems(search);
|
|
||||||
|
|
||||||
return InlineActionsResult(
|
|
||||||
title: customTitle?.isNotEmpty == true
|
|
||||||
? customTitle!
|
|
||||||
: LocaleKeys.inlineActions_pageReference.tr(),
|
|
||||||
results: _filtered,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<List<InlineActionsMenuItem>> _generatePageItems(
|
Future<List<InlineActionsMenuItem>> _generatePageItems(
|
||||||
String currentViewId,
|
String currentViewId,
|
||||||
ViewLayoutPB? viewLayout,
|
ViewLayoutPB? viewLayout,
|
||||||
|
@ -1,9 +1,12 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
import 'package:appflowy/date/date_service.dart';
|
import 'package:appflowy/date/date_service.dart';
|
||||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||||
import 'package:appflowy/plugins/document/application/doc_bloc.dart';
|
import 'package:appflowy/plugins/document/application/doc_bloc.dart';
|
||||||
import 'package:appflowy/plugins/document/presentation/editor_plugins/base/string_extension.dart';
|
import 'package:appflowy/plugins/document/presentation/editor_plugins/base/string_extension.dart';
|
||||||
import 'package:appflowy/plugins/document/presentation/editor_plugins/mention/mention_block.dart';
|
import 'package:appflowy/plugins/document/presentation/editor_plugins/mention/mention_block.dart';
|
||||||
import 'package:appflowy/plugins/inline_actions/inline_actions_result.dart';
|
import 'package:appflowy/plugins/inline_actions/inline_actions_result.dart';
|
||||||
|
import 'package:appflowy/plugins/inline_actions/service_handler.dart';
|
||||||
import 'package:appflowy/user/application/reminder/reminder_bloc.dart';
|
import 'package:appflowy/user/application/reminder/reminder_bloc.dart';
|
||||||
import 'package:appflowy/user/application/reminder/reminder_extension.dart';
|
import 'package:appflowy/user/application/reminder/reminder_extension.dart';
|
||||||
import 'package:appflowy/workspace/presentation/widgets/date_picker/widgets/reminder_selector.dart';
|
import 'package:appflowy/workspace/presentation/widgets/date_picker/widgets/reminder_selector.dart';
|
||||||
@ -11,7 +14,6 @@ import 'package:appflowy_backend/protobuf/flowy-user/reminder.pb.dart';
|
|||||||
import 'package:appflowy_editor/appflowy_editor.dart';
|
import 'package:appflowy_editor/appflowy_editor.dart';
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:fixnum/fixnum.dart';
|
import 'package:fixnum/fixnum.dart';
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:nanoid/nanoid.dart';
|
import 'package:nanoid/nanoid.dart';
|
||||||
|
|
||||||
@ -20,7 +22,7 @@ final _keywords = [
|
|||||||
LocaleKeys.inlineActions_reminder_shortKeyword.tr().toLowerCase(),
|
LocaleKeys.inlineActions_reminder_shortKeyword.tr().toLowerCase(),
|
||||||
];
|
];
|
||||||
|
|
||||||
class ReminderReferenceService {
|
class ReminderReferenceService extends InlineActionsDelegate {
|
||||||
ReminderReferenceService(this.context) {
|
ReminderReferenceService(this.context) {
|
||||||
// Initialize locale
|
// Initialize locale
|
||||||
_locale = context.locale.toLanguageTag();
|
_locale = context.locale.toLanguageTag();
|
||||||
@ -36,7 +38,8 @@ class ReminderReferenceService {
|
|||||||
|
|
||||||
List<InlineActionsMenuItem> options = [];
|
List<InlineActionsMenuItem> options = [];
|
||||||
|
|
||||||
Future<InlineActionsResult> reminderReferenceDelegate([
|
@override
|
||||||
|
Future<InlineActionsResult> search([
|
||||||
String? search,
|
String? search,
|
||||||
]) async {
|
]) async {
|
||||||
// Checks if Locale has changed since last
|
// Checks if Locale has changed since last
|
||||||
|
@ -41,7 +41,7 @@ Future<bool> inlineActionsCommandHandler(
|
|||||||
|
|
||||||
final List<InlineActionsResult> initialResults = [];
|
final List<InlineActionsResult> initialResults = [];
|
||||||
for (final handler in service.handlers) {
|
for (final handler in service.handlers) {
|
||||||
final group = await handler();
|
final group = await handler.search(null);
|
||||||
|
|
||||||
if (group.results.isNotEmpty) {
|
if (group.results.isNotEmpty) {
|
||||||
initialResults.add(group);
|
initialResults.add(group);
|
||||||
|
@ -1,9 +1,6 @@
|
|||||||
import 'package:appflowy/plugins/inline_actions/inline_actions_result.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
typedef InlineActionsDelegate = Future<InlineActionsResult> Function([
|
import 'package:appflowy/plugins/inline_actions/service_handler.dart';
|
||||||
String? search,
|
|
||||||
]);
|
|
||||||
|
|
||||||
abstract class _InlineActionsProvider {
|
abstract class _InlineActionsProvider {
|
||||||
void dispose();
|
void dispose();
|
||||||
@ -26,7 +23,10 @@ class InlineActionsService extends _InlineActionsProvider {
|
|||||||
/// we set the [BuildContext] to null.
|
/// we set the [BuildContext] to null.
|
||||||
///
|
///
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
Future<void> dispose() async {
|
||||||
|
for (final handler in handlers) {
|
||||||
|
await handler.dispose();
|
||||||
|
}
|
||||||
context = null;
|
context = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,7 @@
|
|||||||
|
import 'package:appflowy/plugins/inline_actions/inline_actions_result.dart';
|
||||||
|
|
||||||
|
abstract class InlineActionsDelegate {
|
||||||
|
Future<InlineActionsResult> search(String? search);
|
||||||
|
|
||||||
|
Future<void> dispose() async {}
|
||||||
|
}
|
@ -1,3 +1,6 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
|
||||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||||
import 'package:appflowy/plugins/inline_actions/inline_actions_menu.dart';
|
import 'package:appflowy/plugins/inline_actions/inline_actions_menu.dart';
|
||||||
import 'package:appflowy/plugins/inline_actions/inline_actions_result.dart';
|
import 'package:appflowy/plugins/inline_actions/inline_actions_result.dart';
|
||||||
@ -7,8 +10,6 @@ import 'package:appflowy_editor/appflowy_editor.dart';
|
|||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:flowy_infra_ui/style_widget/text.dart';
|
import 'package:flowy_infra_ui/style_widget/text.dart';
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter/services.dart';
|
|
||||||
|
|
||||||
/// All heights are in physical pixels
|
/// All heights are in physical pixels
|
||||||
const double _groupTextHeight = 14; // 12 height + 2 bottom spacing
|
const double _groupTextHeight = 14; // 12 height + 2 bottom spacing
|
||||||
@ -91,7 +92,7 @@ class _InlineActionsHandlerState extends State<InlineActionsHandler> {
|
|||||||
Future<void> _doSearch() async {
|
Future<void> _doSearch() async {
|
||||||
final List<InlineActionsResult> newResults = [];
|
final List<InlineActionsResult> newResults = [];
|
||||||
for (final handler in widget.service.handlers) {
|
for (final handler in widget.service.handlers) {
|
||||||
final group = await handler.call(_search);
|
final group = await handler.search(_search);
|
||||||
|
|
||||||
if (group.results.isNotEmpty) {
|
if (group.results.isNotEmpty) {
|
||||||
newResults.add(group);
|
newResults.add(group);
|
||||||
@ -208,6 +209,10 @@ class _InlineActionsHandlerState extends State<InlineActionsHandler> {
|
|||||||
results[groupIndex].results[handlerIndex];
|
results[groupIndex].results[handlerIndex];
|
||||||
|
|
||||||
KeyEventResult onKeyEvent(focus, KeyEvent event) {
|
KeyEventResult onKeyEvent(focus, KeyEvent event) {
|
||||||
|
if (event is! KeyDownEvent) {
|
||||||
|
return KeyEventResult.ignored;
|
||||||
|
}
|
||||||
|
|
||||||
const moveKeys = [
|
const moveKeys = [
|
||||||
LogicalKeyboardKey.arrowUp,
|
LogicalKeyboardKey.arrowUp,
|
||||||
LogicalKeyboardKey.arrowDown,
|
LogicalKeyboardKey.arrowDown,
|
||||||
|
@ -1,3 +1,6 @@
|
|||||||
|
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/workspace/application/menu/menu_bloc.dart';
|
import 'package:appflowy/workspace/application/menu/menu_bloc.dart';
|
||||||
@ -8,17 +11,17 @@ import 'package:appflowy/workspace/presentation/home/menu/view/view_item.dart';
|
|||||||
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
|
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
import 'package:flowy_infra_ui/flowy_infra_ui.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';
|
||||||
|
|
||||||
class PersonalFolder extends StatelessWidget {
|
class PersonalFolder extends StatelessWidget {
|
||||||
const PersonalFolder({
|
const PersonalFolder({
|
||||||
super.key,
|
super.key,
|
||||||
required this.views,
|
required this.views,
|
||||||
|
this.isHoverEnabled = true,
|
||||||
});
|
});
|
||||||
|
|
||||||
final List<ViewPB> views;
|
final List<ViewPB> views;
|
||||||
|
final bool isHoverEnabled;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@ -60,6 +63,7 @@ class PersonalFolder extends StatelessWidget {
|
|||||||
},
|
},
|
||||||
onTertiarySelected: (view) =>
|
onTertiarySelected: (view) =>
|
||||||
context.read<TabsBloc>().openTab(view),
|
context.read<TabsBloc>().openTab(view),
|
||||||
|
isHoverEnabled: isHoverEnabled,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
@ -1,3 +1,7 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:flutter/material.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/favorite/favorite_bloc.dart';
|
import 'package:appflowy/workspace/application/favorite/favorite_bloc.dart';
|
||||||
@ -18,7 +22,6 @@ import 'package:appflowy_backend/protobuf/flowy-user/protobuf.dart'
|
|||||||
show UserProfilePB;
|
show UserProfilePB;
|
||||||
import 'package:appflowy_editor/appflowy_editor.dart';
|
import 'package:appflowy_editor/appflowy_editor.dart';
|
||||||
import 'package:flowy_infra_ui/widget/spacing.dart';
|
import 'package:flowy_infra_ui/widget/spacing.dart';
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
|
||||||
/// Home Sidebar is the left side bar of the home page.
|
/// Home Sidebar is the left side bar of the home page.
|
||||||
@ -28,7 +31,7 @@ import 'package:flutter_bloc/flutter_bloc.dart';
|
|||||||
/// - settings
|
/// - settings
|
||||||
/// - scrollable document list
|
/// - scrollable document list
|
||||||
/// - trash
|
/// - trash
|
||||||
class HomeSideBar extends StatelessWidget {
|
class HomeSideBar extends StatefulWidget {
|
||||||
const HomeSideBar({
|
const HomeSideBar({
|
||||||
super.key,
|
super.key,
|
||||||
required this.userProfile,
|
required this.userProfile,
|
||||||
@ -39,6 +42,43 @@ class HomeSideBar extends StatelessWidget {
|
|||||||
|
|
||||||
final WorkspaceSettingPB workspaceSetting;
|
final WorkspaceSettingPB workspaceSetting;
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<HomeSideBar> createState() => _HomeSideBarState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _HomeSideBarState extends State<HomeSideBar> {
|
||||||
|
final _scrollController = ScrollController();
|
||||||
|
Timer? _srollDebounce;
|
||||||
|
bool isScrolling = false;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_scrollController.addListener(_onScrollChanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _onScrollChanged() {
|
||||||
|
setState(() => isScrolling = true);
|
||||||
|
|
||||||
|
_srollDebounce?.cancel();
|
||||||
|
_srollDebounce =
|
||||||
|
Timer(const Duration(milliseconds: 300), _setScrollStopped);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _setScrollStopped() {
|
||||||
|
if (mounted) {
|
||||||
|
setState(() => isScrolling = false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_srollDebounce?.cancel();
|
||||||
|
_scrollController.removeListener(_onScrollChanged);
|
||||||
|
_scrollController.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return MultiBlocProvider(
|
return MultiBlocProvider(
|
||||||
@ -48,8 +88,8 @@ class HomeSideBar extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
BlocProvider(
|
BlocProvider(
|
||||||
create: (_) => MenuBloc(
|
create: (_) => MenuBloc(
|
||||||
user: userProfile,
|
user: widget.userProfile,
|
||||||
workspaceId: workspaceSetting.workspaceId,
|
workspaceId: widget.workspaceSetting.workspaceId,
|
||||||
)..add(const MenuEvent.initial()),
|
)..add(const MenuEvent.initial()),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@ -108,8 +148,14 @@ class HomeSideBar extends StatelessWidget {
|
|||||||
Padding(
|
Padding(
|
||||||
padding: menuHorizontalInset,
|
padding: menuHorizontalInset,
|
||||||
child: FeatureFlag.collaborativeWorkspace.isOn
|
child: FeatureFlag.collaborativeWorkspace.isOn
|
||||||
? SidebarWorkspace(userProfile: userProfile, views: views)
|
? SidebarWorkspace(
|
||||||
: SidebarUser(userProfile: userProfile, views: views),
|
userProfile: widget.userProfile,
|
||||||
|
views: views,
|
||||||
|
)
|
||||||
|
: SidebarUser(
|
||||||
|
userProfile: widget.userProfile,
|
||||||
|
views: views,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
const VSpace(20),
|
const VSpace(20),
|
||||||
@ -118,9 +164,12 @@ class HomeSideBar extends StatelessWidget {
|
|||||||
child: Padding(
|
child: Padding(
|
||||||
padding: menuHorizontalInset,
|
padding: menuHorizontalInset,
|
||||||
child: SingleChildScrollView(
|
child: SingleChildScrollView(
|
||||||
|
controller: _scrollController,
|
||||||
|
physics: const ClampingScrollPhysics(),
|
||||||
child: SidebarFolder(
|
child: SidebarFolder(
|
||||||
views: views,
|
views: views,
|
||||||
favoriteViews: favoriteViews,
|
favoriteViews: favoriteViews,
|
||||||
|
isHoverEnabled: !isScrolling,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -1,20 +1,23 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
import 'package:appflowy/startup/startup.dart';
|
import 'package:appflowy/startup/startup.dart';
|
||||||
import 'package:appflowy/workspace/presentation/home/menu/menu_shared_state.dart';
|
import 'package:appflowy/workspace/presentation/home/menu/menu_shared_state.dart';
|
||||||
import 'package:appflowy/workspace/presentation/home/menu/sidebar/folder/favorite_folder.dart';
|
import 'package:appflowy/workspace/presentation/home/menu/sidebar/folder/favorite_folder.dart';
|
||||||
import 'package:appflowy/workspace/presentation/home/menu/sidebar/folder/personal_folder.dart';
|
import 'package:appflowy/workspace/presentation/home/menu/sidebar/folder/personal_folder.dart';
|
||||||
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
|
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
|
||||||
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
class SidebarFolder extends StatelessWidget {
|
class SidebarFolder extends StatelessWidget {
|
||||||
const SidebarFolder({
|
const SidebarFolder({
|
||||||
super.key,
|
super.key,
|
||||||
required this.views,
|
required this.views,
|
||||||
required this.favoriteViews,
|
required this.favoriteViews,
|
||||||
|
this.isHoverEnabled = true,
|
||||||
});
|
});
|
||||||
|
|
||||||
final List<ViewPB> views;
|
final List<ViewPB> views;
|
||||||
final List<ViewPB> favoriteViews;
|
final List<ViewPB> favoriteViews;
|
||||||
|
final bool isHoverEnabled;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@ -38,7 +41,7 @@ class SidebarFolder extends StatelessWidget {
|
|||||||
const VSpace(10),
|
const VSpace(10),
|
||||||
],
|
],
|
||||||
// personal
|
// personal
|
||||||
PersonalFolder(views: views),
|
PersonalFolder(views: views, isHoverEnabled: isHoverEnabled),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
@ -42,6 +42,7 @@ class ViewItem extends StatelessWidget {
|
|||||||
this.isDraggable = true,
|
this.isDraggable = true,
|
||||||
required this.isFeedback,
|
required this.isFeedback,
|
||||||
this.height = 28.0,
|
this.height = 28.0,
|
||||||
|
this.isHoverEnabled = true,
|
||||||
});
|
});
|
||||||
|
|
||||||
final ViewPB view;
|
final ViewPB view;
|
||||||
@ -75,6 +76,8 @@ class ViewItem extends StatelessWidget {
|
|||||||
|
|
||||||
final double height;
|
final double height;
|
||||||
|
|
||||||
|
final bool isHoverEnabled;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return BlocProvider(
|
return BlocProvider(
|
||||||
@ -101,6 +104,7 @@ class ViewItem extends StatelessWidget {
|
|||||||
isDraggable: isDraggable,
|
isDraggable: isDraggable,
|
||||||
isFeedback: isFeedback,
|
isFeedback: isFeedback,
|
||||||
height: height,
|
height: height,
|
||||||
|
isHoverEnabled: isHoverEnabled,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@ -127,6 +131,7 @@ class InnerViewItem extends StatelessWidget {
|
|||||||
this.isFirstChild = false,
|
this.isFirstChild = false,
|
||||||
required this.isFeedback,
|
required this.isFeedback,
|
||||||
required this.height,
|
required this.height,
|
||||||
|
this.isHoverEnabled = true,
|
||||||
});
|
});
|
||||||
|
|
||||||
final ViewPB view;
|
final ViewPB view;
|
||||||
@ -148,6 +153,8 @@ class InnerViewItem extends StatelessWidget {
|
|||||||
final ViewItemOnSelected? onTertiarySelected;
|
final ViewItemOnSelected? onTertiarySelected;
|
||||||
final double height;
|
final double height;
|
||||||
|
|
||||||
|
final bool isHoverEnabled;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
Widget child = SingleInnerViewItem(
|
Widget child = SingleInnerViewItem(
|
||||||
@ -264,6 +271,7 @@ class SingleInnerViewItem extends StatefulWidget {
|
|||||||
this.onTertiarySelected,
|
this.onTertiarySelected,
|
||||||
required this.isFeedback,
|
required this.isFeedback,
|
||||||
required this.height,
|
required this.height,
|
||||||
|
this.isHoverEnabled = true,
|
||||||
});
|
});
|
||||||
|
|
||||||
final ViewPB view;
|
final ViewPB view;
|
||||||
@ -282,6 +290,8 @@ class SingleInnerViewItem extends StatefulWidget {
|
|||||||
final FolderCategoryType categoryType;
|
final FolderCategoryType categoryType;
|
||||||
final double height;
|
final double height;
|
||||||
|
|
||||||
|
final bool isHoverEnabled;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<SingleInnerViewItem> createState() => _SingleInnerViewItemState();
|
State<SingleInnerViewItem> createState() => _SingleInnerViewItemState();
|
||||||
}
|
}
|
||||||
@ -292,13 +302,16 @@ class _SingleInnerViewItemState extends State<SingleInnerViewItem> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
if (widget.isFeedback) {
|
|
||||||
return _buildViewItem(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
final isSelected =
|
final isSelected =
|
||||||
getIt<MenuSharedState>().latestOpenView?.id == widget.view.id;
|
getIt<MenuSharedState>().latestOpenView?.id == widget.view.id;
|
||||||
|
|
||||||
|
if (widget.isFeedback || !widget.isHoverEnabled) {
|
||||||
|
return _buildViewItem(
|
||||||
|
false,
|
||||||
|
!widget.isHoverEnabled ? isSelected : false,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return FlowyHover(
|
return FlowyHover(
|
||||||
style: HoverStyle(
|
style: HoverStyle(
|
||||||
hoverColor: Theme.of(context).colorScheme.secondary,
|
hoverColor: Theme.of(context).colorScheme.secondary,
|
||||||
|
@ -27,7 +27,8 @@ use crate::entities::{
|
|||||||
UpdateViewParams, ViewPB, WorkspacePB, WorkspaceSettingPB,
|
UpdateViewParams, ViewPB, WorkspacePB, WorkspaceSettingPB,
|
||||||
};
|
};
|
||||||
use crate::manager_observer::{
|
use crate::manager_observer::{
|
||||||
notify_child_views_changed, notify_parent_view_did_change, ChildViewChangeReason,
|
notify_child_views_changed, notify_did_update_workspace, notify_parent_view_did_change,
|
||||||
|
ChildViewChangeReason,
|
||||||
};
|
};
|
||||||
use crate::notification::{
|
use crate::notification::{
|
||||||
send_notification, send_workspace_setting_notification, FolderNotification,
|
send_notification, send_workspace_setting_notification, FolderNotification,
|
||||||
@ -991,7 +992,15 @@ impl FolderManager {
|
|||||||
send_notification(&view_pb.id, FolderNotification::DidUpdateView)
|
send_notification(&view_pb.id, FolderNotification::DidUpdateView)
|
||||||
.payload(view_pb)
|
.payload(view_pb)
|
||||||
.send();
|
.send();
|
||||||
|
|
||||||
|
if let Ok(workspace_id) = self.get_current_workspace_id().await {
|
||||||
|
let folder = &self.mutex_folder.lock();
|
||||||
|
if let Some(folder) = folder.as_ref() {
|
||||||
|
notify_did_update_workspace(&workspace_id, folder);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user