Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -20,35 +20,43 @@ sealed class Source {
override fun toString() = url.toString()
}

data class GitHubPullRequest(val url: Url) : Source() {
override fun toString() = url.toString()
}

companion object {
fun from(value: String) = when (value) {
Local.SENTINEL -> Local
API.SENTINEL -> API
else -> Remote(Url(value))
else ->
if (value.matches(Regex("^https://github\\.com/([A-Za-z0-9_.-]+)/([A-Za-z0-9_.-]+)/pull/(\\d+)/?\$")))
GitHubPullRequest(Url(value))
else
Remote(Url(value))
}
}
}

@Entity(tableName = "patch_bundles")
data class PatchBundleEntity(
@PrimaryKey val uid: Int,
@ColumnInfo(name = "name") val name: String,
@ColumnInfo(name = "display_name") val displayName: String? = null,
@ColumnInfo(name = "version") val versionHash: String? = null,
@ColumnInfo(name = "source") val source: Source,
@ColumnInfo(name = "auto_update") val autoUpdate: Boolean,
@ColumnInfo(name = "sort_order") val sortOrder: Int,
@ColumnInfo(name = "created_at") val createdAt: Long? = null,
@ColumnInfo(name = "updated_at") val updatedAt: Long? = null
)

data class PatchBundleProperties(
@ColumnInfo(name = "name") val name: String,
@ColumnInfo(name = "display_name") val displayName: String? = null,
@ColumnInfo(name = "version") val versionHash: String? = null,
@ColumnInfo(name = "source") val source: Source,
@ColumnInfo(name = "auto_update") val autoUpdate: Boolean,
@ColumnInfo(name = "sort_order") val sortOrder: Int,
@ColumnInfo(name = "created_at") val createdAt: Long? = null,
@ColumnInfo(name = "updated_at") val updatedAt: Long? = null
)
@Entity(tableName = "patch_bundles")
data class PatchBundleEntity(
@PrimaryKey val uid: Int,
@ColumnInfo(name = "name") val name: String,
@ColumnInfo(name = "display_name") val displayName: String? = null,
@ColumnInfo(name = "version") val versionHash: String? = null,
@ColumnInfo(name = "source") val source: Source,
@ColumnInfo(name = "auto_update") val autoUpdate: Boolean,
@ColumnInfo(name = "sort_order") val sortOrder: Int,
@ColumnInfo(name = "created_at") val createdAt: Long? = null,
@ColumnInfo(name = "updated_at") val updatedAt: Long? = null
)
data class PatchBundleProperties(
@ColumnInfo(name = "name") val name: String,
@ColumnInfo(name = "display_name") val displayName: String? = null,
@ColumnInfo(name = "version") val versionHash: String? = null,
@ColumnInfo(name = "source") val source: Source,
@ColumnInfo(name = "auto_update") val autoUpdate: Boolean,
@ColumnInfo(name = "sort_order") val sortOrder: Int,
@ColumnInfo(name = "created_at") val createdAt: Long? = null,
@ColumnInfo(name = "updated_at") val updatedAt: Long? = null
)
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
package app.revanced.manager.domain.bundles
import androidx.compose.runtime.Stable
import app.revanced.manager.data.redux.ActionContext
import app.revanced.manager.patcher.patch.PatchBundle
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import java.io.File
import java.io.OutputStream
/**
* A [PatchBundle] source.
*/
@Stable
package app.revanced.manager.domain.bundles

import androidx.compose.runtime.Stable
import app.revanced.manager.data.redux.ActionContext
import app.revanced.manager.patcher.patch.PatchBundle
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import java.io.File
import java.io.OutputStream

/**
* A [PatchBundle] source.
*/
@Stable
sealed class PatchBundleSource(
val name: String,
val uid: Int,
Expand All @@ -21,53 +21,53 @@ sealed class PatchBundleSource(
error: Throwable?,
protected val directory: File
) {
protected val patchesFile = directory.resolve("patches.jar")
val state = when {
error != null -> State.Failed(error)
!hasInstalled() -> State.Missing
else -> State.Available(PatchBundle(patchesFile.absolutePath))
}
val patchBundle get() = (state as? State.Available)?.bundle
val version get() = patchBundle?.manifestAttributes?.version
val isNameOutOfDate get() = patchBundle?.manifestAttributes?.name?.let { it != name } == true
val error get() = (state as? State.Failed)?.throwable
val displayTitle get() = displayName?.takeUnless { it.isBlank() } ?: name
suspend fun ActionContext.deleteLocalFile() = withContext(Dispatchers.IO) {
patchesFile.delete()
}
protected val patchesFile = directory.resolve("patches.jar")

val state = when {
error != null -> State.Failed(error)
!hasInstalled() -> State.Missing
else -> State.Available(PatchBundle(patchesFile.absolutePath))
}

val patchBundle get() = (state as? State.Available)?.bundle
val version get() = patchBundle?.manifestAttributes?.version
val isNameOutOfDate get() = patchBundle?.manifestAttributes?.name?.let { it != name } == true
val error get() = (state as? State.Failed)?.throwable
val displayTitle get() = displayName?.takeUnless { it.isBlank() } ?: name

suspend fun ActionContext.deleteLocalFile() = withContext(Dispatchers.IO) {
patchesFile.delete()
}

abstract fun copy(
error: Throwable? = this.error,
name: String = this.name,
displayName: String? = this.displayName,
createdAt: Long? = this.createdAt,
updatedAt: Long? = this.updatedAt
): PatchBundleSource
protected fun hasInstalled() = patchesFile.exists()
protected fun patchBundleOutputStream(): OutputStream = with(patchesFile) {
// Android 14+ requires dex containers to be readonly.
try {
setWritable(true, true)
outputStream()
} finally {
setReadOnly()
}
}
sealed interface State {
data object Missing : State
data class Failed(val throwable: Throwable) : State
data class Available(val bundle: PatchBundle) : State
}
companion object Extensions {
val PatchBundleSource.isDefault inline get() = uid == 0
val PatchBundleSource.asRemoteOrNull inline get() = this as? RemotePatchBundle
val PatchBundleSource.actualName inline get() = name
}
}

protected fun hasInstalled() = patchesFile.exists()

protected fun patchBundleOutputStream(): OutputStream = with(patchesFile) {
// Android 14+ requires dex containers to be readonly.
try {
setWritable(true, true)
outputStream()
} finally {
setReadOnly()
}
}

sealed interface State {
data object Missing : State
data class Failed(val throwable: Throwable) : State
data class Available(val bundle: PatchBundle) : State
}

companion object Extensions {
val PatchBundleSource.isDefault inline get() = uid == 0
val PatchBundleSource.asRemoteOrNull inline get() = this as? RemotePatchBundle
val PatchBundleSource.actualName inline get() = name
}
}
Loading