From ebd2729f39603a39d6b93ffe36d145e4ac4e902c Mon Sep 17 00:00:00 2001
From: Ellet <hello@freshplatform.net>
Date: Fri, 10 Nov 2023 18:29:02 +0300
Subject: [PATCH] Fix platform checking logic (#1518)

* Fix platform checking logic

* Update _defaultOnTapOutside
---
 CHANGELOG.md                                  |   1 +
 example/lib/pages/home_page.dart              |   4 +-
 example/lib/pages/read_only_page.dart         |   2 +-
 flutter_quill_extensions/CHANGELOG.md         |   3 +
 .../embeds/editor/image/image.dart            |  17 +-
 .../image_button/select_image_source.dart     |   2 +-
 .../video_button/select_video_source.dart     |   2 +-
 .../models/config/editor/image/image.dart     |  10 +-
 lib/src/utils/platform.dart                   | 130 +++++++++++----
 lib/src/widgets/cursor.dart                   |   2 +-
 lib/src/widgets/default_styles.dart           |   2 +-
 lib/src/widgets/delegate.dart                 |   4 +-
 lib/src/widgets/editor/editor.dart            |  23 ++-
 .../widgets/raw_editor/raw_editor_state.dart  |   8 +-
 lib/src/widgets/text_line.dart                |   6 +-
 pubspec.yaml                                  |   1 +
 test/utils/platform_test.dart                 | 156 ++++++++++++++++++
 test/widgets/controller_test.dart             |   2 +-
 18 files changed, 303 insertions(+), 72 deletions(-)
 create mode 100644 test/utils/platform_test.dart

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2c73ec2a..7dbb538f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,6 +3,7 @@
 - **Breaking change**: the `customButtons` in the `QuillToolbarConfigurations` is now of type `List<QuillToolbarCustomButtonOptions>`
 - Bug fixes with the new `8.0.0` update
 - Update `README.md`
+- Improve the platform checking
 
 ## [8.3.0]
 - Added a `iconButtonFactor` property to `QuillToolbarBaseButtonOptions` to customise how big the button is compared to its icon size (defaults to `kIconButtonFactor` which is the same as previous releases)
diff --git a/example/lib/pages/home_page.dart b/example/lib/pages/home_page.dart
index 538e8f40..379b4f2a 100644
--- a/example/lib/pages/home_page.dart
+++ b/example/lib/pages/home_page.dart
@@ -414,7 +414,7 @@ class _HomePageState extends State<HomePage> {
         placeholder: 'Add content',
         readOnly: _isReadOnly,
         autoFocus: false,
-        enableSelectionToolbar: isMobile(),
+        enableSelectionToolbar: isMobile(supportWeb: false),
         expands: false,
         padding: EdgeInsets.zero,
         onImagePaste: _onImagePaste,
@@ -500,7 +500,7 @@ class _HomePageState extends State<HomePage> {
         // afterButtonPressed: _focusNode.requestFocus,
       );
     }
-    if (isDesktop()) {
+    if (isDesktop(supportWeb: false)) {
       return QuillToolbar(
         configurations: QuillToolbarConfigurations(
           customButtons: customButtons,
diff --git a/example/lib/pages/read_only_page.dart b/example/lib/pages/read_only_page.dart
index 6f38741a..9670c152 100644
--- a/example/lib/pages/read_only_page.dart
+++ b/example/lib/pages/read_only_page.dart
@@ -23,7 +23,7 @@ class _ReadOnlyPageState extends State<ReadOnlyPage> {
   @override
   Widget build(BuildContext context) {
     return DemoScaffold(
-      documentFilename: isDesktop()
+      documentFilename: isDesktop(supportWeb: false)
           ? 'assets/sample_data_nomedia.json'
           : 'sample_data_nomedia.json',
       builder: _buildContent,
diff --git a/flutter_quill_extensions/CHANGELOG.md b/flutter_quill_extensions/CHANGELOG.md
index baf0e9e3..2cb20ab3 100644
--- a/flutter_quill_extensions/CHANGELOG.md
+++ b/flutter_quill_extensions/CHANGELOG.md
@@ -1,3 +1,6 @@
+## 0.6.5
+- Support the new improved platform checking of `flutter_quill`
+
 ## 0.6.4
 - Update `QuillImageUtilities`
 - Add new extension on `QuillController` to access `QuillImageUtilities` instance easier
diff --git a/flutter_quill_extensions/lib/presentation/embeds/editor/image/image.dart b/flutter_quill_extensions/lib/presentation/embeds/editor/image/image.dart
index 0f40233a..7f3d6e94 100644
--- a/flutter_quill_extensions/lib/presentation/embeds/editor/image/image.dart
+++ b/flutter_quill_extensions/lib/presentation/embeds/editor/image/image.dart
@@ -41,7 +41,7 @@ class QuillEditorImageEmbedBuilder extends EmbedBuilder {
     final style = node.style.attributes['style'];
 
     if (style != null) {
-      final attrs = base.isMobile()
+      final attrs = base.isMobile(supportWeb: false)
           ? base.parseKeyValuePairs(style.value.toString(), {
               Attribute.mobileWidth,
               Attribute.mobileHeight,
@@ -56,21 +56,21 @@ class QuillEditorImageEmbedBuilder extends EmbedBuilder {
             });
       if (attrs.isNotEmpty) {
         final width = double.tryParse(
-          (base.isMobile()
+          (base.isMobile(supportWeb: false)
                   ? attrs[Attribute.mobileWidth]
                   : attrs[Attribute.width.key]) ??
               '',
         );
         final height = double.tryParse(
-          (base.isMobile()
+          (base.isMobile(supportWeb: false)
                   ? attrs[Attribute.mobileHeight]
                   : attrs[Attribute.height.key]) ??
               '',
         );
-        final alignment = base.getAlignment(base.isMobile()
+        final alignment = base.getAlignment(base.isMobile(supportWeb: false)
             ? attrs[Attribute.mobileAlignment]
             : attrs[Attribute.alignment]);
-        final margin = (base.isMobile()
+        final margin = (base.isMobile(supportWeb: false)
                 ? double.tryParse(Attribute.mobileMargin)
                 : double.tryParse(Attribute.margin)) ??
             0.0;
@@ -106,7 +106,7 @@ class QuillEditorImageEmbedBuilder extends EmbedBuilder {
     }
 
     if (!readOnly &&
-        (base.isMobile() ||
+        (base.isMobile(supportWeb: false) ||
             configurations.forceUseMobileOptionMenuForImageClick)) {
       return GestureDetector(
         onTap: () {
@@ -188,7 +188,8 @@ class QuillEditorImageEmbedBuilder extends EmbedBuilder {
                                       getImageStyleString(controller),
                                       width: w,
                                       height: h,
-                                      isMobile: base.isMobile(),
+                                      isMobile:
+                                          base.isMobile(supportWeb: false),
                                     );
                                     controller
                                       ..skipRequestKeyboard = true
@@ -220,7 +221,7 @@ class QuillEditorImageEmbedBuilder extends EmbedBuilder {
     if (!readOnly || isImageBase64(imageUrl)) {
       // To enforce using it on the desktop and other platforms
       // and that is up to the developer
-      if (!base.isMobile() &&
+      if (!base.isMobile(supportWeb: false) &&
           configurations.forceUseMobileOptionMenuForImageClick) {
         return _menuOptionsForReadonlyImage(
           context: context,
diff --git a/flutter_quill_extensions/lib/presentation/embeds/toolbar/image_button/select_image_source.dart b/flutter_quill_extensions/lib/presentation/embeds/toolbar/image_button/select_image_source.dart
index 8753bb87..5d1cf4b2 100644
--- a/flutter_quill_extensions/lib/presentation/embeds/toolbar/image_button/select_image_source.dart
+++ b/flutter_quill_extensions/lib/presentation/embeds/toolbar/image_button/select_image_source.dart
@@ -28,7 +28,7 @@ class SelectImageSourceDialog extends StatelessWidget {
                 'Take a photo using your phone camera',
               ),
               leading: const Icon(Icons.camera),
-              enabled: !isDesktop(),
+              enabled: !isDesktop(supportWeb: false),
               onTap: () => Navigator.of(context).pop(InsertImageSource.camera),
             ),
             ListTile(
diff --git a/flutter_quill_extensions/lib/presentation/embeds/toolbar/video_button/select_video_source.dart b/flutter_quill_extensions/lib/presentation/embeds/toolbar/video_button/select_video_source.dart
index da2fb8ef..8e2d34d5 100644
--- a/flutter_quill_extensions/lib/presentation/embeds/toolbar/video_button/select_video_source.dart
+++ b/flutter_quill_extensions/lib/presentation/embeds/toolbar/video_button/select_video_source.dart
@@ -28,7 +28,7 @@ class SelectVideoSourceDialog extends StatelessWidget {
                 'Record a video using your phone camera',
               ),
               leading: const Icon(Icons.camera),
-              enabled: !isDesktop(),
+              enabled: !isDesktop(supportWeb: false),
               onTap: () => Navigator.of(context).pop(InsertVideoSource.camera),
             ),
             ListTile(
diff --git a/flutter_quill_extensions/lib/presentation/models/config/editor/image/image.dart b/flutter_quill_extensions/lib/presentation/models/config/editor/image/image.dart
index f33913e7..3e159d0e 100644
--- a/flutter_quill_extensions/lib/presentation/models/config/editor/image/image.dart
+++ b/flutter_quill_extensions/lib/presentation/models/config/editor/image/image.dart
@@ -112,7 +112,11 @@ class QuillEditorImageEmbedConfigurations {
 
   static ImageEmbedBuilderOnRemovedCallback get defaultOnImageRemovedCallback {
     return (imageUrl) async {
-      final mobile = isMobile();
+      if (isWeb()) {
+        return;
+      }
+
+      final mobile = isMobile(supportWeb: false);
       // If the platform is not mobile, return void;
       // Since the mobile OS gives us a copy of the image
 
@@ -134,10 +138,6 @@ class QuillEditorImageEmbedConfigurations {
       // it without
       // permission
 
-      if (isWeb()) {
-        return;
-      }
-
       final dartIoImageFile = File(imageUrl);
 
       final isFileExists = await dartIoImageFile.exists();
diff --git a/lib/src/utils/platform.dart b/lib/src/utils/platform.dart
index 73a89fcb..020cfae3 100644
--- a/lib/src/utils/platform.dart
+++ b/lib/src/utils/platform.dart
@@ -4,62 +4,113 @@ import 'package:device_info_plus/device_info_plus.dart';
 import 'package:flutter/foundation.dart'
     show kIsWeb, TargetPlatform, defaultTargetPlatform;
 
-bool isWeb() {
-  return kIsWeb;
+/// If you want to override the [kIsWeb] use [overrideIsWeb]
+bool isWeb({bool? overrideIsWeb}) {
+  return overrideIsWeb ?? kIsWeb;
 }
 
-bool isMobile([TargetPlatform? targetPlatform]) {
-  if (isWeb()) return false;
-  targetPlatform ??= defaultTargetPlatform;
-  return {TargetPlatform.iOS, TargetPlatform.android}.contains(targetPlatform);
+/// [supportWeb] is a parameter that ask you if we should care about web support
+/// if the value is true then we will return the result no matter if we are
+/// on web or using a native app to run the flutter app
+bool isMobile({
+  required bool supportWeb,
+  TargetPlatform? platform,
+  bool? overrideIsWeb,
+}) {
+  if (isWeb(overrideIsWeb: overrideIsWeb) && !supportWeb) return false;
+  platform ??= defaultTargetPlatform;
+  return {TargetPlatform.iOS, TargetPlatform.android}.contains(platform);
 }
 
-bool isDesktop([TargetPlatform? targetPlatform]) {
-  if (isWeb()) return false;
-  targetPlatform ??= defaultTargetPlatform;
+/// [supportWeb] is a parameter that ask you if we should care about web support
+/// if the value is true then we will return the result no matter if we are
+/// on web or using a native app to run the flutter app
+bool isDesktop({
+  required bool supportWeb,
+  TargetPlatform? platform,
+  bool? overrideIsWeb,
+}) {
+  if (isWeb(overrideIsWeb: overrideIsWeb) && !supportWeb) return false;
+  platform ??= defaultTargetPlatform;
   return {TargetPlatform.macOS, TargetPlatform.linux, TargetPlatform.windows}
-      .contains(targetPlatform);
+      .contains(platform);
 }
 
-bool isKeyboardOS([TargetPlatform? targetPlatform]) {
-  targetPlatform ??= defaultTargetPlatform;
-  return isDesktop(targetPlatform) || targetPlatform == TargetPlatform.fuchsia;
+/// [supportWeb] is a parameter that ask you if we should care about web support
+/// if the value is true then we will return the result no matter if we are
+/// on web or using a native app to run the flutter app
+bool isKeyboardOS({
+  required bool supportWeb,
+  TargetPlatform? platform,
+  bool? overrideIsWeb,
+}) {
+  platform ??= defaultTargetPlatform;
+  return isDesktop(
+          platform: platform,
+          supportWeb: supportWeb,
+          overrideIsWeb: overrideIsWeb) ||
+      platform == TargetPlatform.fuchsia;
 }
 
-bool isAppleOS([TargetPlatform? targetPlatform]) {
-  if (isWeb()) return false;
-  targetPlatform ??= defaultTargetPlatform;
+/// [supportWeb] is a parameter that ask you if we should care about web support
+/// if the value is true then we will return the result no matter if we are
+/// on web or using a native app to run the flutter app
+bool isAppleOS({
+  required bool supportWeb,
+  TargetPlatform? platform,
+  bool? overrideIsWeb,
+}) {
+  if (isWeb(overrideIsWeb: overrideIsWeb) && !supportWeb) return false;
+  platform ??= defaultTargetPlatform;
   return {
     TargetPlatform.macOS,
     TargetPlatform.iOS,
-  }.contains(targetPlatform);
+  }.contains(platform);
 }
 
-bool isMacOS([TargetPlatform? targetPlatform]) {
-  if (isWeb()) return false;
-  targetPlatform ??= defaultTargetPlatform;
-  return TargetPlatform.macOS == targetPlatform;
+/// [supportWeb] is a parameter that ask you if we should care about web support
+/// if the value is true then we will return the result no matter if we are
+/// on web or using a native app to run the flutter app
+bool isMacOS({
+  required bool supportWeb,
+  TargetPlatform? platform,
+  bool? overrideIsWeb,
+}) {
+  if (isWeb(overrideIsWeb: overrideIsWeb) && !supportWeb) return false;
+  platform ??= defaultTargetPlatform;
+  return TargetPlatform.macOS == platform;
 }
 
-bool isIOS([TargetPlatform? targetPlatform]) {
-  if (isWeb()) return false;
-  targetPlatform ??= defaultTargetPlatform;
-  return TargetPlatform.iOS == targetPlatform;
+/// [supportWeb] is a parameter that ask you if we should care about web support
+/// if the value is true then we will return the result no matter if we are
+/// on web or using a native app to run the flutter app
+bool isIOS({
+  required bool supportWeb,
+  TargetPlatform? platform,
+  bool? overrideIsWeb,
+}) {
+  if (isWeb(overrideIsWeb: overrideIsWeb) && !supportWeb) return false;
+  platform ??= defaultTargetPlatform;
+  return TargetPlatform.iOS == platform;
 }
 
-bool isAndroid([TargetPlatform? targetPlatform]) {
-  if (isWeb()) return false;
-  targetPlatform ??= defaultTargetPlatform;
-  return TargetPlatform.android == targetPlatform;
+/// [supportWeb] is a parameter that ask you if we should care about web support
+/// if the value is true then we will return the result no matter if we are
+/// on web or using a native app to run the flutter app
+bool isAndroid({
+  required bool supportWeb,
+  TargetPlatform? platform,
+  bool? overrideIsWeb,
+}) {
+  if (isWeb(overrideIsWeb: overrideIsWeb) && !supportWeb) return false;
+  platform ??= defaultTargetPlatform;
+  return TargetPlatform.android == platform;
 }
 
-bool isFlutterTest() {
-  if (isWeb()) return false;
-  return Platform.environment.containsKey('FLUTTER_TEST');
-}
-
-Future<bool> isIOSSimulator() async {
-  if (!isAppleOS()) {
+Future<bool> isIOSSimulator({
+  bool? overrideIsWeb,
+}) async {
+  if (!isAppleOS(supportWeb: false, overrideIsWeb: overrideIsWeb)) {
     return false;
   }
 
@@ -73,3 +124,10 @@ Future<bool> isIOSSimulator() async {
   }
   return false;
 }
+
+bool isFlutterTest({
+  bool? overrideIsWeb,
+}) {
+  if (isWeb(overrideIsWeb: overrideIsWeb)) return false;
+  return Platform.environment.containsKey('FLUTTER_TEST');
+}
diff --git a/lib/src/widgets/cursor.dart b/lib/src/widgets/cursor.dart
index 293b2ec6..929118b1 100644
--- a/lib/src/widgets/cursor.dart
+++ b/lib/src/widgets/cursor.dart
@@ -291,7 +291,7 @@ class CursorPainter {
 
     final caretHeight = editable!.getFullHeightForCaret(position);
     if (caretHeight != null) {
-      if (isAppleOS()) {
+      if (isAppleOS(supportWeb: true)) {
         // Center the caret vertically along the text.
         caretRect = Rect.fromLTWH(
           caretRect.left,
diff --git a/lib/src/widgets/default_styles.dart b/lib/src/widgets/default_styles.dart
index 6af846eb..5d5949f8 100644
--- a/lib/src/widgets/default_styles.dart
+++ b/lib/src/widgets/default_styles.dart
@@ -204,7 +204,7 @@ class DefaultStyles {
     );
     const baseSpacing = VerticalSpacing(6, 0);
     String fontFamily;
-    if (isAppleOS(themeData.platform)) {
+    if (isAppleOS(platform: themeData.platform, supportWeb: true)) {
       fontFamily = 'Menlo';
     } else {
       fontFamily = 'Roboto Mono';
diff --git a/lib/src/widgets/delegate.dart b/lib/src/widgets/delegate.dart
index f595beff..5d021606 100644
--- a/lib/src/widgets/delegate.dart
+++ b/lib/src/widgets/delegate.dart
@@ -331,7 +331,9 @@ class EditorTextSelectionGestureDetectorBuilder {
   @protected
   void onDragSelectionEnd(DragEndDetails details) {
     renderEditor!.handleDragEnd(details);
-    if (isDesktop() &&
+    // TODO: Should we care if the platform is desktop using native desktop app
+    // or the flutter app is running using web app??
+    if (isDesktop(supportWeb: true) &&
         delegate.selectionEnabled &&
         shouldShowSelectionToolbar) {
       // added to show selection copy/paste toolbar after drag to select
diff --git a/lib/src/widgets/editor/editor.dart b/lib/src/widgets/editor/editor.dart
index 9d20a552..dea30332 100644
--- a/lib/src/widgets/editor/editor.dart
+++ b/lib/src/widgets/editor/editor.dart
@@ -215,7 +215,10 @@ class QuillEditorState extends State<QuillEditor>
     Color selectionColor;
     Radius? cursorRadius;
 
-    if (isAppleOS(theme.platform)) {
+    if (isAppleOS(
+      platform: theme.platform,
+      supportWeb: true,
+    )) {
       final cupertinoTheme = CupertinoTheme.of(context);
       textSelectionControls = cupertinoTextSelectionControls;
       paintCursorAboveText = true;
@@ -257,7 +260,10 @@ class QuillEditorState extends State<QuillEditor>
               ? (configurations.contextMenuBuilder ??
                   QuillRawEditor.defaultContextMenuBuilder)
               : null,
-          showSelectionHandles: isMobile(theme.platform),
+          showSelectionHandles: isMobile(
+            platform: theme.platform,
+            supportWeb: true,
+          ),
           showCursor: configurations.showCursor,
           cursorStyle: CursorStyle(
             color: cursorColor,
@@ -407,7 +413,10 @@ class _QuillEditorSelectionGestureDetectorBuilder
     }
 
     final platform = Theme.of(_state.context).platform;
-    if (isAppleOS(platform)) {
+    if (isAppleOS(
+      platform: platform,
+      supportWeb: true,
+    )) {
       renderEditor!.selectPositionAt(
         from: details.globalPosition,
         cause: SelectionChangedCause.longPress,
@@ -480,7 +489,8 @@ class _QuillEditorSelectionGestureDetectorBuilder
     try {
       if (delegate.selectionEnabled && !_isPositionSelected(details)) {
         final platform = Theme.of(_state.context).platform;
-        if (isAppleOS(platform) || isDesktop()) {
+        if (isAppleOS(platform: platform, supportWeb: true) ||
+            isDesktop(platform: platform, supportWeb: true)) {
           // added isDesktop() to enable extend selection in Windows platform
           switch (details.kind) {
             case PointerDeviceKind.mouse:
@@ -544,7 +554,10 @@ class _QuillEditorSelectionGestureDetectorBuilder
 
     if (delegate.selectionEnabled) {
       final platform = Theme.of(_state.context).platform;
-      if (isAppleOS(platform)) {
+      if (isAppleOS(
+        platform: platform,
+        supportWeb: true,
+      )) {
         renderEditor!.selectPositionAt(
           from: details.globalPosition,
           cause: SelectionChangedCause.longPress,
diff --git a/lib/src/widgets/raw_editor/raw_editor_state.dart b/lib/src/widgets/raw_editor/raw_editor_state.dart
index 9c903ee2..0775686c 100644
--- a/lib/src/widgets/raw_editor/raw_editor_state.dart
+++ b/lib/src/widgets/raw_editor/raw_editor_state.dart
@@ -185,10 +185,6 @@ class QuillRawEditorState extends EditorState
   }
 
   void _defaultOnTapOutside(PointerDownEvent event) {
-    if (isWeb()) {
-      widget.focusNode.unfocus();
-    }
-
     /// The focus dropping behavior is only present on desktop platforms
     /// and mobile browsers.
     switch (defaultTargetPlatform) {
@@ -322,7 +318,7 @@ class QuillRawEditorState extends EditorState
     // so if we ovveride the platform in material app theme data
     // it will not depend on it and doesn't change here but I don't think
     // we need to
-    final isDesktopMacOS = isMacOS();
+    final isDesktopMacOS = isMacOS(supportWeb: true);
 
     return TextFieldTapRegion(
       enabled: widget.enableUnfocusOnTapOutside,
@@ -859,7 +855,7 @@ class QuillRawEditorState extends EditorState
     _floatingCursorResetController = AnimationController(vsync: this);
     _floatingCursorResetController.addListener(onFloatingCursorResetTick);
 
-    if (isKeyboardOS()) {
+    if (isKeyboardOS(supportWeb: true)) {
       _keyboardVisible = true;
     } else if (!isWeb() && isFlutterTest()) {
       // treat tests like a keyboard OS
diff --git a/lib/src/widgets/text_line.dart b/lib/src/widgets/text_line.dart
index de0c24bb..0d1243d3 100644
--- a/lib/src/widgets/text_line.dart
+++ b/lib/src/widgets/text_line.dart
@@ -90,7 +90,7 @@ class _TextLineState extends State<TextLine> {
 
     // Desktop platforms (macOS, Linux, Windows):
     // only allow Meta (Control) + Click combinations
-    if (isDesktop()) {
+    if (isDesktop(supportWeb: false)) {
       return _metaOrControlPressed;
     }
     // Mobile platforms (ios, android): always allow but we install a
@@ -434,7 +434,7 @@ class _TextLineState extends State<TextLine> {
     }
 
     if (isLink && canLaunchLinks) {
-      if (isDesktop() || widget.readOnly) {
+      if (isDesktop(supportWeb: true) || widget.readOnly) {
         _linkRecognizers[segment] = TapGestureRecognizer()
           ..onTap = () => _tapNodeLink(segment);
       } else {
@@ -896,7 +896,7 @@ class RenderEditableTextLine extends RenderEditableBox {
   void _computeCaretPrototype() {
     // If the cursor is taller only on iOS and not AppleOS then we should check
     // only for iOS instead of AppleOS (macOS for example)
-    if (isIOS()) {
+    if (isIOS(supportWeb: true)) {
       _caretPrototype = Rect.fromLTWH(0, 0, cursorWidth, cursorHeight + 2);
     } else {
       _caretPrototype = Rect.fromLTWH(0, 2, cursorWidth, cursorHeight - 4.0);
diff --git a/pubspec.yaml b/pubspec.yaml
index 8cbbdbc7..18f2f9ce 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -55,6 +55,7 @@ dev_dependencies:
   flutter_test:
     sdk: flutter
   flutter_quill_test: ^0.0.4
+  test: ^1.24.3
 
 flutter:
   uses-material-design: true
\ No newline at end of file
diff --git a/test/utils/platform_test.dart b/test/utils/platform_test.dart
new file mode 100644
index 00000000..aafda16e
--- /dev/null
+++ b/test/utils/platform_test.dart
@@ -0,0 +1,156 @@
+import 'package:flutter/foundation.dart' show TargetPlatform;
+import 'package:flutter_quill/src/utils/platform.dart';
+import 'package:test/test.dart';
+
+void main() {
+  group('Test platform checking logic', () {
+    var platform = TargetPlatform.linux;
+    test('Check isDesktop()', () {
+      platform = TargetPlatform.android;
+      expect(
+        isDesktop(
+          platform: platform,
+          supportWeb: true,
+        ),
+        false,
+      );
+
+      for (final desktopPlatform in [
+        TargetPlatform.macOS,
+        TargetPlatform.linux,
+        TargetPlatform.windows
+      ]) {
+        expect(
+          isDesktop(
+            supportWeb: false,
+            platform: desktopPlatform,
+            overrideIsWeb: false,
+          ),
+          true,
+        );
+
+        expect(
+          isDesktop(
+            supportWeb: false,
+            overrideIsWeb: true,
+            platform: desktopPlatform,
+          ),
+          false,
+        );
+
+        expect(
+          isDesktop(
+            supportWeb: true,
+            overrideIsWeb: true,
+            platform: desktopPlatform,
+          ),
+          true,
+        );
+      }
+    });
+    test('Check isMobile()', () {
+      platform = TargetPlatform.macOS;
+      expect(
+        isMobile(
+          platform: platform,
+          supportWeb: true,
+        ),
+        false,
+      );
+
+      for (final mobilePlatform in [
+        TargetPlatform.android,
+        TargetPlatform.iOS,
+      ]) {
+        expect(
+          isMobile(
+            supportWeb: false,
+            platform: mobilePlatform,
+            overrideIsWeb: false,
+          ),
+          true,
+        );
+
+        expect(
+          isMobile(
+            supportWeb: false,
+            overrideIsWeb: true,
+            platform: mobilePlatform,
+          ),
+          false,
+        );
+
+        expect(
+          isMobile(
+            supportWeb: true,
+            overrideIsWeb: true,
+            platform: mobilePlatform,
+          ),
+          true,
+        );
+      }
+    });
+    test(
+      'Check supportWeb parameter when using desktop platform on web',
+      () {
+        platform = TargetPlatform.macOS;
+        expect(
+          isDesktop(
+            platform: platform,
+            supportWeb: true,
+          ),
+          true,
+        );
+        expect(
+          isDesktop(
+            platform: platform,
+            supportWeb: false,
+            overrideIsWeb: false,
+          ),
+          true,
+        );
+
+        expect(
+          isDesktop(
+            platform: platform,
+            supportWeb: false,
+            overrideIsWeb: true,
+          ),
+          false,
+        );
+      },
+    );
+
+    test(
+      'Check supportWeb parameter when using mobile platform on web',
+      () {
+        platform = TargetPlatform.android;
+        expect(
+          isMobile(
+            platform: platform,
+            supportWeb: true,
+            overrideIsWeb: true,
+          ),
+          true,
+        );
+        expect(
+          isMobile(
+            platform: platform,
+            supportWeb: false,
+            overrideIsWeb: false,
+          ),
+          true,
+        );
+
+        expect(
+          isMobile(
+            platform: platform,
+            supportWeb: false,
+            overrideIsWeb: true,
+          ),
+          false,
+        );
+      },
+    );
+  });
+}
diff --git a/test/widgets/controller_test.dart b/test/widgets/controller_test.dart
index 3decfc47..930cdccf 100644
--- a/test/widgets/controller_test.dart
+++ b/test/widgets/controller_test.dart
@@ -1,6 +1,6 @@
 import 'package:flutter/material.dart';
 import 'package:flutter_quill/flutter_quill.dart';
-import 'package:flutter_test/flutter_test.dart';
+import 'package:test/test.dart';
 
 void main() {
   const testDocumentContents = 'data';