@developer_tribe/react-native-comnyx 0.13.13 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (126) hide show
  1. package/android/generated/RCTAppDependencyProvider.h +25 -0
  2. package/android/generated/RCTAppDependencyProvider.mm +55 -0
  3. package/android/generated/RCTModulesConformingToProtocolsProvider.h +18 -0
  4. package/android/generated/RCTModulesConformingToProtocolsProvider.mm +33 -0
  5. package/android/generated/RCTThirdPartyComponentsProvider.h +16 -0
  6. package/android/generated/RCTThirdPartyComponentsProvider.mm +23 -0
  7. package/android/generated/ReactAppDependencyProvider.podspec +34 -0
  8. package/android/generated/jni/CMakeLists.txt +36 -0
  9. package/android/generated/jni/RNComnyxSpec-generated.cpp +22 -0
  10. package/android/generated/jni/RNComnyxSpec.h +24 -0
  11. package/android/generated/jni/react/renderer/components/RNComnyxSpec/RNComnyxSpecJSI-generated.cpp +17 -0
  12. package/android/generated/jni/react/renderer/components/RNComnyxSpec/RNComnyxSpecJSI.h +19 -0
  13. package/android/src/main/AndroidManifest.xml +15 -0
  14. package/android/src/main/AndroidManifestNew.xml +4 -0
  15. package/android/src/main/java/com/comnyx/ComnyxMediaPickerModule.kt +301 -0
  16. package/android/src/main/java/com/comnyx/ComnyxPackage.kt +1 -1
  17. package/android/src/main/java/com/comnyx/VideoPlayerActivity.kt +91 -0
  18. package/ios/ComnyxMediaPicker.m +23 -0
  19. package/ios/ComnyxMediaPicker.swift +377 -0
  20. package/lib/commonjs/NativeComnyxMediaPicker.js +62 -0
  21. package/lib/commonjs/NativeComnyxMediaPicker.js.map +1 -0
  22. package/lib/commonjs/api/index.js +19 -0
  23. package/lib/commonjs/api/index.js.map +1 -1
  24. package/lib/commonjs/api/media.js +76 -0
  25. package/lib/commonjs/api/media.js.map +1 -0
  26. package/lib/commonjs/assets/attachment-01.png +0 -0
  27. package/lib/commonjs/assets/x-circle.png +0 -0
  28. package/lib/commonjs/components/ChatList.js +48 -22
  29. package/lib/commonjs/components/ChatList.js.map +1 -1
  30. package/lib/commonjs/components/LinkifyText.js +5 -1
  31. package/lib/commonjs/components/LinkifyText.js.map +1 -1
  32. package/lib/commonjs/components/MediaMessageItem.js +333 -0
  33. package/lib/commonjs/components/MediaMessageItem.js.map +1 -0
  34. package/lib/commonjs/components/MediaPickerButton.js +47 -0
  35. package/lib/commonjs/components/MediaPickerButton.js.map +1 -0
  36. package/lib/commonjs/components/MediaViewerModal.js +157 -0
  37. package/lib/commonjs/components/MediaViewerModal.js.map +1 -0
  38. package/lib/commonjs/components/MessageInput.js +344 -73
  39. package/lib/commonjs/components/MessageInput.js.map +1 -1
  40. package/lib/commonjs/components/MessageItem.js +17 -7
  41. package/lib/commonjs/components/MessageItem.js.map +1 -1
  42. package/lib/commonjs/constants/translations.js +203 -29
  43. package/lib/commonjs/constants/translations.js.map +1 -1
  44. package/lib/commonjs/data/fake/media.js +105 -0
  45. package/lib/commonjs/data/fake/media.js.map +1 -0
  46. package/lib/commonjs/types/MediaTypes.js +2 -0
  47. package/lib/commonjs/types/MediaTypes.js.map +1 -0
  48. package/lib/commonjs/version.js +1 -1
  49. package/lib/commonjs/version.js.map +1 -1
  50. package/lib/module/NativeComnyxMediaPicker.js +54 -0
  51. package/lib/module/NativeComnyxMediaPicker.js.map +1 -0
  52. package/lib/module/api/index.js +1 -0
  53. package/lib/module/api/index.js.map +1 -1
  54. package/lib/module/api/media.js +70 -0
  55. package/lib/module/api/media.js.map +1 -0
  56. package/lib/module/assets/attachment-01.png +0 -0
  57. package/lib/module/assets/x-circle.png +0 -0
  58. package/lib/module/components/ChatList.js +48 -22
  59. package/lib/module/components/ChatList.js.map +1 -1
  60. package/lib/module/components/LinkifyText.js +5 -1
  61. package/lib/module/components/LinkifyText.js.map +1 -1
  62. package/lib/module/components/MediaMessageItem.js +330 -0
  63. package/lib/module/components/MediaMessageItem.js.map +1 -0
  64. package/lib/module/components/MediaPickerButton.js +43 -0
  65. package/lib/module/components/MediaPickerButton.js.map +1 -0
  66. package/lib/module/components/MediaViewerModal.js +153 -0
  67. package/lib/module/components/MediaViewerModal.js.map +1 -0
  68. package/lib/module/components/MessageInput.js +347 -75
  69. package/lib/module/components/MessageInput.js.map +1 -1
  70. package/lib/module/components/MessageItem.js +17 -7
  71. package/lib/module/components/MessageItem.js.map +1 -1
  72. package/lib/module/constants/translations.js +203 -29
  73. package/lib/module/constants/translations.js.map +1 -1
  74. package/lib/module/data/fake/media.js +99 -0
  75. package/lib/module/data/fake/media.js.map +1 -0
  76. package/lib/module/types/MediaTypes.js +2 -0
  77. package/lib/module/types/MediaTypes.js.map +1 -0
  78. package/lib/module/version.js +1 -1
  79. package/lib/module/version.js.map +1 -1
  80. package/lib/typescript/src/NativeComnyxMediaPicker.d.ts +7 -0
  81. package/lib/typescript/src/NativeComnyxMediaPicker.d.ts.map +1 -0
  82. package/lib/typescript/src/api/index.d.ts +1 -0
  83. package/lib/typescript/src/api/index.d.ts.map +1 -1
  84. package/lib/typescript/src/api/media.d.ts +7 -0
  85. package/lib/typescript/src/api/media.d.ts.map +1 -0
  86. package/lib/typescript/src/components/ChatList.d.ts.map +1 -1
  87. package/lib/typescript/src/components/LinkifyText.d.ts.map +1 -1
  88. package/lib/typescript/src/components/MediaMessageItem.d.ts +6 -0
  89. package/lib/typescript/src/components/MediaMessageItem.d.ts.map +1 -0
  90. package/lib/typescript/src/components/MediaPickerButton.d.ts +5 -0
  91. package/lib/typescript/src/components/MediaPickerButton.d.ts.map +1 -0
  92. package/lib/typescript/src/components/MediaViewerModal.d.ts +8 -0
  93. package/lib/typescript/src/components/MediaViewerModal.d.ts.map +1 -0
  94. package/lib/typescript/src/components/MessageInput.d.ts.map +1 -1
  95. package/lib/typescript/src/components/MessageItem.d.ts.map +1 -1
  96. package/lib/typescript/src/constants/translations.d.ts.map +1 -1
  97. package/lib/typescript/src/data/fake/media.d.ts +6 -0
  98. package/lib/typescript/src/data/fake/media.d.ts.map +1 -0
  99. package/lib/typescript/src/types/Conversation.d.ts +19 -0
  100. package/lib/typescript/src/types/Conversation.d.ts.map +1 -1
  101. package/lib/typescript/src/types/LocalizationKeys.d.ts +6 -0
  102. package/lib/typescript/src/types/LocalizationKeys.d.ts.map +1 -1
  103. package/lib/typescript/src/types/MediaTypes.d.ts +26 -0
  104. package/lib/typescript/src/types/MediaTypes.d.ts.map +1 -0
  105. package/lib/typescript/src/version.d.ts +1 -1
  106. package/lib/typescript/src/version.d.ts.map +1 -1
  107. package/package.json +1 -1
  108. package/src/NativeComnyxMediaPicker.ts +62 -0
  109. package/src/api/index.ts +1 -0
  110. package/src/api/media.ts +116 -0
  111. package/src/assets/attachment-01.png +0 -0
  112. package/src/assets/x-circle.png +0 -0
  113. package/src/components/ChatList.tsx +81 -24
  114. package/src/components/CustomerForm.tsx +1 -1
  115. package/src/components/LinkifyText.tsx +3 -2
  116. package/src/components/MediaMessageItem.tsx +390 -0
  117. package/src/components/MediaPickerButton.tsx +48 -0
  118. package/src/components/MediaViewerModal.tsx +161 -0
  119. package/src/components/MessageInput.tsx +396 -84
  120. package/src/components/MessageItem.tsx +19 -4
  121. package/src/constants/translations.ts +174 -0
  122. package/src/data/fake/media.ts +110 -0
  123. package/src/types/Conversation.ts +20 -0
  124. package/src/types/LocalizationKeys.ts +6 -0
  125. package/src/types/MediaTypes.ts +27 -0
  126. package/src/version.ts +1 -1
