diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 1cb8f4ab..0995eaa6 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -41,6 +41,7 @@ import { HashtagComponent } from './components/stream/hashtag/hashtag.component' import { StreamOverlayComponent } from './components/stream/stream-overlay/stream-overlay.component'; import { DatabindedTextComponent } from './components/stream/status/databinded-text/databinded-text.component'; import { MastodonTimePipe } from './pipes/mastodon-time.pipe'; +import { TimeAgoPipe } from './pipes/time-ago.pipe'; const routes: Routes = [ { path: "", redirectTo: "home", pathMatch: "full" }, @@ -74,7 +75,8 @@ const routes: Routes = [ HashtagComponent, StreamOverlayComponent, DatabindedTextComponent, - MastodonTimePipe + MastodonTimePipe, + TimeAgoPipe ], imports: [ BrowserModule, diff --git a/src/app/components/stream/status/status.component.html b/src/app/components/stream/status/status.component.html index c3a9e341..9161e98c 100644 --- a/src/app/components/stream/status/status.component.html +++ b/src/app/components/stream/status/status.component.html @@ -13,7 +13,7 @@
{{ - status.created_at | mastodontime }}
+ status.created_at | timeAgo | async }} diff --git a/src/app/pipes/time-ago.pipe.spec.ts b/src/app/pipes/time-ago.pipe.spec.ts new file mode 100644 index 00000000..c3d7df28 --- /dev/null +++ b/src/app/pipes/time-ago.pipe.spec.ts @@ -0,0 +1,8 @@ +import { TimeAgoPipe } from './time-ago.pipe'; + +describe('TimeAgoPipe', () => { + it('create an instance', () => { + const pipe = new TimeAgoPipe(); + expect(pipe).toBeTruthy(); + }); +}); diff --git a/src/app/pipes/time-ago.pipe.ts b/src/app/pipes/time-ago.pipe.ts new file mode 100644 index 00000000..bb7f0a9d --- /dev/null +++ b/src/app/pipes/time-ago.pipe.ts @@ -0,0 +1,104 @@ +//https://github.com/AndrewPoyntz/time-ago-pipe/issues/6#issuecomment-313726956 + +import { Pipe, PipeTransform, NgZone } from "@angular/core"; +import { Observable, Observer } from 'rxjs'; + +interface processOutput { + text: string; // Convert timestamp to string + timeToUpdate: number; // Time until update in milliseconds +} + +@Pipe({ + name: 'timeAgo', + pure: true +}) +export class TimeAgoPipe implements PipeTransform { + + constructor(private ngZone: NgZone) { } + + private process = (timestamp: number): processOutput => { + let text: string; + let timeToUpdate: number; + + const now = new Date(); + + // Time ago in milliseconds + const timeAgo: number = now.getTime() - timestamp; + + const seconds = timeAgo / 1000; + const minutes = seconds / 60; + const hours = minutes / 60; + const days = hours / 24; + // const months = days / 30.416; + // const years = days / 365; + + if (seconds <= 60) { + text = Math.round(seconds) + 's'; + } else if (minutes <= 90) { + text = Math.round(minutes) + 'm'; + } else if (hours <= 24) { + text = Math.round(hours) + 'h'; + } else { + text = Math.round(days) + 'd'; + } + + if (minutes < 1) { + // update every 2 secs + timeToUpdate = 2 * 1000; + } else if (hours < 1) { + // update every 30 secs + timeToUpdate = 30 * 1000; + } else if (days < 1) { + // update every 5 mins + timeToUpdate = 300 * 1000; + } else { + // update every hour + timeToUpdate = 3600 * 1000; + } + + return { + text, + timeToUpdate + }; + } + + public transform = (value: string | Date): Observable => { + let d: Date; + if (value instanceof Date) { + d = value; + } + else { + d = new Date(value); + } + // time value in milliseconds + const timestamp = d.getTime(); + + let timeoutID: any; + + return Observable.create((observer: Observer) => { + let latestText = ''; + + // Repeatedly set new timeouts for new update checks. + const registerUpdate = () => { + const processOutput = this.process(timestamp); + if (processOutput.text !== latestText) { + latestText = processOutput.text; + this.ngZone.run(() => { + observer.next(latestText); + }); + } + timeoutID = setTimeout(registerUpdate, processOutput.timeToUpdate); + }; + + this.ngZone.runOutsideAngular(registerUpdate); + + // Return teardown function + const teardownFunction = () => { + if (timeoutID) { + clearTimeout(timeoutID); + } + }; + return teardownFunction; + }); + } +} \ No newline at end of file