Auto-detect time format by nearest country

This commit is contained in:
Alexander Zinchuk 2021-11-05 21:57:44 +03:00
parent 3b603ff4bf
commit 67dca172db
14 changed files with 101 additions and 65 deletions

View File

@ -132,13 +132,16 @@ function buildApiCountry(country: GramJs.help.Country, code?: GramJs.help.Countr
}
export function buildApiCountryList(countries: GramJs.help.Country[]) {
const listByCode = flatten(countries
.filter((country) => !country.hidden)
.map((country) => (
country.countryCodes.map((code) => buildApiCountry(country, code))
))).sort((a: ApiCountry, b: ApiCountry) => (
a.name ? a.name.localeCompare(b.name!) : a.defaultName.localeCompare(b.defaultName)
));
const listByCode = flatten(
countries
.filter((country) => !country.hidden)
.map((country) => (
country.countryCodes.map((code) => buildApiCountry(country, code))
)),
)
.sort((a: ApiCountry, b: ApiCountry) => (
a.name ? a.name.localeCompare(b.name!) : a.defaultName.localeCompare(b.defaultName)
));
const generalList = countries
.filter((country) => !country.hidden)

View File

@ -26,8 +26,7 @@ export {
} from './messages';
export {
fetchFullUser, fetchNearestCountry, fetchCountryList,
fetchTopUsers, fetchContactList, fetchUsers,
fetchFullUser, fetchNearestCountry, fetchTopUsers, fetchContactList, fetchUsers,
addContact, updateContact, deleteUser, fetchProfilePhotos,
} from './users';
@ -47,7 +46,7 @@ export {
fetchAuthorizations, terminateAuthorization, terminateAllAuthorizations,
fetchNotificationExceptions, fetchNotificationSettings, updateContactSignUpNotification, updateNotificationSettings,
fetchLanguages, fetchLangPack, fetchPrivacySettings, setPrivacySettings, registerDevice, unregisterDevice,
updateIsOnline, fetchContentSettings, updateContentSettings, fetchLangStrings,
updateIsOnline, fetchContentSettings, updateContentSettings, fetchLangStrings, fetchCountryList,
} from './settings';
export {

View File

@ -4,11 +4,11 @@ import { Api as GramJs } from '../../../lib/gramjs';
import {
ApiChat, ApiLangString, ApiLanguage, ApiNotifyException, ApiUser, ApiWallpaper,
} from '../../types';
import { ApiPrivacyKey, InputPrivacyRules } from '../../../types';
import { ApiPrivacyKey, InputPrivacyRules, LangCode } from '../../../types';
import { BLOCKED_LIST_LIMIT, DEFAULT_LANG_PACK, LANG_PACKS } from '../../../config';
import {
buildApiWallpaper, buildApiSession, buildPrivacyRules, buildApiNotifyException,
buildApiWallpaper, buildApiSession, buildPrivacyRules, buildApiNotifyException, buildApiCountryList,
} from '../apiBuilders/misc';
import { buildApiUser } from '../apiBuilders/users';
@ -17,9 +17,9 @@ import { buildInputPrivacyKey, buildInputPeer, buildInputEntity } from '../gramj
import { invokeRequest, uploadFile, getClient } from './client';
import { omitVirtualClassFields } from '../apiBuilders/helpers';
import { buildCollectionByKey } from '../../../util/iteratees';
import localDb from '../localDb';
import { getServerTime } from '../../../util/serverTime';
import { buildApiPeerId, getApiChatIdFromMtpPeer } from '../apiBuilders/peers';
import localDb from '../localDb';
const MAX_INT_32 = 2 ** 31 - 1;
const BETA_LANG_CODES = ['ar', 'fa', 'id', 'ko', 'uz'];
@ -447,3 +447,14 @@ function updateLocalDb(
}
});
}
export async function fetchCountryList({ langCode = 'en' }: { langCode?: LangCode }) {
const countryList = await invokeRequest(new GramJs.help.GetCountriesList({
langCode,
}));
if (!(countryList instanceof GramJs.help.CountriesList)) {
return undefined;
}
return buildApiCountryList(countryList.countries);
}

View File

