Skip to content

Commit d5a5ec6

Browse files
authored
feat: Show release dates and patch count (#3185)
1 parent 2aaef8c commit d5a5ec6

File tree

17 files changed

+685
-41
lines changed

17 files changed

+685
-41
lines changed

app/schemas/app.revanced.manager.data.room.AppDatabase/4.json

Lines changed: 493 additions & 0 deletions
Large diffs are not rendered by default.

app/src/main/java/app/revanced/manager/data/room/AppDatabase.kt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,14 +26,16 @@ import kotlin.random.Random
2626

2727
@Database(
2828
entities = [PatchBundleEntity::class, PatchSelection::class, SelectedPatch::class, DownloadedApp::class, InstalledApp::class, AppliedPatch::class, InstalledPatchBundle::class, OptionGroup::class, Option::class, DownloaderEntity::class],
29-
version = 3,
29+
version = 4,
30+
exportSchema = true,
3031
autoMigrations = [
3132
AutoMigration(from = 1, to = 2),
3233
AutoMigration(
3334
from = 2,
3435
to = 3,
3536
spec = AppDatabase.DeleteTrustedDownloaders::class
36-
)
37+
),
38+
AutoMigration(from = 3, to = 4)
3739
]
3840
)
3941
@TypeConverters(Converters::class)

