From aea912f4995ccf890a921afcbab5435503cbbbba Mon Sep 17 00:00:00 2001 From: Mikhail Barashkov Date: Fri, 12 Feb 2021 11:58:15 +0300 Subject: [PATCH 01/57] Implement "pause/play" toggle on hardware keyboard space button. --- .../schabi/newpipe/fragments/detail/VideoDetailFragment.java | 1 + app/src/main/res/layout/fragment_video_detail.xml | 2 ++ 2 files changed, 3 insertions(+) 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 cb4cfb8b6..7f800a304 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 @@ -1850,6 +1850,7 @@ public final class VideoDetailFragment if (fullscreen) { hideSystemUiIfNeeded(); + binding.overlayPlayPauseButton.requestFocus(); } else { showSystemUi(); } diff --git a/app/src/main/res/layout/fragment_video_detail.xml b/app/src/main/res/layout/fragment_video_detail.xml index 246e9b4d9..498b16b9c 100644 --- a/app/src/main/res/layout/fragment_video_detail.xml +++ b/app/src/main/res/layout/fragment_video_detail.xml @@ -675,6 +675,8 @@ android:background="?attr/selectableItemBackground" android:padding="10dp" android:scaleType="center" + android:focusable="true" + android:focusedByDefault="true" app:srcCompat="?attr/ic_play_arrow" tools:ignore="ContentDescription,RtlHardcoded" /> From 80161c36c6d3ed20414547af293414cd829ce386 Mon Sep 17 00:00:00 2001 From: Mikhail Barashkov Date: Fri, 12 Feb 2021 12:17:46 +0300 Subject: [PATCH 02/57] Apply the space button shortcut to large screens as well --- app/src/main/res/layout-large-land/fragment_video_detail.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/res/layout-large-land/fragment_video_detail.xml b/app/src/main/res/layout-large-land/fragment_video_detail.xml index 14459b494..42bd4bb91 100644 --- a/app/src/main/res/layout-large-land/fragment_video_detail.xml +++ b/app/src/main/res/layout-large-land/fragment_video_detail.xml @@ -703,6 +703,8 @@ android:background="?attr/selectableItemBackground" android:padding="10dp" android:scaleType="center" + android:focusable="true" + android:focusedByDefault="true" app:srcCompat="?attr/ic_play_arrow" tools:ignore="ContentDescription,RtlHardcoded" /> From eba0b07782b2520c4aadd2e9df4f2f86528d6834 Mon Sep 17 00:00:00 2001 From: Robin Date: Tue, 19 Jan 2021 09:27:29 +0100 Subject: [PATCH 03/57] Update to ExoPlayer 2.12.3 --- app/build.gradle | 2 +- .../org/schabi/newpipe/player/Player.java | 9 +++-- .../newpipe/player/helper/LoadController.java | 7 ++-- .../newpipe/player/helper/PlayerHelper.java | 4 +-- .../player/mediasource/FailedMediaSource.java | 9 +++++ .../player/mediasource/LoadedMediaSource.java | 34 +++++++++++++++++++ .../mediasource/PlaceholderMediaSource.java | 9 +++++ 7 files changed, 64 insertions(+), 10 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 486502cd8..37eca2ed5 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -96,7 +96,7 @@ ext { checkstyleVersion = '8.38' stethoVersion = '1.5.1' leakCanaryVersion = '2.5' - exoPlayerVersion = '2.11.8' + exoPlayerVersion = '2.12.3' androidxLifecycleVersion = '2.2.0' androidxRoomVersion = '2.3.0-alpha03' groupieVersion = '2.8.1' 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 ba8e856df..535a5033a 100644 --- a/app/src/main/java/org/schabi/newpipe/player/Player.java +++ b/app/src/main/java/org/schabi/newpipe/player/Player.java @@ -601,7 +601,8 @@ public final class Player implements final PlaybackParameters savedParameters = retrievePlaybackParametersFromPrefs(this); final float playbackSpeed = savedParameters.speed; final float playbackPitch = savedParameters.pitch; - final boolean playbackSkipSilence = savedParameters.skipSilence; + final boolean playbackSkipSilence = getPrefs().getBoolean(getContext().getString( + R.string.playback_skip_silence_key), getPlaybackSkipSilence()); final boolean samePlayQueue = playQueue != null && playQueue.equals(newQueue); final int repeatMode = intent.getIntExtra(REPEAT_MODE, getRepeatMode()); @@ -1432,7 +1433,8 @@ public final class Player implements } public boolean getPlaybackSkipSilence() { - return getPlaybackParameters().skipSilence; + return simpleExoPlayer != null + && simpleExoPlayer.getAudioComponent().getSkipSilenceEnabled(); } public PlaybackParameters getPlaybackParameters() { @@ -1457,7 +1459,8 @@ public final class Player implements savePlaybackParametersToPrefs(this, roundedSpeed, roundedPitch, skipSilence); simpleExoPlayer.setPlaybackParameters( - new PlaybackParameters(roundedSpeed, roundedPitch, skipSilence)); + new PlaybackParameters(roundedSpeed, roundedPitch)); + simpleExoPlayer.getAudioComponent().setSkipSilenceEnabled(skipSilence); } //endregion diff --git a/app/src/main/java/org/schabi/newpipe/player/helper/LoadController.java b/app/src/main/java/org/schabi/newpipe/player/helper/LoadController.java index 0604e6ae8..162872267 100644 --- a/app/src/main/java/org/schabi/newpipe/player/helper/LoadController.java +++ b/app/src/main/java/org/schabi/newpipe/player/helper/LoadController.java @@ -80,12 +80,13 @@ public class LoadController implements LoadControl { } @Override - public boolean shouldContinueLoading(final long bufferedDurationUs, - final float playbackSpeed) { + public boolean shouldContinueLoading(final long playbackPositionUs, + final long bufferedDurationUs, final float playbackSpeed) { if (!preloadingEnabled) { return false; } - return internalLoadControl.shouldContinueLoading(bufferedDurationUs, playbackSpeed); + return internalLoadControl.shouldContinueLoading(playbackPositionUs, bufferedDurationUs, + playbackSpeed); } @Override diff --git a/app/src/main/java/org/schabi/newpipe/player/helper/PlayerHelper.java b/app/src/main/java/org/schabi/newpipe/player/helper/PlayerHelper.java index ccc73e81f..f653531eb 100644 --- a/app/src/main/java/org/schabi/newpipe/player/helper/PlayerHelper.java +++ b/app/src/main/java/org/schabi/newpipe/player/helper/PlayerHelper.java @@ -494,9 +494,7 @@ public final class PlayerHelper { R.string.playback_speed_key), player.getPlaybackSpeed()); final float pitch = player.getPrefs().getFloat(player.getContext().getString( R.string.playback_pitch_key), player.getPlaybackPitch()); - final boolean skipSilence = player.getPrefs().getBoolean(player.getContext().getString( - R.string.playback_skip_silence_key), player.getPlaybackSkipSilence()); - return new PlaybackParameters(speed, pitch, skipSilence); + return new PlaybackParameters(speed, pitch); } public static void savePlaybackParametersToPrefs(final Player player, diff --git a/app/src/main/java/org/schabi/newpipe/player/mediasource/FailedMediaSource.java b/app/src/main/java/org/schabi/newpipe/player/mediasource/FailedMediaSource.java index c09a44c08..7594f3a16 100644 --- a/app/src/main/java/org/schabi/newpipe/player/mediasource/FailedMediaSource.java +++ b/app/src/main/java/org/schabi/newpipe/player/mediasource/FailedMediaSource.java @@ -5,6 +5,7 @@ import android.util.Log; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import com.google.android.exoplayer2.MediaItem; import com.google.android.exoplayer2.source.BaseMediaSource; import com.google.android.exoplayer2.source.MediaPeriod; import com.google.android.exoplayer2.upstream.Allocator; @@ -54,6 +55,14 @@ public class FailedMediaSource extends BaseMediaSource implements ManagedMediaSo return System.currentTimeMillis() >= retryTimestamp; } + /** + * Returns the {@link MediaItem} whose media is provided by the source. + */ + @Override + public MediaItem getMediaItem() { + return MediaItem.fromUri(playQueueItem.getUrl()); + } + @Override public void maybeThrowSourceInfoRefreshError() throws IOException { throw new IOException(error); diff --git a/app/src/main/java/org/schabi/newpipe/player/mediasource/LoadedMediaSource.java b/app/src/main/java/org/schabi/newpipe/player/mediasource/LoadedMediaSource.java index cdbf8609b..746a97581 100644 --- a/app/src/main/java/org/schabi/newpipe/player/mediasource/LoadedMediaSource.java +++ b/app/src/main/java/org/schabi/newpipe/player/mediasource/LoadedMediaSource.java @@ -5,6 +5,8 @@ import android.os.Handler; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import com.google.android.exoplayer2.MediaItem; +import com.google.android.exoplayer2.drm.DrmSessionEventListener; import com.google.android.exoplayer2.source.MediaPeriod; import com.google.android.exoplayer2.source.MediaSource; import com.google.android.exoplayer2.source.MediaSourceEventListener; @@ -83,6 +85,38 @@ public class LoadedMediaSource implements ManagedMediaSource { source.removeEventListener(eventListener); } + /** + * Adds a {@link DrmSessionEventListener} to the list of listeners which are notified of DRM + * events for this media source. + * + * @param handler A handler on the which listener events will be posted. + * @param eventListener The listener to be added. + */ + @Override + public void addDrmEventListener(final Handler handler, + final DrmSessionEventListener eventListener) { + source.addDrmEventListener(handler, eventListener); + } + + /** + * Removes a {@link DrmSessionEventListener} from the list of listeners which are notified of + * DRM events for this media source. + * + * @param eventListener The listener to be removed. + */ + @Override + public void removeDrmEventListener(final DrmSessionEventListener eventListener) { + source.removeDrmEventListener(eventListener); + } + + /** + * Returns the {@link MediaItem} whose media is provided by the source. + */ + @Override + public MediaItem getMediaItem() { + return source.getMediaItem(); + } + @Override public boolean shouldBeReplacedWith(@NonNull final PlayQueueItem newIdentity, final boolean isInterruptable) { diff --git a/app/src/main/java/org/schabi/newpipe/player/mediasource/PlaceholderMediaSource.java b/app/src/main/java/org/schabi/newpipe/player/mediasource/PlaceholderMediaSource.java index f73a219d7..1cd855627 100644 --- a/app/src/main/java/org/schabi/newpipe/player/mediasource/PlaceholderMediaSource.java +++ b/app/src/main/java/org/schabi/newpipe/player/mediasource/PlaceholderMediaSource.java @@ -3,6 +3,7 @@ package org.schabi.newpipe.player.mediasource; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import com.google.android.exoplayer2.MediaItem; import com.google.android.exoplayer2.source.BaseMediaSource; import com.google.android.exoplayer2.source.MediaPeriod; import com.google.android.exoplayer2.upstream.Allocator; @@ -11,6 +12,14 @@ import com.google.android.exoplayer2.upstream.TransferListener; import org.schabi.newpipe.player.playqueue.PlayQueueItem; public class PlaceholderMediaSource extends BaseMediaSource implements ManagedMediaSource { + /** + * Returns the {@link MediaItem} whose media is provided by the source. + */ + @Override + public MediaItem getMediaItem() { + return null; + } + // Do nothing, so this will stall the playback @Override public void maybeThrowSourceInfoRefreshError() { } From 8978187c6429407abf6f5b23ed1bc3f67bcaf30d Mon Sep 17 00:00:00 2001 From: Stypox Date: Tue, 16 Feb 2021 16:54:44 +0100 Subject: [PATCH 04/57] Improve code style and fix some warnings Removed a textTrack null check on a now- NonNull method Added a error type switch case (TIMEOUT) --- app/src/main/java/org/schabi/newpipe/player/Player.java | 9 ++++++--- .../org/schabi/newpipe/player/helper/LoadController.java | 7 ++++--- 2 files changed, 10 insertions(+), 6 deletions(-) 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 535a5033a..0a10a2cb7 100644 --- a/app/src/main/java/org/schabi/newpipe/player/Player.java +++ b/app/src/main/java/org/schabi/newpipe/player/Player.java @@ -1433,7 +1433,7 @@ public final class Player implements } public boolean getPlaybackSkipSilence() { - return simpleExoPlayer != null + return !exoPlayerIsNull() && simpleExoPlayer.getAudioComponent() != null && simpleExoPlayer.getAudioComponent().getSkipSilenceEnabled(); } @@ -1460,7 +1460,9 @@ public final class Player implements savePlaybackParametersToPrefs(this, roundedSpeed, roundedPitch, skipSilence); simpleExoPlayer.setPlaybackParameters( new PlaybackParameters(roundedSpeed, roundedPitch)); - simpleExoPlayer.getAudioComponent().setSkipSilenceEnabled(skipSilence); + if (simpleExoPlayer.getAudioComponent() != null) { + simpleExoPlayer.getAudioComponent().setSkipSilenceEnabled(skipSilence); + } } //endregion @@ -2336,6 +2338,7 @@ public final class Player implements case ExoPlaybackException.TYPE_OUT_OF_MEMORY: case ExoPlaybackException.TYPE_REMOTE: case ExoPlaybackException.TYPE_RENDERER: + case ExoPlaybackException.TYPE_TIMEOUT: default: showUnrecoverableError(error); onPlaybackShutdown(); @@ -3358,7 +3361,7 @@ public final class Player implements final List availableLanguages = new ArrayList<>(textTracks.length); for (int i = 0; i < textTracks.length; i++) { final TrackGroup textTrack = textTracks.get(i); - if (textTrack.length > 0 && textTrack.getFormat(0) != null) { + if (textTrack.length > 0) { availableLanguages.add(textTrack.getFormat(0).language); } } diff --git a/app/src/main/java/org/schabi/newpipe/player/helper/LoadController.java b/app/src/main/java/org/schabi/newpipe/player/helper/LoadController.java index 162872267..ba9a2f1ec 100644 --- a/app/src/main/java/org/schabi/newpipe/player/helper/LoadController.java +++ b/app/src/main/java/org/schabi/newpipe/player/helper/LoadController.java @@ -81,12 +81,13 @@ public class LoadController implements LoadControl { @Override public boolean shouldContinueLoading(final long playbackPositionUs, - final long bufferedDurationUs, final float playbackSpeed) { + final long bufferedDurationUs, + final float playbackSpeed) { if (!preloadingEnabled) { return false; } - return internalLoadControl.shouldContinueLoading(playbackPositionUs, bufferedDurationUs, - playbackSpeed); + return internalLoadControl.shouldContinueLoading( + playbackPositionUs, bufferedDurationUs, playbackSpeed); } @Override From b236bb407b8f15f324d4fcbdfa60f0ec25f9f1ab Mon Sep 17 00:00:00 2001 From: FireMasterK <20838718+FireMasterK@users.noreply.github.com> Date: Sat, 20 Feb 2021 16:49:37 +0530 Subject: [PATCH 05/57] Change UA to privacy.resistFingerprinting. --- app/src/main/java/org/schabi/newpipe/DownloaderImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/org/schabi/newpipe/DownloaderImpl.java b/app/src/main/java/org/schabi/newpipe/DownloaderImpl.java index 50972fb2f..a81c812df 100644 --- a/app/src/main/java/org/schabi/newpipe/DownloaderImpl.java +++ b/app/src/main/java/org/schabi/newpipe/DownloaderImpl.java @@ -43,7 +43,7 @@ import static org.schabi.newpipe.MainActivity.DEBUG; public final class DownloaderImpl extends Downloader { public static final String USER_AGENT - = "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:68.0) Gecko/20100101 Firefox/68.0"; + = "Mozilla/5.0 (Windows NT 10.0; rv:78.0) Gecko/20100101 Firefox/78.0"; public static final String YOUTUBE_RESTRICTED_MODE_COOKIE_KEY = "youtube_restricted_mode_key"; public static final String YOUTUBE_RESTRICTED_MODE_COOKIE = "PREF=f2=8000000"; From 85a468bda9e45098335a557b7e79a65665943aa7 Mon Sep 17 00:00:00 2001 From: TobiGr Date: Fri, 5 Mar 2021 22:44:28 +0100 Subject: [PATCH 06/57] Update translations: app MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Translated using Weblate (French) Currently translated at 100.0% (624 of 624 strings) Translated using Weblate (Italian) Currently translated at 100.0% (624 of 624 strings) Translated using Weblate (Portuguese) Currently translated at 100.0% (624 of 624 strings) Translated using Weblate (Slovenian) Currently translated at 75.1% (469 of 624 strings) Translated using Weblate (Greek) Currently translated at 100.0% (624 of 624 strings) Translated using Weblate (Polish) Currently translated at 100.0% (624 of 624 strings) Translated using Weblate (Portuguese (Brazil)) Currently translated at 100.0% (624 of 624 strings) Translated using Weblate (Chinese (Simplified)) Currently translated at 100.0% (624 of 624 strings) Translated using Weblate (Chinese (Traditional)) Currently translated at 100.0% (624 of 624 strings) Translated using Weblate (Hebrew) Currently translated at 100.0% (624 of 624 strings) Translated using Weblate (Albanian) Currently translated at 98.2% (613 of 624 strings) Translated using Weblate (Norwegian Bokmål) Currently translated at 96.4% (602 of 624 strings) Translated using Weblate (Portuguese (Portugal)) Currently translated at 100.0% (624 of 624 strings) Translated using Weblate (Kurdish (Northern)) Currently translated at 100.0% (624 of 624 strings) --- .../main/res/values-b+zh+HANS+CN/strings.xml | 1 + app/src/main/res/values-el/strings.xml | 1 + app/src/main/res/values-fr/strings.xml | 1 + app/src/main/res/values-he/strings.xml | 1 + app/src/main/res/values-it/strings.xml | 1 + app/src/main/res/values-kmr/strings.xml | 1 + app/src/main/res/values-nb-rNO/strings.xml | 1 + app/src/main/res/values-pl/strings.xml | 1 + app/src/main/res/values-pt-rBR/strings.xml | 9 +- app/src/main/res/values-pt-rPT/strings.xml | 1 + app/src/main/res/values-pt/strings.xml | 1 + app/src/main/res/values-sl/strings.xml | 163 +++++++++++++++++- app/src/main/res/values-sq/strings.xml | 15 ++ app/src/main/res/values-zh-rTW/strings.xml | 1 + 14 files changed, 186 insertions(+), 12 deletions(-) diff --git a/app/src/main/res/values-b+zh+HANS+CN/strings.xml b/app/src/main/res/values-b+zh+HANS+CN/strings.xml index b5cefcabc..4d2ac263f 100644 --- a/app/src/main/res/values-b+zh+HANS+CN/strings.xml +++ b/app/src/main/res/values-b+zh+HANS+CN/strings.xml @@ -657,4 +657,5 @@ 显示视频描述和其他信息 用…打开 设备上没有应用可以打开 + 让应用崩溃 \ No newline at end of file diff --git a/app/src/main/res/values-el/strings.xml b/app/src/main/res/values-el/strings.xml index 5b00bc0a4..80f6c32ba 100644 --- a/app/src/main/res/values-el/strings.xml +++ b/app/src/main/res/values-el/strings.xml @@ -662,4 +662,5 @@ Εμφάνιση περιγραφής Άνοιγμα με Καμία εφαρμογή στη συσκευή σας δεν μπορεί το ανοίξει + Κατάρρευση εφαρμογής \ No newline at end of file diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index d98a95ec3..c1afa106d 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -664,4 +664,5 @@ Commentaires Désactiver pour masquer la description de la vidéo et les informations supplémentaires Afficher la description + Plante l\'application \ No newline at end of file diff --git a/app/src/main/res/values-he/strings.xml b/app/src/main/res/values-he/strings.xml index d90ec25d9..7ebc93c4d 100644 --- a/app/src/main/res/values-he/strings.xml +++ b/app/src/main/res/values-he/strings.xml @@ -682,4 +682,5 @@ הצגת תיאור פתיחה באמצעות אין יישומון על המכשיר שלך שיכול לפתוח את זה + להקריס את היישומון \ No newline at end of file diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index cabc00434..d469b4144 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -662,4 +662,5 @@ Mostra descrizione Apri con Sul tuo dispositivo non c\'è alcuna app che può aprirlo + Fai crashare l\'app \ No newline at end of file diff --git a/app/src/main/res/values-kmr/strings.xml b/app/src/main/res/values-kmr/strings.xml index f20ac0faa..75ca42bc8 100644 --- a/app/src/main/res/values-kmr/strings.xml +++ b/app/src/main/res/values-kmr/strings.xml @@ -663,4 +663,5 @@ Lîsansên partiya sêyemîn Derbar Mîhengên + Serlêdanê kilît bikin \ No newline at end of file diff --git a/app/src/main/res/values-nb-rNO/strings.xml b/app/src/main/res/values-nb-rNO/strings.xml index 017862121..25f86d1b1 100644 --- a/app/src/main/res/values-nb-rNO/strings.xml +++ b/app/src/main/res/values-nb-rNO/strings.xml @@ -662,4 +662,5 @@ Skru av for å skjule videobeskrivelse og ytterligere info Vis beskrivelse Åpne med + Krasj programmet \ No newline at end of file diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index 0f06a1fd3..b3aa620ec 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -672,4 +672,5 @@ Otwórz za pomocą Żadna aplikacja na Twoim urządzeniu nie może tego otworzyć Powiązane strumienie + Awaria aplikacji \ No newline at end of file diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index 8ee7dd8ef..5456bd6b7 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -335,10 +335,10 @@ \n6. A partir do arquivo zip baixado, retire o arquivo .json (geralmente em \"YouTube e YouTube Music/assinaturas/assinaturas.json\") e importe aqui. Importe um perfil do SoundCloud digitando o URL ou seu ID: \n -\n1. Ative o \"modo desktop\" no navegador (o site está indisponível em celulares) -\n2. Acesse este URL: %1$s -\n3. Logue quando solicitado -\n4. Copie o URL do perfil redirecionado +\n1. Ative o \"modo desktop\" no navegador (o site está indisponível em celulares) +\n2. Acesse este URL: %1$s +\n3. Logue quando solicitado +\n4. Copie o URL do perfil redirecionado. seuID, soundcloud.com/seuid Tenha em mente que esta operação poderá usar bastante a conexão com a internet. \n @@ -662,4 +662,5 @@ Mostrar descrição Abrir com Nenhum aplicativo em seu dispositivo pode abrir isso + O aplicativo parou \ No newline at end of file diff --git a/app/src/main/res/values-pt-rPT/strings.xml b/app/src/main/res/values-pt-rPT/strings.xml index bb20d52be..e1fef7875 100644 --- a/app/src/main/res/values-pt-rPT/strings.xml +++ b/app/src/main/res/values-pt-rPT/strings.xml @@ -662,4 +662,5 @@ Desative para ocultar a descrição do vídeo e informações adicionais Mostrar descrição Abrir com + A app travou \ No newline at end of file diff --git a/app/src/main/res/values-pt/strings.xml b/app/src/main/res/values-pt/strings.xml index 71200df95..5f1467eeb 100644 --- a/app/src/main/res/values-pt/strings.xml +++ b/app/src/main/res/values-pt/strings.xml @@ -662,4 +662,5 @@ Desative para ocultar a descrição do vídeo e informações adicionais Mostrar descrição Abrir com + A app travou \ No newline at end of file diff --git a/app/src/main/res/values-sl/strings.xml b/app/src/main/res/values-sl/strings.xml index ca2c76cc7..2e2d08d6a 100644 --- a/app/src/main/res/values-sl/strings.xml +++ b/app/src/main/res/values-sl/strings.xml @@ -25,8 +25,8 @@ Pokaži možnost \"Predvajaj s Kodi\" Privzet zapis zvoka Zvok - Prejem - Pokaži naslednji video in podobne posnetke + Prenesi + Pokaži naslednje in podobne posnetke Zapis naslova URL ni podprt. Privzeti jezik vsebine Video in Zvok @@ -165,9 +165,9 @@ odpiranje v pojavnem načinu Znak za zamenjavo Črke in številke Večina posebnih znakov - Preišči zgodovino + Zgodovina iskanja Iskalne poizvedbe shranjuj krajevno - Zgodovina + Zgodovina ogledov Sledi zgodovini predvajanih posnetkov Nadaljuj po prekinitvi Nadaljuj s predvajanjem po prekinitvi (na primer zaradi telefonskega klica) @@ -230,7 +230,7 @@ odpiranje v pojavnem načinu Spletišče Storitev Neveljaven naslov URL - Prejmi datoteko pretoka. + Prenesi datoteko pretoka. Pokaži podrobnosti Zaznamki Dodaj k @@ -348,13 +348,13 @@ odpiranje v pojavnem načinu Kanali Posodobitve Samo HTTPS URL-ji so podprti - Prikaži namig \"Drži za dodajanje\" + Prikaži namig \"drži za dodajanje\" Počisti podatke Pozicija v seznamih - Avtomatsko predvajaj naslednji video + Samodejno predvajaj naslednji video Izbriši shranjene metapodatke Predshramba za slike je bila izbrisana - Prikaži komentar + Prikaži komentarje Izberi Zavihek Nov Zavihek Odjava @@ -367,4 +367,151 @@ odpiranje v pojavnem načinu Izbriši piškotke, ki jih NewPipe shrani, ko rešite reCAPTCHA Izbrišite piškodke reCAPTCHA Nadaljuj s predvajanjem + Povrni zadnji položaj predvajanja + Samodejno uvrščanje + Predpomnjeni metapodatki so bili odstranjeni + Prikaži meta informacije + Onemogoči da se ustavi prikazovanje komentarjev + Izklopite, če želite preprečiti nalaganje sličic, s tem bo varčeval na podatkih in uporabi spomina. Spremembe bodo izbrisale predpomnilnik v spominu in na disku. + Dejavna vrsta bo zamenjana + Preklop na drugi predvajanik lahko zamenja vašo čakalno vrsto + Vprašaj za potrditev pred čiščenjem vrste + Prepustite, da Android izbere barvo obvestila na podlagi glavne barve v sličici (upoštevajte, da to ni na voljo v vseh napravah) + Obarvajte obvestilo + Nič + Nalaganje + Naključno + Ponovi + Izberete lahko največ 3 dejanja, ki se bodo prikazala v kompaktnem obvestilu! + Uredite vsako obvestilo z klikom na obvestilo. Izberite do 3 obvestila, ki se bodo prikazala v kompaktnem obvestilu z uporabo potrditvenega polja na desni. + Gumb za peto dejanje + Gumb za četrto dejanje + Gumb za tretje dejanje + Gumb za drugo dejanje + Gumb za prvo dejanje + Povečaj sličico videa, ki je prikazana v obvestilu iz razmerja 16:9 v razmerje 1:1 (lahko pride do popačenja) + Zruši aplikacijo + Spremeni velikost besedila podnapisov in stil ozadja v predvajalniku. Zahteva ponovni zagon aplikacije, da učinkuje. + Podnapisi + Samodejno ustvarjeno + Prilagodi zaslonu + Ni podnapisov + Samodejno ustvarjenjo (nalagalca ni bilo mogoče najti) + Sličica seznama predvajanja je bila spremenjena. + Na seznamu predvajanja + Odstrani zaznamek + Shrani seznam predvajanja med zaznamke + Nastavi kot sličico seznama predvajanja + Vklopi zvok + Utišaj + Ime + Predvajalnik v pojavnem oknu + Privzeto dejanje ob odprtju vsebine — %s + Prednostno dejanje \'odpri\' + Zapri omaro + Odpri omaro + Začni predvajati v pojavnem oknu + Začni s predvajanjem tukaj + Uvrščeno + Uvrsti + Pridržite za uvrstitev + Predvajaj seznam + Konference + Priljubljeno + Kiosk + To bo nadomestilo vaše trenutne nastavitve. + Opozorilo: ni mogoče uvoziti vseh datotek. + Izberi seznam predvajanja + Ali ste prepričani, da želite izbrisati vse elemente iz zgodovine\? + Ali želite odstraniti ta element iz zgodovine ogledov\? + NewPipe je prosta in odprta programska oprema: lahko jo uporabljaš, preučuješ in izboljšaš po želji. Lahko jo distributiraš in/ali spremeniš pod pogoji GNU General Public Licence, kot jo je izdala Free Software Foundation v različici 3 ali po izbiri v katerikoli novejši različici. + Projekt NewPipe jemlje vašo zasebnost zelo resno. Aplikacija zato ne zbira kakršnih koli podatkov brez vašega dovoljenja. +\nPolitika zasebnosti NewPipe-a podrobno pojasnjuje, kateri podatki so poslani in shranjeni, ko pošljete poročilo o zrušitvi. + Pomagaj + NewPipe razvijajo prostovoljci, ki preživljajo svoj prosti čas, da vam prinašajo najboljšo uporabniško izkušnjo. Pomagajte razvijalcem pri izdelavi še boljšega NewPipe-a medtem ko uživajo skodelico kave. + Za predvajanje te datoteke ni nameščena nobena aplikacija + Pritisni \"končano\" ko je rešena + Odstranjen 1 element. + Izračun zgoščevalne funkcije je v teku + ∞ videoposnetkov + 100+ videov + + %s poslušalec + %s poslušalca + %s poslušalcev + %s poslušalcev + + + %s gledalec + %s gledalca + %s gledalcev + %s gledalcev + + Število naročnikov ni na voljo + Vklop/izklop storitve, trenutno izbrana: + Povlecite za preureditev + Opis + Podobni pretoki + Komentarji + Prosimo preverite, če težava, ki opisuje vašo zrušitev aplikacije že obstaja. Ko ustvarite dvojne pripombe, vzamete naš čas, ki bi ga lahko porabili z odpravljanjem dejanske napake. + Prijavite na GitHub-u + Kopiraj oblikovano poročilo + Odobrite dovoljenje, da se ta aplikacija prikaže pred drugimi aplikacijami + Ali želite obnoviti privzete vrednosti\? + Povrni privzeto + Nobeden pretok ni na voljo za prenos + Ime datoteke ne sme biti prazno + Datoteka ne obstaja ali ji manjka dovoljenje za branje ali pisanje + Ni takšne datoteke/vira vsebine + Zunanji predvajalniki ne podpirajo teh vrst povezav + Obnavljanje od napake predvajanika + Prišlo je do neobnovljive napake v predvajalniku + Zunanja shramba ni na voljo + Pomoč + Izbriše zgodovino ključnih besed za iskanje + Položaji predvajalnika so bili izbrisani. + Ali želite izbrisati vse položaje predvajalnika\? + Izbriše vse položaje predvajalnika + Izbriši položaje predvajalnika + Izbriše zgodovino predvajanih videoposnetkov in položajev predvajalnika + Prepiše vašo trenutno zgodovino in naročnine + Piškotki reCAPTCHA so bili izbrisani + Obvestila za zgoščevanje videa v teku + Obvestilo hash-a videa + Obvestila za nove verzije NewPipe + Izvajalci + Albumi + Pesmi + Dogodki + Posnetki + Videoposnetki + Ta video ima omejitev starosti. +\n +\nVklopite \"%1$s\" v nastavitvah, če ga želite predvajati. + Youtube ponuja \"omejeni način\", ki skrije potencialno vsebino za odrasle + Vklop YouTubovega \"omejenega načina\" + Prikaz vsebin, ki so morda neprimerne za otroke zaradi omejitve starosti (kot na primer 18+) + Uvrščeno v predvajalnik v pojavnem oknu + Uvrščeno na predvajalnik v ozadju + Obvestilo + Instanca že obstaja + Validacija instance ni bila mogoča + Vnesite URL instance + Dodaj instanco + Najdite instance, ki so vam všeč na %s + Izberite vaše najljubše instance PeerTuba + Instance PeerTube + Privzeta država vsebine + URL-ja ni bilo mogoče prepoznati. Želite odpreti z drugo aplikacijo\? + Pokaži nasvet, ko boste pritisnili na ozadje ali pojavno okno v \"Podrobnosti:\" + Samodejno predvajanje + Pokaži indikator položaja predvajalnika na seznamih + Uporabi poteze za nadzor svetlosti predvajalnika + Poteza za nadzor svetlosti + Uporabi poteze za nadzor glasnosti predvajalnika + Nadzor potez za glasnost + Izklopite, če želite skriti opis videa in dodatnih informacij + Prikaži opis + Spremenite mapo z prenosi + Prikazujem rezultate za %s \ No newline at end of file diff --git a/app/src/main/res/values-sq/strings.xml b/app/src/main/res/values-sq/strings.xml index ac4793a0a..9f1e69221 100644 --- a/app/src/main/res/values-sq/strings.xml +++ b/app/src/main/res/values-sq/strings.xml @@ -637,4 +637,19 @@ Biskotat reCAPTCHA janë pastruar Pastroni biskotat reCAPTCHA Ngjyros njoftimin + Nuk ka app në këtë pajisje që mund ta ngarkojë + Kapitujt + Të fundit + Shfaq pamjen miniaturë + Duke llogaritur hash + Përshkrimi + Streams të ngjashme + Komentet + Njoftimet mbi progresin e hash-imit të videove + Njoftimi për Hash e Videos + Shfaq të dhënat meta + Ç\'aktivizoje për të fshehur përshkrimin e videos dhe informacione shtesë + Shfaq përshkrimin + Lejoje Android që të modifikojë ngjyrën e njoftimit bazuar tek ngjyra kryesore në pamjen miniaturë (mbani mend që kjo nuk është e disponueshme në të gjitha pajisjet) + Hape me \ No newline at end of file diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index 8be326dfa..b14012126 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -652,4 +652,5 @@ 顯示描述 開啟以 您裝置上沒有應用程式可以打開這個 + 應用程式當機 \ No newline at end of file From 9e1744f904e597ffab91c61f70dfc9ce0a802fa1 Mon Sep 17 00:00:00 2001 From: iamthesenate1 <77978836+iamthesenate1@users.noreply.github.com> Date: Sat, 6 Mar 2021 12:20:01 +0200 Subject: [PATCH 07/57] Add spcace after the comma, before Rommanian. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 80c7e2e88..f1791de4c 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@

