diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 39efde8..b038503 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -103,8 +103,8 @@ jobs:
build-ios:
runs-on: macos-latest
- env:
- TURBO_CACHE_DIR: .turbo/ios
+ # env:
+ # TURBO_CACHE_DIR: .turbo/ios
steps:
- name: Checkout
uses: actions/checkout@v3
@@ -112,32 +112,32 @@ jobs:
- name: Setup
uses: ./.github/actions/setup
- - name: Cache turborepo for iOS
- uses: actions/cache@v3
- with:
- path: ${{ env.TURBO_CACHE_DIR }}
- key: ${{ runner.os }}-turborepo-ios-${{ hashFiles('**/yarn.lock') }}
- restore-keys: |
- ${{ runner.os }}-turborepo-ios-
-
- - name: Check turborepo cache for iOS
- run: |
- TURBO_CACHE_STATUS=$(node -p "($(yarn --silent turbo run build:ios --cache-dir="${{ env.TURBO_CACHE_DIR }}" --dry=json)).tasks.find(t => t.task === 'build:ios').cache.status")
-
- if [[ $TURBO_CACHE_STATUS == "HIT" ]]; then
- echo "turbo_cache_hit=1" >> $GITHUB_ENV
- fi
-
- - name: Cache cocoapods
- if: env.turbo_cache_hit != 1
- id: cocoapods-cache
- uses: actions/cache@v3
- with:
- path: |
- **/ios/Pods
- key: ${{ runner.os }}-cocoapods-${{ hashFiles('example/ios/Podfile.lock') }}
- restore-keys: |
- ${{ runner.os }}-cocoapods-
+ # - name: Cache turborepo for iOS
+ # uses: actions/cache@v3
+ # with:
+ # path: ${{ env.TURBO_CACHE_DIR }}
+ # key: ${{ runner.os }}-turborepo-ios-${{ hashFiles('**/yarn.lock') }}
+ # restore-keys: |
+ # ${{ runner.os }}-turborepo-ios-
+
+ # - name: Check turborepo cache for iOS
+ # run: |
+ # TURBO_CACHE_STATUS=$(node -p "($(yarn --silent turbo run build:ios --cache-dir="${{ env.TURBO_CACHE_DIR }}" --dry=json)).tasks.find(t => t.task === 'build:ios').cache.status")
+
+ # if [[ $TURBO_CACHE_STATUS == "HIT" ]]; then
+ # echo "turbo_cache_hit=1" >> $GITHUB_ENV
+ # fi
+
+ # - name: Cache cocoapods
+ # if: env.turbo_cache_hit != 1
+ # id: cocoapods-cache
+ # uses: actions/cache@v3
+ # with:
+ # path: |
+ # **/ios/Pods
+ # key: ${{ runner.os }}-cocoapods-${{ hashFiles('example/ios/Podfile.lock') }}
+ # restore-keys: |
+ # ${{ runner.os }}-cocoapods-
- name: Install cocoapods
if: env.turbo_cache_hit != 1 && steps.cocoapods-cache.outputs.cache-hit != 'true'
@@ -148,4 +148,6 @@ jobs:
- name: Build example for iOS
run: |
- yarn turbo run build:ios --cache-dir="${{ env.TURBO_CACHE_DIR }}"
+ # yarn turbo run build:ios --cache-dir="${{ env.TURBO_CACHE_DIR }}"
+ yarn turbo run build:ios
+
diff --git a/example/ios/TurboImageExample.xcodeproj/project.pbxproj b/example/ios/TurboImageExample.xcodeproj/project.pbxproj
index 72ff34e..b70874d 100644
--- a/example/ios/TurboImageExample.xcodeproj/project.pbxproj
+++ b/example/ios/TurboImageExample.xcodeproj/project.pbxproj
@@ -486,6 +486,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = 1;
+ DEFINES_MODULE = NO;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = TurboImageExample/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
@@ -513,6 +514,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = 1;
+ DEFINES_MODULE = NO;
INFOPLIST_FILE = TurboImageExample/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
diff --git a/example/src/App.tsx b/example/src/App.tsx
index 8328331..ac87d7c 100644
--- a/example/src/App.tsx
+++ b/example/src/App.tsx
@@ -3,15 +3,22 @@ import { ScrollView, StyleSheet } from 'react-native';
import TurboImage from 'react-native-turbo-image';
export default function App() {
- const image = { source: 'https://picsum.photos/seed/picsum/200/300' };
- const images = Array(100).fill(image);
+ const image = { source: 'https://placedog.net/300/200?id=12' };
+ const images = Array(10).fill(image);
return (
{images.map((img, idx) => (
-
+
))}
);
@@ -26,8 +33,6 @@ const styles = StyleSheet.create({
justifyContent: 'center',
},
box: {
- width: 300,
- height: 200,
marginVertical: 20,
},
});
diff --git a/ios/TurboImage/RCTConvert+ScaleMode.swift b/ios/TurboImage/RCTConvert+ScaleMode.swift
new file mode 100644
index 0000000..ecc5b8c
--- /dev/null
+++ b/ios/TurboImage/RCTConvert+ScaleMode.swift
@@ -0,0 +1,49 @@
+import Foundation
+import React
+import Kingfisher
+
+@objc
+enum ScaleMode: Int {
+
+ /// Not scale the content.
+ case none
+
+ /// Scales the content to fit the size of the view by maintaining the aspect ratio.
+ case aspectFit
+
+ /// Scales the content to fill the size of the view.
+ case aspectFill
+}
+
+extension ScaleMode {
+
+ static func mapContentMode(by scaleMode: ScaleMode) -> ContentMode {
+ var contentMode: Kingfisher.ContentMode
+ switch scaleMode.rawValue {
+ case 1:
+ contentMode = .aspectFit
+ case 2:
+ contentMode = .aspectFill
+ default:
+ contentMode = .none
+ }
+ return contentMode
+ }
+}
+
+
+extension RCTConvert {
+ @objc(ScaleMode:)
+ static func scaleMode(_ value: Any) -> ScaleMode {
+ let ScaleModeMap: [String: ScaleMode] = [
+ "fill": .aspectFill,
+ "fit": .aspectFit
+ ]
+
+ guard let value = value as? String,
+ let mv = ScaleModeMap[value]
+ else { return .none }
+ return mv
+ }
+}
+
diff --git a/ios/TurboImage/TurboImageView.swift b/ios/TurboImage/TurboImageView.swift
index c5892d8..7c708de 100644
--- a/ios/TurboImage/TurboImageView.swift
+++ b/ios/TurboImage/TurboImageView.swift
@@ -1,22 +1,59 @@
import Kingfisher
+import React
class TurboImageView : UIView {
var image: UIImage?
- @objc var color: String = "" {
+ var imageView: UIImageView?
+ private var needsReload: Bool = false
+
+ var width: CGFloat? {
+ didSet {
+ guard let width = width else { return }
+ imageView?.frame.size.width = width
+ }
+ }
+ var height: CGFloat? {
+ didSet {
+ guard let height = height else { return }
+ imageView?.frame.size.height = height
+ }
+ }
+
+ @objc var source: String? {
didSet {
- self.backgroundColor = hexStringToUIColor(hexColor: color)
+ needsReload = true
}
}
- @objc var source: String?
+ var scaleMode: ScaleMode?
override init(frame: CGRect) {
super.init(frame: frame)
+ clipsToBounds = true
+ imageView = UIImageView()
+ addSubview(imageView!)
+ }
+
+ @objc
+ func setHeight(_ height: CGFloat) {
+ self.height = height
+ }
+
+ @objc
+ func setWidth(_ width: CGFloat) {
+ self.width = width
+ }
+
+ @objc
+ func setScaleMode(_ scaleMode: ScaleMode) {
+ self.scaleMode = scaleMode
}
override func didSetProps(_ changedProps: [String]!) {
- reloadImage()
+ if needsReload {
+ loadImage(with: source)
+ }
}
required init?(coder: NSCoder) {
@@ -24,36 +61,29 @@ class TurboImageView : UIView {
}
}
+
extension TurboImageView {
- private func reloadImage() {
- guard let url = URL(string: source!) else { return }
- let resource: KF.ImageResource = KF.ImageResource(downloadURL: url)
- KingfisherManager.shared.retrieveImage(with: resource) { [self] result in
- switch result {
- case .success(let response):
- image = response.image
- let imageView = UIImageView(image: image)
- addSubview(imageView)
- case .failure(let error):
- print("🐵 ---- error \(error)") // TODO: 🐵 handle error
- }
- }
- }
-
- func hexStringToUIColor(hexColor: String) -> UIColor {
- let stringScanner = Scanner(string: hexColor)
-
- if(hexColor.hasPrefix("#")) {
- stringScanner.scanLocation = 1
- }
- var color: UInt32 = 0
- stringScanner.scanHexInt32(&color)
-
- let r = CGFloat(Int(color >> 16) & 0x000000FF)
- let g = CGFloat(Int(color >> 8) & 0x000000FF)
- let b = CGFloat(Int(color) & 0x000000FF)
+ func loadImage(with source: String?) {
+ guard let source = source,
+ let url = URL(string: source),
+ let width = width,
+ let height = height,
+ let scaleMode = scaleMode
+ else { return }
- return UIColor(red: r / 255.0, green: g / 255.0, blue: b / 255.0, alpha: 1)
+ let resource: KF.ImageResource = KF.ImageResource(downloadURL: url)
+ let scale = UIScreen.main.scale
+ let contentMode = ScaleMode.mapContentMode(by: scaleMode)
+ let referenceSize = CGSize(width: width * scale, height: height * scale)
+ let processor = ResizingImageProcessor(referenceSize: referenceSize,
+ mode: contentMode)
+ let options: KingfisherOptionsInfo = [.processor(processor)]
+ imageView?.kf.indicatorType = .activity
+ imageView?.kf.setImage(with: resource,
+ placeholder: nil,
+ options: options,
+ progressBlock: nil
+ )
}
}
diff --git a/ios/TurboImage/TurboImageViewManager.m b/ios/TurboImage/TurboImageViewManager.m
index e9d85ba..a2496a5 100644
--- a/ios/TurboImage/TurboImageViewManager.m
+++ b/ios/TurboImage/TurboImageViewManager.m
@@ -1,8 +1,14 @@
#import
+#import "ReactNativeTurboImage-umbrella.h"
+//#import
@interface RCT_EXTERN_MODULE(TurboImageViewManager, RCTViewManager)
RCT_EXPORT_VIEW_PROPERTY(color, NSString)
RCT_EXPORT_VIEW_PROPERTY(source, NSString)
+RCT_EXPORT_VIEW_PROPERTY(width, double)
+RCT_EXPORT_VIEW_PROPERTY(height, double)
+RCT_EXPORT_VIEW_PROPERTY(scaleMode, ScaleMode)
@end
+
diff --git a/src/index.tsx b/src/index.tsx
index 54fdb5d..f6a49c4 100644
--- a/src/index.tsx
+++ b/src/index.tsx
@@ -6,13 +6,7 @@ import type { ColorValue } from 'react-native';
import type { AccessibilityProps } from 'react-native';
import type { ShadowStyleIOS } from 'react-native';
import type { FlexStyle } from 'react-native';
-import {
- View,
- StyleSheet,
- requireNativeComponent,
- UIManager,
- Platform,
-} from 'react-native';
+import { requireNativeComponent, UIManager, Platform } from 'react-native';
const LINKING_ERROR =
`The package 'react-native-turbo-image' doesn't seem to be linked. Make sure: \n\n` +
@@ -20,6 +14,19 @@ const LINKING_ERROR =
'- You rebuilt the app after installing the package\n' +
'- You are not using Expo Go\n';
+export type ScaleMode = 'fit' | 'fill';
+/**
+ * **aspectFit**
+ * Scales the content to fit the size of the view by maintaining the aspect ratio.
+ *
+ * **aspectFill**
+ * Scales the content to fill the size of the view.
+ */
+const scaleMode = {
+ fit: 'fit',
+ fill: 'fill',
+} as const;
+
export interface ImageStyle extends FlexStyle, TransformsStyle, ShadowStyleIOS {
backfaceVisibility?: 'visible' | 'hidden';
borderBottomLeftRadius?: number;
@@ -35,6 +42,8 @@ export interface ImageStyle extends FlexStyle, TransformsStyle, ShadowStyleIOS {
}
export interface TurboImageProps extends AccessibilityProps, ViewProps {
source: string;
+ ref?: React.Ref;
+ scaleMode?: ScaleMode;
/**
*
* Style
@@ -56,6 +65,8 @@ export interface TurboImageProps extends AccessibilityProps, ViewProps {
* Render children within the image.
*/
children?: React.ReactNode;
+ width: number;
+ height: number;
}
const ComponentName = 'TurboImageView';
@@ -70,27 +81,29 @@ const TurboImageView =
const TurboImageBase = (
props: TurboImageProps & { forwardedRef: React.Ref }
) => {
- const { source, tintColor, style, children, forwardedRef, ...restProps } =
- props;
+ const {
+ source,
+ tintColor,
+ style,
+ forwardedRef,
+ width,
+ height,
+ ...restProps
+ } = props;
+
return (
-
-
- {children}
-
+
);
};
-const styles = StyleSheet.create({
- imageContainer: {
- overflow: 'hidden',
- },
-});
-
const TurboImageMemo = memo(TurboImageBase);
const TurboImageComponent: React.ComponentType = forwardRef(
@@ -99,11 +112,15 @@ const TurboImageComponent: React.ComponentType = forwardRef(
)
);
-TurboImageComponent.displayName = 'FastImage';
+TurboImageComponent.displayName = 'TurboImage';
-export interface TurboImageStaticProperties {}
+export interface TurboImageStaticProperties {
+ scaleMode: typeof scaleMode;
+}
const TurboImage: React.ComponentType &
TurboImageStaticProperties = TurboImageComponent as any;
+TurboImage.scaleMode = scaleMode;
+
export default TurboImage;