Telegram Web K with changes to work inside I2P
https://web.telegram.i2p/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
494 lines
15 KiB
494 lines
15 KiB
/* |
|
* https://github.com/morethanwords/tweb |
|
* Copyright (C) 2019-2021 Eduard Kuzmenko |
|
* https://github.com/morethanwords/tweb/blob/master/LICENSE |
|
*/ |
|
|
|
import { MOUNT_CLASS_TO } from "../config/debug"; |
|
import I18n, { i18n } from "../lib/langPack"; |
|
import { capitalizeFirstLetter } from "./string"; |
|
|
|
export const months = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']; |
|
export const days = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']; |
|
|
|
export const ONE_DAY = 86400; |
|
|
|
// https://stackoverflow.com/a/6117889 |
|
export const getWeekNumber = (date: Date) => { |
|
const d = new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate())); |
|
const dayNum = d.getUTCDay() || 7; |
|
d.setUTCDate(d.getUTCDate() + 4 - dayNum); |
|
const yearStart = new Date(Date.UTC(d.getUTCFullYear(), 0, 1)); |
|
return Math.ceil((((d.getTime() - yearStart.getTime()) / ONE_DAY) + 1) / 7); |
|
}; |
|
|
|
export function formatDateAccordingToTodayNew(time: Date) { |
|
const today = new Date(); |
|
const now = today.getTime() / 1000 | 0; |
|
const timestamp = time.getTime() / 1000 | 0; |
|
|
|
const options: Intl.DateTimeFormatOptions = {}; |
|
if((now - timestamp) < ONE_DAY && today.getDate() === time.getDate()) { // if the same day |
|
options.hour = options.minute = '2-digit'; |
|
} else if(today.getFullYear() !== time.getFullYear()) { // different year |
|
options.year = options.day = 'numeric'; |
|
options.month = '2-digit'; |
|
} else if((now - timestamp) < (ONE_DAY * 7) && getWeekNumber(today) === getWeekNumber(time)) { // current week |
|
options.weekday = 'short'; |
|
} else { // same year |
|
options.month = 'short'; |
|
options.day = 'numeric'; |
|
} |
|
|
|
return new I18n.IntlDateElement({ |
|
date: time, |
|
options |
|
}).element; |
|
} |
|
|
|
export function formatFullSentTime(timestamp: number) { |
|
const date = new Date(); |
|
const time = new Date(timestamp * 1000); |
|
const now = date.getTime() / 1000; |
|
|
|
const timeEl = formatTime(time); |
|
|
|
let dateEl: Node | string; |
|
if((now - timestamp) < ONE_DAY && date.getDate() === time.getDate()) { // if the same day |
|
dateEl = i18n('Date.Today'); |
|
} else if((now - timestamp) < (ONE_DAY * 2) && (date.getDate() - 1) === time.getDate()) { // yesterday |
|
dateEl = capitalizeFirstLetter(I18n.format('Yesterday', true)); |
|
} else if(date.getFullYear() !== time.getFullYear()) { // different year |
|
dateEl = new I18n.IntlDateElement({ |
|
date: time, |
|
options: { |
|
month: 'short', |
|
day: 'numeric', |
|
year: 'numeric' |
|
} |
|
}).element; |
|
// dateStr = months[time.getMonth()].slice(0, 3) + ' ' + time.getDate() + ', ' + time.getFullYear(); |
|
} else { |
|
dateEl = new I18n.IntlDateElement({ |
|
date: time, |
|
options: { |
|
month: 'short', |
|
day: 'numeric' |
|
} |
|
}).element; |
|
// dateStr = months[time.getMonth()].slice(0, 3) + ' ' + time.getDate(); |
|
} |
|
|
|
const fragment = document.createDocumentFragment(); |
|
fragment.append(dateEl, ' ', i18n('ScheduleController.at'), ' ', timeEl); |
|
return fragment; |
|
} |
|
|
|
export function formatTime(date: Date) { |
|
return new I18n.IntlDateElement({ |
|
date, |
|
options: { |
|
hour: '2-digit', |
|
minute: '2-digit' |
|
} |
|
}).element; |
|
} |
|
|
|
MOUNT_CLASS_TO && (MOUNT_CLASS_TO.formatDateAccordingToTodayNew = formatDateAccordingToTodayNew); |
|
|
|
export const getFullDate = (date: Date, options: Partial<{ |
|
noTime: true, |
|
noSeconds: true, |
|
monthAsNumber: true, |
|
leadingZero: true |
|
}> = {}) => { |
|
const joiner = options.monthAsNumber ? '.' : ' '; |
|
const time = ('0' + date.getHours()).slice(-2) + ':' + ('0' + date.getMinutes()).slice(-2) + (options.noSeconds ? '' : ':' + ('0' + date.getSeconds()).slice(-2)); |
|
|
|
return (options.leadingZero ? ('0' + date.getDate()).slice(-2) : date.getDate()) + |
|
joiner + (options.monthAsNumber ? ('0' + (date.getMonth() + 1)).slice(-2) : months[date.getMonth()]) + |
|
joiner + date.getFullYear() + |
|
(options.noTime ? '' : ', ' + time); |
|
}; |
|
|
|
export function tsNow(seconds?: true) { |
|
const t = Date.now(); |
|
return seconds ? t / 1000 | 0 : t; |
|
} |
|
|
|
// https://github.com/DrKLO/Telegram/blob/d52b2c921abd3c1e8d6368858313ad0cb0468c07/TMessagesProj/src/main/java/org/telegram/ui/Adapters/FiltersView.java |
|
const minYear = 2013; |
|
const yearPattern = new RegExp("20[0-9]{1,2}"); |
|
const monthYearOrDayPattern = new RegExp("(\\w{3,}) ([0-9]{0,4})", 'i'); |
|
const yearOrDayAndMonthPattern = new RegExp("([0-9]{0,4}) (\\w{2,})", 'i'); |
|
const shortDate = new RegExp("^([0-9]{1,4})(\\.| |/|\\-)([0-9]{1,4})$", 'i'); |
|
const longDate = new RegExp("^([0-9]{1,2})(\\.| |/|\\-)([0-9]{1,2})(\\.| |/|\\-)([0-9]{1,4})$", 'i'); |
|
const numberOfDaysEachMonth = [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]; |
|
export type DateData = { |
|
title: string, |
|
minDate: number, |
|
maxDate: number, |
|
}; |
|
export function fillTipDates(query: string, dates: DateData[]) { |
|
const q = query.trim().toLowerCase(); |
|
|
|
if(q.length < 3) { |
|
return; |
|
} |
|
|
|
if("today".indexOf(q) === 0) { |
|
const date = new Date(); |
|
const year = date.getFullYear(); |
|
const month = date.getMonth(); |
|
const day = date.getDate(); |
|
date.setFullYear(year, month, day); |
|
date.setHours(0, 0, 0); |
|
|
|
const minDate = date.getTime(); |
|
date.setFullYear(year, month, day + 1); |
|
date.setHours(0, 0, 0); |
|
|
|
const maxDate = date.getTime() - 1; |
|
dates.push({ |
|
title: 'Today', |
|
minDate, |
|
maxDate |
|
}); |
|
return; |
|
} |
|
|
|
if("yesterday".indexOf(q) === 0) { |
|
const date = new Date(); |
|
const year = date.getFullYear(); |
|
const month = date.getMonth(); |
|
const day = date.getDate(); |
|
date.setFullYear(year, month, day); |
|
date.setHours(0, 0, 0); |
|
|
|
const minDate = date.getTime() - 86400000; |
|
date.setFullYear(year, month, day + 1); |
|
date.setHours(0, 0, 0); |
|
|
|
const maxDate = date.getTime() - 86400001; |
|
dates.push({ |
|
title: 'Yesterday', |
|
minDate, |
|
maxDate |
|
}); |
|
return; |
|
} |
|
|
|
const dayOfWeek = getDayOfWeek(q); |
|
if(dayOfWeek >= 0) { |
|
const date = new Date(); |
|
const now = date.getTime(); |
|
const currentDay = date.getDay(); |
|
const distance = dayOfWeek - currentDay; |
|
date.setDate(date.getDate() + distance); |
|
if(date.getTime() > now) { |
|
date.setTime(date.getTime() - 604800000); |
|
} |
|
const year = date.getFullYear() |
|
const month = date.getMonth(); |
|
const day = date.getDate(); |
|
date.setFullYear(year, month, day); |
|
date.setHours(0, 0, 0); |
|
|
|
const minDate = date.getTime(); |
|
date.setFullYear(year, month, day + 1); |
|
date.setHours(0, 0, 0); |
|
|
|
const maxDate = date.getTime() - 1; |
|
dates.push({ |
|
title: formatWeekLong(minDate), |
|
minDate, |
|
maxDate |
|
}); |
|
return; |
|
} |
|
|
|
let matches: any[]; |
|
if((matches = shortDate.exec(q)) !== null) { |
|
const g1 = matches[1]; |
|
const g2 = matches[3]; |
|
const k = parseInt(g1); |
|
const k1 = parseInt(g2); |
|
if(k > 0 && k <= 31) { |
|
if(k1 >= minYear && k <= 12) { |
|
const selectedYear = k1; |
|
const month = k - 1; |
|
createForMonthYear(dates, month, selectedYear); |
|
return; |
|
} else if (k1 <= 12) { |
|
const day = k - 1; |
|
const month = k1 - 1; |
|
createForDayMonth(dates, day, month); |
|
} |
|
} else if (k >= minYear && k1 <= 12) { |
|
const selectedYear = k; |
|
const month = k1 - 1; |
|
createForMonthYear(dates, month, selectedYear); |
|
} |
|
|
|
return; |
|
} |
|
|
|
if((matches = longDate.exec(q)) !== null) { |
|
const g1 = matches[1]; |
|
const g2 = matches[3]; |
|
const g3 = matches[5]; |
|
if(!matches[2] === matches[4]) { |
|
return; |
|
} |
|
|
|
const day = parseInt(g1); |
|
const month = parseInt(g2) - 1; |
|
let year = parseInt(g3); |
|
if(year >= 10 && year <= 99) { |
|
year += 2000; |
|
} |
|
|
|
const currentYear = new Date().getFullYear(); |
|
if(validDateForMonth(day - 1, month) && year >= minYear && year <= currentYear) { |
|
const date = new Date(); |
|
date.setFullYear(year, month, day); |
|
date.setHours(0, 0, 0); |
|
|
|
const minDate = date.getTime(); |
|
date.setFullYear(year, month, day + 1); |
|
date.setHours(0, 0, 0); |
|
|
|
const maxDate = date.getTime() - 1; |
|
dates.push({ |
|
title: formatterYearMax(minDate), |
|
minDate, |
|
maxDate |
|
}); |
|
return; |
|
} |
|
|
|
return; |
|
} |
|
|
|
if((matches = yearPattern.exec(q)) !== null) { |
|
let selectedYear = +q; |
|
const currentYear = new Date().getFullYear(); |
|
if(selectedYear < minYear) { |
|
selectedYear = minYear; |
|
for(let i = currentYear; i >= selectedYear; i--) { |
|
const date = new Date(); |
|
date.setFullYear(i, 0, 1); |
|
date.setHours(0, 0, 0); |
|
|
|
const minDate = date.getTime(); |
|
date.setFullYear(i + 1, 0, 1); |
|
date.setHours(0, 0, 0); |
|
|
|
const maxDate = date.getTime() - 1; |
|
dates.push({ |
|
title: '' + i, |
|
minDate, |
|
maxDate |
|
}); |
|
} |
|
} else if(selectedYear <= currentYear) { |
|
const date = new Date(); |
|
date.setFullYear(selectedYear, 0, 1); |
|
date.setHours(0, 0, 0); |
|
|
|
const minDate = date.getTime(); |
|
date.setFullYear(selectedYear + 1, 0, 1); |
|
date.setHours(0, 0, 0); |
|
|
|
const maxDate = date.getTime() - 1; |
|
dates.push({ |
|
title: '' + selectedYear, |
|
minDate, |
|
maxDate |
|
}); |
|
} |
|
|
|
return; |
|
} |
|
|
|
if((matches = monthYearOrDayPattern.exec(q)) !== null) { |
|
const g1 = matches[1]; |
|
const g2 = matches[2]; |
|
const month = getMonth(g1); |
|
if(month >= 0) { |
|
const k = +g2; |
|
if(k > 0 && k <= 31) { |
|
const day = k - 1; |
|
createForDayMonth(dates, day, month); |
|
return; |
|
} else if(k >= minYear) { |
|
const selectedYear = k; |
|
createForMonthYear(dates, month, selectedYear); |
|
return; |
|
} |
|
} |
|
} |
|
|
|
if((matches = yearOrDayAndMonthPattern.exec(q)) !== null) { |
|
const g1 = matches[1]; |
|
const g2 = matches[2]; |
|
const month = getMonth(g2); |
|
if(month >= 0) { |
|
const k = +g1; |
|
if(k > 0 && k <= 31) { |
|
const day = k - 1; |
|
createForDayMonth(dates, day, month); |
|
return; |
|
} else if (k >= minYear) { |
|
const selectedYear = k; |
|
createForMonthYear(dates, month, selectedYear); |
|
} |
|
} |
|
} |
|
} |
|
|
|
function createForMonthYear(dates: DateData[], month: number, selectedYear: number) { |
|
const currentYear = new Date().getFullYear(); |
|
const today = Date.now(); |
|
if(selectedYear >= minYear && selectedYear <= currentYear) { |
|
const date = new Date(); |
|
date.setFullYear(selectedYear, month, 1); |
|
date.setHours(0, 0, 0); |
|
const minDate = date.getTime(); |
|
if(minDate > today) { |
|
return; |
|
} |
|
date.setMonth(date.getMonth() + 1); |
|
const maxDate = date.getTime() - 1; |
|
|
|
dates.push({ |
|
title: formatterMonthYear(minDate), |
|
minDate, |
|
maxDate |
|
}); |
|
} |
|
} |
|
|
|
function createForDayMonth(dates: DateData[], day: number, month: number) { |
|
if(validDateForMonth(day, month)) { |
|
const currentYear = new Date().getFullYear(); |
|
const today = Date.now(); |
|
|
|
for(let i = currentYear; i >= minYear; i--) { |
|
if(month === 1 && day === 28 && !isLeapYear(i)) { |
|
continue; |
|
} |
|
|
|
const date = new Date(); |
|
date.setFullYear(i, month, day + 1); |
|
date.setHours(0, 0, 0); |
|
|
|
const minDate = date.getTime(); |
|
if(minDate > today) { |
|
continue; |
|
} |
|
|
|
date.setFullYear(i, month, day + 2); |
|
date.setHours(0, 0, 0); |
|
const maxDate = date.getTime() - 1; |
|
if(i === currentYear) { |
|
dates.push({ |
|
title: formatterDayMonth(minDate), |
|
minDate, |
|
maxDate |
|
}); |
|
} else { |
|
dates.push({ |
|
title: formatterYearMax(minDate), |
|
minDate, |
|
maxDate |
|
}); |
|
} |
|
} |
|
} |
|
} |
|
|
|
function formatterMonthYear(timestamp: number) { |
|
const date = new Date(timestamp); |
|
return months[date.getMonth()].slice(0, 3) + ' ' + date.getFullYear(); |
|
} |
|
|
|
function formatterDayMonth(timestamp: number) { |
|
const date = new Date(timestamp); |
|
return months[date.getMonth()].slice(0, 3) + ' ' + date.getDate(); |
|
} |
|
|
|
function formatterYearMax(timestamp: number) { |
|
const date = new Date(timestamp); |
|
return ('0' + date.getDate()).slice(-2) + '.' + ('0' + (date.getMonth() + 1)).slice(-2) + '.' + date.getFullYear(); |
|
} |
|
|
|
function formatWeekLong(timestamp: number) { |
|
const date = new Date(timestamp); |
|
return days[date.getDay()]; |
|
} |
|
|
|
function validDateForMonth(day: number, month: number) { |
|
if(month >= 0 && month < 12) { |
|
if(day >= 0 && day < numberOfDaysEachMonth[month]) { |
|
return true; |
|
} |
|
} |
|
return false; |
|
} |
|
|
|
function isLeapYear(year: number) { |
|
return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0); |
|
} |
|
|
|
function getMonth(q: string) { |
|
/* String[] months = new String[]{ |
|
LocaleController.getString("January", R.string.January).toLowerCase(), |
|
LocaleController.getString("February", R.string.February).toLowerCase(), |
|
LocaleController.getString("March", R.string.March).toLowerCase(), |
|
LocaleController.getString("April", R.string.April).toLowerCase(), |
|
LocaleController.getString("May", R.string.May).toLowerCase(), |
|
LocaleController.getString("June", R.string.June).toLowerCase(), |
|
LocaleController.getString("July", R.string.July).toLowerCase(), |
|
LocaleController.getString("August", R.string.August).toLowerCase(), |
|
LocaleController.getString("September", R.string.September).toLowerCase(), |
|
LocaleController.getString("October", R.string.October).toLowerCase(), |
|
LocaleController.getString("November", R.string.November).toLowerCase(), |
|
LocaleController.getString("December", R.string.December).toLowerCase() |
|
}; */ |
|
|
|
/* String[] monthsEng = new String[12]; |
|
Calendar c = Calendar.getInstance(); |
|
for (int i = 1; i <= 12; i++) { |
|
c.set(0, 0, 0, 0, 0, 0); |
|
c.set(Calendar.MONTH, i); |
|
monthsEng[i - 1] = c.getDisplayName(Calendar.MONTH, Calendar.LONG, Locale.ENGLISH).toLowerCase(); |
|
} */ |
|
|
|
q = q.toLowerCase(); |
|
for(let i = 0; i < 12; i++) { |
|
const month = months[i].toLowerCase(); |
|
if(month.indexOf(q) === 0) { |
|
return i; |
|
} |
|
} |
|
return -1; |
|
} |
|
|
|
function getDayOfWeek(q: string) { |
|
const c = new Date(); |
|
if(q.length <= 3) { |
|
return -1; |
|
} |
|
|
|
for(let i = 0; i < 7; i++) { |
|
c.setDate(c.getDate() + 1); |
|
|
|
if(formatWeekLong(c.getTime()).toLowerCase().indexOf(q) === 0) { |
|
return c.getDay(); |
|
} |
|
} |
|
return -1; |
|
} |
|
|
|
MOUNT_CLASS_TO.fillTipDates = fillTipDates;
|
|
|