From 9e19a3584a4a3514e08564be9635ad3714c5b4de Mon Sep 17 00:00:00 2001 From: Albin <56157868+albinpk@users.noreply.github.com> Date: Fri, 12 Dec 2025 22:45:22 +0530 Subject: [PATCH 1/3] chore: add example app to workspace --- .fvmrc | 2 +- .../example/pubspec.lock | 204 ------------------ .../example/pubspec.yaml | 2 + pubspec.yaml | 1 + 4 files changed, 4 insertions(+), 205 deletions(-) delete mode 100644 packages/flutter_onscreen_keyboard/example/pubspec.lock diff --git a/.fvmrc b/.fvmrc index 9bf4ad9..5d5dd6e 100644 --- a/.fvmrc +++ b/.fvmrc @@ -1,3 +1,3 @@ { - "flutter": "3.38.3" + "flutter": "3.38.4" } diff --git a/packages/flutter_onscreen_keyboard/example/pubspec.lock b/packages/flutter_onscreen_keyboard/example/pubspec.lock deleted file mode 100644 index 854e48e..0000000 --- a/packages/flutter_onscreen_keyboard/example/pubspec.lock +++ /dev/null @@ -1,204 +0,0 @@ -# Generated by pub -# See https://dart.dev/tools/pub/glossary#lockfile -packages: - async: - dependency: transitive - description: - name: async - sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb" - url: "https://pub.dev" - source: hosted - version: "2.13.0" - boolean_selector: - dependency: transitive - description: - name: boolean_selector - sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea" - url: "https://pub.dev" - source: hosted - version: "2.1.2" - characters: - dependency: transitive - description: - name: characters - sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803 - url: "https://pub.dev" - source: hosted - version: "1.4.0" - clock: - dependency: transitive - description: - name: clock - sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b - url: "https://pub.dev" - source: hosted - version: "1.1.2" - collection: - dependency: transitive - description: - name: collection - sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" - url: "https://pub.dev" - source: hosted - version: "1.19.1" - fake_async: - dependency: transitive - description: - name: fake_async - sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44" - url: "https://pub.dev" - source: hosted - version: "1.3.3" - flutter: - dependency: "direct main" - description: flutter - source: sdk - version: "0.0.0" - flutter_onscreen_keyboard: - dependency: "direct main" - description: - path: ".." - relative: true - source: path - version: "0.4.1" - flutter_test: - dependency: "direct dev" - description: flutter - source: sdk - version: "0.0.0" - leak_tracker: - dependency: transitive - description: - name: leak_tracker - sha256: "33e2e26bdd85a0112ec15400c8cbffea70d0f9c3407491f672a2fad47915e2de" - url: "https://pub.dev" - source: hosted - version: "11.0.2" - leak_tracker_flutter_testing: - dependency: transitive - description: - name: leak_tracker_flutter_testing - sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1" - url: "https://pub.dev" - source: hosted - version: "3.0.10" - leak_tracker_testing: - dependency: transitive - description: - name: leak_tracker_testing - sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1" - url: "https://pub.dev" - source: hosted - version: "3.0.2" - matcher: - dependency: transitive - description: - name: matcher - sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2 - url: "https://pub.dev" - source: hosted - version: "0.12.17" - material_color_utilities: - dependency: transitive - description: - name: material_color_utilities - sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec - url: "https://pub.dev" - source: hosted - version: "0.11.1" - meta: - dependency: transitive - description: - name: meta - sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394" - url: "https://pub.dev" - source: hosted - version: "1.17.0" - path: - dependency: transitive - description: - name: path - sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" - url: "https://pub.dev" - source: hosted - version: "1.9.1" - sky_engine: - dependency: transitive - description: flutter - source: sdk - version: "0.0.0" - source_span: - dependency: transitive - description: - name: source_span - sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c" - url: "https://pub.dev" - source: hosted - version: "1.10.1" - stack_trace: - dependency: transitive - description: - name: stack_trace - sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1" - url: "https://pub.dev" - source: hosted - version: "1.12.1" - stream_channel: - dependency: transitive - description: - name: stream_channel - sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d" - url: "https://pub.dev" - source: hosted - version: "2.1.4" - string_scanner: - dependency: transitive - description: - name: string_scanner - sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43" - url: "https://pub.dev" - source: hosted - version: "1.4.1" - term_glyph: - dependency: transitive - description: - name: term_glyph - sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e" - url: "https://pub.dev" - source: hosted - version: "1.2.2" - test_api: - dependency: transitive - description: - name: test_api - sha256: ab2726c1a94d3176a45960b6234466ec367179b87dd74f1611adb1f3b5fb9d55 - url: "https://pub.dev" - source: hosted - version: "0.7.7" - vector_math: - dependency: transitive - description: - name: vector_math - sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b - url: "https://pub.dev" - source: hosted - version: "2.2.0" - very_good_analysis: - dependency: "direct dev" - description: - name: very_good_analysis - sha256: "96245839dbcc45dfab1af5fa551603b5c7a282028a64746c19c547d21a7f1e3a" - url: "https://pub.dev" - source: hosted - version: "10.0.0" - vm_service: - dependency: transitive - description: - name: vm_service - sha256: "45caa6c5917fa127b5dbcfbd1fa60b14e583afdc08bfc96dda38886ca252eb60" - url: "https://pub.dev" - source: hosted - version: "15.0.2" -sdks: - dart: ">=3.9.0 <4.0.0" - flutter: ">=3.18.0-18.0.pre.54" diff --git a/packages/flutter_onscreen_keyboard/example/pubspec.yaml b/packages/flutter_onscreen_keyboard/example/pubspec.yaml index 0ef1751..7c5e231 100644 --- a/packages/flutter_onscreen_keyboard/example/pubspec.yaml +++ b/packages/flutter_onscreen_keyboard/example/pubspec.yaml @@ -3,6 +3,8 @@ description: "A new Flutter project." publish_to: "none" version: 0.1.0 +resolution: workspace + environment: sdk: ^3.8.1 diff --git a/pubspec.yaml b/pubspec.yaml index ba22ffc..c5e9fb6 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -7,6 +7,7 @@ environment: workspace: - packages/flutter_onscreen_keyboard + - packages/flutter_onscreen_keyboard/example dev_dependencies: melos: ^7.0.0 From 69b05bc0e7961e13409e68aa16e97ab3d696e4b9 Mon Sep 17 00:00:00 2001 From: Albin <56157868+albinpk@users.noreply.github.com> Date: Fri, 12 Dec 2025 22:54:55 +0530 Subject: [PATCH 2/3] feat: add `useSafeArea` to `OnscreenKeyboardThemeData` --- .../lib/src/onscreen_keyboard.dart | 276 +++++++++--------- .../theme/onscreen_keyboard_theme_data.dart | 6 + 2 files changed, 152 insertions(+), 130 deletions(-) diff --git a/packages/flutter_onscreen_keyboard/lib/src/onscreen_keyboard.dart b/packages/flutter_onscreen_keyboard/lib/src/onscreen_keyboard.dart index ac3c41c..ece803d 100644 --- a/packages/flutter_onscreen_keyboard/lib/src/onscreen_keyboard.dart +++ b/packages/flutter_onscreen_keyboard/lib/src/onscreen_keyboard.dart @@ -444,146 +444,162 @@ class _OnscreenKeyboardState extends State // keyboard if (_visible) Positioned.fill( - child: SafeArea( - child: Builder( - builder: (context) { - // drag handle keyboard widget - final dragHandle = GestureDetector( - onPanStart: (_) => _draggingListener.value = true, - onPanCancel: () => - _draggingListener.value = false, - onPanDown: (_) => _draggingListener.value = true, - onPanEnd: (_) => _draggingListener.value = false, - onPanUpdate: (details) { - final keyboardSize = - _keyboardKey.currentContext!.size!; - _alignListener.value = ( - (_alignListener.value.$1 + - details.delta.dx / - (context.size!.width - - keyboardSize.width)) - .clamp(0.0, 1.0), - (_alignListener.value.$2 + - details.delta.dy / - (context.size!.height - - keyboardSize.height)) - .clamp(0.0, 1.0), + child: Builder( + builder: (context) { + final useSaveArea = context.theme.useSafeArea ?? true; + return SafeArea( + top: useSaveArea, + right: useSaveArea, + bottom: useSaveArea, + left: useSaveArea, + child: Builder( + builder: (context) { + // drag handle keyboard widget + final dragHandle = GestureDetector( + onPanStart: (_) => + _draggingListener.value = true, + onPanCancel: () => + _draggingListener.value = false, + onPanDown: (_) => + _draggingListener.value = true, + onPanEnd: (_) => + _draggingListener.value = false, + onPanUpdate: (details) { + final keyboardSize = + _keyboardKey.currentContext!.size!; + _alignListener.value = ( + (_alignListener.value.$1 + + details.delta.dx / + (context.size!.width - + keyboardSize.width)) + .clamp(0.0, 1.0), + (_alignListener.value.$2 + + details.delta.dy / + (context.size!.height - + keyboardSize.height)) + .clamp(0.0, 1.0), + ); + }, + child: ValueListenableBuilder( + valueListenable: _draggingListener, + builder: (context, value, child) { + // user defined drag handle + if (child != null) return child; + return IconButton( + mouseCursor: value + ? SystemMouseCursors.grabbing + : SystemMouseCursors.grab, + onPressed: null, + icon: Icon( + Icons.drag_handle_rounded, + color: Theme.of( + context, + ).iconTheme.color, + ), + ); + }, + child: widget.dragHandle, + ), ); - }, - child: ValueListenableBuilder( - valueListenable: _draggingListener, - builder: (context, value, child) { - // user defined drag handle - if (child != null) return child; - return IconButton( - mouseCursor: value - ? SystemMouseCursors.grabbing - : SystemMouseCursors.grab, - onPressed: null, - icon: Icon( - Icons.drag_handle_rounded, - color: Theme.of(context).iconTheme.color, - ), - ); - }, - child: widget.dragHandle, - ), - ); - - // keyboard widget - final keyboard = TextFieldTapRegion( - // theme override for modes - child: OnscreenKeyboardTheme( - data: - _layout.modes[_mode]!.theme?.call( - context, - ) ?? - context.theme, - child: Builder( - key: _keyboardKey, - builder: (context) { - final colors = Theme.of( - context, - ).colorScheme; - final theme = context.theme; - final borderRadius = - theme.borderRadius ?? - BorderRadius.circular(6); - return Material( - type: MaterialType.transparency, - child: Container( - width: widget.width?.call(context), - margin: theme.margin, - padding: theme.padding, - clipBehavior: Clip.hardEdge, - decoration: BoxDecoration( - color: theme.color, - borderRadius: borderRadius, - gradient: theme.gradient, - boxShadow: - theme.boxShadow ?? - [ - BoxShadow( - color: colors.shadow.fade( - 0.05, + + // keyboard widget + final keyboard = TextFieldTapRegion( + // theme override for modes + child: OnscreenKeyboardTheme( + data: + _layout.modes[_mode]!.theme?.call( + context, + ) ?? + context.theme, + child: Builder( + key: _keyboardKey, + builder: (context) { + final colors = Theme.of( + context, + ).colorScheme; + final theme = context.theme; + final borderRadius = + theme.borderRadius ?? + BorderRadius.circular(6); + return Material( + type: MaterialType.transparency, + child: Container( + width: widget.width?.call(context), + margin: theme.margin, + padding: theme.padding, + clipBehavior: Clip.hardEdge, + decoration: BoxDecoration( + color: theme.color, + borderRadius: borderRadius, + gradient: theme.gradient, + boxShadow: + theme.boxShadow ?? + [ + BoxShadow( + color: colors.shadow.fade( + 0.05, + ), + spreadRadius: 5, + blurRadius: 5, + ), + ], + ), + foregroundDecoration: BoxDecoration( + borderRadius: borderRadius, + border: + theme.border ?? + Border.all( + color: colors.outline + .fade(), + ), + ), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + if (widget.showControlBar) + _ControlBar( + dragHandle: dragHandle, + actions: widget + .buildControlBarActions + ?.call(context), ), - spreadRadius: 5, - blurRadius: 5, + RawOnscreenKeyboard( + aspectRatio: + widget.aspectRatio, + onKeyDown: _onKeyDown, + onKeyUp: _onKeyUp, + layout: _layout, + mode: _mode, + pressedActionKeys: + _pressedActionKeys, + showSecondary: _showSecondary, ), ], - ), - foregroundDecoration: BoxDecoration( - borderRadius: borderRadius, - border: - theme.border ?? - Border.all( - color: colors.outline.fade(), - ), - ), - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - if (widget.showControlBar) - _ControlBar( - dragHandle: dragHandle, - actions: widget - .buildControlBarActions - ?.call(context), - ), - RawOnscreenKeyboard( - aspectRatio: widget.aspectRatio, - onKeyDown: _onKeyDown, - onKeyUp: _onKeyUp, - layout: _layout, - mode: _mode, - pressedActionKeys: - _pressedActionKeys, - showSecondary: _showSecondary, ), - ], - ), + ), + ); + }, + ), + ), + ); + + return AnimatedBuilder( + animation: _alignListener, + builder: (context, child) { + return Align( + alignment: Alignment( + _alignListener.value.$1 * 2 - 1, + _alignListener.value.$2 * 2 - 1, ), + child: child, ); }, - ), - ), - ); - - return AnimatedBuilder( - animation: _alignListener, - builder: (context, child) { - return Align( - alignment: Alignment( - _alignListener.value.$1 * 2 - 1, - _alignListener.value.$2 * 2 - 1, - ), - child: child, + child: keyboard, ); }, - child: keyboard, - ); - }, - ), + ), + ); + }, ), ), ], diff --git a/packages/flutter_onscreen_keyboard/lib/src/theme/onscreen_keyboard_theme_data.dart b/packages/flutter_onscreen_keyboard/lib/src/theme/onscreen_keyboard_theme_data.dart index 61ccae8..7d21881 100644 --- a/packages/flutter_onscreen_keyboard/lib/src/theme/onscreen_keyboard_theme_data.dart +++ b/packages/flutter_onscreen_keyboard/lib/src/theme/onscreen_keyboard_theme_data.dart @@ -21,6 +21,7 @@ class OnscreenKeyboardThemeData { this.textKeyThemeData = const TextKeyThemeData(), this.actionKeyThemeData = const ActionKeyThemeData(), this.controlBarColor, + this.useSafeArea, }); /// The background color of the keyboard. @@ -53,6 +54,9 @@ class OnscreenKeyboardThemeData { /// The background color of the control bar. final Color? controlBarColor; + /// Whether to wrap the keyboard in a [SafeArea] widget. Defaults to `true`. + final bool? useSafeArea; + /// Copies the current [OnscreenKeyboardThemeData] with the provided changes. OnscreenKeyboardThemeData copyWith({ Color? color, @@ -65,6 +69,7 @@ class OnscreenKeyboardThemeData { TextKeyThemeData? textKeyThemeData, ActionKeyThemeData? actionKeyThemeData, Color? controlBarColor, + bool? useSafeArea, }) { return OnscreenKeyboardThemeData( color: color ?? this.color, @@ -77,6 +82,7 @@ class OnscreenKeyboardThemeData { textKeyThemeData: textKeyThemeData ?? this.textKeyThemeData, actionKeyThemeData: actionKeyThemeData ?? this.actionKeyThemeData, controlBarColor: controlBarColor ?? this.controlBarColor, + useSafeArea: useSafeArea ?? this.useSafeArea, ); } From 9eaf9861a88eaf2b60c519c5cb46fc8eb855e263 Mon Sep 17 00:00:00 2001 From: Albin <56157868+albinpk@users.noreply.github.com> Date: Fri, 12 Dec 2025 22:57:06 +0530 Subject: [PATCH 3/3] chore: upgrade dependencies --- pubspec.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pubspec.lock b/pubspec.lock index da57c71..96eaaf6 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -420,10 +420,10 @@ packages: dependency: transitive description: name: yaml_edit - sha256: fb38626579fb345ad00e674e2af3a5c9b0cc4b9bfb8fd7f7ff322c7c9e62aef5 + sha256: ec709065bb2c911b336853b67f3732dd13e0336bd065cc2f1061d7610ddf45e3 url: "https://pub.dev" source: hosted - version: "2.2.2" + version: "2.2.3" sdks: dart: ">=3.9.0 <4.0.0" flutter: ">=3.18.0-18.0.pre.54"