diff --git a/CHANGELOG.md b/CHANGELOG.md index 11a296b2e..24569e73e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +## 1.4.1 +* fix: platform issue on Web by @LucasXu0 in ([#498](https://github.com/AppFlowy-IO/appflowy-editor/pull/498)) + ## 1.4.1 * fix: build error on Flutter 3.13 by @LucasXu0 in ([#488](https://github.com/AppFlowy-IO/appflowy-editor/pull/488)) diff --git a/lib/src/editor/editor_component/service/ime/non_delta_input_service.dart b/lib/src/editor/editor_component/service/ime/non_delta_input_service.dart index e19b44b52..b53990b1c 100644 --- a/lib/src/editor/editor_component/service/ime/non_delta_input_service.dart +++ b/lib/src/editor/editor_component/service/ime/non_delta_input_service.dart @@ -1,4 +1,3 @@ -import 'dart:io'; import 'dart:math'; import 'package:appflowy_editor/appflowy_editor.dart'; @@ -79,7 +78,7 @@ class NonDeltaTextInputService extends TextInputService with TextInputClient { // the set editing state will update the text editing value in macOS. // we just skip the unnecessary update. - if (Platform.isMacOS) { + if (PlatformExtension.isMacOS) { skipUpdateEditingValue += 1; } @@ -96,7 +95,7 @@ class NonDeltaTextInputService extends TextInputService with TextInputClient { @override void updateEditingValue(TextEditingValue value) { - if (Platform.isMacOS && skipUpdateEditingValue > 0) { + if (PlatformExtension.isMacOS && skipUpdateEditingValue > 0) { skipUpdateEditingValue -= 1; return; } diff --git a/lib/src/editor/editor_component/service/keyboard_service_widget.dart b/lib/src/editor/editor_component/service/keyboard_service_widget.dart index 3a495788f..1fd8e4190 100644 --- a/lib/src/editor/editor_component/service/keyboard_service_widget.dart +++ b/lib/src/editor/editor_component/service/keyboard_service_widget.dart @@ -257,6 +257,11 @@ class KeyboardServiceWidgetState extends State 'keyboard service - focus changed: ${focusNode.hasFocus}}', ); + /// On web, we don't need to close the keyboard when the focus is lost. + if (kIsWeb) { + return; + } + // clear the selection when the focus is lost. if (!focusNode.hasFocus) { if (PlatformExtension.isDesktopOrWeb) { diff --git a/lib/src/editor/editor_component/service/shortcuts/command_shortcut_event.dart b/lib/src/editor/editor_component/service/shortcuts/command_shortcut_event.dart index 876fe374c..0e378a967 100644 --- a/lib/src/editor/editor_component/service/shortcuts/command_shortcut_event.dart +++ b/lib/src/editor/editor_component/service/shortcuts/command_shortcut_event.dart @@ -1,7 +1,4 @@ -import 'dart:io'; - import 'package:appflowy_editor/appflowy_editor.dart'; -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; typedef CommandShortcutEventHandler = KeyEventResult Function( @@ -67,23 +64,17 @@ class CommandShortcutEvent { return; } var matched = false; - if (kIsWeb) { - // We shouldn't continue to run the below `else if` code in Web platform, it will throw an `_operatingSystem` exception. - if (command != null && command.isNotEmpty) { - this.command = command; - matched = true; - } - } else if (Platform.isWindows && + if ((PlatformExtension.isWindows || PlatformExtension.isWebOnWindows) && windowsCommand != null && windowsCommand.isNotEmpty) { this.command = windowsCommand; matched = true; - } else if (Platform.isMacOS && + } else if ((PlatformExtension.isMacOS || PlatformExtension.isWebOnMacOS) && macOSCommand != null && macOSCommand.isNotEmpty) { this.command = macOSCommand; matched = true; - } else if (Platform.isLinux && + } else if ((PlatformExtension.isLinux || PlatformExtension.isWebOnLinux) && linuxCommand != null && linuxCommand.isNotEmpty) { this.command = linuxCommand; diff --git a/lib/src/editor/util/platform_extension.dart b/lib/src/editor/util/platform_extension.dart index e9bb3a751..e5a021df7 100644 --- a/lib/src/editor/util/platform_extension.dart +++ b/lib/src/editor/util/platform_extension.dart @@ -1,9 +1,22 @@ import 'dart:io'; import 'package:flutter/foundation.dart'; +import 'package:universal_html/html.dart' show window; // TODO(Xazin): Refactor to honor `Theme.platform` extension PlatformExtension on Platform { + static String get _webPlatform => + window.navigator.platform?.toLowerCase() ?? ''; + + /// Returns true if the operating system is macOS and not running on Web platform. + static bool get isMacOS { + if (kIsWeb) { + return false; + } + return Platform.isMacOS; + } + + /// Returns true if the operating system is Windows and not running on Web platform. static bool get isWindows { if (kIsWeb) { return false; @@ -11,6 +24,38 @@ extension PlatformExtension on Platform { return Platform.isWindows; } + /// Returns true if the operating system is Linux and not running on Web platform. + static bool get isLinux { + if (kIsWeb) { + return false; + } + return Platform.isLinux; + } + + /// Returns true if the operating system is macOS and running on Web platform. + static bool get isWebOnMacOS { + if (!kIsWeb) { + return false; + } + return _webPlatform.contains('mac') == true; + } + + /// Returns true if the operating system is Windows and running on Web platform. + static bool get isWebOnWindows { + if (!kIsWeb) { + return false; + } + return _webPlatform.contains('windows') == true; + } + + /// Returns true if the operating system is Linux and running on Web platform. + static bool get isWebOnLinux { + if (!kIsWeb) { + return false; + } + return _webPlatform.contains('linux') == true; + } + static bool get isDesktopOrWeb { if (kIsWeb) { return true; diff --git a/lib/src/service/shortcut_event/shortcut_event.dart b/lib/src/service/shortcut_event/shortcut_event.dart deleted file mode 100644 index a23a8c74b..000000000 --- a/lib/src/service/shortcut_event/shortcut_event.dart +++ /dev/null @@ -1,150 +0,0 @@ -import 'dart:io'; - -import 'package:appflowy_editor/src/service/shortcut_event/keybinding.dart'; -import 'package:appflowy_editor/src/service/shortcut_event/shortcut_event_handler.dart'; -import 'package:flutter/foundation.dart'; - -/// Defines the implementation of shortcut event. -class ShortcutEvent { - ShortcutEvent({ - required this.key, - this.character, - this.command, - required this.handler, - String? windowsCommand, - String? macOSCommand, - String? linuxCommand, - }) { - // character and command cannot be null at the same time - assert( - !(character == null && - command == null && - windowsCommand == null && - macOSCommand == null && - linuxCommand == null), - 'character and command cannot be null at the same time', - ); - assert( - !(character != null && - (command != null && - windowsCommand != null && - macOSCommand != null && - linuxCommand != null)), - 'character and command cannot be set at the same time', - ); - - updateCommand( - command: command, - windowsCommand: windowsCommand, - macOSCommand: macOSCommand, - linuxCommand: linuxCommand, - ); - } - - /// The unique key. - /// - /// Usually, uses the description as the key. - final String key; - - /// The string representation for the keyboard keys. - /// - /// The following is the mapping relationship of modify key. - /// ctrl: Ctrl - /// meta: Command in macOS or Control in Windows. - /// alt: Alt - /// shift: Shift - /// cmd: meta - /// win: meta - /// - /// Refer to [keyMapping] for other keys. - /// - /// Uses ',' to split different keyboard key combinations. - /// - /// Like, 'ctrl+c,cmd+c' - /// - String? command; - - String? character; - - final ShortcutEventHandler handler; - - List get keybindings => _keybindings; - List _keybindings = []; - - void updateCommand({ - String? command, - String? windowsCommand, - String? macOSCommand, - String? linuxCommand, - }) { - if (command == null && - windowsCommand == null && - macOSCommand == null && - linuxCommand == null) { - return; - } - var matched = false; - if (kIsWeb) { - // We shouldn't continue to run the below `else if` code in Web platform, it will throw an `_operatingSystem` exception. - if (command != null && command.isNotEmpty) { - this.command = command; - matched = true; - } - } else if (Platform.isWindows && - windowsCommand != null && - windowsCommand.isNotEmpty) { - this.command = windowsCommand; - matched = true; - } else if (Platform.isMacOS && - macOSCommand != null && - macOSCommand.isNotEmpty) { - this.command = macOSCommand; - matched = true; - } else if (Platform.isLinux && - linuxCommand != null && - linuxCommand.isNotEmpty) { - this.command = linuxCommand; - matched = true; - } else if (command != null && command.isNotEmpty) { - this.command = command; - matched = true; - } - - if (matched && this.command != null) { - _keybindings = this - .command! - .split(',') - .map((e) => Keybinding.parse(e)) - .toList(growable: false); - } - } - - ShortcutEvent copyWith({ - String? key, - String? command, - ShortcutEventHandler? handler, - }) { - return ShortcutEvent( - key: key ?? this.key, - command: command ?? this.command, - handler: handler ?? this.handler, - ); - } - - @override - String toString() => - 'ShortcutEvent(key: $key, command: $command, handler: $handler)'; - - @override - bool operator ==(Object other) { - if (identical(this, other)) return true; - - return other is ShortcutEvent && - other.key == key && - other.command == command && - other.handler == handler; - } - - @override - int get hashCode => key.hashCode ^ command.hashCode ^ handler.hashCode; -} diff --git a/pubspec.yaml b/pubspec.yaml index b5a4343ad..512490566 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: appflowy_editor description: A highly customizable rich-text editor for Flutter. The AppFlowy Editor project for AppFlowy and beyond. -version: 1.4.1 +version: 1.4.2 homepage: https://github.com/AppFlowy-IO/appflowy-editor platforms: @@ -38,6 +38,7 @@ dependencies: path: ^1.8.3 diff_match_patch: ^0.4.1 string_validator: ^1.0.0 + universal_html: ^2.2.4 dev_dependencies: flutter_test: diff --git a/test/editor/util/platform_extension_test.dart b/test/editor/util/platform_extension_test.dart new file mode 100644 index 000000000..df9cd2364 --- /dev/null +++ b/test/editor/util/platform_extension_test.dart @@ -0,0 +1,26 @@ +import 'dart:io'; + +import 'package:appflowy_editor/appflowy_editor.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + group('platform extension', () { + test('test safe platform judgement', () { + if (!kIsWeb && Platform.isLinux) { + expect(PlatformExtension.isLinux, true); + expect(PlatformExtension.isWebOnLinux, false); + } + + if (!kIsWeb && Platform.isWindows) { + expect(PlatformExtension.isWindows, true); + expect(PlatformExtension.isWebOnWindows, false); + } + + if (!kIsWeb && Platform.isMacOS) { + expect(PlatformExtension.isMacOS, true); + expect(PlatformExtension.isWebOnMacOS, false); + } + }); + }); +} diff --git a/test/service/shortcut_event/shortcut_event_test.dart b/test/service/shortcut_event/shortcut_event_test.dart index 037c3cc94..98a24589a 100644 --- a/test/service/shortcut_event/shortcut_event_test.dart +++ b/test/service/shortcut_event/shortcut_event_test.dart @@ -1,10 +1,9 @@ import 'dart:io'; -import 'package:appflowy_editor/src/service/shortcut_event/shortcut_event.dart'; +import 'package:appflowy_editor/appflowy_editor.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:appflowy_editor/appflowy_editor.dart'; import '../../new/infra/testable_editor.dart'; @@ -15,10 +14,10 @@ void main() async { group('shortcut_event.dart', () { test('redefine shortcut event command', () { - final shortcutEvent = ShortcutEvent( + final shortcutEvent = CommandShortcutEvent( key: 'Sample', command: 'cmd+shift+alt+ctrl+a', - handler: (editorState, event) { + handler: (editorState) { return KeyEventResult.handled; }, );