mirror of
https://gitlab.com/openstapps/openstapps.git
synced 2026-01-20 00:23:03 +00:00
158 lines
4.9 KiB
TypeScript
158 lines
4.9 KiB
TypeScript
/*
|
|
* Copyright (C) 2023 StApps
|
|
* This program is free software: you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License as published by the Free
|
|
* Software Foundation, version 3.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
* more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along with
|
|
* this program. If not, see <https://www.gnu.org/licenses/>.
|
|
*/
|
|
import {Component, ContentChild, EventEmitter, Input, OnInit, Output, TemplateRef} from '@angular/core';
|
|
import {ActivatedRoute, Router} from '@angular/router';
|
|
import {ModalController} from '@ionic/angular';
|
|
import {LangChangeEvent, TranslateService} from '@ngx-translate/core';
|
|
import {SCLanguageCode, SCSaveableThing, SCThings, SCUuid} from '@openstapps/core';
|
|
import {DataProvider, DataScope} from '../data.provider';
|
|
import {FavoritesService} from '../../favorites/favorites.service';
|
|
import {take} from 'rxjs/operators';
|
|
import {Network} from '@capacitor/network';
|
|
import {DataListContext} from '../list/data-list.component';
|
|
|
|
export interface ExternalDataLoadEvent {
|
|
uid: SCUuid;
|
|
forceReload: boolean;
|
|
resolve: (item: SCThings | null | undefined) => void;
|
|
}
|
|
|
|
/**
|
|
* A Component to display an SCThing detailed
|
|
*/
|
|
@Component({
|
|
selector: 'stapps-data-detail',
|
|
styleUrls: ['data-detail.scss'],
|
|
templateUrl: 'data-detail.html',
|
|
})
|
|
export class DataDetailComponent implements OnInit {
|
|
/**
|
|
* The associated item
|
|
*
|
|
* undefined if not loaded, null when unavailable
|
|
*/
|
|
item?: SCThings | null = undefined;
|
|
|
|
collapse = false;
|
|
|
|
@Input() inputItem?: SCThings;
|
|
|
|
@Input() isModal = false;
|
|
|
|
@Input() autoRouteDataPath = true;
|
|
|
|
/**
|
|
* The language of the item
|
|
*/
|
|
language: SCLanguageCode;
|
|
|
|
/**
|
|
* Indicating wether internet connectivity is given or not
|
|
*/
|
|
isDisconnected: Promise<boolean>;
|
|
|
|
@ContentChild(TemplateRef) contentTemplateRef: TemplateRef<DataListContext<SCThings>>;
|
|
|
|
@Input() externalData = false;
|
|
|
|
/**
|
|
* This is kind of a stupid situation where we would
|
|
* like to use the default header in overriding elements
|
|
* such as the assessment detail page, however the ionic
|
|
* back button will not work if the header is in a subcomponent
|
|
* which then means we have to copy and paste the header from
|
|
* here into the overriding component.
|
|
*/
|
|
@Input() defaultHeader = true;
|
|
|
|
@Output() loadItem: EventEmitter<ExternalDataLoadEvent> = new EventEmitter<ExternalDataLoadEvent>();
|
|
|
|
/**
|
|
* Type guard for SCSavableThing
|
|
*/
|
|
static isSCSavableThing(thing: SCThings | SCSaveableThing): thing is SCSaveableThing {
|
|
return (thing as SCSaveableThing).data !== undefined;
|
|
}
|
|
|
|
constructor(
|
|
protected readonly route: ActivatedRoute,
|
|
router: Router,
|
|
private readonly dataProvider: DataProvider,
|
|
private readonly favoritesService: FavoritesService,
|
|
readonly modalController: ModalController,
|
|
translateService: TranslateService,
|
|
) {
|
|
this.inputItem = router.getCurrentNavigation()?.extras.state?.item;
|
|
if (!this.inputItem?.origin) {
|
|
// We received a ThingWithoutReferences.
|
|
// This can happen, for example, when detail views use `inPlace` list items
|
|
delete this.inputItem;
|
|
}
|
|
this.language = translateService.currentLang as SCLanguageCode;
|
|
translateService.onLangChange.subscribe((event: LangChangeEvent) => {
|
|
this.language = event.lang as SCLanguageCode;
|
|
});
|
|
|
|
this.isDisconnected = new Promise(async resolve => {
|
|
const isConnected = (await Network.getStatus()).connected;
|
|
resolve(!isConnected);
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Provides data item with given UID
|
|
* @param uid Unique identifier of a thing
|
|
* @param forceReload Indicating whether cached data should be ignored
|
|
*/
|
|
async getItem(uid: SCUuid, forceReload: boolean) {
|
|
try {
|
|
const item =
|
|
this.inputItem ??
|
|
(await (this.externalData
|
|
? new Promise<SCThings | null | undefined>(resolve =>
|
|
this.loadItem.emit({uid, forceReload, resolve}),
|
|
)
|
|
: this.dataProvider.get(uid, DataScope.Remote)));
|
|
|
|
this.item = item
|
|
? // eslint-disable-next-line unicorn/no-null
|
|
DataDetailComponent.isSCSavableThing(item)
|
|
? item.data
|
|
: item
|
|
: // eslint-disable-next-line unicorn/no-null
|
|
null;
|
|
} catch {
|
|
// eslint-disable-next-line unicorn/no-null
|
|
this.item = null;
|
|
}
|
|
}
|
|
|
|
async ngOnInit() {
|
|
const uid = this.route.snapshot.paramMap.get('uid') || '';
|
|
await this.getItem(uid ?? '', false);
|
|
// fallback to the saved item (from favorites)
|
|
if (this.item === null) {
|
|
this.favoritesService
|
|
.get(uid)
|
|
.pipe(take(1))
|
|
.subscribe(item => {
|
|
if (item !== undefined) {
|
|
this.item = item.data;
|
|
}
|
|
});
|
|
}
|
|
}
|
|
}
|