mirror of
https://github.com/TeamNewPipe/NewPipe.git
synced 2025-10-03 17:59:41 +02:00
Merge e8c3892c7d
into 3a2d427a46
This commit is contained in:
commit
7a9bc95b3b
5 changed files with 165 additions and 37 deletions
|
@ -775,14 +775,14 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
|
||||||
|
|
||||||
if (showLocalSuggestions && shallShowRemoteSuggestionsNow) {
|
if (showLocalSuggestions && shallShowRemoteSuggestionsNow) {
|
||||||
return Observable.zip(
|
return Observable.zip(
|
||||||
getLocalSuggestionsObservable(query, 3),
|
getLocalSuggestionsObservable(query, 3),
|
||||||
getRemoteSuggestionsObservable(query),
|
getRemoteSuggestionsObservable(query),
|
||||||
(local, remote) -> {
|
(local, remote) -> {
|
||||||
remote.removeIf(remoteItem -> local.stream().anyMatch(
|
remote.removeIf(remoteItem -> local.stream().anyMatch(
|
||||||
localItem -> localItem.equals(remoteItem)));
|
localItem -> localItem.equals(remoteItem)));
|
||||||
local.addAll(remote);
|
local.addAll(remote);
|
||||||
return local;
|
return local;
|
||||||
})
|
})
|
||||||
.materialize();
|
.materialize();
|
||||||
} else if (showLocalSuggestions) {
|
} else if (showLocalSuggestions) {
|
||||||
return getLocalSuggestionsObservable(query, 25)
|
return getLocalSuggestionsObservable(query, 25)
|
||||||
|
@ -887,9 +887,9 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
|
||||||
searchDisposable.dispose();
|
searchDisposable.dispose();
|
||||||
}
|
}
|
||||||
searchDisposable = ExtractorHelper.searchFor(serviceId,
|
searchDisposable = ExtractorHelper.searchFor(serviceId,
|
||||||
searchString,
|
searchString,
|
||||||
Arrays.asList(contentFilter),
|
Arrays.asList(contentFilter),
|
||||||
sortFilter)
|
sortFilter)
|
||||||
.subscribeOn(Schedulers.io())
|
.subscribeOn(Schedulers.io())
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
.doOnEvent((searchResult, throwable) -> isLoading.set(false))
|
.doOnEvent((searchResult, throwable) -> isLoading.set(false))
|
||||||
|
@ -908,11 +908,11 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
|
||||||
searchDisposable.dispose();
|
searchDisposable.dispose();
|
||||||
}
|
}
|
||||||
searchDisposable = ExtractorHelper.getMoreSearchItems(
|
searchDisposable = ExtractorHelper.getMoreSearchItems(
|
||||||
serviceId,
|
serviceId,
|
||||||
searchString,
|
searchString,
|
||||||
asList(contentFilter),
|
asList(contentFilter),
|
||||||
sortFilter,
|
sortFilter,
|
||||||
nextPage)
|
nextPage)
|
||||||
.subscribeOn(Schedulers.io())
|
.subscribeOn(Schedulers.io())
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
.doOnEvent((nextItemsResult, throwable) -> isLoading.set(false))
|
.doOnEvent((nextItemsResult, throwable) -> isLoading.set(false))
|
||||||
|
|
|
@ -20,7 +20,6 @@ import androidx.preference.Preference;
|
||||||
import androidx.preference.PreferenceFragmentCompat;
|
import androidx.preference.PreferenceFragmentCompat;
|
||||||
|
|
||||||
import com.evernote.android.state.State;
|
import com.evernote.android.state.State;
|
||||||
import com.jakewharton.rxbinding4.widget.RxTextView;
|
|
||||||
import com.livefront.bridge.Bridge;
|
import com.livefront.bridge.Bridge;
|
||||||
|
|
||||||
import org.schabi.newpipe.MainActivity;
|
import org.schabi.newpipe.MainActivity;
|
||||||
|
@ -41,6 +40,10 @@ import org.schabi.newpipe.views.FocusOverlayView;
|
||||||
|
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import io.reactivex.rxjava3.disposables.Disposable;
|
||||||
|
|
||||||
|
import com.jakewharton.rxbinding4.widget.RxTextView;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Created by Christian Schabesberger on 31.08.15.
|
* Created by Christian Schabesberger on 31.08.15.
|
||||||
*
|
*
|
||||||
|
@ -84,6 +87,8 @@ public class SettingsActivity extends AppCompatActivity implements
|
||||||
@State
|
@State
|
||||||
boolean wasSearchActive;
|
boolean wasSearchActive;
|
||||||
|
|
||||||
|
private Disposable searchDisposable;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(final Bundle savedInstanceBundle) {
|
protected void onCreate(final Bundle savedInstanceBundle) {
|
||||||
setTheme(ThemeHelper.getSettingsThemeStyle(this));
|
setTheme(ThemeHelper.getSettingsThemeStyle(this));
|
||||||
|
@ -108,9 +113,7 @@ public class SettingsActivity extends AppCompatActivity implements
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
getSupportFragmentManager().beginTransaction()
|
showMainSettingsFragment();
|
||||||
.replace(R.id.settings_fragment_holder, new MainSettingsFragment())
|
|
||||||
.commit();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (DeviceUtils.isTv(this)) {
|
if (DeviceUtils.isTv(this)) {
|
||||||
|
@ -186,8 +189,18 @@ public class SettingsActivity extends AppCompatActivity implements
|
||||||
.commit();
|
.commit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void showMainSettingsFragment() {
|
||||||
|
getSupportFragmentManager().beginTransaction()
|
||||||
|
.replace(R.id.settings_fragment_holder, new MainSettingsFragment())
|
||||||
|
.commit();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onDestroy() {
|
protected void onDestroy() {
|
||||||
|
if (searchDisposable != null && !searchDisposable.isDisposed()) {
|
||||||
|
searchDisposable.dispose();
|
||||||
|
}
|
||||||
setMenuSearchItem(null);
|
setMenuSearchItem(null);
|
||||||
searchFragment = null;
|
searchFragment = null;
|
||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
|
@ -202,16 +215,43 @@ public class SettingsActivity extends AppCompatActivity implements
|
||||||
final SettingsLayoutBinding settingsLayoutBinding,
|
final SettingsLayoutBinding settingsLayoutBinding,
|
||||||
final boolean restored
|
final boolean restored
|
||||||
) {
|
) {
|
||||||
|
|
||||||
searchContainer =
|
searchContainer =
|
||||||
settingsLayoutBinding.settingsToolbarLayout.toolbar
|
settingsLayoutBinding.settingsToolbarLayout.toolbar
|
||||||
.findViewById(R.id.toolbar_search_container);
|
.findViewById(R.id.toolbar_search_container);
|
||||||
|
|
||||||
// Configure input field for search
|
// Configure input field for search
|
||||||
searchEditText = searchContainer.findViewById(R.id.toolbar_search_edit_text);
|
searchEditText = searchContainer.findViewById(R.id.toolbar_search_edit_text);
|
||||||
RxTextView.textChanges(searchEditText)
|
searchDisposable = RxTextView.textChanges(searchEditText)
|
||||||
|
// Ignore the initial empty state
|
||||||
|
.skipInitialValue()
|
||||||
// Wait some time after the last input before actually searching
|
// Wait some time after the last input before actually searching
|
||||||
.debounce(200, TimeUnit.MILLISECONDS)
|
.debounce(200, TimeUnit.MILLISECONDS)
|
||||||
.subscribe(v -> runOnUiThread(this::onSearchChanged));
|
.subscribe(charSequence -> runOnUiThread(() -> {
|
||||||
|
// Change Fragment based on search text
|
||||||
|
if (charSequence.length() > 0) {
|
||||||
|
if (searchFragment != null) {
|
||||||
|
if (!searchFragment.isAdded()) {
|
||||||
|
getSupportFragmentManager().beginTransaction()
|
||||||
|
.replace(R.id.settings_fragment_holder, searchFragment,
|
||||||
|
PreferenceSearchFragment.NAME)
|
||||||
|
.addToBackStack(PreferenceSearchFragment.NAME)
|
||||||
|
.commit();
|
||||||
|
} else {
|
||||||
|
showSettingsFragment(searchFragment);
|
||||||
|
}
|
||||||
|
onSearchChanged();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
final Fragment current = getSupportFragmentManager()
|
||||||
|
.findFragmentById(R.id.settings_fragment_holder);
|
||||||
|
if (!(current instanceof MainSettingsFragment)) {
|
||||||
|
getSupportFragmentManager()
|
||||||
|
.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
|
||||||
|
showMainSettingsFragment();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
// Configure clear button
|
// Configure clear button
|
||||||
searchContainer.findViewById(R.id.toolbar_search_clear)
|
searchContainer.findViewById(R.id.toolbar_search_clear)
|
||||||
|
@ -290,25 +330,36 @@ public class SettingsActivity extends AppCompatActivity implements
|
||||||
Log.d(TAG, "setSearchActive called active=" + active);
|
Log.d(TAG, "setSearchActive called active=" + active);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Only reset the text when activating search from the toolbar
|
||||||
|
if (active && !isSearchActive()) {
|
||||||
|
resetSearchText();
|
||||||
|
}
|
||||||
|
|
||||||
// Ignore if search is already in correct state
|
// Ignore if search is already in correct state
|
||||||
if (isSearchActive() == active) {
|
if (isSearchActive() == active) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
wasSearchActive = active;
|
wasSearchActive = active;
|
||||||
|
if (wasSearchActive) {
|
||||||
|
searchEditText.post(() -> {
|
||||||
|
searchEditText.requestFocus();
|
||||||
|
KeyboardUtil.showKeyboard(this, searchEditText);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
searchContainer.setVisibility(active ? View.VISIBLE : View.GONE);
|
searchContainer.setVisibility(active ? View.VISIBLE : View.GONE);
|
||||||
if (menuSearchItem != null) {
|
if (menuSearchItem != null) {
|
||||||
menuSearchItem.setVisible(!active);
|
menuSearchItem.setVisible(!active);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (active) {
|
if (active && searchText == null) {
|
||||||
getSupportFragmentManager()
|
showMainSettingsFragment();
|
||||||
.beginTransaction()
|
} else if (active) {
|
||||||
.add(FRAGMENT_HOLDER_ID, searchFragment, PreferenceSearchFragment.NAME)
|
// Only add if not already added
|
||||||
.addToBackStack(PreferenceSearchFragment.NAME)
|
if (!searchFragment.isAdded()) {
|
||||||
.commit();
|
showSettingsFragment(searchFragment);
|
||||||
|
}
|
||||||
KeyboardUtil.showKeyboard(this, searchEditText);
|
KeyboardUtil.showKeyboard(this, searchEditText);
|
||||||
} else if (searchFragment != null) {
|
} else if (searchFragment != null) {
|
||||||
hideSearchFragment();
|
hideSearchFragment();
|
||||||
|
@ -319,8 +370,6 @@ public class SettingsActivity extends AppCompatActivity implements
|
||||||
|
|
||||||
KeyboardUtil.hideKeyboard(this, searchEditText);
|
KeyboardUtil.hideKeyboard(this, searchEditText);
|
||||||
}
|
}
|
||||||
|
|
||||||
resetSearchText();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void hideSearchFragment() {
|
private void hideSearchFragment() {
|
||||||
|
@ -384,5 +433,18 @@ public class SettingsActivity extends AppCompatActivity implements
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Functions needed for testing
|
||||||
|
protected EditText getSearchEditText() {
|
||||||
|
return searchEditText;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMockEditText(final EditText editText) {
|
||||||
|
this.searchEditText = editText;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static int getFragmentHolderId() {
|
||||||
|
return FRAGMENT_HOLDER_ID;
|
||||||
|
}
|
||||||
|
|
||||||
//endregion
|
//endregion
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,6 @@
|
||||||
package org.schabi.newpipe.settings.preferencesearch;
|
package org.schabi.newpipe.settings.preferencesearch;
|
||||||
|
|
||||||
import android.text.TextUtils;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@ -21,9 +18,6 @@ public class PreferenceSearcher {
|
||||||
}
|
}
|
||||||
|
|
||||||
List<PreferenceSearchItem> searchFor(final String keyword) {
|
List<PreferenceSearchItem> searchFor(final String keyword) {
|
||||||
if (TextUtils.isEmpty(keyword)) {
|
|
||||||
return Collections.emptyList();
|
|
||||||
}
|
|
||||||
|
|
||||||
return configuration.getSearcher()
|
return configuration.getSearcher()
|
||||||
.search(allEntries.stream(), keyword)
|
.search(allEntries.stream(), keyword)
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
|
android:clickable="true"
|
||||||
android:visibility="gone"
|
android:visibility="gone"
|
||||||
tools:visibility="gone">
|
tools:visibility="gone">
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,71 @@
|
||||||
|
package org.schabi.newpipe.settings;
|
||||||
|
|
||||||
|
import android.widget.EditText;
|
||||||
|
|
||||||
|
import androidx.fragment.app.Fragment;
|
||||||
|
import androidx.fragment.app.FragmentManager;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.mockito.Mockito;
|
||||||
|
import org.schabi.newpipe.settings.preferencesearch.PreferenceSearchFragment;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static org.mockito.ArgumentMatchers.anyInt;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
public class SettingsActivityTest {
|
||||||
|
|
||||||
|
private SettingsActivity activity;
|
||||||
|
private FragmentManager fragmentManager;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
activity = Mockito.spy(new SettingsActivity());
|
||||||
|
fragmentManager = Mockito.mock(FragmentManager.class);
|
||||||
|
Mockito.doReturn(fragmentManager).when(activity).getSupportFragmentManager();
|
||||||
|
// Mock the searchEditText
|
||||||
|
final EditText editText = Mockito.mock(EditText.class);
|
||||||
|
activity.setMockEditText(editText);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void mainSettingsFragmentDisplayedWhenSearchInactive() {
|
||||||
|
when(fragmentManager.findFragmentById(anyInt()))
|
||||||
|
.thenReturn(new MainSettingsFragment());
|
||||||
|
|
||||||
|
activity.setSearchActive(false);
|
||||||
|
|
||||||
|
final Fragment fragment = activity.getSupportFragmentManager()
|
||||||
|
.findFragmentById(SettingsActivity.getFragmentHolderId());
|
||||||
|
assertTrue(fragment instanceof MainSettingsFragment);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void preferenceSearchFragmentDisplayedWhenSearchActiveAndTextNotEmpty() {
|
||||||
|
when(fragmentManager.findFragmentById(anyInt()))
|
||||||
|
.thenReturn(new PreferenceSearchFragment());
|
||||||
|
|
||||||
|
activity.setSearchActive(true);
|
||||||
|
Mockito.when(activity.getSearchEditText().getText())
|
||||||
|
.thenReturn(new android.text.SpannableStringBuilder("query"));
|
||||||
|
|
||||||
|
final Fragment fragment = activity.getSupportFragmentManager()
|
||||||
|
.findFragmentById(SettingsActivity.getFragmentHolderId());
|
||||||
|
assertTrue(fragment instanceof PreferenceSearchFragment);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void mainSettingsFragmentDisplayedWhenSearchActiveButTextEmpty() {
|
||||||
|
when(fragmentManager.findFragmentById(anyInt()))
|
||||||
|
.thenReturn(new MainSettingsFragment());
|
||||||
|
|
||||||
|
activity.setSearchActive(true);
|
||||||
|
Mockito.when(activity.getSearchEditText().getText())
|
||||||
|
.thenReturn(new android.text.SpannableStringBuilder(""));
|
||||||
|
|
||||||
|
final Fragment fragment = activity.getSupportFragmentManager()
|
||||||
|
.findFragmentById(SettingsActivity.getFragmentHolderId());
|
||||||
|
assertTrue(fragment instanceof MainSettingsFragment);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue