refactor static time formatting into new service
This commit is contained in:
parent
92de208414
commit
9984621e5e
@ -21,6 +21,7 @@ import { StorageService } from './services/storage.service';
|
||||
import { HttpCacheInterceptor } from './services/http-cache.interceptor';
|
||||
import { LanguageService } from './services/language.service';
|
||||
import { ThemeService } from './services/theme.service';
|
||||
import { TimeService } from './services/time.service';
|
||||
import { FiatShortenerPipe } from './shared/pipes/fiat-shortener.pipe';
|
||||
import { FiatCurrencyPipe } from './shared/pipes/fiat-currency.pipe';
|
||||
import { ShortenStringPipe } from './shared/pipes/shorten-string-pipe/shorten-string.pipe';
|
||||
@ -42,6 +43,7 @@ const providers = [
|
||||
EnterpriseService,
|
||||
LanguageService,
|
||||
ThemeService,
|
||||
TimeService,
|
||||
ShortenStringPipe,
|
||||
FiatShortenerPipe,
|
||||
FiatCurrencyPipe,
|
||||
|
@ -1,29 +1,6 @@
|
||||
import { Component, OnInit, OnDestroy, ChangeDetectionStrategy, Input, ChangeDetectorRef, OnChanges } from '@angular/core';
|
||||
import { StateService } from '../../services/state.service';
|
||||
import { dates } from '../../shared/i18n/dates';
|
||||
import { DatePipe } from '@angular/common';
|
||||
|
||||
const datePipe = new DatePipe(navigator.language || 'en-US');
|
||||
|
||||
const intervals = {
|
||||
year: 31536000,
|
||||
month: 2592000,
|
||||
week: 604800,
|
||||
day: 86400,
|
||||
hour: 3600,
|
||||
minute: 60,
|
||||
second: 1
|
||||
};
|
||||
|
||||
const precisionThresholds = {
|
||||
year: 100,
|
||||
month: 18,
|
||||
week: 12,
|
||||
day: 31,
|
||||
hour: 48,
|
||||
minute: 90,
|
||||
second: 90
|
||||
};
|
||||
import { TimeService } from '../../services/time.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-time',
|
||||
@ -52,6 +29,7 @@ export class TimeComponent implements OnInit, OnChanges, OnDestroy {
|
||||
constructor(
|
||||
private ref: ChangeDetectorRef,
|
||||
private stateService: StateService,
|
||||
private timeService: TimeService,
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
@ -79,7 +57,7 @@ export class TimeComponent implements OnInit, OnChanges, OnDestroy {
|
||||
}
|
||||
|
||||
calculateTime(): void {
|
||||
const { text, tooltip } = TimeComponent.calculate(
|
||||
const { text, tooltip } = this.timeService.calculate(
|
||||
this.time,
|
||||
this.kind,
|
||||
this.relative,
|
||||
@ -95,238 +73,4 @@ export class TimeComponent implements OnInit, OnChanges, OnDestroy {
|
||||
this.text = text;
|
||||
this.tooltip = tooltip;
|
||||
}
|
||||
|
||||
static calculate(
|
||||
time: number,
|
||||
kind: 'plain' | 'since' | 'until' | 'span' | 'before' | 'within',
|
||||
relative: boolean = false,
|
||||
precision: number = 0,
|
||||
minUnit: 'year' | 'month' | 'week' | 'day' | 'hour' | 'minute' | 'second' = 'second',
|
||||
showTooltip: boolean = false,
|
||||
units: string[] = ['year', 'month', 'week', 'day', 'hour', 'minute', 'second'],
|
||||
dateString?: string,
|
||||
lowercaseStart: boolean = false,
|
||||
numUnits: number = 1,
|
||||
fractionDigits: number = 0,
|
||||
): { text: string, tooltip: string } {
|
||||
if (time == null) {
|
||||
return { text: '', tooltip: '' };
|
||||
}
|
||||
|
||||
let seconds: number;
|
||||
let tooltip: string = '';
|
||||
switch (kind) {
|
||||
case 'since':
|
||||
seconds = Math.floor((+new Date() - +new Date(dateString || time * 1000)) / 1000);
|
||||
tooltip = datePipe.transform(new Date(dateString || time * 1000), 'yyyy-MM-dd HH:mm');
|
||||
break;
|
||||
case 'until':
|
||||
case 'within':
|
||||
seconds = (+new Date(time) - +new Date()) / 1000;
|
||||
tooltip = datePipe.transform(new Date(time), 'yyyy-MM-dd HH:mm');
|
||||
break;
|
||||
default:
|
||||
seconds = Math.floor(time);
|
||||
tooltip = '';
|
||||
}
|
||||
|
||||
if (!showTooltip || relative) {
|
||||
tooltip = '';
|
||||
}
|
||||
|
||||
if (seconds < 1 && kind === 'span') {
|
||||
return { tooltip, text: $localize`:@@date-base.immediately:Immediately` };
|
||||
} else if (seconds < 60) {
|
||||
if (relative || kind === 'since') {
|
||||
if (lowercaseStart) {
|
||||
return { tooltip, text: $localize`:@@date-base.just-now:Just now`.charAt(0).toLowerCase() + $localize`:@@date-base.just-now:Just now`.slice(1) };
|
||||
}
|
||||
return { tooltip, text: $localize`:@@date-base.just-now:Just now` };
|
||||
} else if (kind === 'until' || kind === 'within') {
|
||||
seconds = 60;
|
||||
}
|
||||
}
|
||||
|
||||
let counter: number;
|
||||
const result = [];
|
||||
let usedUnits = 0;
|
||||
for (const [index, unit] of units.entries()) {
|
||||
let precisionUnit = units[Math.min(units.length - 1, index + precision)];
|
||||
counter = Math.floor(seconds / intervals[unit]);
|
||||
const precisionCounter = Math.round(seconds / intervals[precisionUnit]);
|
||||
if (precisionCounter > precisionThresholds[precisionUnit]) {
|
||||
precisionUnit = unit;
|
||||
}
|
||||
if (units.indexOf(precisionUnit) === units.indexOf(minUnit)) {
|
||||
counter = Math.max(1, counter);
|
||||
}
|
||||
if (counter > 0) {
|
||||
let rounded;
|
||||
const roundFactor = Math.pow(10,fractionDigits || 0);
|
||||
if ((kind === 'until' || kind === 'within') && usedUnits < numUnits) {
|
||||
rounded = Math.floor((seconds / intervals[precisionUnit]) * roundFactor) / roundFactor;
|
||||
} else {
|
||||
rounded = Math.round((seconds / intervals[precisionUnit]) * roundFactor) / roundFactor;
|
||||
}
|
||||
if ((kind !== 'until' && kind !== 'within')|| numUnits === 1) {
|
||||
return { tooltip, text: TimeComponent.formatTime(kind, precisionUnit, rounded) };
|
||||
} else {
|
||||
if (!usedUnits) {
|
||||
result.push(TimeComponent.formatTime(kind, precisionUnit, rounded));
|
||||
} else {
|
||||
result.push(TimeComponent.formatTime('', precisionUnit, rounded));
|
||||
}
|
||||
seconds -= (rounded * intervals[precisionUnit]);
|
||||
usedUnits++;
|
||||
if (usedUnits >= numUnits) {
|
||||
return { tooltip, text: result.join(', ') };
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return { tooltip, text: result.join(', ') };
|
||||
}
|
||||
|
||||
static formatTime(kind, unit, number): string {
|
||||
const dateStrings = dates(number);
|
||||
switch (kind) {
|
||||
case 'since':
|
||||
if (number === 1) {
|
||||
switch (unit) { // singular (1 day)
|
||||
case 'year': return $localize`:@@time-since:${dateStrings.i18nYear}:DATE: ago`; break;
|
||||
case 'month': return $localize`:@@time-since:${dateStrings.i18nMonth}:DATE: ago`; break;
|
||||
case 'week': return $localize`:@@time-since:${dateStrings.i18nWeek}:DATE: ago`; break;
|
||||
case 'day': return $localize`:@@time-since:${dateStrings.i18nDay}:DATE: ago`; break;
|
||||
case 'hour': return $localize`:@@time-since:${dateStrings.i18nHour}:DATE: ago`; break;
|
||||
case 'minute': return $localize`:@@time-since:${dateStrings.i18nMinute}:DATE: ago`; break;
|
||||
case 'second': return $localize`:@@time-since:${dateStrings.i18nSecond}:DATE: ago`; break;
|
||||
}
|
||||
} else {
|
||||
switch (unit) { // plural (2 days)
|
||||
case 'year': return $localize`:@@time-since:${dateStrings.i18nYears}:DATE: ago`; break;
|
||||
case 'month': return $localize`:@@time-since:${dateStrings.i18nMonths}:DATE: ago`; break;
|
||||
case 'week': return $localize`:@@time-since:${dateStrings.i18nWeeks}:DATE: ago`; break;
|
||||
case 'day': return $localize`:@@time-since:${dateStrings.i18nDays}:DATE: ago`; break;
|
||||
case 'hour': return $localize`:@@time-since:${dateStrings.i18nHours}:DATE: ago`; break;
|
||||
case 'minute': return $localize`:@@time-since:${dateStrings.i18nMinutes}:DATE: ago`; break;
|
||||
case 'second': return $localize`:@@time-since:${dateStrings.i18nSeconds}:DATE: ago`; break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'until':
|
||||
if (number === 1) {
|
||||
switch (unit) { // singular (In ~1 day)
|
||||
case 'year': return $localize`:@@time-until:In ~${dateStrings.i18nYear}:DATE:`; break;
|
||||
case 'month': return $localize`:@@time-until:In ~${dateStrings.i18nMonth}:DATE:`; break;
|
||||
case 'week': return $localize`:@@time-until:In ~${dateStrings.i18nWeek}:DATE:`; break;
|
||||
case 'day': return $localize`:@@time-until:In ~${dateStrings.i18nDay}:DATE:`; break;
|
||||
case 'hour': return $localize`:@@time-until:In ~${dateStrings.i18nHour}:DATE:`; break;
|
||||
case 'minute': return $localize`:@@time-until:In ~${dateStrings.i18nMinute}:DATE:`;
|
||||
case 'second': return $localize`:@@time-until:In ~${dateStrings.i18nSecond}:DATE:`;
|
||||
}
|
||||
} else {
|
||||
switch (unit) { // plural (In ~2 days)
|
||||
case 'year': return $localize`:@@time-until:In ~${dateStrings.i18nYears}:DATE:`; break;
|
||||
case 'month': return $localize`:@@time-until:In ~${dateStrings.i18nMonths}:DATE:`; break;
|
||||
case 'week': return $localize`:@@time-until:In ~${dateStrings.i18nWeeks}:DATE:`; break;
|
||||
case 'day': return $localize`:@@time-until:In ~${dateStrings.i18nDays}:DATE:`; break;
|
||||
case 'hour': return $localize`:@@time-until:In ~${dateStrings.i18nHours}:DATE:`; break;
|
||||
case 'minute': return $localize`:@@time-until:In ~${dateStrings.i18nMinutes}:DATE:`; break;
|
||||
case 'second': return $localize`:@@time-until:In ~${dateStrings.i18nSeconds}:DATE:`; break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'within':
|
||||
if (number === 1) {
|
||||
switch (unit) { // singular (In ~1 day)
|
||||
case 'year': return $localize`:@@time-within:within ~${dateStrings.i18nYear}:DATE:`; break;
|
||||
case 'month': return $localize`:@@time-within:within ~${dateStrings.i18nMonth}:DATE:`; break;
|
||||
case 'week': return $localize`:@@time-within:within ~${dateStrings.i18nWeek}:DATE:`; break;
|
||||
case 'day': return $localize`:@@time-within:within ~${dateStrings.i18nDay}:DATE:`; break;
|
||||
case 'hour': return $localize`:@@time-within:within ~${dateStrings.i18nHour}:DATE:`; break;
|
||||
case 'minute': return $localize`:@@time-within:within ~${dateStrings.i18nMinute}:DATE:`;
|
||||
case 'second': return $localize`:@@time-within:within ~${dateStrings.i18nSecond}:DATE:`;
|
||||
}
|
||||
} else {
|
||||
switch (unit) { // plural (In ~2 days)
|
||||
case 'year': return $localize`:@@time-within:within ~${dateStrings.i18nYears}:DATE:`; break;
|
||||
case 'month': return $localize`:@@time-within:within ~${dateStrings.i18nMonths}:DATE:`; break;
|
||||
case 'week': return $localize`:@@time-within:within ~${dateStrings.i18nWeeks}:DATE:`; break;
|
||||
case 'day': return $localize`:@@time-within:within ~${dateStrings.i18nDays}:DATE:`; break;
|
||||
case 'hour': return $localize`:@@time-within:within ~${dateStrings.i18nHours}:DATE:`; break;
|
||||
case 'minute': return $localize`:@@time-within:within ~${dateStrings.i18nMinutes}:DATE:`; break;
|
||||
case 'second': return $localize`:@@time-within:within ~${dateStrings.i18nSeconds}:DATE:`; break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'span':
|
||||
if (number === 1) {
|
||||
switch (unit) { // singular (1 day)
|
||||
case 'year': return $localize`:@@time-span:After ${dateStrings.i18nYear}:DATE:`; break;
|
||||
case 'month': return $localize`:@@time-span:After ${dateStrings.i18nMonth}:DATE:`; break;
|
||||
case 'week': return $localize`:@@time-span:After ${dateStrings.i18nWeek}:DATE:`; break;
|
||||
case 'day': return $localize`:@@time-span:After ${dateStrings.i18nDay}:DATE:`; break;
|
||||
case 'hour': return $localize`:@@time-span:After ${dateStrings.i18nHour}:DATE:`; break;
|
||||
case 'minute': return $localize`:@@time-span:After ${dateStrings.i18nMinute}:DATE:`; break;
|
||||
case 'second': return $localize`:@@time-span:After ${dateStrings.i18nSecond}:DATE:`; break;
|
||||
}
|
||||
} else {
|
||||
switch (unit) { // plural (2 days)
|
||||
case 'year': return $localize`:@@time-span:After ${dateStrings.i18nYears}:DATE:`; break;
|
||||
case 'month': return $localize`:@@time-span:After ${dateStrings.i18nMonths}:DATE:`; break;
|
||||
case 'week': return $localize`:@@time-span:After ${dateStrings.i18nWeeks}:DATE:`; break;
|
||||
case 'day': return $localize`:@@time-span:After ${dateStrings.i18nDays}:DATE:`; break;
|
||||
case 'hour': return $localize`:@@time-span:After ${dateStrings.i18nHours}:DATE:`; break;
|
||||
case 'minute': return $localize`:@@time-span:After ${dateStrings.i18nMinutes}:DATE:`; break;
|
||||
case 'second': return $localize`:@@time-span:After ${dateStrings.i18nSeconds}:DATE:`; break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'before':
|
||||
if (number === 1) {
|
||||
switch (unit) { // singular (1 day)
|
||||
case 'year': return $localize`:@@time-before:${dateStrings.i18nYear}:DATE: before`; break;
|
||||
case 'month': return $localize`:@@time-before:${dateStrings.i18nMonth}:DATE: before`; break;
|
||||
case 'week': return $localize`:@@time-before:${dateStrings.i18nWeek}:DATE: before`; break;
|
||||
case 'day': return $localize`:@@time-before:${dateStrings.i18nDay}:DATE: before`; break;
|
||||
case 'hour': return $localize`:@@time-before:${dateStrings.i18nHour}:DATE: before`; break;
|
||||
case 'minute': return $localize`:@@time-before:${dateStrings.i18nMinute}:DATE: before`; break;
|
||||
case 'second': return $localize`:@@time-before:${dateStrings.i18nSecond}:DATE: before`; break;
|
||||
}
|
||||
} else {
|
||||
switch (unit) { // plural (2 days)
|
||||
case 'year': return $localize`:@@time-before:${dateStrings.i18nYears}:DATE: before`; break;
|
||||
case 'month': return $localize`:@@time-before:${dateStrings.i18nMonths}:DATE: before`; break;
|
||||
case 'week': return $localize`:@@time-before:${dateStrings.i18nWeeks}:DATE: before`; break;
|
||||
case 'day': return $localize`:@@time-before:${dateStrings.i18nDays}:DATE: before`; break;
|
||||
case 'hour': return $localize`:@@time-before:${dateStrings.i18nHours}:DATE: before`; break;
|
||||
case 'minute': return $localize`:@@time-before:${dateStrings.i18nMinutes}:DATE: before`; break;
|
||||
case 'second': return $localize`:@@time-before:${dateStrings.i18nSeconds}:DATE: before`; break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (number === 1) {
|
||||
switch (unit) { // singular (1 day)
|
||||
case 'year': return dateStrings.i18nYear; break;
|
||||
case 'month': return dateStrings.i18nMonth; break;
|
||||
case 'week': return dateStrings.i18nWeek; break;
|
||||
case 'day': return dateStrings.i18nDay; break;
|
||||
case 'hour': return dateStrings.i18nHour; break;
|
||||
case 'minute': return dateStrings.i18nMinute; break;
|
||||
case 'second': return dateStrings.i18nSecond; break;
|
||||
}
|
||||
} else {
|
||||
switch (unit) { // plural (2 days)
|
||||
case 'year': return dateStrings.i18nYears; break;
|
||||
case 'month': return dateStrings.i18nMonths; break;
|
||||
case 'week': return dateStrings.i18nWeeks; break;
|
||||
case 'day': return dateStrings.i18nDays; break;
|
||||
case 'hour': return dateStrings.i18nHours; break;
|
||||
case 'minute': return dateStrings.i18nMinutes; break;
|
||||
case 'second': return dateStrings.i18nSeconds; break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, NgZone, OnChanges, OnDestroy, SimpleChanges } from '@angular/core';
|
||||
import { EChartsOption } from '../../graphs/echarts';
|
||||
import { BehaviorSubject, Subscription } from 'rxjs';
|
||||
import { Subscription } from 'rxjs';
|
||||
import { Utxo } from '../../interfaces/electrs.interface';
|
||||
import { StateService } from '../../services/state.service';
|
||||
import { Router } from '@angular/router';
|
||||
@ -8,6 +8,7 @@ import { RelativeUrlPipe } from '../../shared/pipes/relative-url/relative-url.pi
|
||||
import { renderSats } from '../../shared/common.utils';
|
||||
import { colorToHex, hexToColor, mix } from '../block-overview-graph/utils';
|
||||
import { TimeComponent } from '../time/time.component';
|
||||
import { TimeService } from '../../services/time.service';
|
||||
|
||||
const newColorHex = '1bd8f4';
|
||||
const oldColorHex = '9339f4';
|
||||
@ -55,6 +56,7 @@ export class UtxoGraphComponent implements OnChanges, OnDestroy {
|
||||
private zone: NgZone,
|
||||
private router: Router,
|
||||
private relativeUrlPipe: RelativeUrlPipe,
|
||||
private timeService: TimeService,
|
||||
) {
|
||||
// re-render the chart every 10 seconds, to keep the age colors up to date
|
||||
this.updateInterval = setInterval(() => {
|
||||
@ -276,7 +278,7 @@ export class UtxoGraphComponent implements OnChanges, OnDestroy {
|
||||
<br>
|
||||
${valueStr}
|
||||
<br>
|
||||
${utxo.status.confirmed ? 'Confirmed ' + TimeComponent.calculate(utxo.status.block_time, 'since', true, 1, 'minute').text : 'Pending'}
|
||||
${utxo.status.confirmed ? 'Confirmed ' + this.timeService.calculate(utxo.status.block_time, 'since', true, 1, 'minute').text : 'Pending'}
|
||||
`;
|
||||
},
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user