WebsiteBlogFAQPress


-*Read this in other languages: [English](README.md), [한국어](README.ko.md), [Soomaali](README.so.md), [Português Brasil](README.pt_BR.md), [日本語](README.ja.md),[Română](README.ro.md) .* +*Read this in other languages: [English](README.md), [한국어](README.ko.md), [Soomaali](README.so.md), [Português Brasil](README.pt_BR.md), [日本語](README.ja.md), [Română](README.ro.md) .* WARNING: THIS IS A BETA VERSION, THEREFORE YOU MAY ENCOUNTER BUGS. IF YOU DO, OPEN AN ISSUE VIA OUR GITHUB REPOSITORY. From 37a96d063f2db6ff9f7082f6ae43a0a188abdd34 Mon Sep 17 00:00:00 2001 From: TiA4f8R <74829229+TiA4f8R@users.noreply.github.com> Date: Sun, 10 Jan 2021 14:13:20 +0100 Subject: [PATCH 08/57] Add different error messages for SoundCloud and YouTube unavailable contents Add new error strings for the six new exceptions created in the extractor and catch these exceptions. Extractor is, of course, updated with this PR. --- app/build.gradle | 2 +- .../newpipe/fragments/BaseStateFragment.java | 30 +++++++++++++++++-- .../schabi/newpipe/util/ExtractorHelper.java | 23 +++++++++++++- app/src/main/res/values-fr/strings.xml | 3 +- app/src/main/res/values/strings.xml | 8 ++++- 5 files changed, 59 insertions(+), 7 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 9a6430f53..7c504e968 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -180,7 +180,7 @@ dependencies { // NewPipe dependencies // You can use a local version by uncommenting a few lines in settings.gradle - implementation 'com.github.TeamNewPipe:NewPipeExtractor:v0.20.11' + implementation "com.github.TeamNewPipe:NewPipeExtractor:7e6f464407fc1a2c8fb0886d294093526a6ef0f1" implementation "com.github.TeamNewPipe:nanojson:1d9e1aea9049fc9f85e68b43ba39fe7be1c1f751" implementation "org.jsoup:jsoup:1.13.1" diff --git a/app/src/main/java/org/schabi/newpipe/fragments/BaseStateFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/BaseStateFragment.java index f876b767c..cf02af4a9 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/BaseStateFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/BaseStateFragment.java @@ -20,9 +20,15 @@ import org.schabi.newpipe.BaseFragment; import org.schabi.newpipe.MainActivity; import org.schabi.newpipe.R; import org.schabi.newpipe.ReCaptchaActivity; +import org.schabi.newpipe.extractor.exceptions.AgeRestrictedContentException; import org.schabi.newpipe.extractor.exceptions.ContentNotAvailableException; import org.schabi.newpipe.extractor.exceptions.ContentNotSupportedException; +import org.schabi.newpipe.extractor.exceptions.GeographicRestrictionException; +import org.schabi.newpipe.extractor.exceptions.PaidContentException; +import org.schabi.newpipe.extractor.exceptions.PrivateContentException; import org.schabi.newpipe.extractor.exceptions.ReCaptchaException; +import org.schabi.newpipe.extractor.exceptions.SoundCloudGoPlusContentException; +import org.schabi.newpipe.extractor.exceptions.YoutubeMusicPremiumContentException; import org.schabi.newpipe.ktx.ExceptionUtils; import org.schabi.newpipe.report.ErrorActivity; import org.schabi.newpipe.report.ErrorInfo; @@ -223,12 +229,30 @@ public abstract class BaseStateFragment extends BaseFragment implements ViewC if (exception instanceof ReCaptchaException) { onReCaptchaException((ReCaptchaException) exception); return true; - } else if (exception instanceof ContentNotAvailableException) { - showError(getString(R.string.content_not_available), false); - return true; } else if (ExceptionUtils.isNetworkRelated(exception)) { showError(getString(R.string.network_error), true); return true; + } else if (exception instanceof AgeRestrictedContentException) { + showError(getString(R.string.restricted_video_no_stream), false); + return true; + } else if (exception instanceof GeographicRestrictionException) { + showError(getString(R.string.georestricted_content), false); + return true; + } else if (exception instanceof PaidContentException) { + showError(getString(R.string.paid_content), false); + return true; + } else if (exception instanceof PrivateContentException) { + showError(getString(R.string.private_content), false); + return true; + } else if (exception instanceof SoundCloudGoPlusContentException) { + showError(getString(R.string.soundcloud_go_plus_content), false); + return true; + } else if (exception instanceof YoutubeMusicPremiumContentException) { + showError(getString(R.string.youtube_music_premium_content), false); + return true; + } else if (exception instanceof ContentNotAvailableException) { + showError(getString(R.string.content_not_available), false); + return true; } else if (exception instanceof ContentNotSupportedException) { showError(getString(R.string.content_not_supported), false); return true; diff --git a/app/src/main/java/org/schabi/newpipe/util/ExtractorHelper.java b/app/src/main/java/org/schabi/newpipe/util/ExtractorHelper.java index 6ee69dcd9..d6e3a0e80 100644 --- a/app/src/main/java/org/schabi/newpipe/util/ExtractorHelper.java +++ b/app/src/main/java/org/schabi/newpipe/util/ExtractorHelper.java @@ -1,6 +1,6 @@ /* * Copyright 2017 Mauricio Colli - * Extractors.java is part of NewPipe + * ExtractorHelper.java is part of NewPipe * * License: GPL-3.0+ * This program is free software: you can redistribute it and/or modify @@ -44,10 +44,16 @@ import org.schabi.newpipe.extractor.Page; import org.schabi.newpipe.extractor.StreamingService; import org.schabi.newpipe.extractor.channel.ChannelInfo; import org.schabi.newpipe.extractor.comments.CommentsInfo; +import org.schabi.newpipe.extractor.exceptions.AgeRestrictedContentException; import org.schabi.newpipe.extractor.exceptions.ContentNotAvailableException; import org.schabi.newpipe.extractor.exceptions.ContentNotSupportedException; +import org.schabi.newpipe.extractor.exceptions.GeographicRestrictionException; +import org.schabi.newpipe.extractor.exceptions.PaidContentException; import org.schabi.newpipe.extractor.exceptions.ParsingException; +import org.schabi.newpipe.extractor.exceptions.PrivateContentException; import org.schabi.newpipe.extractor.exceptions.ReCaptchaException; +import org.schabi.newpipe.extractor.exceptions.SoundCloudGoPlusContentException; +import org.schabi.newpipe.extractor.exceptions.YoutubeMusicPremiumContentException; import org.schabi.newpipe.extractor.feed.FeedExtractor; import org.schabi.newpipe.extractor.feed.FeedInfo; import org.schabi.newpipe.extractor.kiosk.KioskInfo; @@ -300,6 +306,21 @@ public final class ExtractorHelper { context.startActivity(intent); } else if (ExceptionUtils.isNetworkRelated(exception)) { Toast.makeText(context, R.string.network_error, Toast.LENGTH_LONG).show(); + } else if (exception instanceof AgeRestrictedContentException) { + Toast.makeText(context, R.string.restricted_video_no_stream, + Toast.LENGTH_LONG).show(); + } else if (exception instanceof GeographicRestrictionException) { + Toast.makeText(context, R.string.georestricted_content, Toast.LENGTH_LONG).show(); + } else if (exception instanceof PaidContentException) { + Toast.makeText(context, R.string.paid_content, Toast.LENGTH_LONG).show(); + } else if (exception instanceof PrivateContentException) { + Toast.makeText(context, R.string.private_content, Toast.LENGTH_LONG).show(); + } else if (exception instanceof SoundCloudGoPlusContentException) { + Toast.makeText(context, R.string.soundcloud_go_plus_content, + Toast.LENGTH_LONG).show(); + } else if (exception instanceof YoutubeMusicPremiumContentException) { + Toast.makeText(context, R.string.youtube_music_premium_content, + Toast.LENGTH_LONG).show(); } else if (exception instanceof ContentNotAvailableException) { Toast.makeText(context, R.string.content_not_available, Toast.LENGTH_LONG).show(); } else if (exception instanceof ContentNotSupportedException) { diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index c1afa106d..c241254db 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -665,4 +665,5 @@ Désactiver pour masquer la description de la vidéo et les informations supplémentaires Afficher la description Plante l\'application - \ No newline at end of file + Ce contenu n\'est pas disponible dans votre pays. + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 6a13c2b03..a8a343645 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,4 +1,4 @@ - + Tap \"Search\" to get started \n @@ -164,6 +164,7 @@ Turn on YouTube\'s \"Restricted Mode\" YouTube provides a \"Restricted Mode\" which hides potentially mature content This video is age restricted.\n\nTurn on \"%1$s\" in the settings if you want to see it. + This video is age-restricted.\nDue to new YouTube policies with age-restricted videos, NewPipe cannot access any of its video streams and thus is unable to play it. Live Downloads Downloads @@ -700,4 +701,9 @@ Recent Chapters No app on your device can open this + This content is not available in your country. + This is a SoundCloud Go+ track, at least in your country, so it cannot be streamed or downloaded by NewPipe. + This content is private, so it cannot be streamed or downloaded by NewPipe. + This video is available only to YouTube Music Premium members, so it cannot be streamed or downloaded by NewPipe. + This content is only available to users who have paid, so it cannot be streamed or downloaded by NewPipe. From 8518933ca87268e6b8008990be46a10bb3ddbef3 Mon Sep 17 00:00:00 2001 From: TobiGr Date: Sun, 7 Mar 2021 16:53:22 +0100 Subject: [PATCH 09/57] Update translations Translated using Weblate (Russian) Currently translated at 100.0% (624 of 624 strings) Translated using Weblate (French) Currently translated at 100.0% (624 of 624 strings) Translated using Weblate (Russian) Currently translated at 100.0% (624 of 624 strings) Translated using Weblate (Czech) Currently translated at 100.0% (624 of 624 strings) Translated using Weblate (Turkish) Currently translated at 100.0% (624 of 624 strings) --- app/src/main/res/values-cs/strings.xml | 1 + app/src/main/res/values-fr/strings.xml | 2 +- app/src/main/res/values-ru/strings.xml | 1 + app/src/main/res/values-tr/strings.xml | 1 + 4 files changed, 4 insertions(+), 1 deletion(-) diff --git a/app/src/main/res/values-cs/strings.xml b/app/src/main/res/values-cs/strings.xml index 7c2ce49c1..dbcdf951e 100644 --- a/app/src/main/res/values-cs/strings.xml +++ b/app/src/main/res/values-cs/strings.xml @@ -672,4 +672,5 @@ Na Vašem zařízení není aplikace, která to umí otevřít Podobné strýmy Vypnout pro skrytí popisu videa a doplňkové informace + Zbořit aplikaci \ No newline at end of file diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index c241254db..526974313 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -664,6 +664,6 @@ Commentaires Désactiver pour masquer la description de la vidéo et les informations supplémentaires Afficher la description - Plante l\'application + Faire planter l\'application Ce contenu n\'est pas disponible dans votre pays. diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 681987cad..db26e27ed 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -673,4 +673,5 @@ Показать описание Открыть в Подходящее приложение не найдено + Сбой приложения \ No newline at end of file diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index 68ee6608b..490bd2143 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -662,4 +662,5 @@ Açıklamayı göster Birlikte aç Aygıtınızdaki hiçbir uygulama bunu açamıyor + Uygulamayı çöktür \ No newline at end of file From 553b80164b4f951e2a967ff26855b408d0ddf070 Mon Sep 17 00:00:00 2001 From: Stypox Date: Wed, 9 Dec 2020 12:42:01 +0100 Subject: [PATCH 10/57] Move all error-related classes into error package --- .../{report => error}/ErrorInfoTest.java | 2 +- app/src/main/AndroidManifest.xml | 4 ++-- app/src/main/java/org/schabi/newpipe/App.java | 7 ++++--- .../schabi/newpipe/CheckForNewAppVersion.java | 19 ++++++++++++------- .../org/schabi/newpipe/DownloaderImpl.java | 1 + .../java/org/schabi/newpipe/MainActivity.java | 2 +- .../org/schabi/newpipe/RouterActivity.java | 2 +- .../newpipe/download/DownloadDialog.java | 6 +++--- .../{report => error}/AcraReportSender.java | 2 +- .../AcraReportSenderFactory.java | 2 +- .../{report => error}/ErrorActivity.java | 2 +- .../newpipe/{report => error}/ErrorInfo.kt | 2 +- .../{ => error}/ReCaptchaActivity.java | 5 ++++- .../newpipe/{report => error}/UserAction.java | 2 +- .../newpipe/fragments/BaseStateFragment.java | 8 ++++---- .../newpipe/fragments/MainFragment.java | 6 +++--- .../fragments/detail/VideoDetailFragment.java | 8 ++++---- .../fragments/list/BaseListFragment.java | 2 +- .../list/channel/ChannelFragment.java | 8 +++----- .../list/comments/CommentsFragment.java | 2 +- .../list/kiosk/DefaultKioskFragment.java | 2 +- .../fragments/list/kiosk/KioskFragment.java | 2 +- .../list/playlist/PlaylistFragment.java | 4 ++-- .../fragments/list/search/SearchFragment.java | 8 ++++---- .../list/videos/RelatedVideosFragment.java | 2 +- .../holder/CommentsMiniInfoItemHolder.java | 2 +- .../local/bookmark/BookmarkFragment.java | 2 +- .../schabi/newpipe/local/feed/FeedFragment.kt | 2 +- .../history/StatisticsPlaylistFragment.java | 6 +++--- .../local/playlist/LocalPlaylistFragment.java | 2 +- .../subscription/SubscriptionFragment.kt | 2 +- .../SubscriptionsImportFragment.java | 6 +++--- .../services/BaseImportExportService.java | 6 +++--- .../settings/ContentSettingsFragment.java | 8 ++++---- .../settings/HistorySettingsFragment.java | 6 +++--- .../settings/SelectChannelFragment.java | 6 +++--- .../newpipe/settings/SelectKioskFragment.java | 6 +++--- .../settings/SelectPlaylistFragment.java | 6 +++--- .../newpipe/settings/SettingMigrations.java | 6 +++--- .../settings/tabs/ChooseTabsFragment.java | 6 +++--- .../org/schabi/newpipe/settings/tabs/Tab.java | 6 +++--- .../schabi/newpipe/util/ExtractorHelper.java | 8 ++++---- .../giga/ui/adapter/MissionAdapter.java | 6 +++--- app/src/main/res/layout/activity_error.xml | 2 +- .../{report => error}/ErrorActivityTest.java | 2 +- .../{ => error}/ReCaptchaActivityTest.kt | 9 ++++----- 46 files changed, 111 insertions(+), 104 deletions(-) rename app/src/androidTest/java/org/schabi/newpipe/{report => error}/ErrorInfoTest.java (97%) rename app/src/main/java/org/schabi/newpipe/{report => error}/AcraReportSender.java (97%) rename app/src/main/java/org/schabi/newpipe/{report => error}/AcraReportSenderFactory.java (97%) rename app/src/main/java/org/schabi/newpipe/{report => error}/ErrorActivity.java (99%) rename app/src/main/java/org/schabi/newpipe/{report => error}/ErrorInfo.kt (94%) rename app/src/main/java/org/schabi/newpipe/{ => error}/ReCaptchaActivity.java (98%) rename app/src/main/java/org/schabi/newpipe/{report => error}/UserAction.java (96%) rename app/src/test/java/org/schabi/newpipe/{report => error}/ErrorActivityTest.java (97%) rename app/src/test/java/org/schabi/newpipe/{ => error}/ReCaptchaActivityTest.kt (83%) diff --git a/app/src/androidTest/java/org/schabi/newpipe/report/ErrorInfoTest.java b/app/src/androidTest/java/org/schabi/newpipe/error/ErrorInfoTest.java similarity index 97% rename from app/src/androidTest/java/org/schabi/newpipe/report/ErrorInfoTest.java rename to app/src/androidTest/java/org/schabi/newpipe/error/ErrorInfoTest.java index 09ae5648d..ef2ff7ec9 100644 --- a/app/src/androidTest/java/org/schabi/newpipe/report/ErrorInfoTest.java +++ b/app/src/androidTest/java/org/schabi/newpipe/error/ErrorInfoTest.java @@ -1,4 +1,4 @@ -package org.schabi.newpipe.report; +package org.schabi.newpipe.error; import android.os.Parcel; diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 1f92548b4..e7fa95759 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -85,7 +85,7 @@ android:name=".ExitActivity" android:label="@string/general_error" android:theme="@android:style/Theme.NoDisplay" /> - + } } - if (disposables != null) { - disposables.clear(); - } + disposables.clear(); if (subscribeButtonMonitor != null) { subscribeButtonMonitor.dispose(); } diff --git a/app/src/main/java/org/schabi/newpipe/fragments/list/comments/CommentsFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/list/comments/CommentsFragment.java index 3682fe13b..797b92c63 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/list/comments/CommentsFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/list/comments/CommentsFragment.java @@ -16,7 +16,7 @@ import org.schabi.newpipe.extractor.NewPipe; import org.schabi.newpipe.extractor.comments.CommentsInfo; import org.schabi.newpipe.fragments.list.BaseListInfoFragment; import org.schabi.newpipe.ktx.ViewUtils; -import org.schabi.newpipe.report.UserAction; +import org.schabi.newpipe.error.UserAction; import org.schabi.newpipe.util.ExtractorHelper; import io.reactivex.rxjava3.core.Single; diff --git a/app/src/main/java/org/schabi/newpipe/fragments/list/kiosk/DefaultKioskFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/list/kiosk/DefaultKioskFragment.java index 1797191b6..d83dfc63b 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/list/kiosk/DefaultKioskFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/list/kiosk/DefaultKioskFragment.java @@ -5,7 +5,7 @@ import android.os.Bundle; import org.schabi.newpipe.extractor.NewPipe; import org.schabi.newpipe.extractor.exceptions.ExtractionException; import org.schabi.newpipe.extractor.kiosk.KioskList; -import org.schabi.newpipe.report.UserAction; +import org.schabi.newpipe.error.UserAction; import org.schabi.newpipe.util.KioskTranslator; import org.schabi.newpipe.util.ServiceHelper; diff --git a/app/src/main/java/org/schabi/newpipe/fragments/list/kiosk/KioskFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/list/kiosk/KioskFragment.java index 2e5e64539..849e07716 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/list/kiosk/KioskFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/list/kiosk/KioskFragment.java @@ -20,7 +20,7 @@ import org.schabi.newpipe.extractor.kiosk.KioskInfo; import org.schabi.newpipe.extractor.linkhandler.ListLinkHandlerFactory; import org.schabi.newpipe.extractor.localization.ContentCountry; import org.schabi.newpipe.fragments.list.BaseListInfoFragment; -import org.schabi.newpipe.report.UserAction; +import org.schabi.newpipe.error.UserAction; import org.schabi.newpipe.util.ExtractorHelper; import org.schabi.newpipe.util.KioskTranslator; import org.schabi.newpipe.util.Localization; 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 85dea83dc..6d4995303 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 @@ -40,8 +40,8 @@ import org.schabi.newpipe.local.playlist.RemotePlaylistManager; import org.schabi.newpipe.player.helper.PlayerHolder; import org.schabi.newpipe.player.playqueue.PlayQueue; import org.schabi.newpipe.player.playqueue.PlaylistPlayQueue; -import org.schabi.newpipe.report.ErrorActivity; -import org.schabi.newpipe.report.UserAction; +import org.schabi.newpipe.error.ErrorActivity; +import org.schabi.newpipe.error.UserAction; import org.schabi.newpipe.util.ExtractorHelper; import org.schabi.newpipe.util.ImageDisplayConstants; import org.schabi.newpipe.util.KoreUtil; 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 5273fd396..0fca2e5a6 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 @@ -35,9 +35,12 @@ import androidx.recyclerview.widget.ItemTouchHelper; import androidx.recyclerview.widget.RecyclerView; import org.schabi.newpipe.R; -import org.schabi.newpipe.ReCaptchaActivity; import org.schabi.newpipe.database.history.model.SearchHistoryEntry; import org.schabi.newpipe.databinding.FragmentSearchBinding; +import org.schabi.newpipe.error.ErrorActivity; +import org.schabi.newpipe.error.ErrorInfo; +import org.schabi.newpipe.error.ReCaptchaActivity; +import org.schabi.newpipe.error.UserAction; import org.schabi.newpipe.extractor.InfoItem; import org.schabi.newpipe.extractor.ListExtractor; import org.schabi.newpipe.extractor.MetaInfo; @@ -54,9 +57,6 @@ import org.schabi.newpipe.fragments.list.BaseListFragment; import org.schabi.newpipe.ktx.AnimationType; import org.schabi.newpipe.ktx.ExceptionUtils; import org.schabi.newpipe.local.history.HistoryRecordManager; -import org.schabi.newpipe.report.ErrorActivity; -import org.schabi.newpipe.report.ErrorInfo; -import org.schabi.newpipe.report.UserAction; import org.schabi.newpipe.util.Constants; import org.schabi.newpipe.util.DeviceUtils; import org.schabi.newpipe.util.ExtractorHelper; diff --git a/app/src/main/java/org/schabi/newpipe/fragments/list/videos/RelatedVideosFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/list/videos/RelatedVideosFragment.java index 7afe69716..7f8410012 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/list/videos/RelatedVideosFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/list/videos/RelatedVideosFragment.java @@ -21,7 +21,7 @@ import org.schabi.newpipe.extractor.NewPipe; import org.schabi.newpipe.extractor.stream.StreamInfo; import org.schabi.newpipe.fragments.list.BaseListInfoFragment; import org.schabi.newpipe.ktx.ViewUtils; -import org.schabi.newpipe.report.UserAction; +import org.schabi.newpipe.error.UserAction; import org.schabi.newpipe.util.RelatedStreamInfo; import java.io.Serializable; diff --git a/app/src/main/java/org/schabi/newpipe/info_list/holder/CommentsMiniInfoItemHolder.java b/app/src/main/java/org/schabi/newpipe/info_list/holder/CommentsMiniInfoItemHolder.java index fe35a18c4..8bad3b6ad 100644 --- a/app/src/main/java/org/schabi/newpipe/info_list/holder/CommentsMiniInfoItemHolder.java +++ b/app/src/main/java/org/schabi/newpipe/info_list/holder/CommentsMiniInfoItemHolder.java @@ -14,11 +14,11 @@ import androidx.appcompat.app.AppCompatActivity; import androidx.preference.PreferenceManager; import org.schabi.newpipe.R; +import org.schabi.newpipe.error.ErrorActivity; import org.schabi.newpipe.extractor.InfoItem; import org.schabi.newpipe.extractor.comments.CommentsInfoItem; import org.schabi.newpipe.info_list.InfoItemBuilder; import org.schabi.newpipe.local.history.HistoryRecordManager; -import org.schabi.newpipe.report.ErrorActivity; import org.schabi.newpipe.util.CommentTextOnTouchListener; import org.schabi.newpipe.util.DeviceUtils; import org.schabi.newpipe.util.ImageDisplayConstants; diff --git a/app/src/main/java/org/schabi/newpipe/local/bookmark/BookmarkFragment.java b/app/src/main/java/org/schabi/newpipe/local/bookmark/BookmarkFragment.java index ee77db89f..b96f23a9e 100644 --- a/app/src/main/java/org/schabi/newpipe/local/bookmark/BookmarkFragment.java +++ b/app/src/main/java/org/schabi/newpipe/local/bookmark/BookmarkFragment.java @@ -26,7 +26,7 @@ import org.schabi.newpipe.database.playlist.model.PlaylistRemoteEntity; import org.schabi.newpipe.local.BaseLocalListFragment; import org.schabi.newpipe.local.playlist.LocalPlaylistManager; import org.schabi.newpipe.local.playlist.RemotePlaylistManager; -import org.schabi.newpipe.report.UserAction; +import org.schabi.newpipe.error.UserAction; import org.schabi.newpipe.util.NavigationHelper; import org.schabi.newpipe.util.OnClickGesture; diff --git a/app/src/main/java/org/schabi/newpipe/local/feed/FeedFragment.kt b/app/src/main/java/org/schabi/newpipe/local/feed/FeedFragment.kt index 04090abc6..efe64d2f2 100644 --- a/app/src/main/java/org/schabi/newpipe/local/feed/FeedFragment.kt +++ b/app/src/main/java/org/schabi/newpipe/local/feed/FeedFragment.kt @@ -38,10 +38,10 @@ import icepick.State import org.schabi.newpipe.R import org.schabi.newpipe.database.feed.model.FeedGroupEntity import org.schabi.newpipe.databinding.FragmentFeedBinding +import org.schabi.newpipe.error.UserAction import org.schabi.newpipe.fragments.list.BaseListFragment import org.schabi.newpipe.ktx.animate import org.schabi.newpipe.local.feed.service.FeedLoadService -import org.schabi.newpipe.report.UserAction import org.schabi.newpipe.util.Localization import java.util.Calendar diff --git a/app/src/main/java/org/schabi/newpipe/local/history/StatisticsPlaylistFragment.java b/app/src/main/java/org/schabi/newpipe/local/history/StatisticsPlaylistFragment.java index f9aa38054..515b623ec 100644 --- a/app/src/main/java/org/schabi/newpipe/local/history/StatisticsPlaylistFragment.java +++ b/app/src/main/java/org/schabi/newpipe/local/history/StatisticsPlaylistFragment.java @@ -34,9 +34,9 @@ import org.schabi.newpipe.local.BaseLocalListFragment; import org.schabi.newpipe.player.helper.PlayerHolder; import org.schabi.newpipe.player.playqueue.PlayQueue; import org.schabi.newpipe.player.playqueue.SinglePlayQueue; -import org.schabi.newpipe.report.ErrorActivity; -import org.schabi.newpipe.report.ErrorInfo; -import org.schabi.newpipe.report.UserAction; +import org.schabi.newpipe.error.ErrorActivity; +import org.schabi.newpipe.error.ErrorInfo; +import org.schabi.newpipe.error.UserAction; import org.schabi.newpipe.settings.SettingsActivity; import org.schabi.newpipe.util.KoreUtil; import org.schabi.newpipe.util.NavigationHelper; diff --git a/app/src/main/java/org/schabi/newpipe/local/playlist/LocalPlaylistFragment.java b/app/src/main/java/org/schabi/newpipe/local/playlist/LocalPlaylistFragment.java index 3137de9e6..c2d6698a9 100644 --- a/app/src/main/java/org/schabi/newpipe/local/playlist/LocalPlaylistFragment.java +++ b/app/src/main/java/org/schabi/newpipe/local/playlist/LocalPlaylistFragment.java @@ -34,6 +34,7 @@ import org.schabi.newpipe.database.stream.model.StreamEntity; import org.schabi.newpipe.database.stream.model.StreamStateEntity; import org.schabi.newpipe.databinding.LocalPlaylistHeaderBinding; import org.schabi.newpipe.databinding.PlaylistControlBinding; +import org.schabi.newpipe.error.UserAction; import org.schabi.newpipe.extractor.stream.StreamInfoItem; import org.schabi.newpipe.extractor.stream.StreamType; import org.schabi.newpipe.info_list.InfoItemDialog; @@ -42,7 +43,6 @@ import org.schabi.newpipe.local.history.HistoryRecordManager; import org.schabi.newpipe.player.helper.PlayerHolder; import org.schabi.newpipe.player.playqueue.PlayQueue; import org.schabi.newpipe.player.playqueue.SinglePlayQueue; -import org.schabi.newpipe.report.UserAction; import org.schabi.newpipe.util.KoreUtil; import org.schabi.newpipe.util.Localization; import org.schabi.newpipe.util.NavigationHelper; diff --git a/app/src/main/java/org/schabi/newpipe/local/subscription/SubscriptionFragment.kt b/app/src/main/java/org/schabi/newpipe/local/subscription/SubscriptionFragment.kt index b74288a34..cdb8b5db5 100644 --- a/app/src/main/java/org/schabi/newpipe/local/subscription/SubscriptionFragment.kt +++ b/app/src/main/java/org/schabi/newpipe/local/subscription/SubscriptionFragment.kt @@ -34,6 +34,7 @@ import org.schabi.newpipe.database.feed.model.FeedGroupEntity import org.schabi.newpipe.databinding.DialogTitleBinding import org.schabi.newpipe.databinding.FeedItemCarouselBinding import org.schabi.newpipe.databinding.FragmentSubscriptionBinding +import org.schabi.newpipe.error.UserAction import org.schabi.newpipe.extractor.channel.ChannelInfoItem import org.schabi.newpipe.fragments.BaseStateFragment import org.schabi.newpipe.ktx.animate @@ -56,7 +57,6 @@ import org.schabi.newpipe.local.subscription.services.SubscriptionsImportService import org.schabi.newpipe.local.subscription.services.SubscriptionsImportService.KEY_MODE import org.schabi.newpipe.local.subscription.services.SubscriptionsImportService.KEY_VALUE import org.schabi.newpipe.local.subscription.services.SubscriptionsImportService.PREVIOUS_EXPORT_MODE -import org.schabi.newpipe.report.UserAction import org.schabi.newpipe.util.FilePickerActivityHelper import org.schabi.newpipe.util.NavigationHelper import org.schabi.newpipe.util.OnClickGesture diff --git a/app/src/main/java/org/schabi/newpipe/local/subscription/SubscriptionsImportFragment.java b/app/src/main/java/org/schabi/newpipe/local/subscription/SubscriptionsImportFragment.java index d7a1051e6..7710c2bba 100644 --- a/app/src/main/java/org/schabi/newpipe/local/subscription/SubscriptionsImportFragment.java +++ b/app/src/main/java/org/schabi/newpipe/local/subscription/SubscriptionsImportFragment.java @@ -26,9 +26,9 @@ import org.schabi.newpipe.extractor.NewPipe; import org.schabi.newpipe.extractor.exceptions.ExtractionException; import org.schabi.newpipe.extractor.subscription.SubscriptionExtractor; import org.schabi.newpipe.local.subscription.services.SubscriptionsImportService; -import org.schabi.newpipe.report.ErrorActivity; -import org.schabi.newpipe.report.ErrorInfo; -import org.schabi.newpipe.report.UserAction; +import org.schabi.newpipe.error.ErrorActivity; +import org.schabi.newpipe.error.ErrorInfo; +import org.schabi.newpipe.error.UserAction; import org.schabi.newpipe.util.Constants; import org.schabi.newpipe.util.FilePickerActivityHelper; import org.schabi.newpipe.util.ServiceHelper; diff --git a/app/src/main/java/org/schabi/newpipe/local/subscription/services/BaseImportExportService.java b/app/src/main/java/org/schabi/newpipe/local/subscription/services/BaseImportExportService.java index f573f4679..6ad0761c8 100644 --- a/app/src/main/java/org/schabi/newpipe/local/subscription/services/BaseImportExportService.java +++ b/app/src/main/java/org/schabi/newpipe/local/subscription/services/BaseImportExportService.java @@ -35,12 +35,12 @@ import androidx.core.app.ServiceCompat; import org.reactivestreams.Publisher; import org.schabi.newpipe.R; +import org.schabi.newpipe.error.ErrorActivity; +import org.schabi.newpipe.error.ErrorInfo; +import org.schabi.newpipe.error.UserAction; import org.schabi.newpipe.extractor.subscription.SubscriptionExtractor; import org.schabi.newpipe.ktx.ExceptionUtils; import org.schabi.newpipe.local.subscription.SubscriptionManager; -import org.schabi.newpipe.report.ErrorActivity; -import org.schabi.newpipe.report.ErrorInfo; -import org.schabi.newpipe.report.UserAction; import java.io.FileNotFoundException; import java.util.Collections; diff --git a/app/src/main/java/org/schabi/newpipe/settings/ContentSettingsFragment.java b/app/src/main/java/org/schabi/newpipe/settings/ContentSettingsFragment.java index c0639131c..cd2a18436 100644 --- a/app/src/main/java/org/schabi/newpipe/settings/ContentSettingsFragment.java +++ b/app/src/main/java/org/schabi/newpipe/settings/ContentSettingsFragment.java @@ -21,13 +21,13 @@ import com.nostra13.universalimageloader.core.ImageLoader; import org.schabi.newpipe.DownloaderImpl; import org.schabi.newpipe.NewPipeDatabase; import org.schabi.newpipe.R; -import org.schabi.newpipe.ReCaptchaActivity; +import org.schabi.newpipe.error.ReCaptchaActivity; import org.schabi.newpipe.extractor.NewPipe; import org.schabi.newpipe.extractor.localization.ContentCountry; import org.schabi.newpipe.extractor.localization.Localization; -import org.schabi.newpipe.report.ErrorActivity; -import org.schabi.newpipe.report.ErrorInfo; -import org.schabi.newpipe.report.UserAction; +import org.schabi.newpipe.error.ErrorActivity; +import org.schabi.newpipe.error.ErrorInfo; +import org.schabi.newpipe.error.UserAction; import org.schabi.newpipe.util.FilePickerActivityHelper; import org.schabi.newpipe.util.ZipHelper; diff --git a/app/src/main/java/org/schabi/newpipe/settings/HistorySettingsFragment.java b/app/src/main/java/org/schabi/newpipe/settings/HistorySettingsFragment.java index 98c1ffc30..3e67d93e2 100644 --- a/app/src/main/java/org/schabi/newpipe/settings/HistorySettingsFragment.java +++ b/app/src/main/java/org/schabi/newpipe/settings/HistorySettingsFragment.java @@ -9,9 +9,9 @@ import androidx.preference.Preference; import org.schabi.newpipe.R; import org.schabi.newpipe.local.history.HistoryRecordManager; -import org.schabi.newpipe.report.ErrorActivity; -import org.schabi.newpipe.report.ErrorInfo; -import org.schabi.newpipe.report.UserAction; +import org.schabi.newpipe.error.ErrorActivity; +import org.schabi.newpipe.error.ErrorInfo; +import org.schabi.newpipe.error.UserAction; import org.schabi.newpipe.util.InfoCache; import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers; diff --git a/app/src/main/java/org/schabi/newpipe/settings/SelectChannelFragment.java b/app/src/main/java/org/schabi/newpipe/settings/SelectChannelFragment.java index afe42d5d8..5854d0a83 100644 --- a/app/src/main/java/org/schabi/newpipe/settings/SelectChannelFragment.java +++ b/app/src/main/java/org/schabi/newpipe/settings/SelectChannelFragment.java @@ -21,9 +21,9 @@ import com.nostra13.universalimageloader.core.ImageLoader; import org.schabi.newpipe.R; import org.schabi.newpipe.database.subscription.SubscriptionEntity; import org.schabi.newpipe.local.subscription.SubscriptionManager; -import org.schabi.newpipe.report.ErrorActivity; -import org.schabi.newpipe.report.ErrorInfo; -import org.schabi.newpipe.report.UserAction; +import org.schabi.newpipe.error.ErrorActivity; +import org.schabi.newpipe.error.ErrorInfo; +import org.schabi.newpipe.error.UserAction; import org.schabi.newpipe.util.ThemeHelper; import java.util.List; diff --git a/app/src/main/java/org/schabi/newpipe/settings/SelectKioskFragment.java b/app/src/main/java/org/schabi/newpipe/settings/SelectKioskFragment.java index fc974607b..7d220578e 100644 --- a/app/src/main/java/org/schabi/newpipe/settings/SelectKioskFragment.java +++ b/app/src/main/java/org/schabi/newpipe/settings/SelectKioskFragment.java @@ -18,9 +18,9 @@ import androidx.recyclerview.widget.RecyclerView; import org.schabi.newpipe.R; import org.schabi.newpipe.extractor.NewPipe; import org.schabi.newpipe.extractor.StreamingService; -import org.schabi.newpipe.report.ErrorActivity; -import org.schabi.newpipe.report.ErrorInfo; -import org.schabi.newpipe.report.UserAction; +import org.schabi.newpipe.error.ErrorActivity; +import org.schabi.newpipe.error.ErrorInfo; +import org.schabi.newpipe.error.UserAction; import org.schabi.newpipe.util.KioskTranslator; import org.schabi.newpipe.util.ServiceHelper; import org.schabi.newpipe.util.ThemeHelper; diff --git a/app/src/main/java/org/schabi/newpipe/settings/SelectPlaylistFragment.java b/app/src/main/java/org/schabi/newpipe/settings/SelectPlaylistFragment.java index 16ccd0953..6dcfc9179 100644 --- a/app/src/main/java/org/schabi/newpipe/settings/SelectPlaylistFragment.java +++ b/app/src/main/java/org/schabi/newpipe/settings/SelectPlaylistFragment.java @@ -26,9 +26,9 @@ import org.schabi.newpipe.database.playlist.PlaylistMetadataEntry; import org.schabi.newpipe.database.playlist.model.PlaylistRemoteEntity; import org.schabi.newpipe.local.playlist.LocalPlaylistManager; import org.schabi.newpipe.local.playlist.RemotePlaylistManager; -import org.schabi.newpipe.report.ErrorActivity; -import org.schabi.newpipe.report.ErrorInfo; -import org.schabi.newpipe.report.UserAction; +import org.schabi.newpipe.error.ErrorActivity; +import org.schabi.newpipe.error.ErrorInfo; +import org.schabi.newpipe.error.UserAction; import java.util.List; import java.util.Vector; diff --git a/app/src/main/java/org/schabi/newpipe/settings/SettingMigrations.java b/app/src/main/java/org/schabi/newpipe/settings/SettingMigrations.java index 9042559c9..33f83bc6f 100644 --- a/app/src/main/java/org/schabi/newpipe/settings/SettingMigrations.java +++ b/app/src/main/java/org/schabi/newpipe/settings/SettingMigrations.java @@ -7,9 +7,9 @@ import android.util.Log; import androidx.preference.PreferenceManager; import org.schabi.newpipe.R; -import org.schabi.newpipe.report.ErrorActivity; -import org.schabi.newpipe.report.ErrorInfo; -import org.schabi.newpipe.report.UserAction; +import org.schabi.newpipe.error.ErrorActivity; +import org.schabi.newpipe.error.ErrorInfo; +import org.schabi.newpipe.error.UserAction; import static org.schabi.newpipe.MainActivity.DEBUG; diff --git a/app/src/main/java/org/schabi/newpipe/settings/tabs/ChooseTabsFragment.java b/app/src/main/java/org/schabi/newpipe/settings/tabs/ChooseTabsFragment.java index cbc47392b..963021b69 100644 --- a/app/src/main/java/org/schabi/newpipe/settings/tabs/ChooseTabsFragment.java +++ b/app/src/main/java/org/schabi/newpipe/settings/tabs/ChooseTabsFragment.java @@ -28,9 +28,9 @@ import com.google.android.material.floatingactionbutton.FloatingActionButton; import org.schabi.newpipe.R; import org.schabi.newpipe.extractor.NewPipe; -import org.schabi.newpipe.report.ErrorActivity; -import org.schabi.newpipe.report.ErrorInfo; -import org.schabi.newpipe.report.UserAction; +import org.schabi.newpipe.error.ErrorActivity; +import org.schabi.newpipe.error.ErrorInfo; +import org.schabi.newpipe.error.UserAction; import org.schabi.newpipe.settings.SelectChannelFragment; import org.schabi.newpipe.settings.SelectKioskFragment; import org.schabi.newpipe.settings.SelectPlaylistFragment; diff --git a/app/src/main/java/org/schabi/newpipe/settings/tabs/Tab.java b/app/src/main/java/org/schabi/newpipe/settings/tabs/Tab.java index ce3874f39..b92a1a3fe 100644 --- a/app/src/main/java/org/schabi/newpipe/settings/tabs/Tab.java +++ b/app/src/main/java/org/schabi/newpipe/settings/tabs/Tab.java @@ -25,9 +25,9 @@ import org.schabi.newpipe.local.feed.FeedFragment; import org.schabi.newpipe.local.history.StatisticsPlaylistFragment; import org.schabi.newpipe.local.playlist.LocalPlaylistFragment; import org.schabi.newpipe.local.subscription.SubscriptionFragment; -import org.schabi.newpipe.report.ErrorActivity; -import org.schabi.newpipe.report.ErrorInfo; -import org.schabi.newpipe.report.UserAction; +import org.schabi.newpipe.error.ErrorActivity; +import org.schabi.newpipe.error.ErrorInfo; +import org.schabi.newpipe.error.UserAction; import org.schabi.newpipe.util.KioskTranslator; import org.schabi.newpipe.util.ServiceHelper; import org.schabi.newpipe.util.ThemeHelper; diff --git a/app/src/main/java/org/schabi/newpipe/util/ExtractorHelper.java b/app/src/main/java/org/schabi/newpipe/util/ExtractorHelper.java index d6e3a0e80..97436dfbc 100644 --- a/app/src/main/java/org/schabi/newpipe/util/ExtractorHelper.java +++ b/app/src/main/java/org/schabi/newpipe/util/ExtractorHelper.java @@ -33,7 +33,10 @@ import androidx.preference.PreferenceManager; import org.schabi.newpipe.MainActivity; import org.schabi.newpipe.R; -import org.schabi.newpipe.ReCaptchaActivity; +import org.schabi.newpipe.error.ErrorActivity; +import org.schabi.newpipe.error.ErrorInfo; +import org.schabi.newpipe.error.ReCaptchaActivity; +import org.schabi.newpipe.error.UserAction; import org.schabi.newpipe.extractor.Info; import org.schabi.newpipe.extractor.InfoItem; import org.schabi.newpipe.extractor.ListExtractor.InfoItemsPage; @@ -64,9 +67,6 @@ import org.schabi.newpipe.extractor.stream.StreamInfo; import org.schabi.newpipe.extractor.stream.StreamInfoItem; import org.schabi.newpipe.extractor.suggestion.SuggestionExtractor; import org.schabi.newpipe.ktx.ExceptionUtils; -import org.schabi.newpipe.report.ErrorActivity; -import org.schabi.newpipe.report.ErrorInfo; -import org.schabi.newpipe.report.UserAction; import java.util.Collections; import java.util.List; diff --git a/app/src/main/java/us/shandian/giga/ui/adapter/MissionAdapter.java b/app/src/main/java/us/shandian/giga/ui/adapter/MissionAdapter.java index bea4b6f94..a8b9f5269 100644 --- a/app/src/main/java/us/shandian/giga/ui/adapter/MissionAdapter.java +++ b/app/src/main/java/us/shandian/giga/ui/adapter/MissionAdapter.java @@ -41,9 +41,9 @@ import com.google.android.material.snackbar.Snackbar; import org.schabi.newpipe.BuildConfig; import org.schabi.newpipe.R; import org.schabi.newpipe.extractor.NewPipe; -import org.schabi.newpipe.report.ErrorActivity; -import org.schabi.newpipe.report.ErrorInfo; -import org.schabi.newpipe.report.UserAction; +import org.schabi.newpipe.error.ErrorActivity; +import org.schabi.newpipe.error.ErrorInfo; +import org.schabi.newpipe.error.UserAction; import org.schabi.newpipe.util.NavigationHelper; import org.schabi.newpipe.util.ShareUtils; diff --git a/app/src/main/res/layout/activity_error.xml b/app/src/main/res/layout/activity_error.xml index 4feea549c..c7161ab8e 100644 --- a/app/src/main/res/layout/activity_error.xml +++ b/app/src/main/res/layout/activity_error.xml @@ -3,7 +3,7 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" - tools:context=".report.ErrorActivity"> + tools:context=".error.ErrorActivity"> Date: Mon, 8 Mar 2021 09:46:05 +0100 Subject: [PATCH 11/57] Fix last resize mode not being restored correctly I think the settings key "last_resize_mode" is ambiguous. While it is used to get the recently used resize mode, someone thought while working on the resize mode switcher, that the old (to be replaced) resize mode should be stored. Fixes #5613 --- .../java/org/schabi/newpipe/player/helper/PlayerHelper.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/org/schabi/newpipe/player/helper/PlayerHelper.java b/app/src/main/java/org/schabi/newpipe/player/helper/PlayerHelper.java index ccc73e81f..e07be0c21 100644 --- a/app/src/main/java/org/schabi/newpipe/player/helper/PlayerHelper.java +++ b/app/src/main/java/org/schabi/newpipe/player/helper/PlayerHelper.java @@ -484,8 +484,9 @@ public final class PlayerHelper { break; } + // save the new resize mode so it can be restored in a future session player.getPrefs().edit().putInt( - player.getContext().getString(R.string.last_resize_mode), resizeMode).apply(); + player.getContext().getString(R.string.last_resize_mode), newResizeMode).apply(); return newResizeMode; } From 70f421b787373b1278ddaa0136f08e44a97e070c Mon Sep 17 00:00:00 2001 From: Tobi Date: Mon, 8 Mar 2021 10:43:05 +0100 Subject: [PATCH 12/57] Add links to Matrix and IRC chat when opening new issues (#5764) --- .github/ISSUE_TEMPLATE/config.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 3ba13e0ce..5a97b3662 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1 +1,8 @@ blank_issues_enabled: false +contact_links: + - name: 💬 IRC + url: https://webchat.freenode.net/#newpipe + about: Chat with us via IRC for quick Q/A + - name: 💬 Matrix + url: https://matrix.to/#/#freenode_#newpipe:matrix.org + about: Chat with us via Matrix for quick Q/A From eeaf3496d5ed8e5aa7624b86cfe0cc1b94f48dd0 Mon Sep 17 00:00:00 2001 From: Poolitzer <25934244+Poolitzer@users.noreply.github.com> Date: Mon, 8 Mar 2021 13:15:22 +0100 Subject: [PATCH 13/57] Fix: CI only on master --- .github/workflows/ci.yml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1f8960bdc..16d0f5a3c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,6 +1,12 @@ name: CI -on: [push, pull_request] +on: + pull_request: + branches: + - master + push: + branches: + - master jobs: build-and-test: From 1db3c57ef00131050ef1b59c77819a3327996562 Mon Sep 17 00:00:00 2001 From: Poolitzer <25934244+Poolitzer@users.noreply.github.com> Date: Mon, 8 Mar 2021 13:19:18 +0100 Subject: [PATCH 14/57] change master to dev --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 16d0f5a3c..d171d5ad3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -3,10 +3,10 @@ name: CI on: pull_request: branches: - - master + - dev push: branches: - - master + - dev jobs: build-and-test: From 3a61ab59f2e086df4978c0a1f4563e6eb32f92ab Mon Sep 17 00:00:00 2001 From: Poolitzer <25934244+Poolitzer@users.noreply.github.com> Date: Tue, 9 Mar 2021 11:21:40 +0100 Subject: [PATCH 15/57] adding master to push trigger Co-authored-by: Tobi --- .github/workflows/ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d171d5ad3..25e16ddfe 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -7,6 +7,7 @@ on: push: branches: - dev + - master jobs: build-and-test: From c43bca6007584c2cca28ddf984ad090baf370c68 Mon Sep 17 00:00:00 2001 From: Stypox Date: Fri, 11 Dec 2020 14:55:47 +0100 Subject: [PATCH 16/57] Add report/solve-recaptcha button in error panel It will be shown even when nothing could be loaded not due to a network error, and the user can choose to ignore or report it. Also improve error reporting arguments Also completely refactor error activity Also improve some code here and there --- app/build.gradle | 2 +- .../schabi/newpipe/error/ErrorInfoTest.java | 2 +- .../schabi/newpipe/ActivityCommunicator.java | 47 ---- app/src/main/java/org/schabi/newpipe/App.java | 12 +- .../schabi/newpipe/CheckForNewAppVersion.java | 15 +- .../java/org/schabi/newpipe/MainActivity.java | 10 +- .../org/schabi/newpipe/RouterActivity.java | 94 ++++++-- .../newpipe/download/DownloadDialog.java | 14 +- .../newpipe/error/AcraReportSender.java | 11 +- .../schabi/newpipe/error/ErrorActivity.java | 181 ++++++--------- .../org/schabi/newpipe/error/ErrorInfo.kt | 110 +++++++++- .../schabi/newpipe/error/ErrorPanelHelper.kt | 136 ++++++++++++ .../org/schabi/newpipe/error/UserAction.java | 15 +- .../newpipe/fragments/BaseStateFragment.java | 207 ++++-------------- .../newpipe/fragments/MainFragment.java | 30 ++- .../newpipe/fragments/ViewContract.java | 4 +- .../fragments/detail/VideoDetailFragment.java | 69 ++---- .../fragments/list/BaseListFragment.java | 19 +- .../fragments/list/BaseListInfoFragment.java | 49 ++++- .../list/channel/ChannelFragment.java | 83 ++----- .../list/comments/CommentsFragment.java | 48 +--- .../list/kiosk/DefaultKioskFragment.java | 6 +- .../fragments/list/kiosk/KioskFragment.java | 26 +-- .../list/playlist/PlaylistFragment.java | 58 ++--- .../fragments/list/search/SearchFragment.java | 110 ++++------ .../list/videos/RelatedVideosFragment.java | 38 +--- .../holder/CommentsMiniInfoItemHolder.java | 4 +- .../newpipe/local/BaseLocalListFragment.java | 26 +-- .../local/bookmark/BookmarkFragment.java | 26 +-- .../schabi/newpipe/local/feed/FeedFragment.kt | 72 ++---- .../history/StatisticsPlaylistFragment.java | 79 ++----- .../local/playlist/LocalPlaylistFragment.java | 82 ++++--- .../subscription/SubscriptionFragment.kt | 20 +- .../SubscriptionsImportFragment.java | 8 +- .../services/BaseImportExportService.java | 10 +- .../settings/ContentSettingsFragment.java | 21 +- .../settings/HistorySettingsFragment.java | 199 ++++++++--------- .../settings/SelectChannelFragment.java | 28 +-- .../newpipe/settings/SelectKioskFragment.java | 15 +- .../settings/SelectPlaylistFragment.java | 4 +- .../newpipe/settings/SettingMigrations.java | 10 +- .../settings/tabs/ChooseTabsFragment.java | 7 +- .../org/schabi/newpipe/settings/tabs/Tab.java | 5 +- .../schabi/newpipe/util/ExtractorHelper.java | 78 ------- .../giga/ui/adapter/MissionAdapter.java | 12 +- .../fragment_video_detail.xml | 2 +- .../{error_retry.xml => error_panel.xml} | 17 +- app/src/main/res/layout/fragment_blank.xml | 2 +- .../main/res/layout/fragment_bookmarks.xml | 2 +- app/src/main/res/layout/fragment_channel.xml | 2 +- app/src/main/res/layout/fragment_comments.xml | 6 +- app/src/main/res/layout/fragment_feed.xml | 2 +- app/src/main/res/layout/fragment_kiosk.xml | 2 +- app/src/main/res/layout/fragment_playlist.xml | 2 +- .../res/layout/fragment_related_streams.xml | 2 +- app/src/main/res/layout/fragment_search.xml | 2 +- .../main/res/layout/fragment_subscription.xml | 2 +- .../main/res/layout/fragment_video_detail.xml | 2 +- app/src/main/res/values/strings.xml | 1 + 59 files changed, 886 insertions(+), 1262 deletions(-) delete mode 100644 app/src/main/java/org/schabi/newpipe/ActivityCommunicator.java create mode 100644 app/src/main/java/org/schabi/newpipe/error/ErrorPanelHelper.kt rename app/src/main/res/layout/{error_retry.xml => error_panel.xml} (64%) diff --git a/app/build.gradle b/app/build.gradle index 7c504e968..8d0db17b2 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -155,7 +155,7 @@ task formatKtlint(type: JavaExec) { } afterEvaluate { - preDebugBuild.dependsOn formatKtlint, runCheckstyle, runKtlint + //preDebugBuild.dependsOn formatKtlint, runCheckstyle, runKtlint } dependencies { diff --git a/app/src/androidTest/java/org/schabi/newpipe/error/ErrorInfoTest.java b/app/src/androidTest/java/org/schabi/newpipe/error/ErrorInfoTest.java index ef2ff7ec9..d491059e5 100644 --- a/app/src/androidTest/java/org/schabi/newpipe/error/ErrorInfoTest.java +++ b/app/src/androidTest/java/org/schabi/newpipe/error/ErrorInfoTest.java @@ -31,7 +31,7 @@ public class ErrorInfoTest { assertEquals(UserAction.USER_REPORT, infoFromParcel.getUserAction()); assertEquals("youtube", infoFromParcel.getServiceName()); assertEquals("request", infoFromParcel.getRequest()); - assertEquals(R.string.general_error, infoFromParcel.getMessage()); + assertEquals(R.string.general_error, infoFromParcel.getMessageStringId()); parcel.recycle(); } diff --git a/app/src/main/java/org/schabi/newpipe/ActivityCommunicator.java b/app/src/main/java/org/schabi/newpipe/ActivityCommunicator.java deleted file mode 100644 index 9321b3071..000000000 --- a/app/src/main/java/org/schabi/newpipe/ActivityCommunicator.java +++ /dev/null @@ -1,47 +0,0 @@ -package org.schabi.newpipe; - -/* - * Created by Christian Schabesberger on 24.12.15. - * - * Copyright (C) Christian Schabesberger 2015 - * ActivityCommunicator.java is part of NewPipe. - * - * NewPipe is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * NewPipe is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with NewPipe. If not, see . - */ - -/** - * Singleton: - * Used to send data between certain Activity/Services within the same process. - * This can be considered as an ugly hack inside the Android universe. - **/ -public class ActivityCommunicator { - - private static ActivityCommunicator activityCommunicator; - private volatile Class returnActivity; - - public static ActivityCommunicator getCommunicator() { - if (activityCommunicator == null) { - activityCommunicator = new ActivityCommunicator(); - } - return activityCommunicator; - } - - public Class getReturnActivity() { - return returnActivity; - } - - public void setReturnActivity(final Class returnActivity) { - this.returnActivity = returnActivity; - } -} diff --git a/app/src/main/java/org/schabi/newpipe/App.java b/app/src/main/java/org/schabi/newpipe/App.java index 05b88148f..d8519d0cb 100644 --- a/app/src/main/java/org/schabi/newpipe/App.java +++ b/app/src/main/java/org/schabi/newpipe/App.java @@ -225,14 +225,10 @@ public class App extends MultiDexApplication { .setBuildConfigClass(BuildConfig.class) .build(); ACRA.init(this, acraConfig); - } catch (final ACRAConfigurationException ace) { - ace.printStackTrace(); - ErrorActivity.reportError(this, - ace, - null, - null, - ErrorInfo.make(UserAction.SOMETHING_ELSE, "none", - "Could not initialize ACRA crash report", R.string.app_ui_crash)); + } catch (final ACRAConfigurationException exception) { + exception.printStackTrace(); + ErrorActivity.reportError(this, null, null, new ErrorInfo(exception, + UserAction.SOMETHING_ELSE, "Could not initialize ACRA crash report")); } } diff --git a/app/src/main/java/org/schabi/newpipe/CheckForNewAppVersion.java b/app/src/main/java/org/schabi/newpipe/CheckForNewAppVersion.java index f4c51144d..ad8aae93d 100644 --- a/app/src/main/java/org/schabi/newpipe/CheckForNewAppVersion.java +++ b/app/src/main/java/org/schabi/newpipe/CheckForNewAppVersion.java @@ -63,9 +63,8 @@ public final class CheckForNewAppVersion { packageInfo = application.getPackageManager().getPackageInfo( application.getPackageName(), PackageManager.GET_SIGNATURES); } catch (final PackageManager.NameNotFoundException e) { - ErrorActivity.reportError(application, e, null, null, - ErrorInfo.make(UserAction.SOMETHING_ELSE, "none", - "Could not find package info", R.string.app_ui_crash)); + ErrorActivity.reportError(application, null, null, new ErrorInfo(e, + UserAction.CHECK_FOR_NEW_APP_VERSION, "Could not find package info")); return ""; } @@ -77,9 +76,8 @@ public final class CheckForNewAppVersion { final CertificateFactory cf = CertificateFactory.getInstance("X509"); c = (X509Certificate) cf.generateCertificate(input); } catch (final CertificateException e) { - ErrorActivity.reportError(application, e, null, null, - ErrorInfo.make(UserAction.SOMETHING_ELSE, "none", - "Certificate error", R.string.app_ui_crash)); + ErrorActivity.reportError(application, null, null, new ErrorInfo(e, + UserAction.CHECK_FOR_NEW_APP_VERSION, "Certificate error")); return ""; } @@ -88,9 +86,8 @@ public final class CheckForNewAppVersion { final byte[] publicKey = md.digest(c.getEncoded()); return byte2HexFormatted(publicKey); } catch (NoSuchAlgorithmException | CertificateEncodingException e) { - ErrorActivity.reportError(application, e, null, null, - ErrorInfo.make(UserAction.SOMETHING_ELSE, "none", - "Could not retrieve SHA1 key", R.string.app_ui_crash)); + ErrorActivity.reportError(application, null, null, new ErrorInfo(e, + UserAction.CHECK_FOR_NEW_APP_VERSION, "Could not retrieve SHA1 key")); return ""; } } diff --git a/app/src/main/java/org/schabi/newpipe/MainActivity.java b/app/src/main/java/org/schabi/newpipe/MainActivity.java index abcf3b04d..211441ba7 100644 --- a/app/src/main/java/org/schabi/newpipe/MainActivity.java +++ b/app/src/main/java/org/schabi/newpipe/MainActivity.java @@ -153,7 +153,7 @@ public class MainActivity extends AppCompatActivity { try { setupDrawer(); } catch (final Exception e) { - ErrorActivity.reportUiError(this, e); + ErrorActivity.reportUiError(this, null, "Setting up drawer", e); } if (DeviceUtils.isTv(this)) { @@ -238,7 +238,7 @@ public class MainActivity extends AppCompatActivity { try { tabSelected(item); } catch (final Exception e) { - ErrorActivity.reportUiError(this, e); + ErrorActivity.reportUiError(this, null, "Selecting main page tab", e); } break; case R.id.menu_options_about_group: @@ -340,7 +340,7 @@ public class MainActivity extends AppCompatActivity { try { showTabs(); } catch (final Exception e) { - ErrorActivity.reportUiError(this, e); + ErrorActivity.reportUiError(this, null, "Showing main page tabs", e); } } } @@ -487,7 +487,7 @@ public class MainActivity extends AppCompatActivity { drawerHeaderBinding.drawerHeaderActionButton.setContentDescription( getString(R.string.drawer_header_description) + selectedServiceName); } catch (final Exception e) { - ErrorActivity.reportUiError(this, e); + ErrorActivity.reportUiError(this, null, "Setting up service toggle", e); } final SharedPreferences sharedPreferences @@ -799,7 +799,7 @@ public class MainActivity extends AppCompatActivity { NavigationHelper.gotoMainFragment(getSupportFragmentManager()); } } catch (final Exception e) { - ErrorActivity.reportUiError(this, e); + ErrorActivity.reportUiError(this, null, "Handling intent", e); } } diff --git a/app/src/main/java/org/schabi/newpipe/RouterActivity.java b/app/src/main/java/org/schabi/newpipe/RouterActivity.java index 101a535f7..59b876386 100644 --- a/app/src/main/java/org/schabi/newpipe/RouterActivity.java +++ b/app/src/main/java/org/schabi/newpipe/RouterActivity.java @@ -33,15 +33,29 @@ import androidx.preference.PreferenceManager; import org.schabi.newpipe.databinding.ListRadioIconItemBinding; import org.schabi.newpipe.databinding.SingleChoiceDialogViewBinding; import org.schabi.newpipe.download.DownloadDialog; +import org.schabi.newpipe.error.ErrorActivity; +import org.schabi.newpipe.error.ErrorInfo; +import org.schabi.newpipe.error.ReCaptchaActivity; +import org.schabi.newpipe.error.UserAction; import org.schabi.newpipe.extractor.Info; import org.schabi.newpipe.extractor.NewPipe; import org.schabi.newpipe.extractor.StreamingService; import org.schabi.newpipe.extractor.StreamingService.LinkType; import org.schabi.newpipe.extractor.channel.ChannelInfo; +import org.schabi.newpipe.extractor.exceptions.AgeRestrictedContentException; +import org.schabi.newpipe.extractor.exceptions.ContentNotAvailableException; +import org.schabi.newpipe.extractor.exceptions.ContentNotSupportedException; import org.schabi.newpipe.extractor.exceptions.ExtractionException; +import org.schabi.newpipe.extractor.exceptions.GeographicRestrictionException; +import org.schabi.newpipe.extractor.exceptions.PaidContentException; +import org.schabi.newpipe.extractor.exceptions.PrivateContentException; +import org.schabi.newpipe.extractor.exceptions.ReCaptchaException; +import org.schabi.newpipe.extractor.exceptions.SoundCloudGoPlusContentException; +import org.schabi.newpipe.extractor.exceptions.YoutubeMusicPremiumContentException; import org.schabi.newpipe.extractor.playlist.PlaylistInfo; import org.schabi.newpipe.extractor.stream.StreamInfo; import org.schabi.newpipe.extractor.stream.VideoStream; +import org.schabi.newpipe.ktx.ExceptionUtils; import org.schabi.newpipe.player.MainPlayer; import org.schabi.newpipe.player.helper.PlayerHelper; import org.schabi.newpipe.player.helper.PlayerHolder; @@ -49,7 +63,6 @@ import org.schabi.newpipe.player.playqueue.ChannelPlayQueue; import org.schabi.newpipe.player.playqueue.PlayQueue; import org.schabi.newpipe.player.playqueue.PlaylistPlayQueue; import org.schabi.newpipe.player.playqueue.SinglePlayQueue; -import org.schabi.newpipe.error.UserAction; import org.schabi.newpipe.util.Constants; import org.schabi.newpipe.util.DeviceUtils; import org.schabi.newpipe.util.ExtractorHelper; @@ -84,13 +97,6 @@ import static org.schabi.newpipe.util.ThemeHelper.resolveResourceIdFromAttr; * Get the url from the intent and open it in the chosen preferred player. */ public class RouterActivity extends AppCompatActivity { - public static final String INTERNAL_ROUTE_KEY = "internalRoute"; - /** - * Removes invisible separators (\p{Z}) and punctuation characters including - * brackets (\p{P}). See http://www.regular-expressions.info/unicode.html for - * more details. - */ - private static final String REGEX_REMOVE_FROM_URL = "[\\p{Z}\\p{P}]"; protected final CompositeDisposable disposables = new CompositeDisposable(); @State protected int currentServiceId = -1; @@ -100,7 +106,6 @@ public class RouterActivity extends AppCompatActivity { protected int selectedRadioPosition = -1; protected int selectedPreviously = -1; protected String currentUrl; - protected boolean internalRoute = false; private StreamingService currentService; private boolean selectionIsDownload = false; @@ -123,7 +128,7 @@ public class RouterActivity extends AppCompatActivity { } @Override - protected void onSaveInstanceState(final Bundle outState) { + protected void onSaveInstanceState(@NonNull final Bundle outState) { super.onSaveInstanceState(outState); Icepick.saveInstanceState(this, outState); } @@ -164,18 +169,61 @@ public class RouterActivity extends AppCompatActivity { } else { showUnsupportedUrlDialog(url); } - }, throwable -> handleError(throwable, url))); + }, throwable -> handleError(this, + new ErrorInfo(throwable, UserAction.SHARE_TO_NEWPIPE, url)))); } - private void handleError(final Throwable throwable, final String url) { - throwable.printStackTrace(); + /** + * @param context the context. If instance of {@link RouterActivity} it will be finished at the + * end, and if needed {@link #showUnsupportedUrlDialog(String)} will be called + * on it. + * @param errorInfo The error information. The field {@link ErrorInfo#getRequest()} has to + * contain the url, if context is instance of {@link RouterActivity}, since it + * could be used to call {@link #showUnsupportedUrlDialog(String)}. + */ + private static void handleError(final Context context, final ErrorInfo errorInfo) { + if (errorInfo.getThrowable() != null) { + errorInfo.getThrowable().printStackTrace(); + } - if (throwable instanceof ExtractionException) { - showUnsupportedUrlDialog(url); + if (errorInfo.getThrowable() instanceof ReCaptchaException) { + Toast.makeText(context, R.string.recaptcha_request_toast, Toast.LENGTH_LONG).show(); + // Starting ReCaptcha Challenge Activity + final Intent intent = new Intent(context, ReCaptchaActivity.class); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + context.startActivity(intent); + } else if (errorInfo.getThrowable() != null + && ExceptionUtils.isNetworkRelated(errorInfo.getThrowable())) { + Toast.makeText(context, R.string.network_error, Toast.LENGTH_LONG).show(); + } else if (errorInfo.getThrowable() instanceof AgeRestrictedContentException) { + Toast.makeText(context, R.string.restricted_video_no_stream, + Toast.LENGTH_LONG).show(); + } else if (errorInfo.getThrowable() instanceof GeographicRestrictionException) { + Toast.makeText(context, R.string.georestricted_content, Toast.LENGTH_LONG).show(); + } else if (errorInfo.getThrowable() instanceof PaidContentException) { + Toast.makeText(context, R.string.paid_content, Toast.LENGTH_LONG).show(); + } else if (errorInfo.getThrowable() instanceof PrivateContentException) { + Toast.makeText(context, R.string.private_content, Toast.LENGTH_LONG).show(); + } else if (errorInfo.getThrowable() instanceof SoundCloudGoPlusContentException) { + Toast.makeText(context, R.string.soundcloud_go_plus_content, + Toast.LENGTH_LONG).show(); + } else if (errorInfo.getThrowable() instanceof YoutubeMusicPremiumContentException) { + Toast.makeText(context, R.string.youtube_music_premium_content, + Toast.LENGTH_LONG).show(); + } else if (errorInfo.getThrowable() instanceof ContentNotAvailableException) { + Toast.makeText(context, R.string.content_not_available, Toast.LENGTH_LONG).show(); + } else if (errorInfo.getThrowable() instanceof ContentNotSupportedException) { + Toast.makeText(context, R.string.content_not_supported, Toast.LENGTH_LONG).show(); + } else if (errorInfo.getThrowable() instanceof ExtractionException + && context instanceof RouterActivity) { + // unfortunately we cannot tell if the error is really caused by an unsupported url + ((RouterActivity) context).showUnsupportedUrlDialog(errorInfo.getRequest()); } else { - ExtractorHelper.handleGeneralException(this, -1, url, throwable, - UserAction.SOMETHING_ELSE, null); - finish(); + ErrorActivity.reportError(context, MainActivity.class, null, errorInfo); + } + + if (context instanceof RouterActivity) { + ((RouterActivity) context).finish(); } } @@ -500,7 +548,8 @@ public class RouterActivity extends AppCompatActivity { .subscribe(intent -> { startActivity(intent); finish(); - }, throwable -> handleError(throwable, currentUrl)) + }, throwable -> handleError(this, + new ErrorInfo(throwable, UserAction.SHARE_TO_NEWPIPE, currentUrl))) ); return; } @@ -580,6 +629,7 @@ public class RouterActivity extends AppCompatActivity { this.playerChoice = playerChoice; } + @NonNull @Override public String toString() { return serviceId + ":" + url + " > " + linkType + " ::: " + playerChoice; @@ -646,9 +696,9 @@ public class RouterActivity extends AppCompatActivity { if (fetcher != null) { fetcher.dispose(); } - }, throwable -> ExtractorHelper.handleGeneralException(this, - choice.serviceId, choice.url, throwable, finalUserAction, - ", opened with " + choice.playerChoice)); + }, throwable -> handleError(this, new ErrorInfo(throwable, finalUserAction, + choice.url + " opened with " + choice.playerChoice, + choice.serviceId))); } } 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 f845969c1..e21b27dd5 100644 --- a/app/src/main/java/org/schabi/newpipe/download/DownloadDialog.java +++ b/app/src/main/java/org/schabi/newpipe/download/DownloadDialog.java @@ -591,17 +591,6 @@ public class DownloadDialog extends DialogFragment .show(); } - private void showErrorActivity(final Exception e) { - ErrorActivity.reportError( - context, - Collections.singletonList(e), - null, - null, - ErrorInfo - .make(UserAction.SOMETHING_ELSE, "-", "-", R.string.general_error) - ); - } - private void prepareSelectedDownload() { final StoredDirectoryHelper mainStorage; final MediaFormat format; @@ -705,7 +694,8 @@ public class DownloadDialog extends DialogFragment mainStorage.getTag()); } } catch (final Exception e) { - showErrorActivity(e); + ErrorActivity.reportError(context, null, null, + new ErrorInfo(e, UserAction.DOWNLOAD_FAILED, "Getting storage")); return; } diff --git a/app/src/main/java/org/schabi/newpipe/error/AcraReportSender.java b/app/src/main/java/org/schabi/newpipe/error/AcraReportSender.java index 8a90f12a5..cc7911417 100644 --- a/app/src/main/java/org/schabi/newpipe/error/AcraReportSender.java +++ b/app/src/main/java/org/schabi/newpipe/error/AcraReportSender.java @@ -4,6 +4,7 @@ import android.content.Context; import androidx.annotation.NonNull; +import org.acra.ReportField; import org.acra.data.CrashReportData; import org.acra.sender.ReportSender; import org.schabi.newpipe.R; @@ -32,8 +33,12 @@ public class AcraReportSender implements ReportSender { @Override public void send(@NonNull final Context context, @NonNull final CrashReportData report) { - ErrorActivity.reportError(context, report, - ErrorInfo.make(UserAction.UI_ERROR, "none", - "App crash, UI failure", R.string.app_ui_crash)); + ErrorActivity.reportError(context, null, null, new ErrorInfo( + new String[]{report.getString(ReportField.STACK_TRACE)}, + UserAction.UI_ERROR, + ErrorInfo.SERVICE_NONE, + "ACRA report", + R.string.app_ui_crash, + null)); } } diff --git a/app/src/main/java/org/schabi/newpipe/error/ErrorActivity.java b/app/src/main/java/org/schabi/newpipe/error/ErrorActivity.java index 7ed92441b..19e764d29 100644 --- a/app/src/main/java/org/schabi/newpipe/error/ErrorActivity.java +++ b/app/src/main/java/org/schabi/newpipe/error/ErrorActivity.java @@ -23,9 +23,6 @@ import androidx.core.app.NavUtils; import com.google.android.material.snackbar.Snackbar; import com.grack.nanojson.JsonWriter; -import org.acra.ReportField; -import org.acra.data.CrashReportData; -import org.schabi.newpipe.ActivityCommunicator; import org.schabi.newpipe.BuildConfig; import org.schabi.newpipe.MainActivity; import org.schabi.newpipe.R; @@ -34,14 +31,9 @@ import org.schabi.newpipe.util.Localization; import org.schabi.newpipe.util.ShareUtils; import org.schabi.newpipe.util.ThemeHelper; -import java.io.PrintWriter; -import java.io.StringWriter; -import java.text.SimpleDateFormat; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; import java.util.Arrays; -import java.util.Date; -import java.util.List; -import java.util.TimeZone; -import java.util.Vector; import static org.schabi.newpipe.util.Localization.assureCorrectAppLanguage; @@ -70,7 +62,6 @@ public class ErrorActivity extends AppCompatActivity { public static final String TAG = ErrorActivity.class.toString(); // BUNDLE TAGS public static final String ERROR_INFO = "error_info"; - public static final String ERROR_LIST = "error_list"; public static final String ERROR_EMAIL_ADDRESS = "crashreport@newpipe.schabi.org"; public static final String ERROR_EMAIL_SUBJECT @@ -79,100 +70,68 @@ public class ErrorActivity extends AppCompatActivity { public static final String ERROR_GITHUB_ISSUE_URL = "https://github.com/TeamNewPipe/NewPipe/issues"; - private String[] errorList; + public static final DateTimeFormatter CURRENT_TIMESTAMP_FORMATTER + = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"); + + + /** + * Singleton: + * Used to send data between certain Activity/Services within the same process. + * This can be considered as an ugly hack inside the Android universe. + **/ + @Nullable private static Class savedReturnActivity = null; + private ErrorInfo errorInfo; - private Class returnActivity; private String currentTimeStamp; private ActivityErrorBinding activityErrorBinding; - public static void reportUiError(final AppCompatActivity activity, final Throwable el) { - reportError(activity, el, activity.getClass(), null, ErrorInfo.make(UserAction.UI_ERROR, - "none", "", R.string.app_ui_crash)); + public static void reportUiError(final Context context, + @Nullable final View rootView, + final String request, + final Throwable throwable) { + reportError(context, (context instanceof Activity ? context.getClass() : null), rootView, + new ErrorInfo(throwable, UserAction.UI_ERROR, request)); } - public static void reportError(final Context context, final List el, - final Class returnActivity, final View rootView, + public static void reportError(final Context context, + final Class returnActivity, + @Nullable final View rootView, final ErrorInfo errorInfo) { if (rootView != null) { - Snackbar.make(rootView, R.string.error_snackbar_message, 3 * 1000) + Snackbar.make(rootView, R.string.error_snackbar_message, Snackbar.LENGTH_LONG) .setActionTextColor(Color.YELLOW) .setAction(context.getString(R.string.error_snackbar_action).toUpperCase(), v -> - startErrorActivity(returnActivity, context, errorInfo, el)).show(); + startErrorActivity(returnActivity, context, errorInfo)).show(); } else { - startErrorActivity(returnActivity, context, errorInfo, el); + startErrorActivity(returnActivity, context, errorInfo); } } - private static void startErrorActivity(final Class returnActivity, final Context context, - final ErrorInfo errorInfo, final List el) { - final ActivityCommunicator ac = ActivityCommunicator.getCommunicator(); - ac.setReturnActivity(returnActivity); - final Intent intent = new Intent(context, ErrorActivity.class); - intent.putExtra(ERROR_INFO, errorInfo); - intent.putExtra(ERROR_LIST, elToSl(el)); - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - context.startActivity(intent); - } - - public static void reportError(final Context context, final Throwable e, - final Class returnActivity, final View rootView, - final ErrorInfo errorInfo) { - List el = null; - if (e != null) { - el = new Vector<>(); - el.add(e); - } - reportError(context, el, returnActivity, rootView, errorInfo); - } - // async call - public static void reportError(final Handler handler, final Context context, - final Throwable e, final Class returnActivity, - final View rootView, final ErrorInfo errorInfo) { - - List el = null; - if (e != null) { - el = new Vector<>(); - el.add(e); - } - reportError(handler, context, el, returnActivity, rootView, errorInfo); - } - - // async call - public static void reportError(final Handler handler, final Context context, - final List el, final Class returnActivity, - final View rootView, final ErrorInfo errorInfo) { - handler.post(() -> reportError(context, el, returnActivity, rootView, errorInfo)); - } - - public static void reportError(final Context context, final CrashReportData report, + public static void reportError(final Handler handler, + final Context context, + final Class returnActivity, + final View rootView, final ErrorInfo errorInfo) { - final String[] el = {report.getString(ReportField.STACK_TRACE)}; + handler.post(() -> reportError(context, returnActivity, rootView, errorInfo)); + } + + //////////////////////////////////////////////////////////////////////// + // UTILS + //////////////////////////////////////////////////////////////////////// + + private static void startErrorActivity(@Nullable final Class returnActivity, + final Context context, + final ErrorInfo errorInfo) { + savedReturnActivity = returnActivity; final Intent intent = new Intent(context, ErrorActivity.class); intent.putExtra(ERROR_INFO, errorInfo); - intent.putExtra(ERROR_LIST, el); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); context.startActivity(intent); } - private static String getStackTrace(final Throwable throwable) { - final StringWriter sw = new StringWriter(); - final PrintWriter pw = new PrintWriter(sw, true); - throwable.printStackTrace(pw); - return sw.getBuffer().toString(); - } - - // errorList to StringList - private static String[] elToSl(final List stackTraces) { - final String[] out = new String[stackTraces.size()]; - for (int i = 0; i < stackTraces.size(); i++) { - out[i] = getStackTrace(stackTraces.get(i)); - } - return out; - } - @Override protected void onCreate(final Bundle savedInstanceState) { assureCorrectAppLanguage(this); @@ -193,38 +152,28 @@ public class ErrorActivity extends AppCompatActivity { actionBar.setDisplayShowTitleEnabled(true); } - final ActivityCommunicator ac = ActivityCommunicator.getCommunicator(); - returnActivity = ac.getReturnActivity(); errorInfo = intent.getParcelableExtra(ERROR_INFO); - errorList = intent.getStringArrayExtra(ERROR_LIST); // important add guru meditation addGuruMeditation(); - currentTimeStamp = getCurrentTimeStamp(); + currentTimeStamp = CURRENT_TIMESTAMP_FORMATTER.format(LocalDateTime.now()); activityErrorBinding.errorReportEmailButton.setOnClickListener(v -> openPrivacyPolicyDialog(this, "EMAIL")); - activityErrorBinding.errorReportCopyButton.setOnClickListener(v -> { - ShareUtils.copyToClipboard(this, buildMarkdown()); - }); + activityErrorBinding.errorReportCopyButton.setOnClickListener(v -> + ShareUtils.copyToClipboard(this, buildMarkdown())); activityErrorBinding.errorReportGitHubButton.setOnClickListener(v -> openPrivacyPolicyDialog(this, "GITHUB")); // normal bugreport buildInfo(errorInfo); - if (errorInfo.getMessage() != 0) { - activityErrorBinding.errorMessageView.setText(errorInfo.getMessage()); - } else { - activityErrorBinding.errorMessageView.setVisibility(View.GONE); - activityErrorBinding.messageWhatHappenedView.setVisibility(View.GONE); - } - - activityErrorBinding.errorView.setText(formErrorText(errorList)); + activityErrorBinding.errorMessageView.setText(errorInfo.getMessageStringId()); + activityErrorBinding.errorView.setText(formErrorText(errorInfo.getStackTraces())); // print stack trace once again for debugging: - for (final String e : errorList) { + for (final String e : errorInfo.getStackTraces()) { Log.e(TAG, e); } } @@ -239,15 +188,14 @@ public class ErrorActivity extends AppCompatActivity { @Override public boolean onOptionsItemSelected(final MenuItem item) { final int id = item.getItemId(); - switch (id) { - case android.R.id.home: - goToReturnActivity(); - break; - case R.id.menu_item_share_error: - ShareUtils.shareText(this, getString(R.string.error_report_title), buildJson()); - break; + if (id == android.R.id.home) { + goToReturnActivity(); + } else if (id == R.id.menu_item_share_error) { + ShareUtils.shareText(this, getString(R.string.error_report_title), buildJson()); + } else { + return false; } - return false; + return true; } private void openPrivacyPolicyDialog(final Context context, final String action) { @@ -311,7 +259,7 @@ public class ErrorActivity extends AppCompatActivity { } private void goToReturnActivity() { - final Class checkedReturnActivity = getReturnActivity(returnActivity); + final Class checkedReturnActivity = getReturnActivity(savedReturnActivity); if (checkedReturnActivity == null) { super.onBackPressed(); } else { @@ -355,7 +303,7 @@ public class ErrorActivity extends AppCompatActivity { .value("version", BuildConfig.VERSION_NAME) .value("os", getOsString()) .value("time", currentTimeStamp) - .array("exceptions", Arrays.asList(errorList)) + .array("exceptions", Arrays.asList(errorInfo.getStackTraces())) .value("user_comment", activityErrorBinding.errorCommentBox.getText() .toString()) .end() @@ -393,27 +341,27 @@ public class ErrorActivity extends AppCompatActivity { // Collapse all logs to a single paragraph when there are more than one // to keep the GitHub issue clean. - if (errorList.length > 1) { + if (errorInfo.getStackTraces().length > 1) { htmlErrorReport .append("
Exceptions (") - .append(errorList.length) + .append(errorInfo.getStackTraces().length) .append(")

\n"); } // add the logs - for (int i = 0; i < errorList.length; i++) { + for (int i = 0; i < errorInfo.getStackTraces().length; i++) { htmlErrorReport.append("

Crash log "); - if (errorList.length > 1) { + if (errorInfo.getStackTraces().length > 1) { htmlErrorReport.append(i + 1); } htmlErrorReport.append("") .append("

\n") - .append("\n```\n").append(errorList[i]).append("\n```\n") + .append("\n```\n").append(errorInfo.getStackTraces()[i]).append("\n```\n") .append("

\n"); } // make sure to close everything - if (errorList.length > 1) { + if (errorInfo.getStackTraces().length > 1) { htmlErrorReport.append("

\n"); } htmlErrorReport.append("
\n"); @@ -466,11 +414,4 @@ public class ErrorActivity extends AppCompatActivity { //super.onBackPressed(); goToReturnActivity(); } - - public String getCurrentTimeStamp() { - final SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm"); - df.setTimeZone(TimeZone.getTimeZone("GMT")); - return df.format(new Date()); - } - } diff --git a/app/src/main/java/org/schabi/newpipe/error/ErrorInfo.kt b/app/src/main/java/org/schabi/newpipe/error/ErrorInfo.kt index bcf8be220..ffbc2cafc 100644 --- a/app/src/main/java/org/schabi/newpipe/error/ErrorInfo.kt +++ b/app/src/main/java/org/schabi/newpipe/error/ErrorInfo.kt @@ -3,21 +3,109 @@ package org.schabi.newpipe.error import android.os.Parcelable import androidx.annotation.StringRes import kotlinx.android.parcel.Parcelize +import org.schabi.newpipe.R +import org.schabi.newpipe.extractor.Info +import org.schabi.newpipe.extractor.NewPipe +import org.schabi.newpipe.extractor.exceptions.ContentNotAvailableException +import org.schabi.newpipe.extractor.exceptions.ContentNotSupportedException +import org.schabi.newpipe.extractor.exceptions.ExtractionException +import org.schabi.newpipe.extractor.services.youtube.extractors.YoutubeStreamExtractor.DeobfuscateException +import org.schabi.newpipe.ktx.isNetworkRelated +import java.io.PrintWriter +import java.io.StringWriter @Parcelize class ErrorInfo( - val userAction: UserAction?, - val serviceName: String, - val request: String, - @field:StringRes @param:StringRes val message: Int + val stackTraces: Array, + val userAction: UserAction, + val serviceName: String, + val request: String, + val messageStringId: Int, + @Transient // no need to store throwable, all data for report is in other variables + var throwable: Throwable? = null ) : Parcelable { - companion object { - @JvmStatic - fun make( - userAction: UserAction?, + + private constructor( + throwable: Throwable, + userAction: UserAction, serviceName: String, - request: String, - @StringRes message: Int - ) = ErrorInfo(userAction, serviceName, request, message) + request: String + ) : this( + throwableToStringList(throwable), + userAction, + serviceName, + request, + getMessageStringId(throwable, userAction), + throwable + ) + + private constructor( + throwable: List, + userAction: UserAction, + serviceName: String, + request: String + ) : this( + throwableListToStringList(throwable), + userAction, + serviceName, + request, + getMessageStringId(throwable.firstOrNull(), userAction), + throwable.firstOrNull() + ) + + // constructors with single throwable + constructor(throwable: Throwable, userAction: UserAction, request: String) + : this(throwable, userAction, SERVICE_NONE, request) + constructor(throwable: Throwable, userAction: UserAction, request: String, serviceId: Int) + : this(throwable, userAction, NewPipe.getNameOfService(serviceId), request) + constructor(throwable: Throwable, userAction: UserAction, request: String, info: Info?) + : this(throwable, userAction, getInfoServiceName(info), request) + + // constructors with list of throwables + constructor(throwable: List, userAction: UserAction, request: String) + : this(throwable, userAction, SERVICE_NONE, request) + constructor(throwable: List, userAction: UserAction, request: String, serviceId: Int) + : this(throwable, userAction, NewPipe.getNameOfService(serviceId), request) + constructor(throwable: List, userAction: UserAction, request: String, info: Info?) + : this(throwable, userAction, getInfoServiceName(info), request) + + companion object { + const val SERVICE_NONE = "none" + + private fun getStackTrace(throwable: Throwable): String { + StringWriter().use { stringWriter -> + PrintWriter(stringWriter, true).use { printWriter -> + throwable.printStackTrace(printWriter) + return stringWriter.buffer.toString() + } + } + } + + fun throwableToStringList(throwable: Throwable) = arrayOf(getStackTrace(throwable)) + + fun throwableListToStringList(throwable: List) = + Array(throwable.size) { i -> getStackTrace(throwable[i]) } + + private fun getInfoServiceName(info: Info?) = + if (info == null) SERVICE_NONE else NewPipe.getNameOfService(info.serviceId) + + @StringRes + private fun getMessageStringId(throwable: Throwable?, + action: UserAction): Int { + return when { + throwable is ContentNotAvailableException -> R.string.content_not_available + throwable != null && throwable.isNetworkRelated -> R.string.network_error + throwable is ContentNotSupportedException -> R.string.content_not_supported + throwable is DeobfuscateException -> R.string.youtube_signature_deobfuscation_error + throwable is ExtractionException -> R.string.parsing_error + action == UserAction.UI_ERROR -> R.string.app_ui_crash + action == UserAction.REQUESTED_COMMENTS -> R.string.error_unable_to_load_comments + action == UserAction.SUBSCRIPTION_CHANGE -> R.string.subscription_change_failed + action == UserAction.SUBSCRIPTION_UPDATE -> R.string.subscription_update_failed + action == UserAction.LOAD_IMAGE -> R.string.could_not_load_thumbnails + action == UserAction.DOWNLOAD_OPEN_DIALOG -> R.string.could_not_setup_download_menu + else -> R.string.general_error + } + } } } diff --git a/app/src/main/java/org/schabi/newpipe/error/ErrorPanelHelper.kt b/app/src/main/java/org/schabi/newpipe/error/ErrorPanelHelper.kt new file mode 100644 index 000000000..82e08d8de --- /dev/null +++ b/app/src/main/java/org/schabi/newpipe/error/ErrorPanelHelper.kt @@ -0,0 +1,136 @@ +package org.schabi.newpipe.error + +import android.content.Context +import android.content.Intent +import android.util.Log +import android.view.View +import android.widget.Button +import android.widget.TextView +import androidx.core.view.isVisible +import androidx.fragment.app.Fragment +import com.jakewharton.rxbinding4.view.clicks +import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers +import io.reactivex.rxjava3.disposables.Disposable +import org.schabi.newpipe.MainActivity +import org.schabi.newpipe.R +import org.schabi.newpipe.extractor.exceptions.AgeRestrictedContentException +import org.schabi.newpipe.extractor.exceptions.ContentNotAvailableException +import org.schabi.newpipe.extractor.exceptions.ContentNotSupportedException +import org.schabi.newpipe.extractor.exceptions.GeographicRestrictionException +import org.schabi.newpipe.extractor.exceptions.PaidContentException +import org.schabi.newpipe.extractor.exceptions.PrivateContentException +import org.schabi.newpipe.extractor.exceptions.ReCaptchaException +import org.schabi.newpipe.extractor.exceptions.SoundCloudGoPlusContentException +import org.schabi.newpipe.extractor.exceptions.YoutubeMusicPremiumContentException +import org.schabi.newpipe.ktx.animate +import org.schabi.newpipe.ktx.isInterruptedCaused +import org.schabi.newpipe.ktx.isNetworkRelated +import java.util.concurrent.TimeUnit + +class ErrorPanelHelper( + private val fragment: Fragment, + rootView: View, + onRetry: Runnable +) { + private val context: Context = rootView.context!! + private val errorPanelRoot: View = rootView.findViewById(R.id.error_panel) + private val errorTextView: TextView = errorPanelRoot.findViewById(R.id.error_message_view) + private val errorButtonAction: Button = errorPanelRoot.findViewById(R.id.error_button_action) + private val errorButtonRetry: Button = errorPanelRoot.findViewById(R.id.error_button_retry) + + private var errorDisposable: Disposable? = null + + init { + errorDisposable = errorButtonRetry.clicks() + .debounce(300, TimeUnit.MILLISECONDS) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe { onRetry.run() } + } + + fun showError(errorInfo: ErrorInfo) { + + if (errorInfo.throwable != null && errorInfo.throwable!!.isInterruptedCaused) { + if (DEBUG) { + Log.w(TAG, "onError() isInterruptedCaused! = [$errorInfo.throwable]") + } + return + } + + errorButtonAction.isVisible = true + if (errorInfo.throwable is ReCaptchaException) { + errorButtonAction.setText(R.string.recaptcha_solve) + errorButtonAction.setOnClickListener { + // Starting ReCaptcha Challenge Activity + val intent = Intent(context, ReCaptchaActivity::class.java) + intent.putExtra(ReCaptchaActivity.RECAPTCHA_URL_EXTRA, + (errorInfo.throwable as ReCaptchaException).url) + fragment.startActivityForResult(intent, ReCaptchaActivity.RECAPTCHA_REQUEST) + errorButtonAction.setOnClickListener(null) + } + errorTextView.setText(R.string.recaptcha_request_toast) + errorButtonRetry.isVisible = true + + } else { + errorButtonAction.setText(R.string.error_snackbar_action) + errorButtonAction.setOnClickListener { + ErrorActivity.reportError( + context, + MainActivity::class.java, + null, + errorInfo + ) + } + + // hide retry button by default, then show only if not unavailable/unsupported content + errorButtonRetry.isVisible = false + errorTextView.setText( + when (errorInfo.throwable) { + is AgeRestrictedContentException -> R.string.restricted_video_no_stream + is GeographicRestrictionException -> R.string.georestricted_content + is PaidContentException -> R.string.paid_content + is PrivateContentException -> R.string.private_content + is SoundCloudGoPlusContentException -> R.string.soundcloud_go_plus_content + is YoutubeMusicPremiumContentException -> R.string.youtube_music_premium_content + is ContentNotAvailableException -> R.string.content_not_available + is ContentNotSupportedException -> R.string.content_not_supported + else -> { + // show retry button only for content which is not unavailable or unsupported + errorButtonRetry.isVisible = true + if (errorInfo.throwable != null && errorInfo.throwable!!.isNetworkRelated) { + R.string.network_error + } else { + R.string.error_snackbar_message + } + } + } + ) + } + errorPanelRoot.animate(true, 300) + } + + fun showTextError(errorString: String) { + errorButtonAction.isVisible = false + errorButtonRetry.isVisible = false + errorTextView.text = errorString + } + + fun hide() { + errorButtonAction.setOnClickListener(null) + errorPanelRoot.animate(false, 150) + } + + fun isVisible(): Boolean { + return errorPanelRoot.isVisible + } + + fun dispose() { + errorButtonAction.setOnClickListener(null) + errorButtonRetry.setOnClickListener(null) + errorDisposable?.dispose() + } + + companion object { + val TAG: String = ErrorPanelHelper::class.simpleName!! + val DEBUG: Boolean = MainActivity.DEBUG + } +} diff --git a/app/src/main/java/org/schabi/newpipe/error/UserAction.java b/app/src/main/java/org/schabi/newpipe/error/UserAction.java index e9d427b01..e8dec9556 100644 --- a/app/src/main/java/org/schabi/newpipe/error/UserAction.java +++ b/app/src/main/java/org/schabi/newpipe/error/UserAction.java @@ -6,9 +6,12 @@ package org.schabi.newpipe.error; public enum UserAction { USER_REPORT("user report"), UI_ERROR("ui error"), - SUBSCRIPTION("subscription"), + SUBSCRIPTION_CHANGE("subscription change"), + SUBSCRIPTION_UPDATE("subscription update"), + SUBSCRIPTION_GET("get subscription"), + SUBSCRIPTION_IMPORT_EXPORT("subscription import or export"), LOAD_IMAGE("load image"), - SOMETHING_ELSE("something"), + SOMETHING_ELSE("something else"), SEARCHED("searched"), GET_SUGGESTIONS("get suggestions"), REQUESTED_STREAM("requested stream"), @@ -17,11 +20,15 @@ public enum UserAction { REQUESTED_KIOSK("requested kiosk"), REQUESTED_COMMENTS("requested comments"), REQUESTED_FEED("requested feed"), + REQUESTED_BOOKMARK("bookmark"), DELETE_FROM_HISTORY("delete from history"), - PLAY_STREAM("Play stream"), + PLAY_STREAM("play stream"), + DOWNLOAD_OPEN_DIALOG("download open dialog"), DOWNLOAD_POSTPROCESSING("download post-processing"), DOWNLOAD_FAILED("download failed"), - PREFERENCES_MIGRATION("migration of preferences"); + PREFERENCES_MIGRATION("migration of preferences"), + SHARE_TO_NEWPIPE("share to newpipe"), + CHECK_FOR_NEW_APP_VERSION("check for new app version"); private final String message; diff --git a/app/src/main/java/org/schabi/newpipe/fragments/BaseStateFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/BaseStateFragment.java index 7566ec2a0..0d244231d 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/BaseStateFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/BaseStateFragment.java @@ -1,48 +1,25 @@ package org.schabi.newpipe.fragments; import android.content.Context; -import android.content.Intent; import android.os.Bundle; import android.util.Log; import android.view.View; -import android.widget.Button; import android.widget.ProgressBar; -import android.widget.TextView; -import android.widget.Toast; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import androidx.annotation.StringRes; - -import com.jakewharton.rxbinding4.view.RxView; import org.schabi.newpipe.BaseFragment; import org.schabi.newpipe.MainActivity; import org.schabi.newpipe.R; import org.schabi.newpipe.error.ErrorActivity; import org.schabi.newpipe.error.ErrorInfo; -import org.schabi.newpipe.error.ReCaptchaActivity; -import org.schabi.newpipe.error.UserAction; -import org.schabi.newpipe.extractor.exceptions.AgeRestrictedContentException; -import org.schabi.newpipe.extractor.exceptions.ContentNotAvailableException; -import org.schabi.newpipe.extractor.exceptions.ContentNotSupportedException; -import org.schabi.newpipe.extractor.exceptions.GeographicRestrictionException; -import org.schabi.newpipe.extractor.exceptions.PaidContentException; -import org.schabi.newpipe.extractor.exceptions.PrivateContentException; -import org.schabi.newpipe.extractor.exceptions.ReCaptchaException; -import org.schabi.newpipe.extractor.exceptions.SoundCloudGoPlusContentException; -import org.schabi.newpipe.extractor.exceptions.YoutubeMusicPremiumContentException; -import org.schabi.newpipe.ktx.ExceptionUtils; +import org.schabi.newpipe.error.ErrorPanelHelper; import org.schabi.newpipe.util.InfoCache; -import java.util.Collections; -import java.util.List; -import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import icepick.State; -import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers; -import io.reactivex.rxjava3.disposables.Disposable; import static org.schabi.newpipe.ktx.ViewUtils.animate; @@ -55,12 +32,7 @@ public abstract class BaseStateFragment extends BaseFragment implements ViewC private View emptyStateView; @Nullable private ProgressBar loadingProgressBar; - - private Disposable errorDisposable; - - protected View errorPanelRoot; - private Button errorButtonRetry; - private TextView errorTextView; + private ErrorPanelHelper errorPanelHelper; @Override public void onViewCreated(@NonNull final View rootView, final Bundle savedInstanceState) { @@ -77,9 +49,7 @@ public abstract class BaseStateFragment extends BaseFragment implements ViewC @Override public void onDestroy() { super.onDestroy(); - if (errorDisposable != null) { - errorDisposable.dispose(); - } + errorPanelHelper.dispose(); } /*////////////////////////////////////////////////////////////////////////// @@ -89,22 +59,9 @@ public abstract class BaseStateFragment extends BaseFragment implements ViewC @Override protected void initViews(final View rootView, final Bundle savedInstanceState) { super.initViews(rootView, savedInstanceState); - emptyStateView = rootView.findViewById(R.id.empty_state_view); loadingProgressBar = rootView.findViewById(R.id.loading_progress_bar); - - errorPanelRoot = rootView.findViewById(R.id.error_panel); - errorButtonRetry = rootView.findViewById(R.id.error_button_retry); - errorTextView = rootView.findViewById(R.id.error_message_view); - } - - @Override - protected void initListeners() { - super.initListeners(); - errorDisposable = RxView.clicks(errorButtonRetry) - .debounce(300, TimeUnit.MILLISECONDS) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(o -> onRetryButtonClicked()); + errorPanelHelper = new ErrorPanelHelper(this, rootView, this::onRetryButtonClicked); } protected void onRetryButtonClicked() { @@ -143,7 +100,7 @@ public abstract class BaseStateFragment extends BaseFragment implements ViewC if (loadingProgressBar != null) { animate(loadingProgressBar, true, 400); } - animate(errorPanelRoot, false, 150); + errorPanelHelper.hide(); } @Override @@ -154,10 +111,9 @@ public abstract class BaseStateFragment extends BaseFragment implements ViewC if (loadingProgressBar != null) { animate(loadingProgressBar, false, 0); } - animate(errorPanelRoot, false, 150); + errorPanelHelper.hide(); } - @Override public void showEmptyState() { isLoading.set(false); if (emptyStateView != null) { @@ -166,26 +122,7 @@ public abstract class BaseStateFragment extends BaseFragment implements ViewC if (loadingProgressBar != null) { animate(loadingProgressBar, false, 0); } - animate(errorPanelRoot, false, 150); - } - - @Override - public void showError(final String message, final boolean showRetryButton) { - if (DEBUG) { - Log.d(TAG, "showError() called with: " - + "message = [" + message + "], showRetryButton = [" + showRetryButton + "]"); - } - isLoading.set(false); - InfoCache.getInstance().clearCache(); - hideLoading(); - - errorTextView.setText(message); - if (showRetryButton) { - animate(errorButtonRetry, true, 600); - } else { - animate(errorButtonRetry, false, 0); - } - animate(errorPanelRoot, true, 300); + errorPanelHelper.hide(); } @Override @@ -196,138 +133,70 @@ public abstract class BaseStateFragment extends BaseFragment implements ViewC hideLoading(); } + @Override + public void handleError() { + isLoading.set(false); + InfoCache.getInstance().clearCache(); + hideLoading(); + } + /*////////////////////////////////////////////////////////////////////////// // Error handling //////////////////////////////////////////////////////////////////////////*/ - /** - * Default implementation handles some general exceptions. - * - * @param exception The exception that should be handled - * @return If the exception was handled - */ - protected boolean onError(final Throwable exception) { - if (DEBUG) { - Log.d(TAG, "onError() called with: exception = [" + exception + "]"); - } - isLoading.set(false); + public final void showError(final ErrorInfo errorInfo) { + handleError(); if (isDetached() || isRemoving()) { if (DEBUG) { - Log.w(TAG, "onError() is detached or removing = [" + exception + "]"); + Log.w(TAG, "showError() is detached or removing = [" + errorInfo + "]"); } - return true; + return; } - if (ExceptionUtils.isInterruptedCaused(exception)) { + errorPanelHelper.showError(errorInfo); + } + + public final void showTextError(final @NonNull String errorString) { + handleError(); + + if (isDetached() || isRemoving()) { if (DEBUG) { - Log.w(TAG, "onError() isInterruptedCaused! = [" + exception + "]"); + Log.w(TAG, "showTextError() is detached or removing = [" + errorString + "]"); } - return true; + return; } - if (exception instanceof ReCaptchaException) { - onReCaptchaException((ReCaptchaException) exception); - return true; - } else if (ExceptionUtils.isNetworkRelated(exception)) { - showError(getString(R.string.network_error), true); - return true; - } else if (exception instanceof AgeRestrictedContentException) { - showError(getString(R.string.restricted_video_no_stream), false); - return true; - } else if (exception instanceof GeographicRestrictionException) { - showError(getString(R.string.georestricted_content), false); - return true; - } else if (exception instanceof PaidContentException) { - showError(getString(R.string.paid_content), false); - return true; - } else if (exception instanceof PrivateContentException) { - showError(getString(R.string.private_content), false); - return true; - } else if (exception instanceof SoundCloudGoPlusContentException) { - showError(getString(R.string.soundcloud_go_plus_content), false); - return true; - } else if (exception instanceof YoutubeMusicPremiumContentException) { - showError(getString(R.string.youtube_music_premium_content), false); - return true; - } else if (exception instanceof ContentNotAvailableException) { - showError(getString(R.string.content_not_available), false); - return true; - } else if (exception instanceof ContentNotSupportedException) { - showError(getString(R.string.content_not_supported), false); - return true; - } - - return false; + errorPanelHelper.showTextError(errorString); } - public void onReCaptchaException(final ReCaptchaException exception) { - if (DEBUG) { - Log.d(TAG, "onReCaptchaException() called"); - } - Toast.makeText(activity, R.string.recaptcha_request_toast, Toast.LENGTH_LONG).show(); - // Starting ReCaptcha Challenge Activity - final Intent intent = new Intent(activity, ReCaptchaActivity.class); - intent.putExtra(ReCaptchaActivity.RECAPTCHA_URL_EXTRA, exception.getUrl()); - startActivityForResult(intent, ReCaptchaActivity.RECAPTCHA_REQUEST); - - showError(getString(R.string.recaptcha_request_toast), false); + public final void hideErrorPanel() { + errorPanelHelper.hide(); } - public void onUnrecoverableError(final Throwable exception, final UserAction userAction, - final String serviceName, final String request, - @StringRes final int errorId) { - onUnrecoverableError(Collections.singletonList(exception), userAction, serviceName, - request, errorId); - } - - public void onUnrecoverableError(final List exception, final UserAction userAction, - final String serviceName, final String request, - @StringRes final int errorId) { - if (DEBUG) { - Log.d(TAG, "onUnrecoverableError() called with: exception = [" + exception + "]"); - } - - ErrorActivity.reportError(getContext(), exception, MainActivity.class, null, - ErrorInfo.make(userAction, serviceName == null ? "none" : serviceName, - request == null ? "none" : request, errorId)); - } - - public void showSnackBarError(final Throwable exception, final UserAction userAction, - final String serviceName, final String request, - @StringRes final int errorId) { - showSnackBarError(Collections.singletonList(exception), userAction, serviceName, request, - errorId); + public final boolean isErrorPanelVisible() { + return errorPanelHelper.isVisible(); } /** * Show a SnackBar and only call - * {@link ErrorActivity#reportError(Context, List, Class, View, ErrorInfo)} + * {@link ErrorActivity#reportError(Context, Class, View, ErrorInfo)} * IF we a find a valid view (otherwise the error screen appears). * - * @param exception List of the exceptions to show - * @param userAction The user action that caused the exception - * @param serviceName The service where the exception happened - * @param request The page that was requested - * @param errorId The ID of the error + * @param errorInfo The error information */ - public void showSnackBarError(final List exception, final UserAction userAction, - final String serviceName, final String request, - @StringRes final int errorId) { + public void showSnackBarError(final ErrorInfo errorInfo) { if (DEBUG) { - Log.d(TAG, "showSnackBarError() called with: " - + "exception = [" + exception + "], userAction = [" + userAction + "], " - + "request = [" + request + "], errorId = [" + errorId + "]"); + Log.d(TAG, "showSnackBarError() called with: errorInfo = [" + errorInfo + "]"); } View rootView = activity != null ? activity.findViewById(android.R.id.content) : null; - if (rootView == null && getView() != null) { + if (rootView == null) { rootView = getView(); } if (rootView == null) { return; } - ErrorActivity.reportError(getContext(), exception, MainActivity.class, rootView, - ErrorInfo.make(userAction, serviceName, request, errorId)); + ErrorActivity.reportError(requireContext(), MainActivity.class, rootView, errorInfo); } } diff --git a/app/src/main/java/org/schabi/newpipe/fragments/MainFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/MainFragment.java index 649f2d5b1..9443bac05 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/MainFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/MainFragment.java @@ -14,7 +14,6 @@ import android.view.ViewGroup; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.app.ActionBar; -import androidx.appcompat.app.AppCompatActivity; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentManager; import androidx.fragment.app.FragmentStatePagerAdapterMenuWorkaround; @@ -25,10 +24,8 @@ import com.google.android.material.tabs.TabLayout; import org.schabi.newpipe.BaseFragment; import org.schabi.newpipe.R; import org.schabi.newpipe.databinding.FragmentMainBinding; -import org.schabi.newpipe.extractor.exceptions.ExtractionException; import org.schabi.newpipe.error.ErrorActivity; -import org.schabi.newpipe.error.ErrorInfo; -import org.schabi.newpipe.error.UserAction; +import org.schabi.newpipe.extractor.exceptions.ExtractionException; import org.schabi.newpipe.settings.tabs.Tab; import org.schabi.newpipe.settings.tabs.TabsManager; import org.schabi.newpipe.util.NavigationHelper; @@ -128,7 +125,8 @@ public class MainFragment extends BaseFragment implements TabLayout.OnTabSelecte //////////////////////////////////////////////////////////////////////////*/ @Override - public void onCreateOptionsMenu(final Menu menu, final MenuInflater inflater) { + public void onCreateOptionsMenu(@NonNull final Menu menu, + @NonNull final MenuInflater inflater) { super.onCreateOptionsMenu(menu, inflater); if (DEBUG) { Log.d(TAG, "onCreateOptionsMenu() called with: " @@ -144,15 +142,14 @@ public class MainFragment extends BaseFragment implements TabLayout.OnTabSelecte @Override public boolean onOptionsItemSelected(final MenuItem item) { - switch (item.getItemId()) { - case R.id.action_search: - try { - NavigationHelper.openSearchFragment(getFM(), - ServiceHelper.getSelectedServiceId(activity), ""); - } catch (final Exception e) { - ErrorActivity.reportUiError((AppCompatActivity) getActivity(), e); - } - return true; + if (item.getItemId() == R.id.action_search) { + try { + NavigationHelper.openSearchFragment(getFM(), + ServiceHelper.getSelectedServiceId(activity), ""); + } catch (final Exception e) { + ErrorActivity.reportUiError(getActivity(), null, "Opening search fragment", e); + } + return true; } return super.onOptionsItemSelected(item); } @@ -241,8 +238,7 @@ public class MainFragment extends BaseFragment implements TabLayout.OnTabSelecte } if (throwable != null) { - ErrorActivity.reportError(context, throwable, null, null, ErrorInfo - .make(UserAction.UI_ERROR, "none", "", R.string.app_ui_crash)); + ErrorActivity.reportUiError(context, null, "Getting fragment item", throwable); return new BlankFragment(); } @@ -254,7 +250,7 @@ public class MainFragment extends BaseFragment implements TabLayout.OnTabSelecte } @Override - public int getItemPosition(final Object object) { + public int getItemPosition(@NonNull final Object object) { // Causes adapter to reload all Fragments when // notifyDataSetChanged is called return POSITION_NONE; diff --git a/app/src/main/java/org/schabi/newpipe/fragments/ViewContract.java b/app/src/main/java/org/schabi/newpipe/fragments/ViewContract.java index bb980ac64..78f644ffb 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/ViewContract.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/ViewContract.java @@ -7,7 +7,7 @@ public interface ViewContract { void showEmptyState(); - void showError(String message, boolean showRetryButton); - void handleResult(I result); + + void handleError(); } 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 505111da5..c6789804c 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 @@ -37,7 +37,6 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.StringRes; import androidx.appcompat.app.AlertDialog; -import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.content.res.AppCompatResources; import androidx.appcompat.widget.Toolbar; import androidx.coordinatorlayout.widget.CoordinatorLayout; @@ -64,9 +63,7 @@ import org.schabi.newpipe.error.ReCaptchaActivity; import org.schabi.newpipe.error.UserAction; import org.schabi.newpipe.extractor.InfoItem; import org.schabi.newpipe.extractor.NewPipe; -import org.schabi.newpipe.extractor.ServiceList; import org.schabi.newpipe.extractor.exceptions.ExtractionException; -import org.schabi.newpipe.extractor.services.youtube.extractors.YoutubeStreamExtractor; import org.schabi.newpipe.extractor.stream.AudioStream; import org.schabi.newpipe.extractor.stream.Stream; import org.schabi.newpipe.extractor.stream.StreamInfo; @@ -526,7 +523,7 @@ public final class VideoDetailFragment NavigationHelper.openChannelFragment(getFM(), currentInfo.getServiceId(), subChannelUrl, subChannelName); } catch (final Exception e) { - ErrorActivity.reportUiError((AppCompatActivity) getActivity(), e); + ErrorActivity.reportUiError(getActivity(), null, "Opening channel fragment", e); } } @@ -684,13 +681,12 @@ public final class VideoDetailFragment binding.detailThumbnailImageView.setImageResource(R.drawable.dummy_thumbnail_dark); if (!isEmpty(info.getThumbnailUrl())) { - final String infoServiceName = NewPipe.getNameOfService(info.getServiceId()); final ImageLoadingListener onFailListener = new SimpleImageLoadingListener() { @Override public void onLoadingFailed(final String imageUri, final View view, final FailReason failReason) { - showSnackBarError(failReason.getCause(), UserAction.LOAD_IMAGE, - infoServiceName, imageUri, R.string.could_not_load_thumbnails); + showSnackBarError(new ErrorInfo(failReason.getCause(), UserAction.LOAD_IMAGE, + imageUri, info)); } }; @@ -906,10 +902,8 @@ public final class VideoDetailFragment openVideoPlayer(); } } - }, throwable -> { - isLoading.set(false); - onError(throwable); - }); + }, throwable -> showError(new ErrorInfo(throwable, UserAction.REQUESTED_STREAM, + url == null ? "no url" : url, serviceId))); } /*////////////////////////////////////////////////////////////////////////// @@ -1327,8 +1321,8 @@ public final class VideoDetailFragment } @Override - public void showError(final String message, final boolean showRetryButton) { - super.showError(message, showRetryButton); + public void handleError() { + super.handleError(); setErrorImage(R.drawable.not_available_monkey); if (binding.relatedStreamsLayout != null) { // hide related streams for tablets @@ -1341,8 +1335,8 @@ public final class VideoDetailFragment } private void hideAgeRestrictedContent() { - showError(getString(R.string.restricted_video, - getString(R.string.show_age_restricted_content_title)), false); + showTextError(getString(R.string.restricted_video, + getString(R.string.show_age_restricted_content_title))); } private void setupBroadcastReceiver() { @@ -1548,11 +1542,8 @@ public final class VideoDetailFragment } if (!info.getErrors().isEmpty()) { - showSnackBarError(info.getErrors(), - UserAction.REQUESTED_STREAM, - NewPipe.getNameOfService(info.getServiceId()), - info.getUrl(), - 0); + showSnackBarError(new ErrorInfo(info.getErrors(), + UserAction.REQUESTED_STREAM, info.getUrl(), info)); } binding.detailControlsDownload.setVisibility(info.getStreamType() == StreamType.LIVE_STREAM @@ -1592,6 +1583,10 @@ public final class VideoDetailFragment } public void openDownloadDialog() { + if (currentInfo == null) { + return; + } + try { final DownloadDialog downloadDialog = DownloadDialog.newInstance(currentInfo); downloadDialog.setVideoStreams(sortedVideoStreams); @@ -1601,18 +1596,10 @@ public final class VideoDetailFragment downloadDialog.show(activity.getSupportFragmentManager(), "downloadDialog"); } catch (final Exception e) { - final ErrorInfo info = ErrorInfo.make(UserAction.UI_ERROR, - ServiceList.all() - .get(currentInfo - .getServiceId()) - .getServiceInfo() - .getName(), "", - R.string.could_not_setup_download_menu); - - ErrorActivity.reportError(activity, - e, - activity.getClass(), - activity.findViewById(android.R.id.content), info); + ErrorActivity.reportError(activity, activity.getClass(), + activity.findViewById(android.R.id.content), + new ErrorInfo(e, UserAction.DOWNLOAD_OPEN_DIALOG, "Showing download dialog", + currentInfo)); } } @@ -1620,24 +1607,6 @@ public final class VideoDetailFragment // Stream Results //////////////////////////////////////////////////////////////////////////*/ - @Override - protected boolean onError(final Throwable exception) { - if (super.onError(exception)) { - return true; - } - - final int errorId = exception instanceof YoutubeStreamExtractor.DeobfuscateException - ? R.string.youtube_signature_deobfuscation_error - : exception instanceof ExtractionException - ? R.string.parsing_error - : R.string.general_error; - - onUnrecoverableError(exception, UserAction.REQUESTED_STREAM, - NewPipe.getNameOfService(serviceId), url, errorId); - - return true; - } - private void updateProgressInfo(@NonNull final StreamInfo info) { if (positionSubscriber != null) { positionSubscriber.dispose(); diff --git a/app/src/main/java/org/schabi/newpipe/fragments/list/BaseListFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/list/BaseListFragment.java index b8c9af05b..d9c18fe44 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/list/BaseListFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/list/BaseListFragment.java @@ -14,7 +14,6 @@ import android.view.View; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.app.ActionBar; -import androidx.appcompat.app.AppCompatActivity; import androidx.preference.PreferenceManager; import androidx.recyclerview.widget.GridLayoutManager; import androidx.recyclerview.widget.RecyclerView; @@ -292,7 +291,7 @@ public abstract class BaseListFragment extends BaseStateFragment selectedItem.getUrl(), selectedItem.getName()); } catch (final Exception e) { - ErrorActivity.reportUiError((AppCompatActivity) getActivity(), e); + ErrorActivity.reportUiError(getActivity(), null, "Opening channel fragment", e); } } }); @@ -307,7 +306,7 @@ public abstract class BaseListFragment extends BaseStateFragment selectedItem.getUrl(), selectedItem.getName()); } catch (final Exception e) { - ErrorActivity.reportUiError((AppCompatActivity) getActivity(), e); + ErrorActivity.reportUiError(getActivity(), null, "Opening playlist fragment", e); } } }); @@ -412,13 +411,6 @@ public abstract class BaseListFragment extends BaseStateFragment animate(itemsList, true, 300); } - @Override - public void showError(final String message, final boolean showRetryButton) { - super.showError(message, showRetryButton); - showListFooter(false); - animate(itemsList, false, 200); - } - @Override public void showEmptyState() { super.showEmptyState(); @@ -439,6 +431,13 @@ public abstract class BaseListFragment extends BaseStateFragment isLoading.set(false); } + @Override + public void handleError() { + super.handleError(); + showListFooter(false); + animate(itemsList, false, 200); + } + @Override public void onSharedPreferenceChanged(final SharedPreferences sharedPreferences, final String key) { diff --git a/app/src/main/java/org/schabi/newpipe/fragments/list/BaseListInfoFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/list/BaseListInfoFragment.java index 006072e93..6874f80d5 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/list/BaseListInfoFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/list/BaseListInfoFragment.java @@ -7,12 +7,17 @@ import android.view.View; import androidx.annotation.NonNull; +import org.schabi.newpipe.error.ErrorInfo; +import org.schabi.newpipe.error.UserAction; import org.schabi.newpipe.extractor.ListExtractor; import org.schabi.newpipe.extractor.ListInfo; import org.schabi.newpipe.extractor.Page; +import org.schabi.newpipe.extractor.exceptions.ContentNotSupportedException; import org.schabi.newpipe.util.Constants; import org.schabi.newpipe.views.NewPipeRecyclerView; +import java.util.ArrayList; +import java.util.List; import java.util.Queue; import icepick.State; @@ -30,10 +35,15 @@ public abstract class BaseListInfoFragment @State protected String url; + private final UserAction errorUserAction; protected I currentInfo; protected Page currentNextPage; protected Disposable currentWorker; + protected BaseListInfoFragment(final UserAction errorUserAction) { + this.errorUserAction = errorUserAction; + } + @Override protected void initViews(final View rootView, final Bundle savedInstanceState) { super.initViews(rootView, savedInstanceState); @@ -133,7 +143,9 @@ public abstract class BaseListInfoFragment currentInfo = result; currentNextPage = result.getNextPage(); handleResult(result); - }, this::onError); + }, throwable -> + showError(new ErrorInfo(throwable, errorUserAction, + "Start loading: " + url, serviceId))); } /** @@ -161,10 +173,9 @@ public abstract class BaseListInfoFragment .subscribe((@NonNull ListExtractor.InfoItemsPage InfoItemsPage) -> { isLoading.set(false); handleNextItems(InfoItemsPage); - }, (@NonNull Throwable throwable) -> { - isLoading.set(false); - onError(throwable); - }); + }, (@NonNull Throwable throwable) -> + dynamicallyShowErrorPanelOrSnackbar(new ErrorInfo(throwable, + errorUserAction, "Loading more items: " + url, serviceId))); } private void forbidDownwardFocusScroll() { @@ -182,10 +193,16 @@ public abstract class BaseListInfoFragment @Override public void handleNextItems(final ListExtractor.InfoItemsPage result) { super.handleNextItems(result); + currentNextPage = result.getNextPage(); infoListAdapter.addInfoItemList(result.getItems()); showListFooter(hasMoreItems()); + + if (!result.getErrors().isEmpty()) { + dynamicallyShowErrorPanelOrSnackbar(new ErrorInfo(result.getErrors(), errorUserAction, + "Get next items of: " + url, serviceId)); + } } @Override @@ -213,6 +230,18 @@ public abstract class BaseListInfoFragment showEmptyState(); } } + + if (!result.getErrors().isEmpty()) { + final List errors = new ArrayList<>(result.getErrors()); + // handling ContentNotSupportedException not to show the error but an appropriate string + // so that crashes won't be sent uselessly and the user will understand what happened + errors.removeIf(throwable -> throwable instanceof ContentNotSupportedException); + + if (!errors.isEmpty()) { + dynamicallyShowErrorPanelOrSnackbar(new ErrorInfo(result.getErrors(), + errorUserAction, "Start loading: " + url, serviceId)); + } + } } /*////////////////////////////////////////////////////////////////////////// @@ -224,4 +253,14 @@ public abstract class BaseListInfoFragment this.url = u; this.name = !TextUtils.isEmpty(title) ? title : ""; } + + private void dynamicallyShowErrorPanelOrSnackbar(final ErrorInfo errorInfo) { + if (infoListAdapter.getItemCount() == 0) { + // show error panel only if no items already visible + showError(errorInfo); + } else { + isLoading.set(false); + showSnackBarError(errorInfo); + } + } } diff --git a/app/src/main/java/org/schabi/newpipe/fragments/list/channel/ChannelFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/list/channel/ChannelFragment.java index ca95c272a..1d5bcce32 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/list/channel/ChannelFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/list/channel/ChannelFragment.java @@ -16,7 +16,6 @@ import android.widget.Button; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.app.ActionBar; -import androidx.appcompat.app.AppCompatActivity; import androidx.core.content.ContextCompat; import androidx.viewbinding.ViewBinding; @@ -27,20 +26,19 @@ import org.schabi.newpipe.database.subscription.SubscriptionEntity; import org.schabi.newpipe.databinding.ChannelHeaderBinding; import org.schabi.newpipe.databinding.FragmentChannelBinding; import org.schabi.newpipe.databinding.PlaylistControlBinding; +import org.schabi.newpipe.error.ErrorActivity; +import org.schabi.newpipe.error.ErrorInfo; +import org.schabi.newpipe.error.UserAction; import org.schabi.newpipe.extractor.InfoItem; import org.schabi.newpipe.extractor.ListExtractor; -import org.schabi.newpipe.extractor.NewPipe; import org.schabi.newpipe.extractor.channel.ChannelInfo; import org.schabi.newpipe.extractor.exceptions.ContentNotSupportedException; -import org.schabi.newpipe.extractor.exceptions.ExtractionException; import org.schabi.newpipe.extractor.stream.StreamInfoItem; import org.schabi.newpipe.fragments.list.BaseListInfoFragment; import org.schabi.newpipe.ktx.AnimationType; import org.schabi.newpipe.local.subscription.SubscriptionManager; import org.schabi.newpipe.player.playqueue.ChannelPlayQueue; import org.schabi.newpipe.player.playqueue.PlayQueue; -import org.schabi.newpipe.error.ErrorActivity; -import org.schabi.newpipe.error.UserAction; import org.schabi.newpipe.util.ExtractorHelper; import org.schabi.newpipe.util.ImageDisplayConstants; import org.schabi.newpipe.util.Localization; @@ -91,6 +89,10 @@ public class ChannelFragment extends BaseListInfoFragment return instance; } + public ChannelFragment() { + super(UserAction.REQUESTED_CHANNEL); + } + @Override public void setUserVisibleHint(final boolean isVisibleToUser) { super.setUserVisibleHint(isVisibleToUser); @@ -217,9 +219,8 @@ public class ChannelFragment extends BaseListInfoFragment private void monitorSubscription(final ChannelInfo info) { final Consumer onError = (Throwable throwable) -> { animate(headerBinding.channelSubscribeButton, false, 100); - showSnackBarError(throwable, UserAction.SUBSCRIPTION, - NewPipe.getNameOfService(currentInfo.getServiceId()), - "Get subscription status", 0); + showSnackBarError(new ErrorInfo(throwable, UserAction.SUBSCRIPTION_GET, + "Get subscription status", currentInfo)); }; final Observable> observable = subscriptionManager @@ -269,11 +270,8 @@ public class ChannelFragment extends BaseListInfoFragment }; final Consumer onError = (@NonNull Throwable throwable) -> - onUnrecoverableError(throwable, - UserAction.SUBSCRIPTION, - NewPipe.getNameOfService(info.getServiceId()), - "Updating Subscription for " + info.getUrl(), - R.string.subscription_update_failed); + showSnackBarError(new ErrorInfo(throwable, UserAction.SUBSCRIPTION_UPDATE, + "Updating subscription for " + info.getUrl(), info)); disposables.add(subscriptionManager.updateChannelInfo(info) .subscribeOn(Schedulers.io()) @@ -290,11 +288,8 @@ public class ChannelFragment extends BaseListInfoFragment }; final Consumer onError = (@NonNull Throwable throwable) -> - onUnrecoverableError(throwable, - UserAction.SUBSCRIPTION, - NewPipe.getNameOfService(currentInfo.getServiceId()), - "Subscription Change", - R.string.subscription_change_failed); + showSnackBarError(new ErrorInfo(throwable, UserAction.SUBSCRIPTION_CHANGE, + "Changing subscription for " + currentInfo.getUrl(), currentInfo)); /* Emit clicks from main thread unto io thread */ return RxView.clicks(subscribeButton) @@ -408,7 +403,7 @@ public class ChannelFragment extends BaseListInfoFragment currentInfo.getParentChannelUrl(), currentInfo.getParentChannelName()); } catch (final Exception e) { - ErrorActivity.reportUiError((AppCompatActivity) getActivity(), e); + ErrorActivity.reportUiError(getActivity(), null, "Opening channel fragment", e); } } else if (DEBUG) { Log.i(TAG, "Can't open parent channel because we got no channel URL"); @@ -469,21 +464,9 @@ public class ChannelFragment extends BaseListInfoFragment playlistControlBinding.getRoot().setVisibility(View.VISIBLE); - final List errors = new ArrayList<>(result.getErrors()); - if (!errors.isEmpty()) { - - // handling ContentNotSupportedException not to show the error but an appropriate string - // so that crashes won't be sent uselessly and the user will understand what happened - errors.removeIf(throwable -> { - if (throwable instanceof ContentNotSupportedException) { - showContentNotSupported(); - } - return throwable instanceof ContentNotSupportedException; - }); - - if (!errors.isEmpty()) { - showSnackBarError(errors, UserAction.REQUESTED_CHANNEL, - NewPipe.getNameOfService(result.getServiceId()), result.getUrl(), 0); + for (final Throwable throwable : result.getErrors()) { + if (throwable instanceof ContentNotSupportedException) { + showContentNotSupported(); } } @@ -537,38 +520,6 @@ public class ChannelFragment extends BaseListInfoFragment currentInfo.getNextPage(), streamItems, index); } - @Override - public void handleNextItems(final ListExtractor.InfoItemsPage result) { - super.handleNextItems(result); - - if (!result.getErrors().isEmpty()) { - showSnackBarError(result.getErrors(), - UserAction.REQUESTED_CHANNEL, - NewPipe.getNameOfService(serviceId), - "Get next page of: " + url, - R.string.general_error); - } - } - - /*////////////////////////////////////////////////////////////////////////// - // OnError - //////////////////////////////////////////////////////////////////////////*/ - - @Override - protected boolean onError(final Throwable exception) { - if (super.onError(exception)) { - return true; - } - - final int errorId = exception instanceof ExtractionException - ? R.string.parsing_error : R.string.general_error; - - onUnrecoverableError(exception, UserAction.REQUESTED_CHANNEL, - NewPipe.getNameOfService(serviceId), url, errorId); - - return true; - } - /*////////////////////////////////////////////////////////////////////////// // Utils //////////////////////////////////////////////////////////////////////////*/ diff --git a/app/src/main/java/org/schabi/newpipe/fragments/list/comments/CommentsFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/list/comments/CommentsFragment.java index 797b92c63..35ab663a6 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/list/comments/CommentsFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/list/comments/CommentsFragment.java @@ -11,12 +11,11 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import org.schabi.newpipe.R; +import org.schabi.newpipe.error.UserAction; import org.schabi.newpipe.extractor.ListExtractor; -import org.schabi.newpipe.extractor.NewPipe; import org.schabi.newpipe.extractor.comments.CommentsInfo; import org.schabi.newpipe.fragments.list.BaseListInfoFragment; import org.schabi.newpipe.ktx.ViewUtils; -import org.schabi.newpipe.error.UserAction; import org.schabi.newpipe.util.ExtractorHelper; import io.reactivex.rxjava3.core.Single; @@ -25,13 +24,17 @@ import io.reactivex.rxjava3.disposables.CompositeDisposable; public class CommentsFragment extends BaseListInfoFragment { private final CompositeDisposable disposables = new CompositeDisposable(); - public static CommentsFragment getInstance(final int serviceId, final String url, + public static CommentsFragment getInstance(final int serviceId, final String url, final String name) { final CommentsFragment instance = new CommentsFragment(); instance.setInitialData(serviceId, url, name); return instance; } + public CommentsFragment() { + super(UserAction.REQUESTED_COMMENTS); + } + /*////////////////////////////////////////////////////////////////////////// // LifeCycle //////////////////////////////////////////////////////////////////////////*/ @@ -67,52 +70,13 @@ public class CommentsFragment extends BaseListInfoFragment { // Contract //////////////////////////////////////////////////////////////////////////*/ - @Override - public void showLoading() { - super.showLoading(); - } - @Override public void handleResult(@NonNull final CommentsInfo result) { super.handleResult(result); - ViewUtils.slideUp(requireView(), 120, 150, 0.06f); - - if (!result.getErrors().isEmpty()) { - showSnackBarError(result.getErrors(), UserAction.REQUESTED_COMMENTS, - NewPipe.getNameOfService(result.getServiceId()), result.getUrl(), 0); - } - disposables.clear(); } - @Override - public void handleNextItems(final ListExtractor.InfoItemsPage result) { - super.handleNextItems(result); - - if (!result.getErrors().isEmpty()) { - showSnackBarError(result.getErrors(), UserAction.REQUESTED_COMMENTS, - NewPipe.getNameOfService(serviceId), "Get next page of: " + url, - R.string.general_error); - } - } - - /*////////////////////////////////////////////////////////////////////////// - // OnError - //////////////////////////////////////////////////////////////////////////*/ - - @Override - protected boolean onError(final Throwable exception) { - if (super.onError(exception)) { - return true; - } - - hideLoading(); - showSnackBarError(exception, UserAction.REQUESTED_COMMENTS, - NewPipe.getNameOfService(serviceId), url, R.string.error_unable_to_load_comments); - return true; - } - /*////////////////////////////////////////////////////////////////////////// // Utils //////////////////////////////////////////////////////////////////////////*/ diff --git a/app/src/main/java/org/schabi/newpipe/fragments/list/kiosk/DefaultKioskFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/list/kiosk/DefaultKioskFragment.java index d83dfc63b..bdca25558 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/list/kiosk/DefaultKioskFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/list/kiosk/DefaultKioskFragment.java @@ -2,6 +2,7 @@ package org.schabi.newpipe.fragments.list.kiosk; import android.os.Bundle; +import org.schabi.newpipe.error.ErrorInfo; import org.schabi.newpipe.extractor.NewPipe; import org.schabi.newpipe.extractor.exceptions.ExtractionException; import org.schabi.newpipe.extractor.kiosk.KioskList; @@ -10,6 +11,7 @@ import org.schabi.newpipe.util.KioskTranslator; import org.schabi.newpipe.util.ServiceHelper; public class DefaultKioskFragment extends KioskFragment { + @Override public void onCreate(final Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -46,8 +48,8 @@ public class DefaultKioskFragment extends KioskFragment { currentInfo = null; currentNextPage = null; } catch (final ExtractionException e) { - onUnrecoverableError(e, UserAction.REQUESTED_KIOSK, "none", - "Loading default kiosk from selected service", 0); + showError(new ErrorInfo(e, UserAction.REQUESTED_KIOSK, + "Loading default kiosk for selected service")); } } } diff --git a/app/src/main/java/org/schabi/newpipe/fragments/list/kiosk/KioskFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/list/kiosk/KioskFragment.java index 849e07716..77aa8e001 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/list/kiosk/KioskFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/list/kiosk/KioskFragment.java @@ -12,6 +12,7 @@ import androidx.annotation.Nullable; import androidx.appcompat.app.ActionBar; import org.schabi.newpipe.R; +import org.schabi.newpipe.error.ErrorInfo; import org.schabi.newpipe.extractor.ListExtractor; import org.schabi.newpipe.extractor.NewPipe; import org.schabi.newpipe.extractor.StreamingService; @@ -82,6 +83,10 @@ public class KioskFragment extends BaseListInfoFragment { return instance; } + public KioskFragment() { + super(UserAction.REQUESTED_KIOSK); + } + /*////////////////////////////////////////////////////////////////////////// // LifeCycle //////////////////////////////////////////////////////////////////////////*/ @@ -102,9 +107,7 @@ public class KioskFragment extends BaseListInfoFragment { try { setTitle(kioskTranslatedName); } catch (final Exception e) { - onUnrecoverableError(e, UserAction.UI_ERROR, - "none", - "none", R.string.app_ui_crash); + showSnackBarError(new ErrorInfo(e, UserAction.UI_ERROR, "Setting kiosk title")); } } } @@ -169,22 +172,5 @@ public class KioskFragment extends BaseListInfoFragment { name = kioskTranslatedName; setTitle(kioskTranslatedName); - - if (!result.getErrors().isEmpty()) { - showSnackBarError(result.getErrors(), - UserAction.REQUESTED_KIOSK, - NewPipe.getNameOfService(result.getServiceId()), result.getUrl(), 0); - } - } - - @Override - public void handleNextItems(final ListExtractor.InfoItemsPage result) { - super.handleNextItems(result); - - if (!result.getErrors().isEmpty()) { - showSnackBarError(result.getErrors(), - UserAction.REQUESTED_PLAYLIST, NewPipe.getNameOfService(serviceId), - "Get next page of: " + url, 0); - } } } 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 6d4995303..b82408b03 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 @@ -14,7 +14,6 @@ import android.view.ViewGroup; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.content.res.AppCompatResources; import androidx.viewbinding.ViewBinding; @@ -25,11 +24,12 @@ import org.schabi.newpipe.R; import org.schabi.newpipe.database.playlist.model.PlaylistRemoteEntity; import org.schabi.newpipe.databinding.PlaylistControlBinding; import org.schabi.newpipe.databinding.PlaylistHeaderBinding; +import org.schabi.newpipe.error.ErrorActivity; +import org.schabi.newpipe.error.ErrorInfo; +import org.schabi.newpipe.error.UserAction; import org.schabi.newpipe.extractor.InfoItem; import org.schabi.newpipe.extractor.ListExtractor; -import org.schabi.newpipe.extractor.NewPipe; import org.schabi.newpipe.extractor.ServiceList; -import org.schabi.newpipe.extractor.exceptions.ExtractionException; import org.schabi.newpipe.extractor.playlist.PlaylistInfo; import org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper; import org.schabi.newpipe.extractor.stream.StreamInfoItem; @@ -40,8 +40,6 @@ import org.schabi.newpipe.local.playlist.RemotePlaylistManager; import org.schabi.newpipe.player.helper.PlayerHolder; import org.schabi.newpipe.player.playqueue.PlayQueue; import org.schabi.newpipe.player.playqueue.PlaylistPlayQueue; -import org.schabi.newpipe.error.ErrorActivity; -import org.schabi.newpipe.error.UserAction; import org.schabi.newpipe.util.ExtractorHelper; import org.schabi.newpipe.util.ImageDisplayConstants; import org.schabi.newpipe.util.KoreUtil; @@ -87,6 +85,10 @@ public class PlaylistFragment extends BaseListInfoFragment { return instance; } + public PlaylistFragment() { + super(UserAction.REQUESTED_PLAYLIST); + } + /*////////////////////////////////////////////////////////////////////////// // LifeCycle //////////////////////////////////////////////////////////////////////////*/ @@ -284,7 +286,7 @@ public class PlaylistFragment extends BaseListInfoFragment { NavigationHelper.openChannelFragment(getFM(), result.getServiceId(), result.getUploaderUrl(), result.getUploaderName()); } catch (final Exception e) { - ErrorActivity.reportUiError((AppCompatActivity) getActivity(), e); + ErrorActivity.reportUiError(getActivity(), null, "Opening channel fragment", e); } }); } @@ -315,8 +317,8 @@ public class PlaylistFragment extends BaseListInfoFragment { .localizeStreamCount(getContext(), result.getStreamCount())); if (!result.getErrors().isEmpty()) { - showSnackBarError(result.getErrors(), UserAction.REQUESTED_PLAYLIST, - NewPipe.getNameOfService(result.getServiceId()), result.getUrl(), 0); + showSnackBarError(new ErrorInfo(result.getErrors(), UserAction.REQUESTED_PLAYLIST, + result.getUrl(), result)); } remotePlaylistManager.getPlaylist(result) @@ -363,33 +365,6 @@ public class PlaylistFragment extends BaseListInfoFragment { ); } - @Override - public void handleNextItems(final ListExtractor.InfoItemsPage result) { - super.handleNextItems(result); - - if (!result.getErrors().isEmpty()) { - showSnackBarError(result.getErrors(), UserAction.REQUESTED_PLAYLIST, - NewPipe.getNameOfService(serviceId), "Get next page of: " + url, 0); - } - } - - /*////////////////////////////////////////////////////////////////////////// - // OnError - //////////////////////////////////////////////////////////////////////////*/ - - @Override - protected boolean onError(final Throwable exception) { - if (super.onError(exception)) { - return true; - } - - final int errorId = exception instanceof ExtractionException - ? R.string.parsing_error : R.string.general_error; - onUnrecoverableError(exception, UserAction.REQUESTED_PLAYLIST, - NewPipe.getNameOfService(serviceId), url, errorId); - return true; - } - /*////////////////////////////////////////////////////////////////////////// // Utils //////////////////////////////////////////////////////////////////////////*/ @@ -434,8 +409,9 @@ public class PlaylistFragment extends BaseListInfoFragment { } @Override - public void onError(final Throwable t) { - PlaylistFragment.this.onError(t); + public void onError(final Throwable throwable) { + showError(new ErrorInfo(throwable, UserAction.REQUESTED_BOOKMARK, + "Get playlist bookmarks")); } @Override @@ -460,12 +436,16 @@ public class PlaylistFragment extends BaseListInfoFragment { if (currentInfo != null && playlistEntity == null) { action = remotePlaylistManager.onBookmark(currentInfo) .observeOn(AndroidSchedulers.mainThread()) - .subscribe(ignored -> { /* Do nothing */ }, this::onError); + .subscribe(ignored -> { /* Do nothing */ }, throwable -> + showError(new ErrorInfo(throwable, UserAction.REQUESTED_BOOKMARK, + "Adding playlist bookmark"))); } else if (playlistEntity != null) { action = remotePlaylistManager.deletePlaylist(playlistEntity.getUid()) .observeOn(AndroidSchedulers.mainThread()) .doFinally(() -> playlistEntity = null) - .subscribe(ignored -> { /* Do nothing */ }, this::onError); + .subscribe(ignored -> { /* Do nothing */ }, throwable -> + showError(new ErrorInfo(throwable, UserAction.REQUESTED_BOOKMARK, + "Deleting playlist bookmark"))); } else { action = Disposable.empty(); } 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 0fca2e5a6..e68ebbf6a 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 @@ -47,7 +47,6 @@ import org.schabi.newpipe.extractor.MetaInfo; import org.schabi.newpipe.extractor.NewPipe; import org.schabi.newpipe.extractor.Page; import org.schabi.newpipe.extractor.StreamingService; -import org.schabi.newpipe.extractor.exceptions.ParsingException; import org.schabi.newpipe.extractor.search.SearchExtractor; import org.schabi.newpipe.extractor.search.SearchInfo; import org.schabi.newpipe.extractor.services.peertube.linkHandler.PeertubeSearchQueryHandlerFactory; @@ -258,11 +257,9 @@ public class SearchFragment extends BaseListFragment suggestionPublisher .onNext(searchEditText.getText().toString()), - throwable -> showSnackBarError(throwable, - UserAction.DELETE_FROM_HISTORY, "none", - "Deleting item failed", R.string.general_error)); + throwable -> showSnackBarError(new ErrorInfo(throwable, + UserAction.DELETE_FROM_HISTORY, + "Deleting item failed"))); disposables.add(onDelete); }) .show(); @@ -763,8 +759,8 @@ public class SearchFragment extends BaseListFragment { if (!ExceptionUtils.isNetworkRelated(throwable)) { - showSnackBarError(throwable, UserAction.GET_SUGGESTIONS, - NewPipe.getNameOfService(serviceId), searchString, 0); + showSnackBarError(new ErrorInfo(throwable, + UserAction.GET_SUGGESTIONS, searchString, serviceId)); } return new ArrayList<>(); }) @@ -800,7 +796,8 @@ public class SearchFragment extends BaseListFragment { getFM().popBackStackImmediate(); activity.startActivity(intent); - }, throwable -> - showError(getString(R.string.unsupported_url), false))); + }, throwable -> showTextError(getString(R.string.unsupported_url)))); return; } } catch (final Exception ignored) { @@ -849,10 +845,9 @@ public class SearchFragment extends BaseListFragment { - }, - error -> showSnackBarError(error, UserAction.SEARCHED, - NewPipe.getNameOfService(serviceId), theSearchString, 0) + ignored -> {}, + throwable -> showSnackBarError(new ErrorInfo(throwable, UserAction.SEARCHED, + theSearchString, serviceId)) )); suggestionPublisher.onNext(theSearchString); startLoading(false); @@ -872,7 +867,7 @@ public class SearchFragment extends BaseListFragment isLoading.set(false)) - .subscribe(this::handleResult, this::onError); + .subscribe(this::handleResult, this::onItemError); } @@ -895,7 +890,7 @@ public class SearchFragment extends BaseListFragment isLoading.set(false)) - .subscribe(this::handleNextItems, this::onError); + .subscribe(this::handleNextItems, this::onItemError); } @Override @@ -909,6 +904,15 @@ public class SearchFragment extends BaseListFragment suggestionListAdapter.setItems(suggestions)); - if (suggestionsPanelVisible && errorPanelRoot.getVisibility() == View.VISIBLE) { + if (suggestionsPanelVisible && isErrorPanelVisible()) { hideLoading(); } } - public void onSuggestionError(final Throwable exception) { - if (DEBUG) { - Log.d(TAG, "onSuggestionError() called with: exception = [" + exception + "]"); - } - if (super.onError(exception)) { - return; - } - - final int errorId = exception instanceof ParsingException - ? R.string.parsing_error - : R.string.general_error; - onUnrecoverableError(exception, UserAction.GET_SUGGESTIONS, - NewPipe.getNameOfService(serviceId), searchString, errorId); - } - /*////////////////////////////////////////////////////////////////////////// // Contract //////////////////////////////////////////////////////////////////////////*/ @@ -975,13 +964,6 @@ public class SearchFragment extends BaseListFragment suggestionPublisher .onNext(searchEditText.getText().toString()), - throwable -> showSnackBarError(throwable, - UserAction.DELETE_FROM_HISTORY, "none", - "Deleting item failed", R.string.general_error)); + throwable -> showSnackBarError(new ErrorInfo(throwable, + UserAction.DELETE_FROM_HISTORY, "Deleting item failed"))); disposables.add(onDelete); } } diff --git a/app/src/main/java/org/schabi/newpipe/fragments/list/videos/RelatedVideosFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/list/videos/RelatedVideosFragment.java index 7f8410012..758cddc55 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/list/videos/RelatedVideosFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/list/videos/RelatedVideosFragment.java @@ -47,6 +47,10 @@ public class RelatedVideosFragment extends BaseListInfoFragment extends BaseStateFragment } } - @Override - public void showError(final String message, final boolean showRetryButton) { - super.showError(message, showRetryButton); - showListFooter(false); - - if (itemsList != null) { - animate(itemsList, false, 200); - } - if (headerRootBinding != null) { - animate(headerRootBinding.getRoot(), false, 200); - } - } - @Override public void showEmptyState() { super.showEmptyState(); @@ -249,9 +236,18 @@ public abstract class BaseLocalListFragment extends BaseStateFragment } @Override - protected boolean onError(final Throwable exception) { + public void handleError() { + super.handleError(); resetFragment(); - return super.onError(exception); + + showListFooter(false); + + if (itemsList != null) { + animate(itemsList, false, 200); + } + if (headerRootBinding != null) { + animate(headerRootBinding.getRoot(), false, 200); + } } @Override diff --git a/app/src/main/java/org/schabi/newpipe/local/bookmark/BookmarkFragment.java b/app/src/main/java/org/schabi/newpipe/local/bookmark/BookmarkFragment.java index b96f23a9e..e043b140e 100644 --- a/app/src/main/java/org/schabi/newpipe/local/bookmark/BookmarkFragment.java +++ b/app/src/main/java/org/schabi/newpipe/local/bookmark/BookmarkFragment.java @@ -23,6 +23,7 @@ import org.schabi.newpipe.database.LocalItem; import org.schabi.newpipe.database.playlist.PlaylistLocalItem; import org.schabi.newpipe.database.playlist.PlaylistMetadataEntry; import org.schabi.newpipe.database.playlist.model.PlaylistRemoteEntity; +import org.schabi.newpipe.error.ErrorInfo; import org.schabi.newpipe.local.BaseLocalListFragment; import org.schabi.newpipe.local.playlist.LocalPlaylistManager; import org.schabi.newpipe.local.playlist.RemotePlaylistManager; @@ -206,7 +207,8 @@ public final class BookmarkFragment extends BaseLocalListFragment disposables.add(deleteReactor .observeOn(AndroidSchedulers.mainThread()) - .subscribe(ignored -> { /*Do nothing on success*/ }, this::onError)) - ) + .subscribe(ignored -> { /*Do nothing on success*/ }, throwable -> + showError(new ErrorInfo(throwable, + UserAction.REQUESTED_BOOKMARK, + "Deleting playlist"))))) .setNegativeButton(R.string.cancel, null) .show(); } @@ -314,7 +307,10 @@ public final class BookmarkFragment extends BaseLocalListFragment { /*Do nothing on success*/ }, this::onError); + .subscribe(longs -> { /*Do nothing on success*/ }, throwable -> showError( + new ErrorInfo(throwable, + UserAction.REQUESTED_BOOKMARK, + "Changing playlist name"))); disposables.add(disposable); } } diff --git a/app/src/main/java/org/schabi/newpipe/local/feed/FeedFragment.kt b/app/src/main/java/org/schabi/newpipe/local/feed/FeedFragment.kt index efe64d2f2..adbff1e54 100644 --- a/app/src/main/java/org/schabi/newpipe/local/feed/FeedFragment.kt +++ b/app/src/main/java/org/schabi/newpipe/local/feed/FeedFragment.kt @@ -38,6 +38,7 @@ import icepick.State import org.schabi.newpipe.R import org.schabi.newpipe.database.feed.model.FeedGroupEntity import org.schabi.newpipe.databinding.FragmentFeedBinding +import org.schabi.newpipe.error.ErrorInfo import org.schabi.newpipe.error.UserAction import org.schabi.newpipe.fragments.list.BaseListFragment import org.schabi.newpipe.ktx.animate @@ -48,7 +49,6 @@ import java.util.Calendar class FeedFragment : BaseListFragment() { private var _feedBinding: FragmentFeedBinding? = null private val feedBinding get() = _feedBinding!! - private val errorBinding get() = _feedBinding!!.errorPanel private lateinit var viewModel: FeedViewModel @State @@ -171,50 +171,24 @@ class FeedFragment : BaseListFragment() { // ///////////////////////////////////////////////////////////////////////// override fun showLoading() { + super.showLoading() feedBinding.refreshRootView.animate(false, 0) feedBinding.itemsList.animate(false, 0) - - feedBinding.loadingProgressBar.animate(true, 200) feedBinding.loadingProgressText.animate(true, 200) - - feedBinding.emptyStateView.root.animate(false, 0) - errorBinding.root.animate(false, 0) } override fun hideLoading() { + super.hideLoading() feedBinding.refreshRootView.animate(true, 200) - feedBinding.itemsList.animate(true, 300) - - feedBinding.loadingProgressBar.animate(false, 0) feedBinding.loadingProgressText.animate(false, 0) - - feedBinding.emptyStateView.root.animate(false, 0) - errorBinding.root.animate(false, 0) feedBinding.swiperefresh.isRefreshing = false } override fun showEmptyState() { + super.showEmptyState() feedBinding.refreshRootView.animate(true, 200) feedBinding.itemsList.animate(false, 0) - - feedBinding.loadingProgressBar.animate(false, 0) feedBinding.loadingProgressText.animate(false, 0) - - feedBinding.emptyStateView.root.animate(true, 800) - errorBinding.root.animate(false, 0) - } - - override fun showError(message: String, showRetryButton: Boolean) { - infoListAdapter.clearStreamItemList() - feedBinding.refreshRootView.animate(false, 120) - feedBinding.itemsList.animate(false, 120) - - feedBinding.loadingProgressBar.animate(false, 120) - feedBinding.loadingProgressText.animate(false, 120) - - errorBinding.errorMessageView.text = message - errorBinding.errorButtonRetry.animate(showRetryButton, if (showRetryButton) 600 else 0) - errorBinding.root.animate(true, 300) } override fun handleResult(result: FeedState) { @@ -227,6 +201,14 @@ class FeedFragment : BaseListFragment() { updateRefreshViewState() } + override fun handleError() { + super.handleError() + infoListAdapter.clearStreamItemList() + feedBinding.refreshRootView.animate(false, 200) + feedBinding.itemsList.animate(false, 200) + feedBinding.loadingProgressText.animate(false, 200) + } + private fun handleProgressState(progressState: FeedState.ProgressState) { showLoading() @@ -266,13 +248,6 @@ class FeedFragment : BaseListFragment() { ) } - if (loadedState.itemsErrors.isNotEmpty()) { - showSnackBarError( - loadedState.itemsErrors, UserAction.REQUESTED_FEED, - "none", "Loading feed", R.string.general_error - ) - } - if (loadedState.items.isEmpty()) { showEmptyState() } else { @@ -281,12 +256,13 @@ class FeedFragment : BaseListFragment() { } private fun handleErrorState(errorState: FeedState.ErrorState): Boolean { - hideLoading() - errorState.error?.let { - onError(errorState.error) - return true + return if (errorState.error == null) { + hideLoading() + false + } else { + showError(ErrorInfo(errorState.error, UserAction.REQUESTED_FEED, "Loading feed")) + true } - return false } private fun updateRelativeTimeViews() { @@ -320,18 +296,6 @@ class FeedFragment : BaseListFragment() { listState = null } - override fun onError(exception: Throwable): Boolean { - if (super.onError(exception)) return true - - if (useAsFrontPage) { - showSnackBarError(exception, UserAction.REQUESTED_FEED, "none", "Loading Feed", 0) - return true - } - - onUnrecoverableError(exception, UserAction.REQUESTED_FEED, "none", "Loading Feed", 0) - return true - } - companion object { const val KEY_GROUP_ID = "ARG_GROUP_ID" const val KEY_GROUP_NAME = "ARG_GROUP_NAME" diff --git a/app/src/main/java/org/schabi/newpipe/local/history/StatisticsPlaylistFragment.java b/app/src/main/java/org/schabi/newpipe/local/history/StatisticsPlaylistFragment.java index 515b623ec..1bece369b 100644 --- a/app/src/main/java/org/schabi/newpipe/local/history/StatisticsPlaylistFragment.java +++ b/app/src/main/java/org/schabi/newpipe/local/history/StatisticsPlaylistFragment.java @@ -14,7 +14,6 @@ import android.widget.Toast; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import androidx.appcompat.app.AlertDialog; import androidx.viewbinding.ViewBinding; import com.google.android.material.snackbar.Snackbar; @@ -27,6 +26,8 @@ import org.schabi.newpipe.database.stream.StreamStatisticsEntry; import org.schabi.newpipe.database.stream.model.StreamEntity; import org.schabi.newpipe.databinding.PlaylistControlBinding; import org.schabi.newpipe.databinding.StatisticPlaylistControlBinding; +import org.schabi.newpipe.error.ErrorInfo; +import org.schabi.newpipe.error.UserAction; import org.schabi.newpipe.extractor.stream.StreamInfoItem; import org.schabi.newpipe.extractor.stream.StreamType; import org.schabi.newpipe.info_list.InfoItemDialog; @@ -34,10 +35,7 @@ import org.schabi.newpipe.local.BaseLocalListFragment; import org.schabi.newpipe.player.helper.PlayerHolder; import org.schabi.newpipe.player.playqueue.PlayQueue; import org.schabi.newpipe.player.playqueue.SinglePlayQueue; -import org.schabi.newpipe.error.ErrorActivity; -import org.schabi.newpipe.error.ErrorInfo; -import org.schabi.newpipe.error.UserAction; -import org.schabi.newpipe.settings.SettingsActivity; +import org.schabi.newpipe.settings.HistorySettingsFragment; import org.schabi.newpipe.util.KoreUtil; import org.schabi.newpipe.util.NavigationHelper; import org.schabi.newpipe.util.OnClickGesture; @@ -49,6 +47,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.List; +import java.util.Objects; import icepick.State; import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers; @@ -163,48 +162,11 @@ public class StatisticsPlaylistFragment @Override public boolean onOptionsItemSelected(final MenuItem item) { - switch (item.getItemId()) { - case R.id.action_history_clear: - new AlertDialog.Builder(activity) - .setTitle(R.string.delete_view_history_alert) - .setNegativeButton(R.string.cancel, ((dialog, which) -> dialog.dismiss())) - .setPositiveButton(R.string.delete, ((dialog, which) -> { - final Disposable onDelete = recordManager.deleteWholeStreamHistory() - .observeOn(AndroidSchedulers.mainThread()) - .subscribe( - howManyDeleted -> Toast.makeText(getContext(), - R.string.watch_history_deleted, - Toast.LENGTH_SHORT).show(), - throwable -> ErrorActivity.reportError(getContext(), - throwable, - SettingsActivity.class, null, - ErrorInfo.make( - UserAction.DELETE_FROM_HISTORY, - "none", - "Delete view history", - R.string.general_error))); - - final Disposable onClearOrphans = recordManager.removeOrphanedRecords() - .observeOn(AndroidSchedulers.mainThread()) - .subscribe( - howManyDeleted -> { - }, - throwable -> ErrorActivity.reportError(getContext(), - throwable, - SettingsActivity.class, null, - ErrorInfo.make( - UserAction.DELETE_FROM_HISTORY, - "none", - "Delete search history", - R.string.general_error))); - disposables.add(onClearOrphans); - disposables.add(onDelete); - })) - .create() - .show(); - break; - default: - return super.onOptionsItemSelected(item); + if (item.getItemId() == R.id.action_history_clear) { + HistorySettingsFragment + .openDeleteWatchHistoryDialog(requireContext(), recordManager, disposables); + } else { + return super.onOptionsItemSelected(item); } return true; } @@ -228,7 +190,7 @@ public class StatisticsPlaylistFragment @Override public void onPause() { super.onPause(); - itemsListState = itemsList.getLayoutManager().onSaveInstanceState(); + itemsListState = Objects.requireNonNull(itemsList.getLayoutManager()).onSaveInstanceState(); } @Override @@ -287,7 +249,8 @@ public class StatisticsPlaylistFragment @Override public void onError(final Throwable exception) { - StatisticsPlaylistFragment.this.onError(exception); + showError( + new ErrorInfo(exception, UserAction.SOMETHING_ELSE, "History Statistics")); } @Override @@ -313,7 +276,7 @@ public class StatisticsPlaylistFragment } itemListAdapter.addItems(processResult(result)); - if (itemsListState != null) { + if (itemsListState != null && itemsList.getLayoutManager() != null) { itemsList.getLayoutManager().onRestoreInstanceState(itemsListState); itemsListState = null; } @@ -341,17 +304,6 @@ public class StatisticsPlaylistFragment } } - @Override - protected boolean onError(final Throwable exception) { - if (super.onError(exception)) { - return true; - } - - onUnrecoverableError(exception, UserAction.SOMETHING_ELSE, - "none", "History Statistics", R.string.general_error); - return true; - } - /*////////////////////////////////////////////////////////////////////////// // Utils //////////////////////////////////////////////////////////////////////////*/ @@ -439,9 +391,8 @@ public class StatisticsPlaylistFragment Toast.LENGTH_SHORT).show(); } }, - throwable -> showSnackBarError(throwable, - UserAction.DELETE_FROM_HISTORY, "none", - "Deleting item failed", R.string.general_error)); + throwable -> showSnackBarError(new ErrorInfo(throwable, + UserAction.DELETE_FROM_HISTORY, "Deleting item"))); disposables.add(onDelete); } diff --git a/app/src/main/java/org/schabi/newpipe/local/playlist/LocalPlaylistFragment.java b/app/src/main/java/org/schabi/newpipe/local/playlist/LocalPlaylistFragment.java index c2d6698a9..33cc9f636 100644 --- a/app/src/main/java/org/schabi/newpipe/local/playlist/LocalPlaylistFragment.java +++ b/app/src/main/java/org/schabi/newpipe/local/playlist/LocalPlaylistFragment.java @@ -34,6 +34,7 @@ import org.schabi.newpipe.database.stream.model.StreamEntity; import org.schabi.newpipe.database.stream.model.StreamStateEntity; import org.schabi.newpipe.databinding.LocalPlaylistHeaderBinding; import org.schabi.newpipe.databinding.PlaylistControlBinding; +import org.schabi.newpipe.error.ErrorInfo; import org.schabi.newpipe.error.UserAction; import org.schabi.newpipe.extractor.stream.StreamInfoItem; import org.schabi.newpipe.extractor.stream.StreamType; @@ -110,7 +111,7 @@ public class LocalPlaylistFragment extends BaseLocalListFragment removeWatchedStreams(false)) - .setNeutralButton( - R.string.remove_watched_popup_yes_and_partially_watched_videos, - (DialogInterface d, int id) -> removeWatchedStreams(true)) - .setNegativeButton(R.string.cancel, - (DialogInterface d, int id) -> d.cancel()) - .create() - .show(); - } - break; - default: - return super.onOptionsItemSelected(item); + if (item.getItemId() == R.id.menu_item_remove_watched) { + if (!isRemovingWatched) { + new AlertDialog.Builder(requireContext()) + .setMessage(R.string.remove_watched_popup_warning) + .setTitle(R.string.remove_watched_popup_title) + .setPositiveButton(R.string.yes, + (DialogInterface d, int id) -> removeWatchedStreams(false)) + .setNeutralButton( + R.string.remove_watched_popup_yes_and_partially_watched_videos, + (DialogInterface d, int id) -> removeWatchedStreams(true)) + .setNegativeButton(R.string.cancel, + (DialogInterface d, int id) -> d.cancel()) + .create() + .show(); + } + } else { + return super.onOptionsItemSelected(item); } return true; } @@ -455,7 +455,8 @@ public class LocalPlaylistFragment extends BaseLocalListFragment showError(new ErrorInfo(throwable, UserAction.REQUESTED_BOOKMARK, + "Removing watched videos, partially watched=" + removePartiallyWatched)))); } @Override @@ -511,17 +512,6 @@ public class LocalPlaylistFragment extends BaseLocalListFragment { /*Do nothing on success*/ }, this::onError); + .subscribe(longs -> { /*Do nothing on success*/ }, throwable -> + showError(new ErrorInfo(throwable, UserAction.REQUESTED_BOOKMARK, + "Renaming playlist"))); disposables.add(disposable); } @@ -583,7 +575,9 @@ public class LocalPlaylistFragment extends BaseLocalListFragment successToast.show(), this::onError); + .subscribe(ignore -> successToast.show(), throwable -> + showError(new ErrorInfo(throwable, UserAction.REQUESTED_BOOKMARK, + "Changing playlist thumbnail"))); disposables.add(disposable); } @@ -632,7 +626,9 @@ public class LocalPlaylistFragment extends BaseLocalListFragment saveImmediate(), this::onError); + .subscribe(ignored -> saveImmediate(), throwable -> + showError(new ErrorInfo(throwable, UserAction.SOMETHING_ELSE, + "Debounced saver"))); } private void saveImmediate() { @@ -669,7 +665,8 @@ public class LocalPlaylistFragment extends BaseLocalListFragment showError(new ErrorInfo(throwable, + UserAction.REQUESTED_BOOKMARK, "Saving playlist")) ); disposables.add(disposable); } @@ -683,7 +680,7 @@ public class LocalPlaylistFragment extends BaseLocalListFragment() { binding.itemsList.adapter = groupAdapter viewModel = ViewModelProvider(this).get(SubscriptionViewModel::class.java) - viewModel.stateLiveData.observe(viewLifecycleOwner, { it?.let(this::handleResult) }) - viewModel.feedGroupsLiveData.observe(viewLifecycleOwner, { it?.let(this::handleFeedGroups) }) + viewModel.stateLiveData.observe(viewLifecycleOwner) { it?.let(this::handleResult) } + viewModel.feedGroupsLiveData.observe(viewLifecycleOwner) { it?.let(this::handleFeedGroups) } } private fun showLongTapDialog(selectedItem: ChannelInfoItem) { @@ -381,7 +382,9 @@ class SubscriptionFragment : BaseStateFragment() { } } is SubscriptionState.ErrorState -> { - result.error?.let { onError(result.error) } + result.error?.let { + showError(ErrorInfo(result.error, UserAction.SOMETHING_ELSE, "Subscriptions")) + } } } } @@ -412,17 +415,6 @@ class SubscriptionFragment : BaseStateFragment() { binding.itemsList.animate(true, 200) } - // ///////////////////////////////////////////////////////////////////////// - // Fragment Error Handling - // ///////////////////////////////////////////////////////////////////////// - - override fun onError(exception: Throwable): Boolean { - if (super.onError(exception)) return true - - onUnrecoverableError(exception, UserAction.SOMETHING_ELSE, "none", "Subscriptions", R.string.general_error) - return true - } - // ///////////////////////////////////////////////////////////////////////// // Grid Mode // ///////////////////////////////////////////////////////////////////////// diff --git a/app/src/main/java/org/schabi/newpipe/local/subscription/SubscriptionsImportFragment.java b/app/src/main/java/org/schabi/newpipe/local/subscription/SubscriptionsImportFragment.java index 7710c2bba..571a8d9b1 100644 --- a/app/src/main/java/org/schabi/newpipe/local/subscription/SubscriptionsImportFragment.java +++ b/app/src/main/java/org/schabi/newpipe/local/subscription/SubscriptionsImportFragment.java @@ -84,10 +84,12 @@ public class SubscriptionsImportFragment extends BaseFragment { setupServiceVariables(); if (supportedSources.isEmpty() && currentServiceId != Constants.NO_SERVICE_ID) { - ErrorActivity.reportError(activity, Collections.emptyList(), null, null, - ErrorInfo.make(UserAction.SOMETHING_ELSE, + ErrorActivity.reportError(activity, null, null, + new ErrorInfo(new String[]{}, UserAction.SUBSCRIPTION_IMPORT_EXPORT, NewPipe.getNameOfService(currentServiceId), - "Service don't support importing", R.string.general_error)); + "Service does not support importing subscriptions", + R.string.general_error, + null)); activity.finish(); } } diff --git a/app/src/main/java/org/schabi/newpipe/local/subscription/services/BaseImportExportService.java b/app/src/main/java/org/schabi/newpipe/local/subscription/services/BaseImportExportService.java index 6ad0761c8..e1a757f3f 100644 --- a/app/src/main/java/org/schabi/newpipe/local/subscription/services/BaseImportExportService.java +++ b/app/src/main/java/org/schabi/newpipe/local/subscription/services/BaseImportExportService.java @@ -43,7 +43,6 @@ import org.schabi.newpipe.ktx.ExceptionUtils; import org.schabi.newpipe.local.subscription.SubscriptionManager; import java.io.FileNotFoundException; -import java.util.Collections; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; @@ -152,13 +151,10 @@ public abstract class BaseImportExportService extends Service { postErrorResult(null, null); } - protected void stopAndReportError(@Nullable final Throwable error, final String request) { + protected void stopAndReportError(final Throwable throwable, final String request) { stopService(); - - final ErrorInfo errorInfo = ErrorInfo - .make(UserAction.SUBSCRIPTION, "unknown", request, R.string.general_error); - ErrorActivity.reportError(this, error != null ? Collections.singletonList(error) - : Collections.emptyList(), null, null, errorInfo); + ErrorActivity.reportError(this, null, null, new ErrorInfo( + throwable, UserAction.SUBSCRIPTION_IMPORT_EXPORT, request)); } protected void postErrorResult(final String title, final String text) { diff --git a/app/src/main/java/org/schabi/newpipe/settings/ContentSettingsFragment.java b/app/src/main/java/org/schabi/newpipe/settings/ContentSettingsFragment.java index cd2a18436..69791ad31 100644 --- a/app/src/main/java/org/schabi/newpipe/settings/ContentSettingsFragment.java +++ b/app/src/main/java/org/schabi/newpipe/settings/ContentSettingsFragment.java @@ -21,13 +21,11 @@ import com.nostra13.universalimageloader.core.ImageLoader; import org.schabi.newpipe.DownloaderImpl; import org.schabi.newpipe.NewPipeDatabase; import org.schabi.newpipe.R; +import org.schabi.newpipe.error.ErrorActivity; import org.schabi.newpipe.error.ReCaptchaActivity; import org.schabi.newpipe.extractor.NewPipe; import org.schabi.newpipe.extractor.localization.ContentCountry; import org.schabi.newpipe.extractor.localization.Localization; -import org.schabi.newpipe.error.ErrorActivity; -import org.schabi.newpipe.error.ErrorInfo; -import org.schabi.newpipe.error.UserAction; import org.schabi.newpipe.util.FilePickerActivityHelper; import org.schabi.newpipe.util.ZipHelper; @@ -198,7 +196,7 @@ public class ContentSettingsFragment extends BasePreferenceFragment { Toast.makeText(getContext(), R.string.export_complete_toast, Toast.LENGTH_SHORT).show(); } catch (final Exception e) { - onError(e); + ErrorActivity.reportUiError(getActivity(), null, "Exporting database", e); } } @@ -243,20 +241,7 @@ public class ContentSettingsFragment extends BasePreferenceFragment { System.exit(0); } } catch (final Exception e) { - onError(e); + ErrorActivity.reportUiError(getActivity(), null, "Importing database", e); } } - - /*////////////////////////////////////////////////////////////////////////// - // Error - //////////////////////////////////////////////////////////////////////////*/ - - protected void onError(final Throwable e) { - final Activity activity = getActivity(); - ErrorActivity.reportError(activity, e, - activity.getClass(), - null, - ErrorInfo.make(UserAction.UI_ERROR, - "none", "", R.string.app_ui_crash)); - } } diff --git a/app/src/main/java/org/schabi/newpipe/settings/HistorySettingsFragment.java b/app/src/main/java/org/schabi/newpipe/settings/HistorySettingsFragment.java index 3e67d93e2..6f99ec1ae 100644 --- a/app/src/main/java/org/schabi/newpipe/settings/HistorySettingsFragment.java +++ b/app/src/main/java/org/schabi/newpipe/settings/HistorySettingsFragment.java @@ -1,8 +1,10 @@ package org.schabi.newpipe.settings; +import android.content.Context; import android.os.Bundle; import android.widget.Toast; +import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.app.AlertDialog; import androidx.preference.Preference; @@ -46,120 +48,103 @@ public class HistorySettingsFragment extends BasePreferenceFragment { public boolean onPreferenceTreeClick(final Preference preference) { if (preference.getKey().equals(cacheWipeKey)) { InfoCache.getInstance().clearCache(); - Toast.makeText(preference.getContext(), R.string.metadata_cache_wipe_complete_notice, - Toast.LENGTH_SHORT).show(); + Toast.makeText(requireContext(), + R.string.metadata_cache_wipe_complete_notice, Toast.LENGTH_SHORT).show(); + } else if (preference.getKey().equals(viewsHistoryClearKey)) { + openDeleteWatchHistoryDialog(requireContext(), recordManager, disposables); + } else if (preference.getKey().equals(playbackStatesClearKey)) { + openDeletePlaybackStatesDialog(requireContext(), recordManager, disposables); + } else if (preference.getKey().equals(searchHistoryClearKey)) { + openDeleteSearchHistoryDialog(requireContext(), recordManager, disposables); + } else { + return super.onPreferenceTreeClick(preference); } + return true; + } - if (preference.getKey().equals(viewsHistoryClearKey)) { - new AlertDialog.Builder(getActivity()) - .setTitle(R.string.delete_view_history_alert) - .setNegativeButton(R.string.cancel, ((dialog, which) -> dialog.dismiss())) - .setPositiveButton(R.string.delete, ((dialog, which) -> { - final Disposable onDeletePlaybackStates - = recordManager.deleteCompleteStreamStateHistory() - .observeOn(AndroidSchedulers.mainThread()) - .subscribe( - howManyDeleted -> Toast.makeText(getActivity(), - R.string.watch_history_states_deleted, - Toast.LENGTH_SHORT).show(), - throwable -> ErrorActivity.reportError(getContext(), - throwable, - SettingsActivity.class, null, - ErrorInfo.make( - UserAction.DELETE_FROM_HISTORY, - "none", - "Delete playback states", - R.string.general_error))); + private static Disposable getDeletePlaybackStatesDisposable( + @NonNull final Context context, final HistoryRecordManager recordManager) { + return recordManager.deleteCompleteStreamStateHistory() + .observeOn(AndroidSchedulers.mainThread()) + .subscribe( + howManyDeleted -> Toast.makeText(context, + R.string.watch_history_states_deleted, Toast.LENGTH_SHORT).show(), + throwable -> ErrorActivity.reportError(context, SettingsActivity.class, + null, new ErrorInfo(throwable, UserAction.DELETE_FROM_HISTORY, + "Delete playback states"))); + } - final Disposable onDelete = recordManager.deleteWholeStreamHistory() - .observeOn(AndroidSchedulers.mainThread()) - .subscribe( - howManyDeleted -> Toast.makeText(getActivity(), - R.string.watch_history_deleted, - Toast.LENGTH_SHORT).show(), - throwable -> ErrorActivity.reportError(getContext(), - throwable, - SettingsActivity.class, null, - ErrorInfo.make( - UserAction.DELETE_FROM_HISTORY, - "none", - "Delete view history", - R.string.general_error))); + private static Disposable getWholeStreamHistoryDisposable( + @NonNull final Context context, final HistoryRecordManager recordManager) { + return recordManager.deleteWholeStreamHistory() + .observeOn(AndroidSchedulers.mainThread()) + .subscribe( + howManyDeleted -> Toast.makeText(context, + R.string.watch_history_deleted, Toast.LENGTH_SHORT).show(), + throwable -> ErrorActivity.reportError(context, SettingsActivity.class, + null, new ErrorInfo(throwable, UserAction.DELETE_FROM_HISTORY, + "Delete from history"))); + } - final Disposable onClearOrphans = recordManager.removeOrphanedRecords() - .observeOn(AndroidSchedulers.mainThread()) - .subscribe( - howManyDeleted -> { - }, - throwable -> ErrorActivity.reportError(getContext(), - throwable, - SettingsActivity.class, null, - ErrorInfo.make( - UserAction.DELETE_FROM_HISTORY, - "none", - "Delete search history", - R.string.general_error))); - disposables.add(onDeletePlaybackStates); - disposables.add(onClearOrphans); - disposables.add(onDelete); - })) - .create() - .show(); - } + private static Disposable getRemoveOrphanedRecordsDisposable( + @NonNull final Context context, final HistoryRecordManager recordManager) { + return recordManager.removeOrphanedRecords() + .observeOn(AndroidSchedulers.mainThread()) + .subscribe( + howManyDeleted -> {}, + throwable -> ErrorActivity.reportError(context, SettingsActivity.class, + null, new ErrorInfo(throwable, UserAction.DELETE_FROM_HISTORY, + "Clear orphaned records"))); + } - if (preference.getKey().equals(playbackStatesClearKey)) { - new AlertDialog.Builder(getActivity()) - .setTitle(R.string.delete_playback_states_alert) - .setNegativeButton(R.string.cancel, ((dialog, which) -> dialog.dismiss())) - .setPositiveButton(R.string.delete, ((dialog, which) -> { + private static Disposable getDeleteSearchHistoryDisposable( + @NonNull final Context context, final HistoryRecordManager recordManager) { + return recordManager.deleteCompleteSearchHistory() + .observeOn(AndroidSchedulers.mainThread()) + .subscribe( + howManyDeleted -> Toast.makeText(context, + R.string.search_history_deleted, Toast.LENGTH_SHORT).show(), + throwable -> ErrorActivity.reportError(context, SettingsActivity.class, + null, new ErrorInfo(throwable, UserAction.DELETE_FROM_HISTORY, + "Delete search history"))); + } - final Disposable onDeletePlaybackStates - = recordManager.deleteCompleteStreamStateHistory() - .observeOn(AndroidSchedulers.mainThread()) - .subscribe( - howManyDeleted -> Toast.makeText(getActivity(), - R.string.watch_history_states_deleted, - Toast.LENGTH_SHORT).show(), - throwable -> ErrorActivity.reportError(getContext(), - throwable, - SettingsActivity.class, null, - ErrorInfo.make( - UserAction.DELETE_FROM_HISTORY, - "none", - "Delete playback states", - R.string.general_error))); + public static void openDeleteWatchHistoryDialog(@NonNull final Context context, + final HistoryRecordManager recordManager, + final CompositeDisposable disposables) { + new AlertDialog.Builder(context) + .setTitle(R.string.delete_view_history_alert) + .setNegativeButton(R.string.cancel, ((dialog, which) -> dialog.dismiss())) + .setPositiveButton(R.string.delete, ((dialog, which) -> { + disposables.add(getDeletePlaybackStatesDisposable(context, recordManager)); + disposables.add(getWholeStreamHistoryDisposable(context, recordManager)); + disposables.add(getRemoveOrphanedRecordsDisposable(context, recordManager)); + })) + .create() + .show(); + } - disposables.add(onDeletePlaybackStates); - })) - .create() - .show(); - } + public static void openDeletePlaybackStatesDialog(@NonNull final Context context, + final HistoryRecordManager recordManager, + final CompositeDisposable disposables) { + new AlertDialog.Builder(context) + .setTitle(R.string.delete_playback_states_alert) + .setNegativeButton(R.string.cancel, ((dialog, which) -> dialog.dismiss())) + .setPositiveButton(R.string.delete, ((dialog, which) -> + disposables.add(getDeletePlaybackStatesDisposable(context, recordManager)))) + .create() + .show(); + } - if (preference.getKey().equals(searchHistoryClearKey)) { - new AlertDialog.Builder(getActivity()) - .setTitle(R.string.delete_search_history_alert) - .setNegativeButton(R.string.cancel, ((dialog, which) -> dialog.dismiss())) - .setPositiveButton(R.string.delete, ((dialog, which) -> { - final Disposable onDelete = recordManager.deleteCompleteSearchHistory() - .observeOn(AndroidSchedulers.mainThread()) - .subscribe( - howManyDeleted -> Toast.makeText(getActivity(), - R.string.search_history_deleted, - Toast.LENGTH_SHORT).show(), - throwable -> ErrorActivity.reportError(getContext(), - throwable, - SettingsActivity.class, null, - ErrorInfo.make( - UserAction.DELETE_FROM_HISTORY, - "none", - "Delete search history", - R.string.general_error))); - disposables.add(onDelete); - })) - .create() - .show(); - } - - return super.onPreferenceTreeClick(preference); + public static void openDeleteSearchHistoryDialog(@NonNull final Context context, + final HistoryRecordManager recordManager, + final CompositeDisposable disposables) { + new AlertDialog.Builder(context) + .setTitle(R.string.delete_search_history_alert) + .setNegativeButton(R.string.cancel, ((dialog, which) -> dialog.dismiss())) + .setPositiveButton(R.string.delete, ((dialog, which) -> + disposables.add(getDeleteSearchHistoryDisposable(context, recordManager)))) + .create() + .show(); } } diff --git a/app/src/main/java/org/schabi/newpipe/settings/SelectChannelFragment.java b/app/src/main/java/org/schabi/newpipe/settings/SelectChannelFragment.java index 5854d0a83..b7353c806 100644 --- a/app/src/main/java/org/schabi/newpipe/settings/SelectChannelFragment.java +++ b/app/src/main/java/org/schabi/newpipe/settings/SelectChannelFragment.java @@ -1,6 +1,5 @@ package org.schabi.newpipe.settings; -import android.app.Activity; import android.content.DialogInterface; import android.os.Bundle; import android.view.LayoutInflater; @@ -20,10 +19,8 @@ import com.nostra13.universalimageloader.core.ImageLoader; import org.schabi.newpipe.R; import org.schabi.newpipe.database.subscription.SubscriptionEntity; -import org.schabi.newpipe.local.subscription.SubscriptionManager; import org.schabi.newpipe.error.ErrorActivity; -import org.schabi.newpipe.error.ErrorInfo; -import org.schabi.newpipe.error.UserAction; +import org.schabi.newpipe.local.subscription.SubscriptionManager; import org.schabi.newpipe.util.ThemeHelper; import java.util.List; @@ -108,7 +105,7 @@ public class SelectChannelFragment extends DialogFragment { emptyView.setVisibility(View.GONE); - final SubscriptionManager subscriptionManager = new SubscriptionManager(getContext()); + final SubscriptionManager subscriptionManager = new SubscriptionManager(requireContext()); subscriptionManager.subscriptions().toObservable() .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) @@ -122,7 +119,7 @@ public class SelectChannelFragment extends DialogFragment { //////////////////////////////////////////////////////////////////////////*/ @Override - public void onCancel(final DialogInterface dialogInterface) { + public void onCancel(@NonNull final DialogInterface dialogInterface) { super.onCancel(dialogInterface); if (onCancelListener != null) { onCancelListener.onCancel(); @@ -156,16 +153,16 @@ public class SelectChannelFragment extends DialogFragment { private Observer> getSubscriptionObserver() { return new Observer>() { @Override - public void onSubscribe(final Disposable d) { } + public void onSubscribe(@NonNull final Disposable disposable) { } @Override - public void onNext(final List newSubscriptions) { + public void onNext(@NonNull final List newSubscriptions) { displayChannels(newSubscriptions); } @Override - public void onError(final Throwable exception) { - SelectChannelFragment.this.onError(exception); + public void onError(@NonNull final Throwable exception) { + ErrorActivity.reportUiError(requireContext(), null, "Loading subscription", exception); } @Override @@ -173,16 +170,6 @@ public class SelectChannelFragment extends DialogFragment { }; } - /*////////////////////////////////////////////////////////////////////////// - // Error - //////////////////////////////////////////////////////////////////////////*/ - - protected void onError(final Throwable e) { - final Activity activity = getActivity(); - ErrorActivity.reportError(activity, e, activity.getClass(), null, ErrorInfo - .make(UserAction.UI_ERROR, "none", "", R.string.app_ui_crash)); - } - /*////////////////////////////////////////////////////////////////////////// // Interfaces //////////////////////////////////////////////////////////////////////////*/ @@ -197,6 +184,7 @@ public class SelectChannelFragment extends DialogFragment { private class SelectChannelAdapter extends RecyclerView.Adapter { + @NonNull @Override public SelectChannelItemHolder onCreateViewHolder(final ViewGroup parent, final int viewType) { diff --git a/app/src/main/java/org/schabi/newpipe/settings/SelectKioskFragment.java b/app/src/main/java/org/schabi/newpipe/settings/SelectKioskFragment.java index 7d220578e..3ab1ee905 100644 --- a/app/src/main/java/org/schabi/newpipe/settings/SelectKioskFragment.java +++ b/app/src/main/java/org/schabi/newpipe/settings/SelectKioskFragment.java @@ -1,6 +1,5 @@ package org.schabi.newpipe.settings; -import android.app.Activity; import android.content.DialogInterface; import android.os.Bundle; import android.view.LayoutInflater; @@ -19,8 +18,6 @@ import org.schabi.newpipe.R; import org.schabi.newpipe.extractor.NewPipe; import org.schabi.newpipe.extractor.StreamingService; import org.schabi.newpipe.error.ErrorActivity; -import org.schabi.newpipe.error.ErrorInfo; -import org.schabi.newpipe.error.UserAction; import org.schabi.newpipe.util.KioskTranslator; import org.schabi.newpipe.util.ServiceHelper; import org.schabi.newpipe.util.ThemeHelper; @@ -83,7 +80,7 @@ public class SelectKioskFragment extends DialogFragment { try { selectKioskAdapter = new SelectKioskAdapter(); } catch (final Exception e) { - onError(e); + ErrorActivity.reportUiError(getActivity(), null, "Selecting kiosk", e); } recyclerView.setAdapter(selectKioskAdapter); @@ -109,16 +106,6 @@ public class SelectKioskFragment extends DialogFragment { dismiss(); } - /*////////////////////////////////////////////////////////////////////////// - // Error - //////////////////////////////////////////////////////////////////////////*/ - - protected void onError(final Throwable e) { - final Activity activity = getActivity(); - ErrorActivity.reportError(activity, e, activity.getClass(), null, ErrorInfo - .make(UserAction.UI_ERROR, "none", "", R.string.app_ui_crash)); - } - /*////////////////////////////////////////////////////////////////////////// // Interfaces //////////////////////////////////////////////////////////////////////////*/ diff --git a/app/src/main/java/org/schabi/newpipe/settings/SelectPlaylistFragment.java b/app/src/main/java/org/schabi/newpipe/settings/SelectPlaylistFragment.java index 6dcfc9179..6f18acac0 100644 --- a/app/src/main/java/org/schabi/newpipe/settings/SelectPlaylistFragment.java +++ b/app/src/main/java/org/schabi/newpipe/settings/SelectPlaylistFragment.java @@ -115,8 +115,8 @@ public class SelectPlaylistFragment extends DialogFragment { protected void onError(final Throwable e) { final Activity activity = requireActivity(); - ErrorActivity.reportError(activity, e, activity.getClass(), null, ErrorInfo - .make(UserAction.UI_ERROR, "none", "load_playlists", R.string.app_ui_crash)); + ErrorActivity.reportError(activity, activity.getClass(), null, new ErrorInfo(e, + UserAction.UI_ERROR, "Loading playlists")); } /*////////////////////////////////////////////////////////////////////////// diff --git a/app/src/main/java/org/schabi/newpipe/settings/SettingMigrations.java b/app/src/main/java/org/schabi/newpipe/settings/SettingMigrations.java index 33f83bc6f..d96bd7353 100644 --- a/app/src/main/java/org/schabi/newpipe/settings/SettingMigrations.java +++ b/app/src/main/java/org/schabi/newpipe/settings/SettingMigrations.java @@ -95,15 +95,13 @@ public final class SettingMigrations { } catch (final Exception e) { // save the version with the last successful migration and report the error sp.edit().putInt(lastPrefVersionKey, currentVersion).apply(); - final ErrorInfo errorInfo = ErrorInfo.make( + ErrorActivity.reportError(context, SettingMigrations.class, null, new ErrorInfo( + e, UserAction.PREFERENCES_MIGRATION, - "none", "Migrating preferences from version " + lastPrefVersion + " to " + VERSION + ". " - + "Error at " + currentVersion + " => " + ++currentVersion, - 0 - ); - ErrorActivity.reportError(context, e, SettingMigrations.class, null, errorInfo); + + "Error at " + currentVersion + " => " + ++currentVersion + )); return; } } diff --git a/app/src/main/java/org/schabi/newpipe/settings/tabs/ChooseTabsFragment.java b/app/src/main/java/org/schabi/newpipe/settings/tabs/ChooseTabsFragment.java index 963021b69..fd290e934 100644 --- a/app/src/main/java/org/schabi/newpipe/settings/tabs/ChooseTabsFragment.java +++ b/app/src/main/java/org/schabi/newpipe/settings/tabs/ChooseTabsFragment.java @@ -183,10 +183,9 @@ public class ChooseTabsFragment extends Fragment { final Tab.Type type = typeFrom(tabId); if (type == null) { - ErrorActivity.reportError(requireContext(), - new IllegalStateException("Tab id not found: " + tabId), null, null, - ErrorInfo.make(UserAction.SOMETHING_ELSE, "none", - "Choosing tabs on settings", 0)); + ErrorActivity.reportError(requireContext(), null, null, + new ErrorInfo(new IllegalStateException("Tab id not found: " + tabId), + UserAction.SOMETHING_ELSE, "Choosing tabs on settings")); return; } diff --git a/app/src/main/java/org/schabi/newpipe/settings/tabs/Tab.java b/app/src/main/java/org/schabi/newpipe/settings/tabs/Tab.java index b92a1a3fe..3f85bc1b4 100644 --- a/app/src/main/java/org/schabi/newpipe/settings/tabs/Tab.java +++ b/app/src/main/java/org/schabi/newpipe/settings/tabs/Tab.java @@ -483,9 +483,8 @@ public abstract class Tab { final StreamingService service = NewPipe.getService(kioskServiceId); kioskId = service.getKioskList().getDefaultKioskId(); } catch (final ExtractionException e) { - ErrorActivity.reportError(context, e, null, null, - ErrorInfo.make(UserAction.REQUESTED_KIOSK, "none", - "Loading default kiosk from selected service", 0)); + ErrorActivity.reportError(context, null, null, new ErrorInfo(e, + UserAction.REQUESTED_KIOSK, "Loading default kiosk for selected service")); } return kioskId; } diff --git a/app/src/main/java/org/schabi/newpipe/util/ExtractorHelper.java b/app/src/main/java/org/schabi/newpipe/util/ExtractorHelper.java index 97436dfbc..a904f360a 100644 --- a/app/src/main/java/org/schabi/newpipe/util/ExtractorHelper.java +++ b/app/src/main/java/org/schabi/newpipe/util/ExtractorHelper.java @@ -20,12 +20,9 @@ package org.schabi.newpipe.util; import android.content.Context; -import android.content.Intent; -import android.os.Handler; import android.util.Log; import android.view.View; import android.widget.TextView; -import android.widget.Toast; import androidx.annotation.Nullable; import androidx.core.text.HtmlCompat; @@ -33,10 +30,6 @@ import androidx.preference.PreferenceManager; import org.schabi.newpipe.MainActivity; import org.schabi.newpipe.R; -import org.schabi.newpipe.error.ErrorActivity; -import org.schabi.newpipe.error.ErrorInfo; -import org.schabi.newpipe.error.ReCaptchaActivity; -import org.schabi.newpipe.error.UserAction; import org.schabi.newpipe.extractor.Info; import org.schabi.newpipe.extractor.InfoItem; import org.schabi.newpipe.extractor.ListExtractor.InfoItemsPage; @@ -47,26 +40,14 @@ import org.schabi.newpipe.extractor.Page; import org.schabi.newpipe.extractor.StreamingService; import org.schabi.newpipe.extractor.channel.ChannelInfo; import org.schabi.newpipe.extractor.comments.CommentsInfo; -import org.schabi.newpipe.extractor.exceptions.AgeRestrictedContentException; -import org.schabi.newpipe.extractor.exceptions.ContentNotAvailableException; -import org.schabi.newpipe.extractor.exceptions.ContentNotSupportedException; -import org.schabi.newpipe.extractor.exceptions.GeographicRestrictionException; -import org.schabi.newpipe.extractor.exceptions.PaidContentException; -import org.schabi.newpipe.extractor.exceptions.ParsingException; -import org.schabi.newpipe.extractor.exceptions.PrivateContentException; -import org.schabi.newpipe.extractor.exceptions.ReCaptchaException; -import org.schabi.newpipe.extractor.exceptions.SoundCloudGoPlusContentException; -import org.schabi.newpipe.extractor.exceptions.YoutubeMusicPremiumContentException; import org.schabi.newpipe.extractor.feed.FeedExtractor; import org.schabi.newpipe.extractor.feed.FeedInfo; import org.schabi.newpipe.extractor.kiosk.KioskInfo; import org.schabi.newpipe.extractor.playlist.PlaylistInfo; import org.schabi.newpipe.extractor.search.SearchInfo; -import org.schabi.newpipe.extractor.services.youtube.extractors.YoutubeStreamExtractor; import org.schabi.newpipe.extractor.stream.StreamInfo; import org.schabi.newpipe.extractor.stream.StreamInfoItem; import org.schabi.newpipe.extractor.suggestion.SuggestionExtractor; -import org.schabi.newpipe.ktx.ExceptionUtils; import java.util.Collections; import java.util.List; @@ -280,65 +261,6 @@ public final class ExtractorHelper { return null != loadFromCache(serviceId, url, infoType).blockingGet(); } - /** - * A simple and general error handler that show a Toast for known exceptions, - * and for others, opens the report error activity with the (optional) error message. - * - * @param context Android app context - * @param serviceId the service the exception happened in - * @param url the URL where the exception happened - * @param exception the exception to be handled - * @param userAction the action of the user that caused the exception - * @param optionalErrorMessage the optional error message - */ - public static void handleGeneralException(final Context context, final int serviceId, - final String url, final Throwable exception, - final UserAction userAction, - final String optionalErrorMessage) { - final Handler handler = new Handler(context.getMainLooper()); - - handler.post(() -> { - if (exception instanceof ReCaptchaException) { - Toast.makeText(context, R.string.recaptcha_request_toast, Toast.LENGTH_LONG).show(); - // Starting ReCaptcha Challenge Activity - final Intent intent = new Intent(context, ReCaptchaActivity.class); - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - context.startActivity(intent); - } else if (ExceptionUtils.isNetworkRelated(exception)) { - Toast.makeText(context, R.string.network_error, Toast.LENGTH_LONG).show(); - } else if (exception instanceof AgeRestrictedContentException) { - Toast.makeText(context, R.string.restricted_video_no_stream, - Toast.LENGTH_LONG).show(); - } else if (exception instanceof GeographicRestrictionException) { - Toast.makeText(context, R.string.georestricted_content, Toast.LENGTH_LONG).show(); - } else if (exception instanceof PaidContentException) { - Toast.makeText(context, R.string.paid_content, Toast.LENGTH_LONG).show(); - } else if (exception instanceof PrivateContentException) { - Toast.makeText(context, R.string.private_content, Toast.LENGTH_LONG).show(); - } else if (exception instanceof SoundCloudGoPlusContentException) { - Toast.makeText(context, R.string.soundcloud_go_plus_content, - Toast.LENGTH_LONG).show(); - } else if (exception instanceof YoutubeMusicPremiumContentException) { - Toast.makeText(context, R.string.youtube_music_premium_content, - Toast.LENGTH_LONG).show(); - } else if (exception instanceof ContentNotAvailableException) { - Toast.makeText(context, R.string.content_not_available, Toast.LENGTH_LONG).show(); - } else if (exception instanceof ContentNotSupportedException) { - Toast.makeText(context, R.string.content_not_supported, Toast.LENGTH_LONG).show(); - } else { - final int errorId = exception instanceof YoutubeStreamExtractor.DeobfuscateException - ? R.string.youtube_signature_deobfuscation_error - : exception instanceof ParsingException - ? R.string.parsing_error : R.string.general_error; - ErrorActivity.reportError(handler, context, exception, MainActivity.class, null, - ErrorInfo.make(userAction, serviceId == -1 ? "none" - : NewPipe.getNameOfService(serviceId), - url + (optionalErrorMessage == null ? "" - : optionalErrorMessage), errorId)); - } - }); - } - /** * Formats the text contained in the meta info list as HTML and puts it into the text view, * while also making the separator visible. If the list is null or empty, or the user chose not diff --git a/app/src/main/java/us/shandian/giga/ui/adapter/MissionAdapter.java b/app/src/main/java/us/shandian/giga/ui/adapter/MissionAdapter.java index a8b9f5269..455dd0614 100644 --- a/app/src/main/java/us/shandian/giga/ui/adapter/MissionAdapter.java +++ b/app/src/main/java/us/shandian/giga/ui/adapter/MissionAdapter.java @@ -583,16 +583,12 @@ public class MissionAdapter extends Adapter implements Handler.Callb try { service = NewPipe.getServiceByUrl(mission.source).getServiceInfo().getName(); } catch (Exception e) { - service = "-"; + service = ErrorInfo.SERVICE_NONE; } - ErrorActivity.reportError( - mContext, - mission.errObject, - null, - null, - ErrorInfo.make(action, service, request.toString(), reason) - ); + ErrorActivity.reportError(mContext, null, null, + new ErrorInfo(ErrorInfo.Companion.throwableToStringList(mission.errObject), action, + service, request.toString(), reason, null)); } public void clearFinishedDownloads(boolean delete) { diff --git a/app/src/main/res/layout-large-land/fragment_video_detail.xml b/app/src/main/res/layout-large-land/fragment_video_detail.xml index 14459b494..a3d947f6f 100644 --- a/app/src/main/res/layout-large-land/fragment_video_detail.xml +++ b/app/src/main/res/layout-large-land/fragment_video_detail.xml @@ -219,7 +219,7 @@ +