Display compatibility information

This commit is contained in:
kitsunyan
2020-06-11 06:49:09 +03:00
parent 858b5aaa3d
commit bb50d77547
7 changed files with 70 additions and 36 deletions
@@ -218,9 +218,9 @@ class IndexHandler(private val repositoryId: Long, private val callback: Callbac
"obbMainFileSha256" -> releaseBuilder.obbMainHash = content
"obbPatchFile" -> releaseBuilder.obbPatch = content
"obbPatchFileSha256" -> releaseBuilder.obbPatchHash = content
"permissions" -> releaseBuilder.permissions += content.split(',')
"features" -> releaseBuilder.features += content.split(',')
"nativecode" -> releaseBuilder.platforms += content.split(',')
"permissions" -> releaseBuilder.permissions += content.split(',').filter { it.isNotEmpty() }
"features" -> releaseBuilder.features += content.split(',').filter { it.isNotEmpty() }
"nativecode" -> releaseBuilder.platforms += content.split(',').filter { it.isNotEmpty() }
}
}
productBuilder != null -> {
@@ -239,9 +239,9 @@ class IndexHandler(private val repositoryId: Long, private val callback: Callbac
"added" -> productBuilder.added = content.parseDate()
"lastupdated" -> productBuilder.updated = content.parseDate()
"marketvercode" -> productBuilder.suggestedVersionCode = content.toLongOrNull() ?: 0L
"categories" -> productBuilder.categories += content.split(',')
"antifeatures" -> productBuilder.antiFeatures += content.split(',')
"license" -> productBuilder.licenses += content.split(',')
"categories" -> productBuilder.categories += content.split(',').filter { it.isNotEmpty() }
"antifeatures" -> productBuilder.antiFeatures += content.split(',').filter { it.isNotEmpty() }
"license" -> productBuilder.licenses += content.split(',').filter { it.isNotEmpty() }
"donate" -> productBuilder.donates += Product.Donate.Regular(content)
"bitcoin" -> productBuilder.donates += Product.Donate.Bitcoin(content)
"litecoin" -> productBuilder.donates += Product.Donate.Litecoin(content)
@@ -49,7 +49,7 @@ object IndexV1Parser {
forEachKey {
when {
it.string("address") -> address = valueAsString
it.array("mirrors") -> mirrors = collectNotNullStrings()
it.array("mirrors") -> mirrors = collectDistinctNotEmptyStrings()
it.string("name") -> name = valueAsString
it.string("description") -> description = valueAsString
it.number("version") -> version = valueAsInt
@@ -117,9 +117,9 @@ object IndexV1Parser {
it.number("added") -> added = valueAsLong
it.number("lastUpdated") -> updated = valueAsLong
it.string("suggestedVersionCode") -> suggestedVersionCode = valueAsString.toLongOrNull() ?: 0L
it.array("categories") -> categories = collectNotNullStrings()
it.array("antiFeatures") -> antiFeatures = collectNotNullStrings()
it.string("license") -> licenses += valueAsString.split(',')
it.array("categories") -> categories = collectDistinctNotEmptyStrings()
it.array("antiFeatures") -> antiFeatures = collectDistinctNotEmptyStrings()
it.string("license") -> licenses += valueAsString.split(',').filter { it.isNotEmpty() }
it.string("donate") -> donates += Product.Donate.Regular(valueAsString)
it.string("bitcoin") -> donates += Product.Donate.Bitcoin(valueAsString)
it.string("flattrID") -> donates += Product.Donate.Flattr(valueAsString)
@@ -140,9 +140,9 @@ object IndexV1Parser {
it.string("summary") -> summary = valueAsString
it.string("description") -> description = valueAsString
it.string("whatsNew") -> whatsNew = valueAsString
it.array("phoneScreenshots") -> phone = collectNotNullStrings()
it.array("sevenInchScreenshots") -> smallTablet = collectNotNullStrings()
it.array("tenInchScreenshots") -> largeTablet = collectNotNullStrings()
it.array("phoneScreenshots") -> phone = collectDistinctNotEmptyStrings()
it.array("sevenInchScreenshots") -> smallTablet = collectDistinctNotEmptyStrings()
it.array("tenInchScreenshots") -> largeTablet = collectDistinctNotEmptyStrings()
else -> skipChildren()
}
}
@@ -215,8 +215,8 @@ object IndexV1Parser {
it.string("obbPatchFileSha256") -> obbPatchHash = valueAsString
it.array("uses-permission") -> collectPermissions(permissions, 0)
it.array("uses-permission-sdk-23") -> collectPermissions(permissions, 23)
it.array("features") -> features = collectNotNullStrings()
it.array("nativecode") -> platforms = collectNotNullStrings()
it.array("features") -> features = collectDistinctNotEmptyStrings()
it.array("nativecode") -> platforms = collectDistinctNotEmptyStrings()
else -> skipChildren()
}
}
@@ -332,9 +332,31 @@ object RepositoryUpdater {
val predicate: (Release) -> Boolean = { unstable || product.suggestedVersionCode <= 0 ||
it.versionCode <= product.suggestedVersionCode }
val compatibleReleaseIndex = releasePairs.indexOfFirst { it.second.isEmpty() && predicate(it.first) }
val releaseIndex = if (compatibleReleaseIndex >= 0) compatibleReleaseIndex else
val firstCompatibleReleaseIndex = releasePairs.indexOfFirst { it.second.isEmpty() && predicate(it.first) }
val releaseIndex = if (firstCompatibleReleaseIndex >= 0) {
val versionCode = releasePairs[firstCompatibleReleaseIndex].first.versionCode
val candidates = releasePairs.mapIndexedNotNull { index, (product, incompatibilities) ->
if (product.versionCode == versionCode && incompatibilities.isEmpty()) index else null
}
if (product.packageName == "org.telegram.messenger") {
val x = candidates
.filter { releasePairs[it].first.platforms.contains(Android.primaryPlatform) }
.minBy { releasePairs[it].first.platforms.size }
val y = candidates.minBy { releasePairs[it].first.platforms.size }
debug("telegram $firstCompatibleReleaseIndex $candidates $x $y")
}
if (candidates.size <= 1) {
firstCompatibleReleaseIndex
} else {
candidates
.filter { releasePairs[it].first.platforms.contains(Android.primaryPlatform) }
.minBy { releasePairs[it].first.platforms.size }
?: candidates.minBy { releasePairs[it].first.platforms.size }
?: firstCompatibleReleaseIndex
}
} else {
releasePairs.indexOfFirst { predicate(it.first) }
}
val releases = releasePairs.mapIndexed { index, (release, incompatibilities) -> release
.copy(incompatibilities = incompatibilities, selected = index == releaseIndex) }
@@ -250,8 +250,7 @@ class ProductAdapter(private val callbacks: Callbacks, private val columns: Int)
get() = ViewType.SCREENSHOT
}
class ReleaseItem(val repository: Repository, val release: Release,
val selectedRepository: Boolean): Item() {
class ReleaseItem(val repository: Repository, val release: Release, val selectedRepository: Boolean): Item() {
override val descriptor: String
get() = "release.${repository.id}.${release.identifier}"
@@ -456,10 +455,10 @@ class ProductAdapter(private val callbacks: Callbacks, private val columns: Int)
val source = itemView.findViewById<TextView>(R.id.source)!!
val added = itemView.findViewById<TextView>(R.id.added)!!
val size = itemView.findViewById<TextView>(R.id.size)!!
val error = itemView.findViewById<TextView>(R.id.error)!!
val compatibility = itemView.findViewById<TextView>(R.id.compatibility)!!
val statefulViews: Sequence<View>
get() = sequenceOf(itemView, version, status, source, added, size, error)
get() = sequenceOf(itemView, version, status, source, added, size, compatibility)
val setStatusActive: (Boolean) -> Unit
@@ -748,18 +747,20 @@ class ProductAdapter(private val callbacks: Callbacks, private val columns: Int)
}
val incompatible = Preferences[Preferences.Key.IncompatibleVersions]
val releases = products.flatMap { (product, repository) -> product.releases
.map { Item.ReleaseItem(repository, it, repository.id == productRepository?.second?.id) } }
.filter { incompatible || it.release.incompatibilities.isEmpty() }
val releaseItems = products.asSequence()
.flatMap { (product, repository) -> product.releases.asSequence()
.filter { incompatible || it.incompatibilities.isEmpty() }
.map { Item.ReleaseItem(repository, it, repository.id == productRepository?.second?.id) } }
.sortedByDescending { it.release.versionCode }
if (releases.isNotEmpty()) {
.toList()
if (releaseItems.isNotEmpty()) {
items += Item.SectionItem(SectionType.RELEASES)
val maxReleases = 5
if (releases.size > maxReleases && ExpandType.RELEASES !in expanded) {
items += releases.take(maxReleases)
items += Item.ExpandItem(ExpandType.RELEASES, false, releases.takeLast(releases.size - maxReleases))
if (releaseItems.size > maxReleases && ExpandType.RELEASES !in expanded) {
items += releaseItems.take(maxReleases)
items += Item.ExpandItem(ExpandType.RELEASES, false, releaseItems.takeLast(releaseItems.size - maxReleases))
} else {
items += releases
items += releaseItems
}
}
@@ -1129,6 +1130,7 @@ class ProductAdapter(private val callbacks: Callbacks, private val columns: Int)
holder as ReleaseViewHolder
item as Item.ReleaseItem
val incompatibility = item.release.incompatibilities.firstOrNull()
val singlePlatform = if (item.release.platforms.size == 1) item.release.platforms.first() else null
val installed = installedItem?.versionCode == item.release.versionCode &&
installedItem?.signature == item.release.signature
val suggested = incompatibility == null && item.release.selected && item.selectedRepository
@@ -1150,15 +1152,20 @@ class ProductAdapter(private val callbacks: Callbacks, private val columns: Int)
holder.added.text = holder.dateFormat.format(item.release.added)
holder.added.setTextColor(primarySecondaryColor)
holder.size.text = item.release.size.formatSize()
holder.error.visibility = if (incompatibility != null) View.VISIBLE else View.GONE
holder.compatibility.visibility = if (incompatibility != null || singlePlatform != null)
View.VISIBLE else View.GONE
if (incompatibility != null) {
holder.error.text = when (incompatibility) {
holder.compatibility.setTextColor(context.getColorFromAttr(R.attr.colorError))
holder.compatibility.text = when (incompatibility) {
is Release.Incompatibility.MinSdk,
is Release.Incompatibility.MaxSdk -> context.getString(R.string.is_not_supported_format, Android.name)
is Release.Incompatibility.Platform -> context.getString(R.string.is_not_supported_format,
is Release.Incompatibility.MaxSdk -> context.getString(R.string.incompatible_with_format, Android.name)
is Release.Incompatibility.Platform -> context.getString(R.string.incompatible_with_format,
Android.primaryPlatform ?: context.getString(R.string.unknown))
is Release.Incompatibility.Feature -> context.getString(R.string.requires_format, incompatibility.feature)
}
} else if (singlePlatform != null) {
holder.compatibility.setTextColor(context.getColorFromAttr(android.R.attr.textColorSecondary))
holder.compatibility.text = context.getString(R.string.compatible_with_only_format, singlePlatform)
}
val enabled = status == null
holder.statefulViews.forEach { it.isEnabled = enabled }
@@ -77,6 +77,10 @@ fun JsonParser.collectNotNullStrings(): List<String> {
return collectNotNull(JsonToken.VALUE_STRING) { valueAsString }
}
fun JsonParser.collectDistinctNotEmptyStrings(): List<String> {
return collectNotNullStrings().asSequence().filter { it.isNotEmpty() }.distinct().toList()
}
inline fun <T> JsonParser.parseDictionary(callback: JsonParser.() -> T): T {
if (nextToken() == JsonToken.START_OBJECT) {
val result = callback()
+2 -2
View File
@@ -96,10 +96,10 @@
</LinearLayout>
<TextView
android:id="@+id/error"
android:id="@+id/compatibility"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="?attr/colorError"
android:textColor="?android:attr/textColorSecondary"
android:textSize="14sp"
android:singleLine="true" />
+2 -1
View File
@@ -31,6 +31,7 @@
<string name="cant_edit_sync_description">Cannot edit repository since it\'s syncing right now.</string>
<string name="changelog">Changelog</string>
<string name="checking_repository">Checking repository</string>
<string name="compatible_with_only_format">Compatible with %s only</string>
<string name="confirm_action">Confirm action</string>
<string name="connecting">Connecting</string>
<string name="dark">Dark</string>
@@ -65,13 +66,13 @@
<string name="incompatible_version">Incompatible version</string>
<string name="incompatible_versions">Incompatible versions</string>
<string name="incompatible_versions_summary">Show application versions incompatible with the device</string>
<string name="incompatible_with_format">Incompatible with %s</string>
<string name="install">Install</string>
<string name="installed">Installed</string>
<string name="installed_empty_summary">No applications installed</string>
<string name="invalid_address">Invalid address</string>
<string name="invalid_fingerprint_format">Invalid fingerprint format</string>
<string name="invalid_username_format">Invalid username format</string>
<string name="is_not_supported_format">%s is not supported</string>
<string name="last_update">Last update</string>
<string name="launch">Launch</string>
<string name="license">License</string>