Update: Merge Repository's entity and database.entity classes

+ Update related DAOs
+ Add needed converters
+ Fix calls
This commit is contained in:
machiav3lli 2022-01-28 00:31:27 +01:00
parent 050ecfd4a0
commit 7bbac86dd4
32 changed files with 418 additions and 419 deletions

View File

@ -214,7 +214,7 @@ class MainApplication : Application(), ImageLoaderFactory {
} }
private fun forceSyncAll() { private fun forceSyncAll() {
db.repositoryDao.all.mapNotNull { it.trueData }.forEach { db.repositoryDao.all.forEach {
if (it.lastModified.isNotEmpty() || it.entityTag.isNotEmpty()) { if (it.lastModified.isNotEmpty() || it.entityTag.isNotEmpty()) {
db.repositoryDao.put(it.copy(lastModified = "", entityTag = "")) db.repositoryDao.put(it.copy(lastModified = "", entityTag = ""))
} }

View File

@ -2,18 +2,21 @@ package com.looker.droidify.database
import androidx.room.TypeConverter import androidx.room.TypeConverter
import com.looker.droidify.entity.ProductItem import com.looker.droidify.entity.ProductItem
import com.looker.droidify.entity.Repository
import com.looker.droidify.utility.jsonGenerate import com.looker.droidify.utility.jsonGenerate
import com.looker.droidify.utility.jsonParse import com.looker.droidify.utility.jsonParse
object Converters { object Converters {
@TypeConverter @TypeConverter
@JvmStatic @JvmStatic
fun toRepository(byteArray: ByteArray) = byteArray.jsonParse { Repository.deserialize(it) } fun toStringList(byteArray: ByteArray): List<String> {
val string = byteArray.toString()
return if (string == "") emptyList()
else string.split(",")
}
@TypeConverter @TypeConverter
@JvmStatic @JvmStatic
fun toByteArray(repository: Repository) = jsonGenerate(repository::serialize) fun toString(list: List<String>): ByteArray = list.toString().toByteArray()
@TypeConverter @TypeConverter
@JvmStatic @JvmStatic

View File

@ -32,15 +32,9 @@ interface RepositoryDao : BaseDao<Repository> {
@get:Query("SELECT COUNT(_id) FROM repository") @get:Query("SELECT COUNT(_id) FROM repository")
val count: Int val count: Int
fun put(repository: com.looker.droidify.entity.Repository): com.looker.droidify.entity.Repository { fun put(repository: Repository): Repository {
repository.let { repository.let { item ->
val dbRepo = Repository().apply { val newId = if (item.id > 0L) update(item).toLong() else returnInsert(item)
if (it.id >= 0L) id = it.id
enabled = if (it.enabled) 1 else 0
deleted = false
data = it
}
val newId = if (it.id > 0L) update(dbRepo).toLong() else returnInsert(dbRepo)
return if (newId != repository.id) repository.copy(id = newId) else repository return if (newId != repository.id) repository.copy(id = newId) else repository
} }
} }
@ -48,35 +42,30 @@ interface RepositoryDao : BaseDao<Repository> {
@Insert @Insert
fun returnInsert(product: Repository): Long fun returnInsert(product: Repository): Long
@Query("SELECT * FROM repository WHERE _id = :id and deleted == 0") @Query("SELECT * FROM repository WHERE _id = :id")
fun get(id: Long): Repository? fun get(id: Long): Repository?
@Query("SELECT * FROM repository WHERE _id = :id and deleted == 0") @Query("SELECT * FROM repository WHERE _id = :id")
fun getLive(id: Long): LiveData<Repository?> fun getLive(id: Long): LiveData<Repository?>
@get:Query("SELECT * FROM repository WHERE deleted == 0 ORDER BY _id ASC") @get:Query("SELECT * FROM repository ORDER BY _id ASC")
val allCursor: Cursor val allCursor: Cursor
@get:Query("SELECT * FROM repository WHERE deleted == 0 ORDER BY _id ASC") @get:Query("SELECT * FROM repository ORDER BY _id ASC")
val all: List<Repository> val all: List<Repository>
@get:Query("SELECT * FROM repository WHERE deleted == 0 ORDER BY _id ASC") @get:Query("SELECT * FROM repository ORDER BY _id ASC")
val allLive: LiveData<List<Repository>> val allLive: LiveData<List<Repository>>
@get:Query("SELECT * FROM repository WHERE deleted == 0 ORDER BY _id ASC") @get:Query("SELECT * FROM repository ORDER BY _id ASC")
val allFlowable: Flowable<List<Repository>> val allFlowable: Flowable<List<Repository>>
@get:Query("SELECT _id, deleted FROM repository WHERE deleted != 0 and enabled == 0 ORDER BY _id ASC") @get:Query("SELECT _id FROM repository WHERE enabled == 0 ORDER BY _id ASC")
val allDisabledDeleted: List<Repository.IdAndDeleted> val allDisabled: List<Long>
// TODO clean up products and other tables afterwards
@Query("DELETE FROM repository WHERE _id = :id") @Query("DELETE FROM repository WHERE _id = :id")
fun deleteById(id: Long): Int fun deleteById(id: Long): Int
// TODO optimize
@Update(onConflict = OnConflictStrategy.REPLACE)
fun markAsDeleted(id: Long) {
get(id).apply { this?.deleted = true }?.let { update(it) }
}
} }
@Dao @Dao
@ -148,8 +137,7 @@ interface ProductDao : BaseDao<Product> {
ON product.${ROW_PACKAGE_NAME} = category.${ROW_PACKAGE_NAME}""" ON product.${ROW_PACKAGE_NAME} = category.${ROW_PACKAGE_NAME}"""
} }
builder += """WHERE repository.${ROW_ENABLED} != 0 AND builder += """WHERE repository.${ROW_ENABLED} != 0"""
repository.${ROW_DELETED} == 0"""
if (section is ProductItem.Section.Category) { if (section is ProductItem.Section.Category) {
builder += "AND category.${ROW_NAME} = ?" builder += "AND category.${ROW_NAME} = ?"
@ -238,8 +226,7 @@ interface ProductDao : BaseDao<Product> {
ON product.${ROW_PACKAGE_NAME} = category.${ROW_PACKAGE_NAME}""" ON product.${ROW_PACKAGE_NAME} = category.${ROW_PACKAGE_NAME}"""
} }
builder += """WHERE repository.${ROW_ENABLED} != 0 AND builder += """WHERE repository.${ROW_ENABLED} != 0"""
repository.${ROW_DELETED} == 0"""
if (section is ProductItem.Section.Category) { if (section is ProductItem.Section.Category) {
builder += "AND category.${ROW_NAME} = ?" builder += "AND category.${ROW_NAME} = ?"
@ -282,8 +269,7 @@ interface CategoryDao : BaseDao<Category> {
FROM category AS category FROM category AS category
JOIN repository AS repository JOIN repository AS repository
ON category.repository_id = repository._id ON category.repository_id = repository._id
WHERE repository.enabled != 0 AND WHERE repository.enabled != 0"""
repository.deleted == 0"""
) )
val allNames: List<String> val allNames: List<String>

View File

@ -6,7 +6,7 @@ import androidx.room.Room
import androidx.room.RoomDatabase import androidx.room.RoomDatabase
import androidx.room.TypeConverters import androidx.room.TypeConverters
import com.looker.droidify.database.entity.* import com.looker.droidify.database.entity.*
import com.looker.droidify.entity.Repository.Companion.defaultRepositories import com.looker.droidify.database.entity.Repository.Companion.defaultRepositories
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@ -77,7 +77,7 @@ abstract class DatabaseX : RoomDatabase() {
} }
} }
fun finishTemporary(repository: com.looker.droidify.entity.Repository, success: Boolean) { fun finishTemporary(repository: Repository, success: Boolean) {
runInTransaction { runInTransaction {
if (success) { if (success) {
productDao.deleteById(repository.id) productDao.deleteById(repository.id)

View File

@ -3,23 +3,331 @@ package com.looker.droidify.database.entity
import androidx.room.ColumnInfo import androidx.room.ColumnInfo
import androidx.room.Entity import androidx.room.Entity
import androidx.room.PrimaryKey import androidx.room.PrimaryKey
import com.looker.droidify.entity.Repository import com.fasterxml.jackson.core.JsonGenerator
import com.fasterxml.jackson.core.JsonParser
import com.looker.droidify.utility.extension.json.collectNotNullStrings
import com.looker.droidify.utility.extension.json.forEachKey
import com.looker.droidify.utility.extension.json.writeArray
import java.net.URL
// TODO LATER: reduce redundancy by merging the entity and database classes
@Entity @Entity
class Repository { data class Repository(
@PrimaryKey(autoGenerate = true) @PrimaryKey(autoGenerate = true)
@ColumnInfo(name = "_id") @ColumnInfo(name = "_id")
var id: Long = 0 var id: Long = 0,
var address: String = "",
var mirrors: List<String> = emptyList(),
var name: String = "",
var description: String = "",
var version: Int = 21,
var enabled: Boolean = false,
var fingerprint: String = "",
var lastModified: String = "",
var entityTag: String = "",
var updated: Long = 0L,
var timestamp: Long = 0L,
var authentication: String = "",
) {
fun edit(address: String, fingerprint: String, authentication: String): Repository = apply {
val changed = this.address != address || this.fingerprint != fingerprint
this.lastModified = if (changed) "" else lastModified
this.entityTag = if (changed) "" else entityTag
this.address = address
this.fingerprint = fingerprint
this.authentication = authentication
}
var enabled = 0 fun update(
var deleted = false mirrors: List<String>, name: String, description: String, version: Int,
lastModified: String, entityTag: String, timestamp: Long,
): Repository = apply {
this.mirrors = mirrors
this.name = name
this.description = description
this.version = if (version >= 0) version else this.version
this.lastModified = lastModified
this.entityTag = entityTag
this.updated = System.currentTimeMillis()
this.timestamp = timestamp
}
@ColumnInfo(typeAffinity = ColumnInfo.BLOB) fun enable(enabled: Boolean): Repository = apply {
var data: Repository? = null this.enabled = enabled
this.lastModified = ""
this.entityTag = ""
}
val trueData: Repository? fun serialize(generator: JsonGenerator) {
get() = data?.copy(id = id) generator.writeNumberField("serialVersion", 1)
generator.writeNumberField("id", id)
generator.writeStringField("address", address)
generator.writeArray("mirrors") { mirrors.forEach { writeString(it) } }
generator.writeStringField("name", name)
generator.writeStringField("description", description)
generator.writeNumberField("version", version)
generator.writeBooleanField("enabled", enabled)
generator.writeStringField("fingerprint", fingerprint)
generator.writeStringField("lastModified", lastModified)
generator.writeStringField("entityTag", entityTag)
generator.writeNumberField("updated", updated)
generator.writeNumberField("timestamp", timestamp)
generator.writeStringField("authentication", authentication)
}
companion object {
fun deserialize(parser: JsonParser): Repository {
var id = 0L
var address = ""
var mirrors = emptyList<String>()
var name = ""
var description = ""
var version = 0
var enabled = false
var fingerprint = ""
var lastModified = ""
var entityTag = ""
var updated = 0L
var timestamp = 0L
var authentication = ""
parser.forEachKey {
when {
it.string("id") -> id = valueAsLong
it.string("address") -> address = valueAsString
it.array("mirrors") -> mirrors = collectNotNullStrings()
it.string("name") -> name = valueAsString
it.string("description") -> description = valueAsString
it.number("version") -> version = valueAsInt
it.boolean("enabled") -> enabled = valueAsBoolean
it.string("fingerprint") -> fingerprint = valueAsString
it.string("lastModified") -> lastModified = valueAsString
it.string("entityTag") -> entityTag = valueAsString
it.number("updated") -> updated = valueAsLong
it.number("timestamp") -> timestamp = valueAsLong
it.string("authentication") -> authentication = valueAsString
else -> skipChildren()
}
}
return Repository(
id, address, mirrors, name, description, version, enabled, fingerprint,
lastModified, entityTag, updated, timestamp, authentication
)
}
fun newRepository(
address: String = "",
fingerprint: String = "",
authentication: String = "",
): Repository {
val name = try {
URL(address).let { "${it.host}${it.path}" }
} catch (e: Exception) {
address
}
return Repository(
address = address,
name = name,
fingerprint = fingerprint,
authentication = authentication
)
}
private fun defaultRepository(
address: String, name: String, description: String,
version: Int, enabled: Boolean, fingerprint: String, authentication: String,
): Repository = Repository(
0, address, emptyList(), name, description, version, enabled,
fingerprint, "", "", 0L, 0L, authentication
)
val defaultRepositories = listOf(run {
defaultRepository(
"https://f-droid.org/repo",
"F-Droid",
"The official F-Droid Free Software repository. " +
"Everything in this repository is always built from the source code.",
21,
true,
"43238D512C1E5EB2D6569F4A3AFBF5523418B82E0A3ED1552770ABB9A9C9CCAB",
""
)
}, run {
defaultRepository(
"https://f-droid.org/archive",
"F-Droid Archive",
"The archive of the official F-Droid Free " +
"Software repository. Apps here are old and can contain known vulnerabilities and security issues!",
21,
false,
"43238D512C1E5EB2D6569F4A3AFBF5523418B82E0A3ED1552770ABB9A9C9CCAB",
""
)
}, run {
defaultRepository(
"https://guardianproject.info/fdroid/repo",
"Guardian Project Official Releases",
"The " +
"official repository of The Guardian Project apps for use with the F-Droid client. Applications in this " +
"repository are official binaries built by the original application developers and signed by the same key as " +
"the APKs that are released in the Google Play Store.",
21,
false,
"B7C2EEFD8DAC7806AF67DFCD92EB18126BC08312A7F2D6F3862E46013C7A6135",
""
)
}, run {
defaultRepository(
"https://guardianproject.info/fdroid/archive",
"Guardian Project Archive",
"The official " +
"repository of The Guardian Project apps for use with the F-Droid client. This contains older versions of " +
"applications from the main repository.",
21,
false,
"B7C2EEFD8DAC7806AF67DFCD92EB18126BC08312A7F2D6F3862E46013C7A6135",
""
)
}, run {
defaultRepository(
"https://apt.izzysoft.de/fdroid/repo", "IzzyOnDroid F-Droid Repo", "This is a " +
"repository of apps to be used with F-Droid the original application developers, taken from the resp. " +
"repositories (mostly GitHub). At this moment I cannot give guarantees on regular updates for all of them, " +
"though most are checked multiple times a week ", 21, true,
"3BF0D6ABFEAE2F401707B6D966BE743BF0EEE49C2561B9BA39073711F628937A", ""
)
}, run {
defaultRepository(
"https://microg.org/fdroid/repo", "MicroG Project",
"Official repository of the open-source implementation of Google Play Services.",
21, false, "9BD06727E62796C0130EB6DAB39B73157451582CBD138E86C468ACC395D14165", ""
)
}, run {
defaultRepository(
"https://repo.netsyms.com/fdroid/repo", "Netsyms Technologies",
"Open-source apps created by Netsyms Technologies.",
21, false, "2581BA7B32D3AB443180C4087CAB6A7E8FB258D3A6E98870ECB3C675E4D64489", ""
)
}, run {
defaultRepository(
"https://fdroid.bromite.org/fdroid/repo", "Bromite",
"Bromite is a Chromium plus ad blocking and enhanced privacy; take back your browser.",
21, false, "E1EE5CD076D7B0DC84CB2B45FB78B86DF2EB39A3B6C56BA3DC292A5E0C3B9504", ""
)
}, run {
defaultRepository(
"https://molly.im/fdroid/foss/fdroid/repo", "Molly",
"Molly is a fork of Signal focused on security.",
21, false, "5198DAEF37FC23C14D5EE32305B2AF45787BD7DF2034DE33AD302BDB3446DF74", ""
)
}, run {
defaultRepository(
"https://archive.newpipe.net/fdroid/repo", "NewPipe",
"NewPipe's official independent repository.",
21, false, "E2402C78F9B97C6C89E97DB914A2751FDA1D02FE2039CC0897A462BDB57E7501", ""
)
}, run {
defaultRepository(
"https://www.collaboraoffice.com/downloads/fdroid/repo", "Collabora Office",
"Collabora Office is an office suite based on LibreOffice.",
21, false, "573258C84E149B5F4D9299E7434B2B69A8410372921D4AE586BA91EC767892CC", ""
)
}, run {
defaultRepository(
"https://www.droidware.info/fdroid/repo", "Ungoogled Chromium",
"Chromium sans dependency on Google web services. It also features some enhancments to privacy, control & transparency",
21, false, "2144449AB1DD270EC31B6087409B5D0EA39A75A9F290DA62AC1B238A0EAAF851", ""
)
}, run {
defaultRepository(
"https://fdroid.libretro.com/repo", "LibRetro",
"The official canary repository for this great retro emulators hub.",
21, false, "3F05B24D497515F31FEAB421297C79B19552C5C81186B3750B7C131EF41D733D", ""
)
}, run {
defaultRepository(
"https://cdn.kde.org/android/fdroid/repo", "KDE Android",
"The official nightly repository for KDE Android apps.",
21, false, "B3EBE10AFA6C5C400379B34473E843D686C61AE6AD33F423C98AF903F056523F", ""
)
}, run {
defaultRepository(
"https://rfc2822.gitlab.io/fdroid-firefox/fdroid/repo", "Unofficial Firefox",
"An unofficial repository with some of the most well known FOSS apps not on F-Droid.",
21, false, "8F992BBBA0340EFE6299C7A410B36D9C8889114CA6C58013C3587CDA411B4AED", ""
)
}, run {
defaultRepository(
"https://calyxos.gitlab.io/calyx-fdroid-repo/fdroid/repo", "Calyx OS Repo",
"The official Calyx Labs F-Droid repository.",
21, false, "C44D58B4547DE5096138CB0B34A1CC99DAB3B4274412ED753FCCBFC11DC1B7B6", ""
)
}, run {
defaultRepository(
"https://divestos.org/fdroid/official", "Divest OS Repo",
"The official Divest OS F-Droid repository.",
21, false, "E4BE8D6ABFA4D9D4FEEF03CDDA7FF62A73FD64B75566F6DD4E5E577550BE8467", ""
)
}, run {
defaultRepository(
"https://fdroid.fedilab.app/repo", "Fedilab",
"Fedilab's official F-Droid repository.",
21, false, "11F0A69910A4280E2CD3CCC3146337D006BE539B18E1A9FEACE15FF757A94FEB", ""
)
}, run {
defaultRepository(
"https://store.nethunter.com/repo", "Kali Nethunter",
"Kali Nethunter's official selection of original binaries.",
21, false, "7E418D34C3AD4F3C37D7E6B0FACE13332364459C862134EB099A3BDA2CCF4494", ""
)
}, run {
defaultRepository(
"https://secfirst.org/fdroid/repo", "Umbrella",
"Security advices, tutorials, tools etc..",
21, false, "39EB57052F8D684514176819D1645F6A0A7BD943DBC31AB101949006AC0BC228", ""
)
}, run {
defaultRepository(
"https://thecapslock.gitlab.io/fdroid-patched-apps/fdroid/repo", "Patched Apps",
"A collection of patched applications to provide better compatibility, privacy etc..",
21, false, "313D9E6E789FF4E8E2D687AAE31EEF576050003ED67963301821AC6D3763E3AC", ""
)
}, run {
defaultRepository(
"https://mobileapp.bitwarden.com/fdroid/repo", "Bitwarden",
"The official repository for Bitwarden.",
21, false, "BC54EA6FD1CD5175BCCCC47C561C5726E1C3ED7E686B6DB4B18BAC843A3EFE6C", ""
)
}, run {
defaultRepository(
"https://briarproject.org/fdroid/repo", "Briar",
"An serverless/offline messenger that hides your metadata.",
21, false, "1FB874BEE7276D28ECB2C9B06E8A122EC4BCB4008161436CE474C257CBF49BD6", ""
)
}, run {
defaultRepository(
"https://guardianproject-wind.s3.amazonaws.com/fdroid/repo", "Wind Project",
"A collection of interesting offline/serverless apps.",
21, false, "182CF464D219D340DA443C62155198E399FEC1BC4379309B775DD9FC97ED97E1", ""
)
}, run {
defaultRepository(
"https://repo.alefvanoon.xyz/fdroid/repo", "Alefvanoon",
"A collection of open-source apps that for one reason or another not on F-Droid.",
21, false, "04DF198F553069C7BE60F057AE12000E99F7700DA895CC1CE2EB11DC871581F1", ""
)
}, run {
defaultRepository(
"https://repo.unifiedpush.org/", "UnifiedPush",
"A repository of apps for unifiedPush.",
21, false, "DF11176406C63A7876103CE6CC1A8FCA239DF76AA5F6DE5CDBAFE73ECDBF1875", ""
)
}, run {
defaultRepository(
"https://nanolx.org/fdroid/repo", "NanoDroid",
"A companion repository to microG's installer.",
21, false, "862ED9F13A3981432BF86FE93D14596B381D75BE83A1D616E2D44A12654AD015", ""
)
})
}
class IdAndDeleted { class IdAndDeleted {
@ColumnInfo(name = "_id") @ColumnInfo(name = "_id")

View File

@ -4,6 +4,7 @@ import android.net.Uri
import com.fasterxml.jackson.core.JsonGenerator import com.fasterxml.jackson.core.JsonGenerator
import com.fasterxml.jackson.core.JsonParser import com.fasterxml.jackson.core.JsonParser
import com.fasterxml.jackson.core.JsonToken import com.fasterxml.jackson.core.JsonToken
import com.looker.droidify.database.entity.Repository
import com.looker.droidify.utility.extension.json.* import com.looker.droidify.utility.extension.json.*
data class Release( data class Release(

View File

@ -1,312 +0,0 @@
package com.looker.droidify.entity
import com.fasterxml.jackson.core.JsonGenerator
import com.fasterxml.jackson.core.JsonParser
import com.looker.droidify.utility.extension.json.collectNotNullStrings
import com.looker.droidify.utility.extension.json.forEachKey
import com.looker.droidify.utility.extension.json.writeArray
import java.net.URL
data class Repository(
var id: Long, val address: String, val mirrors: List<String>,
val name: String, val description: String, val version: Int, var enabled: Boolean,
val fingerprint: String, val lastModified: String, val entityTag: String,
val updated: Long, val timestamp: Long, val authentication: String,
) {
fun edit(address: String, fingerprint: String, authentication: String): Repository {
val addressChanged = this.address != address
val fingerprintChanged = this.fingerprint != fingerprint
val changed = addressChanged || fingerprintChanged
return copy(
address = address,
fingerprint = fingerprint,
lastModified = if (changed) "" else lastModified,
entityTag = if (changed) "" else entityTag,
authentication = authentication
)
}
fun update(
mirrors: List<String>, name: String, description: String, version: Int,
lastModified: String, entityTag: String, timestamp: Long,
): Repository {
return copy(
mirrors = mirrors, name = name, description = description,
version = if (version >= 0) version else this.version, lastModified = lastModified,
entityTag = entityTag, updated = System.currentTimeMillis(), timestamp = timestamp
)
}
fun enable(enabled: Boolean): Repository {
return copy(enabled = enabled, lastModified = "", entityTag = "")
}
fun serialize(generator: JsonGenerator) {
generator.writeNumberField("serialVersion", 1)
generator.writeNumberField("id", id)
generator.writeStringField("address", address)
generator.writeArray("mirrors") { mirrors.forEach { writeString(it) } }
generator.writeStringField("name", name)
generator.writeStringField("description", description)
generator.writeNumberField("version", version)
generator.writeBooleanField("enabled", enabled)
generator.writeStringField("fingerprint", fingerprint)
generator.writeStringField("lastModified", lastModified)
generator.writeStringField("entityTag", entityTag)
generator.writeNumberField("updated", updated)
generator.writeNumberField("timestamp", timestamp)
generator.writeStringField("authentication", authentication)
}
companion object {
fun deserialize(parser: JsonParser): Repository {
var id = 0L
var address = ""
var mirrors = emptyList<String>()
var name = ""
var description = ""
var version = 0
var enabled = false
var fingerprint = ""
var lastModified = ""
var entityTag = ""
var updated = 0L
var timestamp = 0L
var authentication = ""
parser.forEachKey {
when {
it.string("id") -> id = valueAsLong
it.string("address") -> address = valueAsString
it.array("mirrors") -> mirrors = collectNotNullStrings()
it.string("name") -> name = valueAsString
it.string("description") -> description = valueAsString
it.number("version") -> version = valueAsInt
it.boolean("enabled") -> enabled = valueAsBoolean
it.string("fingerprint") -> fingerprint = valueAsString
it.string("lastModified") -> lastModified = valueAsString
it.string("entityTag") -> entityTag = valueAsString
it.number("updated") -> updated = valueAsLong
it.number("timestamp") -> timestamp = valueAsLong
it.string("authentication") -> authentication = valueAsString
else -> skipChildren()
}
}
return Repository(
id, address, mirrors, name, description, version, enabled, fingerprint,
lastModified, entityTag, updated, timestamp, authentication
)
}
fun newRepository(
address: String,
fingerprint: String,
authentication: String,
): Repository {
val name = try {
URL(address).let { "${it.host}${it.path}" }
} catch (e: Exception) {
address
}
return defaultRepository(address, name, "", 0, true, fingerprint, authentication)
}
private fun defaultRepository(
address: String, name: String, description: String,
version: Int, enabled: Boolean, fingerprint: String, authentication: String,
): Repository {
return Repository(
-1, address, emptyList(), name, description, version, enabled,
fingerprint, "", "", 0L, 0L, authentication
)
}
val defaultRepositories = listOf(run {
defaultRepository(
"https://f-droid.org/repo",
"F-Droid",
"The official F-Droid Free Software repository. " +
"Everything in this repository is always built from the source code.",
21,
true,
"43238D512C1E5EB2D6569F4A3AFBF5523418B82E0A3ED1552770ABB9A9C9CCAB",
""
)
}, run {
defaultRepository(
"https://f-droid.org/archive",
"F-Droid Archive",
"The archive of the official F-Droid Free " +
"Software repository. Apps here are old and can contain known vulnerabilities and security issues!",
21,
false,
"43238D512C1E5EB2D6569F4A3AFBF5523418B82E0A3ED1552770ABB9A9C9CCAB",
""
)
}, run {
defaultRepository(
"https://guardianproject.info/fdroid/repo",
"Guardian Project Official Releases",
"The " +
"official repository of The Guardian Project apps for use with the F-Droid client. Applications in this " +
"repository are official binaries built by the original application developers and signed by the same key as " +
"the APKs that are released in the Google Play Store.",
21,
false,
"B7C2EEFD8DAC7806AF67DFCD92EB18126BC08312A7F2D6F3862E46013C7A6135",
""
)
}, run {
defaultRepository(
"https://guardianproject.info/fdroid/archive",
"Guardian Project Archive",
"The official " +
"repository of The Guardian Project apps for use with the F-Droid client. This contains older versions of " +
"applications from the main repository.",
21,
false,
"B7C2EEFD8DAC7806AF67DFCD92EB18126BC08312A7F2D6F3862E46013C7A6135",
""
)
}, run {
defaultRepository(
"https://apt.izzysoft.de/fdroid/repo", "IzzyOnDroid F-Droid Repo", "This is a " +
"repository of apps to be used with F-Droid the original application developers, taken from the resp. " +
"repositories (mostly GitHub). At this moment I cannot give guarantees on regular updates for all of them, " +
"though most are checked multiple times a week ", 21, true,
"3BF0D6ABFEAE2F401707B6D966BE743BF0EEE49C2561B9BA39073711F628937A", ""
)
}, run {
defaultRepository(
"https://microg.org/fdroid/repo", "MicroG Project",
"Official repository of the open-source implementation of Google Play Services.",
21, false, "9BD06727E62796C0130EB6DAB39B73157451582CBD138E86C468ACC395D14165", ""
)
}, run {
defaultRepository(
"https://repo.netsyms.com/fdroid/repo", "Netsyms Technologies",
"Open-source apps created by Netsyms Technologies.",
21, false, "2581BA7B32D3AB443180C4087CAB6A7E8FB258D3A6E98870ECB3C675E4D64489", ""
)
}, run {
defaultRepository(
"https://fdroid.bromite.org/fdroid/repo", "Bromite",
"Bromite is a Chromium plus ad blocking and enhanced privacy; take back your browser.",
21, false, "E1EE5CD076D7B0DC84CB2B45FB78B86DF2EB39A3B6C56BA3DC292A5E0C3B9504", ""
)
}, run {
defaultRepository(
"https://molly.im/fdroid/foss/fdroid/repo", "Molly",
"Molly is a fork of Signal focused on security.",
21, false, "5198DAEF37FC23C14D5EE32305B2AF45787BD7DF2034DE33AD302BDB3446DF74", ""
)
}, run {
defaultRepository(
"https://archive.newpipe.net/fdroid/repo", "NewPipe",
"NewPipe's official independent repository.",
21, false, "E2402C78F9B97C6C89E97DB914A2751FDA1D02FE2039CC0897A462BDB57E7501", ""
)
}, run {
defaultRepository(
"https://www.collaboraoffice.com/downloads/fdroid/repo", "Collabora Office",
"Collabora Office is an office suite based on LibreOffice.",
21, false, "573258C84E149B5F4D9299E7434B2B69A8410372921D4AE586BA91EC767892CC", ""
)
}, run {
defaultRepository(
"https://www.droidware.info/fdroid/repo", "Ungoogled Chromium",
"Chromium sans dependency on Google web services. It also features some enhancments to privacy, control & transparency",
21, false, "2144449AB1DD270EC31B6087409B5D0EA39A75A9F290DA62AC1B238A0EAAF851", ""
)
}, run {
defaultRepository(
"https://fdroid.libretro.com/repo", "LibRetro",
"The official canary repository for this great retro emulators hub.",
21, false, "3F05B24D497515F31FEAB421297C79B19552C5C81186B3750B7C131EF41D733D", ""
)
}, run {
defaultRepository(
"https://cdn.kde.org/android/fdroid/repo", "KDE Android",
"The official nightly repository for KDE Android apps.",
21, false, "B3EBE10AFA6C5C400379B34473E843D686C61AE6AD33F423C98AF903F056523F", ""
)
}, run {
defaultRepository(
"https://rfc2822.gitlab.io/fdroid-firefox/fdroid/repo", "Unofficial Firefox",
"An unofficial repository with some of the most well known FOSS apps not on F-Droid.",
21, false, "8F992BBBA0340EFE6299C7A410B36D9C8889114CA6C58013C3587CDA411B4AED", ""
)
}, run {
defaultRepository(
"https://calyxos.gitlab.io/calyx-fdroid-repo/fdroid/repo", "Calyx OS Repo",
"The official Calyx Labs F-Droid repository.",
21, false, "C44D58B4547DE5096138CB0B34A1CC99DAB3B4274412ED753FCCBFC11DC1B7B6", ""
)
}, run {
defaultRepository(
"https://divestos.org/fdroid/official", "Divest OS Repo",
"The official Divest OS F-Droid repository.",
21, false, "E4BE8D6ABFA4D9D4FEEF03CDDA7FF62A73FD64B75566F6DD4E5E577550BE8467", ""
)
}, run {
defaultRepository(
"https://fdroid.fedilab.app/repo", "Fedilab",
"Fedilab's official F-Droid repository.",
21, false, "11F0A69910A4280E2CD3CCC3146337D006BE539B18E1A9FEACE15FF757A94FEB", ""
)
}, run {
defaultRepository(
"https://store.nethunter.com/repo", "Kali Nethunter",
"Kali Nethunter's official selection of original binaries.",
21, false, "7E418D34C3AD4F3C37D7E6B0FACE13332364459C862134EB099A3BDA2CCF4494", ""
)
}, run {
defaultRepository(
"https://secfirst.org/fdroid/repo", "Umbrella",
"Security advices, tutorials, tools etc..",
21, false, "39EB57052F8D684514176819D1645F6A0A7BD943DBC31AB101949006AC0BC228", ""
)
}, run {
defaultRepository(
"https://thecapslock.gitlab.io/fdroid-patched-apps/fdroid/repo", "Patched Apps",
"A collection of patched applications to provide better compatibility, privacy etc..",
21, false, "313D9E6E789FF4E8E2D687AAE31EEF576050003ED67963301821AC6D3763E3AC", ""
)
}, run {
defaultRepository(
"https://mobileapp.bitwarden.com/fdroid/repo", "Bitwarden",
"The official repository for Bitwarden.",
21, false, "BC54EA6FD1CD5175BCCCC47C561C5726E1C3ED7E686B6DB4B18BAC843A3EFE6C", ""
)
}, run {
defaultRepository(
"https://briarproject.org/fdroid/repo", "Briar",
"An serverless/offline messenger that hides your metadata.",
21, false, "1FB874BEE7276D28ECB2C9B06E8A122EC4BCB4008161436CE474C257CBF49BD6", ""
)
}, run {
defaultRepository(
"https://guardianproject-wind.s3.amazonaws.com/fdroid/repo", "Wind Project",
"A collection of interesting offline/serverless apps.",
21, false, "182CF464D219D340DA443C62155198E399FEC1BC4379309B775DD9FC97ED97E1", ""
)
}, run {
defaultRepository(
"https://repo.alefvanoon.xyz/fdroid/repo", "Alefvanoon",
"A collection of open-source apps that for one reason or another not on F-Droid.",
21, false, "04DF198F553069C7BE60F057AE12000E99F7700DA895CC1CE2EB11DC871581F1", ""
)
}, run {
defaultRepository(
"https://repo.unifiedpush.org/", "UnifiedPush",
"A repository of apps for unifiedPush.",
21, false, "DF11176406C63A7876103CE6CC1A8FCA239DF76AA5F6DE5CDBAFE73ECDBF1875", ""
)
}, run {
defaultRepository(
"https://nanolx.org/fdroid/repo", "NanoDroid",
"A companion repository to microG's installer.",
21, false, "862ED9F13A3981432BF86FE93D14596B381D75BE83A1D616E2D44A12654AD015", ""
)
})
}
}

View File

@ -4,9 +4,9 @@ import android.content.Context
import android.net.Uri import android.net.Uri
import com.looker.droidify.content.Cache import com.looker.droidify.content.Cache
import com.looker.droidify.database.DatabaseX import com.looker.droidify.database.DatabaseX
import com.looker.droidify.database.entity.Repository
import com.looker.droidify.entity.Product import com.looker.droidify.entity.Product
import com.looker.droidify.entity.Release import com.looker.droidify.entity.Release
import com.looker.droidify.entity.Repository
import com.looker.droidify.network.Downloader import com.looker.droidify.network.Downloader
import com.looker.droidify.utility.ProgressInputStream import com.looker.droidify.utility.ProgressInputStream
import com.looker.droidify.utility.RxUtils import com.looker.droidify.utility.RxUtils
@ -69,17 +69,15 @@ object RepositoryUpdater {
.observeOn(Schedulers.io()) .observeOn(Schedulers.io())
.flatMapSingle { .flatMapSingle {
RxUtils.querySingle { RxUtils.querySingle {
db.repositoryDao.allDisabledDeleted db.repositoryDao.allDisabled
} }
} }
.forEach { it -> .forEach { it ->
val newDisabled = it.asSequence().filter { !it.deleted }.map { it.id }.toSet() val newDisabled = it.toSet()
val disabled = newDisabled - lastDisabled val disabled = newDisabled - lastDisabled
lastDisabled = newDisabled lastDisabled = newDisabled
val deleted = it.asSequence().filter { it.deleted }.map { it.id }.toSet() if (disabled.isNotEmpty()) {
if (disabled.isNotEmpty() || deleted.isNotEmpty()) { val pairs = (disabled.asSequence().map { Pair(it, false) }).toSet()
val pairs = (disabled.asSequence().map { Pair(it, false) } +
deleted.asSequence().map { Pair(it, true) }).toSet()
synchronized(cleanupLock) { db.cleanUp(pairs) } synchronized(cleanupLock) { db.cleanUp(pairs) }
} }
} }

View File

@ -3,8 +3,8 @@ package com.looker.droidify.network
import android.content.Context import android.content.Context
import android.net.Uri import android.net.Uri
import android.view.View import android.view.View
import com.looker.droidify.database.entity.Repository
import com.looker.droidify.entity.Product import com.looker.droidify.entity.Product
import com.looker.droidify.entity.Repository
import com.looker.droidify.utility.extension.text.nullIfEmpty import com.looker.droidify.utility.extension.text.nullIfEmpty
import okhttp3.Cache import okhttp3.Cache
import okhttp3.Call import okhttp3.Call

View File

@ -17,8 +17,8 @@ import androidx.fragment.app.DialogFragment
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.looker.droidify.R import com.looker.droidify.R
import com.looker.droidify.database.entity.Repository
import com.looker.droidify.databinding.EditRepositoryBinding import com.looker.droidify.databinding.EditRepositoryBinding
import com.looker.droidify.entity.Repository
import com.looker.droidify.network.Downloader import com.looker.droidify.network.Downloader
import com.looker.droidify.service.Connection import com.looker.droidify.service.Connection
import com.looker.droidify.service.SyncService import com.looker.droidify.service.SyncService
@ -37,7 +37,6 @@ import java.net.URI
import java.net.URL import java.net.URL
import java.nio.charset.Charset import java.nio.charset.Charset
import java.util.* import java.util.*
import kotlin.collections.ArrayList
import kotlin.math.min import kotlin.math.min
class EditRepositoryFragment() : ScreenFragment() { class EditRepositoryFragment() : ScreenFragment() {
@ -153,7 +152,7 @@ class EditRepositoryFragment() : ScreenFragment() {
} }
if (savedInstanceState == null) { if (savedInstanceState == null) {
val repository = repositoryId?.let { screenActivity.db.repositoryDao.get(it)?.trueData } val repository = repositoryId?.let { screenActivity.db.repositoryDao.get(it) }
if (repository == null) { if (repository == null) {
val clipboardManager = val clipboardManager =
requireContext().getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager requireContext().getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
@ -232,7 +231,7 @@ class EditRepositoryFragment() : ScreenFragment() {
} }
lifecycleScope.launch { lifecycleScope.launch {
val list = screenActivity.db.repositoryDao.all.mapNotNull { it.trueData } val list = screenActivity.db.repositoryDao.all
takenAddresses = list.asSequence().filter { it.id != repositoryId } takenAddresses = list.asSequence().filter { it.id != repositoryId }
.flatMap { (it.mirrors + it.address).asSequence() } .flatMap { (it.mirrors + it.address).asSequence() }
.map { it.withoutKnownPath }.toSet() .map { it.withoutKnownPath }.toSet()
@ -448,7 +447,7 @@ class EditRepositoryFragment() : ScreenFragment() {
MessageDialog(MessageDialog.Message.CantEditSyncing).show(childFragmentManager) MessageDialog(MessageDialog.Message.CantEditSyncing).show(childFragmentManager)
invalidateState() invalidateState()
} else { } else {
val repository = repositoryId?.let { screenActivity.db.repositoryDao.get(it)?.trueData } val repository = repositoryId?.let { screenActivity.db.repositoryDao.get(it) }
?.edit(address, fingerprint, authentication) ?.edit(address, fingerprint, authentication)
?: Repository.newRepository(address, fingerprint, authentication) ?: Repository.newRepository(address, fingerprint, authentication)
val changedRepository = screenActivity.db.repositoryDao.put(repository) val changedRepository = screenActivity.db.repositoryDao.put(repository)

View File

@ -9,7 +9,7 @@ import com.google.android.material.card.MaterialCardView
import com.google.android.material.imageview.ShapeableImageView import com.google.android.material.imageview.ShapeableImageView
import com.google.android.material.textview.MaterialTextView import com.google.android.material.textview.MaterialTextView
import com.looker.droidify.R import com.looker.droidify.R
import com.looker.droidify.entity.Repository import com.looker.droidify.database.entity.Repository
import com.looker.droidify.utility.extension.resources.clear import com.looker.droidify.utility.extension.resources.clear
import com.looker.droidify.utility.extension.resources.getColorFromAttr import com.looker.droidify.utility.extension.resources.getColorFromAttr
import com.looker.droidify.utility.extension.resources.inflate import com.looker.droidify.utility.extension.resources.inflate

View File

@ -98,7 +98,7 @@ class RepositoryFragment() : ScreenFragment() {
} }
private fun updateRepositoryView() { private fun updateRepositoryView() {
val repository = screenActivity.db.repositoryDao.get(repositoryId)?.trueData val repository = screenActivity.db.repositoryDao.get(repositoryId)
val layout = layout!! val layout = layout!!
layout.removeAllViews() layout.removeAllViews()
if (repository == null) { if (repository == null) {

View File

@ -10,8 +10,8 @@ import coil.load
import com.google.android.material.card.MaterialCardView import com.google.android.material.card.MaterialCardView
import com.google.android.material.imageview.ShapeableImageView import com.google.android.material.imageview.ShapeableImageView
import com.looker.droidify.R import com.looker.droidify.R
import com.looker.droidify.database.entity.Repository
import com.looker.droidify.entity.Product import com.looker.droidify.entity.Product
import com.looker.droidify.entity.Repository
import com.looker.droidify.graphics.PaddingDrawable import com.looker.droidify.graphics.PaddingDrawable
import com.looker.droidify.network.CoilDownloader import com.looker.droidify.network.CoilDownloader
import com.looker.droidify.utility.extension.resources.getColorFromAttr import com.looker.droidify.utility.extension.resources.getColorFromAttr

View File

@ -20,8 +20,8 @@ import coil.load
import com.google.android.material.imageview.ShapeableImageView import com.google.android.material.imageview.ShapeableImageView
import com.looker.droidify.R import com.looker.droidify.R
import com.looker.droidify.database.DatabaseX import com.looker.droidify.database.DatabaseX
import com.looker.droidify.database.entity.Repository
import com.looker.droidify.entity.Product import com.looker.droidify.entity.Product
import com.looker.droidify.entity.Repository
import com.looker.droidify.graphics.PaddingDrawable import com.looker.droidify.graphics.PaddingDrawable
import com.looker.droidify.network.CoilDownloader import com.looker.droidify.network.CoilDownloader
import com.looker.droidify.utility.RxUtils import com.looker.droidify.utility.RxUtils
@ -143,7 +143,7 @@ class ScreenshotsFragment() : DialogFragment() {
.map { it -> .map { it ->
Pair( Pair(
it.find { it.repositoryId == repositoryId }, it.find { it.repositoryId == repositoryId },
db.repositoryDao.get(repositoryId)?.trueData db.repositoryDao.get(repositoryId)
) )
} }
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())

View File

@ -246,7 +246,7 @@ class TabsFragment : ScreenFragment() {
repositoriesDisposable = Observable.just(Unit) repositoriesDisposable = Observable.just(Unit)
//.concatWith(Database.observable(Database.Subject.Repositories)) // TODO have to be replaced like whole rxJava //.concatWith(Database.observable(Database.Subject.Repositories)) // TODO have to be replaced like whole rxJava
.observeOn(Schedulers.io()) .observeOn(Schedulers.io())
.flatMapSingle { RxUtils.querySingle { screenActivity.db.repositoryDao.all.mapNotNull { it.trueData } } } .flatMapSingle { RxUtils.querySingle { screenActivity.db.repositoryDao.all } }
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.subscribe { it -> .subscribe { it ->
setSectionsAndUpdate(null, it.asSequence().filter { it.enabled } setSectionsAndUpdate(null, it.asSequence().filter { it.enabled }

View File

@ -9,21 +9,32 @@ import android.view.ContextThemeWrapper
import androidx.core.app.NotificationCompat import androidx.core.app.NotificationCompat
import com.looker.droidify.* import com.looker.droidify.*
import com.looker.droidify.content.Cache import com.looker.droidify.content.Cache
import com.looker.droidify.database.entity.Repository
import com.looker.droidify.entity.Release import com.looker.droidify.entity.Release
import com.looker.droidify.entity.Repository
import com.looker.droidify.installer.AppInstaller import com.looker.droidify.installer.AppInstaller
import com.looker.droidify.network.Downloader import com.looker.droidify.network.Downloader
import com.looker.droidify.utility.Utils import com.looker.droidify.utility.Utils
import com.looker.droidify.utility.extension.android.* import com.looker.droidify.utility.extension.android.Android
import com.looker.droidify.utility.extension.resources.* import com.looker.droidify.utility.extension.android.notificationManager
import com.looker.droidify.utility.extension.text.* import com.looker.droidify.utility.extension.android.singleSignature
import com.looker.droidify.utility.extension.android.versionCodeCompat
import com.looker.droidify.utility.extension.resources.getColorFromAttr
import com.looker.droidify.utility.extension.text.formatSize
import com.looker.droidify.utility.extension.text.hex
import com.looker.droidify.utility.extension.text.nullIfEmpty
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.disposables.Disposable import io.reactivex.rxjava3.disposables.Disposable
import kotlinx.coroutines.* import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.* import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.cancel
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
import java.io.File import java.io.File
import java.security.MessageDigest import java.security.MessageDigest
import kotlin.math.* import kotlin.math.roundToInt
class DownloadService : ConnectionService<DownloadService.Binder>() { class DownloadService : ConnectionService<DownloadService.Binder>() {
companion object { companion object {

View File

@ -15,8 +15,8 @@ import androidx.fragment.app.Fragment
import com.looker.droidify.* import com.looker.droidify.*
import com.looker.droidify.content.Preferences import com.looker.droidify.content.Preferences
import com.looker.droidify.database.DatabaseX import com.looker.droidify.database.DatabaseX
import com.looker.droidify.database.entity.Repository
import com.looker.droidify.entity.ProductItem import com.looker.droidify.entity.ProductItem
import com.looker.droidify.entity.Repository
import com.looker.droidify.index.RepositoryUpdater import com.looker.droidify.index.RepositoryUpdater
import com.looker.droidify.utility.RxUtils import com.looker.droidify.utility.RxUtils
import com.looker.droidify.utility.Utils import com.looker.droidify.utility.Utils
@ -100,7 +100,7 @@ class SyncService : ConnectionService<SyncService.Binder>() {
fun sync(request: SyncRequest) { fun sync(request: SyncRequest) {
GlobalScope.launch { GlobalScope.launch {
val ids = db.repositoryDao.all.mapNotNull { it.trueData } val ids = db.repositoryDao.all
.asSequence().filter { it.enabled }.map { it.id }.toList() .asSequence().filter { it.enabled }.map { it.id }.toList()
sync(ids, request) sync(ids, request)
} }
@ -146,10 +146,10 @@ class SyncService : ConnectionService<SyncService.Binder>() {
} }
fun deleteRepository(repositoryId: Long): Boolean { fun deleteRepository(repositoryId: Long): Boolean {
val repository = db.repositoryDao.get(repositoryId)?.trueData val repository = db.repositoryDao.get(repositoryId)
return repository != null && run { return repository != null && run {
setEnabled(repository, false) setEnabled(repository, false)
db.repositoryDao.markAsDeleted(repository.id) db.repositoryDao.deleteById(repository.id)
true true
} }
} }
@ -337,7 +337,7 @@ class SyncService : ConnectionService<SyncService.Binder>() {
GlobalScope.launch { GlobalScope.launch {
if (tasks.isNotEmpty()) { if (tasks.isNotEmpty()) {
val task = tasks.removeAt(0) val task = tasks.removeAt(0)
val repository = db.repositoryDao.get(task.repositoryId)?.trueData val repository = db.repositoryDao.get(task.repositoryId)
if (repository != null && repository.enabled) { if (repository != null && repository.enabled) {
val lastStarted = started val lastStarted = started
val newStarted = val newStarted =
@ -454,7 +454,7 @@ class SyncService : ConnectionService<SyncService.Binder>() {
installedItem.package_name installedItem.package_name
) )
.filter { product -> product?.repository_id == repository.id } .filter { product -> product?.repository_id == repository.id }
.map { product -> Pair(product?.data!!, repository.data!!) } .map { product -> Pair(product?.data!!, repository) }
scope.launch { scope.launch {
Utils.startUpdate( Utils.startUpdate(

View File

@ -44,20 +44,23 @@ import com.looker.droidify.R
import com.looker.droidify.content.Preferences import com.looker.droidify.content.Preferences
import com.looker.droidify.content.ProductPreferences import com.looker.droidify.content.ProductPreferences
import com.looker.droidify.database.entity.Installed import com.looker.droidify.database.entity.Installed
import com.looker.droidify.entity.* import com.looker.droidify.database.entity.Repository
import com.looker.droidify.entity.Product
import com.looker.droidify.entity.ProductPreference
import com.looker.droidify.entity.Release
import com.looker.droidify.network.CoilDownloader import com.looker.droidify.network.CoilDownloader
import com.looker.droidify.screen.ScreenshotsAdapter import com.looker.droidify.screen.ScreenshotsAdapter
import com.looker.droidify.utility.KParcelable import com.looker.droidify.utility.KParcelable
import com.looker.droidify.utility.PackageItemResolver import com.looker.droidify.utility.PackageItemResolver
import com.looker.droidify.utility.Utils import com.looker.droidify.utility.Utils
import com.looker.droidify.utility.extension.android.* import com.looker.droidify.utility.extension.android.Android
import com.looker.droidify.utility.extension.resources.* import com.looker.droidify.utility.extension.resources.*
import com.looker.droidify.utility.extension.text.* import com.looker.droidify.utility.extension.text.*
import com.looker.droidify.widget.ClickableMovementMethod import com.looker.droidify.widget.ClickableMovementMethod
import com.looker.droidify.widget.StableRecyclerAdapter import com.looker.droidify.widget.StableRecyclerAdapter
import java.lang.ref.WeakReference import java.lang.ref.WeakReference
import java.util.* import java.util.*
import kotlin.math.* import kotlin.math.roundToInt
class AppDetailAdapter(private val callbacks: Callbacks) : class AppDetailAdapter(private val callbacks: Callbacks) :
StableRecyclerAdapter<AppDetailAdapter.ViewType, RecyclerView.ViewHolder>() { StableRecyclerAdapter<AppDetailAdapter.ViewType, RecyclerView.ViewHolder>() {

View File

@ -16,8 +16,8 @@ import com.google.android.material.progressindicator.CircularProgressIndicator
import com.google.android.material.textview.MaterialTextView import com.google.android.material.textview.MaterialTextView
import com.looker.droidify.R import com.looker.droidify.R
import com.looker.droidify.content.Preferences import com.looker.droidify.content.Preferences
import com.looker.droidify.database.entity.Repository
import com.looker.droidify.entity.ProductItem import com.looker.droidify.entity.ProductItem
import com.looker.droidify.entity.Repository
import com.looker.droidify.network.CoilDownloader import com.looker.droidify.network.CoilDownloader
import com.looker.droidify.utility.Utils import com.looker.droidify.utility.Utils
import com.looker.droidify.utility.extension.resources.* import com.looker.droidify.utility.extension.resources.*

View File

@ -17,7 +17,10 @@ import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.looker.droidify.R import com.looker.droidify.R
import com.looker.droidify.content.ProductPreferences import com.looker.droidify.content.ProductPreferences
import com.looker.droidify.entity.* import com.looker.droidify.database.entity.Repository
import com.looker.droidify.entity.Product
import com.looker.droidify.entity.ProductPreference
import com.looker.droidify.entity.Release
import com.looker.droidify.installer.AppInstaller import com.looker.droidify.installer.AppInstaller
import com.looker.droidify.screen.MessageDialog import com.looker.droidify.screen.MessageDialog
import com.looker.droidify.screen.ScreenFragment import com.looker.droidify.screen.ScreenFragment
@ -142,7 +145,7 @@ class AppDetailFragment() : ScreenFragment(), AppDetailAdapter.Callbacks {
} }
.flatMapSingle { products -> .flatMapSingle { products ->
RxUtils RxUtils
.querySingle { screenActivity.db.repositoryDao.all.mapNotNull { it.trueData } } .querySingle { screenActivity.db.repositoryDao.all }
.map { it -> .map { it ->
it.asSequence().map { Pair(it.id, it) }.toMap() it.asSequence().map { Pair(it.id, it) }.toMap()
.let { .let {

View File

@ -83,7 +83,7 @@ class AppListFragment() : BaseFragment(), CursorOwner.Callback {
repositoriesDisposable = Observable.just(Unit) repositoriesDisposable = Observable.just(Unit)
//.concatWith(Database.observable(Database.Subject.Repositories)) // TODO have to be replaced like whole rxJava //.concatWith(Database.observable(Database.Subject.Repositories)) // TODO have to be replaced like whole rxJava
.observeOn(Schedulers.io()) .observeOn(Schedulers.io())
.flatMapSingle { RxUtils.querySingle { screenActivity.db.repositoryDao.all.mapNotNull { it.trueData } } } .flatMapSingle { RxUtils.querySingle { screenActivity.db.repositoryDao.all } }
.map { it.asSequence().map { Pair(it.id, it) }.toMap() } .map { it.asSequence().map { Pair(it.id, it) }.toMap() }
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.subscribe { (recyclerView?.adapter as? AppListAdapter)?.repositories = it } .subscribe { (recyclerView?.adapter as? AppListAdapter)?.repositories = it }

View File

@ -133,7 +133,7 @@ class EditRepositorySheetX() : FullscreenBottomSheetDialogFragment() {
binding.save.setOnClickListener { onSaveRepositoryClick() } binding.save.setOnClickListener { onSaveRepositoryClick() }
GlobalScope.launch { GlobalScope.launch {
val list = viewModel.db.repositoryDao.all.mapNotNull { it.trueData } val list = viewModel.db.repositoryDao.all
takenAddresses = list.asSequence().filter { it.id != repositoryId } takenAddresses = list.asSequence().filter { it.id != repositoryId }
.flatMap { (it.mirrors + it.address).asSequence() } .flatMap { (it.mirrors + it.address).asSequence() }
.map { it.withoutKnownPath }.toSet() .map { it.withoutKnownPath }.toSet()
@ -142,7 +142,7 @@ class EditRepositorySheetX() : FullscreenBottomSheetDialogFragment() {
} }
override fun updateSheet() { override fun updateSheet() {
val repository = viewModel.repo.value?.trueData val repository = viewModel.repo.value
if (repository == null) { if (repository == null) {
val clipboardManager = val clipboardManager =
requireContext().getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager requireContext().getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
@ -391,7 +391,7 @@ class EditRepositorySheetX() : FullscreenBottomSheetDialogFragment() {
invalidateState() invalidateState()
} else { } else {
viewModel.updateRepo( viewModel.updateRepo(
viewModel.repo.value?.trueData?.copy( viewModel.repo.value?.copy(
address = address, address = address,
fingerprint = fingerprint, fingerprint = fingerprint,
authentication = authentication authentication = authentication

View File

@ -6,8 +6,8 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import com.looker.droidify.database.entity.Product import com.looker.droidify.database.entity.Product
import com.looker.droidify.database.entity.Repository
import com.looker.droidify.databinding.FragmentExploreXBinding import com.looker.droidify.databinding.FragmentExploreXBinding
import com.looker.droidify.entity.Repository
import com.looker.droidify.ui.items.VAppItem import com.looker.droidify.ui.items.VAppItem
import com.looker.droidify.utility.PRODUCT_ASYNC_DIFFER_CONFIG import com.looker.droidify.utility.PRODUCT_ASYNC_DIFFER_CONFIG
import com.looker.droidify.utility.RxUtils import com.looker.droidify.utility.RxUtils
@ -43,7 +43,7 @@ class ExploreFragment : MainNavFragmentX() {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
viewModel.db.repositoryDao.allFlowable viewModel.db.repositoryDao.allFlowable
.observeOn(Schedulers.io()) .observeOn(Schedulers.io())
.flatMapSingle { list -> RxUtils.querySingle { list.mapNotNull { it.trueData } } } .flatMapSingle { list -> RxUtils.querySingle { list } }
.map { list -> list.asSequence().map { Pair(it.id, it) }.toMap() } .map { list -> list.asSequence().map { Pair(it.id, it) }.toMap() }
.subscribeOn(AndroidSchedulers.mainThread()) .subscribeOn(AndroidSchedulers.mainThread())
.subscribe { repositories = it } .subscribe { repositories = it }

View File

@ -7,8 +7,8 @@ import android.view.ViewGroup
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import com.looker.droidify.database.entity.Product import com.looker.droidify.database.entity.Product
import com.looker.droidify.database.entity.Repository
import com.looker.droidify.databinding.FragmentInstalledXBinding import com.looker.droidify.databinding.FragmentInstalledXBinding
import com.looker.droidify.entity.Repository
import com.looker.droidify.ui.items.HAppItem import com.looker.droidify.ui.items.HAppItem
import com.looker.droidify.ui.items.VAppItem import com.looker.droidify.ui.items.VAppItem
import com.looker.droidify.utility.PRODUCT_ASYNC_DIFFER_CONFIG import com.looker.droidify.utility.PRODUCT_ASYNC_DIFFER_CONFIG
@ -47,7 +47,7 @@ class InstalledFragment : MainNavFragmentX() {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
viewModel.db.repositoryDao.allFlowable viewModel.db.repositoryDao.allFlowable
.observeOn(Schedulers.io()) .observeOn(Schedulers.io())
.flatMapSingle { list -> RxUtils.querySingle { list.mapNotNull { it.trueData } } } .flatMapSingle { list -> RxUtils.querySingle { list } }
.map { list -> list.asSequence().map { Pair(it.id, it) }.toMap() } .map { list -> list.asSequence().map { Pair(it.id, it) }.toMap() }
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.subscribe { repositories = it } .subscribe { repositories = it }

View File

@ -7,8 +7,8 @@ import android.view.ViewGroup
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import com.looker.droidify.database.entity.Product import com.looker.droidify.database.entity.Product
import com.looker.droidify.database.entity.Repository
import com.looker.droidify.databinding.FragmentLatestXBinding import com.looker.droidify.databinding.FragmentLatestXBinding
import com.looker.droidify.entity.Repository
import com.looker.droidify.ui.items.HAppItem import com.looker.droidify.ui.items.HAppItem
import com.looker.droidify.ui.items.VAppItem import com.looker.droidify.ui.items.VAppItem
import com.looker.droidify.utility.PRODUCT_ASYNC_DIFFER_CONFIG import com.looker.droidify.utility.PRODUCT_ASYNC_DIFFER_CONFIG
@ -48,7 +48,7 @@ class LatestFragment : MainNavFragmentX() {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
viewModel.db.repositoryDao.allFlowable viewModel.db.repositoryDao.allFlowable
.observeOn(Schedulers.io()) .observeOn(Schedulers.io())
.flatMapSingle { list -> RxUtils.querySingle { list.mapNotNull { it.trueData } } } .flatMapSingle { list -> RxUtils.querySingle { list } }
.map { list -> list.asSequence().map { Pair(it.id, it) }.toMap() } .map { list -> list.asSequence().map { Pair(it.id, it) }.toMap() }
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.subscribe { repositories = it } .subscribe { repositories = it }

View File

@ -75,25 +75,24 @@ class PrefsRepositoriesFragment : BaseNavFragment() {
layoutManager = LinearLayoutManager(context) layoutManager = LinearLayoutManager(context)
adapter = reposFastAdapter adapter = reposFastAdapter
} }
binding.addRepository.setOnClickListener { viewModel.addRepository() }
} }
override fun setupLayout() { override fun setupLayout() {
viewModel.repositories.observe(requireActivity()) { viewModel.repositories.observe(requireActivity()) {
// Function: sync when an enabled repo got edited // Function: sync when an enabled repo got edited
val enabledList = it.filter { it.enabled == 1 } val enabledList = it.filter { it.enabled }
reposItemAdapter.adapterItems.filter(RepoItem::isEnabled).forEach { item -> reposItemAdapter.adapterItems.filter(RepoItem::isEnabled).forEach { item ->
enabledList.firstOrNull { it.trueData?.id == item.item.id }?.let { repo -> enabledList.firstOrNull { it.id == item.item.id }?.let { repo ->
repo.trueData?.let { data -> repo.let { data ->
if (data != item.item) syncConnection.binder?.sync(data) if (data != item.item) syncConnection.binder?.sync(data)
} }
} }
} }
reposItemAdapter.set( reposItemAdapter.set(
it.sortedBy { repo -> -repo.enabled } it.sortedBy { repo -> !repo.enabled }
.mapNotNull { dbRepo -> .mapNotNull { dbRepo ->
dbRepo.trueData?.let { repo -> RepoItem(dbRepo)
RepoItem(repo)
}
} }
) )
} }

View File

@ -71,7 +71,7 @@ class RepositorySheetX() : FullscreenBottomSheetDialogFragment() {
} }
override fun updateSheet() { override fun updateSheet() {
val repository = viewModel.repo.value?.trueData val repository = viewModel.repo.value
if (repository == null) { if (repository == null) {
binding.address.text = getString(R.string.unknown) binding.address.text = getString(R.string.unknown)

View File

@ -5,9 +5,9 @@ import android.view.ViewGroup
import coil.load import coil.load
import coil.transform.RoundedCornersTransformation import coil.transform.RoundedCornersTransformation
import com.looker.droidify.R import com.looker.droidify.R
import com.looker.droidify.database.entity.Repository
import com.looker.droidify.databinding.ItemAppHorizXBinding import com.looker.droidify.databinding.ItemAppHorizXBinding
import com.looker.droidify.entity.ProductItem import com.looker.droidify.entity.ProductItem
import com.looker.droidify.entity.Repository
import com.looker.droidify.network.CoilDownloader import com.looker.droidify.network.CoilDownloader
import com.looker.droidify.utility.Utils import com.looker.droidify.utility.Utils
import com.looker.droidify.utility.extension.resources.toPx import com.looker.droidify.utility.extension.resources.toPx

View File

@ -5,8 +5,8 @@ import android.view.LayoutInflater
import android.view.ViewGroup import android.view.ViewGroup
import coil.load import coil.load
import com.looker.droidify.R import com.looker.droidify.R
import com.looker.droidify.database.entity.Repository
import com.looker.droidify.databinding.ItemRepositoryXBinding import com.looker.droidify.databinding.ItemRepositoryXBinding
import com.looker.droidify.entity.Repository
import com.looker.droidify.utility.extension.resources.clear import com.looker.droidify.utility.extension.resources.clear
import com.looker.droidify.utility.extension.resources.getColorFromAttr import com.looker.droidify.utility.extension.resources.getColorFromAttr
import com.mikepenz.fastadapter.binding.AbstractBindingItem import com.mikepenz.fastadapter.binding.AbstractBindingItem

View File

@ -7,9 +7,9 @@ import androidx.core.content.res.ResourcesCompat
import coil.load import coil.load
import coil.transform.RoundedCornersTransformation import coil.transform.RoundedCornersTransformation
import com.looker.droidify.R import com.looker.droidify.R
import com.looker.droidify.database.entity.Repository
import com.looker.droidify.databinding.ItemAppVerticalXBinding import com.looker.droidify.databinding.ItemAppVerticalXBinding
import com.looker.droidify.entity.ProductItem import com.looker.droidify.entity.ProductItem
import com.looker.droidify.entity.Repository
import com.looker.droidify.network.CoilDownloader import com.looker.droidify.network.CoilDownloader
import com.looker.droidify.utility.Utils import com.looker.droidify.utility.Utils
import com.looker.droidify.utility.extension.resources.getColorFromAttr import com.looker.droidify.utility.extension.resources.getColorFromAttr

View File

@ -20,7 +20,7 @@ class RepositoryViewModelX(val db: DatabaseX, val repositoryId: Long) : ViewMode
appsCount.addSource(db.productDao.countForRepositoryLive(repositoryId), appsCount::setValue) appsCount.addSource(db.productDao.countForRepositoryLive(repositoryId), appsCount::setValue)
} }
fun updateRepo(newValue: com.looker.droidify.entity.Repository?) { fun updateRepo(newValue: Repository?) {
newValue?.let { newValue?.let {
viewModelScope.launch { viewModelScope.launch {
update(it) update(it)
@ -28,7 +28,7 @@ class RepositoryViewModelX(val db: DatabaseX, val repositoryId: Long) : ViewMode
} }
} }
private suspend fun update(newValue: com.looker.droidify.entity.Repository) { private suspend fun update(newValue: Repository) {
withContext(Dispatchers.IO) { withContext(Dispatchers.IO) {
db.repositoryDao.put(newValue) db.repositoryDao.put(newValue)
} }

View File

@ -17,10 +17,10 @@ import com.fasterxml.jackson.core.JsonParser
import com.looker.droidify.* import com.looker.droidify.*
import com.looker.droidify.content.Preferences import com.looker.droidify.content.Preferences
import com.looker.droidify.database.entity.Installed import com.looker.droidify.database.entity.Installed
import com.looker.droidify.database.entity.Repository
import com.looker.droidify.entity.InstalledItem import com.looker.droidify.entity.InstalledItem
import com.looker.droidify.entity.Product import com.looker.droidify.entity.Product
import com.looker.droidify.entity.ProductItem import com.looker.droidify.entity.ProductItem
import com.looker.droidify.entity.Repository
import com.looker.droidify.service.Connection import com.looker.droidify.service.Connection
import com.looker.droidify.service.DownloadService import com.looker.droidify.service.DownloadService
import com.looker.droidify.utility.extension.android.Android import com.looker.droidify.utility.extension.android.Android