Skip to content

Commit fe5b842

Browse files
feat: use swift code which is closer to original swift lib
1 parent 4ddccf5 commit fe5b842

File tree

45 files changed

+3661
-117
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+3661
-117
lines changed

LoaderKit.podspec

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,8 @@ Pod::Spec.new do |s|
1313
s.platforms = { :ios => min_ios_version_supported }
1414
s.source = { :git => "https://github.com/maitrungduc1410/react-native-loader-kit.git", :tag => "#{s.version}" }
1515

16-
s.source_files = "ios/**/*.{h,m,mm,cpp}"
16+
s.source_files = "ios/**/*.{h,m,mm,swift}"
1717
s.private_header_files = "ios/**/*.h"
1818

19-
s.dependency "NVActivityIndicatorView-ObjC"
20-
2119
install_modules_dependencies(s)
2220
end

example/ios/Podfile.lock

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,10 @@ PODS:
88
- hermes-engine (0.79.2):
99
- hermes-engine/Pre-built (= 0.79.2)
1010
- hermes-engine/Pre-built (0.79.2)
11-
- LoaderKit (3.0.0):
11+
- LoaderKit (4.0.0):
1212
- DoubleConversion
1313
- glog
1414
- hermes-engine
15-
- NVActivityIndicatorView-ObjC
1615
- RCT-Folly (= 2024.11.18.00)
1716
- RCTRequired
1817
- RCTTypeSafety
@@ -33,7 +32,6 @@ PODS:
3332
- ReactCommon/turbomodule/bridging
3433
- ReactCommon/turbomodule/core
3534
- Yoga
36-
- NVActivityIndicatorView-ObjC (1.0.1)
3735
- RCT-Folly (2024.11.18.00):
3836
- boost
3937
- DoubleConversion
@@ -1760,7 +1758,6 @@ DEPENDENCIES:
17601758

17611759
SPEC REPOS:
17621760
trunk:
1763-
- NVActivityIndicatorView-ObjC
17641761
- SocketRocket
17651762

17661763
EXTERNAL SOURCES:
@@ -1916,8 +1913,7 @@ SPEC CHECKSUMS:
19161913
fmt: a40bb5bd0294ea969aaaba240a927bd33d878cdd
19171914
glog: 5683914934d5b6e4240e497e0f4a3b42d1854183
19181915
hermes-engine: 314be5250afa5692b57b4dd1705959e1973a8ebe
1919-
LoaderKit: 984fcf908338cee4137a65115a0f44df26e9754a
1920-
NVActivityIndicatorView-ObjC: a2394f53d84c32f71823743a2030e0378d40332f
1916+
LoaderKit: a1a6f4a99814e4bf7b1b5792272551d24e04a22f
19211917
RCT-Folly: 36fe2295e44b10d831836cc0d1daec5f8abcf809
19221918
RCTDeprecation: 83ffb90c23ee5cea353bd32008a7bca100908f8c
19231919
RCTRequired: eb7c0aba998009f47a540bec9e9d69a54f68136e

