From 7308e3741d3992cbeaaf590caed5d169da955762 Mon Sep 17 00:00:00 2001 From: PierreCapo Date: Fri, 29 Dec 2023 23:30:29 +0100 Subject: [PATCH] feat: migrate to native views --- README.md | 24 ++-- android/src/main/AndroidManifest.xml | 6 +- android/src/main/AndroidManifestNew.xml | 7 +- .../com/pictures/PictureViewerActivity.kt | 81 ------------- .../main/java/com/pictures/PicturesModule.kt | 30 ----- .../main/java/com/pictures/PicturesPackage.kt | 4 +- .../java/com/pictures/PicturesViewManager.kt | 72 ++++++++++++ .../PicturesExample.xcodeproj/project.pbxproj | 10 +- example/ios/PicturesExample/Info.plist | 2 - example/ios/Podfile.lock | 6 +- example/src/App.tsx | 30 ++--- ios/Pictures-Bridging-Header.h | 1 - ios/Pictures.mm | 14 --- ios/Pictures.swift | 17 --- ios/PicturesManager.swift | 42 ------- ios/PicturesViewManager.m | 7 ++ ...roller.swift => PicturesViewManager.swift} | 108 ++++++++++-------- package.json | 6 +- react-native-pictures.podspec | 5 +- src/index.tsx | 32 +++--- yarn.lock | 63 +++++++--- 21 files changed, 250 insertions(+), 317 deletions(-) delete mode 100644 android/src/main/java/com/pictures/PictureViewerActivity.kt delete mode 100644 android/src/main/java/com/pictures/PicturesModule.kt create mode 100644 android/src/main/java/com/pictures/PicturesViewManager.kt delete mode 100644 ios/Pictures.mm delete mode 100644 ios/Pictures.swift delete mode 100644 ios/PicturesManager.swift create mode 100644 ios/PicturesViewManager.m rename ios/{PictureViewerViewController.swift => PicturesViewManager.swift} (74%) diff --git a/README.md b/README.md index e1c93d7..b825578 100644 --- a/README.md +++ b/README.md @@ -16,26 +16,36 @@ npm install react-native-pictures ## Usage -Here's a simple example to showcase how you can use React Native Pictures in your app: +Here's a simple example to showcase how you can use React Native Pictures in your app. +It's recommended that the viewer takes the entire available space: ```js -import PictureManager from 'react-native-pictures'; +import {PictureViewer} from 'react-native-pictures'; // ... -const imageUrl = "https://images.unsplash.com/photo-1462331940025-496dfbfc7564" -const result = PictureManager.openPictureViewer(imageUrl); + ``` ## API -For now, the only function supported is `openPictureViewer(url: string)`. -More to come! +### PictureViewer + +| Props | Type | Description | +| --- | --- | --- | +| imageUrl | string | The remote image url you want to see | +| style | ViewStyle | Style of PictureViewer. ## Roadmap +- **More controls:** Add ability to display local images, gesture event listeners, etc. - **Custom Android Implementation:** Replace PhotoView with a custom implementation, as PhotoView is no longer maintained. -- **Native Component Integration:** Transition from Activity/UIViewController to View/UIView for seamless embedding within React Native screens. This will allow greater flexibility for consumer applications. - **Image Cropping Feature:** Implement a cropping feature to leverage the pan and zoom capabilities, making it easier to integrate an image cropping screen. diff --git a/android/src/main/AndroidManifest.xml b/android/src/main/AndroidManifest.xml index 760394d..392dab2 100644 --- a/android/src/main/AndroidManifest.xml +++ b/android/src/main/AndroidManifest.xml @@ -1,7 +1,3 @@ - - - - + package="com.pictures"> diff --git a/android/src/main/AndroidManifestNew.xml b/android/src/main/AndroidManifestNew.xml index 760394d..a2f47b6 100644 --- a/android/src/main/AndroidManifestNew.xml +++ b/android/src/main/AndroidManifestNew.xml @@ -1,7 +1,2 @@ - - - - - + diff --git a/android/src/main/java/com/pictures/PictureViewerActivity.kt b/android/src/main/java/com/pictures/PictureViewerActivity.kt deleted file mode 100644 index ee8bf7a..0000000 --- a/android/src/main/java/com/pictures/PictureViewerActivity.kt +++ /dev/null @@ -1,81 +0,0 @@ -package com.pictures - -import android.app.Activity -import android.os.Bundle -import android.graphics.BitmapFactory -import android.graphics.Color -import android.view.Gravity -import android.widget.FrameLayout -import android.widget.ImageView -import com.github.chrisbanes.photoview.PhotoView -import java.net.HttpURLConnection -import java.net.URL - -class PictureViewerActivity : Activity() { - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - // Set the layout for the activity - // Create a LinearLayout - // Create a FrameLayout - - val frameLayout = FrameLayout(this).apply { - layoutParams = FrameLayout.LayoutParams( - FrameLayout.LayoutParams.MATCH_PARENT, - FrameLayout.LayoutParams.MATCH_PARENT - ) - setBackgroundColor(Color.WHITE) - } - - // Create and configure PhotoView - val imageUrl = intent.getStringExtra("imageUrl") - val imageView = PhotoView(this).apply { - layoutParams = FrameLayout.LayoutParams( - FrameLayout.LayoutParams.MATCH_PARENT, - FrameLayout.LayoutParams.MATCH_PARENT - ) - } - - // Add PhotoView to FrameLayout - frameLayout.addView(imageView) - - // Create and configure Close Button - val closeButton = ImageView(this).apply { - layoutParams = FrameLayout.LayoutParams( - FrameLayout.LayoutParams.WRAP_CONTENT, - FrameLayout.LayoutParams.WRAP_CONTENT - ).also { - it.gravity = Gravity.TOP or Gravity.END - it.setMargins(0, 30, 30, 0) // Adjust margins as needed - } - setImageResource(android.R.drawable.ic_menu_close_clear_cancel) // Use a suitable close icon - setOnClickListener { - finish() // Close the activity - } - } - closeButton.setColorFilter(Color.BLACK) - - // Add Close Button to FrameLayout - frameLayout.addView(closeButton) - - // Set FrameLayout as the content view - setContentView(frameLayout) - - Thread { - try { - val url = URL(imageUrl) - val connection = url.openConnection() as HttpURLConnection - connection.doInput = true - connection.connect() - val inputStream = connection.inputStream - val bitmap = BitmapFactory.decodeStream(inputStream) - - runOnUiThread { - imageView.setImageBitmap(bitmap) - } - } catch (e: Exception) { - e.printStackTrace() - // Handle exceptions - } - }.start() - } -} diff --git a/android/src/main/java/com/pictures/PicturesModule.kt b/android/src/main/java/com/pictures/PicturesModule.kt deleted file mode 100644 index f5aad5f..0000000 --- a/android/src/main/java/com/pictures/PicturesModule.kt +++ /dev/null @@ -1,30 +0,0 @@ -package com.pictures - -import android.content.Intent -import com.facebook.react.bridge.ReactApplicationContext -import com.facebook.react.bridge.ReactContextBaseJavaModule -import com.facebook.react.bridge.ReactMethod -import com.facebook.react.bridge.Promise - -class PicturesModule(reactContext: ReactApplicationContext) : - ReactContextBaseJavaModule(reactContext) { - - override fun getName(): String { - return NAME - } - - // Example method - // See https://reactnative.dev/docs/native-modules-android - @ReactMethod - fun openPictureViewer(url: String, promise: Promise) { - val intent = Intent(reactApplicationContext, PictureViewerActivity::class.java) - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK) - intent.putExtra("imageUrl", url) - reactApplicationContext.startActivity(intent) - promise.resolve(null) - } - - companion object { - const val NAME = "Pictures" - } -} diff --git a/android/src/main/java/com/pictures/PicturesPackage.kt b/android/src/main/java/com/pictures/PicturesPackage.kt index 82ee3d6..d8bd81b 100644 --- a/android/src/main/java/com/pictures/PicturesPackage.kt +++ b/android/src/main/java/com/pictures/PicturesPackage.kt @@ -8,10 +8,10 @@ import com.facebook.react.uimanager.ViewManager class PicturesPackage : ReactPackage { override fun createNativeModules(reactContext: ReactApplicationContext): List { - return listOf(PicturesModule(reactContext)) + return emptyList() } override fun createViewManagers(reactContext: ReactApplicationContext): List> { - return emptyList() + return listOf(PicturesViewManager()) } } diff --git a/android/src/main/java/com/pictures/PicturesViewManager.kt b/android/src/main/java/com/pictures/PicturesViewManager.kt new file mode 100644 index 0000000..1067094 --- /dev/null +++ b/android/src/main/java/com/pictures/PicturesViewManager.kt @@ -0,0 +1,72 @@ +package com.pictures + +import android.view.View +import com.facebook.react.uimanager.SimpleViewManager +import com.facebook.react.uimanager.ThemedReactContext +import com.facebook.react.uimanager.annotations.ReactProp +import android.content.Context +import android.graphics.Bitmap +import android.graphics.BitmapFactory +import android.widget.FrameLayout +import com.github.chrisbanes.photoview.PhotoView +import java.net.HttpURLConnection +import java.net.URL + +class PicturesViewManager : SimpleViewManager() { + override fun getName() = "PicturesView" + + override fun createViewInstance(reactContext: ThemedReactContext): PicturesView { + return PicturesView(reactContext) + } + + @ReactProp(name = "imageUrl") + fun setImageUrl(view: PicturesView, imageUrl: String) { + view.loadImage(imageUrl) + } + +} + +class PicturesView(context: Context) : FrameLayout(context) { + + private val imageView: PhotoView = PhotoView(context).apply { + layoutParams = LayoutParams( + LayoutParams.MATCH_PARENT, + LayoutParams.MATCH_PARENT + ) + } + + init { + addView(imageView) + } + + fun loadImage(imageUrl: String) { + // Load the image similarly as in your activity + Thread { + try { + val url = URL(imageUrl) + val connection = url.openConnection() as HttpURLConnection + connection.doInput = true + connection.connect() + val inputStream = connection.inputStream + val originalBitmap = BitmapFactory.decodeStream(inputStream) + + // Resize the bitmap to avoid Bitmap being too big and causing a crash + val aspectRatio = originalBitmap.width.toFloat() / originalBitmap.height.toFloat() + val targetWidth = imageView.width // You might want to adjust this + val targetHeight = (targetWidth / aspectRatio).toInt() + + val resizedBitmap = + Bitmap.createScaledBitmap(originalBitmap, targetWidth, targetHeight, false) + + + post { + imageView.setImageBitmap(resizedBitmap) + } + } catch (e: Exception) { + e.printStackTrace() + // Handle exceptions + } + }.start() + } +} + diff --git a/example/ios/PicturesExample.xcodeproj/project.pbxproj b/example/ios/PicturesExample.xcodeproj/project.pbxproj index 57fb778..b23020d 100644 --- a/example/ios/PicturesExample.xcodeproj/project.pbxproj +++ b/example/ios/PicturesExample.xcodeproj/project.pbxproj @@ -418,7 +418,7 @@ "$(inherited)", ); INFOPLIST_FILE = PicturesExampleTests/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 14.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.4; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -442,7 +442,7 @@ BUNDLE_LOADER = "$(TEST_HOST)"; COPY_PHASE_STRIP = NO; INFOPLIST_FILE = PicturesExampleTests/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 14.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.4; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -469,7 +469,6 @@ DEVELOPMENT_TEAM = 9A48KBL3Q4; ENABLE_BITCODE = NO; INFOPLIST_FILE = PicturesExample/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 14.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -497,7 +496,6 @@ CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = 9A48KBL3Q4; INFOPLIST_FILE = PicturesExample/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 14.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -564,7 +562,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 14.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.4; LD_RUNPATH_SEARCH_PATHS = ( /usr/lib/swift, "$(inherited)", @@ -637,7 +635,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 14.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.4; LD_RUNPATH_SEARCH_PATHS = ( /usr/lib/swift, "$(inherited)", diff --git a/example/ios/PicturesExample/Info.plist b/example/ios/PicturesExample/Info.plist index 9ddd099..8b6828e 100644 --- a/example/ios/PicturesExample/Info.plist +++ b/example/ios/PicturesExample/Info.plist @@ -45,8 +45,6 @@ UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight - NSPhotoLibraryUsageDescription - This app wants to access your photo gallery UIViewControllerBasedStatusBarAppearance diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index 3036e01..22c1e97 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -944,7 +944,7 @@ PODS: - React-Mapbuffer (0.73.1): - glog - React-debug - - react-native-pictures (0.1.0): + - react-native-pictures (0.3.1): - glog - RCT-Folly (= 2022.05.16.00) - React-Core @@ -1351,7 +1351,7 @@ SPEC CHECKSUMS: React-jsinspector: 369048694e39942063c5d08e9580b43e2edd379a React-logger: e0c1e918d9588a9f39c9bc62d9d6bfe9ca238d9d React-Mapbuffer: 9731a0a63ebaf8976014623c4d637744d7353a7c - react-native-pictures: eda9d4b7353153b57a5db140260e44764d74b5ba + react-native-pictures: de0d1c027204e14785cfa3d025024aebbbd2e8c4 React-nativeconfig: 37aecd26d64b79327c3f10e43b2e9a6c425e0a60 React-NativeModulesApple: 9ca6d2eaa1dd5606588262195b46d0774bdec83a React-perflogger: 5ffc4d6ccb74eaac7b8b2867e58a447232483d6d @@ -1375,6 +1375,6 @@ SPEC CHECKSUMS: SocketRocket: f32cd54efbe0f095c4d7594881e52619cfe80b17 Yoga: 4f53dc50008d626fa679c7a1cb4bed898f8c0bde -PODFILE CHECKSUM: 18fe640b479ffb2cb7af6a7e58899b09d1f31fcc +PODFILE CHECKSUM: 26fc151c7d8586e3b6acee2c5d9760d45e6d6ffb COCOAPODS: 1.14.3 diff --git a/example/src/App.tsx b/example/src/App.tsx index 1abbf2f..8c40e8d 100644 --- a/example/src/App.tsx +++ b/example/src/App.tsx @@ -1,28 +1,15 @@ import * as React from 'react'; -import { StyleSheet, View, Text, Pressable } from 'react-native'; -import { openPictureViewer } from 'react-native-pictures'; +import { StyleSheet, View } from 'react-native'; +import { PicturesViewer } from 'react-native-pictures'; export default function App() { return ( - { - openPictureViewer( - 'https://images.unsplash.com/photo-1462331940025-496dfbfc7564?q=80&w=2422&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D' - ); - }} - style={{ - height: 50, - paddingHorizontal: 32, - borderRadius: 12, - backgroundColor: 'cyan', - justifyContent: 'center', - alignItems: 'center', - }} - > - Click me - + ); } @@ -32,10 +19,11 @@ const styles = StyleSheet.create({ flex: 1, alignItems: 'center', justifyContent: 'center', + backgroundColor: 'white', }, box: { - width: 60, - height: 60, + width: '100%', + height: '100%', marginVertical: 20, }, }); diff --git a/ios/Pictures-Bridging-Header.h b/ios/Pictures-Bridging-Header.h index dea7ff6..16eb5eb 100644 --- a/ios/Pictures-Bridging-Header.h +++ b/ios/Pictures-Bridging-Header.h @@ -1,2 +1 @@ -#import #import diff --git a/ios/Pictures.mm b/ios/Pictures.mm deleted file mode 100644 index 6f721d7..0000000 --- a/ios/Pictures.mm +++ /dev/null @@ -1,14 +0,0 @@ -#import - -@interface RCT_EXTERN_MODULE(Pictures, NSObject) - -RCT_EXTERN_METHOD(openPictureViewer:(NSString)url - withResolver:(RCTPromiseResolveBlock)resolve - withRejecter:(RCTPromiseRejectBlock)reject) - -+ (BOOL)requiresMainQueueSetup -{ - return NO; -} - -@end diff --git a/ios/Pictures.swift b/ios/Pictures.swift deleted file mode 100644 index 475f5d1..0000000 --- a/ios/Pictures.swift +++ /dev/null @@ -1,17 +0,0 @@ -@objc(Pictures) -class Pictures: NSObject { - - @objc(openPictureViewer:withResolver:withRejecter:) - func openPictureViewer( - url: String, - resolve:RCTPromiseResolveBlock, - reject:RCTPromiseRejectBlock) -> Void { - - Task { @MainActor in - let rootVC = RCTSharedApplication()?.delegate?.window??.rootViewController - guard let rootVC else { return } - let picturesManager = PicturesManager(parent: rootVC) - try picturesManager.openPictureViewer(imageUrl: url) - } - } -} diff --git a/ios/PicturesManager.swift b/ios/PicturesManager.swift deleted file mode 100644 index 1facd15..0000000 --- a/ios/PicturesManager.swift +++ /dev/null @@ -1,42 +0,0 @@ -// The Swift Programming Language -// https://docs.swift.org/swift-book - -import UIKit -import Photos -import PhotosUI - -public class PicturesManager { - private weak var parentVC: UIViewController? - - public init(parent viewController: UIViewController) { - self.parentVC = viewController - } - - func openPictureViewer(imageUrl: String) throws { - let url = URL(string: imageUrl) - guard let url else { - throw ImageViewerError.incorrectURL - } - - let newVc = PictureViewerViewController(imageUrl: url) - newVc.modalPresentationStyle = .fullScreen - parentVC?.present(newVc, animated: true) - } -} - -enum ImageViewerError: Error { - case incorrectURL - case incorrectImageData - case incorrectImage - - func getKey() -> String { - switch self { - case .incorrectURL: - return "INCORRECT_URL" - case .incorrectImageData: - return "INCORRECT_IMAGE_DATA" - case .incorrectImage: - return "INCORRECT_IMAGE" - } - } -} diff --git a/ios/PicturesViewManager.m b/ios/PicturesViewManager.m new file mode 100644 index 0000000..8f6a5af --- /dev/null +++ b/ios/PicturesViewManager.m @@ -0,0 +1,7 @@ +#import + +@interface RCT_EXTERN_MODULE(PicturesViewManager, RCTViewManager) + +RCT_EXPORT_VIEW_PROPERTY(imageUrl, NSString) + +@end diff --git a/ios/PictureViewerViewController.swift b/ios/PicturesViewManager.swift similarity index 74% rename from ios/PictureViewerViewController.swift rename to ios/PicturesViewManager.swift index ae9a5e5..75f4a29 100644 --- a/ios/PictureViewerViewController.swift +++ b/ios/PicturesViewManager.swift @@ -1,46 +1,50 @@ -// -// File.swift -// -// -// Created by Pierre Caporossi on 17/12/2023. -// - -import Foundation -import UIKit +@objc(PicturesViewManager) +class PicturesViewManager: RCTViewManager { + + override func view() -> (PicturesView) { + return PicturesView() + } + + @objc override static func requiresMainQueueSetup() -> Bool { + return false + } +} -class PictureViewerViewController: UIViewController { - var imageUrl: URL +class PicturesView: UIView { + let imageView = UIImageView() let scrollView = UIScrollView() - let button = UIButton() - - init(imageUrl: URL) { + + @objc var imageUrl: String? = nil { + didSet { + Task { + try? await loadImage(imageUrl: imageUrl) + } + } + } + + init(imageUrl: String? = nil) { self.imageUrl = imageUrl - imageView.alpha = 0 - super.init(nibName: nil, bundle: nil) + super.init(frame: .zero) + layoutContent() } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } - override func viewDidLoad() { - super.viewDidLoad() - Task { - try? await loadImage() - } - view.backgroundColor = .white + func layoutContent() { scrollView.translatesAutoresizingMaskIntoConstraints = false imageView.translatesAutoresizingMaskIntoConstraints = false - view.addSubview(scrollView) + self.addSubview(scrollView) scrollView.addSubview(imageView) imageView.contentMode = .scaleAspectFit NSLayoutConstraint.activate([ - scrollView.topAnchor.constraint(equalTo: view.topAnchor), - scrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor), - scrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor), - scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor), + scrollView.topAnchor.constraint(equalTo: self.topAnchor), + scrollView.leadingAnchor.constraint(equalTo: self.leadingAnchor), + scrollView.trailingAnchor.constraint(equalTo: self.trailingAnchor), + scrollView.bottomAnchor.constraint(equalTo: self.bottomAnchor), imageView.topAnchor.constraint(equalTo: scrollView.topAnchor), imageView.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor), imageView.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor), @@ -56,19 +60,8 @@ class PictureViewerViewController: UIViewController { let doubleTapGest = UITapGestureRecognizer(target: self, action: #selector(handleDoubleTap(_:))) doubleTapGest.numberOfTapsRequired = 2 scrollView.addGestureRecognizer(doubleTapGest) - button.setImage(UIImage(systemName: "xmark"), for: .normal) - button.tintColor = .black - button.addTarget(self, action: #selector(buttonTapped(sender:)), for: .touchUpInside) - view.addSubview(button) - button.translatesAutoresizingMaskIntoConstraints = false - NSLayoutConstraint.activate([ - button.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -8), - button.topAnchor.constraint(equalTo: view.topAnchor, constant: 46), - button.widthAnchor.constraint(equalToConstant: 46), - button.heightAnchor.constraint(equalToConstant: 46) - ]) } - + @objc func handleDoubleTap(_ recognizer: UITapGestureRecognizer) { let scale = min(scrollView.zoomScale * 2, scrollView.maximumZoomScale) @@ -96,13 +89,17 @@ class PictureViewerViewController: UIViewController { return zoomRect } - @objc - func buttonTapped(sender: UIButton) { - self.dismiss(animated: true) - } - - func loadImage() async throws { - let (imageData, _) = try await URLSession.shared.data(from: imageUrl) + func loadImage(imageUrl: String?) async throws { + guard let imageUrl else { + return + } + + guard let url = URL(string: imageUrl) else { + throw ImageViewerError.incorrectURL + } + + + let (imageData, _) = try await URLSession.shared.data(from: url) guard let image = UIImage(data: imageData) else { throw ImageViewerError.incorrectImage @@ -117,7 +114,7 @@ class PictureViewerViewController: UIViewController { } } -extension PictureViewerViewController: UIScrollViewDelegate { +extension PicturesView: UIScrollViewDelegate { func viewForZooming(in scrollView: UIScrollView) -> UIView? { return imageView } @@ -144,3 +141,20 @@ extension PictureViewerViewController: UIScrollViewDelegate { } } } + +enum ImageViewerError: Error { + case incorrectURL + case incorrectImageData + case incorrectImage + + func getKey() -> String { + switch self { + case .incorrectURL: + return "INCORRECT_URL" + case .incorrectImageData: + return "INCORRECT_IMAGE_DATA" + case .incorrectImage: + return "INCORRECT_IMAGE" + } + } +} diff --git a/package.json b/package.json index 05567d1..6a8e3be 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "react-native-pictures", "version": "0.3.1", - "description": "Toolset for handling pictures within your react-native app", + "description": "React Native Pictures is a comprehensive toolkit for handling images within your React Native application. Our goal is to provide a modern, efficient codebase using Swift and Kotlin, offering common solutions for image-related features in your React Native app.", "main": "lib/commonjs/index", "module": "lib/module/index", "types": "lib/typescript/src/index.d.ts", @@ -70,10 +70,10 @@ "prettier": "^2.0.5", "react": "18.2.0", "react-native": "0.73.1", - "react-native-builder-bob": "^0.23.2", + "react-native-builder-bob": "^0.20.0", "release-it": "^15.0.0", "turbo": "^1.10.7", - "typescript": "^5.0.2" + "typescript": "5.0.2" }, "resolutions": { "@types/react": "17.0.21" diff --git a/react-native-pictures.podspec b/react-native-pictures.podspec index 6780809..e32093a 100644 --- a/react-native-pictures.podspec +++ b/react-native-pictures.podspec @@ -11,7 +11,7 @@ Pod::Spec.new do |s| s.license = package["license"] s.authors = package["author"] - s.platforms = { :ios => "13.4" } + s.platforms = { :ios => "11.0" } s.source = { :git => "https://github.com/PierreCapo/react-native-pictures.git", :tag => "#{s.version}" } s.source_files = "ios/**/*.{h,m,mm,swift}" @@ -31,11 +31,12 @@ Pod::Spec.new do |s| "OTHER_CPLUSPLUSFLAGS" => "-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1", "CLANG_CXX_LANGUAGE_STANDARD" => "c++17" } + s.dependency "React-RCTFabric" s.dependency "React-Codegen" s.dependency "RCT-Folly" s.dependency "RCTRequired" s.dependency "RCTTypeSafety" s.dependency "ReactCommon/turbomodule/core" end - end + end end diff --git a/src/index.tsx b/src/index.tsx index 76e9973..a695fd6 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -1,4 +1,9 @@ -import { NativeModules, Platform } from 'react-native'; +import { + requireNativeComponent, + UIManager, + Platform, + type ViewStyle, +} from 'react-native'; const LINKING_ERROR = `The package 'react-native-pictures' doesn't seem to be linked. Make sure: \n\n` + @@ -6,17 +11,16 @@ const LINKING_ERROR = '- You rebuilt the app after installing the package\n' + '- You are not using Expo Go\n'; -const Pictures = NativeModules.Pictures - ? NativeModules.Pictures - : new Proxy( - {}, - { - get() { - throw new Error(LINKING_ERROR); - }, - } - ); +type PicturesProps = { + style?: ViewStyle; + imageUrl: string; +}; -export function openPictureViewer(url: string): Promise { - return Pictures.openPictureViewer(url); -} +const ComponentName = 'PicturesView'; + +export const PicturesViewer = + UIManager.getViewManagerConfig(ComponentName) != null + ? requireNativeComponent(ComponentName) + : () => { + throw new Error(LINKING_ERROR); + }; diff --git a/yarn.lock b/yarn.lock index 7aea6c9..cb10708 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3634,11 +3634,11 @@ __metadata: linkType: hard "acorn@npm:^8.4.1, acorn@npm:^8.7.0, acorn@npm:^8.8.2, acorn@npm:^8.9.0": - version: 8.11.2 - resolution: "acorn@npm:8.11.2" + version: 8.11.3 + resolution: "acorn@npm:8.11.3" bin: acorn: bin/acorn - checksum: 818450408684da89423e3daae24e4dc9b68692db8ab49ea4569c7c5abb7a3f23669438bf129cc81dfdada95e1c9b944ee1bfca2c57a05a4dc73834a612fbf6a7 + checksum: 76d8e7d559512566b43ab4aadc374f11f563f0a9e21626dd59cb2888444e9445923ae9f3699972767f18af61df89cd89f5eaaf772d1327b055b45cb829b4a88c languageName: node linkType: hard @@ -5138,11 +5138,11 @@ __metadata: linkType: hard "core-js-compat@npm:^3.31.0, core-js-compat@npm:^3.33.1": - version: 3.34.0 - resolution: "core-js-compat@npm:3.34.0" + version: 3.35.0 + resolution: "core-js-compat@npm:3.35.0" dependencies: browserslist: ^4.22.2 - checksum: 6281f7f57a72f254c06611ec088445e11cf84e0b4edfb5f43dece1a1ff8b0ed0e81ed0bc291024761cd90c39d0f007d8bc46548265139808081d311c7cbc9c81 + checksum: 64c41ce6870aa9130b9d0cb8f00c05204094f46db7e345d520ec2e38f8b6e1d51e921d4974ceb880948f19c0a79e5639e55be0e56f88ea20e32e9a6274da7f82 languageName: node linkType: hard @@ -8617,6 +8617,17 @@ __metadata: languageName: node linkType: hard +"jetifier@npm:^2.0.0": + version: 2.0.0 + resolution: "jetifier@npm:2.0.0" + bin: + jetifier: bin/jetify + jetifier-standalone: bin/jetifier-standalone + jetify: bin/jetify + checksum: 57886c2bb7eddd1c697f0cd8f54162c037a50688d55d994a88918ca2018c3996fe6b5e9a56a57b067348260bb728e71d36e0d28d5dba87316fdb3b227d29af0e + languageName: node + linkType: hard + "joi@npm:^17.2.1": version: 17.11.0 resolution: "joi@npm:17.11.0" @@ -10878,9 +10889,9 @@ __metadata: languageName: node linkType: hard -"react-native-builder-bob@npm:^0.23.2": - version: 0.23.2 - resolution: "react-native-builder-bob@npm:0.23.2" +"react-native-builder-bob@npm:^0.20.0": + version: 0.20.4 + resolution: "react-native-builder-bob@npm:0.20.4" dependencies: "@babel/core": ^7.18.5 "@babel/plugin-proposal-class-properties": ^7.17.12 @@ -10896,14 +10907,18 @@ __metadata: fs-extra: ^10.1.0 glob: ^8.0.3 is-git-dirty: ^2.0.1 + jetifier: ^2.0.0 json5: ^2.2.1 kleur: ^4.1.4 prompts: ^2.4.2 which: ^2.0.2 yargs: ^17.5.1 + dependenciesMeta: + jetifier: + optional: true bin: bob: bin/bob - checksum: 1bee701c21f28f10c5737c8000e7fd6d8f641cf46fe7de03f5086d9951d2c5f3cb45375e292519b85f44a28f907e37f6c7bff324cfb1913b3bee0cb4db2efeb7 + checksum: 258da6ecd03be52cc05a3e3a7c481890c7c0b7b62ae9f263c5f3d6fafeae95bd9445ad2f6c2513f7f4e4569eee935a18ae94c7491f58d6916af515c88de9e0a1 languageName: node linkType: hard @@ -10945,10 +10960,10 @@ __metadata: prettier: ^2.0.5 react: 18.2.0 react-native: 0.73.1 - react-native-builder-bob: ^0.23.2 + react-native-builder-bob: ^0.20.0 release-it: ^15.0.0 turbo: ^1.10.7 - typescript: ^5.0.2 + typescript: 5.0.2 peerDependencies: react: "*" react-native: "*" @@ -12751,7 +12766,17 @@ __metadata: languageName: node linkType: hard -"typescript@npm:^4.6.4 || ^5.2.2, typescript@npm:^5.0.2": +"typescript@npm:5.0.2": + version: 5.0.2 + resolution: "typescript@npm:5.0.2" + bin: + tsc: bin/tsc + tsserver: bin/tsserver + checksum: bef1dcd166acfc6934b2ec4d72f93edb8961a5fab36b8dd2aaf6f4f4cd5c0210f2e0850aef4724f3b4913d5aef203a94a28ded731b370880c8bcff7e4ff91fc1 + languageName: node + linkType: hard + +"typescript@npm:^4.6.4 || ^5.2.2": version: 5.3.3 resolution: "typescript@npm:5.3.3" bin: @@ -12761,7 +12786,17 @@ __metadata: languageName: node linkType: hard -"typescript@patch:typescript@^4.6.4 || ^5.2.2#~builtin, typescript@patch:typescript@^5.0.2#~builtin": +"typescript@patch:typescript@5.0.2#~builtin": + version: 5.0.2 + resolution: "typescript@patch:typescript@npm%3A5.0.2#~builtin::version=5.0.2&hash=b5f058" + bin: + tsc: bin/tsc + tsserver: bin/tsserver + checksum: 0411be9e19bf6a547d574b3261fa8598f55a5243123f2a50a79b0dc15a017abbf541f15b8b43331294e409cc978e548ac5ae4e0c5b98ba5ae98029304de047be + languageName: node + linkType: hard + +"typescript@patch:typescript@^4.6.4 || ^5.2.2#~builtin": version: 5.3.3 resolution: "typescript@patch:typescript@npm%3A5.3.3#~builtin::version=5.3.3&hash=14eedb" bin: