mirror of
				https://github.com/TeamNewPipe/NewPipe
				synced 2025-10-31 15:23:00 +00:00 
			
		
		
		
	Update most dependencies
This commit is contained in:
		| @@ -38,13 +38,13 @@ import java.util.Arrays; | ||||
| import java.util.Collections; | ||||
| import java.util.List; | ||||
|  | ||||
| import io.reactivex.disposables.Disposable; | ||||
| import io.reactivex.exceptions.CompositeException; | ||||
| import io.reactivex.exceptions.MissingBackpressureException; | ||||
| import io.reactivex.exceptions.OnErrorNotImplementedException; | ||||
| import io.reactivex.exceptions.UndeliverableException; | ||||
| import io.reactivex.functions.Consumer; | ||||
| import io.reactivex.plugins.RxJavaPlugins; | ||||
| import io.reactivex.rxjava3.disposables.Disposable; | ||||
| import io.reactivex.rxjava3.exceptions.CompositeException; | ||||
| import io.reactivex.rxjava3.exceptions.MissingBackpressureException; | ||||
| import io.reactivex.rxjava3.exceptions.OnErrorNotImplementedException; | ||||
| import io.reactivex.rxjava3.exceptions.UndeliverableException; | ||||
| import io.reactivex.rxjava3.functions.Consumer; | ||||
| import io.reactivex.rxjava3.plugins.RxJavaPlugins; | ||||
|  | ||||
| /* | ||||
|  * Copyright (C) Hans-Christoph Steiner 2016 <hans@eds.org> | ||||
|   | ||||
| @@ -35,10 +35,10 @@ import java.security.cert.CertificateException; | ||||
| import java.security.cert.CertificateFactory; | ||||
| import java.security.cert.X509Certificate; | ||||
|  | ||||
| import io.reactivex.Maybe; | ||||
| import io.reactivex.android.schedulers.AndroidSchedulers; | ||||
| import io.reactivex.disposables.Disposable; | ||||
| import io.reactivex.schedulers.Schedulers; | ||||
| import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers; | ||||
| import io.reactivex.rxjava3.core.Maybe; | ||||
| import io.reactivex.rxjava3.disposables.Disposable; | ||||
| import io.reactivex.rxjava3.schedulers.Schedulers; | ||||
|  | ||||
| public final class CheckForNewAppVersion { | ||||
|     private CheckForNewAppVersion() { } | ||||
|   | ||||
| @@ -66,13 +66,13 @@ import java.util.List; | ||||
|  | ||||
| import icepick.Icepick; | ||||
| import icepick.State; | ||||
| import io.reactivex.Observable; | ||||
| import io.reactivex.Single; | ||||
| import io.reactivex.android.schedulers.AndroidSchedulers; | ||||
| import io.reactivex.disposables.CompositeDisposable; | ||||
| import io.reactivex.disposables.Disposable; | ||||
| import io.reactivex.functions.Consumer; | ||||
| import io.reactivex.schedulers.Schedulers; | ||||
| import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers; | ||||
| import io.reactivex.rxjava3.core.Observable; | ||||
| import io.reactivex.rxjava3.core.Single; | ||||
| import io.reactivex.rxjava3.disposables.CompositeDisposable; | ||||
| import io.reactivex.rxjava3.disposables.Disposable; | ||||
| import io.reactivex.rxjava3.functions.Consumer; | ||||
| import io.reactivex.rxjava3.schedulers.Schedulers; | ||||
|  | ||||
| import static org.schabi.newpipe.extractor.StreamingService.ServiceInfo.MediaCapability.AUDIO; | ||||
| import static org.schabi.newpipe.extractor.StreamingService.ServiceInfo.MediaCapability.VIDEO; | ||||
|   | ||||
| @@ -20,7 +20,7 @@ import java.io.Serializable; | ||||
| import java.util.Arrays; | ||||
| import java.util.Comparator; | ||||
|  | ||||
| import io.reactivex.disposables.CompositeDisposable; | ||||
| import io.reactivex.rxjava3.disposables.CompositeDisposable; | ||||
|  | ||||
| /** | ||||
|  * Fragment containing the software licenses. | ||||
|   | ||||
| @@ -16,11 +16,10 @@ import java.io.IOException; | ||||
| import java.io.InputStreamReader; | ||||
| import java.nio.charset.StandardCharsets; | ||||
|  | ||||
| import io.reactivex.Observable; | ||||
| import io.reactivex.android.schedulers.AndroidSchedulers; | ||||
| import io.reactivex.disposables.Disposable; | ||||
| import io.reactivex.disposables.Disposables; | ||||
| import io.reactivex.schedulers.Schedulers; | ||||
| import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers; | ||||
| import io.reactivex.rxjava3.core.Observable; | ||||
| import io.reactivex.rxjava3.disposables.Disposable; | ||||
| import io.reactivex.rxjava3.schedulers.Schedulers; | ||||
|  | ||||
| import static org.schabi.newpipe.util.Localization.assureCorrectAppLanguage; | ||||
|  | ||||
| @@ -55,7 +54,7 @@ public final class LicenseFragmentHelper { | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param context | ||||
|      * @param context the Android context | ||||
|      * @return String which is a CSS stylesheet according to the context's theme | ||||
|      */ | ||||
|     private static String getLicenseStylesheet(@NonNull final Context context) { | ||||
| @@ -86,7 +85,7 @@ public final class LicenseFragmentHelper { | ||||
|  | ||||
|     static Disposable showLicense(@Nullable final Context context, @NonNull final License license) { | ||||
|         if (context == null) { | ||||
|             return Disposables.empty(); | ||||
|             return Disposable.empty(); | ||||
|         } | ||||
|  | ||||
|         return Observable.fromCallable(() -> getFormattedLicense(context, license)) | ||||
|   | ||||
| @@ -9,7 +9,7 @@ import androidx.room.Update; | ||||
| import java.util.Collection; | ||||
| import java.util.List; | ||||
|  | ||||
| import io.reactivex.Flowable; | ||||
| import io.reactivex.rxjava3.core.Flowable; | ||||
|  | ||||
| @Dao | ||||
| public interface BasicDAO<Entity> { | ||||
|   | ||||
| @@ -1,24 +1,20 @@ | ||||
| package org.schabi.newpipe.database.feed.dao | ||||
|  | ||||
| import androidx.room.Dao | ||||
| import androidx.room.Insert | ||||
| import androidx.room.OnConflictStrategy | ||||
| import androidx.room.Query | ||||
| import androidx.room.Transaction | ||||
| import androidx.room.Update | ||||
| import io.reactivex.Flowable | ||||
| import java.time.OffsetDateTime | ||||
| import androidx.room.* | ||||
| import io.reactivex.rxjava3.core.Flowable | ||||
| import org.schabi.newpipe.database.feed.model.FeedEntity | ||||
| import org.schabi.newpipe.database.feed.model.FeedLastUpdatedEntity | ||||
| import org.schabi.newpipe.database.stream.model.StreamEntity | ||||
| import org.schabi.newpipe.database.subscription.SubscriptionEntity | ||||
| import java.time.OffsetDateTime | ||||
|  | ||||
| @Dao | ||||
| abstract class FeedDAO { | ||||
|     @Query("DELETE FROM feed") | ||||
|     abstract fun deleteAll(): Int | ||||
|  | ||||
|     @Query(""" | ||||
|     @Query( | ||||
|         """ | ||||
|         SELECT s.* FROM streams s | ||||
|  | ||||
|         INNER JOIN feed f | ||||
| @@ -27,10 +23,12 @@ abstract class FeedDAO { | ||||
|         ORDER BY s.upload_date IS NULL DESC, s.upload_date DESC, s.uploader ASC | ||||
|  | ||||
|         LIMIT 500 | ||||
|         """) | ||||
|         """ | ||||
|     ) | ||||
|     abstract fun getAllStreams(): Flowable<List<StreamEntity>> | ||||
|  | ||||
|     @Query(""" | ||||
|     @Query( | ||||
|         """ | ||||
|         SELECT s.* FROM streams s | ||||
|  | ||||
|         INNER JOIN feed f | ||||
| @@ -46,10 +44,12 @@ abstract class FeedDAO { | ||||
|  | ||||
|         ORDER BY s.upload_date IS NULL DESC, s.upload_date DESC, s.uploader ASC | ||||
|         LIMIT 500 | ||||
|         """) | ||||
|         """ | ||||
|     ) | ||||
|     abstract fun getAllStreamsFromGroup(groupId: Long): Flowable<List<StreamEntity>> | ||||
|  | ||||
|     @Query(""" | ||||
|     @Query( | ||||
|         """ | ||||
|         DELETE FROM feed WHERE | ||||
|  | ||||
|         feed.stream_id IN ( | ||||
| @@ -60,10 +60,12 @@ abstract class FeedDAO { | ||||
|  | ||||
|             WHERE s.upload_date < :offsetDateTime | ||||
|         ) | ||||
|         """) | ||||
|         """ | ||||
|     ) | ||||
|     abstract fun unlinkStreamsOlderThan(offsetDateTime: OffsetDateTime) | ||||
|  | ||||
|     @Query(""" | ||||
|     @Query( | ||||
|         """ | ||||
|         DELETE FROM feed | ||||
|          | ||||
|         WHERE feed.subscription_id = :subscriptionId | ||||
| @@ -76,7 +78,8 @@ abstract class FeedDAO { | ||||
|  | ||||
|             WHERE s.stream_type = "LIVE_STREAM" OR s.stream_type = "AUDIO_LIVE_STREAM" | ||||
|         ) | ||||
|         """) | ||||
|         """ | ||||
|     ) | ||||
|     abstract fun unlinkOldLivestreams(subscriptionId: Long) | ||||
|  | ||||
|     @Insert(onConflict = OnConflictStrategy.IGNORE) | ||||
| @@ -100,12 +103,14 @@ abstract class FeedDAO { | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @Query(""" | ||||
|     @Query( | ||||
|         """ | ||||
|         SELECT MIN(lu.last_updated) FROM feed_last_updated lu | ||||
|  | ||||
|         INNER JOIN feed_group_subscription_join fgs | ||||
|         ON fgs.subscription_id = lu.subscription_id AND fgs.group_id = :groupId | ||||
|         """) | ||||
|         """ | ||||
|     ) | ||||
|     abstract fun oldestSubscriptionUpdate(groupId: Long): Flowable<List<OffsetDateTime>> | ||||
|  | ||||
|     @Query("SELECT MIN(last_updated) FROM feed_last_updated") | ||||
| @@ -114,7 +119,8 @@ abstract class FeedDAO { | ||||
|     @Query("SELECT COUNT(*) FROM feed_last_updated WHERE last_updated IS NULL") | ||||
|     abstract fun notLoadedCount(): Flowable<Long> | ||||
|  | ||||
|     @Query(""" | ||||
|     @Query( | ||||
|         """ | ||||
|         SELECT COUNT(*) FROM subscriptions s | ||||
|          | ||||
|         INNER JOIN feed_group_subscription_join fgs | ||||
| @@ -124,20 +130,24 @@ abstract class FeedDAO { | ||||
|         ON s.uid = lu.subscription_id  | ||||
|  | ||||
|         WHERE lu.last_updated IS NULL | ||||
|         """) | ||||
|         """ | ||||
|     ) | ||||
|     abstract fun notLoadedCountForGroup(groupId: Long): Flowable<Long> | ||||
|  | ||||
|     @Query(""" | ||||
|     @Query( | ||||
|         """ | ||||
|         SELECT s.* FROM subscriptions s | ||||
|  | ||||
|         LEFT JOIN feed_last_updated lu | ||||
|         ON s.uid = lu.subscription_id  | ||||
|  | ||||
|         WHERE lu.last_updated IS NULL OR lu.last_updated < :outdatedThreshold | ||||
|         """) | ||||
|         """ | ||||
|     ) | ||||
|     abstract fun getAllOutdated(outdatedThreshold: OffsetDateTime): Flowable<List<SubscriptionEntity>> | ||||
|  | ||||
|     @Query(""" | ||||
|     @Query( | ||||
|         """ | ||||
|         SELECT s.* FROM subscriptions s | ||||
|  | ||||
|         INNER JOIN feed_group_subscription_join fgs | ||||
| @@ -147,6 +157,7 @@ abstract class FeedDAO { | ||||
|         ON s.uid = lu.subscription_id | ||||
|  | ||||
|         WHERE lu.last_updated IS NULL OR lu.last_updated < :outdatedThreshold | ||||
|         """) | ||||
|         """ | ||||
|     ) | ||||
|     abstract fun getAllOutdatedForGroup(groupId: Long, outdatedThreshold: OffsetDateTime): Flowable<List<SubscriptionEntity>> | ||||
| } | ||||
|   | ||||
| @@ -6,8 +6,8 @@ import androidx.room.OnConflictStrategy | ||||
| import androidx.room.Query | ||||
| import androidx.room.Transaction | ||||
| import androidx.room.Update | ||||
| import io.reactivex.Flowable | ||||
| import io.reactivex.Maybe | ||||
| import io.reactivex.rxjava3.core.Flowable | ||||
| import io.reactivex.rxjava3.core.Maybe | ||||
| import org.schabi.newpipe.database.feed.model.FeedGroupEntity | ||||
| import org.schabi.newpipe.database.feed.model.FeedGroupSubscriptionEntity | ||||
|  | ||||
|   | ||||
| @@ -10,21 +10,24 @@ import org.schabi.newpipe.database.feed.model.FeedEntity.Companion.SUBSCRIPTION_ | ||||
| import org.schabi.newpipe.database.stream.model.StreamEntity | ||||
| import org.schabi.newpipe.database.subscription.SubscriptionEntity | ||||
|  | ||||
| @Entity(tableName = FEED_TABLE, | ||||
|         primaryKeys = [STREAM_ID, SUBSCRIPTION_ID], | ||||
|         indices = [Index(SUBSCRIPTION_ID)], | ||||
|         foreignKeys = [ | ||||
|             ForeignKey( | ||||
|                     entity = StreamEntity::class, | ||||
|                     parentColumns = [StreamEntity.STREAM_ID], | ||||
|                     childColumns = [STREAM_ID], | ||||
|                     onDelete = ForeignKey.CASCADE, onUpdate = ForeignKey.CASCADE, deferred = true), | ||||
|             ForeignKey( | ||||
|                     entity = SubscriptionEntity::class, | ||||
|                     parentColumns = [SubscriptionEntity.SUBSCRIPTION_UID], | ||||
|                     childColumns = [SUBSCRIPTION_ID], | ||||
|                     onDelete = ForeignKey.CASCADE, onUpdate = ForeignKey.CASCADE, deferred = true) | ||||
|         ] | ||||
| @Entity( | ||||
|     tableName = FEED_TABLE, | ||||
|     primaryKeys = [STREAM_ID, SUBSCRIPTION_ID], | ||||
|     indices = [Index(SUBSCRIPTION_ID)], | ||||
|     foreignKeys = [ | ||||
|         ForeignKey( | ||||
|             entity = StreamEntity::class, | ||||
|             parentColumns = [StreamEntity.STREAM_ID], | ||||
|             childColumns = [STREAM_ID], | ||||
|             onDelete = ForeignKey.CASCADE, onUpdate = ForeignKey.CASCADE, deferred = true | ||||
|         ), | ||||
|         ForeignKey( | ||||
|             entity = SubscriptionEntity::class, | ||||
|             parentColumns = [SubscriptionEntity.SUBSCRIPTION_UID], | ||||
|             childColumns = [SUBSCRIPTION_ID], | ||||
|             onDelete = ForeignKey.CASCADE, onUpdate = ForeignKey.CASCADE, deferred = true | ||||
|         ) | ||||
|     ] | ||||
| ) | ||||
| data class FeedEntity( | ||||
|     @ColumnInfo(name = STREAM_ID) | ||||
|   | ||||
| @@ -9,8 +9,8 @@ import org.schabi.newpipe.database.feed.model.FeedGroupEntity.Companion.SORT_ORD | ||||
| import org.schabi.newpipe.local.subscription.FeedGroupIcon | ||||
|  | ||||
| @Entity( | ||||
|         tableName = FEED_GROUP_TABLE, | ||||
|         indices = [Index(SORT_ORDER)] | ||||
|     tableName = FEED_GROUP_TABLE, | ||||
|     indices = [Index(SORT_ORDER)] | ||||
| ) | ||||
| data class FeedGroupEntity( | ||||
|     @PrimaryKey(autoGenerate = true) | ||||
|   | ||||
| @@ -11,22 +11,24 @@ import org.schabi.newpipe.database.feed.model.FeedGroupSubscriptionEntity.Compan | ||||
| import org.schabi.newpipe.database.subscription.SubscriptionEntity | ||||
|  | ||||
| @Entity( | ||||
|         tableName = FEED_GROUP_SUBSCRIPTION_TABLE, | ||||
|         primaryKeys = [GROUP_ID, SUBSCRIPTION_ID], | ||||
|         indices = [Index(SUBSCRIPTION_ID)], | ||||
|         foreignKeys = [ | ||||
|             ForeignKey( | ||||
|                     entity = FeedGroupEntity::class, | ||||
|                     parentColumns = [FeedGroupEntity.ID], | ||||
|                     childColumns = [GROUP_ID], | ||||
|                     onDelete = CASCADE, onUpdate = CASCADE, deferred = true), | ||||
|     tableName = FEED_GROUP_SUBSCRIPTION_TABLE, | ||||
|     primaryKeys = [GROUP_ID, SUBSCRIPTION_ID], | ||||
|     indices = [Index(SUBSCRIPTION_ID)], | ||||
|     foreignKeys = [ | ||||
|         ForeignKey( | ||||
|             entity = FeedGroupEntity::class, | ||||
|             parentColumns = [FeedGroupEntity.ID], | ||||
|             childColumns = [GROUP_ID], | ||||
|             onDelete = CASCADE, onUpdate = CASCADE, deferred = true | ||||
|         ), | ||||
|  | ||||
|             ForeignKey( | ||||
|                     entity = SubscriptionEntity::class, | ||||
|                     parentColumns = [SubscriptionEntity.SUBSCRIPTION_UID], | ||||
|                     childColumns = [SUBSCRIPTION_ID], | ||||
|                     onDelete = CASCADE, onUpdate = CASCADE, deferred = true) | ||||
|         ] | ||||
|         ForeignKey( | ||||
|             entity = SubscriptionEntity::class, | ||||
|             parentColumns = [SubscriptionEntity.SUBSCRIPTION_UID], | ||||
|             childColumns = [SUBSCRIPTION_ID], | ||||
|             onDelete = CASCADE, onUpdate = CASCADE, deferred = true | ||||
|         ) | ||||
|     ] | ||||
| ) | ||||
| data class FeedGroupSubscriptionEntity( | ||||
|     @ColumnInfo(name = GROUP_ID) | ||||
|   | ||||
| @@ -4,20 +4,21 @@ import androidx.room.ColumnInfo | ||||
| import androidx.room.Entity | ||||
| import androidx.room.ForeignKey | ||||
| import androidx.room.PrimaryKey | ||||
| import java.time.OffsetDateTime | ||||
| import org.schabi.newpipe.database.feed.model.FeedLastUpdatedEntity.Companion.FEED_LAST_UPDATED_TABLE | ||||
| import org.schabi.newpipe.database.feed.model.FeedLastUpdatedEntity.Companion.SUBSCRIPTION_ID | ||||
| import org.schabi.newpipe.database.subscription.SubscriptionEntity | ||||
| import java.time.OffsetDateTime | ||||
|  | ||||
| @Entity( | ||||
|         tableName = FEED_LAST_UPDATED_TABLE, | ||||
|         foreignKeys = [ | ||||
|             ForeignKey( | ||||
|                     entity = SubscriptionEntity::class, | ||||
|                     parentColumns = [SubscriptionEntity.SUBSCRIPTION_UID], | ||||
|                     childColumns = [SUBSCRIPTION_ID], | ||||
|                     onDelete = ForeignKey.CASCADE, onUpdate = ForeignKey.CASCADE, deferred = true) | ||||
|         ] | ||||
|     tableName = FEED_LAST_UPDATED_TABLE, | ||||
|     foreignKeys = [ | ||||
|         ForeignKey( | ||||
|             entity = SubscriptionEntity::class, | ||||
|             parentColumns = [SubscriptionEntity.SUBSCRIPTION_UID], | ||||
|             childColumns = [SUBSCRIPTION_ID], | ||||
|             onDelete = ForeignKey.CASCADE, onUpdate = ForeignKey.CASCADE, deferred = true | ||||
|         ) | ||||
|     ] | ||||
| ) | ||||
| data class FeedLastUpdatedEntity( | ||||
|     @PrimaryKey | ||||
|   | ||||
| @@ -8,7 +8,7 @@ import org.schabi.newpipe.database.history.model.SearchHistoryEntry; | ||||
|  | ||||
| import java.util.List; | ||||
|  | ||||
| import io.reactivex.Flowable; | ||||
| import io.reactivex.rxjava3.core.Flowable; | ||||
|  | ||||
| import static org.schabi.newpipe.database.history.model.SearchHistoryEntry.CREATION_DATE; | ||||
| import static org.schabi.newpipe.database.history.model.SearchHistoryEntry.ID; | ||||
|   | ||||
| @@ -10,7 +10,7 @@ import org.schabi.newpipe.database.stream.StreamStatisticsEntry; | ||||
|  | ||||
| import java.util.List; | ||||
|  | ||||
| import io.reactivex.Flowable; | ||||
| import io.reactivex.rxjava3.core.Flowable; | ||||
|  | ||||
| import static org.schabi.newpipe.database.history.model.StreamHistoryEntity.JOIN_STREAM_ID; | ||||
| import static org.schabi.newpipe.database.history.model.StreamHistoryEntity.STREAM_ACCESS_DATE; | ||||
|   | ||||
| @@ -2,8 +2,8 @@ package org.schabi.newpipe.database.history.model | ||||
|  | ||||
| import androidx.room.ColumnInfo | ||||
| import androidx.room.Embedded | ||||
| import java.time.OffsetDateTime | ||||
| import org.schabi.newpipe.database.stream.model.StreamEntity | ||||
| import java.time.OffsetDateTime | ||||
|  | ||||
| data class StreamHistoryEntry( | ||||
|     @Embedded | ||||
| @@ -25,6 +25,6 @@ data class StreamHistoryEntry( | ||||
|  | ||||
|     fun hasEqualValues(other: StreamHistoryEntry): Boolean { | ||||
|         return this.streamEntity.uid == other.streamEntity.uid && streamId == other.streamId && | ||||
|                 accessDate.isEqual(other.accessDate) | ||||
|             accessDate.isEqual(other.accessDate) | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -8,7 +8,7 @@ import org.schabi.newpipe.database.playlist.model.PlaylistEntity; | ||||
|  | ||||
| import java.util.List; | ||||
|  | ||||
| import io.reactivex.Flowable; | ||||
| import io.reactivex.rxjava3.core.Flowable; | ||||
|  | ||||
| import static org.schabi.newpipe.database.playlist.model.PlaylistEntity.PLAYLIST_ID; | ||||
| import static org.schabi.newpipe.database.playlist.model.PlaylistEntity.PLAYLIST_TABLE; | ||||
|   | ||||
| @@ -9,7 +9,7 @@ import org.schabi.newpipe.database.playlist.model.PlaylistRemoteEntity; | ||||
|  | ||||
| import java.util.List; | ||||
|  | ||||
| import io.reactivex.Flowable; | ||||
| import io.reactivex.rxjava3.core.Flowable; | ||||
|  | ||||
| import static org.schabi.newpipe.database.playlist.model.PlaylistRemoteEntity.REMOTE_PLAYLIST_ID; | ||||
| import static org.schabi.newpipe.database.playlist.model.PlaylistRemoteEntity.REMOTE_PLAYLIST_SERVICE_ID; | ||||
|   | ||||
| @@ -11,7 +11,7 @@ import org.schabi.newpipe.database.playlist.model.PlaylistStreamEntity; | ||||
|  | ||||
| import java.util.List; | ||||
|  | ||||
| import io.reactivex.Flowable; | ||||
| import io.reactivex.rxjava3.core.Flowable; | ||||
|  | ||||
| import static org.schabi.newpipe.database.playlist.PlaylistMetadataEntry.PLAYLIST_STREAM_COUNT; | ||||
| import static org.schabi.newpipe.database.playlist.model.PlaylistEntity.PLAYLIST_ID; | ||||
|   | ||||
| @@ -1,19 +1,14 @@ | ||||
| package org.schabi.newpipe.database.stream.dao | ||||
|  | ||||
| import androidx.room.ColumnInfo | ||||
| import androidx.room.Dao | ||||
| import androidx.room.Insert | ||||
| import androidx.room.OnConflictStrategy | ||||
| import androidx.room.Query | ||||
| import androidx.room.Transaction | ||||
| import io.reactivex.Flowable | ||||
| import java.time.OffsetDateTime | ||||
| import androidx.room.* | ||||
| import io.reactivex.rxjava3.core.Flowable | ||||
| import org.schabi.newpipe.database.BasicDAO | ||||
| import org.schabi.newpipe.database.stream.model.StreamEntity | ||||
| import org.schabi.newpipe.database.stream.model.StreamEntity.Companion.STREAM_ID | ||||
| import org.schabi.newpipe.extractor.stream.StreamType | ||||
| import org.schabi.newpipe.extractor.stream.StreamType.AUDIO_LIVE_STREAM | ||||
| import org.schabi.newpipe.extractor.stream.StreamType.LIVE_STREAM | ||||
| import java.time.OffsetDateTime | ||||
|  | ||||
| @Dao | ||||
| abstract class StreamDAO : BasicDAO<StreamEntity> { | ||||
| @@ -35,10 +30,12 @@ abstract class StreamDAO : BasicDAO<StreamEntity> { | ||||
|     @Insert(onConflict = OnConflictStrategy.IGNORE) | ||||
|     internal abstract fun silentInsertAllInternal(streams: List<StreamEntity>): List<Long> | ||||
|  | ||||
|     @Query(""" | ||||
|     @Query( | ||||
|         """ | ||||
|         SELECT uid, stream_type, textual_upload_date, upload_date, is_upload_date_approximation, duration  | ||||
|         FROM streams WHERE url = :url AND service_id = :serviceId | ||||
|         """) | ||||
|         """ | ||||
|     ) | ||||
|     internal abstract fun getMinimalStreamForCompare(serviceId: Int, url: String): StreamCompareFeed? | ||||
|  | ||||
|     @Transaction | ||||
| @@ -79,7 +76,7 @@ abstract class StreamDAO : BasicDAO<StreamEntity> { | ||||
|  | ||||
|     private fun compareAndUpdateStream(newerStream: StreamEntity) { | ||||
|         val existentMinimalStream = getMinimalStreamForCompare(newerStream.serviceId, newerStream.url) | ||||
|                 ?: throw IllegalStateException("Stream cannot be null just after insertion.") | ||||
|             ?: throw IllegalStateException("Stream cannot be null just after insertion.") | ||||
|         newerStream.uid = existentMinimalStream.uid | ||||
|  | ||||
|         val isNewerStreamLive = newerStream.streamType == AUDIO_LIVE_STREAM || newerStream.streamType == LIVE_STREAM | ||||
| @@ -88,7 +85,7 @@ abstract class StreamDAO : BasicDAO<StreamEntity> { | ||||
|             // Use the existent upload date if the newer stream does not have a better precision | ||||
|             // (i.e. is an approximation). This is done to prevent unnecessary changes. | ||||
|             val hasBetterPrecision = | ||||
|                     newerStream.uploadDate != null && newerStream.isUploadDateApproximation != true | ||||
|                 newerStream.uploadDate != null && newerStream.isUploadDateApproximation != true | ||||
|             if (existentMinimalStream.uploadDate != null && !hasBetterPrecision) { | ||||
|                 newerStream.uploadDate = existentMinimalStream.uploadDate | ||||
|                 newerStream.textualUploadDate = existentMinimalStream.textualUploadDate | ||||
| @@ -101,7 +98,8 @@ abstract class StreamDAO : BasicDAO<StreamEntity> { | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @Query(""" | ||||
|     @Query( | ||||
|         """ | ||||
|         DELETE FROM streams WHERE | ||||
|  | ||||
|         NOT EXISTS (SELECT 1 FROM stream_history sh | ||||
| @@ -112,7 +110,8 @@ abstract class StreamDAO : BasicDAO<StreamEntity> { | ||||
|  | ||||
|         AND NOT EXISTS (SELECT 1 FROM feed f | ||||
|         WHERE f.stream_id = streams.uid) | ||||
|         """) | ||||
|         """ | ||||
|     ) | ||||
|     abstract fun deleteOrphans(): Int | ||||
|  | ||||
|     /** | ||||
|   | ||||
| @@ -11,7 +11,7 @@ import org.schabi.newpipe.database.stream.model.StreamStateEntity; | ||||
|  | ||||
| import java.util.List; | ||||
|  | ||||
| import io.reactivex.Flowable; | ||||
| import io.reactivex.rxjava3.core.Flowable; | ||||
|  | ||||
| import static org.schabi.newpipe.database.stream.model.StreamStateEntity.JOIN_STREAM_ID; | ||||
| import static org.schabi.newpipe.database.stream.model.StreamStateEntity.STREAM_STATE_TABLE; | ||||
|   | ||||
| @@ -1,12 +1,6 @@ | ||||
| package org.schabi.newpipe.database.stream.model | ||||
|  | ||||
| import androidx.room.ColumnInfo | ||||
| import androidx.room.Entity | ||||
| import androidx.room.Ignore | ||||
| import androidx.room.Index | ||||
| import androidx.room.PrimaryKey | ||||
| import java.io.Serializable | ||||
| import java.time.OffsetDateTime | ||||
| import androidx.room.* | ||||
| import org.schabi.newpipe.database.stream.model.StreamEntity.Companion.STREAM_SERVICE_ID | ||||
| import org.schabi.newpipe.database.stream.model.StreamEntity.Companion.STREAM_TABLE | ||||
| import org.schabi.newpipe.database.stream.model.StreamEntity.Companion.STREAM_URL | ||||
| @@ -15,11 +9,14 @@ import org.schabi.newpipe.extractor.stream.StreamInfo | ||||
| import org.schabi.newpipe.extractor.stream.StreamInfoItem | ||||
| import org.schabi.newpipe.extractor.stream.StreamType | ||||
| import org.schabi.newpipe.player.playqueue.PlayQueueItem | ||||
| import java.io.Serializable | ||||
| import java.time.OffsetDateTime | ||||
|  | ||||
| @Entity(tableName = STREAM_TABLE, | ||||
|         indices = [ | ||||
|             Index(value = [STREAM_SERVICE_ID, STREAM_URL], unique = true) | ||||
|         ] | ||||
| @Entity( | ||||
|     tableName = STREAM_TABLE, | ||||
|     indices = [ | ||||
|         Index(value = [STREAM_SERVICE_ID, STREAM_URL], unique = true) | ||||
|     ] | ||||
| ) | ||||
| data class StreamEntity( | ||||
|     @PrimaryKey(autoGenerate = true) | ||||
| @@ -61,27 +58,27 @@ data class StreamEntity( | ||||
| ) : Serializable { | ||||
|     @Ignore | ||||
|     constructor(item: StreamInfoItem) : this( | ||||
|             serviceId = item.serviceId, url = item.url, title = item.name, | ||||
|             streamType = item.streamType, duration = item.duration, uploader = item.uploaderName, | ||||
|             thumbnailUrl = item.thumbnailUrl, viewCount = item.viewCount, | ||||
|             textualUploadDate = item.textualUploadDate, uploadDate = item.uploadDate?.offsetDateTime(), | ||||
|             isUploadDateApproximation = item.uploadDate?.isApproximation | ||||
|         serviceId = item.serviceId, url = item.url, title = item.name, | ||||
|         streamType = item.streamType, duration = item.duration, uploader = item.uploaderName, | ||||
|         thumbnailUrl = item.thumbnailUrl, viewCount = item.viewCount, | ||||
|         textualUploadDate = item.textualUploadDate, uploadDate = item.uploadDate?.offsetDateTime(), | ||||
|         isUploadDateApproximation = item.uploadDate?.isApproximation | ||||
|     ) | ||||
|  | ||||
|     @Ignore | ||||
|     constructor(info: StreamInfo) : this( | ||||
|             serviceId = info.serviceId, url = info.url, title = info.name, | ||||
|             streamType = info.streamType, duration = info.duration, uploader = info.uploaderName, | ||||
|             thumbnailUrl = info.thumbnailUrl, viewCount = info.viewCount, | ||||
|             textualUploadDate = info.textualUploadDate, uploadDate = info.uploadDate?.offsetDateTime(), | ||||
|             isUploadDateApproximation = info.uploadDate?.isApproximation | ||||
|         serviceId = info.serviceId, url = info.url, title = info.name, | ||||
|         streamType = info.streamType, duration = info.duration, uploader = info.uploaderName, | ||||
|         thumbnailUrl = info.thumbnailUrl, viewCount = info.viewCount, | ||||
|         textualUploadDate = info.textualUploadDate, uploadDate = info.uploadDate?.offsetDateTime(), | ||||
|         isUploadDateApproximation = info.uploadDate?.isApproximation | ||||
|     ) | ||||
|  | ||||
|     @Ignore | ||||
|     constructor(item: PlayQueueItem) : this( | ||||
|             serviceId = item.serviceId, url = item.url, title = item.title, | ||||
|             streamType = item.streamType, duration = item.duration, uploader = item.uploader, | ||||
|             thumbnailUrl = item.thumbnailUrl | ||||
|         serviceId = item.serviceId, url = item.url, title = item.title, | ||||
|         streamType = item.streamType, duration = item.duration, uploader = item.uploader, | ||||
|         thumbnailUrl = item.thumbnailUrl | ||||
|     ) | ||||
|  | ||||
|     fun toStreamInfoItem(): StreamInfoItem { | ||||
|   | ||||
| @@ -5,8 +5,8 @@ import androidx.room.Insert | ||||
| import androidx.room.OnConflictStrategy | ||||
| import androidx.room.Query | ||||
| import androidx.room.Transaction | ||||
| import io.reactivex.Flowable | ||||
| import io.reactivex.Maybe | ||||
| import io.reactivex.rxjava3.core.Flowable | ||||
| import io.reactivex.rxjava3.core.Maybe | ||||
| import org.schabi.newpipe.database.BasicDAO | ||||
|  | ||||
| @Dao | ||||
| @@ -20,16 +20,19 @@ abstract class SubscriptionDAO : BasicDAO<SubscriptionEntity> { | ||||
|     @Query("SELECT * FROM subscriptions ORDER BY name COLLATE NOCASE ASC") | ||||
|     abstract override fun getAll(): Flowable<List<SubscriptionEntity>> | ||||
|  | ||||
|     @Query(""" | ||||
|     @Query( | ||||
|         """ | ||||
|         SELECT * FROM subscriptions | ||||
|  | ||||
|         WHERE name LIKE '%' || :filter || '%' | ||||
|  | ||||
|         ORDER BY name COLLATE NOCASE ASC | ||||
|         """) | ||||
|         """ | ||||
|     ) | ||||
|     abstract fun getSubscriptionsFiltered(filter: String): Flowable<List<SubscriptionEntity>> | ||||
|  | ||||
|     @Query(""" | ||||
|     @Query( | ||||
|         """ | ||||
|         SELECT * FROM subscriptions s | ||||
|  | ||||
|         LEFT JOIN feed_group_subscription_join fgs | ||||
| @@ -38,12 +41,14 @@ abstract class SubscriptionDAO : BasicDAO<SubscriptionEntity> { | ||||
|         WHERE (fgs.subscription_id IS NULL OR fgs.group_id = :currentGroupId) | ||||
|  | ||||
|         ORDER BY name COLLATE NOCASE ASC | ||||
|         """) | ||||
|         """ | ||||
|     ) | ||||
|     abstract fun getSubscriptionsOnlyUngrouped( | ||||
|         currentGroupId: Long | ||||
|     ): Flowable<List<SubscriptionEntity>> | ||||
|  | ||||
|     @Query(""" | ||||
|     @Query( | ||||
|         """ | ||||
|         SELECT * FROM subscriptions s | ||||
|  | ||||
|         LEFT JOIN feed_group_subscription_join fgs | ||||
| @@ -53,7 +58,8 @@ abstract class SubscriptionDAO : BasicDAO<SubscriptionEntity> { | ||||
|         AND s.name LIKE '%' || :filter || '%' | ||||
|  | ||||
|         ORDER BY name COLLATE NOCASE ASC | ||||
|         """) | ||||
|         """ | ||||
|     ) | ||||
|     abstract fun getSubscriptionsOnlyUngroupedFiltered( | ||||
|         currentGroupId: Long, | ||||
|         filter: String | ||||
|   | ||||
| @@ -10,7 +10,6 @@ import android.net.Uri; | ||||
| import android.os.Bundle; | ||||
| import android.os.Environment; | ||||
| import android.os.IBinder; | ||||
| import androidx.preference.PreferenceManager; | ||||
| import android.util.Log; | ||||
| import android.util.SparseArray; | ||||
| import android.view.LayoutInflater; | ||||
| @@ -34,6 +33,7 @@ import androidx.appcompat.view.menu.ActionMenuItemView; | ||||
| import androidx.appcompat.widget.Toolbar; | ||||
| import androidx.documentfile.provider.DocumentFile; | ||||
| import androidx.fragment.app.DialogFragment; | ||||
| import androidx.preference.PreferenceManager; | ||||
|  | ||||
| import com.nononsenseapps.filepicker.Utils; | ||||
|  | ||||
| @@ -70,7 +70,7 @@ import java.util.Locale; | ||||
|  | ||||
| import icepick.Icepick; | ||||
| import icepick.State; | ||||
| import io.reactivex.disposables.CompositeDisposable; | ||||
| import io.reactivex.rxjava3.disposables.CompositeDisposable; | ||||
| import us.shandian.giga.get.MissionRecoveryInfo; | ||||
| import us.shandian.giga.io.StoredDirectoryHelper; | ||||
| import us.shandian.giga.io.StoredFileHelper; | ||||
|   | ||||
| @@ -13,7 +13,7 @@ import android.widget.Toast; | ||||
| import androidx.annotation.Nullable; | ||||
| import androidx.annotation.StringRes; | ||||
|  | ||||
| import com.jakewharton.rxbinding2.view.RxView; | ||||
| import com.jakewharton.rxbinding4.view.RxView; | ||||
|  | ||||
| import org.schabi.newpipe.BaseFragment; | ||||
| import org.schabi.newpipe.MainActivity; | ||||
| @@ -34,8 +34,8 @@ import java.util.concurrent.TimeUnit; | ||||
| import java.util.concurrent.atomic.AtomicBoolean; | ||||
|  | ||||
| import icepick.State; | ||||
| import io.reactivex.android.schedulers.AndroidSchedulers; | ||||
| import io.reactivex.disposables.Disposable; | ||||
| import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers; | ||||
| import io.reactivex.rxjava3.disposables.Disposable; | ||||
|  | ||||
| import static org.schabi.newpipe.util.AnimationUtils.animateView; | ||||
|  | ||||
|   | ||||
| @@ -15,9 +15,6 @@ import android.os.Build; | ||||
| import android.os.Bundle; | ||||
| import android.os.Handler; | ||||
| import android.os.Looper; | ||||
| import android.view.ViewTreeObserver; | ||||
| import androidx.core.text.HtmlCompat; | ||||
| import androidx.preference.PreferenceManager; | ||||
| import android.provider.Settings; | ||||
| import android.text.TextUtils; | ||||
| import android.text.util.Linkify; | ||||
| @@ -27,6 +24,7 @@ import android.view.LayoutInflater; | ||||
| import android.view.MotionEvent; | ||||
| import android.view.View; | ||||
| import android.view.ViewGroup; | ||||
| import android.view.ViewTreeObserver; | ||||
| import android.view.WindowManager; | ||||
| import android.view.animation.DecelerateInterpolator; | ||||
| import android.widget.FrameLayout; | ||||
| @@ -45,7 +43,9 @@ import androidx.appcompat.content.res.AppCompatResources; | ||||
| import androidx.appcompat.widget.Toolbar; | ||||
| import androidx.coordinatorlayout.widget.CoordinatorLayout; | ||||
| import androidx.core.content.ContextCompat; | ||||
| import androidx.core.text.HtmlCompat; | ||||
| import androidx.fragment.app.Fragment; | ||||
| import androidx.preference.PreferenceManager; | ||||
| import androidx.viewpager.widget.ViewPager; | ||||
|  | ||||
| import com.google.android.exoplayer2.ExoPlaybackException; | ||||
| @@ -116,11 +116,11 @@ import java.util.concurrent.TimeUnit; | ||||
| import icepick.State; | ||||
| import io.noties.markwon.Markwon; | ||||
| import io.noties.markwon.linkify.LinkifyPlugin; | ||||
| import io.reactivex.Single; | ||||
| import io.reactivex.android.schedulers.AndroidSchedulers; | ||||
| import io.reactivex.disposables.CompositeDisposable; | ||||
| import io.reactivex.disposables.Disposable; | ||||
| import io.reactivex.schedulers.Schedulers; | ||||
| import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers; | ||||
| import io.reactivex.rxjava3.core.Single; | ||||
| import io.reactivex.rxjava3.disposables.CompositeDisposable; | ||||
| import io.reactivex.rxjava3.disposables.Disposable; | ||||
| import io.reactivex.rxjava3.schedulers.Schedulers; | ||||
|  | ||||
| import static org.schabi.newpipe.extractor.StreamingService.ServiceInfo.MediaCapability.COMMENTS; | ||||
| import static org.schabi.newpipe.extractor.stream.StreamExtractor.NO_AGE_LIMIT; | ||||
|   | ||||
| @@ -16,10 +16,10 @@ import org.schabi.newpipe.views.NewPipeRecyclerView; | ||||
| import java.util.Queue; | ||||
|  | ||||
| import icepick.State; | ||||
| import io.reactivex.Single; | ||||
| import io.reactivex.android.schedulers.AndroidSchedulers; | ||||
| import io.reactivex.disposables.Disposable; | ||||
| import io.reactivex.schedulers.Schedulers; | ||||
| import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers; | ||||
| import io.reactivex.rxjava3.core.Single; | ||||
| import io.reactivex.rxjava3.disposables.Disposable; | ||||
| import io.reactivex.rxjava3.schedulers.Schedulers; | ||||
|  | ||||
| public abstract class BaseListInfoFragment<I extends ListInfo> | ||||
|         extends BaseListFragment<I, ListExtractor.InfoItemsPage> { | ||||
|   | ||||
| @@ -24,7 +24,7 @@ import androidx.appcompat.app.ActionBar; | ||||
| import androidx.appcompat.app.AppCompatActivity; | ||||
| import androidx.core.content.ContextCompat; | ||||
|  | ||||
| import com.jakewharton.rxbinding2.view.RxView; | ||||
| import com.jakewharton.rxbinding4.view.RxView; | ||||
|  | ||||
| import org.schabi.newpipe.R; | ||||
| import org.schabi.newpipe.database.subscription.SubscriptionEntity; | ||||
| @@ -53,15 +53,15 @@ import java.util.ArrayList; | ||||
| import java.util.List; | ||||
| import java.util.concurrent.TimeUnit; | ||||
|  | ||||
| import io.reactivex.Observable; | ||||
| import io.reactivex.Single; | ||||
| import io.reactivex.android.schedulers.AndroidSchedulers; | ||||
| import io.reactivex.disposables.CompositeDisposable; | ||||
| import io.reactivex.disposables.Disposable; | ||||
| import io.reactivex.functions.Action; | ||||
| import io.reactivex.functions.Consumer; | ||||
| import io.reactivex.functions.Function; | ||||
| import io.reactivex.schedulers.Schedulers; | ||||
| import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers; | ||||
| import io.reactivex.rxjava3.core.Observable; | ||||
| import io.reactivex.rxjava3.core.Single; | ||||
| import io.reactivex.rxjava3.disposables.CompositeDisposable; | ||||
| import io.reactivex.rxjava3.disposables.Disposable; | ||||
| import io.reactivex.rxjava3.functions.Action; | ||||
| import io.reactivex.rxjava3.functions.Consumer; | ||||
| import io.reactivex.rxjava3.functions.Function; | ||||
| import io.reactivex.rxjava3.schedulers.Schedulers; | ||||
|  | ||||
| import static org.schabi.newpipe.util.AnimationUtils.animateBackgroundColor; | ||||
| import static org.schabi.newpipe.util.AnimationUtils.animateTextColor; | ||||
|   | ||||
| @@ -20,8 +20,8 @@ import org.schabi.newpipe.report.UserAction; | ||||
| import org.schabi.newpipe.util.AnimationUtils; | ||||
| import org.schabi.newpipe.util.ExtractorHelper; | ||||
|  | ||||
| import io.reactivex.Single; | ||||
| import io.reactivex.disposables.CompositeDisposable; | ||||
| import io.reactivex.rxjava3.core.Single; | ||||
| import io.reactivex.rxjava3.disposables.CompositeDisposable; | ||||
|  | ||||
| public class CommentsFragment extends BaseListInfoFragment<CommentsInfo> { | ||||
|     private final CompositeDisposable disposables = new CompositeDisposable(); | ||||
|   | ||||
| @@ -26,7 +26,7 @@ import org.schabi.newpipe.util.KioskTranslator; | ||||
| import org.schabi.newpipe.util.Localization; | ||||
|  | ||||
| import icepick.State; | ||||
| import io.reactivex.Single; | ||||
| import io.reactivex.rxjava3.core.Single; | ||||
|  | ||||
| import static org.schabi.newpipe.util.AnimationUtils.animateView; | ||||
|  | ||||
|   | ||||
| @@ -51,12 +51,11 @@ import java.util.Arrays; | ||||
| import java.util.List; | ||||
| import java.util.concurrent.atomic.AtomicBoolean; | ||||
|  | ||||
| import io.reactivex.Flowable; | ||||
| import io.reactivex.Single; | ||||
| import io.reactivex.android.schedulers.AndroidSchedulers; | ||||
| import io.reactivex.disposables.CompositeDisposable; | ||||
| import io.reactivex.disposables.Disposable; | ||||
| import io.reactivex.disposables.Disposables; | ||||
| import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers; | ||||
| import io.reactivex.rxjava3.core.Flowable; | ||||
| import io.reactivex.rxjava3.core.Single; | ||||
| import io.reactivex.rxjava3.disposables.CompositeDisposable; | ||||
| import io.reactivex.rxjava3.disposables.Disposable; | ||||
|  | ||||
| import static org.schabi.newpipe.util.AnimationUtils.animateView; | ||||
|  | ||||
| @@ -460,7 +459,7 @@ public class PlaylistFragment extends BaseListInfoFragment<PlaylistInfo> { | ||||
|                     .doFinally(() -> playlistEntity = null) | ||||
|                     .subscribe(ignored -> { /* Do nothing */ }, this::onError); | ||||
|         } else { | ||||
|             action = Disposables.empty(); | ||||
|             action = Disposable.empty(); | ||||
|         } | ||||
|  | ||||
|         disposables.add(action); | ||||
|   | ||||
| @@ -68,13 +68,13 @@ import java.util.Queue; | ||||
| import java.util.concurrent.TimeUnit; | ||||
|  | ||||
| import icepick.State; | ||||
| import io.reactivex.Flowable; | ||||
| import io.reactivex.Observable; | ||||
| import io.reactivex.android.schedulers.AndroidSchedulers; | ||||
| import io.reactivex.disposables.CompositeDisposable; | ||||
| import io.reactivex.disposables.Disposable; | ||||
| import io.reactivex.schedulers.Schedulers; | ||||
| import io.reactivex.subjects.PublishSubject; | ||||
| import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers; | ||||
| import io.reactivex.rxjava3.core.Flowable; | ||||
| import io.reactivex.rxjava3.core.Observable; | ||||
| import io.reactivex.rxjava3.disposables.CompositeDisposable; | ||||
| import io.reactivex.rxjava3.disposables.Disposable; | ||||
| import io.reactivex.rxjava3.schedulers.Schedulers; | ||||
| import io.reactivex.rxjava3.subjects.PublishSubject; | ||||
|  | ||||
| import static androidx.recyclerview.widget.ItemTouchHelper.Callback.makeMovementFlags; | ||||
| import static java.util.Arrays.asList; | ||||
| @@ -709,7 +709,7 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I | ||||
|  | ||||
|         final Observable<String> observable = suggestionPublisher | ||||
|                 .debounce(SUGGESTIONS_DEBOUNCE, TimeUnit.MILLISECONDS) | ||||
|                 .startWith(searchString != null | ||||
|                 .startWithItem(searchString != null | ||||
|                         ? searchString | ||||
|                         : "") | ||||
|                 .filter(ss -> isSuggestionsEnabled); | ||||
|   | ||||
| @@ -3,7 +3,6 @@ package org.schabi.newpipe.fragments.list.videos; | ||||
| import android.content.Context; | ||||
| import android.content.SharedPreferences; | ||||
| import android.os.Bundle; | ||||
| import androidx.preference.PreferenceManager; | ||||
| import android.view.LayoutInflater; | ||||
| import android.view.Menu; | ||||
| import android.view.MenuInflater; | ||||
| @@ -13,6 +12,7 @@ import android.widget.Switch; | ||||
|  | ||||
| import androidx.annotation.NonNull; | ||||
| import androidx.annotation.Nullable; | ||||
| import androidx.preference.PreferenceManager; | ||||
|  | ||||
| import org.schabi.newpipe.R; | ||||
| import org.schabi.newpipe.extractor.ListExtractor; | ||||
| @@ -25,8 +25,8 @@ import org.schabi.newpipe.util.RelatedStreamInfo; | ||||
|  | ||||
| import java.io.Serializable; | ||||
|  | ||||
| import io.reactivex.Single; | ||||
| import io.reactivex.disposables.CompositeDisposable; | ||||
| import io.reactivex.rxjava3.core.Single; | ||||
| import io.reactivex.rxjava3.disposables.CompositeDisposable; | ||||
|  | ||||
| public class RelatedVideosFragment extends BaseListInfoFragment<RelatedStreamInfo> | ||||
|         implements SharedPreferences.OnSharedPreferenceChangeListener { | ||||
|   | ||||
| @@ -33,11 +33,11 @@ import org.schabi.newpipe.util.OnClickGesture; | ||||
| import java.util.List; | ||||
|  | ||||
| import icepick.State; | ||||
| import io.reactivex.Flowable; | ||||
| import io.reactivex.Single; | ||||
| import io.reactivex.android.schedulers.AndroidSchedulers; | ||||
| import io.reactivex.disposables.CompositeDisposable; | ||||
| import io.reactivex.disposables.Disposable; | ||||
| import io.reactivex.rxjava3.core.Flowable; | ||||
| import io.reactivex.rxjava3.core.Single; | ||||
| import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers; | ||||
| import io.reactivex.rxjava3.disposables.CompositeDisposable; | ||||
| import io.reactivex.rxjava3.disposables.Disposable; | ||||
|  | ||||
| public final class BookmarkFragment extends BaseLocalListFragment<List<PlaylistLocalItem>, Void> { | ||||
|     @State | ||||
|   | ||||
| @@ -28,9 +28,9 @@ import java.util.ArrayList; | ||||
| import java.util.Collections; | ||||
| import java.util.List; | ||||
|  | ||||
| import io.reactivex.android.schedulers.AndroidSchedulers; | ||||
| import io.reactivex.disposables.CompositeDisposable; | ||||
| import io.reactivex.disposables.Disposable; | ||||
| import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers; | ||||
| import io.reactivex.rxjava3.disposables.CompositeDisposable; | ||||
| import io.reactivex.rxjava3.disposables.Disposable; | ||||
|  | ||||
| public final class PlaylistAppendDialog extends PlaylistDialog { | ||||
|     private static final String TAG = PlaylistAppendDialog.class.getCanonicalName(); | ||||
| @@ -98,7 +98,7 @@ public final class PlaylistAppendDialog extends PlaylistDialog { | ||||
|         super.onViewCreated(view, savedInstanceState); | ||||
|  | ||||
|         final LocalPlaylistManager playlistManager = | ||||
|                 new LocalPlaylistManager(NewPipeDatabase.getInstance(getContext())); | ||||
|                 new LocalPlaylistManager(NewPipeDatabase.getInstance(requireContext())); | ||||
|  | ||||
|         playlistAdapter = new LocalItemListAdapter(getActivity()); | ||||
|         playlistAdapter.setSelectedListener(new OnClickGesture<LocalItem>() { | ||||
| @@ -113,7 +113,7 @@ public final class PlaylistAppendDialog extends PlaylistDialog { | ||||
|         }); | ||||
|  | ||||
|         playlistRecyclerView = view.findViewById(R.id.playlist_list); | ||||
|         playlistRecyclerView.setLayoutManager(new LinearLayoutManager(getContext())); | ||||
|         playlistRecyclerView.setLayoutManager(new LinearLayoutManager(requireContext())); | ||||
|         playlistRecyclerView.setAdapter(playlistAdapter); | ||||
|  | ||||
|         final View newPlaylistButton = view.findViewById(R.id.newPlaylist); | ||||
| @@ -146,12 +146,12 @@ public final class PlaylistAppendDialog extends PlaylistDialog { | ||||
|     //////////////////////////////////////////////////////////////////////////*/ | ||||
|  | ||||
|     public void openCreatePlaylistDialog() { | ||||
|         if (getStreams() == null || getFragmentManager() == null) { | ||||
|         if (getStreams() == null || !isAdded()) { | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         PlaylistCreationDialog.newInstance(getStreams()).show(getFragmentManager(), TAG); | ||||
|         getDialog().dismiss(); | ||||
|         PlaylistCreationDialog.newInstance(getStreams()).show(getParentFragmentManager(), TAG); | ||||
|         requireDialog().dismiss(); | ||||
|     } | ||||
|  | ||||
|     private void onPlaylistsReceived(@NonNull final List<PlaylistMetadataEntry> playlists) { | ||||
| @@ -183,6 +183,6 @@ public final class PlaylistAppendDialog extends PlaylistDialog { | ||||
|                 .observeOn(AndroidSchedulers.mainThread()) | ||||
|                 .subscribe(ignored -> successToast.show())); | ||||
|  | ||||
|         getDialog().dismiss(); | ||||
|         requireDialog().dismiss(); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -17,7 +17,7 @@ import org.schabi.newpipe.local.playlist.LocalPlaylistManager; | ||||
|  | ||||
| import java.util.List; | ||||
|  | ||||
| import io.reactivex.android.schedulers.AndroidSchedulers; | ||||
| import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers; | ||||
|  | ||||
| public final class PlaylistCreationDialog extends PlaylistDialog { | ||||
|     public static PlaylistCreationDialog newInstance(final List<StreamEntity> streams) { | ||||
|   | ||||
| @@ -2,11 +2,11 @@ package org.schabi.newpipe.local.feed | ||||
|  | ||||
| import android.content.Context | ||||
| import android.util.Log | ||||
| import io.reactivex.Completable | ||||
| import io.reactivex.Flowable | ||||
| import io.reactivex.Maybe | ||||
| import io.reactivex.android.schedulers.AndroidSchedulers | ||||
| import io.reactivex.schedulers.Schedulers | ||||
| import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers | ||||
| import io.reactivex.rxjava3.core.Completable | ||||
| import io.reactivex.rxjava3.core.Flowable | ||||
| import io.reactivex.rxjava3.core.Maybe | ||||
| import io.reactivex.rxjava3.schedulers.Schedulers | ||||
| import java.time.LocalDate | ||||
| import java.time.OffsetDateTime | ||||
| import java.time.ZoneOffset | ||||
| @@ -44,9 +44,9 @@ class FeedDatabaseManager(context: Context) { | ||||
|             else -> feedTable.getAllStreamsFromGroup(groupId) | ||||
|         } | ||||
|  | ||||
|         return streams.map<List<StreamInfoItem>> { | ||||
|         return streams.map { | ||||
|             val items = ArrayList<StreamInfoItem>(it.size) | ||||
|             it.mapTo(items) { it.toStreamInfoItem() } | ||||
|             it.mapTo(items) { stream -> stream.toStreamInfoItem() } | ||||
|             return@map items | ||||
|         } | ||||
|     } | ||||
| @@ -61,10 +61,10 @@ class FeedDatabaseManager(context: Context) { | ||||
|     } | ||||
|  | ||||
|     fun outdatedSubscriptionsForGroup(groupId: Long = FeedGroupEntity.GROUP_ALL_ID, outdatedThreshold: OffsetDateTime) = | ||||
|             feedTable.getAllOutdatedForGroup(groupId, outdatedThreshold) | ||||
|         feedTable.getAllOutdatedForGroup(groupId, outdatedThreshold) | ||||
|  | ||||
|     fun markAsOutdated(subscriptionId: Long) = feedTable | ||||
|             .setLastUpdatedForSubscription(FeedLastUpdatedEntity(subscriptionId, null)) | ||||
|         .setLastUpdatedForSubscription(FeedLastUpdatedEntity(subscriptionId, null)) | ||||
|  | ||||
|     fun upsertAll( | ||||
|         subscriptionId: Long, | ||||
| @@ -113,38 +113,38 @@ class FeedDatabaseManager(context: Context) { | ||||
|  | ||||
|     fun subscriptionIdsForGroup(groupId: Long): Flowable<List<Long>> { | ||||
|         return feedGroupTable.getSubscriptionIdsFor(groupId) | ||||
|                 .subscribeOn(Schedulers.io()) | ||||
|                 .observeOn(AndroidSchedulers.mainThread()) | ||||
|             .subscribeOn(Schedulers.io()) | ||||
|             .observeOn(AndroidSchedulers.mainThread()) | ||||
|     } | ||||
|  | ||||
|     fun updateSubscriptionsForGroup(groupId: Long, subscriptionIds: List<Long>): Completable { | ||||
|         return Completable.fromCallable { feedGroupTable.updateSubscriptionsForGroup(groupId, subscriptionIds) } | ||||
|                 .subscribeOn(Schedulers.io()) | ||||
|                 .observeOn(AndroidSchedulers.mainThread()) | ||||
|             .subscribeOn(Schedulers.io()) | ||||
|             .observeOn(AndroidSchedulers.mainThread()) | ||||
|     } | ||||
|  | ||||
|     fun createGroup(name: String, icon: FeedGroupIcon): Maybe<Long> { | ||||
|         return Maybe.fromCallable { feedGroupTable.insert(FeedGroupEntity(0, name, icon)) } | ||||
|                 .subscribeOn(Schedulers.io()) | ||||
|                 .observeOn(AndroidSchedulers.mainThread()) | ||||
|             .subscribeOn(Schedulers.io()) | ||||
|             .observeOn(AndroidSchedulers.mainThread()) | ||||
|     } | ||||
|  | ||||
|     fun getGroup(groupId: Long): Maybe<FeedGroupEntity> { | ||||
|         return feedGroupTable.getGroup(groupId) | ||||
|                 .subscribeOn(Schedulers.io()) | ||||
|                 .observeOn(AndroidSchedulers.mainThread()) | ||||
|             .subscribeOn(Schedulers.io()) | ||||
|             .observeOn(AndroidSchedulers.mainThread()) | ||||
|     } | ||||
|  | ||||
|     fun updateGroup(feedGroupEntity: FeedGroupEntity): Completable { | ||||
|         return Completable.fromCallable { feedGroupTable.update(feedGroupEntity) } | ||||
|                 .subscribeOn(Schedulers.io()) | ||||
|                 .observeOn(AndroidSchedulers.mainThread()) | ||||
|             .subscribeOn(Schedulers.io()) | ||||
|             .observeOn(AndroidSchedulers.mainThread()) | ||||
|     } | ||||
|  | ||||
|     fun deleteGroup(groupId: Long): Completable { | ||||
|         return Completable.fromCallable { feedGroupTable.delete(groupId) } | ||||
|                 .subscribeOn(Schedulers.io()) | ||||
|                 .observeOn(AndroidSchedulers.mainThread()) | ||||
|             .subscribeOn(Schedulers.io()) | ||||
|             .observeOn(AndroidSchedulers.mainThread()) | ||||
|     } | ||||
|  | ||||
|     fun updateGroupsOrder(groupIdList: List<Long>): Completable { | ||||
| @@ -152,8 +152,8 @@ class FeedDatabaseManager(context: Context) { | ||||
|         val orderMap = groupIdList.associateBy({ it }, { index++ }) | ||||
|  | ||||
|         return Completable.fromCallable { feedGroupTable.updateOrder(orderMap) } | ||||
|                 .subscribeOn(Schedulers.io()) | ||||
|                 .observeOn(AndroidSchedulers.mainThread()) | ||||
|             .subscribeOn(Schedulers.io()) | ||||
|             .observeOn(AndroidSchedulers.mainThread()) | ||||
|     } | ||||
|  | ||||
|     fun oldestSubscriptionUpdate(groupId: Long): Flowable<List<OffsetDateTime>> { | ||||
|   | ||||
| @@ -37,7 +37,6 @@ import androidx.lifecycle.ViewModelProvider | ||||
| import androidx.preference.PreferenceManager | ||||
| import androidx.swiperefreshlayout.widget.SwipeRefreshLayout | ||||
| import icepick.State | ||||
| import java.util.Calendar | ||||
| import kotlinx.android.synthetic.main.error_retry.error_button_retry | ||||
| import kotlinx.android.synthetic.main.error_retry.error_message_view | ||||
| import kotlinx.android.synthetic.main.fragment_feed.empty_state_view | ||||
| @@ -55,6 +54,7 @@ import org.schabi.newpipe.local.feed.service.FeedLoadService | ||||
| import org.schabi.newpipe.report.UserAction | ||||
| import org.schabi.newpipe.util.AnimationUtils.animateView | ||||
| import org.schabi.newpipe.util.Localization | ||||
| import java.util.Calendar | ||||
|  | ||||
| class FeedFragment : BaseListFragment<FeedState, Unit>() { | ||||
|     private lateinit var viewModel: FeedViewModel | ||||
| @@ -76,7 +76,7 @@ class FeedFragment : BaseListFragment<FeedState, Unit>() { | ||||
|         super.onCreate(savedInstanceState) | ||||
|  | ||||
|         groupId = arguments?.getLong(KEY_GROUP_ID, FeedGroupEntity.GROUP_ALL_ID) | ||||
|                 ?: FeedGroupEntity.GROUP_ALL_ID | ||||
|             ?: FeedGroupEntity.GROUP_ALL_ID | ||||
|         groupName = arguments?.getString(KEY_GROUP_NAME) ?: "" | ||||
|     } | ||||
|  | ||||
| @@ -144,15 +144,15 @@ class FeedFragment : BaseListFragment<FeedState, Unit>() { | ||||
|             } | ||||
|  | ||||
|             AlertDialog.Builder(requireContext()) | ||||
|                     .setMessage(R.string.feed_use_dedicated_fetch_method_help_text) | ||||
|                     .setNeutralButton(enableDisableButtonText) { _, _ -> | ||||
|                         sharedPreferences.edit { | ||||
|                             putBoolean(getString(R.string.feed_use_dedicated_fetch_method_key), !usingDedicatedMethod) | ||||
|                         } | ||||
|                 .setMessage(R.string.feed_use_dedicated_fetch_method_help_text) | ||||
|                 .setNeutralButton(enableDisableButtonText) { _, _ -> | ||||
|                     sharedPreferences.edit { | ||||
|                         putBoolean(getString(R.string.feed_use_dedicated_fetch_method_key), !usingDedicatedMethod) | ||||
|                     } | ||||
|                     .setPositiveButton(resources.getString(R.string.finish), null) | ||||
|                     .create() | ||||
|                     .show() | ||||
|                 } | ||||
|                 .setPositiveButton(resources.getString(R.string.finish), null) | ||||
|                 .create() | ||||
|                 .show() | ||||
|             return true | ||||
|         } | ||||
|  | ||||
| @@ -234,7 +234,7 @@ class FeedFragment : BaseListFragment<FeedState, Unit>() { | ||||
|         showLoading() | ||||
|  | ||||
|         val isIndeterminate = progressState.currentProgress == -1 && | ||||
|                 progressState.maxProgress == -1 | ||||
|             progressState.maxProgress == -1 | ||||
|  | ||||
|         if (!isIndeterminate) { | ||||
|             loading_progress_text.text = "${progressState.currentProgress}/${progressState.maxProgress}" | ||||
| @@ -245,7 +245,7 @@ class FeedFragment : BaseListFragment<FeedState, Unit>() { | ||||
|         } | ||||
|  | ||||
|         loading_progress_bar.isIndeterminate = isIndeterminate || | ||||
|                 (progressState.maxProgress > 0 && progressState.currentProgress == 0) | ||||
|             (progressState.maxProgress > 0 && progressState.currentProgress == 0) | ||||
|         loading_progress_bar.progress = progressState.currentProgress | ||||
|  | ||||
|         loading_progress_bar.max = progressState.maxProgress | ||||
| @@ -267,8 +267,10 @@ class FeedFragment : BaseListFragment<FeedState, Unit>() { | ||||
|         } | ||||
|  | ||||
|         if (loadedState.itemsErrors.isNotEmpty()) { | ||||
|             showSnackBarError(loadedState.itemsErrors, UserAction.REQUESTED_FEED, | ||||
|                     "none", "Loading feed", R.string.general_error) | ||||
|             showSnackBarError( | ||||
|                 loadedState.itemsErrors, UserAction.REQUESTED_FEED, | ||||
|                 "none", "Loading feed", R.string.general_error | ||||
|             ) | ||||
|         } | ||||
|  | ||||
|         if (loadedState.items.isEmpty()) { | ||||
| @@ -311,9 +313,11 @@ class FeedFragment : BaseListFragment<FeedState, Unit>() { | ||||
|     override fun hasMoreItems() = false | ||||
|  | ||||
|     private fun triggerUpdate() { | ||||
|         getActivity()?.startService(Intent(requireContext(), FeedLoadService::class.java).apply { | ||||
|             putExtra(FeedLoadService.EXTRA_GROUP_ID, groupId) | ||||
|         }) | ||||
|         getActivity()?.startService( | ||||
|             Intent(requireContext(), FeedLoadService::class.java).apply { | ||||
|                 putExtra(FeedLoadService.EXTRA_GROUP_ID, groupId) | ||||
|             } | ||||
|         ) | ||||
|         listState = null | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -1,8 +1,8 @@ | ||||
| package org.schabi.newpipe.local.feed | ||||
|  | ||||
| import androidx.annotation.StringRes | ||||
| import java.util.Calendar | ||||
| import org.schabi.newpipe.extractor.stream.StreamInfoItem | ||||
| import java.util.Calendar | ||||
|  | ||||
| sealed class FeedState { | ||||
|     data class ProgressState( | ||||
|   | ||||
| @@ -5,21 +5,18 @@ import androidx.lifecycle.LiveData | ||||
| import androidx.lifecycle.MutableLiveData | ||||
| import androidx.lifecycle.ViewModel | ||||
| import androidx.lifecycle.ViewModelProvider | ||||
| import io.reactivex.Flowable | ||||
| import io.reactivex.android.schedulers.AndroidSchedulers | ||||
| import io.reactivex.functions.Function4 | ||||
| import io.reactivex.schedulers.Schedulers | ||||
| import java.time.OffsetDateTime | ||||
| import java.util.concurrent.TimeUnit | ||||
| import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers | ||||
| import io.reactivex.rxjava3.core.Flowable | ||||
| import io.reactivex.rxjava3.functions.Function4 | ||||
| import io.reactivex.rxjava3.schedulers.Schedulers | ||||
| import org.schabi.newpipe.database.feed.model.FeedGroupEntity | ||||
| import org.schabi.newpipe.extractor.stream.StreamInfoItem | ||||
| import org.schabi.newpipe.ktx.toCalendar | ||||
| import org.schabi.newpipe.local.feed.service.FeedEventManager | ||||
| import org.schabi.newpipe.local.feed.service.FeedEventManager.Event.ErrorResultEvent | ||||
| import org.schabi.newpipe.local.feed.service.FeedEventManager.Event.IdleEvent | ||||
| import org.schabi.newpipe.local.feed.service.FeedEventManager.Event.ProgressEvent | ||||
| import org.schabi.newpipe.local.feed.service.FeedEventManager.Event.SuccessResultEvent | ||||
| import org.schabi.newpipe.local.feed.service.FeedEventManager.Event.* | ||||
| import org.schabi.newpipe.util.DEFAULT_THROTTLE_TIMEOUT | ||||
| import java.time.OffsetDateTime | ||||
| import java.util.concurrent.TimeUnit | ||||
|  | ||||
| class FeedViewModel(applicationContext: Context, val groupId: Long = FeedGroupEntity.GROUP_ALL_ID) : ViewModel() { | ||||
|     class Factory(val context: Context, val groupId: Long = FeedGroupEntity.GROUP_ALL_ID) : ViewModelProvider.Factory { | ||||
| @@ -35,34 +32,34 @@ class FeedViewModel(applicationContext: Context, val groupId: Long = FeedGroupEn | ||||
|     val stateLiveData: LiveData<FeedState> = mutableStateLiveData | ||||
|  | ||||
|     private var combineDisposable = Flowable | ||||
|             .combineLatest( | ||||
|                     FeedEventManager.events(), | ||||
|                     feedDatabaseManager.asStreamItems(groupId), | ||||
|                     feedDatabaseManager.notLoadedCount(groupId), | ||||
|                     feedDatabaseManager.oldestSubscriptionUpdate(groupId), | ||||
|         .combineLatest( | ||||
|             FeedEventManager.events(), | ||||
|             feedDatabaseManager.asStreamItems(groupId), | ||||
|             feedDatabaseManager.notLoadedCount(groupId), | ||||
|             feedDatabaseManager.oldestSubscriptionUpdate(groupId), | ||||
|                 Function4 { t1: FeedEventManager.Event, t2: List<StreamInfoItem>, t3: Long, t4: List<OffsetDateTime> -> | ||||
|                     return@Function4 CombineResultHolder(t1, t2, t3, t4.firstOrNull()) | ||||
|                 } | ||||
|         ) | ||||
|         .throttleLatest(DEFAULT_THROTTLE_TIMEOUT, TimeUnit.MILLISECONDS) | ||||
|         .subscribeOn(Schedulers.io()) | ||||
|         .observeOn(AndroidSchedulers.mainThread()) | ||||
|         .subscribe { (event, listFromDB, notLoadedCount, oldestUpdate) -> | ||||
|             val oldestUpdateCalendar = oldestUpdate?.toCalendar() | ||||
|  | ||||
|                     Function4 { t1: FeedEventManager.Event, t2: List<StreamInfoItem>, t3: Long, t4: List<OffsetDateTime> -> | ||||
|                         return@Function4 CombineResultHolder(t1, t2, t3, t4.firstOrNull()) | ||||
|                     } | ||||
|             ) | ||||
|             .throttleLatest(DEFAULT_THROTTLE_TIMEOUT, TimeUnit.MILLISECONDS) | ||||
|             .subscribeOn(Schedulers.io()) | ||||
|             .observeOn(AndroidSchedulers.mainThread()) | ||||
|             .subscribe { (event, listFromDB, notLoadedCount, oldestUpdate) -> | ||||
|  | ||||
|                 val oldestUpdateCalendar = oldestUpdate?.toCalendar() | ||||
|  | ||||
|                 mutableStateLiveData.postValue(when (event) { | ||||
|             mutableStateLiveData.postValue( | ||||
|                 when (event) { | ||||
|                     is IdleEvent -> FeedState.LoadedState(listFromDB, oldestUpdateCalendar, notLoadedCount) | ||||
|                     is ProgressEvent -> FeedState.ProgressState(event.currentProgress, event.maxProgress, event.progressMessage) | ||||
|                     is SuccessResultEvent -> FeedState.LoadedState(listFromDB, oldestUpdateCalendar, notLoadedCount, event.itemsErrors) | ||||
|                     is ErrorResultEvent -> FeedState.ErrorState(event.error) | ||||
|                 }) | ||||
|  | ||||
|                 if (event is ErrorResultEvent || event is SuccessResultEvent) { | ||||
|                     FeedEventManager.reset() | ||||
|                 } | ||||
|             ) | ||||
|  | ||||
|             if (event is ErrorResultEvent || event is SuccessResultEvent) { | ||||
|                 FeedEventManager.reset() | ||||
|             } | ||||
|         } | ||||
|  | ||||
|     override fun onCleared() { | ||||
|         super.onCleared() | ||||
|   | ||||
| @@ -1,15 +1,15 @@ | ||||
| package org.schabi.newpipe.local.feed.service | ||||
|  | ||||
| import androidx.annotation.StringRes | ||||
| import io.reactivex.Flowable | ||||
| import io.reactivex.processors.BehaviorProcessor | ||||
| import java.util.concurrent.atomic.AtomicBoolean | ||||
| import io.reactivex.rxjava3.core.Flowable | ||||
| import io.reactivex.rxjava3.processors.BehaviorProcessor | ||||
| import org.schabi.newpipe.local.feed.service.FeedEventManager.Event.IdleEvent | ||||
| import java.util.concurrent.atomic.AtomicBoolean | ||||
|  | ||||
| object FeedEventManager { | ||||
|     private var processor: BehaviorProcessor<Event> = BehaviorProcessor.create() | ||||
|     private var ignoreUpstream = AtomicBoolean() | ||||
|     private var eventsFlowable = processor.startWith(IdleEvent) | ||||
|     private var eventsFlowable = processor.startWithItem(IdleEvent) | ||||
|  | ||||
|     fun postEvent(event: Event) { | ||||
|         processor.onNext(event) | ||||
|   | ||||
| @@ -31,21 +31,15 @@ import android.util.Log | ||||
| import androidx.core.app.NotificationCompat | ||||
| import androidx.core.app.NotificationManagerCompat | ||||
| import androidx.preference.PreferenceManager | ||||
| import io.reactivex.Flowable | ||||
| import io.reactivex.Notification | ||||
| import io.reactivex.Single | ||||
| import io.reactivex.android.schedulers.AndroidSchedulers | ||||
| import io.reactivex.disposables.CompositeDisposable | ||||
| import io.reactivex.functions.Consumer | ||||
| import io.reactivex.functions.Function | ||||
| import io.reactivex.processors.PublishProcessor | ||||
| import io.reactivex.schedulers.Schedulers | ||||
| import java.io.IOException | ||||
| import java.time.OffsetDateTime | ||||
| import java.time.ZoneOffset | ||||
| import java.util.concurrent.TimeUnit | ||||
| import java.util.concurrent.atomic.AtomicBoolean | ||||
| import java.util.concurrent.atomic.AtomicInteger | ||||
| import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers | ||||
| import io.reactivex.rxjava3.core.Flowable | ||||
| import io.reactivex.rxjava3.core.Notification | ||||
| import io.reactivex.rxjava3.core.Single | ||||
| import io.reactivex.rxjava3.disposables.CompositeDisposable | ||||
| import io.reactivex.rxjava3.functions.Consumer | ||||
| import io.reactivex.rxjava3.functions.Function | ||||
| import io.reactivex.rxjava3.processors.PublishProcessor | ||||
| import io.reactivex.rxjava3.schedulers.Schedulers | ||||
| import org.reactivestreams.Subscriber | ||||
| import org.reactivestreams.Subscription | ||||
| import org.schabi.newpipe.MainActivity.DEBUG | ||||
| @@ -55,14 +49,17 @@ import org.schabi.newpipe.extractor.ListInfo | ||||
| import org.schabi.newpipe.extractor.exceptions.ReCaptchaException | ||||
| import org.schabi.newpipe.extractor.stream.StreamInfoItem | ||||
| import org.schabi.newpipe.local.feed.FeedDatabaseManager | ||||
| import org.schabi.newpipe.local.feed.service.FeedEventManager.Event.ErrorResultEvent | ||||
| import org.schabi.newpipe.local.feed.service.FeedEventManager.Event.IdleEvent | ||||
| import org.schabi.newpipe.local.feed.service.FeedEventManager.Event.ProgressEvent | ||||
| import org.schabi.newpipe.local.feed.service.FeedEventManager.Event.SuccessResultEvent | ||||
| import org.schabi.newpipe.local.feed.service.FeedEventManager.Event.* | ||||
| import org.schabi.newpipe.local.feed.service.FeedEventManager.postEvent | ||||
| import org.schabi.newpipe.local.subscription.SubscriptionManager | ||||
| import org.schabi.newpipe.util.ExceptionUtils | ||||
| import org.schabi.newpipe.util.ExtractorHelper | ||||
| import java.io.IOException | ||||
| import java.time.OffsetDateTime | ||||
| import java.time.ZoneOffset | ||||
| import java.util.concurrent.TimeUnit | ||||
| import java.util.concurrent.atomic.AtomicBoolean | ||||
| import java.util.concurrent.atomic.AtomicInteger | ||||
|  | ||||
| class FeedLoadService : Service() { | ||||
|     companion object { | ||||
| @@ -109,8 +106,11 @@ class FeedLoadService : Service() { | ||||
|  | ||||
|     override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { | ||||
|         if (DEBUG) { | ||||
|             Log.d(TAG, "onStartCommand() called with: intent = [" + intent + "]," + | ||||
|                     " flags = [" + flags + "], startId = [" + startId + "]") | ||||
|             Log.d( | ||||
|                 TAG, | ||||
|                 "onStartCommand() called with: intent = [" + intent + "]," + | ||||
|                     " flags = [" + flags + "], startId = [" + startId + "]" | ||||
|             ) | ||||
|         } | ||||
|  | ||||
|         if (intent == null || loadingSubscription != null) { | ||||
| @@ -123,10 +123,10 @@ class FeedLoadService : Service() { | ||||
|  | ||||
|         val groupId = intent.getLongExtra(EXTRA_GROUP_ID, FeedGroupEntity.GROUP_ALL_ID) | ||||
|         val useFeedExtractor = defaultSharedPreferences | ||||
|                 .getBoolean(getString(R.string.feed_use_dedicated_fetch_method_key), false) | ||||
|             .getBoolean(getString(R.string.feed_use_dedicated_fetch_method_key), false) | ||||
|  | ||||
|         val thresholdOutdatedSecondsString = defaultSharedPreferences | ||||
|                 .getString(getString(R.string.feed_update_threshold_key), getString(R.string.feed_update_threshold_default_value)) | ||||
|             .getString(getString(R.string.feed_update_threshold_key), getString(R.string.feed_update_threshold_default_value)) | ||||
|         val thresholdOutdatedSeconds = thresholdOutdatedSecondsString!!.toInt() | ||||
|  | ||||
|         startLoading(groupId, useFeedExtractor, thresholdOutdatedSeconds) | ||||
| @@ -181,63 +181,63 @@ class FeedLoadService : Service() { | ||||
|         } | ||||
|  | ||||
|         subscriptions | ||||
|                 .limit(1) | ||||
|             .take(1) | ||||
|  | ||||
|                 .doOnNext { | ||||
|                     currentProgress.set(0) | ||||
|                     maxProgress.set(it.size) | ||||
|             .doOnNext { | ||||
|                 currentProgress.set(0) | ||||
|                 maxProgress.set(it.size) | ||||
|             } | ||||
|             .filter { it.isNotEmpty() } | ||||
|  | ||||
|             .observeOn(AndroidSchedulers.mainThread()) | ||||
|             .doOnNext { | ||||
|                 startForeground(NOTIFICATION_ID, notificationBuilder.build()) | ||||
|                 updateNotificationProgress(null) | ||||
|                 broadcastProgress() | ||||
|             } | ||||
|  | ||||
|             .observeOn(Schedulers.io()) | ||||
|             .flatMap { Flowable.fromIterable(it) } | ||||
|             .takeWhile { !cancelSignal.get() } | ||||
|  | ||||
|             .parallel(PARALLEL_EXTRACTIONS, PARALLEL_EXTRACTIONS * 2) | ||||
|             .runOn(Schedulers.io(), PARALLEL_EXTRACTIONS * 2) | ||||
|             .filter { !cancelSignal.get() } | ||||
|  | ||||
|             .map { subscriptionEntity -> | ||||
|                 try { | ||||
|                     val listInfo = if (useFeedExtractor) { | ||||
|                         ExtractorHelper | ||||
|                             .getFeedInfoFallbackToChannelInfo(subscriptionEntity.serviceId, subscriptionEntity.url) | ||||
|                             .blockingGet() | ||||
|                     } else { | ||||
|                         ExtractorHelper | ||||
|                             .getChannelInfo(subscriptionEntity.serviceId, subscriptionEntity.url, true) | ||||
|                             .blockingGet() | ||||
|                     } as ListInfo<StreamInfoItem> | ||||
|  | ||||
|                     return@map Notification.createOnNext(Pair(subscriptionEntity.uid, listInfo)) | ||||
|                 } catch (e: Throwable) { | ||||
|                     val request = "${subscriptionEntity.serviceId}:${subscriptionEntity.url}" | ||||
|                     val wrapper = RequestException(subscriptionEntity.uid, request, e) | ||||
|                     return@map Notification.createOnError<Pair<Long, ListInfo<StreamInfoItem>>>(wrapper) | ||||
|                 } | ||||
|                 .filter { it.isNotEmpty() } | ||||
|             } | ||||
|             .sequential() | ||||
|  | ||||
|                 .observeOn(AndroidSchedulers.mainThread()) | ||||
|                 .doOnNext { | ||||
|                     startForeground(NOTIFICATION_ID, notificationBuilder.build()) | ||||
|                     updateNotificationProgress(null) | ||||
|                     broadcastProgress() | ||||
|                 } | ||||
|             .observeOn(AndroidSchedulers.mainThread()) | ||||
|             .doOnNext(errorHandlingConsumer) | ||||
|  | ||||
|                 .observeOn(Schedulers.io()) | ||||
|                 .flatMap { Flowable.fromIterable(it) } | ||||
|                 .takeWhile { !cancelSignal.get() } | ||||
|             .observeOn(AndroidSchedulers.mainThread()) | ||||
|             .doOnNext(notificationsConsumer) | ||||
|  | ||||
|                 .parallel(PARALLEL_EXTRACTIONS, PARALLEL_EXTRACTIONS * 2) | ||||
|                 .runOn(Schedulers.io(), PARALLEL_EXTRACTIONS * 2) | ||||
|                 .filter { !cancelSignal.get() } | ||||
|             .observeOn(Schedulers.io()) | ||||
|             .buffer(BUFFER_COUNT_BEFORE_INSERT) | ||||
|             .doOnNext(databaseConsumer) | ||||
|  | ||||
|                 .map { subscriptionEntity -> | ||||
|                     try { | ||||
|                         val listInfo = if (useFeedExtractor) { | ||||
|                             ExtractorHelper | ||||
|                                     .getFeedInfoFallbackToChannelInfo(subscriptionEntity.serviceId, subscriptionEntity.url) | ||||
|                                     .blockingGet() | ||||
|                         } else { | ||||
|                             ExtractorHelper | ||||
|                                     .getChannelInfo(subscriptionEntity.serviceId, subscriptionEntity.url, true) | ||||
|                                     .blockingGet() | ||||
|                         } as ListInfo<StreamInfoItem> | ||||
|  | ||||
|                         return@map Notification.createOnNext(Pair(subscriptionEntity.uid, listInfo)) | ||||
|                     } catch (e: Throwable) { | ||||
|                         val request = "${subscriptionEntity.serviceId}:${subscriptionEntity.url}" | ||||
|                         val wrapper = RequestException(subscriptionEntity.uid, request, e) | ||||
|                         return@map Notification.createOnError<Pair<Long, ListInfo<StreamInfoItem>>>(wrapper) | ||||
|                     } | ||||
|                 } | ||||
|                 .sequential() | ||||
|  | ||||
|                 .observeOn(AndroidSchedulers.mainThread()) | ||||
|                 .doOnNext(errorHandlingConsumer) | ||||
|  | ||||
|                 .observeOn(AndroidSchedulers.mainThread()) | ||||
|                 .doOnNext(notificationsConsumer) | ||||
|  | ||||
|                 .observeOn(Schedulers.io()) | ||||
|                 .buffer(BUFFER_COUNT_BEFORE_INSERT) | ||||
|                 .doOnNext(databaseConsumer) | ||||
|  | ||||
|                 .subscribeOn(Schedulers.io()) | ||||
|                 .observeOn(AndroidSchedulers.mainThread()) | ||||
|                 .subscribe(resultSubscriber) | ||||
|             .subscribeOn(Schedulers.io()) | ||||
|             .observeOn(AndroidSchedulers.mainThread()) | ||||
|             .subscribe(resultSubscriber) | ||||
|     } | ||||
|  | ||||
|     private fun broadcastProgress() { | ||||
| @@ -274,7 +274,8 @@ class FeedLoadService : Service() { | ||||
|                 notificationUpdater.onNext(getString(R.string.feed_processing_message)) | ||||
|                 postEvent(ProgressEvent(R.string.feed_processing_message)) | ||||
|  | ||||
|                 disposables.add(Single | ||||
|                 disposables.add( | ||||
|                     Single | ||||
|                         .fromCallable { | ||||
|                             feedResultsHolder.ready() | ||||
|  | ||||
| @@ -293,7 +294,8 @@ class FeedLoadService : Service() { | ||||
|                                 return@subscribe | ||||
|                             } | ||||
|                             stopService() | ||||
|                         }) | ||||
|                         } | ||||
|                 ) | ||||
|             } | ||||
|         } | ||||
|  | ||||
| @@ -364,16 +366,18 @@ class FeedLoadService : Service() { | ||||
|     private var maxProgress = AtomicInteger(-1) | ||||
|  | ||||
|     private fun createNotification(): NotificationCompat.Builder { | ||||
|         val cancelActionIntent = PendingIntent.getBroadcast(this, | ||||
|                 NOTIFICATION_ID, Intent(ACTION_CANCEL), 0) | ||||
|         val cancelActionIntent = PendingIntent.getBroadcast( | ||||
|             this, | ||||
|             NOTIFICATION_ID, Intent(ACTION_CANCEL), 0 | ||||
|         ) | ||||
|  | ||||
|         return NotificationCompat.Builder(this, getString(R.string.notification_channel_id)) | ||||
|                 .setOngoing(true) | ||||
|                 .setProgress(-1, -1, true) | ||||
|                 .setSmallIcon(R.drawable.ic_newpipe_triangle_white) | ||||
|                 .setVisibility(NotificationCompat.VISIBILITY_PUBLIC) | ||||
|                 .addAction(0, getString(R.string.cancel), cancelActionIntent) | ||||
|                 .setContentTitle(getString(R.string.feed_notification_loading)) | ||||
|             .setOngoing(true) | ||||
|             .setProgress(-1, -1, true) | ||||
|             .setSmallIcon(R.drawable.ic_newpipe_triangle_white) | ||||
|             .setVisibility(NotificationCompat.VISIBILITY_PUBLIC) | ||||
|             .addAction(0, getString(R.string.cancel), cancelActionIntent) | ||||
|             .setContentTitle(getString(R.string.feed_notification_loading)) | ||||
|     } | ||||
|  | ||||
|     private fun setupNotification() { | ||||
| @@ -381,13 +385,15 @@ class FeedLoadService : Service() { | ||||
|         notificationBuilder = createNotification() | ||||
|  | ||||
|         val throttleAfterFirstEmission = Function { flow: Flowable<String> -> | ||||
|             flow.limit(1).concatWith(flow.skip(1).throttleLatest(NOTIFICATION_SAMPLING_PERIOD.toLong(), TimeUnit.MILLISECONDS)) | ||||
|             flow.take(1).concatWith(flow.skip(1).throttleLatest(NOTIFICATION_SAMPLING_PERIOD.toLong(), TimeUnit.MILLISECONDS)) | ||||
|         } | ||||
|  | ||||
|         disposables.add(notificationUpdater | ||||
|         disposables.add( | ||||
|             notificationUpdater | ||||
|                 .publish(throttleAfterFirstEmission) | ||||
|                 .observeOn(AndroidSchedulers.mainThread()) | ||||
|                 .subscribe(this::updateNotificationProgress)) | ||||
|                 .subscribe(this::updateNotificationProgress) | ||||
|         ) | ||||
|     } | ||||
|  | ||||
|     private fun updateNotificationProgress(updateDescription: String?) { | ||||
|   | ||||
| @@ -50,11 +50,11 @@ import java.util.ArrayList; | ||||
| import java.util.Collection; | ||||
| import java.util.List; | ||||
|  | ||||
| import io.reactivex.Completable; | ||||
| import io.reactivex.Flowable; | ||||
| import io.reactivex.Maybe; | ||||
| import io.reactivex.Single; | ||||
| import io.reactivex.schedulers.Schedulers; | ||||
| import io.reactivex.rxjava3.core.Completable; | ||||
| import io.reactivex.rxjava3.core.Flowable; | ||||
| import io.reactivex.rxjava3.core.Maybe; | ||||
| import io.reactivex.rxjava3.core.Single; | ||||
| import io.reactivex.rxjava3.schedulers.Schedulers; | ||||
|  | ||||
| public class HistoryRecordManager { | ||||
|     private final AppDatabase database; | ||||
|   | ||||
| @@ -49,9 +49,9 @@ import java.util.Comparator; | ||||
| import java.util.List; | ||||
|  | ||||
| import icepick.State; | ||||
| import io.reactivex.android.schedulers.AndroidSchedulers; | ||||
| import io.reactivex.disposables.CompositeDisposable; | ||||
| import io.reactivex.disposables.Disposable; | ||||
| import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers; | ||||
| import io.reactivex.rxjava3.disposables.CompositeDisposable; | ||||
| import io.reactivex.rxjava3.disposables.Disposable; | ||||
|  | ||||
| public class StatisticsPlaylistFragment | ||||
|         extends BaseLocalListFragment<List<StreamStatisticsEntry>, Void> { | ||||
|   | ||||
| @@ -55,13 +55,12 @@ import java.util.concurrent.TimeUnit; | ||||
| import java.util.concurrent.atomic.AtomicBoolean; | ||||
|  | ||||
| import icepick.State; | ||||
| import io.reactivex.Flowable; | ||||
| import io.reactivex.android.schedulers.AndroidSchedulers; | ||||
| import io.reactivex.disposables.CompositeDisposable; | ||||
| import io.reactivex.disposables.Disposable; | ||||
| import io.reactivex.disposables.Disposables; | ||||
| import io.reactivex.schedulers.Schedulers; | ||||
| import io.reactivex.subjects.PublishSubject; | ||||
| import io.reactivex.rxjava3.core.Flowable; | ||||
| import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers; | ||||
| import io.reactivex.rxjava3.disposables.CompositeDisposable; | ||||
| import io.reactivex.rxjava3.disposables.Disposable; | ||||
| import io.reactivex.rxjava3.schedulers.Schedulers; | ||||
| import io.reactivex.rxjava3.subjects.PublishSubject; | ||||
|  | ||||
| import static org.schabi.newpipe.util.AnimationUtils.animateView; | ||||
|  | ||||
| @@ -641,7 +640,7 @@ public class LocalPlaylistFragment extends BaseLocalListFragment<List<PlaylistSt | ||||
|  | ||||
|     private Disposable getDebouncedSaver() { | ||||
|         if (debouncedSaveSignal == null) { | ||||
|             return Disposables.empty(); | ||||
|             return Disposable.empty(); | ||||
|         } | ||||
|  | ||||
|         return debouncedSaveSignal | ||||
|   | ||||
| @@ -15,11 +15,11 @@ import org.schabi.newpipe.database.stream.model.StreamEntity; | ||||
| import java.util.ArrayList; | ||||
| import java.util.List; | ||||
|  | ||||
| import io.reactivex.Completable; | ||||
| import io.reactivex.Flowable; | ||||
| import io.reactivex.Maybe; | ||||
| import io.reactivex.Single; | ||||
| import io.reactivex.schedulers.Schedulers; | ||||
| import io.reactivex.rxjava3.core.Completable; | ||||
| import io.reactivex.rxjava3.core.Flowable; | ||||
| import io.reactivex.rxjava3.core.Maybe; | ||||
| import io.reactivex.rxjava3.core.Single; | ||||
| import io.reactivex.rxjava3.schedulers.Schedulers; | ||||
|  | ||||
| public class LocalPlaylistManager { | ||||
|     private final AppDatabase database; | ||||
|   | ||||
| @@ -7,9 +7,9 @@ import org.schabi.newpipe.extractor.playlist.PlaylistInfo; | ||||
|  | ||||
| import java.util.List; | ||||
|  | ||||
| import io.reactivex.Flowable; | ||||
| import io.reactivex.Single; | ||||
| import io.reactivex.schedulers.Schedulers; | ||||
| import io.reactivex.rxjava3.core.Flowable; | ||||
| import io.reactivex.rxjava3.core.Single; | ||||
| import io.reactivex.rxjava3.schedulers.Schedulers; | ||||
|  | ||||
| public class RemotePlaylistManager { | ||||
|  | ||||
|   | ||||
| @@ -28,13 +28,7 @@ import com.xwray.groupie.Item | ||||
| import com.xwray.groupie.Section | ||||
| import com.xwray.groupie.kotlinandroidextensions.GroupieViewHolder | ||||
| import icepick.State | ||||
| import io.reactivex.disposables.CompositeDisposable | ||||
| import java.io.File | ||||
| import java.text.SimpleDateFormat | ||||
| import java.util.Date | ||||
| import java.util.Locale | ||||
| import kotlin.math.floor | ||||
| import kotlin.math.max | ||||
| import io.reactivex.rxjava3.disposables.CompositeDisposable | ||||
| import kotlinx.android.synthetic.main.dialog_title.view.itemAdditionalDetails | ||||
| import kotlinx.android.synthetic.main.dialog_title.view.itemTitleView | ||||
| import kotlinx.android.synthetic.main.fragment_subscription.items_list | ||||
| @@ -68,6 +62,12 @@ import org.schabi.newpipe.util.NavigationHelper | ||||
| import org.schabi.newpipe.util.OnClickGesture | ||||
| import org.schabi.newpipe.util.ShareUtils | ||||
| import org.schabi.newpipe.util.ThemeHelper | ||||
| import java.io.File | ||||
| import java.text.SimpleDateFormat | ||||
| import java.util.Date | ||||
| import java.util.Locale | ||||
| import kotlin.math.floor | ||||
| import kotlin.math.max | ||||
|  | ||||
| class SubscriptionFragment : BaseStateFragment<SubscriptionState>() { | ||||
|     private lateinit var viewModel: SubscriptionViewModel | ||||
| @@ -208,14 +208,19 @@ class SubscriptionFragment : BaseStateFragment<SubscriptionState>() { | ||||
|                 if (!exportFile.parentFile.canWrite() || !exportFile.parentFile.canRead()) { | ||||
|                     Toast.makeText(activity, R.string.invalid_directory, Toast.LENGTH_SHORT).show() | ||||
|                 } else { | ||||
|                     activity.startService(Intent(activity, SubscriptionsExportService::class.java) | ||||
|                             .putExtra(KEY_FILE_PATH, exportFile.absolutePath)) | ||||
|                     activity.startService( | ||||
|                         Intent(activity, SubscriptionsExportService::class.java) | ||||
|                             .putExtra(KEY_FILE_PATH, exportFile.absolutePath) | ||||
|                     ) | ||||
|                 } | ||||
|             } else if (requestCode == REQUEST_IMPORT_CODE) { | ||||
|                 val path = Utils.getFileForUri(data.data!!).absolutePath | ||||
|                 ImportConfirmationDialog.show(this, Intent(activity, SubscriptionsImportService::class.java) | ||||
|                 ImportConfirmationDialog.show( | ||||
|                     this, | ||||
|                     Intent(activity, SubscriptionsImportService::class.java) | ||||
|                         .putExtra(KEY_MODE, PREVIOUS_EXPORT_MODE) | ||||
|                         .putExtra(KEY_VALUE, path)) | ||||
|                         .putExtra(KEY_VALUE, path) | ||||
|                 ) | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| @@ -247,9 +252,9 @@ class SubscriptionFragment : BaseStateFragment<SubscriptionState>() { | ||||
|  | ||||
|             feedGroupsCarousel = FeedGroupCarouselItem(requireContext(), carouselAdapter) | ||||
|             feedGroupsSortMenuItem = HeaderWithMenuItem( | ||||
|                     getString(R.string.feed_groups_header_title), | ||||
|                     ThemeHelper.resolveResourceIdFromAttr(requireContext(), R.attr.ic_sort), | ||||
|                     menuItemOnClickListener = ::openReorderDialog | ||||
|                 getString(R.string.feed_groups_header_title), | ||||
|                 ThemeHelper.resolveResourceIdFromAttr(requireContext(), R.attr.ic_sort), | ||||
|                 menuItemOnClickListener = ::openReorderDialog | ||||
|             ) | ||||
|             add(Section(feedGroupsSortMenuItem, listOf(feedGroupsCarousel))) | ||||
|  | ||||
| @@ -260,10 +265,11 @@ class SubscriptionFragment : BaseStateFragment<SubscriptionState>() { | ||||
|         subscriptionsSection.setHideWhenEmpty(true) | ||||
|  | ||||
|         importExportItem = FeedImportExportItem( | ||||
|                 { onImportPreviousSelected() }, | ||||
|                 { onImportFromServiceSelected(it) }, | ||||
|                 { onExportSelected() }, | ||||
|                 importExportItemExpandedState ?: false) | ||||
|             { onImportPreviousSelected() }, | ||||
|             { onImportFromServiceSelected(it) }, | ||||
|             { onExportSelected() }, | ||||
|             importExportItemExpandedState ?: false | ||||
|         ) | ||||
|         groupAdapter.add(Section(importExportItem, listOf(subscriptionsSection))) | ||||
|     } | ||||
|  | ||||
| @@ -284,8 +290,8 @@ class SubscriptionFragment : BaseStateFragment<SubscriptionState>() { | ||||
|  | ||||
|     private fun showLongTapDialog(selectedItem: ChannelInfoItem) { | ||||
|         val commands = arrayOf( | ||||
|                 getString(R.string.share), | ||||
|                 getString(R.string.unsubscribe) | ||||
|             getString(R.string.share), | ||||
|             getString(R.string.unsubscribe) | ||||
|         ) | ||||
|  | ||||
|         val actions = DialogInterface.OnClickListener { _, i -> | ||||
| @@ -301,16 +307,18 @@ class SubscriptionFragment : BaseStateFragment<SubscriptionState>() { | ||||
|         bannerView.itemAdditionalDetails.visibility = View.GONE | ||||
|  | ||||
|         AlertDialog.Builder(requireContext()) | ||||
|                 .setCustomTitle(bannerView) | ||||
|                 .setItems(commands, actions) | ||||
|                 .create() | ||||
|                 .show() | ||||
|             .setCustomTitle(bannerView) | ||||
|             .setItems(commands, actions) | ||||
|             .create() | ||||
|             .show() | ||||
|     } | ||||
|  | ||||
|     private fun deleteChannel(selectedItem: ChannelInfoItem) { | ||||
|         disposables.add(subscriptionManager.deleteSubscription(selectedItem.serviceId, selectedItem.url).subscribe { | ||||
|             Toast.makeText(requireContext(), getString(R.string.channel_unsubscribed), Toast.LENGTH_SHORT).show() | ||||
|         }) | ||||
|         disposables.add( | ||||
|             subscriptionManager.deleteSubscription(selectedItem.serviceId, selectedItem.url).subscribe { | ||||
|                 Toast.makeText(requireContext(), getString(R.string.channel_unsubscribed), Toast.LENGTH_SHORT).show() | ||||
|             } | ||||
|         ) | ||||
|     } | ||||
|  | ||||
|     override fun doInitialLoadLogic() = Unit | ||||
| @@ -332,8 +340,10 @@ class SubscriptionFragment : BaseStateFragment<SubscriptionState>() { | ||||
|     } | ||||
|  | ||||
|     private val listenerChannelItem = object : OnClickGesture<ChannelInfoItem>() { | ||||
|         override fun selected(selectedItem: ChannelInfoItem) = NavigationHelper.openChannelFragment(fm, | ||||
|                 selectedItem.serviceId, selectedItem.url, selectedItem.name) | ||||
|         override fun selected(selectedItem: ChannelInfoItem) = NavigationHelper.openChannelFragment( | ||||
|             fm, | ||||
|             selectedItem.serviceId, selectedItem.url, selectedItem.name | ||||
|         ) | ||||
|  | ||||
|         override fun held(selectedItem: ChannelInfoItem) = showLongTapDialog(selectedItem) | ||||
|     } | ||||
| @@ -420,14 +430,16 @@ class SubscriptionFragment : BaseStateFragment<SubscriptionState>() { | ||||
|  | ||||
|     private fun shouldUseGridLayout(): Boolean { | ||||
|         val listMode = PreferenceManager.getDefaultSharedPreferences(requireContext()) | ||||
|                 .getString(getString(R.string.list_view_mode_key), getString(R.string.list_view_mode_value)) | ||||
|             .getString(getString(R.string.list_view_mode_key), getString(R.string.list_view_mode_value)) | ||||
|  | ||||
|         return when (listMode) { | ||||
|             getString(R.string.list_view_mode_auto_key) -> { | ||||
|                 val configuration = resources.configuration | ||||
|  | ||||
|                 (configuration.orientation == Configuration.ORIENTATION_LANDSCAPE && | ||||
|                         configuration.isLayoutSizeAtLeast(Configuration.SCREENLAYOUT_SIZE_LARGE)) | ||||
|                 ( | ||||
|                     configuration.orientation == Configuration.ORIENTATION_LANDSCAPE && | ||||
|                         configuration.isLayoutSizeAtLeast(Configuration.SCREENLAYOUT_SIZE_LARGE) | ||||
|                     ) | ||||
|             } | ||||
|             getString(R.string.list_view_mode_grid_key) -> true | ||||
|             else -> false | ||||
|   | ||||
| @@ -1,10 +1,10 @@ | ||||
| package org.schabi.newpipe.local.subscription | ||||
|  | ||||
| import android.content.Context | ||||
| import io.reactivex.Completable | ||||
| import io.reactivex.Flowable | ||||
| import io.reactivex.android.schedulers.AndroidSchedulers | ||||
| import io.reactivex.schedulers.Schedulers | ||||
| import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers | ||||
| import io.reactivex.rxjava3.core.Completable | ||||
| import io.reactivex.rxjava3.core.Flowable | ||||
| import io.reactivex.rxjava3.schedulers.Schedulers | ||||
| import org.schabi.newpipe.NewPipeDatabase | ||||
| import org.schabi.newpipe.database.feed.model.FeedGroupEntity | ||||
| import org.schabi.newpipe.database.subscription.SubscriptionDAO | ||||
| @@ -32,7 +32,8 @@ class SubscriptionManager(context: Context) { | ||||
|             filterQuery.isNotEmpty() -> { | ||||
|                 return if (showOnlyUngrouped) { | ||||
|                     subscriptionTable.getSubscriptionsOnlyUngroupedFiltered( | ||||
|                         currentGroupId, filterQuery) | ||||
|                         currentGroupId, filterQuery | ||||
|                     ) | ||||
|                 } else { | ||||
|                     subscriptionTable.getSubscriptionsFiltered(filterQuery) | ||||
|                 } | ||||
| @@ -44,7 +45,8 @@ class SubscriptionManager(context: Context) { | ||||
|  | ||||
|     fun upsertAll(infoList: List<ChannelInfo>): List<SubscriptionEntity> { | ||||
|         val listEntities = subscriptionTable.upsertAll( | ||||
|             infoList.map { SubscriptionEntity.from(it) }) | ||||
|             infoList.map { SubscriptionEntity.from(it) } | ||||
|         ) | ||||
|  | ||||
|         database.runInTransaction { | ||||
|             infoList.forEachIndexed { index, info -> | ||||
|   | ||||
| @@ -5,12 +5,12 @@ import androidx.lifecycle.AndroidViewModel | ||||
| import androidx.lifecycle.LiveData | ||||
| import androidx.lifecycle.MutableLiveData | ||||
| import com.xwray.groupie.Group | ||||
| import io.reactivex.schedulers.Schedulers | ||||
| import java.util.concurrent.TimeUnit | ||||
| import io.reactivex.rxjava3.schedulers.Schedulers | ||||
| import org.schabi.newpipe.local.feed.FeedDatabaseManager | ||||
| import org.schabi.newpipe.local.subscription.item.ChannelItem | ||||
| import org.schabi.newpipe.local.subscription.item.FeedGroupCardItem | ||||
| import org.schabi.newpipe.util.DEFAULT_THROTTLE_TIMEOUT | ||||
| import java.util.concurrent.TimeUnit | ||||
|  | ||||
| class SubscriptionViewModel(application: Application) : AndroidViewModel(application) { | ||||
|     private var feedDatabaseManager: FeedDatabaseManager = FeedDatabaseManager(application) | ||||
| @@ -22,22 +22,22 @@ class SubscriptionViewModel(application: Application) : AndroidViewModel(applica | ||||
|     val feedGroupsLiveData: LiveData<List<Group>> = mutableFeedGroupsLiveData | ||||
|  | ||||
|     private var feedGroupItemsDisposable = feedDatabaseManager.groups() | ||||
|             .throttleLatest(DEFAULT_THROTTLE_TIMEOUT, TimeUnit.MILLISECONDS) | ||||
|             .map { it.map(::FeedGroupCardItem) } | ||||
|             .subscribeOn(Schedulers.io()) | ||||
|             .subscribe( | ||||
|                     { mutableFeedGroupsLiveData.postValue(it) }, | ||||
|                     { mutableStateLiveData.postValue(SubscriptionState.ErrorState(it)) } | ||||
|             ) | ||||
|         .throttleLatest(DEFAULT_THROTTLE_TIMEOUT, TimeUnit.MILLISECONDS) | ||||
|         .map { it.map(::FeedGroupCardItem) } | ||||
|         .subscribeOn(Schedulers.io()) | ||||
|         .subscribe( | ||||
|             { mutableFeedGroupsLiveData.postValue(it) }, | ||||
|             { mutableStateLiveData.postValue(SubscriptionState.ErrorState(it)) } | ||||
|         ) | ||||
|  | ||||
|     private var stateItemsDisposable = subscriptionManager.subscriptions() | ||||
|             .throttleLatest(DEFAULT_THROTTLE_TIMEOUT, TimeUnit.MILLISECONDS) | ||||
|             .map { it.map { entity -> ChannelItem(entity.toChannelInfoItem(), entity.uid, ChannelItem.ItemVersion.MINI) } } | ||||
|             .subscribeOn(Schedulers.io()) | ||||
|             .subscribe( | ||||
|                     { mutableStateLiveData.postValue(SubscriptionState.LoadedState(it)) }, | ||||
|                     { mutableStateLiveData.postValue(SubscriptionState.ErrorState(it)) } | ||||
|             ) | ||||
|         .throttleLatest(DEFAULT_THROTTLE_TIMEOUT, TimeUnit.MILLISECONDS) | ||||
|         .map { it.map { entity -> ChannelItem(entity.toChannelInfoItem(), entity.uid, ChannelItem.ItemVersion.MINI) } } | ||||
|         .subscribeOn(Schedulers.io()) | ||||
|         .subscribe( | ||||
|             { mutableStateLiveData.postValue(SubscriptionState.LoadedState(it)) }, | ||||
|             { mutableStateLiveData.postValue(SubscriptionState.ErrorState(it)) } | ||||
|         ) | ||||
|  | ||||
|     override fun onCleared() { | ||||
|         super.onCleared() | ||||
|   | ||||
| @@ -24,8 +24,6 @@ import com.xwray.groupie.Section | ||||
| import com.xwray.groupie.kotlinandroidextensions.GroupieViewHolder | ||||
| import icepick.Icepick | ||||
| import icepick.State | ||||
| import java.io.Serializable | ||||
| import kotlin.collections.contains | ||||
| import kotlinx.android.synthetic.main.dialog_feed_group_create.* | ||||
| import kotlinx.android.synthetic.main.toolbar_search_layout.* | ||||
| import org.schabi.newpipe.R | ||||
| @@ -43,6 +41,8 @@ import org.schabi.newpipe.local.subscription.item.PickerIconItem | ||||
| import org.schabi.newpipe.local.subscription.item.PickerSubscriptionItem | ||||
| import org.schabi.newpipe.util.DeviceUtils | ||||
| import org.schabi.newpipe.util.ThemeHelper | ||||
| import java.io.Serializable | ||||
| import kotlin.collections.contains | ||||
|  | ||||
| class FeedGroupDialog : DialogFragment(), BackPressable { | ||||
|     private lateinit var viewModel: FeedGroupDialogViewModel | ||||
| @@ -116,21 +116,30 @@ class FeedGroupDialog : DialogFragment(), BackPressable { | ||||
|     override fun onViewCreated(view: View, savedInstanceState: Bundle?) { | ||||
|         super.onViewCreated(view, savedInstanceState) | ||||
|  | ||||
|         viewModel = ViewModelProvider(this, | ||||
|             FeedGroupDialogViewModel.Factory(requireContext(), | ||||
|                 groupId, subscriptionsCurrentSearchQuery, subscriptionsShowOnlyUngrouped) | ||||
|         viewModel = ViewModelProvider( | ||||
|             this, | ||||
|             FeedGroupDialogViewModel.Factory( | ||||
|                 requireContext(), | ||||
|                 groupId, subscriptionsCurrentSearchQuery, subscriptionsShowOnlyUngrouped | ||||
|             ) | ||||
|         ).get(FeedGroupDialogViewModel::class.java) | ||||
|  | ||||
|         viewModel.groupLiveData.observe(viewLifecycleOwner, Observer(::handleGroup)) | ||||
|         viewModel.subscriptionsLiveData.observe(viewLifecycleOwner, Observer { | ||||
|             setupSubscriptionPicker(it.first, it.second) | ||||
|         }) | ||||
|         viewModel.dialogEventLiveData.observe(viewLifecycleOwner, Observer { | ||||
|             when (it) { | ||||
|                 ProcessingEvent -> disableInput() | ||||
|                 SuccessEvent -> dismiss() | ||||
|         viewModel.subscriptionsLiveData.observe( | ||||
|             viewLifecycleOwner, | ||||
|             Observer { | ||||
|                 setupSubscriptionPicker(it.first, it.second) | ||||
|             } | ||||
|         }) | ||||
|         ) | ||||
|         viewModel.dialogEventLiveData.observe( | ||||
|             viewLifecycleOwner, | ||||
|             Observer { | ||||
|                 when (it) { | ||||
|                     ProcessingEvent -> disableInput() | ||||
|                     SuccessEvent -> dismiss() | ||||
|                 } | ||||
|             } | ||||
|         ) | ||||
|  | ||||
|         subscriptionGroupAdapter = GroupAdapter<GroupieViewHolder>().apply { | ||||
|             add(subscriptionMainSection) | ||||
| @@ -141,8 +150,10 @@ class FeedGroupDialog : DialogFragment(), BackPressable { | ||||
|             // Disable animations, too distracting. | ||||
|             itemAnimator = null | ||||
|             adapter = subscriptionGroupAdapter | ||||
|             layoutManager = GridLayoutManager(requireContext(), subscriptionGroupAdapter.spanCount, | ||||
|                 RecyclerView.VERTICAL, false).apply { | ||||
|             layoutManager = GridLayoutManager( | ||||
|                 requireContext(), subscriptionGroupAdapter.spanCount, | ||||
|                 RecyclerView.VERTICAL, false | ||||
|             ).apply { | ||||
|                 spanSizeLookup = subscriptionGroupAdapter.spanSizeLookup | ||||
|             } | ||||
|         } | ||||
| @@ -346,7 +357,8 @@ class FeedGroupDialog : DialogFragment(), BackPressable { | ||||
|         val selectedCount = this.selectedSubscriptions.size | ||||
|         val selectedCountText = resources.getQuantityString( | ||||
|             R.plurals.feed_group_dialog_selection_count, | ||||
|             selectedCount, selectedCount) | ||||
|             selectedCount, selectedCount | ||||
|         ) | ||||
|         selected_subscription_count_view.text = selectedCountText | ||||
|         subscriptions_header_info.text = selectedCountText | ||||
|     } | ||||
| @@ -401,10 +413,12 @@ class FeedGroupDialog : DialogFragment(), BackPressable { | ||||
|         separator.onlyVisibleIn(SubscriptionsPickerScreen, IconPickerScreen) | ||||
|         cancel_button.onlyVisibleIn(InitialScreen, DeleteScreen) | ||||
|  | ||||
|         confirm_button.setText(when { | ||||
|             currentScreen == InitialScreen && groupId == NO_GROUP_SELECTED -> R.string.create | ||||
|             else -> android.R.string.ok | ||||
|         }) | ||||
|         confirm_button.setText( | ||||
|             when { | ||||
|                 currentScreen == InitialScreen && groupId == NO_GROUP_SELECTED -> R.string.create | ||||
|                 else -> android.R.string.ok | ||||
|             } | ||||
|         ) | ||||
|  | ||||
|         delete_button.isGone = currentScreen != InitialScreen || groupId == NO_GROUP_SELECTED | ||||
|  | ||||
| @@ -454,8 +468,10 @@ class FeedGroupDialog : DialogFragment(), BackPressable { | ||||
|     } | ||||
|  | ||||
|     private fun hideKeyboardSearch() { | ||||
|         inputMethodManager.hideSoftInputFromWindow(toolbar_search_edit_text.windowToken, | ||||
|             InputMethodManager.RESULT_UNCHANGED_SHOWN) | ||||
|         inputMethodManager.hideSoftInputFromWindow( | ||||
|             toolbar_search_edit_text.windowToken, | ||||
|             InputMethodManager.RESULT_UNCHANGED_SHOWN | ||||
|         ) | ||||
|         toolbar_search_edit_text.clearFocus() | ||||
|     } | ||||
|  | ||||
| @@ -466,8 +482,10 @@ class FeedGroupDialog : DialogFragment(), BackPressable { | ||||
|     } | ||||
|  | ||||
|     private fun hideKeyboard() { | ||||
|         inputMethodManager.hideSoftInputFromWindow(group_name_input.windowToken, | ||||
|             InputMethodManager.RESULT_UNCHANGED_SHOWN) | ||||
|         inputMethodManager.hideSoftInputFromWindow( | ||||
|             group_name_input.windowToken, | ||||
|             InputMethodManager.RESULT_UNCHANGED_SHOWN | ||||
|         ) | ||||
|         group_name_input.clearFocus() | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -5,12 +5,12 @@ import androidx.lifecycle.LiveData | ||||
| import androidx.lifecycle.MutableLiveData | ||||
| import androidx.lifecycle.ViewModel | ||||
| import androidx.lifecycle.ViewModelProvider | ||||
| import io.reactivex.Completable | ||||
| import io.reactivex.Flowable | ||||
| import io.reactivex.disposables.Disposable | ||||
| import io.reactivex.functions.BiFunction | ||||
| import io.reactivex.processors.BehaviorProcessor | ||||
| import io.reactivex.schedulers.Schedulers | ||||
| import io.reactivex.rxjava3.core.Completable | ||||
| import io.reactivex.rxjava3.core.Flowable | ||||
| import io.reactivex.rxjava3.disposables.Disposable | ||||
| import io.reactivex.rxjava3.functions.BiFunction | ||||
| import io.reactivex.rxjava3.processors.BehaviorProcessor | ||||
| import io.reactivex.rxjava3.schedulers.Schedulers | ||||
| import org.schabi.newpipe.database.feed.model.FeedGroupEntity | ||||
| import org.schabi.newpipe.local.feed.FeedDatabaseManager | ||||
| import org.schabi.newpipe.local.subscription.FeedGroupIcon | ||||
| @@ -32,9 +32,9 @@ class FeedGroupDialogViewModel( | ||||
|  | ||||
|     private var subscriptionsFlowable = Flowable | ||||
|         .combineLatest( | ||||
|                 filterSubscriptions.startWith(initialQuery), | ||||
|                 toggleShowOnlyUngrouped.startWith(initialShowOnlyUngrouped), | ||||
|                 BiFunction { t1: String, t2: Boolean -> Filter(t1, t2) } | ||||
|             filterSubscriptions.startWithItem(initialQuery), | ||||
|             toggleShowOnlyUngrouped.startWithItem(initialShowOnlyUngrouped), | ||||
|             BiFunction { t1: String, t2: Boolean -> Filter(t1, t2) } | ||||
|         ) | ||||
|         .distinctUntilChanged() | ||||
|         .switchMap { (query, showOnlyUngrouped) -> | ||||
| @@ -55,8 +55,10 @@ class FeedGroupDialogViewModel( | ||||
|         .subscribe(mutableGroupLiveData::postValue) | ||||
|  | ||||
|     private var subscriptionsDisposable = Flowable | ||||
|         .combineLatest(subscriptionsFlowable, feedDatabaseManager.subscriptionIdsForGroup(groupId), | ||||
|             BiFunction { t1: List<PickerSubscriptionItem>, t2: List<Long> -> t1 to t2.toSet() }) | ||||
|         .combineLatest( | ||||
|             subscriptionsFlowable, feedDatabaseManager.subscriptionIdsForGroup(groupId), | ||||
|             BiFunction { t1: List<PickerSubscriptionItem>, t2: List<Long> -> t1 to t2.toSet() } | ||||
|         ) | ||||
|         .subscribeOn(Schedulers.io()) | ||||
|         .subscribe(mutableSubscriptionsLiveData::postValue) | ||||
|  | ||||
| @@ -68,15 +70,19 @@ class FeedGroupDialogViewModel( | ||||
|     } | ||||
|  | ||||
|     fun createGroup(name: String, selectedIcon: FeedGroupIcon, selectedSubscriptions: Set<Long>) { | ||||
|         doAction(feedDatabaseManager.createGroup(name, selectedIcon) | ||||
|             .flatMapCompletable { | ||||
|                 feedDatabaseManager.updateSubscriptionsForGroup(it, selectedSubscriptions.toList()) | ||||
|             }) | ||||
|         doAction( | ||||
|             feedDatabaseManager.createGroup(name, selectedIcon) | ||||
|                 .flatMapCompletable { | ||||
|                     feedDatabaseManager.updateSubscriptionsForGroup(it, selectedSubscriptions.toList()) | ||||
|                 } | ||||
|         ) | ||||
|     } | ||||
|  | ||||
|     fun updateGroup(name: String, selectedIcon: FeedGroupIcon, selectedSubscriptions: Set<Long>, sortOrder: Long) { | ||||
|         doAction(feedDatabaseManager.updateSubscriptionsForGroup(groupId, selectedSubscriptions.toList()) | ||||
|             .andThen(feedDatabaseManager.updateGroup(FeedGroupEntity(groupId, name, selectedIcon, sortOrder)))) | ||||
|         doAction( | ||||
|             feedDatabaseManager.updateSubscriptionsForGroup(groupId, selectedSubscriptions.toList()) | ||||
|                 .andThen(feedDatabaseManager.updateGroup(FeedGroupEntity(groupId, name, selectedIcon, sortOrder))) | ||||
|         ) | ||||
|     } | ||||
|  | ||||
|     fun deleteGroup() { | ||||
| @@ -120,8 +126,10 @@ class FeedGroupDialogViewModel( | ||||
|     ) : ViewModelProvider.Factory { | ||||
|         @Suppress("UNCHECKED_CAST") | ||||
|         override fun <T : ViewModel?> create(modelClass: Class<T>): T { | ||||
|             return FeedGroupDialogViewModel(context.applicationContext, | ||||
|                 groupId, initialQuery, initialShowOnlyUngrouped) as T | ||||
|             return FeedGroupDialogViewModel( | ||||
|                 context.applicationContext, | ||||
|                 groupId, initialQuery, initialShowOnlyUngrouped | ||||
|             ) as T | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -16,7 +16,6 @@ import com.xwray.groupie.TouchCallback | ||||
| import com.xwray.groupie.kotlinandroidextensions.GroupieViewHolder | ||||
| import icepick.Icepick | ||||
| import icepick.State | ||||
| import java.util.Collections | ||||
| import kotlinx.android.synthetic.main.dialog_feed_group_reorder.confirm_button | ||||
| import kotlinx.android.synthetic.main.dialog_feed_group_reorder.feed_groups_list | ||||
| import org.schabi.newpipe.R | ||||
| @@ -25,6 +24,7 @@ import org.schabi.newpipe.local.subscription.dialog.FeedGroupReorderDialogViewMo | ||||
| import org.schabi.newpipe.local.subscription.dialog.FeedGroupReorderDialogViewModel.DialogEvent.SuccessEvent | ||||
| import org.schabi.newpipe.local.subscription.item.FeedGroupReorderItem | ||||
| import org.schabi.newpipe.util.ThemeHelper | ||||
| import java.util.Collections | ||||
|  | ||||
| class FeedGroupReorderDialog : DialogFragment() { | ||||
|     private lateinit var viewModel: FeedGroupReorderDialogViewModel | ||||
| @@ -51,12 +51,15 @@ class FeedGroupReorderDialog : DialogFragment() { | ||||
|  | ||||
|         viewModel = ViewModelProvider(this).get(FeedGroupReorderDialogViewModel::class.java) | ||||
|         viewModel.groupsLiveData.observe(viewLifecycleOwner, Observer(::handleGroups)) | ||||
|         viewModel.dialogEventLiveData.observe(viewLifecycleOwner, Observer { | ||||
|             when (it) { | ||||
|                 ProcessingEvent -> disableInput() | ||||
|                 SuccessEvent -> dismiss() | ||||
|         viewModel.dialogEventLiveData.observe( | ||||
|             viewLifecycleOwner, | ||||
|             Observer { | ||||
|                 when (it) { | ||||
|                     ProcessingEvent -> disableInput() | ||||
|                     SuccessEvent -> dismiss() | ||||
|                 } | ||||
|             } | ||||
|         }) | ||||
|         ) | ||||
|  | ||||
|         feed_groups_list.layoutManager = LinearLayoutManager(requireContext()) | ||||
|         feed_groups_list.adapter = groupAdapter | ||||
|   | ||||
| @@ -4,9 +4,9 @@ import android.app.Application | ||||
| import androidx.lifecycle.AndroidViewModel | ||||
| import androidx.lifecycle.LiveData | ||||
| import androidx.lifecycle.MutableLiveData | ||||
| import io.reactivex.Completable | ||||
| import io.reactivex.disposables.Disposable | ||||
| import io.reactivex.schedulers.Schedulers | ||||
| import io.reactivex.rxjava3.core.Completable | ||||
| import io.reactivex.rxjava3.disposables.Disposable | ||||
| import io.reactivex.rxjava3.schedulers.Schedulers | ||||
| import org.schabi.newpipe.database.feed.model.FeedGroupEntity | ||||
| import org.schabi.newpipe.local.feed.FeedDatabaseManager | ||||
|  | ||||
| @@ -21,9 +21,9 @@ class FeedGroupReorderDialogViewModel(application: Application) : AndroidViewMod | ||||
|     private var actionProcessingDisposable: Disposable? = null | ||||
|  | ||||
|     private var groupsDisposable = feedDatabaseManager.groups() | ||||
|             .limit(1) | ||||
|             .subscribeOn(Schedulers.io()) | ||||
|             .subscribe(mutableGroupsLiveData::postValue) | ||||
|         .take(1) | ||||
|         .subscribeOn(Schedulers.io()) | ||||
|         .subscribe(mutableGroupsLiveData::postValue) | ||||
|  | ||||
|     override fun onCleared() { | ||||
|         super.onCleared() | ||||
| @@ -40,8 +40,8 @@ class FeedGroupReorderDialogViewModel(application: Application) : AndroidViewMod | ||||
|             mutableDialogEventLiveData.value = DialogEvent.ProcessingEvent | ||||
|  | ||||
|             actionProcessingDisposable = completable | ||||
|                     .subscribeOn(Schedulers.io()) | ||||
|                     .subscribe { mutableDialogEventLiveData.postValue(DialogEvent.SuccessEvent) } | ||||
|                 .subscribeOn(Schedulers.io()) | ||||
|                 .subscribe { mutableDialogEventLiveData.postValue(DialogEvent.SuccessEvent) } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -36,8 +36,10 @@ class ChannelItem( | ||||
|         viewHolder.itemAdditionalDetails.text = getDetailLine(viewHolder.root.context) | ||||
|         if (itemVersion == ItemVersion.NORMAL) viewHolder.itemChannelDescriptionView.text = infoItem.description | ||||
|  | ||||
|         ImageLoader.getInstance().displayImage(infoItem.thumbnailUrl, viewHolder.itemThumbnailView, | ||||
|                 ImageDisplayConstants.DISPLAY_THUMBNAIL_OPTIONS) | ||||
|         ImageLoader.getInstance().displayImage( | ||||
|             infoItem.thumbnailUrl, viewHolder.itemThumbnailView, | ||||
|             ImageDisplayConstants.DISPLAY_THUMBNAIL_OPTIONS | ||||
|         ) | ||||
|  | ||||
|         gesturesListener?.run { | ||||
|             viewHolder.containerView.setOnClickListener { selected(infoItem) } | ||||
|   | ||||
| @@ -20,7 +20,7 @@ data class FeedGroupReorderItem( | ||||
|     val dragCallback: ItemTouchHelper | ||||
| ) : Item() { | ||||
|     constructor (feedGroupEntity: FeedGroupEntity, dragCallback: ItemTouchHelper) : | ||||
|             this(feedGroupEntity.uid, feedGroupEntity.name, feedGroupEntity.icon, dragCallback) | ||||
|         this(feedGroupEntity.uid, feedGroupEntity.name, feedGroupEntity.icon, dragCallback) | ||||
|  | ||||
|     override fun getId(): Long { | ||||
|         return when (groupId) { | ||||
|   | ||||
| @@ -49,8 +49,10 @@ class FeedImportExportItem( | ||||
|  | ||||
|         expandIconListener?.let { viewHolder.import_export_options.removeListener(it) } | ||||
|         expandIconListener = CollapsibleView.StateListener { newState -> | ||||
|             AnimationUtils.animateRotation(viewHolder.import_export_expand_icon, | ||||
|                     250, if (newState == CollapsibleView.COLLAPSED) 0 else 180) | ||||
|             AnimationUtils.animateRotation( | ||||
|                 viewHolder.import_export_expand_icon, | ||||
|                 250, if (newState == CollapsibleView.COLLAPSED) 0 else 180 | ||||
|             ) | ||||
|         } | ||||
|  | ||||
|         viewHolder.import_export_options.currentState = if (isExpanded) CollapsibleView.EXPANDED else CollapsibleView.COLLAPSED | ||||
| @@ -85,8 +87,10 @@ class FeedImportExportItem( | ||||
|     } | ||||
|  | ||||
|     private fun setupImportFromItems(listHolder: ViewGroup) { | ||||
|         val previousBackupItem = addItemView(listHolder.context.getString(R.string.previous_export), | ||||
|                 ThemeHelper.resolveResourceIdFromAttr(listHolder.context, R.attr.ic_backup), listHolder) | ||||
|         val previousBackupItem = addItemView( | ||||
|             listHolder.context.getString(R.string.previous_export), | ||||
|             ThemeHelper.resolveResourceIdFromAttr(listHolder.context, R.attr.ic_backup), listHolder | ||||
|         ) | ||||
|         previousBackupItem.setOnClickListener { onImportPreviousSelected() } | ||||
|  | ||||
|         val iconColor = if (ThemeHelper.isLightThemeSelected(listHolder.context)) Color.BLACK else Color.WHITE | ||||
| @@ -112,8 +116,10 @@ class FeedImportExportItem( | ||||
|     } | ||||
|  | ||||
|     private fun setupExportToItems(listHolder: ViewGroup) { | ||||
|         val previousBackupItem = addItemView(listHolder.context.getString(R.string.file), | ||||
|                 ThemeHelper.resolveResourceIdFromAttr(listHolder.context, R.attr.ic_save), listHolder) | ||||
|         val previousBackupItem = addItemView( | ||||
|             listHolder.context.getString(R.string.file), | ||||
|             ThemeHelper.resolveResourceIdFromAttr(listHolder.context, R.attr.ic_save), listHolder | ||||
|         ) | ||||
|         previousBackupItem.setOnClickListener { onExportSelected() } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -36,11 +36,11 @@ class HeaderWithMenuItem( | ||||
|         viewHolder.header_menu_item.setImageResource(itemIcon) | ||||
|  | ||||
|         val listener: OnClickListener? = | ||||
|                 onClickListener?.let { OnClickListener { onClickListener.invoke() } } | ||||
|             onClickListener?.let { OnClickListener { onClickListener.invoke() } } | ||||
|         viewHolder.root.setOnClickListener(listener) | ||||
|  | ||||
|         val menuItemListener: OnClickListener? = | ||||
|                 menuItemOnClickListener?.let { OnClickListener { menuItemOnClickListener.invoke() } } | ||||
|             menuItemOnClickListener?.let { OnClickListener { menuItemOnClickListener.invoke() } } | ||||
|         viewHolder.header_menu_item.setOnClickListener(menuItemListener) | ||||
|         updateMenuItemVisibility(viewHolder) | ||||
|     } | ||||
|   | ||||
| @@ -22,8 +22,10 @@ data class PickerSubscriptionItem( | ||||
|     override fun getSpanSize(spanCount: Int, position: Int): Int = 1 | ||||
|  | ||||
|     override fun bind(viewHolder: GroupieViewHolder, position: Int) { | ||||
|         ImageLoader.getInstance().displayImage(subscriptionEntity.avatarUrl, | ||||
|                 viewHolder.thumbnail_view, ImageDisplayConstants.DISPLAY_AVATAR_OPTIONS) | ||||
|         ImageLoader.getInstance().displayImage( | ||||
|             subscriptionEntity.avatarUrl, | ||||
|             viewHolder.thumbnail_view, ImageDisplayConstants.DISPLAY_AVATAR_OPTIONS | ||||
|         ) | ||||
|  | ||||
|         viewHolder.title_view.text = subscriptionEntity.name | ||||
|         viewHolder.selected_highlight.isVisible = isSelected | ||||
| @@ -39,7 +41,9 @@ data class PickerSubscriptionItem( | ||||
|  | ||||
|     fun updateSelected(containerView: View, isSelected: Boolean) { | ||||
|         this.isSelected = isSelected | ||||
|         animateView(containerView.selected_highlight, | ||||
|                 AnimationUtils.Type.LIGHT_SCALE_AND_ALPHA, isSelected, 150) | ||||
|         animateView( | ||||
|             containerView.selected_highlight, | ||||
|             AnimationUtils.Type.LIGHT_SCALE_AND_ALPHA, isSelected, 150 | ||||
|         ) | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -46,11 +46,11 @@ import java.util.Collections; | ||||
| import java.util.concurrent.TimeUnit; | ||||
| import java.util.concurrent.atomic.AtomicInteger; | ||||
|  | ||||
| import io.reactivex.Flowable; | ||||
| import io.reactivex.android.schedulers.AndroidSchedulers; | ||||
| import io.reactivex.disposables.CompositeDisposable; | ||||
| import io.reactivex.functions.Function; | ||||
| import io.reactivex.processors.PublishProcessor; | ||||
| import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers; | ||||
| import io.reactivex.rxjava3.core.Flowable; | ||||
| import io.reactivex.rxjava3.disposables.CompositeDisposable; | ||||
| import io.reactivex.rxjava3.functions.Function; | ||||
| import io.reactivex.rxjava3.processors.PublishProcessor; | ||||
|  | ||||
| public abstract class BaseImportExportService extends Service { | ||||
|     protected final String TAG = this.getClass().getSimpleName(); | ||||
| @@ -120,7 +120,7 @@ public abstract class BaseImportExportService extends Service { | ||||
|         startForeground(getNotificationId(), notificationBuilder.build()); | ||||
|  | ||||
|         final Function<Flowable<String>, Publisher<String>> throttleAfterFirstEmission = flow -> | ||||
|                 flow.limit(1).concatWith(flow.skip(1) | ||||
|                 flow.take(1).concatWith(flow.skip(1) | ||||
|                         .throttleLast(NOTIFICATION_SAMPLING_PERIOD, TimeUnit.MILLISECONDS)); | ||||
|  | ||||
|         disposables.add(notificationUpdater | ||||
|   | ||||
| @@ -37,9 +37,9 @@ import java.io.FileOutputStream; | ||||
| import java.util.ArrayList; | ||||
| import java.util.List; | ||||
|  | ||||
| import io.reactivex.android.schedulers.AndroidSchedulers; | ||||
| import io.reactivex.functions.Function; | ||||
| import io.reactivex.schedulers.Schedulers; | ||||
| import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers; | ||||
| import io.reactivex.rxjava3.functions.Function; | ||||
| import io.reactivex.rxjava3.schedulers.Schedulers; | ||||
|  | ||||
| import static org.schabi.newpipe.MainActivity.DEBUG; | ||||
|  | ||||
|   | ||||
| @@ -46,12 +46,12 @@ import java.io.InputStream; | ||||
| import java.util.ArrayList; | ||||
| import java.util.List; | ||||
|  | ||||
| import io.reactivex.Flowable; | ||||
| import io.reactivex.Notification; | ||||
| import io.reactivex.android.schedulers.AndroidSchedulers; | ||||
| import io.reactivex.functions.Consumer; | ||||
| import io.reactivex.functions.Function; | ||||
| import io.reactivex.schedulers.Schedulers; | ||||
| import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers; | ||||
| import io.reactivex.rxjava3.core.Flowable; | ||||
| import io.reactivex.rxjava3.core.Notification; | ||||
| import io.reactivex.rxjava3.functions.Consumer; | ||||
| import io.reactivex.rxjava3.functions.Function; | ||||
| import io.reactivex.rxjava3.schedulers.Schedulers; | ||||
|  | ||||
| import static org.schabi.newpipe.MainActivity.DEBUG; | ||||
|  | ||||
|   | ||||
| @@ -27,13 +27,13 @@ import android.content.SharedPreferences; | ||||
| import android.graphics.Bitmap; | ||||
| import android.graphics.BitmapFactory; | ||||
| import android.media.AudioManager; | ||||
| import androidx.preference.PreferenceManager; | ||||
| import android.util.Log; | ||||
| import android.view.View; | ||||
| import android.widget.Toast; | ||||
|  | ||||
| import androidx.annotation.NonNull; | ||||
| import androidx.annotation.Nullable; | ||||
| import androidx.preference.PreferenceManager; | ||||
|  | ||||
| import com.google.android.exoplayer2.C; | ||||
| import com.google.android.exoplayer2.DefaultRenderersFactory; | ||||
| @@ -77,17 +77,16 @@ import org.schabi.newpipe.util.SerializedCache; | ||||
|  | ||||
| import java.io.IOException; | ||||
|  | ||||
| import io.reactivex.Observable; | ||||
| import io.reactivex.android.schedulers.AndroidSchedulers; | ||||
| import io.reactivex.disposables.CompositeDisposable; | ||||
| import io.reactivex.disposables.Disposable; | ||||
| import io.reactivex.disposables.SerialDisposable; | ||||
| import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers; | ||||
| import io.reactivex.rxjava3.core.Observable; | ||||
| import io.reactivex.rxjava3.disposables.CompositeDisposable; | ||||
| import io.reactivex.rxjava3.disposables.Disposable; | ||||
| import io.reactivex.rxjava3.disposables.SerialDisposable; | ||||
|  | ||||
| import static com.google.android.exoplayer2.Player.DISCONTINUITY_REASON_INTERNAL; | ||||
| import static com.google.android.exoplayer2.Player.DISCONTINUITY_REASON_PERIOD_TRANSITION; | ||||
| import static com.google.android.exoplayer2.Player.DISCONTINUITY_REASON_SEEK; | ||||
| import static com.google.android.exoplayer2.Player.DISCONTINUITY_REASON_SEEK_ADJUSTMENT; | ||||
| import static io.reactivex.android.schedulers.AndroidSchedulers.mainThread; | ||||
| import static java.util.concurrent.TimeUnit.MILLISECONDS; | ||||
|  | ||||
| /** | ||||
| @@ -720,8 +719,9 @@ public abstract class BasePlayer implements | ||||
|     } | ||||
|  | ||||
|     private Disposable getProgressReactor() { | ||||
|         return Observable.interval(PROGRESS_LOOP_INTERVAL_MILLIS, MILLISECONDS, mainThread()) | ||||
|                 .observeOn(mainThread()) | ||||
|         return Observable.interval(PROGRESS_LOOP_INTERVAL_MILLIS, MILLISECONDS, | ||||
|                 AndroidSchedulers.mainThread()) | ||||
|                 .observeOn(AndroidSchedulers.mainThread()) | ||||
|                 .subscribe(ignored -> triggerProgressUpdate(), | ||||
|                         error -> Log.e(TAG, "Progress update failure: ", error)); | ||||
|     } | ||||
| @@ -1319,7 +1319,7 @@ public abstract class BasePlayer implements | ||||
|         final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); | ||||
|         if (prefs.getBoolean(context.getString(R.string.enable_watch_history_key), true)) { | ||||
|             final Disposable stateSaver = recordManager.saveStreamState(info, progress) | ||||
|                     .observeOn(mainThread()) | ||||
|                     .observeOn(AndroidSchedulers.mainThread()) | ||||
|                     .doOnError((e) -> { | ||||
|                         if (DEBUG) { | ||||
|                             e.printStackTrace(); | ||||
| @@ -1339,7 +1339,7 @@ public abstract class BasePlayer implements | ||||
|         if (prefs.getBoolean(context.getString(R.string.enable_watch_history_key), true)) { | ||||
|             final Disposable stateSaver = queueItem.getStream() | ||||
|                     .flatMapCompletable(info -> recordManager.saveStreamState(info, 0)) | ||||
|                     .observeOn(mainThread()) | ||||
|                     .observeOn(AndroidSchedulers.mainThread()) | ||||
|                     .doOnError((e) -> { | ||||
|                         if (DEBUG) { | ||||
|                             e.printStackTrace(); | ||||
|   | ||||
| @@ -30,14 +30,14 @@ import java.util.Set; | ||||
| import java.util.concurrent.TimeUnit; | ||||
| import java.util.concurrent.atomic.AtomicBoolean; | ||||
|  | ||||
| import io.reactivex.Observable; | ||||
| import io.reactivex.Single; | ||||
| import io.reactivex.android.schedulers.AndroidSchedulers; | ||||
| import io.reactivex.disposables.CompositeDisposable; | ||||
| import io.reactivex.disposables.Disposable; | ||||
| import io.reactivex.internal.subscriptions.EmptySubscription; | ||||
| import io.reactivex.schedulers.Schedulers; | ||||
| import io.reactivex.subjects.PublishSubject; | ||||
| import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers; | ||||
| import io.reactivex.rxjava3.core.Observable; | ||||
| import io.reactivex.rxjava3.core.Single; | ||||
| import io.reactivex.rxjava3.disposables.CompositeDisposable; | ||||
| import io.reactivex.rxjava3.disposables.Disposable; | ||||
| import io.reactivex.rxjava3.internal.subscriptions.EmptySubscription; | ||||
| import io.reactivex.rxjava3.schedulers.Schedulers; | ||||
| import io.reactivex.rxjava3.subjects.PublishSubject; | ||||
|  | ||||
| import static org.schabi.newpipe.player.mediasource.FailedMediaSource.MediaSourceResolutionException; | ||||
| import static org.schabi.newpipe.player.mediasource.FailedMediaSource.StreamInfoLoadException; | ||||
|   | ||||
| @@ -14,8 +14,8 @@ import java.util.ArrayList; | ||||
| import java.util.Collections; | ||||
| import java.util.List; | ||||
|  | ||||
| import io.reactivex.SingleObserver; | ||||
| import io.reactivex.disposables.Disposable; | ||||
| import io.reactivex.rxjava3.core.SingleObserver; | ||||
| import io.reactivex.rxjava3.disposables.Disposable; | ||||
|  | ||||
| abstract class AbstractInfoPlayQueue<T extends ListInfo, U extends InfoItem> extends PlayQueue { | ||||
|     boolean isInitial; | ||||
|   | ||||
| @@ -9,8 +9,8 @@ import org.schabi.newpipe.util.ExtractorHelper; | ||||
|  | ||||
| import java.util.List; | ||||
|  | ||||
| import io.reactivex.android.schedulers.AndroidSchedulers; | ||||
| import io.reactivex.schedulers.Schedulers; | ||||
| import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers; | ||||
| import io.reactivex.rxjava3.schedulers.Schedulers; | ||||
|  | ||||
| public final class ChannelPlayQueue extends AbstractInfoPlayQueue<ChannelInfo, ChannelInfoItem> { | ||||
|     public ChannelPlayQueue(final ChannelInfoItem item) { | ||||
|   | ||||
| @@ -21,10 +21,10 @@ import java.util.Collections; | ||||
| import java.util.List; | ||||
| import java.util.concurrent.atomic.AtomicInteger; | ||||
|  | ||||
| import io.reactivex.BackpressureStrategy; | ||||
| import io.reactivex.Flowable; | ||||
| import io.reactivex.android.schedulers.AndroidSchedulers; | ||||
| import io.reactivex.subjects.BehaviorSubject; | ||||
| import io.reactivex.rxjava3.core.BackpressureStrategy; | ||||
| import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers; | ||||
| import io.reactivex.rxjava3.core.Flowable; | ||||
| import io.reactivex.rxjava3.subjects.BehaviorSubject; | ||||
|  | ||||
| /** | ||||
|  * PlayQueue is responsible for keeping track of a list of streams and the index of | ||||
| @@ -80,7 +80,7 @@ public abstract class PlayQueue implements Serializable { | ||||
|  | ||||
|         broadcastReceiver = eventBroadcast.toFlowable(BackpressureStrategy.BUFFER) | ||||
|                 .observeOn(AndroidSchedulers.mainThread()) | ||||
|                 .startWith(new InitEvent()); | ||||
|                 .startWithItem(new InitEvent()); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|   | ||||
| @@ -20,8 +20,8 @@ import org.schabi.newpipe.util.FallbackViewHolder; | ||||
|  | ||||
| import java.util.List; | ||||
|  | ||||
| import io.reactivex.Observer; | ||||
| import io.reactivex.disposables.Disposable; | ||||
| import io.reactivex.rxjava3.core.Observer; | ||||
| import io.reactivex.rxjava3.disposables.Disposable; | ||||
|  | ||||
| /** | ||||
|  * Created by Christian Schabesberger on 01.08.16. | ||||
|   | ||||
| @@ -10,8 +10,8 @@ import org.schabi.newpipe.util.ExtractorHelper; | ||||
|  | ||||
| import java.io.Serializable; | ||||
|  | ||||
| import io.reactivex.Single; | ||||
| import io.reactivex.schedulers.Schedulers; | ||||
| import io.reactivex.rxjava3.core.Single; | ||||
| import io.reactivex.rxjava3.schedulers.Schedulers; | ||||
|  | ||||
| public class PlayQueueItem implements Serializable { | ||||
|     public static final long RECOVERY_UNSET = Long.MIN_VALUE; | ||||
|   | ||||
| @@ -8,8 +8,8 @@ import org.schabi.newpipe.util.ExtractorHelper; | ||||
|  | ||||
| import java.util.List; | ||||
|  | ||||
| import io.reactivex.android.schedulers.AndroidSchedulers; | ||||
| import io.reactivex.schedulers.Schedulers; | ||||
| import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers; | ||||
| import io.reactivex.rxjava3.schedulers.Schedulers; | ||||
|  | ||||
| public final class PlaylistPlayQueue extends AbstractInfoPlayQueue<PlaylistInfo, PlaylistInfoItem> { | ||||
|     public PlaylistPlayQueue(final PlaylistInfoItem item) { | ||||
|   | ||||
| @@ -14,9 +14,9 @@ import org.schabi.newpipe.report.ErrorInfo; | ||||
| import org.schabi.newpipe.report.UserAction; | ||||
| import org.schabi.newpipe.util.InfoCache; | ||||
|  | ||||
| import io.reactivex.android.schedulers.AndroidSchedulers; | ||||
| import io.reactivex.disposables.CompositeDisposable; | ||||
| import io.reactivex.disposables.Disposable; | ||||
| import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers; | ||||
| import io.reactivex.rxjava3.disposables.CompositeDisposable; | ||||
| import io.reactivex.rxjava3.disposables.Disposable; | ||||
|  | ||||
| public class HistorySettingsFragment extends BasePreferenceFragment { | ||||
|     private String cacheWipeKey; | ||||
|   | ||||
| @@ -16,4 +16,4 @@ class NotificationSettingsFragment : BasePreferenceFragment() { | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| } | ||||
|   | ||||
| @@ -4,7 +4,6 @@ import android.annotation.SuppressLint; | ||||
| import android.content.Context; | ||||
| import android.content.SharedPreferences; | ||||
| import android.os.Bundle; | ||||
| import androidx.preference.PreferenceManager; | ||||
| import android.text.InputType; | ||||
| import android.view.LayoutInflater; | ||||
| import android.view.Menu; | ||||
| @@ -26,6 +25,7 @@ import androidx.appcompat.app.AlertDialog; | ||||
| import androidx.appcompat.content.res.AppCompatResources; | ||||
| import androidx.appcompat.widget.AppCompatImageView; | ||||
| import androidx.fragment.app.Fragment; | ||||
| import androidx.preference.PreferenceManager; | ||||
| import androidx.recyclerview.widget.ItemTouchHelper; | ||||
| import androidx.recyclerview.widget.LinearLayoutManager; | ||||
| import androidx.recyclerview.widget.RecyclerView; | ||||
| @@ -44,11 +44,11 @@ import java.util.ArrayList; | ||||
| import java.util.Collections; | ||||
| import java.util.List; | ||||
|  | ||||
| import io.reactivex.Single; | ||||
| import io.reactivex.android.schedulers.AndroidSchedulers; | ||||
| import io.reactivex.disposables.CompositeDisposable; | ||||
| import io.reactivex.disposables.Disposable; | ||||
| import io.reactivex.schedulers.Schedulers; | ||||
| import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers; | ||||
| import io.reactivex.rxjava3.core.Single; | ||||
| import io.reactivex.rxjava3.disposables.CompositeDisposable; | ||||
| import io.reactivex.rxjava3.disposables.Disposable; | ||||
| import io.reactivex.rxjava3.schedulers.Schedulers; | ||||
|  | ||||
| public class PeertubeInstanceListFragment extends Fragment { | ||||
|     private static final int MENU_ITEM_RESTORE_ID = 123456; | ||||
|   | ||||
| @@ -30,10 +30,10 @@ import java.util.List; | ||||
| import java.util.Vector; | ||||
|  | ||||
| import de.hdodenhof.circleimageview.CircleImageView; | ||||
| import io.reactivex.Observer; | ||||
| import io.reactivex.android.schedulers.AndroidSchedulers; | ||||
| import io.reactivex.disposables.Disposable; | ||||
| import io.reactivex.schedulers.Schedulers; | ||||
| import io.reactivex.rxjava3.core.Observer; | ||||
| import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers; | ||||
| import io.reactivex.rxjava3.disposables.Disposable; | ||||
| import io.reactivex.rxjava3.schedulers.Schedulers; | ||||
|  | ||||
| /** | ||||
|  * Created by Christian Schabesberger on 26.09.17. | ||||
|   | ||||
| @@ -33,9 +33,9 @@ import org.schabi.newpipe.report.UserAction; | ||||
| import java.util.List; | ||||
| import java.util.Vector; | ||||
|  | ||||
| import io.reactivex.Flowable; | ||||
| import io.reactivex.android.schedulers.AndroidSchedulers; | ||||
| import io.reactivex.disposables.Disposable; | ||||
| import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers; | ||||
| import io.reactivex.rxjava3.core.Flowable; | ||||
| import io.reactivex.rxjava3.disposables.Disposable; | ||||
|  | ||||
| public class SelectPlaylistFragment extends DialogFragment { | ||||
|     /** | ||||
|   | ||||
| @@ -23,9 +23,9 @@ import org.schabi.newpipe.player.playqueue.SinglePlayQueue; | ||||
| import java.util.regex.Matcher; | ||||
| import java.util.regex.Pattern; | ||||
|  | ||||
| import io.reactivex.Single; | ||||
| import io.reactivex.android.schedulers.AndroidSchedulers; | ||||
| import io.reactivex.schedulers.Schedulers; | ||||
| import io.reactivex.rxjava3.core.Single; | ||||
| import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers; | ||||
| import io.reactivex.rxjava3.schedulers.Schedulers; | ||||
|  | ||||
| public class CommentTextOnTouchListener implements View.OnTouchListener { | ||||
|     public static final CommentTextOnTouchListener INSTANCE = new CommentTextOnTouchListener(); | ||||
|   | ||||
| @@ -10,9 +10,11 @@ class ExceptionUtils { | ||||
|          */ | ||||
|         @JvmStatic | ||||
|         fun isInterruptedCaused(throwable: Throwable): Boolean { | ||||
|             return hasExactCause(throwable, | ||||
|                     InterruptedIOException::class.java, | ||||
|                     InterruptedException::class.java) | ||||
|             return hasExactCause( | ||||
|                 throwable, | ||||
|                 InterruptedIOException::class.java, | ||||
|                 InterruptedException::class.java | ||||
|             ) | ||||
|         } | ||||
|  | ||||
|         /** | ||||
| @@ -20,8 +22,10 @@ class ExceptionUtils { | ||||
|          */ | ||||
|         @JvmStatic | ||||
|         fun isNetworkRelated(throwable: Throwable): Boolean { | ||||
|             return hasAssignableCause(throwable, | ||||
|                     IOException::class.java) | ||||
|             return hasAssignableCause( | ||||
|                 throwable, | ||||
|                 IOException::class.java | ||||
|             ) | ||||
|         } | ||||
|  | ||||
|         /** | ||||
|   | ||||
| @@ -57,8 +57,8 @@ import org.schabi.newpipe.report.UserAction; | ||||
| import java.util.Collections; | ||||
| import java.util.List; | ||||
|  | ||||
| import io.reactivex.Maybe; | ||||
| import io.reactivex.Single; | ||||
| import io.reactivex.rxjava3.core.Maybe; | ||||
| import io.reactivex.rxjava3.core.Single; | ||||
|  | ||||
| public final class ExtractorHelper { | ||||
|     private static final String TAG = ExtractorHelper.class.getSimpleName(); | ||||
|   | ||||
| @@ -23,9 +23,9 @@ import java.util.Collections; | ||||
| import java.util.List; | ||||
| import java.util.concurrent.Callable; | ||||
|  | ||||
| import io.reactivex.Single; | ||||
| import io.reactivex.android.schedulers.AndroidSchedulers; | ||||
| import io.reactivex.schedulers.Schedulers; | ||||
| import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers; | ||||
| import io.reactivex.rxjava3.core.Single; | ||||
| import io.reactivex.rxjava3.schedulers.Schedulers; | ||||
| import us.shandian.giga.util.Utility; | ||||
|  | ||||
| /** | ||||
|   | ||||
| @@ -49,10 +49,10 @@ import java.util.ArrayList; | ||||
| import java.util.Arrays; | ||||
| import java.util.Iterator; | ||||
|  | ||||
| import io.reactivex.Observable; | ||||
| import io.reactivex.android.schedulers.AndroidSchedulers; | ||||
| import io.reactivex.disposables.CompositeDisposable; | ||||
| import io.reactivex.schedulers.Schedulers; | ||||
| import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers; | ||||
| import io.reactivex.rxjava3.core.Observable; | ||||
| import io.reactivex.rxjava3.disposables.CompositeDisposable; | ||||
| import io.reactivex.rxjava3.schedulers.Schedulers; | ||||
| import us.shandian.giga.get.DownloadMission; | ||||
| import us.shandian.giga.get.FinishedMission; | ||||
| import us.shandian.giga.get.Mission; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Stypox
					Stypox