diff --git a/src/assets/icons/Icon32PauseCircle.svg b/src/assets/icons/Icon32PauseCircle.svg deleted file mode 100644 index d19c9adb..00000000 --- a/src/assets/icons/Icon32PauseCircle.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/assets/icons/Icon32PauseCircle.tsx b/src/assets/icons/Icon32PauseCircle.tsx new file mode 100644 index 00000000..4dab7051 --- /dev/null +++ b/src/assets/icons/Icon32PauseCircle.tsx @@ -0,0 +1,24 @@ +import { defineComponent, useId } from 'vue' + +type Props = { + withUnlistenedDot?: boolean +} + +export const Icon32PauseCircle = defineComponent((props) => { + const id = useId() + + return () => ( + + {props.withUnlistenedDot && ( + + + + + )} + + {props.withUnlistenedDot && } + + ) +}, { + props: ['withUnlistenedDot'] +}) diff --git a/src/assets/icons/Icon32PlayCircle.svg b/src/assets/icons/Icon32PlayCircle.svg deleted file mode 100644 index 0fcdf3d4..00000000 --- a/src/assets/icons/Icon32PlayCircle.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/assets/icons/Icon32PlayCircle.tsx b/src/assets/icons/Icon32PlayCircle.tsx new file mode 100644 index 00000000..d184c0f1 --- /dev/null +++ b/src/assets/icons/Icon32PlayCircle.tsx @@ -0,0 +1,24 @@ +import { defineComponent, useId } from 'vue' + +type Props = { + withUnlistenedDot?: boolean +} + +export const Icon32PlayCircle = defineComponent((props) => { + const id = useId() + + return () => ( + + {props.withUnlistenedDot && ( + + + + + )} + + {props.withUnlistenedDot && } + + ) +}, { + props: ['withUnlistenedDot'] +}) diff --git a/src/assets/icons/index.ts b/src/assets/icons/index.ts index 0e16aa1b..603a830b 100644 --- a/src/assets/icons/index.ts +++ b/src/assets/icons/index.ts @@ -28,7 +28,7 @@ export { default as Icon24ViewOutline } from './Icon24ViewOutline.svg' export { default as Icon24VolumeOutline } from './Icon24VolumeOutline.svg' export { default as Icon28DeleteOutline } from './Icon28DeleteOutline.svg' export { default as Icon32DonutCircleFillYellow } from './Icon32DonutCircleFillYellow.svg' -export { default as Icon32PauseCircle } from './Icon32PauseCircle.svg' -export { default as Icon32PlayCircle } from './Icon32PlayCircle.svg' +export { Icon32PauseCircle } from './Icon32PauseCircle' +export { Icon32PlayCircle } from './Icon32PlayCircle' export { default as Icon32Spinner } from './Icon32Spinner.svg' export { default as Icon44Spinner } from './Icon44Spinner.svg' diff --git a/src/converters/AttachConverter.ts b/src/converters/AttachConverter.ts index 907ccbbe..bff733db 100644 --- a/src/converters/AttachConverter.ts +++ b/src/converters/AttachConverter.ts @@ -9,7 +9,10 @@ import * as Peer from 'model/Peer' import { insertPeers } from 'actions' import { isNonEmptyArray } from 'misc/utils' -export function fromApiAttaches(apiAttaches: MessagesMessageAttachment[]): Attach.Attaches { +export function fromApiAttaches( + apiAttaches: MessagesMessageAttachment[], + wasVoiceMessageListened: boolean +): Attach.Attaches { const attaches: Attach.Attaches = {} const addUnknown = (attach: MessagesMessageAttachment) => { @@ -54,7 +57,8 @@ export function fromApiAttaches(apiAttaches: MessagesMessageAttachment[]): Attac linkOgg: apiAttach.audio_message.link_ogg, duration: apiAttach.audio_message.duration, waveform: apiAttach.audio_message.waveform, - transcript: apiAttach.audio_message.transcript, + wasListened: wasVoiceMessageListened, + transcript: apiAttach.audio_message.transcript?.trim() ?? '', transcriptState: apiAttach.audio_message.transcript_state } break @@ -143,7 +147,7 @@ function fromApiAttachWall(apiWall: MessagesMessageAttachmentWall): Attach.Wall accessKey: apiWall.access_key, createdAt: (apiWall.date ?? 0) * 1000, text: apiWall.text ?? '', - attaches: fromApiAttaches(apiWall.attachments ?? []), + attaches: fromApiAttaches(apiWall.attachments ?? [], true), isDeleted: !!apiWall.is_deleted, donutPlaceholder: apiWall.donut?.placeholder?.text, repost: apiWall.copy_history?.[0] diff --git a/src/converters/MessageConverter.ts b/src/converters/MessageConverter.ts index 7663e8a8..d941b5b6 100644 --- a/src/converters/MessageConverter.ts +++ b/src/converters/MessageConverter.ts @@ -37,7 +37,7 @@ export function fromApiMessage(message: MessagesMessage): Message.Message { return { kind: 'Normal', text: message.text, - attaches: fromApiAttaches(message.attachments ?? []), + attaches: fromApiAttaches(message.attachments ?? [], !!message.was_listened), replyMessage: message.reply_message && fromApiForeignMessage( message.reply_message, baseMessage.peerId, @@ -164,7 +164,7 @@ function fromApiForeignMessage( authorId: Peer.resolveOwnerId(foreignMessage.from_id), sentAt: foreignMessage.date * 1000, text: foreignMessage.text, - attaches: fromApiAttaches(foreignMessage.attachments ?? []), + attaches: fromApiAttaches(foreignMessage.attachments ?? [], !!foreignMessage.was_listened), replyMessage: foreignMessage.reply_message && fromApiForeignMessage( foreignMessage.reply_message, rootPeerId, @@ -211,7 +211,7 @@ export function fromApiPinnedMessage(pinnedMessage: MessagesPinnedMessage): Mess authorId: Peer.resolveOwnerId(pinnedMessage.from_id), sentAt: pinnedMessage.date * 1000, text: pinnedMessage.text, - attaches: fromApiAttaches(pinnedMessage.attachments ?? []), + attaches: fromApiAttaches(pinnedMessage.attachments ?? [], true), replyMessage: pinnedMessage.reply_message && fromApiForeignMessage( pinnedMessage.reply_message, peerId, diff --git a/src/lang/ru.ts b/src/lang/ru.ts index e21357d3..e0c3aa7e 100644 --- a/src/lang/ru.ts +++ b/src/lang/ru.ts @@ -111,8 +111,9 @@ export const ru = { me_chat_leaved_status: 'Вы вышли из чата', me_chat_kicked_status: 'Вы были исключены из чата', - me_voice_transcription_empty: 'Слова не распознаны', - me_voice_transcription_in_progress: 'Расшифровка...', + me_voice_transcript_error: 'Ошибка составления транскрипци', + me_voice_transcript_in_progress: 'Расшифровка...', + me_voice_transcript_empty: 'Слова не распознаны', me_chat_members_count: { one: '{count} участник', diff --git a/src/model/Attach.ts b/src/model/Attach.ts index 63d5fac5..c5d62972 100644 --- a/src/model/Attach.ts +++ b/src/model/Attach.ts @@ -47,7 +47,8 @@ export type Voice = { linkOgg: string duration: number waveform: number[] - transcript?: string + wasListened: boolean + transcript: string transcriptState: 'in_progress' | 'done' | 'error' } diff --git a/src/model/api-types/objects/MessagesForeignMessage.ts b/src/model/api-types/objects/MessagesForeignMessage.ts index 78baad49..122bdacc 100644 --- a/src/model/api-types/objects/MessagesForeignMessage.ts +++ b/src/model/api-types/objects/MessagesForeignMessage.ts @@ -11,11 +11,11 @@ export type MessagesForeignMessage = { fwd_messages?: MessagesForeignMessage[] geo?: MessagesMessageAttachmentGeo id?: number + was_listened?: boolean peer_id?: number reply_message?: MessagesForeignMessage text: string update_time?: number - was_listened?: boolean was_played?: boolean payload?: string is_expired?: boolean diff --git a/src/ui/messenger/ConvoMessage/ConvoMessage.tsx b/src/ui/messenger/ConvoMessage/ConvoMessage.tsx index aa9ab96c..b6034df5 100644 --- a/src/ui/messenger/ConvoMessage/ConvoMessage.tsx +++ b/src/ui/messenger/ConvoMessage/ConvoMessage.tsx @@ -43,7 +43,9 @@ export const ConvoMessage = defineComponent((props) => { )} {message.text && {message.text}} - {hasAttaches && } + {hasAttaches && ( + + )} {isEmpty && ( diff --git a/src/ui/messenger/attaches/AttachVoice/AttachVoice.css b/src/ui/messenger/attaches/AttachVoice/AttachVoice.css index 65add351..4c163d9f 100644 --- a/src/ui/messenger/attaches/AttachVoice/AttachVoice.css +++ b/src/ui/messenger/attaches/AttachVoice/AttachVoice.css @@ -5,17 +5,14 @@ .AttachVoice__player { display: flex; gap: 8px; - color: var(--vkui--color_background_accent_themed); } -.AttachVoice__track { - display: flex; - align-items: center; - flex-grow: 1; +.AttachVoice__playButton { + color: var(--vkui--color_text_accent_themed); } -.AttachVoice__trackContent { - flex: 1 1 auto; +.AttachVoice__track { + flex-grow: 1; } .AttachVoice__range { @@ -47,19 +44,17 @@ box-shadow: -300px 0 0 300px var(--vkui--color_background_accent_themed); } -.AttachVoice__button { - position: relative; +.AttachVoice__toggleTranscription { align-self: flex-start; - border: none; + height: 20px; + width: 30px; + color: var(--vkui--color_text_accent_themed); border-radius: 8px; - background: none; margin-top: 2px; - margin-left: 12px; padding: 2px 6px; - color: var(--vkui--color_icon_accent); } -.AttachVoice__button::before { +.AttachVoice__toggleTranscription::before { content: ''; border-radius: inherit; position: absolute; @@ -68,31 +63,34 @@ left: 0; right: 0; background: var(--vkui--color_background_accent); - opacity: 0.12; - transition: opacity 0.14s; + opacity: 0.1; + transition: opacity var(--fastTransition); +} + +.AttachVoice__toggleTranscription:hover::before { + opacity: 0.2; } .AttachVoice__time { - display: inline-block; font: var(--messageDateFontSize) / var(--messageDateLineHeight) var(--fontFamily); + color: var(--vkui--color_text_accent_themed); } .AttachVoice__transcript { + position: relative; display: flex; margin-top: 8px; + padding-left: 12px; } -.AttachVoice__collapse { - position: relative; - overflow: hidden; - padding-left: 12px; +.AttachVoice__transcript--notReady { + opacity: 0.4; } -.AttachVoice__collapse::before { +.AttachVoice__transcript::before { content: ''; position: absolute; - top: 1px; - bottom: 0; + top: 0; left: 0; width: 2px; height: 100%; @@ -100,16 +98,6 @@ background: var(--vkui--color_stroke_accent); } -.AttachVoice__collapse--open { - height: auto; -} - -.AttachVoice__collapse--close { - height: 0; - white-space: pre; -} - -.AttachVoice__collapse--faded { +.AttachVoice__transcript:not(.AttachVoice__transcript--notReady)::before { opacity: 0.4; - font-size: 15px; } diff --git a/src/ui/messenger/attaches/AttachVoice/AttachVoice.tsx b/src/ui/messenger/attaches/AttachVoice/AttachVoice.tsx index cf77a26d..8de5a482 100644 --- a/src/ui/messenger/attaches/AttachVoice/AttachVoice.tsx +++ b/src/ui/messenger/attaches/AttachVoice/AttachVoice.tsx @@ -17,29 +17,20 @@ export const AttachVoice = defineComponent((props) => { const range = shallowRef(0) const isRange = shallowRef(false) const requestId = shallowRef(-1) - const isHiddenCollapse = shallowRef(true) - - const transcriptNotReady = computed(() => { - return !props.voice.transcript || - props.voice.transcript.trim() === '' || - props.voice.transcriptState === 'error' || - props.voice.transcriptState === 'in_progress' - }) - - const text = computed(() => { - if (props.voice.transcript && props.voice.transcript.trim() === '') { - return lang.use('me_voice_transcription_empty') - } + const showTranscript = shallowRef(false) + const transcriptNotReadyStatus = computed(() => { if (props.voice.transcriptState === 'error') { - return lang.use('me_voice_transcription_empty') + return lang.use('me_voice_transcript_error') } if (props.voice.transcriptState === 'in_progress') { - return lang.use('me_voice_transcription_in_progress') + return lang.use('me_voice_transcript_in_progress') } - return props.voice.transcript + if (!props.voice.transcript) { + return lang.use('me_voice_transcript_empty') + } }) const getCurrentTime = () => { @@ -90,44 +81,46 @@ export const AttachVoice = defineComponent((props) => {
: } + icon={ + isPause.value + ? + : + } /> +
-
- moveRange(event)} - onTouchstart={() => (isRange.value = true)} - onTouchend={() => (isRange.value = false)} - onMousedown={() => (isRange.value = true)} - onMouseup={() => (isRange.value = false)} - /> - {getCurrentTime()} -
- : } - onClick={() => (isHiddenCollapse.value = !isHiddenCollapse.value)} + moveRange(event)} + onTouchstart={() => (isRange.value = true)} + onTouchend={() => (isRange.value = false)} + onMousedown={() => (isRange.value = true)} + onMouseup={() => (isRange.value = false)} /> + {getCurrentTime()}
+ : } + onClick={() => (showTranscript.value = !showTranscript.value)} + />
- {!isHiddenCollapse.value && ( -
-
- {text.value} -
+ > + {transcriptNotReadyStatus.value ?? props.voice.transcript}
)}
diff --git a/src/ui/ui/ButtonIcon/ButtonIcon.css b/src/ui/ui/ButtonIcon/ButtonIcon.css index 1287c94a..d954cb7f 100644 --- a/src/ui/ui/ButtonIcon/ButtonIcon.css +++ b/src/ui/ui/ButtonIcon/ButtonIcon.css @@ -5,6 +5,7 @@ flex: none; position: relative; border-radius: 6px; + line-height: 0; transition: background-color var(--fastTransition), opacity var(--fastTransition); }