diff --git a/app/src/main/java/app/revanced/manager/ui/component/AppScaffold.kt b/app/src/main/java/app/revanced/manager/ui/component/AppScaffold.kt index 7bd8c2761a..a29cd846d5 100644 --- a/app/src/main/java/app/revanced/manager/ui/component/AppScaffold.kt +++ b/app/src/main/java/app/revanced/manager/ui/component/AppScaffold.kt @@ -6,7 +6,6 @@ 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 @@ -22,6 +21,7 @@ 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,7 +69,11 @@ fun AppTopBar( scrollBehavior = scrollBehavior, navigationIcon = { if (onBackClick != null) { - IconButton(onClick = onBackClick) { + TooltipIconButton( + modifier = Modifier, + onClick = onBackClick, + tooltip = stringResource(R.string.back), + ) { backIcon() } } @@ -108,7 +112,11 @@ fun AppTopBar( scrollBehavior = scrollBehavior, navigationIcon = { if (onBackClick != null) { - IconButton(onClick = onBackClick) { + TooltipIconButton( + modifier = Modifier, + onClick = onBackClick, + tooltip = stringResource(R.string.back), + ) { backIcon() } } diff --git a/app/src/main/java/app/revanced/manager/ui/component/ArrowButton.kt b/app/src/main/java/app/revanced/manager/ui/component/ArrowButton.kt index aed7e0c7db..63dcffea3d 100644 --- a/app/src/main/java/app/revanced/manager/ui/component/ArrowButton.kt +++ b/app/src/main/java/app/revanced/manager/ui/component/ArrowButton.kt @@ -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,7 +27,11 @@ fun ArrowButton( ) onClick?.let { - IconButton(onClick = it) { + TooltipIconButton( + modifier = Modifier, + onClick = it, + tooltip = stringResource(description), + ) { Icon( imageVector = Icons.Filled.KeyboardArrowUp, contentDescription = stringResource(description), diff --git a/app/src/main/java/app/revanced/manager/ui/component/ExceptionViewerDialog.kt b/app/src/main/java/app/revanced/manager/ui/component/ExceptionViewerDialog.kt index 3925c48bcf..24bb92c108 100644 --- a/app/src/main/java/app/revanced/manager/ui/component/ExceptionViewerDialog.kt +++ b/app/src/main/java/app/revanced/manager/ui/component/ExceptionViewerDialog.kt @@ -9,7 +9,6 @@ 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 @@ -18,6 +17,7 @@ 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,7 +39,8 @@ fun ExceptionViewerDialog(text: String, onDismiss: () -> Unit) { ) }, actions = { - IconButton( + TooltipIconButton( + modifier = Modifier, onClick = { val sendIntent: Intent = Intent().apply { action = Intent.ACTION_SEND @@ -52,7 +53,8 @@ fun ExceptionViewerDialog(text: String, onDismiss: () -> Unit) { val shareIntent = Intent.createChooser(sendIntent, null) context.startActivity(shareIntent) - } + }, + tooltip = stringResource(R.string.share), ) { Icon( Icons.Outlined.Share, diff --git a/app/src/main/java/app/revanced/manager/ui/component/NotificationCard.kt b/app/src/main/java/app/revanced/manager/ui/component/NotificationCard.kt index 0357a18f8e..b2976dcac2 100644 --- a/app/src/main/java/app/revanced/manager/ui/component/NotificationCard.kt +++ b/app/src/main/java/app/revanced/manager/ui/component/NotificationCard.kt @@ -14,7 +14,6 @@ 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 @@ -25,6 +24,7 @@ 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,7 +138,11 @@ fun NotificationCard( ) } if (onDismiss != null) { - IconButton(onClick = onDismiss) { + TooltipIconButton( + modifier = modifier, + onClick = onDismiss, + tooltip = stringResource(R.string.close), + ) { Icon( imageVector = Icons.Outlined.Close, contentDescription = stringResource(R.string.close), diff --git a/app/src/main/java/app/revanced/manager/ui/component/PasswordField.kt b/app/src/main/java/app/revanced/manager/ui/component/PasswordField.kt index ee64c05ba0..1ad0caa636 100644 --- a/app/src/main/java/app/revanced/manager/ui/component/PasswordField.kt +++ b/app/src/main/java/app/revanced/manager/ui/component/PasswordField.kt @@ -5,7 +5,6 @@ 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 @@ -19,6 +18,7 @@ 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,9 +33,15 @@ fun PasswordField(modifier: Modifier = Modifier, value: String, onValueChange: ( label = label, modifier = modifier, trailingIcon = { - IconButton(onClick = { - visible = !visible - }) { + TooltipIconButton( + modifier = Modifier, + onClick = { + visible = !visible + }, + tooltip = if (visible) stringResource(R.string.show_password_field) else stringResource( + R.string.hide_password_field + ), + ) { 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 } diff --git a/app/src/main/java/app/revanced/manager/ui/component/SearchView.kt b/app/src/main/java/app/revanced/manager/ui/component/SearchView.kt index 04b5b58949..fd76c6a726 100644 --- a/app/src/main/java/app/revanced/manager/ui/component/SearchView.kt +++ b/app/src/main/java/app/revanced/manager/ui/component/SearchView.kt @@ -5,7 +5,6 @@ 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 @@ -19,6 +18,7 @@ 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,7 +48,11 @@ fun SearchView( onExpandedChange = onActiveChange, placeholder = placeholder, leadingIcon = { - IconButton(onClick = { onActiveChange(false) }) { + TooltipIconButton( + modifier = Modifier, + tooltip = stringResource(R.string.back), + onClick = { onActiveChange(false) } + ) { Icon( Icons.AutoMirrored.Filled.ArrowBack, stringResource(R.string.back) diff --git a/app/src/main/java/app/revanced/manager/ui/component/bundle/BundleInformationDialog.kt b/app/src/main/java/app/revanced/manager/ui/component/bundle/BundleInformationDialog.kt index 20d2d7c4ef..f72a1bbf9c 100644 --- a/app/src/main/java/app/revanced/manager/ui/component/bundle/BundleInformationDialog.kt +++ b/app/src/main/java/app/revanced/manager/ui/component/bundle/BundleInformationDialog.kt @@ -22,6 +22,7 @@ import app.revanced.manager.domain.bundles.PatchBundleSource.Extensions.isDefaul import app.revanced.manager.domain.bundles.PatchBundleSource.Extensions.nameState import app.revanced.manager.ui.component.ExceptionViewerDialog import app.revanced.manager.ui.component.FullscreenDialog +import app.revanced.manager.ui.component.tooltip.TooltipIconButton import kotlinx.coroutines.launch import org.koin.compose.koinInject @@ -73,7 +74,11 @@ fun BundleInformationDialog( }, actions = { if (!bundle.isDefault) { - IconButton(onClick = onDeleteRequest) { + TooltipIconButton( + modifier = Modifier, + onClick = onDeleteRequest, + tooltip = stringResource(R.string.delete), + ) { Icon( Icons.Outlined.DeleteOutline, stringResource(R.string.delete) @@ -81,7 +86,11 @@ fun BundleInformationDialog( } } if (!isLocal && hasNetwork) { - IconButton(onClick = onUpdate) { + TooltipIconButton( + modifier = Modifier, + onClick = onUpdate, + tooltip = stringResource(R.string.refresh), + ) { Icon( Icons.Outlined.Update, stringResource(R.string.refresh) diff --git a/app/src/main/java/app/revanced/manager/ui/component/bundle/BundleTopBar.kt b/app/src/main/java/app/revanced/manager/ui/component/bundle/BundleTopBar.kt index 543d2d3465..da4fa2d1c1 100644 --- a/app/src/main/java/app/revanced/manager/ui/component/bundle/BundleTopBar.kt +++ b/app/src/main/java/app/revanced/manager/ui/component/bundle/BundleTopBar.kt @@ -2,7 +2,6 @@ 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 @@ -10,7 +9,11 @@ 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 @@ -33,7 +36,11 @@ fun BundleTopBar( scrollBehavior = scrollBehavior, navigationIcon = { if (onBackClick != null) { - IconButton(onClick = onBackClick) { + TooltipIconButton( + modifier = Modifier, + tooltip = stringResource(R.string.back), + onClick = onBackClick + ) { backIcon() } } diff --git a/app/src/main/java/app/revanced/manager/ui/component/bundle/ImportBundleDialog.kt b/app/src/main/java/app/revanced/manager/ui/component/bundle/ImportBundleDialog.kt index 1a05d8662a..cf5d748cf3 100644 --- a/app/src/main/java/app/revanced/manager/ui/component/bundle/ImportBundleDialog.kt +++ b/app/src/main/java/app/revanced/manager/ui/component/bundle/ImportBundleDialog.kt @@ -189,6 +189,7 @@ 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) } diff --git a/app/src/main/java/app/revanced/manager/ui/component/haptics/HapticSmallFloatingActionButton.kt b/app/src/main/java/app/revanced/manager/ui/component/haptics/HapticSmallFloatingActionButton.kt new file mode 100644 index 0000000000..36b9751166 --- /dev/null +++ b/app/src/main/java/app/revanced/manager/ui/component/haptics/HapticSmallFloatingActionButton.kt @@ -0,0 +1,38 @@ +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 + ) +} diff --git a/app/src/main/java/app/revanced/manager/ui/component/patches/OptionFields.kt b/app/src/main/java/app/revanced/manager/ui/component/patches/OptionFields.kt index eaacc38cf7..4322fb34cd 100644 --- a/app/src/main/java/app/revanced/manager/ui/component/patches/OptionFields.kt +++ b/app/src/main/java/app/revanced/manager/ui/component/patches/OptionFields.kt @@ -14,7 +14,6 @@ import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.foundation.lazy.LazyListItemInfo import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.foundation.lazy.rememberLazyListState @@ -68,19 +67,18 @@ 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 import app.revanced.manager.util.saver.snapshotStateSetSaver import app.revanced.manager.util.toast import app.revanced.manager.util.transparentListItemColors -import kotlinx.coroutines.CoroutineScope import kotlinx.parcelize.Parcelize import org.koin.compose.koinInject import org.koin.core.component.KoinComponent import org.koin.core.component.get import sh.calvin.reorderable.ReorderableItem -import sh.calvin.reorderable.rememberReorderableLazyColumnState import sh.calvin.reorderable.rememberReorderableLazyListState import java.io.Serializable import kotlin.random.Random @@ -113,7 +111,11 @@ private interface OptionEditor { @Composable fun ListItemTrailingContent(scope: OptionEditorScope) { - IconButton(onClick = { clickAction(scope) }) { + TooltipIconButton( + modifier = Modifier, + tooltip = stringResource(R.string.edit), + onClick = { clickAction(scope) } + ) { Icon(Icons.Outlined.Edit, stringResource(R.string.edit)) } } @@ -249,13 +251,12 @@ private object StringOptionEditor : OptionEditor { }, trailingIcon = { var showDropdownMenu by rememberSaveable { mutableStateOf(false) } - IconButton( + TooltipIconButton( + modifier = Modifier, + tooltip = stringResource(R.string.string_option_menu_description), onClick = { showDropdownMenu = true } ) { - Icon( - Icons.Outlined.MoreVert, - stringResource(R.string.string_option_menu_description) - ) + Icon(Icons.Outlined.MoreVert, stringResource(R.string.string_option_menu_description)) } DropdownMenu( @@ -551,7 +552,9 @@ private class ListOptionEditor(private val elementEditor: Opti }, actions = { if (deleteMode) { - IconButton( + TooltipIconButton( + modifier = Modifier, + tooltip = stringResource(R.string.select_deselect_all), onClick = { if (items.size == deletionTargets.size) deletionTargets.clear() else deletionTargets.addAll(items.map { it.key }) @@ -562,7 +565,9 @@ private class ListOptionEditor(private val elementEditor: Opti stringResource(R.string.select_deselect_all) ) } - IconButton( + TooltipIconButton( + modifier = Modifier, + tooltip = stringResource(R.string.delete), onClick = { items.removeIf { it.key in deletionTargets } deletionTargets.clear() @@ -575,8 +580,15 @@ private class ListOptionEditor(private val elementEditor: Opti ) } } else { - IconButton(onClick = items::clear) { - Icon(Icons.Outlined.Restore, stringResource(R.string.reset)) + TooltipIconButton( + modifier = Modifier, + tooltip = stringResource(R.string.reset), + onClick = items::clear + ) { + Icon( + Icons.Outlined.Restore, + stringResource(R.string.reset) + ) } } } @@ -643,9 +655,10 @@ private class ListOptionEditor(private val elementEditor: Opti ), tonalElevation = if (deleteMode && item.key in deletionTargets) 8.dp else 0.dp, leadingContent = { - IconButton( + TooltipIconButton( modifier = Modifier.draggableHandle(interactionSource = interactionSource), - onClick = {}, + tooltip = stringResource(R.string.delete), + onClick = { } ) { Icon( Icons.Filled.DragHandle, diff --git a/app/src/main/java/app/revanced/manager/ui/component/settings/IntegerItem.kt b/app/src/main/java/app/revanced/manager/ui/component/settings/IntegerItem.kt index 56553b28cb..cdd967b82c 100644 --- a/app/src/main/java/app/revanced/manager/ui/component/settings/IntegerItem.kt +++ b/app/src/main/java/app/revanced/manager/ui/component/settings/IntegerItem.kt @@ -5,7 +5,6 @@ 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 @@ -17,6 +16,7 @@ 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,10 +65,14 @@ fun IntegerItem( headlineContent = stringResource(headline), supportingContent = stringResource(description), trailingContent = { - IconButton(onClick = { dialogOpen = true }) { + TooltipIconButton( + modifier = modifier, + onClick = { dialogOpen = true }, + tooltip = stringResource(R.string.edit), + ) { Icon( - Icons.Outlined.Edit, - contentDescription = stringResource(R.string.edit) + imageVector = Icons.Outlined.Edit, + contentDescription = stringResource(R.string.edit), ) } } diff --git a/app/src/main/java/app/revanced/manager/ui/component/tooltip/TooltipFloatingActionButton.kt b/app/src/main/java/app/revanced/manager/ui/component/tooltip/TooltipFloatingActionButton.kt new file mode 100644 index 0000000000..6ad081bf14 --- /dev/null +++ b/app/src/main/java/app/revanced/manager/ui/component/tooltip/TooltipFloatingActionButton.kt @@ -0,0 +1,109 @@ +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( + modifier = modifier, + 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( + modifier = modifier, + 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, + ) + } +} diff --git a/app/src/main/java/app/revanced/manager/ui/component/tooltip/TooltipIconButton.kt b/app/src/main/java/app/revanced/manager/ui/component/tooltip/TooltipIconButton.kt new file mode 100644 index 0000000000..37ac7016c1 --- /dev/null +++ b/app/src/main/java/app/revanced/manager/ui/component/tooltip/TooltipIconButton.kt @@ -0,0 +1,98 @@ +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( + modifier = modifier, + 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( + modifier = modifier, + tooltip = tooltip, + positionProvider = positionProvider, + haptic = haptic, + hapticFeedbackType = hapticFeedbackType, + ) { + IconButton( + onClick = onClick, + modifier = modifier, + enabled = enabled, + colors = colors, + interactionSource = interactionSource, + content = content, + ) + } +} diff --git a/app/src/main/java/app/revanced/manager/ui/component/tooltip/TooltipSmallFloatingActionButton.kt b/app/src/main/java/app/revanced/manager/ui/component/tooltip/TooltipSmallFloatingActionButton.kt new file mode 100644 index 0000000000..99d5bbd3a5 --- /dev/null +++ b/app/src/main/java/app/revanced/manager/ui/component/tooltip/TooltipSmallFloatingActionButton.kt @@ -0,0 +1,109 @@ +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( + modifier = modifier, + 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( + modifier = modifier, + 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, + ) + } +} diff --git a/app/src/main/java/app/revanced/manager/ui/component/tooltip/TooltipWrap.kt b/app/src/main/java/app/revanced/manager/ui/component/tooltip/TooltipWrap.kt new file mode 100644 index 0000000000..53a85fa2cb --- /dev/null +++ b/app/src/main/java/app/revanced/manager/ui/component/tooltip/TooltipWrap.kt @@ -0,0 +1,96 @@ +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, + 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, + @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, + ) +} diff --git a/app/src/main/java/app/revanced/manager/ui/screen/AppSelectorScreen.kt b/app/src/main/java/app/revanced/manager/ui/screen/AppSelectorScreen.kt index 299463dfbb..9c28870d21 100644 --- a/app/src/main/java/app/revanced/manager/ui/screen/AppSelectorScreen.kt +++ b/app/src/main/java/app/revanced/manager/ui/screen/AppSelectorScreen.kt @@ -16,7 +16,6 @@ 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 @@ -44,6 +43,7 @@ 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,8 +162,15 @@ fun AppSelectorScreen( scrollBehavior = scrollBehavior, onBackClick = onBackClick, actions = { - IconButton(onClick = { search = true }) { - Icon(Icons.Outlined.Search, stringResource(R.string.search)) + TooltipIconButton( + modifier = Modifier, + tooltip = stringResource(R.string.search_patches), + onClick = { search = true } + ) { + Icon( + Icons.Outlined.Search, + stringResource(R.string.search) + ) } } ) diff --git a/app/src/main/java/app/revanced/manager/ui/screen/DashboardScreen.kt b/app/src/main/java/app/revanced/manager/ui/screen/DashboardScreen.kt index 03eff51f19..34be99b073 100644 --- a/app/src/main/java/app/revanced/manager/ui/screen/DashboardScreen.kt +++ b/app/src/main/java/app/revanced/manager/ui/screen/DashboardScreen.kt @@ -62,12 +62,13 @@ import app.revanced.manager.ui.component.AlertDialogExtended import app.revanced.manager.ui.component.AppTopBar import app.revanced.manager.ui.component.AutoUpdatesDialog import app.revanced.manager.ui.component.AvailableUpdateDialog -import app.revanced.manager.ui.component.NotificationCard import app.revanced.manager.ui.component.ConfirmDialog +import app.revanced.manager.ui.component.NotificationCard 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 @@ -183,21 +184,25 @@ fun DashboardScreen( ) }, actions = { - IconButton( + TooltipIconButton( + modifier = Modifier, onClick = { showDeleteConfirmationDialog = true - } + }, + tooltip = stringResource(R.string.delete), ) { Icon( Icons.Outlined.DeleteOutline, stringResource(R.string.delete) ) } - IconButton( + TooltipIconButton( + modifier = Modifier, onClick = { vm.selectedSources.forEach { vm.update(it) } vm.cancelSourceSelection() - } + }, + tooltip = stringResource(R.string.refresh), ) { Icon( Icons.Outlined.Refresh, @@ -211,8 +216,10 @@ fun DashboardScreen( title = stringResource(R.string.app_name), actions = { if (!vm.updatedManagerVersion.isNullOrEmpty()) { - IconButton( + TooltipIconButton( + modifier = Modifier, onClick = onUpdateClick, + tooltip = stringResource(R.string.update), ) { BadgedBox( badge = { @@ -223,8 +230,18 @@ fun DashboardScreen( } } } - IconButton(onClick = onSettingsClick) { - Icon(Icons.Outlined.Settings, stringResource(R.string.settings)) + TooltipIconButton( + modifier = Modifier, + onClick = onSettingsClick, + tooltip = stringResource(R.string.settings), + ) { + BadgedBox( + badge = { + Badge(modifier = Modifier.size(6.dp)) + } + ) { + Icon(Icons.Outlined.Settings, stringResource(R.string.settings)) + } } }, applyContainerColor = true @@ -232,7 +249,9 @@ fun DashboardScreen( } }, floatingActionButton = { - HapticFloatingActionButton( + TooltipFloatingActionButton( + modifier = Modifier, + tooltip = stringResource(R.string.add), onClick = { vm.cancelSourceSelection() @@ -245,11 +264,11 @@ fun DashboardScreen( DashboardPage.BUNDLES.ordinal ) } - return@HapticFloatingActionButton + return@TooltipFloatingActionButton } if (vm.android11BugActive) { showAndroid11Dialog = true - return@HapticFloatingActionButton + return@TooltipFloatingActionButton } onAppSelectorClick() diff --git a/app/src/main/java/app/revanced/manager/ui/screen/PatcherScreen.kt b/app/src/main/java/app/revanced/manager/ui/screen/PatcherScreen.kt index af09bfa593..52067dbc27 100644 --- a/app/src/main/java/app/revanced/manager/ui/screen/PatcherScreen.kt +++ b/app/src/main/java/app/revanced/manager/ui/screen/PatcherScreen.kt @@ -25,7 +25,6 @@ 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 @@ -51,6 +50,7 @@ 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,15 +164,19 @@ fun PatcherScreen( bottomBar = { BottomAppBar( actions = { - IconButton( + TooltipIconButton( + modifier = Modifier, onClick = { exportApkLauncher.launch("${viewModel.packageName}_${viewModel.version}_revanced_patched.apk") }, - enabled = patcherSucceeded == true + enabled = patcherSucceeded == true, + tooltip = stringResource(R.string.save_apk), ) { Icon(Icons.Outlined.Save, stringResource(id = R.string.save_apk)) } - IconButton( + TooltipIconButton( + modifier = Modifier, onClick = { viewModel.exportLogs(context) }, - enabled = patcherSucceeded != null + enabled = patcherSucceeded != null, + tooltip = stringResource(R.string.save_logs), ) { Icon(Icons.Outlined.PostAdd, stringResource(id = R.string.save_logs)) } diff --git a/app/src/main/java/app/revanced/manager/ui/screen/PatchesSelectorScreen.kt b/app/src/main/java/app/revanced/manager/ui/screen/PatchesSelectorScreen.kt index 2bb29e4a3a..af908c6d70 100644 --- a/app/src/main/java/app/revanced/manager/ui/screen/PatchesSelectorScreen.kt +++ b/app/src/main/java/app/revanced/manager/ui/screen/PatchesSelectorScreen.kt @@ -41,7 +41,6 @@ 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 @@ -73,6 +72,9 @@ 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.viewmodel.PatchesSelectorViewModel import app.revanced.manager.ui.viewmodel.PatchesSelectorViewModel.Companion.SHOW_INCOMPATIBLE import app.revanced.manager.ui.viewmodel.PatchesSelectorViewModel.Companion.SHOW_UNIVERSAL @@ -259,14 +261,16 @@ fun PatchesSelectorScreen( animationSpec = tween(durationMillis = 400, easing = EaseInOut), label = "SearchBar back button" ) - IconButton( + TooltipIconButton( + modifier = Modifier.rotate(rotation), onClick = { if (searchExpanded) { setSearchExpanded(false) } else { onBackClick() } - } + }, + tooltip = stringResource(R.string.back), ) { Icon( modifier = Modifier.rotate(rotation), @@ -282,9 +286,11 @@ fun PatchesSelectorScreen( transitionSpec = { fadeIn() togetherWith fadeOut() } ) { searchExpanded -> if (searchExpanded) { - IconButton( + TooltipIconButton( + modifier = Modifier, onClick = { setQuery("") }, - enabled = query.isNotEmpty() + enabled = query.isNotEmpty(), + tooltip = stringResource(R.string.clear), ) { Icon( imageVector = Icons.Filled.Close, @@ -292,7 +298,11 @@ fun PatchesSelectorScreen( ) } } else { - IconButton(onClick = { showBottomSheet = true }) { + TooltipIconButton( + modifier = Modifier, + onClick = { showBottomSheet = true }, + tooltip = stringResource(R.string.more), + ) { Icon( imageVector = Icons.Outlined.FilterList, contentDescription = stringResource(R.string.more) @@ -354,7 +364,20 @@ fun PatchesSelectorScreen( horizontalAlignment = Alignment.End, verticalArrangement = Arrangement.spacedBy(4.dp) ) { - SmallFloatingActionButton( + TooltipSmallFloatingActionButton( + modifier = Modifier, + tooltip = stringResource(R.string.more), + onClick = { showBottomSheet = true }, + containerColor = MaterialTheme.colorScheme.tertiaryContainer + ) { + Icon( + imageVector = Icons.Outlined.FilterList, + contentDescription = stringResource(R.string.more) + ) + } + TooltipSmallFloatingActionButton( + modifier = Modifier, + tooltip = stringResource(R.string.reset), onClick = viewModel::reset, containerColor = MaterialTheme.colorScheme.tertiaryContainer ) { @@ -517,6 +540,7 @@ 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) } @@ -540,7 +564,11 @@ fun ListHeader( }, trailingContent = onHelpClick?.let { { - IconButton(onClick = it) { + TooltipIconButton( + modifier = Modifier, + tooltip = stringResource(R.string.help), + onClick = it + ) { Icon( Icons.AutoMirrored.Outlined.HelpOutline, stringResource(R.string.help) @@ -619,7 +647,11 @@ private fun OptionsDialog( title = patch.name, onBackClick = onDismissRequest, actions = { - IconButton(onClick = reset) { + TooltipIconButton( + modifier = Modifier, + tooltip = stringResource(R.string.reset), + onClick = reset + ) { Icon(Icons.Outlined.Restore, stringResource(R.string.reset)) } } diff --git a/app/src/main/java/app/revanced/manager/ui/screen/settings/AboutSettingsScreen.kt b/app/src/main/java/app/revanced/manager/ui/screen/settings/AboutSettingsScreen.kt index 80fc6636ea..e096ae2e4d 100644 --- a/app/src/main/java/app/revanced/manager/ui/screen/settings/AboutSettingsScreen.kt +++ b/app/src/main/java/app/revanced/manager/ui/screen/settings/AboutSettingsScreen.kt @@ -19,7 +19,6 @@ 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 @@ -50,6 +49,7 @@ 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,9 +252,10 @@ fun AboutSettingsScreen( horizontalArrangement = Arrangement.spacedBy(8.dp, Alignment.CenterHorizontally) ) { socialButtons.forEach { (icon, text, onClick) -> - IconButton( - onClick = onClick, + TooltipIconButton( modifier = Modifier.padding(end = 8.dp), + tooltip = text, + onClick = onClick ) { Icon( icon, diff --git a/app/src/main/java/app/revanced/manager/ui/screen/settings/AdvancedSettingsScreen.kt b/app/src/main/java/app/revanced/manager/ui/screen/settings/AdvancedSettingsScreen.kt index 39d7e9b14f..e70faa874c 100644 --- a/app/src/main/java/app/revanced/manager/ui/screen/settings/AdvancedSettingsScreen.kt +++ b/app/src/main/java/app/revanced/manager/ui/screen/settings/AdvancedSettingsScreen.kt @@ -21,7 +21,6 @@ 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 @@ -52,6 +51,7 @@ 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,7 +243,11 @@ private fun APIUrlDialog(currentUrl: String, defaultUrl: String, onSubmit: (Stri onValueChange = { url = it }, label = { Text(stringResource(R.string.api_url)) }, trailingIcon = { - IconButton(onClick = { url = defaultUrl }) { + TooltipIconButton( + modifier = Modifier, + tooltip = stringResource(R.string.api_url_dialog_reset), + onClick = { url = defaultUrl } + ) { Icon(Icons.Outlined.Restore, stringResource(R.string.api_url_dialog_reset)) } } diff --git a/app/src/main/java/app/revanced/manager/ui/screen/settings/DownloadsSettingsScreen.kt b/app/src/main/java/app/revanced/manager/ui/screen/settings/DownloadsSettingsScreen.kt index 3d57ee505c..bbf31a4a45 100644 --- a/app/src/main/java/app/revanced/manager/ui/screen/settings/DownloadsSettingsScreen.kt +++ b/app/src/main/java/app/revanced/manager/ui/screen/settings/DownloadsSettingsScreen.kt @@ -10,6 +10,7 @@ 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 @@ -45,8 +46,10 @@ 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 @@ -81,7 +84,11 @@ fun DownloadsSettingsScreen( onBackClick = onBackClick, actions = { if (viewModel.appSelection.isNotEmpty()) { - IconButton(onClick = { showDeleteConfirmationDialog = true }) { + TooltipIconButton( + modifier = Modifier, + tooltip = stringResource(R.string.delete), + onClick = { showDeleteConfirmationDialog = true } + ) { Icon(Icons.Default.Delete, stringResource(R.string.delete)) } } diff --git a/app/src/main/res/mipmap-anydpi/ic_launcher.xml b/app/src/main/res/mipmap-anydpi/ic_launcher.xml index ef49c99170..0b0d585e42 100644 --- a/app/src/main/res/mipmap-anydpi/ic_launcher.xml +++ b/app/src/main/res/mipmap-anydpi/ic_launcher.xml @@ -3,4 +3,4 @@ - \ No newline at end of file +