Merge branch 'dev' into pr2335
This commit is contained in:
commit
d5cfcb28fc
110 changed files with 645 additions and 487 deletions
|
|
@ -1,79 +0,0 @@
|
|||
package org.schabi.newpipe.database.history.model;
|
||||
|
||||
import androidx.room.ColumnInfo;
|
||||
import androidx.room.Entity;
|
||||
import androidx.room.Ignore;
|
||||
import androidx.room.Index;
|
||||
import androidx.room.PrimaryKey;
|
||||
|
||||
import java.time.OffsetDateTime;
|
||||
|
||||
import static org.schabi.newpipe.database.history.model.SearchHistoryEntry.SEARCH;
|
||||
|
||||
@Entity(tableName = SearchHistoryEntry.TABLE_NAME,
|
||||
indices = {@Index(value = SEARCH)})
|
||||
public class SearchHistoryEntry {
|
||||
public static final String ID = "id";
|
||||
public static final String TABLE_NAME = "search_history";
|
||||
public static final String SERVICE_ID = "service_id";
|
||||
public static final String CREATION_DATE = "creation_date";
|
||||
public static final String SEARCH = "search";
|
||||
|
||||
@ColumnInfo(name = ID)
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
private long id;
|
||||
|
||||
@ColumnInfo(name = CREATION_DATE)
|
||||
private OffsetDateTime creationDate;
|
||||
|
||||
@ColumnInfo(name = SERVICE_ID)
|
||||
private int serviceId;
|
||||
|
||||
@ColumnInfo(name = SEARCH)
|
||||
private String search;
|
||||
|
||||
public SearchHistoryEntry(final OffsetDateTime creationDate, final int serviceId,
|
||||
final String search) {
|
||||
this.serviceId = serviceId;
|
||||
this.creationDate = creationDate;
|
||||
this.search = search;
|
||||
}
|
||||
|
||||
public long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(final long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public OffsetDateTime getCreationDate() {
|
||||
return creationDate;
|
||||
}
|
||||
|
||||
public void setCreationDate(final OffsetDateTime creationDate) {
|
||||
this.creationDate = creationDate;
|
||||
}
|
||||
|
||||
public int getServiceId() {
|
||||
return serviceId;
|
||||
}
|
||||
|
||||
public void setServiceId(final int serviceId) {
|
||||
this.serviceId = serviceId;
|
||||
}
|
||||
|
||||
public String getSearch() {
|
||||
return search;
|
||||
}
|
||||
|
||||
public void setSearch(final String search) {
|
||||
this.search = search;
|
||||
}
|
||||
|
||||
@Ignore
|
||||
public boolean hasEqualValues(final SearchHistoryEntry otherEntry) {
|
||||
return getServiceId() == otherEntry.getServiceId()
|
||||
&& getSearch().equals(otherEntry.getSearch());
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
package org.schabi.newpipe.database.history.model
|
||||
|
||||
import androidx.room.ColumnInfo
|
||||
import androidx.room.Entity
|
||||
import androidx.room.Ignore
|
||||
import androidx.room.Index
|
||||
import androidx.room.PrimaryKey
|
||||
import java.time.OffsetDateTime
|
||||
|
||||
@Entity(
|
||||
tableName = SearchHistoryEntry.TABLE_NAME,
|
||||
indices = [Index(value = [SearchHistoryEntry.SEARCH])]
|
||||
)
|
||||
data class SearchHistoryEntry(
|
||||
@field:ColumnInfo(name = CREATION_DATE) var creationDate: OffsetDateTime?,
|
||||
@field:ColumnInfo(
|
||||
name = SERVICE_ID
|
||||
) var serviceId: Int,
|
||||
@field:ColumnInfo(name = SEARCH) var search: String?
|
||||
) {
|
||||
@ColumnInfo(name = ID)
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
var id: Long = 0
|
||||
|
||||
@Ignore
|
||||
fun hasEqualValues(otherEntry: SearchHistoryEntry): Boolean {
|
||||
return (
|
||||
serviceId == otherEntry.serviceId &&
|
||||
search == otherEntry.search
|
||||
)
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val ID = "id"
|
||||
const val TABLE_NAME = "search_history"
|
||||
const val SERVICE_ID = "service_id"
|
||||
const val CREATION_DATE = "creation_date"
|
||||
const val SEARCH = "search"
|
||||
}
|
||||
}
|
||||
|
|
@ -1098,6 +1098,11 @@ public final class VideoDetailFragment
|
|||
|
||||
toggleFullscreenIfInFullscreenMode();
|
||||
|
||||
if (isPlayerAvailable()) {
|
||||
// FIXME Workaround #7427
|
||||
player.setRecovery();
|
||||
}
|
||||
|
||||
if (!useExternalAudioPlayer) {
|
||||
openNormalBackgroundPlayer(append);
|
||||
} else {
|
||||
|
|
@ -1114,6 +1119,9 @@ public final class VideoDetailFragment
|
|||
// See UI changes while remote playQueue changes
|
||||
if (!isPlayerAvailable()) {
|
||||
playerHolder.startService(false, this);
|
||||
} else {
|
||||
// FIXME Workaround #7427
|
||||
player.setRecovery();
|
||||
}
|
||||
|
||||
toggleFullscreenIfInFullscreenMode();
|
||||
|
|
@ -2208,12 +2216,20 @@ public final class VideoDetailFragment
|
|||
mainFragment.setDescendantFocusability(afterDescendants);
|
||||
toolbar.setDescendantFocusability(afterDescendants);
|
||||
((ViewGroup) requireView()).setDescendantFocusability(blockDescendants);
|
||||
mainFragment.requestFocus();
|
||||
// Only focus the mainFragment if the mainFragment (e.g. search-results)
|
||||
// or the toolbar (e.g. Textfield for search) don't have focus.
|
||||
// This was done to fix problems with the keyboard input, see also #7490
|
||||
if (!mainFragment.hasFocus() && !toolbar.hasFocus()) {
|
||||
mainFragment.requestFocus();
|
||||
}
|
||||
} else {
|
||||
mainFragment.setDescendantFocusability(blockDescendants);
|
||||
toolbar.setDescendantFocusability(blockDescendants);
|
||||
((ViewGroup) requireView()).setDescendantFocusability(afterDescendants);
|
||||
binding.detailThumbnailRootLayout.requestFocus();
|
||||
// Only focus the player if it not already has focus
|
||||
if (!binding.getRoot().hasFocus()) {
|
||||
binding.detailThumbnailRootLayout.requestFocus();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -268,7 +268,10 @@ public class PlaylistFragment extends BaseListInfoFragment<PlaylistInfo> {
|
|||
ShareUtils.openUrlInBrowser(requireContext(), url);
|
||||
break;
|
||||
case R.id.menu_item_share:
|
||||
ShareUtils.shareText(requireContext(), name, url, currentInfo.getThumbnailUrl());
|
||||
if (currentInfo != null) {
|
||||
ShareUtils.shareText(requireContext(), name, url,
|
||||
currentInfo.getThumbnailUrl());
|
||||
}
|
||||
break;
|
||||
case R.id.menu_item_bookmark:
|
||||
onBookmarkClicked();
|
||||
|
|
|
|||
|
|
@ -271,7 +271,7 @@ class FeedFragment : BaseStateFragment<FeedState>() {
|
|||
|
||||
override fun onDestroyView() {
|
||||
// Ensure that all animations are canceled
|
||||
feedBinding.newItemsLoadedButton?.clearAnimation()
|
||||
tryGetNewItemsLoadedButton()?.clearAnimation()
|
||||
|
||||
feedBinding.itemsList.adapter = null
|
||||
_feedBinding = null
|
||||
|
|
|
|||
|
|
@ -635,6 +635,7 @@ public final class Player implements
|
|||
final boolean isMuted = intent.getBooleanExtra(IS_MUTED, isMuted());
|
||||
|
||||
/*
|
||||
* TODO As seen in #7427 this does not work:
|
||||
* There are 3 situations when playback shouldn't be started from scratch (zero timestamp):
|
||||
* 1. User pressed on a timestamp link and the same video should be rewound to the timestamp
|
||||
* 2. User changed a player from, for example. main to popup, or from audio to main, etc
|
||||
|
|
|
|||
|
|
@ -157,9 +157,8 @@ public final class NavigationHelper {
|
|||
return;
|
||||
}
|
||||
|
||||
if (PlayerHolder.getInstance().getType() != PlayerType.POPUP) {
|
||||
Toast.makeText(context, R.string.popup_playing_toast, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
Toast.makeText(context, R.string.popup_playing_toast, Toast.LENGTH_SHORT).show();
|
||||
|
||||
final Intent intent = getPlayerIntent(context, MainPlayer.class, queue, resumePlayback);
|
||||
intent.putExtra(Player.PLAYER_TYPE, MainPlayer.PlayerType.POPUP.ordinal());
|
||||
ContextCompat.startForegroundService(context, intent);
|
||||
|
|
@ -168,12 +167,7 @@ public final class NavigationHelper {
|
|||
public static void playOnBackgroundPlayer(final Context context,
|
||||
final PlayQueue queue,
|
||||
final boolean resumePlayback) {
|
||||
Toast.makeText(
|
||||
context,
|
||||
PlayerHolder.getInstance().getType() == PlayerType.AUDIO
|
||||
? R.string.background_player_already_playing_toast
|
||||
: R.string.background_player_playing_toast,
|
||||
Toast.LENGTH_SHORT)
|
||||
Toast.makeText(context, R.string.background_player_playing_toast, Toast.LENGTH_SHORT)
|
||||
.show();
|
||||
|
||||
final Intent intent = getPlayerIntent(context, MainPlayer.class, queue, resumePlayback);
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package org.schabi.newpipe.util;
|
|||
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
import android.util.Log;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
|
@ -21,6 +22,7 @@ import org.schabi.newpipe.util.external_communication.ShareUtils;
|
|||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.rxjava3.schedulers.Schedulers;
|
||||
|
|
@ -63,20 +65,24 @@ public enum StreamDialogEntry {
|
|||
* Info: Add this entry within showStreamDialog.
|
||||
*/
|
||||
enqueue(R.string.enqueue_stream, (fragment, item) -> {
|
||||
NavigationHelper.enqueueOnPlayer(fragment.getContext(), new SinglePlayQueue(item));
|
||||
fetchItemInfoIfSparse(fragment, item, fullItem ->
|
||||
NavigationHelper.enqueueOnPlayer(fragment.getContext(), fullItem));
|
||||
}),
|
||||
|
||||
enqueue_next(R.string.enqueue_next_stream, (fragment, item) -> {
|
||||
NavigationHelper.enqueueNextOnPlayer(fragment.getContext(), new SinglePlayQueue(item));
|
||||
fetchItemInfoIfSparse(fragment, item, fullItem ->
|
||||
NavigationHelper.enqueueNextOnPlayer(fragment.getContext(), fullItem));
|
||||
}),
|
||||
|
||||
start_here_on_background(R.string.start_here_on_background, (fragment, item) ->
|
||||
NavigationHelper.playOnBackgroundPlayer(fragment.getContext(),
|
||||
new SinglePlayQueue(item), true)),
|
||||
start_here_on_background(R.string.start_here_on_background, (fragment, item) -> {
|
||||
fetchItemInfoIfSparse(fragment, item, fullItem ->
|
||||
NavigationHelper.playOnBackgroundPlayer(fragment.getContext(), fullItem, true));
|
||||
}),
|
||||
|
||||
start_here_on_popup(R.string.start_here_on_popup, (fragment, item) ->
|
||||
NavigationHelper.playOnPopupPlayer(fragment.getContext(),
|
||||
new SinglePlayQueue(item), true)),
|
||||
start_here_on_popup(R.string.start_here_on_popup, (fragment, item) -> {
|
||||
fetchItemInfoIfSparse(fragment, item, fullItem ->
|
||||
NavigationHelper.playOnPopupPlayer(fragment.getContext(), fullItem, true));
|
||||
}),
|
||||
|
||||
set_as_playlist_thumbnail(R.string.set_as_playlist_thumbnail, (fragment, item) -> {
|
||||
}), // has to be set manually
|
||||
|
|
@ -218,4 +224,39 @@ public enum StreamDialogEntry {
|
|||
fragment.requireActivity().getSupportFragmentManager(),
|
||||
item.getServiceId(), uploaderUrl, item.getUploaderName());
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////
|
||||
// helper functions //
|
||||
/////////////////////////////////////////////
|
||||
|
||||
private static void fetchItemInfoIfSparse(final Fragment fragment,
|
||||
final StreamInfoItem item,
|
||||
final Consumer<SinglePlayQueue> callback) {
|
||||
if (!(item.getStreamType() == StreamType.LIVE_STREAM
|
||||
|| item.getStreamType() == StreamType.AUDIO_LIVE_STREAM)
|
||||
&& item.getDuration() < 0) {
|
||||
// Sparse item: fetched by fast fetch
|
||||
ExtractorHelper.getStreamInfo(
|
||||
item.getServiceId(),
|
||||
item.getUrl(),
|
||||
false
|
||||
)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(result -> {
|
||||
final HistoryRecordManager recordManager =
|
||||
new HistoryRecordManager(fragment.getContext());
|
||||
recordManager.saveStreamState(result, 0)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.doOnError(throwable -> Log.e("StreamDialogEntry",
|
||||
throwable.toString()))
|
||||
.subscribe();
|
||||
|
||||
callback.accept(new SinglePlayQueue(result));
|
||||
}, throwable -> Log.e("StreamDialogEntry", throwable.toString()));
|
||||
} else {
|
||||
callback.accept(new SinglePlayQueue(item));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue