Add search and watch history (#626)
Add search and watch history * Make MainActicity a single task * Remove some casting * SearchFragment: start searching when created with query * Handle settings change in onResume * History: Log pop up and background playback * History: Add swipe to remove functionallity * Enable history by default * Use stream item * Store more information about the stream * Integrate history database into AppDatabase * Remove redundant casts * Re-enable date converters * History: Use Rx Java and run DB in background * Also make HistoryDAO extend BasicDAO * History: RX-ify swipe to remove * Sort history entries by creation date * History: Set toolbar title * Don't repeat history entries * Introduced setters so we can update entries in the database * If the latest entry has the same (main) values, just update it
This commit is contained in:
parent
09159ec245
commit
c0515de6b7
37 changed files with 1470 additions and 33 deletions
|
|
@ -2,14 +2,25 @@ package org.schabi.newpipe.database;
|
|||
|
||||
import android.arch.persistence.room.Database;
|
||||
import android.arch.persistence.room.RoomDatabase;
|
||||
import android.arch.persistence.room.TypeConverters;
|
||||
|
||||
import org.schabi.newpipe.database.history.dao.SearchHistoryDAO;
|
||||
import org.schabi.newpipe.database.history.dao.WatchHistoryDAO;
|
||||
import org.schabi.newpipe.database.history.model.SearchHistoryEntry;
|
||||
import org.schabi.newpipe.database.history.model.WatchHistoryEntry;
|
||||
import org.schabi.newpipe.database.subscription.SubscriptionDAO;
|
||||
import org.schabi.newpipe.database.subscription.SubscriptionEntity;
|
||||
import org.schabi.newpipe.database.history.Converters;
|
||||
|
||||
@Database(entities = {SubscriptionEntity.class}, version = 1, exportSchema = false)
|
||||
@TypeConverters({Converters.class})
|
||||
@Database(entities = {SubscriptionEntity.class, WatchHistoryEntry.class, SearchHistoryEntry.class}, version = 1, exportSchema = false)
|
||||
public abstract class AppDatabase extends RoomDatabase{
|
||||
|
||||
public static final String DATABASE_NAME = "newpipe.db";
|
||||
|
||||
public abstract SubscriptionDAO subscriptionDAO();
|
||||
|
||||
public abstract WatchHistoryDAO watchHistoryDAO();
|
||||
|
||||
public abstract SearchHistoryDAO searchHistoryDAO();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ import android.arch.persistence.room.Update;
|
|||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import io.reactivex.Completable;
|
||||
import io.reactivex.Flowable;
|
||||
|
||||
@Dao
|
||||
|
|
@ -39,6 +38,8 @@ public interface BasicDAO<Entity> {
|
|||
@Delete
|
||||
int delete(final Collection<Entity> entities);
|
||||
|
||||
int deleteAll();
|
||||
|
||||
/* Updates */
|
||||
@Update
|
||||
int update(final Entity entity);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,28 @@
|
|||
package org.schabi.newpipe.database.history;
|
||||
|
||||
import android.arch.persistence.room.TypeConverter;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
public class Converters {
|
||||
|
||||
/**
|
||||
* Convert a long value to a date
|
||||
* @param value the long value
|
||||
* @return the date
|
||||
*/
|
||||
@TypeConverter
|
||||
public static Date fromTimestamp(Long value) {
|
||||
return value == null ? null : new Date(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a date to a long value
|
||||
* @param date the date
|
||||
* @return the long value
|
||||
*/
|
||||
@TypeConverter
|
||||
public static Long dateToTimestamp(Date date) {
|
||||
return date == null ? null : date.getTime();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
package org.schabi.newpipe.database.history.dao;
|
||||
|
||||
import org.schabi.newpipe.database.BasicDAO;
|
||||
|
||||
public interface HistoryDAO<T> extends BasicDAO<T> {
|
||||
T getLatestEntry();
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
package org.schabi.newpipe.database.history.dao;
|
||||
|
||||
import android.arch.persistence.room.Dao;
|
||||
import android.arch.persistence.room.Query;
|
||||
|
||||
import org.schabi.newpipe.database.history.model.SearchHistoryEntry;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import io.reactivex.Flowable;
|
||||
|
||||
import static org.schabi.newpipe.database.history.model.SearchHistoryEntry.CREATION_DATE;
|
||||
import static org.schabi.newpipe.database.history.model.SearchHistoryEntry.ID;
|
||||
import static org.schabi.newpipe.database.history.model.SearchHistoryEntry.SERVICE_ID;
|
||||
import static org.schabi.newpipe.database.history.model.SearchHistoryEntry.TABLE_NAME;
|
||||
|
||||
@Dao
|
||||
public interface SearchHistoryDAO extends HistoryDAO<SearchHistoryEntry> {
|
||||
|
||||
String ORDER_BY_CREATION_DATE = " ORDER BY " + CREATION_DATE + " DESC";
|
||||
|
||||
@Query("SELECT * FROM " + TABLE_NAME + " WHERE " + ID + " = (SELECT MAX(" + ID + ") FROM " + TABLE_NAME + ")")
|
||||
@Override
|
||||
SearchHistoryEntry getLatestEntry();
|
||||
|
||||
@Query("DELETE FROM " + TABLE_NAME)
|
||||
@Override
|
||||
int deleteAll();
|
||||
|
||||
@Query("SELECT * FROM " + TABLE_NAME + ORDER_BY_CREATION_DATE)
|
||||
@Override
|
||||
Flowable<List<SearchHistoryEntry>> findAll();
|
||||
|
||||
@Query("SELECT * FROM " + TABLE_NAME + " WHERE " + SERVICE_ID + " = :serviceId" + ORDER_BY_CREATION_DATE)
|
||||
@Override
|
||||
Flowable<List<SearchHistoryEntry>> listByService(int serviceId);
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
package org.schabi.newpipe.database.history.dao;
|
||||
|
||||
import android.arch.persistence.room.Dao;
|
||||
import android.arch.persistence.room.Query;
|
||||
|
||||
import org.schabi.newpipe.database.history.model.WatchHistoryEntry;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import io.reactivex.Flowable;
|
||||
|
||||
import static org.schabi.newpipe.database.history.model.WatchHistoryEntry.CREATION_DATE;
|
||||
import static org.schabi.newpipe.database.history.model.WatchHistoryEntry.ID;
|
||||
import static org.schabi.newpipe.database.history.model.WatchHistoryEntry.SERVICE_ID;
|
||||
import static org.schabi.newpipe.database.history.model.WatchHistoryEntry.TABLE_NAME;
|
||||
|
||||
@Dao
|
||||
public interface WatchHistoryDAO extends HistoryDAO<WatchHistoryEntry> {
|
||||
|
||||
String ORDER_BY_CREATION_DATE = " ORDER BY " + CREATION_DATE + " DESC";
|
||||
|
||||
@Query("SELECT * FROM " + TABLE_NAME + " WHERE " + ID + " = (SELECT MAX(" + ID + ") FROM " + TABLE_NAME + ")")
|
||||
@Override
|
||||
WatchHistoryEntry getLatestEntry();
|
||||
|
||||
@Query("DELETE FROM " + TABLE_NAME)
|
||||
@Override
|
||||
int deleteAll();
|
||||
|
||||
@Query("SELECT * FROM " + TABLE_NAME + ORDER_BY_CREATION_DATE)
|
||||
@Override
|
||||
Flowable<List<WatchHistoryEntry>> findAll();
|
||||
|
||||
@Query("SELECT * FROM " + TABLE_NAME + " WHERE " + SERVICE_ID + " = :serviceId" + ORDER_BY_CREATION_DATE)
|
||||
@Override
|
||||
Flowable<List<WatchHistoryEntry>> listByService(int serviceId);
|
||||
}
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
package org.schabi.newpipe.database.history.model;
|
||||
|
||||
import android.arch.persistence.room.ColumnInfo;
|
||||
import android.arch.persistence.room.Entity;
|
||||
import android.arch.persistence.room.Ignore;
|
||||
import android.arch.persistence.room.PrimaryKey;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
@Entity
|
||||
public abstract class HistoryEntry {
|
||||
|
||||
public static final String ID = "id";
|
||||
public static final String SERVICE_ID = "service_id";
|
||||
public static final String CREATION_DATE = "creation_date";
|
||||
|
||||
@ColumnInfo(name = CREATION_DATE)
|
||||
private Date creationDate;
|
||||
|
||||
@ColumnInfo(name = SERVICE_ID)
|
||||
private int serviceId;
|
||||
|
||||
@ColumnInfo(name = ID)
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
private long id;
|
||||
|
||||
public HistoryEntry(Date creationDate, int serviceId) {
|
||||
this.serviceId = serviceId;
|
||||
this.creationDate = creationDate;
|
||||
}
|
||||
|
||||
public long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Date getCreationDate() {
|
||||
return creationDate;
|
||||
}
|
||||
|
||||
public void setCreationDate(Date creationDate) {
|
||||
this.creationDate = creationDate;
|
||||
}
|
||||
|
||||
public int getServiceId() {
|
||||
return serviceId;
|
||||
}
|
||||
|
||||
public void setServiceId(int serviceId) {
|
||||
this.serviceId = serviceId;
|
||||
}
|
||||
|
||||
@Ignore
|
||||
public boolean hasEqualValues(HistoryEntry otherEntry) {
|
||||
return otherEntry != null && getServiceId() == otherEntry.getServiceId();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
package org.schabi.newpipe.database.history.model;
|
||||
|
||||
import android.arch.persistence.room.ColumnInfo;
|
||||
import android.arch.persistence.room.Entity;
|
||||
import android.arch.persistence.room.Ignore;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
@Entity(tableName = SearchHistoryEntry.TABLE_NAME)
|
||||
public class SearchHistoryEntry extends HistoryEntry {
|
||||
|
||||
public static final String TABLE_NAME = "search_history";
|
||||
public static final String SEARCH = "search";
|
||||
|
||||
@ColumnInfo(name = SEARCH)
|
||||
private String search;
|
||||
|
||||
public SearchHistoryEntry(Date creationDate, int serviceId, String search) {
|
||||
super(creationDate, serviceId);
|
||||
this.search = search;
|
||||
}
|
||||
|
||||
public String getSearch() {
|
||||
return search;
|
||||
}
|
||||
|
||||
public void setSearch(String search) {
|
||||
this.search = search;
|
||||
}
|
||||
|
||||
@Ignore
|
||||
@Override
|
||||
public boolean hasEqualValues(HistoryEntry otherEntry) {
|
||||
return otherEntry instanceof SearchHistoryEntry && super.hasEqualValues(otherEntry)
|
||||
&& getSearch().equals(((SearchHistoryEntry) otherEntry).getSearch());
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,109 @@
|
|||
package org.schabi.newpipe.database.history.model;
|
||||
|
||||
import android.arch.persistence.room.ColumnInfo;
|
||||
import android.arch.persistence.room.Entity;
|
||||
import android.arch.persistence.room.Ignore;
|
||||
|
||||
import org.schabi.newpipe.extractor.stream_info.StreamInfo;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
@Entity(tableName = WatchHistoryEntry.TABLE_NAME)
|
||||
public class WatchHistoryEntry extends HistoryEntry {
|
||||
|
||||
public static final String TABLE_NAME = "watch_history";
|
||||
public static final String TITLE = "title";
|
||||
public static final String URL = "url";
|
||||
public static final String STREAM_ID = "stream_id";
|
||||
public static final String THUMBNAIL_URL = "thumbnail_url";
|
||||
public static final String UPLOADER = "uploader";
|
||||
public static final String DURATION = "duration";
|
||||
|
||||
@ColumnInfo(name = TITLE)
|
||||
private String title;
|
||||
|
||||
@ColumnInfo(name = URL)
|
||||
private String url;
|
||||
|
||||
@ColumnInfo(name = STREAM_ID)
|
||||
private String streamId;
|
||||
|
||||
@ColumnInfo(name = THUMBNAIL_URL)
|
||||
private String thumbnailURL;
|
||||
|
||||
@ColumnInfo(name = UPLOADER)
|
||||
private String uploader;
|
||||
|
||||
@ColumnInfo(name = DURATION)
|
||||
private int duration;
|
||||
|
||||
public WatchHistoryEntry(Date creationDate, int serviceId, String title, String url, String streamId, String thumbnailURL, String uploader, int duration) {
|
||||
super(creationDate, serviceId);
|
||||
this.title = title;
|
||||
this.url = url;
|
||||
this.streamId = streamId;
|
||||
this.thumbnailURL = thumbnailURL;
|
||||
this.uploader = uploader;
|
||||
this.duration = duration;
|
||||
}
|
||||
|
||||
public WatchHistoryEntry(StreamInfo streamInfo) {
|
||||
this(new Date(), streamInfo.service_id, streamInfo.title, streamInfo.webpage_url,
|
||||
streamInfo.id, streamInfo.thumbnail_url, streamInfo.uploader, streamInfo.duration);
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
public void setUrl(String url) {
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public String getStreamId() {
|
||||
return streamId;
|
||||
}
|
||||
|
||||
public void setStreamId(String streamId) {
|
||||
this.streamId = streamId;
|
||||
}
|
||||
|
||||
public String getThumbnailURL() {
|
||||
return thumbnailURL;
|
||||
}
|
||||
|
||||
public void setThumbnailURL(String thumbnailURL) {
|
||||
this.thumbnailURL = thumbnailURL;
|
||||
}
|
||||
|
||||
public String getUploader() {
|
||||
return uploader;
|
||||
}
|
||||
|
||||
public void setUploader(String uploader) {
|
||||
this.uploader = uploader;
|
||||
}
|
||||
|
||||
public int getDuration() {
|
||||
return duration;
|
||||
}
|
||||
|
||||
public void setDuration(int duration) {
|
||||
this.duration = duration;
|
||||
}
|
||||
|
||||
@Ignore
|
||||
@Override
|
||||
public boolean hasEqualValues(HistoryEntry otherEntry) {
|
||||
return otherEntry instanceof WatchHistoryEntry && super.hasEqualValues(otherEntry)
|
||||
&& getUrl().equals(((WatchHistoryEntry) otherEntry).getUrl());
|
||||
}
|
||||
}
|
||||
|
|
@ -19,6 +19,10 @@ public interface SubscriptionDAO extends BasicDAO<SubscriptionEntity> {
|
|||
@Query("SELECT * FROM " + SUBSCRIPTION_TABLE)
|
||||
Flowable<List<SubscriptionEntity>> findAll();
|
||||
|
||||
@Override
|
||||
@Query("DELETE FROM " + SUBSCRIPTION_TABLE)
|
||||
int deleteAll();
|
||||
|
||||
@Override
|
||||
@Query("SELECT * FROM " + SUBSCRIPTION_TABLE + " WHERE " + SUBSCRIPTION_SERVICE_ID + " = :serviceId")
|
||||
Flowable<List<SubscriptionEntity>> listByService(int serviceId);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue