diff --git a/app/src/main/java/com/sameerasw/essentials/data/repository/SettingsRepository.kt b/app/src/main/java/com/sameerasw/essentials/data/repository/SettingsRepository.kt index 422a8c13b..a13899bfd 100644 --- a/app/src/main/java/com/sameerasw/essentials/data/repository/SettingsRepository.kt +++ b/app/src/main/java/com/sameerasw/essentials/data/repository/SettingsRepository.kt @@ -439,6 +439,9 @@ class SettingsRepository( const val KEY_PIXEL_SEARCH_RESULT_FILES = "pixel_search_result_files" const val KEY_PIXEL_SEARCH_BUBBLES_WEB = "pixel_search_bubbles_web" const val KEY_PIXEL_SEARCH_ENGINE = "pixel_search_engine" + const val KEY_PIXEL_SEARCH_BLUR = "pixel_search_blur_enabled" + const val KEY_PIXEL_SEARCH_WALLPAPER_BG = "pixel_search_wallpaper_bg" + const val KEY_PIXEL_SEARCH_BLUR_RADIUS = "pixel_search_blur_radius" const val KEY_AUTO_ACCESSIBILITY_ENABLED = "auto_accessibility_enabled" const val KEY_USE_BLUR = "use_blur" const val KEY_USE_RIPPLE = "use_ripple" @@ -3702,6 +3705,15 @@ class SettingsRepository( fun getPixelSearchEngine(): String = getString(KEY_PIXEL_SEARCH_ENGINE, "Google") ?: "Google" fun setPixelSearchEngine(engine: String) = putString(KEY_PIXEL_SEARCH_ENGINE, engine) + fun isPixelSearchBlurEnabled(): Boolean = getBoolean(KEY_PIXEL_SEARCH_BLUR, true) + fun setPixelSearchBlurEnabled(enabled: Boolean) = putBoolean(KEY_PIXEL_SEARCH_BLUR, enabled) + + fun isPixelSearchWallpaperBackgroundEnabled(): Boolean = getBoolean(KEY_PIXEL_SEARCH_WALLPAPER_BG, true) + fun setPixelSearchWallpaperBackgroundEnabled(enabled: Boolean) = putBoolean(KEY_PIXEL_SEARCH_WALLPAPER_BG, enabled) + + fun getPixelSearchBlurRadius(): Float = getFloat(KEY_PIXEL_SEARCH_BLUR_RADIUS, 60f) + fun setPixelSearchBlurRadius(radius: Float) = putFloat(KEY_PIXEL_SEARCH_BLUR_RADIUS, radius) + fun isBubbleWebFullscreen(): Boolean = getBoolean(KEY_BUBBLE_WEB_FULLSCREEN, false) fun setBubbleWebFullscreen(fullscreen: Boolean) = putBoolean(KEY_BUBBLE_WEB_FULLSCREEN, fullscreen) diff --git a/app/src/main/java/com/sameerasw/essentials/ui/activities/PixelSearchResultsActivity.kt b/app/src/main/java/com/sameerasw/essentials/ui/activities/PixelSearchResultsActivity.kt index aab20b7d8..e7908b67a 100644 --- a/app/src/main/java/com/sameerasw/essentials/ui/activities/PixelSearchResultsActivity.kt +++ b/app/src/main/java/com/sameerasw/essentials/ui/activities/PixelSearchResultsActivity.kt @@ -14,6 +14,8 @@ import android.content.Context import android.content.Intent import android.content.pm.PackageManager import android.net.Uri +import android.graphics.PixelFormat +import android.graphics.drawable.ColorDrawable import android.os.Build import android.os.Bundle import android.provider.ContactsContract @@ -155,6 +157,8 @@ class PixelSearchResultsActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { WindowCompat.setDecorFitsSystemWindows(window, false) super.onCreate(savedInstanceState) + window.setBackgroundDrawable(ColorDrawable(android.graphics.Color.TRANSPARENT)) + window.setFormat(PixelFormat.TRANSLUCENT) enableEdgeToEdge( statusBarStyle = SystemBarStyle.auto( android.graphics.Color.TRANSPARENT, @@ -170,18 +174,7 @@ class PixelSearchResultsActivity : ComponentActivity() { window.isNavigationBarContrastEnforced = false } - val isSystemDark = (resources.configuration.uiMode and android.content.res.Configuration.UI_MODE_NIGHT_MASK) == android.content.res.Configuration.UI_MODE_NIGHT_YES - val dimAmount = if (isSystemDark) 0.2f else 0.08f - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { - window.addFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND) - window.attributes.blurBehindRadius = 60 - window.addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND) - window.setDimAmount(dimAmount) - } else { - window.addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND) - window.setDimAmount(if (isSystemDark) 0.35f else 0.15f) - } + applyBlur() val initialQuery = intent.getStringExtra(SearchManager.QUERY) ?: intent.getStringExtra("query") @@ -200,9 +193,48 @@ class PixelSearchResultsActivity : ComponentActivity() { } } + override fun onResume() { + super.onResume() + applyBlur() + } + override fun onNewIntent(intent: Intent) { super.onNewIntent(intent) setIntent(intent) + applyBlur() + } + + private fun applyBlur() { + val isSystemDark = (resources.configuration.uiMode and android.content.res.Configuration.UI_MODE_NIGHT_MASK) == android.content.res.Configuration.UI_MODE_NIGHT_YES + val dimAmount = if (isSystemDark) 0.2f else 0.08f + + val repository = SettingsRepository(this) + val isBlurEnabled = repository.isPixelSearchBlurEnabled() + val isWallpaperBg = repository.isPixelSearchWallpaperBackgroundEnabled() + val blurRadius = repository.getPixelSearchBlurRadius().toInt().coerceIn(1, 300) + + if (isWallpaperBg) { + window.addFlags(WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER) + } else { + window.clearFlags(WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER) + } + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + val params = window.attributes + if (isBlurEnabled) { + window.addFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND) + params.blurBehindRadius = blurRadius + } else { + window.clearFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND) + params.blurBehindRadius = 0 + } + window.attributes = params + window.addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND) + window.setDimAmount(dimAmount) + } else { + window.addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND) + window.setDimAmount(if (isSystemDark) 0.35f else 0.15f) + } } } @@ -637,7 +669,21 @@ fun PixelSearchResultsScreen( } } - val scrimColor = MaterialTheme.colorScheme.surfaceContainer.copy(alpha = 0.55f) + val isWallpaperBg = remember { repository.isPixelSearchWallpaperBackgroundEnabled() } + val isBlurEffective = remember(context) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + val windowManager = context.getSystemService(WindowManager::class.java) + repository.isPixelSearchBlurEnabled() && (windowManager?.isCrossWindowBlurEnabled == true) + } else { + false + } + } + val scrimAlpha = when { + !isBlurEffective -> 0.85f + !isWallpaperBg -> 0.45f + else -> 0.55f + } + val scrimColor = MaterialTheme.colorScheme.surfaceContainer.copy(alpha = scrimAlpha) Box( modifier = Modifier diff --git a/app/src/main/java/com/sameerasw/essentials/ui/activities/PixelSearchbarSettingsActivity.kt b/app/src/main/java/com/sameerasw/essentials/ui/activities/PixelSearchbarSettingsActivity.kt index 182ed120a..0ae050a25 100644 --- a/app/src/main/java/com/sameerasw/essentials/ui/activities/PixelSearchbarSettingsActivity.kt +++ b/app/src/main/java/com/sameerasw/essentials/ui/activities/PixelSearchbarSettingsActivity.kt @@ -87,6 +87,7 @@ import com.sameerasw.essentials.ui.core.containers.RoundedCardContainer import com.sameerasw.essentials.ui.core.pickers.SegmentedPicker import com.sameerasw.essentials.ui.core.sheets.FeatureHelpBottomSheet import com.sameerasw.essentials.ui.core.sheets.PermissionsBottomSheet +import com.sameerasw.essentials.ui.core.sheets.PixelSearchBlurOptionsBottomSheet import com.sameerasw.essentials.ui.modifiers.BlurDirection import com.sameerasw.essentials.ui.modifiers.progressiveBlur import com.sameerasw.essentials.ui.modifiers.scrollMotionBlur @@ -324,6 +325,7 @@ fun PixelSearchbarSettingsUI( var pendingWidgetId by remember { mutableStateOf(AppWidgetManager.INVALID_APPWIDGET_ID) } var showWidgetPicker by remember { mutableStateOf(false) } var isWidgetUnsupported by remember { mutableStateOf(false) } + var showBlurOptionsSheet by remember { mutableStateOf(false) } LaunchedEffect(currentType) { while (currentType == "widget") { @@ -988,11 +990,33 @@ fun PixelSearchbarSettingsUI( } } } + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + val blurEnabled = viewModel.pixelSearchBlur.value + IconToggleItem( + iconRes = R.drawable.rounded_blur_on_24, + title = stringResource(R.string.pref_pixel_search_blur_title), + description = stringResource(R.string.pref_pixel_search_blur_desc), + isChecked = blurEnabled, + onCheckedChange = { checked -> + HapticUtil.performVirtualKeyHaptic(view) + viewModel.setPixelSearchBlurEnabled(checked) + }, + onSettingsClick = { showBlurOptionsSheet = true }, + ) + } } } } } + if (showBlurOptionsSheet) { + PixelSearchBlurOptionsBottomSheet( + viewModel = viewModel, + onDismissRequest = { showBlurOptionsSheet = false }, + ) + } + if (showPermissionSheet) { val permissionItem = remember(context, viewModel) { diff --git a/app/src/main/java/com/sameerasw/essentials/ui/core/sheets/PixelSearchBlurOptionsBottomSheet.kt b/app/src/main/java/com/sameerasw/essentials/ui/core/sheets/PixelSearchBlurOptionsBottomSheet.kt new file mode 100644 index 000000000..863c9c085 --- /dev/null +++ b/app/src/main/java/com/sameerasw/essentials/ui/core/sheets/PixelSearchBlurOptionsBottomSheet.kt @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2026 sameerasw.com + * License: MIT License + * + * Feature Module: UI Core Sheets + * File: PixelSearchBlurOptionsBottomSheet.kt + * Description: Bottom sheet for configuring Pixel Search blur and wallpaper background options. + */ + +package com.sameerasw.essentials.ui.core.sheets + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalView +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp +import com.sameerasw.essentials.R +import com.sameerasw.essentials.ui.components.sliders.ConfigSliderItem +import com.sameerasw.essentials.ui.core.cards.IconToggleItem +import com.sameerasw.essentials.ui.core.containers.RoundedCardContainer +import com.sameerasw.essentials.utils.HapticUtil +import com.sameerasw.essentials.viewmodels.MainViewModel + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun PixelSearchBlurOptionsBottomSheet( + viewModel: MainViewModel, + onDismissRequest: () -> Unit, +) { + val view = LocalView.current + + EssentialsBottomSheet(onDismissRequest = onDismissRequest) { + Column( + modifier = + Modifier + .fillMaxWidth() + .padding(horizontal = 16.dp) + .padding(bottom = 24.dp), + verticalArrangement = Arrangement.spacedBy(16.dp), + ) { + Text( + text = stringResource(R.string.pixel_search_blur_options_title), + style = MaterialTheme.typography.titleLarge, + color = MaterialTheme.colorScheme.onSurface, + modifier = Modifier.padding(start = 8.dp, bottom = 4.dp), + ) + + RoundedCardContainer(spacing = 2.dp, cornerRadius = 24.dp) { + IconToggleItem( + iconRes = R.drawable.rounded_wallpaper_24, + title = stringResource(R.string.pref_pixel_search_wallpaper_bg_title), + isChecked = viewModel.pixelSearchWallpaperBackground.value, + onCheckedChange = { checked -> + HapticUtil.performVirtualKeyHaptic(view) + viewModel.setPixelSearchWallpaperBackgroundEnabled(checked) + }, + ) + + ConfigSliderItem( + title = stringResource(R.string.pref_pixel_search_blur_intensity_title), + value = viewModel.pixelSearchBlurRadius.floatValue, + onValueChange = { + HapticUtil.performUIHaptic(view) + viewModel.setPixelSearchBlurRadius(it) + }, + valueRange = 10f..150f, + increment = 5f, + iconRes = R.drawable.rounded_blur_on_24, + valueFormatter = { "${it.toInt()} dp" }, + ) + } + } + } +} diff --git a/app/src/main/java/com/sameerasw/essentials/ui/core/sheets/UnsupportedFeaturesConfirmationSheet.kt b/app/src/main/java/com/sameerasw/essentials/ui/core/sheets/UnsupportedFeaturesConfirmationSheet.kt index 6517af9b7..2de0f142d 100644 --- a/app/src/main/java/com/sameerasw/essentials/ui/core/sheets/UnsupportedFeaturesConfirmationSheet.kt +++ b/app/src/main/java/com/sameerasw/essentials/ui/core/sheets/UnsupportedFeaturesConfirmationSheet.kt @@ -74,7 +74,10 @@ fun UnsupportedFeaturesConfirmationSheet( ) RoundedCardContainer( - modifier = Modifier.fillMaxWidth(), + modifier = + Modifier + .fillMaxWidth() + .weight(1f, fill = false), ) { LazyColumn( verticalArrangement = Arrangement.spacedBy(8.dp), diff --git a/app/src/main/java/com/sameerasw/essentials/viewmodels/MainViewModel.kt b/app/src/main/java/com/sameerasw/essentials/viewmodels/MainViewModel.kt index af2c0b880..bdb6e767b 100644 --- a/app/src/main/java/com/sameerasw/essentials/viewmodels/MainViewModel.kt +++ b/app/src/main/java/com/sameerasw/essentials/viewmodels/MainViewModel.kt @@ -2890,6 +2890,9 @@ class MainViewModel : ViewModel() { pixelSearchResultShortcuts.value = settingsRepository.isPixelSearchResultShortcutsEnabled() pixelSearchResultWeb.value = settingsRepository.isPixelSearchResultWebEnabled() pixelSearchBubblesWeb.value = settingsRepository.isPixelSearchBubblesWebEnabled() + pixelSearchBlur.value = settingsRepository.isPixelSearchBlurEnabled() + pixelSearchWallpaperBackground.value = settingsRepository.isPixelSearchWallpaperBackgroundEnabled() + pixelSearchBlurRadius.floatValue = settingsRepository.getPixelSearchBlurRadius() pixelSearchEngine.value = settingsRepository.getPixelSearchEngine() isPocketModeEnabled.value = settingsRepository.getBoolean(SettingsRepository.KEY_POCKET_MODE_ENABLED) @@ -4682,6 +4685,9 @@ class MainViewModel : ViewModel() { val pixelSearchResultShortcuts = mutableStateOf(true) val pixelSearchResultWeb = mutableStateOf(true) val pixelSearchBubblesWeb = mutableStateOf(false) + val pixelSearchBlur = mutableStateOf(true) + val pixelSearchWallpaperBackground = mutableStateOf(true) + val pixelSearchBlurRadius = mutableFloatStateOf(60f) val pixelSearchEngine = mutableStateOf("Google") fun setPixelSearchResultAppsEnabled(enabled: Boolean) { @@ -4724,6 +4730,21 @@ class MainViewModel : ViewModel() { settingsRepository.setPixelSearchBubblesWebEnabled(enabled) } + fun setPixelSearchBlurEnabled(enabled: Boolean) { + pixelSearchBlur.value = enabled + settingsRepository.setPixelSearchBlurEnabled(enabled) + } + + fun setPixelSearchWallpaperBackgroundEnabled(enabled: Boolean) { + pixelSearchWallpaperBackground.value = enabled + settingsRepository.setPixelSearchWallpaperBackgroundEnabled(enabled) + } + + fun setPixelSearchBlurRadius(radius: Float) { + pixelSearchBlurRadius.floatValue = radius + settingsRepository.setPixelSearchBlurRadius(radius) + } + fun setPixelSearchEngine(engine: String) { pixelSearchEngine.value = engine settingsRepository.setPixelSearchEngine(engine) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 9f8312f3d..fab55033d 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -2666,6 +2666,11 @@ Custom tap action Use DIY tap action instead of widget\'s own Music + Blur + Blur the background of search results + Blur options + Show wallpaper in background + Blur intensity Restart Shizuku Please enter Shizuku auth token in settings first diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml index f7434c70f..5ec4b65e8 100644 --- a/app/src/main/res/values/themes.xml +++ b/app/src/main/res/values/themes.xml @@ -20,7 +20,6 @@ @android:color/transparent @null true - true @null true @null