mirror of
https://gitlab.futo.org/videostreaming/grayjay.git
synced 2025-04-20 03:24:50 +00:00
WIP Store/testing
This commit is contained in:
parent
10e3d2122f
commit
99c06c516f
15 changed files with 439 additions and 29 deletions
|
@ -39,7 +39,7 @@ protobuf {
|
|||
|
||||
android {
|
||||
namespace 'com.futo.platformplayer'
|
||||
compileSdk 33
|
||||
compileSdk 34
|
||||
flavorDimensions "buildType"
|
||||
productFlavors {
|
||||
stable {
|
||||
|
|
|
@ -1,24 +1,18 @@
|
|||
package com.futo.platformplayer.states
|
||||
|
||||
import android.Manifest
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import android.content.pm.PackageManager
|
||||
import android.media.AudioManager
|
||||
import android.net.ConnectivityManager
|
||||
import android.net.Network
|
||||
import android.net.NetworkCapabilities
|
||||
import android.net.NetworkRequest
|
||||
import android.net.Uri
|
||||
import android.os.Environment
|
||||
import android.provider.DocumentsContract
|
||||
import android.util.DisplayMetrics
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.core.net.toUri
|
||||
import androidx.documentfile.provider.DocumentFile
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
|
@ -28,10 +22,9 @@ import com.futo.platformplayer.R
|
|||
import com.futo.platformplayer.activities.CaptchaActivity
|
||||
import com.futo.platformplayer.activities.IWithResultLauncher
|
||||
import com.futo.platformplayer.activities.MainActivity
|
||||
import com.futo.platformplayer.api.media.Serializer
|
||||
import com.futo.platformplayer.api.media.models.video.SerializedPlatformVideo
|
||||
import com.futo.platformplayer.api.media.platforms.js.DevJSClient
|
||||
import com.futo.platformplayer.api.media.platforms.js.JSClient
|
||||
import com.futo.platformplayer.api.media.platforms.js.internal.JSHttpClient
|
||||
import com.futo.platformplayer.background.BackgroundWorker
|
||||
import com.futo.platformplayer.cache.ChannelContentCache
|
||||
import com.futo.platformplayer.casting.StateCasting
|
||||
|
@ -43,20 +36,20 @@ import com.futo.platformplayer.logging.AndroidLogConsumer
|
|||
import com.futo.platformplayer.logging.FileLogConsumer
|
||||
import com.futo.platformplayer.logging.LogLevel
|
||||
import com.futo.platformplayer.logging.Logger
|
||||
import com.futo.platformplayer.models.HistoryVideo
|
||||
import com.futo.platformplayer.receivers.AudioNoisyReceiver
|
||||
import com.futo.platformplayer.services.DownloadService
|
||||
import com.futo.platformplayer.stores.FragmentedStorage
|
||||
import com.futo.platformplayer.stores.db.types.DBHistory
|
||||
import com.futo.platformplayer.stores.v2.ManagedStore
|
||||
import com.stripe.android.core.utils.encodeToJson
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.serialization.encodeToString
|
||||
import kotlinx.serialization.decodeFromString
|
||||
import kotlinx.serialization.json.Json
|
||||
import java.io.File
|
||||
import java.time.OffsetDateTime
|
||||
import java.util.*
|
||||
import java.util.concurrent.TimeUnit
|
||||
import kotlin.system.measureTimeMillis
|
||||
import kotlin.time.measureTime
|
||||
|
||||
/***
|
||||
* This class contains global context for unconventional cases where obtaining context is hard.
|
||||
|
@ -545,7 +538,73 @@ class StateApp {
|
|||
|
||||
StateAnnouncement.instance.registerDidYouKnow();
|
||||
Logger.i(TAG, "MainApp Started: Finished");
|
||||
|
||||
|
||||
if(true) {
|
||||
Logger.i(TAG, "TEST:--------(200)---------");
|
||||
testHistoryDB(200);
|
||||
Logger.i(TAG, "TEST:--------(1000)---------");
|
||||
testHistoryDB(1000);
|
||||
Logger.i(TAG, "TEST:--------(2000)---------");
|
||||
testHistoryDB(2000);
|
||||
Logger.i(TAG, "TEST:--------(4000)---------");
|
||||
testHistoryDB(4000);
|
||||
Logger.i(TAG, "TEST:--------(6000)---------");
|
||||
testHistoryDB(6000);
|
||||
}
|
||||
}
|
||||
fun testHistoryDB(count: Int) {
|
||||
Logger.i(TAG, "TEST: Starting tests");
|
||||
StatePlaylists.instance._historyDBStore.deleteAll();
|
||||
|
||||
val testHistoryItem = StatePlaylists.instance.getHistory().first();
|
||||
val testItemJson = StatePlaylists.instance.getHistory().first().video.toJson();
|
||||
val now = OffsetDateTime.now();
|
||||
|
||||
val testSet = (0..count).map { HistoryVideo(Json.decodeFromString<SerializedPlatformVideo>(testItemJson.replace(testHistoryItem.video.url, UUID.randomUUID().toString())), it.toLong(), now.minusHours(it.toLong())) }
|
||||
|
||||
|
||||
Logger.i(TAG, "TEST: Inserting (${testSet.size})");
|
||||
val insertMS = measureTimeMillis {
|
||||
for(item in testSet)
|
||||
StatePlaylists.instance._historyDBStore.insert(item);
|
||||
};
|
||||
Logger.i(TAG, "TEST: Inserting in ${insertMS}ms");
|
||||
|
||||
var fetched: List<DBHistory.Index>? = null;
|
||||
val fetchMS = measureTimeMillis {
|
||||
fetched = StatePlaylists.instance._historyDBStore.getAll();
|
||||
Logger.i(TAG, "TEST: Fetched: ${fetched?.size}");
|
||||
};
|
||||
Logger.i(TAG, "TEST: Fetch speed ${fetchMS}MS");
|
||||
val deserializeMS = measureTimeMillis {
|
||||
val deserialized = StatePlaylists.instance._historyDBStore.convertObjects(fetched!!);
|
||||
Logger.i(TAG, "TEST: Deserialized: ${deserialized.size}");
|
||||
};
|
||||
Logger.i(TAG, "TEST: Deserialize speed ${deserializeMS}MS");
|
||||
|
||||
var fetchedIndex: List<DBHistory.Index>? = null;
|
||||
val fetchIndexMS = measureTimeMillis {
|
||||
fetchedIndex = StatePlaylists.instance._historyDBStore.getAllIndexes();
|
||||
Logger.i(TAG, "TEST: Fetched Index: ${fetchedIndex!!.size}");
|
||||
};
|
||||
Logger.i(TAG, "TEST: Fetched Index speed ${fetchIndexMS}ms");
|
||||
val fetchFromIndex = measureTimeMillis {
|
||||
for(preItem in testSet) {
|
||||
val item = StatePlaylists.instance.historyIndex[preItem.video.url];
|
||||
if(item == null)
|
||||
throw IllegalStateException("Missing item [${preItem.video.url}]");
|
||||
if(item.url != preItem.video.url)
|
||||
throw IllegalStateException("Mismatch item [${preItem.video.url}]");
|
||||
}
|
||||
};
|
||||
Logger.i(TAG, "TEST: Index Lookup speed ${fetchFromIndex}ms");
|
||||
|
||||
val page1 = StatePlaylists.instance._historyDBStore.getPage(0, 20);
|
||||
val page2 = StatePlaylists.instance._historyDBStore.getPage(1, 20);
|
||||
val page3 = StatePlaylists.instance._historyDBStore.getPage(2, 20);
|
||||
}
|
||||
|
||||
fun mainAppStartedWithExternalFiles(context: Context) {
|
||||
if(!Settings.instance.didFirstStart) {
|
||||
if(StateBackup.hasAutomaticBackup()) {
|
||||
|
|
|
@ -3,6 +3,7 @@ package com.futo.platformplayer.states
|
|||
import android.content.Context
|
||||
import android.net.Uri
|
||||
import androidx.core.content.FileProvider
|
||||
import androidx.sqlite.db.SimpleSQLiteQuery
|
||||
import com.futo.platformplayer.R
|
||||
import com.futo.platformplayer.api.media.PlatformID
|
||||
import com.futo.platformplayer.api.media.exceptions.NoPlatformClientException
|
||||
|
@ -19,6 +20,8 @@ import com.futo.platformplayer.logging.Logger
|
|||
import com.futo.platformplayer.models.HistoryVideo
|
||||
import com.futo.platformplayer.models.Playlist
|
||||
import com.futo.platformplayer.stores.FragmentedStorage
|
||||
import com.futo.platformplayer.stores.db.ManagedDBStore
|
||||
import com.futo.platformplayer.stores.db.types.DBHistory
|
||||
import com.futo.platformplayer.stores.v2.ManagedStore
|
||||
import com.futo.platformplayer.stores.v2.ReconstructStore
|
||||
import kotlinx.serialization.encodeToString
|
||||
|
@ -26,6 +29,8 @@ import kotlinx.serialization.json.Json
|
|||
import java.io.File
|
||||
import java.time.OffsetDateTime
|
||||
import java.time.temporal.ChronoUnit
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
import java.util.concurrent.ConcurrentMap
|
||||
|
||||
/***
|
||||
* Used to maintain playlists
|
||||
|
@ -50,6 +55,11 @@ class StatePlaylists {
|
|||
.withRestore(PlaylistBackup())
|
||||
.load();
|
||||
|
||||
val historyIndex: ConcurrentMap<Any, DBHistory.Index> = ConcurrentHashMap();
|
||||
val _historyDBStore = ManagedDBStore.create("history", DBHistory.Descriptor())
|
||||
.withIndex({ it.url }, historyIndex)
|
||||
.load();
|
||||
|
||||
val playlistShareDir = FragmentedStorage.getOrCreateDirectory("shares");
|
||||
|
||||
var onHistoricVideoChanged = Event2<IPlatformVideo, Long>();
|
||||
|
|
|
@ -2,6 +2,8 @@ package com.futo.platformplayer.stores
|
|||
|
||||
import com.futo.platformplayer.Settings
|
||||
import com.futo.platformplayer.logging.Logger
|
||||
import com.futo.platformplayer.stores.db.ManagedDBIndex
|
||||
import com.futo.platformplayer.stores.db.ManagedDBStore
|
||||
import com.futo.platformplayer.stores.v2.JsonStoreSerializer
|
||||
import com.futo.platformplayer.stores.v2.ManagedStore
|
||||
import com.futo.platformplayer.stores.v2.StoreSerializer
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
package com.futo.platformplayer.stores.db
|
||||
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Delete
|
||||
import androidx.room.Insert
|
||||
import androidx.room.Query
|
||||
import androidx.room.Update
|
||||
|
||||
/*
|
||||
@Dao
|
||||
class ManagedDBContext<T, I: ManagedDBIndex<T>> {
|
||||
|
||||
fun get(id: Int): I;
|
||||
fun gets(vararg id: Int): List<I>;
|
||||
fun getAll(): List<I>;
|
||||
|
||||
@Insert
|
||||
fun insert(index: I);
|
||||
@Insert
|
||||
fun insertAll(vararg indexes: I)
|
||||
|
||||
@Update
|
||||
fun update(index: I);
|
||||
|
||||
@Delete
|
||||
fun delete(index: I);
|
||||
}*/
|
|
@ -0,0 +1,11 @@
|
|||
package com.futo.platformplayer.stores.db
|
||||
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Delete
|
||||
import androidx.room.Insert
|
||||
import androidx.room.Update
|
||||
|
||||
@Dao
|
||||
interface ManagedDBContextPaged<T, I: ManagedDBIndex<T>> {
|
||||
fun getPaged(page: Int, pageSize: Int): List<I>;
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
package com.futo.platformplayer.stores.db
|
||||
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Delete
|
||||
import androidx.room.Insert
|
||||
import androidx.room.Query
|
||||
import androidx.room.RawQuery
|
||||
import androidx.room.Update
|
||||
import androidx.sqlite.db.SupportSQLiteQuery
|
||||
|
||||
|
||||
@Dao
|
||||
interface ManagedDBDAOBase<T, I: ManagedDBIndex<T>> {
|
||||
|
||||
@RawQuery
|
||||
fun get(query: SupportSQLiteQuery): I;
|
||||
@RawQuery
|
||||
fun getMultiple(query: SupportSQLiteQuery): List<I>;
|
||||
|
||||
@RawQuery
|
||||
fun action(query: SupportSQLiteQuery): Int
|
||||
|
||||
@Insert
|
||||
fun insert(index: I): Long;
|
||||
@Insert
|
||||
fun insertAll(vararg indexes: I)
|
||||
|
||||
@Update
|
||||
fun update(index: I);
|
||||
|
||||
@Delete
|
||||
fun delete(index: I);
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
package com.futo.platformplayer.stores.db
|
||||
|
||||
import androidx.room.RoomDatabase
|
||||
|
||||
abstract class ManagedDBDatabase<T, I: ManagedDBIndex<T>, D: ManagedDBDAOBase<T, I>>: RoomDatabase() {
|
||||
abstract fun base(): D;
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
package com.futo.platformplayer.stores.db
|
||||
|
||||
import androidx.sqlite.db.SimpleSQLiteQuery
|
||||
import com.futo.platformplayer.models.HistoryVideo
|
||||
import com.futo.platformplayer.stores.db.types.DBHistory
|
||||
|
||||
|
||||
abstract class ManagedDBDescriptor<T, I: ManagedDBIndex<T>, D: ManagedDBDatabase<T, I, DA>, DA: ManagedDBDAOBase<T, I>> {
|
||||
abstract fun dbClass(): Class<D>;
|
||||
abstract fun create(obj: T): I;
|
||||
|
||||
open val ordered: String? = null;
|
||||
|
||||
open fun sqlIndexOnly(tableName: String): SimpleSQLiteQuery? = null;
|
||||
open fun sqlPage(tableName: String, page: Int, length: Int): SimpleSQLiteQuery? = null;
|
||||
}
|
|
@ -1,8 +1,14 @@
|
|||
package com.futo.platformplayer.stores.db
|
||||
|
||||
import androidx.room.ColumnInfo
|
||||
import androidx.room.Ignore
|
||||
import androidx.room.PrimaryKey
|
||||
import com.futo.platformplayer.api.media.Serializer
|
||||
|
||||
open class ManagedDBIndex(
|
||||
@PrimaryKey(true)
|
||||
val id: Int? = null
|
||||
)
|
||||
interface ManagedDBIndex<T> {
|
||||
var id: Long?
|
||||
var serialized: ByteArray?
|
||||
|
||||
@get:Ignore
|
||||
var obj: T?;
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
package com.futo.platformplayer.stores.db
|
||||
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Delete
|
||||
import androidx.room.Insert
|
||||
import androidx.room.Update
|
||||
|
||||
@Dao
|
||||
interface ManagedDBIndexOnly<T, I: ManagedDBIndex<T>> {
|
||||
fun getIndex(): List<I>;
|
||||
}
|
|
@ -1,28 +1,40 @@
|
|||
package com.futo.platformplayer.stores.db
|
||||
|
||||
import androidx.room.Room
|
||||
import androidx.sqlite.db.SimpleSQLiteQuery
|
||||
import com.futo.platformplayer.assume
|
||||
import com.futo.platformplayer.stores.v2.ManagedStore
|
||||
import com.futo.platformplayer.stores.v2.ReconstructStore
|
||||
import com.futo.platformplayer.states.StateApp
|
||||
import com.futo.platformplayer.stores.v2.JsonStoreSerializer
|
||||
import com.futo.platformplayer.stores.v2.StoreSerializer
|
||||
import java.io.File
|
||||
import kotlinx.serialization.KSerializer
|
||||
import java.util.concurrent.ConcurrentMap
|
||||
import kotlin.reflect.KClass
|
||||
import kotlin.reflect.KType
|
||||
|
||||
class ManagedDBStore<I, T> {
|
||||
class ManagedDBStore<I: ManagedDBIndex<T>, T, D: ManagedDBDatabase<T, I, DA>, DA: ManagedDBDAOBase<T, I>> {
|
||||
private val _class: KType;
|
||||
private val _name: String;
|
||||
private val _serializer: StoreSerializer<T>;
|
||||
|
||||
private var _db: ManagedDBDatabase<T, I, *>? = null;
|
||||
private var _dbDaoBase: ManagedDBDAOBase<T, I>? = null;
|
||||
val dbDaoBase: ManagedDBDAOBase<T, I> get() = _dbDaoBase ?: throw IllegalStateException("Not initialized db [${name}]");
|
||||
|
||||
private var _isLoaded = false;
|
||||
private var _dbDescriptor: ManagedDBDescriptor<T, I, D, DA>;
|
||||
|
||||
private var _withUnique: ((I) -> Any)? = null;
|
||||
private val _sqlAll: SimpleSQLiteQuery;
|
||||
private val _sqlDeleteAll: SimpleSQLiteQuery;
|
||||
private var _sqlIndexed: SimpleSQLiteQuery? = null;
|
||||
|
||||
val className: String? get() = _class.classifier?.assume<KClass<*>>()?.simpleName;
|
||||
|
||||
val name: String;
|
||||
|
||||
constructor(name: String, clazz: KType, serializer: StoreSerializer<T>, niceName: String? = null) {
|
||||
private val _indexes: ArrayList<Pair<(I)->Any, ConcurrentMap<Any, I>>> = arrayListOf();
|
||||
|
||||
|
||||
constructor(name: String, descriptor: ManagedDBDescriptor<T, I, D, DA>, clazz: KType, serializer: StoreSerializer<T>, niceName: String? = null) {
|
||||
_dbDescriptor = descriptor;
|
||||
_name = name;
|
||||
this.name = niceName ?: name.let {
|
||||
if(it.isNotEmpty())
|
||||
|
@ -31,11 +43,119 @@ class ManagedDBStore<I, T> {
|
|||
};
|
||||
_serializer = serializer;
|
||||
_class = clazz;
|
||||
|
||||
_sqlAll = SimpleSQLiteQuery("SELECT * FROM $_name" + if(descriptor.ordered.isNullOrEmpty()) "" else " ${descriptor.ordered}");
|
||||
_sqlDeleteAll = SimpleSQLiteQuery("DELETE FROM ${_name}");
|
||||
_sqlIndexed = descriptor.sqlIndexOnly(_name);
|
||||
}
|
||||
|
||||
fun load() {
|
||||
throw NotImplementedError();
|
||||
_isLoaded = true;
|
||||
fun withIndex(keySelector: (I)->Any, indexContainer: ConcurrentMap<Any, I>): ManagedDBStore<I, T, D, DA> {
|
||||
if(_sqlIndexed == null)
|
||||
throw IllegalStateException("Can only create indexes if sqlIndexOnly is implemented");
|
||||
_indexes.add(Pair(keySelector, indexContainer));
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
fun load(): ManagedDBStore<I, T, D, DA> {
|
||||
_db = Room.databaseBuilder(StateApp.instance.context, _dbDescriptor.dbClass(), _name)
|
||||
.fallbackToDestructiveMigration()
|
||||
.allowMainThreadQueries()
|
||||
.build()
|
||||
_dbDaoBase = _db!!.base() as ManagedDBDAOBase<T, I>;
|
||||
if(_indexes.any()) {
|
||||
val allItems = _dbDaoBase!!.getMultiple(_sqlIndexed!!);
|
||||
for(index in _indexes)
|
||||
index.second.putAll(allItems.associateBy(index.first));
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
fun insert(obj: T) {
|
||||
val newIndex = _dbDescriptor.create(obj);
|
||||
newIndex.serialized = serialize(obj);
|
||||
newIndex.id = dbDaoBase.insert(newIndex);
|
||||
newIndex.serialized = null;
|
||||
|
||||
if(!_indexes.isEmpty()) {
|
||||
for (index in _indexes) {
|
||||
val key = index.first(newIndex);
|
||||
index.second.put(key, newIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
fun update(id: Long, obj: T) {
|
||||
val newIndex = _dbDescriptor.create(obj);
|
||||
newIndex.id = id;
|
||||
newIndex.serialized = serialize(obj);
|
||||
dbDaoBase.update(newIndex);
|
||||
newIndex.serialized = null;
|
||||
|
||||
if(!_indexes.isEmpty()) {
|
||||
for (index in _indexes) {
|
||||
val key = index.first(newIndex);
|
||||
index.second.put(key, newIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun getAllIndexes(): List<I> {
|
||||
if(_sqlIndexed == null)
|
||||
throw IllegalStateException("Can only create indexes if sqlIndexOnly is implemented");
|
||||
return dbDaoBase.getMultiple(_sqlIndexed!!);
|
||||
}
|
||||
|
||||
fun getAllObjects(): List<T> = convertObjects(getAll());
|
||||
fun getAll(): List<I> {
|
||||
return dbDaoBase.getMultiple(_sqlAll);
|
||||
}
|
||||
|
||||
fun getObject(id: Long) = convertObject(get(id));
|
||||
fun get(id: Long): I {
|
||||
return dbDaoBase.get(SimpleSQLiteQuery("SELECT * FROM $_name WHERE id = ?", arrayOf(id)));
|
||||
}
|
||||
|
||||
fun getAllObjects(vararg id: Long): List<T> = convertObjects(getAll(*id));
|
||||
fun getAll(vararg id: Long): List<I> {
|
||||
return dbDaoBase.getMultiple(SimpleSQLiteQuery("SELECT * FROM $_name WHERE id IN (?)", arrayOf(id)));
|
||||
}
|
||||
|
||||
fun getPageObjects(page: Int, length: Int): List<T> = convertObjects(getPage(page, length));
|
||||
fun getPage(page: Int, length: Int): List<I> {
|
||||
val query = _dbDescriptor.sqlPage(_name, page, length) ?: throw IllegalStateException("Paged db not setup for ${_name}");
|
||||
return dbDaoBase.getMultiple(query);
|
||||
}
|
||||
fun delete(item: I) {
|
||||
dbDaoBase.delete(item);
|
||||
|
||||
for(index in _indexes)
|
||||
index.second.remove(index.first(item));
|
||||
}
|
||||
fun deleteAll() {
|
||||
dbDaoBase.action(_sqlDeleteAll);
|
||||
|
||||
for(index in _indexes)
|
||||
index.second.clear();
|
||||
}
|
||||
|
||||
|
||||
fun convertObject(index: ManagedDBIndex<T>): T? {
|
||||
return index.serialized?.let {
|
||||
_serializer.deserialize(_class, it);
|
||||
};
|
||||
}
|
||||
fun convertObjects(indexes: List<ManagedDBIndex<T>>): List<T> {
|
||||
return indexes.mapNotNull { convertObject(it) };
|
||||
}
|
||||
|
||||
fun serialize(obj: T): ByteArray {
|
||||
return _serializer.serialize(_class, obj);
|
||||
}
|
||||
|
||||
companion object {
|
||||
inline fun <reified T, I: ManagedDBIndex<T>, D: ManagedDBDatabase<T, I, DA>, DA: ManagedDBDAOBase<T, I>> create(name: String, descriptor: ManagedDBDescriptor<T, I, D, DA>, serializer: KSerializer<T>? = null)
|
||||
= ManagedDBStore(name, descriptor, kotlin.reflect.typeOf<T>(), JsonStoreSerializer.create(serializer));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
package com.futo.platformplayer.stores.db.types
|
||||
|
||||
import androidx.room.ColumnInfo
|
||||
import androidx.room.Ignore
|
||||
import androidx.room.PrimaryKey
|
||||
import com.futo.platformplayer.api.media.models.video.SerializedPlatformContent
|
||||
import com.futo.platformplayer.models.HistoryVideo
|
||||
import com.futo.platformplayer.stores.db.ManagedDBIndex
|
||||
|
||||
class DBChannelCache {
|
||||
companion object {
|
||||
const val TABLE_NAME = "channelCache";
|
||||
}
|
||||
|
||||
class Index: ManagedDBIndex<SerializedPlatformContent> {
|
||||
@PrimaryKey(true)
|
||||
override var id: Long? = null;
|
||||
@ColumnInfo(typeAffinity = ColumnInfo.BLOB)
|
||||
override var serialized: ByteArray? = null;
|
||||
|
||||
@Ignore
|
||||
override var obj: SerializedPlatformContent? = null;
|
||||
|
||||
var feedType: String? = null;
|
||||
var channelUrl: String? = null;
|
||||
|
||||
|
||||
constructor() {}
|
||||
constructor(sCache: SerializedPlatformContent) {
|
||||
id = null;
|
||||
serialized = null;
|
||||
obj = sCache;
|
||||
channelUrl = sCache.author.url;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
package com.futo.platformplayer.stores.db.types
|
||||
|
||||
import androidx.room.ColumnInfo
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Database
|
||||
import androidx.room.Entity
|
||||
import androidx.room.Ignore
|
||||
import androidx.room.PrimaryKey
|
||||
import androidx.room.Query
|
||||
import androidx.sqlite.db.SimpleSQLiteQuery
|
||||
import com.futo.platformplayer.api.media.models.video.SerializedPlatformContent
|
||||
import com.futo.platformplayer.models.HistoryVideo
|
||||
import com.futo.platformplayer.stores.db.ManagedDBDAOBase
|
||||
import com.futo.platformplayer.stores.db.ManagedDBDatabase
|
||||
import com.futo.platformplayer.stores.db.ManagedDBDescriptor
|
||||
import com.futo.platformplayer.stores.db.ManagedDBIndex
|
||||
import com.futo.platformplayer.stores.db.ManagedDBStore
|
||||
import kotlin.reflect.KType
|
||||
|
||||
class DBHistory {
|
||||
companion object {
|
||||
const val TABLE_NAME = "history";
|
||||
}
|
||||
|
||||
@Dao
|
||||
interface DBDAO: ManagedDBDAOBase<HistoryVideo, Index> {}
|
||||
@Database(entities = [Index::class], version = 2)
|
||||
abstract class DB: ManagedDBDatabase<HistoryVideo, Index, DBDAO>() {
|
||||
abstract override fun base(): DBDAO;
|
||||
}
|
||||
|
||||
class Descriptor: ManagedDBDescriptor<HistoryVideo, Index, DB, DBDAO>() {
|
||||
override fun create(obj: HistoryVideo): Index = Index(obj);
|
||||
override fun dbClass(): Class<DB> = DB::class.java;
|
||||
|
||||
//Optional
|
||||
override fun sqlIndexOnly(tableName: String): SimpleSQLiteQuery = SimpleSQLiteQuery("SELECT id, url, position, date FROM $TABLE_NAME");
|
||||
override fun sqlPage(tableName: String, page: Int, length: Int): SimpleSQLiteQuery = SimpleSQLiteQuery("SELECT * FROM $TABLE_NAME ORDER BY date DESC, id DESC LIMIT ? OFFSET ?", arrayOf(length, page * length));
|
||||
}
|
||||
|
||||
@Entity(TABLE_NAME)
|
||||
class Index: ManagedDBIndex<HistoryVideo> {
|
||||
@PrimaryKey(true)
|
||||
override var id: Long? = null;
|
||||
@ColumnInfo(typeAffinity = ColumnInfo.BLOB)
|
||||
override var serialized: ByteArray? = null;
|
||||
|
||||
@Ignore
|
||||
override var obj: HistoryVideo? = null;
|
||||
|
||||
var url: String;
|
||||
var position: Long;
|
||||
var date: Long;
|
||||
|
||||
constructor() {
|
||||
url = "";
|
||||
position = 0;
|
||||
date = 0;
|
||||
}
|
||||
constructor(historyVideo: HistoryVideo) {
|
||||
id = null;
|
||||
serialized = null;
|
||||
url = historyVideo.video.url;
|
||||
position = historyVideo.position;
|
||||
date = historyVideo.date.toEpochSecond();
|
||||
obj = historyVideo;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -92,7 +92,11 @@ class GestureControlView : LinearLayout {
|
|||
override fun onDown(p0: MotionEvent): Boolean { return false; }
|
||||
override fun onShowPress(p0: MotionEvent) = Unit;
|
||||
override fun onSingleTapUp(p0: MotionEvent): Boolean { return false; }
|
||||
override fun onScroll(p0: MotionEvent, p1: MotionEvent, distanceX: Float, distanceY: Float): Boolean {
|
||||
override fun onFling(p0: MotionEvent?, p1: MotionEvent, p2: Float, p3: Float): Boolean { return false; }
|
||||
override fun onScroll(p0: MotionEvent?, p1: MotionEvent, distanceX: Float, distanceY: Float): Boolean {
|
||||
if(p0 == null)
|
||||
return false;
|
||||
|
||||
if (_isFullScreen && _adjustingBrightness) {
|
||||
val adjustAmount = (distanceY * 2) / height;
|
||||
_brightnessFactor = (_brightnessFactor + adjustAmount).coerceAtLeast(0.0f).coerceAtMost(1.0f);
|
||||
|
@ -132,8 +136,7 @@ class GestureControlView : LinearLayout {
|
|||
|
||||
return true;
|
||||
}
|
||||
override fun onLongPress(p0: MotionEvent) = Unit;
|
||||
override fun onFling(p0: MotionEvent, p1: MotionEvent, p2: Float, p3: Float): Boolean { return false; }
|
||||
override fun onLongPress(p0: MotionEvent) = Unit
|
||||
});
|
||||
|
||||
gestureController.setOnDoubleTapListener(object : GestureDetector.OnDoubleTapListener {
|
||||
|
|
Loading…
Add table
Reference in a new issue