intent error on android solved
This commit is contained in:
parent
b05a779c09
commit
925c231db4
|
@ -0,0 +1,78 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<Scheme
|
||||||
|
LastUpgradeVersion = "1420"
|
||||||
|
version = "1.3">
|
||||||
|
<BuildAction
|
||||||
|
parallelizeBuildables = "YES"
|
||||||
|
buildImplicitDependencies = "YES">
|
||||||
|
<BuildActionEntries>
|
||||||
|
<BuildActionEntry
|
||||||
|
buildForTesting = "YES"
|
||||||
|
buildForRunning = "YES"
|
||||||
|
buildForProfiling = "YES"
|
||||||
|
buildForArchiving = "YES"
|
||||||
|
buildForAnalyzing = "YES">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "504EC3031FED79650016851F"
|
||||||
|
BuildableName = "App.app"
|
||||||
|
BlueprintName = "App"
|
||||||
|
ReferencedContainer = "container:App.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildActionEntry>
|
||||||
|
</BuildActionEntries>
|
||||||
|
</BuildAction>
|
||||||
|
<TestAction
|
||||||
|
buildConfiguration = "Debug"
|
||||||
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||||
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
|
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||||
|
<Testables>
|
||||||
|
</Testables>
|
||||||
|
</TestAction>
|
||||||
|
<LaunchAction
|
||||||
|
buildConfiguration = "Debug"
|
||||||
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||||
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
|
launchStyle = "0"
|
||||||
|
useCustomWorkingDirectory = "NO"
|
||||||
|
ignoresPersistentStateOnLaunch = "NO"
|
||||||
|
debugDocumentVersioning = "YES"
|
||||||
|
debugServiceExtension = "internal"
|
||||||
|
allowLocationSimulation = "YES">
|
||||||
|
<BuildableProductRunnable
|
||||||
|
runnableDebuggingMode = "0">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "504EC3031FED79650016851F"
|
||||||
|
BuildableName = "App.app"
|
||||||
|
BlueprintName = "App"
|
||||||
|
ReferencedContainer = "container:App.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildableProductRunnable>
|
||||||
|
</LaunchAction>
|
||||||
|
<ProfileAction
|
||||||
|
buildConfiguration = "Release"
|
||||||
|
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||||
|
savedToolIdentifier = ""
|
||||||
|
useCustomWorkingDirectory = "NO"
|
||||||
|
debugDocumentVersioning = "YES">
|
||||||
|
<BuildableProductRunnable
|
||||||
|
runnableDebuggingMode = "0">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "504EC3031FED79650016851F"
|
||||||
|
BuildableName = "App.app"
|
||||||
|
BlueprintName = "App"
|
||||||
|
ReferencedContainer = "container:App.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildableProductRunnable>
|
||||||
|
</ProfileAction>
|
||||||
|
<AnalyzeAction
|
||||||
|
buildConfiguration = "Debug">
|
||||||
|
</AnalyzeAction>
|
||||||
|
<ArchiveAction
|
||||||
|
buildConfiguration = "Release"
|
||||||
|
revealArchiveInOrganizer = "YES">
|
||||||
|
</ArchiveAction>
|
||||||
|
</Scheme>
|
|
@ -0,0 +1,101 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<Scheme
|
||||||
|
LastUpgradeVersion = "1420"
|
||||||
|
wasCreatedForAppExtension = "YES"
|
||||||
|
version = "2.0">
|
||||||
|
<BuildAction
|
||||||
|
parallelizeBuildables = "YES"
|
||||||
|
buildImplicitDependencies = "YES">
|
||||||
|
<BuildActionEntries>
|
||||||
|
<BuildActionEntry
|
||||||
|
buildForTesting = "YES"
|
||||||
|
buildForRunning = "YES"
|
||||||
|
buildForProfiling = "YES"
|
||||||
|
buildForArchiving = "YES"
|
||||||
|
buildForAnalyzing = "YES">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "65B5150F29BB4AB8005DC684"
|
||||||
|
BuildableName = "upload.appex"
|
||||||
|
BlueprintName = "upload"
|
||||||
|
ReferencedContainer = "container:App.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildActionEntry>
|
||||||
|
<BuildActionEntry
|
||||||
|
buildForTesting = "YES"
|
||||||
|
buildForRunning = "YES"
|
||||||
|
buildForProfiling = "YES"
|
||||||
|
buildForArchiving = "YES"
|
||||||
|
buildForAnalyzing = "YES">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "504EC3031FED79650016851F"
|
||||||
|
BuildableName = "App.app"
|
||||||
|
BlueprintName = "App"
|
||||||
|
ReferencedContainer = "container:App.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildActionEntry>
|
||||||
|
</BuildActionEntries>
|
||||||
|
</BuildAction>
|
||||||
|
<TestAction
|
||||||
|
buildConfiguration = "Debug"
|
||||||
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||||
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
|
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||||
|
<Testables>
|
||||||
|
</Testables>
|
||||||
|
</TestAction>
|
||||||
|
<LaunchAction
|
||||||
|
buildConfiguration = "Debug"
|
||||||
|
selectedDebuggerIdentifier = ""
|
||||||
|
selectedLauncherIdentifier = "Xcode.IDEFoundation.Launcher.PosixSpawn"
|
||||||
|
launchStyle = "0"
|
||||||
|
askForAppToLaunch = "Yes"
|
||||||
|
useCustomWorkingDirectory = "NO"
|
||||||
|
ignoresPersistentStateOnLaunch = "NO"
|
||||||
|
debugDocumentVersioning = "YES"
|
||||||
|
debugServiceExtension = "internal"
|
||||||
|
allowLocationSimulation = "YES"
|
||||||
|
launchAutomaticallySubstyle = "2">
|
||||||
|
<RemoteRunnable
|
||||||
|
runnableDebuggingMode = "1"
|
||||||
|
BundleIdentifier = "gcube.workspace.starter"
|
||||||
|
RemotePath = "/Users/lucio/Library/Developer/CoreSimulator/Devices/F17E9BEA-B875-4A5C-A276-00EF1DC47FE7/data/Containers/Bundle/Application/6B87E654-9A60-4478-927C-BFC257A7CCAF/App.app">
|
||||||
|
</RemoteRunnable>
|
||||||
|
<MacroExpansion>
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "504EC3031FED79650016851F"
|
||||||
|
BuildableName = "App.app"
|
||||||
|
BlueprintName = "App"
|
||||||
|
ReferencedContainer = "container:App.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</MacroExpansion>
|
||||||
|
</LaunchAction>
|
||||||
|
<ProfileAction
|
||||||
|
buildConfiguration = "Release"
|
||||||
|
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||||
|
savedToolIdentifier = ""
|
||||||
|
useCustomWorkingDirectory = "NO"
|
||||||
|
debugDocumentVersioning = "YES"
|
||||||
|
askForAppToLaunch = "Yes"
|
||||||
|
launchAutomaticallySubstyle = "2">
|
||||||
|
<BuildableProductRunnable
|
||||||
|
runnableDebuggingMode = "0">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "504EC3031FED79650016851F"
|
||||||
|
BuildableName = "App.app"
|
||||||
|
BlueprintName = "App"
|
||||||
|
ReferencedContainer = "container:App.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildableProductRunnable>
|
||||||
|
</ProfileAction>
|
||||||
|
<AnalyzeAction
|
||||||
|
buildConfiguration = "Debug">
|
||||||
|
</AnalyzeAction>
|
||||||
|
<ArchiveAction
|
||||||
|
buildConfiguration = "Release"
|
||||||
|
revealArchiveInOrganizer = "YES">
|
||||||
|
</ArchiveAction>
|
||||||
|
</Scheme>
|
|
@ -0,0 +1,24 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13122.16" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="j1y-V4-xli">
|
||||||
|
<dependencies>
|
||||||
|
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13104.12"/>
|
||||||
|
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||||
|
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||||
|
</dependencies>
|
||||||
|
<scenes>
|
||||||
|
<!--Share View Controller-->
|
||||||
|
<scene sceneID="ceB-am-kn3">
|
||||||
|
<objects>
|
||||||
|
<viewController id="j1y-V4-xli" customClass="ShareViewController" customModuleProvider="target" sceneMemberID="viewController">
|
||||||
|
<view key="view" opaque="NO" contentMode="scaleToFill" id="wbc-yd-nQP">
|
||||||
|
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
|
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
|
<viewLayoutGuide key="safeArea" id="1Xd-am-t49"/>
|
||||||
|
</view>
|
||||||
|
</viewController>
|
||||||
|
<placeholder placeholderIdentifier="IBFirstResponder" id="CEy-Cv-SGf" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||||
|
</objects>
|
||||||
|
</scene>
|
||||||
|
</scenes>
|
||||||
|
</document>
|
|
@ -0,0 +1,18 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>NSExtension</key>
|
||||||
|
<dict>
|
||||||
|
<key>NSExtensionAttributes</key>
|
||||||
|
<dict>
|
||||||
|
<key>NSExtensionActivationRule</key>
|
||||||
|
<string>TRUEPREDICATE</string>
|
||||||
|
</dict>
|
||||||
|
<key>NSExtensionMainStoryboard</key>
|
||||||
|
<string>MainInterface</string>
|
||||||
|
<key>NSExtensionPointIdentifier</key>
|
||||||
|
<string>com.apple.share-services</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
|
@ -0,0 +1,192 @@
|
||||||
|
//
|
||||||
|
// ShareViewController.swift
|
||||||
|
// upload
|
||||||
|
//
|
||||||
|
// Created by Lucio Lelii on 10/03/23.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
import Social
|
||||||
|
import MobileCoreServices
|
||||||
|
import Foundation.NSURLSession
|
||||||
|
|
||||||
|
class ShareItem {
|
||||||
|
public var title: String?
|
||||||
|
public var type: String?
|
||||||
|
public var url: String?
|
||||||
|
public var webPath: String?
|
||||||
|
}
|
||||||
|
|
||||||
|
class ShareViewController: UIViewController {
|
||||||
|
private var shareItems: [ShareItem] = []
|
||||||
|
override public func viewDidAppear(_ animated: Bool) {
|
||||||
|
super.viewDidAppear(animated)
|
||||||
|
print("did appear called");
|
||||||
|
self.extensionContext!.completeRequest(returningItems: [], completionHandler: nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
override public func viewDidLoad() {
|
||||||
|
super.viewDidLoad()
|
||||||
|
shareItems.removeAll()
|
||||||
|
let extensionItem = extensionContext?.inputItems[0] as! NSExtensionItem
|
||||||
|
Task {
|
||||||
|
try await withThrowingTaskGroup(
|
||||||
|
of: ShareItem.self,
|
||||||
|
body: { taskGroup in
|
||||||
|
for attachment in extensionItem.attachments! {
|
||||||
|
if attachment.hasItemConformingToTypeIdentifier(kUTTypeURL as String) {
|
||||||
|
taskGroup.addTask {
|
||||||
|
return try await self.handleTypeUrl(attachment)
|
||||||
|
}
|
||||||
|
} else if attachment.hasItemConformingToTypeIdentifier(kUTTypeText as String) {
|
||||||
|
taskGroup.addTask {
|
||||||
|
return try await self.handleTypeText(attachment)
|
||||||
|
}
|
||||||
|
} else if attachment.hasItemConformingToTypeIdentifier(kUTTypeMovie as String) {
|
||||||
|
taskGroup.addTask {
|
||||||
|
return try await self.handleTypeMovie(attachment)
|
||||||
|
}
|
||||||
|
} else if attachment.hasItemConformingToTypeIdentifier(kUTTypeImage as String) {
|
||||||
|
taskGroup.addTask {
|
||||||
|
return try await self.handleTypeImage(attachment)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for try await item in taskGroup {
|
||||||
|
self.shareItems.append(item)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
self.sendData()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func sendData() {
|
||||||
|
let queryItems = shareItems.map {
|
||||||
|
[
|
||||||
|
URLQueryItem(
|
||||||
|
name: "title",
|
||||||
|
value: $0.title?.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed) ?? ""),
|
||||||
|
URLQueryItem(name: "description", value: ""),
|
||||||
|
URLQueryItem(
|
||||||
|
name: "type",
|
||||||
|
value: $0.type?.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed) ?? ""),
|
||||||
|
URLQueryItem(
|
||||||
|
name: "url",
|
||||||
|
value: $0.url?.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed) ?? ""),
|
||||||
|
URLQueryItem(
|
||||||
|
name: "webPath",
|
||||||
|
value: $0.webPath?.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed) ?? "")
|
||||||
|
]
|
||||||
|
}.flatMap({ $0 })
|
||||||
|
var urlComps = URLComponents(string: "d4sworkspace://share-input")!
|
||||||
|
urlComps.queryItems = queryItems
|
||||||
|
var opened = openURL(urlComps.url!)
|
||||||
|
print("sending data %s",opened);
|
||||||
|
}
|
||||||
|
|
||||||
|
fileprivate func createSharedFileUrl(_ url: URL?) -> String {
|
||||||
|
let fileManager = FileManager.default
|
||||||
|
print("share url: " + url!.absoluteString)
|
||||||
|
let copyFileUrl =
|
||||||
|
fileManager.containerURL(forSecurityApplicationGroupIdentifier: "group.gcube.workspace")!
|
||||||
|
.absoluteString.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)! + url!
|
||||||
|
.lastPathComponent.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)!
|
||||||
|
try? Data(contentsOf: url!).write(to: URL(string: copyFileUrl)!)
|
||||||
|
|
||||||
|
return copyFileUrl
|
||||||
|
}
|
||||||
|
|
||||||
|
func saveScreenshot(_ image: UIImage) -> String {
|
||||||
|
let fileManager = FileManager.default
|
||||||
|
|
||||||
|
let copyFileUrl =
|
||||||
|
fileManager.containerURL(forSecurityApplicationGroupIdentifier: "group.gcube.workspace")!
|
||||||
|
.absoluteString.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)!
|
||||||
|
+ "/screenshot.png"
|
||||||
|
do {
|
||||||
|
try image.pngData()?.write(to: URL(string: copyFileUrl)!)
|
||||||
|
return copyFileUrl
|
||||||
|
} catch {
|
||||||
|
print(error.localizedDescription)
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fileprivate func handleTypeUrl(_ attachment: NSItemProvider)
|
||||||
|
async throws -> ShareItem
|
||||||
|
{
|
||||||
|
let results = try await attachment.loadItem(forTypeIdentifier: kUTTypeURL as String, options: nil)
|
||||||
|
let url = results as! URL?
|
||||||
|
let shareItem: ShareItem = ShareItem()
|
||||||
|
|
||||||
|
if url!.isFileURL {
|
||||||
|
shareItem.title = url!.lastPathComponent
|
||||||
|
shareItem.type = "application/" + url!.pathExtension.lowercased()
|
||||||
|
shareItem.url = createSharedFileUrl(url)
|
||||||
|
shareItem.webPath = "capacitor://localhost/_capacitor_file_" + URL(string: shareItem.url ?? "")!.path
|
||||||
|
} else {
|
||||||
|
shareItem.title = url!.absoluteString
|
||||||
|
shareItem.url = url!.absoluteString
|
||||||
|
shareItem.webPath = url!.absoluteString
|
||||||
|
shareItem.type = "text/plain"
|
||||||
|
}
|
||||||
|
return shareItem
|
||||||
|
}
|
||||||
|
|
||||||
|
fileprivate func handleTypeText(_ attachment: NSItemProvider)
|
||||||
|
async throws -> ShareItem
|
||||||
|
{
|
||||||
|
let results = try await attachment.loadItem(forTypeIdentifier: kUTTypeText as String, options: nil)
|
||||||
|
let shareItem: ShareItem = ShareItem()
|
||||||
|
let text = results as! String
|
||||||
|
shareItem.title = text
|
||||||
|
shareItem.type = "text/plain"
|
||||||
|
return shareItem
|
||||||
|
}
|
||||||
|
|
||||||
|
fileprivate func handleTypeMovie(_ attachment: NSItemProvider)
|
||||||
|
async throws -> ShareItem
|
||||||
|
{
|
||||||
|
let results = try await attachment.loadItem(forTypeIdentifier: kUTTypeMovie as String, options: nil)
|
||||||
|
let shareItem: ShareItem = ShareItem()
|
||||||
|
let url = results as! URL?
|
||||||
|
shareItem.title = url!.lastPathComponent
|
||||||
|
shareItem.type = "video/" + url!.pathExtension.lowercased()
|
||||||
|
shareItem.url = createSharedFileUrl(url)
|
||||||
|
shareItem.webPath = "capacitor://localhost/_capacitor_file_" + URL(string: shareItem.url ?? "")!.path
|
||||||
|
return shareItem
|
||||||
|
}
|
||||||
|
|
||||||
|
fileprivate func handleTypeImage(_ attachment: NSItemProvider)
|
||||||
|
async throws -> ShareItem
|
||||||
|
{
|
||||||
|
let data = try await attachment.loadItem(forTypeIdentifier: kUTTypeImage as String, options: nil)
|
||||||
|
let shareItem: ShareItem = ShareItem()
|
||||||
|
switch data {
|
||||||
|
case let image as UIImage:
|
||||||
|
shareItem.title = "screenshot"
|
||||||
|
shareItem.type = "image/png"
|
||||||
|
shareItem.url = self.saveScreenshot(image)
|
||||||
|
shareItem.webPath = "capacitor://localhost/_capacitor_file_" + URL(string: shareItem.url ?? "")!.path
|
||||||
|
case let url as URL:
|
||||||
|
shareItem.title = url.lastPathComponent
|
||||||
|
shareItem.type = "image/" + url.pathExtension.lowercased()
|
||||||
|
shareItem.url = self.createSharedFileUrl(url)
|
||||||
|
shareItem.webPath = "capacitor://localhost/_capacitor_file_" + URL(string: shareItem.url ?? "")!.path
|
||||||
|
default:
|
||||||
|
print("Unexpected image data:", type(of: data))
|
||||||
|
}
|
||||||
|
return shareItem
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc func openURL(_ url: URL) -> Bool {
|
||||||
|
var responder: UIResponder? = self
|
||||||
|
while responder != nil {
|
||||||
|
if let application = responder as? UIApplication {
|
||||||
|
return application.perform(#selector(openURL(_:)), with: url) != nil
|
||||||
|
}
|
||||||
|
responder = responder?.next
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
import { ShareExtension } from "capacitor-share-extension";
|
||||||
|
import { D4sIntentService } from "../d4s-intent.service";
|
||||||
|
|
||||||
|
export function initializeIntent(d4sIntent: D4sIntentService) {
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
window.addEventListener('sendIntentReceived', () => {
|
||||||
|
console.log("event fired");
|
||||||
|
d4sIntent.checkIntent();
|
||||||
|
});
|
||||||
|
d4sIntent.checkIntent();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
import { AlertController } from "@ionic/angular";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Format bytes as human-readable text.
|
||||||
|
*
|
||||||
|
* @param bytes Number of bytes.
|
||||||
|
* @param si True to use metric (SI) units, aka powers of 1000. False to use
|
||||||
|
* binary (IEC), aka powers of 1024.
|
||||||
|
* @param dp Number of decimal places to display.
|
||||||
|
*
|
||||||
|
* @return Formatted string.
|
||||||
|
*/
|
||||||
|
export function humanFileSize(bytes:number, si=true, dp=1) {
|
||||||
|
const thresh = si ? 1000 : 1024;
|
||||||
|
|
||||||
|
if (Math.abs(bytes) < thresh) {
|
||||||
|
return bytes + ' B';
|
||||||
|
}
|
||||||
|
|
||||||
|
const units = si
|
||||||
|
? ['kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']
|
||||||
|
: ['KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB'];
|
||||||
|
let u = -1;
|
||||||
|
const r = 10**dp;
|
||||||
|
|
||||||
|
do {
|
||||||
|
bytes /= thresh;
|
||||||
|
++u;
|
||||||
|
} while (Math.round(Math.abs(bytes) * r) / r >= thresh && u < units.length - 1);
|
||||||
|
|
||||||
|
|
||||||
|
return bytes.toFixed(dp) + ' ' + units[u];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export async function presentConnectionAlert(err: string, alertCtrl: AlertController){
|
||||||
|
const alert = await alertCtrl.create({
|
||||||
|
header: 'Connection ERROR',
|
||||||
|
message: err,
|
||||||
|
buttons: ['OK'],
|
||||||
|
});
|
||||||
|
await alert.present();
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
import { TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { D4sIntentService } from './d4s-intent.service';
|
||||||
|
|
||||||
|
describe('D4sIntentService', () => {
|
||||||
|
let service: D4sIntentService;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
TestBed.configureTestingModule({});
|
||||||
|
service = TestBed.inject(D4sIntentService);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be created', () => {
|
||||||
|
expect(service).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,61 @@
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { ModalController, ModalOptions, ToastController } from '@ionic/angular';
|
||||||
|
import { ShareExtension } from 'capacitor-share-extension';
|
||||||
|
import { EventService } from './event.service';
|
||||||
|
import { UploadFile } from './model/actions/upload-file';
|
||||||
|
import { StoragehubService } from './storagehub.service';
|
||||||
|
import { UploaderInfoService } from './uploader-info.service';
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
|
export class D4sIntentService {
|
||||||
|
|
||||||
|
constructor(private modalCtrl: ModalController,
|
||||||
|
private toastController: ToastController,
|
||||||
|
private storagehub: StoragehubService,
|
||||||
|
private uploaderInfo: UploaderInfoService,
|
||||||
|
private event: EventService) { }
|
||||||
|
|
||||||
|
|
||||||
|
async checkIntent() {
|
||||||
|
try {
|
||||||
|
const result: any = await ShareExtension.checkSendIntentReceived();
|
||||||
|
/* sample result::
|
||||||
|
{ payload: [
|
||||||
|
{
|
||||||
|
"type":"image%2Fjpg",
|
||||||
|
"description":"",
|
||||||
|
"title":"IMG_0002.JPG",
|
||||||
|
// url contains a full, platform-specific file URL that can be read later using the Filsystem API.
|
||||||
|
"url":"file%3A%2F%2F%2FUsers%2Fcalvinho%2FLibrary%2FDeveloper%2FCoreSimulator%2FDevices%2FE4C13502-3A0B-4DF4-98ED-9F31DDF03672%2Fdata%2FContainers%2FShared%2FAppGroup%2FF41DC1F5-54D7-4EC5-9785-5248BAE06588%2FIMG_0002.JPG",
|
||||||
|
// webPath returns a path that can be used to set the src attribute of an image for efficient loading and rendering.
|
||||||
|
"webPath":"capacitor%3A%2F%2Flocalhost%2F_capacitor_file_%2FUsers%2Fcalvinho%2FLibrary%2FDeveloper%2FCoreSimulator%2FDevices%2FE4C13502-3A0B-4DF4-98ED-9F31DDF03672%2Fdata%2FContainers%2FShared%2FAppGroup%2FF41DC1F5-54D7-4EC5-9785-5248BAE06588%2FIMG_0002.JPG",
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
if (result && result.payload && result.payload.length) {
|
||||||
|
console.log('Intent received: ', JSON.stringify(result.payload[0]));
|
||||||
|
var modalOptions: ModalOptions = new UploadFile().getModalOptions(this.storagehub, this.uploaderInfo, result.payload[0],
|
||||||
|
(id : string) =>{
|
||||||
|
this.event.ReloadEvent.emit(id);
|
||||||
|
ShareExtension.finish();
|
||||||
|
}, (text: string) => this.presentToast(text));
|
||||||
|
let modal = await this.modalCtrl.create(modalOptions);
|
||||||
|
await modal.present();
|
||||||
|
} else {
|
||||||
|
console.log("nothing received");
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.log(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async presentToast(text: string) {
|
||||||
|
const toast = await this.toastController.create({
|
||||||
|
message: text,
|
||||||
|
duration: 1500
|
||||||
|
});
|
||||||
|
await toast.present();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
import { TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { EventService } from './event.service';
|
||||||
|
|
||||||
|
describe('EventService', () => {
|
||||||
|
let service: EventService;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
TestBed.configureTestingModule({});
|
||||||
|
service = TestBed.inject(EventService);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be created', () => {
|
||||||
|
expect(service).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,13 @@
|
||||||
|
import { EventEmitter, Injectable } from '@angular/core';
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
|
export class EventService {
|
||||||
|
|
||||||
|
ReloadEvent = new EventEmitter<string>();
|
||||||
|
|
||||||
|
constructor() { }
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,99 @@
|
||||||
|
import { AlertController, LoadingController } from "@ionic/angular";
|
||||||
|
import { WSItem } from "../ws-item";
|
||||||
|
import { StoragehubService } from "src/app/storagehub.service";
|
||||||
|
import { Directory, Filesystem } from "@capacitor/filesystem";
|
||||||
|
import { FileOpener } from "@awesome-cordova-plugins/file-opener/ngx";
|
||||||
|
import { App } from '@capacitor/app';
|
||||||
|
import { isPlatform } from '@ionic/angular';
|
||||||
|
import { presentConnectionAlert } from "src/app/_helper/utils";
|
||||||
|
|
||||||
|
|
||||||
|
export class OpenFile {
|
||||||
|
|
||||||
|
pluginListener: any;
|
||||||
|
|
||||||
|
item: WSItem;
|
||||||
|
|
||||||
|
constructor(item: WSItem) {
|
||||||
|
this.item = item;
|
||||||
|
if (isPlatform("android")) {
|
||||||
|
App.addListener('resume', () => {
|
||||||
|
Filesystem.deleteFile(
|
||||||
|
{
|
||||||
|
path: item.getTitle(),
|
||||||
|
directory: Directory.Documents
|
||||||
|
}).then(() => console.log("file deleted"));
|
||||||
|
this.pluginListener?.remove();
|
||||||
|
}).then((handler) => this.pluginListener = handler);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async open(storageHub: StoragehubService, fileOpener: FileOpener, loadingCtrl: LoadingController, alertCtrl: AlertController) {
|
||||||
|
const size = this.item.item.content?.size;
|
||||||
|
if (!size || size / 1000000 > 20) {
|
||||||
|
this.presentAlert(alertCtrl);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.showLoading(loadingCtrl);
|
||||||
|
storageHub.downloadFile(this.item.item.id).then(obs => obs.subscribe({
|
||||||
|
next: async blob => {
|
||||||
|
const base64 = await this.blobToBase64(blob) as string;
|
||||||
|
const fileWrited = await Filesystem.writeFile({
|
||||||
|
path: this.item.getTitle(),
|
||||||
|
data: base64,
|
||||||
|
directory: Directory.Documents
|
||||||
|
});
|
||||||
|
|
||||||
|
const mimeType = this.item.item.content?.mimeType;
|
||||||
|
fileOpener.open(fileWrited.uri, mimeType ? mimeType : "application/octet-stream").then(() => {
|
||||||
|
loadingCtrl.dismiss();
|
||||||
|
if (isPlatform("ios"))
|
||||||
|
Filesystem.deleteFile(
|
||||||
|
{
|
||||||
|
path: this.item.getTitle(),
|
||||||
|
directory: Directory.Documents
|
||||||
|
});
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
},
|
||||||
|
error: (err) => {
|
||||||
|
loadingCtrl.dismiss();
|
||||||
|
this.pluginListener?.remove();
|
||||||
|
presentConnectionAlert(err, alertCtrl);
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async presentAlert(alertCtrl: AlertController) {
|
||||||
|
const alert = await alertCtrl.create({
|
||||||
|
header: 'Alert',
|
||||||
|
message: 'File too big to be opeend here!',
|
||||||
|
buttons: ['OK'],
|
||||||
|
});
|
||||||
|
|
||||||
|
await alert.present();
|
||||||
|
}
|
||||||
|
|
||||||
|
async showLoading(loadingCtrl: LoadingController) {
|
||||||
|
const loading = await loadingCtrl.create({
|
||||||
|
message: 'Loading...',
|
||||||
|
duration: 20000,
|
||||||
|
spinner: 'circles',
|
||||||
|
});
|
||||||
|
|
||||||
|
loading.present();
|
||||||
|
return loading;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
blobToBase64(blob: Blob) {
|
||||||
|
return new Promise((resolve, _) => {
|
||||||
|
const reader = new FileReader();
|
||||||
|
reader.onloadend = () => resolve(reader.result);
|
||||||
|
reader.readAsDataURL(blob);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,57 @@
|
||||||
|
import { ModalOptions } from "@ionic/angular";
|
||||||
|
import { StoragehubService } from "src/app/storagehub.service";
|
||||||
|
import { WsViewerComponent } from "src/app/ws-viewer/ws-viewer.component";
|
||||||
|
import { WSItem } from "../ws-item";
|
||||||
|
import { Filesystem } from "@capacitor/filesystem";
|
||||||
|
import { UploaderInfoService } from "src/app/uploader-info.service";
|
||||||
|
|
||||||
|
export class UploadFile {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
getModalOptions(storagehub: StoragehubService, uploaderInfo: UploaderInfoService, data: any, reload: Function, notify: Function): ModalOptions {
|
||||||
|
return {
|
||||||
|
component: WsViewerComponent,
|
||||||
|
componentProps: {
|
||||||
|
finishLabel: "Upload here",
|
||||||
|
title: "Select destination folder",
|
||||||
|
notClickableIds: [],
|
||||||
|
notSelectableIds: [],
|
||||||
|
onSelected: (destinationItem: WSItem) => {
|
||||||
|
const itemId = destinationItem.item.id;
|
||||||
|
uploaderInfo.uploadStarted(itemId, data.title);
|
||||||
|
this.actionHandler(destinationItem, data, storagehub).then( obs => obs.subscribe({
|
||||||
|
next: () => {},
|
||||||
|
error: err => uploaderInfo.uploadFinished(itemId, data.title),
|
||||||
|
complete: () => {
|
||||||
|
notify(`uploaded file ${data.title}`);
|
||||||
|
uploaderInfo.uploadFinished(itemId, data.title),
|
||||||
|
reload(itemId);
|
||||||
|
},
|
||||||
|
|
||||||
|
}
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async actionHandler(destinationItem: WSItem, result: any, storagehub: StoragehubService) {
|
||||||
|
const pathDecodedWebPath = decodeURIComponent(result.webPath);
|
||||||
|
|
||||||
|
const file = await fetch(pathDecodedWebPath)
|
||||||
|
.then(res => res.blob()) // Gets the response and returns it as a blob
|
||||||
|
.then(blob => { return new File([blob], result.title)});
|
||||||
|
|
||||||
|
console.log("before uploading file ");
|
||||||
|
return storagehub.uploadFile(destinationItem.item.id, result.title, file);
|
||||||
|
}
|
||||||
|
|
||||||
|
getName(): string {
|
||||||
|
return "UploadFile";
|
||||||
|
}
|
||||||
|
getActionType(): string | undefined {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
import { TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { UploaderInfoService } from './uploader-info.service';
|
||||||
|
|
||||||
|
describe('UploaderInfoService', () => {
|
||||||
|
let service: UploaderInfoService;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
TestBed.configureTestingModule({});
|
||||||
|
service = TestBed.inject(UploaderInfoService);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be created', () => {
|
||||||
|
expect(service).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,38 @@
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
|
export class UploaderInfoService {
|
||||||
|
|
||||||
|
myMap = new Map<string, string[]>();
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
}
|
||||||
|
|
||||||
|
uploadStarted(itemId: string, fileName: string) {
|
||||||
|
var values = this.myMap.get(itemId);
|
||||||
|
if (!values)
|
||||||
|
values = [fileName];
|
||||||
|
else
|
||||||
|
values.push(fileName);
|
||||||
|
this.myMap.set(itemId, values);
|
||||||
|
}
|
||||||
|
|
||||||
|
uploadFinished(itemId: string , fileName: string) {
|
||||||
|
var values = this.myMap.get(itemId);
|
||||||
|
var newValues: string[] = [];
|
||||||
|
values?.filter(val => val!= fileName).forEach(val => newValues?.push(val))
|
||||||
|
if (newValues)
|
||||||
|
if (newValues.length>0)
|
||||||
|
this.myMap.set(itemId, newValues);
|
||||||
|
else this.myMap.delete(itemId);
|
||||||
|
}
|
||||||
|
|
||||||
|
getUnderUpload(itemId: string): string[]{
|
||||||
|
var values = this.myMap.get(itemId);
|
||||||
|
//console.log(`get upload called with array ${values}`);
|
||||||
|
return values? values : [];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue