move to haze for blurring

This commit is contained in:
Kavish Devar
2024-12-06 13:06:00 +05:30
parent 2679205dc3
commit 4374a81915
5 changed files with 123 additions and 74 deletions

View File

@@ -14,7 +14,7 @@ android {
minSdk = 28 minSdk = 28
targetSdk = 35 targetSdk = 35
versionCode = 1 versionCode = 1
versionName = "0.0.2-beta" versionName = "0.0.2-beta3"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
} }
@@ -54,6 +54,8 @@ dependencies {
implementation(libs.annotations) implementation(libs.annotations)
implementation(libs.androidx.navigation.compose) implementation(libs.androidx.navigation.compose)
implementation(libs.androidx.constraintlayout) implementation(libs.androidx.constraintlayout)
implementation(libs.haze)
implementation(libs.haze.materials)
testImplementation(libs.junit) testImplementation(libs.junit)
androidTestImplementation(libs.androidx.junit) androidTestImplementation(libs.androidx.junit)
androidTestImplementation(libs.androidx.espresso.core) androidTestImplementation(libs.androidx.espresso.core)
@@ -61,5 +63,4 @@ dependencies {
androidTestImplementation(libs.androidx.ui.test.junit4) androidTestImplementation(libs.androidx.ui.test.junit4)
debugImplementation(libs.androidx.ui.tooling) debugImplementation(libs.androidx.ui.tooling)
debugImplementation(libs.androidx.ui.test.manifest) debugImplementation(libs.androidx.ui.test.manifest)
implementation("com.github.prime-zs.toolkit:core-ktx:2.1.0")
} }

View File

