Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add check for external keyboard on iOS(iPad). Replaced bool status with KeyboardVisibilityStatus which extended with iOS external keyboard #158

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
//

#import "FlutterKeyboardVisibilityPlugin.h"
#import <GameController/GameController.h>

@interface FlutterKeyboardVisibilityPlugin() <FlutterStreamHandler>

Expand All @@ -17,11 +18,33 @@ @interface FlutterKeyboardVisibilityPlugin() <FlutterStreamHandler>
@end


@interface KeyboardDetector : NSObject

+ (BOOL)isExternalKeyboardConnected;

@end

@implementation KeyboardDetector

+ (BOOL)isExternalKeyboardConnected {
// Check if GameController framework is available
if (@available(iOS 14.0, *)) {
GCKeyboard *coalescedKeyboard = [GCKeyboard coalescedKeyboard];
return (coalescedKeyboard != nil);
} else {
return NO; // GameController framework is not available before iOS 14
}
}

@end


@implementation FlutterKeyboardVisibilityPlugin


+(void) registerWithRegistrar:(NSObject<FlutterPluginRegistrar> *)registrar {
FlutterEventChannel *stream = [FlutterEventChannel eventChannelWithName:@"flutter_keyboard_visibility" binaryMessenger:[registrar messenger]];

FlutterKeyboardVisibilityPlugin *instance = [[FlutterKeyboardVisibilityPlugin alloc] init];
[stream setStreamHandler:instance];
}
Expand All @@ -46,7 +69,12 @@ - (void)didShow
if (!self.isVisible) {
self.isVisible = YES;
if (self.flutterEventListening) {
self.flutterEventSink([NSNumber numberWithInt:1]);
BOOL isExternalKeyboardConnected = [KeyboardDetector isExternalKeyboardConnected];
if (isExternalKeyboardConnected) {
self.flutterEventSink([NSNumber numberWithInt:2]);
} else {
self.flutterEventSink([NSNumber numberWithInt:1]);
}
}
}
}
Expand All @@ -57,7 +85,12 @@ - (void)willShow
if (!self.isVisible) {
self.isVisible = YES;
if (self.flutterEventListening) {
self.flutterEventSink([NSNumber numberWithInt:1]);
BOOL isExternalKeyboardConnected = [KeyboardDetector isExternalKeyboardConnected];
if (isExternalKeyboardConnected) {
self.flutterEventSink([NSNumber numberWithInt:2]);
} else {
self.flutterEventSink([NSNumber numberWithInt:1]);
}
}
}
}
Expand All @@ -79,7 +112,12 @@ -(FlutterError*)onListenWithArguments:(id)arguments eventSink:(FlutterEventSink)

// if keyboard is visible at startup, let our subscriber know
if (self.isVisible) {
self.flutterEventSink([NSNumber numberWithInt:1]);
BOOL isExternalKeyboardConnected = [KeyboardDetector isExternalKeyboardConnected];
if (isExternalKeyboardConnected) {
self.flutterEventSink([NSNumber numberWithInt:2]);
} else {
self.flutterEventSink([NSNumber numberWithInt:1]);
}
}

return nil;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ export 'package:flutter_keyboard_visibility/src/keyboard_visibility_test_util.da
export 'package:flutter_keyboard_visibility/src/ui/keyboard_dismiss_on_tap.dart';
export 'package:flutter_keyboard_visibility/src/ui/keyboard_visibility_builder.dart';
export 'package:flutter_keyboard_visibility/src/ui/keyboard_visibility_provider.dart';
export 'package:flutter_keyboard_visibility_platform_interface/flutter_keyboard_visibility_platform_interface.dart';
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import 'package:flutter_keyboard_visibility/src/keyboard_visibility_handler.dart';
import 'package:flutter_keyboard_visibility_platform_interface/flutter_keyboard_visibility_platform_interface.dart';