@ -3,7 +3,6 @@ import { Api as GramJs } from '../../../lib/gramjs';
import {
OnApiUpdate, ApiUser, ApiChat, ApiPhoto,
} from '../../types';
import { LangCode } from '../../../types';
import { PROFILE_PHOTOS_LIMIT } from '../../../config';
import { invokeRequest } from './client';
@ -18,7 +17,6 @@ import { buildApiChatFromPreview } from '../apiBuilders/chats';
import { buildApiPhoto } from '../apiBuilders/common';
import localDb from '../localDb';
import { addPhotoToLocalDb } from '../helpers';
import { buildApiCountryList } from '../apiBuilders/misc';
import { buildApiPeerId } from '../apiBuilders/peers';
let onUpdate: OnApiUpdate;
@ -62,17 +60,6 @@ export async function fetchNearestCountry() {
return dcInfo?.country;
}
export async function fetchCountryList({ langCode = 'en' }: { langCode?: LangCode }) {
const countryList = await invokeRequest(new GramJs.help.GetCountriesList({
langCode,
}));
if (!(countryList instanceof GramJs.help.CountriesList)) {
return undefined;
}
return buildApiCountryList(countryList.countries);
}
export async function fetchTopUsers() {
const topPeers = await invokeRequest(new GramJs.contacts.GetTopPeers({
correspondents: true,

View File

@ -132,10 +132,11 @@ const SettingsGeneral: FC<OwnProps & StateProps & DispatchProps> = ({
setSettingOption({ messageTextSize: newSize });
}, [setSettingOption]);
const handleTimeFormatChange = useCallback((value: string) => {
setTimeFormat(value as TimeFormat, () => {
setSettingOption({ timeFormat: value });
});
const handleTimeFormatChange = useCallback((newTimeFormat: string) => {
setSettingOption({ timeFormat: newTimeFormat });
setSettingOption({ wasTimeFormatSetManually: true });
setTimeFormat(newTimeFormat as TimeFormat);
}, [setSettingOption]);
const handleStickerSetClick = useCallback((value: ApiSticker) => {

View File

@ -48,7 +48,6 @@ import StickerSetModal from '../common/StickerSetModal.async';
import './Main.scss';
type StateProps = {
animationLevel: number;
lastSyncTime?: number;
isLeftColumnShown: boolean;
isRightColumnShown: boolean;
@ -61,14 +60,17 @@ type StateProps = {
safeLinkModalUrl?: string;
isHistoryCalendarOpen: boolean;
shouldSkipHistoryAnimations?: boolean;
language?: LangCode;
openedStickerSetShortName?: string;
isServiceChatReady?: boolean;
animationLevel: number;
language?: LangCode;
wasTimeFormatSetManually?: boolean;
};
type DispatchProps = Pick<GlobalActions, (
'loadAnimatedEmojis' | 'loadNotificationSettings' | 'loadNotificationExceptions' | 'updateIsOnline' |
'loadTopInlineBots' | 'loadEmojiKeywords' | 'openStickerSetShortName' | 'loadCountryList' | 'checkVersionNotification'
'loadTopInlineBots' | 'loadEmojiKeywords' | 'openStickerSetShortName' |
'loadCountryList' | 'ensureTimeFormat' | 'checkVersionNotification'
)>;
const NOTIFICATION_INTERVAL = 1000;
@ -84,7 +86,6 @@ const Main: FC<StateProps & DispatchProps> = ({
isRightColumnShown,
isMediaViewerOpen,
isForwardModalOpen,
animationLevel,
hasNotifications,
hasDialogs,
audioMessage,
@ -92,9 +93,11 @@ const Main: FC<StateProps & DispatchProps> = ({
safeLinkModalUrl,
isHistoryCalendarOpen,
shouldSkipHistoryAnimations,
language,
openedStickerSetShortName,
isServiceChatReady,
animationLevel,
language,
wasTimeFormatSetManually,
loadAnimatedEmojis,
loadNotificationSettings,
loadNotificationExceptions,
@ -102,6 +105,7 @@ const Main: FC<StateProps & DispatchProps> = ({
loadTopInlineBots,
loadEmojiKeywords,
loadCountryList,
ensureTimeFormat,
openStickerSetShortName,
checkVersionNotification,
}) => {
@ -138,6 +142,12 @@ const Main: FC<StateProps & DispatchProps> = ({
}
}, [lastSyncTime, isServiceChatReady, checkVersionNotification]);
useEffect(() => {
if (lastSyncTime && !wasTimeFormatSetManually) {
ensureTimeFormat();
}
}, [lastSyncTime, wasTimeFormatSetManually, ensureTimeFormat]);
useEffect(() => {
if (lastSyncTime && LOCATION_HASH.startsWith('#?tgaddr=')) {
processDeepLink(decodeURIComponent(LOCATION_HASH.substr('#?tgaddr='.length)));
@ -291,13 +301,13 @@ function updatePageTitle(nextTitle: string) {
export default memo(withGlobal(
(global): StateProps => {
const { settings: { byKey: { animationLevel, language, wasTimeFormatSetManually } } } = global;
const { chatId: audioChatId, messageId: audioMessageId, origin } = global.audioPlayer;
const audioMessage = audioChatId && audioMessageId
? selectChatMessage(global, audioChatId, audioMessageId)
: undefined;
return {
animationLevel: global.settings.byKey.animationLevel,
lastSyncTime: global.lastSyncTime,
isLeftColumnShown: global.isLeftColumnShown,
isRightColumnShown: selectIsRightColumnShown(global),
@ -310,13 +320,16 @@ export default memo(withGlobal(
safeLinkModalUrl: global.safeLinkModalUrl,
isHistoryCalendarOpen: Boolean(global.historyCalendarSelectedAt),
shouldSkipHistoryAnimations: global.shouldSkipHistoryAnimations,
language: global.settings.byKey.language,
openedStickerSetShortName: global.openedStickerSetShortName,
isServiceChatReady: selectIsServiceChatReady(global),
animationLevel,
language,
wasTimeFormatSetManually,
};
},
(setGlobal, actions): DispatchProps => pick(actions, [
'loadAnimatedEmojis', 'loadNotificationSettings', 'loadNotificationExceptions', 'updateIsOnline',
'loadTopInlineBots', 'loadEmojiKeywords', 'openStickerSetShortName', 'loadCountryList', 'checkVersionNotification',
'loadTopInlineBots', 'loadEmojiKeywords', 'openStickerSetShortName', 'loadCountryList', 'ensureTimeFormat',
'checkVersionNotification',
]),
)(Main));

View File

@ -145,6 +145,9 @@ export const RE_MENTION_TEMPLATE = '(@[\\w\\d_-]+)';
export const RE_TG_LINK = /^tg:(\/\/)?([?=&\d\w_-]+)?/gm;
export const RE_TME_LINK = /^(?:https?:\/\/)?(?:t\.me\/)/gm;
// eslint-disable-next-line max-len
export const COUNTRIES_WITH_12H_TIME_FORMAT = new Set(['AU', 'BD', 'CA', 'CO', 'EG', 'HN', 'IE', 'IN', 'JO', 'MX', 'MY', 'NI', 'NZ', 'PH', 'PK', 'SA', 'SV', 'US']);
// MTProto constants
export const SERVICE_NOTIFICATIONS_USER_ID = '777000';
export const REPLIES_USER_ID = '1271266957'; // TODO For Test connection ID must be equal to 708513

View File

@ -149,6 +149,7 @@ export const INITIAL_STATE: GlobalState = {
shouldLoopStickers: true,
language: 'en',
timeFormat: '24h',
wasTimeFormatSetManually: false,
},
themes: {
light: {

View File

@ -500,7 +500,7 @@ export type ActionTypes = (
'togglePreHistoryHidden' | 'updateChatDefaultBannedRights' | 'updateChatMemberBannedRights' | 'updateChatAdmin' |
'acceptInviteConfirmation' |
// users
'loadFullUser' | 'openUserInfo' | 'loadNearestCountry' | 'loadCountryList' | 'loadTopUsers' | 'loadContactList' |
'loadFullUser' | 'openUserInfo' | 'loadNearestCountry' | 'loadTopUsers' | 'loadContactList' |
'loadCurrentUser' | 'updateProfile' | 'checkUsername' | 'addContact' | 'updateContact' |
'deleteUser' | 'loadUser' | 'setUserSearchQuery' |
// Channel / groups creation
@ -523,11 +523,13 @@ export type ActionTypes = (
// bots
'clickInlineButton' | 'sendBotCommand' | 'loadTopInlineBots' | 'queryInlineBot' | 'sendInlineBotResult' |
'resetInlineBot' | 'restartBot' | 'startBot' |
// misc
// media viewer & audio player
'openMediaViewer' | 'closeMediaViewer' | 'openAudioPlayer' | 'setAudioPlayerVolume' | 'closeAudioPlayer' |
// misc
'openPollModal' | 'closePollModal' | 'loadWebPagePreview' | 'clearWebPagePreview' |
'loadWallpapers' | 'uploadWallpaper' | 'setDeviceToken' | 'deleteDeviceToken' |
'checkVersionNotification' | 'createServiceNotification' |
'loadCountryList' | 'ensureTimeFormat' |
// payment
'openPaymentModal' | 'closePaymentModal' | 'addPaymentError' |
'validateRequestedInfo' | 'setPaymentStep' | 'sendPaymentForm' | 'getPaymentForm' | 'getReceipt' |

View File

@ -182,21 +182,6 @@ addReducer('loadNearestCountry', (global) => {
})();
});
addReducer('loadCountryList', (global, actions, payload = {}) => {
let { langCode } = payload;
if (!langCode) langCode = global.settings.byKey.language;
(async () => {
const countryList = await callApi('fetchCountryList', { langCode });
if (!countryList) return;
setGlobal({
...getGlobal(),
countryList,
});
})();
});
addReducer('setDeviceToken', (global, actions, deviceToken) => {
setGlobal({
...global,

View File

@ -6,9 +6,11 @@ import {
UPLOADING_WALLPAPER_SLUG,
} from '../../../types';
import { COUNTRIES_WITH_12H_TIME_FORMAT } from '../../../config';
import { callApi } from '../../../api/gramjs';
import { buildCollectionByKey } from '../../../util/iteratees';
import { subscribe, unsubscribe } from '../../../util/notifications';
import { setTimeFormat } from '../../../util/langProvider';
import { selectUser } from '../../selectors';
import {
addUsers, addBlockedContact, updateChats, updateUser, removeBlockedContact, replaceSettings, updateNotifySettings,
@ -564,3 +566,39 @@ addReducer('updateContentSettings', (global, actions, payload) => {
}
})();
});
addReducer('loadCountryList', (global, actions, payload = {}) => {
let { langCode } = payload;
if (!langCode) langCode = global.settings.byKey.language;
(async () => {
const countryList = await callApi('fetchCountryList', { langCode });
if (!countryList) return;
setGlobal({
...getGlobal(),
countryList,
});
})();
});
addReducer('ensureTimeFormat', (global, actions) => {
if (global.authNearestCountry) {
const timeFormat = COUNTRIES_WITH_12H_TIME_FORMAT.has(global.authNearestCountry.toUpperCase()) ? '12h' : '24h';
actions.setSettingOption({ timeFormat });
setTimeFormat(timeFormat);
}
(async () => {
if (getGlobal().settings.byKey.wasTimeFormatSetManually) {
return;
}
const nearestCountryCode = await callApi('fetchNearestCountry');
if (nearestCountryCode) {
const timeFormat = COUNTRIES_WITH_12H_TIME_FORMAT.has(nearestCountryCode.toUpperCase()) ? '12h' : '24h';
actions.setSettingOption({ timeFormat });
setTimeFormat(timeFormat);
}
})();
});

View File

@ -70,6 +70,7 @@ export interface ISettings extends NotifySettings, Record<string, any> {
isSensitiveEnabled?: boolean;
canChangeSensitive?: boolean;
timeFormat: TimeFormat;
wasTimeFormatSetManually: boolean;
}
export interface ApiPrivacySettings {

View File

@ -139,22 +139,14 @@ export async function setLanguage(langCode: LangCode, callback?: NoneToVoidFunct
runCallbacks();
}
export function setTimeFormat(timeFormat: TimeFormat, callback?: NoneToVoidFunction) {
export function setTimeFormat(timeFormat: TimeFormat) {
if (timeFormat && timeFormat === currentTimeFormat) {
if (callback) {
callback();
}
return;
}
currentTimeFormat = timeFormat;
getTranslation.timeFormat = timeFormat;
if (callback) {
callback();
}
runCallbacks();
}

View File

@ -8,7 +8,7 @@ export function getCountryCodesByIso(phoneCodeList: ApiCountryCode[], iso: strin
return phoneCodeList.filter((country) => country.iso2 === iso);
}
export function getCountryFromPhoneNumber(phoneCodeList: ApiCountryCode[], input: string = '') {
export function getCountryFromPhoneNumber(phoneCodeList: ApiCountryCode[], input = '') {
let phoneNumber = input.replace(/[^\d+]+/g, '');
if (phoneNumber.startsWith('+')) {
phoneNumber = phoneNumber.substr(1);