From 86285a6fffdf0f8ed050aaa1d7ec1c49969577b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=99=BD=E7=86=B1?= Date: Tue, 15 Jul 2025 13:37:03 +0800 Subject: [PATCH] feat: enhance mobile UI by adding new plugins and improving component registration (#5535) --- examples/src/mobile-s/main.ts | 7 +- .../mobile/mobile-sheet-ui.controller.ts | 76 +++++- packages/sheets-ui/src/mobile-plugin.ts | 242 +++++++++++++----- packages/ui/src/mobile-plugin.ts | 67 +++-- 4 files changed, 295 insertions(+), 97 deletions(-) diff --git a/examples/src/mobile-s/main.ts b/examples/src/mobile-s/main.ts index 299038cc75..f7357d917f 100644 --- a/examples/src/mobile-s/main.ts +++ b/examples/src/mobile-s/main.ts @@ -30,10 +30,12 @@ import { UniverSheetsDataValidationMobileUIPlugin } from '@univerjs/sheets-data- import { UniverSheetsFilterPlugin } from '@univerjs/sheets-filter'; import { UniverSheetsFilterMobileUIPlugin } from '@univerjs/sheets-filter-ui'; import { UniverSheetsFormulaPlugin } from '@univerjs/sheets-formula'; +import { UniverSheetsFormulaUIPlugin } from '@univerjs/sheets-formula-ui'; import { UniverSheetsNumfmtPlugin } from '@univerjs/sheets-numfmt'; +import { UniverSheetsNumfmtUIPlugin } from '@univerjs/sheets-numfmt-ui'; + import { UniverSheetsMobileUIPlugin } from '@univerjs/sheets-ui'; import { UniverMobileUIPlugin } from '@univerjs/ui'; - import '../global.css'; // univer @@ -52,7 +54,6 @@ univer.registerPlugin(UniverDocsPlugin); univer.registerPlugin(UniverRenderEnginePlugin); univer.registerPlugin(UniverMobileUIPlugin, { container: 'app', - contextMenu: true, }); const worker = new Worker(new URL('./worker.js', import.meta.url), { type: 'module' }); @@ -66,7 +67,9 @@ univer.registerPlugin(UniverSheetsMobileUIPlugin); univer.registerPlugin(UniverSheetsFilterPlugin); univer.registerPlugin(UniverSheetsFilterMobileUIPlugin); univer.registerPlugin(UniverSheetsNumfmtPlugin); +univer.registerPlugin(UniverSheetsNumfmtUIPlugin); univer.registerPlugin(UniverSheetsFormulaPlugin); +univer.registerPlugin(UniverSheetsFormulaUIPlugin); univer.registerPlugin(UniverSheetsConditionalFormattingMobileUIPlugin); univer.registerPlugin(UniverSheetsDataValidationPlugin); univer.registerPlugin(UniverSheetsDataValidationMobileUIPlugin); diff --git a/packages/sheets-ui/src/controllers/mobile/mobile-sheet-ui.controller.ts b/packages/sheets-ui/src/controllers/mobile/mobile-sheet-ui.controller.ts index 88cbca2a76..584c3eb7ad 100644 --- a/packages/sheets-ui/src/controllers/mobile/mobile-sheet-ui.controller.ts +++ b/packages/sheets-ui/src/controllers/mobile/mobile-sheet-ui.controller.ts @@ -14,7 +14,10 @@ * limitations under the License. */ -import { Disposable, ICommandService, Inject, Injector, UniverInstanceType } from '@univerjs/core'; +import { Disposable, ICommandService, IConfigService, Inject, Injector, IUniverInstanceService, UniverInstanceType } from '@univerjs/core'; +import { DocSelectionRenderService } from '@univerjs/docs-ui'; +import { getCurrentTypeOfRenderer, IRenderManagerService } from '@univerjs/engine-render'; +import { HideGridlinesDoubleIcon } from '@univerjs/icons'; import { SetBoldCommand, SetFontFamilyCommand, @@ -23,8 +26,15 @@ import { SetStrikeThroughCommand, SetUnderlineCommand, } from '@univerjs/sheets'; -import { BuiltInUIPart, ComponentManager, connectInjector, ILayoutService, IMenuManagerService, IShortcutService, IUIPartsService } from '@univerjs/ui'; - +import { + BuiltInUIPart, + ComponentManager, + connectInjector, + ILayoutService, + IMenuManagerService, + IShortcutService, + IUIPartsService, +} from '@univerjs/ui'; import { AddWorksheetMergeAllCommand, AddWorksheetMergeCommand, @@ -34,8 +44,10 @@ import { import { AutoClearContentCommand, AutoFillCommand } from '../../commands/commands/auto-fill.command'; import { DeleteRangeMoveLeftConfirmCommand } from '../../commands/commands/delete-range-move-left-confirm.command'; import { DeleteRangeMoveUpConfirmCommand } from '../../commands/commands/delete-range-move-up-confirm.command'; +import { SetColumnHeaderHeightCommand, SetRowHeaderWidthCommand } from '../../commands/commands/headersize-changed.command'; import { HideColConfirmCommand, HideRowConfirmCommand } from '../../commands/commands/hide-row-col-confirm.command'; import { + ResetRangeTextColorCommand, SetRangeBoldCommand, SetRangeFontFamilyCommand, SetRangeFontSizeCommand, @@ -69,6 +81,7 @@ import { MoveSelectionEnterAndTabCommand, SelectAllCommand, } from '../../commands/commands/set-selection.command'; +import { SetWorksheetColAutoWidthCommand } from '../../commands/commands/set-worksheet-auto-col-width.command'; import { ChangeZoomRatioCommand, SetZoomRatioCommand } from '../../commands/commands/set-zoom-ratio.command'; import { ShowMenuListCommand } from '../../commands/commands/unhide.command'; import { ChangeSheetProtectionFromSheetBarCommand, DeleteWorksheetProtectionFormSheetBarCommand } from '../../commands/commands/worksheet-protection.command'; @@ -79,6 +92,7 @@ import { SetCellEditVisibleWithF2Operation, } from '../../commands/operations/cell-edit.operation'; import { RenameSheetOperation } from '../../commands/operations/rename-sheet.operation'; +import { ScrollToRangeOperation } from '../../commands/operations/scroll-to-range.operation'; import { SetScrollOperation } from '../../commands/operations/scroll.operation'; import { SetFormatPainterOperation } from '../../commands/operations/set-format-painter.operation'; import { SetZoomRatioOperation } from '../../commands/operations/set-zoom-ratio.operation'; @@ -88,17 +102,23 @@ import { SidebarDefinedNameOperation } from '../../commands/operations/sidebar-d import { BorderPanel } from '../../components/border-panel/BorderPanel'; import { BORDER_PANEL_COMPONENT } from '../../components/border-panel/interface'; import { MENU_ITEM_INPUT_COMPONENT, MenuItemInput } from '../../components/menu-item-input'; +import { CellPopup } from '../../views/cell-popup'; +import { CELL_POPUP_COMPONENT_KEY } from '../../views/cell-popup/config'; import { DEFINED_NAME_CONTAINER } from '../../views/defined-name/component-name'; import { DefinedNameContainer } from '../../views/defined-name/DefinedNameContainer'; import { MobileSheetBar } from '../../views/mobile/sheet-bar/MobileSheetBar'; +import { RenderSheetContent } from '../../views/sheet-container/SheetContainer'; import { EditorBreakLineShortcut, + EditorCursorCtrlEnterShortcut, EditorCursorEnterShortcut, EditorCursorEscShortcut, EditorCursorTabShortcut, EditorDeleteLeftShortcut, EditorDeleteLeftShortcutInActive, + EditorDeleteRightShortcut, generateArrowSelectionShortCutItem, + ShiftEditorDeleteLeftShortcut, StartEditWithF2Shortcut, } from '../shortcuts/editor.shortcut'; import { SetColHiddenShortcutItem, SetRowHiddenShortcutItem } from '../shortcuts/operation.shortcut'; @@ -132,7 +152,7 @@ import { SetStrikeThroughShortcutItem, SetUnderlineShortcutItem, } from '../shortcuts/style.shortcut'; -import { ClearSelectionValueShortcutItem } from '../shortcuts/value.shortcut'; +import { ClearSelectionValueShortcutItem, ClearSelectionValueShortcutItemMac, ShiftClearSelectionValueShortcutItem, ShiftDeleteSelectionValueShortcutItem } from '../shortcuts/value.shortcut'; import { PreventDefaultResetZoomShortcutItem, PreventDefaultZoomInShortcutItem, @@ -145,13 +165,14 @@ import { menuSchema } from './menu.schema'; export class SheetUIMobileController extends Disposable { constructor( - @Inject(Injector) private readonly _injector: Injector, - @Inject(ComponentManager) private readonly _componentManager: ComponentManager, - @ILayoutService private readonly _layoutService: ILayoutService, - @ICommandService private readonly _commandService: ICommandService, - @IShortcutService private readonly _shortcutService: IShortcutService, + @Inject(Injector) protected readonly _injector: Injector, + @Inject(ComponentManager) protected readonly _componentManager: ComponentManager, + @ILayoutService protected readonly _layoutService: ILayoutService, + @ICommandService protected readonly _commandService: ICommandService, + @IShortcutService protected readonly _shortcutService: IShortcutService, @IMenuManagerService protected readonly _menuManagerService: IMenuManagerService, - @IUIPartsService private readonly _uiPartsService: IUIPartsService + @IUIPartsService protected readonly _uiPartsService: IUIPartsService, + @IConfigService protected readonly _configService: IConfigService ) { super(); @@ -159,7 +180,7 @@ export class SheetUIMobileController extends Disposable { } private _init(): void { - this._initCustomComponents(); + this._initComponents(); this._initCommands(); this._initMenus(); this._initShortcuts(); @@ -167,11 +188,17 @@ export class SheetUIMobileController extends Disposable { this._initFocusHandler(); } - private _initCustomComponents(): void { + private _initComponents(): void { const componentManager = this._componentManager; + + // init custom components this.disposeWithMe(componentManager.register(MENU_ITEM_INPUT_COMPONENT, MenuItemInput)); this.disposeWithMe(componentManager.register(BORDER_PANEL_COMPONENT, BorderPanel)); this.disposeWithMe(componentManager.register(DEFINED_NAME_CONTAINER, DefinedNameContainer)); + this.disposeWithMe(componentManager.register(CELL_POPUP_COMPONENT_KEY, CellPopup)); + + // init icons + this.disposeWithMe(componentManager.register('HideGridlinesDoubleIcon', HideGridlinesDoubleIcon)); } private _initCommands(): void { @@ -207,6 +234,7 @@ export class SheetUIMobileController extends Disposable { SetRangeFontSizeCommand, SetRangeFontFamilyCommand, SetRangeTextColorCommand, + ResetRangeTextColorCommand, SetItalicCommand, SetStrikeThroughCommand, SetFontFamilyCommand, @@ -220,6 +248,7 @@ export class SheetUIMobileController extends Disposable { SetSelectionFrozenCommand, SetRowFrozenCommand, SetColumnFrozenCommand, + ScrollToRangeOperation, SetUnderlineCommand, SetZoomRatioCommand, SetZoomRatioOperation, @@ -245,6 +274,9 @@ export class SheetUIMobileController extends Disposable { DeleteRangeProtectionFromContextMenuCommand, SetRangeProtectionFromContextMenuCommand, DeleteWorksheetProtectionFormSheetBarCommand, + SetWorksheetColAutoWidthCommand, + SetRowHeaderWidthCommand, + SetColumnHeaderHeightCommand, ].forEach((c) => { this.disposeWithMe(this._commandService.registerCommand(c)); }); @@ -296,14 +328,20 @@ export class SheetUIMobileController extends Disposable { // cell content editing shortcuts ClearSelectionValueShortcutItem, + ClearSelectionValueShortcutItemMac, + ShiftClearSelectionValueShortcutItem, + ShiftDeleteSelectionValueShortcutItem, ...generateArrowSelectionShortCutItem(), EditorCursorEnterShortcut, StartEditWithF2Shortcut, EditorCursorTabShortcut, EditorBreakLineShortcut, EditorDeleteLeftShortcut, + EditorDeleteRightShortcut, EditorDeleteLeftShortcutInActive, EditorCursorEscShortcut, + EditorCursorCtrlEnterShortcut, + ShiftEditorDeleteLeftShortcut, // operation shortcuts SetRowHiddenShortcutItem, @@ -314,13 +352,25 @@ export class SheetUIMobileController extends Disposable { } private _initWorkbenchParts(): void { - this._uiPartsService.registerComponent(BuiltInUIPart.HEADER, () => connectInjector(MobileSheetBar, this._injector)); + const uiController = this._uiPartsService; + const injector = this._injector; + + this.disposeWithMe(uiController.registerComponent(BuiltInUIPart.HEADER, () => connectInjector(MobileSheetBar, injector))); + this.disposeWithMe(uiController.registerComponent(BuiltInUIPart.CONTENT, () => connectInjector(RenderSheetContent, injector))); } private _initFocusHandler(): void { this.disposeWithMe( this._layoutService.registerFocusHandler(UniverInstanceType.UNIVER_SHEET, (_unitId: string) => { + // DEBT: `_unitId` is not used hence we cannot support Univer mode now // TODO@wzhudev: focus is different on mobile devices + + const renderManagerService = this._injector.get(IRenderManagerService); + const instanceService = this._injector.get(IUniverInstanceService); + const currentEditorRender = getCurrentTypeOfRenderer(UniverInstanceType.UNIVER_DOC, instanceService, renderManagerService); + const docSelectionRenderService = currentEditorRender?.with(DocSelectionRenderService); + + docSelectionRenderService?.focus(); }) ); } diff --git a/packages/sheets-ui/src/mobile-plugin.ts b/packages/sheets-ui/src/mobile-plugin.ts index 070ca83a03..a721287497 100644 --- a/packages/sheets-ui/src/mobile-plugin.ts +++ b/packages/sheets-ui/src/mobile-plugin.ts @@ -15,38 +15,54 @@ */ import type { Dependency, Workbook } from '@univerjs/core'; +import type { IUniverUIConfig } from '@univerjs/ui'; import type { IUniverSheetsUIConfig } from './controllers/config.schema'; -import { DependentOn, Inject, Injector, IUniverInstanceService, Plugin, UniverInstanceType } from '@univerjs/core'; - +import { DependentOn, IConfigService, Inject, Injector, IUniverInstanceService, merge, mergeOverrideWithDependencies, Plugin, registerDependencies, touchDependencies, UniverInstanceType } from '@univerjs/core'; import { IRenderManagerService } from '@univerjs/engine-render'; import { IRefSelectionsService, RefSelectionsService, UniverSheetsPlugin } from '@univerjs/sheets'; - -import { UniverMobileUIPlugin } from '@univerjs/ui'; +import { ComponentManager, UI_PLUGIN_CONFIG_KEY, UniverMobileUIPlugin } from '@univerjs/ui'; import { filter } from 'rxjs/operators'; +import { UNIVER_SHEET_PERMISSION_BACKGROUND, UNIVER_SHEET_PERMISSION_USER_PART } from './consts/permission'; import { ActiveWorksheetController } from './controllers/active-worksheet/active-worksheet.controller'; +import { AutoFillController } from './controllers/auto-fill.controller'; import { AutoHeightController } from './controllers/auto-height.controller'; +import { AutoWidthController } from './controllers/auto-width.controller'; import { CellAlertRenderController } from './controllers/cell-alert.controller'; import { CellCustomRenderController } from './controllers/cell-custom-render.controller'; +import { SheetCheckboxController } from './controllers/checkbox.controller'; import { SheetClipboardController } from './controllers/clipboard/clipboard.controller'; -import { defaultPluginConfig } from './controllers/config.schema'; -// import { SheetContextMenuRenderController } from './controllers/render-controllers/contextmenu.render-controller'; +import { defaultPluginConfig, SHEETS_UI_PLUGIN_CONFIG_KEY } from './controllers/config.schema'; +import { SheetsDefinedNameController } from './controllers/defined-name/defined-name.controller'; import { DragRenderController } from './controllers/drag-render.controller'; +import { EditorDataSyncController } from './controllers/editor/data-sync.controller'; +import { EditingRenderController } from './controllers/editor/editing.render-controller'; +import { FormulaEditorController } from './controllers/editor/formula-editor.controller'; import { ForceStringAlertRenderController } from './controllers/force-string-alert-render.controller'; import { ForceStringRenderController } from './controllers/force-string-render.controller'; +import { FormatPainterController } from './controllers/format-painter/format-painter.controller'; import { HoverRenderController } from './controllers/hover-render.controller'; import { MarkSelectionRenderController } from './controllers/mark-selection.controller'; import { SheetUIMobileController } from './controllers/mobile/mobile-sheet-ui.controller'; +import { MoveRangeRenderController } from './controllers/move-range.controller'; import { SheetPermissionCheckUIController } from './controllers/permission/sheet-permission-check-ui.controller'; +import { SheetPermissionInitUIController } from './controllers/permission/sheet-permission-init-ui.controller'; import { SheetPermissionInterceptorCanvasRenderController } from './controllers/permission/sheet-permission-interceptor-canvas-render.controller'; import { SheetPermissionInterceptorClipboardController } from './controllers/permission/sheet-permission-interceptor-clipboard.controller'; import { SheetPermissionInterceptorFormulaRenderController } from './controllers/permission/sheet-permission-interceptor-formula-render.controller'; import { SheetPermissionRenderController, SheetPermissionRenderManagerController, WorksheetProtectionRenderController } from './controllers/permission/sheet-permission-render.controller'; +import { ClipboardRenderController } from './controllers/render-controllers/clipboard.render-controller'; +import { EditorBridgeRenderController } from './controllers/render-controllers/editor-bridge.render-controller'; import { FormatPainterRenderController } from './controllers/render-controllers/format-painter.render-controller'; import { HeaderFreezeRenderController } from './controllers/render-controllers/freeze.render-controller'; +import { HeaderMenuRenderController } from './controllers/render-controllers/header-menu.render-controller'; import { HeaderMoveRenderController } from './controllers/render-controllers/header-move.render-controller'; -import { SheetContextMenuMobileRenderController } from './controllers/render-controllers/mobile/mobile-contextmenu.render-controller'; +import { HeaderResizeRenderController } from './controllers/render-controllers/header-resize.render-controller'; +import { HeaderUnhideRenderController } from './controllers/render-controllers/header-unhide.render-controller'; +// import { SheetContextMenuMobileRenderController } from './controllers/render-controllers/mobile/mobile-contextmenu.render-controller'; import { MobileSheetsScrollRenderController } from './controllers/render-controllers/mobile/mobile-scroll.render-controller'; +import { SheetsScrollRenderController } from './controllers/render-controllers/scroll.render-controller'; import { SheetRenderController } from './controllers/render-controllers/sheet.render-controller'; +import { SheetSkeletonRenderController } from './controllers/render-controllers/skeleton.render-controller'; import { SheetsZoomRenderController } from './controllers/render-controllers/zoom.render-controller'; import { StatusBarController } from './controllers/status-bar.controller'; import { AutoFillService, IAutoFillService } from './services/auto-fill/auto-fill.service'; @@ -58,6 +74,12 @@ import { CellPopupManagerService } from './services/cell-popup-manager.service'; import { ISheetClipboardService, SheetClipboardService } from './services/clipboard/clipboard.service'; import { DragManagerService } from './services/drag-manager.service'; import { EditorBridgeService, IEditorBridgeService } from './services/editor-bridge.service'; +import { CellEditorManagerService, ICellEditorManagerService } from './services/editor/cell-editor-manager.service'; +import { SheetCellEditorResizeService } from './services/editor/cell-editor-resize.service'; +import { + FormulaEditorManagerService, + IFormulaEditorManagerService, +} from './services/editor/formula-editor-manager.service'; import { FormatPainterService, IFormatPainterService } from './services/format-painter/format-painter.service'; import { HoverManagerService } from './services/hover-manager.service'; import { IMarkSelectionService, MarkSelectionService } from './services/mark-selection/mark-selection.service'; @@ -74,101 +96,177 @@ import { SheetsRenderService } from './services/sheets-render.service'; import { ShortcutExperienceService } from './services/shortcut-experience.service'; import { IStatusBarService, StatusBarService } from './services/status-bar.service'; -/** - * @ignore - */ @DependentOn(UniverSheetsPlugin, UniverMobileUIPlugin) export class UniverSheetsMobileUIPlugin extends Plugin { static override pluginName = 'SHEET_UI_PLUGIN'; static override type = UniverInstanceType.UNIVER_SHEET; + /** @ignore */ constructor( private readonly _config: Partial = defaultPluginConfig, @Inject(Injector) override readonly _injector: Injector, @IRenderManagerService private readonly _renderManagerService: IRenderManagerService, - @IUniverInstanceService private readonly _univerInstanceService: IUniverInstanceService + @IConfigService private readonly _configService: IConfigService, + @IUniverInstanceService private readonly _univerInstanceService: IUniverInstanceService, + @Inject(ComponentManager) private readonly _componentManager: ComponentManager ) { super(); + + // Manage the plugin configuration. + const { menu, ...rest } = merge( + {}, + defaultPluginConfig, + this._config + ); + + const { customComponents = new Set() } = rest; + if (rest.protectedRangeShadow === false) { + customComponents.add(UNIVER_SHEET_PERMISSION_BACKGROUND); + } + + if (rest.protectedRangeUserSelector) { + customComponents.add(UNIVER_SHEET_PERMISSION_USER_PART); + + this.disposeWithMe( + this._componentManager.register( + UNIVER_SHEET_PERMISSION_USER_PART, + rest.protectedRangeUserSelector.component, + { + framework: rest.protectedRangeUserSelector.framework, + } + ) + ); + } + + if (menu) { + this._configService.setConfig('menu', menu, { merge: true }); + } + + this._configService.setConfig(SHEETS_UI_PLUGIN_CONFIG_KEY, { ...rest, customComponents }); } override onStarting(): void { - ( - [ - [ShortcutExperienceService], - [ISheetClipboardService, { useClass: SheetClipboardService }], - [ISheetBarService, { useClass: SheetBarService }], - [IFormatPainterService, { useClass: FormatPainterService }], - [IAutoFillService, { useClass: AutoFillService }], - [SheetPrintInterceptorService], - [ISheetSelectionRenderService, { useClass: MobileSheetsSelectionRenderService }], - [IStatusBarService, { useClass: StatusBarService }], - [IMarkSelectionService, { useClass: MarkSelectionService }], - [IEditorBridgeService, { useClass: EditorBridgeService }], - [HoverManagerService], - [DragManagerService], - [SheetCanvasPopManagerService], - [CellPopupManagerService], - [CellAlertManagerService], - [SelectAllService], - [ISheetCellDropdownManagerService, { useClass: SheetCellDropdownManagerService }], + registerDependencies(this._injector, mergeOverrideWithDependencies([ + [ShortcutExperienceService], + [IEditorBridgeService, { useClass: EditorBridgeService }], + [ISheetClipboardService, { useClass: SheetClipboardService }], + [ISheetBarService, { useClass: SheetBarService }], + [IFormatPainterService, { useClass: FormatPainterService }], + [ICellEditorManagerService, { useClass: CellEditorManagerService }], + [IFormulaEditorManagerService, { useClass: FormulaEditorManagerService }], + [IRefSelectionsService, { useClass: RefSelectionsService }], + [IAutoFillService, { useClass: AutoFillService }], + [SheetPrintInterceptorService], + [IStatusBarService, { useClass: StatusBarService }], + [IMarkSelectionService, { useClass: MarkSelectionService }], + [HoverManagerService], + [DragManagerService], + [SheetCanvasPopManagerService], + [CellPopupManagerService], + [CellAlertManagerService], + [SelectAllService], + [ISheetCellDropdownManagerService, { useClass: SheetCellDropdownManagerService }], + [SheetCellEditorResizeService], - [ActiveWorksheetController], - [AutoHeightController], - [SheetClipboardController], - [SheetsRenderService], - [SheetUIMobileController], - [StatusBarController], - [IRefSelectionsService, { useClass: RefSelectionsService }], + // controllers + [ActiveWorksheetController], + [AutoHeightController], + [AutoWidthController], + [FormulaEditorController], + [SheetsRenderService], + [SheetUIMobileController], + [StatusBarController], + [AutoFillController], + [FormatPainterController], + [SheetsDefinedNameController], + [EditorDataSyncController], + [SheetCheckboxController], + [EditingRenderController], - // permission - [SheetPermissionPanelModel], - [SheetPermissionUserManagerService], - [WorksheetProtectionRenderController], - [SheetPermissionInterceptorClipboardController], - [SheetPermissionCheckUIController], - [SheetPermissionRenderManagerController], - ] as Dependency[] - ).forEach((d) => this._injector.add(d)); + // permission + [SheetPermissionPanelModel], + [SheetPermissionInitUIController], + [SheetPermissionUserManagerService], + [SheetPermissionInterceptorClipboardController], + [SheetPermissionCheckUIController], + [SheetPermissionRenderManagerController], + ] as Dependency[], this._config.override)); } override onReady(): void { - this._markSheetAsFocused(); + if (!this._config.disableAutoFocus) { + this._initAutoFocus(); + } + + registerDependencies(this._injector, [ + [SheetClipboardController], + ]); + this._registerRenderBasics(); - this._injector.get(SheetUIMobileController); + touchDependencies(this._injector, [ + [SheetUIMobileController], + [SheetsRenderService], + [ActiveWorksheetController], + [SheetPermissionCheckUIController], + [SheetPermissionInitUIController], + ]); } override onRendered(): void { this._registerRenderModules(); + + touchDependencies(this._injector, [ + [SheetPermissionRenderManagerController], + [SheetPermissionPanelModel], + [SheetClipboardController], + [FormulaEditorController], + [SheetsDefinedNameController], + [StatusBarController], + [AutoHeightController], + [AutoWidthController], + [EditorDataSyncController], + [SheetCheckboxController], + [EditingRenderController], + ]); + } + + override onSteady(): void { + touchDependencies(this._injector, [ + [FormatPainterController], + [AutoFillController], + [SheetPermissionInterceptorClipboardController], + ]); } private _registerRenderBasics(): void { ([ [SheetSkeletonManagerService], + [SheetSkeletonRenderController], [SheetRenderController], [ISheetSelectionRenderService, { useClass: MobileSheetsSelectionRenderService }], [SheetScrollManagerService], [AutoHeightService], - ] as Dependency[]).forEach((renderDep) => { - this.disposeWithMe(this._renderManagerService.registerRenderModule(UniverInstanceType.UNIVER_SHEET, renderDep)); + ] as Dependency[]).forEach((m) => { + this.disposeWithMe(this._renderManagerService.registerRenderModule(UniverInstanceType.UNIVER_SHEET, m)); }); } // We have to let render basics get bootstrapped before. Because some render controllers relies on // a correct skeleton when they get loaded. private _registerRenderModules(): void { - ([ - // https://github.com/dream-num/univer-pro/issues/669 - // HeaderMoveRenderController(HMRC) must be initialized before SelectionRenderController(SRC). - // Before HMRC expected selections remain unchanged when user clicks on the header. If we don't initialize HMRC before SRC, - // the selections will be changed by SRC first. Maybe we should merge row/col header related render controllers to one class. + const modules: Dependency[] = [ [HeaderMoveRenderController], - [HeaderFreezeRenderController], - // Caution: ScrollRenderController should placed before ZoomRenderController - // because ZoomRenderController would change scrollInfo in currentSkeletonBefore$. + [HeaderUnhideRenderController], + [HeaderResizeRenderController], + // TODO: Should not register these two Controllers at the same time + [SheetsScrollRenderController], [MobileSheetsScrollRenderController], + [HeaderFreezeRenderController], [SheetsZoomRenderController], + [FormatPainterRenderController], + [ClipboardRenderController], [CellAlertRenderController], [ForceStringAlertRenderController], [MarkSelectionRenderController], @@ -176,23 +274,35 @@ export class UniverSheetsMobileUIPlugin extends Plugin { [DragRenderController], [ForceStringRenderController], [CellCustomRenderController], - [SheetContextMenuMobileRenderController], + // [SheetContextMenuMobileRenderController], + [MoveRangeRenderController], + // editor + [EditorBridgeRenderController], + + // permission [SheetPermissionInterceptorCanvasRenderController], [SheetPermissionInterceptorFormulaRenderController], [SheetPermissionRenderController], - ] as Dependency[]).forEach((renderModule) => { - this.disposeWithMe(this._renderManagerService.registerRenderModule(UniverInstanceType.UNIVER_SHEET, renderModule)); + [WorksheetProtectionRenderController], + ]; + + // If the context menu is disabled, we don't need to register the context menu render controller. + const config = this._configService.getConfig(UI_PLUGIN_CONFIG_KEY); + const showContextMenu = config?.contextMenu ?? true; + if (showContextMenu) { + modules.push([HeaderMenuRenderController]); + } + + modules.forEach((m) => { + this.disposeWithMe(this._renderManagerService.registerRenderModule(UniverInstanceType.UNIVER_SHEET, m)); }); } - private _markSheetAsFocused(): void { + private _initAutoFocus(): void { const univerInstanceService = this._univerInstanceService; this.disposeWithMe(univerInstanceService.getCurrentTypeOfUnit$(UniverInstanceType.UNIVER_SHEET) .pipe(filter((v) => !!v)) - .subscribe((workbook) => { - if (this._univerInstanceService.getFocusedUnit() === workbook) return; - univerInstanceService.focusUnit(workbook!.getUnitId()); - })); + .subscribe((workbook) => univerInstanceService.focusUnit(workbook!.getUnitId()))); } } diff --git a/packages/ui/src/mobile-plugin.ts b/packages/ui/src/mobile-plugin.ts index 088271f726..ff7cfea650 100644 --- a/packages/ui/src/mobile-plugin.ts +++ b/packages/ui/src/mobile-plugin.ts @@ -14,14 +14,15 @@ * limitations under the License. */ -import type { Dependency } from '@univerjs/core'; import type { IUniverUIConfig } from './controllers/config.schema'; -import { DependentOn, ILocalStorageService, Inject, Injector, mergeOverrideWithDependencies, Plugin } from '@univerjs/core'; +import { DependentOn, generateRandomId, IConfigService, IContextService, ILocalStorageService, Inject, Injector, merge, mergeOverrideWithDependencies, Plugin, registerDependencies, touchDependencies } from '@univerjs/core'; import { UniverRenderEnginePlugin } from '@univerjs/engine-render'; import { ComponentManager } from './common/component-manager'; import { ZIndexManager } from './common/z-index-manager'; +import { defaultPluginConfig, UI_PLUGIN_CONFIG_KEY } from './controllers/config.schema'; import { ErrorController } from './controllers/error/error.controller'; import { SharedController } from './controllers/shared-shortcut.controller'; +import { ShortcutPanelController } from './controllers/shortcut-display/shortcut-panel.controller'; import { MobileUIController } from './controllers/ui/ui-mobile.controller'; import { IUIController } from './controllers/ui/ui.controller'; import { DesktopBeforeCloseService, IBeforeCloseService } from './services/before-close/before-close.service'; @@ -37,6 +38,8 @@ import { IGalleryService } from './services/gallery/gallery.service'; import { DesktopGlobalZoneService } from './services/global-zone/desktop-global-zone.service'; import { IGlobalZoneService } from './services/global-zone/global-zone.service'; import { DesktopLayoutService, ILayoutService } from './services/layout/layout.service'; +import { DesktopLocalFileService } from './services/local-file/desktop-local-file.service'; +import { ILocalFileService } from './services/local-file/local-file.service'; import { DesktopLocalStorageService } from './services/local-storage/local-storage.service'; import { IMenuManagerService, MenuManagerService } from './services/menu/menu-manager.service'; import { DesktopMessageService } from './services/message/desktop-message.service'; @@ -54,32 +57,51 @@ import { ThemeSwitcherService } from './services/theme-switcher/theme-switcher.s import { DesktopZenZoneService } from './services/zen-zone/desktop-zen-zone.service'; import { IZenZoneService } from './services/zen-zone/zen-zone.service'; -export const UNIVER_MOBILE_UI_PLUGIN_NAME = 'UNIVER_MOBILE_UI_PLUGIN'; +export const UNIVER_UI_PLUGIN_NAME = 'UNIVER_MOBILE_UI_PLUGIN'; + +export const DISABLE_AUTO_FOCUS_KEY = 'DISABLE_AUTO_FOCUS'; /** - * @ignore + * UI plugin provides basic interaction with users. Including workbench (menus, UI parts, notifications etc.), copy paste, shortcut. */ @DependentOn(UniverRenderEnginePlugin) export class UniverMobileUIPlugin extends Plugin { - static override pluginName = UNIVER_MOBILE_UI_PLUGIN_NAME; + static override pluginName = UNIVER_UI_PLUGIN_NAME; constructor( - private readonly _config: IUniverUIConfig, - @Inject(Injector) protected readonly _injector: Injector + private readonly _config: Partial = defaultPluginConfig, + @IContextService private readonly _contextService: IContextService, + @Inject(Injector) protected readonly _injector: Injector, + @IConfigService private readonly _configService: IConfigService ) { super(); + + // Manage the plugin configuration. + const { menu, ...rest } = merge( + { + popupRootId: `univer-popup-portal-${generateRandomId(6)}`, + }, + defaultPluginConfig, + this._config + ); + + if (rest.disableAutoFocus) { + this._contextService.setContextValue(DISABLE_AUTO_FOCUS_KEY, true); + } + if (menu) { + this._configService.setConfig('menu', menu, { merge: true }); + } + this._configService.setConfig(UI_PLUGIN_CONFIG_KEY, rest); } override onStarting(): void { - const dependencies: Dependency[] = mergeOverrideWithDependencies([ + registerDependencies(this._injector, mergeOverrideWithDependencies([ [ComponentManager], + [ThemeSwitcherService], [ZIndexManager], - - // services [ShortcutPanelService], [IUIPartsService, { useClass: UIPartsService }], [ILayoutService, { useClass: DesktopLayoutService }], - [ThemeSwitcherService], [IShortcutService, { useClass: ShortcutService }], [IPlatformService, { useClass: PlatformService }], [IMenuManagerService, { useClass: MenuManagerService }], @@ -95,10 +117,10 @@ export class UniverMobileUIPlugin extends Plugin { [IMessageService, { useClass: DesktopMessageService, lazy: true }], [ILocalStorageService, { useClass: DesktopLocalStorageService, lazy: true }], [IBeforeCloseService, { useClass: DesktopBeforeCloseService }], + [ILocalFileService, { useClass: DesktopLocalFileService }], [ICanvasPopupService, { useClass: CanvasPopupService }], [CanvasFloatDomService], - // controllers [ IUIController, { @@ -108,11 +130,24 @@ export class UniverMobileUIPlugin extends Plugin { ], [SharedController], [ErrorController], - ], this._config.override); + [ShortcutPanelController], + ], this._config.override)); - dependencies.forEach((dependency) => this._injector.add(dependency)); + touchDependencies(this._injector, [ + [IUIController], + [ErrorController], + ]); + } - this._injector.get(IUIController); - this._injector.get(ErrorController); + override onReady(): void { + touchDependencies(this._injector, [ + [SharedController], + ]); + } + + override onSteady(): void { + touchDependencies(this._injector, [ + [ShortcutPanelController], + ]); } }