refactor: update search to latest core changes

This commit is contained in:
Tim 2024-01-02 17:41:45 +01:00
parent f77a90e31d
commit 5903502f2f
12 changed files with 103 additions and 87 deletions

14
package-lock.json generated
View file

@ -12,7 +12,7 @@
"@babel/runtime": "7.16.0",
"@sentry/browser": "6.13.3",
"@stremio/stremio-colors": "5.0.1",
"@stremio/stremio-core-web": "0.45.1",
"@stremio/stremio-core-web": "0.46.0",
"@stremio/stremio-icons": "5.0.0-beta.3",
"@stremio/stremio-video": "0.0.26",
"a-color-picker": "1.2.1",
@ -3181,9 +3181,9 @@
"integrity": "sha512-Dt3PYmy1DZ473QNs99KYXVWQPHtpIl37VUY0+gCEvvuCqE1fRrZIJtZ9KbysUKonvO7WwdQDztgcW0iGoc1dEA=="
},
"node_modules/@stremio/stremio-core-web": {
"version": "0.45.1",
"resolved": "https://registry.npmjs.org/@stremio/stremio-core-web/-/stremio-core-web-0.45.1.tgz",
"integrity": "sha512-aoLsi0Mvd/46V5qz/CSdIle+tvHfRYsLsmNolraze469JLwzNXW1g1ZAAkEDayspwIroqd3QasU//GBgTrvDXg==",
"version": "0.46.0",
"resolved": "https://registry.npmjs.org/@stremio/stremio-core-web/-/stremio-core-web-0.46.0.tgz",
"integrity": "sha512-eGc0PfeJB5dYbk1jJz/BJNU+an0/LA8LWAxEDkOq6YtqjvQrsH+djuXL8u0ZDrwxt7YlHhHk6B7W+MBx/gX4pQ==",
"dependencies": {
"@babel/runtime": "7.16.0"
}
@ -18049,9 +18049,9 @@
"integrity": "sha512-Dt3PYmy1DZ473QNs99KYXVWQPHtpIl37VUY0+gCEvvuCqE1fRrZIJtZ9KbysUKonvO7WwdQDztgcW0iGoc1dEA=="
},
"@stremio/stremio-core-web": {
"version": "0.45.1",
"resolved": "https://registry.npmjs.org/@stremio/stremio-core-web/-/stremio-core-web-0.45.1.tgz",
"integrity": "sha512-aoLsi0Mvd/46V5qz/CSdIle+tvHfRYsLsmNolraze469JLwzNXW1g1ZAAkEDayspwIroqd3QasU//GBgTrvDXg==",
"version": "0.46.0",
"resolved": "https://registry.npmjs.org/@stremio/stremio-core-web/-/stremio-core-web-0.46.0.tgz",
"integrity": "sha512-eGc0PfeJB5dYbk1jJz/BJNU+an0/LA8LWAxEDkOq6YtqjvQrsH+djuXL8u0ZDrwxt7YlHhHk6B7W+MBx/gX4pQ==",
"requires": {
"@babel/runtime": "7.16.0"
}

View file

@ -15,7 +15,7 @@
"@babel/runtime": "7.16.0",
"@sentry/browser": "6.13.3",
"@stremio/stremio-colors": "5.0.1",
"@stremio/stremio-core-web": "0.45.1",
"@stremio/stremio-core-web": "0.46.0",
"@stremio/stremio-icons": "5.0.0-beta.3",
"@stremio/stremio-video": "0.0.26",
"a-color-picker": "1.2.1",

View file

@ -3,6 +3,7 @@
const React = require('react');
const PropTypes = require('prop-types');
const classnames = require('classnames');
const debounce = require('lodash.debounce');
const { useTranslation } = require('react-i18next');
const { default: Icon } = require('@stremio/stremio-icons/react');
const { useRouteFocused } = require('stremio-router');
@ -10,20 +11,22 @@ const Button = require('stremio/common/Button');
const TextInput = require('stremio/common/TextInput');
const useTorrent = require('stremio/common/useTorrent');
const { withCoreSuspender } = require('stremio/common/CoreSuspender');
const styles = require('./styles');
const useSearchHistory = require('../../../../routes/Search/useSearchHistory');
const useSearchHistory = require('./useSearchHistory');
const useLocalSearch = require('./useLocalSearch');
const styles = require('./styles');
const SearchBar = React.memo(({ className, query, active }) => {
const { t } = useTranslation();
const routeFocused = useRouteFocused();
const searchHistory = useSearchHistory();
const localSearch = useLocalSearch();
const { createTorrentFromMagnet } = useTorrent();
const [showHistory, setShowHistory] = React.useState(false);
const [currentQuery, setCurrentQuery] = React.useState(query || '');
const localSearch = useLocalSearch(currentQuery);
const searchInputRef = React.useRef(null);
const labelRef = React.useRef(null);
const containerRef = React.useRef(null);
const searchBarOnClick = React.useCallback(() => {
if (!active) {
@ -32,7 +35,7 @@ const SearchBar = React.memo(({ className, query, active }) => {
}, [active]);
const searchHistoryOnClose = React.useCallback((event) => {
if (showHistory && labelRef.current && !labelRef.current.contains(event.target)) {
if (showHistory && containerRef.current && !containerRef.current.contains(event.target)) {
setShowHistory(false);
}
}, [showHistory]);
@ -70,38 +73,28 @@ const SearchBar = React.memo(({ className, query, active }) => {
window.location.hash = '/search';
}, []);
const updateLocalSearchDebounced = React.useCallback(debounce((query) => {
localSearch.search(query);
}, 250), []);
React.useEffect(() => {
updateLocalSearchDebounced(currentQuery);
}, [currentQuery]);
React.useEffect(() => {
if (routeFocused && active) {
searchInputRef.current.focus();
}
}, [routeFocused, active]);
const renderSearchHistoryItems = () => {
return (
<div className={styles['search-history-results']}>
{searchHistory.items.slice(0, 8).map((item, index) => (
<a key={index} className={styles['search-history-item']} onClick={(e) => queryInputOnSubmit(`/search?search=${item.query}`, e)}>
{item.query}
</a>
))}
</div>
);
};
const renderLocalSearchItems = () => {
return (
<div className={styles['search-history-results']}>
<div className={styles['search-history-label']}>{ t('Recommendations') }</div>
{localSearch.searchResults.map((item, index) => (
<a key={index} className={styles['search-history-item']} onClick={(e) => queryInputOnSubmit(`/search?search=${item.name}`, e)}>
{item.name}
</a>
))}
</div>
);
};
React.useEffect(() => {
return () => {
updateLocalSearchDebounced.cancel();
};
}, []);
return (
<label className={classnames(className, styles['search-bar-container'], { 'active': active })} onClick={searchBarOnClick} ref={labelRef}>
<div className={classnames(className, styles['search-bar-container'], { 'active': active })} onClick={searchBarOnClick} ref={containerRef}>
{
active ?
<TextInput
@ -133,34 +126,48 @@ const SearchBar = React.memo(({ className, query, active }) => {
}
{
showHistory ?
<div className={styles['search-history']}>
<div className={styles['menu-container']}>
{
localSearch.searchResults.length === 0 && searchHistory.items.length === 0 ?
<div className={styles['search-history-label']}>{ t('Start typing ...') }</div>
localSearch.items.length === 0 && searchHistory.items.length === 0 ?
<div className={styles['label']}>{ t('Start typing ...') }</div>
:
null
}
{
searchHistory.items.length > 0 ?
<div className={styles['search-history-actions']}>
<div className={styles['search-history-label']}>{ t('STREMIO_TV_SEARCH_HISTORY_TITLE') }</div>
<button className={styles['search-history-clear']} onClick={searchHistory.clear}>
{t('CLEAR_HISTORY')}
</button>
</div>
:
null
}
<div className={styles['search-history-items']}>
<div className={styles['content']}>
{
searchHistory.items.length > 0 ?
renderSearchHistoryItems()
searchHistory?.items?.length > 0 ?
<div className={styles['items']}>
<div className={styles['title']}>
<div className={styles['label']}>{ t('STREMIO_TV_SEARCH_HISTORY_TITLE') }</div>
<button className={styles['search-history-clear']} onClick={searchHistory.clear}>
{ t('CLEAR_HISTORY') }
</button>
</div>
{
searchHistory.items.slice(0, 8).map(({ query, deepLinks }, index) => (
<Button key={index} className={styles['item']} href={deepLinks.search}>
{query}
</Button>
))
}
</div>
:
null
}
{
localSearch.searchResults.length > 0 ?
renderLocalSearchItems()
localSearch?.items?.length ?
<div className={styles['items']}>
<div className={styles['title']}>
<div className={styles['label']}>{ t('Recommendations') }</div>
</div>
{
localSearch.items.map(({ query, deepLinks }, index) => (
<Button key={index} className={styles['item']} href={deepLinks.search}>
{query}
</Button>
))
}
</div>
:
null
}
@ -169,7 +176,7 @@ const SearchBar = React.memo(({ className, query, active }) => {
:
null
}
</label>
</div>
);
});

View file

@ -49,7 +49,7 @@
}
}
.search-history {
.menu-container {
position: absolute;
width: 100%;
height: auto;
@ -60,23 +60,18 @@
background-color: var(--modal-background-color);
border-radius: var(--border-radius);
.search-history-label {
.label {
font-size: 0.9rem;
color: var(--primary-foreground-color);
}
.search-history-actions {
.title {
display: flex;
justify-content: space-between;
width: 100%;
opacity: 0.8;
padding-bottom: 1rem;
.search-history-label {
font-size: 0.9rem;
color: var(--primary-foreground-color);
}
.search-history-clear {
cursor: pointer;
color: var(--primary-foreground-color);
@ -88,24 +83,24 @@
}
}
.search-history-items {
.content {
width: 100%;
margin: 0 auto;
display: flex;
justify-content: center;
align-items: flex-start;
flex-direction: column;
gap: 1.5rem;
.search-history-results {
.items {
width: 100%;
margin: 0 auto;
display: flex;
justify-content: center;
align-items: flex-start;
flex-direction: column;
padding-bottom: 1rem;
.search-history-item {
.item {
width: 90%;
color: var(--primary-foreground-color);
text-align: left;
@ -121,12 +116,6 @@
}
}
}
.search-history-label {
font-size: 0.9rem;
color: var(--primary-foreground-color);
margin-bottom: 1rem;
}
}
}
}

View file

@ -0,0 +1,2 @@
declare const useLocalSearch: () => { items: LocalSearchItem[], search: (query: string) => void };
export = useLocalSearch;

View file

@ -2,9 +2,9 @@
const React = require('react');
const { useServices } = require('stremio/services');
const useModelState = require('../../../../common/useModelState');
const useModelState = require('stremio/common/useModelState');
const useLocalSearch = (query) => {
const useLocalSearch = () => {
const { core } = useServices();
const action = React.useMemo(() => ({
@ -14,9 +14,9 @@ const useLocalSearch = (query) => {
}
}), []);
const { searchResults } = useModelState({ model: 'local_search', action });
const { items } = useModelState({ model: 'local_search', action });
const dispatchSearch = React.useEffect(() => {
const search = React.useCallback((query) => {
core.transport.dispatch({
action: 'Search',
args: {
@ -27,11 +27,11 @@ const useLocalSearch = (query) => {
}
},
});
}, [query]);
}, []);
return {
searchResults,
dispatchSearch
items,
search,
};
};

View file

@ -1,2 +1,2 @@
declare const useSearchHistory: () => { items: SearchHistory, clear: () => {} };
declare const useSearchHistory: () => { items: SearchHistory, clear: () => void };
export = useSearchHistory;

View file

@ -131,7 +131,7 @@ Search.propTypes = {
};
const SearchFallback = ({ queryParams }) => (
<MainNavBars className={styles['search-container']} route={'search'} query={queryParams.get('search')} />
<MainNavBars className={styles['search-container']} route={'search'} query={queryParams.get('search') ?? queryParams.get('query')} />
);
SearchFallback.propTypes = Search.propTypes;

View file

@ -32,14 +32,15 @@ const useSearch = (queryParams) => {
// };
// }, [queryParams.get('search')]);
const action = React.useMemo(() => {
if (queryParams.has('search') && queryParams.get('search').length > 0) {
const query = queryParams.get('search') ?? queryParams.get('query');
if (query?.length > 0) {
return {
action: 'Load',
args: {
model: 'CatalogsWithExtra',
args: {
extra: [
['search', queryParams.get('search')]
['search', query]
]
}
}

View file

@ -57,7 +57,14 @@ type NotificationItem = {
videoReleased: string,
}
type SearchHistory = string[];
type SearchHistoryItem = {
query: string,
deepLinks: {
search: string,
},
};
type SearchHistory = SearchHistoryItem[];
type Ctx = {
profile: Profile,

10
src/types/models/LocalSearch.d.ts vendored Normal file
View file

@ -0,0 +1,10 @@
type LocalSearchItem = {
query: string,
deepLinks: {
search: string,
},
};
type LocalSearch = {
items: LocalSearchItem[],
};