claim-search by language
setting to search only in language as default add channel update language selection and about bump searchable languages
This commit is contained in:
parent
54466edafc
commit
c4d05a5a1a
15 changed files with 221 additions and 9 deletions
|
@ -136,7 +136,7 @@
|
|||
"imagesloaded": "^4.1.4",
|
||||
"json-loader": "^0.5.4",
|
||||
"lbry-format": "https://github.com/lbryio/lbry-format.git",
|
||||
"lbry-redux": "lbryio/lbry-redux#1fc5afa0c45cfb4126539513088b580db9c4aca1",
|
||||
"lbry-redux": "lbryio/lbry-redux#6828dc2b86818a00d762c1b883572ea17f0bf6b9",
|
||||
"lbryinc": "lbryio/lbryinc#517c28a183d6ab69a357227809bc7c3c12d8411e",
|
||||
"lint-staged": "^7.0.2",
|
||||
"localforage": "^1.7.1",
|
||||
|
|
|
@ -1457,6 +1457,12 @@
|
|||
"Pin": "Pin",
|
||||
"Unpin": "Unpin",
|
||||
"LBRY leveled up": "LBRY leveled up",
|
||||
"Post": "Post",
|
||||
"Primary Language": "Primary Language",
|
||||
"Your main content language": "Your main content language",
|
||||
"None selected": "None selected",
|
||||
"Secondary Language": "Secondary Language",
|
||||
"Your other content language": "Your other content language",
|
||||
"This link leads to an external website.": "This link leads to an external website.",
|
||||
"Hold on, we are setting up your account": "Hold on, we are setting up your account",
|
||||
"No Content Found": "No Content Found",
|
||||
|
|
|
@ -7,6 +7,7 @@ const select = (state, props) => ({
|
|||
description: makeSelectMetadataItemForUri(props.uri, 'description')(state),
|
||||
website: makeSelectMetadataItemForUri(props.uri, 'website_url')(state),
|
||||
email: makeSelectMetadataItemForUri(props.uri, 'email')(state),
|
||||
languages: makeSelectMetadataItemForUri(props.uri, 'languages')(state),
|
||||
});
|
||||
|
||||
export default connect(select, null)(ChannelAbout);
|
||||
|
|
|
@ -8,6 +8,7 @@ import Button from 'component/button';
|
|||
import * as PAGES from 'constants/pages';
|
||||
import DateTime from 'component/dateTime';
|
||||
import YoutubeBadge from 'component/youtubeBadge';
|
||||
import SUPPORTED_LANGUAGES from 'constants/supported_languages';
|
||||
|
||||
type Props = {
|
||||
claim: ChannelClaim,
|
||||
|
@ -15,6 +16,7 @@ type Props = {
|
|||
description: ?string,
|
||||
email: ?string,
|
||||
website: ?string,
|
||||
languages: Array<string>,
|
||||
};
|
||||
|
||||
const formatEmail = (email: string) => {
|
||||
|
@ -27,7 +29,7 @@ const formatEmail = (email: string) => {
|
|||
};
|
||||
|
||||
function ChannelAbout(props: Props) {
|
||||
const { claim, uri, description, email, website } = props;
|
||||
const { claim, uri, description, email, website, languages } = props;
|
||||
const claimId = claim && claim.claim_id;
|
||||
|
||||
return (
|
||||
|
@ -64,6 +66,12 @@ function ChannelAbout(props: Props) {
|
|||
<ClaimTags uri={uri} type="large" />
|
||||
</div>
|
||||
|
||||
<label>{__('Languages')}</label>
|
||||
<div className="media__info-text">
|
||||
{/* this could use some nice 'tags' styling */}
|
||||
{`${SUPPORTED_LANGUAGES[languages[0]]}${languages[1] ? ', ' + SUPPORTED_LANGUAGES[languages[1]] : ''}`}
|
||||
</div>
|
||||
|
||||
<label>{__('Total Uploads')}</label>
|
||||
<div className="media__info-text">{claim.meta.claims_in_channel}</div>
|
||||
|
||||
|
|
|
@ -18,6 +18,9 @@ import Card from 'component/common/card';
|
|||
import * as PAGES from 'constants/pages';
|
||||
import analytics from 'analytics';
|
||||
import LbcSymbol from 'component/common/lbc-symbol';
|
||||
import SUPPORTED_LANGUAGES from 'constants/supported_languages';
|
||||
const LANG_NONE = 'none';
|
||||
|
||||
const MAX_TAG_SELECT = 5;
|
||||
|
||||
type Props = {
|
||||
|
@ -63,7 +66,7 @@ function ChannelForm(props: Props) {
|
|||
coverUrl,
|
||||
tags,
|
||||
locations,
|
||||
languages,
|
||||
languages = [],
|
||||
onDone,
|
||||
updateChannel,
|
||||
updateError,
|
||||
|
@ -83,6 +86,9 @@ function ChannelForm(props: Props) {
|
|||
const name = params.name;
|
||||
const isNewChannel = !uri;
|
||||
const { replace } = useHistory();
|
||||
const languageParam = params.languages;
|
||||
const primaryLanguage = Array.isArray(languageParam) && languageParam.length && languageParam[0];
|
||||
const secondaryLanguage = Array.isArray(languageParam) && languageParam.length >= 2 && languageParam[1];
|
||||
|
||||
function getChannelParams() {
|
||||
// fill this in with sdk data
|
||||
|
@ -141,6 +147,25 @@ function ChannelForm(props: Props) {
|
|||
}
|
||||
}
|
||||
|
||||
function handleLanguageChange(index, code) {
|
||||
let langs = [...languageParam];
|
||||
if (index === 0) {
|
||||
if (code === LANG_NONE) {
|
||||
// clear all
|
||||
langs = [];
|
||||
} else {
|
||||
langs[0] = code;
|
||||
}
|
||||
} else {
|
||||
if (code === LANG_NONE || code === langs[0]) {
|
||||
langs.splice(1, 1);
|
||||
} else {
|
||||
langs[index] = code;
|
||||
}
|
||||
}
|
||||
setParams({ ...params, languages: langs });
|
||||
}
|
||||
|
||||
function handleThumbnailChange(thumbnailUrl: string) {
|
||||
setParams({ ...params, thumbnailUrl });
|
||||
}
|
||||
|
@ -356,6 +381,43 @@ function ChannelForm(props: Props) {
|
|||
value={params.email}
|
||||
onChange={e => setParams({ ...params, email: e.target.value })}
|
||||
/>
|
||||
<FormField
|
||||
name="language_select"
|
||||
type="select"
|
||||
label={__('Primary Language')}
|
||||
onChange={event => handleLanguageChange(0, event.target.value)}
|
||||
value={primaryLanguage}
|
||||
helper={__('Your main content language')}
|
||||
>
|
||||
<option key={'pri-langNone'} value={LANG_NONE}>
|
||||
{__('None selected')}
|
||||
</option>
|
||||
{Object.keys(SUPPORTED_LANGUAGES).map(language => (
|
||||
<option key={language} value={language}>
|
||||
{SUPPORTED_LANGUAGES[language]}
|
||||
</option>
|
||||
))}
|
||||
</FormField>
|
||||
<FormField
|
||||
name="language_select2"
|
||||
type="select"
|
||||
label={__('Secondary Language')}
|
||||
onChange={event => handleLanguageChange(1, event.target.value)}
|
||||
value={secondaryLanguage}
|
||||
disabled={!languageParam[0]}
|
||||
helper={__('Your other content language')}
|
||||
>
|
||||
<option key={'sec-langNone'} value={LANG_NONE}>
|
||||
{__('None selected')}
|
||||
</option>
|
||||
{Object.keys(SUPPORTED_LANGUAGES)
|
||||
.filter(lang => lang !== languageParam[0])
|
||||
.map(language => (
|
||||
<option key={language} value={language}>
|
||||
{SUPPORTED_LANGUAGES[language]}
|
||||
</option>
|
||||
))}
|
||||
</FormField>
|
||||
</>
|
||||
}
|
||||
/>
|
||||
|
|
|
@ -19,7 +19,9 @@ const select = state => ({
|
|||
loading: selectFetchingClaimSearch(state),
|
||||
showNsfw: makeSelectClientSetting(SETTINGS.SHOW_MATURE)(state),
|
||||
hideReposts: makeSelectClientSetting(SETTINGS.HIDE_REPOSTS)(state),
|
||||
languageSetting: makeSelectClientSetting(SETTINGS.LANGUAGE)(state),
|
||||
hiddenUris: selectBlockedChannels(state),
|
||||
searchInLanguage: makeSelectClientSetting(SETTINGS.SEARCH_IN_LANGUAGE)(state),
|
||||
});
|
||||
|
||||
const perform = {
|
||||
|
|
|
@ -61,6 +61,8 @@ type Props = {
|
|||
hideFilters?: boolean,
|
||||
maxPages?: number,
|
||||
forceShowReposts?: boolean,
|
||||
languageSetting: string,
|
||||
searchInLanguage: boolean,
|
||||
};
|
||||
|
||||
function ClaimListDiscover(props: Props) {
|
||||
|
@ -106,6 +108,8 @@ function ClaimListDiscover(props: Props) {
|
|||
claimIds,
|
||||
maxPages,
|
||||
forceShowReposts = false,
|
||||
languageSetting,
|
||||
searchInLanguage,
|
||||
} = props;
|
||||
const didNavigateForward = history.action === 'PUSH';
|
||||
const { search } = location;
|
||||
|
@ -121,6 +125,20 @@ function ClaimListDiscover(props: Props) {
|
|||
(urlParams.get(CS.TAGS_KEY) !== null && urlParams.get(CS.TAGS_KEY)) ||
|
||||
(defaultTags && getParamFromTags(defaultTags));
|
||||
const freshnessParam = freshness || urlParams.get(CS.FRESH_KEY) || defaultFreshness;
|
||||
|
||||
const langParam = urlParams.get(CS.LANGUAGE_KEY) || null;
|
||||
const languageParam = searchInLanguage
|
||||
? langParam === null
|
||||
? languageSetting
|
||||
: langParam === 'any'
|
||||
? null
|
||||
: langParam
|
||||
: langParam === null
|
||||
? null
|
||||
: langParam === 'any'
|
||||
? null
|
||||
: langParam;
|
||||
|
||||
const contentTypeParam = urlParams.get(CS.CONTENT_KEY);
|
||||
const claimTypeParam =
|
||||
claimType || (CS.CLAIM_TYPES.includes(contentTypeParam) && contentTypeParam) || defaultClaimType || null;
|
||||
|
@ -159,6 +177,7 @@ function ClaimListDiscover(props: Props) {
|
|||
page: number,
|
||||
no_totals: boolean,
|
||||
any_tags?: Array<string>,
|
||||
any_languages?: Array<string>,
|
||||
not_tags: Array<string>,
|
||||
channel_ids?: Array<string>,
|
||||
claim_ids?: Array<string>,
|
||||
|
@ -280,6 +299,24 @@ function ClaimListDiscover(props: Props) {
|
|||
}
|
||||
}
|
||||
|
||||
if (languageParam) {
|
||||
if (languageParam !== CS.LANGUAGES_ALL) {
|
||||
options.any_languages = [languageParam];
|
||||
}
|
||||
}
|
||||
|
||||
if (tagsParam) {
|
||||
if (tagsParam !== CS.TAGS_ALL && tagsParam !== '') {
|
||||
if (tagsParam === CS.TAGS_FOLLOWED) {
|
||||
options.any_tags = followed;
|
||||
} else if (Array.isArray(tagsParam)) {
|
||||
options.any_tags = tagsParam;
|
||||
} else {
|
||||
options.any_tags = tagsParam.split(',');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (hideReposts && !options.reposted_claim_id && !forceShowReposts) {
|
||||
if (Array.isArray(options.claim_type)) {
|
||||
if (options.claim_type.length > 1) {
|
||||
|
|
|
@ -10,6 +10,8 @@ const select = state => ({
|
|||
followedTags: selectFollowedTags(state),
|
||||
loading: selectFetchingClaimSearch(state),
|
||||
showNsfw: makeSelectClientSetting(SETTINGS.SHOW_MATURE)(state),
|
||||
searchInLanguage: makeSelectClientSetting(SETTINGS.SEARCH_IN_LANGUAGE)(state),
|
||||
languageSetting: makeSelectClientSetting(SETTINGS.LANGUAGE)(state),
|
||||
});
|
||||
|
||||
const perform = {
|
||||
|
|
|
@ -11,6 +11,7 @@ import { SETTINGS } from 'lbry-redux';
|
|||
import { FormField } from 'component/common/form';
|
||||
import Button from 'component/button';
|
||||
import { toCapitalCase } from 'util/string';
|
||||
import SEARCHABLE_LANGUAGES from 'constants/searchable_languages';
|
||||
|
||||
type Props = {
|
||||
defaultTags: string,
|
||||
|
@ -32,6 +33,8 @@ type Props = {
|
|||
doSetClientSetting: (string, boolean, ?boolean) => void,
|
||||
setPage: number => void,
|
||||
hideFilters: boolean,
|
||||
searchInLanguage: boolean,
|
||||
languageSetting: string,
|
||||
};
|
||||
|
||||
function ClaimListHeader(props: Props) {
|
||||
|
@ -55,6 +58,8 @@ function ClaimListHeader(props: Props) {
|
|||
doSetClientSetting,
|
||||
setPage,
|
||||
hideFilters,
|
||||
searchInLanguage,
|
||||
languageSetting,
|
||||
} = props;
|
||||
const { action, push, location } = useHistory();
|
||||
const { search } = location;
|
||||
|
@ -72,6 +77,7 @@ function ClaimListHeader(props: Props) {
|
|||
const streamTypeParam =
|
||||
streamType || (CS.FILE_TYPES.includes(contentTypeParam) && contentTypeParam) || defaultStreamType || null;
|
||||
const durationParam = urlParams.get(CS.DURATION_KEY) || null;
|
||||
const languageParam = urlParams.get(CS.LANGUAGE_KEY) || null;
|
||||
const channelIdsInUrl = urlParams.get(CS.CHANNEL_IDS_KEY);
|
||||
const channelIdsParam = channelIdsInUrl ? channelIdsInUrl.split(',') : channelIds;
|
||||
const feeAmountParam = urlParams.get('fee_amount') || feeAmount || CS.FEE_AMOUNT_ANY;
|
||||
|
@ -82,9 +88,22 @@ function ClaimListHeader(props: Props) {
|
|||
urlParams.get(CS.CONTENT_KEY) ||
|
||||
urlParams.get(CS.DURATION_KEY) ||
|
||||
urlParams.get(CS.TAGS_KEY) ||
|
||||
urlParams.get(CS.FEE_AMOUNT_KEY)
|
||||
urlParams.get(CS.FEE_AMOUNT_KEY) ||
|
||||
urlParams.get(CS.LANGUAGE_KEY)
|
||||
);
|
||||
|
||||
const languageValue = searchInLanguage
|
||||
? languageParam === null
|
||||
? languageSetting
|
||||
: languageParam
|
||||
: languageParam === null
|
||||
? CS.LANGUAGES_ALL
|
||||
: languageParam;
|
||||
|
||||
const shouldHighlight = searchInLanguage
|
||||
? languageParam !== languageSetting && languageParam !== null
|
||||
: languageParam !== CS.LANGUAGES_ALL && languageParam !== null;
|
||||
|
||||
React.useEffect(() => {
|
||||
if (action !== 'POP' && isFiltered()) {
|
||||
setExpanded(true);
|
||||
|
@ -172,6 +191,9 @@ function ClaimListHeader(props: Props) {
|
|||
newUrlParams.set(CS.DURATION_KEY, delta.value);
|
||||
}
|
||||
break;
|
||||
case CS.LANGUAGE_KEY:
|
||||
newUrlParams.set(CS.LANGUAGE_KEY, delta.value);
|
||||
break;
|
||||
case CS.TAGS_KEY:
|
||||
if (delta.value === CS.TAGS_ALL) {
|
||||
if (defaultTags === CS.TAGS_ALL) {
|
||||
|
@ -334,6 +356,43 @@ function ClaimListHeader(props: Props) {
|
|||
</div>
|
||||
)}
|
||||
|
||||
{/* LANGUAGE FIELD */}
|
||||
{!claimType && (
|
||||
<div
|
||||
className={classnames('claim-search__input-container', {
|
||||
'claim-search__input-container--selected': shouldHighlight,
|
||||
})}
|
||||
>
|
||||
<FormField
|
||||
className={classnames('claim-search__dropdown', {
|
||||
'claim-search__dropdown--selected': shouldHighlight,
|
||||
})}
|
||||
type="select"
|
||||
name="claimType"
|
||||
label={__('Language')}
|
||||
value={languageValue || CS.LANGUAGES_ALL}
|
||||
onChange={e =>
|
||||
handleChange({
|
||||
key: CS.LANGUAGE_KEY,
|
||||
value: e.target.value,
|
||||
})
|
||||
}
|
||||
>
|
||||
<option key={CS.LANGUAGES_ALL} value={CS.LANGUAGES_ALL}>
|
||||
{__('Any')}
|
||||
{/* i18fixme */}
|
||||
</option>
|
||||
{Object.entries(SEARCHABLE_LANGUAGES).map(([code, label]) => {
|
||||
return (
|
||||
<option key={code} value={code}>
|
||||
{__(String(label))}
|
||||
</option>
|
||||
);
|
||||
})}
|
||||
</FormField>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* DURATIONS FIELD */}
|
||||
{showDuration && (
|
||||
<div className={'claim-search__input-container'}>
|
||||
|
|
|
@ -1,15 +1,17 @@
|
|||
import { connect } from 'react-redux';
|
||||
import { SETTINGS } from 'lbry-redux';
|
||||
import { doSetLanguage } from 'redux/actions/settings';
|
||||
import { doSetLanguage, doSetClientSetting } from 'redux/actions/settings';
|
||||
import { makeSelectClientSetting } from 'redux/selectors/settings';
|
||||
import SettingLanguage from './view';
|
||||
|
||||
const select = state => ({
|
||||
language: makeSelectClientSetting(SETTINGS.LANGUAGE)(state),
|
||||
searchInLanguage: makeSelectClientSetting(SETTINGS.SEARCH_IN_LANGUAGE)(state),
|
||||
});
|
||||
|
||||
const perform = dispatch => ({
|
||||
setLanguage: value => dispatch(doSetLanguage(value)),
|
||||
setSearchInLanguage: value => dispatch(doSetClientSetting(SETTINGS.SEARCH_IN_LANGUAGE, value)),
|
||||
});
|
||||
|
||||
export default connect(select, perform)(SettingLanguage);
|
||||
|
|
|
@ -3,15 +3,17 @@
|
|||
import React, { useState } from 'react';
|
||||
import { FormField } from 'component/common/form';
|
||||
import Spinner from 'component/spinner';
|
||||
import SUPPORTED_LANGUAGES from '../../constants/supported_languages';
|
||||
import SUPPORTED_LANGUAGES from 'constants/supported_languages';
|
||||
|
||||
type Props = {
|
||||
language: string,
|
||||
setLanguage: string => void,
|
||||
searchInLanguage: boolean,
|
||||
setSearchInLanguage: boolean => void,
|
||||
};
|
||||
|
||||
function SettingLanguage(props: Props) {
|
||||
const { language, setLanguage } = props;
|
||||
const { language, setLanguage, searchInLanguage, setSearchInLanguage } = props;
|
||||
|
||||
const [previousLanguage, setPreviousLanguage] = useState(null);
|
||||
const languages = SUPPORTED_LANGUAGES;
|
||||
|
@ -45,6 +47,13 @@ function SettingLanguage(props: Props) {
|
|||
))}
|
||||
</FormField>
|
||||
{previousLanguage && <Spinner type="small" />}
|
||||
<FormField
|
||||
name="search-in-language"
|
||||
type="checkbox"
|
||||
label={__('Search only in this language by default')}
|
||||
checked={searchInLanguage}
|
||||
onChange={() => setSearchInLanguage(!searchInLanguage)}
|
||||
/>
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ export const PAGE_SIZE = 20;
|
|||
export const FRESH_KEY = 'fresh';
|
||||
export const ORDER_BY_KEY = 'order';
|
||||
export const DURATION_KEY = 'duration';
|
||||
export const LANGUAGE_KEY = 'language';
|
||||
export const TAGS_KEY = 't';
|
||||
export const CONTENT_KEY = 'content';
|
||||
export const REPOSTED_URI_KEY = 'reposted_uri';
|
||||
|
@ -15,6 +16,8 @@ export const FEE_AMOUNT_ANY = '>=0';
|
|||
export const FEE_AMOUNT_ONLY_PAID = '>0';
|
||||
export const FEE_AMOUNT_ONLY_FREE = '<=0';
|
||||
|
||||
export const LANGUAGES_ALL = 'all';
|
||||
|
||||
export const FRESH_DAY = 'day';
|
||||
export const FRESH_WEEK = 'week';
|
||||
export const FRESH_MONTH = 'month';
|
||||
|
|
20
ui/constants/searchable_languages.js
Normal file
20
ui/constants/searchable_languages.js
Normal file
|
@ -0,0 +1,20 @@
|
|||
import LANGUAGES from './languages';
|
||||
|
||||
const SEARCHABLE_LANGUAGES = {
|
||||
en: LANGUAGES.en[1],
|
||||
hr: LANGUAGES.hr[1],
|
||||
nl: LANGUAGES.nl[1],
|
||||
fr: LANGUAGES.fr[1],
|
||||
de: LANGUAGES.de[1],
|
||||
it: LANGUAGES.it[1],
|
||||
pl: LANGUAGES.pl[1],
|
||||
pt: LANGUAGES.pt[1],
|
||||
ru: LANGUAGES.ru[1],
|
||||
es: LANGUAGES.es[1],
|
||||
tr: LANGUAGES.tr[1],
|
||||
cs: LANGUAGES.cs[1],
|
||||
};
|
||||
|
||||
// Properties: language code (e.g. 'ja')
|
||||
// Values: name of the language in native form (e.g. '日本語')
|
||||
export default SEARCHABLE_LANGUAGES;
|
|
@ -37,6 +37,7 @@ const defaultState = {
|
|||
|
||||
// UI
|
||||
[SETTINGS.LANGUAGE]: settingLanguage.find(language => SUPPORTED_LANGUAGES[language]),
|
||||
[SETTINGS.SEARCH_IN_LANGUAGE]: false,
|
||||
[SETTINGS.THEME]: __('light'),
|
||||
[SETTINGS.THEMES]: [__('light'), __('dark')],
|
||||
[SETTINGS.HIDE_SPLASH_ANIMATION]: false,
|
||||
|
|
|
@ -7391,9 +7391,9 @@ lazy-val@^1.0.4:
|
|||
yargs "^13.2.2"
|
||||
zstd-codec "^0.1.1"
|
||||
|
||||
lbry-redux@lbryio/lbry-redux#1fc5afa0c45cfb4126539513088b580db9c4aca1:
|
||||
lbry-redux@lbryio/lbry-redux#6828dc2b86818a00d762c1b883572ea17f0bf6b9:
|
||||
version "0.0.1"
|
||||
resolved "https://codeload.github.com/lbryio/lbry-redux/tar.gz/1fc5afa0c45cfb4126539513088b580db9c4aca1"
|
||||
resolved "https://codeload.github.com/lbryio/lbry-redux/tar.gz/6828dc2b86818a00d762c1b883572ea17f0bf6b9"
|
||||
dependencies:
|
||||
proxy-polyfill "0.1.6"
|
||||
reselect "^3.0.0"
|
||||
|
|
Loading…
Reference in a new issue