mirror of
https://gitlab.com/openstapps/openstapps.git
synced 2026-01-21 17:12:43 +00:00
feat: add not found screen
This commit is contained in:
@@ -29,6 +29,11 @@
|
|||||||
"glob": "**/*.svg",
|
"glob": "**/*.svg",
|
||||||
"input": "node_modules/ionicons/dist/ionicons/svg",
|
"input": "node_modules/ionicons/dist/ionicons/svg",
|
||||||
"output": "./svg"
|
"output": "./svg"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"glob": "**/*.svg",
|
||||||
|
"input": "src/assets/custom-ion-icons",
|
||||||
|
"output": "./svg"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"styles": [{
|
"styles": [{
|
||||||
|
|||||||
23840
package-lock.json
generated
23840
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -43,8 +43,10 @@
|
|||||||
"@angular/platform-browser": "9.1.12",
|
"@angular/platform-browser": "9.1.12",
|
||||||
"@angular/platform-browser-dynamic": "9.1.12",
|
"@angular/platform-browser-dynamic": "9.1.12",
|
||||||
"@angular/router": "9.1.12",
|
"@angular/router": "9.1.12",
|
||||||
|
"@capacitor/core": "2.4.6",
|
||||||
"@ionic-native/core": "5.29.0",
|
"@ionic-native/core": "5.29.0",
|
||||||
"@ionic-native/geolocation": "5.29.0",
|
"@ionic-native/geolocation": "5.29.0",
|
||||||
|
"@ionic-native/network": "5.31.1",
|
||||||
"@ionic-native/splash-screen": "5.29.0",
|
"@ionic-native/splash-screen": "5.29.0",
|
||||||
"@ionic-native/status-bar": "5.29.0",
|
"@ionic-native/status-bar": "5.29.0",
|
||||||
"@ionic/angular": "5.4.1",
|
"@ionic/angular": "5.4.1",
|
||||||
@@ -61,6 +63,7 @@
|
|||||||
"cordova-plugin-geolocation": "4.1.0",
|
"cordova-plugin-geolocation": "4.1.0",
|
||||||
"cordova-plugin-ionic-keyboard": "2.2.0",
|
"cordova-plugin-ionic-keyboard": "2.2.0",
|
||||||
"cordova-plugin-ionic-webview": "5.0.0",
|
"cordova-plugin-ionic-webview": "5.0.0",
|
||||||
|
"cordova-plugin-network-information": "^2.0.2",
|
||||||
"cordova-plugin-splashscreen": "6.0.0",
|
"cordova-plugin-splashscreen": "6.0.0",
|
||||||
"cordova-plugin-whitelist": "1.3.4",
|
"cordova-plugin-whitelist": "1.3.4",
|
||||||
"core-js": "2.6.5",
|
"core-js": "2.6.5",
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import {CommonModule} from '@angular/common';
|
|||||||
import {HttpClientModule} from '@angular/common/http';
|
import {HttpClientModule} from '@angular/common/http';
|
||||||
import {NgModule} from '@angular/core';
|
import {NgModule} from '@angular/core';
|
||||||
import {FormsModule} from '@angular/forms';
|
import {FormsModule} from '@angular/forms';
|
||||||
|
import {Network} from '@ionic-native/network/ngx';
|
||||||
import {IonicModule} from '@ionic/angular';
|
import {IonicModule} from '@ionic/angular';
|
||||||
import {TranslateModule} from '@ngx-translate/core';
|
import {TranslateModule} from '@ngx-translate/core';
|
||||||
import {MarkdownModule} from 'ngx-markdown';
|
import {MarkdownModule} from 'ngx-markdown';
|
||||||
@@ -135,6 +136,7 @@ import {VideoListItem} from './types/video/video-list-item.component';
|
|||||||
providers: [
|
providers: [
|
||||||
DataProvider,
|
DataProvider,
|
||||||
DataFacetsProvider,
|
DataFacetsProvider,
|
||||||
|
Network,
|
||||||
StAppsWebHttpClient,
|
StAppsWebHttpClient,
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -12,43 +12,53 @@
|
|||||||
* You should have received a copy of the GNU General Public License along with
|
* You should have received a copy of the GNU General Public License along with
|
||||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
import {Component} from '@angular/core';
|
import {Component, OnInit} from '@angular/core';
|
||||||
import {ActivatedRoute} from '@angular/router';
|
import {ActivatedRoute} from '@angular/router';
|
||||||
|
import {Network} from '@ionic-native/network/ngx';
|
||||||
import {IonRefresher} from '@ionic/angular';
|
import {IonRefresher} from '@ionic/angular';
|
||||||
import {LangChangeEvent, TranslateService} from '@ngx-translate/core';
|
import {LangChangeEvent, TranslateService} from '@ngx-translate/core';
|
||||||
import {SCLanguageCode, SCThing, SCUuid} from '@openstapps/core';
|
import {SCLanguageCode, SCSaveableThing, SCThings, SCUuid} from '@openstapps/core';
|
||||||
import {DataProvider, DataScope} from '../data.provider';
|
import {DataProvider, DataScope} from '../data.provider';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODO
|
* A Component to display an SCThing detailed
|
||||||
*/
|
*/
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'stapps-data-detail',
|
selector: 'stapps-data-detail',
|
||||||
styleUrls: ['data-detail.scss'],
|
styleUrls: ['data-detail.scss'],
|
||||||
templateUrl: 'data-detail.html',
|
templateUrl: 'data-detail.html',
|
||||||
})
|
})
|
||||||
export class DataDetailComponent {
|
export class DataDetailComponent implements OnInit {
|
||||||
/**
|
/**
|
||||||
* TODO
|
* The associated item
|
||||||
|
*
|
||||||
|
* undefined if not loaded, null when unavailable
|
||||||
*/
|
*/
|
||||||
dataProvider: DataProvider;
|
item?: SCThings | null = undefined;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODO
|
* The language of the item
|
||||||
*/
|
|
||||||
item: SCThing;
|
|
||||||
/**
|
|
||||||
* TODO
|
|
||||||
*/
|
*/
|
||||||
language: SCLanguageCode;
|
language: SCLanguageCode;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
* Type guard for SCSavableThing
|
||||||
* @param route TODO
|
|
||||||
* @param dataProvider TODO
|
|
||||||
* @param translateService TODO
|
|
||||||
*/
|
*/
|
||||||
constructor(private readonly route: ActivatedRoute, dataProvider: DataProvider, translateService: TranslateService) {
|
static isSCSavableThing(thing: SCThings | SCSaveableThing<SCThings>): thing is SCSaveableThing<SCThings> {
|
||||||
this.dataProvider = dataProvider;
|
return typeof (thing as SCSaveableThing<SCThings>).data !== 'undefined';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param route the route the page was accessed from
|
||||||
|
* @param dataProvider the data provider
|
||||||
|
* @param network the network provider
|
||||||
|
* @param translateService the translation service
|
||||||
|
*/
|
||||||
|
constructor(private readonly route: ActivatedRoute,
|
||||||
|
private readonly dataProvider: DataProvider,
|
||||||
|
private readonly network: Network,
|
||||||
|
translateService: TranslateService) {
|
||||||
this.language = translateService.currentLang as SCLanguageCode;
|
this.language = translateService.currentLang as SCLanguageCode;
|
||||||
translateService.onLangChange.subscribe((event: LangChangeEvent) => {
|
translateService.onLangChange.subscribe((event: LangChangeEvent) => {
|
||||||
this.language = event.lang as SCLanguageCode;
|
this.language = event.lang as SCLanguageCode;
|
||||||
@@ -60,19 +70,27 @@ export class DataDetailComponent {
|
|||||||
*
|
*
|
||||||
* @param uid Unique identifier of a thing
|
* @param uid Unique identifier of a thing
|
||||||
*/
|
*/
|
||||||
async getItem(uid: SCUuid): Promise<void> {
|
async getItem(uid: SCUuid) {
|
||||||
await this.dataProvider.get(uid, DataScope.Remote)
|
try {
|
||||||
.then((data) => {
|
const item = await this.dataProvider.get(uid, DataScope.Remote);
|
||||||
this.item = data;
|
this.item = DataDetailComponent.isSCSavableThing(item) ? item.data : item;
|
||||||
});
|
} catch (_) {
|
||||||
|
this.item = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODO
|
* Check if we have internet
|
||||||
|
*/
|
||||||
|
isDisconnected(): boolean {
|
||||||
|
return this.network.type === this.network.Connection.NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize
|
||||||
*/
|
*/
|
||||||
// tslint:disable-next-line:prefer-function-over-method
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.getItem(this.route.snapshot.paramMap.get('uid') || '');
|
void this.getItem(this.route.snapshot.paramMap.get('uid') ?? '');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -81,7 +99,7 @@ export class DataDetailComponent {
|
|||||||
* @param refresher Refresher component that triggers the update
|
* @param refresher Refresher component that triggers the update
|
||||||
*/
|
*/
|
||||||
async refresh(refresher: IonRefresher) {
|
async refresh(refresher: IonRefresher) {
|
||||||
await this.getItem(this.item.uid);
|
await this.getItem(this.item?.uid ?? this.route.snapshot.paramMap.get('uid') ?? '');
|
||||||
refresher.complete();
|
await refresher.complete();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,12 +13,32 @@
|
|||||||
refreshingText="{{'data.REFRESHING' | translate}}">
|
refreshingText="{{'data.REFRESHING' | translate}}">
|
||||||
</ion-refresher-content>
|
</ion-refresher-content>
|
||||||
</ion-refresher>
|
</ion-refresher>
|
||||||
<ng-container *ngIf="!item">
|
<div [ngSwitch]="true">
|
||||||
<stapps-skeleton-list-item></stapps-skeleton-list-item>
|
<ng-container *ngSwitchCase='!item && isDisconnected()'>
|
||||||
<stapps-skeleton-simple-card></stapps-skeleton-simple-card>
|
<div class='notFoundContainer'>
|
||||||
</ng-container>
|
<ion-icon name='no-connection'>
|
||||||
<ng-container *ngIf="item">
|
</ion-icon>
|
||||||
<stapps-data-list-item [item]="item"></stapps-data-list-item>
|
<ion-label>
|
||||||
<stapps-data-detail-content [item]="item"></stapps-data-detail-content>
|
{{ 'data.detail.COULD_NOT_CONNECT' | translate }}
|
||||||
</ng-container>
|
</ion-label>
|
||||||
|
</div>
|
||||||
|
</ng-container>
|
||||||
|
<ng-container *ngSwitchCase="item === null">
|
||||||
|
<div class="notFoundContainer">
|
||||||
|
<ion-icon name="broken-link">
|
||||||
|
</ion-icon>
|
||||||
|
<ion-label>
|
||||||
|
{{ 'data.detail.NOT_FOUND' | translate }}
|
||||||
|
</ion-label>
|
||||||
|
</div>
|
||||||
|
</ng-container>
|
||||||
|
<ng-container *ngSwitchCase="!item && item !== null">
|
||||||
|
<stapps-skeleton-list-item></stapps-skeleton-list-item>
|
||||||
|
<stapps-skeleton-simple-card></stapps-skeleton-simple-card>
|
||||||
|
</ng-container>
|
||||||
|
<ng-container *ngSwitchDefault>
|
||||||
|
<stapps-data-list-item [item]="item"></stapps-data-list-item>
|
||||||
|
<stapps-data-detail-content [item]="item"></stapps-data-detail-content>
|
||||||
|
</ng-container>
|
||||||
|
</div>
|
||||||
</ion-content>
|
</ion-content>
|
||||||
|
|||||||
@@ -11,3 +11,20 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.notFoundContainer {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
text-align: center;
|
||||||
|
min-height: 50vh;
|
||||||
|
|
||||||
|
ion-icon {
|
||||||
|
font-size: 64px;
|
||||||
|
}
|
||||||
|
|
||||||
|
ion-label {
|
||||||
|
font-size: x-large;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
27
src/assets/custom-ion-icons/broken-link.svg
Normal file
27
src/assets/custom-ion-icons/broken-link.svg
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg width="100%" height="100%" viewBox="0 0 500 500" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linecap:round;stroke-linejoin:round;">
|
||||||
|
<g transform="matrix(1,0,0,1,-600,0)">
|
||||||
|
<rect id="Artboard2" x="600" y="0" width="500" height="500" style="fill:none;"/>
|
||||||
|
<g id="Artboard21" serif:id="Artboard2">
|
||||||
|
<g transform="matrix(0.448766,-0.893649,0.893649,0.448766,469.063,342.066)">
|
||||||
|
<path d="M172.406,353.651L144,352C91.336,352 48,308.664 48,256C48,203.336 91.336,160 144,160L208,160" style="fill:none;fill-rule:nonzero;stroke:currentColor;stroke-width:36px;"/>
|
||||||
|
</g>
|
||||||
|
<g transform="matrix(0.998306,-0.0581818,0.0581818,0.998306,578.658,-36.4373)">
|
||||||
|
<path d="M304,160L368,160C420.664,160 464,203.336 464,256C464,308.664 420.664,352 368,352L344.108,351.046" style="fill:none;fill-rule:nonzero;stroke:currentColor;stroke-width:36px;"/>
|
||||||
|
</g>
|
||||||
|
<g transform="matrix(0.835467,-0.54954,0.54954,0.835467,485.54,168.526)">
|
||||||
|
<path d="M313.991,245.837L367.731,276.894" style="fill:none;fill-rule:nonzero;stroke:currentColor;stroke-width:36px;"/>
|
||||||
|
</g>
|
||||||
|
<g transform="matrix(0.835467,-0.54954,-0.54954,-0.835467,642.903,689.819)">
|
||||||
|
<path d="M308.423,242.423L368.097,273.154" style="fill:none;fill-rule:nonzero;stroke:currentColor;stroke-width:36px;"/>
|
||||||
|
</g>
|
||||||
|
<g transform="matrix(0.835467,-0.54954,-0.54954,-0.835467,611.794,572.634)">
|
||||||
|
<path d="M343.592,241L328.795,281" style="fill:none;fill-rule:nonzero;stroke:currentColor;stroke-width:36px;"/>
|
||||||
|
</g>
|
||||||
|
<g transform="matrix(0.835467,-0.54954,0.54954,0.835467,397.953,88.4905)">
|
||||||
|
<path d="M343.592,241L328.795,281" style="fill:none;fill-rule:nonzero;stroke:currentColor;stroke-width:36px;"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 2.2 KiB |
13
src/assets/custom-ion-icons/no-connection.svg
Normal file
13
src/assets/custom-ion-icons/no-connection.svg
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg width="100%" height="100%" viewBox="0 0 512 512" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linecap:round;stroke-miterlimit:10;">
|
||||||
|
<path d="M74.216,154.839C57.516,184.784 48,219.281 48,256C48,370.87 141.13,464 256,464C293.515,464 328.711,454.067 359.102,436.688" style="fill:none;fill-rule:nonzero;stroke:black;stroke-width:32px;"/>
|
||||||
|
<path d="M437.104,358.371C454.225,328.147 464,293.215 464,256C464,141.13 370.87,48 256,48C218.643,48 183.586,57.849 153.283,75.093" style="fill:none;fill-rule:nonzero;stroke:black;stroke-width:32px;"/>
|
||||||
|
<path d="M367.788,281.198C368.369,272.938 368.67,264.529 368.67,256C368.67,141.13 314.07,48 256,48C229.248,48 203.232,67.766 182.951,100.317" style="fill:none;fill-rule:nonzero;stroke:black;stroke-width:32px;"/>
|
||||||
|
<path d="M144.485,227.192C143.725,236.608 143.33,246.225 143.33,256C143.33,370.87 197.93,464 256,464C282.923,464 309.099,443.982 329.435,411.06" style="fill:none;fill-rule:nonzero;stroke:black;stroke-width:32px;"/>
|
||||||
|
<path d="M238.57,160.066C244.322,160.466 250.135,160.67 256,160.67C308.29,160.67 356.43,144.48 394.67,117.33M276.68,352.181C269.87,351.618 262.972,351.33 256,351.33C203.71,351.33 155.57,367.52 117.33,394.67" style="fill:none;fill-rule:nonzero;stroke:black;stroke-width:32px;stroke-linejoin:round;stroke-miterlimit:4;"/>
|
||||||
|
<path d="M256,48L256,176.215M464,256L332.18,256" style="fill:none;fill-rule:nonzero;stroke:black;stroke-width:32px;"/>
|
||||||
|
<path d="M256,335.311L256,464" style="fill:none;fill-rule:nonzero;stroke:black;stroke-width:32px;"/>
|
||||||
|
<path d="M180.214,256L48,256" style="fill:none;fill-rule:nonzero;stroke:black;stroke-width:32px;"/>
|
||||||
|
<path d="M448,448L64,64" style="fill:none;fill-rule:nonzero;stroke:black;stroke-width:32px;"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 2.0 KiB |
@@ -3,7 +3,9 @@
|
|||||||
"REFRESH_ACTION": "Aktualisieren",
|
"REFRESH_ACTION": "Aktualisieren",
|
||||||
"REFRESHING": "Aktualisierung läuft...",
|
"REFRESHING": "Aktualisierung läuft...",
|
||||||
"detail": {
|
"detail": {
|
||||||
"TITLE": "Detailansicht"
|
"TITLE": "Detailansicht",
|
||||||
|
"NOT_FOUND": "Nicht gefunden",
|
||||||
|
"COULD_NOT_CONNECT": "Verbindung fehlgeschlagen"
|
||||||
},
|
},
|
||||||
"types": {
|
"types": {
|
||||||
"dish": {
|
"dish": {
|
||||||
|
|||||||
@@ -3,7 +3,9 @@
|
|||||||
"REFRESH_ACTION": "Refresh",
|
"REFRESH_ACTION": "Refresh",
|
||||||
"REFRESHING": "Refreshing...",
|
"REFRESHING": "Refreshing...",
|
||||||
"detail": {
|
"detail": {
|
||||||
"TITLE": "Details"
|
"TITLE": "Details",
|
||||||
|
"NOT_FOUND": "Not found",
|
||||||
|
"COULD_NOT_CONNECT": "Couldn't connect"
|
||||||
},
|
},
|
||||||
"types": {
|
"types": {
|
||||||
"dish": {
|
"dish": {
|
||||||
|
|||||||
Reference in New Issue
Block a user