app/src/main/java/app/revanced/manager/data/room/bundles/PatchBundleDao.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ interface PatchBundleDao {
2323
@Query("DELETE FROM patch_bundles WHERE uid = :uid")
2424
suspend fun remove(uid: Int)
2525

26-
@Query("SELECT name, version, auto_update, source FROM patch_bundles WHERE uid = :uid")
26+
@Query("SELECT name, version, auto_update, source, released_at FROM patch_bundles WHERE uid = :uid")
2727
suspend fun getProps(uid: Int): SourceProperties?
2828

2929
@Upsert

app/src/main/java/app/revanced/manager/data/room/bundles/PatchBundleEntity.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,6 @@ data class PatchBundleEntity(
1010
@ColumnInfo(name = "name") val name: String,
1111
@ColumnInfo(name = "version") val versionHash: String? = null,
1212
@ColumnInfo(name = "source") val source: Source,
13-
@ColumnInfo(name = "auto_update") val autoUpdate: Boolean
13+
@ColumnInfo(name = "auto_update") val autoUpdate: Boolean,
14+
@ColumnInfo(name = "released_at") val releasedAt: Long? = null,
1415
) : SourceManager.DatabaseEntity

app/src/main/java/app/revanced/manager/data/room/downloader/DownloaderDao.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ interface DownloaderDao {
2626
@Query("DELETE FROM downloaders WHERE uid = :uid")
2727
suspend fun remove(uid: Int)
2828

29-
@Query("SELECT name, version, auto_update, source FROM downloaders WHERE uid = :uid")
29+
@Query("SELECT name, version, auto_update, source, released_at FROM downloaders WHERE uid = :uid")
3030
suspend fun getProps(uid: Int): SourceProperties?
3131

3232
@Upsert

app/src/main/java/app/revanced/manager/data/room/downloader/DownloaderEntity.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,6 @@ data class DownloaderEntity(
1010
@ColumnInfo(name = "name") val name: String,
1111
@ColumnInfo(name = "version") val versionHash: String? = null,
1212
@ColumnInfo(name = "source") val source: Source,
13-
@ColumnInfo(name = "auto_update") val autoUpdate: Boolean
13+
@ColumnInfo(name = "auto_update") val autoUpdate: Boolean,
14+
@ColumnInfo(name = "released_at") val releasedAt: Long? = null
1415
) : SourceManager.DatabaseEntity

app/src/main/java/app/revanced/manager/data/room/sources/Source.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,5 +34,6 @@ data class SourceProperties(
3434
@ColumnInfo(name = "name") val name: String,
3535
@ColumnInfo(name = "version") val versionHash: String? = null,
3636
@ColumnInfo(name = "source") val source: Source,
37-
@ColumnInfo(name = "auto_update") val autoUpdate: Boolean
37+
@ColumnInfo(name = "auto_update") val autoUpdate: Boolean,
38+
@ColumnInfo(name = "released_at") val releasedAt: Long? = null,
3839
)

app/src/main/java/app/revanced/manager/domain/manager/SourceManager.kt

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ import kotlinx.coroutines.awaitAll
2626
import kotlinx.coroutines.flow.map
2727
import kotlinx.coroutines.supervisorScope
2828
import kotlinx.coroutines.withContext
29+
import kotlinx.datetime.LocalDateTime
30+
import kotlinx.datetime.TimeZone
31+
import kotlinx.datetime.toInstant
2932
import org.koin.core.component.KoinComponent
3033
import org.koin.core.component.inject
3134
import java.io.File
@@ -114,7 +117,12 @@ abstract class SourceManager<DB : SourceManager.DatabaseEntity, LOADED, OUTPUT>(
114117
val newName = src.loaded?.let(::realNameOf).takeIf { it != src.name }
115118
?: return@syncName
116119

117-
updateDb(uid) { it.copy(name = newName) }
120+
updateDb(uid) {
121+
it.copy(
122+
name = newName,
123+
releasedAt = (src as? RemoteSource)?.releasedAt?.toEpochMillis()
124+
)
125+
}
118126
sources[uid] = src.copy(name = newName)
119127
}
120128

@@ -141,7 +149,7 @@ abstract class SourceManager<DB : SourceManager.DatabaseEntity, LOADED, OUTPUT>(
141149
private suspend fun createEntity(
142150
name: String,
143151
source: SourceInfo,
144-
autoUpdate: Boolean = false
152+
autoUpdate: Boolean = false,
145153
) =
146154
entityFromProps(
147155
uid = generateUid(),
@@ -150,6 +158,7 @@ abstract class SourceManager<DB : SourceManager.DatabaseEntity, LOADED, OUTPUT>(
150158
versionHash = null,
151159
source = source,
152160
autoUpdate = autoUpdate,
161+
releasedAt = null,
153162
)
154163
).also {
155164
dbUpsert(it)
@@ -172,6 +181,7 @@ abstract class SourceManager<DB : SourceManager.DatabaseEntity, LOADED, OUTPUT>(
172181
versionHash = new.versionHash,
173182
source = new.source,
174183
autoUpdate = new.autoUpdate,
184+
releasedAt = new.releasedAt,
175185
)
176186
)
177187
)
@@ -238,7 +248,7 @@ abstract class SourceManager<DB : SourceManager.DatabaseEntity, LOADED, OUTPUT>(
238248
this@SourceManager.store.state.value.sources.values.filterIsInstance<APISource<LOADED>>()
239249
.forEach { src ->
240250
with(src) { deleteLocalFile() }
241-
updateDb(src.uid) { it.copy(versionHash = null) }
251+
updateDb(src.uid) { it.copy(versionHash = null, releasedAt = null) }
242252
}
243253

244254
doReload(state)
@@ -308,15 +318,15 @@ abstract class SourceManager<DB : SourceManager.DatabaseEntity, LOADED, OUTPUT>(
308318
async update@{
309319
Log.d(tag, "Updating: ${it.name}")
310320

311-
val newVersion = it.runCatching {
321+
val updateResult = it.runCatching {
312322
when {
313323
redownload -> downloadLatest()
314-
checkOnly -> getUpdateInfo()?.version
324+
checkOnly -> getUpdateInfo()?.let { info -> RemoteSource.UpdateResult(info.version, info.createdAt) }
315325
else -> update()
316326
} ?: return@update null
317327
}
318328

319-
it to newVersion
329+
it to updateResult
320330
}
321331
}
322332
.awaitAll()
@@ -332,15 +342,19 @@ abstract class SourceManager<DB : SourceManager.DatabaseEntity, LOADED, OUTPUT>(
332342

333343
var hasErrors = false
334344
results.forEach { (src, result) ->
335-
result.getOrNull()?.let { newVersionHash ->
345+
result.getOrNull()?.let { updateResult ->
336346
if (checkOnly) {
337347
outdated.add(src.uid)
338348
return@let
339349
}
340350

341351
val name = src.loaded?.let(::realNameOf) ?: src.name
342352
updateDb(src.uid) {
343-
it.copy(versionHash = newVersionHash, name = name)
353+
it.copy(
354+
versionHash = updateResult.versionHash,
355+
name = name,
356+
releasedAt = updateResult.releasedAt.toEpochMillis()
357+
)
344358
}
345359
}
346360
result.exceptionOrNull()?.let {
@@ -378,4 +392,6 @@ abstract class SourceManager<DB : SourceManager.DatabaseEntity, LOADED, OUTPUT>(
378392
interface DatabaseEntity {
379393
val uid: Int
380394
}
381-
}
395+
}
396+
397+
private fun LocalDateTime.toEpochMillis() = toInstant(TimeZone.UTC).toEpochMilliseconds()

app/src/main/java/app/revanced/manager/domain/repository/DownloaderRepository.kt

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,11 @@ import app.revanced.manager.network.downloader.DownloaderPackage
3030
import app.revanced.manager.util.PM
3131
import dalvik.system.PathClassLoader
3232
import kotlinx.coroutines.flow.map
33+
import kotlinx.datetime.toLocalDateTime
3334
import java.io.File
3435
import java.lang.ref.WeakReference
3536
import java.lang.reflect.Modifier
37+
import kotlin.time.Instant
3638
import app.revanced.manager.data.room.sources.Source as SourceInfo
3739

3840
@OptIn(DownloaderHostApi::class)
@@ -61,14 +63,20 @@ class DownloaderRepository(
6163
override fun loadEntity(entity: DownloaderEntity): Source<DownloaderPackage> = with(entity) {
6264
val file = directoryOf(uid).resolve("downloader.jar")
6365
val actualName =
64-
entity.name.ifEmpty { app.getString(if (uid == 0) R.string.auto_updates_dialog_downloaders else R.string.source_name_fallback) }
66+
name.ifEmpty { app.getString(if (uid == 0) R.string.auto_updates_dialog_downloaders else R.string.source_name_fallback) }
67+
68+
val releasedAt = entity.releasedAt?.let {
69+
Instant.fromEpochMilliseconds(it)
70+
.toLocalDateTime(kotlinx.datetime.TimeZone.UTC)
71+
}
6572

6673
return when (source) {
6774
is SourceInfo.Local -> LocalSource(actualName, uid, null, file, loader)
6875
is SourceInfo.API -> APISource(
6976
actualName,
7077
uid,
7178
versionHash,
79+
releasedAt,
7280
null,
7381
file,
7482
SourceInfo.API.SENTINEL,
@@ -80,6 +88,7 @@ class DownloaderRepository(
8088
actualName,
8189
uid,
8290
versionHash,
91+
releasedAt,
8392
null,
8493
file,
8594
source.url.toString(),
@@ -97,7 +106,8 @@ class DownloaderRepository(
97106
name = props.name,
98107
versionHash = props.versionHash,
99108
source = props.source,
100-
autoUpdate = props.autoUpdate
109+
autoUpdate = props.autoUpdate,
110+
releasedAt = props.releasedAt
101111
)
102112

103113
override fun realNameOf(loaded: DownloaderPackage) = loaded.name

app/src/main/java/app/revanced/manager/domain/repository/PatchBundleRepository.kt

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import app.revanced.manager.domain.sources.LocalPatchBundle
1515
import app.revanced.manager.domain.sources.PatchBundleSource
1616
import app.revanced.manager.domain.manager.SourceManager
1717
import app.revanced.manager.domain.sources.Loader
18+
import app.revanced.manager.domain.sources.RemotePatchBundle
1819
import app.revanced.manager.domain.sources.Source
1920
import app.revanced.manager.patcher.patch.PatchInfo
2021
import app.revanced.manager.patcher.patch.PatchBundle
@@ -27,9 +28,13 @@ import kotlinx.coroutines.flow.first
2728
import kotlinx.coroutines.flow.map
2829
import kotlinx.coroutines.runInterruptible
2930
import kotlinx.coroutines.withContext
31+
import kotlinx.datetime.TimeZone
32+
import kotlinx.datetime.toInstant
33+
import kotlinx.datetime.toLocalDateTime
3034
import java.io.File
3135
import kotlin.collections.map
3236
import kotlin.text.ifEmpty
37+
import kotlin.time.Instant
3338

3439
private typealias Info = PersistentMap<Int, PatchBundleInfo.Global>
3540

@@ -58,12 +63,18 @@ class PatchBundleRepository(
5863
val actualName =
5964
entity.name.ifEmpty { app.getString(if (uid == 0) R.string.patches_name_default else R.string.source_name_fallback) }
6065

66+
val releasedAt = entity.releasedAt?.let {
67+
Instant.fromEpochMilliseconds(it)
68+
.toLocalDateTime(TimeZone.UTC)
69+
}
70+
6171
return when (source) {
6272
is SourceInfo.Local -> LocalPatchBundle(actualName, uid, null, file, PatchBundleLoader)
6373
is SourceInfo.API -> APIPatchBundle(
6474
actualName,
6575
uid,
6676
versionHash,
77+
releasedAt,
6778
null,
6879
file,
6980
SourceInfo.API.SENTINEL,
@@ -75,6 +86,7 @@ class PatchBundleRepository(
7586
actualName,
7687
uid,
7788
versionHash,
89+
releasedAt,
7890
null,
7991
file,
8092
source.url.toString(),
@@ -92,7 +104,8 @@ class PatchBundleRepository(
92104
name = props.name,
93105
versionHash = props.versionHash,
94106
source = props.source,
95-
autoUpdate = props.autoUpdate
107+
autoUpdate = props.autoUpdate,
108+
releasedAt = props.releasedAt
96109
)
97110

98111
override fun realNameOf(loaded: PatchBundle) = loaded.manifestAttributes?.name
@@ -173,6 +186,7 @@ class PatchBundleRepository(
173186
this[src.uid] = PatchBundleInfo.Global(
174187
src.name,
175188
bundle.manifestAttributes?.version,
189+
(src as? RemotePatchBundle)?.releasedAt,
176190
src.uid,
177191
result.getOrThrow().toList()
178192
)

0 commit comments

Comments
 (0)