mirror of
https://github.com/TeamNewPipe/NewPipe
synced 2025-01-26 08:56:57 +00:00
searchfilters: Moving DividerItem from NewPipeExtractor into NewPipe
DividerItem was inserted in the content filter framework in the NewPipeExtractor to have a section title for YoutubeMusic. But as UI releated stuff seems a bit out of place in the Extractor I came up with injecting the DividerItem aka section title in the frontend without having to change too much in the frontend.
This commit is contained in:
parent
3c038aaf7c
commit
7c650f6e9d
@ -0,0 +1,147 @@
|
|||||||
|
package org.schabi.newpipe.fragments.list.search.filter;
|
||||||
|
|
||||||
|
import org.schabi.newpipe.App;
|
||||||
|
import org.schabi.newpipe.R;
|
||||||
|
import org.schabi.newpipe.extractor.NewPipe;
|
||||||
|
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
|
||||||
|
import org.schabi.newpipe.extractor.search.filter.FilterContainer;
|
||||||
|
import org.schabi.newpipe.extractor.search.filter.FilterGroup;
|
||||||
|
import org.schabi.newpipe.extractor.search.filter.FilterItem;
|
||||||
|
import org.schabi.newpipe.extractor.search.filter.LibraryStringIds;
|
||||||
|
import org.schabi.newpipe.extractor.services.youtube.search.filter.YoutubeFilters;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inject a {@link FilterItem} that actually should not be a real filter.
|
||||||
|
* <p>
|
||||||
|
* This base class is meant to inject eg {@link DividerItem} (that inherits {@link FilterItem})
|
||||||
|
* as Divider between {@link FilterItem}. It will be shown in the UI's.
|
||||||
|
* <p>
|
||||||
|
* Of course you have to handle {@link DividerItem} or whatever in the Ui's.
|
||||||
|
* For that for example have a look at {@link SearchFilterDialogSpinnerAdapter}.
|
||||||
|
*/
|
||||||
|
public abstract class InjectFilterItem {
|
||||||
|
|
||||||
|
protected InjectFilterItem(
|
||||||
|
@NonNull final String serviceName,
|
||||||
|
final int injectedAfterFilterWithId,
|
||||||
|
@NonNull final FilterItem toBeInjectedFilterItem) {
|
||||||
|
|
||||||
|
prepareAndInject(serviceName, injectedAfterFilterWithId, toBeInjectedFilterItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Please refer a static boolean to determine if already injected
|
||||||
|
protected abstract boolean isAlreadyInjected();
|
||||||
|
|
||||||
|
// Please refer a static boolean to determine if already injected
|
||||||
|
protected abstract void setAsInjected();
|
||||||
|
|
||||||
|
private void prepareAndInject(
|
||||||
|
@NonNull final String serviceName,
|
||||||
|
final int injectedAfterFilterWithId,
|
||||||
|
@NonNull final FilterItem toBeInjectedFilterItem) {
|
||||||
|
|
||||||
|
if (isAlreadyInjected()) { // already run
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try { // using serviceName to test if we are trying to inject into the right service
|
||||||
|
final List<FilterGroup> groups = NewPipe.getService(serviceName)
|
||||||
|
.getSearchQHFactory().getAvailableContentFilter().getFilterGroups();
|
||||||
|
injectFilterItemIntoGroup(
|
||||||
|
groups,
|
||||||
|
injectedAfterFilterWithId,
|
||||||
|
toBeInjectedFilterItem);
|
||||||
|
setAsInjected();
|
||||||
|
} catch (final ExtractionException ignored) {
|
||||||
|
// no the service we want to prepareAndInject -> so ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void injectFilterItemIntoGroup(
|
||||||
|
@NonNull final List<FilterGroup> groups,
|
||||||
|
final int injectedAfterFilterWithId,
|
||||||
|
@NonNull final FilterItem toBeInjectedFilterItem) {
|
||||||
|
|
||||||
|
int indexForFilterId = 0;
|
||||||
|
boolean isFilterItemFound = false;
|
||||||
|
FilterGroup groupWithTheSearchFilterItem = null;
|
||||||
|
|
||||||
|
for (final FilterGroup group : groups) {
|
||||||
|
for (final FilterItem item : group.getFilterItems()) {
|
||||||
|
if (item.getIdentifier() == injectedAfterFilterWithId) {
|
||||||
|
isFilterItemFound = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
indexForFilterId++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isFilterItemFound) {
|
||||||
|
groupWithTheSearchFilterItem = group;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isFilterItemFound) {
|
||||||
|
// we want to insert after the FilterItem we've searched
|
||||||
|
indexForFilterId++;
|
||||||
|
groupWithTheSearchFilterItem.getFilterItems()
|
||||||
|
.add(indexForFilterId, toBeInjectedFilterItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inject DividerItem between YouTube content filters and YoutubeMusic content filters.
|
||||||
|
*/
|
||||||
|
public static class DividerBetweenYoutubeAndYoutubeMusic extends InjectFilterItem {
|
||||||
|
|
||||||
|
private static boolean isYoutubeMusicDividerInjected = false;
|
||||||
|
|
||||||
|
protected DividerBetweenYoutubeAndYoutubeMusic() {
|
||||||
|
super(App.getApp().getApplicationContext().getString(R.string.youtube),
|
||||||
|
YoutubeFilters.ID_CF_MAIN_PLAYLISTS,
|
||||||
|
new DividerItem(R.string.search_filters_youtube_music)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Have a static runner method to avoid creating unnecessary objects if already inserted.
|
||||||
|
*/
|
||||||
|
public static void run() {
|
||||||
|
if (!isYoutubeMusicDividerInjected) {
|
||||||
|
new DividerBetweenYoutubeAndYoutubeMusic();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean isAlreadyInjected() {
|
||||||
|
return isYoutubeMusicDividerInjected;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void setAsInjected() {
|
||||||
|
isYoutubeMusicDividerInjected = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to have a title divider between regular {@link FilterItem}s.
|
||||||
|
*/
|
||||||
|
public static class DividerItem extends FilterItem {
|
||||||
|
|
||||||
|
private final int resId;
|
||||||
|
|
||||||
|
public DividerItem(final int resId) {
|
||||||
|
// the LibraryStringIds.. is not needed at all I just need one to satisfy FilterItem.
|
||||||
|
super(FilterContainer.ITEM_IDENTIFIER_UNKNOWN, LibraryStringIds.SEARCH_FILTERS_ALL);
|
||||||
|
this.resId = resId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getStringResId() {
|
||||||
|
return this.resId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,85 @@
|
|||||||
|
package org.schabi.newpipe.filter;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.schabi.newpipe.extractor.NewPipe;
|
||||||
|
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
|
||||||
|
import org.schabi.newpipe.extractor.search.filter.FilterContainer;
|
||||||
|
import org.schabi.newpipe.extractor.search.filter.FilterGroup;
|
||||||
|
import org.schabi.newpipe.extractor.search.filter.FilterItem;
|
||||||
|
import org.schabi.newpipe.extractor.services.youtube.search.filter.YoutubeFilters;
|
||||||
|
import org.schabi.newpipe.fragments.list.search.filter.InjectFilterItem;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
|
import static junit.framework.TestCase.assertFalse;
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
public class InjectFilterItemTest {
|
||||||
|
|
||||||
|
static final String SERVICE_NAME = "YouTube";
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void injectIntoFilterGroupTest() throws ExtractionException {
|
||||||
|
final FilterContainer filterContainer = NewPipe.getService(SERVICE_NAME)
|
||||||
|
.getSearchQHFactory().getAvailableContentFilter();
|
||||||
|
|
||||||
|
final AtomicInteger itemCount = new AtomicInteger();
|
||||||
|
assertFalse(getInjectedFilterItem(filterContainer, itemCount).isPresent());
|
||||||
|
|
||||||
|
InjectDividerTestClass.run(SERVICE_NAME);
|
||||||
|
|
||||||
|
final int expectedInjectedItemPosition = 5;
|
||||||
|
final AtomicInteger injectedItemPosition = new AtomicInteger();
|
||||||
|
assertTrue(getInjectedFilterItem(filterContainer, injectedItemPosition).isPresent());
|
||||||
|
assertTrue(itemCount.get() > injectedItemPosition.get());
|
||||||
|
assertEquals(expectedInjectedItemPosition, injectedItemPosition.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
private Optional<FilterItem> getInjectedFilterItem(
|
||||||
|
@NonNull final FilterContainer filterContainer,
|
||||||
|
@NonNull final AtomicInteger itemCount) {
|
||||||
|
|
||||||
|
return filterContainer.getFilterGroups().stream()
|
||||||
|
.map(FilterGroup::getFilterItems)
|
||||||
|
.flatMap(Collection::stream)
|
||||||
|
.filter(item -> {
|
||||||
|
itemCount.getAndIncrement();
|
||||||
|
return item instanceof InjectFilterItem.DividerItem;
|
||||||
|
})
|
||||||
|
.findAny();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class InjectDividerTestClass extends InjectFilterItem {
|
||||||
|
|
||||||
|
private static boolean isDividerInjected = false;
|
||||||
|
|
||||||
|
protected InjectDividerTestClass(@NonNull final String serviceName) {
|
||||||
|
super(serviceName,
|
||||||
|
YoutubeFilters.ID_CF_MAIN_PLAYLISTS,
|
||||||
|
new DividerItem(0)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void run(final String serviceName) {
|
||||||
|
if (!isDividerInjected) {
|
||||||
|
new InjectDividerTestClass(serviceName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean isAlreadyInjected() {
|
||||||
|
return isDividerInjected;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void setAsInjected() {
|
||||||
|
isDividerInjected = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user