example/src/App.tsx

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -34,18 +34,19 @@ const getDisplayName = (name: IndicatorName) => {
3434
export default function App() {
3535
const [speed, setSpeed] = useState(1.0);
3636
const indicators = getIndicators();
37-
37+
3838
const spacing = 10;
3939
const columns = 4;
4040
const itemWidth = (screenWidth - spacing * (columns + 1)) / columns;
4141
const itemHeight = itemWidth + 45; // Extra height for label
42-
42+
4343
const renderIndicator = (name: IndicatorName, index: number) => {
4444
const isIOSOnly = IOS_ONLY_INDICATORS.includes(name as any);
45-
const backgroundColor = isIOSOnly && Platform.OS === 'android'
46-
? 'rgba(255, 255, 255, 0.3)'
47-
: 'transparent';
48-
45+
const backgroundColor =
46+
isIOSOnly && Platform.OS === 'android'
47+
? 'rgba(255, 255, 255, 0.3)'
48+
: 'transparent';
49+
4950
return (
5051
<View
5152
key={name}
@@ -61,7 +62,7 @@ export default function App() {
6162
<View style={styles.indicatorWrapper}>
6263
<LoaderKitView
6364
name={name}
64-
color="white"
65+
color="blue"
6566
animationSpeedMultiplier={speed}
6667
style={styles.indicator}
6768
/>
@@ -106,11 +107,12 @@ export default function App() {
106107
<View style={styles.grid}>
107108
{indicators.map((name, index) => renderIndicator(name, index))}
108109
</View>
109-
110+
110111
{/* Platform Info */}
111112
<View style={styles.infoContainer}>
112113
<Text style={styles.infoText}>
113-
Platform: {Platform.OS.charAt(0).toUpperCase() + Platform.OS.slice(1)}
114+
Platform:{' '}
115+
{Platform.OS.charAt(0).toUpperCase() + Platform.OS.slice(1)}
114116
</Text>
115117
<Text style={styles.infoText}>
116118
Available Indicators: {indicators.length}

ios/LoaderKit-Bridging-Header.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
#import <React/RCTViewManager.h>

ios/LoaderKitView.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,4 @@ NS_ASSUME_NONNULL_END
1818

1919
#import "React/RCTViewManager.h"
2020

21-
@interface LoaderKitViewManager : RCTViewManager
22-
@end
23-
2421
#endif

ios/LoaderKitView.mm

Lines changed: 16 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,16 @@
11
#import "LoaderKitView.h"
2-
#import "NVActivityIndicatorView.h"
3-
#import "React/RCTConvert.h"
4-
5-
static const NSDictionary *nameToTypeMap = @{
6-
@"BallPulse": @(NVActivityIndicatorTypeBallPulse),
7-
@"BallGridPulse": @(NVActivityIndicatorTypeBallGridPulse),
8-
@"BallClipRotate": @(NVActivityIndicatorTypeBallClipRotate),
9-
@"SquareSpin": @(NVActivityIndicatorTypeSquareSpin),
10-
@"BallClipRotatePulse": @(NVActivityIndicatorTypeBallClipRotatePulse),
11-
@"BallClipRotateMultiple": @(NVActivityIndicatorTypeBallClipRotateMultiple),
12-
@"BallPulseRise": @(NVActivityIndicatorTypeBallPulseRise),
13-
@"BallRotate": @(NVActivityIndicatorTypeBallRotate),
14-
@"CubeTransition": @(NVActivityIndicatorTypeCubeTransition),
15-
@"BallZigZag": @(NVActivityIndicatorTypeBallZigZag),
16-
@"BallZigZagDeflect": @(NVActivityIndicatorTypeBallZigZagDeflect),
17-
@"BallTrianglePath": @(NVActivityIndicatorTypeBallTrianglePath),
18-
@"BallScale": @(NVActivityIndicatorTypeBallScale),
19-
@"LineScale": @(NVActivityIndicatorTypeLineScale),
20-
@"LineScaleParty": @(NVActivityIndicatorTypeLineScaleParty),
21-
@"BallScaleMultiple": @(NVActivityIndicatorTypeBallScaleMultiple),
22-
@"BallPulseSync": @(NVActivityIndicatorTypeBallPulseSync),
23-
@"BallBeat": @(NVActivityIndicatorTypeBallBeat),
24-
@"LineScalePulseOut": @(NVActivityIndicatorTypeLineScalePulseOut),
25-
@"LineScalePulseOutRapid": @(NVActivityIndicatorTypeLineScalePulseOutRapid),
26-
@"BallScaleRipple": @(NVActivityIndicatorTypeBallScaleRipple),
27-
@"BallScaleRippleMultiple": @(NVActivityIndicatorTypeBallScaleRippleMultiple),
28-
@"BallSpinFadeLoader": @(NVActivityIndicatorTypeBallSpinFadeLoader),
29-
@"LineSpinFadeLoader": @(NVActivityIndicatorTypeLineSpinFadeLoader),
30-
@"TriangleSkewSpin": @(NVActivityIndicatorTypeTriangleSkewSpin),
31-
@"Pacman": @(NVActivityIndicatorTypePacman),
32-
@"BallGridBeat": @(NVActivityIndicatorTypeBallGridBeat),
33-
@"SemiCircleSpin": @(NVActivityIndicatorTypeSemiCircleSpin),
34-
@"BallRotateChase": @(NVActivityIndicatorTypeBallRotateChase),
35-
@"Orbit": @(NVActivityIndicatorTypeOrbit),
36-
@"AudioEqualizer": @(NVActivityIndicatorTypeAudioEqualizer),
37-
@"CircleStrokeSpin": @(NVActivityIndicatorTypeCircleStrokeSpin),
38-
@"BallDoubleBounce": @(NVActivityIndicatorTypeBallDoubleBounce)
39-
};
402

413
#ifdef RCT_NEW_ARCH_ENABLED
424

5+
#import "React/RCTConvert.h"
6+
7+
#if __has_include(<LoaderKit/LoaderKit-Swift.h>)
8+
// if use_frameworks! :static
9+
#import <LoaderKit/LoaderKit-Swift.h>
10+
#else
11+
#import "LoaderKit-Swift.h"
12+
#endif
13+
4314
#import <react/renderer/components/LoaderKitViewSpec/ComponentDescriptors.h>
4415
#import <react/renderer/components/LoaderKitViewSpec/EventEmitters.h>
4516
#import <react/renderer/components/LoaderKitViewSpec/Props.h>
@@ -68,8 +39,8 @@ - (instancetype)initWithFrame:(CGRect)frame
6839
static const auto defaultProps = std::make_shared<const LoaderKitViewProps>();
6940
_props = defaultProps;
7041

71-
_indicatorView = [[NVActivityIndicatorView alloc] init];
72-
42+
_indicatorView = [[NVActivityIndicatorView alloc] initWithFrame:CGRectZero];
43+
7344
self.contentView = _indicatorView;
7445
}
7546

@@ -82,9 +53,7 @@ - (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &
8253
const auto &newViewProps = *std::static_pointer_cast<LoaderKitViewProps const>(props);
8354

8455
if (oldViewProps.name != newViewProps.name) {
85-
NSString * indicatorName = [[NSString alloc] initWithUTF8String: newViewProps.name.c_str()];
86-
NVActivityIndicatorType type = [self getIndicatorTypeFromName:indicatorName];
87-
_indicatorView.type = type;
56+
_indicatorView.name = [[NSString alloc] initWithUTF8String: newViewProps.name.c_str()];
8857
}
8958

9059
// Update color
@@ -104,65 +73,17 @@ - (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &
10473
return LoaderKitView.class;
10574
}
10675

107-
- (NVActivityIndicatorType)getIndicatorTypeFromName:(NSString *)name
108-
{
109-
if (!name) return NVActivityIndicatorTypeBallPulse;
110-
111-
NSNumber *typeNumber = nameToTypeMap[name];
112-
if (typeNumber) {
113-
return (NVActivityIndicatorType)[typeNumber integerValue];
114-
}
115-
116-
return NVActivityIndicatorTypeBallPulse; // Default fallback
117-
}
118-
11976
@end
12077

12178
#else
12279

123-
@implementation LoaderKitViewManager
80+
@interface RCT_EXTERN_MODULE(LoaderKitViewManager, RCTViewManager)
12481

125-
RCT_EXPORT_MODULE(LoaderKitView)
82+
RCT_EXPORT_VIEW_PROPERTY(name, NSString)
12683

127-
- (UIView *)view
128-
{
129-
return [[NVActivityIndicatorView alloc] init];
130-
}
84+
RCT_REMAP_VIEW_PROPERTY(color, colorRN, NSNumber) // map from "colorRN" of native view to "color" of react prop
13185

132-
- (NVActivityIndicatorType)getIndicatorTypeFromName:(NSString *)name
133-
{
134-
if (!name) return NVActivityIndicatorTypeBallPulse;
135-
136-
NSNumber *typeNumber = nameToTypeMap[name];
137-
if (typeNumber) {
138-
return (NVActivityIndicatorType)[typeNumber integerValue];
139-
}
140-
141-
return NVActivityIndicatorTypeBallPulse;
142-
}
143-
144-
RCT_CUSTOM_VIEW_PROPERTY(name, NSString, NVActivityIndicatorView)
145-
{
146-
NSString *indicatorName = [RCTConvert NSString:json];
147-
if (indicatorName) {
148-
NVActivityIndicatorType type = [self getIndicatorTypeFromName:indicatorName];
149-
view.type = type;
150-
}
151-
}
152-
153-
RCT_CUSTOM_VIEW_PROPERTY(color, UIColor, NVActivityIndicatorView)
154-
{
155-
UIColor *color = [RCTConvert UIColor:json];
156-
if (color) {
157-
view.color = color;
158-
}
159-
}
160-
161-
RCT_CUSTOM_VIEW_PROPERTY(animationSpeedMultiplier, CGFloat, NVActivityIndicatorView)
162-
{
163-
CGFloat speedMultiplier = [RCTConvert CGFloat:json];
164-
view.animationSpeedMultiplier = speedMultiplier;
165-
}
86+
RCT_REMAP_VIEW_PROPERTY(animationSpeedMultiplier, animationSpeedMultiplierRN, NSNumber) // map from "animationSpeedMultiplierRN" of native view to "animationSpeedMultiplier" of react prop
16687

16788
@end
16889

ios/LoaderKitView.swift

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
//
2+
// LoaderKitView.swift
3+
// LoaderKit
4+
//
5+
// Created by Duc Trung Mai on 10/21/25.
6+
//
7+
8+
import React
9+
10+
@objc(LoaderKitViewManager)
11+
class LoaderKitViewManager: RCTViewManager {
12+
13+
override func view() -> (NVActivityIndicatorView) {
14+
return NVActivityIndicatorView(frame: .zero)
15+
}
16+
17+
@objc override static func requiresMainQueueSetup() -> Bool {
18+
return true
19+
}
20+
}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
//
2+
// NVActivityIndicatorAnimationAudioEqualizer.swift
3+
// NVActivityIndicatorView
4+
//
5+
// The MIT License (MIT)
6+
7+
// Copyright (c) 2016 Vinh Nguyen
8+
9+
// Permission is hereby granted, free of charge, to any person obtaining a copy
10+
// of this software and associated documentation files (the "Software"), to deal
11+
// in the Software without restriction, including without limitation the rights
12+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13+
// copies of the Software, and to permit persons to whom the Software is
14+
// furnished to do so, subject to the following conditions:
15+
16+
// The above copyright notice and this permission notice shall be included in all
17+
// copies or substantial portions of the Software.
18+
19+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25+
// SOFTWARE.
26+
//
27+
28+
#if canImport(UIKit)
29+
import UIKit
30+
31+
class NVActivityIndicatorAnimationAudioEqualizer: NVActivityIndicatorAnimationDelegate {
32+
33+
func setUpAnimation(in layer: CALayer, size: CGSize, color: UIColor, animationSpeedMultiplier: CGFloat) {
34+
let lineSize = size.width / 9
35+
let x = (layer.bounds.size.width - lineSize * 7) / 2
36+
let y = (layer.bounds.size.height - size.height) / 2
37+
let duration: [CFTimeInterval] = [4.3 / CFTimeInterval(animationSpeedMultiplier),
38+
2.5 / CFTimeInterval(animationSpeedMultiplier),
39+
1.7 / CFTimeInterval(animationSpeedMultiplier),
40+
3.1 / CFTimeInterval(animationSpeedMultiplier)]
41+
let values = [0, 0.7, 0.4, 0.05, 0.95, 0.3, 0.9, 0.4, 0.15, 0.18, 0.75, 0.01]
42+
43+
// Draw lines
44+
for i in 0 ..< 4 {
45+
let animation = CAKeyframeAnimation()
46+
47+
animation.keyPath = "path"
48+
animation.isAdditive = true
49+
animation.values = []
50+
51+
for j in 0 ..< values.count {
52+
let heightFactor = values[j]
53+
let height = size.height * CGFloat(heightFactor)
54+
let point = CGPoint(x: 0, y: size.height - height)
55+
let path = UIBezierPath(rect: CGRect(origin: point, size: CGSize(width: lineSize, height: height)))
56+
57+
animation.values?.append(path.cgPath)
58+
}
59+
animation.duration = duration[i]
60+
animation.repeatCount = HUGE
61+
animation.isRemovedOnCompletion = false
62+
63+
let line = NVActivityIndicatorShape.line.layerWith(size: CGSize(width: lineSize, height: size.height), color: color)
64+
let frame = CGRect(x: x + lineSize * 2 * CGFloat(i),
65+
y: y,
66+
width: lineSize,
67+
height: size.height)
68+
69+
line.frame = frame
70+
line.add(animation, forKey: "animation")
71+
layer.addSublayer(line)
72+
}
73+
}
74+
}
75+
#endif

0 commit comments

Comments
 (0)