Add NewVersionCheckerService

This commit is contained in:
Milad Raeisi
2024-09-26 06:15:44 +04:00
parent 8d6a86e98d
commit 36793f1860
11 changed files with 160 additions and 30 deletions

View File

@@ -1,29 +1,6 @@
{
"$schema": "./node_modules/@angular/service-worker/config/schema.json",
"index": "/index.html",
"assetGroups": [
{
"name": "app",
"installMode": "prefetch",
"resources": {
"files": [
"/favicon.ico",
"/index.html",
"/manifest.webmanifest",
"/*.css",
"/*.js"
]
}
},
{
"name": "assets",
"installMode": "lazy",
"updateMode": "prefetch",
"resources": {
"files": [
"/**/*.(svg|cur|jpg|jpeg|png|apng|webp|avif|gif|otf|ttf|woff|woff2)"
]
}
}
]
"$schema": "./node_modules/@angular/service-worker/config/schema.json",
"index": "/index.html",
"assetGroups": [],
"navigationRequestStrategy": "freshness"
}

View File

@@ -19,7 +19,7 @@ import { ChatService } from '../chat.service';
import { Chat, Profile } from '../chat.types';
import { NewChatComponent } from '../new-chat/new-chat.component';
import { ProfileComponent } from '../profile/profile.component';
import { AgoPipe } from 'app/shared/ago.pipe';
import { AgoPipe } from 'app/shared/pipes/ago.pipe';
@Component({

View File

@@ -1,7 +1,6 @@
<div class="flex h-full w-full flex-col items-center justify-center">
<div class="flex h-full w-full flex-col items-center justify-center p-10">
<div class="w-full max-w-3xl">
<div class="prose prose-sm mx-auto max-w-none">
<img class="w-20" src="images/logo/logo.svg" alt="Angor Hub" />
<h1>Welcome to Angor Hub</h1>
<p>
Angor Hub is a Nostr client that is customized around the Angor protocol, a decentralized crowdfunding platform. Leveraging the power of Nostr the platform allows you to explore projects that are raising funds using Angor, engage with investors, and connect directly with founders.

View File

@@ -0,0 +1,78 @@
import { Injectable, NgZone } from '@angular/core';
import { SwUpdate } from '@angular/service-worker';
import { Subscription, interval } from 'rxjs';
@Injectable({ providedIn: 'root' })
export class NewVersionCheckerService {
isNewVersionAvailable: boolean = false;
newVersionSubscription?: Subscription;
intervalSource = interval(15 * 60 * 1000); // every 15 mins
intervalSubscription?: Subscription;
constructor(
private swUpdate: SwUpdate,
private zone: NgZone,
) {
this.checkForUpdateOnInterval();
this.checkForUpdateOnLoad();
}
applyUpdate(): void {
// Reload the page to update to the latest version after the new version is activated
this.swUpdate
.activateUpdate()
.then(() => document.location.reload())
.catch((error) => console.error('Failed to apply updates:', error));
}
checkForUpdateOnInterval(): void {
this.intervalSubscription?.unsubscribe();
if (!this.swUpdate.isEnabled) {
return;
}
this.zone.runOutsideAngular(() => {
this.intervalSubscription = this.intervalSource.subscribe(async () => {
if (!this.isNewVersionAvailable) {
try {
this.isNewVersionAvailable = await this.swUpdate.checkForUpdate();
console.log(this.isNewVersionAvailable ? 'A new version is available.' : 'Already on the latest version.');
} catch (error) {
console.error('Failed to check for updates:', error);
}
} else {
// Check for updates at interval, which will keep the
// browser updating to latest version as long as it's being kept open.
await this.swUpdate.checkForUpdate();
}
});
});
}
checkForUpdateOnLoad(): void {
this.newVersionSubscription?.unsubscribe();
if (!this.swUpdate.isEnabled) {
console.log('Service worker updates are disabled for this app.');
return;
}
this.newVersionSubscription = this.swUpdate.versionUpdates.subscribe((evt) => {
console.log('New version update event:');
console.log(evt);
switch (evt.type) {
case 'VERSION_DETECTED':
console.log(`Downloading new app version: ${evt.version.hash}`);
break;
case 'VERSION_READY':
console.log(`Current app version: ${evt.currentVersion.hash}`);
console.log(`New app version ready for use: ${evt.latestVersion.hash}`);
this.isNewVersionAvailable = true;
break;
case 'VERSION_INSTALLATION_FAILED':
console.log(`Failed to install app version '${evt.version.hash}': ${evt.error}`);
break;
}
});
console.log('Subscribed to new version updates.');
}
}

View File

@@ -0,0 +1,14 @@
import { Pipe, PipeTransform } from '@angular/core';
import { DomSanitizer, SafeResourceUrl } from '@angular/platform-browser';
@Pipe({
name: 'safeResourceUrl',
standalone: true,
})
export class SafeUrlPipe implements PipeTransform {
constructor(private readonly sanitizer: DomSanitizer) {}
public transform(url: string): SafeResourceUrl {
return this.sanitizer.bypassSecurityTrustResourceUrl(url);
}
}

View File

@@ -0,0 +1,8 @@
import { SizePipe } from './size.pipe';
describe('SizePipe', () => {
it('create an instance', () => {
const pipe = new SizePipe();
expect(pipe).toBeTruthy();
});
});

View File

@@ -0,0 +1,23 @@
import { Pipe, PipeTransform } from '@angular/core';
@Pipe({
name: 'size',
standalone: true,
})
export class SizePipe implements PipeTransform {
transform(value: any, args?: any): any {
if (value == null) {
return '';
}
if (value === 0) {
return '0 Bytes';
}
const k = 1024;
const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB'];
const i = Math.floor(Math.log(value) / Math.log(k));
return parseFloat((value / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
}
}

View File

@@ -0,0 +1,31 @@
import { Pipe, PipeTransform } from '@angular/core';
@Pipe({
name: 'stripHtml',
standalone: true,
})
export class StripHtmlPipe implements PipeTransform {
transform(value: string, limit: number = 200): string {
if (!value) {
return '...';
}
// Strip HTML tags and replace them with a space
let strippedText = value.replace(/<\/?[^>]+(>|$)/g, ' ');
// Replace &nbsp; with a space
strippedText = strippedText.replace(/&nbsp;/g, ' ');
// Remove extra spaces
const normalizedText = strippedText.replace(/\s\s+/g, ' ').trim();
// Limit the text to the specified number of characters
let result = normalizedText;
if (normalizedText.length > limit) {
result = normalizedText.substring(0, limit);
}
// Always add "..." at the end
return result.trim() + '...';
}
}