Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion android/app/capacitor.build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ android {

apply from: "../capacitor-cordova-android-plugins/cordova.variables.gradle"
dependencies {

implementation project(':capacitor-blob-writer')

}

Expand Down
3 changes: 2 additions & 1 deletion android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
android:theme="@style/AppTheme"
android:networkSecurityConfig="@xml/network_security_config">

<meta-data android:name="com.google.firebase.messaging.default_notification_icon" android:resource="@drawable/ic_capture_lite" />

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
import com.getcapacitor.BridgeActivity;
import com.getcapacitor.Plugin;

import com.equimaps.capacitorblobwriter.BlobWriter;

import java.util.ArrayList;

public class MainActivity extends BridgeActivity {
Expand All @@ -15,7 +17,7 @@ public void onCreate(Bundle savedInstanceState) {
// Initializes the Bridge
this.init(savedInstanceState, new ArrayList<Class<? extends Plugin>>() {{
// Additional plugins you've installed go here
// Ex: add(TotallyAwesomePlugin.class);
add(BlobWriter.class);
}});
}
}
6 changes: 6 additions & 0 deletions android/app/src/main/res/xml/network_security_config.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<domain-config cleartextTrafficPermitted="true">
<domain includeSubdomains="false">localhost</domain>
</domain-config>
</network-security-config>
3 changes: 3 additions & 0 deletions android/capacitor.settings.gradle
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
// DO NOT EDIT THIS FILE! IT IS GENERATED EACH TIME "capacitor update" IS RUN
include ':capacitor-android'
project(':capacitor-android').projectDir = new File('../node_modules/@capacitor/android/capacitor')

include ':capacitor-blob-writer'
project(':capacitor-blob-writer').projectDir = new File('../node_modules/capacitor-blob-writer/android')
2 changes: 1 addition & 1 deletion ios/App/Podfile
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ def capacitor_pods
# Automatic Capacitor Pod dependencies, do not delete
pod 'Capacitor', :path => '../../node_modules/@capacitor/ios'
pod 'CapacitorCordova', :path => '../../node_modules/@capacitor/ios'

pod 'CapacitorBlobWriter', :path => '../../node_modules/capacitor-blob-writer'
# Do not delete
end

Expand Down
15 changes: 15 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
"@ngx-formly/material": "^5.10.15",
"@ngx-formly/schematics": "^5.10.15",
"async-mutex": "^0.3.1",
"capacitor-blob-writer": "^0.2.1",
"compressorjs": "^1.0.7",
"immutable": "^4.0.0-rc.12",
"lodash-es": "^4.17.21",
Expand Down
64 changes: 44 additions & 20 deletions src/app/shared/media/media-store/media-store.service.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
import { HttpClient } from '@angular/common/http';
import { Inject, Injectable } from '@angular/core';
import {
Capacitor,
FilesystemDirectory,
FilesystemPlugin,
} from '@capacitor/core';
import { Mutex } from 'async-mutex';
import { writeFile } from 'capacitor-blob-writer';
import Compressor from 'compressorjs';
import { defer, merge } from 'rxjs';
import { concatMap, map } from 'rxjs/operators';
import { sha256WithBase64 } from '../../../utils/crypto/crypto';
import { base64ToBlob, blobToBase64 } from '../../../utils/encoding/encoding';
import { MimeType, toExtension } from '../../../utils/mime-type';
import { fromExtension, MimeType, toExtension } from '../../../utils/mime-type';
import { toDataUrl } from '../../../utils/url';
import { FILESYSTEM_PLUGIN } from '../../capacitor-plugins/capacitor-plugins.module';
import { Database } from '../../database/database.service';
Expand Down Expand Up @@ -38,7 +40,8 @@ export class MediaStore {
constructor(
@Inject(FILESYSTEM_PLUGIN)
private readonly filesystemPlugin: FilesystemPlugin,
private readonly database: Database
private readonly database: Database,
private readonly httpClient: HttpClient
) {}

private async initialize() {
Expand All @@ -61,7 +64,18 @@ export class MediaStore {
});
}

async read(index: string) {
async read(index: string): Promise<string> {
await this.initialize();
const extension = await this.getExtension(index);
if (!extension) throw new Error(`Cannot get extension of ${index}.`);
const url = await this.getUrl(index, fromExtension(extension));
const blob = await this.httpClient
.get(url, { responseType: 'blob' })
.toPromise();
return blobToBase64(blob);
}

async readWithFileSystem(index: string) {
await this.initialize();
const extension = await this.getExtension(index);
const result = await this.filesystemPlugin.readFile({
Expand All @@ -82,22 +96,30 @@ export class MediaStore {
return this._write(index, base64, mimeType);
}
const exists = await this.exists(index);
if (exists) {
return index;
}
if (exists) return index;
return this._write(index, base64, mimeType);
}

private async _write(index: string, base64: string, mimeType: MimeType) {
await this.initialize();
return this.mutex.runExclusive(async () => {
const mediaExtension = await this.setMediaExtension(index, mimeType);
await this.filesystemPlugin.writeFile({
directory: this.directory,
path: `${this.rootDir}/${index}.${mediaExtension.extension}`,
data: base64,
recursive: true,
});
if (Capacitor.isNative) {
const blob = await base64ToBlob(base64, mimeType);
await writeFile({
directory: this.directory,
path: `${this.rootDir}/${index}.${mediaExtension.extension}`,
data: blob,
recursive: true,
});
} else {
await this.filesystemPlugin.writeFile({
directory: this.directory,
path: `${this.rootDir}/${index}.${mediaExtension.extension}`,
data: base64,
recursive: true,
});
}
return index;
});
}
Expand Down Expand Up @@ -158,11 +180,13 @@ export class MediaStore {

private async makeThumbnail(index: string, mimeType: MimeType) {
const thumbnailSize = 100;
const blob = await base64ToBlob(await this.read(index), mimeType);
const thumbnailBlob = mimeType.startsWith('video')
? await makeVideoThumbnail({ video: blob, width: thumbnailSize })
? await makeVideoThumbnail({
videoUrl: await this.getUrl(index, mimeType),
width: thumbnailSize,
})
: await makeImageThumbnail({
image: blob,
image: await base64ToBlob(await this.read(index), mimeType),
width: thumbnailSize,
});
return blobToBase64(thumbnailBlob);
Expand Down Expand Up @@ -224,7 +248,7 @@ export class MediaStore {
if (Capacitor.isNative)
return Capacitor.convertFileSrc(await this.getUri(index));
return URL.createObjectURL(
await base64ToBlob(await this.read(index), mimeType)
await base64ToBlob(await this.readWithFileSystem(index), mimeType)
);
}

Expand Down Expand Up @@ -317,11 +341,11 @@ async function makeImageThumbnail({
}

async function makeVideoThumbnail({
video,
videoUrl,
width,
quality = 0.6,
}: {
video: Blob;
videoUrl: string;
width: number;
quality?: number;
}) {
Expand Down Expand Up @@ -349,13 +373,13 @@ async function makeVideoThumbnail({
resolve(makeImageThumbnail({ image: blob, width, quality }));
else reject(TypeError('canvas.toBlob is null.'));
},
video.type,
'image/jpeg',
quality
);
}
});
videoElement.preload = 'auto';
videoElement.src = URL.createObjectURL(video);
videoElement.src = videoUrl;
videoElement.load();
});
}
2 changes: 0 additions & 2 deletions src/app/shared/shared-testing.module.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { HttpClientTestingModule } from '@angular/common/http/testing';
import { NgModule } from '@angular/core';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { RouterTestingModule } from '@angular/router/testing';
Expand All @@ -11,7 +10,6 @@ import { SharedModule } from './shared.module';
@NgModule({
imports: [
SharedModule,
HttpClientTestingModule,
RouterTestingModule,
BrowserAnimationsModule,
getTranslocoTestingModule(),
Expand Down