react-native-attachment-kit 1.0.9 → 1.0.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +16 -0
- package/android/src/main/libs/rnattachmentkit-release.aar +0 -0
- package/android/src/newarch/java/com/rnattachmentkit/RNAttachmentKitModule.kt +12 -1
- package/android/src/oldarch/java/com/rnattachmentkit/RNAttachmentKitModule.kt +12 -1
- package/ios/RNAttachmentKit.swift +35 -11
- package/ios/RNAttachmentKit.xcframework/Info.plist +5 -5
- package/ios/RNAttachmentKit.xcframework/ios-arm64/RNAttachmentKit.framework/Assets.car +0 -0
- package/ios/RNAttachmentKit.xcframework/ios-arm64/RNAttachmentKit.framework/Modules/RNAttachmentKit.swiftmodule/arm64-apple-ios.abi.json +190 -94
- package/ios/RNAttachmentKit.xcframework/ios-arm64/RNAttachmentKit.framework/Modules/RNAttachmentKit.swiftmodule/arm64-apple-ios.private.swiftinterface +1 -0
- package/ios/RNAttachmentKit.xcframework/ios-arm64/RNAttachmentKit.framework/Modules/RNAttachmentKit.swiftmodule/arm64-apple-ios.swiftdoc +0 -0
- package/ios/RNAttachmentKit.xcframework/ios-arm64/RNAttachmentKit.framework/Modules/RNAttachmentKit.swiftmodule/arm64-apple-ios.swiftinterface +1 -0
- package/ios/RNAttachmentKit.xcframework/ios-arm64/RNAttachmentKit.framework/RNAttachmentKit +0 -0
- package/ios/RNAttachmentKit.xcframework/ios-arm64/RNAttachmentKit.framework/_CodeSignature/CodeDirectory +0 -0
- package/ios/RNAttachmentKit.xcframework/ios-arm64/RNAttachmentKit.framework/_CodeSignature/CodeResources +12 -12
- package/ios/RNAttachmentKit.xcframework/ios-arm64/RNAttachmentKit.framework/_CodeSignature/CodeSignature +0 -0
- package/ios/RNAttachmentKit.xcframework/ios-arm64_x86_64-simulator/RNAttachmentKit.framework/Modules/RNAttachmentKit.swiftmodule/arm64-apple-ios-simulator.abi.json +190 -94
- package/ios/RNAttachmentKit.xcframework/ios-arm64_x86_64-simulator/RNAttachmentKit.framework/Modules/RNAttachmentKit.swiftmodule/arm64-apple-ios-simulator.private.swiftinterface +1 -0
- package/ios/RNAttachmentKit.xcframework/ios-arm64_x86_64-simulator/RNAttachmentKit.framework/Modules/RNAttachmentKit.swiftmodule/arm64-apple-ios-simulator.swiftdoc +0 -0
- package/ios/RNAttachmentKit.xcframework/ios-arm64_x86_64-simulator/RNAttachmentKit.framework/Modules/RNAttachmentKit.swiftmodule/arm64-apple-ios-simulator.swiftinterface +1 -0
- package/ios/RNAttachmentKit.xcframework/ios-arm64_x86_64-simulator/RNAttachmentKit.framework/Modules/RNAttachmentKit.swiftmodule/x86_64-apple-ios-simulator.abi.json +190 -94
- package/ios/RNAttachmentKit.xcframework/ios-arm64_x86_64-simulator/RNAttachmentKit.framework/Modules/RNAttachmentKit.swiftmodule/x86_64-apple-ios-simulator.private.swiftinterface +1 -0
- package/ios/RNAttachmentKit.xcframework/ios-arm64_x86_64-simulator/RNAttachmentKit.framework/Modules/RNAttachmentKit.swiftmodule/x86_64-apple-ios-simulator.swiftdoc +0 -0
- package/ios/RNAttachmentKit.xcframework/ios-arm64_x86_64-simulator/RNAttachmentKit.framework/Modules/RNAttachmentKit.swiftmodule/x86_64-apple-ios-simulator.swiftinterface +1 -0
- package/ios/RNAttachmentKit.xcframework/ios-arm64_x86_64-simulator/RNAttachmentKit.framework/RNAttachmentKit +0 -0
- package/ios/RNAttachmentKit.xcframework/ios-arm64_x86_64-simulator/RNAttachmentKit.framework/_CodeSignature/CodeDirectory +0 -0
- package/ios/RNAttachmentKit.xcframework/ios-arm64_x86_64-simulator/RNAttachmentKit.framework/_CodeSignature/CodeResources +20 -20
- package/package.json +1 -1
- package/src/types.ts +6 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.0.11 — 2026-10-20
|
|
4
|
+
|
|
5
|
+
- Viewer: `showDeleteButton` option (iOS + Android) — hides only the trash icon in the top bar (default `true`; save / share stay).
|
|
6
|
+
- Android: the gallery camera cell's "Tap to allow camera" is localized (59 languages).
|
|
7
|
+
- Android: the picker asks for video permission once when only "selected photos" access was granted (Android 14+).
|
|
8
|
+
|
|
9
|
+
## 1.0.10 — 2026-10-19
|
|
10
|
+
|
|
11
|
+
- iOS: photos just saved from another app (e.g. KakaoTalk) now show at the top of "최근 항목". Recents is ordered by when photos were added (like the Photos app and the Android picker) instead of capture date — a saved photo keeps its original EXIF date and used to land far down the list.
|
|
12
|
+
|
|
13
|
+
## 1.0.9 — 2026-10-19
|
|
14
|
+
|
|
15
|
+
- **Location, video and AI need a license key** (`init`). Without one only photos work (pick, edit with watermark, view): the Location tab, AI buttons and video recording show a "License required" notice, `mediaType` video/all shows photos only, and `openMapViewer` / `renderLocationThumbnail` / `reverseGeocode` / video viewer APIs reject with `E_LICENSE_REQUIRED`.
|
|
16
|
+
- Photo thumbnails: `thumbnail` option for `openGallery` / `openEditor`.
|
|
17
|
+
- Android: 16 KB page size support; Back closes the overlay viewer; Android 14+ "Allow limited access" works in the picker.
|
|
18
|
+
|
|
3
19
|
## 1.0.8 — 2026-10-16
|
|
4
20
|
|
|
5
21
|
- **AI screens are the same in every app (iOS + Android)**. Generate: woman / man, country, age (up to the 80s), style, situation, aspect ratio + Create, sample chips and the chat input; chat text is sent together with the chosen settings, and tapping a sample shows a summary of the settings before creating. The glamour situations / samples and the detail options were removed from the generate screen. Edit: the full editing screen everywhere. Generated and edited images are stored for the gallery's "AI 이미지" tab in every app.
|
|
Binary file
|
|
@@ -506,7 +506,11 @@ class RNAttachmentKitModule(reactContext: ReactApplicationContext) :
|
|
|
506
506
|
}
|
|
507
507
|
|
|
508
508
|
val permissionsToRequest = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE && permission == Manifest.permission.READ_MEDIA_IMAGES) {
|
|
509
|
-
|
|
509
|
+
// 일부만 허용한 사용자는 열 때마다 사진 선택 창을 다시 띄우지 않으려고 바로 엶.
|
|
510
|
+
// 단 동영상도 보여야 하는데 READ_MEDIA_VIDEO 를 한 번도 묻지 않았으면 한 번은 물어봄 — 예전엔 사진 전용으로
|
|
511
|
+
// 권한을 받은 사용자(예: 가입 때 프로필 사진)가 여기서 바로 열려 동영상 권한을 영영 묻지 않아 동영상이 안 보였음
|
|
512
|
+
if (ContextCompat.checkSelfPermission(fragmentActivity, Manifest.permission.READ_MEDIA_VISUAL_USER_SELECTED) == PackageManager.PERMISSION_GRANTED &&
|
|
513
|
+
(mediaType == "photo" || ContextCompat.checkSelfPermission(fragmentActivity, Manifest.permission.READ_MEDIA_VIDEO) == PackageManager.PERMISSION_GRANTED || wasVideoPermissionAsked())) {
|
|
510
514
|
showSheet()
|
|
511
515
|
return
|
|
512
516
|
}
|
|
@@ -515,6 +519,7 @@ class RNAttachmentKitModule(reactContext: ReactApplicationContext) :
|
|
|
515
519
|
mediaPermissions
|
|
516
520
|
}
|
|
517
521
|
|
|
522
|
+
if (permissionsToRequest.contains(Manifest.permission.READ_MEDIA_VIDEO)) markVideoPermissionAsked()
|
|
518
523
|
permissionAwareActivity.requestPermissions(permissionsToRequest, 100, object : PermissionListener {
|
|
519
524
|
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray): Boolean {
|
|
520
525
|
if (requestCode == 100 && grantResults != null) {
|
|
@@ -537,6 +542,11 @@ class RNAttachmentKitModule(reactContext: ReactApplicationContext) :
|
|
|
537
542
|
}
|
|
538
543
|
}
|
|
539
544
|
|
|
545
|
+
// 동영상 권한(READ_MEDIA_VIDEO)을 한 번 물어봤는지 — 물어본 뒤 거절했으면 다시 묻지 않음 (Android 14+ 일부 허용 경로)
|
|
546
|
+
private fun mediaPermPrefs() = reactApplicationContext.getSharedPreferences("rnak_media_perm", android.content.Context.MODE_PRIVATE)
|
|
547
|
+
private fun wasVideoPermissionAsked(): Boolean = mediaPermPrefs().getBoolean("video_asked", false)
|
|
548
|
+
private fun markVideoPermissionAsked() { mediaPermPrefs().edit().putBoolean("video_asked", true).apply() }
|
|
549
|
+
|
|
540
550
|
override fun openViewer(options: ReadableMap, promise: Promise) {
|
|
541
551
|
// 동영상 페이지는 라이선스 키가 있어야
|
|
542
552
|
if (!LicenseGate.isLicensed && options.hasKey("videos")) {
|
|
@@ -688,6 +698,7 @@ class RNAttachmentKitModule(reactContext: ReactApplicationContext) :
|
|
|
688
698
|
// 상단바 저장/공유/삭제 버튼과 그 문구들 (iOS와 동일한 옵션 키). 문구를 안 넘기면
|
|
689
699
|
// 네이티브 쪽 로케일 리소스(values-ko/ja/zh, 그 외 en)가 자동 적용됩니다.
|
|
690
700
|
putBoolean("showActionButtons", !options.hasKey("showActionButtons") || options.getBoolean("showActionButtons"))
|
|
701
|
+
putBoolean("showDeleteButton", !options.hasKey("showDeleteButton") || options.getBoolean("showDeleteButton"))
|
|
691
702
|
for (key in listOf(
|
|
692
703
|
"saveAllText", "saveOneText", "shareAllText", "shareOneText", "actionCancelText",
|
|
693
704
|
"deleteConfirmTitle", "deleteConfirmMessage", "deleteConfirmGroupMessage", "deleteButtonText"
|
|
@@ -444,7 +444,11 @@ class RNAttachmentKitModule(reactContext: ReactApplicationContext) :
|
|
|
444
444
|
}
|
|
445
445
|
|
|
446
446
|
val permissionsToRequest = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE && permission == Manifest.permission.READ_MEDIA_IMAGES) {
|
|
447
|
-
|
|
447
|
+
// 일부만 허용한 사용자는 열 때마다 사진 선택 창을 다시 띄우지 않으려고 바로 엶.
|
|
448
|
+
// 단 동영상도 보여야 하는데 READ_MEDIA_VIDEO 를 한 번도 묻지 않았으면 한 번은 물어봄 — 예전엔 사진 전용으로
|
|
449
|
+
// 권한을 받은 사용자(예: 가입 때 프로필 사진)가 여기서 바로 열려 동영상 권한을 영영 묻지 않아 동영상이 안 보였음
|
|
450
|
+
if (ContextCompat.checkSelfPermission(fragmentActivity, Manifest.permission.READ_MEDIA_VISUAL_USER_SELECTED) == PackageManager.PERMISSION_GRANTED &&
|
|
451
|
+
(mediaType == "photo" || ContextCompat.checkSelfPermission(fragmentActivity, Manifest.permission.READ_MEDIA_VIDEO) == PackageManager.PERMISSION_GRANTED || wasVideoPermissionAsked())) {
|
|
448
452
|
showSheet()
|
|
449
453
|
return
|
|
450
454
|
}
|
|
@@ -453,6 +457,7 @@ class RNAttachmentKitModule(reactContext: ReactApplicationContext) :
|
|
|
453
457
|
mediaPermissions
|
|
454
458
|
}
|
|
455
459
|
|
|
460
|
+
if (permissionsToRequest.contains(Manifest.permission.READ_MEDIA_VIDEO)) markVideoPermissionAsked()
|
|
456
461
|
permissionAwareActivity.requestPermissions(permissionsToRequest, 100, object : PermissionListener {
|
|
457
462
|
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray): Boolean {
|
|
458
463
|
if (requestCode == 100 && grantResults != null) {
|
|
@@ -545,6 +550,11 @@ class RNAttachmentKitModule(reactContext: ReactApplicationContext) :
|
|
|
545
550
|
}
|
|
546
551
|
|
|
547
552
|
@ReactMethod
|
|
553
|
+
// 동영상 권한(READ_MEDIA_VIDEO)을 한 번 물어봤는지 — 물어본 뒤 거절했으면 다시 묻지 않음 (Android 14+ 일부 허용 경로)
|
|
554
|
+
private fun mediaPermPrefs() = reactApplicationContext.getSharedPreferences("rnak_media_perm", android.content.Context.MODE_PRIVATE)
|
|
555
|
+
private fun wasVideoPermissionAsked(): Boolean = mediaPermPrefs().getBoolean("video_asked", false)
|
|
556
|
+
private fun markVideoPermissionAsked() { mediaPermPrefs().edit().putBoolean("video_asked", true).apply() }
|
|
557
|
+
|
|
548
558
|
override fun openViewer(options: ReadableMap, promise: Promise) {
|
|
549
559
|
// 동영상 페이지는 라이선스 키가 있어야
|
|
550
560
|
if (!LicenseGate.isLicensed && options.hasKey("videos")) {
|
|
@@ -697,6 +707,7 @@ class RNAttachmentKitModule(reactContext: ReactApplicationContext) :
|
|
|
697
707
|
// 상단바 저장/공유/삭제 버튼과 그 문구들 (iOS와 동일한 옵션 키). 문구를 안 넘기면
|
|
698
708
|
// 네이티브 쪽 로케일 리소스(values-ko/ja/zh, 그 외 en)가 자동 적용됩니다.
|
|
699
709
|
putBoolean("showActionButtons", !options.hasKey("showActionButtons") || options.getBoolean("showActionButtons"))
|
|
710
|
+
putBoolean("showDeleteButton", !options.hasKey("showDeleteButton") || options.getBoolean("showDeleteButton"))
|
|
700
711
|
for (key in listOf(
|
|
701
712
|
"saveAllText", "saveOneText", "shareAllText", "shareOneText", "actionCancelText",
|
|
702
713
|
"deleteConfirmTitle", "deleteConfirmMessage", "deleteConfirmGroupMessage", "deleteButtonText"
|
|
@@ -448,6 +448,7 @@ class RNAttachmentKit: RCTEventEmitter {
|
|
|
448
448
|
// 저장/공유/삭제 상단바 버튼 - 사용자가 준 스크린샷(전체 저장/이 사진만 저장 등)에
|
|
449
449
|
// 맞춘 기본 한국어 문구가 있으므로, JS에서 안 넘기면 그 기본값을 그대로 씁니다.
|
|
450
450
|
let showActionButtons = (options["showActionButtons"] as? Bool) ?? true
|
|
451
|
+
let showDeleteButton = (options["showDeleteButton"] as? Bool) ?? true
|
|
451
452
|
let saveAllText = options["saveAllText"] as? String
|
|
452
453
|
let saveOneText = options["saveOneText"] as? String
|
|
453
454
|
let shareAllText = options["shareAllText"] as? String
|
|
@@ -528,6 +529,7 @@ class RNAttachmentKit: RCTEventEmitter {
|
|
|
528
529
|
viewerVC.themeColor = color
|
|
529
530
|
}
|
|
530
531
|
viewerVC.showActionButtons = showActionButtons
|
|
532
|
+
viewerVC.showDeleteButton = showDeleteButton
|
|
531
533
|
if let saveAllText = saveAllText { viewerVC.saveAllText = saveAllText }
|
|
532
534
|
if let saveOneText = saveOneText { viewerVC.saveOneText = saveOneText }
|
|
533
535
|
if let shareAllText = shareAllText { viewerVC.shareAllText = shareAllText }
|
|
@@ -701,7 +703,7 @@ class RNAttachmentKit: RCTEventEmitter {
|
|
|
701
703
|
let parsedThumbnail = PhotoThumbnailOptions(options["thumbnail"])
|
|
702
704
|
|
|
703
705
|
DispatchQueue.main.async {
|
|
704
|
-
guard
|
|
706
|
+
guard self.getRootViewController() != nil else {
|
|
705
707
|
reject("ERROR", "Unable to get root view controller", nil)
|
|
706
708
|
return
|
|
707
709
|
}
|
|
@@ -752,11 +754,7 @@ class RNAttachmentKit: RCTEventEmitter {
|
|
|
752
754
|
}
|
|
753
755
|
}
|
|
754
756
|
|
|
755
|
-
|
|
756
|
-
while let presented = topController.presentedViewController {
|
|
757
|
-
topController = presented
|
|
758
|
-
}
|
|
759
|
-
topController.present(editorVC, animated: true)
|
|
757
|
+
self.presentOnTop(editorVC, reject: reject)
|
|
760
758
|
|
|
761
759
|
} else {
|
|
762
760
|
guard let url = URL(string: uri) ?? URL(string: "file://" + uri.replacingOccurrences(of: "file://", with: "")) else {
|
|
@@ -796,11 +794,7 @@ class RNAttachmentKit: RCTEventEmitter {
|
|
|
796
794
|
}
|
|
797
795
|
}
|
|
798
796
|
|
|
799
|
-
|
|
800
|
-
while let presented = topController.presentedViewController {
|
|
801
|
-
topController = presented
|
|
802
|
-
}
|
|
803
|
-
topController.present(editorVC, animated: true)
|
|
797
|
+
self.presentOnTop(editorVC, reject: reject)
|
|
804
798
|
}
|
|
805
799
|
} else {
|
|
806
800
|
DispatchQueue.main.async {
|
|
@@ -1776,6 +1770,36 @@ class RNAttachmentKit: RCTEventEmitter {
|
|
|
1776
1770
|
return (fileName, fileExtension, fileSize)
|
|
1777
1771
|
}
|
|
1778
1772
|
|
|
1773
|
+
/// 맨 위 컨트롤러에 present. 맨 위가 닫히거나 열리는 중이면(예: openGallery 가 끝난 직후 갤러리 시트가
|
|
1774
|
+
/// 닫히는 애니메이션) UIKit 이 present 를 조용히 버리므로, 전환이 끝난 뒤 다시 시도합니다.
|
|
1775
|
+
/// 끝내 present 되지 않으면 reject — 안 그러면 JS 약속이 안 풀리고 _editorOpen 가드에 계속 막힙니다.
|
|
1776
|
+
private func presentOnTop(_ vc: UIViewController, reject: @escaping RCTPromiseRejectBlock, attempt: Int = 0) {
|
|
1777
|
+
guard let top = getRootViewController() else {
|
|
1778
|
+
reject("E_NO_ROOT", "Unable to get root view controller", nil)
|
|
1779
|
+
return
|
|
1780
|
+
}
|
|
1781
|
+
if (top.isBeingDismissed || top.isBeingPresented) && attempt < 20 {
|
|
1782
|
+
let retry: () -> Void = { [weak self] in
|
|
1783
|
+
guard let self = self else {
|
|
1784
|
+
reject("E_PRESENT_FAILED", "Module deallocated", nil)
|
|
1785
|
+
return
|
|
1786
|
+
}
|
|
1787
|
+
self.presentOnTop(vc, reject: reject, attempt: attempt + 1)
|
|
1788
|
+
}
|
|
1789
|
+
if let coordinator = top.transitionCoordinator {
|
|
1790
|
+
coordinator.animate(alongsideTransition: nil) { _ in DispatchQueue.main.async(execute: retry) }
|
|
1791
|
+
} else {
|
|
1792
|
+
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1, execute: retry)
|
|
1793
|
+
}
|
|
1794
|
+
return
|
|
1795
|
+
}
|
|
1796
|
+
top.present(vc, animated: true)
|
|
1797
|
+
// present 가 받아들여지면 presentingViewController 가 바로 잡힘. nil 이면 UIKit 이 거부한 것
|
|
1798
|
+
if vc.presentingViewController == nil {
|
|
1799
|
+
reject("E_PRESENT_FAILED", "Unable to present \(type(of: vc)) on \(type(of: top))", nil)
|
|
1800
|
+
}
|
|
1801
|
+
}
|
|
1802
|
+
|
|
1779
1803
|
private func getRootViewController() -> UIViewController? {
|
|
1780
1804
|
var rootViewController: UIViewController?
|
|
1781
1805
|
|
|
@@ -8,32 +8,32 @@
|
|
|
8
8
|
<key>BinaryPath</key>
|
|
9
9
|
<string>RNAttachmentKit.framework/RNAttachmentKit</string>
|
|
10
10
|
<key>LibraryIdentifier</key>
|
|
11
|
-
<string>ios-
|
|
11
|
+
<string>ios-arm64_x86_64-simulator</string>
|
|
12
12
|
<key>LibraryPath</key>
|
|
13
13
|
<string>RNAttachmentKit.framework</string>
|
|
14
14
|
<key>SupportedArchitectures</key>
|
|
15
15
|
<array>
|
|
16
16
|
<string>arm64</string>
|
|
17
|
+
<string>x86_64</string>
|
|
17
18
|
</array>
|
|
18
19
|
<key>SupportedPlatform</key>
|
|
19
20
|
<string>ios</string>
|
|
21
|
+
<key>SupportedPlatformVariant</key>
|
|
22
|
+
<string>simulator</string>
|
|
20
23
|
</dict>
|
|
21
24
|
<dict>
|
|
22
25
|
<key>BinaryPath</key>
|
|
23
26
|
<string>RNAttachmentKit.framework/RNAttachmentKit</string>
|
|
24
27
|
<key>LibraryIdentifier</key>
|
|
25
|
-
<string>ios-
|
|
28
|
+
<string>ios-arm64</string>
|
|
26
29
|
<key>LibraryPath</key>
|
|
27
30
|
<string>RNAttachmentKit.framework</string>
|
|
28
31
|
<key>SupportedArchitectures</key>
|
|
29
32
|
<array>
|
|
30
33
|
<string>arm64</string>
|
|
31
|
-
<string>x86_64</string>
|
|
32
34
|
</array>
|
|
33
35
|
<key>SupportedPlatform</key>
|
|
34
36
|
<string>ios</string>
|
|
35
|
-
<key>SupportedPlatformVariant</key>
|
|
36
|
-
<string>simulator</string>
|
|
37
37
|
</dict>
|
|
38
38
|
</array>
|
|
39
39
|
<key>CFBundlePackageType</key>
|