license headers

pull/260/head
Lucas Nogueira 2 years ago
parent 6940f74acd
commit c34afb7187
No known key found for this signature in database
GPG Key ID: 7C32FCA95C8C95D7

@ -27,7 +27,7 @@ const ignore = [
async function checkFile(file) {
if (
extensions.some((e) => file.endsWith(e)) &&
!ignore.some((i) => file.endsWith(i))
!ignore.some((i) => file.includes(i))
) {
const fileStream = fs.createReadStream(file);
const rl = readline.createInterface({
@ -113,7 +113,8 @@ if (files.length > 0) {
run();
} else {
check(path.resolve(new URL(import.meta.url).pathname, "../../..")).then(
check(path.resolve(new URL(
import.meta.url).pathname, "../../..")).then(
(missing) => {
if (missing.length > 0) {
console.log(missing.join("\n"));

@ -1,3 +1,7 @@
// Copyright 2019-2023 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
package app.tauri.camera
import androidx.test.platform.app.InstrumentationRegistry

@ -1,3 +1,7 @@
// Copyright 2019-2023 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
package app.tauri.camera
import android.annotation.SuppressLint

@ -1,3 +1,7 @@
// Copyright 2019-2023 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
package app.tauri.camera
import android.Manifest

@ -1,3 +1,7 @@
// Copyright 2019-2023 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
package app.tauri.camera
import android.app.Activity

@ -1,3 +1,7 @@
// Copyright 2019-2023 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
package app.tauri.camera
import androidx.exifinterface.media.ExifInterface.*

@ -1,3 +1,7 @@
// Copyright 2019-2023 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
package app.tauri.camera
import android.content.Context

@ -1,3 +1,7 @@
// Copyright 2019-2023 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
package app.tauri.camera
import org.junit.Test

@ -1,3 +1,7 @@
// Copyright 2019-2023 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
export declare enum Source {
Prompt = "PROMPT",
Camera = "CAMERA",

@ -1,4 +1,7 @@
// swift-tools-version:5.3
// Copyright 2019-2023 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
// The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription
@ -6,14 +9,14 @@ import PackageDescription
let package = Package(
name: "tauri-plugin-camera",
platforms: [
.iOS(.v11),
.iOS(.v11)
],
products: [
// Products define the executables and libraries a package produces, and make them visible to other packages.
.library(
name: "tauri-plugin-camera",
type: .static,
targets: ["tauri-plugin-camera"]),
targets: ["tauri-plugin-camera"])
],
dependencies: [
.package(name: "Tauri", path: "../.tauri/tauri-api")

@ -1,5 +1,9 @@
import UIKit
// Copyright 2019-2023 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
import Photos
import UIKit
internal protocol CameraAuthorizationState {
var authorizationState: String { get }
@ -40,7 +44,7 @@ extension PHAuthorizationStatus: CameraAuthorizationState {
}
}
internal extension PHAsset {
extension PHAsset {
/**
Retrieves the image metadata for the asset.
*/
@ -52,11 +56,13 @@ internal extension PHAsset {
options.version = .current
var result: [String: Any] = [:]
_ = PHCachingImageManager().requestImageDataAndOrientation(for: self, options: options) { (data, _, _, _) in
_ = PHCachingImageManager().requestImageDataAndOrientation(for: self, options: options) {
(data, _, _, _) in
if let data = data as NSData? {
let options = [kCGImageSourceShouldCache as String: kCFBooleanFalse] as CFDictionary
if let imgSrc = CGImageSourceCreateWithData(data, options),
let metadata = CGImageSourceCopyPropertiesAtIndex(imgSrc, 0, options) as? [String: Any] {
let metadata = CGImageSourceCopyPropertiesAtIndex(imgSrc, 0, options) as? [String: Any]
{
result = metadata
}
}
@ -65,7 +71,7 @@ internal extension PHAsset {
}
}
internal extension UIImage {
extension UIImage {
/**
Generates a new image from the existing one, implicitly resetting any orientation.
Dimensions greater than 0 will resize the image while preserving the aspect ratio.
@ -97,7 +103,8 @@ internal extension UIImage {
let format: UIGraphicsImageRendererFormat = UIGraphicsImageRendererFormat.default()
format.scale = 1.0
format.opaque = false
let renderer = UIGraphicsImageRenderer(size: CGSize(width: targetWidth, height: targetHeight), format: format)
let renderer = UIGraphicsImageRenderer(
size: CGSize(width: targetWidth, height: targetHeight), format: format)
return renderer.image { (_) in
self.draw(in: CGRect(origin: .zero, size: CGSize(width: targetWidth, height: targetHeight)))
}

@ -1,8 +1,12 @@
import UIKit
import WebKit
import Tauri
// Copyright 2019-2023 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
import Photos
import PhotosUI
import Tauri
import UIKit
import WebKit
public class CameraPlugin: Plugin {
private var invoke: Invoke?
@ -34,11 +38,13 @@ public class CameraPlugin: Plugin {
@objc override public func requestPermissions(_ invoke: Invoke) {
// get the list of desired types, if passed
let typeList = invoke.getArray("permissions", String.self)?.compactMap({ (type) -> CameraPermissionType? in
let typeList =
invoke.getArray("permissions", String.self)?.compactMap({ (type) -> CameraPermissionType? in
return CameraPermissionType(rawValue: type)
}) ?? []
// otherwise check everything
let permissions: [CameraPermissionType] = (typeList.count > 0) ? typeList : CameraPermissionType.allCases
let permissions: [CameraPermissionType] =
(typeList.count > 0) ? typeList : CameraPermissionType.allCases
// request the permissions
let group = DispatchGroup()
for permission in permissions {
@ -115,7 +121,9 @@ public class CameraPlugin: Plugin {
let fullSize = CGSize(width: asset.pixelWidth, height: asset.pixelHeight)
group.enter()
imageManager.requestImage(for: asset, targetSize: fullSize, contentMode: .default, options: options) { image, _ in
imageManager.requestImage(
for: asset, targetSize: fullSize, contentMode: .default, options: options
) { image, _ in
guard let image = image else {
group.leave()
return
@ -186,9 +194,14 @@ public class CameraPlugin: Plugin {
var settings = CameraSettings()
settings.jpegQuality = min(abs(CGFloat(invoke.getFloat("quality") ?? 100.0)) / 100.0, 1.0)
settings.allowEditing = invoke.getBool("allowEditing") ?? false
settings.source = CameraSource(rawValue: invoke.getString("source") ?? defaultSource.rawValue) ?? defaultSource
settings.direction = CameraDirection(rawValue: invoke.getString("direction") ?? defaultDirection.rawValue) ?? defaultDirection
if let typeString = invoke.getString("resultType"), let type = CameraResultType(rawValue: typeString) {
settings.source =
CameraSource(rawValue: invoke.getString("source") ?? defaultSource.rawValue) ?? defaultSource
settings.direction =
CameraDirection(rawValue: invoke.getString("direction") ?? defaultDirection.rawValue)
?? defaultDirection
if let typeString = invoke.getString("resultType"),
let type = CameraResultType(rawValue: typeString)
{
settings.resultType = type
}
settings.saveToGallery = invoke.getBool("saveToGallery") ?? false
@ -201,7 +214,8 @@ public class CameraPlugin: Plugin {
settings.shouldResize = true
}
settings.shouldCorrectOrientation = invoke.getBool("correctOrientation") ?? true
settings.userPromptText = CameraPromptText(title: invoke.getString("promptLabelHeader"),
settings.userPromptText = CameraPromptText(
title: invoke.getString("promptLabelHeader"),
photoAction: invoke.getString("promptLabelPhoto"),
cameraAction: invoke.getString("promptLabelPicture"),
cancelAction: invoke.getString("promptLabelCancel"))
@ -216,13 +230,17 @@ public class CameraPlugin: Plugin {
}
// public delegate methods
extension CameraPlugin: UIImagePickerControllerDelegate, UINavigationControllerDelegate, UIPopoverPresentationControllerDelegate {
extension CameraPlugin: UIImagePickerControllerDelegate, UINavigationControllerDelegate,
UIPopoverPresentationControllerDelegate
{
public func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
picker.dismiss(animated: true)
self.invoke?.reject("User cancelled photos app")
}
public func popoverPresentationControllerDidDismissPopover(_ popoverPresentationController: UIPopoverPresentationController) {
public func popoverPresentationControllerDidDismissPopover(
_ popoverPresentationController: UIPopoverPresentationController
) {
self.invoke?.reject("User cancelled photos app")
}
@ -230,7 +248,10 @@ extension CameraPlugin: UIImagePickerControllerDelegate, UINavigationControllerD
self.invoke?.reject("User cancelled photos app")
}
public func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any]) {
public func imagePickerController(
_ picker: UIImagePickerController,
didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any]
) {
picker.dismiss(animated: true) {
if let processedImage = self.processImage(from: info) {
self.returnProcessedImage(processedImage)
@ -301,8 +322,8 @@ extension CameraPlugin: PHPickerViewControllerDelegate {
}
}
private extension CameraPlugin {
func returnImage(_ processedImage: ProcessedImage, isSaved: Bool) {
extension CameraPlugin {
fileprivate func returnImage(_ processedImage: ProcessedImage, isSaved: Bool) {
guard let jpeg = processedImage.generateJPEG(with: settings.jpegQuality) else {
self.invoke?.reject("Unable to convert image to jpeg")
return
@ -310,18 +331,21 @@ private extension CameraPlugin {
if settings.resultType == CameraResultType.uri || multiple {
guard let fileURL = try? saveTemporaryImage(jpeg),
let webURL = manager.assetUrl(fromLocalURL: fileURL) else {
let webURL = manager.assetUrl(fromLocalURL: fileURL)
else {
invoke?.reject("Unable to get asset URL to file")
return
}
if self.multiple {
invoke?.resolve([
"photos": [[
"photos": [
[
"data": fileURL.absoluteString,
"exif": processedImage.exifData,
"assetUrl": webURL.absoluteString,
"format": "jpeg"
]]
"format": "jpeg",
]
]
])
return
}
@ -330,26 +354,26 @@ private extension CameraPlugin {
"exif": processedImage.exifData,
"assetUrl": webURL.absoluteString,
"format": "jpeg",
"saved": isSaved
"saved": isSaved,
])
} else if settings.resultType == CameraResultType.base64 {
self.invoke?.resolve([
"data": jpeg.base64EncodedString(),
"exif": processedImage.exifData,
"format": "jpeg",
"saved": isSaved
"saved": isSaved,
])
} else if settings.resultType == CameraResultType.dataURL {
invoke?.resolve([
"data": "data:image/jpeg;base64," + jpeg.base64EncodedString(),
"exif": processedImage.exifData,
"format": "jpeg",
"saved": isSaved
"saved": isSaved,
])
}
}
func returnImages(_ processedImages: [ProcessedImage]) {
fileprivate func returnImages(_ processedImages: [ProcessedImage]) {
var photos: [JsonObject] = []
for processedImage in processedImages {
guard let jpeg = processedImage.generateJPEG(with: settings.jpegQuality) else {
@ -358,7 +382,8 @@ private extension CameraPlugin {
}
guard let fileURL = try? saveTemporaryImage(jpeg),
let webURL = manager.assetUrl(fromLocalURL: fileURL) else {
let webURL = manager.assetUrl(fromLocalURL: fileURL)
else {
invoke?.reject("Unable to get asset URL to file")
return
}
@ -367,7 +392,7 @@ private extension CameraPlugin {
"path": fileURL.absoluteString,
"exif": processedImage.exifData,
"assetUrl": webURL.absoluteString,
"format": "jpeg"
"format": "jpeg",
])
}
invoke?.resolve([
@ -375,9 +400,12 @@ private extension CameraPlugin {
])
}
func returnProcessedImage(_ processedImage: ProcessedImage) {
fileprivate func returnProcessedImage(_ processedImage: ProcessedImage) {
// conditionally save the image
if settings.saveToGallery && (processedImage.flags.contains(.edited) == true || processedImage.flags.contains(.gallery) == false) {
if settings.saveToGallery
&& (processedImage.flags.contains(.edited) == true
|| processedImage.flags.contains(.gallery) == false)
{
_ = ImageSaver(image: processedImage.image) { error in
var isSaved = false
if error == nil {
@ -390,27 +418,40 @@ private extension CameraPlugin {
}
}
func showPrompt() {
fileprivate func showPrompt() {
// Build the action sheet
let alert = UIAlertController(title: settings.userPromptText.title, message: nil, preferredStyle: UIAlertController.Style.actionSheet)
alert.addAction(UIAlertAction(title: settings.userPromptText.photoAction, style: .default, handler: { [weak self] (_: UIAlertAction) in
let alert = UIAlertController(
title: settings.userPromptText.title, message: nil,
preferredStyle: UIAlertController.Style.actionSheet)
alert.addAction(
UIAlertAction(
title: settings.userPromptText.photoAction, style: .default,
handler: { [weak self] (_: UIAlertAction) in
self?.showPhotos()
}))
alert.addAction(UIAlertAction(title: settings.userPromptText.cameraAction, style: .default, handler: { [weak self] (_: UIAlertAction) in
alert.addAction(
UIAlertAction(
title: settings.userPromptText.cameraAction, style: .default,
handler: { [weak self] (_: UIAlertAction) in
self?.showCamera()
}))
alert.addAction(UIAlertAction(title: settings.userPromptText.cancelAction, style: .cancel, handler: { [weak self] (_: UIAlertAction) in
alert.addAction(
UIAlertAction(
title: settings.userPromptText.cancelAction, style: .cancel,
handler: { [weak self] (_: UIAlertAction) in
self?.invoke?.reject("User cancelled photos app prompt")
}))
UIUtils.centerPopover(rootViewController: manager.viewController, popoverController: alert)
self.manager.viewController?.present(alert, animated: true, completion: nil)
}
func showCamera() {
fileprivate func showCamera() {
// check if we have a camera
if manager.isSimEnvironment || !UIImagePickerController.isSourceTypeAvailable(UIImagePickerController.SourceType.camera) {
if manager.isSimEnvironment
|| !UIImagePickerController.isSourceTypeAvailable(UIImagePickerController.SourceType.camera)
{
Logger.error("[PLUGIN]", "Camera", "-", "Camera not available in simulator")
invoke?.reject("Camera not available while running in Simulator")
return
@ -433,7 +474,7 @@ private extension CameraPlugin {
}
}
func showPhotos() {
fileprivate func showPhotos() {
// check for permission
let authStatus = PHPhotoLibrary.authorizationStatus()
if authStatus == .restricted || authStatus == .denied {
@ -456,7 +497,7 @@ private extension CameraPlugin {
}
}
func presentCameraPicker() {
fileprivate func presentCameraPicker() {
let picker = UIImagePickerController()
picker.delegate = self
picker.allowsEditing = self.settings.allowEditing
@ -464,7 +505,8 @@ private extension CameraPlugin {
picker.sourceType = .camera
if settings.direction == .rear, UIImagePickerController.isCameraDeviceAvailable(.rear) {
picker.cameraDevice = .rear
} else if settings.direction == .front, UIImagePickerController.isCameraDeviceAvailable(.front) {
} else if settings.direction == .front, UIImagePickerController.isCameraDeviceAvailable(.front)
{
picker.cameraDevice = .front
}
// present
@ -476,7 +518,7 @@ private extension CameraPlugin {
manager.viewController?.present(picker, animated: true, completion: nil)
}
func presentSystemAppropriateImagePicker() {
fileprivate func presentSystemAppropriateImagePicker() {
if #available(iOS 14, *) {
presentPhotoPicker()
} else {
@ -484,7 +526,7 @@ private extension CameraPlugin {
}
}
func presentImagePicker() {
fileprivate func presentImagePicker() {
let picker = UIImagePickerController()
picker.delegate = self
picker.allowsEditing = self.settings.allowEditing
@ -500,7 +542,7 @@ private extension CameraPlugin {
}
@available(iOS 14, *)
func presentPhotoPicker() {
fileprivate func presentPhotoPicker() {
var configuration = PHPickerConfiguration(photoLibrary: PHPhotoLibrary.shared())
configuration.selectionLimit = self.multiple ? (self.invoke?.getInt("limit") ?? 0) : 1
configuration.filter = .images
@ -515,18 +557,21 @@ private extension CameraPlugin {
manager.viewController?.present(picker, animated: true, completion: nil)
}
func saveTemporaryImage(_ data: Data) throws -> URL {
fileprivate func saveTemporaryImage(_ data: Data) throws -> URL {
var url: URL
repeat {
imageCounter += 1
url = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent("photo-\(imageCounter).jpg")
url = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(
"photo-\(imageCounter).jpg")
} while FileManager.default.fileExists(atPath: url.path)
try data.write(to: url, options: .atomic)
return url
}
func processImage(from info: [UIImagePickerController.InfoKey: Any]) -> ProcessedImage? {
fileprivate func processImage(from info: [UIImagePickerController.InfoKey: Any])
-> ProcessedImage?
{
var selectedImage: UIImage?
var flags: PhotoFlags = []
// get the image
@ -555,11 +600,14 @@ private extension CameraPlugin {
return result
}
func processedImage(from image: UIImage, with metadata: [String: Any]?) -> ProcessedImage {
fileprivate func processedImage(from image: UIImage, with metadata: [String: Any]?)
-> ProcessedImage
{
var result = ProcessedImage(image: image, metadata: metadata ?? [:])
// resizing the image only makes sense if we have real values to which to constrain it
if settings.shouldResize, settings.width > 0 || settings.height > 0 {
result.image = result.image.reformat(to: CGSize(width: settings.width, height: settings.height))
result.image = result.image.reformat(
to: CGSize(width: settings.width, height: settings.height))
result.overwriteMetadataOrientation(to: 1)
} else if settings.shouldCorrectOrientation {
// resizing implicitly reformats the image so this is only needed if we aren't resizing

@ -1,3 +1,7 @@
// Copyright 2019-2023 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
import UIKit
// MARK: - Public

@ -1,3 +1,7 @@
// Copyright 2019-2023 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
import UIKit
class ImageSaver: NSObject {

@ -1,3 +1,8 @@
// Copyright 2019-2023 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
import XCTest
@testable import ExamplePlugin

Loading…
Cancel
Save