@@ -12,7 +12,6 @@ import android.content.IntentFilter
import android.content.SharedPreferences import android.content.SharedPreferences
import android.os.Build import android.os.Build
import android.os.ParcelUuid import android.os.ParcelUuid
import android.util.Log
import androidx.annotation.RequiresApi import androidx.annotation.RequiresApi
import androidx.compose.animation.core.animateDpAsState import androidx.compose.animation.core.animateDpAsState
import androidx.compose.foundation.Image 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.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import androidx.navigation.NavController import androidx.navigation.NavController
import com.primex.core.ExperimentalToolkitApi import dev.chrisbanes.haze.HazeState
import com.primex.core.blur.newBackgroundBlur import dev.chrisbanes.haze.haze
import me.kavishdevar.aln.AirPodsService import dev.chrisbanes.haze.hazeChild
import dev.chrisbanes.haze.materials.CupertinoMaterials
import dev.chrisbanes.haze.materials.ExperimentalHazeMaterialsApi
import kotlin.math.roundToInt 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") @SuppressLint("MissingPermission", "NewApi")
@Composable @Composable
fun AirPodsSettingsScreen(device: BluetoothDevice?, service: AirPodsService, fun AirPodsSettingsScreen(dev: BluetoothDevice?, service: AirPodsService,
navController: NavController, isConnected: Boolean) { navController: NavController, isConnected: Boolean) {
val sharedPreferences = LocalContext.current.getSharedPreferences("settings", MODE_PRIVATE) 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 ?: "") ?: "")) } var deviceName by remember { mutableStateOf(TextFieldValue(sharedPreferences.getString("name", device?.name ?: "") ?: "")) }
val verticalScrollState = rememberScrollState() val verticalScrollState = rememberScrollState()
val hazeState = remember { HazeState() }
@SuppressLint("UnusedMaterial3ScaffoldPaddingParameter") @SuppressLint("UnusedMaterial3ScaffoldPaddingParameter")
Scaffold( Scaffold(
containerColor = if (MaterialTheme.colorScheme.surface.luminance() < 0.5) Color( containerColor = if (MaterialTheme.colorScheme.surface.luminance() < 0.5) Color(
@@ -517,73 +520,93 @@ fun AirPodsSettingsScreen(device: BluetoothDevice?, service: AirPodsService,
), ),
topBar = { topBar = {
val darkMode = MaterialTheme.colorScheme.surface.luminance() < 0.5 val darkMode = MaterialTheme.colorScheme.surface.luminance() < 0.5
CenterAlignedTopAppBar( val mdensity = remember { mutableFloatStateOf(1f) }
title = { CenterAlignedTopAppBar(
Text( title = {
text = if (device != null) LocalContext.current.getSharedPreferences("settings", MODE_PRIVATE).getString("name", device.name).toString() else "", Text(
color = if (MaterialTheme.colorScheme.surface.luminance() < 0.5) Color.White else Color.Black, text = deviceName.text
) )
},
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
)
}
}, },
colors = TopAppBarDefaults.centerAlignedTopAppBarColors( modifier = Modifier
containerColor = if (MaterialTheme.colorScheme.surface.luminance() < 0.5) Color.Black.copy(0.3f) else Color(0xFFF2F2F7).copy(0.2f), .hazeChild(
), state = hazeState,
actions = { style = CupertinoMaterials.thin(),
val context = LocalContext.current block = {
IconButton( // make the background transparent when not scrolled yet
onClick = { alpha = if (verticalScrollState.value > 55.dp.value * mdensity.floatValue) 1f else 0f
val bluetoothAdapter = context.getSystemService(BluetoothManager::class.java).adapter }
bluetoothAdapter.bondedDevices.forEach { device -> )
if (device.uuids.contains(ParcelUuid.fromString("74ec2172-0bad-4d01-8f77-997b2be0722a"))) { .drawBehind {
bluetoothAdapter.getProfileProxy(context, object : BluetoothProfile.ServiceListener { mdensity.value = density
override fun onServiceConnected(profile: Int, proxy: BluetoothProfile) { val strokeWidth = 0.7.dp.value * density
if (profile == BluetoothProfile.A2DP) { val y = size.height - strokeWidth / 2
val connectedDevices = proxy.connectedDevices if (verticalScrollState.value > 55.dp.value * density) {
if (connectedDevices.isNotEmpty()) { drawLine(
service.connectToSocket(device) if (darkMode) Color.DarkGray else Color.LightGray,
} Offset(0f, y),
} Offset(size.width, y),
bluetoothAdapter.closeProfileProxy(profile, proxy) strokeWidth
} )
override fun onServiceDisconnected(profile: Int) { }
}, BluetoothProfile.A2DP)
}
} }
}, },
colors = IconButtonDefaults.iconButtonColors( colors = TopAppBarDefaults.centerAlignedTopAppBarColors(
containerColor = Color.Transparent, containerColor = Color.Transparent
contentColor = if (MaterialTheme.colorScheme.surface.luminance() < 0.5) Color.White else Color.Black ),
) actions = {
) { val context = LocalContext.current
Icon( IconButton(
imageVector = Icons.Default.Refresh, onClick = {
contentDescription = "Settings", 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 -> ) { paddingValues ->
if (isConnected == true) { if (isConnected == true) {
Column( Column(
modifier = Modifier modifier = Modifier
.haze(hazeState)
.fillMaxSize() .fillMaxSize()
.padding(horizontal = 16.dp) .padding(horizontal = 16.dp)
.verticalScroll( .verticalScroll(
@@ -840,7 +863,7 @@ fun NoiseControlSlider(service: AirPodsService, sharedPreferences: SharedPrefere
@Preview @Preview
@Composable @Composable
fun Preview() { 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 @Composable

View File

@@ -1,5 +1,8 @@
@file:OptIn(ExperimentalHazeMaterialsApi::class)
package me.kavishdevar.aln package me.kavishdevar.aln
import android.annotation.SuppressLint
import android.content.BroadcastReceiver import android.content.BroadcastReceiver
import android.content.ComponentName import android.content.ComponentName
import android.content.Context 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.Column
import androidx.compose.foundation.layout.ExperimentalLayoutApi import androidx.compose.foundation.layout.ExperimentalLayoutApi
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.imePadding import androidx.compose.foundation.layout.imePadding
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
@@ -35,6 +40,7 @@ import androidx.compose.material3.Text
import androidx.compose.material3.TextField import androidx.compose.material3.TextField
import androidx.compose.material3.TextFieldDefaults import androidx.compose.material3.TextFieldDefaults
import androidx.compose.material3.TopAppBar import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.mutableStateListOf 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.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import androidx.navigation.NavController 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) @OptIn(ExperimentalMaterial3Api::class, ExperimentalLayoutApi::class)
@SuppressLint("UnusedMaterial3ScaffoldPaddingParameter")
@Composable @Composable
fun DebugScreen(navController: NavController) { fun DebugScreen(navController: NavController) {
val hazeState = remember { HazeState() }
Scaffold( Scaffold(
topBar = { topBar = {
TopAppBar( TopAppBar(
@@ -65,7 +78,15 @@ fun DebugScreen(navController: NavController) {
}) { }) {
Icon(Icons.AutoMirrored.Filled.ArrowBack, null) 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) containerColor = if (MaterialTheme.colorScheme.surface.luminance() < 0.5) Color(0xFF000000)
@@ -97,13 +118,15 @@ fun DebugScreen(navController: NavController) {
listState.animateScrollToItem(text.size - 1) listState.animateScrollToItem(text.size - 1)
} }
} }
Column( Column(
modifier = Modifier modifier = Modifier
.fillMaxSize() .fillMaxSize()
.padding(paddingValues) // .padding(paddingValues)
.imePadding(), // Ensures padding for keyboard visibility .imePadding()
.haze(hazeState)
.padding(top = 0.dp)
) { ) {
Spacer(modifier = Modifier.height(55.dp))
LazyColumn( LazyColumn(
state = listState, state = listState,
modifier = Modifier modifier = Modifier

View File

@@ -34,7 +34,6 @@ import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController import androidx.navigation.compose.rememberNavController
import com.google.accompanist.permissions.ExperimentalPermissionsApi import com.google.accompanist.permissions.ExperimentalPermissionsApi
import com.google.accompanist.permissions.rememberMultiplePermissionsState import com.google.accompanist.permissions.rememberMultiplePermissionsState
import com.primex.core.ExperimentalToolkitApi
import me.kavishdevar.aln.ui.theme.ALNTheme import me.kavishdevar.aln.ui.theme.ALNTheme
lateinit var serviceConnection: ServiceConnection lateinit var serviceConnection: ServiceConnection
@@ -42,7 +41,6 @@ lateinit var connectionStatusReceiver: BroadcastReceiver
@ExperimentalMaterial3Api @ExperimentalMaterial3Api
class MainActivity : ComponentActivity() { class MainActivity : ComponentActivity() {
@OptIn(ExperimentalToolkitApi::class)
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
enableEdgeToEdge() enableEdgeToEdge()
@@ -138,7 +136,7 @@ fun Main() {
composable("settings") { composable("settings") {
if (airPodsService.value != null) { if (airPodsService.value != null) {
AirPodsSettingsScreen( AirPodsSettingsScreen(
device = airPodsService.value?.device, dev = airPodsService.value?.device,
service = airPodsService.value!!, service = airPodsService.value!!,
navController = navController, navController = navController,
isConnected = isConnected.value isConnected = isConnected.value

View File

@@ -13,6 +13,8 @@ composeBom = "2024.11.00"
annotations = "26.0.0" annotations = "26.0.0"
navigationCompose = "2.8.4" navigationCompose = "2.8.4"
constraintlayout = "2.2.0" constraintlayout = "2.2.0"
haze = "1.1.1"
hazeMaterials = "1.1.1"
[libraries] [libraries]
accompanist-permissions = { module = "com.google.accompanist:accompanist-permissions", version.ref = "accompanistPermissions" } 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" } annotations = { group = "org.jetbrains", name = "annotations", version.ref = "annotations" }
androidx-navigation-compose = { group = "androidx.navigation", name = "navigation-compose", version.ref = "navigationCompose" } androidx-navigation-compose = { group = "androidx.navigation", name = "navigation-compose", version.ref = "navigationCompose" }
androidx-constraintlayout = { group = "androidx.constraintlayout", name = "constraintlayout", version.ref = "constraintlayout" } 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] [plugins]
android-application = { id = "com.android.application", version.ref = "agp" } android-application = { id = "com.android.application", version.ref = "agp" }