diff --git a/app/build.gradle b/app/build.gradle index f14513c20..95313b6e6 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -15,7 +15,7 @@ android { applicationId "org.schabi.newpipe" resValue "string", "app_name", "NewPipe" minSdk 21 - targetSdk 29 + targetSdk 33 versionCode 991 versionName "0.24.1" @@ -107,7 +107,7 @@ ext { groupieVersion = '2.10.1' markwonVersion = '4.6.2' - leakCanaryVersion = '2.5' + leakCanaryVersion = '2.9.1' stethoVersion = '1.6.0' mockitoVersion = '4.0.0' assertJVersion = '3.23.1' @@ -179,7 +179,7 @@ sonar { dependencies { /** Desugaring **/ - coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.6' + coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.8' /** NewPipe libraries **/ // You can use a local version by uncommenting a few lines in settings.gradle @@ -259,14 +259,14 @@ dependencies { implementation "io.noties.markwon:linkify:${markwonVersion}" // Crash reporting - implementation "ch.acra:acra-core:5.9.3" + implementation "ch.acra:acra-core:5.9.7" // Properly restarting implementation 'com.jakewharton:process-phoenix:2.1.2' // Reactive extensions for Java VM - implementation "io.reactivex.rxjava3:rxjava:3.0.13" - implementation "io.reactivex.rxjava3:rxandroid:3.0.0" + implementation "io.reactivex.rxjava3:rxjava:3.1.5" + implementation "io.reactivex.rxjava3:rxandroid:3.0.2" // RxJava binding APIs for Android UI widgets implementation "com.jakewharton.rxbinding4:rxbinding:4.0.0" diff --git a/app/src/androidTest/java/org/schabi/newpipe/util/StreamItemAdapterTest.kt b/app/src/androidTest/java/org/schabi/newpipe/util/StreamItemAdapterTest.kt index 016feb576..0fe251c16 100644 --- a/app/src/androidTest/java/org/schabi/newpipe/util/StreamItemAdapterTest.kt +++ b/app/src/androidTest/java/org/schabi/newpipe/util/StreamItemAdapterTest.kt @@ -1,12 +1,12 @@ package org.schabi.newpipe.util import android.content.Context -import android.util.SparseArray import android.view.View import android.view.View.GONE import android.view.View.INVISIBLE import android.view.View.VISIBLE import android.widget.Spinner +import androidx.collection.SparseArrayCompat import androidx.test.core.app.ApplicationProvider import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.MediumTest @@ -39,9 +39,7 @@ class StreamItemAdapterTest { @Test fun videoStreams_noSecondaryStream() { val adapter = StreamItemAdapter( - context, - getVideoStreams(true, true, true, true), - null + getVideoStreams(true, true, true, true) ) spinner.adapter = adapter @@ -54,7 +52,6 @@ class StreamItemAdapterTest { @Test fun videoStreams_hasSecondaryStream() { val adapter = StreamItemAdapter( - context, getVideoStreams(false, true, false, true), getAudioStreams(false, true, false, true) ) @@ -69,7 +66,6 @@ class StreamItemAdapterTest { @Test fun videoStreams_Mixed() { val adapter = StreamItemAdapter( - context, getVideoStreams(true, true, true, true, true, false, true, true), getAudioStreams(false, true, false, false, false, true, true, true) ) @@ -88,7 +84,6 @@ class StreamItemAdapterTest { @Test fun subtitleStreams_noIcon() { val adapter = StreamItemAdapter( - context, StreamItemAdapter.StreamSizeWrapper( (0 until 5).map { SubtitlesStream.Builder() @@ -99,8 +94,7 @@ class StreamItemAdapterTest { .build() }, context - ), - null + ) ) spinner.adapter = adapter for (i in 0 until spinner.count) { @@ -111,7 +105,6 @@ class StreamItemAdapterTest { @Test fun audioStreams_noIcon() { val adapter = StreamItemAdapter( - context, StreamItemAdapter.StreamSizeWrapper( (0 until 5).map { AudioStream.Builder() @@ -122,8 +115,7 @@ class StreamItemAdapterTest { .build() }, context - ), - null + ) ) spinner.adapter = adapter for (i in 0 until spinner.count) { @@ -200,7 +192,7 @@ class StreamItemAdapterTest { * Helper function that builds a secondary stream list. */ private fun getSecondaryStreamsFromList(streams: List) = - SparseArray?>(streams.size).apply { + SparseArrayCompat?>(streams.size).apply { streams.forEachIndexed { index, stream -> val secondaryStreamHelper: SecondaryStreamHelper? = stream?.let { SecondaryStreamHelper( diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 3ca19e8c0..3e987abdb 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -9,6 +9,7 @@ + @@ -39,7 +41,9 @@ - + @@ -47,7 +51,7 @@ @@ -56,15 +60,18 @@ @@ -73,6 +80,7 @@ @@ -85,13 +93,18 @@ - + + @@ -99,6 +112,7 @@ @@ -109,6 +123,7 @@ @@ -353,30 +369,30 @@ - - - + + + - - + + - - - + + + - - - + + + - - + + - - - + + + @@ -385,11 +401,17 @@ android:exported="false" /> - + - + - + diff --git a/app/src/main/java/org/schabi/newpipe/MainActivity.java b/app/src/main/java/org/schabi/newpipe/MainActivity.java index 0f82c8a9f..73a81450e 100644 --- a/app/src/main/java/org/schabi/newpipe/MainActivity.java +++ b/app/src/main/java/org/schabi/newpipe/MainActivity.java @@ -157,9 +157,12 @@ public class MainActivity extends AppCompatActivity { } openMiniPlayerUponPlayerStarted(); - // Schedule worker for checking for new streams and creating corresponding notifications - // if this is enabled by the user. - NotificationWorker.initialize(this); + if (PermissionHelper.checkPostNotificationsPermission(this, + PermissionHelper.POST_NOTIFICATIONS_REQUEST_CODE)) { + // Schedule worker for checking for new streams and creating corresponding notifications + // if this is enabled by the user. + NotificationWorker.initialize(this); + } } @Override @@ -599,6 +602,9 @@ public class MainActivity extends AppCompatActivity { ((VideoDetailFragment) fragment).openDownloadDialog(); } break; + case PermissionHelper.POST_NOTIFICATIONS_REQUEST_CODE: + NotificationWorker.initialize(this); + break; } } diff --git a/app/src/main/java/org/schabi/newpipe/QueueItemMenuUtil.java b/app/src/main/java/org/schabi/newpipe/QueueItemMenuUtil.java index 7c646d0e4..3255489b0 100644 --- a/app/src/main/java/org/schabi/newpipe/QueueItemMenuUtil.java +++ b/app/src/main/java/org/schabi/newpipe/QueueItemMenuUtil.java @@ -1,5 +1,6 @@ package org.schabi.newpipe; +import static org.schabi.newpipe.util.SparseItemUtil.fetchStreamInfoAndSaveToDatabase; import static org.schabi.newpipe.util.external_communication.ShareUtils.shareText; import android.content.Context; @@ -10,6 +11,7 @@ import android.widget.PopupMenu; import androidx.fragment.app.FragmentManager; import org.schabi.newpipe.database.stream.model.StreamEntity; +import org.schabi.newpipe.download.DownloadDialog; import org.schabi.newpipe.local.dialog.PlaylistDialog; import org.schabi.newpipe.player.playqueue.PlayQueue; import org.schabi.newpipe.player.playqueue.PlayQueueItem; @@ -75,6 +77,14 @@ public final class QueueItemMenuUtil { shareText(context, item.getTitle(), item.getUrl(), item.getThumbnailUrl()); return true; + case R.id.menu_item_download: + fetchStreamInfoAndSaveToDatabase(context, item.getServiceId(), item.getUrl(), + info -> { + final DownloadDialog downloadDialog = new DownloadDialog(context, + info); + downloadDialog.show(fragmentManager, "downloadDialog"); + }); + return true; } return false; }); diff --git a/app/src/main/java/org/schabi/newpipe/download/DownloadDialog.java b/app/src/main/java/org/schabi/newpipe/download/DownloadDialog.java index 2975fe43a..3f3384b8e 100644 --- a/app/src/main/java/org/schabi/newpipe/download/DownloadDialog.java +++ b/app/src/main/java/org/schabi/newpipe/download/DownloadDialog.java @@ -17,7 +17,6 @@ import android.os.Bundle; import android.os.Environment; import android.os.IBinder; import android.util.Log; -import android.util.SparseArray; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -36,6 +35,7 @@ import androidx.annotation.StringRes; import androidx.appcompat.app.AlertDialog; import androidx.appcompat.view.menu.ActionMenuItemView; import androidx.appcompat.widget.Toolbar; +import androidx.collection.SparseArrayCompat; import androidx.documentfile.provider.DocumentFile; import androidx.fragment.app.DialogFragment; import androidx.preference.PreferenceManager; @@ -211,8 +211,7 @@ public class DownloadDialog extends DialogFragment setStyle(STYLE_NO_TITLE, ThemeHelper.getDialogTheme(context)); Icepick.restoreInstanceState(this, savedInstanceState); - final SparseArray> secondaryStreams = - new SparseArray<>(4); + final var secondaryStreams = new SparseArrayCompat>(4); final List videoStreams = wrappedVideoStreams.getStreamsList(); for (int i = 0; i < videoStreams.size(); i++) { @@ -236,10 +235,9 @@ public class DownloadDialog extends DialogFragment } } - this.videoStreamsAdapter = new StreamItemAdapter<>(context, wrappedVideoStreams, - secondaryStreams); - this.audioStreamsAdapter = new StreamItemAdapter<>(context, wrappedAudioStreams); - this.subtitleStreamsAdapter = new StreamItemAdapter<>(context, wrappedSubtitleStreams); + this.videoStreamsAdapter = new StreamItemAdapter<>(wrappedVideoStreams, secondaryStreams); + this.audioStreamsAdapter = new StreamItemAdapter<>(wrappedAudioStreams); + this.subtitleStreamsAdapter = new StreamItemAdapter<>(wrappedSubtitleStreams); final Intent intent = new Intent(context, DownloadManagerService.class); context.startService(intent); diff --git a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java index bf0b63e4b..2fb62413f 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java @@ -10,8 +10,11 @@ import static org.schabi.newpipe.player.helper.PlayerHelper.isClearingQueueConfi import static org.schabi.newpipe.player.playqueue.PlayQueueItem.RECOVERY_UNSET; import static org.schabi.newpipe.util.ExtractorHelper.showMetaInfoInTextView; import static org.schabi.newpipe.util.ListHelper.getUrlAndNonTorrentStreams; +import static org.schabi.newpipe.util.NavigationHelper.openPlayQueue; +import static org.schabi.newpipe.util.NavigationHelper.playWithKore; import android.animation.ValueAnimator; +import android.annotation.SuppressLint; import android.app.Activity; import android.content.BroadcastReceiver; import android.content.Context; @@ -119,6 +122,7 @@ import java.util.List; import java.util.Objects; import java.util.Optional; import java.util.concurrent.TimeUnit; +import java.util.function.Consumer; import icepick.State; import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers; @@ -129,9 +133,6 @@ import io.reactivex.rxjava3.schedulers.Schedulers; public final class VideoDetailFragment extends BaseStateFragment implements BackPressable, - SharedPreferences.OnSharedPreferenceChangeListener, - View.OnClickListener, - View.OnLongClickListener, PlayerServiceExtendedEventListener, OnKeyDownListener { public static final String KEY_SWITCHING_PLAYERS = "switching_players"; @@ -167,6 +168,20 @@ public final class VideoDetailFragment private boolean tabSettingsChanged = false; private int lastAppBarVerticalOffset = Integer.MAX_VALUE; // prevents useless updates + private final SharedPreferences.OnSharedPreferenceChangeListener preferenceChangeListener = + (sharedPreferences, key) -> { + if (key.equals(getString(R.string.show_comments_key))) { + showComments = sharedPreferences.getBoolean(key, true); + tabSettingsChanged = true; + } else if (key.equals(getString(R.string.show_next_video_key))) { + showRelatedItems = sharedPreferences.getBoolean(key, true); + tabSettingsChanged = true; + } else if (key.equals(getString(R.string.show_description_key))) { + showDescription = sharedPreferences.getBoolean(key, true); + tabSettingsChanged = true; + } + }; + @State protected int serviceId = Constants.NO_SERVICE_ID; @State @@ -291,7 +306,7 @@ public final class VideoDetailFragment showDescription = prefs.getBoolean(getString(R.string.show_description_key), true); selectedTabTag = prefs.getString( getString(R.string.stream_info_selected_tab_key), COMMENTS_TAB_TAG); - prefs.registerOnSharedPreferenceChangeListener(this); + prefs.registerOnSharedPreferenceChangeListener(preferenceChangeListener); setupBroadcastReceiver(); @@ -378,7 +393,7 @@ public final class VideoDetailFragment } PreferenceManager.getDefaultSharedPreferences(activity) - .unregisterOnSharedPreferenceChangeListener(this); + .unregisterOnSharedPreferenceChangeListener(preferenceChangeListener); activity.unregisterReceiver(broadcastReceiver); activity.getContentResolver().unregisterContentObserver(settingsContentObserver); @@ -424,130 +439,129 @@ public final class VideoDetailFragment } } - @Override - public void onSharedPreferenceChanged(final SharedPreferences sharedPreferences, - final String key) { - if (key.equals(getString(R.string.show_comments_key))) { - showComments = sharedPreferences.getBoolean(key, true); - tabSettingsChanged = true; - } else if (key.equals(getString(R.string.show_next_video_key))) { - showRelatedItems = sharedPreferences.getBoolean(key, true); - tabSettingsChanged = true; - } else if (key.equals(getString(R.string.show_description_key))) { - showDescription = sharedPreferences.getBoolean(key, true); - tabSettingsChanged = true; - } - } - /*////////////////////////////////////////////////////////////////////////// // OnClick //////////////////////////////////////////////////////////////////////////*/ - @Override - public void onClick(final View v) { - switch (v.getId()) { - case R.id.detail_controls_background: - openBackgroundPlayer(false); - break; - case R.id.detail_controls_popup: - openPopupPlayer(false); - break; - case R.id.detail_controls_playlist_append: - if (getFM() != null && currentInfo != null) { - disposables.add( - PlaylistDialog.createCorrespondingDialog( - getContext(), - List.of(new StreamEntity(currentInfo)), - dialog -> dialog.show(getFM(), TAG) - ) - ); - } - break; - case R.id.detail_controls_download: - if (PermissionHelper.checkStoragePermissions(activity, - PermissionHelper.DOWNLOAD_DIALOG_REQUEST_CODE)) { - this.openDownloadDialog(); - } - break; - case R.id.detail_controls_share: - if (currentInfo != null) { - ShareUtils.shareText(requireContext(), currentInfo.getName(), - currentInfo.getUrl(), currentInfo.getThumbnailUrl()); - } - break; - case R.id.detail_controls_open_in_browser: - if (currentInfo != null) { - ShareUtils.openUrlInBrowser(requireContext(), currentInfo.getUrl()); - } - break; - case R.id.detail_controls_play_with_kodi: - if (currentInfo != null) { - try { - NavigationHelper.playWithKore( - requireContext(), Uri.parse(currentInfo.getUrl())); - } catch (final Exception e) { - if (DEBUG) { - Log.i(TAG, "Failed to start kore", e); - } - KoreUtils.showInstallKoreDialog(requireContext()); - } - } - break; - case R.id.detail_uploader_root_layout: - if (isEmpty(currentInfo.getSubChannelUrl())) { - if (!isEmpty(currentInfo.getUploaderUrl())) { - openChannel(currentInfo.getUploaderUrl(), currentInfo.getUploaderName()); - } - - if (DEBUG) { - Log.i(TAG, "Can't open sub-channel because we got no channel URL"); - } - } else { - openChannel(currentInfo.getSubChannelUrl(), - currentInfo.getSubChannelName()); - } - break; - case R.id.detail_thumbnail_root_layout: - // make sure not to open any player if there is nothing currently loaded! - // FIXME removing this `if` causes the player service to start correctly, then stop, - // then restart badly without calling `startForeground()`, causing a crash when - // later closing the detail fragment - if (currentInfo != null) { - autoPlayEnabled = true; // forcefully start playing - // FIXME Workaround #7427 - if (isPlayerAvailable()) { - player.setRecovery(); - } - openVideoPlayerAutoFullscreen(); - } - break; - case R.id.detail_title_root_layout: - toggleTitleAndSecondaryControls(); - break; - case R.id.overlay_thumbnail: - case R.id.overlay_metadata_layout: - case R.id.overlay_buttons_layout: - bottomSheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED); - break; - case R.id.overlay_play_queue_button: - NavigationHelper.openPlayQueue(getContext()); - break; - case R.id.overlay_play_pause_button: - if (playerIsNotStopped()) { - player.playPause(); - player.UIs().get(VideoPlayerUi.class).ifPresent(ui -> ui.hideControls(0, 0)); - showSystemUi(); - } else { - autoPlayEnabled = true; // forcefully start playing - openVideoPlayer(false); + private void setOnClickListeners() { + binding.detailTitleRootLayout.setOnClickListener(v -> toggleTitleAndSecondaryControls()); + binding.detailUploaderRootLayout.setOnClickListener(makeOnClickListener(info -> { + if (isEmpty(info.getSubChannelUrl())) { + if (!isEmpty(info.getUploaderUrl())) { + openChannel(info.getUploaderUrl(), info.getUploaderName()); } - setOverlayPlayPauseImage(isPlayerAvailable() && player.isPlaying()); - break; - case R.id.overlay_close_button: - bottomSheetBehavior.setState(BottomSheetBehavior.STATE_HIDDEN); - break; + if (DEBUG) { + Log.i(TAG, "Can't open sub-channel because we got no channel URL"); + } + } else { + openChannel(info.getSubChannelUrl(), info.getSubChannelName()); + } + })); + binding.detailThumbnailRootLayout.setOnClickListener(v -> { + autoPlayEnabled = true; // forcefully start playing + // FIXME Workaround #7427 + if (isPlayerAvailable()) { + player.setRecovery(); + } + openVideoPlayerAutoFullscreen(); + }); + + binding.detailControlsBackground.setOnClickListener(v -> openBackgroundPlayer(false)); + binding.detailControlsPopup.setOnClickListener(v -> openPopupPlayer(false)); + binding.detailControlsPlaylistAppend.setOnClickListener(makeOnClickListener(info -> + disposables.add(PlaylistDialog.createCorrespondingDialog(requireContext(), + List.of(new StreamEntity(info)), + dialog -> dialog.show(getParentFragmentManager(), TAG))))); + binding.detailControlsDownload.setOnClickListener(v -> { + if (PermissionHelper.checkStoragePermissions(activity, + PermissionHelper.DOWNLOAD_DIALOG_REQUEST_CODE)) { + openDownloadDialog(); + } + }); + binding.detailControlsShare.setOnClickListener(makeOnClickListener(info -> + ShareUtils.shareText(requireContext(), info.getName(), info.getUrl(), + info.getThumbnailUrl()))); + binding.detailControlsOpenInBrowser.setOnClickListener(makeOnClickListener(info -> + ShareUtils.openUrlInBrowser(requireContext(), info.getUrl()))); + binding.detailControlsPlayWithKodi.setOnClickListener(makeOnClickListener(info -> { + try { + playWithKore(requireContext(), Uri.parse(info.getUrl())); + } catch (final Exception e) { + if (DEBUG) { + Log.i(TAG, "Failed to start kore", e); + } + KoreUtils.showInstallKoreDialog(requireContext()); + } + })); + if (DEBUG) { + binding.detailControlsCrashThePlayer.setOnClickListener(v -> + VideoDetailPlayerCrasher.onCrashThePlayer(requireContext(), player)); } + + final View.OnClickListener overlayListener = v -> bottomSheetBehavior + .setState(BottomSheetBehavior.STATE_EXPANDED); + binding.overlayThumbnail.setOnClickListener(overlayListener); + binding.overlayMetadataLayout.setOnClickListener(overlayListener); + binding.overlayButtonsLayout.setOnClickListener(overlayListener); + binding.overlayCloseButton.setOnClickListener(v -> bottomSheetBehavior + .setState(BottomSheetBehavior.STATE_HIDDEN)); + binding.overlayPlayQueueButton.setOnClickListener(v -> openPlayQueue(requireContext())); + binding.overlayPlayPauseButton.setOnClickListener(v -> { + if (playerIsNotStopped()) { + player.playPause(); + player.UIs().get(VideoPlayerUi.class).ifPresent(ui -> ui.hideControls(0, 0)); + showSystemUi(); + } else { + autoPlayEnabled = true; // forcefully start playing + openVideoPlayer(false); + } + + setOverlayPlayPauseImage(isPlayerAvailable() && player.isPlaying()); + }); + } + + private View.OnClickListener makeOnClickListener(final Consumer consumer) { + return v -> { + if (!isLoading.get() && currentInfo != null) { + consumer.accept(currentInfo); + } + }; + } + + private void setOnLongClickListeners() { + binding.detailTitleRootLayout.setOnLongClickListener(makeOnLongClickListener(info -> + ShareUtils.copyToClipboard(requireContext(), + binding.detailVideoTitleView.getText().toString()))); + binding.detailUploaderRootLayout.setOnLongClickListener(makeOnLongClickListener(info -> { + if (isEmpty(info.getSubChannelUrl())) { + Log.w(TAG, "Can't open parent channel because we got no parent channel URL"); + } else { + openChannel(info.getUploaderUrl(), info.getUploaderName()); + } + })); + + binding.detailControlsBackground.setOnLongClickListener(makeOnLongClickListener(info -> + openBackgroundPlayer(true))); + binding.detailControlsPopup.setOnLongClickListener(makeOnLongClickListener(info -> + openPopupPlayer(true))); + binding.detailControlsDownload.setOnLongClickListener(makeOnLongClickListener(info -> + NavigationHelper.openDownloads(activity))); + + final View.OnLongClickListener overlayListener = makeOnLongClickListener(info -> + openChannel(info.getUploaderUrl(), info.getUploaderName())); + binding.overlayThumbnail.setOnLongClickListener(overlayListener); + binding.overlayMetadataLayout.setOnLongClickListener(overlayListener); + } + + private View.OnLongClickListener makeOnLongClickListener(final Consumer consumer) { + return v -> { + if (isLoading.get() || currentInfo == null) { + return false; + } + consumer.accept(currentInfo); + return true; + }; } private void openChannel(final String subChannelUrl, final String subChannelName) { @@ -559,43 +573,6 @@ public final class VideoDetailFragment } } - @Override - public boolean onLongClick(final View v) { - if (isLoading.get() || currentInfo == null) { - return false; - } - - switch (v.getId()) { - case R.id.detail_controls_background: - openBackgroundPlayer(true); - break; - case R.id.detail_controls_popup: - openPopupPlayer(true); - break; - case R.id.detail_controls_download: - NavigationHelper.openDownloads(activity); - break; - case R.id.overlay_thumbnail: - case R.id.overlay_metadata_layout: - openChannel(currentInfo.getUploaderUrl(), currentInfo.getUploaderName()); - break; - case R.id.detail_uploader_root_layout: - if (isEmpty(currentInfo.getSubChannelUrl())) { - Log.w(TAG, - "Can't open parent channel because we got no parent channel URL"); - } else { - openChannel(currentInfo.getUploaderUrl(), currentInfo.getUploaderName()); - } - break; - case R.id.detail_title_root_layout: - ShareUtils.copyToClipboard(requireContext(), - binding.detailVideoTitleView.getText().toString()); - break; - } - - return true; - } - private void toggleTitleAndSecondaryControls() { if (binding.detailSecondaryControlPanel.getVisibility() == View.GONE) { binding.detailVideoTitleView.setMaxLines(10); @@ -616,11 +593,6 @@ public final class VideoDetailFragment // Init //////////////////////////////////////////////////////////////////////////*/ - @Override - public void onViewCreated(@NonNull final View rootView, final Bundle savedInstanceState) { - super.onViewCreated(rootView, savedInstanceState); - } - @Override // called from onViewCreated in {@link BaseFragment#onViewCreated} protected void initViews(final View rootView, final Bundle savedInstanceState) { super.initViews(rootView, savedInstanceState); @@ -646,44 +618,25 @@ public final class VideoDetailFragment } @Override + @SuppressLint("ClickableViewAccessibility") protected void initListeners() { super.initListeners(); - binding.detailTitleRootLayout.setOnClickListener(this); - binding.detailTitleRootLayout.setOnLongClickListener(this); - binding.detailUploaderRootLayout.setOnClickListener(this); - binding.detailUploaderRootLayout.setOnLongClickListener(this); - binding.detailThumbnailRootLayout.setOnClickListener(this); + setOnClickListeners(); + setOnLongClickListeners(); - binding.detailControlsBackground.setOnClickListener(this); - binding.detailControlsBackground.setOnLongClickListener(this); - binding.detailControlsPopup.setOnClickListener(this); - binding.detailControlsPopup.setOnLongClickListener(this); - binding.detailControlsPlaylistAppend.setOnClickListener(this); - binding.detailControlsDownload.setOnClickListener(this); - binding.detailControlsDownload.setOnLongClickListener(this); - binding.detailControlsShare.setOnClickListener(this); - binding.detailControlsOpenInBrowser.setOnClickListener(this); - binding.detailControlsPlayWithKodi.setOnClickListener(this); - if (DEBUG) { - binding.detailControlsCrashThePlayer.setOnClickListener( - v -> VideoDetailPlayerCrasher.onCrashThePlayer( - this.getContext(), - this.player) - ); - } + final View.OnTouchListener controlsTouchListener = (view, motionEvent) -> { + if (motionEvent.getAction() == MotionEvent.ACTION_DOWN + && PreferenceManager.getDefaultSharedPreferences(activity) + .getBoolean(getString(R.string.show_hold_to_append_key), true)) { - binding.overlayThumbnail.setOnClickListener(this); - binding.overlayThumbnail.setOnLongClickListener(this); - binding.overlayMetadataLayout.setOnClickListener(this); - binding.overlayMetadataLayout.setOnLongClickListener(this); - binding.overlayButtonsLayout.setOnClickListener(this); - binding.overlayPlayQueueButton.setOnClickListener(this); - binding.overlayCloseButton.setOnClickListener(this); - binding.overlayPlayPauseButton.setOnClickListener(this); - - binding.detailControlsBackground.setOnTouchListener(getOnControlsTouchListener()); - binding.detailControlsPopup.setOnTouchListener(getOnControlsTouchListener()); + animate(binding.touchAppendDetail, true, 250, AnimationType.ALPHA, 0, () -> + animate(binding.touchAppendDetail, false, 1500, AnimationType.ALPHA, 1000)); + } + return false; + }; + binding.detailControlsBackground.setOnTouchListener(controlsTouchListener); + binding.detailControlsPopup.setOnTouchListener(controlsTouchListener); binding.appBarLayout.addOnOffsetChangedListener((layout, verticalOffset) -> { // prevent useless updates to tab layout visibility if nothing changed @@ -702,23 +655,6 @@ public final class VideoDetailFragment } } - private View.OnTouchListener getOnControlsTouchListener() { - return (view, motionEvent) -> { - if (!PreferenceManager.getDefaultSharedPreferences(activity) - .getBoolean(getString(R.string.show_hold_to_append_key), true)) { - return false; - } - - if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) { - animate(binding.touchAppendDetail, true, 250, AnimationType.ALPHA, - 0, () -> - animate(binding.touchAppendDetail, false, 1500, - AnimationType.ALPHA, 1000)); - } - return false; - }; - } - private void initThumbnailViews(@NonNull final StreamInfo info) { PicassoHelper.loadDetailsThumbnail(info.getThumbnailUrl()).tag(PICASSO_VIDEO_DETAILS_TAG) .into(binding.detailThumbnailImageView, new Callback() { diff --git a/app/src/main/java/org/schabi/newpipe/fragments/list/playlist/PlaylistFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/list/playlist/PlaylistFragment.java index e3caeb522..a3150a773 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/list/playlist/PlaylistFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/list/playlist/PlaylistFragment.java @@ -230,24 +230,24 @@ public class PlaylistFragment extends BaseListInfoFragment dialog.show(getFM(), TAG) - )); + if (currentInfo != null) { + disposables.add(PlaylistDialog.createCorrespondingDialog( + getContext(), + getPlayQueue() + .getStreams() + .stream() + .map(StreamEntity::new) + .collect(Collectors.toList()), + dialog -> dialog.show(getFM(), TAG) + )); + } break; default: return super.onOptionsItemSelected(item); diff --git a/app/src/main/java/org/schabi/newpipe/fragments/list/search/SearchFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/list/search/SearchFragment.java index 5175e0096..26a283229 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/list/search/SearchFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/list/search/SearchFragment.java @@ -33,6 +33,7 @@ import androidx.annotation.Nullable; import androidx.appcompat.app.ActionBar; import androidx.appcompat.app.AlertDialog; import androidx.appcompat.widget.TooltipCompat; +import androidx.collection.SparseArrayCompat; import androidx.core.text.HtmlCompat; import androidx.preference.PreferenceManager; import androidx.recyclerview.widget.ItemTouchHelper; @@ -70,9 +71,7 @@ import org.schabi.newpipe.util.ServiceHelper; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; -import java.util.HashMap; import java.util.List; -import java.util.Map; import java.util.Queue; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; @@ -141,7 +140,7 @@ public class SearchFragment extends BaseListFragment menuItemToFilterName = null; + private final SparseArrayCompat menuItemToFilterName = new SparseArrayCompat<>(); private StreamingService service; private Page nextPage; private boolean showLocalSuggestions = true; @@ -426,8 +425,6 @@ public class SearchFragment extends BaseListFragment(); - int itemId = 0; boolean isFirstItem = true; final Context c = getContext(); @@ -468,11 +465,8 @@ public class SearchFragment extends BaseListFragment cf = new ArrayList<>(1); - cf.add(menuItemToFilterName.get(item.getItemId())); - changeContentFilter(item, cf); - } + final var filter = Collections.singletonList(menuItemToFilterName.get(item.getItemId())); + changeContentFilter(item, filter); return true; } diff --git a/app/src/main/java/org/schabi/newpipe/player/Player.java b/app/src/main/java/org/schabi/newpipe/player/Player.java index 99d36f66e..95520ba1e 100644 --- a/app/src/main/java/org/schabi/newpipe/player/Player.java +++ b/app/src/main/java/org/schabi/newpipe/player/Player.java @@ -216,7 +216,6 @@ public final class Player implements PlaybackListener, Listener { // minimized to background but will resume automatically to the original player type private boolean isAudioOnly = false; private boolean isPrepared = false; - private boolean wasPlaying = false; /*////////////////////////////////////////////////////////////////////////// // UIs, listeners and disposables @@ -918,13 +917,6 @@ public final class Player implements PlaybackListener, Listener { error -> Log.e(TAG, "Progress update failure: ", error)); } - public void saveWasPlaying() { - this.wasPlaying = getPlayWhenReady(); - } - - public boolean wasPlaying() { - return wasPlaying; - } //endregion diff --git a/app/src/main/java/org/schabi/newpipe/player/PlayerService.java b/app/src/main/java/org/schabi/newpipe/player/PlayerService.java index 33b024e3d..d81301205 100644 --- a/app/src/main/java/org/schabi/newpipe/player/PlayerService.java +++ b/app/src/main/java/org/schabi/newpipe/player/PlayerService.java @@ -86,8 +86,6 @@ public final class PlayerService extends Service { } if (!player.exoPlayerIsNull()) { - player.saveWasPlaying(); - // Releases wifi & cpu, disables keepScreenOn, etc. // We can't just pause the player here because it will make transition // from one stream to a new stream not smooth diff --git a/app/src/main/java/org/schabi/newpipe/player/seekbarpreview/SeekbarPreviewThumbnailHolder.java b/app/src/main/java/org/schabi/newpipe/player/seekbarpreview/SeekbarPreviewThumbnailHolder.java index 08c6366c8..50ffa2f2a 100644 --- a/app/src/main/java/org/schabi/newpipe/player/seekbarpreview/SeekbarPreviewThumbnailHolder.java +++ b/app/src/main/java/org/schabi/newpipe/player/seekbarpreview/SeekbarPreviewThumbnailHolder.java @@ -1,6 +1,7 @@ package org.schabi.newpipe.player.seekbarpreview; import static org.schabi.newpipe.player.seekbarpreview.SeekbarPreviewThumbnailHelper.SeekbarPreviewThumbnailType; +import static org.schabi.newpipe.player.seekbarpreview.SeekbarPreviewThumbnailHelper.getSeekbarPreviewThumbnailType; import android.content.Context; import android.graphics.Bitmap; @@ -8,6 +9,7 @@ import android.util.Log; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.collection.SparseArrayCompat; import com.google.common.base.Stopwatch; @@ -15,12 +17,9 @@ import org.schabi.newpipe.extractor.stream.Frameset; import org.schabi.newpipe.util.PicassoHelper; import java.util.Comparator; -import java.util.HashMap; import java.util.List; -import java.util.Map; import java.util.Optional; import java.util.UUID; -import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.function.Supplier; @@ -34,18 +33,15 @@ public class SeekbarPreviewThumbnailHolder { // Key = Position of the picture in milliseconds // Supplier = Supplies the bitmap for that position - private final Map> seekbarPreviewData = new ConcurrentHashMap<>(); + private final SparseArrayCompat> seekbarPreviewData = + new SparseArrayCompat<>(); // This ensures that if the reset is still undergoing // and another reset starts, only the last reset is processed private UUID currentUpdateRequestIdentifier = UUID.randomUUID(); - public synchronized void resetFrom( - @NonNull final Context context, - final List framesets) { - - final int seekbarPreviewType = - SeekbarPreviewThumbnailHelper.getSeekbarPreviewThumbnailType(context); + public void resetFrom(@NonNull final Context context, final List framesets) { + final int seekbarPreviewType = getSeekbarPreviewThumbnailType(context); final UUID updateRequestIdentifier = UUID.randomUUID(); this.currentUpdateRequestIdentifier = updateRequestIdentifier; @@ -63,13 +59,12 @@ public class SeekbarPreviewThumbnailHolder { executorService.shutdown(); } - private void resetFromAsync( - final int seekbarPreviewType, - final List framesets, - final UUID updateRequestIdentifier) { - + private void resetFromAsync(final int seekbarPreviewType, final List framesets, + final UUID updateRequestIdentifier) { Log.d(TAG, "Clearing seekbarPreviewData"); - seekbarPreviewData.clear(); + synchronized (seekbarPreviewData) { + seekbarPreviewData.clear(); + } if (seekbarPreviewType == SeekbarPreviewThumbnailType.NONE) { Log.d(TAG, "Not processing seekbarPreviewData due to settings"); @@ -94,10 +89,8 @@ public class SeekbarPreviewThumbnailHolder { generateDataFrom(frameset, updateRequestIdentifier); } - private Frameset getFrameSetForType( - final List framesets, - final int seekbarPreviewType) { - + private Frameset getFrameSetForType(final List framesets, + final int seekbarPreviewType) { if (seekbarPreviewType == SeekbarPreviewThumbnailType.HIGH_QUALITY) { Log.d(TAG, "Strategy for seekbarPreviewData: high quality"); return framesets.stream() @@ -111,17 +104,14 @@ public class SeekbarPreviewThumbnailHolder { } } - private void generateDataFrom( - final Frameset frameset, - final UUID updateRequestIdentifier) { - + private void generateDataFrom(final Frameset frameset, final UUID updateRequestIdentifier) { Log.d(TAG, "Starting generation of seekbarPreviewData"); final Stopwatch sw = Log.isLoggable(TAG, Log.DEBUG) ? Stopwatch.createStarted() : null; int currentPosMs = 0; int pos = 1; - final int frameCountPerUrl = frameset.getFramesPerPageX() * frameset.getFramesPerPageY(); + final int urlFrameCount = frameset.getFramesPerPageX() * frameset.getFramesPerPageY(); // Process each url in the frameset for (final String url : frameset.getUrls()) { @@ -130,11 +120,11 @@ public class SeekbarPreviewThumbnailHolder { // The data is not added directly to "seekbarPreviewData" due to // concurrency and checks for "updateRequestIdentifier" - final Map> generatedDataForUrl = new HashMap<>(); + final var generatedDataForUrl = new SparseArrayCompat>(urlFrameCount); // The bitmap consists of several images, which we process here // foreach frame in the returned bitmap - for (int i = 0; i < frameCountPerUrl; i++) { + for (int i = 0; i < urlFrameCount; i++) { // Frames outside the video length are skipped if (pos > frameset.getTotalCount()) { break; @@ -161,7 +151,9 @@ public class SeekbarPreviewThumbnailHolder { // Check if we are still the latest request // If not abort method execution if (isRequestIdentifierCurrent(updateRequestIdentifier)) { - seekbarPreviewData.putAll(generatedDataForUrl); + synchronized (seekbarPreviewData) { + seekbarPreviewData.putAll(generatedDataForUrl); + } } else { Log.d(TAG, "Aborted of generation of seekbarPreviewData"); break; @@ -169,7 +161,7 @@ public class SeekbarPreviewThumbnailHolder { } if (sw != null) { - Log.d(TAG, "Generation of seekbarPreviewData took " + sw.stop().toString()); + Log.d(TAG, "Generation of seekbarPreviewData took " + sw.stop()); } } @@ -189,17 +181,14 @@ public class SeekbarPreviewThumbnailHolder { final Bitmap bitmap = PicassoHelper.loadSeekbarThumbnailPreview(url).get(); if (sw != null) { - Log.d(TAG, - "Download of bitmap for seekbarPreview from '" + url - + "' took " + sw.stop().toString()); + Log.d(TAG, "Download of bitmap for seekbarPreview from '" + url + "' took " + + sw.stop()); } return bitmap; } catch (final Exception ex) { - Log.w(TAG, - "Failed to get bitmap for seekbarPreview from url='" + url - + "' in time", - ex); + Log.w(TAG, "Failed to get bitmap for seekbarPreview from url='" + url + + "' in time", ex); return null; } } @@ -208,32 +197,20 @@ public class SeekbarPreviewThumbnailHolder { return this.currentUpdateRequestIdentifier.equals(requestIdentifier); } - public Optional getBitmapAt(final int positionInMs) { - // Check if the BitmapData is empty - if (seekbarPreviewData.isEmpty()) { - return Optional.empty(); + // Get the frame supplier closest to the requested position + Supplier closestFrame = () -> null; + synchronized (seekbarPreviewData) { + int min = Integer.MAX_VALUE; + for (int i = 0; i < seekbarPreviewData.size(); i++) { + final int pos = Math.abs(seekbarPreviewData.keyAt(i) - positionInMs); + if (pos < min) { + closestFrame = seekbarPreviewData.valueAt(i); + min = pos; + } + } } - // Get the closest frame to the requested position - final int closestIndexPosition = - seekbarPreviewData.keySet().stream() - .min(Comparator.comparingInt(i -> Math.abs(i - positionInMs))) - .orElse(-1); - - // this should never happen, because - // it indicates that "seekbarPreviewData" is empty which was already checked - if (closestIndexPosition == -1) { - return Optional.empty(); - } - - try { - // Get the bitmap for the position (executes the supplier) - return Optional.ofNullable(seekbarPreviewData.get(closestIndexPosition).get()); - } catch (final Exception ex) { - // If there is an error, log it and return Optional.empty - Log.w(TAG, "Unable to get seekbar preview", ex); - return Optional.empty(); - } + return Optional.ofNullable(closestFrame.get()); } } diff --git a/app/src/main/java/org/schabi/newpipe/player/ui/MainPlayerUi.java b/app/src/main/java/org/schabi/newpipe/player/ui/MainPlayerUi.java index 248104738..6226900f6 100644 --- a/app/src/main/java/org/schabi/newpipe/player/ui/MainPlayerUi.java +++ b/app/src/main/java/org/schabi/newpipe/player/ui/MainPlayerUi.java @@ -154,6 +154,16 @@ public final class MainPlayerUi extends VideoPlayerUi implements View.OnLayoutCh protected void initListeners() { super.initListeners(); + binding.screenRotationButton.setOnClickListener(makeOnClickListener(() -> { + // Only if it's not a vertical video or vertical video but in landscape with locked + // orientation a screen orientation can be changed automatically + if (!isVerticalVideo || (isLandscape() && globalScreenOrientationLocked(context))) { + player.getFragmentListener() + .ifPresent(PlayerServiceEventListener::onScreenRotationButtonClicked); + } else { + toggleFullscreen(); + } + })); binding.queueButton.setOnClickListener(v -> onQueueClicked()); binding.segmentsButton.setOnClickListener(v -> onSegmentsClicked()); @@ -173,6 +183,14 @@ public final class MainPlayerUi extends VideoPlayerUi implements View.OnLayoutCh settingsContentObserver); binding.getRoot().addOnLayoutChangeListener(this); + + binding.moreOptionsButton.setOnLongClickListener(v -> { + player.getFragmentListener() + .ifPresent(PlayerServiceEventListener::onMoreOptionsLongClicked); + hideControls(0, 0); + hideSystemUIIfNeeded(); + return true; + }); } @Override @@ -846,23 +864,6 @@ public final class MainPlayerUi extends VideoPlayerUi implements View.OnLayoutCh //////////////////////////////////////////////////////////////////////////*/ //region Click listeners - @Override - public void onClick(final View v) { - if (v.getId() == binding.screenRotationButton.getId()) { - // Only if it's not a vertical video or vertical video but in landscape with locked - // orientation a screen orientation can be changed automatically - if (!isVerticalVideo || (isLandscape() && globalScreenOrientationLocked(context))) { - player.getFragmentListener().ifPresent( - PlayerServiceEventListener::onScreenRotationButtonClicked); - } else { - toggleFullscreen(); - } - } - - // call it later since it calls manageControlsAfterOnClick at the end - super.onClick(v); - } - @Override protected void onPlaybackSpeedClicked() { final AppCompatActivity activity = getParentActivity().orElse(null); @@ -875,18 +876,6 @@ public final class MainPlayerUi extends VideoPlayerUi implements View.OnLayoutCh .show(activity.getSupportFragmentManager(), null); } - @Override - public boolean onLongClick(final View v) { - if (v.getId() == binding.moreOptionsButton.getId() && isFullscreen) { - player.getFragmentListener().ifPresent( - PlayerServiceEventListener::onMoreOptionsLongClicked); - hideControls(0, 0); - hideSystemUIIfNeeded(); - return true; - } - return super.onLongClick(v); - } - @Override public boolean onKeyDown(final int keyCode) { if (keyCode == KeyEvent.KEYCODE_SPACE && isFullscreen) { diff --git a/app/src/main/java/org/schabi/newpipe/player/ui/VideoPlayerUi.java b/app/src/main/java/org/schabi/newpipe/player/ui/VideoPlayerUi.java index 6eb97b8fa..bce75d77f 100644 --- a/app/src/main/java/org/schabi/newpipe/player/ui/VideoPlayerUi.java +++ b/app/src/main/java/org/schabi/newpipe/player/ui/VideoPlayerUi.java @@ -84,11 +84,11 @@ import org.schabi.newpipe.util.external_communication.ShareUtils; import org.schabi.newpipe.views.player.PlayerFastSeekOverlay; import java.util.List; +import java.util.Objects; import java.util.Optional; import java.util.stream.Collectors; -public abstract class VideoPlayerUi extends PlayerUi - implements SeekBar.OnSeekBarChangeListener, View.OnClickListener, View.OnLongClickListener, +public abstract class VideoPlayerUi extends PlayerUi implements SeekBar.OnSeekBarChangeListener, PopupMenu.OnMenuItemClickListener, PopupMenu.OnDismissListener { private static final String TAG = VideoPlayerUi.class.getSimpleName(); @@ -132,9 +132,11 @@ public abstract class VideoPlayerUi extends PlayerUi private GestureDetector gestureDetector; private BasePlayerGestureListener playerGestureListener; - @Nullable private View.OnLayoutChangeListener onLayoutChangeListener = null; + @Nullable + private View.OnLayoutChangeListener onLayoutChangeListener = null; - @NonNull private final SeekbarPreviewThumbnailHolder seekbarPreviewThumbnailHolder = + @NonNull + private final SeekbarPreviewThumbnailHolder seekbarPreviewThumbnailHolder = new SeekbarPreviewThumbnailHolder(); @@ -187,13 +189,13 @@ public abstract class VideoPlayerUi extends PlayerUi abstract BasePlayerGestureListener buildGestureListener(); protected void initListeners() { - binding.qualityTextView.setOnClickListener(this); - binding.playbackSpeed.setOnClickListener(this); + binding.qualityTextView.setOnClickListener(makeOnClickListener(this::onQualityClicked)); + binding.playbackSpeed.setOnClickListener(makeOnClickListener(this::onPlaybackSpeedClicked)); binding.playbackSeekBar.setOnSeekBarChangeListener(this); - binding.captionTextView.setOnClickListener(this); - binding.resizeTextView.setOnClickListener(this); - binding.playbackLiveSync.setOnClickListener(this); + binding.captionTextView.setOnClickListener(makeOnClickListener(this::onCaptionClicked)); + binding.resizeTextView.setOnClickListener(makeOnClickListener(this::onResizeClicked)); + binding.playbackLiveSync.setOnClickListener(makeOnClickListener(player::seekToDefault)); playerGestureListener = buildGestureListener(); gestureDetector = new GestureDetector(context, playerGestureListener); @@ -202,20 +204,36 @@ public abstract class VideoPlayerUi extends PlayerUi binding.repeatButton.setOnClickListener(v -> onRepeatClicked()); binding.shuffleButton.setOnClickListener(v -> onShuffleClicked()); - binding.playPauseButton.setOnClickListener(this); - binding.playPreviousButton.setOnClickListener(this); - binding.playNextButton.setOnClickListener(this); + binding.playPauseButton.setOnClickListener(makeOnClickListener(player::playPause)); + binding.playPreviousButton.setOnClickListener(makeOnClickListener(player::playPrevious)); + binding.playNextButton.setOnClickListener(makeOnClickListener(player::playNext)); - binding.moreOptionsButton.setOnClickListener(this); - binding.moreOptionsButton.setOnLongClickListener(this); - binding.share.setOnClickListener(this); - binding.share.setOnLongClickListener(this); - binding.fullScreenButton.setOnClickListener(this); - binding.screenRotationButton.setOnClickListener(this); - binding.playWithKodi.setOnClickListener(this); - binding.openInBrowser.setOnClickListener(this); - binding.playerCloseButton.setOnClickListener(this); - binding.switchMute.setOnClickListener(this); + binding.moreOptionsButton.setOnClickListener( + makeOnClickListener(this::onMoreOptionsClicked)); + binding.share.setOnClickListener(makeOnClickListener(() -> { + final PlayQueueItem currentItem = player.getCurrentItem(); + if (currentItem != null) { + ShareUtils.shareText(context, currentItem.getTitle(), + player.getVideoUrlAtCurrentTime(), currentItem.getThumbnailUrl()); + } + })); + binding.share.setOnLongClickListener(v -> { + ShareUtils.copyToClipboard(context, player.getVideoUrlAtCurrentTime()); + return true; + }); + binding.fullScreenButton.setOnClickListener(makeOnClickListener(() -> { + player.setRecovery(); + NavigationHelper.playOnMainPlayer(context, + Objects.requireNonNull(player.getPlayQueue()), true); + })); + binding.playWithKodi.setOnClickListener(makeOnClickListener(this::onPlayWithKodiClicked)); + binding.openInBrowser.setOnClickListener(makeOnClickListener(this::onOpenInBrowserClicked)); + binding.playerCloseButton.setOnClickListener(makeOnClickListener(() -> + // set package to this app's package to prevent the intent from being seen outside + context.sendBroadcast(new Intent(VideoDetailFragment.ACTION_HIDE_MAIN_PLAYER) + .setPackage(App.PACKAGE_NAME)) + )); + binding.switchMute.setOnClickListener(makeOnClickListener(player::toggleMute)); ViewCompat.setOnApplyWindowInsetsListener(binding.itemsListPanel, (view, windowInsets) -> { final Insets cutout = windowInsets.getInsets(WindowInsetsCompat.Type.displayCutout()); @@ -229,11 +247,8 @@ public abstract class VideoPlayerUi extends PlayerUi // player_overlays and fast_seek_overlay too. Without it they will be off-centered. onLayoutChangeListener = (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> { - binding.playerOverlays.setPadding( - v.getPaddingLeft(), - v.getPaddingTop(), - v.getPaddingRight(), - v.getPaddingBottom()); + binding.playerOverlays.setPadding(v.getPaddingLeft(), v.getPaddingTop(), + v.getPaddingRight(), v.getPaddingBottom()); // If we added padding to the fast seek overlay, too, it would not go under the // system ui. Instead we apply negative margins equal to the window insets of @@ -603,11 +618,6 @@ public abstract class VideoPlayerUi extends PlayerUi player.changeState(STATE_PAUSED_SEEK); } - player.saveWasPlaying(); - if (player.isPlaying()) { - player.getExoPlayer().pause(); - } - showControls(0); animate(binding.currentDisplaySeek, true, DEFAULT_CONTROLS_DURATION, AnimationType.SCALE_AND_ALPHA); @@ -622,7 +632,7 @@ public abstract class VideoPlayerUi extends PlayerUi } player.seekTo(seekBar.getProgress()); - if (player.wasPlaying() || player.getExoPlayer().getDuration() == seekBar.getProgress()) { + if (player.getExoPlayer().getDuration() == seekBar.getProgress()) { player.getExoPlayer().play(); } @@ -636,9 +646,8 @@ public abstract class VideoPlayerUi extends PlayerUi if (!player.isProgressLoopRunning()) { player.startProgressLoop(); } - if (player.wasPlaying()) { - showControlsThenHide(); - } + + showControlsThenHide(); } //endregion @@ -1173,8 +1182,6 @@ public abstract class VideoPlayerUi extends PlayerUi binding.qualityTextView.setText(MediaFormat.getNameById(videoStream.getFormatId()) + " " + videoStream.getResolution()); } - - player.saveWasPlaying(); } /** @@ -1326,86 +1333,39 @@ public abstract class VideoPlayerUi extends PlayerUi //////////////////////////////////////////////////////////////////////////*/ //region Click listeners - @Override - public void onClick(final View v) { - if (DEBUG) { - Log.d(TAG, "onClick() called with: v = [" + v + "]"); - } - if (v.getId() == binding.resizeTextView.getId()) { - onResizeClicked(); - } else if (v.getId() == binding.captionTextView.getId()) { - onCaptionClicked(); - } else if (v.getId() == binding.playbackLiveSync.getId()) { - player.seekToDefault(); - } else if (v.getId() == binding.playPauseButton.getId()) { - player.playPause(); - } else if (v.getId() == binding.playPreviousButton.getId()) { - player.playPrevious(); - } else if (v.getId() == binding.playNextButton.getId()) { - player.playNext(); - } else if (v.getId() == binding.moreOptionsButton.getId()) { - onMoreOptionsClicked(); - } else if (v.getId() == binding.share.getId()) { - final PlayQueueItem currentItem = player.getCurrentItem(); - if (currentItem != null) { - ShareUtils.shareText(context, currentItem.getTitle(), - player.getVideoUrlAtCurrentTime(), currentItem.getThumbnailUrl()); - } - } else if (v.getId() == binding.playWithKodi.getId()) { - onPlayWithKodiClicked(); - } else if (v.getId() == binding.openInBrowser.getId()) { - onOpenInBrowserClicked(); - } else if (v.getId() == binding.fullScreenButton.getId()) { - player.setRecovery(); - NavigationHelper.playOnMainPlayer(context, player.getPlayQueue(), true); - return; - } else if (v.getId() == binding.switchMute.getId()) { - player.toggleMute(); - } else if (v.getId() == binding.playerCloseButton.getId()) { - // set package to this app's package to prevent the intent from being seen outside - context.sendBroadcast(new Intent(VideoDetailFragment.ACTION_HIDE_MAIN_PLAYER) - .setPackage(App.PACKAGE_NAME)); - } else if (v.getId() == binding.playbackSpeed.getId()) { - onPlaybackSpeedClicked(); - } else if (v.getId() == binding.qualityTextView.getId()) { - onQualityClicked(); - } - - manageControlsAfterOnClick(v); - } - /** - * Manages the controls after a click occurred on the player UI. - * @param v – The view that was clicked + * Create on-click listener which manages the player controls after the view on-click action. + * + * @param runnable The action to be executed. + * @return The view click listener. */ - public void manageControlsAfterOnClick(@NonNull final View v) { - if (player.getCurrentState() == STATE_COMPLETED) { - return; - } + protected View.OnClickListener makeOnClickListener(@NonNull final Runnable runnable) { + return v -> { + if (DEBUG) { + Log.d(TAG, "onClick() called with: v = [" + v + "]"); + } - controlsVisibilityHandler.removeCallbacksAndMessages(null); - showHideShadow(true, DEFAULT_CONTROLS_DURATION); - animate(binding.playbackControlRoot, true, DEFAULT_CONTROLS_DURATION, - AnimationType.ALPHA, 0, () -> { - if (player.getCurrentState() == STATE_PLAYING && !isSomePopupMenuVisible) { - if (v.getId() == binding.playPauseButton.getId() - // Hide controls in fullscreen immediately - || (v.getId() == binding.screenRotationButton.getId() - && isFullscreen())) { - hideControls(0, 0); - } else { - hideControls(DEFAULT_CONTROLS_DURATION, DEFAULT_CONTROLS_HIDE_TIME); + runnable.run(); + + // Manages the player controls after handling the view click. + if (player.getCurrentState() == STATE_COMPLETED) { + return; + } + controlsVisibilityHandler.removeCallbacksAndMessages(null); + showHideShadow(true, DEFAULT_CONTROLS_DURATION); + animate(binding.playbackControlRoot, true, DEFAULT_CONTROLS_DURATION, + AnimationType.ALPHA, 0, () -> { + if (player.getCurrentState() == STATE_PLAYING && !isSomePopupMenuVisible) { + if (v == binding.playPauseButton + // Hide controls in fullscreen immediately + || (v == binding.screenRotationButton && isFullscreen())) { + hideControls(0, 0); + } else { + hideControls(DEFAULT_CONTROLS_DURATION, DEFAULT_CONTROLS_HIDE_TIME); + } } - } - }); - } - - @Override - public boolean onLongClick(final View v) { - if (v.getId() == binding.share.getId()) { - ShareUtils.copyToClipboard(context, player.getVideoUrlAtCurrentTime()); - } - return true; + }); + }; } public boolean onKeyDown(final int keyCode) { diff --git a/app/src/main/java/org/schabi/newpipe/settings/AppearanceSettingsFragment.java b/app/src/main/java/org/schabi/newpipe/settings/AppearanceSettingsFragment.java index 550d64d06..ef0e8670c 100644 --- a/app/src/main/java/org/schabi/newpipe/settings/AppearanceSettingsFragment.java +++ b/app/src/main/java/org/schabi/newpipe/settings/AppearanceSettingsFragment.java @@ -44,7 +44,13 @@ public class AppearanceSettingsFragment extends BasePreferenceFragment { return false; }); } else { - removePreference(nightThemeKey); + // disable the night theme selection + final Preference preference = findPreference(nightThemeKey); + if (preference != null) { + preference.setEnabled(false); + preference.setSummary(getString(R.string.night_theme_available, + getString(R.string.auto_device_theme_title))); + } } } @@ -61,13 +67,6 @@ public class AppearanceSettingsFragment extends BasePreferenceFragment { return super.onPreferenceTreeClick(preference); } - private void removePreference(final String preferenceKey) { - final Preference preference = findPreference(preferenceKey); - if (preference != null) { - getPreferenceScreen().removePreference(preference); - } - } - private void applyThemeChange(final String beginningThemeKey, final String themeKey, final Object newValue) { diff --git a/app/src/main/java/org/schabi/newpipe/util/PermissionHelper.java b/app/src/main/java/org/schabi/newpipe/util/PermissionHelper.java index f3151ec8b..f47494770 100644 --- a/app/src/main/java/org/schabi/newpipe/util/PermissionHelper.java +++ b/app/src/main/java/org/schabi/newpipe/util/PermissionHelper.java @@ -21,6 +21,7 @@ import org.schabi.newpipe.R; import org.schabi.newpipe.settings.NewPipeSettings; public final class PermissionHelper { + public static final int POST_NOTIFICATIONS_REQUEST_CODE = 779; public static final int DOWNLOAD_DIALOG_REQUEST_CODE = 778; public static final int DOWNLOADS_REQUEST_CODE = 777; @@ -71,8 +72,7 @@ public final class PermissionHelper { // No explanation needed, we can request the permission. ActivityCompat.requestPermissions(activity, - new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, - requestCode); + new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, requestCode); // PERMISSION_WRITE_STORAGE is an // app-defined int constant. The callback method gets the @@ -83,6 +83,18 @@ public final class PermissionHelper { return true; } + public static boolean checkPostNotificationsPermission(final Activity activity, + final int requestCode) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU + && ContextCompat.checkSelfPermission(activity, + Manifest.permission.POST_NOTIFICATIONS) + != PackageManager.PERMISSION_GRANTED) { + ActivityCompat.requestPermissions(activity, + new String[] {Manifest.permission.POST_NOTIFICATIONS}, requestCode); + return false; + } + return true; + } /** * In order to be able to draw over other apps, diff --git a/app/src/main/java/org/schabi/newpipe/util/StreamItemAdapter.java b/app/src/main/java/org/schabi/newpipe/util/StreamItemAdapter.java index 4b5e675c9..74de45720 100644 --- a/app/src/main/java/org/schabi/newpipe/util/StreamItemAdapter.java +++ b/app/src/main/java/org/schabi/newpipe/util/StreamItemAdapter.java @@ -1,7 +1,6 @@ package org.schabi.newpipe.util; import android.content.Context; -import android.util.SparseArray; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -11,6 +10,8 @@ import android.widget.Spinner; import android.widget.TextView; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.collection.SparseArrayCompat; import org.schabi.newpipe.DownloaderImpl; import org.schabi.newpipe.R; @@ -39,10 +40,10 @@ import us.shandian.giga.util.Utility; * @param the secondary stream type's class extending {@link Stream} */ public class StreamItemAdapter extends BaseAdapter { - private final Context context; - + @NonNull private final StreamSizeWrapper streamsWrapper; - private final SparseArray> secondaryStreams; + @NonNull + private final SparseArrayCompat> secondaryStreams; /** * Indicates that at least one of the primary streams is an instance of {@link VideoStream}, @@ -51,9 +52,10 @@ public class StreamItemAdapter extends BaseA */ private final boolean hasAnyVideoOnlyStreamWithNoSecondaryStream; - public StreamItemAdapter(final Context context, final StreamSizeWrapper streamsWrapper, - final SparseArray> secondaryStreams) { - this.context = context; + public StreamItemAdapter( + @NonNull final StreamSizeWrapper streamsWrapper, + @NonNull final SparseArrayCompat> secondaryStreams + ) { this.streamsWrapper = streamsWrapper; this.secondaryStreams = secondaryStreams; @@ -61,15 +63,15 @@ public class StreamItemAdapter extends BaseA checkHasAnyVideoOnlyStreamWithNoSecondaryStream(); } - public StreamItemAdapter(final Context context, final StreamSizeWrapper streamsWrapper) { - this(context, streamsWrapper, null); + public StreamItemAdapter(final StreamSizeWrapper streamsWrapper) { + this(streamsWrapper, new SparseArrayCompat<>(0)); } public List getAll() { return streamsWrapper.getStreamsList(); } - public SparseArray> getAllSecondary() { + public SparseArrayCompat> getAllSecondary() { return secondaryStreams; } @@ -106,6 +108,7 @@ public class StreamItemAdapter extends BaseA final View view, final ViewGroup parent, final boolean isDropdownItem) { + final var context = parent.getContext(); View convertView = view; if (convertView == null) { convertView = LayoutInflater.from(context).inflate( @@ -129,7 +132,7 @@ public class StreamItemAdapter extends BaseA if (hasAnyVideoOnlyStreamWithNoSecondaryStream) { if (videoStream.isVideoOnly()) { - woSoundIconVisibility = hasSecondaryStream(position) + woSoundIconVisibility = secondaryStreams.get(position) != null // It has a secondary stream associated with it, so check if it's a // dropdown view so it doesn't look out of place (missing margin) // compared to those that don't. @@ -163,8 +166,7 @@ public class StreamItemAdapter extends BaseA } if (streamsWrapper.getSizeInBytes(position) > 0) { - final SecondaryStreamHelper secondary = secondaryStreams == null ? null - : secondaryStreams.get(position); + final var secondary = secondaryStreams.get(position); if (secondary != null) { final long size = secondary.getSizeInBytes() + streamsWrapper.getSizeInBytes(position); @@ -196,14 +198,6 @@ public class StreamItemAdapter extends BaseA return convertView; } - /** - * @param position which primary stream to check. - * @return whether the primary stream at position has a secondary stream associated with it. - */ - private boolean hasSecondaryStream(final int position) { - return secondaryStreams != null && secondaryStreams.get(position) != null; - } - /** * @return if there are any video-only streams with no secondary stream associated with them. * @see #hasAnyVideoOnlyStreamWithNoSecondaryStream @@ -213,7 +207,7 @@ public class StreamItemAdapter extends BaseA final T stream = streamsWrapper.getStreamsList().get(i); if (stream instanceof VideoStream) { final boolean videoOnly = ((VideoStream) stream).isVideoOnly(); - if (videoOnly && !hasSecondaryStream(i)) { + if (videoOnly && secondaryStreams.get(i) == null) { return true; } } @@ -228,16 +222,15 @@ public class StreamItemAdapter extends BaseA * @param the stream type's class extending {@link Stream} */ public static class StreamSizeWrapper implements Serializable { - private static final StreamSizeWrapper EMPTY = new StreamSizeWrapper<>( - Collections.emptyList(), null); + private static final StreamSizeWrapper EMPTY = + new StreamSizeWrapper<>(Collections.emptyList(), null); private final List streamsList; private final long[] streamSizes; private final String unknownSize; - public StreamSizeWrapper(final List sL, final Context context) { - this.streamsList = sL != null - ? sL - : Collections.emptyList(); + public StreamSizeWrapper(@NonNull final List streamList, + @Nullable final Context context) { + this.streamsList = streamList; this.streamSizes = new long[streamsList.size()]; this.unknownSize = context == null ? "--.-" : context.getString(R.string.unknown_content); @@ -297,10 +290,6 @@ public class StreamItemAdapter extends BaseA return formatSize(getSizeInBytes(streamIndex)); } - public String getFormattedSize(final T stream) { - return formatSize(getSizeInBytes(stream)); - } - private String formatSize(final long size) { if (size > -1) { return Utility.formatBytes(size); @@ -308,10 +297,6 @@ public class StreamItemAdapter extends BaseA return unknownSize; } - public void setSize(final int streamIndex, final long sizeInBytes) { - streamSizes[streamIndex] = sizeInBytes; - } - public void setSize(final T stream, final long sizeInBytes) { streamSizes[streamsList.indexOf(stream)] = sizeInBytes; } diff --git a/app/src/main/java/us/shandian/giga/service/DownloadManagerService.java b/app/src/main/java/us/shandian/giga/service/DownloadManagerService.java index 25ec87f80..dc56ee205 100755 --- a/app/src/main/java/us/shandian/giga/service/DownloadManagerService.java +++ b/app/src/main/java/us/shandian/giga/service/DownloadManagerService.java @@ -1,5 +1,8 @@ package us.shandian.giga.service; +import static org.schabi.newpipe.BuildConfig.APPLICATION_ID; +import static org.schabi.newpipe.BuildConfig.DEBUG; + import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; @@ -22,12 +25,12 @@ import android.os.IBinder; import android.os.Message; import android.os.Parcelable; import android.util.Log; -import android.util.SparseArray; import android.widget.Toast; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.StringRes; +import androidx.collection.SparseArrayCompat; import androidx.core.app.NotificationCompat; import androidx.core.app.NotificationCompat.Builder; import androidx.core.app.ServiceCompat; @@ -37,24 +40,21 @@ import androidx.preference.PreferenceManager; import org.schabi.newpipe.R; import org.schabi.newpipe.download.DownloadActivity; import org.schabi.newpipe.player.helper.LockManager; - -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; - -import us.shandian.giga.get.DownloadMission; -import us.shandian.giga.get.MissionRecoveryInfo; import org.schabi.newpipe.streams.io.StoredDirectoryHelper; import org.schabi.newpipe.streams.io.StoredFileHelper; import org.schabi.newpipe.util.Localization; import org.schabi.newpipe.util.PendingIntentCompat; +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import us.shandian.giga.get.DownloadMission; +import us.shandian.giga.get.MissionRecoveryInfo; import us.shandian.giga.postprocessing.Postprocessing; import us.shandian.giga.service.DownloadManager.NetworkState; -import static org.schabi.newpipe.BuildConfig.APPLICATION_ID; -import static org.schabi.newpipe.BuildConfig.DEBUG; - public class DownloadManagerService extends Service { private static final String TAG = "DownloadManagerService"; @@ -95,7 +95,7 @@ public class DownloadManagerService extends Service { private Builder downloadDoneNotification = null; private StringBuilder downloadDoneList = null; - private final ArrayList mEchoObservers = new ArrayList<>(1); + private final List mEchoObservers = new ArrayList<>(1); private ConnectivityManager mConnectivityManager; private ConnectivityManager.NetworkCallback mNetworkStateListenerL = null; @@ -108,7 +108,8 @@ public class DownloadManagerService extends Service { private int downloadFailedNotificationID = DOWNLOADS_NOTIFICATION_ID + 1; private Builder downloadFailedNotification = null; - private final SparseArray mFailedDownloads = new SparseArray<>(5); + private final SparseArrayCompat mFailedDownloads = + new SparseArrayCompat<>(5); private Bitmap icLauncher; private Bitmap icDownloadDone; @@ -277,7 +278,7 @@ public class DownloadManagerService extends Service { } if (msg.what != MESSAGE_ERROR) - mFailedDownloads.delete(mFailedDownloads.indexOfValue(mission)); + mFailedDownloads.remove(mFailedDownloads.indexOfValue(mission)); for (Callback observer : mEchoObservers) observer.handleMessage(msg); @@ -461,7 +462,7 @@ public class DownloadManagerService extends Service { } public void notifyFailedDownload(DownloadMission mission) { - if (!mDownloadNotificationEnable || mFailedDownloads.indexOfValue(mission) >= 0) return; + if (!mDownloadNotificationEnable || mFailedDownloads.containsValue(mission)) return; int id = downloadFailedNotificationID++; mFailedDownloads.put(id, mission); diff --git a/app/src/main/res/layout/playlist_control.xml b/app/src/main/res/layout/playlist_control.xml index 5a8856128..685082013 100644 --- a/app/src/main/res/layout/playlist_control.xml +++ b/app/src/main/res/layout/playlist_control.xml @@ -48,6 +48,8 @@ + \ No newline at end of file diff --git a/app/src/main/res/values-az/strings.xml b/app/src/main/res/values-az/strings.xml index a4491688f..22f3ba5e5 100644 --- a/app/src/main/res/values-az/strings.xml +++ b/app/src/main/res/values-az/strings.xml @@ -5,7 +5,7 @@ Yayım oynadıcı tapılmadı. \"VLC\" yüklənilsin\? Yayım oynadıcı tapılmadı (Oynatmaq üçün VLC\'ni quraşdıra bilərsiniz). Yüklə - İmtina + Ləğv et Brauzerdə aç Paylaş Endir @@ -17,7 +17,7 @@ Xarici video oynadıcı istifadə et Bəzi qətnamələrdə səsi silir Xarici səs oynadıcı istifadə et - Abunə Olun + Abunə Ol Abunə olundu Kanal abunəliyi ləğv edildi Məlumat göstər @@ -30,7 +30,7 @@ Video faylları üçün endirmə qovluğunu seç Səs endirmə qovluğu Endirilmiş səs faylları burada saxlanılır - Səs faylları üçün endirmə qovluğunu seç + Səs faylları üçün endirmə qovluğu seç Defolt keyfiyyət Daha böyük keyfiyyət seçimləri göstər \"Kodi\" ilə Oynat @@ -40,13 +40,13 @@ Səs Defolt səs formatı Defolt video formatı - Mövzu + Tema İşıqlı Qaranlıq Qara Abunəlikdən çıxın Ani pəncərə rejimində aç - Avtomatik oynatma + Avtomatik oynat Endir Fasilələrdən sonra (məsələn, telefon zəngləri) oynatmağa davam etdir Oynatmanı davam etdir @@ -54,24 +54,24 @@ Məlumat təmizlə Siyahılarda oynatma mövqelərini göstər Siyahılardakı mövqelər - Son oynatma mövqeyinə qaytar + Son oynatma mövqeyini qaytar Oynatmanı davam etdir Baxış tarixçəsi Axtarış sorğularını yerli olaraq saxla Axtarış tarixçəsi Axtarış edərkən göstəriləcək təklifləri seç Axtarış təklifləri - Oynadıcının parlaqlığını nizamlamaq üçün jestlərdən istifadə et - Parlaqlığı jestlə nizamlama - Oynadıcının səsini nizamlamaq üçün jestlərdən istifadə et - Səsi jestlə nizamla - Avto-növbələmə - Növbəti Yayımı Avto-növbələmə + Oynadıcının parlaqlığını nizamlamaq üçün jestləri istifadə et + Parlaqlığı jestlə nizamlamaq + Oynadıcı səsini nizamlamaq üçün jestləri istifadə et + Səsi jestlə idarə etmək + Avto-növbələ + Növbəti Yayımı Avto-növbələ Üst məlumat keşi silindi Keşlənmiş bütün veb-səhifə məlumatlarını sil Keşlənmiş üst məlumatı təmizlə Şəkil keşi silindi - Şərhləri gizlətmək üçün söndür + Şərhləri gizlətmək üçün bağla Şərhləri göstər Aktiv oynadıcının növbəsi dəyişdiriləcək Bir oynadıcıdan digərinə keçid növbənizi dəyişdirə bilər @@ -94,7 +94,7 @@ Ani Pəncərə Paneli Seç Abunəliyi yeniləmək alınmadı - Abunəliyi dəyişdirmək alınmadı + Abunəliyi dəyişmək alınmadı Nəticələr göstərilir: %s Kanallar %s tərəfindən @@ -102,8 +102,8 @@ Yaş həddi səbəbiylə (məsələn, 18+) uşaqlar üçün uyğun olmayan məzmunu göstər Yaş məhdudiyyətli məzmunu göstər Məzmun - Ani pəncərədə oynadılır - Arxa fonda oynadılır + Ani pəncərə rejimində oynadılır + Fonda oynadılır Yeniləmələr Sazlama Görünüş @@ -115,7 +115,7 @@ Defolt məzmun ölkəsi URL\'i tanımaq olmadı. Başqa tətbiqlə açılsın\? Dəstəklənməyən URL\'i - \"Növbəyə əlavə etmək üçün basılı saxla\" ipucusun göstər + \"Növbələmək üçün basılı saxla\" tövsiyəsin göstər \"Növbəti\" və \"Bənzər\" videoları göstər Tarixçəni, abunəlikləri, pleylistləri və tənzimləmələri ixrac edin Cari tarixçənizi, abunəliklərinizi, pleylistlərinizi və (könüllü) tənzimləmələrinizi etibarsız edir @@ -179,7 +179,7 @@ Xəta Axtarış tarixçəsi silindi Bütün axtarış tarixçəsi silinsin\? - Axtarışdakı açar sözlərin tarixçəsini silir + Açar sözləri axtarışının tarixçəsini silir Axtarış tarixçəsini silin Oynatma mövqeləri silindi Bütün oynatma mövqeləri silinsin\? @@ -208,7 +208,7 @@ Mobil internet istifadə edərkən görüntü keyfiyyətini məhdudlaşdır Limitsiz 1 element silindi. - Server əlavə edin + Nümunə əlavə et Sevimli \"PeerTube\" nümunələrinizi seçin Endirilmiş faylları silin Endirmə tarixçənizi təmizləmək və ya endirilmiş bütün faylları silmək istəyirsiniz\? @@ -217,7 +217,7 @@ Endirmələri dayandır Haraya endiriləcəyini soruş Sizdən hər endirmənin harada saxlanılacağı soruşulacaq. -\nXarici SD karta yükləmək istəyirsinizsə, sistem qovluğu seçicisini (SAF) aktiv edin +\nXarici SD karta endirmək istəyirsinizsə, sistem qovluğu seçicisini (SAF) aktiv edin \'Yaddaş Giriş Çərçivəsi \' xarici SD karta endirməyə imkan verir Sistem defoltu Tətbiq dili @@ -262,7 +262,7 @@ Xarici yaddaş əlçatan deyil Oynadılmış yayımlar tarixçəsini və oynatma mövqelərini silir Üst məlumatı göstər - Video açıqlamasını və əlavə məlumatı gizlətmək üçün söndürün + Video açıqlamasını və əlavə məlumatı gizlətmək üçün bağla Açıqlamanı göstər Bildirişi rəngləndir Belə qovluq yoxdur @@ -270,10 +270,10 @@ Xarici oynadıcılar bu cür linkləri dəstəkləmir Yerli axtarış təklifləri Video - Əlaqədar yayımlar + Əlaqəli elementlər Baxılmış kimi işarələ ilə aç - Gecə Mövzusu + Gecə Teması Ani pəncərə xüsusiyyətlərini xatırla Ani pəncərənin son ölçüsü və mövqeyini xatırla Video yayımı tapılmadı @@ -292,7 +292,7 @@ Digər tətbiqlərin üzərində göstərməyə icazə ver İlkin tənzimləmələri qaytarmaq istəyirsiniz\? Miniatürlərin yüklənməsini, dataya qənaət etmək və yaddaşdan istifadəni azaltmaq üçün söndürün. Dəyişikliklər həm yaddaşdaxili, həm də diskdə olan təsvir keşini təmizləyir - Növbətini sıraya salın + Növbətini növbələ Yenidən Cəhd Et Cari oynatma yayımı bildirişini konfiqurasiya et Bildirişlər @@ -302,7 +302,7 @@ Fayl adı boş ola bilməz Yadda saxlanmış tabları oxumaq mümkün olmadı, buna görə defolt tablardan istifadə edin NewPipe xəta ilə qarşılaşdı, bildirmək üçün toxun - Bağışlayın, belə olmamalı idi. + Bağışlayın, o baş verməməli idi. Bu xətanı e-poçt vasitəsilə bildirin GitHub\'da Hesabat Ver Zəhmət olmasa, xətanızı müzakirə edən məsələnin mövcud olub-olmadığını yoxlayın. Dublikat biletləri yaradarkən, bizdən faktiki səhvi düzəltməyə sərf edəcəyimiz vaxt alırsınız. @@ -324,7 +324,7 @@ Video yoxdur Şərhlər qeyri-aktivdir Başlat - Dayandır + Fasilə Təsdiqləmə İmtina Xəta @@ -386,7 +386,7 @@ Avtomatik yaradıldı Altyazılar LeakCanary yoxdur - Yaddaş sızmasının monitorinqi yığın boşaltma zamanı tətbiqin cavab verməməsinə səbəb ola bilər + Yaddaş sızma monitorinqi yığın boşaltma zamanı tətbiqin cavab verməməsinə səbəb ola bilər Yaddaş sızmalarını göstər Utilizasiyadan sonra fraqment və ya fəaliyyətin yaşam dövründən kənarda çatdırıla bilməyən Rx istisnaları barədə hesabat verməyə məcbur et Xidmətlərdən alınmış orijinal mətnlər yayım elementlərində görünəcək @@ -430,8 +430,8 @@ Ən Yeni Bu məzmun ölkənizdə mövcud deyil. Bu məzmun yalnız ödəniş etmiş istifadəçilər üçün əlçatandır, ona görə də NewPipe tərəfindən yayımlana və ya endirilə bilməz. - Avtomatik (cihaz mövzusu) - Sevimli gecə mövzunuzu seçin — %s + Avtomatik (cihaz teması) + Sevimli gecə temanızı seçin — %s Sabitlənmiş şərh Bildirişlər deaktiv edilib Bildiriş al @@ -464,7 +464,7 @@ Sizdən hər endirmənin harada saxlanılacağı soruşulacaq \"Yaddaş Giriş Çərçivəsi\"yalnız Android 10\'dan başlayaraq dəstəklənir Kanalın avatar miniatürü - Sevdiyiniz gecə mövzusunu aşağıda seçə bilərsiniz + Sevdiyiniz gecə temasını aşağıda seçə bilərsiniz Android\'in bildiriş rəngini miniatürdəki əsas rəngə uyğun fərdiləşdirməsini təmin et (qeyd edək ki, bu, bütün cihazlarda mövcud deyil) GitHub\'da Bax İanə Et @@ -498,10 +498,10 @@ Miniatürü 1:1 görünüş nisbətinə kəs Yükləmə intervalının həcmini dəyişdir (hazırda %s). Daha aşağı dəyər ilkin video yükləməni sürətləndirə bilər. Dəyişikliklər oynadıcının yenidən başladılmasını tələb edir Yayım yaradıcısı, məzmunu və ya axtarış sorğusu haqqında əlavə məlumat olan üst məlumat qutularını gizlətmək üçün söndürün - Əlaqədar yayımı əlavə etməklə (təkrarlanmayan) sonlanacaq oynatma sırasını davam etdir + Əlaqəli yayımı əlavə etməklə (təkrarlanmayan) sonlanacaq oynatma növbəsini davam etdir Kənar axtarış təklifləri - Server artıq mövcuddur - Videoları mini oynadıcıda başlatma, avtomatik fırlatma kilidlidirsə, birbaşa tam ekran rejiminə keçid. Siz hələ də tam ekran rejimindən çıxmaqla mini pleyerə daxil ola bilərsiniz + Nümunə artıq mövcuddur + Videoları mini oynadıcıda başlatma, avtomatik fırlatma kilidlidirsə, birbaşa tam ekran rejiminə keçid. Siz hələ də tam ekrandan çıxmaqla mini oynadıcıya daxil ola bilərsiniz 100+ video ∞ video Şərhlər yoxdur @@ -548,7 +548,7 @@ Yarımton Endirmə tamamlandı - %s endirmələr tamamlandı + %s endirmə tamamlandı Defolt ExoPlayer Mövcud olduqda xüsusi axından al @@ -605,11 +605,11 @@ Nə:\\nTələb:\\nMəzmun Dili:\\nMəzmun Ölkəsi:\\nTətbiq Dili:\\nXidmət:\\nGMT Saatı:\\nPaket:\\nVersiya:\\nƏS versiyası: Bağışlayın, nəsə xəta baş verdi. Formatlanmış hesabatı kopyala - Server URL\'sini daxil edin - Serveri doğrulamaq mümkün olmadı + Nümunə URL\'sini daxil et + Nümunəni doğrulamaq mümkün olmadı %s-də bəyəndiyiniz nümunələri tapın Video \"Təfsilatlar:\"səhifəsində fon və ya ani pəncərə düyməsini basarkən ipucu göstər - Oynadıcı altyazı miqyasını və arxa fon üslublarını dəyişdirin. Effektiv olması üçün tətbiqin yenidən başladılması tələb olunur + Oynadıcı altyazı mətn miqyasını və arxa fon üslublarını dəyişdirin. Effektiv olması üçün tətbiqi yenidən başlatmaq tələb olunur Xəta baş verdi: %1$s Fayl mövcud deyil, yaxud oxumaq və ya yazmaq icazəsi yoxdur Veb saytı təhlil etmək alınmadı @@ -654,7 +654,7 @@ Video URL\'i imzasının şifrəsi qırılmadı Endirmək üçün heç bir yayım yoxdur Xəta baş verdi, bildirişə baxın - Şərhiniz (İngilis dilində): + Şərhiniz (İngiliscə): Video oynat, müddət: Zəhmət olmasa, daha sonra tənzimləmələrdə endirmə qovluğunu təyin et NewPipe Endirilir @@ -704,8 +704,8 @@ \nZəhmət olmasa ,Yaddaş Giriş Çərçivəsinə uyğun fayl menecerini quraşdırın Bu video yalnız YouTube Music Premium üzvləri üçün əlçatandır, ona görə də NewPipe tərəfindən yayımlamaq və ya endirmək mümkün deyil. İndi açıqlamadakı mətni seçə bilərsiniz. Nəzərə alın ki, seçim rejimində səhifə titrəyə və keçidlər kliklənməyə bilər. - Bildirişdə göstərilən video miniatürünü 16:9-dan 1:1 nisbətinə qədər kəs - Aşağıdakı bildiriş fəaliyyətini hər birinin üzərinə toxunaraq redaktə edin. Sağdakı təsdiq qutularından istifadə edərək yığcam bildirişdə göstərilməsi üçün onlardan üçə qədərini seç + Bildirişdə göstərilən video miniatürünü 16:9-dan 1:1 görünüş nisbətinə qədər kəs + Aşağıdakı bildiriş fəaliyyətini hər birinin üzərinə toxunaraq redaktə edin. Sağdakı təsdiq qutularından istifadə edərək yığcam bildirişdə göstərilməsi üçün onların üçə qədərini seç Belə fayl/məzmun mənbəyi yoxdur Seçilmiş yayım xarici oynadıcılar tərəfindən dəstəklənmir Yükləyici tərəfindən hələ dəstəklənməyən yayımlar göstərilmir diff --git a/app/src/main/res/values-hi/strings.xml b/app/src/main/res/values-hi/strings.xml index df6d3f3d3..b4f9fadc0 100644 --- a/app/src/main/res/values-hi/strings.xml +++ b/app/src/main/res/values-hi/strings.xml @@ -18,7 +18,7 @@ ध्वनि रौशनी काला - देखे हुए विडियोज का इतिहास + देखे हुए वीडियोज़ का इतिहास डाउनलोड करे वीडियो और ऑडियो इतिहास और कैश @@ -29,7 +29,7 @@ तृतीय-पक्ष लाइसेंस ऐप के बारे में और सामान्य प्रश्न लाइसेंस - GitHub में देखें + गिटहब में देखें न्यूपाइप का लाइसेंस लाइसेंस पढ़ें योगदान करें @@ -41,12 +41,12 @@ रद्द करें क्या आप का मतलब \"%1$s\" था\? के साथ शेयर करे - कोई दूसरा विडियो चालक प्रयोग करें - कुछ विडियो गुणवत्ता स्तर पर ध्वनि हट सकती है + कोई दूसरा वीडियो चालक प्रयोग करें + कुछ वीडियो गुणवत्ता स्तर पर ध्वनि हट सकती है कोई दूसरा ध्वनि चालक उपयोग करें सब्सक्रिप्शन बदली नहीं जा सकी सब्सक्रिप्शन अपडेट नहीं किया जा सका - देखे की क्या नया है + देखें कि क्या नया है वीडियो डाउनलोड का फ़ोल्डर डाउनलोड की गई वीडियो फ़ाइलें यहां संग्रहीत हैं वीडियो फ़ाइलों के लिए डाउनलोड फ़ोल्डर चुनें @@ -56,33 +56,33 @@ प्रथम स्थापित गुणवत्ता स्तर पॉपअप का प्रथम स्थापित गुणवत्ता स्तर उच्च गुणवत्ता स्तर दिखाएं - केवल कुछ ही यंत्र 2K/4K मे विडियो चला सकते हैं + केवल कुछ ही यंत्र 2K/4K मे वीडियो चला सकते हैं Kodi मे चलाए Kore ऐप नहीं मिली, इसे स्थापित करें\? \"Kodi मे चलाएं\" वाला विकल्प दिखाएँ - Kodi मीडिया सेंटर से विडियो चलने के लिए विकल्प प्रदर्शित करें + कोडी मीडिया सेंटर से वीडियो चलने के लिए विकल्प प्रदर्शित करें प्रथम स्थापित ध्वनि फॉर्मेट - प्रथम स्थापित विडियो फॉर्मेट + प्रथम स्थापित वीडियो फॉर्मेट ऐप थीम गहरा - विडियो पॉपअप का आकर और उसकी स्थति को याद रखे - विडियो पॉपअप की अंतिम स्थिति और आकर को याद रखे + वीडियो पॉपअप का आकार और उसकी स्थिति को याद रखें + वीडियो पॉपअप की अंतिम स्थिति और आकार को याद रखें खोज में सुझाव खोज के दौरान दिखाये जाने वाले सुझाव चुने खोज का इतिहास खोज के डेटा को सिर्फ डिवाइस मेमोरी में रखे - देखे गए विडियोज की सूची रखे + देखे गए वीडियोज़ की सूची रखें प्लेबैक फिर से शुरू करें - रूकावटे खत्म होने के बाद विडियो प्ले करे (जैसे - फ़ोन कॉल) + रुकावटें खत्म होने के बाद वीडियो प्ले करें (जैसे - फ़ोन कॉल) \'अगला\' और \'समान\' वीडियो दिखाए \"कतार में जोड़ने के लिए स्पर्श बनाये रखें\" दिखाएं - जब बैकग्राउंड और पॉपअप बटन विडियो के विवरण पन्ने में दबाई जाए तो सलाह दिखाएं + जब बैकग्राउंड और पॉपअप बटन वीडियो के विवरण पन्ने में दबाई जाए तो सलाह दिखाएं असमर्थित URL डिफ़ॉल्ट विषय की भाषा प्लेयर चाल चलन दिखावट - विडियो पॉपअप के अंदाज में चल रहा + वीडियो पॉपअप के अंदाज में चल रहा विषयवस्तु आयु प्रतिबंधित सामग्री दिखाएं लाइव @@ -92,23 +92,23 @@ सारे बंद करे साफ़ - बेहतर विडियो की क्वालिटी - वापस जाए + बेहतर वीडियो की क्वालिटी + वापस जाएँ सारे प्ले करे NewPipe की सूचनापत्र - न्यूपाइप के बैकग्राउंड में चल रहे विडियो और पॉपअप विडियो के लिए सूचनापत्र + न्यूपाइप के बैकग्राउंड में चल रहे वीडियो और पॉपअप वीडियो के लिए सूचनापत्र [नहीं जानते] त्रुटी नेटवर्क में त्रुटी सारे thumbnail(फोटो जो फ़ोन की मेमोरी में है ) भरे नहीं जा सकते - विडियो के URL signature को decrypt नहीं कर सकते + वीडियो के URL हस्ताक्षर को डीऑबफस्केट नहीं कर सकते इस website का निरंक्षण नहीं कर सकते विषय वस्तु उपलब्ध नहीं है डाउनलोड मेनू को स्थापित नहीं कर सकते APP/UI टूट गया - इस विडियो को चलाने में असफल हुए - कभी ठीक न होने वाले विडियो प्लेयर की त्रुटी आ रही है - विडियो प्लेयर त्रुटी से ठीक हो रहा है + इस वीडियो को चलाने में असफल हुए + कभी ठीक न होने वाले वीडियो प्लेयर की त्रुटी आ रही है + वीडियो प्लेयर त्रुटी से ठीक हो रहा है खेद है की, ऐसा होना नहीं चाहिए था. त्रुटी की रिपोर्ट को ईमेल से भेजे माफ़ करे , कुछ त्रुटियाँ हो रही है @@ -124,7 +124,7 @@ नापसंद कोई परिणाम नहीं मिला यहां के खालीपन को दूर करने के लिए कुछ सर्च करें या किसी चैनल को सब्सक्राइब करें - विडियो + वीडियो ऑडियो फिर से कोशिश करे हज़ार @@ -146,7 +146,7 @@ शुरू रोकें मिटाएँ - checksum + चेकसम ठीक है फाइल का नाम मेसेज के thread @@ -187,10 +187,10 @@ स्ट्रीमिंग करने के लिए कोई चालक उपलब्ध नहीं है (आप इसे चलाने के लिए VLC चालक स्थापित कर सकते हैं)। स्ट्रीम फाइल डाउनलोड करें जानकारी दिखाएं - बुकमार्क किये गए प्लेलिस्टस + बुकमार्क की गई प्लेलिस्टें में शामिल करें डिफ़ॉल्ट देश का विषय - हमेशा के लिए + हमेशा सिर्फ एक बार के लिए बैकग्राउंड में स्विच करें पॉपअप मोड में जाएं @@ -208,7 +208,7 @@ नाम बदलें दान करें न्यूपाइप स्वयंसेवकों द्वारा विकसित किया जाता है जो आपको अच्छा अनुभव देने के लिए अपना खाली समय व्यतीत करते हैं। स्वयंसेवको को मदद भेजे, ताकि वह न्यूपाइप को और अच्छा बना सके। - वापस दे + वापस दें वेबसाइट अधिक जानकारी और खबरों के लिए न्यूपाइप की वेबसाइट पर जाएं। पिछला चलाया गया @@ -281,7 +281,7 @@ \nन्यूपाइप की गोपनीयता नीति विस्तार से समज़ाती है कि कोनसा डेटा भेजा या संग्रह किया जाता है जब आप क्रेश विवरण भेजते है। गोपनीयता नीति पढ़े क्या आप सेटिंग्स भी आयात करना चाहते है? - पसंदीदा \'खोलने\' कि प्रक्रिया + पसंदीदा \'खोलने\' की प्रक्रिया सामग्री खोलते समय डिफ़ॉल्ट कारवाही — %s अनुशीर्षक प्लेयर अनुशीर्षक के शब्दों का परिमाण और पृष्ठभूमि शैलियों को बदले। लागू करने के लिए ऐप को पुनः प्रारम्भ करना जरूरी है @@ -321,7 +321,7 @@ ऐप बदलते समय उसे मिनिमाइज करे मुख्य वीडियो चालक से दूसरी ऐप पर जाने पर — %s कोई नही - पृष्ठभूमि प्लेयर में बदले + बैकग्राउंड प्लेयर में बदले पॉप अप प्लेयर में बदले न्यूपाइप एक काॅपीलेफ़्ट फ़्री साॅफ़्टवेर है: इसे आप अपनी इच्छा के अनुसार इस्तेमाल, जाँच, बाँट तथा और बेहतर बना सकते है। खास तौर पर आप इसे फ़्री साॅफ़्टवेर फ़ाउंडेशन के द्वारा जारी जीएनयू जनरल पब्लिक लाइसेंस के तीसरे या उसके बाद आने वाले कोई भी वर्णन के शर्तों के मुताबिक फिर से बाँट या बदल सकते हैं। अनसब्सक्राईब करें @@ -690,7 +690,7 @@ आइटम्स का असल अपलोड समय दिखाएं सेवाओं से मूल पाठ स्ट्रीम आइटम में दिखाई देंगे प्लेलिस्ट में जोड़े गए पहले और बाद में देखे गए वीडियो हटा दिए जाएंगे। -\nक्या आपको यकीन है\? इसे असंपादित नहीं किया जा सकेगा! +\nक्या यक़ीनन आप ऐसा चाह्ते हैं\? इसे असंपादित नहीं किया जा सकेगा! %d मिनट %d मिनट @@ -712,7 +712,7 @@ निर्माता द्वारा दिया दिल टैबलेट मोड आपने इस चैनल को अब सब्सक्राइब किया है - बाहरी प्लेयरस के लिए कोई विडियो स्ट्रीम उपलब्ध नहीं है + बाहरी प्लेयरस के लिए कोई वीडियो स्ट्रीम उपलब्ध नहीं है बाहरी प्लेयरस के लिए कोई ऑडियो स्ट्रीम उपलब्ध नहीं है कुछ सेवाओं में उपलब्ध, यह आमतौर पर बहुत तेज होता है लेकिन सीमित मात्रा में आइटम और अक्सर अधूरी जानकारी (जैसे कोई अवधि नहीं, आइटम प्रकार, कोई लाइव स्थिति नहीं) लौटा सकता है इस क्रिया के लिए कोई उपयुक्त फ़ाइल प्रबंधक नहीं मिला। diff --git a/app/src/main/res/values-hu/strings.xml b/app/src/main/res/values-hu/strings.xml index 6db9216a7..8a518bda6 100644 --- a/app/src/main/res/values-hu/strings.xml +++ b/app/src/main/res/values-hu/strings.xml @@ -135,9 +135,9 @@ Közvetítési fájl letöltése Hozzáadás ehhez Gyorsabb, de pontatlan tekerés használata - A pontatlan tekerés lehetővé teszi, hogy gyorsabban ugorjon a pozíciókra, de kisebb pontossággal. Az 5, 15, vagy 25 másodperces tekerés nem működik ebben a módban. + A pontatlan tekerés lehetővé teszi, hogy gyorsabban ugorjon a pozíciókra, de kisebb pontossággal. Az 5, 15, vagy 25 másodperces tekerés nem működik ebben a módban Bélyegképek betöltése - Kapcsolja ki, hogy a megelőzze a bélyegképek betöltését, így csökkentve az adat- és memóriahasználatot. A megváltoztatása törli a memóriában és a meghajtón lévő képgyorsítótárat. + Kapcsolja ki, hogy a megelőzze a bélyegképek betöltését, így csökkentve az adat- és memóriahasználatot. A megváltoztatása törli a memóriában és a meghajtón lévő képgyorsítótárat A bélyegkép gyorsítótár törölve Gyorsítótárazott metaadatok törlése Minden gyorsítótárazott weboldaladat törlése @@ -266,7 +266,7 @@ Nagyítás Automatikusan létrehozott Feliratok - Feliratok méretének és hátterének stílusbeli módosítása. A módosítások életbe lépésehez az alkalmazás újraindítása szükséges. + Feliratok méretének és hátterének stílusbeli módosítása. A módosítások életbe lépésehez az alkalmazás újraindítása szükséges Importálás Importálás a következőből Exportálás a következőbe @@ -491,7 +491,7 @@ Frissítési értesítés megjelenítése, amikor egy új verzió érhető el Frissítések Az Android igazítsa az értesítés színét a bélyegkép meghatározó színéhez (nem minden eszközön érhető el) - Legfeljebb három művelet jeleníthető meg a kompakt értesítésben. + Legfeljebb három művelet jeleníthető meg a kompakt értesítésben! Koppintással szerkesztheti az egyes értesítéseken megjelenő műveleteket. Válasszon ki legfeljebb hármat a jobb oldali jelölőnégyzetekkel, amelyek a kompakt értesítéseken is megjelennek. Ötödik műveletgomb Negyedik műveletgomb @@ -568,13 +568,13 @@ Helyi keresési javaslatok Távoli keresési javaslatok A fő lejátszó teljes képernyős indítása - A videókat ne a kis lejátszóban indítsa el, hanem kapcsolja be a teljes képernyős módot, ha az automatikus forgatás zárolva van. Továbbra is elérheti a kis lejátszót, ha kilép a teljes képernyőből. + A videókat ne a kis lejátszóban indítsa el, hanem kapcsolja be a teljes képernyős módot, ha az automatikus forgatás zárolva van. Továbbra is elérheti a kis lejátszót, ha kilép a teljes képernyőből Szolgáltatás be/ki, jelenleg kiválasztott: A megjegyzések ki vannak kapcsolva Húzza oldalra az elemeket az eltávolításukhoz A következő sorba állítása A következő sorba állítva - Feldolgozás… Ez eltarthat egy ideig. + Feldolgozás… Ez eltarthat egy ideig Az eltávolítás utáni, fragment vagy activity életcikluson kívüli, nem kézbesíthető Rx kivételek jelentésének kényszerítése Eredeti „ennyi ideje” megjelenítése az elemeken Tiltsa le a médiacsatornázást, ha fekete képernyőt vagy akadozást tapasztal videólejátszáskor @@ -617,7 +617,7 @@ Nem listázott Ki Nem található megfelelő fájlkezelő ehhez a művelethez. -\nTelepítsen egy fájlkezelőt, vagy próbálja meg letiltani a következőt a letöltési beállításokban: „%s”. +\nTelepítsen egy fájlkezelőt, vagy próbálja meg letiltani a következőt a letöltési beállításokban: „%s” Letöltés befejezve %s letöltés befejezve @@ -656,7 +656,7 @@ Frissítések keresése… Készítette: %s Nem található megfelelő fájlkezelő ehhez a művelethez. -\nTelepítsen egy olyan fájlkezelőt, amely kompatibilis a Storage Access Frameworkkel. +\nTelepítsen egy olyan fájlkezelőt, amely kompatibilis a Storage Access Frameworkkel Szöveg kijelölésének engedélyezése a leírásban Kategória Címkék @@ -664,7 +664,7 @@ Gyors mód letiltása Igen, és távolítsa el a részben megnézett videókat is A videók, melyeket már megnézett miután a lejátszási listához adta őket, el lesznek távolítva. -\nBiztos benne\? Ez nem vonható vissza. +\nBiztos benne\? Ez nem vonható vissza! A szolgáltatásokból származó eredeti szövegek láthatók lesznek a közvetítési elemeken Lejátszó összeomlasztása Képjelölők megjelenítése @@ -682,7 +682,7 @@ Rögzített megjegyzés LeakCanary nem elérhető Lejátszó értesítés - Módosítsa a betöltési intervallum méretét (jelenleg %s). Az alacsonyabb érték felgyorsíthatja a videó kezdeti betöltését. A változtatásokhoz a lejátszó újraindítása szükséges. + Módosítsa a betöltési intervallum méretét (jelenleg %s). Az alacsonyabb érték felgyorsíthatja a videó kezdeti betöltését. A változtatásokhoz a lejátszó újraindítása szükséges Az aktuális lejátszás konfigurálása értesítés Értesítések Új élő közvetítések @@ -720,6 +720,10 @@ Gyakran ismételt kérdések Megtekintés a weboldalon Rendezés - Ha problémája van az alkalmazás használatával, akkor nézze meg az ezekre a gyakori kérdésekre adott válaszokat. + Ha problémája van az alkalmazás használatával, akkor nézze meg az ezekre a gyakori kérdésekre adott válaszokat! Megnézett elemek elrejtése + Gyors mód + Feliratkozások importálása vagy exportálása a 3 pontos menüből + Ön a Newpipe legfrissebb verzióját futtatja + Nyomjon a %s letöltéséhez \ No newline at end of file diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml index f0e510bfd..2390f8e69 100644 --- a/app/src/main/res/values-nl/strings.xml +++ b/app/src/main/res/values-nl/strings.xml @@ -721,4 +721,9 @@ Veelgestelde vragen Als u problemen ondervindt bij het gebruik van de app, bekijk dan deze antwoorden op veelgestelde vragen! Bekijk op de website + Sorteer + Snelle modus + Importeer of exporteer abonnementen vanuit het 3-punten menu + U heeft de laatste versie van NewPipe + Klik om %s te downloaden \ No newline at end of file diff --git a/app/src/main/res/values-pa/strings.xml b/app/src/main/res/values-pa/strings.xml index 7be904b99..08c7e47c9 100644 --- a/app/src/main/res/values-pa/strings.xml +++ b/app/src/main/res/values-pa/strings.xml @@ -16,7 +16,7 @@ ਕੀ ਤੁਹਾਡਾ ਮਤਲਬ ਸੀ \"%1$s\"\? ਇਸ ਨਾਲ਼ ਸਾਂਝਾ ਕਰੋ ਬਾਹਰੀ ਵੀਡੀਓ ਪਲੇਅਰ ਵਰਤੋ - ਕੁਝ ਰੈਜ਼ੋਲੂਸ਼ਨਾਂ \'ਤੇ ਆਵਾਜ਼ ਨੂੰ ਹਟਾ ਦਿੰਦਾ ਹੈ + ਕੁਝ ਰੈਜ਼ੋਲਿਊਸ਼ਨਾਂ \'ਤੇ ਆਵਾਜ਼ ਨੂੰ ਹਟਾ ਦਿੰਦਾ ਹੈ ਬਾਹਰੀ ਆਡੀਓ ਪਲੇਅਰ ਵਰਤੋ ਸਬਸਕ੍ਰਾਈਬ ਕਰੋ ਸਬਸਕ੍ਰਾਈਬ ਹੈ @@ -36,9 +36,9 @@ ਆਡੀਓ ਲਈ ਡਾਊਨਲੋਡ ਫ਼ੋਲਡਰ ਡਾਊਨਲੋਡ ਕੀਤੀਆਂ ਆਡੀਓ ਇੱਥੇ ਜਮ੍ਹਾਂ ਹੁੰਦੀਆਂ ਹਨ ਆਡੀਓ ਫ਼ਾਈਲਾਂ ਲਈ ਡਾਊਨਲੋਡ ਫ਼ੋਲਡਰ ਚੁਣੋ - ਡਿਫ਼ਾਲਟ ਰੈਜ਼ੋਲੂਸ਼ਨ - ਪੌਪ-ਅਪ ਲਈ ਡਿਫ਼ਾਲਟ ਰੈਜ਼ੋਲੂਸ਼ਨ - ਵੱਡੀਆਂ ਰੈਜ਼ੋਲੂਸ਼ਨਾਂ ਦਿਖਾਓ + ਡਿਫ਼ਾਲਟ ਰੈਜ਼ੋਲਿਊਸ਼ਨ + ਪੌਪ-ਅਪ ਲਈ ਡਿਫ਼ਾਲਟ ਰੈਜ਼ੋਲਿਊਸ਼ਨ + ਵੱਡੀਆਂ ਰੈਜ਼ੋਲਿਊਸ਼ਨਜ਼ ਦਿਖਾਓ ਸਿਰਫ਼ ਕੁਝ ਹੀ ਡਿਵਾਈਸ 2K/4K ਵੀਡੀਓ ਨੂੰ ਚਲਾ ਸਕਦੇ ਹਨ Kodi ਵਿੱਚ ਚਲਾਓ Kodi ਐਪ ਇੰਸਟਾਲ ਨਹੀਂ ਹੈ\? @@ -53,13 +53,13 @@ ਕਾਲ੍ਹਾ ਪੌਪ-ਅਪ ਦਾ ਆਕਾਰ ਅਤੇ ਸਥਿਤੀ ਯਾਦ ਰੱਖੋ ਪੌਪ-ਅਪ ਦਾ ਆਖਰੀ ਅਕਾਰ ਅਤੇ ਸਥਿਤੀ ਯਾਦ ਰੱਖੋ - ਤੇਜ਼ ਪਰ inexact seek ਵਰਤੋ - Inexact seek ਵੀਡੀਓ ਨੂੰ ਤੇਜ਼ ਪਰ ਅਣ-ਸਟੀਕ ਢੰਗ ਨਾਲ ਅੱਗੇ-ਪਿੱਛੇ ਲਿਜਾਂਦਾ ਹੈ । ਇਸ ਨਾਲ ਅੱਗੇ-ਪਿੱਛੇ 5,15 ਜਾਂ 25 ਸਕਿੰਟ ਜਾਣਾ ਕੰਮ ਨਹੀਂ ਕਰੇਗਾ + ਤੇਜ਼ ਪਰ ਅਸਪੱਸ਼ਟ ਸੀਕ ਵਰਤੋ + ਅਸਪੱਸ਼ਟ ਸੀਕ ਵੀਡੀਓ ਨੂੰ ਤੇਜ਼ ਪਰ ਅਣ-ਸਟੀਕ ਢੰਗ ਨਾਲ ਅੱਗੇ-ਪਿੱਛੇ ਲਿਜਾਂਦਾ ਹੈ । ਇਸ ਨਾਲ ਅੱਗੇ-ਪਿੱਛੇ 5,15 ਜਾਂ 25 ਸਕਿੰਟ ਜਾਣਾ ਕੰਮ ਨਹੀਂ ਕਰੇਗਾ ਥੰਮਨੇਲ ਲੋਡ ਕਰੋ ਥੰਮਨੇਲ ਲੋਡ, ਡਾਟਾ ਦੀ ਬੱਚਤ ਅਤੇ ਮੈਮੋਰੀ ਦੀ ਵਰਤੋਂ ਨੂੰ ਰੋਕਣ ਲਈ ਇਸਨੂੰ ਬੰਦ ਕਰੋ। ਇਸ ਵਿਚ ਤਬਦੀਲੀ ਕਰਨ ਨਾਲ ਇਨ-ਮੈਮੋਰੀ ਅਤੇ ਆਨ-ਡਿਸਕ ਚਿੱਤਰ cache ਦੋਵੇਂ ਮਿਟ ਜਾਣਗੇ ਚਿੱਤਰ cache ਮਿਟਾ ਦਿੱਤੀ ਗਈ ਹੈ - Cached ਮੈਟਾ-ਡਾਟਾ ਮਿਟਾਓ - ਸਾਰੇ cached ਵੈੱਬ-ਪੇਜਾਂ ਦਾ ਡਾਟਾ ਮਿਟਾਓ + ਕੈਸ਼ ਕੀਤਾ ਮੈਟਾ-ਡਾਟਾ ਮਿਟਾਓ + ਸਾਰੇ ਕੈਸ਼ ਕੀਤੇ ਵੈੱਬ-ਪੇਜਾਂ ਦਾ ਡਾਟਾ ਮਿਟਾਓ ਮੈਟਾ-ਡਾਟਾ cache ਮਿਟਾ ਦਿੱਤੀ ਗਈ ਹੈ ਅਗਲੀ ਸਟ੍ਰੀਮ ਨੂੰ ਆਟੋ-ਕਤਾਰਬੱਧ ਕਰੋ ਇੱਕ ਮੁੱਕਣ ਵਾਲੀ ਪਰ ਨਾ-ਦੁਹਰਾਉਣ ਵਾਲੀ ਕਤਾਰ ਨੂੰ, ਸੰਬੰਧਤ ਸਟ੍ਰੀਮ ਜੋੜਦਿਆਂ, ਚਲਾਉਂਦੇ ਜਾਓ @@ -94,7 +94,7 @@ ਸਾਰੇ ਬੰਦ ਕੀਤਾ ਮਿਟਾਓ - ਵਧੀਆ ਰੈਜ਼ੋਲੂਸ਼ਨ + ਵਧੀਆ ਰੈਜ਼ੋਲਿਊਸ਼ਨ ਵਾਪਿਸ ਸਾਰੇ ਚਲਾਓ ਹਮੇਸ਼ਾ @@ -110,7 +110,7 @@ ਡਾਟਾਬੇਸ ਨਿਰਯਾਤ ਕਰੋ ਤੁਹਾਡੇ ਮੌਜੂਦਾ ਇਤਿਹਾਸ, ਸਬਸਕ੍ਰਿਪਸ਼ਨਜ਼, ਪਲੇਸੂਚੀ ਅਤੇ (ਆਪਨਸ਼ਨਲੀ) ਸੈਟਿੰਗਾਂ ਨੂੰ ਨਵਿਆਂ ਨਾਲ਼ ਬਦਲ ਦਿੰਦਾ ਹੈ ਇਤਿਹਾਸ, ਸੁਬਸਕ੍ਰਿਪਸ਼ਨਜ਼, ਪਲੇ-ਸੂਚੀ ਅਤੇ ਸੈਟਿੰਗਾਂ ਦਰਾਮਦ ਕਰੋ - ਦੇਖੇ ਗਏ ਵੀਡੀਓਜ਼ ਦੀ ਸੂਚੀ ਮਿਟਾਓ + ਵੇਖੇ ਗਏ ਵੀਡੀਓਜ਼ ਦੀ ਸੂਚੀ ਮਿਟਾਓ ਚਲਾਏ ਗਏ ਵੀਡੀਓਜ਼ ਦੇ ਇਤਿਹਾਸ ਅਤੇ ਪਲੇ-ਸਥਿਤੀਆਂ ਨੂੰ ਮਿਟਾਉਂਦਾ ਹੈ ਕੀ ਵੇਖੇ ਗਏ ਵੀਡੀਓਜ਼ ਦਾ ਇਤਿਹਾਸ ਮਿਟਾ ਦਿੱਤਾ ਜਾਵੇ\? ਖੋਜ ਸੂਚੀ ਦਾ ਇਤਿਹਾਸ ਮਿਟਾਓ @@ -318,7 +318,7 @@ ਸਵੀਕਾਰ ਕਰੋ ਅਸਵੀਕਾਰ ਕੋਈ ਸੀਮਾ ਨਹੀਂ - ਮੋਬਾਈਲ ਡਾਟਾ ਦੀ ਵਰਤੋਂ ਕਰਦੇ ਸਮੇਂ ਰੈਜ਼ੋਲੂਸ਼ਨ ਨੂੰ ਸੀਮਿਤ ਕਰੋ + ਮੋਬਾਈਲ ਡਾਟਾ ਦੀ ਵਰਤੋਂ ਕਰਦੇ ਸਮੇਂ ਰੈਜ਼ੋਲਿਊਸ਼ਨ ਨੂੰ ਸੀਮਿਤ ਕਰੋ ਐਪ ਸਵਿੱਚ ਕਰਨ ਤੇ ਮਿਨੀਮਾਈਜ਼ ਕਰੋ ਮੁੱਖ ਵੀਡੀਓ ਪਲੇਅਰ ਤੋਂ ਦੂਜੇ ਐਪ \'ਤੇ ਜਾਣ ਵੇਲ਼ੇ ਕਾਰਵਾਈ — %s ਕੋਈ ਨਹੀਂ @@ -327,7 +327,7 @@ ਚੁੱਪ ਦੌਰਾਨ ਤੇਜ਼ੀ ਨਾਲ ਅੱਗੇ ਕਰੋ ਕਦਮ ਰੀਸੈੱਟ - ਚੈਨਲਾਂ + ਚੈਨਲ ਪਲੇ ਸੂਚੀਆਂ ਟਰੈਕਸ ਯੂਜ਼ਰਸ @@ -575,11 +575,11 @@ ਸਾਰੀਆਂ ਪਲੇ-ਸਥਿਤੀਆਂ ਮਿਟਾਉਣੀਆਂ ਹਨ\? ਸਾਰੀਆਂ ਪਲੇ-ਸਥਿਤੀਆਂ ਮਿਟਾਉਂਦਾ ਹੈ ਪਲੇ-ਸਥਿਤੀਆਂ ਮਿਟਾਓ - ਵੀਡੀਉ ਹੈਸ਼ ਇਤਲਾਹ + ਵੀਡੀਓ ਹੈਸ਼ ਇਤਲਾਹ ਐਲਬਮਾਂ ਕਲਾਕਾਰ ਗੀਤ - ਵਿਡੀਉ + ਵੀਡੀਓ ਇਹ ਵੀਡੀਓ ਉਮਰ-ਪਾਬੰਦੀਸ਼ੁਦਾ ਹੈ। \n \nਜੇ ਤੁਸੀਂ ਇਸਨੂੰ ਵੇਖਣਾ ਚਾਹੁੰਦੇ ਹੋ ਤਾਂ ਸੈਟਿੰਗਾਂ ਵਿੱਚੋਂ \"%1$s\" ਚਾਲੂ ਕਰੋ। @@ -598,7 +598,7 @@ ਆਪ-ਮੁਖ਼ਤਾਰ ਕਤਾਰ ਕਰੋ ਸਟ੍ਰੀਮ ਦੇ ਕਰਤਾ, ਸਮੱਗਰੀ ਜਾਂ ਖੋਜ ਬੇਨਤੀ ਵਾਲੇ ਵਾਧੂ ਜਾਣਕਾਰੀ ਬਕਸਿਆਂ ਵਾਲ਼ੀ ਮੈਟਾ ਜਾਣਕਾਰੀ ਲੁਕਾਉਣ ਲਈ ਇਸਨੂੰ ਬੰਦ ਕਰ ਦਿਓ ਮੈਟਾ ਜਾਣਕਾਰੀ ਦਿਖਾਓ - ਵੀਡੀਉ ਵੇਰਵਾ ਅਤੇ ਵਾਧੂ ਜਾਣਕਾਰੀ ਲੁਕਾਉਣ ਲਈ ਇਸਨੂੰ ਬੰਦ ਕਰੋ + ਵੀਡੀਓ ਵੇਰਵਾ ਅਤੇ ਵਾਧੂ ਜਾਣਕਾਰੀ ਲੁਕਾਉਣ ਲਈ ਇਸਨੂੰ ਬੰਦ ਕਰੋ ਵੇਰਵਾ ਦਿਖਾਓ ਸਰਗਰਮ ਪਲੇਅਰ ਕਤਾਰ ਬਦਲ ਜਾਵੇਗੀ ਪਲੇਅਰ ਬਦਲਣ ਨਾਲ ਤੁਹਾਡੀ ਕਤਾਰ ਬਦਲ ਸਕਦੀ ਹੈ diff --git a/app/src/main/res/values-pt-rPT/strings.xml b/app/src/main/res/values-pt-rPT/strings.xml index 25a3f6e70..0a2205eee 100644 --- a/app/src/main/res/values-pt-rPT/strings.xml +++ b/app/src/main/res/values-pt-rPT/strings.xml @@ -493,7 +493,7 @@ Conteúdo indisponível Subscrito Cache de imagens limpa - Acerca + Sobre e FAQ Contagem de subscrições indisponível Ação padrão ao abrir o conteúdo — %s Repor @@ -716,9 +716,14 @@ Selecione a qualidade para reprodutores externos Tamanho do intervalo de carregamento da reprodução Mostrar artigos futuros - Ocultar artigos vistos + Ocultar itens reproduzidos Ocultar artigos futuros Perguntas frequentes Se tem problemas a usar a app, veja estas respostas para perguntas frequentes! Ver no sítio web + Modo rápido + Importar ou exportar subscrições do menu de 3 pontos + Já está a executar a versão mais recente do NewPipe + Toque para descarregar %s + Ordenação \ No newline at end of file diff --git a/app/src/main/res/values-ro/strings.xml b/app/src/main/res/values-ro/strings.xml index a8d49d46d..636c617b2 100644 --- a/app/src/main/res/values-ro/strings.xml +++ b/app/src/main/res/values-ro/strings.xml @@ -735,4 +735,8 @@ Dacă întâmpinați probleme cu utilizarea aplicației, nu uitați să consultați aceste răspunsuri la întrebări frecvente! Întrebări puse frecvent Sortează + Modul rapid + Importați sau exportați abonamente din meniul cu 3 puncte + Rulați cea mai recentă versiune NewPipe + Atingeți pentru a descărca %s \ No newline at end of file diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index e611059e1..159b27a2a 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -716,7 +716,7 @@ Закреплённый комментарий LeakCanary недоступна Стандартное значение ExoPlayer - Изменить размер предварительной загрузки (сейчас %s). Меньшее значение может ускорить загрузку видео. При изменении требуется перезапуск плеера + Изменить интервал загрузки (сейчас %s). Меньшее значение может ускорить запуск видео. Нужен перезапуск плеера Загрузка сведений о трансляции… Проверить наличие новых трансляций Удалить все загруженные файлы\? diff --git a/app/src/main/res/values-ta/strings.xml b/app/src/main/res/values-ta/strings.xml index 7aec8a4e9..3b8bff427 100644 --- a/app/src/main/res/values-ta/strings.xml +++ b/app/src/main/res/values-ta/strings.xml @@ -373,4 +373,5 @@ சந்தாவுக்கான புதிய ஸ்ட்ரீம்கள் பற்றிய அறிவிப்புகள் இந்த வீடியோ வயது வரம்புக்குட்பட்டது. \nவயது வரம்புக்குட்பட்ட வீடியோக்கள் கொண்ட புதிய YouTube கொள்கைகள் காரணமாக, NewPipe ஆல் அதன் எந்த வீடியோ ஸ்ட்ரீம்களையும் அணுக முடியாது, இதனால் அதை இயக்க முடியவில்லை. + வேகமான பயன்முறை \ No newline at end of file diff --git a/app/src/main/res/values-te/strings.xml b/app/src/main/res/values-te/strings.xml index bc310bf2a..ac34a316e 100644 --- a/app/src/main/res/values-te/strings.xml +++ b/app/src/main/res/values-te/strings.xml @@ -449,4 +449,26 @@ అడుగు నిశ్శబ్ద సమయంలో వేగంగా ముందుకు వెళ్లుము ప్లేబ్యాక్ స్పీడ్ నియంత్రణలు + ఏమిలేదు + మీరు బ్లాక్ స్క్రీన్ లేదా చలనచిత్రం ప్లేబ్యాక్‌లో అంతరాయాన్ని అనుభవిస్తే మీడియా టన్నెలింగ్‌ను నిలిపివేయండి + చిత్రాల మూలాన్ని సూచించే విధంగా వాటి పైభాగంలో పికాసో రంగు రిబ్బన్‌లను చూపండి: నెట్‌వర్క్ కోసం ఎరుపు, డిస్క్ కోసం నీలం మరియు మెమరీ కోసం ఆకుపచ్చ + లోపం స్నాక్‌బార్‌ని చూపండి + మీరు NewPipe యొక్క తాజా సంస్కరణను అమలు చేస్తున్నారు + NewPipe నవీకరణ అందుబాటులో ఉంది! + పూర్తయింది + వేలాడుతున్న + సర్వీస్‌ల నుండి ఒరిజినల్ టెక్స్ట్‌లు స్ట్రీమ్ ఐటెమ్‌లలో కనిపిస్తాయి + \"ప్లేయర్ పతనం\" చూపించు + ప్లేయర్‌ని ఉపయోగిస్తున్నప్పుడు పతనం ఎంపికను చూపుము + యాప్‌ను పతనం చేయండి + తక్కువ నాణ్యత (చిన్నది) + చూపించవద్దు + మీడియా టన్నెలింగ్‌ని నిలిపివేయండి + చిత్ర సూచికలను చూపు + కొత్త స్ట్రీమ్‌ల కోసం తనిఖీని అమలు చేయండి + ఎర్రర్ నోటిఫికేషన్‌ను సృష్టించండి + దిగుమతి + ఆగిపోయింది + క్రమం + %sని డౌన్‌లోడ్ చేయడానికి నొక్కండి \ No newline at end of file diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml index a2b392324..9c4ec3957 100644 --- a/app/src/main/res/values-uk/strings.xml +++ b/app/src/main/res/values-uk/strings.xml @@ -321,7 +321,7 @@ Імпортувати разом з налаштуваннями\? Політика приватності NewPipe Проєкт NewPipe дуже серйозно ставиться до вашої приватності. Тому застосунок не збирає ніяких даних без вашої згоди. -\nПолітика приватності докладно NewPipe пояснює, які дані надсилаються і зберігаються у звіті про збій програми. +\nПолітика приватності докладно NewPipe пояснює, які дані надсилаються і зберігаються у звіті про збій. Читати політику приватності З метою дотримання Загального регламенту про захист даних ЄС (General Data Protection Regulation, GDPR) ми звертаємо вашу увагу на політику приватності NewPipe. Будь ласка, прочитайте уважно. \nВи маєте прийняти її, аби надіслати нам звіт про помилку. @@ -578,7 +578,7 @@ Повʼязані елементи Коментарі Налаштувати повідомлення про відтворюваний наразі потік - Не розпізнано URL. Відкрити через іншу програму\? + Не розпізнано URL. Відкрити через інший застосунок\? Автоматична черга Показувати метадані Показувати описи diff --git a/app/src/main/res/values-ur/strings.xml b/app/src/main/res/values-ur/strings.xml index 0a105c5a8..686644fd9 100644 --- a/app/src/main/res/values-ur/strings.xml +++ b/app/src/main/res/values-ur/strings.xml @@ -498,4 +498,14 @@ کے ساتھ کھولیں ویڈیو پلیئر کو کریش کریں دیکھے ہوئے کو نشان لگائیں + مقامی تلاش کی سفارشات + اطلاعات + مین پلیئر کو مکمل سکرین سے شروع کریں + غلطی کی دستاویزات کی اطلاع + غلطی کی حبر کی اطلاعات + جب ٹھیک ہو جائے تو \"Done\" دبائیں + حل کریں + زیادہ تر پوچھے گئے سوالات + اگر آپ کو یہ ایپ استعمال کرنے میں دشواری آ رہی ہو تو ان عام سوالات کے جوابات کو ضرور دیکھیں! + ویب سائٹ پر دیکھیں \ No newline at end of file diff --git a/app/src/main/res/values-zh-rHK/strings.xml b/app/src/main/res/values-zh-rHK/strings.xml index 8dd8684b5..ab902d373 100644 --- a/app/src/main/res/values-zh-rHK/strings.xml +++ b/app/src/main/res/values-zh-rHK/strings.xml @@ -709,4 +709,8 @@ 排序 常見問題 若然您用呢個 app 有疑問,然而「亦有些難啟齒」,不妨睇下常見問題集,話唔定會發現「有場舞還未發表」! + 快速模式 + 右上角嘅選單有得匯入或匯出訂閱 + 您已經用緊最新版本嘅 NewPipe + 撳一下去下載 %s \ No newline at end of file diff --git a/app/src/main/res/values/settings_keys.xml b/app/src/main/res/values/settings_keys.xml index 9244f05c4..17ed547a0 100644 --- a/app/src/main/res/values/settings_keys.xml +++ b/app/src/main/res/values/settings_keys.xml @@ -441,6 +441,7 @@ hu nl no + nn uz pl pt-PT @@ -519,6 +520,7 @@ Magyar Nederlands Norsk + Nynorsk O‘zbek Polski Português diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 76b828746..4e6889304 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -716,6 +716,7 @@ Automatic (device theme) Select your favorite night theme — %s You can select your favorite night theme below + This option is only available if %s is selected for Theme Download has started You can now select text inside the description. Note that the page may flicker and links may not be clickable while in selection mode. Enable selecting text in the description diff --git a/build.gradle b/build.gradle index a0c1fdf27..d2f1dc4c5 100644 --- a/build.gradle +++ b/build.gradle @@ -7,7 +7,7 @@ buildscript { mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:7.3.0' + classpath 'com.android.tools.build:gradle:7.3.1' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" // NOTE: Do not place your application dependencies here; they belong diff --git a/fastlane/metadata/android/fr/changelogs/740.txt b/fastlane/metadata/android/fr/changelogs/740.txt new file mode 100644 index 000000000..da4bdc2f8 --- /dev/null +++ b/fastlane/metadata/android/fr/changelogs/740.txt @@ -0,0 +1,23 @@ +

Améliorations

+
    +
  • Rendre les liens dans les commentaires cliquables, augmenter la taille du texte
  • +
  • Rechercher en cliquant sur les liens d'horodatage dans les commentaires
  • +
  • Afficher l'onglet préféré en fonction de l'état récemment sélectionné
  • +
  • Ajouter la liste de lecture à la file d'attente lors d'un clic long sur 'Arrière-plan' dans la fenêtre de la liste de lecture
  • +
  • Rechercher le texte partagé lorsqu'il ne s'agit pas d'une URL
  • +
  • Ajouter "partager à l'heure actuelle" bouton au lecteur vidéo principal lecteur vidéo principal
  • +
  • Ajouter un bouton de fermeture du lecteur principal lorsque la file d'attente vidéo est terminée
  • +
  • Ajouter "jouer directement en arrière-plan" au menu longpress pour les éléments de la liste vidéo
  • +
  • Améliorer les traductions en anglais des commandes Play/Enqueue
  • +
  • Petites améliorations des performances
  • +
  • Supprimer les fichiers inutilisés
  • +
  • Mise à jour ExoPlayer à 2.9.6
  • +
  • Ajouter le support pour les liens Invidious
  • +
+

Corrections

+
    +
  • Défilement avec les commentaires et les flux associés désactivés
  • +
  • CheckForNewAppVersionTask qui est exécuté alors qu'il ne devrait pas l'être'
  • +
  • Importation des abonnements YouTube : ignorer ceux dont l’URL est invalide et conserver ceux dont le titre est vide
  • +
  • URL YouTube invalide : le nom de la balise signature n'est pas toujours "signature", ce qui empêche le chargement des flux.
  • +
diff --git a/fastlane/metadata/android/fr/changelogs/991.txt b/fastlane/metadata/android/fr/changelogs/991.txt new file mode 100644 index 000000000..59a34f25e --- /dev/null +++ b/fastlane/metadata/android/fr/changelogs/991.txt @@ -0,0 +1,13 @@ +Nouveautés +• Ajout du bouton « Ouvrir dans un navigateur » dans le paneau d'erreur +• Ajout de la possibilité d'afficher les groupes de chaîne en liste +• [YouTube] Appuis long sur le segment d'un flux pour partager l'URL avec l'horodatage +• Ajout d'un bouton sur le lecteur reduit + +Améliorations +• Ajout de la traduction en islandais et mise à jour de d'autre langues +• De nombreuses améliorations internes + +Corrections +• Correction de plantages +• [YouTube] Correction du chargement des chaînes diff --git a/fastlane/metadata/android/it/changelogs/740.txt b/fastlane/metadata/android/it/changelogs/740.txt index 785280b90..297ff9a3c 100644 --- a/fastlane/metadata/android/it/changelogs/740.txt +++ b/fastlane/metadata/android/it/changelogs/740.txt @@ -1,4 +1,4 @@ -
  • Miglioramenti

    +

    Miglioramenti

    • rendi cliccabili i link nei commenti, aumenta la dimensione del testo
    • cerca facendo clic sui collegamenti timestamp nei commenti
    • diff --git a/fastlane/metadata/android/te/changelogs/65.txt b/fastlane/metadata/android/te/changelogs/65.txt new file mode 100644 index 000000000..34d16b0eb --- /dev/null +++ b/fastlane/metadata/android/te/changelogs/65.txt @@ -0,0 +1,26 @@ +### మెరుగుదలలు + +- బర్గర్‌మెను ఐకాన్ యానిమేషన్ #1486ని నిలిపివేయండి +- డౌన్‌లోడ్‌ల తొలగింపును రద్దు చేయండి #1472 +- షేర్ మెను #1498లో డౌన్‌లోడ్ ఎంపిక +- లాంగ్ ట్యాప్ మెనూ #1454కి షేర్ ఆప్షన్ జోడించబడింది +- నిష్క్రమణ #1354లో ప్రధాన ప్లేయర్‌ని తగ్గించండి +- లైబ్రరీ వెర్షన్ అప్‌డేట్ మరియు డేటాబేస్ బ్యాకప్ ఫిక్స్ #1510 +- ExoPlayer 2.8.2 నవీకరణ #1392 + - వేగవంతమైన స్పీడ్ మార్పు కోసం వివిధ దశల పరిమాణాలకు మద్దతు ఇవ్వడానికి ప్లేబ్యాక్ స్పీడ్ కంట్రోల్ డైలాగ్‌ని మళ్లీ రూపొందించారు. + - ప్లేబ్యాక్ స్పీడ్ కంట్రోల్‌లో నిశ్శబ్దం సమయంలో ఫాస్ట్-ఫార్వర్డ్ చేయడానికి టోగుల్ జోడించబడింది. ఇది ఆడియోబుక్‌లు మరియు నిర్దిష్ట సంగీత శైలులకు సహాయకరంగా ఉండాలి మరియు నిజమైన అతుకులు లేని అనుభవాన్ని అందించగలదు (మరియు అనేక నిశ్శబ్దాలతో పాటను విచ్ఛిన్నం చేయవచ్చు =\\). + - మాన్యువల్‌గా కాకుండా ప్లేయర్‌లో అంతర్గతంగా మీడియాతో పాటు మెటాడేటాను పాస్ చేయడానికి రీఫ్యాక్టర్డ్ మీడియా సోర్స్ రిజల్యూషన్. ఇప్పుడు మేము మెటాడేటా యొక్క ఒకే మూలాన్ని కలిగి ఉన్నాము మరియు ప్లేబ్యాక్ ప్రారంభమైనప్పుడు నేరుగా అందుబాటులో ఉంటుంది. + - ప్లేజాబితా భాగాన్ని తెరిచినప్పుడు కొత్త మెటాడేటా అందుబాటులో ఉన్నప్పుడు స్థిర రిమోట్ ప్లేజాబితా మెటాడేటా నవీకరించబడదు. + - వివిధ UI పరిష్కారాలు: #1383, బ్యాక్‌గ్రౌండ్ ప్లేయర్ నోటిఫికేషన్ నియంత్రణలు ఇప్పుడు ఎల్లప్పుడూ తెల్లగా ఉంటాయి, ఫ్లింగ్ ద్వారా పాప్‌అప్ ప్లేయర్‌ని షట్‌డౌన్ చేయడం సులభం +- మల్టీసర్వీస్ కోసం రీఫ్యాక్టర్డ్ ఆర్కిటెక్చర్‌తో కొత్త ఎక్స్‌ట్రాక్టర్‌ని ఉపయోగించండి + +### పరిష్కారాలు + +- #1440 బ్రోకెన్ వీడియో ఇన్ఫో లేఅవుట్ #1491ని పరిష్కరించండి +- చరిత్ర పరిష్కారాన్ని వీక్షించండి #1497 + - #1495, యూజర్ ప్లేజాబితాను యాక్సెస్ చేసిన వెంటనే మెటాడేటా (థంబ్‌నెయిల్, టైటిల్ మరియు వీడియో కౌంట్) అప్‌డేట్ చేయడం ద్వారా. + - #1475, వినియోగదారు వివరాలు ఫ్రాగ్‌మెంట్‌పై బాహ్య ప్లేయర్‌లో వీడియోను ప్రారంభించినప్పుడు డేటాబేస్‌లో వీక్షణను నమోదు చేయడం ద్వారా. +- పాప్అప్ మోడ్ విషయంలో స్క్రీన్ సమయం ముగియడాన్ని పరిష్కరించండి. #1463 (స్థిర #640) +- ప్రధాన వీడియో ప్లేయర్ ఫిక్స్ #1509 + - [#1412] ప్లేయర్ యాక్టివిటీ బ్యాక్‌గ్రౌండ్‌లో ఉన్నప్పుడు కొత్త ఉద్దేశం వచ్చినప్పుడు ప్లేయర్ NPEకి కారణమయ్యే ఫిక్స్డ్ రిపీట్ మోడ్. + - పాప్‌అప్‌కి ప్లేయర్‌ని కనిష్టీకరించడం అనేది పాప్‌అప్ అనుమతి ఇవ్వనప్పుడు ప్లేయర్‌ను నాశనం చేయదు. diff --git a/fastlane/metadata/android/uk/changelogs/951.txt b/fastlane/metadata/android/uk/changelogs/951.txt index 1cd68b0b8..37ebfd318 100644 --- a/fastlane/metadata/android/uk/changelogs/951.txt +++ b/fastlane/metadata/android/uk/changelogs/951.txt @@ -5,7 +5,7 @@ •Швид.перемот.вперед/назад у фоні/вікні програв.черги •Показ порад пошуку: мали на увазі й показ результ. для Покр. -•Вил.запис метадан.програми в зміш.файли +•Вил.запис метадан.застосунку в зміш.файли •Не вилуч.невдалі потоки з черги •Оновл.колір пан.стану відповідно до коль.пан.засобів Випр.