Compare commits

..

12 Commits

Author SHA1 Message Date
Pun Butrach
8e9a564e53 build: Migrate major breaking changes from all dependencies (except Placeholder) 2025-09-23 20:11:20 +07:00
Pun Butrach
c9fbc8eb46 ci: Bump dependencies and consistency in Java 2025-09-23 18:44:52 +07:00
Pun Butrach
9b4cea074e build: Bump dependencies 2025-09-23 18:31:11 +07:00
Pun Butrach
c68c493781 revert: ProGuard rules 2025-09-23 17:55:59 +07:00
Pun Butrach
6c4003a21b Merge branch 'compose-dev' into build/optimisation-compose 2025-09-03 17:17:57 +07:00
kitadai31
797777d214 build: Clean up ProGuard rules (#2663) 2025-09-02 22:12:06 +02:00
Pun Butrach
ba9955addb ci: Remove fetch-depth from checkout (#2628) 2025-09-02 13:57:25 +02:00
Pun Butrach
2cdb027e60 build: Bump Gradle Wrapper to 9.0.0 2025-08-03 20:32:33 +07:00
Pun Butrach
079ae38330 chore: multiple commits 2025-08-03 20:26:36 +07:00
Pun Butrach
4b22de012c build: Bump minimum to 3gb of memory (+1gb for meta) 2025-08-03 19:57:11 +07:00
Pun Butrach
66a7f0d60e build: Enable build parallelism 2025-08-03 19:39:18 +07:00
Pun Butrach
5f77d644df build: Bump all dependencies across every ecosystems 2025-08-03 19:20:43 +07:00
40 changed files with 175 additions and 749 deletions

View File

@@ -5,6 +5,7 @@ on:
pull_request:
branches:
- dev
- compose-dev
jobs:
release:
@@ -12,12 +13,16 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v5
- name: Setup Java
uses: actions/setup-java@v5
with:
fetch-depth: 0
distribution: 'temurin'
java-version: '17'
- name: Cache Gradle
uses: burrunan/gradle-cache-action@v1
uses: burrunan/gradle-cache-action@v3
- name: Build
env:

View File

@@ -15,7 +15,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v5
- name: Open pull request
uses: repo-sync/pull-request@v2

View File

@@ -17,18 +17,16 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
uses: actions/checkout@v5
- name: Setup Java
uses: actions/setup-java@v4
uses: actions/setup-java@v5
with:
distribution: 'temurin'
java-version: '17'
- name: Cache Gradle
uses: burrunan/gradle-cache-action@v1
uses: burrunan/gradle-cache-action@v3
- name: Build
env:
@@ -36,7 +34,7 @@ jobs:
run: ./gradlew assembleRelease
- name: Setup Node.js
uses: actions/setup-node@v4
uses: actions/setup-node@v5
with:
node-version: "lts/*"
cache: 'npm'
@@ -56,7 +54,7 @@ jobs:
echo "${{ secrets.KEYSTORE }}" | base64 --decode > "app/keystore.jks"
- name: Semantic Release
uses: cycjimmy/semantic-release-action@v4
uses: cycjimmy/semantic-release-action@v5
id: semantic
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -66,7 +64,7 @@ jobs:
- name: Attest
if: steps.semantic.outputs.new_release_published == 'true'
uses: actions/attest-build-provenance@v2
uses: actions/attest-build-provenance@v3
with:
subject-name: 'ReVanced Manager ${{ steps.release.outputs.new_release_git_tag }}'
subject-path: app/build/outputs/apk/release/revanced-manager*.apk

View File

@@ -1,3 +1,4 @@
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
import java.io.IOException
plugins {
@@ -58,7 +59,7 @@ tasks.matching { it.name.startsWith("publish") }.configureEach {
android {
namespace = "app.revanced.manager.plugin.downloader"
compileSdk = 35
compileSdk = 36
defaultConfig {
minSdk = 26
@@ -81,8 +82,10 @@ android {
targetCompatibility = JavaVersion.VERSION_17
}
kotlinOptions {
jvmTarget = "17"
kotlin {
compilerOptions {
jvmTarget = JvmTarget.fromTarget("17")
}
}
buildFeatures {

View File

@@ -1,3 +1,4 @@
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
import kotlin.random.Random
plugins {
@@ -52,7 +53,6 @@ dependencies {
// Room
implementation(libs.room.runtime)
implementation(libs.room.ktx)
annotationProcessor(libs.room.compiler)
ksp(libs.room.compiler)
// ReVanced
@@ -60,7 +60,7 @@ dependencies {
implementation(libs.revanced.library)
// Downloader plugins
implementation(project(":api"))
implementation(projects.api)
// Native processes
implementation(libs.kotlin.process)
@@ -111,19 +111,21 @@ dependencies {
android {
namespace = "app.revanced.manager"
compileSdk = 35
buildToolsVersion = "35.0.1"
compileSdk = 36
buildToolsVersion = "36.0.0"
defaultConfig {
applicationId = "app.revanced.manager"
minSdk = 26
targetSdk = 35
targetSdk = 36
versionCode = 1
versionName = "0.0.1"
vectorDrawables.useSupportLibrary = true
}
buildTypes {
configureEach {
}
debug {
applicationIdSuffix = ".debug"
resValue("string", "app_name", "ReVanced Manager (Debug)")
@@ -199,8 +201,11 @@ android {
arg("room.schemaLocation", "$projectDir/schemas")
}
kotlinOptions {
jvmTarget = "17"
kotlin {
compilerOptions {
jvmTarget = JvmTarget.fromTarget("17")
jvmToolchain(17)
}
}
buildFeatures {
@@ -223,10 +228,6 @@ android {
}
}
kotlin {
jvmToolchain(17)
}
tasks {
// Needed by gradle-semantic-release-plugin.
// Tracking: https://github.com/KengoTODA/gradle-semantic-release-plugin/issues/435.

View File

@@ -1,63 +1,14 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.kts.kts.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
-dontobfuscate
# Required for serialization to work properly
-if @kotlinx.serialization.Serializable class **
-keepclassmembers class <1> {
static <1>$Companion Companion;
}
-if @kotlinx.serialization.Serializable class ** {
static **$* *;
}
-keepclassmembers class <2>$<3> {
kotlinx.serialization.KSerializer serializer(...);
}
-if @kotlinx.serialization.Serializable class ** {
public static ** INSTANCE;
}
-keepclassmembers class <1> {
public static <1> INSTANCE;
kotlinx.serialization.KSerializer serializer(...);
}
-keep class app.revanced.manager.patcher.runtime.process.* { *; }
-keep class app.revanced.manager.plugin.** { *; }
-keep class app.revanced.patcher.** { *; }
-keep class com.android.tools.smali.** { *; }
-keep class kotlin.** { *; }
-keepnames class com.android.apksig.internal.** { *; }
-keepnames class org.xmlpull.** { *; }
# This required for the process runtime.
-keep class app.revanced.manager.patcher.runtime.process.* {
*;
}
# Required for the patcher to function correctly
-keep class app.revanced.patcher.** {
*;
}
-keep class brut.** {
*;
}
-keep class org.xmlpull.** {
*;
}
-keep class kotlin.** {
*;
}
-keep class org.jf.** {
*;
}
-keep class com.android.** {
*;
}
-keep class app.revanced.manager.plugin.** {
*;
}
-dontwarn com.google.auto.value.**
-dontwarn com.google.j2objc.annotations.*
-dontwarn java.awt.**
-dontwarn javax.**
-dontwarn org.slf4j.**
-dontwarn it.skrape.fetcher.*
-dontwarn com.google.j2objc.annotations.*
-keepattributes RuntimeVisibleAnnotations,AnnotationDefault
-dontwarn org.slf4j.**

View File

@@ -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)
}
}

View File

@@ -6,6 +6,7 @@ import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
@@ -21,7 +22,6 @@ import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import app.revanced.manager.R
import app.revanced.manager.ui.component.tooltip.TooltipIconButton
@OptIn(ExperimentalMaterial3Api::class)
@Composable
@@ -69,10 +69,7 @@ fun AppTopBar(
scrollBehavior = scrollBehavior,
navigationIcon = {
if (onBackClick != null) {
TooltipIconButton(
onClick = onBackClick,
tooltip = stringResource(R.string.back),
) {
IconButton(onClick = onBackClick) {
backIcon()
}
}
@@ -111,10 +108,7 @@ fun AppTopBar(
scrollBehavior = scrollBehavior,
navigationIcon = {
if (onBackClick != null) {
TooltipIconButton(
onClick = onBackClick,
tooltip = stringResource(R.string.back),
) {
IconButton(onClick = onBackClick) {
backIcon()
}
}

View File

@@ -4,13 +4,13 @@ import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.KeyboardArrowUp
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.rotate
import androidx.compose.ui.res.stringResource
import app.revanced.manager.R
import app.revanced.manager.ui.component.tooltip.TooltipIconButton
@Composable
fun ArrowButton(
@@ -27,11 +27,7 @@ fun ArrowButton(
)
onClick?.let {
TooltipIconButton(
modifier = Modifier,
onClick = it,
tooltip = stringResource(description),
) {
IconButton(onClick = it) {
Icon(
imageVector = Icons.Filled.KeyboardArrowUp,
contentDescription = stringResource(description),

View File

@@ -9,6 +9,7 @@ import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material.icons.outlined.Share
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
@@ -17,7 +18,6 @@ import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import app.revanced.manager.R
import app.revanced.manager.ui.component.bundle.BundleTopBar
import app.revanced.manager.ui.component.tooltip.TooltipIconButton
@OptIn(ExperimentalMaterial3Api::class)
@Composable
@@ -39,8 +39,7 @@ fun ExceptionViewerDialog(text: String, onDismiss: () -> Unit) {
)
},
actions = {
TooltipIconButton(
modifier = Modifier,
IconButton(
onClick = {
val sendIntent: Intent = Intent().apply {
action = Intent.ACTION_SEND
@@ -53,8 +52,7 @@ fun ExceptionViewerDialog(text: String, onDismiss: () -> Unit) {
val shareIntent = Intent.createChooser(sendIntent, null)
context.startActivity(shareIntent)
},
tooltip = stringResource(R.string.share),
}
) {
Icon(
Icons.Outlined.Share,

View File

@@ -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()
),
)
)
}

View File

@@ -14,6 +14,7 @@ import androidx.compose.material.icons.outlined.Close
import androidx.compose.material3.Card
import androidx.compose.material3.CardDefaults
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
@@ -24,7 +25,6 @@ import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import app.revanced.manager.R
import app.revanced.manager.ui.component.tooltip.TooltipIconButton
@Composable
fun NotificationCard(
@@ -138,10 +138,7 @@ fun NotificationCard(
)
}
if (onDismiss != null) {
TooltipIconButton(
onClick = onDismiss,
tooltip = stringResource(R.string.close),
) {
IconButton(onClick = onDismiss) {
Icon(
imageVector = Icons.Outlined.Close,
contentDescription = stringResource(R.string.close),

View File

@@ -5,6 +5,7 @@ import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.Visibility
import androidx.compose.material.icons.outlined.VisibilityOff
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.OutlinedTextField
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
@@ -18,7 +19,6 @@ import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.input.PasswordVisualTransformation
import androidx.compose.ui.text.input.VisualTransformation
import app.revanced.manager.R
import app.revanced.manager.ui.component.tooltip.TooltipIconButton
@Composable
fun PasswordField(modifier: Modifier = Modifier, value: String, onValueChange: (String) -> Unit, label: @Composable (() -> Unit)? = null, placeholder: @Composable (() -> Unit)? = null) {
@@ -33,15 +33,9 @@ fun PasswordField(modifier: Modifier = Modifier, value: String, onValueChange: (
label = label,
modifier = modifier,
trailingIcon = {
TooltipIconButton(
modifier = Modifier,
onClick = {
visible = !visible
},
tooltip = if (visible) stringResource(R.string.show_password_field) else stringResource(
R.string.hide_password_field
),
) {
IconButton(onClick = {
visible = !visible
}) {
val (icon, description) = remember(visible) {
if (visible) Icons.Outlined.VisibilityOff to R.string.hide_password_field else Icons.Outlined.Visibility to R.string.show_password_field
}

View File

@@ -5,6 +5,7 @@ import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.SearchBar
import androidx.compose.material3.SearchBarColors
@@ -18,7 +19,6 @@ import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
import androidx.compose.ui.res.stringResource
import app.revanced.manager.R
import app.revanced.manager.ui.component.tooltip.TooltipIconButton
@OptIn(ExperimentalMaterial3Api::class)
@Composable
@@ -48,10 +48,7 @@ fun SearchView(
onExpandedChange = onActiveChange,
placeholder = placeholder,
leadingIcon = {
TooltipIconButton(
tooltip = stringResource(R.string.back),
onClick = { onActiveChange(false) }
) {
IconButton(onClick = { onActiveChange(false) }) {
Icon(
Icons.AutoMirrored.Filled.ArrowBack,
stringResource(R.string.back)

View File

@@ -49,7 +49,6 @@ import app.revanced.manager.domain.repository.PatchBundleRepository
import app.revanced.manager.ui.component.ColumnWithScrollbar
import app.revanced.manager.ui.component.ExceptionViewerDialog
import app.revanced.manager.ui.component.FullscreenDialog
import app.revanced.manager.ui.component.tooltip.TooltipIconButton
import app.revanced.manager.ui.component.TextInputDialog
import app.revanced.manager.ui.component.haptics.HapticSwitch
import kotlinx.coroutines.launch
@@ -104,11 +103,7 @@ fun BundleInformationDialog(
},
actions = {
if (!src.isDefault) {
TooltipIconButton(
modifier = Modifier,
onClick = onDeleteRequest,
tooltip = stringResource(R.string.delete),
) {
IconButton(onClick = onDeleteRequest) {
Icon(
Icons.Outlined.DeleteOutline,
stringResource(R.string.delete)
@@ -116,11 +111,7 @@ fun BundleInformationDialog(
}
}
if (!isLocal && hasNetwork) {
TooltipIconButton(
modifier = Modifier,
onClick = onUpdate,
tooltip = stringResource(R.string.refresh),
) {
IconButton(onClick = onUpdate) {
Icon(
Icons.Outlined.Update,
stringResource(R.string.refresh)

View File

@@ -2,6 +2,7 @@ package app.revanced.manager.ui.component.bundle
import androidx.compose.foundation.layout.RowScope
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
@@ -9,11 +10,7 @@ import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.material3.TopAppBarScrollBehavior
import androidx.compose.material3.surfaceColorAtElevation
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import app.revanced.manager.R
import app.revanced.manager.ui.component.tooltip.TooltipIconButton
@OptIn(ExperimentalMaterial3Api::class)
@Composable
@@ -36,10 +33,7 @@ fun BundleTopBar(
scrollBehavior = scrollBehavior,
navigationIcon = {
if (onBackClick != null) {
TooltipIconButton(
tooltip = stringResource(R.string.back),
onClick = onBackClick
) {
IconButton(onClick = onBackClick) {
backIcon()
}
}

View File

@@ -193,7 +193,6 @@ private fun ImportBundleStep(
},
supportingContent = { Text(stringResource(if (patchBundle != null) R.string.file_field_set else R.string.file_field_not_set)) },
trailingContent = {
// TODO: Determine if this button should be [TooltipWrap]'ped
IconButton(onClick = launchPatchActivity) {
Icon(imageVector = Icons.Default.Topic, contentDescription = null)
}

View File

@@ -1,38 +0,0 @@
package app.revanced.manager.ui.component.haptics
import android.view.HapticFeedbackConstants
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.material3.FloatingActionButton
import androidx.compose.material3.FloatingActionButtonDefaults
import androidx.compose.material3.FloatingActionButtonElevation
import androidx.compose.material3.SmallFloatingActionButton
import androidx.compose.material3.contentColorFor
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Shape
import app.revanced.manager.util.withHapticFeedback
@Composable
fun HapticSmallFloatingActionButton (
onClick: () -> Unit,
modifier: Modifier = Modifier,
shape: Shape = FloatingActionButtonDefaults.smallShape,
containerColor: Color = FloatingActionButtonDefaults.containerColor,
contentColor: Color = contentColorFor(containerColor),
elevation: FloatingActionButtonElevation = FloatingActionButtonDefaults.elevation(),
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
content: @Composable () -> Unit,
) {
SmallFloatingActionButton(
onClick = onClick.withHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY),
modifier = modifier,
shape = shape,
containerColor = containerColor,
contentColor = contentColor,
elevation = elevation,
interactionSource = interactionSource,
content = content
)
}

View File

@@ -67,7 +67,6 @@ import app.revanced.manager.ui.component.LongInputDialog
import app.revanced.manager.ui.component.haptics.HapticExtendedFloatingActionButton
import app.revanced.manager.ui.component.haptics.HapticRadioButton
import app.revanced.manager.ui.component.haptics.HapticSwitch
import app.revanced.manager.ui.component.tooltip.TooltipIconButton
import app.revanced.manager.util.isScrollingUp
import app.revanced.manager.util.mutableStateSetOf
import app.revanced.manager.util.saver.snapshotStateListSaver
@@ -124,11 +123,7 @@ private interface OptionEditor<T : Any> {
@Composable
fun ListItemTrailingContent(scope: OptionEditorScope<T>) {
TooltipIconButton(
modifier = Modifier,
tooltip = stringResource(R.string.edit),
onClick = { scope.checkSafeguard { clickAction(scope) } }
) {
IconButton(onClick = { scope.checkSafeguard { clickAction(scope) } }) {
Icon(Icons.Outlined.Edit, stringResource(R.string.edit))
}
}
@@ -275,9 +270,7 @@ private object StringOptionEditor : OptionEditor<String> {
},
trailingIcon = {
var showDropdownMenu by rememberSaveable { mutableStateOf(false) }
TooltipIconButton(
modifier = Modifier,
tooltip = stringResource(R.string.string_option_menu_description),
IconButton(
onClick = { showDropdownMenu = true }
) {
Icon(
@@ -587,9 +580,7 @@ private class ListOptionEditor<T : Serializable>(private val elementEditor: Opti
},
actions = {
if (deleteMode) {
TooltipIconButton(
modifier = Modifier,
tooltip = stringResource(R.string.select_deselect_all),
IconButton(
onClick = {
if (items.size == deletionTargets.size) deletionTargets.clear()
else deletionTargets.addAll(items.map { it.key })
@@ -600,9 +591,7 @@ private class ListOptionEditor<T : Serializable>(private val elementEditor: Opti
stringResource(R.string.select_deselect_all)
)
}
TooltipIconButton(
modifier = Modifier,
tooltip = stringResource(R.string.delete),
IconButton(
onClick = {
items.removeIf { it.key in deletionTargets }
deletionTargets.clear()
@@ -615,15 +604,8 @@ private class ListOptionEditor<T : Serializable>(private val elementEditor: Opti
)
}
} else {
TooltipIconButton(
modifier = Modifier,
tooltip = stringResource(R.string.reset),
onClick = items::clear
) {
Icon(
Icons.Outlined.Restore,
stringResource(R.string.reset)
)
IconButton(onClick = items::clear) {
Icon(Icons.Outlined.Restore, stringResource(R.string.reset))
}
}
}
@@ -691,10 +673,9 @@ private class ListOptionEditor<T : Serializable>(private val elementEditor: Opti
),
tonalElevation = if (deleteMode && item.key in deletionTargets) 8.dp else 0.dp,
leadingContent = {
TooltipIconButton(
IconButton(
modifier = Modifier.draggableHandle(interactionSource = interactionSource),
tooltip = stringResource(R.string.delete),
onClick = { }
onClick = {},
) {
Icon(
Icons.Filled.DragHandle,

View File

@@ -5,6 +5,7 @@ import androidx.compose.foundation.clickable
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.Edit
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
@@ -16,7 +17,6 @@ import androidx.compose.ui.res.stringResource
import app.revanced.manager.R
import app.revanced.manager.domain.manager.base.Preference
import app.revanced.manager.ui.component.IntInputDialog
import app.revanced.manager.ui.component.tooltip.TooltipIconButton
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
@@ -65,14 +65,10 @@ fun IntegerItem(
headlineContent = stringResource(headline),
supportingContent = stringResource(description),
trailingContent = {
TooltipIconButton(
modifier = modifier,
onClick = { dialogOpen = true },
tooltip = stringResource(R.string.edit),
) {
IconButton(onClick = { dialogOpen = true }) {
Icon(
imageVector = Icons.Outlined.Edit,
contentDescription = stringResource(R.string.edit),
Icons.Outlined.Edit,
contentDescription = stringResource(R.string.edit)
)
}
}

View File

@@ -1,107 +0,0 @@
package app.revanced.manager.ui.component.tooltip
import androidx.annotation.StringRes
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.FloatingActionButtonDefaults
import androidx.compose.material3.FloatingActionButtonElevation
import androidx.compose.material3.TooltipDefaults
import androidx.compose.material3.contentColorFor
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.hapticfeedback.HapticFeedbackType
import androidx.compose.ui.window.PopupPositionProvider
import app.revanced.manager.ui.component.haptics.HapticFloatingActionButton
/**
* [HapticFloatingActionButton] with tooltip-specific params.
*
* @param tooltip [String] text to show in a tooltip.
* @param positionProvider [PopupPositionProvider] Anchor point for the tooltip.
* @param haptic Whether to perform haptic feedback when the tooltip shown.
* @param hapticFeedbackType The type of haptic feedback to perform.
*
* @see [HapticFloatingActionButton]
*/
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun TooltipFloatingActionButton(
onClick: () -> Unit,
modifier: Modifier = Modifier,
shape: Shape = FloatingActionButtonDefaults.shape,
containerColor: Color = FloatingActionButtonDefaults.containerColor,
contentColor: Color = contentColorFor(containerColor),
elevation: FloatingActionButtonElevation = FloatingActionButtonDefaults.elevation(),
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
tooltip: String,
positionProvider: PopupPositionProvider = TooltipDefaults.rememberPlainTooltipPositionProvider(),
haptic: Boolean = true,
hapticFeedbackType: HapticFeedbackType = HapticFeedbackType.LongPress,
content: @Composable (() -> Unit)
) {
TooltipWrap(
tooltip = tooltip,
positionProvider = positionProvider,
haptic = haptic,
hapticFeedbackType = hapticFeedbackType,
) {
HapticFloatingActionButton(
onClick = onClick,
modifier = modifier,
shape = shape,
containerColor = containerColor,
contentColor = contentColor,
elevation = elevation,
interactionSource = interactionSource,
content = content,
)
}
}
/**
* [HapticFloatingActionButton] with tooltip-specific params.
*
* @param tooltip [Int] or `id` string resource to show in a tooltip.
* @param positionProvider [PopupPositionProvider] Anchor point for the tooltip.
* @param haptic Whether to perform haptic feedback when the tooltip shown.
* @param hapticFeedbackType The type of haptic feedback to perform.
*
* @see [HapticFloatingActionButton]
*/
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun TooltipFloatingActionButton(
onClick: () -> Unit,
modifier: Modifier = Modifier,
shape: Shape = FloatingActionButtonDefaults.shape,
containerColor: Color = FloatingActionButtonDefaults.containerColor,
contentColor: Color = contentColorFor(containerColor),
elevation: FloatingActionButtonElevation = FloatingActionButtonDefaults.elevation(),
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
@StringRes tooltip: Int,
positionProvider: PopupPositionProvider = TooltipDefaults.rememberPlainTooltipPositionProvider(),
haptic: Boolean = true,
hapticFeedbackType: HapticFeedbackType = HapticFeedbackType.LongPress,
content: @Composable (() -> Unit)
) {
TooltipWrap(
tooltip = tooltip,
positionProvider = positionProvider,
haptic = haptic,
hapticFeedbackType = hapticFeedbackType,
) {
HapticFloatingActionButton(
onClick = onClick,
modifier = modifier,
shape = shape,
containerColor = containerColor,
contentColor = contentColor,
elevation = elevation,
interactionSource = interactionSource,
content = content,
)
}
}

View File

@@ -1,96 +0,0 @@
package app.revanced.manager.ui.component.tooltip
import androidx.annotation.StringRes
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.IconButton
import androidx.compose.material3.IconButtonColors
import androidx.compose.material3.IconButtonDefaults
import androidx.compose.material3.TooltipDefaults
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.hapticfeedback.HapticFeedbackType
import androidx.compose.ui.window.PopupPositionProvider
/**
* [IconButton] with tooltip-specific params.
*
* @param tooltip [String] text to show in a tooltip.
* @param positionProvider [PopupPositionProvider] Anchor point for the tooltip.
* @param haptic Whether to perform haptic feedback when the tooltip shown.
* @param hapticFeedbackType The type of haptic feedback to perform.
*
* @see [IconButton]
*/
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun TooltipIconButton(
onClick: () -> Unit,
modifier: Modifier = Modifier,
enabled: Boolean = true,
colors: IconButtonColors = IconButtonDefaults.iconButtonColors(),
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
tooltip: String,
positionProvider: PopupPositionProvider = TooltipDefaults.rememberPlainTooltipPositionProvider(),
haptic: Boolean = true,
hapticFeedbackType: HapticFeedbackType = HapticFeedbackType.LongPress,
content: @Composable (() -> Unit),
) {
TooltipWrap(
tooltip = tooltip,
positionProvider = positionProvider,
haptic = haptic,
hapticFeedbackType = hapticFeedbackType,
) {
IconButton(
onClick = onClick,
modifier = modifier,
enabled = enabled,
colors = colors,
interactionSource = interactionSource,
content = content,
)
}
}
/**
* [IconButton] with tooltip-specific params.
*
* @param tooltip [Int] or `id` string resource to show in a tooltip.
* @param positionProvider [PopupPositionProvider] Anchor point for the tooltip.
* @param haptic Whether to perform haptic feedback when the tooltip shown.
* @param hapticFeedbackType The type of haptic feedback to perform.
*
* @see [IconButton]
*/
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun TooltipIconButton(
onClick: () -> Unit,
modifier: Modifier = Modifier,
enabled: Boolean = true,
colors: IconButtonColors = IconButtonDefaults.iconButtonColors(),
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
@StringRes tooltip: Int,
positionProvider: PopupPositionProvider = TooltipDefaults.rememberPlainTooltipPositionProvider(),
haptic: Boolean = true,
hapticFeedbackType: HapticFeedbackType = HapticFeedbackType.LongPress,
content: @Composable (() -> Unit),
) {
TooltipWrap(
tooltip = tooltip,
positionProvider = positionProvider,
haptic = haptic,
hapticFeedbackType = hapticFeedbackType,
) {
IconButton(
onClick = onClick,
modifier = modifier,
enabled = enabled,
colors = colors,
interactionSource = interactionSource,
content = content,
)
}
}

View File

@@ -1,107 +0,0 @@
package app.revanced.manager.ui.component.tooltip
import androidx.annotation.StringRes
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.FloatingActionButtonDefaults
import androidx.compose.material3.FloatingActionButtonElevation
import androidx.compose.material3.TooltipDefaults
import androidx.compose.material3.contentColorFor
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.hapticfeedback.HapticFeedbackType
import androidx.compose.ui.window.PopupPositionProvider
import app.revanced.manager.ui.component.haptics.HapticSmallFloatingActionButton
/**
* [HapticSmallFloatingActionButton] with tooltip-specific params.
*
* @param tooltip [String] text to show in a tooltip.
* @param positionProvider [PopupPositionProvider] Anchor point for the tooltip.
* @param haptic Whether to perform haptic feedback when the tooltip shown.
* @param hapticFeedbackType The type of haptic feedback to perform.
*
* @see [HapticSmallFloatingActionButton]
*/
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun TooltipSmallFloatingActionButton(
onClick: () -> Unit,
modifier: Modifier = Modifier,
shape: Shape = FloatingActionButtonDefaults.smallShape,
containerColor: Color = FloatingActionButtonDefaults.containerColor,
contentColor: Color = contentColorFor(containerColor),
elevation: FloatingActionButtonElevation = FloatingActionButtonDefaults.elevation(),
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
tooltip: String,
positionProvider: PopupPositionProvider = TooltipDefaults.rememberPlainTooltipPositionProvider(),
haptic: Boolean = true,
hapticFeedbackType: HapticFeedbackType = HapticFeedbackType.LongPress,
content: @Composable (() -> Unit)
) {
TooltipWrap(
tooltip = tooltip,
positionProvider = positionProvider,
haptic = haptic,
hapticFeedbackType = hapticFeedbackType,
) {
HapticSmallFloatingActionButton(
onClick = onClick,
modifier = modifier,
shape = shape,
containerColor = containerColor,
contentColor = contentColor,
elevation = elevation,
interactionSource = interactionSource,
content = content,
)
}
}
/**
* [HapticSmallFloatingActionButton] with tooltip-specific params.
*
* @param tooltip [Int] or `id` string resource to show in a tooltip.
* @param positionProvider [PopupPositionProvider] Anchor point for the tooltip.
* @param haptic Whether to perform haptic feedback when the tooltip shown.
* @param hapticFeedbackType The type of haptic feedback to perform.
*
* @see [HapticSmallFloatingActionButton]
*/
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun TooltipSmallFloatingActionButton(
onClick: () -> Unit,
modifier: Modifier = Modifier,
shape: Shape = FloatingActionButtonDefaults.smallShape,
containerColor: Color = FloatingActionButtonDefaults.containerColor,
contentColor: Color = contentColorFor(containerColor),
elevation: FloatingActionButtonElevation = FloatingActionButtonDefaults.elevation(),
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
@StringRes tooltip: Int,
positionProvider: PopupPositionProvider = TooltipDefaults.rememberPlainTooltipPositionProvider(),
haptic: Boolean = true,
hapticFeedbackType: HapticFeedbackType = HapticFeedbackType.LongPress,
content: @Composable (() -> Unit)
) {
TooltipWrap(
tooltip = tooltip,
positionProvider = positionProvider,
haptic = haptic,
hapticFeedbackType = hapticFeedbackType,
) {
HapticSmallFloatingActionButton(
onClick = onClick,
modifier = modifier,
shape = shape,
containerColor = containerColor,
contentColor = contentColor,
elevation = elevation,
interactionSource = interactionSource,
content = content,
)
}
}

View File

@@ -1,96 +0,0 @@
package app.revanced.manager.ui.component.tooltip
import androidx.annotation.StringRes
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.PlainTooltip
import androidx.compose.material3.Text
import androidx.compose.material3.TooltipBox
import androidx.compose.material3.TooltipDefaults
import androidx.compose.material3.rememberTooltipState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.ui.Modifier
import androidx.compose.ui.hapticfeedback.HapticFeedbackType
import androidx.compose.ui.platform.LocalHapticFeedback
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.window.PopupPositionProvider
/**
* Wraps a composable with a tooltip.
*
* @param modifier the [Modifier] to applied to Tooltip.
* @param tooltip [String] text to show in a tooltip.
* @param positionProvider [PopupPositionProvider] Anchor point for the tooltip.
* @param content The composable UI to wrapped with.
* @param haptic Whether to perform haptic feedback when the tooltip shown.
* @param hapticFeedbackType The type of haptic feedback to perform.
*
* @see [TooltipBox]
*/
@Composable
@OptIn(ExperimentalMaterial3Api::class)
fun TooltipWrap(
modifier: Modifier = Modifier,
tooltip: String,
positionProvider: PopupPositionProvider = TooltipDefaults.rememberPlainTooltipPositionProvider(),
haptic: Boolean = true,
hapticFeedbackType: HapticFeedbackType = HapticFeedbackType.LongPress,
content: @Composable () -> Unit
) {
val tooltipState = rememberTooltipState()
val localHaptic = LocalHapticFeedback.current
LaunchedEffect(tooltipState.isVisible) {
if (tooltipState.isVisible && haptic) {
localHaptic.performHapticFeedback(hapticFeedbackType)
}
}
TooltipBox(
modifier = modifier,
positionProvider = positionProvider,
tooltip = { PlainTooltip { Text(tooltip) } },
state = tooltipState,
content = content,
)
}
/**
* Wraps a composable with a tooltip.
*
* @param modifier the [Modifier] to applied to tooltip.
* @param tooltip [Int] or `id` string resource to show in a tooltip.
* @param positionProvider [PopupPositionProvider] Anchor point for the tooltip.
* @param content The composable UI to wrapped with.
* @param haptic Whether to perform haptic feedback when the tooltip shown.
* @param hapticFeedbackType The type of haptic feedback to perform.
*
* @see [TooltipBox]
*/
@Composable
@OptIn(ExperimentalMaterial3Api::class)
fun TooltipWrap(
modifier: Modifier = Modifier,
@StringRes tooltip: Int,
positionProvider: PopupPositionProvider = TooltipDefaults.rememberPlainTooltipPositionProvider(),
haptic: Boolean = true,
hapticFeedbackType: HapticFeedbackType = HapticFeedbackType.LongPress,
content: @Composable () -> Unit
) {
val tooltipState = rememberTooltipState()
val localHaptic = LocalHapticFeedback.current
LaunchedEffect(tooltipState.isVisible) {
if (tooltipState.isVisible && haptic) {
localHaptic.performHapticFeedback(hapticFeedbackType)
}
}
TooltipBox(
modifier = modifier,
positionProvider = positionProvider,
tooltip = { PlainTooltip { Text(stringResource(tooltip)) } },
state = tooltipState,
content = content,
)
}

View File

@@ -16,6 +16,7 @@ import androidx.compose.material.icons.outlined.Search
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.ListItem
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
@@ -43,7 +44,6 @@ import app.revanced.manager.ui.component.LazyColumnWithScrollbar
import app.revanced.manager.ui.component.LoadingIndicator
import app.revanced.manager.ui.component.NonSuggestedVersionDialog
import app.revanced.manager.ui.component.SearchView
import app.revanced.manager.ui.component.tooltip.TooltipIconButton
import app.revanced.manager.ui.model.SelectedApp
import app.revanced.manager.ui.viewmodel.AppSelectorViewModel
import app.revanced.manager.util.APK_MIMETYPE
@@ -162,14 +162,8 @@ fun AppSelectorScreen(
scrollBehavior = scrollBehavior,
onBackClick = onBackClick,
actions = {
TooltipIconButton(
tooltip = stringResource(R.string.search_patches),
onClick = { search = true }
) {
Icon(
Icons.Outlined.Search,
stringResource(R.string.search)
)
IconButton(onClick = { search = true }) {
Icon(Icons.Outlined.Search, stringResource(R.string.search))
}
}
)

View File

@@ -66,9 +66,8 @@ import app.revanced.manager.ui.component.NotificationCard
import app.revanced.manager.ui.component.ConfirmDialog
import app.revanced.manager.ui.component.bundle.BundleTopBar
import app.revanced.manager.ui.component.bundle.ImportPatchBundleDialog
import app.revanced.manager.ui.component.haptics.HapticFloatingActionButton
import app.revanced.manager.ui.component.haptics.HapticTab
import app.revanced.manager.ui.component.tooltip.TooltipFloatingActionButton
import app.revanced.manager.ui.component.tooltip.TooltipIconButton
import app.revanced.manager.ui.viewmodel.DashboardViewModel
import app.revanced.manager.util.RequestInstallAppsContract
import app.revanced.manager.util.toast
@@ -182,20 +181,18 @@ fun DashboardScreen(
)
},
actions = {
TooltipIconButton(
IconButton(
onClick = {
showDeleteConfirmationDialog = true
},
tooltip = stringResource(R.string.delete),
}
) {
Icon(
Icons.Outlined.DeleteOutline,
stringResource(R.string.delete)
)
}
TooltipIconButton(
onClick = vm::updateSources,
tooltip = stringResource(R.string.refresh)
IconButton(
onClick = vm::updateSources
) {
Icon(
Icons.Outlined.Refresh,
@@ -209,9 +206,8 @@ fun DashboardScreen(
title = stringResource(R.string.app_name),
actions = {
if (!vm.updatedManagerVersion.isNullOrEmpty()) {
TooltipIconButton(
IconButton(
onClick = onUpdateClick,
tooltip = stringResource(R.string.update),
) {
BadgedBox(
badge = {
@@ -222,17 +218,8 @@ fun DashboardScreen(
}
}
}
TooltipIconButton(
onClick = onSettingsClick,
tooltip = stringResource(R.string.settings),
) {
BadgedBox(
badge = {
Badge(modifier = Modifier.size(6.dp))
}
) {
Icon(Icons.Outlined.Settings, stringResource(R.string.settings))
}
IconButton(onClick = onSettingsClick) {
Icon(Icons.Outlined.Settings, stringResource(R.string.settings))
}
},
applyContainerColor = true
@@ -240,8 +227,7 @@ fun DashboardScreen(
}
},
floatingActionButton = {
TooltipFloatingActionButton(
tooltip = stringResource(R.string.add),
HapticFloatingActionButton(
onClick = {
vm.cancelSourceSelection()
@@ -254,11 +240,11 @@ fun DashboardScreen(
DashboardPage.BUNDLES.ordinal
)
}
return@TooltipFloatingActionButton
return@HapticFloatingActionButton
}
if (vm.android11BugActive) {
showAndroid11Dialog = true
return@TooltipFloatingActionButton
return@HapticFloatingActionButton
}
onAppSelectorClick()

View File

@@ -25,6 +25,7 @@ import androidx.compose.material3.AlertDialog
import androidx.compose.material3.BottomAppBar
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.LinearProgressIndicator
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
@@ -50,7 +51,6 @@ import app.revanced.manager.ui.component.InstallerStatusDialog
import app.revanced.manager.ui.component.haptics.HapticExtendedFloatingActionButton
import app.revanced.manager.ui.component.patcher.InstallPickerDialog
import app.revanced.manager.ui.component.patcher.Steps
import app.revanced.manager.ui.component.tooltip.TooltipIconButton
import app.revanced.manager.ui.model.StepCategory
import app.revanced.manager.ui.viewmodel.PatcherViewModel
import app.revanced.manager.util.APK_MIMETYPE
@@ -164,17 +164,15 @@ fun PatcherScreen(
bottomBar = {
BottomAppBar(
actions = {
TooltipIconButton(
IconButton(
onClick = { exportApkLauncher.launch("${viewModel.packageName}_${viewModel.version}_revanced_patched.apk") },
enabled = patcherSucceeded == true,
tooltip = stringResource(R.string.save_apk),
enabled = patcherSucceeded == true
) {
Icon(Icons.Outlined.Save, stringResource(id = R.string.save_apk))
}
TooltipIconButton(
IconButton(
onClick = { viewModel.exportLogs(context) },
enabled = patcherSucceeded != null,
tooltip = stringResource(R.string.save_logs),
enabled = patcherSucceeded != null
) {
Icon(Icons.Outlined.PostAdd, stringResource(id = R.string.save_logs))
}

View File

@@ -41,6 +41,7 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.ModalBottomSheet
import androidx.compose.material3.Scaffold
import androidx.compose.material3.ScrollableTabRow
import androidx.compose.material3.SmallFloatingActionButton
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.material3.surfaceColorAtElevation
@@ -72,9 +73,6 @@ import app.revanced.manager.ui.component.haptics.HapticCheckbox
import app.revanced.manager.ui.component.haptics.HapticExtendedFloatingActionButton
import app.revanced.manager.ui.component.haptics.HapticTab
import app.revanced.manager.ui.component.patches.OptionItem
import app.revanced.manager.ui.component.tooltip.TooltipFloatingActionButton
import app.revanced.manager.ui.component.tooltip.TooltipIconButton
import app.revanced.manager.ui.component.tooltip.TooltipSmallFloatingActionButton
import app.revanced.manager.ui.component.patches.SelectionWarningDialog
import app.revanced.manager.ui.viewmodel.PatchesSelectorViewModel
import app.revanced.manager.ui.viewmodel.PatchesSelectorViewModel.Companion.SHOW_INCOMPATIBLE
@@ -261,15 +259,14 @@ fun PatchesSelectorScreen(
animationSpec = tween(durationMillis = 400, easing = EaseInOut),
label = "SearchBar back button"
)
TooltipIconButton(
IconButton(
onClick = {
if (searchExpanded) {
setSearchExpanded(false)
} else {
onBackClick()
}
},
tooltip = stringResource(R.string.back),
}
) {
Icon(
modifier = Modifier.rotate(rotation),
@@ -285,10 +282,9 @@ fun PatchesSelectorScreen(
transitionSpec = { fadeIn() togetherWith fadeOut() }
) { searchExpanded ->
if (searchExpanded) {
TooltipIconButton(
IconButton(
onClick = { setQuery("") },
enabled = query.isNotEmpty(),
tooltip = stringResource(R.string.clear),
enabled = query.isNotEmpty()
) {
Icon(
imageVector = Icons.Filled.Close,
@@ -296,10 +292,7 @@ fun PatchesSelectorScreen(
)
}
} else {
TooltipIconButton(
onClick = { showBottomSheet = true },
tooltip = stringResource(R.string.more),
) {
IconButton(onClick = { showBottomSheet = true }) {
Icon(
imageVector = Icons.Outlined.FilterList,
contentDescription = stringResource(R.string.more)
@@ -361,8 +354,7 @@ fun PatchesSelectorScreen(
horizontalAlignment = Alignment.End,
verticalArrangement = Arrangement.spacedBy(4.dp)
) {
TooltipSmallFloatingActionButton(
tooltip = stringResource(R.string.reset),
SmallFloatingActionButton(
onClick = viewModel::reset,
containerColor = MaterialTheme.colorScheme.tertiaryContainer
) {
@@ -514,7 +506,6 @@ private fun PatchItem(
supportingContent = patch.description?.let { { Text(it) } },
trailingContent = {
if (patch.options?.isNotEmpty() == true) {
// TODO: Determine if this button should be [TooltipWrap]
IconButton(onClick = onOptionsDialog, enabled = compatible) {
Icon(Icons.Outlined.Settings, null)
}
@@ -538,10 +529,7 @@ fun ListHeader(
},
trailingContent = onHelpClick?.let {
{
TooltipIconButton(
tooltip = stringResource(R.string.help),
onClick = it
) {
IconButton(onClick = it) {
Icon(
Icons.AutoMirrored.Outlined.HelpOutline,
stringResource(R.string.help)
@@ -621,10 +609,7 @@ private fun OptionsDialog(
title = patch.name,
onBackClick = onDismissRequest,
actions = {
TooltipIconButton(
tooltip = stringResource(R.string.reset),
onClick = reset
) {
IconButton(onClick = reset) {
Icon(Icons.Outlined.Restore, stringResource(R.string.reset))
}
}

View File

@@ -19,6 +19,7 @@ import androidx.compose.material.icons.outlined.MailOutline
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.FilledTonalButton
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedCard
import androidx.compose.material3.Scaffold
@@ -49,7 +50,6 @@ import app.revanced.manager.network.dto.ReVancedSocial
import app.revanced.manager.ui.component.AppTopBar
import app.revanced.manager.ui.component.ColumnWithScrollbar
import app.revanced.manager.ui.component.settings.SettingsListItem
import app.revanced.manager.ui.component.tooltip.TooltipIconButton
import app.revanced.manager.ui.model.navigation.Settings
import app.revanced.manager.ui.viewmodel.AboutViewModel
import app.revanced.manager.ui.viewmodel.AboutViewModel.Companion.DEVELOPER_OPTIONS_TAPS
@@ -252,10 +252,9 @@ fun AboutSettingsScreen(
horizontalArrangement = Arrangement.spacedBy(8.dp, Alignment.CenterHorizontally)
) {
socialButtons.forEach { (icon, text, onClick) ->
TooltipIconButton(
IconButton(
onClick = onClick,
modifier = Modifier.padding(end = 8.dp),
tooltip = text,
onClick = onClick
) {
Icon(
icon,

View File

@@ -21,6 +21,7 @@ import androidx.compose.material.icons.outlined.Restore
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Scaffold
@@ -51,7 +52,6 @@ import app.revanced.manager.ui.component.settings.BooleanItem
import app.revanced.manager.ui.component.settings.IntegerItem
import app.revanced.manager.ui.component.settings.SafeguardBooleanItem
import app.revanced.manager.ui.component.settings.SettingsListItem
import app.revanced.manager.ui.component.tooltip.TooltipIconButton
import app.revanced.manager.ui.viewmodel.AdvancedSettingsViewModel
import app.revanced.manager.util.toast
import app.revanced.manager.util.withHapticFeedback
@@ -243,11 +243,7 @@ private fun APIUrlDialog(currentUrl: String, defaultUrl: String, onSubmit: (Stri
onValueChange = { url = it },
label = { Text(stringResource(R.string.api_url)) },
trailingIcon = {
TooltipIconButton(
modifier = Modifier,
tooltip = stringResource(R.string.api_url_dialog_reset),
onClick = { url = defaultUrl }
) {
IconButton(onClick = { url = defaultUrl }) {
Icon(Icons.Outlined.Restore, stringResource(R.string.api_url_dialog_reset))
}
}

View File

@@ -9,7 +9,6 @@ import androidx.compose.foundation.lazy.items
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Delete
import androidx.compose.material.icons.outlined.Delete
import androidx.compose.material.icons.outlined.Search
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
@@ -41,10 +40,8 @@ import app.revanced.manager.ui.component.ExceptionViewerDialog
import app.revanced.manager.ui.component.GroupHeader
import app.revanced.manager.ui.component.LazyColumnWithScrollbar
import app.revanced.manager.ui.component.ConfirmDialog
import app.revanced.manager.ui.component.tooltip.TooltipWrap
import app.revanced.manager.ui.component.haptics.HapticCheckbox
import app.revanced.manager.ui.component.settings.SettingsListItem
import app.revanced.manager.ui.component.tooltip.TooltipIconButton
import app.revanced.manager.ui.viewmodel.DownloadsViewModel
import org.koin.androidx.compose.koinViewModel
import java.security.MessageDigest
@@ -78,10 +75,7 @@ fun DownloadsSettingsScreen(
onBackClick = onBackClick,
actions = {
if (viewModel.appSelection.isNotEmpty()) {
TooltipIconButton(
tooltip = stringResource(R.string.delete),
onClick = { showDeleteConfirmationDialog = true }
) {
IconButton(onClick = { showDeleteConfirmationDialog = true }) {
Icon(Icons.Default.Delete, stringResource(R.string.delete))
}
}

View File

@@ -87,7 +87,7 @@ class UpdateViewModel(
url(release.downloadUrl)
onDownload { bytesSentTotal, contentLength ->
downloadedSize = bytesSentTotal
totalSize = contentLength
totalSize = contentLength ?: 0
}
}
installUpdate()

View File

@@ -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<Int, Set<String>>
typealias Options = Map<Int, Map<String, Map<String, Any?>>>
@@ -141,9 +141,10 @@ suspend fun <T> Flow<Iterable<T>>.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 {

View File

@@ -3,4 +3,4 @@
<background android:drawable="@color/ic_launcher_background"/>
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
<monochrome android:drawable="@drawable/ic_launcher_foreground"/>
</adaptive-icon>
</adaptive-icon>

View File

@@ -6,11 +6,11 @@
# http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
org.gradle.jvmargs=-Xmx3072m -XX:MaxMetaspaceSize=1024m -Dfile.encoding=UTF-8
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
org.gradle.parallel=true
# AndroidX package structure to make it clearer which packages are bundled with the
# Android operating system, and which are packaged with your app's APK
# https://developer.android.com/topic/libraries/support-library/androidx-rn

View File

@@ -1,32 +1,32 @@
[versions]
ktx = "1.16.0"
ktx = "1.17.0"
material3 = "1.3.2"
ui-tooling = "1.8.1"
viewmodel-lifecycle = "2.9.0"
ui-tooling = "1.9.1"
viewmodel-lifecycle = "2.9.4"
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"
activity = "1.11.0"
appcompat = "1.7.1"
preferences-datastore = "1.1.7"
work-runtime = "2.10.4"
compose-bom = "2025.09.00"
navigation = "2.9.4"
accompanist = "0.37.3"
placeholder = "2.0.0"
reorderable = "2.5.1"
serialization = "1.9.0"
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.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.2.20"
android-gradle-plugin = "8.13.0"
dev-tools-gradle-plugin = "2.2.20-2.0.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

Binary file not shown.

View File

@@ -1,7 +1,7 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionSha256Sum=61ad310d3c7d3e5da131b76bbf22b5a4c0786e9d892dae8c1658d4b484de3caa
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14-bin.zip
distributionSha256Sum=a17ddd85a26b6a7f5ddb71ff8b05fc5104c0202c6e64782429790c933686c806
distributionUrl=https\://services.gradle.org/distributions/gradle-9.1.0-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME

2
gradlew vendored
View File

@@ -1,7 +1,7 @@
#!/bin/sh
#
# Copyright © 2015-2021 the original authors.
# Copyright © 2015 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@@ -22,5 +22,7 @@ dependencyResolutionManagement {
}
}
enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS")
rootProject.name = "revanced-manager"
include(":app", ":api")