Skip to content

Commit 1c85a4a

Browse files
committed
refactor: replace react-native-haptic-feedback and expo-haptics with native implementation
Remove third-party haptic feedback dependencies (react-native-haptic-feedback, expo-haptics) and replace them with a built-in native module using the existing shared-native pattern (Swift + Kotlin).
1 parent 8d003bc commit 1c85a4a

File tree

14 files changed

+168
-97
lines changed

14 files changed

+168
-97
lines changed

examples/SampleApp/package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,6 @@
5656
"react-native-blob-util": "^0.22.2",
5757
"react-native-fast-image": "^8.6.3",
5858
"react-native-gesture-handler": "^2.31.0",
59-
"react-native-haptic-feedback": "^2.3.3",
6059
"react-native-image-picker": "^8.2.1",
6160
"react-native-maps": "1.20.1",
6261
"react-native-nitro-modules": "^0.31.3",

examples/TypeScriptMessaging/package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@
2828
"react-native-audio-recorder-player": "^3.6.13",
2929
"react-native-blob-util": "^0.22.2",
3030
"react-native-gesture-handler": "^2.26.0",
31-
"react-native-haptic-feedback": "^2.3.3",
3231
"react-native-image-picker": "^8.2.1",
3332
"react-native-reanimated": "^4.0.1",
3433
"react-native-safe-area-context": "^5.4.1",

package/expo-package/android/src/main/java/com/streamchatexpo/StreamChatExpoPackage.java

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,14 @@
1515