/// Provides direct information about keyboard visibility and allows you
/// to subscribe to changes.
Expand All @@ -16,7 +17,7 @@ class KeyboardVisibilityController {
static final KeyboardVisibilityController _instance =
KeyboardVisibilityController._();

Stream<bool> get onChange => KeyboardVisibilityHandler.onChange;
Stream<KeyboardVisibilityStatus> get onChange => KeyboardVisibilityHandler.onChange;

bool get isVisible => KeyboardVisibilityHandler.isVisible;
KeyboardVisibilityStatus get isVisible => KeyboardVisibilityHandler.isVisible;
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,40 +10,40 @@ class KeyboardVisibilityHandler {
static FlutterKeyboardVisibilityPlatform get _platform =>
FlutterKeyboardVisibilityPlatform.instance;

static bool _isInitialized = false;
static final _onChangeController = StreamController<bool>();
static KeyboardVisibilityStatus _isInitialized = KeyboardVisibilityStatus.notVisible;
static final _onChangeController = StreamController<KeyboardVisibilityStatus>();
static final _onChange = _onChangeController.stream.asBroadcastStream();

/// Emits true every time the keyboard is shown, and false every time the
/// keyboard is dismissed.
static Stream<bool> get onChange {
static Stream<KeyboardVisibilityStatus> get onChange {
// If _testIsVisible set, don't try to create the EventChannel
if (!_isInitialized && _testIsVisible == null) {
if (_isInitialized == KeyboardVisibilityStatus.notVisible && _testIsVisible == null) {
_platform.onChange.listen(_updateValue);
_isInitialized = true;
_isInitialized = KeyboardVisibilityStatus.visible;
}
return _onChange;
}

/// Returns true if the keyboard is currently visible, false if not.
static bool get isVisible => _testIsVisible ?? _isVisible;
static bool _isVisible = false;
static KeyboardVisibilityStatus get isVisible => _testIsVisible ?? _isVisible;
static KeyboardVisibilityStatus _isVisible = KeyboardVisibilityStatus.notVisible;

/// Fake representation of whether or not the keyboard is visible
/// for testing purposes. When this value is non-null, it will be
/// reported exclusively by the `isVisible` getter.
static bool? _testIsVisible;
static KeyboardVisibilityStatus? _testIsVisible;

/// Forces `KeyboardVisibilityHandler` to report `isKeyboardVisible`
/// for testing purposes.
///
/// `KeyboardVisibilityHandler` will continue reporting `isKeyboardVisible`
/// until the value is changed again with this method.
static void setVisibilityForTesting(bool isKeyboardVisible) {
static void setVisibilityForTesting(KeyboardVisibilityStatus isKeyboardVisible) {
_updateValue(isKeyboardVisible);
}

static void _updateValue(bool newValue) {
static void _updateValue(KeyboardVisibilityStatus newValue) {
_testIsVisible = newValue;

// Don't report the same value multiple times
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:flutter_keyboard_visibility/src/keyboard_visibility_handler.dart';
import 'package:flutter_keyboard_visibility_platform_interface/flutter_keyboard_visibility_platform_interface.dart';

@visibleForTesting
class KeyboardVisibilityTesting {
Expand All @@ -9,7 +10,7 @@ class KeyboardVisibilityTesting {
/// `KeyboardVisibility` will continue reporting `isKeyboardVisible`
/// until the value is changed again with this method.
@visibleForTesting
static void setVisibilityForTesting(bool isKeyboardVisible) {
static void setVisibilityForTesting(KeyboardVisibilityStatus isKeyboardVisible) {
KeyboardVisibilityHandler.setVisibilityForTesting(isKeyboardVisible);
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import 'package:flutter/widgets.dart';
import 'package:flutter_keyboard_visibility/src/keyboard_visibility_controller.dart';
import 'package:flutter_keyboard_visibility_platform_interface/flutter_keyboard_visibility_platform_interface.dart';

/// A convenience builder that exposes if the native keyboard is visible.
class KeyboardVisibilityBuilder extends StatelessWidget {
Expand All @@ -18,18 +19,18 @@ class KeyboardVisibilityBuilder extends StatelessWidget {
}) : super(key: key);

/// A builder method that exposes if the native keyboard is visible.
final Widget Function(BuildContext, bool isKeyboardVisible) builder;
final Widget Function(BuildContext, KeyboardVisibilityStatus isKeyboardVisible) builder;

@override
Widget build(BuildContext context) {
return StreamBuilder<bool>(
return StreamBuilder<KeyboardVisibilityStatus>(
stream: _controller.onChange,
initialData: _controller.isVisible,
builder: (context, snapshot) {
if (snapshot.data != null) {
return builder(context, snapshot.data!);
} else {
return builder(context, false);
return builder(context, KeyboardVisibilityStatus.notVisible);
}
},
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import 'dart:async';
import 'package:flutter/widgets.dart';
import 'package:flutter_keyboard_visibility/src/keyboard_visibility_controller.dart';
import 'package:flutter_keyboard_visibility_platform_interface/flutter_keyboard_visibility_platform_interface.dart';

/// Widget that reports to its descendants whether or not
/// the keyboard is currently visible.
Expand All @@ -16,7 +17,7 @@ import 'package:flutter_keyboard_visibility/src/keyboard_visibility_controller.d
/// return KeyboardVisibilityProvider(
/// child: Builder(
/// builder: (BuildContext context) {
/// final bool isKeyboardVisible = KeyboardVisibilityProvider.isKeyboardVisible(context);
/// final KeyboardVisibilityStatus isKeyboardVisible = KeyboardVisibilityProvider.isKeyboardVisible(context);
///
/// return Text('Keyboard is visible: $isKeyboardVisible');
/// },
Expand Down Expand Up @@ -48,7 +49,7 @@ class KeyboardVisibilityProvider extends StatefulWidget {
/// This method also establishes an `InheritedWidget` dependency
/// with the given `context`, and therefore the given `context`
/// will automatically rebuild if the keyboard visibility changes.
static bool isKeyboardVisible(BuildContext context) {
static KeyboardVisibilityStatus isKeyboardVisible(BuildContext context) {
return context
.dependOnInheritedWidgetOfExactType<
_KeyboardVisibilityInheritedWidget>()!
Expand All @@ -63,7 +64,7 @@ class KeyboardVisibilityProvider extends StatefulWidget {
class _KeyboardVisibilityProviderState
extends State<KeyboardVisibilityProvider> {
late StreamSubscription _subscription;
bool _isKeyboardVisible = false;
KeyboardVisibilityStatus _isKeyboardVisible = KeyboardVisibilityStatus.notVisible;

@override
void initState() {
Expand All @@ -73,7 +74,7 @@ class _KeyboardVisibilityProviderState
widget._controller.onChange.listen(_onKeyboardVisibilityChange);
}

void _onKeyboardVisibilityChange(bool isKeyboardVisible) {
void _onKeyboardVisibilityChange(KeyboardVisibilityStatus isKeyboardVisible) {
setState(() {
_isKeyboardVisible = isKeyboardVisible;
});
Expand Down Expand Up @@ -103,7 +104,7 @@ class _KeyboardVisibilityInheritedWidget extends InheritedWidget {
required Widget child,
}) : super(key: key, child: child);

final bool isKeyboardVisible;
final KeyboardVisibilityStatus isKeyboardVisible;

@override
bool updateShouldNotify(_KeyboardVisibilityInheritedWidget oldWidget) {
Expand Down
32 changes: 27 additions & 5 deletions flutter_keyboard_visibility/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,39 @@ version: 6.0.0
homepage: https://github.com/MisterJimson/flutter_keyboard_visibility
repository: https://github.com/MisterJimson/flutter_keyboard_visibility

publish_to: 'none' # TODO: remove on fork merge

environment:
sdk: '>=2.12.0 <4.0.0'
flutter: ">=1.20.0"

dependencies:
meta: ">=1.0.0 <2.0.0"
flutter_keyboard_visibility_platform_interface: ^2.0.0
flutter_keyboard_visibility_linux: ^1.0.0
flutter_keyboard_visibility_macos: ^1.0.0
flutter_keyboard_visibility_web: ^2.0.0
flutter_keyboard_visibility_windows: ^1.0.0
flutter_keyboard_visibility_platform_interface:
git:
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the reviewers have the ability to test it via current working pubspec dependencies.
After I get an approval for this PR, I will revert pubspec changes

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@MisterJimson
also, if you are satisfied with general idea, I will update all places of the doc comments across the package to the status instead of isKeyboardVisible

url: https://github.com/HaltiaAI/flutter_keyboard_visibility.git
ref: feature/detect_ipad_external_keyboard
path: flutter_keyboard_visibility_platform_interface
flutter_keyboard_visibility_linux:
git:
url: https://github.com/HaltiaAI/flutter_keyboard_visibility.git
ref: feature/detect_ipad_external_keyboard
path: flutter_keyboard_visibility_linux
flutter_keyboard_visibility_macos:
git:
url: https://github.com/HaltiaAI/flutter_keyboard_visibility.git
ref: feature/detect_ipad_external_keyboard
path: flutter_keyboard_visibility_macos
flutter_keyboard_visibility_web:
git:
url: https://github.com/HaltiaAI/flutter_keyboard_visibility.git
ref: feature/detect_ipad_external_keyboard
path: flutter_keyboard_visibility_web
flutter_keyboard_visibility_windows:
git:
url: https://github.com/HaltiaAI/flutter_keyboard_visibility.git
ref: feature/detect_ipad_external_keyboard
path: flutter_keyboard_visibility_windows
flutter:
sdk: flutter

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ class FlutterKeyboardVisibilityPluginLinux
}

/// Emits changes to keyboard visibility from the platform. Linux is not
/// implemented yet so false is returned.
/// implemented yet so `notVisible` is returned.
@override
Stream<bool> get onChange async* {
yield false;
Stream<KeyboardVisibilityStatus> get onChange async* {
yield KeyboardVisibilityStatus.notVisible;
}
}
8 changes: 7 additions & 1 deletion flutter_keyboard_visibility_linux/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ version: 1.0.0
homepage: https://github.com/MisterJimson/flutter_keyboard_visibility
repository: https://github.com/MisterJimson/flutter_keyboard_visibility

publish_to: 'none' # TODO: remove on fork merge

environment:
sdk: '>=2.12.0 <4.0.0'
flutter: '>=1.20.0'
Expand All @@ -16,7 +18,11 @@ flutter:
dartPluginClass: FlutterKeyboardVisibilityPluginLinux

dependencies:
flutter_keyboard_visibility_platform_interface: ^2.0.0
flutter_keyboard_visibility_platform_interface:
git:
url: https://github.com/HaltiaAI/flutter_keyboard_visibility.git
ref: feature/detect_ipad_external_keyboard
path: flutter_keyboard_visibility_platform_interface
flutter:
sdk: flutter

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ class FlutterKeyboardVisibilityPluginMacos
}

/// Emits changes to keyboard visibility from the platform. MacOS is not
/// implemented yet so false is returned.
/// implemented yet so `notVisible` is returned.
@override
Stream<bool> get onChange async* {
yield false;
Stream<KeyboardVisibilityStatus> get onChange async* {
yield KeyboardVisibilityStatus.notVisible;
}
}
8 changes: 7 additions & 1 deletion flutter_keyboard_visibility_macos/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ version: 1.0.0
homepage: https://github.com/MisterJimson/flutter_keyboard_visibility
repository: https://github.com/MisterJimson/flutter_keyboard_visibility

publish_to: 'none' # TODO: remove on fork merge

environment:
sdk: '>=2.12.0 <4.0.0'
flutter: ">=1.20.0"
Expand All @@ -16,7 +18,11 @@ flutter:
dartPluginClass: FlutterKeyboardVisibilityPluginMacos

dependencies:
flutter_keyboard_visibility_platform_interface: ^2.0.0
flutter_keyboard_visibility_platform_interface:
git:
url: https://github.com/HaltiaAI/flutter_keyboard_visibility.git
ref: feature/detect_ipad_external_keyboard
path: flutter_keyboard_visibility_platform_interface
flutter:
sdk: flutter

Expand Down
Loading