add more info for claim-preview-tile aria label

This commit is contained in:
btzr-io 2021-07-15 18:12:11 -05:00
parent 7c8c43d3a7
commit 60c5d3bf67
5 changed files with 66 additions and 26 deletions

View file

@ -2054,5 +2054,7 @@
"Item removed from Watch Later": "Item removed from Watch Later", "Item removed from Watch Later": "Item removed from Watch Later",
"Skip Navigation": "Skip Navigation", "Skip Navigation": "Skip Navigation",
"In Favorites": "In Favorites", "In Favorites": "In Favorites",
"%title% by %channelTitle%, %mediaDuration%": "%title% by %channelTitle%, %mediaDuration%",
"%title% by %channelTitle%": "%title% by %channelTitle%",
"--end--": "--end--" "--end--": "--end--"
} }

View file

@ -14,20 +14,28 @@ import { selectMutedChannels } from 'redux/selectors/blocked';
import { selectBlackListedOutpoints, selectFilteredOutpoints } from 'lbryinc'; import { selectBlackListedOutpoints, selectFilteredOutpoints } from 'lbryinc';
import { selectShowMatureContent } from 'redux/selectors/settings'; import { selectShowMatureContent } from 'redux/selectors/settings';
import ClaimPreviewTile from './view'; import ClaimPreviewTile from './view';
import formatMediaDuration from 'util/formatMediaDuration';
const select = (state, props) => ({ const select = (state, props) => {
claim: props.uri && makeSelectClaimForUri(props.uri)(state), const claim = props.uri && makeSelectClaimForUri(props.uri)(state);
channel: props.uri && makeSelectChannelForClaimUri(props.uri)(state), const media = claim && claim.value && (claim.value.video || claim.value.audio);
isResolvingUri: props.uri && makeSelectIsUriResolving(props.uri)(state), const mediaDuration = media && media.duration && formatMediaDuration(media.duration, { screenReader: true });
thumbnail: props.uri && makeSelectThumbnailForUri(props.uri)(state),
title: props.uri && makeSelectTitleForUri(props.uri)(state), return {
blackListedOutpoints: selectBlackListedOutpoints(state), claim,
filteredOutpoints: selectFilteredOutpoints(state), mediaDuration,
blockedChannelUris: selectMutedChannels(state), channel: props.uri && makeSelectChannelForClaimUri(props.uri)(state),
showMature: selectShowMatureContent(state), isResolvingUri: props.uri && makeSelectIsUriResolving(props.uri)(state),
isMature: makeSelectClaimIsNsfw(props.uri)(state), thumbnail: props.uri && makeSelectThumbnailForUri(props.uri)(state),
isLivestream: makeSelectClaimIsStreamPlaceholder(props.uri)(state), title: props.uri && makeSelectTitleForUri(props.uri)(state),
}); blackListedOutpoints: selectBlackListedOutpoints(state),
filteredOutpoints: selectFilteredOutpoints(state),
blockedChannelUris: selectMutedChannels(state),
showMature: selectShowMatureContent(state),
isMature: makeSelectClaimIsNsfw(props.uri)(state),
isLivestream: makeSelectClaimIsStreamPlaceholder(props.uri)(state),
};
};
const perform = (dispatch) => ({ const perform = (dispatch) => ({
resolveUri: (uri) => dispatch(doResolveUri(uri)), resolveUri: (uri) => dispatch(doResolveUri(uri)),

View file

@ -21,6 +21,7 @@ import CollectionPreviewOverlay from 'component/collectionPreviewOverlay';
type Props = { type Props = {
uri: string, uri: string,
claim: ?Claim, claim: ?Claim,
mediaDuration?: string,
resolveUri: (string) => void, resolveUri: (string) => void,
isResolvingUri: boolean, isResolvingUri: boolean,
history: { push: (string) => void }, history: { push: (string) => void },
@ -72,6 +73,7 @@ function ClaimPreviewTile(props: Props) {
showNoSourceClaims, showNoSourceClaims,
isLivestream, isLivestream,
collectionId, collectionId,
mediaDuration,
} = props; } = props;
const isRepost = claim && claim.repost_channel_url; const isRepost = claim && claim.repost_channel_url;
const isCollection = claim && claim.value_type === 'collection'; const isCollection = claim && claim.value_type === 'collection';
@ -114,6 +116,18 @@ function ClaimPreviewTile(props: Props) {
const signingChannel = claim && claim.signing_channel; const signingChannel = claim && claim.signing_channel;
const channelUri = !isChannel ? signingChannel && signingChannel.permanent_url : claim && claim.permanent_url; const channelUri = !isChannel ? signingChannel && signingChannel.permanent_url : claim && claim.permanent_url;
const channelTitle = signingChannel && (signingChannel.value.title || signingChannel.name);
// Aria-label value for claim preview
let ariaLabelData = title;
if (!isChannel && channelTitle) {
if (mediaDuration) {
ariaLabelData = __('%title% by %channelTitle%, %mediaDuration%', { title, channelTitle, mediaDuration });
} else {
ariaLabelData = __('%title% by %channelTitle%', { title, channelTitle });
}
}
function handleClick(e) { function handleClick(e) {
if (navigateUrl) { if (navigateUrl) {
@ -226,7 +240,7 @@ function ClaimPreviewTile(props: Props) {
</FileThumbnail> </FileThumbnail>
</NavLink> </NavLink>
<div className="claim-tile__header"> <div className="claim-tile__header">
<NavLink {...navLinkProps}> <NavLink aria-label={ariaLabelData} {...navLinkProps}>
<h2 className="claim-tile__title"> <h2 className="claim-tile__title">
<TruncatedText text={title || (claim && claim.name)} lines={isChannel ? 1 : 2} /> <TruncatedText text={title || (claim && claim.name)} lines={isChannel ? 1 : 2} />
{isChannel && ( {isChannel && (

View file

@ -1,6 +1,6 @@
// @flow // @flow
import React from 'react'; import React from 'react';
import formatMediaDuration from 'util/formatMediaDuration';
type Props = { type Props = {
claim: ?StreamClaim, claim: ?StreamClaim,
className?: string, className?: string,
@ -9,19 +9,11 @@ type Props = {
function VideoDuration(props: Props) { function VideoDuration(props: Props) {
const { claim, className } = props; const { claim, className } = props;
const video = claim && claim.value && (claim.value.video || claim.value.audio); const media = claim && claim.value && (claim.value.video || claim.value.audio);
let duration; let duration;
if (video && video.duration) { if (media && media.duration) {
// $FlowFixMe // $FlowFixMe
let date = new Date(null); duration = formatMediaDuration(media.duration);
date.setSeconds(video.duration);
let timeString = date.toISOString().substr(11, 8);
if (timeString.startsWith('00:')) {
timeString = timeString.substr(3);
}
duration = timeString;
} }
return duration ? <span className={className}>{duration}</span> : null; return duration ? <span className={className}>{duration}</span> : null;

View file

@ -0,0 +1,24 @@
import moment from 'moment';
export default function formatMediaDuration(duration = 0, config) {
const options = {
screenReader: false,
...config,
};
// Optimize for screen readers
if (options.screenReader) {
return moment.utc(moment.duration(duration, 'seconds').asMilliseconds()).format('HH:mm:ss');
}
// Normal format
let date = new Date(null);
date.setSeconds(duration);
let timeString = date.toISOString().substr(11, 8);
if (timeString.startsWith('00:')) {
timeString = timeString.substr(3);
}
return timeString;
}