1616
public class StreamChatExpoPackage extends TurboReactPackage {
1717
private static final String STREAM_VIDEO_THUMBNAIL_MODULE = "StreamVideoThumbnail";
18+
private static final String STREAM_HAPTIC_FEEDBACK_MODULE = "StreamHapticFeedback";
1819

1920
@Nullable
2021
@Override
2122
public NativeModule getModule(String name, ReactApplicationContext reactContext) {
22-
if (name.equals(STREAM_VIDEO_THUMBNAIL_MODULE) && BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
23+
if (name.equals(STREAM_HAPTIC_FEEDBACK_MODULE)) {
24+
return new StreamHapticFeedbackModule(reactContext);
25+
} else if (name.equals(STREAM_VIDEO_THUMBNAIL_MODULE) && BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
2326
return createNewArchModule("com.streamchatexpo.StreamVideoThumbnailModule", reactContext);
2427
}
2528

@@ -31,6 +34,17 @@ public ReactModuleInfoProvider getReactModuleInfoProvider() {
3134
return () -> {
3235
final Map<String, ReactModuleInfo> moduleInfos = new HashMap<>();
3336
boolean isTurboModule = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED;
37+
moduleInfos.put(
38+
STREAM_HAPTIC_FEEDBACK_MODULE,
39+
new ReactModuleInfo(
40+
STREAM_HAPTIC_FEEDBACK_MODULE,
41+
STREAM_HAPTIC_FEEDBACK_MODULE,
42+
false, // canOverrideExistingModule
43+
false, // needsEagerInit
44+
false, // hasConstants
45+
false, // isCxxModule
46+
false // isTurboModule
47+
));
3448
moduleInfos.put(
3549
STREAM_VIDEO_THUMBNAIL_MODULE,
3650
new ReactModuleInfo(
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package com.streamchatexpo
2+
3+
import com.facebook.react.bridge.ReactApplicationContext
4+
import com.facebook.react.bridge.ReactContextBaseJavaModule
5+
import com.facebook.react.bridge.ReactMethod
6+
import com.streamchatreactnative.shared.StreamHapticFeedback
7+
8+
class StreamHapticFeedbackModule(
9+
reactContext: ReactApplicationContext,
10+
) : ReactContextBaseJavaModule(reactContext) {
11+
override fun getName(): String = NAME
12+
13+
@ReactMethod
14+
fun triggerHaptic(type: String) {
15+
StreamHapticFeedback.trigger(currentActivity, type)
16+
}
17+
18+
companion object {
19+
const val NAME = "StreamHapticFeedback"
20+
}
21+
}

package/expo-package/package.json

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@
3636
"expo-clipboard": "*",
3737
"expo-document-picker": "*",
3838
"expo-file-system": "*",
39-
"expo-haptics": "*",
4039
"expo-image-manipulator": "*",
4140
"expo-image-picker": "*",
4241
"expo-media-library": "*",
@@ -74,9 +73,6 @@
7473
},
7574
"expo-sharing": {
7675
"optional": true
77-
},
78-
"expo-haptics": {
79-
"optional": true
8076
}
8177
},
8278
"devDependencies": {
Lines changed: 5 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,9 @@
1-
let Haptics;
1+
import { NativeModules } from 'react-native';
22

3-
try {
4-
Haptics = require('expo-haptics');
5-
} catch (e) {
6-
// do nothing
7-
}
3+
const { StreamHapticFeedback } = NativeModules;
84

9-
if (!Haptics) {
10-
console.log(
11-
'expo-haptics is not installed. Installing this package will enable haptic feedback when scaling images in the image gallery if the scaling hits the higher or lower limits for its value.',
12-
);
13-
}
14-
15-
type HapticFeedbackTypes =
16-
| 'impactHeavy'
17-
| 'impactLight'
18-
| 'impactMedium'
19-
| 'notificationError'
20-
| 'notificationSuccess'
21-
| 'notificationWarning';
22-
23-
export const triggerHaptic = Haptics
24-
? (method: HapticFeedbackTypes) => {
25-
switch (method) {
26-
case 'impactHeavy':
27-
Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Heavy);
28-
break;
29-
case 'impactLight':
30-
Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light);
31-
break;
32-
case 'impactMedium':
33-
Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Medium);
34-
break;
35-
case 'notificationError':
36-
Haptics.notificationAsync(Haptics.NotificationFeedbackType.Error);
37-
break;
38-
case 'notificationSuccess':
39-
Haptics.notificationAsync(Haptics.NotificationFeedbackType.Success);
40-
break;
41-
case 'notificationWarning':
42-
Haptics.notificationAsync(Haptics.NotificationFeedbackType.Warning);
43-
break;
44-
default:
45-
Haptics.selectionAsync();
46-
}
5+
export const triggerHaptic = StreamHapticFeedback
6+
? (method: string) => {
7+
StreamHapticFeedback.triggerHaptic(method);
478
}
489
: () => {};

package/native-package/android/src/main/java/com/streamchatreactnative/StreamChatReactNativePackage.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,15 @@
1515

1616
public class StreamChatReactNativePackage extends TurboReactPackage {
1717
private static final String STREAM_VIDEO_THUMBNAIL_MODULE = "StreamVideoThumbnail";
18+
private static final String STREAM_HAPTIC_FEEDBACK_MODULE = "StreamHapticFeedback";
1819

1920
@Nullable
2021
@Override
2122
public NativeModule getModule(String name, ReactApplicationContext reactContext) {
2223
if (name.equals(StreamChatReactNativeModule.NAME)) {
2324
return new StreamChatReactNativeModule(reactContext);
25+
} else if (name.equals(STREAM_HAPTIC_FEEDBACK_MODULE)) {
26+
return new StreamHapticFeedbackModule(reactContext);
2427
} else if (name.equals(STREAM_VIDEO_THUMBNAIL_MODULE) && BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
2528
return createNewArchModule(
2629
"com.streamchatreactnative.StreamVideoThumbnailModule",
@@ -47,6 +50,17 @@ public ReactModuleInfoProvider getReactModuleInfoProvider() {
4750
false, // isCxxModule
4851
isTurboModule // isTurboModule
4952
));
53+
moduleInfos.put(
54+
STREAM_HAPTIC_FEEDBACK_MODULE,
55+
new ReactModuleInfo(
56+
STREAM_HAPTIC_FEEDBACK_MODULE,
57+
STREAM_HAPTIC_FEEDBACK_MODULE,
58+
false, // canOverrideExistingModule
59+
false, // needsEagerInit
60+
false, // hasConstants
61+
false, // isCxxModule
62+
false // isTurboModule
63+
));
5064
moduleInfos.put(
5165
STREAM_VIDEO_THUMBNAIL_MODULE,
5266
new ReactModuleInfo(
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package com.streamchatreactnative
2+
3+
import com.facebook.react.bridge.ReactApplicationContext
4+
import com.facebook.react.bridge.ReactContextBaseJavaModule
5+
import com.facebook.react.bridge.ReactMethod
6+
import com.streamchatreactnative.shared.StreamHapticFeedback
7+
8+
class StreamHapticFeedbackModule(
9+
reactContext: ReactApplicationContext,
10+
) : ReactContextBaseJavaModule(reactContext) {
11+
override fun getName(): String = NAME
12+
13+
@ReactMethod
14+
fun triggerHaptic(type: String) {
15+
StreamHapticFeedback.trigger(currentActivity, type)
16+
}
17+
18+
companion object {
19+
const val NAME = "StreamHapticFeedback"
20+
}
21+
}

package/native-package/package.json

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@
4040
"react-native-audio-recorder-player": ">=3.6.13",
4141
"react-native-nitro-sound": ">=0.2.9",
4242
"react-native-blob-util": ">=0.22.0",
43-
"react-native-haptic-feedback": ">=2.3.0",
4443
"react-native-image-picker": ">=7.1.2",
4544
"react-native-share": ">=11.0.0",
4645
"react-native-video": ">=6.18.0"
@@ -59,9 +58,6 @@
5958
"@react-native-documents/picker": {
6059
"optional": true
6160
},
62-
"react-native-haptic-feedback": {
63-
"optional": true
64-
},
6561
"react-native-image-picker": {
6662
"optional": true
6763
},
Lines changed: 5 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,9 @@
1-
let ReactNativeHapticFeedback;
1+
import { NativeModules } from 'react-native';
22

3-
try {
4-
ReactNativeHapticFeedback = require('react-native-haptic-feedback').default;
5-
} catch (e) {
6-
console.warn('react-native-haptic-feedback is not installed.');
7-
}
3+
const { StreamHapticFeedback } = NativeModules;
84

9-
/**
10-
* Since react-native-haptic-feedback isn't installed by default, we've
11-
* copied the types from the package here.
12-
*
13-
* @see https://github.com/junina-de/react-native-haptic-feedback/blob/master/index.d.ts
14-
* */
15-
export type HapticFeedbackTypes =
16-
| 'selection'
17-
| 'impactLight'
18-
| 'impactMedium'
19-
| 'impactHeavy'
20-
| 'rigid'
21-
| 'soft'
22-
| 'notificationSuccess'
23-
| 'notificationWarning'
24-
| 'notificationError'
25-
| 'clockTick'
26-
| 'contextClick'
27-
| 'keyboardPress'
28-
| 'keyboardRelease'
29-
| 'keyboardTap'
30-
| 'longPress'
31-
| 'textHandleMove'
32-
| 'virtualKey'
33-
| 'virtualKeyRelease'
34-
| 'effectClick'
35-
| 'effectDoubleClick'
36-
| 'effectHeavyClick'
37-
| 'effectTick';
38-
39-
export const triggerHaptic = ReactNativeHapticFeedback
40-
? (method: HapticFeedbackTypes) => {
41-
ReactNativeHapticFeedback.trigger(method, {
42-
enableVibrateFallback: false,
43-
ignoreAndroidSystemSettings: false,
44-
});
5+
export const triggerHaptic = StreamHapticFeedback
6+
? (method: string) => {
7+
StreamHapticFeedback.triggerHaptic(method);
458
}
469
: () => {};

0 commit comments

Comments
 (0)