mirror of
https://github.com/ReVanced/revanced-manager.git
synced 2026-01-12 14:16:18 +00:00
Compare commits
5 Commits
v1.26.0-de
...
dev
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7615453eec | ||
|
|
4c0b6b02e9 | ||
|
|
fe84b22b6f | ||
|
|
1b21f5d4ab | ||
|
|
72b1db9a2f |
@@ -24,14 +24,6 @@ public final class app/revanced/manager/plugin/downloader/DownloadUrl : android/
|
||||
public final fun writeToParcel (Landroid/os/Parcel;I)V
|
||||
}
|
||||
|
||||
public final class app/revanced/manager/plugin/downloader/DownloadUrl$Creator : android/os/Parcelable$Creator {
|
||||
public fun <init> ()V
|
||||
public final fun createFromParcel (Landroid/os/Parcel;)Lapp/revanced/manager/plugin/downloader/DownloadUrl;
|
||||
public synthetic fun createFromParcel (Landroid/os/Parcel;)Ljava/lang/Object;
|
||||
public final fun newArray (I)[Lapp/revanced/manager/plugin/downloader/DownloadUrl;
|
||||
public synthetic fun newArray (I)[Ljava/lang/Object;
|
||||
}
|
||||
|
||||
public final class app/revanced/manager/plugin/downloader/Downloader {
|
||||
public static final field $stable I
|
||||
}
|
||||
@@ -85,14 +77,6 @@ public final class app/revanced/manager/plugin/downloader/Package : android/os/P
|
||||
public final fun writeToParcel (Landroid/os/Parcel;I)V
|
||||
}
|
||||
|
||||
public final class app/revanced/manager/plugin/downloader/Package$Creator : android/os/Parcelable$Creator {
|
||||
public fun <init> ()V
|
||||
public final fun createFromParcel (Landroid/os/Parcel;)Lapp/revanced/manager/plugin/downloader/Package;
|
||||
public synthetic fun createFromParcel (Landroid/os/Parcel;)Ljava/lang/Object;
|
||||
public final fun newArray (I)[Lapp/revanced/manager/plugin/downloader/Package;
|
||||
public synthetic fun newArray (I)[Ljava/lang/Object;
|
||||
}
|
||||
|
||||
public abstract interface annotation class app/revanced/manager/plugin/downloader/PluginHostApi : java/lang/annotation/Annotation {
|
||||
}
|
||||
|
||||
@@ -159,14 +143,6 @@ public abstract class app/revanced/manager/plugin/downloader/webview/IWebViewEve
|
||||
public fun onTransact (ILandroid/os/Parcel;Landroid/os/Parcel;I)Z
|
||||
}
|
||||
|
||||
public final class app/revanced/manager/plugin/downloader/webview/WebViewActivity$Parameters$Creator : android/os/Parcelable$Creator {
|
||||
public fun <init> ()V
|
||||
public final fun createFromParcel (Landroid/os/Parcel;)Lapp/revanced/manager/plugin/downloader/webview/WebViewActivity$Parameters;
|
||||
public synthetic fun createFromParcel (Landroid/os/Parcel;)Ljava/lang/Object;
|
||||
public final fun newArray (I)[Lapp/revanced/manager/plugin/downloader/webview/WebViewActivity$Parameters;
|
||||
public synthetic fun newArray (I)[Ljava/lang/Object;
|
||||
}
|
||||
|
||||
public abstract interface class app/revanced/manager/plugin/downloader/webview/WebViewCallbackScope : app/revanced/manager/plugin/downloader/Scope {
|
||||
public abstract fun finish (Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
||||
public abstract fun load (Ljava/lang/String;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
||||
|
||||
plugins {
|
||||
alias(libs.plugins.android.library)
|
||||
alias(libs.plugins.kotlin.android)
|
||||
@@ -17,9 +19,16 @@ dependencies {
|
||||
implementation(libs.appcompat)
|
||||
}
|
||||
|
||||
kotlin {
|
||||
jvmToolchain(17)
|
||||
compilerOptions {
|
||||
jvmTarget = JvmTarget.JVM_17
|
||||
}
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "app.revanced.manager.plugin.downloader"
|
||||
compileSdk = 35
|
||||
compileSdk = 36
|
||||
|
||||
defaultConfig {
|
||||
minSdk = 26
|
||||
@@ -42,10 +51,6 @@ android {
|
||||
targetCompatibility = JavaVersion.VERSION_17
|
||||
}
|
||||
|
||||
kotlinOptions {
|
||||
jvmTarget = "17"
|
||||
}
|
||||
|
||||
buildFeatures {
|
||||
aidl = true
|
||||
}
|
||||
|
||||
@@ -1,3 +1,17 @@
|
||||
# app [1.26.0-dev.20](https://github.com/ReVanced/revanced-manager/compare/v1.26.0-dev.19...v1.26.0-dev.20) (2026-01-09)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Save FAB freaking out in select patches screen ([4c0b6b0](https://github.com/ReVanced/revanced-manager/commit/4c0b6b02e95a8d6f655bcf5c25493b1f9a4a4dcd))
|
||||
|
||||
# app [1.26.0-dev.19](https://github.com/ReVanced/revanced-manager/compare/v1.26.0-dev.18...v1.26.0-dev.19) (2026-01-08)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **locales:** use buildconfig instead of generating kt file ([72b1db9](https://github.com/ReVanced/revanced-manager/commit/72b1db9a2f33ab5d5fffd8ba83c05901eff19bea))
|
||||
|
||||
# app [1.26.0-dev.18](https://github.com/ReVanced/revanced-manager/compare/v1.26.0-dev.17...v1.26.0-dev.18) (2026-01-08)
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
import com.mikepenz.aboutlibraries.plugin.DuplicateMode
|
||||
import com.mikepenz.aboutlibraries.plugin.DuplicateRule
|
||||
import io.github.z4kn4fein.semver.toVersion
|
||||
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
||||
import kotlin.random.Random
|
||||
|
||||
plugins {
|
||||
@@ -9,6 +12,7 @@ plugins {
|
||||
alias(libs.plugins.compose.compiler)
|
||||
alias(libs.plugins.devtools)
|
||||
alias(libs.plugins.about.libraries)
|
||||
alias(libs.plugins.about.libraries.android)
|
||||
signing
|
||||
}
|
||||
|
||||
@@ -81,7 +85,8 @@ dependencies {
|
||||
implementation(libs.koin.workmanager)
|
||||
|
||||
// Licenses
|
||||
implementation(libs.about.libraries)
|
||||
implementation(libs.about.libraries.core)
|
||||
implementation(libs.about.libraries.m3)
|
||||
|
||||
// Ktor
|
||||
implementation(libs.ktor.core)
|
||||
@@ -126,7 +131,7 @@ buildscript {
|
||||
|
||||
android {
|
||||
namespace = "app.revanced.manager"
|
||||
compileSdk = 35
|
||||
compileSdk = 36
|
||||
buildToolsVersion = "35.0.1"
|
||||
|
||||
defaultConfig {
|
||||
@@ -143,6 +148,19 @@ android {
|
||||
(preRelease?.substringAfterLast('.')?.toInt() ?: 99)
|
||||
}
|
||||
vectorDrawables.useSupportLibrary = true
|
||||
|
||||
val resDir = file("src/main/res")
|
||||
val locales = resDir.listFiles()
|
||||
.orEmpty()
|
||||
//noinspection WrongGradleMethod
|
||||
.filter { it.isDirectory && it.name.matches(Regex("values-[a-z]{2}(-r[A-Z]{2})?")) }
|
||||
//noinspection WrongGradleMethod
|
||||
.map { it.name.removePrefix("values-").replace("-r", "-") }
|
||||
.sorted()
|
||||
//noinspection WrongGradleMethod
|
||||
.joinToString(prefix = "{", separator = ",", postfix = "}") { "\"$it\"" }
|
||||
|
||||
buildConfigField("String[]", "SUPPORTED_LOCALES", locales)
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
@@ -220,20 +238,14 @@ android {
|
||||
arg("room.schemaLocation", "$projectDir/schemas")
|
||||
}
|
||||
|
||||
kotlinOptions {
|
||||
jvmTarget = "17"
|
||||
}
|
||||
|
||||
buildFeatures {
|
||||
compose = true
|
||||
aidl = true
|
||||
buildConfig = true
|
||||
}
|
||||
|
||||
android {
|
||||
androidResources {
|
||||
generateLocaleConfig = true
|
||||
}
|
||||
androidResources {
|
||||
generateLocaleConfig = true
|
||||
}
|
||||
|
||||
externalNativeBuild {
|
||||
@@ -242,55 +254,25 @@ android {
|
||||
version = "3.22.1"
|
||||
}
|
||||
}
|
||||
|
||||
sourceSets["main"].kotlin.srcDir(layout.buildDirectory.dir("generated/source/locales"))
|
||||
}
|
||||
|
||||
kotlin {
|
||||
jvmToolchain(17)
|
||||
compilerOptions {
|
||||
jvmTarget = JvmTarget.JVM_17
|
||||
}
|
||||
}
|
||||
|
||||
aboutLibraries {
|
||||
library {
|
||||
// Enable the duplication mode, allows to merge, or link dependencies which relate
|
||||
duplicationMode = DuplicateMode.MERGE
|
||||
// Configure the duplication rule, to match "duplicates" with
|
||||
duplicationRule = DuplicateRule.EXACT
|
||||
}
|
||||
}
|
||||
|
||||
tasks {
|
||||
val generateSupportedLocales by registering {
|
||||
description = "Generate list of supported locales from resource directories"
|
||||
|
||||
val resDir = file("src/main/res")
|
||||
val outputDir = layout.buildDirectory.dir("generated/source/locales")
|
||||
|
||||
inputs.dir(resDir)
|
||||
outputs.dir(outputDir)
|
||||
|
||||
doLast {
|
||||
val locales = resDir.listFiles()
|
||||
.orEmpty()
|
||||
.filter { it.isDirectory && it.name.matches(Regex("values-[a-z]{2}(-r[A-Z]{2})?")) }
|
||||
.map { it.name.removePrefix("values-").replace("-r", "-") }
|
||||
.sorted()
|
||||
.joinToString("\n ") { "Locale.forLanguageTag(\"$it\")," }
|
||||
|
||||
val output = outputDir.get().asFile.resolve("app/revanced/manager/util/GeneratedLocales.kt")
|
||||
output.parentFile.mkdirs()
|
||||
output.writeText(
|
||||
"""
|
||||
|package app.revanced.manager.util
|
||||
|
|
||||
|import java.util.Locale
|
||||
|
|
||||
|object GeneratedLocales {
|
||||
| val SUPPORTED_LOCALES = listOf(
|
||||
| Locale.ENGLISH,$locales
|
||||
| )
|
||||
|}
|
||||
""".trimMargin()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
preBuild {
|
||||
dependsOn(generateSupportedLocales)
|
||||
}
|
||||
|
||||
|
||||
// Needed by gradle-semantic-release-plugin.
|
||||
// Tracking: https://github.com/KengoTODA/gradle-semantic-release-plugin/issues/435.
|
||||
val publish by registering {
|
||||
|
||||
@@ -1 +1 @@
|
||||
version = 1.26.0-dev.18
|
||||
version = 1.26.0-dev.20
|
||||
|
||||
@@ -59,7 +59,6 @@ import app.revanced.manager.ui.viewmodel.SelectedAppInfoViewModel
|
||||
import app.revanced.manager.util.EventEffect
|
||||
import kotlinx.coroutines.launch
|
||||
import org.koin.androidx.compose.koinViewModel
|
||||
import org.koin.androidx.compose.navigation.koinNavViewModel
|
||||
import org.koin.core.parameter.parametersOf
|
||||
import org.koin.androidx.viewmodel.ext.android.getViewModel as getActivityViewModel
|
||||
|
||||
@@ -185,7 +184,7 @@ private fun ReVancedManager(vm: MainViewModel) {
|
||||
val data =
|
||||
parentBackStackEntry.getComplexArg<SelectedApplicationInfo.ViewModelParams>()
|
||||
val viewModel =
|
||||
koinNavViewModel<SelectedAppInfoViewModel>(viewModelStoreOwner = parentBackStackEntry) {
|
||||
koinViewModel<SelectedAppInfoViewModel>(viewModelStoreOwner = parentBackStackEntry) {
|
||||
parametersOf(data)
|
||||
}
|
||||
|
||||
@@ -226,7 +225,7 @@ private fun ReVancedManager(vm: MainViewModel) {
|
||||
composable<SelectedApplicationInfo.PatchesSelector> {
|
||||
val data =
|
||||
it.getComplexArg<SelectedApplicationInfo.PatchesSelector.ViewModelParams>()
|
||||
val selectedAppInfoVm = koinNavViewModel<SelectedAppInfoViewModel>(
|
||||
val selectedAppInfoVm = koinViewModel<SelectedAppInfoViewModel>(
|
||||
viewModelStoreOwner = navController.navGraphEntry(it)
|
||||
)
|
||||
|
||||
@@ -243,7 +242,7 @@ private fun ReVancedManager(vm: MainViewModel) {
|
||||
composable<SelectedApplicationInfo.RequiredOptions> {
|
||||
val data =
|
||||
it.getComplexArg<SelectedApplicationInfo.PatchesSelector.ViewModelParams>()
|
||||
val selectedAppInfoVm = koinNavViewModel<SelectedAppInfoViewModel>(
|
||||
val selectedAppInfoVm = koinViewModel<SelectedAppInfoViewModel>(
|
||||
viewModelStoreOwner = navController.navGraphEntry(it)
|
||||
)
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package app.revanced.manager.di
|
||||
|
||||
import app.revanced.manager.ui.viewmodel.*
|
||||
import org.koin.androidx.viewmodel.dsl.viewModelOf
|
||||
import org.koin.core.module.dsl.*
|
||||
import org.koin.dsl.module
|
||||
|
||||
val viewModelModule = module {
|
||||
|
||||
@@ -16,8 +16,11 @@ 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.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 +72,12 @@ class HttpService(
|
||||
) {
|
||||
http.prepareGet(builder).execute { httpResponse ->
|
||||
if (httpResponse.status.isSuccess()) {
|
||||
val channel: ByteReadChannel = httpResponse.body()
|
||||
withContext(Dispatchers.IO) {
|
||||
while (!channel.isClosedForRead) {
|
||||
val channel: ByteReadChannel = httpResponse.body()
|
||||
val sink = outputStream.asSink()
|
||||
while (!channel.exhausted()) {
|
||||
val packet = channel.readRemaining(DEFAULT_BUFFER_SIZE.toLong())
|
||||
while (packet.isNotEmpty) {
|
||||
val bytes = packet.readBytes()
|
||||
outputStream.write(bytes)
|
||||
}
|
||||
packet.transferTo(sink)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.ColorFilter
|
||||
import androidx.compose.ui.graphics.vector.rememberVectorPainter
|
||||
import coil.compose.AsyncImage
|
||||
import io.github.fornewid.placeholder.material3.placeholder
|
||||
import com.eygraber.compose.placeholder.material3.placeholder
|
||||
|
||||
@Composable
|
||||
fun AppIcon(
|
||||
|
||||
@@ -16,7 +16,7 @@ import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import app.revanced.manager.R
|
||||
import io.github.fornewid.placeholder.material3.placeholder
|
||||
import com.eygraber.compose.placeholder.material3.placeholder
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ fun LoadingIndicator(
|
||||
progress: () -> Float? = { null },
|
||||
color: Color = ProgressIndicatorDefaults.circularColor,
|
||||
strokeWidth: Dp = ProgressIndicatorDefaults.CircularStrokeWidth,
|
||||
trackColor: Color = ProgressIndicatorDefaults.circularTrackColor,
|
||||
trackColor: Color = ProgressIndicatorDefaults.circularIndeterminateTrackColor,
|
||||
strokeCap: StrokeCap = ProgressIndicatorDefaults.CircularDeterminateStrokeCap
|
||||
) {
|
||||
progress()?.let {
|
||||
|
||||
@@ -18,8 +18,6 @@ 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),
|
||||
|
||||
@@ -29,7 +29,8 @@ fun SearchBar(
|
||||
) {
|
||||
val colors = SearchBarColors(
|
||||
containerColor = MaterialTheme.colorScheme.surfaceContainerHigh,
|
||||
dividerColor = MaterialTheme.colorScheme.outline
|
||||
dividerColor = MaterialTheme.colorScheme.outline,
|
||||
inputFieldColors = SearchBarDefaults.inputFieldColors()
|
||||
)
|
||||
val keyboardController = LocalSoftwareKeyboardController.current
|
||||
|
||||
|
||||
@@ -31,7 +31,8 @@ fun SearchView(
|
||||
) {
|
||||
val colors = SearchBarColors(
|
||||
containerColor = MaterialTheme.colorScheme.surfaceContainerHigh,
|
||||
dividerColor = MaterialTheme.colorScheme.outline
|
||||
dividerColor = MaterialTheme.colorScheme.outline,
|
||||
inputFieldColors = SearchBarDefaults.inputFieldColors()
|
||||
)
|
||||
val focusRequester = remember { FocusRequester() }
|
||||
val keyboardController = LocalSoftwareKeyboardController.current
|
||||
|
||||
@@ -6,7 +6,7 @@ import app.revanced.manager.R
|
||||
import app.revanced.manager.patcher.StepId
|
||||
import kotlinx.parcelize.Parcelize
|
||||
|
||||
enum class StepCategory(@StringRes val displayName: Int) {
|
||||
enum class StepCategory(@param:StringRes val displayName: Int) {
|
||||
PREPARING(R.string.patcher_step_group_preparing),
|
||||
PATCHING(R.string.patcher_step_group_patching),
|
||||
SAVING(R.string.patcher_step_group_saving)
|
||||
|
||||
@@ -36,7 +36,7 @@ import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.TabRow
|
||||
import androidx.compose.material3.SecondaryTabRow
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.material3.surfaceColorAtElevation
|
||||
@@ -53,6 +53,7 @@ import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalResources
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
@@ -100,6 +101,7 @@ fun DashboardScreen(
|
||||
false
|
||||
)
|
||||
val androidContext = LocalContext.current
|
||||
val resources = LocalResources.current
|
||||
val composableScope = rememberCoroutineScope()
|
||||
val pagerState = rememberPagerState(
|
||||
initialPage = DashboardPage.DASHBOARD.ordinal,
|
||||
@@ -234,7 +236,7 @@ fun DashboardScreen(
|
||||
when (pagerState.currentPage) {
|
||||
DashboardPage.DASHBOARD.ordinal -> {
|
||||
if (availablePatches < 1) {
|
||||
androidContext.toast(androidContext.getString(R.string.no_patch_found))
|
||||
androidContext.toast(resources.getString(R.string.no_patch_found))
|
||||
composableScope.launch {
|
||||
pagerState.animateScrollToPage(
|
||||
DashboardPage.BUNDLES.ordinal
|
||||
@@ -259,7 +261,7 @@ fun DashboardScreen(
|
||||
}
|
||||
) { paddingValues ->
|
||||
Column(Modifier.padding(paddingValues)) {
|
||||
TabRow(
|
||||
SecondaryTabRow(
|
||||
selectedTabIndex = pagerState.currentPage,
|
||||
containerColor = MaterialTheme.colorScheme.surfaceColorAtElevation(3.0.dp)
|
||||
) {
|
||||
|
||||
@@ -40,6 +40,7 @@ import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalResources
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import app.revanced.manager.R
|
||||
@@ -69,6 +70,7 @@ fun PatcherScreen(
|
||||
}
|
||||
|
||||
val context = LocalContext.current
|
||||
val resources = LocalResources.current
|
||||
val exportApkLauncher =
|
||||
rememberLauncherForActivityResult(CreateDocument(APK_MIMETYPE), viewModel::export)
|
||||
|
||||
@@ -79,7 +81,7 @@ fun PatcherScreen(
|
||||
|
||||
fun onPageBack() = when {
|
||||
patcherSucceeded == null -> showDismissConfirmationDialog = true
|
||||
viewModel.isInstalling -> context.toast(context.getString(R.string.patcher_install_in_progress))
|
||||
viewModel.isInstalling -> context.toast(resources.getString(R.string.patcher_install_in_progress))
|
||||
else -> onLeave()
|
||||
}
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ import androidx.compose.material3.ListItem
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.ModalBottomSheet
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.ScrollableTabRow
|
||||
import androidx.compose.material3.SecondaryScrollableTabRow
|
||||
import androidx.compose.material3.SmallFloatingActionButton
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
@@ -49,10 +49,12 @@ import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.derivedStateOf
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.produceState
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.runtime.snapshotFlow
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.alpha
|
||||
@@ -81,9 +83,11 @@ import app.revanced.manager.util.Options
|
||||
import app.revanced.manager.util.PatchSelection
|
||||
import app.revanced.manager.util.isScrollingUp
|
||||
import app.revanced.manager.util.transparentListItemColors
|
||||
import kotlinx.coroutines.FlowPreview
|
||||
import kotlinx.coroutines.flow.sample
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class, ExperimentalLayoutApi::class)
|
||||
@OptIn(ExperimentalMaterial3Api::class, ExperimentalLayoutApi::class, FlowPreview::class)
|
||||
@Composable
|
||||
fun PatchesSelectorScreen(
|
||||
onSave: (PatchSelection?, Options) -> Unit,
|
||||
@@ -231,7 +235,8 @@ fun PatchesSelectorScreen(
|
||||
viewModel.selectionWarningEnabled -> showSelectionWarning = true
|
||||
|
||||
// Show universal warning if universal patch is selected and the toggle is off
|
||||
patch.compatiblePackages == null && viewModel.universalPatchWarningEnabled -> showUniversalWarning = true
|
||||
patch.compatiblePackages == null && viewModel.universalPatchWarningEnabled -> showUniversalWarning =
|
||||
true
|
||||
|
||||
// Toggle the patch otherwise
|
||||
else -> viewModel.togglePatch(uid, patch)
|
||||
@@ -360,6 +365,21 @@ fun PatchesSelectorScreen(
|
||||
) {
|
||||
Icon(Icons.Outlined.Restore, stringResource(R.string.reset))
|
||||
}
|
||||
|
||||
val isScrollingUp =
|
||||
patchLazyListStates.getOrNull(pagerState.currentPage)?.isScrollingUp()
|
||||
val expanded by produceState(true, isScrollingUp) {
|
||||
val state = isScrollingUp ?: return@produceState
|
||||
value = state.value
|
||||
|
||||
// Use snapshotFlow and sample to prevent the value from changing too often.
|
||||
snapshotFlow { state.value }
|
||||
.sample(333L)
|
||||
.collect {
|
||||
value = it
|
||||
}
|
||||
}
|
||||
|
||||
HapticExtendedFloatingActionButton(
|
||||
text = {
|
||||
Text(
|
||||
@@ -375,8 +395,7 @@ fun PatchesSelectorScreen(
|
||||
contentDescription = stringResource(R.string.save)
|
||||
)
|
||||
},
|
||||
expanded = patchLazyListStates.getOrNull(pagerState.currentPage)?.isScrollingUp
|
||||
?: true,
|
||||
expanded = expanded,
|
||||
onClick = {
|
||||
onSave(viewModel.getCustomSelection(), viewModel.getOptions())
|
||||
}
|
||||
@@ -392,7 +411,7 @@ fun PatchesSelectorScreen(
|
||||
.padding(top = 16.dp)
|
||||
) {
|
||||
if (bundles.size > 1) {
|
||||
ScrollableTabRow(
|
||||
SecondaryScrollableTabRow(
|
||||
selectedTabIndex = pagerState.currentPage,
|
||||
containerColor = MaterialTheme.colorScheme.surfaceColorAtElevation(3.0.dp)
|
||||
) {
|
||||
|
||||
@@ -13,7 +13,7 @@ import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.ScrollableTabRow
|
||||
import androidx.compose.material3.SecondaryScrollableTabRow
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TopAppBarDefaults
|
||||
import androidx.compose.material3.rememberTopAppBarState
|
||||
@@ -106,7 +106,7 @@ fun RequiredOptionsScreen(
|
||||
.padding(paddingValues)
|
||||
) {
|
||||
if (list.isEmpty()) return@Column
|
||||
else if (list.size > 1) ScrollableTabRow(
|
||||
else if (list.size > 1) SecondaryScrollableTabRow(
|
||||
selectedTabIndex = pagerState.currentPage,
|
||||
containerColor = MaterialTheme.colorScheme.surfaceColorAtElevation(3.0.dp)
|
||||
) {
|
||||
|
||||
@@ -32,6 +32,7 @@ import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalResources
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
@@ -68,6 +69,7 @@ fun SelectedAppInfoScreen(
|
||||
vm: SelectedAppInfoViewModel
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
val resources = LocalResources.current
|
||||
val networkInfo = koinInject<NetworkInfo>()
|
||||
val networkConnected = remember { networkInfo.isConnected() }
|
||||
val networkMetered = remember { !networkInfo.isUnmetered() }
|
||||
@@ -118,7 +120,7 @@ fun SelectedAppInfoScreen(
|
||||
},
|
||||
onClick = patchClick@{
|
||||
if (selectedPatchCount == 0) {
|
||||
context.toast(context.getString(R.string.no_patches_selected))
|
||||
context.toast(resources.getString(R.string.no_patches_selected))
|
||||
|
||||
return@patchClick
|
||||
}
|
||||
|
||||
@@ -22,8 +22,8 @@ import app.revanced.manager.ui.model.navigation.Settings
|
||||
import org.koin.compose.koinInject
|
||||
|
||||
private data class Section(
|
||||
@StringRes val name: Int,
|
||||
@StringRes val description: Int,
|
||||
@param:StringRes val name: Int,
|
||||
@param:StringRes val description: Int,
|
||||
val image: ImageVector,
|
||||
val destination: Settings.Destination,
|
||||
)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package app.revanced.manager.ui.screen.settings
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import androidx.appcompat.content.res.AppCompatResources
|
||||
import androidx.compose.foundation.BorderStroke
|
||||
import androidx.compose.foundation.Image
|
||||
@@ -40,6 +41,7 @@ import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalResources
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.semantics.hideFromAccessibility
|
||||
import androidx.compose.ui.semantics.semantics
|
||||
@@ -67,8 +69,9 @@ fun AboutSettingsScreen(
|
||||
viewModel: AboutViewModel = koinViewModel()
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
val resources = LocalResources.current
|
||||
// painterResource() is broken on release builds for some reason.
|
||||
val icon = rememberDrawablePainter(drawable = remember {
|
||||
val icon = rememberDrawablePainter(drawable = remember(resources) {
|
||||
AppCompatResources.getDrawable(context, R.drawable.ic_logo_ring)
|
||||
})
|
||||
|
||||
@@ -76,7 +79,7 @@ fun AboutSettingsScreen(
|
||||
viewModel.socials.partition(ReVancedSocial::preferred)
|
||||
}
|
||||
|
||||
val preferredSocialButtons = remember(preferredSocials, viewModel.donate, viewModel.contact) {
|
||||
val preferredSocialButtons = remember(resources, preferredSocials, viewModel.donate, viewModel.contact) {
|
||||
preferredSocials.map {
|
||||
Triple(
|
||||
getSocialIcon(it.name),
|
||||
@@ -89,7 +92,7 @@ fun AboutSettingsScreen(
|
||||
viewModel.donate?.let {
|
||||
Triple(
|
||||
Icons.Outlined.FavoriteBorder,
|
||||
context.getString(R.string.donate),
|
||||
resources.getString(R.string.donate),
|
||||
third = {
|
||||
context.openUrl(it)
|
||||
}
|
||||
@@ -98,7 +101,7 @@ fun AboutSettingsScreen(
|
||||
viewModel.contact?.let {
|
||||
Triple(
|
||||
Icons.Outlined.MailOutline,
|
||||
context.getString(R.string.contact),
|
||||
resources.getString(R.string.contact),
|
||||
third = {
|
||||
context.openUrl("mailto:$it")
|
||||
}
|
||||
@@ -131,7 +134,7 @@ fun AboutSettingsScreen(
|
||||
stringResource(R.string.contributors_description),
|
||||
third = nav@{
|
||||
if (!viewModel.isConnected) {
|
||||
context.toast(context.getString(R.string.no_network_toast))
|
||||
context.toast(resources.getString(R.string.no_network_toast))
|
||||
return@nav
|
||||
}
|
||||
|
||||
@@ -153,7 +156,7 @@ fun AboutSettingsScreen(
|
||||
LaunchedEffect(developerTaps) {
|
||||
if (developerTaps == 0) return@LaunchedEffect
|
||||
if (showDeveloperSettings) {
|
||||
snackbarHostState.showSnackbar(context.getString(R.string.developer_options_already_enabled))
|
||||
snackbarHostState.showSnackbar(resources.getString(R.string.developer_options_already_enabled))
|
||||
developerTaps = 0
|
||||
return@LaunchedEffect
|
||||
}
|
||||
@@ -161,7 +164,7 @@ fun AboutSettingsScreen(
|
||||
val remaining = DEVELOPER_OPTIONS_TAPS - developerTaps
|
||||
if (remaining > 0) {
|
||||
snackbarHostState.showSnackbar(
|
||||
context.getString(
|
||||
resources.getString(
|
||||
R.string.developer_options_taps,
|
||||
remaining
|
||||
),
|
||||
@@ -169,7 +172,7 @@ fun AboutSettingsScreen(
|
||||
)
|
||||
} else if (remaining == 0) {
|
||||
viewModel.showDeveloperSettings.update(true)
|
||||
snackbarHostState.showSnackbar(context.getString(R.string.developer_options_enabled))
|
||||
snackbarHostState.showSnackbar(resources.getString(R.string.developer_options_enabled))
|
||||
}
|
||||
|
||||
// Reset the counter
|
||||
|
||||
@@ -38,6 +38,7 @@ import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalResources
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
@@ -64,9 +65,10 @@ fun AdvancedSettingsScreen(
|
||||
viewModel: AdvancedSettingsViewModel = koinViewModel()
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
val memoryLimit = remember {
|
||||
val resources = LocalResources.current
|
||||
val memoryLimit = remember(resources) {
|
||||
val activityManager = context.getSystemService<ActivityManager>()!!
|
||||
context.getString(
|
||||
resources.getString(
|
||||
R.string.device_memory_limit_format,
|
||||
activityManager.memoryClass,
|
||||
activityManager.largeMemoryClass
|
||||
@@ -183,7 +185,7 @@ fun AdvancedSettingsScreen(
|
||||
ClipData.newPlainText("Device Information", deviceContent)
|
||||
)
|
||||
|
||||
context.toast(context.getString(R.string.toast_copied_to_clipboard))
|
||||
context.toast(resources.getString(R.string.toast_copied_to_clipboard))
|
||||
}.withHapticFeedback(HapticFeedbackConstants.LONG_PRESS)
|
||||
),
|
||||
headlineContent = stringResource(R.string.about_device),
|
||||
|
||||
@@ -36,6 +36,7 @@ import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalResources
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
@@ -64,6 +65,7 @@ fun ImportExportSettingsScreen(
|
||||
vm: ImportExportViewModel = koinViewModel()
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
val resources = LocalResources.current
|
||||
val coroutineScope = rememberCoroutineScope()
|
||||
var selectorDialog by rememberSaveable { mutableStateOf<(@Composable () -> Unit)?>(null) }
|
||||
|
||||
@@ -108,7 +110,7 @@ fun ImportExportSettingsScreen(
|
||||
vm.viewModelScope.launch {
|
||||
uiSafe(context, R.string.failed_to_import_keystore, "Failed to import keystore") {
|
||||
val result = vm.tryKeystoreImport(alias, pass)
|
||||
if (!result) context.toast(context.getString(R.string.import_keystore_wrong_credentials))
|
||||
if (!result) context.toast(resources.getString(R.string.import_keystore_wrong_credentials))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -166,7 +168,7 @@ fun ImportExportSettingsScreen(
|
||||
GroupItem(
|
||||
onClick = {
|
||||
if (!vm.canExport()) {
|
||||
context.toast(context.getString(R.string.export_keystore_unavailable))
|
||||
context.toast(resources.getString(R.string.export_keystore_unavailable))
|
||||
return@GroupItem
|
||||
}
|
||||
exportKeystoreLauncher.launch("Manager.keystore")
|
||||
|
||||
@@ -7,15 +7,18 @@ import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import app.revanced.manager.R
|
||||
import app.revanced.manager.ui.component.AppScaffold
|
||||
import app.revanced.manager.ui.component.AppTopBar
|
||||
import app.revanced.manager.ui.component.Scrollbar
|
||||
import com.mikepenz.aboutlibraries.ui.compose.LibrariesContainer
|
||||
import com.mikepenz.aboutlibraries.ui.compose.LibraryDefaults
|
||||
import com.mikepenz.aboutlibraries.ui.compose.libraryColors
|
||||
import com.mikepenz.aboutlibraries.ui.compose.android.produceLibraries
|
||||
import com.mikepenz.aboutlibraries.ui.compose.m3.LibrariesContainer
|
||||
import com.mikepenz.aboutlibraries.ui.compose.m3.chipColors
|
||||
import com.mikepenz.aboutlibraries.ui.compose.m3.libraryColors
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
@@ -33,16 +36,23 @@ fun LicensesSettingsScreen(
|
||||
) { paddingValues ->
|
||||
Column(modifier = Modifier.padding(paddingValues)) {
|
||||
val lazyListState = rememberLazyListState()
|
||||
val libraries by produceLibraries(R.raw.aboutlibraries)
|
||||
val chipColors = LibraryDefaults.chipColors(
|
||||
containerColor = MaterialTheme.colorScheme.primary,
|
||||
contentColor = MaterialTheme.colorScheme.onPrimary,
|
||||
)
|
||||
|
||||
LibrariesContainer(
|
||||
modifier = Modifier
|
||||
.fillMaxSize(),
|
||||
libraries = libraries,
|
||||
lazyListState = lazyListState,
|
||||
colors = LibraryDefaults.libraryColors(
|
||||
backgroundColor = MaterialTheme.colorScheme.background,
|
||||
contentColor = MaterialTheme.colorScheme.onBackground,
|
||||
badgeBackgroundColor = MaterialTheme.colorScheme.primary,
|
||||
badgeContentColor = MaterialTheme.colorScheme.onPrimary,
|
||||
libraryBackgroundColor = MaterialTheme.colorScheme.background,
|
||||
libraryContentColor = MaterialTheme.colorScheme.onBackground,
|
||||
versionChipColors = chipColors,
|
||||
licenseChipColors = chipColors,
|
||||
fundingChipColors = chipColors,
|
||||
)
|
||||
)
|
||||
Scrollbar(lazyListState = lazyListState, modifier = Modifier.padding(paddingValues))
|
||||
|
||||
@@ -12,6 +12,7 @@ import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalResources
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import app.revanced.manager.R
|
||||
import app.revanced.manager.ui.component.AppTopBar
|
||||
@@ -33,6 +34,7 @@ fun UpdatesSettingsScreen(
|
||||
vm: UpdatesSettingsViewModel = koinViewModel(),
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
val resources = LocalResources.current
|
||||
val coroutineScope = rememberCoroutineScope()
|
||||
val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(rememberTopAppBarState())
|
||||
|
||||
@@ -57,7 +59,7 @@ fun UpdatesSettingsScreen(
|
||||
modifier = Modifier.clickable {
|
||||
coroutineScope.launch {
|
||||
if (!vm.isConnected) {
|
||||
context.toast(context.getString(R.string.no_network_toast))
|
||||
context.toast(resources.getString(R.string.no_network_toast))
|
||||
return@launch
|
||||
}
|
||||
if (vm.checkForUpdates()) onUpdateClick()
|
||||
@@ -70,7 +72,7 @@ fun UpdatesSettingsScreen(
|
||||
SettingsListItem(
|
||||
modifier = Modifier.clickable {
|
||||
if (!vm.isConnected) {
|
||||
context.toast(context.getString(R.string.no_network_toast))
|
||||
context.toast(resources.getString(R.string.no_network_toast))
|
||||
return@clickable
|
||||
}
|
||||
onChangelogClick()
|
||||
|
||||
@@ -36,8 +36,8 @@ import kotlin.io.path.deleteExisting
|
||||
import kotlin.io.path.inputStream
|
||||
|
||||
sealed class ResetDialogState(
|
||||
@StringRes val titleResId: Int,
|
||||
@StringRes val descriptionResId: Int,
|
||||
@param:StringRes val titleResId: Int,
|
||||
@param:StringRes val descriptionResId: Int,
|
||||
val onConfirm: () -> Unit,
|
||||
val dialogOptionName: String? = null
|
||||
) {
|
||||
|
||||
@@ -90,8 +90,10 @@ class UpdateViewModel(
|
||||
http.download(location) {
|
||||
url(release.downloadUrl)
|
||||
onDownload { bytesSentTotal, contentLength ->
|
||||
downloadedSize = bytesSentTotal
|
||||
totalSize = contentLength
|
||||
withContext(Dispatchers.Main) {
|
||||
downloadedSize = bytesSentTotal
|
||||
contentLength?.let { totalSize = it }
|
||||
}
|
||||
}
|
||||
}
|
||||
installUpdate()
|
||||
|
||||
@@ -1,21 +1,22 @@
|
||||
package app.revanced.manager.util
|
||||
|
||||
import android.app.LocaleConfig
|
||||
import android.content.Context
|
||||
import android.os.Build
|
||||
import android.os.LocaleList
|
||||
import androidx.appcompat.app.AppCompatDelegate
|
||||
import androidx.core.os.LocaleListCompat
|
||||
import app.revanced.manager.BuildConfig
|
||||
import java.util.Locale
|
||||
|
||||
object SupportedLocales {
|
||||
fun getSupportedLocales(context: Context): List<Locale> {
|
||||
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
runCatching {
|
||||
android.app.LocaleConfig(context).supportedLocales?.toList()
|
||||
}.getOrNull() ?: GeneratedLocales.SUPPORTED_LOCALES
|
||||
} else {
|
||||
GeneratedLocales.SUPPORTED_LOCALES
|
||||
}
|
||||
var result: List<Locale>? = null
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) result = runCatching {
|
||||
LocaleConfig(context).supportedLocales?.toList()
|
||||
}.getOrNull()
|
||||
|
||||
return result ?: generated
|
||||
}
|
||||
|
||||
fun getCurrentLocale(): Locale? =
|
||||
@@ -29,4 +30,11 @@ object SupportedLocales {
|
||||
locale.getDisplayName(locale).replaceFirstChar { it.uppercase(locale) }
|
||||
|
||||
private fun LocaleList.toList() = (0 until size()).map { get(it) }
|
||||
|
||||
private val generated by lazy {
|
||||
listOf(
|
||||
Locale.ENGLISH,
|
||||
*BuildConfig.SUPPORTED_LOCALES.map(Locale::forLanguageTag).toTypedArray()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,12 +15,10 @@ import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.ReadOnlyComposable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.derivedStateOf
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableIntStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.produceState
|
||||
import androidx.compose.runtime.rememberUpdatedState
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.runtime.snapshotFlow
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.alpha
|
||||
import androidx.compose.ui.graphics.Color
|
||||
@@ -43,7 +41,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
|
||||
@@ -51,9 +48,11 @@ import kotlinx.datetime.format.char
|
||||
import kotlinx.datetime.toInstant
|
||||
import kotlinx.datetime.toLocalDateTime
|
||||
import java.util.Locale
|
||||
import kotlin.math.abs
|
||||
import kotlin.properties.PropertyDelegateProvider
|
||||
import kotlin.properties.ReadWriteProperty
|
||||
import kotlin.reflect.KProperty
|
||||
import kotlin.time.Clock
|
||||
|
||||
typealias PatchSelection = Map<Int, Set<String>>
|
||||
typealias Options = Map<Int, Map<String, Map<String, Any?>>>
|
||||
@@ -169,7 +168,7 @@ fun LocalDateTime.relativeTime(context: Context): String {
|
||||
else -> LocalDateTime.Format {
|
||||
monthName(MonthNames.ENGLISH_ABBREVIATED)
|
||||
char(' ')
|
||||
dayOfMonth()
|
||||
day()
|
||||
if (now.toLocalDateTime(TimeZone.UTC).year != this@relativeTime.year) {
|
||||
chars(", ")
|
||||
year()
|
||||
@@ -196,7 +195,12 @@ val transparentListItemColors
|
||||
.also { transparentListItemColorsCached = it }
|
||||
|
||||
@Composable
|
||||
fun <T> EventEffect(flow: Flow<T>, vararg keys: Any?, state: Lifecycle.State = Lifecycle.State.STARTED, block: suspend (T) -> Unit) {
|
||||
fun <T> EventEffect(
|
||||
flow: Flow<T>,
|
||||
vararg keys: Any?,
|
||||
state: Lifecycle.State = Lifecycle.State.STARTED,
|
||||
block: suspend (T) -> Unit
|
||||
) {
|
||||
val lifecycleOwner = LocalLifecycleOwner.current
|
||||
val currentBlock by rememberUpdatedState(block)
|
||||
|
||||
@@ -212,40 +216,36 @@ fun <T> EventEffect(flow: Flow<T>, vararg keys: Any?, state: Lifecycle.State = L
|
||||
const val isScrollingUpSensitivity = 10
|
||||
|
||||
@Composable
|
||||
fun LazyListState.isScrollingUp(): State<Boolean> {
|
||||
return remember(this) {
|
||||
var previousIndex by mutableIntStateOf(firstVisibleItemIndex)
|
||||
var previousScrollOffset by mutableIntStateOf(firstVisibleItemScrollOffset)
|
||||
fun LazyListState.isScrollingUp() = produceState(true, this) {
|
||||
var previousIndex = firstVisibleItemIndex
|
||||
var previousScrollOffset = firstVisibleItemScrollOffset
|
||||
|
||||
derivedStateOf {
|
||||
val indexChanged = previousIndex != firstVisibleItemIndex
|
||||
val offsetChanged =
|
||||
kotlin.math.abs(previousScrollOffset - firstVisibleItemScrollOffset) > isScrollingUpSensitivity
|
||||
snapshotFlow {
|
||||
firstVisibleItemIndex to firstVisibleItemScrollOffset
|
||||
}.collect { (index, scrollOffset) ->
|
||||
val indexChanged = previousIndex != index
|
||||
val offsetChanged = abs(previousScrollOffset - scrollOffset) > isScrollingUpSensitivity
|
||||
|
||||
if (indexChanged) {
|
||||
previousIndex > firstVisibleItemIndex
|
||||
} else if (offsetChanged) {
|
||||
previousScrollOffset > firstVisibleItemScrollOffset
|
||||
} else {
|
||||
true
|
||||
}.also {
|
||||
previousIndex = firstVisibleItemIndex
|
||||
previousScrollOffset = firstVisibleItemScrollOffset
|
||||
}
|
||||
value = when {
|
||||
indexChanged -> previousIndex > index
|
||||
offsetChanged -> previousScrollOffset > scrollOffset
|
||||
else -> value
|
||||
}
|
||||
previousIndex = index
|
||||
previousScrollOffset = scrollOffset
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: support sensitivity
|
||||
@Composable
|
||||
fun ScrollState.isScrollingUp(): State<Boolean> {
|
||||
return remember(this) {
|
||||
var previousScrollOffset by mutableIntStateOf(value)
|
||||
derivedStateOf {
|
||||
(previousScrollOffset >= value).also {
|
||||
previousScrollOffset = value
|
||||
}
|
||||
fun ScrollState.isScrollingUp() = produceState(true, this) {
|
||||
var previousScrollOffset = this@isScrollingUp.value
|
||||
|
||||
snapshotFlow { this@isScrollingUp.value }.collect { scrollOffset ->
|
||||
if (abs(previousScrollOffset - scrollOffset) > isScrollingUpSensitivity) {
|
||||
value = previousScrollOffset >= scrollOffset
|
||||
}
|
||||
|
||||
previousScrollOffset = scrollOffset
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,5 +6,6 @@ plugins {
|
||||
alias(libs.plugins.kotlin.serialization) apply false
|
||||
alias(libs.plugins.kotlin.parcelize) apply false
|
||||
alias(libs.plugins.about.libraries) apply false
|
||||
alias(libs.plugins.about.libraries.android) apply false
|
||||
alias(libs.plugins.compose.compiler) apply false
|
||||
}
|
||||
|
||||
@@ -1,32 +1,32 @@
|
||||
[versions]
|
||||
ktx = "1.16.0"
|
||||
material3 = "1.3.2"
|
||||
ui-tooling = "1.8.1"
|
||||
viewmodel-lifecycle = "2.9.0"
|
||||
splash-screen = "1.0.1"
|
||||
activity = "1.10.1"
|
||||
appcompat = "1.7.0"
|
||||
preferences-datastore = "1.1.2"
|
||||
work-runtime = "2.10.1"
|
||||
compose-bom = "2025.05.00"
|
||||
navigation = "2.8.6"
|
||||
accompanist = "0.37.0"
|
||||
placeholder = "1.1.2"
|
||||
reorderable = "2.4.3"
|
||||
serialization = "1.8.0"
|
||||
collection = "0.3.8"
|
||||
datetime = "0.6.1"
|
||||
room-version = "2.7.1"
|
||||
ktx = "1.17.0"
|
||||
material3 = "1.4.0"
|
||||
ui-tooling = "1.10.0"
|
||||
viewmodel-lifecycle = "2.10.0"
|
||||
splash-screen = "1.2.0"
|
||||
activity = "1.12.2"
|
||||
appcompat = "1.7.1"
|
||||
preferences-datastore = "1.2.0"
|
||||
work-runtime = "2.11.0"
|
||||
compose-bom = "2025.12.01"
|
||||
navigation = "2.9.6"
|
||||
accompanist = "0.37.3"
|
||||
placeholder = "1.0.12"
|
||||
reorderable = "3.0.0"
|
||||
serialization = "1.9.0"
|
||||
collection = "0.4.0"
|
||||
datetime = "0.7.1"
|
||||
room-version = "2.8.4"
|
||||
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.3"
|
||||
markdown-renderer = "0.39.0"
|
||||
fading-edges = "1.0.4"
|
||||
kotlin = "2.1.10"
|
||||
android-gradle-plugin = "8.9.1"
|
||||
dev-tools-gradle-plugin = "2.1.10-1.0.29"
|
||||
about-libraries-gradle-plugin = "12.1.2"
|
||||
kotlin = "2.3.0"
|
||||
android-gradle-plugin = "8.13.2"
|
||||
dev-tools-gradle-plugin = "2.3.4"
|
||||
about-libraries = "13.2.1"
|
||||
coil = "2.7.0"
|
||||
app-icon-loader-coil = "1.5.0"
|
||||
libsu = "6.0.0"
|
||||
@@ -34,10 +34,10 @@ 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"
|
||||
semver-parser = "3.0.0"
|
||||
ackpine = "0.18.5"
|
||||
ackpine = "0.19.1"
|
||||
|
||||
[libraries]
|
||||
# AndroidX Core
|
||||
@@ -68,7 +68,7 @@ coil-appiconloader = { group = "me.zhanghai.android.appiconloader", name = "appi
|
||||
accompanist-drawablepainter = { group = "com.google.accompanist", name = "accompanist-drawablepainter", version.ref = "accompanist" }
|
||||
|
||||
# Placeholder
|
||||
placeholder-material3 = { group = "io.github.fornewid", name = "placeholder-material3", version.ref = "placeholder"}
|
||||
placeholder-material3 = { group = "com.eygraber", name = "compose-placeholder-material3", version.ref = "placeholder" }
|
||||
|
||||
# Kotlinx
|
||||
kotlinx-serialization-json = { group = "org.jetbrains.kotlinx", name = "kotlinx-serialization-json", version.ref = "serialization" }
|
||||
@@ -91,7 +91,8 @@ koin-compose-navigation = { group = "io.insert-koin", name = "koin-androidx-comp
|
||||
koin-workmanager = { group = "io.insert-koin", name = "koin-androidx-workmanager", version.ref = "koin" }
|
||||
|
||||
# About Libraries
|
||||
about-libraries = { group = "com.mikepenz", name = "aboutlibraries-compose", version.ref = "about-libraries-gradle-plugin" }
|
||||
about-libraries-core = { group = "com.mikepenz", name = "aboutlibraries-compose-core", version.ref = "about-libraries" }
|
||||
about-libraries-m3 = { group = "com.mikepenz", name = "aboutlibraries-compose-m3", version.ref = "about-libraries" }
|
||||
|
||||
# Ktor
|
||||
ktor-core = { group = "io.ktor", name = "ktor-client-core", version.ref = "ktor" }
|
||||
@@ -146,5 +147,6 @@ kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", versi
|
||||
kotlin-parcelize = { id = "org.jetbrains.kotlin.plugin.parcelize", version.ref = "kotlin" }
|
||||
compose-compiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
|
||||
devtools = { id = "com.google.devtools.ksp", version.ref = "dev-tools-gradle-plugin" }
|
||||
about-libraries = { id = "com.mikepenz.aboutlibraries.plugin", version.ref = "about-libraries-gradle-plugin" }
|
||||
about-libraries = { id = "com.mikepenz.aboutlibraries.plugin", version.ref = "about-libraries" }
|
||||
about-libraries-android = { id = "com.mikepenz.aboutlibraries.plugin.android", version.ref = "about-libraries" }
|
||||
binary-compatibility-validator = { id = "org.jetbrains.kotlinx.binary-compatibility-validator", version.ref = "binary-compatibility-validator" }
|
||||
|
||||
Reference in New Issue
Block a user