Merge branch 'dev' into bumpRoom

This commit is contained in:
Stypox 2022-08-04 10:40:09 +02:00 committed by GitHub
commit 7972678fe6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 84 additions and 71 deletions

View File

@ -97,12 +97,12 @@ android {
ext { ext {
checkstyleVersion = '10.3.1' checkstyleVersion = '10.3.1'
androidxLifecycleVersion = '2.3.1' androidxLifecycleVersion = '2.5.1'
androidxRoomVersion = '2.4.3' androidxRoomVersion = '2.4.3'
androidxWorkVersion = '2.7.1' androidxWorkVersion = '2.7.1'
icepickVersion = '3.2.0' icepickVersion = '3.2.0'
exoPlayerVersion = '2.18.0' exoPlayerVersion = '2.18.1'
googleAutoServiceVersion = '1.0.1' googleAutoServiceVersion = '1.0.1'
groupieVersion = '2.10.1' groupieVersion = '2.10.1'
markwonVersion = '4.6.2' markwonVersion = '4.6.2'
@ -197,14 +197,14 @@ dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:${kotlin_version}" implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:${kotlin_version}"
/** AndroidX **/ /** AndroidX **/
implementation 'androidx.appcompat:appcompat:1.3.1' implementation 'androidx.appcompat:appcompat:1.4.2'
implementation 'androidx.cardview:cardview:1.0.0' implementation 'androidx.cardview:cardview:1.0.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4' implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation 'androidx.core:core-ktx:1.8.0' implementation 'androidx.core:core-ktx:1.8.0'
implementation 'androidx.documentfile:documentfile:1.0.1' implementation 'androidx.documentfile:documentfile:1.0.1'
implementation 'androidx.fragment:fragment-ktx:1.3.6' implementation 'androidx.fragment:fragment-ktx:1.4.1'
implementation "androidx.lifecycle:lifecycle-livedata:${androidxLifecycleVersion}" implementation "androidx.lifecycle:lifecycle-livedata-ktx:${androidxLifecycleVersion}"
implementation "androidx.lifecycle:lifecycle-viewmodel:${androidxLifecycleVersion}" implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:${androidxLifecycleVersion}"
implementation 'androidx.localbroadcastmanager:localbroadcastmanager:1.1.0' implementation 'androidx.localbroadcastmanager:localbroadcastmanager:1.1.0'
implementation 'androidx.media:media:1.6.0' implementation 'androidx.media:media:1.6.0'
implementation 'androidx.preference:preference:1.2.0' implementation 'androidx.preference:preference:1.2.0'
@ -218,7 +218,7 @@ dependencies {
implementation 'androidx.viewpager2:viewpager2:1.1.0-beta01' implementation 'androidx.viewpager2:viewpager2:1.1.0-beta01'
implementation "androidx.work:work-runtime-ktx:${androidxWorkVersion}" implementation "androidx.work:work-runtime-ktx:${androidxWorkVersion}"
implementation "androidx.work:work-rxjava3:${androidxWorkVersion}" implementation "androidx.work:work-rxjava3:${androidxWorkVersion}"
implementation 'com.google.android.material:material:1.5.0' implementation 'com.google.android.material:material:1.6.1'
/** Third-party libraries **/ /** Third-party libraries **/
// Instance state boilerplate elimination // Instance state boilerplate elimination

View File

@ -14,8 +14,6 @@ import org.schabi.newpipe.extractor.exceptions.ExtractionException
import org.schabi.newpipe.extractor.services.youtube.extractors.YoutubeStreamExtractor.DeobfuscateException import org.schabi.newpipe.extractor.services.youtube.extractors.YoutubeStreamExtractor.DeobfuscateException
import org.schabi.newpipe.ktx.isNetworkRelated import org.schabi.newpipe.ktx.isNetworkRelated
import org.schabi.newpipe.util.ServiceHelper import org.schabi.newpipe.util.ServiceHelper
import java.io.PrintWriter
import java.io.StringWriter
@Parcelize @Parcelize
class ErrorInfo( class ErrorInfo(
@ -80,19 +78,10 @@ class ErrorInfo(
companion object { companion object {
const val SERVICE_NONE = "none" const val SERVICE_NONE = "none"
private fun getStackTrace(throwable: Throwable): String { fun throwableToStringList(throwable: Throwable) = arrayOf(throwable.stackTraceToString())
StringWriter().use { stringWriter ->
PrintWriter(stringWriter, true).use { printWriter ->
throwable.printStackTrace(printWriter)
return stringWriter.buffer.toString()
}
}
}
fun throwableToStringList(throwable: Throwable) = arrayOf(getStackTrace(throwable)) fun throwableListToStringList(throwableList: List<Throwable>) =
throwableList.map { it.stackTraceToString() }.toTypedArray()
fun throwableListToStringList(throwable: List<Throwable>) =
Array(throwable.size) { i -> getStackTrace(throwable[i]) }
private fun getInfoServiceName(info: Info?) = private fun getInfoServiceName(info: Info?) =
if (info == null) SERVICE_NONE else ServiceHelper.getNameOfServiceById(info.serviceId) if (info == null) SERVICE_NONE else ServiceHelper.getNameOfServiceById(info.serviceId)

View File

@ -202,10 +202,9 @@ public class DescriptionFragment extends BaseFragment {
private void addTagsMetadataItem(final LayoutInflater inflater, final LinearLayout layout) { private void addTagsMetadataItem(final LayoutInflater inflater, final LinearLayout layout) {
if (streamInfo.getTags() != null && !streamInfo.getTags().isEmpty()) { if (streamInfo.getTags() != null && !streamInfo.getTags().isEmpty()) {
final ItemMetadataTagsBinding itemBinding = final var itemBinding = ItemMetadataTagsBinding.inflate(inflater, layout, false);
ItemMetadataTagsBinding.inflate(inflater, layout, false);
streamInfo.getTags().stream().sorted().forEach(tag -> { streamInfo.getTags().stream().sorted(String.CASE_INSENSITIVE_ORDER).forEach(tag -> {
final Chip chip = (Chip) inflater.inflate(R.layout.chip, final Chip chip = (Chip) inflater.inflate(R.layout.chip,
itemBinding.metadataTagsChips, false); itemBinding.metadataTagsChips, false);
chip.setText(tag); chip.setText(tag);

View File

@ -21,7 +21,6 @@ import android.content.SharedPreferences;
import android.content.pm.ActivityInfo; import android.content.pm.ActivityInfo;
import android.database.ContentObserver; import android.database.ContentObserver;
import android.graphics.Color; import android.graphics.Color;
import android.graphics.Point;
import android.graphics.Rect; import android.graphics.Rect;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.net.Uri; import android.net.Uri;
@ -1051,15 +1050,13 @@ public final class VideoDetailFragment
// call `post()` to be sure `viewPager.getHitRect()` // call `post()` to be sure `viewPager.getHitRect()`
// is up to date and not being currently recomputed // is up to date and not being currently recomputed
binding.tabLayout.post(() -> { binding.tabLayout.post(() -> {
if (getContext() != null) { final var activity = getActivity();
if (activity != null) {
final Rect pagerHitRect = new Rect(); final Rect pagerHitRect = new Rect();
binding.viewPager.getHitRect(pagerHitRect); binding.viewPager.getHitRect(pagerHitRect);
final Point displaySize = new Point(); final int height = DeviceUtils.getWindowHeight(activity.getWindowManager());
Objects.requireNonNull(ContextCompat.getSystemService(getContext(), final int viewPagerVisibleHeight = height - pagerHitRect.top;
WindowManager.class)).getDefaultDisplay().getSize(displaySize);
final int viewPagerVisibleHeight = displaySize.y - pagerHitRect.top;
// see TabLayout.DEFAULT_HEIGHT, which is equal to 48dp // see TabLayout.DEFAULT_HEIGHT, which is equal to 48dp
final float tabLayoutHeight = TypedValue.applyDimension( final float tabLayoutHeight = TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP, 48, getResources().getDisplayMetrics()); TypedValue.COMPLEX_UNIT_DIP, 48, getResources().getDisplayMetrics());
@ -1312,9 +1309,11 @@ public final class VideoDetailFragment
// Prevent from re-adding a view multiple times // Prevent from re-adding a view multiple times
new Handler(Looper.getMainLooper()).post(() -> new Handler(Looper.getMainLooper()).post(() ->
player.UIs().get(MainPlayerUi.class).ifPresent(playerUi -> { player.UIs().get(MainPlayerUi.class).ifPresent(playerUi -> {
playerUi.removeViewFromParent(); if (binding != null) {
binding.playerPlaceholder.addView(playerUi.getBinding().getRoot()); playerUi.removeViewFromParent();
playerUi.setupVideoSurfaceIfNeeded(); binding.playerPlaceholder.addView(playerUi.getBinding().getRoot());
playerUi.setupVideoSurfaceIfNeeded();
}
})); }));
} }

View File

@ -135,8 +135,8 @@ class FeedFragment : BaseStateFragment<FeedState>() {
_feedBinding = FragmentFeedBinding.bind(rootView) _feedBinding = FragmentFeedBinding.bind(rootView)
super.onViewCreated(rootView, savedInstanceState) super.onViewCreated(rootView, savedInstanceState)
val factory = FeedViewModel.Factory(requireContext(), groupId) val factory = FeedViewModel.getFactory(requireContext(), groupId)
viewModel = ViewModelProvider(this, factory).get(FeedViewModel::class.java) viewModel = ViewModelProvider(this, factory)[FeedViewModel::class.java]
showPlayedItems = viewModel.getShowPlayedItemsFromPreferences() showPlayedItems = viewModel.getShowPlayedItemsFromPreferences()
showFutureItems = viewModel.getShowFutureItemsFromPreferences() showFutureItems = viewModel.getShowFutureItemsFromPreferences()
viewModel.stateLiveData.observe(viewLifecycleOwner) { it?.let(::handleResult) } viewModel.stateLiveData.observe(viewLifecycleOwner) { it?.let(::handleResult) }

View File

@ -1,17 +1,20 @@
package org.schabi.newpipe.local.feed package org.schabi.newpipe.local.feed
import android.app.Application
import android.content.Context import android.content.Context
import androidx.core.content.edit import androidx.core.content.edit
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.viewmodel.initializer
import androidx.lifecycle.viewmodel.viewModelFactory
import androidx.preference.PreferenceManager import androidx.preference.PreferenceManager
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.core.Flowable import io.reactivex.rxjava3.core.Flowable
import io.reactivex.rxjava3.functions.Function5 import io.reactivex.rxjava3.functions.Function5
import io.reactivex.rxjava3.processors.BehaviorProcessor import io.reactivex.rxjava3.processors.BehaviorProcessor
import io.reactivex.rxjava3.schedulers.Schedulers import io.reactivex.rxjava3.schedulers.Schedulers
import org.schabi.newpipe.App
import org.schabi.newpipe.R import org.schabi.newpipe.R
import org.schabi.newpipe.database.feed.model.FeedGroupEntity import org.schabi.newpipe.database.feed.model.FeedGroupEntity
import org.schabi.newpipe.database.stream.StreamWithState import org.schabi.newpipe.database.stream.StreamWithState
@ -26,12 +29,12 @@ import java.time.OffsetDateTime
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
class FeedViewModel( class FeedViewModel(
private val applicationContext: Context, private val application: Application,
groupId: Long = FeedGroupEntity.GROUP_ALL_ID, groupId: Long = FeedGroupEntity.GROUP_ALL_ID,
initialShowPlayedItems: Boolean = true, initialShowPlayedItems: Boolean = true,
initialShowFutureItems: Boolean = true initialShowFutureItems: Boolean = true
) : ViewModel() { ) : ViewModel() {
private var feedDatabaseManager: FeedDatabaseManager = FeedDatabaseManager(applicationContext) private val feedDatabaseManager = FeedDatabaseManager(application)
private val toggleShowPlayedItems = BehaviorProcessor.create<Boolean>() private val toggleShowPlayedItems = BehaviorProcessor.create<Boolean>()
private val toggleShowPlayedItemsFlowable = toggleShowPlayedItems private val toggleShowPlayedItemsFlowable = toggleShowPlayedItems
@ -113,24 +116,24 @@ class FeedViewModel(
} }
fun saveShowPlayedItemsToPreferences(showPlayedItems: Boolean) = fun saveShowPlayedItemsToPreferences(showPlayedItems: Boolean) =
PreferenceManager.getDefaultSharedPreferences(applicationContext).edit { PreferenceManager.getDefaultSharedPreferences(application).edit {
this.putBoolean(applicationContext.getString(R.string.feed_show_played_items_key), showPlayedItems) this.putBoolean(application.getString(R.string.feed_show_played_items_key), showPlayedItems)
this.apply() this.apply()
} }
fun getShowPlayedItemsFromPreferences() = getShowPlayedItemsFromPreferences(applicationContext) fun getShowPlayedItemsFromPreferences() = getShowPlayedItemsFromPreferences(application)
fun toggleFutureItems(showFutureItems: Boolean) { fun toggleFutureItems(showFutureItems: Boolean) {
toggleShowFutureItems.onNext(showFutureItems) toggleShowFutureItems.onNext(showFutureItems)
} }
fun saveShowFutureItemsToPreferences(showFutureItems: Boolean) = fun saveShowFutureItemsToPreferences(showFutureItems: Boolean) =
PreferenceManager.getDefaultSharedPreferences(applicationContext).edit { PreferenceManager.getDefaultSharedPreferences(application).edit {
this.putBoolean(applicationContext.getString(R.string.feed_show_future_items_key), showFutureItems) this.putBoolean(application.getString(R.string.feed_show_future_items_key), showFutureItems)
this.apply() this.apply()
} }
fun getShowFutureItemsFromPreferences() = getShowFutureItemsFromPreferences(applicationContext) fun getShowFutureItemsFromPreferences() = getShowFutureItemsFromPreferences(application)
companion object { companion object {
private fun getShowPlayedItemsFromPreferences(context: Context) = private fun getShowPlayedItemsFromPreferences(context: Context) =
@ -139,21 +142,16 @@ class FeedViewModel(
private fun getShowFutureItemsFromPreferences(context: Context) = private fun getShowFutureItemsFromPreferences(context: Context) =
PreferenceManager.getDefaultSharedPreferences(context) PreferenceManager.getDefaultSharedPreferences(context)
.getBoolean(context.getString(R.string.feed_show_future_items_key), true) .getBoolean(context.getString(R.string.feed_show_future_items_key), true)
} fun getFactory(context: Context, groupId: Long) = viewModelFactory {
initializer {
class Factory( FeedViewModel(
private val context: Context, App.getApp(),
private val groupId: Long = FeedGroupEntity.GROUP_ALL_ID groupId,
) : ViewModelProvider.Factory { // Read initial value from preferences
@Suppress("UNCHECKED_CAST") getShowPlayedItemsFromPreferences(context.applicationContext),
override fun <T : ViewModel?> create(modelClass: Class<T>): T { getShowFutureItemsFromPreferences(context.applicationContext)
return FeedViewModel( )
context.applicationContext, }
groupId,
// Read initial value from preferences
getShowPlayedItemsFromPreferences(context.applicationContext),
getShowFutureItemsFromPreferences(context.applicationContext)
) as T
} }
} }
} }

View File

@ -122,7 +122,7 @@ class FeedGroupDialogViewModel(
private val initialShowOnlyUngrouped: Boolean = false private val initialShowOnlyUngrouped: Boolean = false
) : ViewModelProvider.Factory { ) : ViewModelProvider.Factory {
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
override fun <T : ViewModel?> create(modelClass: Class<T>): T { override fun <T : ViewModel> create(modelClass: Class<T>): T {
return FeedGroupDialogViewModel( return FeedGroupDialogViewModel(
context.applicationContext, context.applicationContext,
groupId, initialQuery, initialShowOnlyUngrouped groupId, initialQuery, initialShowOnlyUngrouped

View File

@ -1,5 +1,5 @@
/* /*
* Based on ExoPlayer's DefaultHttpDataSource, version 2.18.0. * Based on ExoPlayer's DefaultHttpDataSource, version 2.18.1.
* *
* Original source code copyright (C) 2016 The Android Open Source Project, licensed under the * Original source code copyright (C) 2016 The Android Open Source Project, licensed under the
* Apache License, Version 2.0. * Apache License, Version 2.0.

View File

@ -8,6 +8,7 @@ import android.view.View;
import android.widget.FrameLayout; import android.widget.FrameLayout;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.coordinatorlayout.widget.CoordinatorLayout; import androidx.coordinatorlayout.widget.CoordinatorLayout;
import com.google.android.material.bottomsheet.BottomSheetBehavior; import com.google.android.material.bottomsheet.BottomSheetBehavior;
@ -18,7 +19,8 @@ import java.util.List;
public class CustomBottomSheetBehavior extends BottomSheetBehavior<FrameLayout> { public class CustomBottomSheetBehavior extends BottomSheetBehavior<FrameLayout> {
public CustomBottomSheetBehavior(final Context context, final AttributeSet attrs) { public CustomBottomSheetBehavior(@NonNull final Context context,
@Nullable final AttributeSet attrs) {
super(context, attrs); super(context, attrs);
} }
@ -32,7 +34,7 @@ public class CustomBottomSheetBehavior extends BottomSheetBehavior<FrameLayout>
@Override @Override
public boolean onInterceptTouchEvent(@NonNull final CoordinatorLayout parent, public boolean onInterceptTouchEvent(@NonNull final CoordinatorLayout parent,
@NonNull final FrameLayout child, @NonNull final FrameLayout child,
final MotionEvent event) { @NonNull final MotionEvent event) {
// Drop following when action ends // Drop following when action ends
if (event.getAction() == MotionEvent.ACTION_CANCEL if (event.getAction() == MotionEvent.ACTION_CANCEL
|| event.getAction() == MotionEvent.ACTION_UP) { || event.getAction() == MotionEvent.ACTION_UP) {

View File

@ -11,7 +11,6 @@ import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable; import android.graphics.drawable.LayerDrawable;
import android.os.Bundle; import android.os.Bundle;
import android.util.Log; import android.util.Log;
import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.widget.CheckBox; import android.widget.CheckBox;
import android.widget.SeekBar; import android.widget.SeekBar;
@ -149,7 +148,7 @@ public class PlaybackParameterDialog extends DialogFragment {
assureCorrectAppLanguage(getContext()); assureCorrectAppLanguage(getContext());
Icepick.restoreInstanceState(this, savedInstanceState); Icepick.restoreInstanceState(this, savedInstanceState);
binding = DialogPlaybackParameterBinding.inflate(LayoutInflater.from(getContext())); binding = DialogPlaybackParameterBinding.inflate(getLayoutInflater());
initUI(); initUI();
final AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(requireActivity()) final AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(requireActivity())

View File

@ -21,6 +21,7 @@ import android.view.LayoutInflater;
import android.view.MotionEvent; import android.view.MotionEvent;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.view.WindowInsets;
import android.view.WindowManager; import android.view.WindowManager;
import android.view.animation.AnticipateInterpolator; import android.view.animation.AnticipateInterpolator;
import android.widget.LinearLayout; import android.widget.LinearLayout;
@ -255,11 +256,20 @@ public final class PopupPlayerUi extends VideoPlayerUi {
} }
public void updateScreenSize() { public void updateScreenSize() {
final DisplayMetrics metrics = new DisplayMetrics(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
windowManager.getDefaultDisplay().getMetrics(metrics); final var windowMetrics = windowManager.getCurrentWindowMetrics();
final var bounds = windowMetrics.getBounds();
screenWidth = metrics.widthPixels; final var windowInsets = windowMetrics.getWindowInsets();
screenHeight = metrics.heightPixels; final var insets = windowInsets.getInsetsIgnoringVisibility(
WindowInsets.Type.navigationBars() | WindowInsets.Type.displayCutout());
screenWidth = bounds.width() - (insets.left + insets.right);
screenHeight = bounds.height() - (insets.top + insets.bottom);
} else {
final DisplayMetrics metrics = new DisplayMetrics();
windowManager.getDefaultDisplay().getMetrics(metrics);
screenWidth = metrics.widthPixels;
screenHeight = metrics.heightPixels;
}
if (DEBUG) { if (DEBUG) {
Log.d(TAG, "updateScreenSize() called: screenWidth = [" Log.d(TAG, "updateScreenSize() called: screenWidth = ["
+ screenWidth + "], screenHeight = [" + screenHeight + "]"); + screenWidth + "], screenHeight = [" + screenHeight + "]");

View File

@ -4,11 +4,14 @@ import android.app.UiModeManager;
import android.content.Context; import android.content.Context;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.content.res.Configuration; import android.content.res.Configuration;
import android.graphics.Point;
import android.os.BatteryManager; import android.os.BatteryManager;
import android.os.Build; import android.os.Build;
import android.provider.Settings; import android.provider.Settings;
import android.util.TypedValue; import android.util.TypedValue;
import android.view.KeyEvent; import android.view.KeyEvent;
import android.view.WindowInsets;
import android.view.WindowManager;
import androidx.annotation.Dimension; import androidx.annotation.Dimension;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
@ -151,4 +154,18 @@ public final class DeviceUtils {
Settings.Global.ANIMATOR_DURATION_SCALE, Settings.Global.ANIMATOR_DURATION_SCALE,
1F) != 0F; 1F) != 0F;
} }
public static int getWindowHeight(@NonNull final WindowManager windowManager) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
final var windowMetrics = windowManager.getCurrentWindowMetrics();
final var windowInsets = windowMetrics.getWindowInsets();
final var insets = windowInsets.getInsetsIgnoringVisibility(
WindowInsets.Type.navigationBars() | WindowInsets.Type.displayCutout());
return windowMetrics.getBounds().height() - (insets.top + insets.bottom);
} else {
final Point point = new Point();
windowManager.getDefaultDisplay().getSize(point);
return point.y;
}
}
} }