open file added

This commit is contained in:
Lucio Lelii 2023-03-13 17:39:14 +01:00
parent 74e2cb68e7
commit c1f6010aa5
17 changed files with 128 additions and 27 deletions

View File

@ -10,6 +10,7 @@ android {
apply from: "../capacitor-cordova-android-plugins/cordova.variables.gradle"
dependencies {
implementation project(':capacitor-app')
implementation project(':capacitor-filesystem')
implementation project(':capacitor-haptics')
implementation project(':capacitor-keyboard')
implementation project(':capacitor-splash-screen')

View File

@ -39,4 +39,6 @@
<!-- Permissions -->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
</manifest>

View File

@ -5,6 +5,9 @@ project(':capacitor-android').projectDir = new File('../node_modules/@capacitor/
include ':capacitor-app'
project(':capacitor-app').projectDir = new File('../node_modules/@capacitor/app/android')
include ':capacitor-filesystem'
project(':capacitor-filesystem').projectDir = new File('../node_modules/@capacitor/filesystem/android')
include ':capacitor-haptics'
project(':capacitor-haptics').projectDir = new File('../node_modules/@capacitor/haptics/android')

View File

@ -33,6 +33,10 @@
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UIFileSharingEnabled</key>
<true/>
<key>LSSupportsOpeningDocumentsInPlace</key>
<true/>
<key>NSExtensionAttributes</key>
<dict>
<key>NSExtensionActivationRule</key>

View File

@ -12,6 +12,7 @@ def capacitor_pods
pod 'Capacitor', :path => '../../node_modules/@capacitor/ios'
pod 'CapacitorCordova', :path => '../../node_modules/@capacitor/ios'
pod 'CapacitorApp', :path => '../../node_modules/@capacitor/app'
pod 'CapacitorFilesystem', :path => '../../node_modules/@capacitor/filesystem'
pod 'CapacitorHaptics', :path => '../../node_modules/@capacitor/haptics'
pod 'CapacitorKeyboard', :path => '../../node_modules/@capacitor/keyboard'
pod 'CapacitorSplashScreen', :path => '../../node_modules/@capacitor/splash-screen'

28
package-lock.json generated
View File

@ -21,6 +21,7 @@
"@capacitor/android": "4.6.3",
"@capacitor/app": "^4.1.1",
"@capacitor/core": "4.6.3",
"@capacitor/filesystem": "^4.1.4",
"@capacitor/haptics": "4.1.0",
"@capacitor/ios": "4.6.3",
"@capacitor/keyboard": "4.1.1",
@ -33,6 +34,7 @@
"@ionic/angular": "^6.5.4",
"angular-oauth2-oidc": "^15.0.1",
"capacitor-share-extension": "^2.0.0",
"cordova-plugin-file-opener2": "^4.0.0",
"cordova-plugin-inappbrowser": "^5.0.0",
"ionicons": "^6.1.3",
"keycloak-angular": "^13.0.0",
@ -2565,6 +2567,14 @@
"tslib": "^2.1.0"
}
},
"node_modules/@capacitor/filesystem": {
"version": "4.1.4",
"resolved": "https://registry.npmjs.org/@capacitor/filesystem/-/filesystem-4.1.4.tgz",
"integrity": "sha512-ivko1RNK4hq63xhMacq8D6D97N5/SAafTsrmY/pghYrG6Cl2SEY0+IgRu7V9/VWeN3FSplyUPucjUTAFQxXN5g==",
"peerDependencies": {
"@capacitor/core": "^4.0.0"
}
},
"node_modules/@capacitor/haptics": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/@capacitor/haptics/-/haptics-4.1.0.tgz",
@ -6612,6 +6622,24 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/cordova-plugin-file-opener2": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/cordova-plugin-file-opener2/-/cordova-plugin-file-opener2-4.0.0.tgz",
"integrity": "sha512-+O+MMldI2k5Kjoa62KXYxnZQIGE4k5VfoCmmOUmaV5XM6U6euiiKMfCkuMrOrdAFb1C5Jsx+SuBHbWx1NEB5lw==",
"engines": {
"cordovaDependencies": {
"2.0.0": {
"cordova": ">=6.0.0"
},
"3.0.0": {
"cordova": ">=7.0.0"
},
"4.0.0": {
"cordova-android": ">=10.0.0"
}
}
}
},
"node_modules/cordova-plugin-inappbrowser": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/cordova-plugin-inappbrowser/-/cordova-plugin-inappbrowser-5.0.0.tgz",

View File

@ -26,6 +26,7 @@
"@capacitor/android": "4.6.3",
"@capacitor/app": "^4.1.1",
"@capacitor/core": "4.6.3",
"@capacitor/filesystem": "^4.1.4",
"@capacitor/haptics": "4.1.0",
"@capacitor/ios": "4.6.3",
"@capacitor/keyboard": "4.1.1",
@ -38,6 +39,7 @@
"@ionic/angular": "^6.5.4",
"angular-oauth2-oidc": "^15.0.1",
"capacitor-share-extension": "^2.0.0",
"cordova-plugin-file-opener2": "^4.0.0",
"cordova-plugin-inappbrowser": "^5.0.0",
"ionicons": "^6.1.3",
"keycloak-angular": "^13.0.0",

View File

@ -11,13 +11,14 @@ import { D4sAuthService } from './d4sauth.service';
import { D4sIntentService } from './d4s-intent.service';
import {initializeIntent} from './_helper/intent-init.factory'
import { StoragehubService } from './storagehub.service';
import { EventService } from './event.service';
@NgModule({
declarations: [AppComponent],
imports: [BrowserModule, IonicModule.forRoot(), AppRoutingModule, HttpClientModule, HttpClientModule, KeycloakAngularModule],
providers: [
D4sAuthService, ModalController, StoragehubService, ToastController,
D4sAuthService, ModalController, StoragehubService, ToastController, EventService,
{ provide: RouteReuseStrategy, useClass: IonicRouteStrategy },
{
provide: APP_INITIALIZER,

View File

@ -63,12 +63,30 @@ export class D4sAuthService {
mustUpdate = true;
console.log("token refreshed");
}
if (this.uma && this.isExpired(35)){
console.log("uma expires in 35, must update")
mustUpdate = true;
}
if (mustUpdate || !this.uma)
this.uma = await this.entitlement(this.audience);
return "Bearer " + this.uma.access_token;
}
isExpired(minValidityInSeconds : number ) {
if (!this.uma) return false;
const expires: number = this.parseJwt(this.uma.access_token).exp;
const time: number = Date.now()/1000;
console.log(`exiperes in ${expires} and now is ${time}`);
return time+minValidityInSeconds > expires;
}
entitlement(resourceServerId: any): Promise<UmaToken> {
return new Promise((resolve, reject) => {
const keycloak = this.keycloak.getKeycloakInstance();

View File

@ -19,7 +19,7 @@ export class CopyAction extends Action {
onSelected: (destinationItem: WSItem) => {
this.actionHandler({ item: item, destinationItem: destinationItem }, storagehub).then( (obs) => obs.subscribe(
() => {
reload();
reload(destinationItem.item.id)
notify(`${item.getTitle()} copied`);
}
))

View File

@ -27,7 +27,7 @@ export class CreateFolderAction extends Action {
text: 'Create',
handler: (data) => {
this.actionHandler({ wsitem: item, name: data.name }, storagehub).then((obs) => obs.subscribe(
() => reload()
() => reload(item.item.id)
)
);
}

View File

@ -18,7 +18,7 @@ export class DeleteAction extends Action {
text: 'Yes',
handler: () => {
this.actionHandler(item, storagehub).then((obs) => obs.subscribe(
() => reload()
() => reload(item.item.parentId)
));
}
}]

View File

@ -18,7 +18,7 @@ export class MoveAction extends Action {
onSelected: (destinationItem:WSItem) =>{
this.actionHandler({item: item, destinationItem: destinationItem}, storagehub).then( (obs) => obs.subscribe(
() => {
reload();
reload(destinationItem.item.id);
notify(`${item.getTitle()} moved`);
}
))

View File

@ -27,7 +27,7 @@ export class RenameAction extends Action {
text: 'Rename',
handler: (data) => {
this.actionHandler({item: item, newName: data.name}, storagehub).then( (obs) => obs.subscribe(
() => reload()
() => reload(item.item.parentId)
));
}
}

View File

@ -38,6 +38,6 @@
</ion-buttons>
</div>
<input hidden type="file" #filepicker (change)="fileSelected($event)" />
<app-items-list [items]="filteredItems" [underUploadItem]="underUploadItem"
<app-items-list [items]="filteredItems" [underUploadItem]="underUpload"
(actionSheetClickedEvent)="presentActionSheet($event)" (itemClickedEvent)="itemClicked($event)"></app-items-list>
</ion-content>

View File

@ -12,11 +12,14 @@ import { CreateFolderAction } from '../model/actions/create-folder';
import { Actions } from '../model/actions/actions';
import { ItemsListComponent } from '../items-list/items-list.component';
import { Sorting, SortName, SortType } from '../model/sorting';
import { UploaderInfoService } from '../uploader-info.service';
import { EventService } from '../event.service';
import { OpenFile } from '../model/actions/open-file';
@Component({
standalone: true,
selector: 'show-folder',
providers: [FileOpener, StoragehubService],
providers: [FileOpener, StoragehubService, UploaderInfoService],
templateUrl: './show-folder.component.html',
styleUrls: ['./show-folder.component.scss'],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
@ -27,7 +30,7 @@ import { Sorting, SortName, SortType } from '../model/sorting';
export class ShowFolderComponent implements OnInit {
@Output() folderClickedEvent = new EventEmitter<WSItem>();
filteredItems: WSItem[] | undefined;
_items: WSItem[] | undefined;
@ -45,14 +48,14 @@ export class ShowFolderComponent implements OnInit {
@Input() root: boolean = false;
underUploadItem: string[] = [];
selectedSegment = "all";
public get sortName(): typeof SortName {
return SortName;
return SortName;
}
underUpload: string[];
@ViewChild('filepicker') uploader!: ElementRef;
customSortAlertOptions = {
@ -65,18 +68,31 @@ export class ShowFolderComponent implements OnInit {
private storagehub: StoragehubService,
private alertCtrl: AlertController,
private modalCtrl: ModalController,
private toastController: ToastController
private toastController: ToastController,
private uploaderInfo: UploaderInfoService,
private event: EventService,
private fileOpener: FileOpener
) {
this.underUpload = this.getUnderUploadItems();
}
ngOnInit(): void {
this.event.ReloadEvent.subscribe((val) => {
console.log(`event received with value ${val} in item ${this.parentItem?.item.id}`);
if (val === this.parentItem?.item.id)
this.loadDocuments();
});
}
getUnderUploadItems(): string[] {
const parentId = this.parentItem?.item.id;
return parentId ? this.uploaderInfo.getUnderUpload(parentId) : [];
}
loadDocuments() {
this.filteredItems = undefined;
if (this.parentItem) {
this.storagehub.getChildren(this.parentItem.item.id).then( (obs) => obs.subscribe(
this.storagehub.getChildren(this.parentItem.item.id).then((obs) => obs.subscribe(
(res) => {
const tmpItems$: WSItem[] = []
const tmpFiltered$: WSItem[] = []
@ -89,8 +105,9 @@ export class ShowFolderComponent implements OnInit {
});
this._items = tmpItems$.sort(Sorting.getSortFunction(this.currentSortName, this.currentSortType));
this.filteredItems = tmpFiltered$.sort(Sorting.getSortFunction(this.currentSortName, this.currentSortType));
this.underUpload = this.getUnderUploadItems();
})
)
)
}
}
@ -133,8 +150,8 @@ export class ShowFolderComponent implements OnInit {
}
changeSortName($event: any) {
var sort : SortName = $event.target.value;
if (this.currentSortName != sort){
var sort: SortName = $event.target.value;
if (this.currentSortName != sort) {
this.currentSortName = sort;
this.updateSort();
}
@ -146,9 +163,13 @@ export class ShowFolderComponent implements OnInit {
}
itemClicked(item: WSItem) {
if (item.isFolder()) {
if (item.isFolder())
this.folderClickedEvent.emit(item);
else if (item.isFile()){
new OpenFile().open(this.storagehub, this.fileOpener, item);
}
}
addFile() {
@ -159,12 +180,23 @@ export class ShowFolderComponent implements OnInit {
const selected = $event.target.files[0];
if (selected && this.parentItem) {
this.underUploadItem = [selected.name];
const upload$ = this.storagehub.uploadFile(this.parentItem.item.id, selected.name, selected);
upload$.then( (obs) => obs.subscribe({
next: () => this.loadDocuments(),
error: () => this.underUploadItem = [],
complete: () => this.underUploadItem = []
const parentId: string = this.parentItem?.item?.id;
this.uploaderInfo.uploadStarted(parentId, selected.name);
const upload$ = this.storagehub.uploadFile(parentId, selected.name, selected);
var first = true;
upload$.then((obs) => obs.subscribe({
next: () => {
if (first) {
this.loadDocuments();
first = false;
}
},
error: () => this.uploaderInfo.uploadFinished(parentId, selected.name),
complete: () => {
console.log
this.uploaderInfo.uploadFinished(parentId, selected.name);
this.loadDocuments();
}
})
);
@ -233,7 +265,7 @@ export class ShowFolderComponent implements OnInit {
await this.presentAlertControl(alertOptions);
} else {
var modalOptions: undefined | ModalOptions = action.getModalOptions(item, this.storagehub,
() => this.loadDocuments(), (text: string) => this.presentToast(text));
(itemId: string) => this.event.ReloadEvent.emit(itemId), (text: string) => this.presentToast(text));
if (modalOptions)
await this.presentModal(modalOptions);
else

View File

@ -8,6 +8,7 @@ import { Item } from './model/item.model';
import { ItemList } from './model/itemlist.model';
import { ItemWrapper } from './model/item-wrapper.model';
import { D4sAuthService } from './d4sauth.service';
import { WSItem } from './model/ws-item';
const shURL ="https://api.dev.d4science.org/workspace"
@ -87,6 +88,14 @@ export class StoragehubService {
);
}
async downloadFile(itemId: string){
const bearer = await this.auth.getSecureHeader();
let downloadUrl = `${shURL}/items/${itemId}/download`;
return this.http.get(downloadUrl, {headers: {"Authorization": bearer }, responseType: 'blob', observe: 'body'}).pipe(
catchError(this.error)
);
}
async createFolder(parentId: string, name: string, description: string) {
const bearer = await this.auth.getSecureHeader();
let createFolderURL = `${shURL}/items/${parentId}/create/FOLDER`;
@ -100,7 +109,7 @@ export class StoragehubService {
async deleteItem(itemId: string) : Promise<Observable<any>> {
const bearer = await this.auth.getSecureHeader();
let deleteItemUrl = `${shURL}/items/${itemId}`;
return this.http.delete( deleteItemUrl).pipe(
return this.http.delete( deleteItemUrl, {headers: {"Authorization": bearer }}).pipe(
catchError(this.error)
);
}