diff --git a/src/api/gramjs/methods/messages.ts b/src/api/gramjs/methods/messages.ts index 4a652a585..075350926 100644 --- a/src/api/gramjs/methods/messages.ts +++ b/src/api/gramjs/methods/messages.ts @@ -813,7 +813,7 @@ export async function searchMessagesLocal({ filter = new GramJs.InputMessagesFilterMusic(); break; case 'voice': - filter = new GramJs.InputMessagesFilterVoice(); + filter = new GramJs.InputMessagesFilterRoundVoice(); break; case 'profilePhoto': filter = new GramJs.InputMessagesFilterChatPhotos(); @@ -890,7 +890,7 @@ export async function searchMessagesGlobal({ filter = new GramJs.InputMessagesFilterMusic(); break; case 'voice': - filter = new GramJs.InputMessagesFilterVoice(); + filter = new GramJs.InputMessagesFilterRoundVoice(); break; case 'text': default: { diff --git a/src/components/common/AnimatedSticker.tsx b/src/components/common/AnimatedSticker.tsx index e7cb68181..e3ef70856 100644 --- a/src/components/common/AnimatedSticker.tsx +++ b/src/components/common/AnimatedSticker.tsx @@ -170,7 +170,7 @@ const AnimatedSticker: FC = ({ if (play || playSegment) { if (isFrozen.current) { wasPlaying.current = true; - } else { + } else if (!animation.isPlaying()) { playAnimation(noLoop); } } else { diff --git a/src/components/common/Audio.tsx b/src/components/common/Audio.tsx index 31b7b914c..9a6b53cbc 100644 --- a/src/components/common/Audio.tsx +++ b/src/components/common/Audio.tsx @@ -79,8 +79,8 @@ const Audio: FC = ({ onCancelUpload, onDateClick, }) => { - const { content: { audio, voice }, isMediaUnread } = message; - const isVoice = Boolean(voice); + const { content: { audio, voice, video }, isMediaUnread } = message; + const isVoice = Boolean(voice || video); const isSeeking = useRef(false); const playStateBeforeSeeking = useRef(false); // eslint-disable-next-line no-null/no-null @@ -229,7 +229,7 @@ const Audio: FC = ({ if (isVoice) { return (
- {formatMediaDuration(voice!.duration)} + {formatMediaDuration((voice || video)!.duration)}
); } @@ -359,7 +359,7 @@ const Audio: FC = ({ lang, audio, duration, isPlaying, playProgress, bufferedProgress, seekerRef, (isDownloadStarted || isUploading), date, transferProgress, onDateClick ? handleDateClick : undefined, )} - {origin === AudioOrigin.SharedMedia && voice && renderWithTitle()} + {origin === AudioOrigin.SharedMedia && (voice || video) && renderWithTitle()} {origin === AudioOrigin.Inline && voice && renderVoice(voice, renderedWaveform, playProgress, isMediaUnread)} ); @@ -408,7 +408,7 @@ function renderAudio( {date && ( <> - {formatMediaDateTime(lang, date * 1000)} + {formatMediaDateTime(lang, date * 1000, true)} )} diff --git a/src/components/common/File.tsx b/src/components/common/File.tsx index 829b85ce1..df5808954 100644 --- a/src/components/common/File.tsx +++ b/src/components/common/File.tsx @@ -147,8 +147,8 @@ const File: FC = ({ {sender && {renderText(sender)}} {!sender && timestamp && ( <> - {' '} - {formatMediaDateTime(lang, timestamp * 1000)} + + {formatMediaDateTime(lang, timestamp * 1000, true)} )} diff --git a/src/components/mediaViewer/SenderInfo.tsx b/src/components/mediaViewer/SenderInfo.tsx index 53e9d9975..f9ce24209 100644 --- a/src/components/mediaViewer/SenderInfo.tsx +++ b/src/components/mediaViewer/SenderInfo.tsx @@ -62,7 +62,7 @@ const SenderInfo: FC = ({ {senderTitle && renderText(senderTitle)}
- {isAvatar ? lang('lng_mediaview_profile_photo') : formatMediaDateTime(lang, message!.date * 1000)} + {isAvatar ? lang('lng_mediaview_profile_photo') : formatMediaDateTime(lang, message!.date * 1000, true)}
diff --git a/src/components/middle/HeaderActions.tsx b/src/components/middle/HeaderActions.tsx index 0c3ff4352..285accfb7 100644 --- a/src/components/middle/HeaderActions.tsx +++ b/src/components/middle/HeaderActions.tsx @@ -162,21 +162,19 @@ const HeaderActions: FC = ({ )} - {(IS_SINGLE_COLUMN_LAYOUT || !canSubscribe) && ( - - )} + {menuPosition && ( ( const canMute = isMainThread && !isChatWithSelf && !canSubscribe; const canLeave = isMainThread && !canSubscribe; - const noMenu = !( - (IS_SINGLE_COLUMN_LAYOUT && canSubscribe) - || (IS_SINGLE_COLUMN_LAYOUT && canSearch) - || canMute - || canLeave - ); - return { - noMenu, + noMenu: false, isChannel, isRightColumnShown, canStartBot, diff --git a/src/components/middle/composer/Composer.scss b/src/components/middle/composer/Composer.scss index 7198cc6bd..19bb012ac 100644 --- a/src/components/middle/composer/Composer.scss +++ b/src/components/middle/composer/Composer.scss @@ -267,17 +267,19 @@ line-height: 3.5rem; height: 3.5rem; padding: 0 3.125rem 0 1rem; + font-family: "Roboto", -apple-system, BlinkMacSystemFont, "Apple Color Emoji", "Helvetica Neue", sans-serif; &::after { content: ''; - width: 10px; - height: 10px; + width: .75rem; + height: .75rem; background: var(--color-error); - border-radius: 5px; + border-radius: .375rem; position: absolute; top: 50%; - margin-top: -5px; - right: 1.375rem; + margin-top: -.375rem; + right: 1.3125rem; + animation: recording-blink-like-macos 1.5s infinite; } @media (max-width: 600px) { @@ -478,3 +480,12 @@ margin: 1rem 0; } } + +@keyframes recording-blink-like-macos { + from { + opacity: 1; + } + to { + opacity: .3; + } +} diff --git a/src/components/middle/message/Poll.scss b/src/components/middle/message/Poll.scss index d8ded7d10..43e53e200 100644 --- a/src/components/middle/message/Poll.scss +++ b/src/components/middle/message/Poll.scss @@ -121,10 +121,14 @@ margin-top: -2px; .Avatar { - border: 1px solid var(--color-white); + border: .0625rem solid var(--color-white); margin-right: 0; box-sizing: content-box; + .Message.own & { + border: .0625rem solid var(--secondary-color); + } + &:not(:first-child) { margin-left: -3px; } diff --git a/src/components/middle/message/RoundVideo.tsx b/src/components/middle/message/RoundVideo.tsx index 36784840d..461544a77 100644 --- a/src/components/middle/message/RoundVideo.tsx +++ b/src/components/middle/message/RoundVideo.tsx @@ -18,6 +18,7 @@ import useTransitionForMedia from '../../../hooks/useTransitionForMedia'; import usePrevious from '../../../hooks/usePrevious'; import useBuffering from '../../../hooks/useBuffering'; import buildClassName from '../../../util/buildClassName'; +import { stopCurrentAudio } from '../../../util/audioPlayer'; import useHeavyAnimationCheckForVideo from '../../../hooks/useHeavyAnimationCheckForVideo'; import useVideoCleanup from '../../../hooks/useVideoCleanup'; import usePauseOnInactive from './hooks/usePauseOnInactive'; @@ -156,6 +157,7 @@ const RoundVideo: FC = ({ if (isActivated) { if (playerEl.paused) { safePlay(playerEl); + stopCurrentAudio(); } else { playerEl.pause(); } @@ -165,6 +167,7 @@ const RoundVideo: FC = ({ playerEl.pause(); playerEl.currentTime = 0; safePlay(playerEl); + stopCurrentAudio(); setIsActivated(true); } diff --git a/src/components/right/Profile.tsx b/src/components/right/Profile.tsx index da843c834..9c5ad25b7 100644 --- a/src/components/right/Profile.tsx +++ b/src/components/right/Profile.tsx @@ -271,14 +271,16 @@ const Profile: FC = ({ text = areMembersHidden ? 'You have no access to group members list.' : 'No members found'; break; case 'documents': - text = lang('lng_media_file_empty_search'); + text = lang('lng_media_file_empty'); break; case 'links': - text = lang('lng_media_link_empty_search'); + text = lang('lng_media_link_empty'); + break; + case 'audio': + text = lang('lng_media_song_empty'); break; case 'voice': - case 'audio': - text = lang('lng_media_song_empty_search'); + text = lang('lng_media_audio_empty'); break; default: text = lang('SharedMedia.EmptyTitle'); diff --git a/src/modules/helpers/messageMedia.ts b/src/modules/helpers/messageMedia.ts index 348d57f59..1b6ab75e7 100644 --- a/src/modules/helpers/messageMedia.ts +++ b/src/modules/helpers/messageMedia.ts @@ -366,7 +366,10 @@ export function getMessageContentIds( break; case 'voice': - validator = getMessageVoice; + validator = (message: ApiMessage) => { + const video = getMessageVideo(message); + return getMessageVoice(message) || (video && video.isRound); + }; break; case 'inlineMedia': diff --git a/src/util/dateFormat.ts b/src/util/dateFormat.ts index af9e38fb5..a9e2259be 100644 --- a/src/util/dateFormat.ts +++ b/src/util/dateFormat.ts @@ -75,20 +75,26 @@ export function formatMonthAndYear(lang: LangFn, date: Date, isShort = false) { return formatDate(lang, date, format); } -export function formatHumanDate(lang: LangFn, datetime: number | Date, isShort = false, noWeekdays = false) { +export function formatHumanDate( + lang: LangFn, + datetime: number | Date, + isShort = false, + noWeekdays = false, + isUpperFirst?: boolean, +) { const date = typeof datetime === 'number' ? new Date(datetime) : datetime; const today = getDayStart(new Date()); if (!noWeekdays) { if (toIsoString(date) === toIsoString(today)) { - return (isShort ? lowerFirst : upperFirst)(lang('Weekday.Today')); + return (isUpperFirst || !isShort ? upperFirst : lowerFirst)(lang('Weekday.Today')); } const yesterday = new Date(today); yesterday.setDate(today.getDate() - 1); if (toIsoString(date) === toIsoString(yesterday)) { - return (isShort ? lowerFirst : upperFirst)(lang('Weekday.Yesterday')); + return (isUpperFirst || !isShort ? upperFirst : lowerFirst)(lang('Weekday.Yesterday')); } const weekAgo = new Date(today); @@ -97,9 +103,9 @@ export function formatHumanDate(lang: LangFn, datetime: number | Date, isShort = weekAhead.setDate(today.getDate() + 7); if (date >= weekAgo && date <= weekAhead) { const weekDay = WEEKDAYS_FULL[date.getDay()]; - return isShort - ? lowerFirst(lang(`Weekday.Short${weekDay}`)) - : upperFirst(lang(`Weekday.${weekDay}`)); + const weekDayString = isShort ? lang(`Weekday.Short${weekDay}`) : lang(`Weekday.${weekDay}`); + + return (isUpperFirst || !isShort ? upperFirst : lowerFirst)(weekDayString); } } @@ -109,7 +115,7 @@ export function formatHumanDate(lang: LangFn, datetime: number | Date, isShort = : (withYear ? 'chatFullDate' : 'chatDate'); const format = lang(formatKey) || 'd MMMM yyyy'; - return (isShort ? lowerFirst : upperFirst)(formatDate(lang, date, format)); + return (isUpperFirst || !isShort ? upperFirst : lowerFirst)(formatDate(lang, date, format)); } function formatDate(lang: LangFn, date: Date, format: string) { @@ -126,10 +132,10 @@ function formatDate(lang: LangFn, date: Date, format: string) { .replace('yyyy', String(date.getFullYear())); } -export function formatMediaDateTime(lang: LangFn, datetime: number | Date) { +export function formatMediaDateTime(lang: LangFn, datetime: number | Date, isUpperFirst?: boolean) { const date = typeof datetime === 'number' ? new Date(datetime) : datetime; - return `${formatHumanDate(lang, date, true)}, ${formatTime(date)}`; + return `${formatHumanDate(lang, date, true, undefined, isUpperFirst)}, ${formatTime(date)}`; } export function formatMediaDuration(duration: number, maxValue?: number) { diff --git a/src/util/windowSize.ts b/src/util/windowSize.ts index ff07d97a8..c8cc00f44 100644 --- a/src/util/windowSize.ts +++ b/src/util/windowSize.ts @@ -36,11 +36,21 @@ const handleResize = throttle(() => { } }, 250, true); -window.addEventListener('resize', handleResize); window.addEventListener('orientationchange', handleResize); +if (IS_IOS) { + window.visualViewport.addEventListener('resize', handleResize); +} else { + window.addEventListener('resize', handleResize); +} export function updateSizes(): IDimensions { - const vh = window.innerHeight * 0.01; + let height: number; + if (IS_IOS) { + height = window.visualViewport.height + window.visualViewport.pageTop; + } else { + height = window.innerHeight; + } + const vh = height * 0.01; document.documentElement.style.setProperty('--vh', `${vh}px`);