From c4e239a4011805a68043194989195d0e358e7402 Mon Sep 17 00:00:00 2001 From: Bruno Windels <274386+bwindels@users.noreply.github.com> Date: Fri, 25 Nov 2022 16:13:22 +0100 Subject: [PATCH] add timeformatter, shared between all view models --- src/domain/ViewModel.ts | 5 ++ .../session/room/timeline/tiles/DateTile.ts | 8 +- src/platform/types/types.ts | 6 +- src/platform/web/Platform.js | 2 + src/platform/web/dom/TimeFormatter.ts | 73 +++++++++++++++++++ 5 files changed, 86 insertions(+), 8 deletions(-) create mode 100644 src/platform/web/dom/TimeFormatter.ts diff --git a/src/domain/ViewModel.ts b/src/domain/ViewModel.ts index 8dbc37ea..878b43ba 100644 --- a/src/domain/ViewModel.ts +++ b/src/domain/ViewModel.ts @@ -29,6 +29,7 @@ import type {ILogger} from "../logging/types"; import type {Navigation} from "./navigation/Navigation"; import type {SegmentType} from "./navigation/index"; import type {IURLRouter} from "./navigation/URLRouter"; +import type { ITimeFormatter } from "../platform/types/types"; export type Options = { platform: Platform; @@ -145,4 +146,8 @@ export class ViewModel = Op // typescript needs a little help here return this._options.navigation as unknown as Navigation; } + + get timeFormatter(): ITimeFormatter { + return this._options.platform.timeFormatter; + } } diff --git a/src/domain/session/room/timeline/tiles/DateTile.ts b/src/domain/session/room/timeline/tiles/DateTile.ts index 36150a68..d8dac808 100644 --- a/src/domain/session/room/timeline/tiles/DateTile.ts +++ b/src/domain/session/room/timeline/tiles/DateTile.ts @@ -48,13 +48,7 @@ export class DateTile extends ViewModel implements ITile { get date(): string { if (!this._dateString) { - const date = new Date(this.refEntry.timestamp); - this._dateString = date.toLocaleDateString({}, { - weekday: 'long', - year: 'numeric', - month: 'long', - day: 'numeric' - }); + this._dateString = this.timeFormatter.formatRelativeDate(new Date(this.refEntry.timestamp)); } return this._dateString; } diff --git a/src/platform/types/types.ts b/src/platform/types/types.ts index 1d359a09..5e982545 100644 --- a/src/platform/types/types.ts +++ b/src/platform/types/types.ts @@ -16,7 +16,7 @@ limitations under the License. import type {RequestResult} from "../web/dom/request/fetch.js"; import type {RequestBody} from "../../matrix/net/common"; -import type {ILogItem} from "../../logging/types"; +import type { BaseObservableValue } from "../../observable/ObservableValue"; export interface IRequestOptions { uploadProgress?: (loadedBytes: number) => void; @@ -43,3 +43,7 @@ export type File = { readonly name: string; readonly blob: IBlobHandle; } + +export interface ITimeFormatter { + formatRelativeDate(date: Date): string; +} \ No newline at end of file diff --git a/src/platform/web/Platform.js b/src/platform/web/Platform.js index 29a83e1f..0d95e585 100644 --- a/src/platform/web/Platform.js +++ b/src/platform/web/Platform.js @@ -39,6 +39,7 @@ import {Disposables} from "../../utils/Disposables"; import {parseHTML} from "./parsehtml.js"; import {handleAvatarError} from "./ui/avatar"; import {ThemeLoader} from "./theming/ThemeLoader"; +import {TimeFormatter} from "./dom/TimeFormatter"; function addScript(src) { return new Promise(function (resolve, reject) { @@ -139,6 +140,7 @@ export class Platform { this._createLogger(options?.development); this.history = new History(); this.onlineStatus = new OnlineStatus(); + this.timeFormatter = new TimeFormatter(); this._serviceWorkerHandler = null; if (assetPaths.serviceWorker && "serviceWorker" in navigator) { this._serviceWorkerHandler = new ServiceWorkerHandler(); diff --git a/src/platform/web/dom/TimeFormatter.ts b/src/platform/web/dom/TimeFormatter.ts new file mode 100644 index 00000000..ab9d454e --- /dev/null +++ b/src/platform/web/dom/TimeFormatter.ts @@ -0,0 +1,73 @@ +/* +Copyright 2022 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import type { ITimeFormatter } from "../../types/types"; +import {Clock} from "./Clock"; + +enum TimeScope { + Minute = 60 * 1000, + Day = 24 * 60 * 60 * 1000, +} + +export class TimeFormatter implements ITimeFormatter { + + private todayMidnight: Date; + private relativeDayFormatter: Intl.RelativeTimeFormat; + private weekdayFormatter: Intl.DateTimeFormat; + private currentYearFormatter: Intl.DateTimeFormat; + private otherYearFormatter: Intl.DateTimeFormat; + + constructor(private clock: Clock) { + // don't use the clock time here as the DOM relative formatters don't support setting the reference date anyway + this.todayMidnight = new Date(); + this.todayMidnight.setHours(0, 0, 0, 0); + this.relativeDayFormatter = new Intl.RelativeTimeFormat(undefined, {numeric: "auto"}); + this.weekdayFormatter = new Intl.DateTimeFormat(undefined, {weekday: 'long'}); + this.currentYearFormatter = new Intl.DateTimeFormat(undefined, { + weekday: 'long', + month: 'long', + day: 'numeric' + }); + this.otherYearFormatter = new Intl.DateTimeFormat(undefined, { + weekday: 'long', + year: 'numeric', + month: 'long', + day: 'numeric' + }); + } + + formatRelativeDate(date: Date): string { + let daysDiff = Math.floor((date.getTime() - this.todayMidnight.getTime()) / TimeScope.Day); + console.log("formatRelativeDate daysDiff", daysDiff, date); + if (daysDiff >= -1 && daysDiff <= 1) { + // Tomorrow, Today, Yesterday + return capitalizeFirstLetter(this.relativeDayFormatter.format(daysDiff, "day")); + } else if (daysDiff > -7 && daysDiff < 0) { + // Wednesday + return this.weekdayFormatter.format(date); + } else if (this.todayMidnight.getFullYear() === date.getFullYear()) { + // Friday, November 6 + return this.currentYearFormatter.format(date); + } else { + // Friday, November 5, 2021 + return this.otherYearFormatter.format(date); + } + } +} + +function capitalizeFirstLetter(str: string) { + return str.slice(0, 1).toLocaleUpperCase() + str.slice(1); +} \ No newline at end of file