From 4374a81915da94e6c35d0b6c2838e56f00b91bf0 Mon Sep 17 00:00:00 2001 From: Kavish Devar Date: Fri, 6 Dec 2024 13:06:00 +0530 Subject: [PATCH] move to haze for blurring --- android/app/build.gradle.kts | 5 +- .../kavishdevar/aln/AirPodsSettingsScreen.kt | 153 ++++++++++-------- .../java/me/kavishdevar/aln/DebugScreen.kt | 31 +++- .../java/me/kavishdevar/aln/MainActivity.kt | 4 +- android/gradle/libs.versions.toml | 4 + 5 files changed, 123 insertions(+), 74 deletions(-) diff --git a/android/app/build.gradle.kts b/android/app/build.gradle.kts index e480f8d..1756977 100644 --- a/android/app/build.gradle.kts +++ b/android/app/build.gradle.kts @@ -14,7 +14,7 @@ android { minSdk = 28 targetSdk = 35 versionCode = 1 - versionName = "0.0.2-beta" + versionName = "0.0.2-beta3" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" } @@ -54,6 +54,8 @@ dependencies { implementation(libs.annotations) implementation(libs.androidx.navigation.compose) implementation(libs.androidx.constraintlayout) + implementation(libs.haze) + implementation(libs.haze.materials) testImplementation(libs.junit) androidTestImplementation(libs.androidx.junit) androidTestImplementation(libs.androidx.espresso.core) @@ -61,5 +63,4 @@ dependencies { androidTestImplementation(libs.androidx.ui.test.junit4) debugImplementation(libs.androidx.ui.tooling) debugImplementation(libs.androidx.ui.test.manifest) - implementation("com.github.prime-zs.toolkit:core-ktx:2.1.0") } \ No newline at end of file diff --git a/android/app/src/main/java/me/kavishdevar/aln/AirPodsSettingsScreen.kt b/android/app/src/main/java/me/kavishdevar/aln/AirPodsSettingsScreen.kt index f7ab83a..84cf904 100644 --- a/android/app/src/main/java/me/kavishdevar/aln/AirPodsSettingsScreen.kt +++ b/android/app/src/main/java/me/kavishdevar/aln/AirPodsSettingsScreen.kt @@ -12,7 +12,6 @@ import android.content.IntentFilter import android.content.SharedPreferences import android.os.Build import android.os.ParcelUuid -import android.util.Log import androidx.annotation.RequiresApi import androidx.compose.animation.core.animateDpAsState import androidx.compose.foundation.Image @@ -87,9 +86,11 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.navigation.NavController -import com.primex.core.ExperimentalToolkitApi -import com.primex.core.blur.newBackgroundBlur -import me.kavishdevar.aln.AirPodsService +import dev.chrisbanes.haze.HazeState +import dev.chrisbanes.haze.haze +import dev.chrisbanes.haze.hazeChild +import dev.chrisbanes.haze.materials.CupertinoMaterials +import dev.chrisbanes.haze.materials.ExperimentalHazeMaterialsApi import kotlin.math.roundToInt @@ -500,14 +501,16 @@ fun AccessibilitySettings(service: AirPodsService, sharedPreferences: SharedPref } } -@OptIn(ExperimentalMaterial3Api::class, ExperimentalToolkitApi::class) +@OptIn(ExperimentalMaterial3Api::class, ExperimentalHazeMaterialsApi::class) @SuppressLint("MissingPermission", "NewApi") @Composable -fun AirPodsSettingsScreen(device: BluetoothDevice?, service: AirPodsService, +fun AirPodsSettingsScreen(dev: BluetoothDevice?, service: AirPodsService, navController: NavController, isConnected: Boolean) { val sharedPreferences = LocalContext.current.getSharedPreferences("settings", MODE_PRIVATE) + var device by remember { mutableStateOf(dev) } var deviceName by remember { mutableStateOf(TextFieldValue(sharedPreferences.getString("name", device?.name ?: "") ?: "")) } val verticalScrollState = rememberScrollState() + val hazeState = remember { HazeState() } @SuppressLint("UnusedMaterial3ScaffoldPaddingParameter") Scaffold( containerColor = if (MaterialTheme.colorScheme.surface.luminance() < 0.5) Color( @@ -517,73 +520,93 @@ fun AirPodsSettingsScreen(device: BluetoothDevice?, service: AirPodsService, ), topBar = { val darkMode = MaterialTheme.colorScheme.surface.luminance() < 0.5 - CenterAlignedTopAppBar( - title = { - Text( - text = if (device != null) LocalContext.current.getSharedPreferences("settings", MODE_PRIVATE).getString("name", device.name).toString() else "", - color = if (MaterialTheme.colorScheme.surface.luminance() < 0.5) Color.White else Color.Black, - ) - }, - modifier = Modifier - .newBackgroundBlur( - radius = 24.dp, - downsample = 0.5f, - ) - .drawBehind { - val strokeWidth = 0.7.dp.value * density - val y = size.height - strokeWidth / 2 - if (verticalScrollState.value > 55.dp.value * density) { - drawLine( - if (darkMode) Color.DarkGray else Color.LightGray, - Offset(0f, y), - Offset(size.width, y), - strokeWidth - ) - } + val mdensity = remember { mutableFloatStateOf(1f) } + CenterAlignedTopAppBar( + title = { + Text( + text = deviceName.text + ) }, - colors = TopAppBarDefaults.centerAlignedTopAppBarColors( - containerColor = if (MaterialTheme.colorScheme.surface.luminance() < 0.5) Color.Black.copy(0.3f) else Color(0xFFF2F2F7).copy(0.2f), - ), - actions = { - val context = LocalContext.current - IconButton( - onClick = { - val bluetoothAdapter = context.getSystemService(BluetoothManager::class.java).adapter - bluetoothAdapter.bondedDevices.forEach { device -> - if (device.uuids.contains(ParcelUuid.fromString("74ec2172-0bad-4d01-8f77-997b2be0722a"))) { - bluetoothAdapter.getProfileProxy(context, object : BluetoothProfile.ServiceListener { - override fun onServiceConnected(profile: Int, proxy: BluetoothProfile) { - if (profile == BluetoothProfile.A2DP) { - val connectedDevices = proxy.connectedDevices - if (connectedDevices.isNotEmpty()) { - service.connectToSocket(device) - } - } - bluetoothAdapter.closeProfileProxy(profile, proxy) - } - - override fun onServiceDisconnected(profile: Int) { } - }, BluetoothProfile.A2DP) - } + modifier = Modifier + .hazeChild( + state = hazeState, + style = CupertinoMaterials.thin(), + block = { +// make the background transparent when not scrolled yet + alpha = if (verticalScrollState.value > 55.dp.value * mdensity.floatValue) 1f else 0f + } + ) + .drawBehind { + mdensity.value = density + val strokeWidth = 0.7.dp.value * density + val y = size.height - strokeWidth / 2 + if (verticalScrollState.value > 55.dp.value * density) { + drawLine( + if (darkMode) Color.DarkGray else Color.LightGray, + Offset(0f, y), + Offset(size.width, y), + strokeWidth + ) } }, - colors = IconButtonDefaults.iconButtonColors( - containerColor = Color.Transparent, - contentColor = if (MaterialTheme.colorScheme.surface.luminance() < 0.5) Color.White else Color.Black - ) - ) { - Icon( - imageVector = Icons.Default.Refresh, - contentDescription = "Settings", - ) + colors = TopAppBarDefaults.centerAlignedTopAppBarColors( + containerColor = Color.Transparent + ), + actions = { + val context = LocalContext.current + IconButton( + onClick = { + val bluetoothAdapter = + context.getSystemService(BluetoothManager::class.java).adapter + bluetoothAdapter.bondedDevices.forEach { d -> + if (d.uuids.contains(ParcelUuid.fromString("74ec2172-0bad-4d01-8f77-997b2be0722a"))) { + bluetoothAdapter.getProfileProxy( + context, + object : BluetoothProfile.ServiceListener { + override fun onServiceConnected( + profile: Int, + proxy: BluetoothProfile + ) { + if (profile == BluetoothProfile.A2DP) { + val connectedDevices = + proxy.connectedDevices + if (connectedDevices.isNotEmpty()) { + service.connectToSocket(d) + device = d + deviceName = TextFieldValue(d.name) + } + } + bluetoothAdapter.closeProfileProxy( + profile, + proxy + ) + } + + override fun onServiceDisconnected(profile: Int) {} + }, + BluetoothProfile.A2DP + ) + } + } + }, + colors = IconButtonDefaults.iconButtonColors( + containerColor = Color.Transparent, + contentColor = if (MaterialTheme.colorScheme.surface.luminance() < 0.5) Color.White else Color.Black + ) + ) { + Icon( + imageVector = Icons.Default.Refresh, + contentDescription = "Settings", + ) + } } - } - ) + ) } ) { paddingValues -> if (isConnected == true) { Column( modifier = Modifier + .haze(hazeState) .fillMaxSize() .padding(horizontal = 16.dp) .verticalScroll( @@ -840,7 +863,7 @@ fun NoiseControlSlider(service: AirPodsService, sharedPreferences: SharedPrefere @Preview @Composable fun Preview() { - IndependentToggle("Case Charging Sounds", AirPodsService(), "setCaseChargingSounds", LocalContext.current.getSharedPreferences("settings", Context.MODE_PRIVATE)) + IndependentToggle("Case Charging Sounds", AirPodsService(), "setCaseChargingSounds", LocalContext.current.getSharedPreferences("settings", MODE_PRIVATE)) } @Composable diff --git a/android/app/src/main/java/me/kavishdevar/aln/DebugScreen.kt b/android/app/src/main/java/me/kavishdevar/aln/DebugScreen.kt index bb4e936..7f8919b 100644 --- a/android/app/src/main/java/me/kavishdevar/aln/DebugScreen.kt +++ b/android/app/src/main/java/me/kavishdevar/aln/DebugScreen.kt @@ -1,5 +1,8 @@ +@file:OptIn(ExperimentalHazeMaterialsApi::class) + package me.kavishdevar.aln +import android.annotation.SuppressLint import android.content.BroadcastReceiver import android.content.ComponentName import android.content.Context @@ -15,8 +18,10 @@ import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.ExperimentalLayoutApi import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.imePadding import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn @@ -35,6 +40,7 @@ import androidx.compose.material3.Text import androidx.compose.material3.TextField import androidx.compose.material3.TextFieldDefaults import androidx.compose.material3.TopAppBar +import androidx.compose.material3.TopAppBarDefaults import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.mutableStateListOf @@ -51,10 +57,17 @@ import androidx.compose.ui.text.input.TextFieldValue import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.navigation.NavController +import dev.chrisbanes.haze.HazeState +import dev.chrisbanes.haze.haze +import dev.chrisbanes.haze.hazeChild +import dev.chrisbanes.haze.materials.CupertinoMaterials +import dev.chrisbanes.haze.materials.ExperimentalHazeMaterialsApi @OptIn(ExperimentalMaterial3Api::class, ExperimentalLayoutApi::class) +@SuppressLint("UnusedMaterial3ScaffoldPaddingParameter") @Composable fun DebugScreen(navController: NavController) { + val hazeState = remember { HazeState() } Scaffold( topBar = { TopAppBar( @@ -65,7 +78,15 @@ fun DebugScreen(navController: NavController) { }) { Icon(Icons.AutoMirrored.Filled.ArrowBack, null) } - } + }, + modifier = Modifier + .hazeChild( + state = hazeState, + style = CupertinoMaterials.thin() + ), + colors = TopAppBarDefaults.topAppBarColors( + containerColor = Color.Transparent + ) ) }, containerColor = if (MaterialTheme.colorScheme.surface.luminance() < 0.5) Color(0xFF000000) @@ -97,13 +118,15 @@ fun DebugScreen(navController: NavController) { listState.animateScrollToItem(text.size - 1) } } - Column( modifier = Modifier .fillMaxSize() - .padding(paddingValues) - .imePadding(), // Ensures padding for keyboard visibility +// .padding(paddingValues) + .imePadding() + .haze(hazeState) + .padding(top = 0.dp) ) { + Spacer(modifier = Modifier.height(55.dp)) LazyColumn( state = listState, modifier = Modifier diff --git a/android/app/src/main/java/me/kavishdevar/aln/MainActivity.kt b/android/app/src/main/java/me/kavishdevar/aln/MainActivity.kt index 36fd3fd..4e77d01 100644 --- a/android/app/src/main/java/me/kavishdevar/aln/MainActivity.kt +++ b/android/app/src/main/java/me/kavishdevar/aln/MainActivity.kt @@ -34,7 +34,6 @@ import androidx.navigation.compose.composable import androidx.navigation.compose.rememberNavController import com.google.accompanist.permissions.ExperimentalPermissionsApi import com.google.accompanist.permissions.rememberMultiplePermissionsState -import com.primex.core.ExperimentalToolkitApi import me.kavishdevar.aln.ui.theme.ALNTheme lateinit var serviceConnection: ServiceConnection @@ -42,7 +41,6 @@ lateinit var connectionStatusReceiver: BroadcastReceiver @ExperimentalMaterial3Api class MainActivity : ComponentActivity() { - @OptIn(ExperimentalToolkitApi::class) override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) enableEdgeToEdge() @@ -138,7 +136,7 @@ fun Main() { composable("settings") { if (airPodsService.value != null) { AirPodsSettingsScreen( - device = airPodsService.value?.device, + dev = airPodsService.value?.device, service = airPodsService.value!!, navController = navController, isConnected = isConnected.value diff --git a/android/gradle/libs.versions.toml b/android/gradle/libs.versions.toml index 6d6d0f2..0eb42fe 100644 --- a/android/gradle/libs.versions.toml +++ b/android/gradle/libs.versions.toml @@ -13,6 +13,8 @@ composeBom = "2024.11.00" annotations = "26.0.0" navigationCompose = "2.8.4" constraintlayout = "2.2.0" +haze = "1.1.1" +hazeMaterials = "1.1.1" [libraries] accompanist-permissions = { module = "com.google.accompanist:accompanist-permissions", version.ref = "accompanistPermissions" } @@ -34,6 +36,8 @@ androidx-material3 = { group = "androidx.compose.material3", name = "material3" annotations = { group = "org.jetbrains", name = "annotations", version.ref = "annotations" } androidx-navigation-compose = { group = "androidx.navigation", name = "navigation-compose", version.ref = "navigationCompose" } androidx-constraintlayout = { group = "androidx.constraintlayout", name = "constraintlayout", version.ref = "constraintlayout" } +haze = { group = "dev.chrisbanes.haze", name = "haze", version.ref = "haze" } +haze-materials = { group = "dev.chrisbanes.haze", name = "haze-materials", version.ref = "hazeMaterials" } [plugins] android-application = { id = "com.android.application", version.ref = "agp" }