diff --git a/app/build.gradle.kts b/app/build.gradle.kts index f36c4a00..dd1f59d6 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -60,7 +60,7 @@ dependencies { implementation(libs.revanced.library) // Downloader plugins - implementation(project(":api")) + implementation(projects.api) // Native processes implementation(libs.kotlin.process) diff --git a/app/src/main/java/app/revanced/manager/network/service/HttpService.kt b/app/src/main/java/app/revanced/manager/network/service/HttpService.kt index ea4cfb18..ae24913f 100644 --- a/app/src/main/java/app/revanced/manager/network/service/HttpService.kt +++ b/app/src/main/java/app/revanced/manager/network/service/HttpService.kt @@ -16,8 +16,12 @@ import io.ktor.http.isSuccess import io.ktor.utils.io.ByteReadChannel import io.ktor.utils.io.core.isNotEmpty import io.ktor.utils.io.core.readBytes +import io.ktor.utils.io.core.remaining +import io.ktor.utils.io.exhausted +import io.ktor.utils.io.readRemaining import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext +import kotlinx.io.asSink import kotlinx.serialization.json.Json import java.io.File import java.io.OutputStream @@ -69,14 +73,14 @@ class HttpService( ) { http.prepareGet(builder).execute { httpResponse -> if (httpResponse.status.isSuccess()) { + val stream = outputStream.asSink() val channel: ByteReadChannel = httpResponse.body() - withContext(Dispatchers.IO) { - while (!channel.isClosedForRead) { - val packet = channel.readRemaining(DEFAULT_BUFFER_SIZE.toLong()) - while (packet.isNotEmpty) { - val bytes = packet.readBytes() - outputStream.write(bytes) - } + var count = 0L + stream.use { + while (!channel.exhausted()) { + val chunk = channel.readRemaining() + count += chunk.remaining + chunk.transferTo(stream) } } diff --git a/app/src/main/java/app/revanced/manager/ui/component/Markdown.kt b/app/src/main/java/app/revanced/manager/ui/component/Markdown.kt index 2b5b276e..1fe78f9c 100644 --- a/app/src/main/java/app/revanced/manager/ui/component/Markdown.kt +++ b/app/src/main/java/app/revanced/manager/ui/component/Markdown.kt @@ -2,7 +2,9 @@ package app.revanced.manager.ui.component import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable +import androidx.compose.ui.text.TextLinkStyles import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextDecoration import com.mikepenz.markdown.compose.Markdown import com.mikepenz.markdown.m3.markdownColor import com.mikepenz.markdown.m3.markdownTypography @@ -18,15 +20,29 @@ fun Markdown( colors = markdownColor( text = MaterialTheme.colorScheme.onSurfaceVariant, codeBackground = MaterialTheme.colorScheme.secondaryContainer, - codeText = MaterialTheme.colorScheme.onSecondaryContainer, - linkText = MaterialTheme.colorScheme.primary ), typography = markdownTypography( h1 = MaterialTheme.typography.headlineSmall.copy(fontWeight = FontWeight.Bold), h2 = MaterialTheme.typography.titleLarge.copy(fontWeight = FontWeight.Bold), h3 = MaterialTheme.typography.titleMedium.copy(fontWeight = FontWeight.Bold), text = MaterialTheme.typography.bodyMedium, - list = MaterialTheme.typography.bodyMedium + code = markdownTypography().code.copy(color = MaterialTheme.colorScheme.onSecondaryContainer), + list = MaterialTheme.typography.bodyMedium, + textLink = TextLinkStyles( + style = MaterialTheme.typography.bodyMedium.copy( + fontWeight = FontWeight.Bold, textDecoration = TextDecoration.Underline, + color = MaterialTheme.colorScheme.primary + ).toSpanStyle(), + hoveredStyle = MaterialTheme.typography.bodyMedium.copy( + fontWeight = FontWeight.Bold, textDecoration = TextDecoration.Underline, + color = MaterialTheme.colorScheme.secondary + ).toSpanStyle(), + pressedStyle = MaterialTheme.typography.bodyMedium.copy( + fontWeight = FontWeight.Bold, textDecoration = TextDecoration.Underline, + color = MaterialTheme.colorScheme.tertiary + ).toSpanStyle() + + ), ) ) } \ No newline at end of file diff --git a/app/src/main/java/app/revanced/manager/ui/viewmodel/UpdateViewModel.kt b/app/src/main/java/app/revanced/manager/ui/viewmodel/UpdateViewModel.kt index db31d654..715b7314 100644 --- a/app/src/main/java/app/revanced/manager/ui/viewmodel/UpdateViewModel.kt +++ b/app/src/main/java/app/revanced/manager/ui/viewmodel/UpdateViewModel.kt @@ -87,7 +87,7 @@ class UpdateViewModel( url(release.downloadUrl) onDownload { bytesSentTotal, contentLength -> downloadedSize = bytesSentTotal - totalSize = contentLength + totalSize = contentLength ?: 0 } } installUpdate() diff --git a/app/src/main/java/app/revanced/manager/util/Util.kt b/app/src/main/java/app/revanced/manager/util/Util.kt index 5b2dfa33..2f56da2b 100644 --- a/app/src/main/java/app/revanced/manager/util/Util.kt +++ b/app/src/main/java/app/revanced/manager/util/Util.kt @@ -42,7 +42,6 @@ import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.launch -import kotlinx.datetime.Clock import kotlinx.datetime.LocalDateTime import kotlinx.datetime.TimeZone import kotlinx.datetime.format.MonthNames @@ -53,6 +52,7 @@ import java.util.Locale import kotlin.properties.PropertyDelegateProvider import kotlin.properties.ReadWriteProperty import kotlin.reflect.KProperty +import kotlin.time.ExperimentalTime typealias PatchSelection = Map> typealias Options = Map>> @@ -141,9 +141,10 @@ suspend fun Flow>.collectEach(block: suspend (T) -> Unit) { } } +@OptIn(ExperimentalTime::class) fun LocalDateTime.relativeTime(context: Context): String { try { - val now = Clock.System.now() + val now = kotlin.time.Clock.System.now() val duration = now - this.toInstant(TimeZone.UTC) return when { diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index ee684daf..831c9d17 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -11,22 +11,22 @@ work-runtime = "2.10.4" compose-bom = "2025.09.00" navigation = "2.9.4" accompanist = "0.37.3" -placeholder = "1.1.2" +placeholder = "2.0.0" reorderable = "2.5.1" serialization = "1.9.0" -collection = "0.3.8" -datetime = "0.6.1" +collection = "0.4.0" +datetime = "0.7.1" room-version = "2.8.0" revanced-patcher = "21.0.0" revanced-library = "3.0.2" -koin = "3.5.3" -ktor = "2.3.9" -markdown-renderer = "0.30.0" +koin = "4.1.1" +ktor = "3.3.0" +markdown-renderer = "0.37.0" fading-edges = "1.0.4" kotlin = "2.2.20" android-gradle-plugin = "8.13.0" dev-tools-gradle-plugin = "2.2.20-2.0.2" -about-libraries-gradle-plugin = "12.1.2" +about-libraries-gradle-plugin = "12.2.4" coil = "2.7.0" app-icon-loader-coil = "1.5.0" libsu = "6.0.0" @@ -34,8 +34,8 @@ scrollbars = "1.0.4" enumutil = "1.1.1" compose-icons = "1.2.4" kotlin-process = "1.5.1" -hidden-api-stub = "4.3.3" -binary-compatibility-validator = "0.17.0" +hidden-api-stub = "4.4.0" +binary-compatibility-validator = "0.18.1" [libraries] # AndroidX Core diff --git a/settings.gradle.kts b/settings.gradle.kts index 2392181c..ec05d355 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -22,5 +22,7 @@ dependencyResolutionManagement { } } +enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS") + rootProject.name = "revanced-manager" include(":app", ":api")