This commit is contained in:
Felitendo
2025-05-20 15:22:07 +02:00
parent c24d95627e
commit 8a6d5d19db
384 changed files with 7065 additions and 4430 deletions

View File

@@ -9,18 +9,18 @@ import android.os.CancellationSignal
import androidx.core.database.sqlite.transaction
import com.fasterxml.jackson.core.JsonGenerator
import com.fasterxml.jackson.core.JsonParser
import com.looker.droidify.BuildConfig
import com.looker.droidify.datastore.model.SortOrder
import com.looker.core.common.extension.Json
import com.looker.core.common.extension.asSequence
import com.looker.core.common.extension.firstOrNull
import com.looker.core.common.extension.parseDictionary
import com.looker.core.common.extension.writeDictionary
import com.looker.core.common.log
import com.looker.core.datastore.model.SortOrder
import com.looker.droidify.model.InstalledItem
import com.looker.droidify.model.Product
import com.looker.droidify.model.ProductItem
import com.looker.droidify.model.Repository
import com.looker.droidify.utility.common.extension.Json
import com.looker.droidify.utility.common.extension.asSequence
import com.looker.droidify.utility.common.extension.firstOrNull
import com.looker.droidify.utility.common.extension.parseDictionary
import com.looker.droidify.utility.common.extension.writeDictionary
import com.looker.droidify.utility.common.log
import com.looker.droidify.BuildConfig
import com.looker.droidify.utility.serialization.product
import com.looker.droidify.utility.serialization.productItem
import com.looker.droidify.utility.serialization.repository
@@ -71,20 +71,14 @@ object Database {
get() = "$databasePrefix$innerName"
fun formatCreateTable(name: String): String {
return buildString(128) {
append("CREATE TABLE ")
append(name)
append(" (")
trimAndJoin(createTable)
append(")")
}
return "CREATE TABLE $name (${QueryBuilder.trimQuery(createTable)})"
}
val createIndexPairFormatted: Pair<String, String>?
get() = createIndex?.let {
Pair(
"CREATE INDEX ${innerName}_index ON $innerName ($it)",
"CREATE INDEX ${name}_index ON $innerName ($it)",
"CREATE INDEX ${name}_index ON $innerName ($it)"
)
}
}
@@ -190,7 +184,7 @@ object Database {
}
}
private class Helper(context: Context) : SQLiteOpenHelper(context, "droidify", null, 5) {
private class Helper(context: Context) : SQLiteOpenHelper(context, "droidify", null, 4) {
var created = false
private set
var updated = false
@@ -220,7 +214,7 @@ object Database {
Schema.Product,
Schema.Category,
Schema.Installed,
Schema.Lock,
Schema.Lock
)
dropOldTables(db, Schema.Repository, Schema.Product, Schema.Category)
this.created = this.created || create
@@ -233,7 +227,7 @@ object Database {
val sql = db.query(
"${table.databasePrefix}sqlite_master",
columns = arrayOf("sql"),
selection = Pair("type = ? AND name = ?", arrayOf("table", table.innerName)),
selection = Pair("type = ? AND name = ?", arrayOf("table", table.innerName))
).use { it.firstOrNull()?.getString(0) }.orEmpty()
table.formatCreateTable(table.innerName) != sql
}
@@ -267,7 +261,7 @@ object Database {
val sqls = db.query(
"${table.databasePrefix}sqlite_master",
columns = arrayOf("name", "sql"),
selection = Pair("type = ? AND tbl_name = ?", arrayOf("index", table.innerName)),
selection = Pair("type = ? AND tbl_name = ?", arrayOf("index", table.innerName))
)
.use { cursor ->
cursor.asSequence()
@@ -295,7 +289,7 @@ object Database {
val tables = db.query(
"sqlite_master",
columns = arrayOf("name"),
selection = Pair("type = ?", arrayOf("table")),
selection = Pair("type = ?", arrayOf("table"))
)
.use { cursor -> cursor.asSequence().mapNotNull { it.getString(0) }.toList() }
.filter { !it.startsWith("sqlite_") && !it.startsWith("android_") }
@@ -351,7 +345,7 @@ object Database {
private fun SQLiteDatabase.insertOrReplace(
replace: Boolean,
table: String,
contentValues: ContentValues,
contentValues: ContentValues
): Long {
return if (replace) {
replace(table, null, contentValues)
@@ -359,7 +353,7 @@ object Database {
insert(
table,
null,
contentValues,
contentValues
)
}
}
@@ -369,7 +363,7 @@ object Database {
columns: Array<String>? = null,
selection: Pair<String, Array<String>>? = null,
orderBy: String? = null,
signal: CancellationSignal? = null,
signal: CancellationSignal? = null
): Cursor {
return query(
false,
@@ -381,7 +375,7 @@ object Database {
null,
orderBy,
null,
signal,
signal
)
}
@@ -403,7 +397,7 @@ object Database {
internal fun putWithoutNotification(
repository: Repository,
shouldReplace: Boolean,
database: SQLiteDatabase,
database: SQLiteDatabase
): Long {
return database.insertOrReplace(
shouldReplace,
@@ -415,7 +409,7 @@ object Database {
put(Schema.Repository.ROW_ENABLED, if (repository.enabled) 1 else 0)
put(Schema.Repository.ROW_DELETED, 0)
put(Schema.Repository.ROW_DATA, jsonGenerate(repository::serialize))
},
}
)
}
@@ -448,8 +442,8 @@ object Database {
Schema.Repository.name,
selection = Pair(
"${Schema.Repository.ROW_ID} = ? AND ${Schema.Repository.ROW_DELETED} == 0",
arrayOf(id.toString()),
),
arrayOf(id.toString())
)
).use { it.firstOrNull()?.let(::transform) }
}
@@ -469,9 +463,9 @@ object Database {
selection = Pair(
"${Schema.Repository.ROW_ENABLED} != 0 AND " +
"${Schema.Repository.ROW_DELETED} == 0",
emptyArray(),
emptyArray()
),
signal = null,
signal = null
).use { it.asSequence().map(::transform).toList() }
}
@@ -479,7 +473,7 @@ object Database {
return db.query(
Schema.Repository.name,
selection = Pair("${Schema.Repository.ROW_DELETED} == 0", emptyArray()),
signal = null,
signal = null
).use { it.asSequence().map(::transform).toList() }
}
@@ -495,9 +489,9 @@ object Database {
selection = Pair(
"${Schema.Repository.ROW_ENABLED} == 0 OR " +
"${Schema.Repository.ROW_DELETED} != 0",
emptyArray(),
emptyArray()
),
signal = null,
signal = null
).use { parentCursor ->
parentCursor.asSequence().associate {
val idIndex = it.getColumnIndexOrThrow(Schema.Repository.ROW_ID)
@@ -514,7 +508,7 @@ object Database {
put(Schema.Repository.ROW_DELETED, 1)
},
"${Schema.Repository.ROW_ID} = ?",
arrayOf(id.toString()),
arrayOf(id.toString())
)
notifyChanged(Subject.Repositories, Subject.Repository(id), Subject.Products)
}
@@ -525,18 +519,18 @@ object Database {
val productsCount = db.delete(
Schema.Product.name,
"${Schema.Product.ROW_REPOSITORY_ID} IN ($idsString)",
null,
null
)
val categoriesCount = db.delete(
Schema.Category.name,
"${Schema.Category.ROW_REPOSITORY_ID} IN ($idsString)",
null,
null
)
if (isDeleted) {
db.delete(
Schema.Repository.name,
"${Schema.Repository.ROW_ID} IN ($id)",
null,
null
)
}
productsCount != 0 || categoriesCount != 0
@@ -561,7 +555,7 @@ object Database {
Schema.Repository.name,
selection = Pair("${Schema.Repository.ROW_DELETED} == 0", emptyArray()),
orderBy = "${Schema.Repository.ROW_ENABLED} DESC",
signal = signal,
signal = signal
).observable(Subject.Repositories)
}
@@ -583,28 +577,26 @@ object Database {
.map { get(packageName, null) }
.flowOn(Dispatchers.IO)
suspend fun getUpdates(skipSignatureCheck: Boolean): List<ProductItem> =
withContext(Dispatchers.IO) {
query(
installed = true,
updates = true,
searchQuery = "",
skipSignatureCheck = skipSignatureCheck,
section = ProductItem.Section.All,
order = SortOrder.NAME,
signal = null,
).use {
it.asSequence()
.map(ProductAdapter::transformItem)
.toList()
}
suspend fun getUpdates(): List<ProductItem> = withContext(Dispatchers.IO) {
query(
installed = true,
updates = true,
searchQuery = "",
section = ProductItem.Section.All,
order = SortOrder.NAME,
signal = null
).use {
it.asSequence()
.map(ProductAdapter::transformItem)
.toList()
}
}
fun getUpdatesStream(skipSignatureCheck: Boolean): Flow<List<ProductItem>> = flowOf(Unit)
fun getUpdatesStream(): Flow<List<ProductItem>> = flowOf(Unit)
.onCompletion { if (it == null) emitAll(flowCollection(Subject.Products)) }
// Crashes due to immediate retrieval of data?
.onEach { delay(50) }
.map { getUpdates(skipSignatureCheck) }
.map { getUpdates() }
.flowOn(Dispatchers.IO)
fun get(packageName: String, signal: CancellationSignal?): List<Product> {
@@ -613,10 +605,10 @@ object Database {
columns = arrayOf(
Schema.Product.ROW_REPOSITORY_ID,
Schema.Product.ROW_DESCRIPTION,
Schema.Product.ROW_DATA,
Schema.Product.ROW_DATA
),
selection = Pair("${Schema.Product.ROW_PACKAGE_NAME} = ?", arrayOf(packageName)),
signal = signal,
signal = signal
).use { it.asSequence().map(::transform).toList() }
}
@@ -631,26 +623,24 @@ object Database {
columns = arrayOf("COUNT (*)"),
selection = Pair(
"${Schema.Product.ROW_REPOSITORY_ID} = ?",
arrayOf(repositoryId.toString()),
),
arrayOf(repositoryId.toString())
)
).use { it.firstOrNull()?.getInt(0) ?: 0 }
}
fun query(
installed: Boolean,
updates: Boolean,
skipSignatureCheck: Boolean = false,
searchQuery: String,
section: ProductItem.Section,
order: SortOrder,
signal: CancellationSignal?,
signal: CancellationSignal?
): Cursor {
val builder = QueryBuilder()
val signatureMatches = if (skipSignatureCheck) "1"
else """installed.${Schema.Installed.ROW_SIGNATURE} IS NOT NULL AND
product.${Schema.Product.ROW_SIGNATURES} LIKE ('%.' || installed.${Schema.Installed.ROW_SIGNATURE} || '.%') AND
product.${Schema.Product.ROW_SIGNATURES} != ''"""
val signatureMatches = """installed.${Schema.Installed.ROW_SIGNATURE} IS NOT NULL AND
product.${Schema.Product.ROW_SIGNATURES} LIKE ('%.' || installed.${Schema.Installed.ROW_SIGNATURE} || '.%') AND
product.${Schema.Product.ROW_SIGNATURES} != ''"""
builder += """SELECT product.rowid AS _id, product.${Schema.Product.ROW_REPOSITORY_ID},
product.${Schema.Product.ROW_PACKAGE_NAME}, product.${Schema.Product.ROW_NAME},
@@ -738,10 +728,6 @@ object Database {
}
}
fun transformPackageName(cursor: Cursor): String {
return cursor.getString(cursor.getColumnIndexOrThrow(Schema.Product.ROW_PACKAGE_NAME))
}
fun transformItem(cursor: Cursor): ProductItem {
return cursor.getBlob(cursor.getColumnIndexOrThrow(Schema.Product.ROW_DATA_ITEM))
.jsonParse {
@@ -807,10 +793,10 @@ object Database {
Schema.Installed.ROW_PACKAGE_NAME,
Schema.Installed.ROW_VERSION,
Schema.Installed.ROW_VERSION_CODE,
Schema.Installed.ROW_SIGNATURE,
Schema.Installed.ROW_SIGNATURE
),
selection = Pair("${Schema.Installed.ROW_PACKAGE_NAME} = ?", arrayOf(packageName)),
signal = signal,
signal = signal
).use { it.firstOrNull()?.let(::transform) }
}
@@ -823,7 +809,7 @@ object Database {
put(Schema.Installed.ROW_VERSION, installedItem.version)
put(Schema.Installed.ROW_VERSION_CODE, installedItem.versionCode)
put(Schema.Installed.ROW_SIGNATURE, installedItem.signature)
},
}
)
if (notify) {
notifyChanged(Subject.Products)
@@ -843,7 +829,7 @@ object Database {
val count = db.delete(
Schema.Installed.name,
"${Schema.Installed.ROW_PACKAGE_NAME} = ?",
arrayOf(packageName),
arrayOf(packageName)
)
if (count > 0) {
notifyChanged(Subject.Products)
@@ -855,7 +841,7 @@ object Database {
cursor.getString(cursor.getColumnIndexOrThrow(Schema.Installed.ROW_PACKAGE_NAME)),
cursor.getString(cursor.getColumnIndexOrThrow(Schema.Installed.ROW_VERSION)),
cursor.getLong(cursor.getColumnIndexOrThrow(Schema.Installed.ROW_VERSION_CODE)),
cursor.getString(cursor.getColumnIndexOrThrow(Schema.Installed.ROW_SIGNATURE)),
cursor.getString(cursor.getColumnIndexOrThrow(Schema.Installed.ROW_SIGNATURE))
)
}
}
@@ -868,7 +854,7 @@ object Database {
ContentValues().apply {
put(Schema.Lock.ROW_PACKAGE_NAME, lock.first)
put(Schema.Lock.ROW_VERSION_CODE, lock.second)
},
}
)
if (notify) {
notifyChanged(Subject.Products)
@@ -924,9 +910,9 @@ object Database {
put(Schema.Product.ROW_DATA, jsonGenerate(product::serialize))
put(
Schema.Product.ROW_DATA_ITEM,
jsonGenerate(product.item()::serialize),
jsonGenerate(product.item()::serialize)
)
},
}
)
for (category in product.categories) {
db.insertOrReplace(
@@ -936,7 +922,7 @@ object Database {
put(Schema.Category.ROW_REPOSITORY_ID, product.repositoryId)
put(Schema.Category.ROW_PACKAGE_NAME, product.packageName)
put(Schema.Category.ROW_NAME, category)
},
}
)
}
}
@@ -949,20 +935,20 @@ object Database {
db.delete(
Schema.Product.name,
"${Schema.Product.ROW_REPOSITORY_ID} = ?",
arrayOf(repository.id.toString()),
arrayOf(repository.id.toString())
)
db.delete(
Schema.Category.name,
"${Schema.Category.ROW_REPOSITORY_ID} = ?",
arrayOf(repository.id.toString()),
arrayOf(repository.id.toString())
)
db.execSQL(
"INSERT INTO ${Schema.Product.name} SELECT * " +
"FROM ${Schema.Product.temporaryName}",
"FROM ${Schema.Product.temporaryName}"
)
db.execSQL(
"INSERT INTO ${Schema.Category.name} SELECT * " +
"FROM ${Schema.Category.temporaryName}",
"FROM ${Schema.Category.temporaryName}"
)
RepositoryAdapter.putWithoutNotification(repository, true, db)
db.execSQL("DROP TABLE IF EXISTS ${Schema.Product.temporaryName}")
@@ -971,7 +957,7 @@ object Database {
notifyChanged(
Subject.Repositories,
Subject.Repository(repository.id),
Subject.Products,
Subject.Products
)
} else {
db.execSQL("DROP TABLE IF EXISTS ${Schema.Product.temporaryName}")