Implement new feed and subscriptions groups
- Introduce Groupie for easier lists implementations - Use some of the new components of the Android Architecture libraries - Add a bunch of icons for groups, using vectors, which still is compatible with older APIs through the compatibility layer
This commit is contained in:
parent
e8ab5aacc7
commit
20a4bb0936
143 changed files with 4099 additions and 1370 deletions
|
|
@ -3,6 +3,7 @@ package org.schabi.newpipe.database;
|
|||
import androidx.room.TypeConverter;
|
||||
|
||||
import org.schabi.newpipe.extractor.stream.StreamType;
|
||||
import org.schabi.newpipe.local.subscription.FeedGroupIcon;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
|
|
@ -37,4 +38,18 @@ public class Converters {
|
|||
public static String stringOf(StreamType streamType) {
|
||||
return streamType.name();
|
||||
}
|
||||
|
||||
@TypeConverter
|
||||
public static Integer integerOf(FeedGroupIcon feedGroupIcon) {
|
||||
return feedGroupIcon.getId();
|
||||
}
|
||||
|
||||
@TypeConverter
|
||||
public static FeedGroupIcon feedGroupIconOf(Integer id) {
|
||||
for (FeedGroupIcon icon : FeedGroupIcon.values()) {
|
||||
if (icon.getId() == id) return icon;
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("There's no feed group icon with the id \"" + id + "\"");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import androidx.room.Query
|
|||
import io.reactivex.Flowable
|
||||
import org.schabi.newpipe.database.feed.model.FeedEntity
|
||||
import org.schabi.newpipe.database.stream.model.StreamEntity
|
||||
import java.util.*
|
||||
|
||||
@Dao
|
||||
abstract class FeedDAO {
|
||||
|
|
@ -19,7 +20,9 @@ abstract class FeedDAO {
|
|||
INNER JOIN feed f
|
||||
ON s.uid = f.stream_id
|
||||
|
||||
ORDER BY s.upload_date IS NULL DESC, s.upload_date DESC
|
||||
ORDER BY s.upload_date IS NULL DESC, s.upload_date DESC, s.uploader ASC
|
||||
|
||||
LIMIT 500
|
||||
""")
|
||||
abstract fun getAllStreams(): Flowable<List<StreamEntity>>
|
||||
|
||||
|
|
@ -36,12 +39,45 @@ abstract class FeedDAO {
|
|||
ON fg.uid = fgs.group_id
|
||||
|
||||
WHERE fgs.group_id = :groupId
|
||||
|
||||
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>>
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.FAIL)
|
||||
@Query("""
|
||||
DELETE FROM feed WHERE
|
||||
|
||||
feed.stream_id IN (
|
||||
SELECT s.uid FROM streams s
|
||||
|
||||
INNER JOIN feed f
|
||||
ON s.uid = f.stream_id
|
||||
|
||||
WHERE s.upload_date < :date
|
||||
)
|
||||
""")
|
||||
abstract fun unlinkStreamsOlderThan(date: Date)
|
||||
|
||||
@Query("""
|
||||
DELETE FROM feed
|
||||
|
||||
WHERE feed.subscription_id = :subscriptionId
|
||||
|
||||
AND feed.stream_id IN (
|
||||
SELECT s.uid FROM streams s
|
||||
|
||||
INNER JOIN feed f
|
||||
ON s.uid = f.stream_id
|
||||
|
||||
WHERE s.stream_type = "LIVE_STREAM" OR s.stream_type = "AUDIO_LIVE_STREAM"
|
||||
)
|
||||
""")
|
||||
abstract fun unlinkOldLivestreams(subscriptionId: Long)
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.IGNORE)
|
||||
abstract fun insert(feedEntity: FeedEntity)
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.FAIL)
|
||||
@Insert(onConflict = OnConflictStrategy.IGNORE)
|
||||
abstract fun insertAll(entities: List<FeedEntity>): List<Long>
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,16 +2,43 @@ package org.schabi.newpipe.database.feed.dao
|
|||
|
||||
import androidx.room.*
|
||||
import io.reactivex.Flowable
|
||||
import io.reactivex.Maybe
|
||||
import org.schabi.newpipe.database.feed.model.FeedGroupEntity
|
||||
import org.schabi.newpipe.database.feed.model.FeedGroupSubscriptionEntity
|
||||
|
||||
@Dao
|
||||
abstract class FeedGroupDAO {
|
||||
@Query("DELETE FROM feed_group")
|
||||
abstract fun deleteAll(): Int
|
||||
|
||||
@Query("SELECT * FROM feed_group")
|
||||
abstract fun getAll(): Flowable<List<FeedGroupEntity>>
|
||||
|
||||
@Query("SELECT * FROM feed_group WHERE uid = :groupId")
|
||||
abstract fun getGroup(groupId: Long): Maybe<FeedGroupEntity>
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.ABORT)
|
||||
abstract fun insert(feedEntity: FeedGroupEntity)
|
||||
abstract fun insert(feedEntity: FeedGroupEntity): Long
|
||||
|
||||
@Update(onConflict = OnConflictStrategy.IGNORE)
|
||||
abstract fun update(feedGroupEntity: FeedGroupEntity): Int
|
||||
|
||||
@Query("DELETE FROM feed_group")
|
||||
abstract fun deleteAll(): Int
|
||||
|
||||
@Query("DELETE FROM feed_group WHERE uid = :groupId")
|
||||
abstract fun delete(groupId: Long): Int
|
||||
|
||||
@Query("SELECT subscription_id FROM feed_group_subscription_join WHERE group_id = :groupId")
|
||||
abstract fun getSubscriptionIdsFor(groupId: Long): Flowable<List<Long>>
|
||||
|
||||
@Query("DELETE FROM feed_group_subscription_join WHERE group_id = :groupId")
|
||||
abstract fun deleteSubscriptionsFromGroup(groupId: Long): Int
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.IGNORE)
|
||||
abstract fun insertSubscriptionsToGroup(entities: List<FeedGroupSubscriptionEntity>): List<Long>
|
||||
|
||||
@Transaction
|
||||
open fun updateSubscriptionsForGroup(groupId: Long, subscriptionIds: List<Long>) {
|
||||
deleteSubscriptionsFromGroup(groupId)
|
||||
insertSubscriptionsToGroup(subscriptionIds.map { FeedGroupSubscriptionEntity(groupId, it) })
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import androidx.room.ColumnInfo
|
|||
import androidx.room.Entity
|
||||
import androidx.room.PrimaryKey
|
||||
import org.schabi.newpipe.database.feed.model.FeedGroupEntity.Companion.FEED_GROUP_TABLE
|
||||
import org.schabi.newpipe.local.subscription.FeedGroupIcon
|
||||
|
||||
@Entity(tableName = FEED_GROUP_TABLE)
|
||||
data class FeedGroupEntity(
|
||||
|
|
@ -15,7 +16,7 @@ data class FeedGroupEntity(
|
|||
var name: String,
|
||||
|
||||
@ColumnInfo(name = ICON)
|
||||
var iconId: Int
|
||||
var icon: FeedGroupIcon
|
||||
) {
|
||||
companion object {
|
||||
const val FEED_GROUP_TABLE = "feed_group"
|
||||
|
|
|
|||
|
|
@ -1,72 +0,0 @@
|
|||
package org.schabi.newpipe.database.subscription;
|
||||
|
||||
import androidx.room.Dao;
|
||||
import androidx.room.Insert;
|
||||
import androidx.room.OnConflictStrategy;
|
||||
import androidx.room.Query;
|
||||
import androidx.room.Transaction;
|
||||
|
||||
import org.schabi.newpipe.database.BasicDAO;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import io.reactivex.Flowable;
|
||||
|
||||
import static org.schabi.newpipe.database.subscription.SubscriptionEntity.SUBSCRIPTION_SERVICE_ID;
|
||||
import static org.schabi.newpipe.database.subscription.SubscriptionEntity.SUBSCRIPTION_TABLE;
|
||||
import static org.schabi.newpipe.database.subscription.SubscriptionEntity.SUBSCRIPTION_UID;
|
||||
import static org.schabi.newpipe.database.subscription.SubscriptionEntity.SUBSCRIPTION_URL;
|
||||
|
||||
@Dao
|
||||
public abstract class SubscriptionDAO implements BasicDAO<SubscriptionEntity> {
|
||||
@Override
|
||||
@Query("SELECT * FROM " + SUBSCRIPTION_TABLE)
|
||||
public abstract Flowable<List<SubscriptionEntity>> getAll();
|
||||
|
||||
@Query("SELECT COUNT(*) FROM subscriptions")
|
||||
public abstract Flowable<Long> rowCount();
|
||||
|
||||
@Override
|
||||
@Query("DELETE FROM " + SUBSCRIPTION_TABLE)
|
||||
public abstract int deleteAll();
|
||||
|
||||
@Override
|
||||
@Query("SELECT * FROM " + SUBSCRIPTION_TABLE + " WHERE " + SUBSCRIPTION_SERVICE_ID + " = :serviceId")
|
||||
public abstract Flowable<List<SubscriptionEntity>> listByService(int serviceId);
|
||||
|
||||
@Query("SELECT * FROM " + SUBSCRIPTION_TABLE + " WHERE " +
|
||||
SUBSCRIPTION_URL + " LIKE :url AND " +
|
||||
SUBSCRIPTION_SERVICE_ID + " = :serviceId")
|
||||
public abstract Flowable<List<SubscriptionEntity>> getSubscription(int serviceId, String url);
|
||||
|
||||
@Query("SELECT " + SUBSCRIPTION_UID + " FROM " + SUBSCRIPTION_TABLE + " WHERE " +
|
||||
SUBSCRIPTION_URL + " LIKE :url AND " +
|
||||
SUBSCRIPTION_SERVICE_ID + " = :serviceId")
|
||||
abstract Long getSubscriptionIdInternal(int serviceId, String url);
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.IGNORE)
|
||||
abstract Long insertInternal(final SubscriptionEntity entities);
|
||||
|
||||
@Transaction
|
||||
public List<SubscriptionEntity> upsertAll(List<SubscriptionEntity> entities) {
|
||||
for (SubscriptionEntity entity : entities) {
|
||||
Long uid = insertInternal(entity);
|
||||
|
||||
if (uid != -1) {
|
||||
entity.setUid(uid);
|
||||
continue;
|
||||
}
|
||||
|
||||
uid = getSubscriptionIdInternal(entity.getServiceId(), entity.getUrl());
|
||||
entity.setUid(uid);
|
||||
|
||||
if (uid == -1) {
|
||||
throw new IllegalStateException("Invalid subscription id (-1)");
|
||||
}
|
||||
|
||||
update(entity);
|
||||
}
|
||||
|
||||
return entities;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
package org.schabi.newpipe.database.subscription
|
||||
|
||||
import androidx.room.*
|
||||
import io.reactivex.Flowable
|
||||
import io.reactivex.Maybe
|
||||
import org.schabi.newpipe.database.BasicDAO
|
||||
|
||||
@Dao
|
||||
abstract class SubscriptionDAO : BasicDAO<SubscriptionEntity> {
|
||||
@Query("SELECT COUNT(*) FROM subscriptions")
|
||||
abstract fun rowCount(): Flowable<Long>
|
||||
|
||||
@Query("SELECT * FROM subscriptions WHERE service_id = :serviceId")
|
||||
abstract override fun listByService(serviceId: Int): Flowable<List<SubscriptionEntity>>
|
||||
|
||||
@Query("SELECT * FROM subscriptions ORDER BY name COLLATE NOCASE ASC")
|
||||
abstract override fun getAll(): Flowable<List<SubscriptionEntity>>
|
||||
|
||||
@Query("SELECT * FROM subscriptions WHERE url LIKE :url AND service_id = :serviceId")
|
||||
abstract fun getSubscriptionFlowable(serviceId: Int, url: String): Flowable<List<SubscriptionEntity>>
|
||||
|
||||
@Query("SELECT * FROM subscriptions WHERE url LIKE :url AND service_id = :serviceId")
|
||||
abstract fun getSubscription(serviceId: Int, url: String): Maybe<SubscriptionEntity>
|
||||
|
||||
@Query("SELECT * FROM subscriptions WHERE uid = :subscriptionId")
|
||||
abstract fun getSubscription(subscriptionId: Long): SubscriptionEntity
|
||||
|
||||
@Query("DELETE FROM subscriptions")
|
||||
abstract override fun deleteAll(): Int
|
||||
|
||||
@Query("DELETE FROM subscriptions WHERE url LIKE :url AND service_id = :serviceId")
|
||||
abstract fun deleteSubscription(serviceId: Int, url: String): Int
|
||||
|
||||
@Query("SELECT uid FROM subscriptions WHERE url LIKE :url AND service_id = :serviceId")
|
||||
internal abstract fun getSubscriptionIdInternal(serviceId: Int, url: String): Long?
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.IGNORE)
|
||||
internal abstract fun silentInsertAllInternal(entities: List<SubscriptionEntity>): List<Long>
|
||||
|
||||
@Transaction
|
||||
open fun upsertAll(entities: List<SubscriptionEntity>): List<SubscriptionEntity> {
|
||||
val insertUidList = silentInsertAllInternal(entities)
|
||||
|
||||
insertUidList.forEachIndexed { index: Int, uidFromInsert: Long ->
|
||||
val entity = entities[index]
|
||||
|
||||
if (uidFromInsert != -1L) {
|
||||
entity.uid = uidFromInsert
|
||||
} else {
|
||||
val subscriptionIdFromDb = getSubscriptionIdInternal(entity.serviceId, entity.url)
|
||||
?: throw IllegalStateException("Subscription cannot be null just after insertion.")
|
||||
entity.uid = subscriptionIdFromDb
|
||||
|
||||
update(entity)
|
||||
}
|
||||
}
|
||||
|
||||
return entities
|
||||
}
|
||||
}
|
||||
|
|
@ -19,14 +19,14 @@ import static org.schabi.newpipe.database.subscription.SubscriptionEntity.SUBSCR
|
|||
indices = {@Index(value = {SUBSCRIPTION_SERVICE_ID, SUBSCRIPTION_URL}, unique = true)})
|
||||
public class SubscriptionEntity {
|
||||
|
||||
public final static String SUBSCRIPTION_UID = "uid";
|
||||
final static String SUBSCRIPTION_TABLE = "subscriptions";
|
||||
final static String SUBSCRIPTION_SERVICE_ID = "service_id";
|
||||
final static String SUBSCRIPTION_URL = "url";
|
||||
final static String SUBSCRIPTION_NAME = "name";
|
||||
final static String SUBSCRIPTION_AVATAR_URL = "avatar_url";
|
||||
final static String SUBSCRIPTION_SUBSCRIBER_COUNT = "subscriber_count";
|
||||
final static String SUBSCRIPTION_DESCRIPTION = "description";
|
||||
public static final String SUBSCRIPTION_UID = "uid";
|
||||
public static final String SUBSCRIPTION_TABLE = "subscriptions";
|
||||
public static final String SUBSCRIPTION_SERVICE_ID = "service_id";
|
||||
public static final String SUBSCRIPTION_URL = "url";
|
||||
public static final String SUBSCRIPTION_NAME = "name";
|
||||
public static final String SUBSCRIPTION_AVATAR_URL = "avatar_url";
|
||||
public static final String SUBSCRIPTION_SUBSCRIBER_COUNT = "subscriber_count";
|
||||
public static final String SUBSCRIPTION_DESCRIPTION = "description";
|
||||
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
private long uid = 0;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue