├── .circleci └── config.yml ├── .github ├── FUNDING.yml └── workflows │ └── docs.yml ├── .gitignore ├── .npmignore ├── CONTRIBUTING.md ├── LICENSE ├── MultipleImagePicker.podspec ├── README.md ├── android ├── CMakeLists.txt ├── build.gradle ├── gradle.properties └── src │ └── main │ ├── AndroidManifest.xml │ ├── cpp │ └── cpp-adapter.cpp │ ├── java │ └── com │ │ └── margelo │ │ └── nitro │ │ └── multipleimagepicker │ │ ├── CameraEngine.kt │ │ ├── Constant.kt │ │ ├── CropEngine.kt │ │ ├── ExoPlayerEngine.kt │ │ ├── GlideEngine.kt │ │ ├── ImageLoaderUtils.kt │ │ ├── LoadingDialog.kt │ │ ├── MultipleImagePicker.kt │ │ ├── MultipleImagePickerImp.kt │ │ ├── MultipleImagePickerPackage.java │ │ ├── PictureSelectorEngineImp.kt │ │ └── VideoThumbnailEngine.kt │ └── res │ ├── anim │ └── anim_modal_in.xml │ ├── drawable │ ├── checkbox_selector.xml │ ├── complete_button.xml │ ├── ic_checkmark.xml │ ├── ic_down.xml │ ├── num_oval.xml │ ├── picture_not_selected.xml │ ├── picture_selector.xml │ ├── preview_gallery_item.xml │ └── preview_gallery_white_bg.xml │ ├── layout │ └── loading_dialog.xml │ └── values │ ├── colors.xml │ └── styles.xml ├── babel.config.js ├── docs ├── .gitignore ├── README.md ├── docs │ ├── CAMERA.mdx │ ├── CONFIG.mdx │ ├── CROP.mdx │ ├── GETTING_STARTED.mdx │ ├── PREVIEW.mdx │ ├── RESULT.mdx │ ├── SHOWCASE │ │ ├── index.mdx │ │ ├── showcase.css │ │ └── showcase.json │ ├── USAGE.mdx │ └── index.md ├── docusaurus.config.ts ├── package-lock.json ├── package.json ├── patches │ └── @gorhom+docusaurus-preset+1.0.2.patch ├── sidebars.ts ├── src │ └── css │ │ └── custom.css ├── static │ ├── .nojekyll │ └── img │ │ ├── RNMIP.png │ │ ├── banner.png │ │ └── favicon.ico ├── tsconfig.json └── yarn.lock ├── example ├── .gitignore ├── App.tsx ├── Gemfile ├── Gemfile.lock ├── README.md ├── app.json ├── assets │ ├── adaptive-icon.png │ ├── icon.png │ └── splash.png ├── babel.config.js ├── metro.config.js ├── package-lock.json ├── package.json ├── react-native.config.js ├── src │ ├── assets │ │ ├── check.png │ │ ├── index.ts │ │ ├── logo.png │ │ └── plus-sign.png │ ├── common │ │ └── const.ts │ ├── components │ │ ├── BottomSheet.tsx │ │ ├── Button.tsx │ │ ├── CheckBox.tsx │ │ ├── CodeTag.tsx │ │ ├── Container.tsx │ │ ├── CounterView.tsx │ │ ├── Divider.tsx │ │ ├── Input.tsx │ │ ├── Row.tsx │ │ ├── SectionView.tsx │ │ ├── SegmentControl.tsx │ │ ├── Text.tsx │ │ ├── View.tsx │ │ └── index.tsx │ ├── hook │ │ ├── context.ts │ │ ├── index.ts │ │ └── useTheme.ts │ ├── index.tsx │ └── theme │ │ ├── color.ts │ │ └── size.ts ├── tsconfig.json └── yarn.lock ├── files ├── banner.png └── logo.png ├── ios ├── Assets.swift ├── Assets.xcassets │ ├── Contents.json │ └── close.imageset │ │ ├── Contents.json │ │ └── close.png ├── ErrorCode.swift ├── HybridMultipleImagePicker+Camera.swift ├── HybridMultipleImagePicker+Config.swift ├── HybridMultipleImagePicker+Crop.swift ├── HybridMultipleImagePicker+Preview.swift ├── HybridMultipleImagePicker+Result.swift ├── HybridMultipleImagePicker.swift ├── MultipleImagePickerOnLoad.mm ├── PHAsset+Thumbnail.swift ├── PhotoCancelItem.swift ├── TopViewController.swift ├── UIColor+Hex.swift ├── UIColor+React.swift ├── UIImage.swift ├── URL+Mime.swift └── Utils.swift ├── nitro.json ├── nitrogen └── generated │ ├── .gitattributes │ ├── android │ ├── MultipleImagePicker+autolinking.cmake │ ├── MultipleImagePicker+autolinking.gradle │ ├── MultipleImagePickerOnLoad.cpp │ ├── MultipleImagePickerOnLoad.hpp │ ├── c++ │ │ ├── JCameraDevice.hpp │ │ ├── JCameraResult.hpp │ │ ├── JCropRatio.hpp │ │ ├── JCropResult.hpp │ │ ├── JFunc_void_CameraResult.hpp │ │ ├── JFunc_void_CropResult.hpp │ │ ├── JFunc_void_double.hpp │ │ ├── JFunc_void_std__vector_PickerResult_.hpp │ │ ├── JHybridMultipleImagePickerSpec.cpp │ │ ├── JHybridMultipleImagePickerSpec.hpp │ │ ├── JLanguage.hpp │ │ ├── JMediaPreview.hpp │ │ ├── JMediaType.hpp │ │ ├── JNitroCameraConfig.hpp │ │ ├── JNitroConfig.hpp │ │ ├── JNitroCropConfig.hpp │ │ ├── JNitroPreviewConfig.hpp │ │ ├── JPickerCameraConfig.hpp │ │ ├── JPickerCropConfig.hpp │ │ ├── JPickerResult.hpp │ │ ├── JPresentation.hpp │ │ ├── JResultType.hpp │ │ ├── JSelectBoxStyle.hpp │ │ ├── JSelectMode.hpp │ │ ├── JText.hpp │ │ └── JTheme.hpp │ └── kotlin │ │ └── com │ │ └── margelo │ │ └── nitro │ │ └── multipleimagepicker │ │ ├── CameraDevice.kt │ │ ├── CameraResult.kt │ │ ├── CropRatio.kt │ │ ├── CropResult.kt │ │ ├── Func_void_CameraResult.kt │ │ ├── Func_void_CropResult.kt │ │ ├── Func_void_double.kt │ │ ├── Func_void_std__vector_PickerResult_.kt │ │ ├── HybridMultipleImagePickerSpec.kt │ │ ├── Language.kt │ │ ├── MediaPreview.kt │ │ ├── MediaType.kt │ │ ├── MultipleImagePickerOnLoad.kt │ │ ├── NitroCameraConfig.kt │ │ ├── NitroConfig.kt │ │ ├── NitroCropConfig.kt │ │ ├── NitroPreviewConfig.kt │ │ ├── PickerCameraConfig.kt │ │ ├── PickerCropConfig.kt │ │ ├── PickerResult.kt │ │ ├── Presentation.kt │ │ ├── ResultType.kt │ │ ├── SelectBoxStyle.kt │ │ ├── SelectMode.kt │ │ ├── Text.kt │ │ └── Theme.kt │ ├── ios │ ├── MultipleImagePicker+autolinking.rb │ ├── MultipleImagePicker-Swift-Cxx-Bridge.cpp │ ├── MultipleImagePicker-Swift-Cxx-Bridge.hpp │ ├── MultipleImagePicker-Swift-Cxx-Umbrella.hpp │ ├── MultipleImagePickerAutolinking.mm │ ├── MultipleImagePickerAutolinking.swift │ ├── c++ │ │ ├── HybridMultipleImagePickerSpecSwift.cpp │ │ └── HybridMultipleImagePickerSpecSwift.hpp │ └── swift │ │ ├── CameraDevice.swift │ │ ├── CameraResult.swift │ │ ├── CropRatio.swift │ │ ├── CropResult.swift │ │ ├── Func_void_CameraResult.swift │ │ ├── Func_void_CropResult.swift │ │ ├── Func_void_double.swift │ │ ├── Func_void_std__vector_PickerResult_.swift │ │ ├── HybridMultipleImagePickerSpec.swift │ │ ├── HybridMultipleImagePickerSpec_cxx.swift │ │ ├── Language.swift │ │ ├── MediaPreview.swift │ │ ├── MediaType.swift │ │ ├── NitroCameraConfig.swift │ │ ├── NitroConfig.swift │ │ ├── NitroCropConfig.swift │ │ ├── NitroPreviewConfig.swift │ │ ├── PickerCameraConfig.swift │ │ ├── PickerCropConfig.swift │ │ ├── PickerResult.swift │ │ ├── Presentation.swift │ │ ├── ResultType.swift │ │ ├── SelectBoxStyle.swift │ │ ├── SelectMode.swift │ │ ├── Text.swift │ │ └── Theme.swift │ └── shared │ └── c++ │ ├── CameraDevice.hpp │ ├── CameraResult.hpp │ ├── CropRatio.hpp │ ├── CropResult.hpp │ ├── HybridMultipleImagePickerSpec.cpp │ ├── HybridMultipleImagePickerSpec.hpp │ ├── Language.hpp │ ├── MediaPreview.hpp │ ├── MediaType.hpp │ ├── NitroCameraConfig.hpp │ ├── NitroConfig.hpp │ ├── NitroCropConfig.hpp │ ├── NitroPreviewConfig.hpp │ ├── PickerCameraConfig.hpp │ ├── PickerCropConfig.hpp │ ├── PickerResult.hpp │ ├── Presentation.hpp │ ├── ResultType.hpp │ ├── SelectBoxStyle.hpp │ ├── SelectMode.hpp │ ├── Text.hpp │ └── Theme.hpp ├── package.json ├── react-native.config.js ├── scripts └── bootstrap.js ├── src ├── index.ts ├── specs │ └── MultipleImagePicker.nitro.ts └── types │ ├── camera.ts │ ├── config.ts │ ├── crop.ts │ ├── error.ts │ ├── index.ts │ ├── picker.ts │ ├── preview.ts │ └── result.ts ├── tsconfig.build.json ├── tsconfig.json └── yarn.lock /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2.1 2 | 3 | executors: 4 | default: 5 | docker: 6 | - image: circleci/node:10 7 | working_directory: ~/project 8 | 9 | commands: 10 | attach_project: 11 | steps: 12 | - attach_workspace: 13 | at: ~/project 14 | 15 | jobs: 16 | install-dependencies: 17 | executor: default 18 | steps: 19 | - checkout 20 | - attach_project 21 | - restore_cache: 22 | keys: 23 | - dependencies-{{ checksum "package.json" }} 24 | - dependencies- 25 | - restore_cache: 26 | keys: 27 | - dependencies-example-{{ checksum "example/package.json" }} 28 | - dependencies-example- 29 | - run: 30 | name: Install dependencies 31 | command: | 32 | yarn install --cwd example --frozen-lockfile 33 | yarn install --frozen-lockfile 34 | - save_cache: 35 | key: dependencies-{{ checksum "package.json" }} 36 | paths: node_modules 37 | - save_cache: 38 | key: dependencies-example-{{ checksum "example/package.json" }} 39 | paths: example/node_modules 40 | - persist_to_workspace: 41 | root: . 42 | paths: . 43 | 44 | lint: 45 | executor: default 46 | steps: 47 | - attach_project 48 | - run: 49 | name: Lint files 50 | command: | 51 | yarn lint 52 | 53 | typescript: 54 | executor: default 55 | steps: 56 | - attach_project 57 | - run: 58 | name: Typecheck files 59 | command: | 60 | yarn typescript 61 | 62 | unit-tests: 63 | executor: default 64 | steps: 65 | - attach_project 66 | - run: 67 | name: Run unit tests 68 | command: | 69 | yarn test --coverage 70 | - store_artifacts: 71 | path: coverage 72 | destination: coverage 73 | 74 | build-package: 75 | executor: default 76 | steps: 77 | - attach_project 78 | - run: 79 | name: Build package 80 | command: | 81 | yarn prepare 82 | 83 | workflows: 84 | build-and-test: 85 | jobs: 86 | - install-dependencies 87 | - lint: 88 | requires: 89 | - install-dependencies 90 | - typescript: 91 | requires: 92 | - install-dependencies 93 | - unit-tests: 94 | requires: 95 | - install-dependencies 96 | - build-package: 97 | requires: 98 | - install-dependencies 99 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: baronha 4 | patreon: baronha 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: baoha 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry 13 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 14 | -------------------------------------------------------------------------------- /.github/workflows/docs.yml: -------------------------------------------------------------------------------- 1 | name: Deploy to GitHub Pages 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | paths: 8 | - 'docs/**' 9 | 10 | jobs: 11 | build: 12 | name: Build Docusaurus 13 | runs-on: ubuntu-latest 14 | steps: 15 | - uses: actions/checkout@v4 16 | with: 17 | fetch-depth: 0 18 | - uses: actions/setup-node@v4 19 | with: 20 | node-version: 18 21 | cache: yarn 22 | 23 | - name: Install dependencies 24 | working-directory: docs 25 | run: yarn install --frozen-lockfile 26 | - name: Build docs 27 | working-directory: docs 28 | run: yarn build 29 | 30 | - name: Upload Build Artifact 31 | uses: actions/upload-pages-artifact@v3 32 | with: 33 | path: docs/build 34 | 35 | deploy: 36 | name: Deploy to GitHub Pages 37 | needs: build 38 | 39 | # Grant GITHUB_TOKEN the permissions required to make a Pages deployment 40 | permissions: 41 | pages: write # to deploy to Pages 42 | id-token: write # to verify the deployment originates from an appropriate source 43 | 44 | # Deploy to the github-pages environment 45 | environment: 46 | name: github-pages 47 | url: ${{ steps.deployment.outputs.page_url }} 48 | 49 | runs-on: ubuntu-latest 50 | steps: 51 | - name: Deploy to GitHub Pages 52 | id: deployment 53 | uses: actions/deploy-pages@v4 54 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # OSX 2 | # 3 | .DS_Store 4 | 5 | # XDE 6 | .expo/ 7 | 8 | # VSCode 9 | .vscode/ 10 | jsconfig.json 11 | 12 | # Xcode 13 | # 14 | build/ 15 | *.pbxuser 16 | !default.pbxuser 17 | *.mode1v3 18 | !default.mode1v3 19 | *.mode2v3 20 | !default.mode2v3 21 | *.perspectivev3 22 | !default.perspectivev3 23 | xcuserdata 24 | *.xccheckout 25 | *.moved-aside 26 | DerivedData 27 | *.hmap 28 | *.ipa 29 | *.xcuserstate 30 | project.xcworkspace 31 | 32 | # Android/IJ 33 | # 34 | .classpath 35 | .cxx 36 | .gradle 37 | .idea 38 | .project 39 | .settings 40 | local.properties 41 | android.iml 42 | 43 | # Cocoapods 44 | # 45 | example/ios/Pods 46 | 47 | # Ruby 48 | example/vendor/ 49 | 50 | # node.js 51 | # 52 | node_modules/ 53 | npm-debug.log 54 | yarn-debug.log 55 | yarn-error.log 56 | 57 | # BUCK 58 | buck-out/ 59 | \.buckd/ 60 | android/app/libs 61 | android/keystores/debug.keystore 62 | 63 | # Yarn 64 | .yarn/* 65 | !.yarn/patches 66 | !.yarn/plugins 67 | !.yarn/releases 68 | !.yarn/sdks 69 | !.yarn/versions 70 | 71 | # Expo 72 | .expo/ 73 | 74 | # Turborepo 75 | .turbo/ 76 | 77 | # generated by bob 78 | lib/ 79 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | example/ 2 | files/ 3 | node_modules/ 4 | npm-debug.log 5 | package-lock.json 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Baron Ha. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /MultipleImagePicker.podspec: -------------------------------------------------------------------------------- 1 | require "json" 2 | 3 | package = JSON.parse(File.read(File.join(__dir__, "package.json"))) 4 | 5 | Pod::Spec.new do |s| 6 | s.name = "MultipleImagePicker" 7 | s.version = package["version"] 8 | s.summary = package["description"] 9 | s.homepage = package["homepage"] 10 | s.license = package["license"] 11 | s.authors = package["author"] 12 | 13 | s.platforms = { :ios => min_ios_version_supported } 14 | s.source = { :git => "https://github.com/baronha/react-native-multiple-image-picker.git", :tag => "#{s.version}" } 15 | 16 | s.source_files = [ 17 | # Implementation (Swift) 18 | "ios/**/*.{swift}", 19 | # Autolinking/Registration (Objective-C++) 20 | "ios/**/*.{m,mm}", 21 | # Implementation (C++ objects) 22 | "cpp/**/*.{hpp,cpp}", 23 | ] 24 | 25 | s.resource_bundles = { 26 | "MultipleImagePicker" => ["ios/Assets.xcassets"] 27 | } 28 | 29 | 30 | s.dependency "HXPhotoPicker/Picker", "4.2.4" 31 | s.dependency "HXPhotoPicker/Camera/Lite", "4.2.4" 32 | s.dependency "HXPhotoPicker/Editor", "4.2.4" 33 | 34 | s.pod_target_xcconfig = { 35 | # C++ compiler flags, mainly for folly. 36 | "CLANG_CXX_LANGUAGE_STANDARD" => "c++20", 37 | "GCC_PREPROCESSOR_DEFINITIONS" => "$(inherited) FOLLY_NO_CONFIG FOLLY_CFG_NO_COROUTINES FOLLY_MOBILE" 38 | } 39 | 40 | if ENV["USE_FRAMEWORKS"] 41 | s.dependency "React-Core" 42 | add_dependency(s, "React-jsinspector", :framework_name => "jsinspector_modern") 43 | add_dependency(s, "React-rendererconsistency", :framework_name => "React_rendererconsistency") 44 | add_dependency(s, "React-jsinspectortracing", :framework_name => 'jsinspector_moderntracing') 45 | end 46 | 47 | load 'nitrogen/generated/ios/MultipleImagePicker+autolinking.rb' 48 | 49 | add_nitrogen_files(s) 50 | 51 | s.dependency 'React-jsi' 52 | s.dependency 'React-callinvoker' 53 | 54 | install_modules_dependencies(s) 55 | end -------------------------------------------------------------------------------- /android/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | project(MultipleImagePicker) 2 | cmake_minimum_required(VERSION 3.9.0) 3 | 4 | set (PACKAGE_NAME MultipleImagePicker) 5 | set (CMAKE_VERBOSE_MAKEFILE ON) 6 | set (CMAKE_CXX_STANDARD 20) 7 | 8 | # Define C++ library and add all sources 9 | add_library(${PACKAGE_NAME} SHARED 10 | src/main/cpp/cpp-adapter.cpp 11 | ) 12 | 13 | # Add Nitrogen specs :) 14 | include(${CMAKE_SOURCE_DIR}/../nitrogen/generated/android/MultipleImagePicker+autolinking.cmake) 15 | 16 | # Set up local includes 17 | include_directories( 18 | "src/main/cpp" 19 | "../cpp" 20 | ) 21 | 22 | find_library(LOG_LIB log) 23 | 24 | # Link all libraries together 25 | target_link_libraries( 26 | ${PACKAGE_NAME} 27 | ${LOG_LIB} 28 | android # <-- Android core 29 | ) 30 | -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | MultipleImagePicker_kotlinVersion=1.9.24 2 | MultipleImagePicker_minSdkVersion=23 3 | MultipleImagePicker_targetSdkVersion=34 4 | MultipleImagePicker_compileSdkVersion=34 5 | MultipleImagePicker_ndkVersion=26.1.10909125 6 | -------------------------------------------------------------------------------- /android/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /android/src/main/cpp/cpp-adapter.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "MultipleImagePickerOnLoad.hpp" 3 | 4 | JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void*) { 5 | return margelo::nitro::multipleimagepicker::initialize(vm); 6 | } 7 | -------------------------------------------------------------------------------- /android/src/main/java/com/margelo/nitro/multipleimagepicker/CameraEngine.kt: -------------------------------------------------------------------------------- 1 | package com.margelo.nitro.multipleimagepicker 2 | 3 | import android.content.Context 4 | import androidx.fragment.app.Fragment 5 | import com.bumptech.glide.Glide 6 | import com.facebook.react.bridge.ColorPropConverter 7 | import com.luck.lib.camerax.SimpleCameraX 8 | import com.luck.picture.lib.interfaces.OnCameraInterceptListener 9 | import java.io.File 10 | 11 | class CameraEngine( 12 | private val appContext: Context, 13 | val config: NitroCameraConfig, 14 | ) : 15 | OnCameraInterceptListener { 16 | override fun openCamera(fragment: Fragment, cameraMode: Int, requestCode: Int) { 17 | val camera = SimpleCameraX.of() 18 | 19 | camera.setImageEngine { context, url, imageView -> 20 | Glide.with(context).load(url).into(imageView) 21 | } 22 | 23 | camera.isAutoRotation(true) 24 | camera.setCameraMode(cameraMode) 25 | camera.isDisplayRecordChangeTime(true) 26 | camera.isManualFocusCameraPreview(true) 27 | camera.isZoomCameraPreview(true) 28 | camera.setRecordVideoMaxSecond(config.videoMaximumDuration?.toInt() ?: 60) 29 | camera.setCameraAroundState(config.cameraDevice == CameraDevice.FRONT) 30 | camera.setOutputPathDir(getSandboxCameraOutputPath()) 31 | 32 | config.color?.let { 33 | val primaryColor = ColorPropConverter.getColor(it, appContext) 34 | camera.setCaptureLoadingColor(primaryColor) 35 | } 36 | 37 | camera.start(fragment.requireActivity(), fragment, requestCode) 38 | } 39 | 40 | private fun getSandboxCameraOutputPath(): String { 41 | val externalFilesDir: File? = appContext.getExternalFilesDir("") 42 | val customFile = File(externalFilesDir?.absolutePath, "Sandbox") 43 | if (!customFile.exists()) { 44 | customFile.mkdirs() 45 | } 46 | return customFile.absolutePath + File.separator 47 | 48 | } 49 | } -------------------------------------------------------------------------------- /android/src/main/java/com/margelo/nitro/multipleimagepicker/Constant.kt: -------------------------------------------------------------------------------- 1 | package com.margelo.nitro.multipleimagepicker 2 | 3 | object Constant { 4 | const val TOOLBAR_TEXT_SIZE = 12 5 | } -------------------------------------------------------------------------------- /android/src/main/java/com/margelo/nitro/multipleimagepicker/GlideEngine.kt: -------------------------------------------------------------------------------- 1 | package com.margelo.nitro.multipleimagepicker 2 | 3 | import android.content.Context 4 | import android.widget.ImageView 5 | import com.bumptech.glide.Glide 6 | import com.bumptech.glide.load.resource.bitmap.CenterCrop 7 | import com.bumptech.glide.load.resource.bitmap.RoundedCorners 8 | import com.luck.picture.lib.engine.ImageEngine 9 | import com.luck.picture.lib.utils.ActivityCompatHelper 10 | 11 | class GlideEngine private constructor() : ImageEngine { 12 | override fun loadImage(context: Context, url: String, imageView: ImageView) { 13 | if (!ActivityCompatHelper.assertValidRequest(context)) { 14 | return 15 | } 16 | Glide.with(context) 17 | .load(url) 18 | .into(imageView) 19 | } 20 | 21 | override fun loadImage( 22 | context: Context, 23 | imageView: ImageView, 24 | url: String, 25 | maxWidth: Int, 26 | maxHeight: Int 27 | ) { 28 | if (!ActivityCompatHelper.assertValidRequest(context)) { 29 | return 30 | } 31 | Glide.with(context) 32 | .load(url) 33 | .override(maxWidth, maxHeight) 34 | .into(imageView) 35 | } 36 | 37 | override fun loadAlbumCover(context: Context, url: String, imageView: ImageView) { 38 | if (!ActivityCompatHelper.assertValidRequest(context)) { 39 | return 40 | } 41 | Glide.with(context) 42 | .asBitmap() 43 | .load(url) 44 | .override(180, 180) 45 | .sizeMultiplier(0.5f) 46 | .transform(CenterCrop(), RoundedCorners(8)) 47 | .into(imageView) 48 | } 49 | 50 | override fun loadGridImage(context: Context, url: String, imageView: ImageView) { 51 | if (!ActivityCompatHelper.assertValidRequest(context)) { 52 | return 53 | } 54 | Glide.with(context) 55 | .load(url) 56 | .override(200, 200) 57 | .centerCrop() 58 | .placeholder(com.luck.picture.lib.R.drawable.ps_image_placeholder) 59 | .into(imageView) 60 | } 61 | 62 | override fun pauseRequests(context: Context) { 63 | if (!ActivityCompatHelper.assertValidRequest(context)) { 64 | return 65 | } 66 | Glide.with(context).pauseRequests() 67 | } 68 | 69 | override fun resumeRequests(context: Context) { 70 | if (!ActivityCompatHelper.assertValidRequest(context)) { 71 | return 72 | } 73 | Glide.with(context).resumeRequests() 74 | } 75 | 76 | private object InstanceHolder { 77 | val instance = GlideEngine() 78 | } 79 | 80 | companion object { 81 | fun createGlideEngine(): GlideEngine { 82 | return InstanceHolder.instance 83 | } 84 | } 85 | } -------------------------------------------------------------------------------- /android/src/main/java/com/margelo/nitro/multipleimagepicker/ImageLoaderUtils.kt: -------------------------------------------------------------------------------- 1 | package com.margelo.nitro.multipleimagepicker 2 | 3 | import android.app.Activity 4 | import android.content.Context 5 | import android.content.ContextWrapper 6 | 7 | object ImageLoaderUtils { 8 | fun assertValidRequest(context: Context?): Boolean { 9 | if (context is Activity) { 10 | return !isDestroy(context) 11 | } else if (context is ContextWrapper) { 12 | if (context.baseContext is Activity) { 13 | val activity = context.baseContext as Activity 14 | return !isDestroy(activity) 15 | } 16 | } 17 | return true 18 | } 19 | 20 | private fun isDestroy(activity: Activity?): Boolean { 21 | return if (activity == null) { 22 | true 23 | } else activity.isFinishing || activity.isDestroyed 24 | } 25 | } -------------------------------------------------------------------------------- /android/src/main/java/com/margelo/nitro/multipleimagepicker/LoadingDialog.kt: -------------------------------------------------------------------------------- 1 | package com.margelo.nitro.multipleimagepicker 2 | 3 | 4 | import android.app.Dialog 5 | import android.content.Context 6 | import android.os.Bundle 7 | import android.view.Gravity 8 | import android.view.ViewGroup 9 | 10 | 11 | class LoadingDialog(context: Context?) : 12 | Dialog(context!!, R.style.Picture_Theme_AlertDialog) { 13 | init { 14 | setCancelable(true) 15 | setCanceledOnTouchOutside(false) 16 | } 17 | 18 | override fun onCreate(savedInstanceState: Bundle) { 19 | super.onCreate(savedInstanceState) 20 | setContentView(R.layout.loading_dialog) 21 | setDialogSize() 22 | } 23 | 24 | private fun setDialogSize() { 25 | val params = window!!.attributes 26 | params.width = ViewGroup.LayoutParams.WRAP_CONTENT 27 | params.height = ViewGroup.LayoutParams.WRAP_CONTENT 28 | params.gravity = Gravity.CENTER 29 | window!!.setWindowAnimations(R.style.PictureThemeDialogWindowStyle) 30 | window!!.attributes = params 31 | } 32 | } -------------------------------------------------------------------------------- /android/src/main/java/com/margelo/nitro/multipleimagepicker/MultipleImagePicker.kt: -------------------------------------------------------------------------------- 1 | package com.margelo.nitro.multipleimagepicker 2 | 3 | import com.margelo.nitro.NitroModules 4 | 5 | 6 | class MultipleImagePicker : HybridMultipleImagePickerSpec() { 7 | override val memorySize: Long 8 | get() = 5 9 | 10 | private val pickerModule = MultipleImagePickerImp(NitroModules.applicationContext) 11 | 12 | override fun openPicker( 13 | config: NitroConfig, 14 | resolved: (result: Array) -> Unit, 15 | rejected: (reject: Double) -> Unit 16 | ) { 17 | pickerModule.openPicker(config, resolved, rejected) 18 | } 19 | 20 | override fun openCrop( 21 | image: String, 22 | config: NitroCropConfig, 23 | resolved: (result: CropResult) -> Unit, 24 | rejected: (reject: Double) -> Unit 25 | ) { 26 | pickerModule.openCrop(image, config, resolved, rejected) 27 | } 28 | 29 | override fun openPreview( 30 | media: Array, 31 | index: Double, 32 | config: NitroPreviewConfig, 33 | onLongPress: (index: Double) -> Unit 34 | ) { 35 | pickerModule.openPreview(media, index.toInt(), config, onLongPress) 36 | } 37 | 38 | override fun openCamera( 39 | config: NitroCameraConfig, 40 | resolved: (result: CameraResult) -> Unit, 41 | rejected: (reject: Double) -> Unit 42 | ) { 43 | pickerModule.openCamera(config, resolved, rejected) 44 | } 45 | 46 | } -------------------------------------------------------------------------------- /android/src/main/java/com/margelo/nitro/multipleimagepicker/MultipleImagePickerPackage.java: -------------------------------------------------------------------------------- 1 | package com.margelo.nitro.multipleimagepicker; 2 | 3 | 4 | import androidx.annotation.NonNull; 5 | import androidx.annotation.Nullable; 6 | 7 | import com.facebook.react.bridge.NativeModule; 8 | import com.facebook.react.bridge.ReactApplicationContext; 9 | import com.facebook.react.module.model.ReactModuleInfoProvider; 10 | import com.facebook.react.TurboReactPackage; 11 | 12 | import java.util.HashMap; 13 | 14 | public class MultipleImagePickerPackage extends TurboReactPackage { 15 | @Nullable 16 | @Override 17 | public NativeModule getModule(@NonNull String name, @NonNull ReactApplicationContext reactContext) { 18 | return null; 19 | } 20 | 21 | @Override 22 | public ReactModuleInfoProvider getReactModuleInfoProvider() { 23 | return HashMap::new; 24 | } 25 | 26 | static { 27 | System.loadLibrary("MultipleImagePicker"); 28 | } 29 | } -------------------------------------------------------------------------------- /android/src/main/java/com/margelo/nitro/multipleimagepicker/PictureSelectorEngineImp.kt: -------------------------------------------------------------------------------- 1 | package com.margelo.nitro.multipleimagepicker 2 | 3 | import android.util.Log 4 | import com.luck.picture.lib.basic.IBridgeLoaderFactory 5 | import com.luck.picture.lib.engine.* 6 | import com.luck.picture.lib.engine.CompressEngine 7 | import com.luck.picture.lib.entity.LocalMedia 8 | import com.luck.picture.lib.interfaces.OnInjectLayoutResourceListener 9 | import com.luck.picture.lib.interfaces.OnResultCallbackListener 10 | 11 | class PictureSelectorEngineImp : PictureSelectorEngine { 12 | /** 13 | * 重新创建[ImageEngine]引擎 14 | * 15 | * @return 16 | */ 17 | override fun createImageLoaderEngine(): ImageEngine { 18 | return GlideEngine.createGlideEngine() 19 | } 20 | 21 | /** 22 | * 重新创建[CompressEngine]引擎 23 | * 24 | * @return 25 | */ 26 | override fun createCompressEngine(): CompressEngine? { 27 | // TODO 这种情况是内存极度不足的情况下,比如开启开发者选项中的不保留活动或后台进程限制,导致CompressEngine被回收 28 | return null 29 | } 30 | 31 | /** 32 | * 重新创建[CompressEngine]引擎 33 | * 34 | * @return 35 | */ 36 | override fun createCompressFileEngine(): CompressFileEngine? { 37 | // TODO 这种情况是内存极度不足的情况下,比如开启开发者选项中的不保留活动或后台进程限制,导致CompressFileEngine被回收 38 | return null 39 | } 40 | 41 | /** 42 | * 重新创建[ExtendLoaderEngine]引擎 43 | * 44 | * @return 45 | */ 46 | override fun createLoaderDataEngine(): ExtendLoaderEngine? { 47 | return null 48 | } 49 | 50 | override fun createVideoPlayerEngine(): VideoPlayerEngine<*>? { 51 | return null 52 | } 53 | 54 | override fun onCreateLoader(): IBridgeLoaderFactory? { 55 | return null 56 | } 57 | 58 | /** 59 | * 重新创建[SandboxFileEngine]引擎 60 | * 61 | * @return 62 | */ 63 | override fun createSandboxFileEngine(): SandboxFileEngine? { 64 | return null 65 | } 66 | 67 | override fun createUriToFileTransformEngine(): UriToFileTransformEngine? { 68 | return null 69 | } 70 | 71 | override fun createLayoutResourceListener(): OnInjectLayoutResourceListener? { 72 | return null 73 | } 74 | 75 | override fun getResultCallbackListener(): OnResultCallbackListener { 76 | return object : OnResultCallbackListener { 77 | override fun onResult(result: ArrayList) { 78 | 79 | Log.i(TAG, "onResult:" + result.size) 80 | } 81 | 82 | override fun onCancel() { 83 | Log.i(TAG, "PictureSelector onCancel") 84 | } 85 | } 86 | } 87 | 88 | companion object { 89 | private val TAG = PictureSelectorEngineImp::class.java.simpleName 90 | } 91 | } -------------------------------------------------------------------------------- /android/src/main/java/com/margelo/nitro/multipleimagepicker/VideoThumbnailEngine.kt: -------------------------------------------------------------------------------- 1 | package com.margelo.nitro.multipleimagepicker 2 | 3 | import android.content.Context 4 | import android.graphics.Bitmap 5 | import android.graphics.drawable.Drawable 6 | import com.bumptech.glide.Glide 7 | import com.bumptech.glide.request.target.CustomTarget 8 | import com.bumptech.glide.request.transition.Transition 9 | import com.luck.picture.lib.interfaces.OnKeyValueResultCallbackListener 10 | import com.luck.picture.lib.interfaces.OnVideoThumbnailEventListener 11 | import com.luck.picture.lib.utils.PictureFileUtils 12 | import java.io.ByteArrayOutputStream 13 | import java.io.File 14 | import java.io.FileOutputStream 15 | import java.io.IOException 16 | 17 | 18 | class VideoThumbnailEngine(private val targetPath: String) : OnVideoThumbnailEventListener { 19 | override fun onVideoThumbnail( 20 | context: Context, videoPath: String, call: OnKeyValueResultCallbackListener 21 | ) { 22 | Glide.with(context).asBitmap().sizeMultiplier(0.6f).load(videoPath) 23 | .into(object : CustomTarget() { 24 | override fun onResourceReady( 25 | resource: Bitmap, transition: Transition? 26 | ) { 27 | val stream = ByteArrayOutputStream() 28 | resource.compress(Bitmap.CompressFormat.JPEG, 60, stream) 29 | var fos: FileOutputStream? = null 30 | var result: String? = null 31 | try { 32 | val targetFile = 33 | File(targetPath, "thumbnails_" + System.currentTimeMillis() + ".jpg") 34 | fos = FileOutputStream(targetFile) 35 | fos.write(stream.toByteArray()) 36 | fos.flush() 37 | result = targetFile.absolutePath 38 | } catch (e: IOException) { 39 | e.printStackTrace() 40 | } finally { 41 | PictureFileUtils.close(fos) 42 | PictureFileUtils.close(stream) 43 | } 44 | call.onCallback(videoPath, result) 45 | } 46 | 47 | override fun onLoadCleared(placeholder: Drawable?) { 48 | call.onCallback(videoPath, "") 49 | } 50 | }) 51 | } 52 | } -------------------------------------------------------------------------------- /android/src/main/res/anim/anim_modal_in.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 10 | 11 | 19 | -------------------------------------------------------------------------------- /android/src/main/res/drawable/checkbox_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /android/src/main/res/drawable/complete_button.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 10 | -------------------------------------------------------------------------------- /android/src/main/res/drawable/ic_checkmark.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 12 | 13 | -------------------------------------------------------------------------------- /android/src/main/res/drawable/ic_down.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /android/src/main/res/drawable/num_oval.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 10 | 13 | -------------------------------------------------------------------------------- /android/src/main/res/drawable/picture_not_selected.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 11 | 12 | -------------------------------------------------------------------------------- /android/src/main/res/drawable/picture_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /android/src/main/res/drawable/preview_gallery_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | -------------------------------------------------------------------------------- /android/src/main/res/drawable/preview_gallery_white_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 8 | 9 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /android/src/main/res/layout/loading_dialog.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 17 | 18 | -------------------------------------------------------------------------------- /android/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #393a3e 4 | #000000 5 | #f6f6f6 6 | #fafafa 7 | #B6B6B6 8 | #f94c51 9 | #43c117 10 | #53575e 11 | #00000000 12 | #FFFFFF 13 | #E0DBDBDB 14 | #7D7DFF 15 | #9b9b9b 16 | #E0FF6100 17 | #FF0000 18 | #FB9300 19 | #333333 20 | #0D333333 21 | 22 | -------------------------------------------------------------------------------- /android/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | 16 | 17 | 21 | 22 | 26 | 27 | 37 | 38 | 42 | 43 | 60 | 61 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: ['module:metro-react-native-babel-preset'], 3 | }; 4 | -------------------------------------------------------------------------------- /docs/.gitignore: -------------------------------------------------------------------------------- 1 | # Dependencies 2 | /node_modules 3 | 4 | # Production 5 | /build 6 | 7 | # Generated files 8 | .docusaurus 9 | .cache-loader 10 | 11 | # Misc 12 | .DS_Store 13 | .env.local 14 | .env.development.local 15 | .env.test.local 16 | .env.production.local 17 | 18 | npm-debug.log* 19 | yarn-debug.log* 20 | yarn-error.log* 21 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # Website 2 | 3 | This website is built using [Docusaurus](https://docusaurus.io/), a modern static website generator. 4 | 5 | ### Installation 6 | 7 | ``` 8 | $ yarn 9 | ``` 10 | 11 | ### Local Development 12 | 13 | ``` 14 | $ yarn start 15 | ``` 16 | 17 | This command starts a local development server and opens up a browser window. Most changes are reflected live without having to restart the server. 18 | 19 | ### Build 20 | 21 | ``` 22 | $ yarn build 23 | ``` 24 | 25 | This command generates static content into the `build` directory and can be served using any static contents hosting service. 26 | 27 | ### Deployment 28 | 29 | Using SSH: 30 | 31 | ``` 32 | $ USE_SSH=true yarn deploy 33 | ``` 34 | 35 | Not using SSH: 36 | 37 | ``` 38 | $ GIT_USER= yarn deploy 39 | ``` 40 | 41 | If you are using GitHub pages for hosting, this command is a convenient way to build the website and push to the `gh-pages` branch. 42 | -------------------------------------------------------------------------------- /docs/docs/CROP.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | id: crop 3 | title: Crop 🍕 4 | sidebar_label: Crop 🍕 5 | slug: /crop 6 | --- 7 | 8 | ## Usage 9 | 10 | ```typescript 11 | import { openCropper } from '@baronha/react-native-multiple-image-picker' 12 | 13 | const cropConfig: CropConfig = { 14 | // ... 15 | } 16 | 17 | const open = async () => { 18 | try { 19 | const response = await openCropper('file://path/to/image.jpg', cropConfig) 20 | setImages(response) 21 | } catch (e) { 22 | // catch error for multiple image picker 23 | } 24 | } 25 | ``` 26 | 27 | ## CropConfig 28 | 29 | ### `circle` 30 | 31 | Enable circular crop mask. 32 | 33 | - **Type**: boolean 34 | - **Default**: `false` 35 | - **Required**: No 36 | - **Platform**: iOS, Android 37 | 38 | ### `ratio` 39 | 40 | Aspect ratios for cropping. 41 | Android: Maximum: 4 items 42 | 43 | - **Type**: `array` 44 | - **Default**: `undefined` 45 | - **Required**: No 46 | - **Platform**: iOS, Android 47 | - **Properties**: 48 | - `title`: string - Display title for the ratio (e.g., "Square", "16:9") 49 | - `width`: number - Width value for the aspect ratio 50 | - `height`: number - Height value for the aspect ratio 51 | 52 | ### `defaultRatio` 53 | 54 | Default ratio to be selected when opening the crop interface. 55 | 56 | - **Type**: `object` 57 | - **Default**: `undefined` 58 | - **Required**: No 59 | - **Platform**: iOS, Android 60 | - **Properties**: 61 | - `title`: string - Display title for the ratio (e.g., "Square", "16:9") 62 | - `width`: number - Width value for the aspect ratio 63 | - `height`: number - Height value for the aspect ratio 64 | 65 | ### `freeStyle` 66 | 67 | Enable free style cropping. 68 | 69 | - **Type**: `boolean` 70 | - **Default**: `false` 71 | - **Required**: No 72 | - **Platform**: iOS, Android 73 | 74 | ### `language` 75 | 76 | - **Type**: `string` 77 | - **Default**: `false` 78 | - **Required**: No 79 | - **Platform**: iOS 80 | 81 | See [**Language**](/config/#language) 82 | 83 | ## Result 84 | 85 | ### `path` 86 | 87 | - **Type**: `string` 88 | 89 | ### `width` 90 | 91 | - **Type**: `number` 92 | 93 | ### `height` 94 | 95 | - **Type**: `number` 96 | -------------------------------------------------------------------------------- /docs/docs/RESULT.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | id: result 3 | title: Result 4 | sidebar_label: Result 5 | slug: /result 6 | --- 7 | 8 | The result object returned for each selected media item. 9 | 10 | ### `path` 11 | 12 | - **Type**: string 13 | - **Description**: Local file path of the media 14 | 15 | ### `fileName` 16 | 17 | - **Type**: string 18 | - **Description**: Name of the media file 19 | 20 | ### `localIdentifier` 21 | 22 | - **Type**: string 23 | - **Description**: Unique identifier for the media asset 24 | 25 | ### `width` 26 | 27 | - **Type**: number 28 | - **Description**: Width of the media in pixels 29 | 30 | ### `height` 31 | 32 | - **Type**: number 33 | - **Description**: Height of the media in pixels 34 | 35 | ### `mime` 36 | 37 | - **Type**: string 38 | - **Description**: MIME type of the media file 39 | 40 | ### `size` 41 | 42 | - **Type**: number 43 | - **Description**: File size in bytes 44 | 45 | ### `bucketId` 46 | 47 | - **Type**: number 48 | - **Description**: ID of the bucket containing the media 49 | - **Platform**: Android 50 | 51 | ### `realPath` 52 | 53 | - **Type**: string 54 | - **Description**: Actual file path in the device storage 55 | - **Platform**: Android 56 | 57 | ### `parentFolderName` 58 | 59 | - **Type**: string 60 | - **Description**: Name of the parent folder 61 | - **Platform**: Android 62 | 63 | ### `creationDate` 64 | 65 | - **Type**: number 66 | - **Description**: Creation timestamp of the media 67 | 68 | ### `type` 69 | 70 | - **Type**: string 71 | - **Options**: `image` | `video` 72 | - **Description**: Type of the media file 73 | 74 | ### `duration` 75 | 76 | - **Type**: number 77 | - **Description**: Duration in seconds (for video files) 78 | 79 | ### `thumbnail` 80 | 81 | - **Type**: string 82 | - **Description**: Thumbnail path for video files 83 | 84 | ### `crop` 85 | 86 | - **Type**: boolean 87 | - **Description**: Indicates if the media has been cropped 88 | -------------------------------------------------------------------------------- /docs/docs/SHOWCASE/index.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | id: showcase 3 | title: Showcase ✨ 4 | sidebar_label: Showcase ✨ 5 | slug: /showcase 6 | --- 7 | 8 | import style from './showcase.css' 9 | import data from './showcase.json' 10 | 11 | List of used applications with `@baronha/react-native-multiple-image-picker` 12 | 13 | > Contributions are welcome! If you have an application that uses `@baronha/react-native-multiple-image-picker`
14 | > please open a [**Pull Request**](https://github.com/baronha/react-native-multiple-image-picker/tree/master/docs/docs/SHOWCASE/showcase.json) to add it to the list. 15 | 16 |
17 | 18 |
19 | {data.map((item, index) => { 20 | return ( 21 | 27 | {item.title} 28 | {item.title} 29 |

{item?.tagline}

30 |
31 | ) 32 | })} 33 |
34 | -------------------------------------------------------------------------------- /docs/docs/SHOWCASE/showcase.css: -------------------------------------------------------------------------------- 1 | .showcaseContainer { 2 | display: flex; 3 | /* justify-content: space-between; */ 4 | flex-wrap: wrap; 5 | gap: 20px; 6 | } 7 | 8 | .showcaseItem { 9 | flex: 1; 10 | color: inherit; 11 | text-decoration: none; 12 | } 13 | 14 | .showcaseItem a:hover { 15 | color: red; 16 | text-decoration: none !important; 17 | } 18 | 19 | .showcaseItem b { 20 | font-size: 1rem; 21 | } 22 | 23 | .showcaseItem .showcaseTagline { 24 | display: -webkit-box; 25 | -webkit-line-clamp: 2; 26 | -webkit-box-orient: vertical; 27 | overflow: hidden; 28 | text-overflow: ellipsis; 29 | margin: 0; 30 | } 31 | 32 | .showcaseBanner { 33 | width: 100%; 34 | aspect-ratio: 16/9; 35 | object-fit: cover; 36 | } 37 | 38 | @media (max-width: 768px) { 39 | .showcaseItem { 40 | flex: 100%; 41 | margin-right: 0; 42 | } 43 | } 44 | 45 | @media (min-width: 992px) { 46 | /* lg */ 47 | .showcaseItem { 48 | max-width: 33.333%; 49 | } 50 | } 51 | 52 | @media (min-width: 1200px) { 53 | /* xl */ 54 | .showcaseItem { 55 | max-width: 33.333%; 56 | } 57 | } 58 | 59 | @media (min-width: 1400px) { 60 | /* xxl */ 61 | .showcaseItem { 62 | max-width: 33.333%; 63 | } 64 | } 65 | 66 | @media (max-width: 480px) { 67 | .showcaseItem { 68 | flex: 100%; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /docs/docs/SHOWCASE/showcase.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "banner": "https://github.com/user-attachments/assets/84ec6432-1557-4649-965c-6100d9c4c12d", 4 | "title": "✨ Binsoo - Photo Filters & Editor", 5 | "link": "https://apps.apple.com/vn/app/binsoo-photo-filters-editor/id6502683720", 6 | "tagline": "Endless aesthetics and effects" 7 | }, 8 | { 9 | "banner": "https://github.com/user-attachments/assets/72a7787a-4a41-40e3-b6bb-a5c7b0eafc83", 10 | "title": "Pupi", 11 | "link": "https://apps.apple.com/vn/app/pupi-h%E1%BB%8Dc-vui-ti%E1%BA%BFn-b%E1%BB%99/id1638474798", 12 | "tagline": "Học vui & tiến b‪ộ" 13 | }, 14 | { 15 | "banner": "https://github.com/user-attachments/assets/dd92d243-7fb0-40ff-9b78-7b4fd2a54092", 16 | "title": "Pety", 17 | "link": "https://apps.apple.com/vn/app/pety/id1506375124", 18 | "tagline": "New Lifestyle for Pet Lovers" 19 | } 20 | ] 21 | -------------------------------------------------------------------------------- /docs/docs/USAGE.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | id: usage 3 | title: Usage 4 | sidebar_label: Usage 5 | slug: /usage 6 | --- 7 | 8 | Here is a simple usage of the Multiple Image Picker.
9 | See more [**Config**](/config) 10 | 11 | ```typescript 12 | import { openPicker, Config } from '@baronha/react-native-multiple-image-picker' 13 | 14 | const config: Config = { 15 | maxSelect: 10, 16 | maxVideo: 10, 17 | primaryColor: '#FB9300', 18 | backgroundDark: '#2f2f2f', 19 | numberOfColumn: 4, 20 | mediaType: 'all', 21 | selectBoxStyle: 'number', 22 | selectMode: 'multiple', 23 | language: 'vi', // 🇻🇳 Vietnamese 24 | theme: 'dark', 25 | isHiddenOriginalButton: false, 26 | primaryColor: '#F6B35D', 27 | } 28 | 29 | const onPicker = async () => { 30 | try { 31 | const response = await openPicker(config) 32 | setImages(response) 33 | } catch (e) { 34 | // catch error for multiple image picker 35 | } 36 | } 37 | ``` 38 | -------------------------------------------------------------------------------- /docs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "docs", 3 | "version": "2.2.3", 4 | "private": true, 5 | "scripts": { 6 | "docusaurus": "docusaurus", 7 | "start": "docusaurus start", 8 | "build": "docusaurus build", 9 | "swizzle": "docusaurus swizzle", 10 | "deploy": "docusaurus deploy", 11 | "clear": "docusaurus clear", 12 | "serve": "docusaurus serve", 13 | "write-translations": "docusaurus write-translations", 14 | "write-heading-ids": "docusaurus write-heading-ids", 15 | "typecheck": "tsc", 16 | "postinstall": "patch-package" 17 | }, 18 | "dependencies": { 19 | "@docusaurus/core": "3.5.2", 20 | "@docusaurus/plugin-google-gtag": "^3.5.2", 21 | "@docusaurus/preset-classic": "3.5.2", 22 | "@gorhom/docusaurus-preset": "*", 23 | "@gorhom/docusaurus-theme": "*", 24 | "@mdx-js/react": "^3.0.0", 25 | "clsx": "^2.0.0", 26 | "prism-react-renderer": "^2.3.0", 27 | "react": "^18.0.0", 28 | "react-dom": "^18.0.0", 29 | "react-player": "^2.16.0" 30 | }, 31 | "devDependencies": { 32 | "@docusaurus/module-type-aliases": "3.5.2", 33 | "@docusaurus/tsconfig": "3.5.2", 34 | "@docusaurus/types": "3.5.2", 35 | "patch-package": "^8.0.0", 36 | "typescript": "~5.6.2" 37 | }, 38 | "browserslist": { 39 | "production": [ 40 | ">0.5%", 41 | "not dead", 42 | "not op_mini all" 43 | ], 44 | "development": [ 45 | "last 3 chrome version", 46 | "last 3 firefox version", 47 | "last 5 safari version" 48 | ] 49 | }, 50 | "engines": { 51 | "node": ">=18.0" 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /docs/patches/@gorhom+docusaurus-preset+1.0.2.patch: -------------------------------------------------------------------------------- 1 | diff --git a/node_modules/@gorhom/docusaurus-preset/lib/index.js b/node_modules/@gorhom/docusaurus-preset/lib/index.js 2 | index 66e815e..7ab6b15 100644 3 | --- a/node_modules/@gorhom/docusaurus-preset/lib/index.js 4 | +++ b/node_modules/@gorhom/docusaurus-preset/lib/index.js 5 | @@ -23,21 +23,21 @@ export default function preset(context, opts = {}) { 6 | theme: prismThemes.github, 7 | darkTheme: prismThemes.dracula, 8 | }; 9 | - // overrides footer 10 | - themeConfig.footer = { 11 | - ...(themeConfig.footer ?? {}), 12 | - copyright: `Open Source by Mo Gorhom.`, 13 | - links: [ 14 | - { 15 | - label: "Github", 16 | - href: "https://github.com/gorhom", 17 | - }, 18 | - { 19 | - label: "X (Twitter)", 20 | - href: "https://twitter.com/gorhom", 21 | - }, 22 | - ] 23 | - }; 24 | + // overrides footer 25 | + themeConfig.footer = { 26 | + 27 | + copyright: `Open Source by Bao Ha.`, 28 | + links: [ 29 | + { 30 | + label: "Github", 31 | + href: "https://github.com/baronha", 32 | + }, 33 | + { 34 | + label: "X (Twitter)", 35 | + href: "https://twitter.com/_baronha", 36 | + }, 37 | + ], 38 | + } 39 | const themes = []; 40 | themes.push(makePluginConfig("@gorhom/docusaurus-theme", theme)); 41 | if (algolia) { 42 | -------------------------------------------------------------------------------- /docs/sidebars.ts: -------------------------------------------------------------------------------- 1 | import type { SidebarsConfig } from '@docusaurus/plugin-content-docs' 2 | 3 | // This runs in Node.js - Don't use client-side code here (browser APIs, JSX...) 4 | 5 | /** 6 | * Creating a sidebar enables you to: 7 | - create an ordered group of docs 8 | - render a sidebar for each doc of that group 9 | - provide next/previous navigation 10 | 11 | The sidebars can be generated from the filesystem, or explicitly defined here. 12 | 13 | Create as many sidebars as you want. 14 | */ 15 | const sidebars: SidebarsConfig = { 16 | 'multiple-image-picker': [ 17 | { 18 | type: 'category', 19 | label: 'RNMIP', 20 | link: { 21 | type: 'doc', 22 | id: 'index', 23 | }, 24 | items: ['getting-started', 'usage', 'config', 'result'], 25 | }, 26 | 'crop', 27 | 'preview', 28 | 'camera', 29 | ], 30 | } 31 | 32 | export default sidebars 33 | -------------------------------------------------------------------------------- /docs/src/css/custom.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NitrogenZLab/react-native-multiple-image-picker/6c531f3f60d7a2ed238386c38f2ee85f55d970f9/docs/src/css/custom.css -------------------------------------------------------------------------------- /docs/static/.nojekyll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NitrogenZLab/react-native-multiple-image-picker/6c531f3f60d7a2ed238386c38f2ee85f55d970f9/docs/static/.nojekyll -------------------------------------------------------------------------------- /docs/static/img/RNMIP.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NitrogenZLab/react-native-multiple-image-picker/6c531f3f60d7a2ed238386c38f2ee85f55d970f9/docs/static/img/RNMIP.png -------------------------------------------------------------------------------- /docs/static/img/banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NitrogenZLab/react-native-multiple-image-picker/6c531f3f60d7a2ed238386c38f2ee85f55d970f9/docs/static/img/banner.png -------------------------------------------------------------------------------- /docs/static/img/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NitrogenZLab/react-native-multiple-image-picker/6c531f3f60d7a2ed238386c38f2ee85f55d970f9/docs/static/img/favicon.ico -------------------------------------------------------------------------------- /docs/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | // This file is not used in compilation. It is here just for a nice editor experience. 3 | "extends": "@docusaurus/tsconfig", 4 | "compilerOptions": { 5 | "baseUrl": "." 6 | }, 7 | "exclude": [".docusaurus", "build"] 8 | } 9 | -------------------------------------------------------------------------------- /example/.gitignore: -------------------------------------------------------------------------------- 1 | # Learn more https://docs.github.com/en/get-started/getting-started-with-git/ignoring-files 2 | 3 | # dependencies 4 | node_modules/ 5 | 6 | # Expo 7 | .expo/ 8 | dist/ 9 | web-build/ 10 | 11 | # Native 12 | *.orig.* 13 | *.jks 14 | *.p8 15 | *.p12 16 | *.key 17 | *.mobileprovision 18 | 19 | # Metro 20 | .metro-health-check* 21 | 22 | # debug 23 | npm-debug.* 24 | yarn-debug.* 25 | yarn-error.* 26 | 27 | # macOS 28 | .DS_Store 29 | *.pem 30 | 31 | # local env files 32 | .env*.local 33 | 34 | # typescript 35 | *.tsbuildinfo 36 | 37 | /ios 38 | /android -------------------------------------------------------------------------------- /example/App.tsx: -------------------------------------------------------------------------------- 1 | import { LogBox, UIManager } from 'react-native' 2 | import App from './src' 3 | 4 | LogBox.ignoreAllLogs() 5 | 6 | UIManager.setLayoutAnimationEnabledExperimental && 7 | UIManager.setLayoutAnimationEnabledExperimental(true) 8 | 9 | export default App 10 | -------------------------------------------------------------------------------- /example/Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | # You may use http://rbenv.org/ or https://rvm.io/ to install and use this version 4 | ruby ">= 3.0.0" 5 | 6 | # Exclude problematic versions of cocoapods and activesupport that causes build failures. 7 | gem 'cocoapods', '>= 1.13', '!= 1.15.0', '!= 1.15.1' 8 | gem 'activesupport', '>= 6.1.7.5', '!= 7.1.0' -------------------------------------------------------------------------------- /example/README.md: -------------------------------------------------------------------------------- 1 | # Example 2 | 3 | This website is built using [Expo](https://docs.expo.dev/) 4 | 5 | https://github.com/user-attachments/assets/79580bc7-237c-46b7-b92e-1479cc6d9079 6 | 7 | 8 | 9 | ### Installation 10 | 11 | ``` 12 | $ yarn 13 | $ yarn prebuild --clean 14 | ``` 15 | 16 | ### Step 2 17 | 18 | ``` 19 | $ NNN Enjoy Bro 🐧 20 | ``` 21 | -------------------------------------------------------------------------------- /example/app.json: -------------------------------------------------------------------------------- 1 | { 2 | "expo": { 3 | "name": "MultipleImagePickerExample", 4 | "slug": "MultipleImagePickerExample", 5 | "version": "1.0.0", 6 | "orientation": "portrait", 7 | "icon": "./assets/icon.png", 8 | "userInterfaceStyle": "automatic", 9 | "splash": { 10 | "image": "./assets/splash.png", 11 | "resizeMode": "contain", 12 | "backgroundColor": "#ffffff" 13 | }, 14 | "ios": { 15 | "supportsTablet": true, 16 | "infoPlist": { 17 | "NSCameraUsageDescription": "We needs to access your camera so that you can upload your photo: (avatar, etc.)", 18 | "NSPhotoLibraryAddUsageDescription": "We needs photo library permissions to allow you to upload profile images.", 19 | "NSPhotoLibraryUsageDescription": "We needs photo library permissions to allow you to upload profile images.", 20 | "NSMicrophoneUsageDescription": "We needs to access your microphone so that you can take your photo: (avatar, etc.)" 21 | }, 22 | "bundleIdentifier": "com.baoha.imagepicker" 23 | }, 24 | "android": { 25 | "adaptiveIcon": { 26 | "foregroundImage": "./assets/adaptive-icon.png", 27 | "backgroundColor": "#ffffff" 28 | }, 29 | "package": "com.baoha.imagepicker" 30 | }, 31 | 32 | "plugins": [ 33 | [ 34 | "expo-build-properties", 35 | { 36 | "ios": { 37 | "deploymentTarget": "15.6", 38 | "useFrameworks": "static" 39 | }, 40 | "android": { 41 | "compileSdkVersion": 34, 42 | "targetSdkVersion": 34, 43 | "buildToolsVersion": "34.0.0" 44 | } 45 | } 46 | ] 47 | ] 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /example/assets/adaptive-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NitrogenZLab/react-native-multiple-image-picker/6c531f3f60d7a2ed238386c38f2ee85f55d970f9/example/assets/adaptive-icon.png -------------------------------------------------------------------------------- /example/assets/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NitrogenZLab/react-native-multiple-image-picker/6c531f3f60d7a2ed238386c38f2ee85f55d970f9/example/assets/icon.png -------------------------------------------------------------------------------- /example/assets/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NitrogenZLab/react-native-multiple-image-picker/6c531f3f60d7a2ed238386c38f2ee85f55d970f9/example/assets/splash.png -------------------------------------------------------------------------------- /example/babel.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | module.exports = function (api) { 3 | api.cache(true) 4 | return { 5 | presets: ['babel-preset-expo'], 6 | plugins: [ 7 | [ 8 | 'module-resolver', 9 | { 10 | extensions: ['.tsx', '.ts', '.js', '.json'], 11 | alias: { 12 | // For development, we want to alias the library to the source 13 | '@baronha/react-native-multiple-image-picker': path.join( 14 | __dirname, 15 | '..', 16 | 'src', 17 | 'index.ts' 18 | ), 19 | }, 20 | }, 21 | ], 22 | ], 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /example/metro.config.js: -------------------------------------------------------------------------------- 1 | // Learn more https://docs.expo.io/guides/customizing-metro 2 | const { getDefaultConfig } = require('expo/metro-config') 3 | const path = require('path') 4 | 5 | const config = getDefaultConfig(__dirname) 6 | 7 | // npm v7+ will install ../node_modules/react-native because of peerDependencies. 8 | // To prevent the incompatible react-native bewtween ./node_modules/react-native and ../node_modules/react-native, 9 | // excludes the one from the parent folder when bundling. 10 | config.resolver.blockList = [ 11 | ...Array.from(config.resolver.blockList ?? []), 12 | new RegExp(path.resolve('..', 'node_modules', 'react-native')), 13 | ] 14 | 15 | config.resolver.nodeModulesPaths = [ 16 | path.resolve(__dirname, './node_modules'), 17 | path.resolve(__dirname, '../node_modules'), 18 | ] 19 | 20 | config.watchFolders = [path.resolve(__dirname, '..')] 21 | 22 | config.transformer.getTransformOptions = async () => ({ 23 | transform: { 24 | experimentalImportSupport: false, 25 | inlineRequires: true, 26 | }, 27 | }) 28 | 29 | module.exports = config 30 | -------------------------------------------------------------------------------- /example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "multipleimagepickerexample", 3 | "version": "2.2.3", 4 | "main": "expo/AppEntry.js", 5 | "scripts": { 6 | "start": "expo start", 7 | "android": "expo run:android", 8 | "ios": "expo run:ios", 9 | "web": "expo start --web", 10 | "pod": "cd ios && bundle exec pod update", 11 | "pod-new-arch": "cd ios && RCT_NEW_ARCH_ENABLED=1 bundle exec pod install", 12 | "prebuild": "expo prebuild", 13 | "gradle": "cd android && ./gradlew clean && ./gradlew build" 14 | }, 15 | "dependencies": { 16 | "@baronha/react-native-image-grid": "^0.2.7", 17 | "@react-native-segmented-control/segmented-control": "2.5.7", 18 | "expo": "53.0.9", 19 | "expo-build-properties": "~0.14.6", 20 | "expo-status-bar": "~2.2.3", 21 | "expo-system-ui": "~5.0.7", 22 | "immer": "^10.1.1", 23 | "react": "19.0.0", 24 | "react-native": "0.79.2", 25 | "use-immer": "^0.10.0" 26 | }, 27 | "devDependencies": { 28 | "@babel/core": "^7.20.0", 29 | "@react-native/babel-preset": "0.75.2", 30 | "@react-native/metro-config": "0.75.2", 31 | "@react-native/typescript-config": "0.75.2", 32 | "@types/react": "~19.0.10", 33 | "react-native-builder-bob": "^0.30.0", 34 | "react-native-nitro-modules": "^0.25.2", 35 | "typescript": "~5.8.3" 36 | }, 37 | "private": true 38 | } 39 | -------------------------------------------------------------------------------- /example/react-native.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const pkg = require('../package.json') 3 | 4 | module.exports = { 5 | project: { 6 | ios: { 7 | automaticPodsInstallation: true, 8 | }, 9 | }, 10 | dependencies: { 11 | [pkg.name]: { 12 | root: path.join(__dirname, '..'), 13 | }, 14 | }, 15 | } 16 | -------------------------------------------------------------------------------- /example/src/assets/check.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NitrogenZLab/react-native-multiple-image-picker/6c531f3f60d7a2ed238386c38f2ee85f55d970f9/example/src/assets/check.png -------------------------------------------------------------------------------- /example/src/assets/index.ts: -------------------------------------------------------------------------------- 1 | const images = { 2 | logo: require('./logo.png'), 3 | plusSign: require('./plus-sign.png'), 4 | check: require('./check.png'), 5 | } 6 | 7 | export default images 8 | -------------------------------------------------------------------------------- /example/src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NitrogenZLab/react-native-multiple-image-picker/6c531f3f60d7a2ed238386c38f2ee85f55d970f9/example/src/assets/logo.png -------------------------------------------------------------------------------- /example/src/assets/plus-sign.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NitrogenZLab/react-native-multiple-image-picker/6c531f3f60d7a2ed238386c38f2ee85f55d970f9/example/src/assets/plus-sign.png -------------------------------------------------------------------------------- /example/src/common/const.ts: -------------------------------------------------------------------------------- 1 | import { Platform } from 'react-native' 2 | 3 | export const IS_IOS = Platform.OS === 'ios' 4 | export const IS_ANDROID = Platform.OS === 'android' 5 | 6 | export const LOCALIZED_LANGUAGES = [ 7 | { 8 | key: 'system', 9 | label: 'System 🌐', 10 | }, 11 | { 12 | key: 'vi', 13 | label: 'Tiếng Việt 🇻🇳', 14 | }, 15 | { 16 | key: 'zh-Hans', 17 | label: '简体中文 🇨🇳', 18 | }, 19 | { 20 | key: 'zh-Hant', 21 | label: '繁體中文 🇹🇼', 22 | }, 23 | { 24 | key: 'ja', 25 | label: '日本語 🇯🇵', 26 | }, 27 | { 28 | key: 'ko', 29 | label: '한국어 🇰🇷', 30 | }, 31 | { 32 | key: 'en', 33 | label: 'English 🇺🇸', 34 | }, 35 | { 36 | key: 'ru', 37 | label: 'Русский 🇷🇺', 38 | }, 39 | { 40 | key: 'de', 41 | label: 'Deutsch 🇩🇪', 42 | }, 43 | { 44 | key: 'fr', 45 | label: 'Français 🇫🇷', 46 | }, 47 | { 48 | key: 'ar', 49 | label: 'العربية 🇸🇦', 50 | }, 51 | 52 | ...(IS_IOS 53 | ? [ 54 | { 55 | key: 'th', 56 | label: 'ไทย 🇹🇭', 57 | }, 58 | { 59 | key: 'id', 60 | label: 'Bahasa Indonesia 🇮🇩', 61 | }, 62 | ] 63 | : []), 64 | ] 65 | -------------------------------------------------------------------------------- /example/src/components/BottomSheet.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { View } from 'react-native' 3 | 4 | export function BottomSheet() { 5 | return ( 6 | 7 | 8 | 9 | ) 10 | } 11 | -------------------------------------------------------------------------------- /example/src/components/Button.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { 3 | StyleSheet, 4 | TouchableOpacity, 5 | TouchableOpacityProps, 6 | } from 'react-native' 7 | import useTheme from '../hook/useTheme' 8 | import { Text } from './Text' 9 | 10 | interface Props extends TouchableOpacityProps { 11 | children: React.ReactNode | string 12 | type?: 'full' | 'outline' 13 | } 14 | 15 | export function Button({ 16 | children, 17 | style: containerStyle, 18 | onPress, 19 | type = 'full', 20 | }: Props) { 21 | const { foreground, background } = useTheme() 22 | const isFull = type === 'full' 23 | 24 | return ( 25 | 37 | {typeof children === 'string' ? ( 38 | 39 | {children} 40 | 41 | ) : ( 42 | children 43 | )} 44 | 45 | ) 46 | } 47 | 48 | const style = StyleSheet.create({ 49 | button: { 50 | padding: 12, 51 | alignItems: 'center', 52 | borderWidth: 1.5, 53 | }, 54 | text: { 55 | fontFamily: 'Avenir', 56 | fontWeight: 'bold', 57 | }, 58 | }) 59 | -------------------------------------------------------------------------------- /example/src/components/CheckBox.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { 3 | Image, 4 | StyleSheet, 5 | TouchableOpacity, 6 | TouchableOpacityProps, 7 | } from 'react-native' 8 | import images from '../assets' 9 | import useTheme from '../hook/useTheme' 10 | 11 | interface CheckBoxProps extends TouchableOpacityProps { 12 | checked?: boolean 13 | onChecked?: (checked: boolean) => void 14 | } 15 | 16 | export function CheckBox({ 17 | checked = false, 18 | onChecked, 19 | ...props 20 | }: CheckBoxProps) { 21 | const { foreground, background_2 } = useTheme() 22 | 23 | return ( 24 | onChecked?.(!checked)} 27 | {...props} 28 | style={[ 29 | style.container, 30 | props.style, 31 | { 32 | backgroundColor: checked ? foreground : background_2, 33 | borderColor: foreground + '64', 34 | }, 35 | ]} 36 | > 37 | {checked && ( 38 | 42 | )} 43 | 44 | ) 45 | } 46 | 47 | const style = StyleSheet.create({ 48 | container: { 49 | width: 24, 50 | height: 24, 51 | alignItems: 'center', 52 | justifyContent: 'center', 53 | borderRadius: 4, 54 | }, 55 | check: { 56 | width: 16, 57 | height: 16, 58 | }, 59 | }) 60 | -------------------------------------------------------------------------------- /example/src/components/CodeTag.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { View } from './View' 3 | import { StyleSheet, TextProps, ViewProps } from 'react-native' 4 | import { Text } from './Text' 5 | 6 | interface CodeTagProps extends ViewProps { 7 | children: string 8 | textProps?: TextProps 9 | } 10 | 11 | export function CodeTag({ children, textProps, ...props }: CodeTagProps) { 12 | return ( 13 | 14 | 15 | {children} 16 | 17 | 18 | ) 19 | } 20 | 21 | const style = StyleSheet.create({ 22 | text: { 23 | // fontFamily: 'monospace', 24 | fontWeight: 600, 25 | fontSize: 16, 26 | }, 27 | container: { 28 | padding: 8, 29 | paddingVertical: 6, 30 | borderRadius: 4, 31 | alignSelf: 'baseline', 32 | }, 33 | }) 34 | -------------------------------------------------------------------------------- /example/src/components/Container.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { StyleSheet, ViewProps } from 'react-native' 3 | import useTheme from '../hook/useTheme' 4 | import { View } from './View' 5 | 6 | interface Props extends ViewProps { 7 | level?: 0 | 1 | 2 | 3 8 | } 9 | 10 | export function Container({ 11 | children, 12 | style: containerStyle, 13 | level = 0, 14 | }: Props) { 15 | const theme = useTheme() 16 | const backgroundColor = !level 17 | ? theme.background 18 | : theme[`background_${level}` as keyof typeof theme] 19 | 20 | return ( 21 | 22 | {children} 23 | 24 | ) 25 | } 26 | 27 | const style = StyleSheet.create({ 28 | container: { 29 | flex: 1, 30 | }, 31 | }) 32 | -------------------------------------------------------------------------------- /example/src/components/CounterView.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { View } from './View' 3 | import { Row, RowProps } from './Row' 4 | import { StyleSheet, TouchableOpacity } from 'react-native' 5 | import { Text } from './Text' 6 | import useTheme from '../hook/useTheme' 7 | 8 | interface CounterViewProps extends RowProps { 9 | value?: number 10 | onChange: (value: number) => void 11 | range?: { 12 | min?: number 13 | max?: number 14 | } 15 | } 16 | 17 | export function CounterView({ 18 | value = 0, 19 | onChange, 20 | range, 21 | ...props 22 | }: CounterViewProps) { 23 | const { background_2 } = useTheme() 24 | 25 | return ( 26 | 27 | { 31 | const min = range?.min ?? 0 32 | onChange(value - 1 < min ? min : value - 1) 33 | }} 34 | > 35 | 36 | 37 | 38 | {value} 39 | 40 | { 44 | const max = range?.max 45 | if (max) onChange(value + 1 > max ? max : value + 1) 46 | else onChange(value + 1) 47 | }} 48 | > 49 | + 50 | 51 | 52 | ) 53 | } 54 | 55 | const style = StyleSheet.create({ 56 | counterView: { 57 | // 58 | height: 32, 59 | paddingHorizontal: 12, 60 | borderRadius: 4, 61 | alignItems: 'center', 62 | justifyContent: 'center', 63 | }, 64 | button: { 65 | borderRadius: 4, 66 | height: 32, 67 | width: 32, 68 | alignItems: 'center', 69 | justifyContent: 'center', 70 | }, 71 | buttonText: { 72 | fontSize: 16, 73 | fontWeight: 'bold', 74 | fontFamily: 'Avenir', 75 | }, 76 | }) 77 | -------------------------------------------------------------------------------- /example/src/components/Divider.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { StyleSheet } from 'react-native' 3 | import useTheme from '../hook/useTheme' 4 | import { View } from './View' 5 | 6 | export default function Divider() { 7 | const { foreground } = useTheme() 8 | return 9 | } 10 | 11 | const style = StyleSheet.create({ 12 | container: { 13 | height: 1, 14 | width: '100%', 15 | opacity: 0.2, 16 | }, 17 | }) 18 | -------------------------------------------------------------------------------- /example/src/components/Input.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { StyleSheet, TextInput, TextInputProps } from 'react-native' 3 | import useTheme from '../hook/useTheme' 4 | 5 | interface InputProps extends TextInputProps {} 6 | 7 | export function Input({ ...props }: InputProps) { 8 | const { background_2, foreground } = useTheme() 9 | 10 | return ( 11 | 20 | ) 21 | } 22 | 23 | const style = StyleSheet.create({ 24 | input: { 25 | paddingHorizontal: 12, 26 | paddingVertical: 12, 27 | borderRadius: 8, 28 | fontSize: 16, 29 | }, 30 | }) 31 | -------------------------------------------------------------------------------- /example/src/components/Row.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { StyleSheet, ViewStyle } from 'react-native' 3 | import { View, ViewProps } from './View' 4 | 5 | export interface RowProps extends ViewProps { 6 | alignItems?: ViewStyle['alignItems'] 7 | gap?: number 8 | } 9 | 10 | export function Row({ 11 | children, 12 | gap, 13 | alignItems = 'center', 14 | ...props 15 | }: RowProps) { 16 | return ( 17 | 21 | {children} 22 | 23 | ) 24 | } 25 | 26 | const style = StyleSheet.create({ 27 | container: { 28 | flexDirection: 'row', 29 | }, 30 | }) 31 | -------------------------------------------------------------------------------- /example/src/components/SectionView.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Row } from './Row' 3 | import { CodeTag } from './CodeTag' 4 | import { View } from './View' 5 | import { Text } from './Text' 6 | import { StyleSheet, Switch } from 'react-native' 7 | import { useAppContext } from '../hook/context' 8 | import { Config } from '@baronha/react-native-multiple-image-picker' 9 | import { SegmentControl } from './SegmentControl' 10 | 11 | type key = keyof Config 12 | interface SectionViewProps { 13 | title: key 14 | description: string 15 | optionKey?: key 16 | children?: React.ReactNode 17 | defaultValue?: boolean 18 | segmentControl?: string[] 19 | } 20 | 21 | export default function SectionView({ 22 | title, 23 | description, 24 | optionKey, 25 | children, 26 | defaultValue = false, 27 | segmentControl, 28 | }: SectionViewProps) { 29 | const { options, setOptions } = useAppContext() 30 | 31 | return ( 32 | 33 | 34 | 35 | {title} 36 | {description} 37 | 38 | {children || 39 | (optionKey ? ( 40 | !segmentControl ? ( 41 | 44 | setOptions(optionKey, valueChange) 45 | } 46 | /> 47 | ) : null 48 | ) : null)} 49 | 50 | 51 | {segmentControl && optionKey ? ( 52 | setOptions(optionKey, valueChange)} 60 | /> 61 | ) : null} 62 | 63 | ) 64 | } 65 | 66 | const style = StyleSheet.create({ 67 | section: { 68 | rowGap: 12, 69 | columnGap: 24, 70 | }, 71 | sectionTitle: { 72 | gap: 8, 73 | }, 74 | 75 | des: { 76 | fontSize: 12, 77 | // marginBottom: 12, 78 | }, 79 | }) 80 | -------------------------------------------------------------------------------- /example/src/components/SegmentControl.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import SegmentedControl, { 3 | SegmentedControlProps, 4 | } from '@react-native-segmented-control/segmented-control' 5 | 6 | export function SegmentControl({ ...props }: SegmentedControlProps) { 7 | return 8 | } 9 | -------------------------------------------------------------------------------- /example/src/components/Text.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Text as RNText, TextProps } from 'react-native' 3 | import useTheme from '../hook/useTheme' 4 | 5 | export function Text({ children, style: containerStyle }: TextProps) { 6 | const { foreground } = useTheme() 7 | 8 | return ( 9 | {children} 10 | ) 11 | } 12 | -------------------------------------------------------------------------------- /example/src/components/View.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { View as RNView, ViewProps as RNViewProps } from 'react-native' 3 | import useTheme from '../hook/useTheme' 4 | 5 | export interface ViewProps extends RNViewProps { 6 | level?: 0 | 1 | 2 | 3 7 | flex?: number 8 | } 9 | 10 | export function View({ 11 | children, 12 | style: containerStyle, 13 | level = 0, 14 | flex, 15 | }: ViewProps) { 16 | const theme = useTheme() 17 | const backgroundColor = !level 18 | ? theme.background 19 | : theme[`background_${level}` as keyof typeof theme] 20 | 21 | return ( 22 | 23 | {children} 24 | 25 | ) 26 | } 27 | -------------------------------------------------------------------------------- /example/src/components/index.tsx: -------------------------------------------------------------------------------- 1 | export * from './Container' 2 | export * from './Button' 3 | export * from './SegmentControl' 4 | export * from './Text' 5 | export * from './View' 6 | export * from './CodeTag' 7 | export * from './Row' 8 | export * from './Divider' 9 | export * from './CheckBox' 10 | export * from './SectionView' 11 | export * from './Input' 12 | export * from './CounterView' 13 | -------------------------------------------------------------------------------- /example/src/hook/context.ts: -------------------------------------------------------------------------------- 1 | import { createContext, useContext } from 'react' 2 | import { 3 | Config, 4 | defaultOptions, 5 | } from '@baronha/react-native-multiple-image-picker' 6 | 7 | export const AppContext = createContext<{ 8 | options: Config 9 | setOptions: (key: keyof Config, value: Config[keyof Config]) => void 10 | }>({ 11 | options: defaultOptions, 12 | setOptions: () => {}, 13 | }) 14 | 15 | export const useAppContext = () => useContext(AppContext) 16 | -------------------------------------------------------------------------------- /example/src/hook/index.ts: -------------------------------------------------------------------------------- 1 | export * from './useTheme' 2 | -------------------------------------------------------------------------------- /example/src/hook/useTheme.ts: -------------------------------------------------------------------------------- 1 | import { useColorScheme } from 'react-native' 2 | import * as color from '../theme/color' 3 | 4 | export default function useTheme() { 5 | const colorScheme = useColorScheme() as keyof typeof color 6 | 7 | return color[colorScheme] 8 | } 9 | -------------------------------------------------------------------------------- /example/src/theme/color.ts: -------------------------------------------------------------------------------- 1 | export const light = { 2 | background: '#ffffff', 3 | foreground: '#000000', 4 | primary: '#000000', 5 | 6 | // background level 7 | background_1: '#f0f0f0', 8 | background_2: '#f3f3f3', 9 | background_3: '#f5f5f5', 10 | } 11 | 12 | export const dark = { 13 | background: '#000000', 14 | foreground: '#ffffff', 15 | primary: '#ffffff', 16 | 17 | // background level 18 | background_1: '#101010', 19 | background_2: '#202020', 20 | background_3: '#303030', 21 | } 22 | 23 | export const colors = { 24 | ...light, 25 | divider: '#D4D4D499', 26 | } 27 | -------------------------------------------------------------------------------- /example/src/theme/size.ts: -------------------------------------------------------------------------------- 1 | import { Dimensions } from 'react-native' 2 | 3 | export const { width: WIDTH, height: HEIGHT } = Dimensions.get('window') 4 | export const HALF_HEIGHT = HEIGHT / 2 5 | export const HALF_WIDTH = WIDTH / 2 6 | -------------------------------------------------------------------------------- /example/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "outDir": "./lib" 4 | }, 5 | "extends": "../tsconfig" 6 | } 7 | -------------------------------------------------------------------------------- /files/banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NitrogenZLab/react-native-multiple-image-picker/6c531f3f60d7a2ed238386c38f2ee85f55d970f9/files/banner.png -------------------------------------------------------------------------------- /files/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NitrogenZLab/react-native-multiple-image-picker/6c531f3f60d7a2ed238386c38f2ee85f55d970f9/files/logo.png -------------------------------------------------------------------------------- /ios/Assets.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Assets.swift 3 | // Pods 4 | // 5 | // Created by BAO HA on 4/12/24. 6 | // 7 | 8 | import UIKit 9 | 10 | class Assets { 11 | class func bundle() -> Bundle { 12 | let podBundle = Bundle(for: Assets.self) 13 | if let url = podBundle.url(forResource: "MultipleImagePicker", withExtension: "bundle") { 14 | let bundle = Bundle(url: url) 15 | return bundle ?? podBundle 16 | } 17 | return podBundle 18 | } 19 | } 20 | 21 | extension UIImage { 22 | static var close = UIImage(name: "close") 23 | 24 | convenience init(name: String) { 25 | self.init(named: name, in: Assets.bundle(), compatibleWith: nil)! 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /ios/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /ios/Assets.xcassets/close.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "close.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /ios/Assets.xcassets/close.imageset/close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NitrogenZLab/react-native-multiple-image-picker/6c531f3f60d7a2ed238386c38f2ee85f55d970f9/ios/Assets.xcassets/close.imageset/close.png -------------------------------------------------------------------------------- /ios/ErrorCode.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ErrorCode.swift 3 | // Pods 4 | // 5 | // Created by BAO HA on 3/12/24. 6 | // 7 | 8 | // enum ErrorCode: Int, Error { 9 | // 10 | // } 11 | -------------------------------------------------------------------------------- /ios/HybridMultipleImagePicker+Preview.swift: -------------------------------------------------------------------------------- 1 | // 2 | // HybridMultipleImagePicker+Preview.swift 3 | // Pods 4 | // 5 | // Created by BAO HA on 11/12/24. 6 | // 7 | 8 | import HXPhotoPicker 9 | 10 | extension HybridMultipleImagePicker { 11 | func openPreview(media: [MediaPreview], index: Double, config: NitroPreviewConfig, onLongPress: @escaping ((Double) -> Void)) throws { 12 | var previewConfig = HXPhotoPicker.PhotoBrowser.Configuration() 13 | previewConfig.showDelete = false 14 | 15 | var assets: [PhotoAsset] = [] 16 | 17 | previewConfig.tintColor = .white 18 | previewConfig.videoPlayType = config.videoAutoPlay == true ? .auto : .normal 19 | previewConfig.livePhotoPlayType = .auto 20 | 21 | previewConfig.languageType = setLocale(language: config.language) 22 | 23 | media.forEach { mediaItem in 24 | 25 | var asset: PhotoAsset? 26 | 27 | if let localIdentifier = mediaItem.localIdentifier { 28 | asset = .init(localIdentifier: localIdentifier) 29 | 30 | // auto play gif 31 | if let filePath = mediaItem.path, 32 | let url = URL(string: filePath), isGifFile(url) == true 33 | { 34 | asset = .init(.init(imageURL: url)) 35 | } 36 | 37 | } else if let path = mediaItem.path, let url = URL(string: path) { 38 | let thumbnail = URL(string: mediaItem.thumbnail ?? "") ?? url 39 | 40 | if mediaItem.type == .image { 41 | // network asset 42 | if path.hasPrefix("https://") || path.hasPrefix("http://") { 43 | asset = PhotoAsset(NetworkImageAsset( 44 | thumbnailURL: thumbnail, 45 | originalURL: url, 46 | thumbnailLoadMode: .alwaysThumbnail, 47 | originalLoadMode: .alwaysThumbnail 48 | )) 49 | 50 | } else { 51 | asset = .init(.init(imageURL: url)) 52 | } 53 | } else { 54 | asset = .init(networkVideoAsset: .init(videoURL: url, coverImageURL: thumbnail)) 55 | } 56 | } 57 | 58 | if let asset { 59 | assets.append(asset) 60 | } 61 | } 62 | 63 | if Int(index) > assets.count - 1 { return } 64 | 65 | DispatchQueue.main.async { 66 | HXPhotoPicker.PhotoBrowser.show( 67 | assets, 68 | pageIndex: Int(index), 69 | config: previewConfig, 70 | longPressHandler: { index, _, _ in 71 | onLongPress(Double(index)) 72 | } 73 | ) 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /ios/HybridMultipleImagePicker+Result.swift: -------------------------------------------------------------------------------- 1 | // 2 | // HybridMultipleImagePicker+Result.swift 3 | // Pods 4 | // 5 | // Created by BAO HA on 24/10/24. 6 | // 7 | 8 | import HXPhotoPicker 9 | // import Photos 10 | 11 | extension HybridMultipleImagePicker { 12 | func getResult(_ asset: PhotoAsset) async throws -> PickerResult { 13 | let urlResult = try await asset.urlResult() 14 | let url = urlResult.url 15 | 16 | let creationDate = Int(asset.phAsset?.creationDate?.timeIntervalSince1970 ?? 0) 17 | 18 | let mime = url.getMimeType() 19 | 20 | let phAsset = asset.phAsset 21 | 22 | let type: ResultType = .init(fromString: asset.mediaType == .video ? "video" : "image")! 23 | let thumbnail = asset.phAsset?.getVideoAssetThumbnail(from: url.absoluteString, in: 1) 24 | 25 | return PickerResult(localIdentifier: phAsset!.localIdentifier, 26 | width: asset.imageSize.width, 27 | height: asset.imageSize.height, 28 | mime: mime, 29 | size: Double(asset.fileSize), 30 | bucketId: nil, 31 | realPath: nil, 32 | parentFolderName: nil, 33 | creationDate: creationDate > 0 ? Double(creationDate) : nil, 34 | crop: false, 35 | path: "file://\(url.absoluteString)", 36 | type: type, 37 | duration: asset.videoDuration, 38 | thumbnail: thumbnail, 39 | fileName: phAsset?.fileName) 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /ios/MultipleImagePickerOnLoad.mm: -------------------------------------------------------------------------------- 1 | // 2 | // MultipleImagePickerOnLoad.mm 3 | // MultipleImagePicker 4 | // 5 | // Created by Marc Rousavy on 22.07.24. 6 | // 7 | 8 | #import 9 | #import 10 | #import "React/RCTBridgeModule.h" 11 | 12 | @interface MultipleImagePickerOnLoad : NSObject 13 | @end 14 | 15 | @implementation MultipleImagePickerOnLoad 16 | 17 | using namespace margelo::nitro; 18 | 19 | + (void)load { 20 | // TODO: Register all Swift Hybrid Objects here 21 | // TODO: Register all C++ Hybrid Objects here 22 | } 23 | 24 | @end 25 | -------------------------------------------------------------------------------- /ios/PHAsset+Thumbnail.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PHAsset+Thumbnail.swift 3 | // Pods 4 | // 5 | // Created by BAO HA on 24/10/24. 6 | // 7 | 8 | import Photos 9 | 10 | extension PHAsset { 11 | func getVideoAssetThumbnail(from moviePath: String, in seconds: Double) -> String? { 12 | if mediaType == .video { 13 | if let path = getVideoThumbnail(from: moviePath, in: seconds) { 14 | return "file://\(path)" 15 | } 16 | } 17 | 18 | return nil 19 | } 20 | 21 | var fileName: String { 22 | if let resources = PHAssetResource.assetResources(for: self).first { 23 | return resources.originalFilename 24 | } 25 | 26 | return "" 27 | } 28 | } 29 | 30 | func getVideoThumbnail(from moviePath: String, in seconds: Double) -> String? { 31 | let filepath = moviePath.replacingOccurrences(of: "file://", with: "") 32 | let vidURL = URL(fileURLWithPath: filepath) 33 | 34 | let asset = AVURLAsset(url: vidURL, options: nil) 35 | let generator = AVAssetImageGenerator(asset: asset) 36 | generator.appliesPreferredTrackTransform = true 37 | 38 | let time = CMTime(seconds: seconds, preferredTimescale: 600) 39 | 40 | var thumbnail: UIImage? 41 | 42 | do { 43 | let imgRef = try generator.copyCGImage(at: time, actualTime: nil) 44 | thumbnail = UIImage(cgImage: imgRef) 45 | } catch { 46 | print("Error create thumbnail: \(error)") 47 | return nil 48 | } 49 | 50 | if let thumbnail { 51 | return thumbnail.getPath(fileName: nil, quality: 0.8) 52 | } 53 | 54 | return nil 55 | } 56 | -------------------------------------------------------------------------------- /ios/PhotoCancelItem.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PhotoCancelItem.swift 3 | // Pods 4 | // 5 | // Created by BAO HA on 4/12/24. 6 | // 7 | 8 | import HXPhotoPicker 9 | import UIKit 10 | 11 | extension UIView: HXPickerCompatible { 12 | var size: CGSize { 13 | get { frame.size } 14 | set { 15 | var rect = frame 16 | rect.size = newValue 17 | frame = rect 18 | } 19 | } 20 | } 21 | 22 | public class PhotoCancelItem: UIView, PhotoNavigationItem { 23 | public weak var itemDelegate: PhotoNavigationItemDelegate? 24 | public var itemType: PhotoNavigationItemType { .cancel } 25 | 26 | let config: PickerConfiguration 27 | public required init(config: PickerConfiguration) { 28 | self.config = config 29 | super.init(frame: .zero) 30 | initView() 31 | } 32 | 33 | var button: UIButton! 34 | func initView() { 35 | button = UIButton(type: .custom) 36 | 37 | button.setImage(UIImage.close, for: .normal) 38 | 39 | button.addTarget(self, action: #selector(didCancelClick), for: .touchUpInside) 40 | 41 | addSubview(button) 42 | 43 | if let btnSize = button.currentImage?.size { 44 | button.size = btnSize 45 | size = btnSize 46 | } 47 | } 48 | 49 | @objc 50 | func didCancelClick() { 51 | print("close ne") 52 | itemDelegate?.photoControllerDidCancel() 53 | } 54 | 55 | @available(*, unavailable) 56 | required init?(coder: NSCoder) { 57 | fatalError("init(coder:) has not been implemented") 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /ios/TopViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TopViewController.swift 3 | // Pods 4 | // 5 | // Created by BAO HA on 11/12/24. 6 | // 7 | 8 | import UIKit 9 | 10 | func getTopViewController() -> UIViewController? { 11 | var controller = UIApplication.shared.keyWindow?.rootViewController 12 | while let presentedViewController = controller?.presentedViewController { 13 | controller = presentedViewController 14 | } 15 | 16 | return controller 17 | } 18 | -------------------------------------------------------------------------------- /ios/UIColor+Hex.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIColor+Hex.swift 3 | // react-native-multiple-image-picker 4 | // 5 | // Created by BAO HA on 15/10/2024. 6 | // 7 | 8 | import UIKit 9 | 10 | extension UIColor { 11 | convenience init(hex: String, alpha: CGFloat = 1.0) { 12 | var cString: String = hex.trimmingCharacters(in: .whitespacesAndNewlines).uppercased() 13 | var rgbValue: UInt32 = 10066329 // color #999999 if string has wrong format 14 | 15 | if cString.hasPrefix("#") { 16 | cString.remove(at: cString.startIndex) 17 | } 18 | 19 | if (cString.count) == 6 { 20 | Scanner(string: cString).scanHexInt32(&rgbValue) 21 | } 22 | 23 | self.init( 24 | red: CGFloat((rgbValue & 0xFF0000) >> 16) / 255.0, 25 | green: CGFloat((rgbValue & 0x00FF00) >> 8) / 255.0, 26 | blue: CGFloat(rgbValue & 0x0000FF) / 255.0, 27 | alpha: alpha 28 | ) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /ios/UIColor+React.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIColor+React.swift 3 | // Pods 4 | // 5 | // Created by BAO HA on 16/10/24. 6 | // 7 | 8 | import React 9 | import UIKit 10 | 11 | func getReactColor(_ color: Int?) -> UIColor? { 12 | RCTConvert.uiColor(color) 13 | } 14 | -------------------------------------------------------------------------------- /ios/UIImage.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIImage.swift 3 | // Pods 4 | // 5 | // Created by BAO HA on 16/12/24. 6 | // 7 | 8 | extension UIImage { 9 | func getPath(fileName name: String? = nil, quality: CGFloat = 1.0) -> String? { 10 | let tempDirectoryURL = FileManager.default.temporaryDirectory 11 | 12 | let data = self.jpegData(compressionQuality: 0.9) 13 | 14 | let fileName = name ?? "IMG_\(Int(Date().timeIntervalSince1970)).jpg" 15 | 16 | let fileURL = tempDirectoryURL.appendingPathComponent(fileName) 17 | 18 | if let imageData = self.jpegData(compressionQuality: quality) { 19 | do { 20 | try imageData.write(to: fileURL) 21 | return fileURL.absoluteString 22 | 23 | } catch { 24 | return nil 25 | } 26 | } 27 | 28 | return nil 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /ios/URL+Mime.swift: -------------------------------------------------------------------------------- 1 | // 2 | // URL+Mime.swift 3 | // Pods 4 | // 5 | // Created by BAO HA on 23/10/24. 6 | // 7 | 8 | import Foundation 9 | import MobileCoreServices 10 | import UniformTypeIdentifiers 11 | 12 | extension URL { 13 | func getMimeType() -> String { 14 | let pathExtension = self.pathExtension.lowercased() 15 | 16 | if #available(iOS 14.0, *) { 17 | // Sử dụng UniformTypeIdentifiers (UTType) cho iOS 14+ 18 | if let utType = UTType(filenameExtension: pathExtension) { 19 | return utType.preferredMIMEType ?? "application/octet-stream" 20 | } 21 | 22 | } else { 23 | // Sử dụng MobileCoreServices (kUTType) cho iOS 13 trở xuống 24 | if let uti = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, pathExtension as CFString, nil)?.takeRetainedValue(), 25 | let mimeType = UTTypeCopyPreferredTagWithClass(uti, kUTTagClassMIMEType)?.takeRetainedValue() 26 | { 27 | return mimeType as String 28 | } 29 | } 30 | 31 | // Trả về MIME type mặc định nếu không tìm thấy 32 | return "application/octet-stream" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /ios/Utils.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Utils.swift 3 | // Pods 4 | // 5 | // Created by BAO HA on 11/12/24. 6 | // 7 | 8 | import MobileCoreServices 9 | import UniformTypeIdentifiers 10 | 11 | func isImage(_ urlString: String) -> Bool { 12 | guard let url = URL(string: urlString), 13 | let pathExtension = url.pathExtension as CFString?, 14 | let uti = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, pathExtension, nil)? 15 | .takeRetainedValue() 16 | else { 17 | return false 18 | } 19 | 20 | return UTTypeConformsTo(uti, kUTTypeImage) 21 | } 22 | 23 | func isGifFile(_ url: URL) -> Bool { 24 | // Kiểm tra phần mở rộng 25 | if url.pathExtension.lowercased() == "gif" { 26 | return true 27 | } 28 | 29 | // Kiểm tra UTI 30 | let fileExtension = url.pathExtension as CFString 31 | guard let uti = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, fileExtension, nil)?.takeRetainedValue() else { 32 | return false 33 | } 34 | 35 | return UTTypeConformsTo(uti, kUTTypeGIF) 36 | } 37 | -------------------------------------------------------------------------------- /nitro.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://nitro.margelo.com/nitro.schema.json", 3 | "cxxNamespace": ["multipleimagepicker"], 4 | "ios": { 5 | "iosModuleName": "MultipleImagePicker" 6 | }, 7 | "android": { 8 | "androidNamespace": ["multipleimagepicker"], 9 | "androidCxxLibName": "MultipleImagePicker" 10 | }, 11 | 12 | "autolinking": { 13 | "MultipleImagePicker": { 14 | "swift": "HybridMultipleImagePicker", 15 | "kotlin": "MultipleImagePicker" 16 | } 17 | }, 18 | "ignorePaths": ["node_modules"] 19 | } 20 | -------------------------------------------------------------------------------- /nitrogen/generated/.gitattributes: -------------------------------------------------------------------------------- 1 | * linguist-generated 2 | -------------------------------------------------------------------------------- /nitrogen/generated/android/MultipleImagePicker+autolinking.gradle: -------------------------------------------------------------------------------- 1 | /// 2 | /// MultipleImagePicker+autolinking.gradle 3 | /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. 4 | /// https://github.com/mrousavy/nitro 5 | /// Copyright © 2025 Marc Rousavy @ Margelo 6 | /// 7 | 8 | /// This is a Gradle file that adds all files generated by Nitrogen 9 | /// to the current Gradle project. 10 | /// 11 | /// To use it, add this to your build.gradle: 12 | /// ```gradle 13 | /// apply from: '../nitrogen/generated/android/MultipleImagePicker+autolinking.gradle' 14 | /// ``` 15 | 16 | logger.warn("[NitroModules] 🔥 MultipleImagePicker is boosted by nitro!") 17 | 18 | android { 19 | sourceSets { 20 | main { 21 | java.srcDirs += [ 22 | // Nitrogen files 23 | "${project.projectDir}/../nitrogen/generated/android/kotlin" 24 | ] 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /nitrogen/generated/android/MultipleImagePickerOnLoad.cpp: -------------------------------------------------------------------------------- 1 | /// 2 | /// MultipleImagePickerOnLoad.cpp 3 | /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. 4 | /// https://github.com/mrousavy/nitro 5 | /// Copyright © 2025 Marc Rousavy @ Margelo 6 | /// 7 | 8 | #ifndef BUILDING_MULTIPLEIMAGEPICKER_WITH_GENERATED_CMAKE_PROJECT 9 | #error MultipleImagePickerOnLoad.cpp is not being built with the autogenerated CMakeLists.txt project. Is a different CMakeLists.txt building this? 10 | #endif 11 | 12 | #include "MultipleImagePickerOnLoad.hpp" 13 | 14 | #include 15 | #include 16 | #include 17 | 18 | #include "JHybridMultipleImagePickerSpec.hpp" 19 | #include "JFunc_void_std__vector_PickerResult_.hpp" 20 | #include "JFunc_void_double.hpp" 21 | #include "JFunc_void_CropResult.hpp" 22 | #include "JFunc_void_CameraResult.hpp" 23 | #include 24 | #include 25 | 26 | namespace margelo::nitro::multipleimagepicker { 27 | 28 | int initialize(JavaVM* vm) { 29 | using namespace margelo::nitro; 30 | using namespace margelo::nitro::multipleimagepicker; 31 | using namespace facebook; 32 | 33 | return facebook::jni::initialize(vm, [] { 34 | // Register native JNI methods 35 | margelo::nitro::multipleimagepicker::JHybridMultipleImagePickerSpec::registerNatives(); 36 | margelo::nitro::multipleimagepicker::JFunc_void_std__vector_PickerResult__cxx::registerNatives(); 37 | margelo::nitro::multipleimagepicker::JFunc_void_double_cxx::registerNatives(); 38 | margelo::nitro::multipleimagepicker::JFunc_void_CropResult_cxx::registerNatives(); 39 | margelo::nitro::multipleimagepicker::JFunc_void_CameraResult_cxx::registerNatives(); 40 | 41 | // Register Nitro Hybrid Objects 42 | HybridObjectRegistry::registerHybridObjectConstructor( 43 | "MultipleImagePicker", 44 | []() -> std::shared_ptr { 45 | static DefaultConstructableObject object("com/margelo/nitro/multipleimagepicker/MultipleImagePicker"); 46 | auto instance = object.create(); 47 | auto globalRef = jni::make_global(instance); 48 | return JNISharedPtr::make_shared_from_jni(globalRef); 49 | } 50 | ); 51 | }); 52 | } 53 | 54 | } // namespace margelo::nitro::multipleimagepicker 55 | -------------------------------------------------------------------------------- /nitrogen/generated/android/MultipleImagePickerOnLoad.hpp: -------------------------------------------------------------------------------- 1 | /// 2 | /// MultipleImagePickerOnLoad.hpp 3 | /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. 4 | /// https://github.com/mrousavy/nitro 5 | /// Copyright © 2025 Marc Rousavy @ Margelo 6 | /// 7 | 8 | #include 9 | #include 10 | 11 | namespace margelo::nitro::multipleimagepicker { 12 | 13 | /** 14 | * Initializes the native (C++) part of MultipleImagePicker, and autolinks all Hybrid Objects. 15 | * Call this in your `JNI_OnLoad` function (probably inside `cpp-adapter.cpp`). 16 | * Example: 17 | * ```cpp (cpp-adapter.cpp) 18 | * JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void*) { 19 | * return margelo::nitro::multipleimagepicker::initialize(vm); 20 | * } 21 | * ``` 22 | */ 23 | int initialize(JavaVM* vm); 24 | 25 | } // namespace margelo::nitro::multipleimagepicker 26 | -------------------------------------------------------------------------------- /nitrogen/generated/android/c++/JCameraDevice.hpp: -------------------------------------------------------------------------------- 1 | /// 2 | /// JCameraDevice.hpp 3 | /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. 4 | /// https://github.com/mrousavy/nitro 5 | /// Copyright © 2025 Marc Rousavy @ Margelo 6 | /// 7 | 8 | #pragma once 9 | 10 | #include 11 | #include "CameraDevice.hpp" 12 | 13 | namespace margelo::nitro::multipleimagepicker { 14 | 15 | using namespace facebook; 16 | 17 | /** 18 | * The C++ JNI bridge between the C++ enum "CameraDevice" and the the Kotlin enum "CameraDevice". 19 | */ 20 | struct JCameraDevice final: public jni::JavaClass { 21 | public: 22 | static auto constexpr kJavaDescriptor = "Lcom/margelo/nitro/multipleimagepicker/CameraDevice;"; 23 | 24 | public: 25 | /** 26 | * Convert this Java/Kotlin-based enum to the C++ enum CameraDevice. 27 | */ 28 | [[maybe_unused]] 29 | [[nodiscard]] 30 | CameraDevice toCpp() const { 31 | static const auto clazz = javaClassStatic(); 32 | static const auto fieldOrdinal = clazz->getField("_ordinal"); 33 | int ordinal = this->getFieldValue(fieldOrdinal); 34 | return static_cast(ordinal); 35 | } 36 | 37 | public: 38 | /** 39 | * Create a Java/Kotlin-based enum with the given C++ enum's value. 40 | */ 41 | [[maybe_unused]] 42 | static jni::alias_ref fromCpp(CameraDevice value) { 43 | static const auto clazz = javaClassStatic(); 44 | static const auto fieldFRONT = clazz->getStaticField("FRONT"); 45 | static const auto fieldBACK = clazz->getStaticField("BACK"); 46 | 47 | switch (value) { 48 | case CameraDevice::FRONT: 49 | return clazz->getStaticFieldValue(fieldFRONT); 50 | case CameraDevice::BACK: 51 | return clazz->getStaticFieldValue(fieldBACK); 52 | default: 53 | std::string stringValue = std::to_string(static_cast(value)); 54 | throw std::invalid_argument("Invalid enum value (" + stringValue + "!"); 55 | } 56 | } 57 | }; 58 | 59 | } // namespace margelo::nitro::multipleimagepicker 60 | -------------------------------------------------------------------------------- /nitrogen/generated/android/c++/JCropRatio.hpp: -------------------------------------------------------------------------------- 1 | /// 2 | /// JCropRatio.hpp 3 | /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. 4 | /// https://github.com/mrousavy/nitro 5 | /// Copyright © 2025 Marc Rousavy @ Margelo 6 | /// 7 | 8 | #pragma once 9 | 10 | #include 11 | #include "CropRatio.hpp" 12 | 13 | #include 14 | #include 15 | 16 | namespace margelo::nitro::multipleimagepicker { 17 | 18 | using namespace facebook; 19 | 20 | /** 21 | * The C++ JNI bridge between the C++ struct "CropRatio" and the the Kotlin data class "CropRatio". 22 | */ 23 | struct JCropRatio final: public jni::JavaClass { 24 | public: 25 | static auto constexpr kJavaDescriptor = "Lcom/margelo/nitro/multipleimagepicker/CropRatio;"; 26 | 27 | public: 28 | /** 29 | * Convert this Java/Kotlin-based struct to the C++ struct CropRatio by copying all values to C++. 30 | */ 31 | [[maybe_unused]] 32 | [[nodiscard]] 33 | CropRatio toCpp() const { 34 | static const auto clazz = javaClassStatic(); 35 | static const auto fieldTitle = clazz->getField("title"); 36 | jni::local_ref title = this->getFieldValue(fieldTitle); 37 | static const auto fieldWidth = clazz->getField("width"); 38 | double width = this->getFieldValue(fieldWidth); 39 | static const auto fieldHeight = clazz->getField("height"); 40 | double height = this->getFieldValue(fieldHeight); 41 | return CropRatio( 42 | title != nullptr ? std::make_optional(title->toStdString()) : std::nullopt, 43 | width, 44 | height 45 | ); 46 | } 47 | 48 | public: 49 | /** 50 | * Create a Java/Kotlin-based struct by copying all values from the given C++ struct to Java. 51 | */ 52 | [[maybe_unused]] 53 | static jni::local_ref fromCpp(const CropRatio& value) { 54 | return newInstance( 55 | value.title.has_value() ? jni::make_jstring(value.title.value()) : nullptr, 56 | value.width, 57 | value.height 58 | ); 59 | } 60 | }; 61 | 62 | } // namespace margelo::nitro::multipleimagepicker 63 | -------------------------------------------------------------------------------- /nitrogen/generated/android/c++/JCropResult.hpp: -------------------------------------------------------------------------------- 1 | /// 2 | /// JCropResult.hpp 3 | /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. 4 | /// https://github.com/mrousavy/nitro 5 | /// Copyright © 2025 Marc Rousavy @ Margelo 6 | /// 7 | 8 | #pragma once 9 | 10 | #include 11 | #include "CropResult.hpp" 12 | 13 | #include 14 | 15 | namespace margelo::nitro::multipleimagepicker { 16 | 17 | using namespace facebook; 18 | 19 | /** 20 | * The C++ JNI bridge between the C++ struct "CropResult" and the the Kotlin data class "CropResult". 21 | */ 22 | struct JCropResult final: public jni::JavaClass { 23 | public: 24 | static auto constexpr kJavaDescriptor = "Lcom/margelo/nitro/multipleimagepicker/CropResult;"; 25 | 26 | public: 27 | /** 28 | * Convert this Java/Kotlin-based struct to the C++ struct CropResult by copying all values to C++. 29 | */ 30 | [[maybe_unused]] 31 | [[nodiscard]] 32 | CropResult toCpp() const { 33 | static const auto clazz = javaClassStatic(); 34 | static const auto fieldPath = clazz->getField("path"); 35 | jni::local_ref path = this->getFieldValue(fieldPath); 36 | static const auto fieldWidth = clazz->getField("width"); 37 | double width = this->getFieldValue(fieldWidth); 38 | static const auto fieldHeight = clazz->getField("height"); 39 | double height = this->getFieldValue(fieldHeight); 40 | return CropResult( 41 | path->toStdString(), 42 | width, 43 | height 44 | ); 45 | } 46 | 47 | public: 48 | /** 49 | * Create a Java/Kotlin-based struct by copying all values from the given C++ struct to Java. 50 | */ 51 | [[maybe_unused]] 52 | static jni::local_ref fromCpp(const CropResult& value) { 53 | return newInstance( 54 | jni::make_jstring(value.path), 55 | value.width, 56 | value.height 57 | ); 58 | } 59 | }; 60 | 61 | } // namespace margelo::nitro::multipleimagepicker 62 | -------------------------------------------------------------------------------- /nitrogen/generated/android/c++/JFunc_void_CameraResult.hpp: -------------------------------------------------------------------------------- 1 | /// 2 | /// JFunc_void_CameraResult.hpp 3 | /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. 4 | /// https://github.com/mrousavy/nitro 5 | /// Copyright © 2025 Marc Rousavy @ Margelo 6 | /// 7 | 8 | #pragma once 9 | 10 | #include 11 | #include 12 | 13 | #include 14 | #include "CameraResult.hpp" 15 | #include "JCameraResult.hpp" 16 | #include 17 | #include "ResultType.hpp" 18 | #include "JResultType.hpp" 19 | #include 20 | 21 | namespace margelo::nitro::multipleimagepicker { 22 | 23 | using namespace facebook; 24 | 25 | /** 26 | * Represents the Java/Kotlin callback `(result: CameraResult) -> Unit`. 27 | * This can be passed around between C++ and Java/Kotlin. 28 | */ 29 | struct JFunc_void_CameraResult: public jni::JavaClass { 30 | public: 31 | static auto constexpr kJavaDescriptor = "Lcom/margelo/nitro/multipleimagepicker/Func_void_CameraResult;"; 32 | 33 | public: 34 | /** 35 | * Invokes the function this `JFunc_void_CameraResult` instance holds through JNI. 36 | */ 37 | void invoke(const CameraResult& result) const { 38 | static const auto method = javaClassStatic()->getMethod /* result */)>("invoke"); 39 | method(self(), JCameraResult::fromCpp(result)); 40 | } 41 | }; 42 | 43 | /** 44 | * An implementation of Func_void_CameraResult that is backed by a C++ implementation (using `std::function<...>`) 45 | */ 46 | struct JFunc_void_CameraResult_cxx final: public jni::HybridClass { 47 | public: 48 | static jni::local_ref fromCpp(const std::function& func) { 49 | return JFunc_void_CameraResult_cxx::newObjectCxxArgs(func); 50 | } 51 | 52 | public: 53 | /** 54 | * Invokes the C++ `std::function<...>` this `JFunc_void_CameraResult_cxx` instance holds. 55 | */ 56 | void invoke_cxx(jni::alias_ref result) { 57 | _func(result->toCpp()); 58 | } 59 | 60 | public: 61 | [[nodiscard]] 62 | inline const std::function& getFunction() const { 63 | return _func; 64 | } 65 | 66 | public: 67 | static auto constexpr kJavaDescriptor = "Lcom/margelo/nitro/multipleimagepicker/Func_void_CameraResult_cxx;"; 68 | static void registerNatives() { 69 | registerHybrid({makeNativeMethod("invoke_cxx", JFunc_void_CameraResult_cxx::invoke_cxx)}); 70 | } 71 | 72 | private: 73 | explicit JFunc_void_CameraResult_cxx(const std::function& func): _func(func) { } 74 | 75 | private: 76 | friend HybridBase; 77 | std::function _func; 78 | }; 79 | 80 | } // namespace margelo::nitro::multipleimagepicker 81 | -------------------------------------------------------------------------------- /nitrogen/generated/android/c++/JFunc_void_CropResult.hpp: -------------------------------------------------------------------------------- 1 | /// 2 | /// JFunc_void_CropResult.hpp 3 | /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. 4 | /// https://github.com/mrousavy/nitro 5 | /// Copyright © 2025 Marc Rousavy @ Margelo 6 | /// 7 | 8 | #pragma once 9 | 10 | #include 11 | #include 12 | 13 | #include 14 | #include "CropResult.hpp" 15 | #include "JCropResult.hpp" 16 | #include 17 | 18 | namespace margelo::nitro::multipleimagepicker { 19 | 20 | using namespace facebook; 21 | 22 | /** 23 | * Represents the Java/Kotlin callback `(result: CropResult) -> Unit`. 24 | * This can be passed around between C++ and Java/Kotlin. 25 | */ 26 | struct JFunc_void_CropResult: public jni::JavaClass { 27 | public: 28 | static auto constexpr kJavaDescriptor = "Lcom/margelo/nitro/multipleimagepicker/Func_void_CropResult;"; 29 | 30 | public: 31 | /** 32 | * Invokes the function this `JFunc_void_CropResult` instance holds through JNI. 33 | */ 34 | void invoke(const CropResult& result) const { 35 | static const auto method = javaClassStatic()->getMethod /* result */)>("invoke"); 36 | method(self(), JCropResult::fromCpp(result)); 37 | } 38 | }; 39 | 40 | /** 41 | * An implementation of Func_void_CropResult that is backed by a C++ implementation (using `std::function<...>`) 42 | */ 43 | struct JFunc_void_CropResult_cxx final: public jni::HybridClass { 44 | public: 45 | static jni::local_ref fromCpp(const std::function& func) { 46 | return JFunc_void_CropResult_cxx::newObjectCxxArgs(func); 47 | } 48 | 49 | public: 50 | /** 51 | * Invokes the C++ `std::function<...>` this `JFunc_void_CropResult_cxx` instance holds. 52 | */ 53 | void invoke_cxx(jni::alias_ref result) { 54 | _func(result->toCpp()); 55 | } 56 | 57 | public: 58 | [[nodiscard]] 59 | inline const std::function& getFunction() const { 60 | return _func; 61 | } 62 | 63 | public: 64 | static auto constexpr kJavaDescriptor = "Lcom/margelo/nitro/multipleimagepicker/Func_void_CropResult_cxx;"; 65 | static void registerNatives() { 66 | registerHybrid({makeNativeMethod("invoke_cxx", JFunc_void_CropResult_cxx::invoke_cxx)}); 67 | } 68 | 69 | private: 70 | explicit JFunc_void_CropResult_cxx(const std::function& func): _func(func) { } 71 | 72 | private: 73 | friend HybridBase; 74 | std::function _func; 75 | }; 76 | 77 | } // namespace margelo::nitro::multipleimagepicker 78 | -------------------------------------------------------------------------------- /nitrogen/generated/android/c++/JFunc_void_double.hpp: -------------------------------------------------------------------------------- 1 | /// 2 | /// JFunc_void_double.hpp 3 | /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. 4 | /// https://github.com/mrousavy/nitro 5 | /// Copyright © 2025 Marc Rousavy @ Margelo 6 | /// 7 | 8 | #pragma once 9 | 10 | #include 11 | #include 12 | 13 | #include 14 | 15 | namespace margelo::nitro::multipleimagepicker { 16 | 17 | using namespace facebook; 18 | 19 | /** 20 | * Represents the Java/Kotlin callback `(index: Double) -> Unit`. 21 | * This can be passed around between C++ and Java/Kotlin. 22 | */ 23 | struct JFunc_void_double: public jni::JavaClass { 24 | public: 25 | static auto constexpr kJavaDescriptor = "Lcom/margelo/nitro/multipleimagepicker/Func_void_double;"; 26 | 27 | public: 28 | /** 29 | * Invokes the function this `JFunc_void_double` instance holds through JNI. 30 | */ 31 | void invoke(double index) const { 32 | static const auto method = javaClassStatic()->getMethod("invoke"); 33 | method(self(), index); 34 | } 35 | }; 36 | 37 | /** 38 | * An implementation of Func_void_double that is backed by a C++ implementation (using `std::function<...>`) 39 | */ 40 | struct JFunc_void_double_cxx final: public jni::HybridClass { 41 | public: 42 | static jni::local_ref fromCpp(const std::function& func) { 43 | return JFunc_void_double_cxx::newObjectCxxArgs(func); 44 | } 45 | 46 | public: 47 | /** 48 | * Invokes the C++ `std::function<...>` this `JFunc_void_double_cxx` instance holds. 49 | */ 50 | void invoke_cxx(double index) { 51 | _func(index); 52 | } 53 | 54 | public: 55 | [[nodiscard]] 56 | inline const std::function& getFunction() const { 57 | return _func; 58 | } 59 | 60 | public: 61 | static auto constexpr kJavaDescriptor = "Lcom/margelo/nitro/multipleimagepicker/Func_void_double_cxx;"; 62 | static void registerNatives() { 63 | registerHybrid({makeNativeMethod("invoke_cxx", JFunc_void_double_cxx::invoke_cxx)}); 64 | } 65 | 66 | private: 67 | explicit JFunc_void_double_cxx(const std::function& func): _func(func) { } 68 | 69 | private: 70 | friend HybridBase; 71 | std::function _func; 72 | }; 73 | 74 | } // namespace margelo::nitro::multipleimagepicker 75 | -------------------------------------------------------------------------------- /nitrogen/generated/android/c++/JHybridMultipleImagePickerSpec.hpp: -------------------------------------------------------------------------------- 1 | /// 2 | /// HybridMultipleImagePickerSpec.hpp 3 | /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. 4 | /// https://github.com/mrousavy/nitro 5 | /// Copyright © 2025 Marc Rousavy @ Margelo 6 | /// 7 | 8 | #pragma once 9 | 10 | #include 11 | #include 12 | #include "HybridMultipleImagePickerSpec.hpp" 13 | 14 | 15 | 16 | 17 | namespace margelo::nitro::multipleimagepicker { 18 | 19 | using namespace facebook; 20 | 21 | class JHybridMultipleImagePickerSpec: public jni::HybridClass, 22 | public virtual HybridMultipleImagePickerSpec { 23 | public: 24 | static auto constexpr kJavaDescriptor = "Lcom/margelo/nitro/multipleimagepicker/HybridMultipleImagePickerSpec;"; 25 | static jni::local_ref initHybrid(jni::alias_ref jThis); 26 | static void registerNatives(); 27 | 28 | protected: 29 | // C++ constructor (called from Java via `initHybrid()`) 30 | explicit JHybridMultipleImagePickerSpec(jni::alias_ref jThis) : 31 | HybridObject(HybridMultipleImagePickerSpec::TAG), 32 | _javaPart(jni::make_global(jThis)) {} 33 | 34 | public: 35 | ~JHybridMultipleImagePickerSpec() override { 36 | // Hermes GC can destroy JS objects on a non-JNI Thread. 37 | jni::ThreadScope::WithClassLoader([&] { _javaPart.reset(); }); 38 | } 39 | 40 | public: 41 | size_t getExternalMemorySize() noexcept override; 42 | 43 | public: 44 | inline const jni::global_ref& getJavaPart() const noexcept { 45 | return _javaPart; 46 | } 47 | 48 | public: 49 | // Properties 50 | 51 | 52 | public: 53 | // Methods 54 | void openPicker(const NitroConfig& config, const std::function& /* result */)>& resolved, const std::function& rejected) override; 55 | void openCrop(const std::string& image, const NitroCropConfig& config, const std::function& resolved, const std::function& rejected) override; 56 | void openPreview(const std::vector& media, double index, const NitroPreviewConfig& config, const std::function& onLongPress) override; 57 | void openCamera(const NitroCameraConfig& config, const std::function& resolved, const std::function& rejected) override; 58 | 59 | private: 60 | friend HybridBase; 61 | using HybridBase::HybridBase; 62 | jni::global_ref _javaPart; 63 | }; 64 | 65 | } // namespace margelo::nitro::multipleimagepicker 66 | -------------------------------------------------------------------------------- /nitrogen/generated/android/c++/JMediaPreview.hpp: -------------------------------------------------------------------------------- 1 | /// 2 | /// JMediaPreview.hpp 3 | /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. 4 | /// https://github.com/mrousavy/nitro 5 | /// Copyright © 2025 Marc Rousavy @ Margelo 6 | /// 7 | 8 | #pragma once 9 | 10 | #include 11 | #include "MediaPreview.hpp" 12 | 13 | #include "JResultType.hpp" 14 | #include "ResultType.hpp" 15 | #include 16 | #include 17 | 18 | namespace margelo::nitro::multipleimagepicker { 19 | 20 | using namespace facebook; 21 | 22 | /** 23 | * The C++ JNI bridge between the C++ struct "MediaPreview" and the the Kotlin data class "MediaPreview". 24 | */ 25 | struct JMediaPreview final: public jni::JavaClass { 26 | public: 27 | static auto constexpr kJavaDescriptor = "Lcom/margelo/nitro/multipleimagepicker/MediaPreview;"; 28 | 29 | public: 30 | /** 31 | * Convert this Java/Kotlin-based struct to the C++ struct MediaPreview by copying all values to C++. 32 | */ 33 | [[maybe_unused]] 34 | [[nodiscard]] 35 | MediaPreview toCpp() const { 36 | static const auto clazz = javaClassStatic(); 37 | static const auto fieldType = clazz->getField("type"); 38 | jni::local_ref type = this->getFieldValue(fieldType); 39 | static const auto fieldPath = clazz->getField("path"); 40 | jni::local_ref path = this->getFieldValue(fieldPath); 41 | static const auto fieldThumbnail = clazz->getField("thumbnail"); 42 | jni::local_ref thumbnail = this->getFieldValue(fieldThumbnail); 43 | static const auto fieldLocalIdentifier = clazz->getField("localIdentifier"); 44 | jni::local_ref localIdentifier = this->getFieldValue(fieldLocalIdentifier); 45 | return MediaPreview( 46 | type->toCpp(), 47 | path != nullptr ? std::make_optional(path->toStdString()) : std::nullopt, 48 | thumbnail != nullptr ? std::make_optional(thumbnail->toStdString()) : std::nullopt, 49 | localIdentifier != nullptr ? std::make_optional(localIdentifier->toStdString()) : std::nullopt 50 | ); 51 | } 52 | 53 | public: 54 | /** 55 | * Create a Java/Kotlin-based struct by copying all values from the given C++ struct to Java. 56 | */ 57 | [[maybe_unused]] 58 | static jni::local_ref fromCpp(const MediaPreview& value) { 59 | return newInstance( 60 | JResultType::fromCpp(value.type), 61 | value.path.has_value() ? jni::make_jstring(value.path.value()) : nullptr, 62 | value.thumbnail.has_value() ? jni::make_jstring(value.thumbnail.value()) : nullptr, 63 | value.localIdentifier.has_value() ? jni::make_jstring(value.localIdentifier.value()) : nullptr 64 | ); 65 | } 66 | }; 67 | 68 | } // namespace margelo::nitro::multipleimagepicker 69 | -------------------------------------------------------------------------------- /nitrogen/generated/android/c++/JMediaType.hpp: -------------------------------------------------------------------------------- 1 | /// 2 | /// JMediaType.hpp 3 | /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. 4 | /// https://github.com/mrousavy/nitro 5 | /// Copyright © 2025 Marc Rousavy @ Margelo 6 | /// 7 | 8 | #pragma once 9 | 10 | #include 11 | #include "MediaType.hpp" 12 | 13 | namespace margelo::nitro::multipleimagepicker { 14 | 15 | using namespace facebook; 16 | 17 | /** 18 | * The C++ JNI bridge between the C++ enum "MediaType" and the the Kotlin enum "MediaType". 19 | */ 20 | struct JMediaType final: public jni::JavaClass { 21 | public: 22 | static auto constexpr kJavaDescriptor = "Lcom/margelo/nitro/multipleimagepicker/MediaType;"; 23 | 24 | public: 25 | /** 26 | * Convert this Java/Kotlin-based enum to the C++ enum MediaType. 27 | */ 28 | [[maybe_unused]] 29 | [[nodiscard]] 30 | MediaType toCpp() const { 31 | static const auto clazz = javaClassStatic(); 32 | static const auto fieldOrdinal = clazz->getField("_ordinal"); 33 | int ordinal = this->getFieldValue(fieldOrdinal); 34 | return static_cast(ordinal); 35 | } 36 | 37 | public: 38 | /** 39 | * Create a Java/Kotlin-based enum with the given C++ enum's value. 40 | */ 41 | [[maybe_unused]] 42 | static jni::alias_ref fromCpp(MediaType value) { 43 | static const auto clazz = javaClassStatic(); 44 | static const auto fieldVIDEO = clazz->getStaticField("VIDEO"); 45 | static const auto fieldIMAGE = clazz->getStaticField("IMAGE"); 46 | static const auto fieldALL = clazz->getStaticField("ALL"); 47 | 48 | switch (value) { 49 | case MediaType::VIDEO: 50 | return clazz->getStaticFieldValue(fieldVIDEO); 51 | case MediaType::IMAGE: 52 | return clazz->getStaticFieldValue(fieldIMAGE); 53 | case MediaType::ALL: 54 | return clazz->getStaticFieldValue(fieldALL); 55 | default: 56 | std::string stringValue = std::to_string(static_cast(value)); 57 | throw std::invalid_argument("Invalid enum value (" + stringValue + "!"); 58 | } 59 | } 60 | }; 61 | 62 | } // namespace margelo::nitro::multipleimagepicker 63 | -------------------------------------------------------------------------------- /nitrogen/generated/android/c++/JNitroPreviewConfig.hpp: -------------------------------------------------------------------------------- 1 | /// 2 | /// JNitroPreviewConfig.hpp 3 | /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. 4 | /// https://github.com/mrousavy/nitro 5 | /// Copyright © 2025 Marc Rousavy @ Margelo 6 | /// 7 | 8 | #pragma once 9 | 10 | #include 11 | #include "NitroPreviewConfig.hpp" 12 | 13 | #include "JLanguage.hpp" 14 | #include "Language.hpp" 15 | #include 16 | 17 | namespace margelo::nitro::multipleimagepicker { 18 | 19 | using namespace facebook; 20 | 21 | /** 22 | * The C++ JNI bridge between the C++ struct "NitroPreviewConfig" and the the Kotlin data class "NitroPreviewConfig". 23 | */ 24 | struct JNitroPreviewConfig final: public jni::JavaClass { 25 | public: 26 | static auto constexpr kJavaDescriptor = "Lcom/margelo/nitro/multipleimagepicker/NitroPreviewConfig;"; 27 | 28 | public: 29 | /** 30 | * Convert this Java/Kotlin-based struct to the C++ struct NitroPreviewConfig by copying all values to C++. 31 | */ 32 | [[maybe_unused]] 33 | [[nodiscard]] 34 | NitroPreviewConfig toCpp() const { 35 | static const auto clazz = javaClassStatic(); 36 | static const auto fieldLanguage = clazz->getField("language"); 37 | jni::local_ref language = this->getFieldValue(fieldLanguage); 38 | static const auto fieldVideoAutoPlay = clazz->getField("videoAutoPlay"); 39 | jni::local_ref videoAutoPlay = this->getFieldValue(fieldVideoAutoPlay); 40 | return NitroPreviewConfig( 41 | language->toCpp(), 42 | videoAutoPlay != nullptr ? std::make_optional(static_cast(videoAutoPlay->value())) : std::nullopt 43 | ); 44 | } 45 | 46 | public: 47 | /** 48 | * Create a Java/Kotlin-based struct by copying all values from the given C++ struct to Java. 49 | */ 50 | [[maybe_unused]] 51 | static jni::local_ref fromCpp(const NitroPreviewConfig& value) { 52 | return newInstance( 53 | JLanguage::fromCpp(value.language), 54 | value.videoAutoPlay.has_value() ? jni::JBoolean::valueOf(value.videoAutoPlay.value()) : nullptr 55 | ); 56 | } 57 | }; 58 | 59 | } // namespace margelo::nitro::multipleimagepicker 60 | -------------------------------------------------------------------------------- /nitrogen/generated/android/c++/JPickerCameraConfig.hpp: -------------------------------------------------------------------------------- 1 | /// 2 | /// JPickerCameraConfig.hpp 3 | /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. 4 | /// https://github.com/mrousavy/nitro 5 | /// Copyright © 2025 Marc Rousavy @ Margelo 6 | /// 7 | 8 | #pragma once 9 | 10 | #include 11 | #include "PickerCameraConfig.hpp" 12 | 13 | #include "CameraDevice.hpp" 14 | #include "JCameraDevice.hpp" 15 | #include 16 | 17 | namespace margelo::nitro::multipleimagepicker { 18 | 19 | using namespace facebook; 20 | 21 | /** 22 | * The C++ JNI bridge between the C++ struct "PickerCameraConfig" and the the Kotlin data class "PickerCameraConfig". 23 | */ 24 | struct JPickerCameraConfig final: public jni::JavaClass { 25 | public: 26 | static auto constexpr kJavaDescriptor = "Lcom/margelo/nitro/multipleimagepicker/PickerCameraConfig;"; 27 | 28 | public: 29 | /** 30 | * Convert this Java/Kotlin-based struct to the C++ struct PickerCameraConfig by copying all values to C++. 31 | */ 32 | [[maybe_unused]] 33 | [[nodiscard]] 34 | PickerCameraConfig toCpp() const { 35 | static const auto clazz = javaClassStatic(); 36 | static const auto fieldCameraDevice = clazz->getField("cameraDevice"); 37 | jni::local_ref cameraDevice = this->getFieldValue(fieldCameraDevice); 38 | static const auto fieldVideoMaximumDuration = clazz->getField("videoMaximumDuration"); 39 | jni::local_ref videoMaximumDuration = this->getFieldValue(fieldVideoMaximumDuration); 40 | return PickerCameraConfig( 41 | cameraDevice != nullptr ? std::make_optional(cameraDevice->toCpp()) : std::nullopt, 42 | videoMaximumDuration != nullptr ? std::make_optional(videoMaximumDuration->value()) : std::nullopt 43 | ); 44 | } 45 | 46 | public: 47 | /** 48 | * Create a Java/Kotlin-based struct by copying all values from the given C++ struct to Java. 49 | */ 50 | [[maybe_unused]] 51 | static jni::local_ref fromCpp(const PickerCameraConfig& value) { 52 | return newInstance( 53 | value.cameraDevice.has_value() ? JCameraDevice::fromCpp(value.cameraDevice.value()) : nullptr, 54 | value.videoMaximumDuration.has_value() ? jni::JDouble::valueOf(value.videoMaximumDuration.value()) : nullptr 55 | ); 56 | } 57 | }; 58 | 59 | } // namespace margelo::nitro::multipleimagepicker 60 | -------------------------------------------------------------------------------- /nitrogen/generated/android/c++/JPresentation.hpp: -------------------------------------------------------------------------------- 1 | /// 2 | /// JPresentation.hpp 3 | /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. 4 | /// https://github.com/mrousavy/nitro 5 | /// Copyright © 2025 Marc Rousavy @ Margelo 6 | /// 7 | 8 | #pragma once 9 | 10 | #include 11 | #include "Presentation.hpp" 12 | 13 | namespace margelo::nitro::multipleimagepicker { 14 | 15 | using namespace facebook; 16 | 17 | /** 18 | * The C++ JNI bridge between the C++ enum "Presentation" and the the Kotlin enum "Presentation". 19 | */ 20 | struct JPresentation final: public jni::JavaClass { 21 | public: 22 | static auto constexpr kJavaDescriptor = "Lcom/margelo/nitro/multipleimagepicker/Presentation;"; 23 | 24 | public: 25 | /** 26 | * Convert this Java/Kotlin-based enum to the C++ enum Presentation. 27 | */ 28 | [[maybe_unused]] 29 | [[nodiscard]] 30 | Presentation toCpp() const { 31 | static const auto clazz = javaClassStatic(); 32 | static const auto fieldOrdinal = clazz->getField("_ordinal"); 33 | int ordinal = this->getFieldValue(fieldOrdinal); 34 | return static_cast(ordinal); 35 | } 36 | 37 | public: 38 | /** 39 | * Create a Java/Kotlin-based enum with the given C++ enum's value. 40 | */ 41 | [[maybe_unused]] 42 | static jni::alias_ref fromCpp(Presentation value) { 43 | static const auto clazz = javaClassStatic(); 44 | static const auto fieldFULLSCREENMODAL = clazz->getStaticField("FULLSCREENMODAL"); 45 | static const auto fieldFORMSHEET = clazz->getStaticField("FORMSHEET"); 46 | 47 | switch (value) { 48 | case Presentation::FULLSCREENMODAL: 49 | return clazz->getStaticFieldValue(fieldFULLSCREENMODAL); 50 | case Presentation::FORMSHEET: 51 | return clazz->getStaticFieldValue(fieldFORMSHEET); 52 | default: 53 | std::string stringValue = std::to_string(static_cast(value)); 54 | throw std::invalid_argument("Invalid enum value (" + stringValue + "!"); 55 | } 56 | } 57 | }; 58 | 59 | } // namespace margelo::nitro::multipleimagepicker 60 | -------------------------------------------------------------------------------- /nitrogen/generated/android/c++/JResultType.hpp: -------------------------------------------------------------------------------- 1 | /// 2 | /// JResultType.hpp 3 | /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. 4 | /// https://github.com/mrousavy/nitro 5 | /// Copyright © 2025 Marc Rousavy @ Margelo 6 | /// 7 | 8 | #pragma once 9 | 10 | #include 11 | #include "ResultType.hpp" 12 | 13 | namespace margelo::nitro::multipleimagepicker { 14 | 15 | using namespace facebook; 16 | 17 | /** 18 | * The C++ JNI bridge between the C++ enum "ResultType" and the the Kotlin enum "ResultType". 19 | */ 20 | struct JResultType final: public jni::JavaClass { 21 | public: 22 | static auto constexpr kJavaDescriptor = "Lcom/margelo/nitro/multipleimagepicker/ResultType;"; 23 | 24 | public: 25 | /** 26 | * Convert this Java/Kotlin-based enum to the C++ enum ResultType. 27 | */ 28 | [[maybe_unused]] 29 | [[nodiscard]] 30 | ResultType toCpp() const { 31 | static const auto clazz = javaClassStatic(); 32 | static const auto fieldOrdinal = clazz->getField("_ordinal"); 33 | int ordinal = this->getFieldValue(fieldOrdinal); 34 | return static_cast(ordinal); 35 | } 36 | 37 | public: 38 | /** 39 | * Create a Java/Kotlin-based enum with the given C++ enum's value. 40 | */ 41 | [[maybe_unused]] 42 | static jni::alias_ref fromCpp(ResultType value) { 43 | static const auto clazz = javaClassStatic(); 44 | static const auto fieldVIDEO = clazz->getStaticField("VIDEO"); 45 | static const auto fieldIMAGE = clazz->getStaticField("IMAGE"); 46 | 47 | switch (value) { 48 | case ResultType::VIDEO: 49 | return clazz->getStaticFieldValue(fieldVIDEO); 50 | case ResultType::IMAGE: 51 | return clazz->getStaticFieldValue(fieldIMAGE); 52 | default: 53 | std::string stringValue = std::to_string(static_cast(value)); 54 | throw std::invalid_argument("Invalid enum value (" + stringValue + "!"); 55 | } 56 | } 57 | }; 58 | 59 | } // namespace margelo::nitro::multipleimagepicker 60 | -------------------------------------------------------------------------------- /nitrogen/generated/android/c++/JSelectBoxStyle.hpp: -------------------------------------------------------------------------------- 1 | /// 2 | /// JSelectBoxStyle.hpp 3 | /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. 4 | /// https://github.com/mrousavy/nitro 5 | /// Copyright © 2025 Marc Rousavy @ Margelo 6 | /// 7 | 8 | #pragma once 9 | 10 | #include 11 | #include "SelectBoxStyle.hpp" 12 | 13 | namespace margelo::nitro::multipleimagepicker { 14 | 15 | using namespace facebook; 16 | 17 | /** 18 | * The C++ JNI bridge between the C++ enum "SelectBoxStyle" and the the Kotlin enum "SelectBoxStyle". 19 | */ 20 | struct JSelectBoxStyle final: public jni::JavaClass { 21 | public: 22 | static auto constexpr kJavaDescriptor = "Lcom/margelo/nitro/multipleimagepicker/SelectBoxStyle;"; 23 | 24 | public: 25 | /** 26 | * Convert this Java/Kotlin-based enum to the C++ enum SelectBoxStyle. 27 | */ 28 | [[maybe_unused]] 29 | [[nodiscard]] 30 | SelectBoxStyle toCpp() const { 31 | static const auto clazz = javaClassStatic(); 32 | static const auto fieldOrdinal = clazz->getField("_ordinal"); 33 | int ordinal = this->getFieldValue(fieldOrdinal); 34 | return static_cast(ordinal); 35 | } 36 | 37 | public: 38 | /** 39 | * Create a Java/Kotlin-based enum with the given C++ enum's value. 40 | */ 41 | [[maybe_unused]] 42 | static jni::alias_ref fromCpp(SelectBoxStyle value) { 43 | static const auto clazz = javaClassStatic(); 44 | static const auto fieldNUMBER = clazz->getStaticField("NUMBER"); 45 | static const auto fieldTICK = clazz->getStaticField("TICK"); 46 | 47 | switch (value) { 48 | case SelectBoxStyle::NUMBER: 49 | return clazz->getStaticFieldValue(fieldNUMBER); 50 | case SelectBoxStyle::TICK: 51 | return clazz->getStaticFieldValue(fieldTICK); 52 | default: 53 | std::string stringValue = std::to_string(static_cast(value)); 54 | throw std::invalid_argument("Invalid enum value (" + stringValue + "!"); 55 | } 56 | } 57 | }; 58 | 59 | } // namespace margelo::nitro::multipleimagepicker 60 | -------------------------------------------------------------------------------- /nitrogen/generated/android/c++/JSelectMode.hpp: -------------------------------------------------------------------------------- 1 | /// 2 | /// JSelectMode.hpp 3 | /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. 4 | /// https://github.com/mrousavy/nitro 5 | /// Copyright © 2025 Marc Rousavy @ Margelo 6 | /// 7 | 8 | #pragma once 9 | 10 | #include 11 | #include "SelectMode.hpp" 12 | 13 | namespace margelo::nitro::multipleimagepicker { 14 | 15 | using namespace facebook; 16 | 17 | /** 18 | * The C++ JNI bridge between the C++ enum "SelectMode" and the the Kotlin enum "SelectMode". 19 | */ 20 | struct JSelectMode final: public jni::JavaClass { 21 | public: 22 | static auto constexpr kJavaDescriptor = "Lcom/margelo/nitro/multipleimagepicker/SelectMode;"; 23 | 24 | public: 25 | /** 26 | * Convert this Java/Kotlin-based enum to the C++ enum SelectMode. 27 | */ 28 | [[maybe_unused]] 29 | [[nodiscard]] 30 | SelectMode toCpp() const { 31 | static const auto clazz = javaClassStatic(); 32 | static const auto fieldOrdinal = clazz->getField("_ordinal"); 33 | int ordinal = this->getFieldValue(fieldOrdinal); 34 | return static_cast(ordinal); 35 | } 36 | 37 | public: 38 | /** 39 | * Create a Java/Kotlin-based enum with the given C++ enum's value. 40 | */ 41 | [[maybe_unused]] 42 | static jni::alias_ref fromCpp(SelectMode value) { 43 | static const auto clazz = javaClassStatic(); 44 | static const auto fieldSINGLE = clazz->getStaticField("SINGLE"); 45 | static const auto fieldMULTIPLE = clazz->getStaticField("MULTIPLE"); 46 | 47 | switch (value) { 48 | case SelectMode::SINGLE: 49 | return clazz->getStaticFieldValue(fieldSINGLE); 50 | case SelectMode::MULTIPLE: 51 | return clazz->getStaticFieldValue(fieldMULTIPLE); 52 | default: 53 | std::string stringValue = std::to_string(static_cast(value)); 54 | throw std::invalid_argument("Invalid enum value (" + stringValue + "!"); 55 | } 56 | } 57 | }; 58 | 59 | } // namespace margelo::nitro::multipleimagepicker 60 | -------------------------------------------------------------------------------- /nitrogen/generated/android/c++/JText.hpp: -------------------------------------------------------------------------------- 1 | /// 2 | /// JText.hpp 3 | /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. 4 | /// https://github.com/mrousavy/nitro 5 | /// Copyright © 2025 Marc Rousavy @ Margelo 6 | /// 7 | 8 | #pragma once 9 | 10 | #include 11 | #include "Text.hpp" 12 | 13 | #include 14 | #include 15 | 16 | namespace margelo::nitro::multipleimagepicker { 17 | 18 | using namespace facebook; 19 | 20 | /** 21 | * The C++ JNI bridge between the C++ struct "Text" and the the Kotlin data class "Text". 22 | */ 23 | struct JText final: public jni::JavaClass { 24 | public: 25 | static auto constexpr kJavaDescriptor = "Lcom/margelo/nitro/multipleimagepicker/Text;"; 26 | 27 | public: 28 | /** 29 | * Convert this Java/Kotlin-based struct to the C++ struct Text by copying all values to C++. 30 | */ 31 | [[maybe_unused]] 32 | [[nodiscard]] 33 | Text toCpp() const { 34 | static const auto clazz = javaClassStatic(); 35 | static const auto fieldFinish = clazz->getField("finish"); 36 | jni::local_ref finish = this->getFieldValue(fieldFinish); 37 | static const auto fieldOriginal = clazz->getField("original"); 38 | jni::local_ref original = this->getFieldValue(fieldOriginal); 39 | static const auto fieldPreview = clazz->getField("preview"); 40 | jni::local_ref preview = this->getFieldValue(fieldPreview); 41 | static const auto fieldEdit = clazz->getField("edit"); 42 | jni::local_ref edit = this->getFieldValue(fieldEdit); 43 | return Text( 44 | finish != nullptr ? std::make_optional(finish->toStdString()) : std::nullopt, 45 | original != nullptr ? std::make_optional(original->toStdString()) : std::nullopt, 46 | preview != nullptr ? std::make_optional(preview->toStdString()) : std::nullopt, 47 | edit != nullptr ? std::make_optional(edit->toStdString()) : std::nullopt 48 | ); 49 | } 50 | 51 | public: 52 | /** 53 | * Create a Java/Kotlin-based struct by copying all values from the given C++ struct to Java. 54 | */ 55 | [[maybe_unused]] 56 | static jni::local_ref fromCpp(const Text& value) { 57 | return newInstance( 58 | value.finish.has_value() ? jni::make_jstring(value.finish.value()) : nullptr, 59 | value.original.has_value() ? jni::make_jstring(value.original.value()) : nullptr, 60 | value.preview.has_value() ? jni::make_jstring(value.preview.value()) : nullptr, 61 | value.edit.has_value() ? jni::make_jstring(value.edit.value()) : nullptr 62 | ); 63 | } 64 | }; 65 | 66 | } // namespace margelo::nitro::multipleimagepicker 67 | -------------------------------------------------------------------------------- /nitrogen/generated/android/c++/JTheme.hpp: -------------------------------------------------------------------------------- 1 | /// 2 | /// JTheme.hpp 3 | /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. 4 | /// https://github.com/mrousavy/nitro 5 | /// Copyright © 2025 Marc Rousavy @ Margelo 6 | /// 7 | 8 | #pragma once 9 | 10 | #include 11 | #include "Theme.hpp" 12 | 13 | namespace margelo::nitro::multipleimagepicker { 14 | 15 | using namespace facebook; 16 | 17 | /** 18 | * The C++ JNI bridge between the C++ enum "Theme" and the the Kotlin enum "Theme". 19 | */ 20 | struct JTheme final: public jni::JavaClass { 21 | public: 22 | static auto constexpr kJavaDescriptor = "Lcom/margelo/nitro/multipleimagepicker/Theme;"; 23 | 24 | public: 25 | /** 26 | * Convert this Java/Kotlin-based enum to the C++ enum Theme. 27 | */ 28 | [[maybe_unused]] 29 | [[nodiscard]] 30 | Theme toCpp() const { 31 | static const auto clazz = javaClassStatic(); 32 | static const auto fieldOrdinal = clazz->getField("_ordinal"); 33 | int ordinal = this->getFieldValue(fieldOrdinal); 34 | return static_cast(ordinal); 35 | } 36 | 37 | public: 38 | /** 39 | * Create a Java/Kotlin-based enum with the given C++ enum's value. 40 | */ 41 | [[maybe_unused]] 42 | static jni::alias_ref fromCpp(Theme value) { 43 | static const auto clazz = javaClassStatic(); 44 | static const auto fieldLIGHT = clazz->getStaticField("LIGHT"); 45 | static const auto fieldDARK = clazz->getStaticField("DARK"); 46 | 47 | switch (value) { 48 | case Theme::LIGHT: 49 | return clazz->getStaticFieldValue(fieldLIGHT); 50 | case Theme::DARK: 51 | return clazz->getStaticFieldValue(fieldDARK); 52 | default: 53 | std::string stringValue = std::to_string(static_cast(value)); 54 | throw std::invalid_argument("Invalid enum value (" + stringValue + "!"); 55 | } 56 | } 57 | }; 58 | 59 | } // namespace margelo::nitro::multipleimagepicker 60 | -------------------------------------------------------------------------------- /nitrogen/generated/android/kotlin/com/margelo/nitro/multipleimagepicker/CameraDevice.kt: -------------------------------------------------------------------------------- 1 | /// 2 | /// CameraDevice.kt 3 | /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. 4 | /// https://github.com/mrousavy/nitro 5 | /// Copyright © 2025 Marc Rousavy @ Margelo 6 | /// 7 | 8 | package com.margelo.nitro.multipleimagepicker 9 | 10 | import androidx.annotation.Keep 11 | import com.facebook.proguard.annotations.DoNotStrip 12 | 13 | /** 14 | * Represents the JavaScript enum/union "CameraDevice". 15 | */ 16 | @DoNotStrip 17 | @Keep 18 | enum class CameraDevice { 19 | FRONT, 20 | BACK; 21 | 22 | @DoNotStrip 23 | @Keep 24 | private val _ordinal = ordinal 25 | } 26 | -------------------------------------------------------------------------------- /nitrogen/generated/android/kotlin/com/margelo/nitro/multipleimagepicker/CameraResult.kt: -------------------------------------------------------------------------------- 1 | /// 2 | /// CameraResult.kt 3 | /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. 4 | /// https://github.com/mrousavy/nitro 5 | /// Copyright © 2025 Marc Rousavy @ Margelo 6 | /// 7 | 8 | package com.margelo.nitro.multipleimagepicker 9 | 10 | import androidx.annotation.Keep 11 | import com.facebook.proguard.annotations.DoNotStrip 12 | import com.margelo.nitro.core.* 13 | 14 | /** 15 | * Represents the JavaScript object/struct "CameraResult". 16 | */ 17 | @DoNotStrip 18 | @Keep 19 | data class CameraResult 20 | @DoNotStrip 21 | @Keep 22 | constructor( 23 | val path: String, 24 | val type: ResultType, 25 | val width: Double?, 26 | val height: Double?, 27 | val duration: Double?, 28 | val thumbnail: String?, 29 | val fileName: String? 30 | ) { 31 | /* main constructor */ 32 | } 33 | -------------------------------------------------------------------------------- /nitrogen/generated/android/kotlin/com/margelo/nitro/multipleimagepicker/CropRatio.kt: -------------------------------------------------------------------------------- 1 | /// 2 | /// CropRatio.kt 3 | /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. 4 | /// https://github.com/mrousavy/nitro 5 | /// Copyright © 2025 Marc Rousavy @ Margelo 6 | /// 7 | 8 | package com.margelo.nitro.multipleimagepicker 9 | 10 | import androidx.annotation.Keep 11 | import com.facebook.proguard.annotations.DoNotStrip 12 | import com.margelo.nitro.core.* 13 | 14 | /** 15 | * Represents the JavaScript object/struct "CropRatio". 16 | */ 17 | @DoNotStrip 18 | @Keep 19 | data class CropRatio 20 | @DoNotStrip 21 | @Keep 22 | constructor( 23 | val title: String?, 24 | val width: Double, 25 | val height: Double 26 | ) { 27 | /* main constructor */ 28 | } 29 | -------------------------------------------------------------------------------- /nitrogen/generated/android/kotlin/com/margelo/nitro/multipleimagepicker/CropResult.kt: -------------------------------------------------------------------------------- 1 | /// 2 | /// CropResult.kt 3 | /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. 4 | /// https://github.com/mrousavy/nitro 5 | /// Copyright © 2025 Marc Rousavy @ Margelo 6 | /// 7 | 8 | package com.margelo.nitro.multipleimagepicker 9 | 10 | import androidx.annotation.Keep 11 | import com.facebook.proguard.annotations.DoNotStrip 12 | import com.margelo.nitro.core.* 13 | 14 | /** 15 | * Represents the JavaScript object/struct "CropResult". 16 | */ 17 | @DoNotStrip 18 | @Keep 19 | data class CropResult 20 | @DoNotStrip 21 | @Keep 22 | constructor( 23 | val path: String, 24 | val width: Double, 25 | val height: Double 26 | ) { 27 | /* main constructor */ 28 | } 29 | -------------------------------------------------------------------------------- /nitrogen/generated/android/kotlin/com/margelo/nitro/multipleimagepicker/Func_void_CameraResult.kt: -------------------------------------------------------------------------------- 1 | /// 2 | /// Func_void_CameraResult.kt 3 | /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. 4 | /// https://github.com/mrousavy/nitro 5 | /// Copyright © 2025 Marc Rousavy @ Margelo 6 | /// 7 | 8 | package com.margelo.nitro.multipleimagepicker 9 | 10 | import androidx.annotation.Keep 11 | import com.facebook.jni.HybridData 12 | import com.facebook.proguard.annotations.DoNotStrip 13 | import com.margelo.nitro.core.* 14 | import dalvik.annotation.optimization.FastNative 15 | 16 | /** 17 | * Represents the JavaScript callback `(result: struct) => void`. 18 | * This can be either implemented in C++ (in which case it might be a callback coming from JS), 19 | * or in Kotlin/Java (in which case it is a native callback). 20 | */ 21 | @DoNotStrip 22 | @Keep 23 | @Suppress("ClassName", "RedundantUnitReturnType") 24 | fun interface Func_void_CameraResult: (CameraResult) -> Unit { 25 | /** 26 | * Call the given JS callback. 27 | * @throws Throwable if the JS function itself throws an error, or if the JS function/runtime has already been deleted. 28 | */ 29 | @DoNotStrip 30 | @Keep 31 | override fun invoke(result: CameraResult): Unit 32 | } 33 | 34 | /** 35 | * Represents the JavaScript callback `(result: struct) => void`. 36 | * This is implemented in C++, via a `std::function<...>`. 37 | * The callback might be coming from JS. 38 | */ 39 | @DoNotStrip 40 | @Keep 41 | @Suppress( 42 | "KotlinJniMissingFunction", "unused", 43 | "RedundantSuppression", "RedundantUnitReturnType", "FunctionName", 44 | "ConvertSecondaryConstructorToPrimary", "ClassName", "LocalVariableName", 45 | ) 46 | class Func_void_CameraResult_cxx: Func_void_CameraResult { 47 | @DoNotStrip 48 | @Keep 49 | private val mHybridData: HybridData 50 | 51 | @DoNotStrip 52 | @Keep 53 | private constructor(hybridData: HybridData) { 54 | mHybridData = hybridData 55 | } 56 | 57 | @DoNotStrip 58 | @Keep 59 | override fun invoke(result: CameraResult): Unit 60 | = invoke_cxx(result) 61 | 62 | @FastNative 63 | private external fun invoke_cxx(result: CameraResult): Unit 64 | } 65 | 66 | /** 67 | * Represents the JavaScript callback `(result: struct) => void`. 68 | * This is implemented in Java/Kotlin, via a `(CameraResult) -> Unit`. 69 | * The callback is always coming from native. 70 | */ 71 | @DoNotStrip 72 | @Keep 73 | @Suppress("ClassName", "RedundantUnitReturnType", "unused") 74 | class Func_void_CameraResult_java(private val function: (CameraResult) -> Unit): Func_void_CameraResult { 75 | @DoNotStrip 76 | @Keep 77 | override fun invoke(result: CameraResult): Unit { 78 | return this.function(result) 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /nitrogen/generated/android/kotlin/com/margelo/nitro/multipleimagepicker/Func_void_CropResult.kt: -------------------------------------------------------------------------------- 1 | /// 2 | /// Func_void_CropResult.kt 3 | /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. 4 | /// https://github.com/mrousavy/nitro 5 | /// Copyright © 2025 Marc Rousavy @ Margelo 6 | /// 7 | 8 | package com.margelo.nitro.multipleimagepicker 9 | 10 | import androidx.annotation.Keep 11 | import com.facebook.jni.HybridData 12 | import com.facebook.proguard.annotations.DoNotStrip 13 | import com.margelo.nitro.core.* 14 | import dalvik.annotation.optimization.FastNative 15 | 16 | /** 17 | * Represents the JavaScript callback `(result: struct) => void`. 18 | * This can be either implemented in C++ (in which case it might be a callback coming from JS), 19 | * or in Kotlin/Java (in which case it is a native callback). 20 | */ 21 | @DoNotStrip 22 | @Keep 23 | @Suppress("ClassName", "RedundantUnitReturnType") 24 | fun interface Func_void_CropResult: (CropResult) -> Unit { 25 | /** 26 | * Call the given JS callback. 27 | * @throws Throwable if the JS function itself throws an error, or if the JS function/runtime has already been deleted. 28 | */ 29 | @DoNotStrip 30 | @Keep 31 | override fun invoke(result: CropResult): Unit 32 | } 33 | 34 | /** 35 | * Represents the JavaScript callback `(result: struct) => void`. 36 | * This is implemented in C++, via a `std::function<...>`. 37 | * The callback might be coming from JS. 38 | */ 39 | @DoNotStrip 40 | @Keep 41 | @Suppress( 42 | "KotlinJniMissingFunction", "unused", 43 | "RedundantSuppression", "RedundantUnitReturnType", "FunctionName", 44 | "ConvertSecondaryConstructorToPrimary", "ClassName", "LocalVariableName", 45 | ) 46 | class Func_void_CropResult_cxx: Func_void_CropResult { 47 | @DoNotStrip 48 | @Keep 49 | private val mHybridData: HybridData 50 | 51 | @DoNotStrip 52 | @Keep 53 | private constructor(hybridData: HybridData) { 54 | mHybridData = hybridData 55 | } 56 | 57 | @DoNotStrip 58 | @Keep 59 | override fun invoke(result: CropResult): Unit 60 | = invoke_cxx(result) 61 | 62 | @FastNative 63 | private external fun invoke_cxx(result: CropResult): Unit 64 | } 65 | 66 | /** 67 | * Represents the JavaScript callback `(result: struct) => void`. 68 | * This is implemented in Java/Kotlin, via a `(CropResult) -> Unit`. 69 | * The callback is always coming from native. 70 | */ 71 | @DoNotStrip 72 | @Keep 73 | @Suppress("ClassName", "RedundantUnitReturnType", "unused") 74 | class Func_void_CropResult_java(private val function: (CropResult) -> Unit): Func_void_CropResult { 75 | @DoNotStrip 76 | @Keep 77 | override fun invoke(result: CropResult): Unit { 78 | return this.function(result) 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /nitrogen/generated/android/kotlin/com/margelo/nitro/multipleimagepicker/Func_void_double.kt: -------------------------------------------------------------------------------- 1 | /// 2 | /// Func_void_double.kt 3 | /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. 4 | /// https://github.com/mrousavy/nitro 5 | /// Copyright © 2025 Marc Rousavy @ Margelo 6 | /// 7 | 8 | package com.margelo.nitro.multipleimagepicker 9 | 10 | import androidx.annotation.Keep 11 | import com.facebook.jni.HybridData 12 | import com.facebook.proguard.annotations.DoNotStrip 13 | import com.margelo.nitro.core.* 14 | import dalvik.annotation.optimization.FastNative 15 | 16 | /** 17 | * Represents the JavaScript callback `(index: number) => void`. 18 | * This can be either implemented in C++ (in which case it might be a callback coming from JS), 19 | * or in Kotlin/Java (in which case it is a native callback). 20 | */ 21 | @DoNotStrip 22 | @Keep 23 | @Suppress("ClassName", "RedundantUnitReturnType") 24 | fun interface Func_void_double: (Double) -> Unit { 25 | /** 26 | * Call the given JS callback. 27 | * @throws Throwable if the JS function itself throws an error, or if the JS function/runtime has already been deleted. 28 | */ 29 | @DoNotStrip 30 | @Keep 31 | override fun invoke(index: Double): Unit 32 | } 33 | 34 | /** 35 | * Represents the JavaScript callback `(index: number) => void`. 36 | * This is implemented in C++, via a `std::function<...>`. 37 | * The callback might be coming from JS. 38 | */ 39 | @DoNotStrip 40 | @Keep 41 | @Suppress( 42 | "KotlinJniMissingFunction", "unused", 43 | "RedundantSuppression", "RedundantUnitReturnType", "FunctionName", 44 | "ConvertSecondaryConstructorToPrimary", "ClassName", "LocalVariableName", 45 | ) 46 | class Func_void_double_cxx: Func_void_double { 47 | @DoNotStrip 48 | @Keep 49 | private val mHybridData: HybridData 50 | 51 | @DoNotStrip 52 | @Keep 53 | private constructor(hybridData: HybridData) { 54 | mHybridData = hybridData 55 | } 56 | 57 | @DoNotStrip 58 | @Keep 59 | override fun invoke(index: Double): Unit 60 | = invoke_cxx(index) 61 | 62 | @FastNative 63 | private external fun invoke_cxx(index: Double): Unit 64 | } 65 | 66 | /** 67 | * Represents the JavaScript callback `(index: number) => void`. 68 | * This is implemented in Java/Kotlin, via a `(Double) -> Unit`. 69 | * The callback is always coming from native. 70 | */ 71 | @DoNotStrip 72 | @Keep 73 | @Suppress("ClassName", "RedundantUnitReturnType", "unused") 74 | class Func_void_double_java(private val function: (Double) -> Unit): Func_void_double { 75 | @DoNotStrip 76 | @Keep 77 | override fun invoke(index: Double): Unit { 78 | return this.function(index) 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /nitrogen/generated/android/kotlin/com/margelo/nitro/multipleimagepicker/Func_void_std__vector_PickerResult_.kt: -------------------------------------------------------------------------------- 1 | /// 2 | /// Func_void_std__vector_PickerResult_.kt 3 | /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. 4 | /// https://github.com/mrousavy/nitro 5 | /// Copyright © 2025 Marc Rousavy @ Margelo 6 | /// 7 | 8 | package com.margelo.nitro.multipleimagepicker 9 | 10 | import androidx.annotation.Keep 11 | import com.facebook.jni.HybridData 12 | import com.facebook.proguard.annotations.DoNotStrip 13 | import com.margelo.nitro.core.* 14 | import dalvik.annotation.optimization.FastNative 15 | 16 | /** 17 | * Represents the JavaScript callback `(result: array) => void`. 18 | * This can be either implemented in C++ (in which case it might be a callback coming from JS), 19 | * or in Kotlin/Java (in which case it is a native callback). 20 | */ 21 | @DoNotStrip 22 | @Keep 23 | @Suppress("ClassName", "RedundantUnitReturnType") 24 | fun interface Func_void_std__vector_PickerResult_: (Array) -> Unit { 25 | /** 26 | * Call the given JS callback. 27 | * @throws Throwable if the JS function itself throws an error, or if the JS function/runtime has already been deleted. 28 | */ 29 | @DoNotStrip 30 | @Keep 31 | override fun invoke(result: Array): Unit 32 | } 33 | 34 | /** 35 | * Represents the JavaScript callback `(result: array) => void`. 36 | * This is implemented in C++, via a `std::function<...>`. 37 | * The callback might be coming from JS. 38 | */ 39 | @DoNotStrip 40 | @Keep 41 | @Suppress( 42 | "KotlinJniMissingFunction", "unused", 43 | "RedundantSuppression", "RedundantUnitReturnType", "FunctionName", 44 | "ConvertSecondaryConstructorToPrimary", "ClassName", "LocalVariableName", 45 | ) 46 | class Func_void_std__vector_PickerResult__cxx: Func_void_std__vector_PickerResult_ { 47 | @DoNotStrip 48 | @Keep 49 | private val mHybridData: HybridData 50 | 51 | @DoNotStrip 52 | @Keep 53 | private constructor(hybridData: HybridData) { 54 | mHybridData = hybridData 55 | } 56 | 57 | @DoNotStrip 58 | @Keep 59 | override fun invoke(result: Array): Unit 60 | = invoke_cxx(result) 61 | 62 | @FastNative 63 | private external fun invoke_cxx(result: Array): Unit 64 | } 65 | 66 | /** 67 | * Represents the JavaScript callback `(result: array) => void`. 68 | * This is implemented in Java/Kotlin, via a `(Array) -> Unit`. 69 | * The callback is always coming from native. 70 | */ 71 | @DoNotStrip 72 | @Keep 73 | @Suppress("ClassName", "RedundantUnitReturnType", "unused") 74 | class Func_void_std__vector_PickerResult__java(private val function: (Array) -> Unit): Func_void_std__vector_PickerResult_ { 75 | @DoNotStrip 76 | @Keep 77 | override fun invoke(result: Array): Unit { 78 | return this.function(result) 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /nitrogen/generated/android/kotlin/com/margelo/nitro/multipleimagepicker/Language.kt: -------------------------------------------------------------------------------- 1 | /// 2 | /// Language.kt 3 | /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. 4 | /// https://github.com/mrousavy/nitro 5 | /// Copyright © 2025 Marc Rousavy @ Margelo 6 | /// 7 | 8 | package com.margelo.nitro.multipleimagepicker 9 | 10 | import androidx.annotation.Keep 11 | import com.facebook.proguard.annotations.DoNotStrip 12 | 13 | /** 14 | * Represents the JavaScript enum/union "Language". 15 | */ 16 | @DoNotStrip 17 | @Keep 18 | enum class Language { 19 | SYSTEM, 20 | ZH_HANS, 21 | ZH_HANT, 22 | JA, 23 | KO, 24 | EN, 25 | TH, 26 | ID, 27 | VI, 28 | RU, 29 | DE, 30 | FR, 31 | AR; 32 | 33 | @DoNotStrip 34 | @Keep 35 | private val _ordinal = ordinal 36 | } 37 | -------------------------------------------------------------------------------- /nitrogen/generated/android/kotlin/com/margelo/nitro/multipleimagepicker/MediaPreview.kt: -------------------------------------------------------------------------------- 1 | /// 2 | /// MediaPreview.kt 3 | /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. 4 | /// https://github.com/mrousavy/nitro 5 | /// Copyright © 2025 Marc Rousavy @ Margelo 6 | /// 7 | 8 | package com.margelo.nitro.multipleimagepicker 9 | 10 | import androidx.annotation.Keep 11 | import com.facebook.proguard.annotations.DoNotStrip 12 | import com.margelo.nitro.core.* 13 | 14 | /** 15 | * Represents the JavaScript object/struct "MediaPreview". 16 | */ 17 | @DoNotStrip 18 | @Keep 19 | data class MediaPreview 20 | @DoNotStrip 21 | @Keep 22 | constructor( 23 | val type: ResultType, 24 | val path: String?, 25 | val thumbnail: String?, 26 | val localIdentifier: String? 27 | ) { 28 | /* main constructor */ 29 | } 30 | -------------------------------------------------------------------------------- /nitrogen/generated/android/kotlin/com/margelo/nitro/multipleimagepicker/MediaType.kt: -------------------------------------------------------------------------------- 1 | /// 2 | /// MediaType.kt 3 | /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. 4 | /// https://github.com/mrousavy/nitro 5 | /// Copyright © 2025 Marc Rousavy @ Margelo 6 | /// 7 | 8 | package com.margelo.nitro.multipleimagepicker 9 | 10 | import androidx.annotation.Keep 11 | import com.facebook.proguard.annotations.DoNotStrip 12 | 13 | /** 14 | * Represents the JavaScript enum/union "MediaType". 15 | */ 16 | @DoNotStrip 17 | @Keep 18 | enum class MediaType { 19 | VIDEO, 20 | IMAGE, 21 | ALL; 22 | 23 | @DoNotStrip 24 | @Keep 25 | private val _ordinal = ordinal 26 | } 27 | -------------------------------------------------------------------------------- /nitrogen/generated/android/kotlin/com/margelo/nitro/multipleimagepicker/MultipleImagePickerOnLoad.kt: -------------------------------------------------------------------------------- 1 | /// 2 | /// MultipleImagePickerOnLoad.kt 3 | /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. 4 | /// https://github.com/mrousavy/nitro 5 | /// Copyright © 2025 Marc Rousavy @ Margelo 6 | /// 7 | 8 | package com.margelo.nitro.multipleimagepicker 9 | 10 | import android.util.Log 11 | 12 | internal class MultipleImagePickerOnLoad { 13 | companion object { 14 | private const val TAG = "MultipleImagePickerOnLoad" 15 | private var didLoad = false 16 | /** 17 | * Initializes the native part of "MultipleImagePicker". 18 | * This method is idempotent and can be called more than once. 19 | */ 20 | @JvmStatic 21 | fun initializeNative() { 22 | if (didLoad) return 23 | try { 24 | Log.i(TAG, "Loading MultipleImagePicker C++ library...") 25 | System.loadLibrary("MultipleImagePicker") 26 | Log.i(TAG, "Successfully loaded MultipleImagePicker C++ library!") 27 | didLoad = true 28 | } catch (e: Error) { 29 | Log.e(TAG, "Failed to load MultipleImagePicker C++ library! Is it properly installed and linked? " + 30 | "Is the name correct? (see `CMakeLists.txt`, at `add_library(...)`)", e) 31 | throw e 32 | } 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /nitrogen/generated/android/kotlin/com/margelo/nitro/multipleimagepicker/NitroCameraConfig.kt: -------------------------------------------------------------------------------- 1 | /// 2 | /// NitroCameraConfig.kt 3 | /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. 4 | /// https://github.com/mrousavy/nitro 5 | /// Copyright © 2025 Marc Rousavy @ Margelo 6 | /// 7 | 8 | package com.margelo.nitro.multipleimagepicker 9 | 10 | import androidx.annotation.Keep 11 | import com.facebook.proguard.annotations.DoNotStrip 12 | import com.margelo.nitro.core.* 13 | 14 | /** 15 | * Represents the JavaScript object/struct "NitroCameraConfig". 16 | */ 17 | @DoNotStrip 18 | @Keep 19 | data class NitroCameraConfig 20 | @DoNotStrip 21 | @Keep 22 | constructor( 23 | val mediaType: MediaType, 24 | val presentation: Presentation, 25 | val language: Language, 26 | val crop: PickerCropConfig?, 27 | val isSaveSystemAlbum: Boolean?, 28 | val color: Double?, 29 | val cameraDevice: CameraDevice?, 30 | val videoMaximumDuration: Double? 31 | ) { 32 | /* main constructor */ 33 | } 34 | -------------------------------------------------------------------------------- /nitrogen/generated/android/kotlin/com/margelo/nitro/multipleimagepicker/NitroConfig.kt: -------------------------------------------------------------------------------- 1 | /// 2 | /// NitroConfig.kt 3 | /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. 4 | /// https://github.com/mrousavy/nitro 5 | /// Copyright © 2025 Marc Rousavy @ Margelo 6 | /// 7 | 8 | package com.margelo.nitro.multipleimagepicker 9 | 10 | import androidx.annotation.Keep 11 | import com.facebook.proguard.annotations.DoNotStrip 12 | import com.margelo.nitro.core.* 13 | 14 | /** 15 | * Represents the JavaScript object/struct "NitroConfig". 16 | */ 17 | @DoNotStrip 18 | @Keep 19 | data class NitroConfig 20 | @DoNotStrip 21 | @Keep 22 | constructor( 23 | val mediaType: MediaType, 24 | val selectedAssets: Array, 25 | val selectBoxStyle: SelectBoxStyle, 26 | val selectMode: SelectMode, 27 | val numberOfColumn: Double?, 28 | val isPreview: Boolean?, 29 | val primaryColor: Double?, 30 | val allowSwipeToSelect: Boolean?, 31 | val spacing: Double?, 32 | val isHiddenPreviewButton: Boolean?, 33 | val isHiddenOriginalButton: Boolean?, 34 | val isShowPreviewList: Boolean?, 35 | val allowHapticTouchPreview: Boolean?, 36 | val allowedLimit: Boolean?, 37 | val maxVideo: Double?, 38 | val maxSelect: Double?, 39 | val maxVideoDuration: Double?, 40 | val minVideoDuration: Double?, 41 | val maxFileSize: Double?, 42 | val backgroundDark: Double?, 43 | val crop: PickerCropConfig?, 44 | val text: Text?, 45 | val language: Language, 46 | val theme: Theme, 47 | val presentation: Presentation, 48 | val camera: PickerCameraConfig? 49 | ) { 50 | /* main constructor */ 51 | } 52 | -------------------------------------------------------------------------------- /nitrogen/generated/android/kotlin/com/margelo/nitro/multipleimagepicker/NitroCropConfig.kt: -------------------------------------------------------------------------------- 1 | /// 2 | /// NitroCropConfig.kt 3 | /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. 4 | /// https://github.com/mrousavy/nitro 5 | /// Copyright © 2025 Marc Rousavy @ Margelo 6 | /// 7 | 8 | package com.margelo.nitro.multipleimagepicker 9 | 10 | import androidx.annotation.Keep 11 | import com.facebook.proguard.annotations.DoNotStrip 12 | import com.margelo.nitro.core.* 13 | 14 | /** 15 | * Represents the JavaScript object/struct "NitroCropConfig". 16 | */ 17 | @DoNotStrip 18 | @Keep 19 | data class NitroCropConfig 20 | @DoNotStrip 21 | @Keep 22 | constructor( 23 | val language: Language, 24 | val presentation: Presentation, 25 | val circle: Boolean?, 26 | val ratio: Array, 27 | val defaultRatio: CropRatio?, 28 | val freeStyle: Boolean? 29 | ) { 30 | /* main constructor */ 31 | } 32 | -------------------------------------------------------------------------------- /nitrogen/generated/android/kotlin/com/margelo/nitro/multipleimagepicker/NitroPreviewConfig.kt: -------------------------------------------------------------------------------- 1 | /// 2 | /// NitroPreviewConfig.kt 3 | /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. 4 | /// https://github.com/mrousavy/nitro 5 | /// Copyright © 2025 Marc Rousavy @ Margelo 6 | /// 7 | 8 | package com.margelo.nitro.multipleimagepicker 9 | 10 | import androidx.annotation.Keep 11 | import com.facebook.proguard.annotations.DoNotStrip 12 | import com.margelo.nitro.core.* 13 | 14 | /** 15 | * Represents the JavaScript object/struct "NitroPreviewConfig". 16 | */ 17 | @DoNotStrip 18 | @Keep 19 | data class NitroPreviewConfig 20 | @DoNotStrip 21 | @Keep 22 | constructor( 23 | val language: Language, 24 | val videoAutoPlay: Boolean? 25 | ) { 26 | /* main constructor */ 27 | } 28 | -------------------------------------------------------------------------------- /nitrogen/generated/android/kotlin/com/margelo/nitro/multipleimagepicker/PickerCameraConfig.kt: -------------------------------------------------------------------------------- 1 | /// 2 | /// PickerCameraConfig.kt 3 | /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. 4 | /// https://github.com/mrousavy/nitro 5 | /// Copyright © 2025 Marc Rousavy @ Margelo 6 | /// 7 | 8 | package com.margelo.nitro.multipleimagepicker 9 | 10 | import androidx.annotation.Keep 11 | import com.facebook.proguard.annotations.DoNotStrip 12 | import com.margelo.nitro.core.* 13 | 14 | /** 15 | * Represents the JavaScript object/struct "PickerCameraConfig". 16 | */ 17 | @DoNotStrip 18 | @Keep 19 | data class PickerCameraConfig 20 | @DoNotStrip 21 | @Keep 22 | constructor( 23 | val cameraDevice: CameraDevice?, 24 | val videoMaximumDuration: Double? 25 | ) { 26 | /* main constructor */ 27 | } 28 | -------------------------------------------------------------------------------- /nitrogen/generated/android/kotlin/com/margelo/nitro/multipleimagepicker/PickerCropConfig.kt: -------------------------------------------------------------------------------- 1 | /// 2 | /// PickerCropConfig.kt 3 | /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. 4 | /// https://github.com/mrousavy/nitro 5 | /// Copyright © 2025 Marc Rousavy @ Margelo 6 | /// 7 | 8 | package com.margelo.nitro.multipleimagepicker 9 | 10 | import androidx.annotation.Keep 11 | import com.facebook.proguard.annotations.DoNotStrip 12 | import com.margelo.nitro.core.* 13 | 14 | /** 15 | * Represents the JavaScript object/struct "PickerCropConfig". 16 | */ 17 | @DoNotStrip 18 | @Keep 19 | data class PickerCropConfig 20 | @DoNotStrip 21 | @Keep 22 | constructor( 23 | val circle: Boolean?, 24 | val ratio: Array, 25 | val defaultRatio: CropRatio?, 26 | val freeStyle: Boolean? 27 | ) { 28 | /* main constructor */ 29 | } 30 | -------------------------------------------------------------------------------- /nitrogen/generated/android/kotlin/com/margelo/nitro/multipleimagepicker/PickerResult.kt: -------------------------------------------------------------------------------- 1 | /// 2 | /// PickerResult.kt 3 | /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. 4 | /// https://github.com/mrousavy/nitro 5 | /// Copyright © 2025 Marc Rousavy @ Margelo 6 | /// 7 | 8 | package com.margelo.nitro.multipleimagepicker 9 | 10 | import androidx.annotation.Keep 11 | import com.facebook.proguard.annotations.DoNotStrip 12 | import com.margelo.nitro.core.* 13 | 14 | /** 15 | * Represents the JavaScript object/struct "PickerResult". 16 | */ 17 | @DoNotStrip 18 | @Keep 19 | data class PickerResult 20 | @DoNotStrip 21 | @Keep 22 | constructor( 23 | val localIdentifier: String, 24 | val width: Double, 25 | val height: Double, 26 | val mime: String, 27 | val size: Double, 28 | val bucketId: Double?, 29 | val realPath: String?, 30 | val parentFolderName: String?, 31 | val creationDate: Double?, 32 | val crop: Boolean?, 33 | val path: String, 34 | val type: ResultType, 35 | val duration: Double?, 36 | val thumbnail: String?, 37 | val fileName: String? 38 | ) { 39 | /* main constructor */ 40 | } 41 | -------------------------------------------------------------------------------- /nitrogen/generated/android/kotlin/com/margelo/nitro/multipleimagepicker/Presentation.kt: -------------------------------------------------------------------------------- 1 | /// 2 | /// Presentation.kt 3 | /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. 4 | /// https://github.com/mrousavy/nitro 5 | /// Copyright © 2025 Marc Rousavy @ Margelo 6 | /// 7 | 8 | package com.margelo.nitro.multipleimagepicker 9 | 10 | import androidx.annotation.Keep 11 | import com.facebook.proguard.annotations.DoNotStrip 12 | 13 | /** 14 | * Represents the JavaScript enum/union "Presentation". 15 | */ 16 | @DoNotStrip 17 | @Keep 18 | enum class Presentation { 19 | FULLSCREENMODAL, 20 | FORMSHEET; 21 | 22 | @DoNotStrip 23 | @Keep 24 | private val _ordinal = ordinal 25 | } 26 | -------------------------------------------------------------------------------- /nitrogen/generated/android/kotlin/com/margelo/nitro/multipleimagepicker/ResultType.kt: -------------------------------------------------------------------------------- 1 | /// 2 | /// ResultType.kt 3 | /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. 4 | /// https://github.com/mrousavy/nitro 5 | /// Copyright © 2025 Marc Rousavy @ Margelo 6 | /// 7 | 8 | package com.margelo.nitro.multipleimagepicker 9 | 10 | import androidx.annotation.Keep 11 | import com.facebook.proguard.annotations.DoNotStrip 12 | 13 | /** 14 | * Represents the JavaScript enum/union "ResultType". 15 | */ 16 | @DoNotStrip 17 | @Keep 18 | enum class ResultType { 19 | VIDEO, 20 | IMAGE; 21 | 22 | @DoNotStrip 23 | @Keep 24 | private val _ordinal = ordinal 25 | } 26 | -------------------------------------------------------------------------------- /nitrogen/generated/android/kotlin/com/margelo/nitro/multipleimagepicker/SelectBoxStyle.kt: -------------------------------------------------------------------------------- 1 | /// 2 | /// SelectBoxStyle.kt 3 | /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. 4 | /// https://github.com/mrousavy/nitro 5 | /// Copyright © 2025 Marc Rousavy @ Margelo 6 | /// 7 | 8 | package com.margelo.nitro.multipleimagepicker 9 | 10 | import androidx.annotation.Keep 11 | import com.facebook.proguard.annotations.DoNotStrip 12 | 13 | /** 14 | * Represents the JavaScript enum/union "SelectBoxStyle". 15 | */ 16 | @DoNotStrip 17 | @Keep 18 | enum class SelectBoxStyle { 19 | NUMBER, 20 | TICK; 21 | 22 | @DoNotStrip 23 | @Keep 24 | private val _ordinal = ordinal 25 | } 26 | -------------------------------------------------------------------------------- /nitrogen/generated/android/kotlin/com/margelo/nitro/multipleimagepicker/SelectMode.kt: -------------------------------------------------------------------------------- 1 | /// 2 | /// SelectMode.kt 3 | /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. 4 | /// https://github.com/mrousavy/nitro 5 | /// Copyright © 2025 Marc Rousavy @ Margelo 6 | /// 7 | 8 | package com.margelo.nitro.multipleimagepicker 9 | 10 | import androidx.annotation.Keep 11 | import com.facebook.proguard.annotations.DoNotStrip 12 | 13 | /** 14 | * Represents the JavaScript enum/union "SelectMode". 15 | */ 16 | @DoNotStrip 17 | @Keep 18 | enum class SelectMode { 19 | SINGLE, 20 | MULTIPLE; 21 | 22 | @DoNotStrip 23 | @Keep 24 | private val _ordinal = ordinal 25 | } 26 | -------------------------------------------------------------------------------- /nitrogen/generated/android/kotlin/com/margelo/nitro/multipleimagepicker/Text.kt: -------------------------------------------------------------------------------- 1 | /// 2 | /// Text.kt 3 | /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. 4 | /// https://github.com/mrousavy/nitro 5 | /// Copyright © 2025 Marc Rousavy @ Margelo 6 | /// 7 | 8 | package com.margelo.nitro.multipleimagepicker 9 | 10 | import androidx.annotation.Keep 11 | import com.facebook.proguard.annotations.DoNotStrip 12 | import com.margelo.nitro.core.* 13 | 14 | /** 15 | * Represents the JavaScript object/struct "Text". 16 | */ 17 | @DoNotStrip 18 | @Keep 19 | data class Text 20 | @DoNotStrip 21 | @Keep 22 | constructor( 23 | val finish: String?, 24 | val original: String?, 25 | val preview: String?, 26 | val edit: String? 27 | ) { 28 | /* main constructor */ 29 | } 30 | -------------------------------------------------------------------------------- /nitrogen/generated/android/kotlin/com/margelo/nitro/multipleimagepicker/Theme.kt: -------------------------------------------------------------------------------- 1 | /// 2 | /// Theme.kt 3 | /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. 4 | /// https://github.com/mrousavy/nitro 5 | /// Copyright © 2025 Marc Rousavy @ Margelo 6 | /// 7 | 8 | package com.margelo.nitro.multipleimagepicker 9 | 10 | import androidx.annotation.Keep 11 | import com.facebook.proguard.annotations.DoNotStrip 12 | 13 | /** 14 | * Represents the JavaScript enum/union "Theme". 15 | */ 16 | @DoNotStrip 17 | @Keep 18 | enum class Theme { 19 | LIGHT, 20 | DARK; 21 | 22 | @DoNotStrip 23 | @Keep 24 | private val _ordinal = ordinal 25 | } 26 | -------------------------------------------------------------------------------- /nitrogen/generated/ios/MultipleImagePicker+autolinking.rb: -------------------------------------------------------------------------------- 1 | # 2 | # MultipleImagePicker+autolinking.rb 3 | # This file was generated by nitrogen. DO NOT MODIFY THIS FILE. 4 | # https://github.com/mrousavy/nitro 5 | # Copyright © 2025 Marc Rousavy @ Margelo 6 | # 7 | 8 | # This is a Ruby script that adds all files generated by Nitrogen 9 | # to the given podspec. 10 | # 11 | # To use it, add this to your .podspec: 12 | # ```ruby 13 | # Pod::Spec.new do |spec| 14 | # # ... 15 | # 16 | # # Add all files generated by Nitrogen 17 | # load 'nitrogen/generated/ios/MultipleImagePicker+autolinking.rb' 18 | # add_nitrogen_files(spec) 19 | # end 20 | # ``` 21 | 22 | def add_nitrogen_files(spec) 23 | Pod::UI.puts "[NitroModules] 🔥 MultipleImagePicker is boosted by nitro!" 24 | 25 | spec.dependency "NitroModules" 26 | 27 | current_source_files = Array(spec.attributes_hash['source_files']) 28 | spec.source_files = current_source_files + [ 29 | # Generated cross-platform specs 30 | "nitrogen/generated/shared/**/*.{h,hpp,c,cpp,swift}", 31 | # Generated bridges for the cross-platform specs 32 | "nitrogen/generated/ios/**/*.{h,hpp,c,cpp,mm,swift}", 33 | ] 34 | 35 | current_public_header_files = Array(spec.attributes_hash['public_header_files']) 36 | spec.public_header_files = current_public_header_files + [ 37 | # Generated specs 38 | "nitrogen/generated/shared/**/*.{h,hpp}", 39 | # Swift to C++ bridging helpers 40 | "nitrogen/generated/ios/MultipleImagePicker-Swift-Cxx-Bridge.hpp" 41 | ] 42 | 43 | current_private_header_files = Array(spec.attributes_hash['private_header_files']) 44 | spec.private_header_files = current_private_header_files + [ 45 | # iOS specific specs 46 | "nitrogen/generated/ios/c++/**/*.{h,hpp}", 47 | # Views are framework-specific and should be private 48 | "nitrogen/generated/shared/**/views/**/*" 49 | ] 50 | 51 | current_pod_target_xcconfig = spec.attributes_hash['pod_target_xcconfig'] || {} 52 | spec.pod_target_xcconfig = current_pod_target_xcconfig.merge({ 53 | # Use C++ 20 54 | "CLANG_CXX_LANGUAGE_STANDARD" => "c++20", 55 | # Enables C++ <-> Swift interop (by default it's only C) 56 | "SWIFT_OBJC_INTEROP_MODE" => "objcxx", 57 | # Enables stricter modular headers 58 | "DEFINES_MODULE" => "YES", 59 | }) 60 | end 61 | -------------------------------------------------------------------------------- /nitrogen/generated/ios/MultipleImagePickerAutolinking.mm: -------------------------------------------------------------------------------- 1 | /// 2 | /// MultipleImagePickerAutolinking.mm 3 | /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. 4 | /// https://github.com/mrousavy/nitro 5 | /// Copyright © 2025 Marc Rousavy @ Margelo 6 | /// 7 | 8 | #import 9 | #import 10 | #import "MultipleImagePicker-Swift-Cxx-Umbrella.hpp" 11 | #import 12 | 13 | #include "HybridMultipleImagePickerSpecSwift.hpp" 14 | 15 | @interface MultipleImagePickerAutolinking : NSObject 16 | @end 17 | 18 | @implementation MultipleImagePickerAutolinking 19 | 20 | + (void) load { 21 | using namespace margelo::nitro; 22 | using namespace margelo::nitro::multipleimagepicker; 23 | 24 | HybridObjectRegistry::registerHybridObjectConstructor( 25 | "MultipleImagePicker", 26 | []() -> std::shared_ptr { 27 | std::shared_ptr hybridObject = MultipleImagePicker::MultipleImagePickerAutolinking::createMultipleImagePicker(); 28 | return hybridObject; 29 | } 30 | ); 31 | } 32 | 33 | @end 34 | -------------------------------------------------------------------------------- /nitrogen/generated/ios/MultipleImagePickerAutolinking.swift: -------------------------------------------------------------------------------- 1 | /// 2 | /// MultipleImagePickerAutolinking.swift 3 | /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. 4 | /// https://github.com/mrousavy/nitro 5 | /// Copyright © 2025 Marc Rousavy @ Margelo 6 | /// 7 | 8 | public final class MultipleImagePickerAutolinking { 9 | public typealias bridge = margelo.nitro.multipleimagepicker.bridge.swift 10 | 11 | /** 12 | * Creates an instance of a Swift class that implements `HybridMultipleImagePickerSpec`, 13 | * and wraps it in a Swift class that can directly interop with C++ (`HybridMultipleImagePickerSpec_cxx`) 14 | * 15 | * This is generated by Nitrogen and will initialize the class specified 16 | * in the `"autolinking"` property of `nitro.json` (in this case, `HybridMultipleImagePicker`). 17 | */ 18 | public static func createMultipleImagePicker() -> bridge.std__shared_ptr_margelo__nitro__multipleimagepicker__HybridMultipleImagePickerSpec_ { 19 | let hybridObject = HybridMultipleImagePicker() 20 | return { () -> bridge.std__shared_ptr_margelo__nitro__multipleimagepicker__HybridMultipleImagePickerSpec_ in 21 | let __cxxWrapped = hybridObject.getCxxWrapper() 22 | return __cxxWrapped.getCxxPart() 23 | }() 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /nitrogen/generated/ios/c++/HybridMultipleImagePickerSpecSwift.cpp: -------------------------------------------------------------------------------- 1 | /// 2 | /// HybridMultipleImagePickerSpecSwift.cpp 3 | /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. 4 | /// https://github.com/mrousavy/nitro 5 | /// Copyright © 2025 Marc Rousavy @ Margelo 6 | /// 7 | 8 | #include "HybridMultipleImagePickerSpecSwift.hpp" 9 | 10 | namespace margelo::nitro::multipleimagepicker { 11 | } // namespace margelo::nitro::multipleimagepicker 12 | -------------------------------------------------------------------------------- /nitrogen/generated/ios/swift/CameraDevice.swift: -------------------------------------------------------------------------------- 1 | /// 2 | /// CameraDevice.swift 3 | /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. 4 | /// https://github.com/mrousavy/nitro 5 | /// Copyright © 2025 Marc Rousavy @ Margelo 6 | /// 7 | 8 | /** 9 | * Represents the JS union `CameraDevice`, backed by a C++ enum. 10 | */ 11 | public typealias CameraDevice = margelo.nitro.multipleimagepicker.CameraDevice 12 | 13 | public extension CameraDevice { 14 | /** 15 | * Get a CameraDevice for the given String value, or 16 | * return `nil` if the given value was invalid/unknown. 17 | */ 18 | init?(fromString string: String) { 19 | switch string { 20 | case "front": 21 | self = .front 22 | case "back": 23 | self = .back 24 | default: 25 | return nil 26 | } 27 | } 28 | 29 | /** 30 | * Get the String value this CameraDevice represents. 31 | */ 32 | var stringValue: String { 33 | switch self { 34 | case .front: 35 | return "front" 36 | case .back: 37 | return "back" 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /nitrogen/generated/ios/swift/CropRatio.swift: -------------------------------------------------------------------------------- 1 | /// 2 | /// CropRatio.swift 3 | /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. 4 | /// https://github.com/mrousavy/nitro 5 | /// Copyright © 2025 Marc Rousavy @ Margelo 6 | /// 7 | 8 | import NitroModules 9 | 10 | /** 11 | * Represents an instance of `CropRatio`, backed by a C++ struct. 12 | */ 13 | public typealias CropRatio = margelo.nitro.multipleimagepicker.CropRatio 14 | 15 | public extension CropRatio { 16 | private typealias bridge = margelo.nitro.multipleimagepicker.bridge.swift 17 | 18 | /** 19 | * Create a new instance of `CropRatio`. 20 | */ 21 | init(title: String?, width: Double, height: Double) { 22 | self.init({ () -> bridge.std__optional_std__string_ in 23 | if let __unwrappedValue = title { 24 | return bridge.create_std__optional_std__string_(std.string(__unwrappedValue)) 25 | } else { 26 | return .init() 27 | } 28 | }(), width, height) 29 | } 30 | 31 | var title: String? { 32 | @inline(__always) 33 | get { 34 | return { () -> String? in 35 | if let __unwrapped = self.__title.value { 36 | return String(__unwrapped) 37 | } else { 38 | return nil 39 | } 40 | }() 41 | } 42 | @inline(__always) 43 | set { 44 | self.__title = { () -> bridge.std__optional_std__string_ in 45 | if let __unwrappedValue = newValue { 46 | return bridge.create_std__optional_std__string_(std.string(__unwrappedValue)) 47 | } else { 48 | return .init() 49 | } 50 | }() 51 | } 52 | } 53 | 54 | var width: Double { 55 | @inline(__always) 56 | get { 57 | return self.__width 58 | } 59 | @inline(__always) 60 | set { 61 | self.__width = newValue 62 | } 63 | } 64 | 65 | var height: Double { 66 | @inline(__always) 67 | get { 68 | return self.__height 69 | } 70 | @inline(__always) 71 | set { 72 | self.__height = newValue 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /nitrogen/generated/ios/swift/CropResult.swift: -------------------------------------------------------------------------------- 1 | /// 2 | /// CropResult.swift 3 | /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. 4 | /// https://github.com/mrousavy/nitro 5 | /// Copyright © 2025 Marc Rousavy @ Margelo 6 | /// 7 | 8 | import NitroModules 9 | 10 | /** 11 | * Represents an instance of `CropResult`, backed by a C++ struct. 12 | */ 13 | public typealias CropResult = margelo.nitro.multipleimagepicker.CropResult 14 | 15 | public extension CropResult { 16 | private typealias bridge = margelo.nitro.multipleimagepicker.bridge.swift 17 | 18 | /** 19 | * Create a new instance of `CropResult`. 20 | */ 21 | init(path: String, width: Double, height: Double) { 22 | self.init(std.string(path), width, height) 23 | } 24 | 25 | var path: String { 26 | @inline(__always) 27 | get { 28 | return String(self.__path) 29 | } 30 | @inline(__always) 31 | set { 32 | self.__path = std.string(newValue) 33 | } 34 | } 35 | 36 | var width: Double { 37 | @inline(__always) 38 | get { 39 | return self.__width 40 | } 41 | @inline(__always) 42 | set { 43 | self.__width = newValue 44 | } 45 | } 46 | 47 | var height: Double { 48 | @inline(__always) 49 | get { 50 | return self.__height 51 | } 52 | @inline(__always) 53 | set { 54 | self.__height = newValue 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /nitrogen/generated/ios/swift/Func_void_CameraResult.swift: -------------------------------------------------------------------------------- 1 | /// 2 | /// Func_void_CameraResult.swift 3 | /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. 4 | /// https://github.com/mrousavy/nitro 5 | /// Copyright © 2025 Marc Rousavy @ Margelo 6 | /// 7 | 8 | import NitroModules 9 | 10 | /** 11 | * Wraps a Swift `(_ result: CameraResult) -> Void` as a class. 12 | * This class can be used from C++, e.g. to wrap the Swift closure as a `std::function`. 13 | */ 14 | public final class Func_void_CameraResult { 15 | public typealias bridge = margelo.nitro.multipleimagepicker.bridge.swift 16 | 17 | private let closure: (_ result: CameraResult) -> Void 18 | 19 | public init(_ closure: @escaping (_ result: CameraResult) -> Void) { 20 | self.closure = closure 21 | } 22 | 23 | @inline(__always) 24 | public func call(result: CameraResult) -> Void { 25 | self.closure(result) 26 | } 27 | 28 | /** 29 | * Casts this instance to a retained unsafe raw pointer. 30 | * This acquires one additional strong reference on the object! 31 | */ 32 | @inline(__always) 33 | public func toUnsafe() -> UnsafeMutableRawPointer { 34 | return Unmanaged.passRetained(self).toOpaque() 35 | } 36 | 37 | /** 38 | * Casts an unsafe pointer to a `Func_void_CameraResult`. 39 | * The pointer has to be a retained opaque `Unmanaged`. 40 | * This removes one strong reference from the object! 41 | */ 42 | @inline(__always) 43 | public static func fromUnsafe(_ pointer: UnsafeMutableRawPointer) -> Func_void_CameraResult { 44 | return Unmanaged.fromOpaque(pointer).takeRetainedValue() 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /nitrogen/generated/ios/swift/Func_void_CropResult.swift: -------------------------------------------------------------------------------- 1 | /// 2 | /// Func_void_CropResult.swift 3 | /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. 4 | /// https://github.com/mrousavy/nitro 5 | /// Copyright © 2025 Marc Rousavy @ Margelo 6 | /// 7 | 8 | import NitroModules 9 | 10 | /** 11 | * Wraps a Swift `(_ result: CropResult) -> Void` as a class. 12 | * This class can be used from C++, e.g. to wrap the Swift closure as a `std::function`. 13 | */ 14 | public final class Func_void_CropResult { 15 | public typealias bridge = margelo.nitro.multipleimagepicker.bridge.swift 16 | 17 | private let closure: (_ result: CropResult) -> Void 18 | 19 | public init(_ closure: @escaping (_ result: CropResult) -> Void) { 20 | self.closure = closure 21 | } 22 | 23 | @inline(__always) 24 | public func call(result: CropResult) -> Void { 25 | self.closure(result) 26 | } 27 | 28 | /** 29 | * Casts this instance to a retained unsafe raw pointer. 30 | * This acquires one additional strong reference on the object! 31 | */ 32 | @inline(__always) 33 | public func toUnsafe() -> UnsafeMutableRawPointer { 34 | return Unmanaged.passRetained(self).toOpaque() 35 | } 36 | 37 | /** 38 | * Casts an unsafe pointer to a `Func_void_CropResult`. 39 | * The pointer has to be a retained opaque `Unmanaged`. 40 | * This removes one strong reference from the object! 41 | */ 42 | @inline(__always) 43 | public static func fromUnsafe(_ pointer: UnsafeMutableRawPointer) -> Func_void_CropResult { 44 | return Unmanaged.fromOpaque(pointer).takeRetainedValue() 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /nitrogen/generated/ios/swift/Func_void_double.swift: -------------------------------------------------------------------------------- 1 | /// 2 | /// Func_void_double.swift 3 | /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. 4 | /// https://github.com/mrousavy/nitro 5 | /// Copyright © 2025 Marc Rousavy @ Margelo 6 | /// 7 | 8 | import NitroModules 9 | 10 | /** 11 | * Wraps a Swift `(_ index: Double) -> Void` as a class. 12 | * This class can be used from C++, e.g. to wrap the Swift closure as a `std::function`. 13 | */ 14 | public final class Func_void_double { 15 | public typealias bridge = margelo.nitro.multipleimagepicker.bridge.swift 16 | 17 | private let closure: (_ index: Double) -> Void 18 | 19 | public init(_ closure: @escaping (_ index: Double) -> Void) { 20 | self.closure = closure 21 | } 22 | 23 | @inline(__always) 24 | public func call(index: Double) -> Void { 25 | self.closure(index) 26 | } 27 | 28 | /** 29 | * Casts this instance to a retained unsafe raw pointer. 30 | * This acquires one additional strong reference on the object! 31 | */ 32 | @inline(__always) 33 | public func toUnsafe() -> UnsafeMutableRawPointer { 34 | return Unmanaged.passRetained(self).toOpaque() 35 | } 36 | 37 | /** 38 | * Casts an unsafe pointer to a `Func_void_double`. 39 | * The pointer has to be a retained opaque `Unmanaged`. 40 | * This removes one strong reference from the object! 41 | */ 42 | @inline(__always) 43 | public static func fromUnsafe(_ pointer: UnsafeMutableRawPointer) -> Func_void_double { 44 | return Unmanaged.fromOpaque(pointer).takeRetainedValue() 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /nitrogen/generated/ios/swift/Func_void_std__vector_PickerResult_.swift: -------------------------------------------------------------------------------- 1 | /// 2 | /// Func_void_std__vector_PickerResult_.swift 3 | /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. 4 | /// https://github.com/mrousavy/nitro 5 | /// Copyright © 2025 Marc Rousavy @ Margelo 6 | /// 7 | 8 | import NitroModules 9 | 10 | /** 11 | * Wraps a Swift `(_ result: [PickerResult]) -> Void` as a class. 12 | * This class can be used from C++, e.g. to wrap the Swift closure as a `std::function`. 13 | */ 14 | public final class Func_void_std__vector_PickerResult_ { 15 | public typealias bridge = margelo.nitro.multipleimagepicker.bridge.swift 16 | 17 | private let closure: (_ result: [PickerResult]) -> Void 18 | 19 | public init(_ closure: @escaping (_ result: [PickerResult]) -> Void) { 20 | self.closure = closure 21 | } 22 | 23 | @inline(__always) 24 | public func call(result: bridge.std__vector_PickerResult_) -> Void { 25 | self.closure(result.map({ __item in __item })) 26 | } 27 | 28 | /** 29 | * Casts this instance to a retained unsafe raw pointer. 30 | * This acquires one additional strong reference on the object! 31 | */ 32 | @inline(__always) 33 | public func toUnsafe() -> UnsafeMutableRawPointer { 34 | return Unmanaged.passRetained(self).toOpaque() 35 | } 36 | 37 | /** 38 | * Casts an unsafe pointer to a `Func_void_std__vector_PickerResult_`. 39 | * The pointer has to be a retained opaque `Unmanaged`. 40 | * This removes one strong reference from the object! 41 | */ 42 | @inline(__always) 43 | public static func fromUnsafe(_ pointer: UnsafeMutableRawPointer) -> Func_void_std__vector_PickerResult_ { 44 | return Unmanaged.fromOpaque(pointer).takeRetainedValue() 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /nitrogen/generated/ios/swift/HybridMultipleImagePickerSpec.swift: -------------------------------------------------------------------------------- 1 | /// 2 | /// HybridMultipleImagePickerSpec.swift 3 | /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. 4 | /// https://github.com/mrousavy/nitro 5 | /// Copyright © 2025 Marc Rousavy @ Margelo 6 | /// 7 | 8 | import Foundation 9 | import NitroModules 10 | 11 | /// See ``HybridMultipleImagePickerSpec`` 12 | public protocol HybridMultipleImagePickerSpec_protocol: HybridObject { 13 | // Properties 14 | 15 | 16 | // Methods 17 | func openPicker(config: NitroConfig, resolved: @escaping (_ result: [PickerResult]) -> Void, rejected: @escaping (_ reject: Double) -> Void) throws -> Void 18 | func openCrop(image: String, config: NitroCropConfig, resolved: @escaping (_ result: CropResult) -> Void, rejected: @escaping (_ reject: Double) -> Void) throws -> Void 19 | func openPreview(media: [MediaPreview], index: Double, config: NitroPreviewConfig, onLongPress: @escaping (_ index: Double) -> Void) throws -> Void 20 | func openCamera(config: NitroCameraConfig, resolved: @escaping (_ result: CameraResult) -> Void, rejected: @escaping (_ reject: Double) -> Void) throws -> Void 21 | } 22 | 23 | /// See ``HybridMultipleImagePickerSpec`` 24 | public class HybridMultipleImagePickerSpec_base { 25 | private weak var cxxWrapper: HybridMultipleImagePickerSpec_cxx? = nil 26 | public func getCxxWrapper() -> HybridMultipleImagePickerSpec_cxx { 27 | #if DEBUG 28 | guard self is HybridMultipleImagePickerSpec else { 29 | fatalError("`self` is not a `HybridMultipleImagePickerSpec`! Did you accidentally inherit from `HybridMultipleImagePickerSpec_base` instead of `HybridMultipleImagePickerSpec`?") 30 | } 31 | #endif 32 | if let cxxWrapper = self.cxxWrapper { 33 | return cxxWrapper 34 | } else { 35 | let cxxWrapper = HybridMultipleImagePickerSpec_cxx(self as! HybridMultipleImagePickerSpec) 36 | self.cxxWrapper = cxxWrapper 37 | return cxxWrapper 38 | } 39 | } 40 | } 41 | 42 | /** 43 | * A Swift base-protocol representing the MultipleImagePicker HybridObject. 44 | * Implement this protocol to create Swift-based instances of MultipleImagePicker. 45 | * ```swift 46 | * class HybridMultipleImagePicker : HybridMultipleImagePickerSpec { 47 | * // ... 48 | * } 49 | * ``` 50 | */ 51 | public typealias HybridMultipleImagePickerSpec = HybridMultipleImagePickerSpec_protocol & HybridMultipleImagePickerSpec_base 52 | -------------------------------------------------------------------------------- /nitrogen/generated/ios/swift/Language.swift: -------------------------------------------------------------------------------- 1 | /// 2 | /// Language.swift 3 | /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. 4 | /// https://github.com/mrousavy/nitro 5 | /// Copyright © 2025 Marc Rousavy @ Margelo 6 | /// 7 | 8 | /** 9 | * Represents the JS union `Language`, backed by a C++ enum. 10 | */ 11 | public typealias Language = margelo.nitro.multipleimagepicker.Language 12 | 13 | public extension Language { 14 | /** 15 | * Get a Language for the given String value, or 16 | * return `nil` if the given value was invalid/unknown. 17 | */ 18 | init?(fromString string: String) { 19 | switch string { 20 | case "system": 21 | self = .system 22 | case "zh-Hans": 23 | self = .zhHans 24 | case "zh-Hant": 25 | self = .zhHant 26 | case "ja": 27 | self = .ja 28 | case "ko": 29 | self = .ko 30 | case "en": 31 | self = .en 32 | case "th": 33 | self = .th 34 | case "id": 35 | self = .id 36 | case "vi": 37 | self = .vi 38 | case "ru": 39 | self = .ru 40 | case "de": 41 | self = .de 42 | case "fr": 43 | self = .fr 44 | case "ar": 45 | self = .ar 46 | default: 47 | return nil 48 | } 49 | } 50 | 51 | /** 52 | * Get the String value this Language represents. 53 | */ 54 | var stringValue: String { 55 | switch self { 56 | case .system: 57 | return "system" 58 | case .zhHans: 59 | return "zh-Hans" 60 | case .zhHant: 61 | return "zh-Hant" 62 | case .ja: 63 | return "ja" 64 | case .ko: 65 | return "ko" 66 | case .en: 67 | return "en" 68 | case .th: 69 | return "th" 70 | case .id: 71 | return "id" 72 | case .vi: 73 | return "vi" 74 | case .ru: 75 | return "ru" 76 | case .de: 77 | return "de" 78 | case .fr: 79 | return "fr" 80 | case .ar: 81 | return "ar" 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /nitrogen/generated/ios/swift/MediaType.swift: -------------------------------------------------------------------------------- 1 | /// 2 | /// MediaType.swift 3 | /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. 4 | /// https://github.com/mrousavy/nitro 5 | /// Copyright © 2025 Marc Rousavy @ Margelo 6 | /// 7 | 8 | /** 9 | * Represents the JS union `MediaType`, backed by a C++ enum. 10 | */ 11 | public typealias MediaType = margelo.nitro.multipleimagepicker.MediaType 12 | 13 | public extension MediaType { 14 | /** 15 | * Get a MediaType for the given String value, or 16 | * return `nil` if the given value was invalid/unknown. 17 | */ 18 | init?(fromString string: String) { 19 | switch string { 20 | case "video": 21 | self = .video 22 | case "image": 23 | self = .image 24 | case "all": 25 | self = .all 26 | default: 27 | return nil 28 | } 29 | } 30 | 31 | /** 32 | * Get the String value this MediaType represents. 33 | */ 34 | var stringValue: String { 35 | switch self { 36 | case .video: 37 | return "video" 38 | case .image: 39 | return "image" 40 | case .all: 41 | return "all" 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /nitrogen/generated/ios/swift/NitroPreviewConfig.swift: -------------------------------------------------------------------------------- 1 | /// 2 | /// NitroPreviewConfig.swift 3 | /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. 4 | /// https://github.com/mrousavy/nitro 5 | /// Copyright © 2025 Marc Rousavy @ Margelo 6 | /// 7 | 8 | import NitroModules 9 | 10 | /** 11 | * Represents an instance of `NitroPreviewConfig`, backed by a C++ struct. 12 | */ 13 | public typealias NitroPreviewConfig = margelo.nitro.multipleimagepicker.NitroPreviewConfig 14 | 15 | public extension NitroPreviewConfig { 16 | private typealias bridge = margelo.nitro.multipleimagepicker.bridge.swift 17 | 18 | /** 19 | * Create a new instance of `NitroPreviewConfig`. 20 | */ 21 | init(language: Language, videoAutoPlay: Bool?) { 22 | self.init(language, { () -> bridge.std__optional_bool_ in 23 | if let __unwrappedValue = videoAutoPlay { 24 | return bridge.create_std__optional_bool_(__unwrappedValue) 25 | } else { 26 | return .init() 27 | } 28 | }()) 29 | } 30 | 31 | var language: Language { 32 | @inline(__always) 33 | get { 34 | return self.__language 35 | } 36 | @inline(__always) 37 | set { 38 | self.__language = newValue 39 | } 40 | } 41 | 42 | var videoAutoPlay: Bool? { 43 | @inline(__always) 44 | get { 45 | return self.__videoAutoPlay.value 46 | } 47 | @inline(__always) 48 | set { 49 | self.__videoAutoPlay = { () -> bridge.std__optional_bool_ in 50 | if let __unwrappedValue = newValue { 51 | return bridge.create_std__optional_bool_(__unwrappedValue) 52 | } else { 53 | return .init() 54 | } 55 | }() 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /nitrogen/generated/ios/swift/PickerCameraConfig.swift: -------------------------------------------------------------------------------- 1 | /// 2 | /// PickerCameraConfig.swift 3 | /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. 4 | /// https://github.com/mrousavy/nitro 5 | /// Copyright © 2025 Marc Rousavy @ Margelo 6 | /// 7 | 8 | import NitroModules 9 | 10 | /** 11 | * Represents an instance of `PickerCameraConfig`, backed by a C++ struct. 12 | */ 13 | public typealias PickerCameraConfig = margelo.nitro.multipleimagepicker.PickerCameraConfig 14 | 15 | public extension PickerCameraConfig { 16 | private typealias bridge = margelo.nitro.multipleimagepicker.bridge.swift 17 | 18 | /** 19 | * Create a new instance of `PickerCameraConfig`. 20 | */ 21 | init(cameraDevice: CameraDevice?, videoMaximumDuration: Double?) { 22 | self.init({ () -> bridge.std__optional_CameraDevice_ in 23 | if let __unwrappedValue = cameraDevice { 24 | return bridge.create_std__optional_CameraDevice_(__unwrappedValue) 25 | } else { 26 | return .init() 27 | } 28 | }(), { () -> bridge.std__optional_double_ in 29 | if let __unwrappedValue = videoMaximumDuration { 30 | return bridge.create_std__optional_double_(__unwrappedValue) 31 | } else { 32 | return .init() 33 | } 34 | }()) 35 | } 36 | 37 | var cameraDevice: CameraDevice? { 38 | @inline(__always) 39 | get { 40 | return self.__cameraDevice.value 41 | } 42 | @inline(__always) 43 | set { 44 | self.__cameraDevice = { () -> bridge.std__optional_CameraDevice_ in 45 | if let __unwrappedValue = newValue { 46 | return bridge.create_std__optional_CameraDevice_(__unwrappedValue) 47 | } else { 48 | return .init() 49 | } 50 | }() 51 | } 52 | } 53 | 54 | var videoMaximumDuration: Double? { 55 | @inline(__always) 56 | get { 57 | return self.__videoMaximumDuration.value 58 | } 59 | @inline(__always) 60 | set { 61 | self.__videoMaximumDuration = { () -> bridge.std__optional_double_ in 62 | if let __unwrappedValue = newValue { 63 | return bridge.create_std__optional_double_(__unwrappedValue) 64 | } else { 65 | return .init() 66 | } 67 | }() 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /nitrogen/generated/ios/swift/Presentation.swift: -------------------------------------------------------------------------------- 1 | /// 2 | /// Presentation.swift 3 | /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. 4 | /// https://github.com/mrousavy/nitro 5 | /// Copyright © 2025 Marc Rousavy @ Margelo 6 | /// 7 | 8 | /** 9 | * Represents the JS union `Presentation`, backed by a C++ enum. 10 | */ 11 | public typealias Presentation = margelo.nitro.multipleimagepicker.Presentation 12 | 13 | public extension Presentation { 14 | /** 15 | * Get a Presentation for the given String value, or 16 | * return `nil` if the given value was invalid/unknown. 17 | */ 18 | init?(fromString string: String) { 19 | switch string { 20 | case "fullScreenModal": 21 | self = .fullscreenmodal 22 | case "formSheet": 23 | self = .formsheet 24 | default: 25 | return nil 26 | } 27 | } 28 | 29 | /** 30 | * Get the String value this Presentation represents. 31 | */ 32 | var stringValue: String { 33 | switch self { 34 | case .fullscreenmodal: 35 | return "fullScreenModal" 36 | case .formsheet: 37 | return "formSheet" 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /nitrogen/generated/ios/swift/ResultType.swift: -------------------------------------------------------------------------------- 1 | /// 2 | /// ResultType.swift 3 | /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. 4 | /// https://github.com/mrousavy/nitro 5 | /// Copyright © 2025 Marc Rousavy @ Margelo 6 | /// 7 | 8 | /** 9 | * Represents the JS union `ResultType`, backed by a C++ enum. 10 | */ 11 | public typealias ResultType = margelo.nitro.multipleimagepicker.ResultType 12 | 13 | public extension ResultType { 14 | /** 15 | * Get a ResultType for the given String value, or 16 | * return `nil` if the given value was invalid/unknown. 17 | */ 18 | init?(fromString string: String) { 19 | switch string { 20 | case "video": 21 | self = .video 22 | case "image": 23 | self = .image 24 | default: 25 | return nil 26 | } 27 | } 28 | 29 | /** 30 | * Get the String value this ResultType represents. 31 | */ 32 | var stringValue: String { 33 | switch self { 34 | case .video: 35 | return "video" 36 | case .image: 37 | return "image" 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /nitrogen/generated/ios/swift/SelectBoxStyle.swift: -------------------------------------------------------------------------------- 1 | /// 2 | /// SelectBoxStyle.swift 3 | /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. 4 | /// https://github.com/mrousavy/nitro 5 | /// Copyright © 2025 Marc Rousavy @ Margelo 6 | /// 7 | 8 | /** 9 | * Represents the JS union `SelectBoxStyle`, backed by a C++ enum. 10 | */ 11 | public typealias SelectBoxStyle = margelo.nitro.multipleimagepicker.SelectBoxStyle 12 | 13 | public extension SelectBoxStyle { 14 | /** 15 | * Get a SelectBoxStyle for the given String value, or 16 | * return `nil` if the given value was invalid/unknown. 17 | */ 18 | init?(fromString string: String) { 19 | switch string { 20 | case "number": 21 | self = .number 22 | case "tick": 23 | self = .tick 24 | default: 25 | return nil 26 | } 27 | } 28 | 29 | /** 30 | * Get the String value this SelectBoxStyle represents. 31 | */ 32 | var stringValue: String { 33 | switch self { 34 | case .number: 35 | return "number" 36 | case .tick: 37 | return "tick" 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /nitrogen/generated/ios/swift/SelectMode.swift: -------------------------------------------------------------------------------- 1 | /// 2 | /// SelectMode.swift 3 | /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. 4 | /// https://github.com/mrousavy/nitro 5 | /// Copyright © 2025 Marc Rousavy @ Margelo 6 | /// 7 | 8 | /** 9 | * Represents the JS union `SelectMode`, backed by a C++ enum. 10 | */ 11 | public typealias SelectMode = margelo.nitro.multipleimagepicker.SelectMode 12 | 13 | public extension SelectMode { 14 | /** 15 | * Get a SelectMode for the given String value, or 16 | * return `nil` if the given value was invalid/unknown. 17 | */ 18 | init?(fromString string: String) { 19 | switch string { 20 | case "single": 21 | self = .single 22 | case "multiple": 23 | self = .multiple 24 | default: 25 | return nil 26 | } 27 | } 28 | 29 | /** 30 | * Get the String value this SelectMode represents. 31 | */ 32 | var stringValue: String { 33 | switch self { 34 | case .single: 35 | return "single" 36 | case .multiple: 37 | return "multiple" 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /nitrogen/generated/ios/swift/Theme.swift: -------------------------------------------------------------------------------- 1 | /// 2 | /// Theme.swift 3 | /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. 4 | /// https://github.com/mrousavy/nitro 5 | /// Copyright © 2025 Marc Rousavy @ Margelo 6 | /// 7 | 8 | /** 9 | * Represents the JS union `Theme`, backed by a C++ enum. 10 | */ 11 | public typealias Theme = margelo.nitro.multipleimagepicker.Theme 12 | 13 | public extension Theme { 14 | /** 15 | * Get a Theme for the given String value, or 16 | * return `nil` if the given value was invalid/unknown. 17 | */ 18 | init?(fromString string: String) { 19 | switch string { 20 | case "light": 21 | self = .light 22 | case "dark": 23 | self = .dark 24 | default: 25 | return nil 26 | } 27 | } 28 | 29 | /** 30 | * Get the String value this Theme represents. 31 | */ 32 | var stringValue: String { 33 | switch self { 34 | case .light: 35 | return "light" 36 | case .dark: 37 | return "dark" 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /nitrogen/generated/shared/c++/HybridMultipleImagePickerSpec.cpp: -------------------------------------------------------------------------------- 1 | /// 2 | /// HybridMultipleImagePickerSpec.cpp 3 | /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. 4 | /// https://github.com/mrousavy/nitro 5 | /// Copyright © 2025 Marc Rousavy @ Margelo 6 | /// 7 | 8 | #include "HybridMultipleImagePickerSpec.hpp" 9 | 10 | namespace margelo::nitro::multipleimagepicker { 11 | 12 | void HybridMultipleImagePickerSpec::loadHybridMethods() { 13 | // load base methods/properties 14 | HybridObject::loadHybridMethods(); 15 | // load custom methods/properties 16 | registerHybrids(this, [](Prototype& prototype) { 17 | prototype.registerHybridMethod("openPicker", &HybridMultipleImagePickerSpec::openPicker); 18 | prototype.registerHybridMethod("openCrop", &HybridMultipleImagePickerSpec::openCrop); 19 | prototype.registerHybridMethod("openPreview", &HybridMultipleImagePickerSpec::openPreview); 20 | prototype.registerHybridMethod("openCamera", &HybridMultipleImagePickerSpec::openCamera); 21 | }); 22 | } 23 | 24 | } // namespace margelo::nitro::multipleimagepicker 25 | -------------------------------------------------------------------------------- /nitrogen/generated/shared/c++/Theme.hpp: -------------------------------------------------------------------------------- 1 | /// 2 | /// Theme.hpp 3 | /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. 4 | /// https://github.com/mrousavy/nitro 5 | /// Copyright © 2025 Marc Rousavy @ Margelo 6 | /// 7 | 8 | #pragma once 9 | 10 | #if __has_include() 11 | #include 12 | #else 13 | #error NitroModules cannot be found! Are you sure you installed NitroModules properly? 14 | #endif 15 | #if __has_include() 16 | #include 17 | #else 18 | #error NitroModules cannot be found! Are you sure you installed NitroModules properly? 19 | #endif 20 | #if __has_include() 21 | #include 22 | #else 23 | #error NitroModules cannot be found! Are you sure you installed NitroModules properly? 24 | #endif 25 | 26 | namespace margelo::nitro::multipleimagepicker { 27 | 28 | /** 29 | * An enum which can be represented as a JavaScript union (Theme). 30 | */ 31 | enum class Theme { 32 | LIGHT SWIFT_NAME(light) = 0, 33 | DARK SWIFT_NAME(dark) = 1, 34 | } CLOSED_ENUM; 35 | 36 | } // namespace margelo::nitro::multipleimagepicker 37 | 38 | namespace margelo::nitro { 39 | 40 | using namespace margelo::nitro::multipleimagepicker; 41 | 42 | // C++ Theme <> JS Theme (union) 43 | template <> 44 | struct JSIConverter final { 45 | static inline Theme fromJSI(jsi::Runtime& runtime, const jsi::Value& arg) { 46 | std::string unionValue = JSIConverter::fromJSI(runtime, arg); 47 | switch (hashString(unionValue.c_str(), unionValue.size())) { 48 | case hashString("light"): return Theme::LIGHT; 49 | case hashString("dark"): return Theme::DARK; 50 | default: [[unlikely]] 51 | throw std::invalid_argument("Cannot convert \"" + unionValue + "\" to enum Theme - invalid value!"); 52 | } 53 | } 54 | static inline jsi::Value toJSI(jsi::Runtime& runtime, Theme arg) { 55 | switch (arg) { 56 | case Theme::LIGHT: return JSIConverter::toJSI(runtime, "light"); 57 | case Theme::DARK: return JSIConverter::toJSI(runtime, "dark"); 58 | default: [[unlikely]] 59 | throw std::invalid_argument("Cannot convert Theme to JS - invalid value: " 60 | + std::to_string(static_cast(arg)) + "!"); 61 | } 62 | } 63 | static inline bool canConvert(jsi::Runtime& runtime, const jsi::Value& value) { 64 | if (!value.isString()) { 65 | return false; 66 | } 67 | std::string unionValue = JSIConverter::fromJSI(runtime, value); 68 | switch (hashString(unionValue.c_str(), unionValue.size())) { 69 | case hashString("light"): 70 | case hashString("dark"): 71 | return true; 72 | default: 73 | return false; 74 | } 75 | } 76 | }; 77 | 78 | } // namespace margelo::nitro 79 | -------------------------------------------------------------------------------- /react-native.config.js: -------------------------------------------------------------------------------- 1 | // https://github.com/react-native-community/cli/blob/main/docs/dependencies.md 2 | 3 | module.exports = { 4 | dependency: { 5 | platforms: { 6 | /** 7 | * @type {import('@react-native-community/cli-types').IOSDependencyParams} 8 | */ 9 | ios: {}, 10 | /** 11 | * @type {import('@react-native-community/cli-types').AndroidDependencyParams} 12 | */ 13 | android: {}, 14 | }, 15 | }, 16 | } 17 | -------------------------------------------------------------------------------- /scripts/bootstrap.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const child_process = require('child_process'); 3 | 4 | const root = path.resolve(__dirname, '..'); 5 | const args = process.argv.slice(2); 6 | const options = { 7 | cwd: process.cwd(), 8 | env: process.env, 9 | stdio: 'inherit', 10 | encoding: 'utf-8', 11 | }; 12 | 13 | let result; 14 | 15 | if (process.cwd() !== root || args.length) { 16 | // We're not in the root of the project, or additional arguments were passed 17 | // In this case, forward the command to `yarn` 18 | result = child_process.spawnSync('yarn', args, options); 19 | } else { 20 | // If `yarn` is run without arguments, perform bootstrap 21 | result = child_process.spawnSync('yarn', ['bootstrap'], options); 22 | } 23 | 24 | process.exitCode = result.status; 25 | -------------------------------------------------------------------------------- /src/specs/MultipleImagePicker.nitro.ts: -------------------------------------------------------------------------------- 1 | import { type HybridObject } from 'react-native-nitro-modules' 2 | import { 3 | CameraResult, 4 | CropResult, 5 | MediaPreview, 6 | NitroCameraConfig, 7 | NitroConfig, 8 | NitroCropConfig, 9 | NitroPreviewConfig, 10 | PickerResult, 11 | } from '../types' 12 | 13 | export interface MultipleImagePicker 14 | extends HybridObject<{ ios: 'swift'; android: 'kotlin' }> { 15 | openPicker( 16 | config: NitroConfig, 17 | resolved: (result: PickerResult[]) => void, 18 | rejected: (reject: number) => void 19 | ): void 20 | 21 | openCrop( 22 | image: string, 23 | config: NitroCropConfig, 24 | resolved: (result: CropResult) => void, 25 | rejected: (reject: number) => void 26 | ): void 27 | 28 | openPreview( 29 | media: MediaPreview[], 30 | index: number, 31 | config: NitroPreviewConfig, 32 | onLongPress: (index: number) => void 33 | ): void 34 | 35 | openCamera( 36 | config: NitroCameraConfig, 37 | resolved: (result: CameraResult) => void, 38 | rejected: (reject: number) => void 39 | ): void 40 | } 41 | -------------------------------------------------------------------------------- /src/types/config.ts: -------------------------------------------------------------------------------- 1 | export type Theme = 'light' | 'dark' 2 | 3 | export type Presentation = 'fullScreenModal' | 'formSheet' 4 | 5 | export type Language = 6 | | 'system' 7 | | 'zh-Hans' 8 | | 'zh-Hant' 9 | | 'ja' 10 | | 'ko' 11 | | 'en' 12 | | 'th' 13 | | 'id' 14 | | 'vi' 15 | | 'ru' 16 | | 'de' 17 | | 'fr' 18 | | 'ar' 19 | 20 | export type MediaType = 'video' | 'image' | 'all' 21 | -------------------------------------------------------------------------------- /src/types/crop.ts: -------------------------------------------------------------------------------- 1 | import { Language, Presentation } from './config' 2 | 3 | export type CropRatio = { title?: string; width: number; height: number } 4 | 5 | /** 6 | * Configuration for image cropping 7 | * @interface PickerCropConfig 8 | */ 9 | export type PickerCropConfig = { 10 | /** Enable circular crop mask */ 11 | circle?: boolean 12 | 13 | ratio: CropRatio[] 14 | 15 | /** 16 | * Default ratio to be selected when opening the crop interface. 17 | * If not specified, the first ratio in the list will be selected. 18 | * 19 | * @platform ios, android 20 | * 21 | * @example 22 | * ```ts 23 | * // Custom ratio without title 24 | * defaultRatio: { width: 4, height: 3 } 25 | */ 26 | defaultRatio?: CropRatio 27 | 28 | /** Enable free style cropping */ 29 | freeStyle?: boolean 30 | } 31 | 32 | // CROP 33 | export interface NitroCropConfig extends PickerCropConfig { 34 | /** 35 | * Interface language 36 | * @type {Language} 37 | */ 38 | language: Language 39 | 40 | presentation: Presentation 41 | } 42 | 43 | export interface CropConfig 44 | extends Omit { 45 | /** 46 | * Language options for the picker. 47 | * 48 | * @platform ios 49 | * 50 | * @description 51 | * - 'system': 🌐 System default 52 | * - 'zh-Hans': 🇨🇳 Simplified Chinese 53 | * - 'zh-Hant': 🇹🇼 Traditional Chinese 54 | * - 'ja': 🇯🇵 Japanese 55 | * - 'ko': 🇰🇷 Korean 56 | * - 'en': 🇬🇧 English 57 | * - 'th': 🇹🇭 Thai 58 | * - 'id': 🇮🇩 Indonesian 59 | * - 'vi': 🇻🇳 Vietnamese (My Country) 60 | * - 'ru': 🇷🇺 Russian 61 | * - 'de': 🇩🇪 German 62 | * - 'fr': 🇫🇷 French 63 | * - 'ar': 🇸🇦 Arabic 64 | */ 65 | language?: Language 66 | 67 | /** 68 | * Array of aspect ratios for image cropping. The ratios will be inserted after the default ratios (Original and Square). 69 | * Android: Maximum: 4 items 70 | * 71 | * @platform ios, android 72 | * 73 | * @property {Array} ratio - Array of custom aspect ratios 74 | * @property {string} [ratio[].title] - Optional display title for the ratio (e.g., "16:9"). If not provided, will use "width/height" 75 | * @property {number} ratio[].width - Width value for aspect ratio 76 | * @property {number} ratio[].height - Height value for aspect ratio 77 | * 78 | * @example 79 | * ```ts 80 | * ratio: [ 81 | * { title: "Instagram", width: 1, height: 1 }, 82 | * { title: "Twitter", width: 16, height: 9 }, 83 | * { width: 12, height: 11 } 84 | * ] 85 | * ``` 86 | */ 87 | ratio?: CropRatio[] 88 | } 89 | 90 | export interface CropResult { 91 | path: string 92 | width: number 93 | height: number 94 | } 95 | -------------------------------------------------------------------------------- /src/types/error.ts: -------------------------------------------------------------------------------- 1 | export enum MultipleImagePickerError { 2 | CANCELLED = 0, 3 | } 4 | 5 | export enum CameraError { 6 | INVALID_OUTPUT_FILE = 1, 7 | } 8 | 9 | export const CropReject = { 10 | 0: { 11 | code: 0, 12 | message: 'Invalid Image', 13 | }, 14 | 1: { 15 | code: 1, 16 | message: 'User Cancelled', 17 | }, 18 | } 19 | -------------------------------------------------------------------------------- /src/types/index.ts: -------------------------------------------------------------------------------- 1 | export * from './result' 2 | export * from './config' 3 | export * from './crop' 4 | export * from './preview' 5 | export * from './picker' 6 | export * from './camera' 7 | -------------------------------------------------------------------------------- /src/types/preview.ts: -------------------------------------------------------------------------------- 1 | import { Language } from './config' 2 | import { ResultType } from './result' 3 | 4 | // PREVIEW 5 | export type NitroPreviewConfig = { 6 | language: Language 7 | 8 | /** 9 | * Auto play video when open preview. 10 | * 11 | * @platform iOS, Android 12 | */ 13 | videoAutoPlay?: boolean 14 | } 15 | 16 | export interface PreviewConfig 17 | extends Omit { 18 | /** 19 | * Language options for the picker. 20 | * 21 | * @platform ios 22 | * 23 | * @description 24 | * - 'system': 🌐 System default 25 | * - 'zh-Hans': 🇨🇳 Simplified Chinese 26 | * - 'zh-Hant': 🇹🇼 Traditional Chinese 27 | * - 'ja': 🇯🇵 Japanese 28 | * - 'ko': 🇰🇷 Korean 29 | * - 'en': 🇬🇧 English 30 | * - 'th': 🇹🇭 Thai 31 | * - 'id': 🇮🇩 Indonesian 32 | * - 'vi': 🇻🇳 Vietnamese (My Country) 33 | * - 'ru': 🇷🇺 Russian 34 | * - 'de': 🇩🇪 German 35 | * - 'fr': 🇫🇷 French 36 | * - 'ar': 🇸🇦 Arabic 37 | */ 38 | language?: Language 39 | 40 | onLongPress?: (index: number) => void 41 | } 42 | 43 | export interface MediaPreview { 44 | type: ResultType 45 | path?: string 46 | thumbnail?: string 47 | localIdentifier?: string 48 | } 49 | -------------------------------------------------------------------------------- /tsconfig.build.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig", 3 | "exclude": ["example", "docs"] 4 | } 5 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": ".", 4 | "outDir": "./lib", 5 | "paths": { 6 | "@baronha/react-native-multiple-image-picker": ["src"] 7 | }, 8 | "allowUnreachableCode": false, 9 | "allowUnusedLabels": false, 10 | "esModuleInterop": true, 11 | "forceConsistentCasingInFileNames": true, 12 | "jsx": "react", 13 | "lib": ["esnext"], 14 | "module": "esnext", 15 | "moduleResolution": "node", 16 | "noFallthroughCasesInSwitch": true, 17 | "noImplicitReturns": true, 18 | "noImplicitUseStrict": false, 19 | "noStrictGenericChecks": false, 20 | "noUnusedLocals": true, 21 | "noUnusedParameters": true, 22 | "resolveJsonModule": true, 23 | "skipLibCheck": true, 24 | "strict": true, 25 | "target": "esnext" 26 | } 27 | } 28 | --------------------------------------------------------------------------------