@@ -0,0 +1,25 @@
1
+ /*
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+
8
+
9
+ #import <Foundation/Foundation.h>
10
+
11
+ #if __has_include(<React-RCTAppDelegate/RCTDependencyProvider.h>)
12
+ #import <React-RCTAppDelegate/RCTDependencyProvider.h>
13
+ #elif __has_include(<React_RCTAppDelegate/RCTDependencyProvider.h>)
14
+ #import <React_RCTAppDelegate/RCTDependencyProvider.h>
15
+ #else
16
+ #import "RCTDependencyProvider.h"
17
+ #endif
18
+
19
+ NS_ASSUME_NONNULL_BEGIN
20
+
21
+ @interface RCTAppDependencyProvider : NSObject <RCTDependencyProvider>
22
+
23
+ @end
24
+
25
+ NS_ASSUME_NONNULL_END
@@ -0,0 +1,55 @@
1
+ /*
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+
8
+ #import "RCTAppDependencyProvider.h"
9
+ #import <ReactCodegen/RCTModulesConformingToProtocolsProvider.h>
10
+ #import <ReactCodegen/RCTThirdPartyComponentsProvider.h>
11
+
12
+ @implementation RCTAppDependencyProvider {
13
+ NSArray<NSString *> * _URLRequestHandlerClassNames;
14
+ NSArray<NSString *> * _imageDataDecoderClassNames;
15
+ NSArray<NSString *> * _imageURLLoaderClassNames;
16
+ NSDictionary<NSString *,Class<RCTComponentViewProtocol>> * _thirdPartyFabricComponents;
17
+ }
18
+
19
+ - (nonnull NSArray<NSString *> *)URLRequestHandlerClassNames {
20
+ static dispatch_once_t requestUrlToken;
21
+ dispatch_once(&requestUrlToken, ^{
22
+ self->_URLRequestHandlerClassNames = RCTModulesConformingToProtocolsProvider.URLRequestHandlerClassNames;
23
+ });
24
+
25
+ return _URLRequestHandlerClassNames;
26
+ }
27
+
28
+ - (nonnull NSArray<NSString *> *)imageDataDecoderClassNames {
29
+ static dispatch_once_t dataDecoderToken;
30
+ dispatch_once(&dataDecoderToken, ^{
31
+ _imageDataDecoderClassNames = RCTModulesConformingToProtocolsProvider.imageDataDecoderClassNames;
32
+ });
33
+
34
+ return _imageDataDecoderClassNames;
35
+ }
36
+
37
+ - (nonnull NSArray<NSString *> *)imageURLLoaderClassNames {
38
+ static dispatch_once_t urlLoaderToken;
39
+ dispatch_once(&urlLoaderToken, ^{
40
+ _imageURLLoaderClassNames = RCTModulesConformingToProtocolsProvider.imageURLLoaderClassNames;
41
+ });
42
+
43
+ return _imageURLLoaderClassNames;
44
+ }
45
+
46
+ - (nonnull NSDictionary<NSString *,Class<RCTComponentViewProtocol>> *)thirdPartyFabricComponents {
47
+ static dispatch_once_t nativeComponentsToken;
48
+ dispatch_once(&nativeComponentsToken, ^{
49
+ _thirdPartyFabricComponents = RCTThirdPartyComponentsProvider.thirdPartyFabricComponents;
50
+ });
51
+
52
+ return _thirdPartyFabricComponents;
53
+ }
54
+
55
+ @end
@@ -0,0 +1,18 @@
1
+ /*
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+
8
+ #import <Foundation/Foundation.h>
9
+
10
+ @interface RCTModulesConformingToProtocolsProvider: NSObject
11
+
12
+ +(NSArray<NSString *> *)imageURLLoaderClassNames;
13
+
14
+ +(NSArray<NSString *> *)imageDataDecoderClassNames;
15
+
16
+ +(NSArray<NSString *> *)URLRequestHandlerClassNames;
17
+
18
+ @end
@@ -0,0 +1,33 @@
1
+ /*
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+
8
+ #import "RCTModulesConformingToProtocolsProvider.h"
9
+
10
+ @implementation RCTModulesConformingToProtocolsProvider
11
+
12
+ +(NSArray<NSString *> *)imageURLLoaderClassNames
13
+ {
14
+ return @[
15
+
16
+ ];
17
+ }
18
+
19
+ +(NSArray<NSString *> *)imageDataDecoderClassNames
20
+ {
21
+ return @[
22
+
23
+ ];
24
+ }
25
+
26
+ +(NSArray<NSString *> *)URLRequestHandlerClassNames
27
+ {
28
+ return @[
29
+
30
+ ];
31
+ }
32
+
33
+ @end
@@ -0,0 +1,16 @@
1
+ /*
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+
8
+ #import <Foundation/Foundation.h>
9
+
10
+ @protocol RCTComponentViewProtocol;
11
+
12
+ @interface RCTThirdPartyComponentsProvider: NSObject
13
+
14
+ + (NSDictionary<NSString *, Class<RCTComponentViewProtocol>> *)thirdPartyFabricComponents;
15
+
16
+ @end
@@ -0,0 +1,23 @@
1
+ /*
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+
8
+
9
+ #import <Foundation/Foundation.h>
10
+
11
+ #import "RCTThirdPartyComponentsProvider.h"
12
+ #import <React/RCTComponentViewProtocol.h>
13
+
14
+ @implementation RCTThirdPartyComponentsProvider
15
+
16
+ + (NSDictionary<NSString *, Class<RCTComponentViewProtocol>> *)thirdPartyFabricComponents
17
+ {
18
+ return @{
19
+
20
+ };
21
+ }
22
+
23
+ @end
@@ -0,0 +1,34 @@
1
+ # Copyright (c) Meta Platforms, Inc. and affiliates.
2
+ #
3
+ # This source code is licensed under the MIT license found in the
4
+ # LICENSE file in the root directory of this source tree.
5
+
6
+ version = "0.78.1"
7
+ source = { :git => 'https://github.com/facebook/react-native.git' }
8
+ if version == '1000.0.0'
9
+ # This is an unpublished version, use the latest commit hash of the react-native repo, which we’re presumably in.
10
+ source[:commit] = `git rev-parse HEAD`.strip if system("git rev-parse --git-dir > /dev/null 2>&1")
11
+ else
12
+ source[:tag] = "v#{version}"
13
+ end
14
+
15
+ Pod::Spec.new do |s|
16
+ s.name = "ReactAppDependencyProvider"
17
+ s.version = version
18
+ s.summary = "The third party dependency provider for the app"
19
+ s.homepage = "https://reactnative.dev/"
20
+ s.documentation_url = "https://reactnative.dev/"
21
+ s.license = "MIT"
22
+ s.author = "Meta Platforms, Inc. and its affiliates"
23
+ s.platforms = min_supported_versions
24
+ s.source = source
25
+ s.source_files = "**/RCTAppDependencyProvider.{h,mm}"
26
+
27
+ # This guard prevent to install the dependencies when we run `pod install` in the old architecture.
28
+ s.pod_target_xcconfig = {
29
+ "CLANG_CXX_LANGUAGE_STANDARD" => rct_cxx_language_standard(),
30
+ "DEFINES_MODULE" => "YES"
31
+ }
32
+
33
+ s.dependency "ReactCodegen"
34
+ end
@@ -0,0 +1,36 @@
1
+ # Copyright (c) Meta Platforms, Inc. and affiliates.
2
+ #
3
+ # This source code is licensed under the MIT license found in the
4
+ # LICENSE file in the root directory of this source tree.
5
+
6
+ cmake_minimum_required(VERSION 3.13)
7
+ set(CMAKE_VERBOSE_MAKEFILE on)
8
+
9
+ file(GLOB react_codegen_SRCS CONFIGURE_DEPENDS *.cpp react/renderer/components/RNComnyxSpec/*.cpp)
10
+
11
+ add_library(
12
+ react_codegen_RNComnyxSpec
13
+ OBJECT
14
+ ${react_codegen_SRCS}
15
+ )
16
+
17
+ target_include_directories(react_codegen_RNComnyxSpec PUBLIC . react/renderer/components/RNComnyxSpec)
18
+
19
+ target_link_libraries(
20
+ react_codegen_RNComnyxSpec
21
+ fbjni
22
+ jsi
23
+ # We need to link different libraries based on whether we are building rncore or not, that's necessary
24
+ # because we want to break a circular dependency between react_codegen_rncore and reactnative
25
+ reactnative
26
+ )
27
+
28
+ target_compile_options(
29
+ react_codegen_RNComnyxSpec
30
+ PRIVATE
31
+ -DLOG_TAG=\"ReactNative\"
32
+ -fexceptions
33
+ -frtti
34
+ -std=c++20
35
+ -Wall
36
+ )
@@ -0,0 +1,22 @@
1
+
2
+ /**
3
+ * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen).
4
+ *
5
+ * Do not edit this file as changes may cause incorrect behavior and will be lost
6
+ * once the code is regenerated.
7
+ *
8
+ * @generated by codegen project: GenerateModuleJniCpp.js
9
+ */
10
+
11
+ #include "RNComnyxSpec.h"
12
+
13
+ namespace facebook::react {
14
+
15
+
16
+
17
+ std::shared_ptr<TurboModule> RNComnyxSpec_ModuleProvider(const std::string &moduleName, const JavaTurboModule::InitParams &params) {
18
+
19
+ return nullptr;
20
+ }
21
+
22
+ } // namespace facebook::react
@@ -0,0 +1,24 @@
1
+
2
+ /**
3
+ * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen).
4
+ *
5
+ * Do not edit this file as changes may cause incorrect behavior and will be lost
6
+ * once the code is regenerated.
7
+ *
8
+ * @generated by codegen project: GenerateModuleJniH.js
9
+ */
10
+
11
+ #pragma once
12
+
13
+ #include <ReactCommon/JavaTurboModule.h>
14
+ #include <ReactCommon/TurboModule.h>
15
+ #include <jsi/jsi.h>
16
+
17
+ namespace facebook::react {
18
+
19
+
20
+
21
+ JSI_EXPORT
22
+ std::shared_ptr<TurboModule> RNComnyxSpec_ModuleProvider(const std::string &moduleName, const JavaTurboModule::InitParams &params);
23
+
24
+ } // namespace facebook::react
@@ -0,0 +1,17 @@
1
+ /**
2
+ * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen).
3
+ *
4
+ * Do not edit this file as changes may cause incorrect behavior and will be lost
5
+ * once the code is regenerated.
6
+ *
7
+ * @generated by codegen project: GenerateModuleCpp.js
8
+ */
9
+
10
+ #include "RNComnyxSpecJSI.h"
11
+
12
+ namespace facebook::react {
13
+
14
+
15
+
16
+
17
+ } // namespace facebook::react
@@ -0,0 +1,19 @@
1
+ /**
2
+ * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen).
3
+ *
4
+ * Do not edit this file as changes may cause incorrect behavior and will be lost
5
+ * once the code is regenerated.
6
+ *
7
+ * @generated by codegen project: GenerateModuleH.js
8
+ */
9
+
10
+ #pragma once
11
+
12
+ #include <ReactCommon/TurboModule.h>
13
+ #include <react/bridging/Bridging.h>
14
+
15
+ namespace facebook::react {
16
+
17
+
18
+
19
+ } // namespace facebook::react
@@ -1,3 +1,18 @@
1
1
  <manifest xmlns:android="http://schemas.android.com/apk/res/android"
2
2
  package="com.comnyx">
3
+
4
+ <application>
5
+ <service
6
+ android:name="com.comnyx.messaging.ComnyxFirebaseMessagingService"
7
+ android:priority="-1500"
8
+ android:exported="true">
9
+ <intent-filter>
10
+ <action android:name="com.google.firebase.MESSAGING_EVENT" />
11
+ </intent-filter>
12
+ </service>
13
+ <activity
14
+ android:name="com.comnyx.VideoPlayerActivity"
15
+ android:theme="@android:style/Theme.Black.NoTitleBar.Fullscreen"
16
+ android:exported="false" />
17
+ </application>
3
18
  </manifest>
@@ -8,5 +8,9 @@
8
8
  <action android:name="com.google.firebase.MESSAGING_EVENT" />
9
9
  </intent-filter>
10
10
  </service>
11
+ <activity
12
+ android:name="com.comnyx.VideoPlayerActivity"
13
+ android:theme="@android:style/Theme.Black.NoTitleBar.Fullscreen"
14
+ android:exported="false" />
11
15
  </application>
12
16
  </manifest>
@@ -0,0 +1,301 @@
1
+ package com.comnyx
2
+
3
+ import android.app.Activity
4
+ import android.content.Intent
5
+ import android.graphics.Bitmap
6
+ import android.graphics.BitmapFactory
7
+ import android.net.Uri
8
+ import android.provider.OpenableColumns
9
+ import android.webkit.MimeTypeMap
10
+ import com.facebook.react.bridge.*
11
+ import java.io.File
12
+ import java.io.FileOutputStream
13
+ import java.io.InputStream
14
+ import android.media.MediaMetadataRetriever
15
+
16
+ class ComnyxMediaPickerModule(reactContext: ReactApplicationContext) :
17
+ ReactContextBaseJavaModule(reactContext), ActivityEventListener {
18
+
19
+ companion object {
20
+ const val NAME = "ComnyxMediaPicker"
21
+ private const val REQUEST_MEDIA = 2003
22
+ private const val COMPRESS_THRESHOLD = 500 * 1024 // 500KB
23
+ private const val COMPRESS_QUALITY = 80
24
+ }
25
+
26
+ private var promise: Promise? = null
27
+
28
+ init {
29
+ reactContext.addActivityEventListener(this)
30
+ }
31
+
32
+ override fun getName(): String = NAME
33
+
34
+
35
+
36
+ // MARK: - Pick Media (both images and videos)
37
+
38
+ @ReactMethod
39
+ fun pickMedia(promise: Promise) {
40
+ this.promise = promise
41
+ val activity = reactApplicationContext.currentActivity
42
+ if (activity == null) {
43
+ promise.reject("NO_ACTIVITY", "Activity is not available")
44
+ return
45
+ }
46
+ val intent = Intent(Intent.ACTION_GET_CONTENT).apply {
47
+ type = "*/*"
48
+ putExtra(Intent.EXTRA_MIME_TYPES, arrayOf("image/*", "video/*"))
49
+ putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true)
50
+ addCategory(Intent.CATEGORY_OPENABLE)
51
+ }
52
+ activity.startActivityForResult(intent, REQUEST_MEDIA)
53
+ }
54
+
55
+ // MARK: - Generate Thumbnail from Video URL
56
+
57
+ @ReactMethod
58
+ fun generateThumbnail(videoUrl: String, promise: Promise) {
59
+ android.util.Log.d("ComnyxMedia", "generateThumbnail called with: $videoUrl")
60
+ Thread {
61
+ try {
62
+ val retriever = MediaMetadataRetriever()
63
+ if (videoUrl.startsWith("http://") || videoUrl.startsWith("https://")) {
64
+ android.util.Log.d("ComnyxMedia", "Setting remote data source")
65
+ retriever.setDataSource(videoUrl, HashMap<String, String>())
66
+ } else {
67
+ android.util.Log.d("ComnyxMedia", "Setting local data source")
68
+ retriever.setDataSource(reactApplicationContext, Uri.parse(videoUrl))
69
+ }
70
+ val bitmap = retriever.getFrameAtTime(0, MediaMetadataRetriever.OPTION_CLOSEST_SYNC)
71
+ retriever.release()
72
+
73
+ if (bitmap != null) {
74
+ android.util.Log.d("ComnyxMedia", "Thumbnail bitmap generated: ${bitmap.width}x${bitmap.height}")
75
+ val thumbFile = File(reactApplicationContext.cacheDir, "thumb_${System.currentTimeMillis()}.jpg")
76
+ FileOutputStream(thumbFile).use { fos ->
77
+ bitmap.compress(Bitmap.CompressFormat.JPEG, 80, fos)
78
+ }
79
+ bitmap.recycle()
80
+ promise.resolve("file://" + thumbFile.absolutePath)
81
+ } else {
82
+ android.util.Log.d("ComnyxMedia", "Thumbnail bitmap is null")
83
+ promise.resolve(null)
84
+ }
85
+ } catch (e: Exception) {
86
+ android.util.Log.e("ComnyxMedia", "generateThumbnail error: ${e.message}", e)
87
+ promise.resolve(null)
88
+ }
89
+ }.start()
90
+ }
91
+
92
+ // MARK: - Open Video
93
+
94
+ @ReactMethod
95
+ fun openVideo(uri: String, promise: Promise) {
96
+ try {
97
+ val activity = reactApplicationContext.currentActivity
98
+ if (activity == null) {
99
+ promise.reject("NO_ACTIVITY", "Activity is not available")
100
+ return
101
+ }
102
+
103
+ if (uri.startsWith("http://") || uri.startsWith("https://")) {
104
+ // Remote URL — use system player for faster streaming
105
+ val intent = Intent(Intent.ACTION_VIEW).apply {
106
+ setDataAndType(Uri.parse(uri), "video/*")
107
+ addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
108
+ }
109
+ activity.startActivity(intent)
110
+ promise.resolve(null)
111
+ } else {
112
+ // Local file — use custom VideoPlayerActivity
113
+ val intent = Intent(activity, VideoPlayerActivity::class.java).apply {
114
+ putExtra("video_uri", uri)
115
+ }
116
+ activity.startActivity(intent)
117
+ promise.resolve(null)
118
+ }
119
+ } catch (e: Exception) {
120
+ promise.reject("OPEN_ERROR", e.message, e)
121
+ }
122
+ }
123
+
124
+ // MARK: - Activity Result
125
+
126
+ override fun onActivityResult(activity: Activity, requestCode: Int, resultCode: Int, data: Intent?) {
127
+ if (requestCode != REQUEST_MEDIA) return
128
+
129
+ if (resultCode != Activity.RESULT_OK || data == null) {
130
+ promise?.resolve(null)
131
+ promise = null
132
+ return
133
+ }
134
+
135
+ // Collect all selected URIs
136
+ val uris = mutableListOf<Uri>()
137
+ val clipData = data.clipData
138
+ if (clipData != null) {
139
+ for (i in 0 until clipData.itemCount) {
140
+ uris.add(clipData.getItemAt(i).uri)
141
+ }
142
+ } else if (data.data != null) {
143
+ uris.add(data.data!!)
144
+ }
145
+
146
+ if (uris.isEmpty()) {
147
+ promise?.resolve(null)
148
+ promise = null
149
+ return
150
+ }
151
+
152
+ // Capture and clear promise to prevent double-resolve races
153
+ val currentPromise = promise
154
+ promise = null
155
+
156
+ // Move all heavy I/O to a background thread to prevent ANR
157
+ Thread {
158
+ try {
159
+ val context = reactApplicationContext
160
+ val contentResolver = context.contentResolver
161
+ val resultsArray = Arguments.createArray()
162
+
163
+ for (uri in uris) {
164
+ val mimeTypeStr = contentResolver.getType(uri) ?: ""
165
+ val isImage = mimeTypeStr.startsWith("image")
166
+ val mimeType = contentResolver.getType(uri) ?: if (isImage) "image/jpeg" else "video/mp4"
167
+
168
+ // Get file name
169
+ var fileName = "file_${System.currentTimeMillis()}"
170
+ val cursor = contentResolver.query(uri, null, null, null, null)
171
+ cursor?.use {
172
+ if (it.moveToFirst()) {
173
+ val nameIndex = it.getColumnIndex(OpenableColumns.DISPLAY_NAME)
174
+ if (nameIndex >= 0) {
175
+ fileName = it.getString(nameIndex) ?: fileName
176
+ }
177
+ }
178
+ }
179
+
180
+ // Copy to temp file
181
+ val tempFile = File(context.cacheDir, "${System.currentTimeMillis()}_$fileName")
182
+ contentResolver.openInputStream(uri)?.use { inputStream ->
183
+ FileOutputStream(tempFile).use { outputStream ->
184
+ inputStream.copyTo(outputStream)
185
+ }
186
+ }
187
+
188
+ var finalFile = tempFile
189
+ var finalMimeType = mimeType
190
+ var finalFileSize = tempFile.length()
191
+
192
+ // Compress image if >500KB
193
+ if (isImage && finalFileSize > COMPRESS_THRESHOLD) {
194
+ val compressed = compressImage(tempFile)
195
+ if (compressed != null) {
196
+ tempFile.delete()
197
+ finalFile = compressed
198
+ finalMimeType = "image/jpeg"
199
+ finalFileSize = compressed.length()
200
+ }
201
+ }
202
+
203
+ val result = Arguments.createMap().apply {
204
+ putString("uri", Uri.fromFile(finalFile).toString())
205
+ putString("type", if (isImage) "image" else "video")
206
+ putString("fileName", finalFile.name)
207
+ putDouble("fileSize", finalFileSize.toDouble())
208
+ putString("mimeType", finalMimeType)
209
+ if (!isImage) {
210
+ val thumbnailUri = generateVideoThumbnail(finalFile)
211
+ if (thumbnailUri != null) {
212
+ putString("thumbnailUri", thumbnailUri)
213
+ }
214
+ }
215
+ }
216
+ resultsArray.pushMap(result)
217
+ }
218
+
219
+ currentPromise?.resolve(resultsArray)
220
+ } catch (e: Exception) {
221
+ currentPromise?.reject("PICK_ERROR", e.message, e)
222
+ }
223
+ }.start()
224
+ }
225
+
226
+ override fun onNewIntent(intent: Intent) {
227
+ // Not needed
228
+ }
229
+
230
+ // MARK: - Image Compression
231
+
232
+ private fun compressImage(file: File): File? {
233
+ return try {
234
+ val bitmap = BitmapFactory.decodeFile(file.absolutePath) ?: return null
235
+ val compressedFile = File(reactApplicationContext.cacheDir, "compressed_${System.currentTimeMillis()}.jpg")
236
+ FileOutputStream(compressedFile).use { outputStream ->
237
+ bitmap.compress(Bitmap.CompressFormat.JPEG, COMPRESS_QUALITY, outputStream)
238
+ }
239
+ bitmap.recycle()
240
+ compressedFile
241
+ } catch (e: Exception) {
242
+ null
243
+ }
244
+ }
245
+
246
+ private fun generateVideoThumbnail(videoFile: File): String? {
247
+ return try {
248
+ val retriever = MediaMetadataRetriever()
249
+ retriever.setDataSource(videoFile.absolutePath)
250
+ val bitmap = retriever.getFrameAtTime(0, MediaMetadataRetriever.OPTION_CLOSEST_SYNC)
251
+ retriever.release()
252
+ if (bitmap != null) {
253
+ val thumbFile = File(reactApplicationContext.cacheDir, "thumb_${System.currentTimeMillis()}.jpg")
254
+ FileOutputStream(thumbFile).use { outputStream ->
255
+ bitmap.compress(Bitmap.CompressFormat.JPEG, 70, outputStream)
256
+ }
257
+ bitmap.recycle()
258
+ Uri.fromFile(thumbFile).toString()
259
+ } else null
260
+ } catch (e: Exception) {
261
+ null
262
+ }
263
+ }
264
+
265
+ @ReactMethod
266
+ fun deleteTempFile(uri: String, promise: Promise) {
267
+ Thread {
268
+ try {
269
+ val path = uri.removePrefix("file://")
270
+ val file = File(path)
271
+ if (file.exists()) {
272
+ file.delete()
273
+ }
274
+ promise.resolve(null)
275
+ } catch (e: Exception) {
276
+ promise.resolve(null)
277
+ }
278
+ }.start()
279
+ }
280
+
281
+ @ReactMethod
282
+ fun cleanupTempFiles(promise: Promise) {
283
+ Thread {
284
+ try {
285
+ val cacheDir = reactApplicationContext.cacheDir
286
+ val files = cacheDir.listFiles() ?: emptyArray()
287
+ for (file in files) {
288
+ val name = file.name.lowercase()
289
+ if (name.startsWith("thumb_") || name.startsWith("compressed_") ||
290
+ (name.contains("_") && (name.endsWith(".jpg") || name.endsWith(".jpeg") ||
291
+ name.endsWith(".png") || name.endsWith(".mp4") || name.endsWith(".mov")))) {
292
+ file.delete()
293
+ }
294
+ }
295
+ promise.resolve(null)
296
+ } catch (e: Exception) {
297
+ promise.resolve(null)
298
+ }
299
+ }.start()
300
+ }
301
+ }
@@ -7,7 +7,7 @@ import com.facebook.react.uimanager.ViewManager
7
7
 
8
8
  class ComnyxPackage : ReactPackage {
9
9
  override fun createNativeModules(reactContext: ReactApplicationContext): List<NativeModule> {
10
- return listOf(ComnyxModule(reactContext))
10
+ return listOf(ComnyxModule(reactContext), ComnyxMediaPickerModule(reactContext))
11
11
  }
12
12
 
13
13
  override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> {