mirror of
https://github.com/kavishdevar/librepods.git
synced 2026-02-10 19:52:24 +00:00
android: improve dropdowns
ai generated
This commit is contained in:
@@ -22,36 +22,39 @@ package me.kavishdevar.librepods.composables
|
|||||||
|
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.gestures.detectDragGesturesAfterLongPress
|
||||||
|
import androidx.compose.foundation.gestures.detectTapGestures
|
||||||
import androidx.compose.foundation.isSystemInDarkTheme
|
import androidx.compose.foundation.isSystemInDarkTheme
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.Spacer
|
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.height
|
import androidx.compose.foundation.layout.height
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.foundation.layout.width
|
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.filled.KeyboardArrowDown
|
import androidx.compose.material.icons.filled.KeyboardArrowDown
|
||||||
import androidx.compose.material3.DropdownMenu
|
|
||||||
import androidx.compose.material3.DropdownMenuItem
|
|
||||||
import androidx.compose.material3.Icon
|
|
||||||
import androidx.compose.material3.HorizontalDivider
|
import androidx.compose.material3.HorizontalDivider
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.DisposableEffect
|
import androidx.compose.runtime.DisposableEffect
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableLongStateOf
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.geometry.Offset
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.input.pointer.pointerInput
|
||||||
|
import androidx.compose.ui.layout.onGloballyPositioned
|
||||||
|
import androidx.compose.ui.layout.positionInParent
|
||||||
|
import androidx.compose.ui.platform.LocalDensity
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.text.TextStyle
|
import androidx.compose.ui.text.TextStyle
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
@@ -89,27 +92,55 @@ fun CallControlSettings() {
|
|||||||
val callControlEnabledValue = service.aacpManager.controlCommandStatusList.find {
|
val callControlEnabledValue = service.aacpManager.controlCommandStatusList.find {
|
||||||
it.identifier == AACPManager.Companion.ControlCommandIdentifiers.CALL_MANAGEMENT_CONFIG
|
it.identifier == AACPManager.Companion.ControlCommandIdentifiers.CALL_MANAGEMENT_CONFIG
|
||||||
}?.value ?: byteArrayOf(0x00, 0x03)
|
}?.value ?: byteArrayOf(0x00, 0x03)
|
||||||
|
|
||||||
var flipped by remember { mutableStateOf(callControlEnabledValue.contentEquals(byteArrayOf(0x00, 0x02))) }
|
val pressOnceText = stringResource(R.string.press_once)
|
||||||
var singlePressAction by remember { mutableStateOf(if (flipped) "Press Twice" else "Press Once") }
|
val pressTwiceText = stringResource(R.string.press_twice)
|
||||||
var doublePressAction by remember { mutableStateOf(if (flipped) "Press Once" else "Press Twice") }
|
|
||||||
|
var flipped by remember {
|
||||||
|
mutableStateOf(
|
||||||
|
callControlEnabledValue.contentEquals(
|
||||||
|
byteArrayOf(
|
||||||
|
0x00,
|
||||||
|
0x02
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
var singlePressAction by remember { mutableStateOf(if (flipped) pressTwiceText else pressOnceText) }
|
||||||
|
var doublePressAction by remember { mutableStateOf(if (flipped) pressOnceText else pressTwiceText) }
|
||||||
|
|
||||||
var showSinglePressDropdown by remember { mutableStateOf(false) }
|
var showSinglePressDropdown by remember { mutableStateOf(false) }
|
||||||
|
var touchOffsetSingle by remember { mutableStateOf<Offset?>(null) }
|
||||||
|
var boxPositionSingle by remember { mutableStateOf(Offset.Zero) }
|
||||||
|
var lastDismissTimeSingle by remember { mutableLongStateOf(0L) }
|
||||||
|
var parentHoveredIndexSingle by remember { mutableStateOf<Int?>(null) }
|
||||||
|
var parentDragActiveSingle by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
var showDoublePressDropdown by remember { mutableStateOf(false) }
|
var showDoublePressDropdown by remember { mutableStateOf(false) }
|
||||||
|
var touchOffsetDouble by remember { mutableStateOf<Offset?>(null) }
|
||||||
|
var boxPositionDouble by remember { mutableStateOf(Offset.Zero) }
|
||||||
|
var lastDismissTimeDouble by remember { mutableLongStateOf(0L) }
|
||||||
|
var parentHoveredIndexDouble by remember { mutableStateOf<Int?>(null) }
|
||||||
|
var parentDragActiveDouble by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
LaunchedEffect(Unit) {
|
LaunchedEffect(Unit) {
|
||||||
val listener = object : AACPManager.ControlCommandListener {
|
val listener = object : AACPManager.ControlCommandListener {
|
||||||
override fun onControlCommandReceived(controlCommand: AACPManager.ControlCommand) {
|
override fun onControlCommandReceived(controlCommand: AACPManager.ControlCommand) {
|
||||||
if (AACPManager.Companion.ControlCommandIdentifiers.fromByte(controlCommand.identifier) ==
|
if (AACPManager.Companion.ControlCommandIdentifiers.fromByte(controlCommand.identifier) ==
|
||||||
AACPManager.Companion.ControlCommandIdentifiers.CALL_MANAGEMENT_CONFIG) {
|
AACPManager.Companion.ControlCommandIdentifiers.CALL_MANAGEMENT_CONFIG
|
||||||
|
) {
|
||||||
val newFlipped = controlCommand.value.contentEquals(byteArrayOf(0x00, 0x02))
|
val newFlipped = controlCommand.value.contentEquals(byteArrayOf(0x00, 0x02))
|
||||||
flipped = newFlipped
|
flipped = newFlipped
|
||||||
singlePressAction = if (newFlipped) "Press Twice" else "Press Once"
|
singlePressAction = if (newFlipped) pressTwiceText else pressOnceText
|
||||||
doublePressAction = if (newFlipped) "Press Once" else "Press Twice"
|
doublePressAction = if (newFlipped) pressOnceText else pressTwiceText
|
||||||
Log.d("CallControlSettings", "Control command received, flipped: $newFlipped")
|
Log.d(
|
||||||
|
"CallControlSettings",
|
||||||
|
"Control command received, flipped: $newFlipped"
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
service.aacpManager.registerControlCommandListener(
|
service.aacpManager.registerControlCommandListener(
|
||||||
AACPManager.Companion.ControlCommandIdentifiers.CALL_MANAGEMENT_CONFIG,
|
AACPManager.Companion.ControlCommandIdentifiers.CALL_MANAGEMENT_CONFIG,
|
||||||
listener
|
listener
|
||||||
@@ -121,11 +152,13 @@ fun CallControlSettings() {
|
|||||||
service.aacpManager.controlCommandListeners[AACPManager.Companion.ControlCommandIdentifiers.CALL_MANAGEMENT_CONFIG]?.clear()
|
service.aacpManager.controlCommandListeners[AACPManager.Companion.ControlCommandIdentifiers.CALL_MANAGEMENT_CONFIG]?.clear()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LaunchedEffect(flipped) {
|
LaunchedEffect(flipped) {
|
||||||
Log.d("CallControlSettings", "Call control flipped: $flipped")
|
Log.d("CallControlSettings", "Call control flipped: $flipped")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val density = LocalDensity.current
|
||||||
|
val itemHeightPx = with(density) { 48.dp.toPx() }
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
@@ -161,7 +194,66 @@ fun CallControlSettings() {
|
|||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(start = 12.dp, end = 12.dp)
|
.padding(start = 12.dp, end = 12.dp)
|
||||||
.height(50.dp),
|
.height(50.dp)
|
||||||
|
.pointerInput(Unit) {
|
||||||
|
detectTapGestures { offset ->
|
||||||
|
val now = System.currentTimeMillis()
|
||||||
|
if (showSinglePressDropdown) {
|
||||||
|
showSinglePressDropdown = false
|
||||||
|
lastDismissTimeSingle = now
|
||||||
|
} else {
|
||||||
|
if (now - lastDismissTimeSingle > 250L) {
|
||||||
|
touchOffsetSingle = offset
|
||||||
|
showSinglePressDropdown = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.pointerInput(Unit) {
|
||||||
|
detectDragGesturesAfterLongPress(
|
||||||
|
onDragStart = { offset ->
|
||||||
|
val now = System.currentTimeMillis()
|
||||||
|
touchOffsetSingle = offset
|
||||||
|
if (!showSinglePressDropdown && now - lastDismissTimeSingle > 250L) {
|
||||||
|
showSinglePressDropdown = true
|
||||||
|
}
|
||||||
|
lastDismissTimeSingle = now
|
||||||
|
parentDragActiveSingle = true
|
||||||
|
parentHoveredIndexSingle = 0
|
||||||
|
},
|
||||||
|
onDrag = { change, _ ->
|
||||||
|
val current = change.position
|
||||||
|
val touch = touchOffsetSingle ?: current
|
||||||
|
val posInPopupY = current.y - touch.y
|
||||||
|
val idx = (posInPopupY / itemHeightPx).toInt()
|
||||||
|
parentHoveredIndexSingle = idx
|
||||||
|
},
|
||||||
|
onDragEnd = {
|
||||||
|
parentDragActiveSingle = false
|
||||||
|
parentHoveredIndexSingle?.let { idx ->
|
||||||
|
val options = listOf(pressOnceText, pressTwiceText)
|
||||||
|
if (idx in options.indices) {
|
||||||
|
val option = options[idx]
|
||||||
|
singlePressAction = option
|
||||||
|
doublePressAction =
|
||||||
|
if (option == pressOnceText) pressTwiceText else pressOnceText
|
||||||
|
showSinglePressDropdown = false
|
||||||
|
lastDismissTimeSingle = System.currentTimeMillis()
|
||||||
|
val bytes = if (option == pressOnceText) byteArrayOf(
|
||||||
|
0x00,
|
||||||
|
0x03
|
||||||
|
) else byteArrayOf(0x00, 0x02)
|
||||||
|
service.aacpManager.sendControlCommand(0x24, bytes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
parentHoveredIndexSingle = null
|
||||||
|
},
|
||||||
|
onDragCancel = {
|
||||||
|
parentDragActiveSingle = false
|
||||||
|
parentHoveredIndexSingle = null
|
||||||
|
}
|
||||||
|
)
|
||||||
|
},
|
||||||
horizontalArrangement = Arrangement.SpaceBetween,
|
horizontalArrangement = Arrangement.SpaceBetween,
|
||||||
verticalAlignment = Alignment.CenterVertically
|
verticalAlignment = Alignment.CenterVertically
|
||||||
) {
|
) {
|
||||||
@@ -171,13 +263,16 @@ fun CallControlSettings() {
|
|||||||
color = textColor,
|
color = textColor,
|
||||||
modifier = Modifier.padding(bottom = 4.dp)
|
modifier = Modifier.padding(bottom = 4.dp)
|
||||||
)
|
)
|
||||||
Box {
|
Box(
|
||||||
|
modifier = Modifier.onGloballyPositioned { coordinates ->
|
||||||
|
boxPositionSingle = coordinates.positionInParent()
|
||||||
|
}
|
||||||
|
) {
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier.clickable { showSinglePressDropdown = true },
|
|
||||||
verticalAlignment = Alignment.CenterVertically
|
verticalAlignment = Alignment.CenterVertically
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
text = if (singlePressAction == "Press Once") stringResource(R.string.press_once) else stringResource(R.string.press_twice),
|
text = singlePressAction,
|
||||||
fontSize = 16.sp,
|
fontSize = 16.sp,
|
||||||
color = textColor.copy(alpha = 0.8f)
|
color = textColor.copy(alpha = 0.8f)
|
||||||
)
|
)
|
||||||
@@ -188,29 +283,31 @@ fun CallControlSettings() {
|
|||||||
tint = textColor.copy(alpha = 0.6f)
|
tint = textColor.copy(alpha = 0.6f)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
DropdownMenu(
|
|
||||||
|
DragSelectableDropdown(
|
||||||
expanded = showSinglePressDropdown,
|
expanded = showSinglePressDropdown,
|
||||||
onDismissRequest = { showSinglePressDropdown = false }
|
onDismissRequest = {
|
||||||
) {
|
showSinglePressDropdown = false
|
||||||
DropdownMenuItem(
|
lastDismissTimeSingle = System.currentTimeMillis()
|
||||||
text = { Text(stringResource(R.string.press_once)) },
|
},
|
||||||
onClick = {
|
options = listOf(pressOnceText, pressTwiceText),
|
||||||
singlePressAction = "Press Once"
|
selectedOption = singlePressAction,
|
||||||
doublePressAction = "Press Twice"
|
touchOffset = touchOffsetSingle,
|
||||||
showSinglePressDropdown = false
|
boxPosition = boxPositionSingle,
|
||||||
service.aacpManager.sendControlCommand(0x24, byteArrayOf(0x00, 0x03))
|
externalHoveredIndex = parentHoveredIndexSingle,
|
||||||
}
|
externalDragActive = parentDragActiveSingle,
|
||||||
)
|
onOptionSelected = { option ->
|
||||||
DropdownMenuItem(
|
singlePressAction = option
|
||||||
text = { Text(stringResource(R.string.press_twice)) },
|
doublePressAction =
|
||||||
onClick = {
|
if (option == pressOnceText) pressTwiceText else pressOnceText
|
||||||
singlePressAction = "Press Twice"
|
showSinglePressDropdown = false
|
||||||
doublePressAction = "Press Once"
|
val bytes = if (option == pressOnceText) byteArrayOf(
|
||||||
showSinglePressDropdown = false
|
0x00,
|
||||||
service.aacpManager.sendControlCommand(0x24, byteArrayOf(0x00, 0x02))
|
0x03
|
||||||
}
|
) else byteArrayOf(0x00, 0x02)
|
||||||
)
|
service.aacpManager.sendControlCommand(0x24, bytes)
|
||||||
}
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
HorizontalDivider(
|
HorizontalDivider(
|
||||||
@@ -224,7 +321,66 @@ fun CallControlSettings() {
|
|||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(start = 12.dp, end = 12.dp)
|
.padding(start = 12.dp, end = 12.dp)
|
||||||
.height(50.dp),
|
.height(50.dp)
|
||||||
|
.pointerInput(Unit) {
|
||||||
|
detectTapGestures { offset ->
|
||||||
|
val now = System.currentTimeMillis()
|
||||||
|
if (showDoublePressDropdown) {
|
||||||
|
showDoublePressDropdown = false
|
||||||
|
lastDismissTimeDouble = now
|
||||||
|
} else {
|
||||||
|
if (now - lastDismissTimeDouble > 250L) {
|
||||||
|
touchOffsetDouble = offset
|
||||||
|
showDoublePressDropdown = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.pointerInput(Unit) {
|
||||||
|
detectDragGesturesAfterLongPress(
|
||||||
|
onDragStart = { offset ->
|
||||||
|
val now = System.currentTimeMillis()
|
||||||
|
touchOffsetDouble = offset
|
||||||
|
if (!showDoublePressDropdown && now - lastDismissTimeDouble > 250L) {
|
||||||
|
showDoublePressDropdown = true
|
||||||
|
}
|
||||||
|
lastDismissTimeDouble = now
|
||||||
|
parentDragActiveDouble = true
|
||||||
|
parentHoveredIndexDouble = 0
|
||||||
|
},
|
||||||
|
onDrag = { change, _ ->
|
||||||
|
val current = change.position
|
||||||
|
val touch = touchOffsetDouble ?: current
|
||||||
|
val posInPopupY = current.y - touch.y
|
||||||
|
val idx = (posInPopupY / itemHeightPx).toInt()
|
||||||
|
parentHoveredIndexDouble = idx
|
||||||
|
},
|
||||||
|
onDragEnd = {
|
||||||
|
parentDragActiveDouble = false
|
||||||
|
parentHoveredIndexDouble?.let { idx ->
|
||||||
|
val options = listOf(pressOnceText, pressTwiceText)
|
||||||
|
if (idx in options.indices) {
|
||||||
|
val option = options[idx]
|
||||||
|
doublePressAction = option
|
||||||
|
singlePressAction =
|
||||||
|
if (option == pressOnceText) pressTwiceText else pressOnceText
|
||||||
|
showDoublePressDropdown = false
|
||||||
|
lastDismissTimeDouble = System.currentTimeMillis()
|
||||||
|
val bytes = if (option == pressOnceText) byteArrayOf(
|
||||||
|
0x00,
|
||||||
|
0x02
|
||||||
|
) else byteArrayOf(0x00, 0x03)
|
||||||
|
service.aacpManager.sendControlCommand(0x24, bytes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
parentHoveredIndexDouble = null
|
||||||
|
},
|
||||||
|
onDragCancel = {
|
||||||
|
parentDragActiveDouble = false
|
||||||
|
parentHoveredIndexDouble = null
|
||||||
|
}
|
||||||
|
)
|
||||||
|
},
|
||||||
horizontalArrangement = Arrangement.SpaceBetween,
|
horizontalArrangement = Arrangement.SpaceBetween,
|
||||||
verticalAlignment = Alignment.CenterVertically
|
verticalAlignment = Alignment.CenterVertically
|
||||||
) {
|
) {
|
||||||
@@ -234,13 +390,16 @@ fun CallControlSettings() {
|
|||||||
color = textColor,
|
color = textColor,
|
||||||
modifier = Modifier.padding(bottom = 4.dp)
|
modifier = Modifier.padding(bottom = 4.dp)
|
||||||
)
|
)
|
||||||
Box {
|
Box(
|
||||||
|
modifier = Modifier.onGloballyPositioned { coordinates ->
|
||||||
|
boxPositionDouble = coordinates.positionInParent()
|
||||||
|
}
|
||||||
|
) {
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier.clickable { showDoublePressDropdown = true },
|
|
||||||
verticalAlignment = Alignment.CenterVertically
|
verticalAlignment = Alignment.CenterVertically
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
text = if (doublePressAction == "Press Once") stringResource(R.string.press_once) else stringResource(R.string.press_twice),
|
text = doublePressAction,
|
||||||
fontSize = 16.sp,
|
fontSize = 16.sp,
|
||||||
color = textColor.copy(alpha = 0.8f)
|
color = textColor.copy(alpha = 0.8f)
|
||||||
)
|
)
|
||||||
@@ -251,29 +410,31 @@ fun CallControlSettings() {
|
|||||||
tint = textColor.copy(alpha = 0.6f)
|
tint = textColor.copy(alpha = 0.6f)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
DropdownMenu(
|
|
||||||
|
DragSelectableDropdown(
|
||||||
expanded = showDoublePressDropdown,
|
expanded = showDoublePressDropdown,
|
||||||
onDismissRequest = { showDoublePressDropdown = false }
|
onDismissRequest = {
|
||||||
) {
|
showDoublePressDropdown = false
|
||||||
DropdownMenuItem(
|
lastDismissTimeDouble = System.currentTimeMillis()
|
||||||
text = { Text(stringResource(R.string.press_once)) },
|
},
|
||||||
onClick = {
|
options = listOf(pressOnceText, pressTwiceText),
|
||||||
doublePressAction = "Press Once"
|
selectedOption = doublePressAction,
|
||||||
singlePressAction = "Press Twice"
|
touchOffset = touchOffsetDouble,
|
||||||
showDoublePressDropdown = false
|
boxPosition = boxPositionDouble,
|
||||||
service.aacpManager.sendControlCommand(0x24, byteArrayOf(0x00, 0x02))
|
externalHoveredIndex = parentHoveredIndexDouble,
|
||||||
}
|
externalDragActive = parentDragActiveDouble,
|
||||||
)
|
onOptionSelected = { option ->
|
||||||
DropdownMenuItem(
|
doublePressAction = option
|
||||||
text = { Text(stringResource(R.string.press_twice)) },
|
singlePressAction =
|
||||||
onClick = {
|
if (option == pressOnceText) pressTwiceText else pressOnceText
|
||||||
doublePressAction = "Press Twice"
|
showDoublePressDropdown = false
|
||||||
singlePressAction = "Press Once"
|
val bytes = if (option == pressOnceText) byteArrayOf(
|
||||||
showDoublePressDropdown = false
|
0x00,
|
||||||
service.aacpManager.sendControlCommand(0x24, byteArrayOf(0x00, 0x03))
|
0x02
|
||||||
}
|
) else byteArrayOf(0x00, 0x03)
|
||||||
)
|
service.aacpManager.sendControlCommand(0x24, bytes)
|
||||||
}
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -284,4 +445,4 @@ fun CallControlSettings() {
|
|||||||
@Composable
|
@Composable
|
||||||
fun CallControlSettingsPreview() {
|
fun CallControlSettingsPreview() {
|
||||||
CallControlSettings()
|
CallControlSettings()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,14 +21,22 @@
|
|||||||
package me.kavishdevar.librepods.composables
|
package me.kavishdevar.librepods.composables
|
||||||
|
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
|
import androidx.compose.animation.AnimatedVisibility
|
||||||
|
import androidx.compose.animation.fadeIn
|
||||||
|
import androidx.compose.animation.fadeOut
|
||||||
|
import androidx.compose.animation.slideInVertically
|
||||||
|
import androidx.compose.animation.slideOutVertically
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
|
import androidx.compose.foundation.gestures.detectDragGestures
|
||||||
|
import androidx.compose.foundation.gestures.detectDragGesturesAfterLongPress
|
||||||
|
import androidx.compose.foundation.gestures.detectTapGestures
|
||||||
|
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||||
import androidx.compose.foundation.isSystemInDarkTheme
|
import androidx.compose.foundation.isSystemInDarkTheme
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.Spacer
|
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.height
|
import androidx.compose.foundation.layout.height
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
@@ -37,27 +45,37 @@ import androidx.compose.foundation.layout.width
|
|||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.filled.KeyboardArrowDown
|
import androidx.compose.material.icons.filled.KeyboardArrowDown
|
||||||
import androidx.compose.material3.DropdownMenu
|
import androidx.compose.material3.Card
|
||||||
import androidx.compose.material3.DropdownMenuItem
|
import androidx.compose.material3.CardDefaults
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Checkbox
|
||||||
|
import androidx.compose.material3.CheckboxDefaults
|
||||||
import androidx.compose.material3.HorizontalDivider
|
import androidx.compose.material3.HorizontalDivider
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.DisposableEffect
|
import androidx.compose.runtime.DisposableEffect
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableLongStateOf
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.draw.clip
|
||||||
|
import androidx.compose.ui.geometry.Offset
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.input.pointer.pointerInput
|
||||||
|
import androidx.compose.ui.layout.onGloballyPositioned
|
||||||
|
import androidx.compose.ui.layout.positionInParent
|
||||||
|
import androidx.compose.ui.platform.LocalDensity
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.text.TextStyle
|
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import androidx.compose.ui.unit.IntOffset
|
||||||
|
import androidx.compose.ui.unit.IntSize
|
||||||
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.compose.ui.window.Popup
|
||||||
import me.kavishdevar.librepods.R
|
import me.kavishdevar.librepods.R
|
||||||
import me.kavishdevar.librepods.services.ServiceManager
|
import me.kavishdevar.librepods.services.ServiceManager
|
||||||
import me.kavishdevar.librepods.utils.AACPManager
|
import me.kavishdevar.librepods.utils.AACPManager
|
||||||
@@ -79,8 +97,8 @@ fun MicrophoneSettings() {
|
|||||||
val micModeValue = service.aacpManager.controlCommandStatusList.find {
|
val micModeValue = service.aacpManager.controlCommandStatusList.find {
|
||||||
it.identifier == AACPManager.Companion.ControlCommandIdentifiers.MIC_MODE
|
it.identifier == AACPManager.Companion.ControlCommandIdentifiers.MIC_MODE
|
||||||
}?.value?.get(0) ?: 0x00.toByte()
|
}?.value?.get(0) ?: 0x00.toByte()
|
||||||
|
|
||||||
var selectedMode by remember {
|
var selectedMode by remember {
|
||||||
mutableStateOf(
|
mutableStateOf(
|
||||||
when (micModeValue) {
|
when (micModeValue) {
|
||||||
0x00.toByte() -> "Automatic"
|
0x00.toByte() -> "Automatic"
|
||||||
@@ -91,22 +109,27 @@ fun MicrophoneSettings() {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
var showDropdown by remember { mutableStateOf(false) }
|
var showDropdown by remember { mutableStateOf(false) }
|
||||||
|
var touchOffset by remember { mutableStateOf<Offset?>(null) }
|
||||||
|
var boxPosition by remember { mutableStateOf(Offset.Zero) }
|
||||||
|
var lastDismissTime by remember { mutableLongStateOf(0L) }
|
||||||
|
val reopenThresholdMs = 250L
|
||||||
|
|
||||||
val listener = object : AACPManager.ControlCommandListener {
|
val listener = object : AACPManager.ControlCommandListener {
|
||||||
override fun onControlCommandReceived(controlCommand: AACPManager.ControlCommand) {
|
override fun onControlCommandReceived(controlCommand: AACPManager.ControlCommand) {
|
||||||
if (AACPManager.Companion.ControlCommandIdentifiers.fromByte(controlCommand.identifier) ==
|
if (AACPManager.Companion.ControlCommandIdentifiers.fromByte(controlCommand.identifier) ==
|
||||||
AACPManager.Companion.ControlCommandIdentifiers.MIC_MODE) {
|
AACPManager.Companion.ControlCommandIdentifiers.MIC_MODE
|
||||||
selectedMode = when (controlCommand.value.get(0)) {
|
) {
|
||||||
0x00.toByte() -> "Automatic"
|
selectedMode = when (controlCommand.value[0]) {
|
||||||
0x01.toByte() -> "Always Right"
|
0x00.toByte() -> "Automatic"
|
||||||
0x02.toByte() -> "Always Left"
|
0x01.toByte() -> "Always Right"
|
||||||
else -> "Automatic"
|
0x02.toByte() -> "Always Left"
|
||||||
}
|
else -> "Automatic"
|
||||||
Log.d("MicrophoneSettings", "Microphone mode received: $selectedMode")
|
|
||||||
}
|
}
|
||||||
|
Log.d("MicrophoneSettings", "Microphone mode received: $selectedMode")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
LaunchedEffect(Unit) {
|
LaunchedEffect(Unit) {
|
||||||
service.aacpManager.registerControlCommandListener(
|
service.aacpManager.registerControlCommandListener(
|
||||||
AACPManager.Companion.ControlCommandIdentifiers.MIC_MODE,
|
AACPManager.Companion.ControlCommandIdentifiers.MIC_MODE,
|
||||||
@@ -123,11 +146,84 @@ fun MicrophoneSettings() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val density = LocalDensity.current
|
||||||
|
val itemHeightPx = with(density) { 48.dp.toPx() }
|
||||||
|
var parentHoveredIndex by remember { mutableStateOf<Int?>(null) }
|
||||||
|
var parentDragActive by remember { mutableStateOf(false) }
|
||||||
|
val microphoneAutomaticText = stringResource(R.string.microphone_automatic)
|
||||||
|
val microphoneAlwaysRightText = stringResource(R.string.microphone_always_right)
|
||||||
|
val microphoneAlwaysLeftText = stringResource(R.string.microphone_always_left)
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(start = 12.dp, end = 12.dp)
|
.padding(start = 12.dp, end = 12.dp)
|
||||||
.height(55.dp),
|
.height(55.dp)
|
||||||
|
.pointerInput(Unit) {
|
||||||
|
detectTapGestures { offset ->
|
||||||
|
val now = System.currentTimeMillis()
|
||||||
|
if (showDropdown) {
|
||||||
|
showDropdown = false
|
||||||
|
lastDismissTime = now
|
||||||
|
} else {
|
||||||
|
if (now - lastDismissTime > reopenThresholdMs) {
|
||||||
|
touchOffset = offset
|
||||||
|
showDropdown = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.pointerInput(Unit) {
|
||||||
|
detectDragGesturesAfterLongPress(
|
||||||
|
onDragStart = { offset ->
|
||||||
|
val now = System.currentTimeMillis()
|
||||||
|
touchOffset = offset
|
||||||
|
if (!showDropdown && now - lastDismissTime > reopenThresholdMs) {
|
||||||
|
showDropdown = true
|
||||||
|
}
|
||||||
|
lastDismissTime = now
|
||||||
|
parentDragActive = true
|
||||||
|
parentHoveredIndex = 0
|
||||||
|
},
|
||||||
|
onDrag = { change, _ ->
|
||||||
|
val current = change.position
|
||||||
|
val touch = touchOffset ?: current
|
||||||
|
val posInPopupY = current.y - touch.y
|
||||||
|
val idx = (posInPopupY / itemHeightPx).toInt()
|
||||||
|
parentHoveredIndex = idx
|
||||||
|
},
|
||||||
|
onDragEnd = {
|
||||||
|
parentDragActive = false
|
||||||
|
parentHoveredIndex?.let { idx ->
|
||||||
|
val options = listOf(
|
||||||
|
microphoneAutomaticText,
|
||||||
|
microphoneAlwaysRightText,
|
||||||
|
microphoneAlwaysLeftText
|
||||||
|
)
|
||||||
|
if (idx in options.indices) {
|
||||||
|
val option = options[idx]
|
||||||
|
selectedMode = option
|
||||||
|
showDropdown = false
|
||||||
|
lastDismissTime = System.currentTimeMillis()
|
||||||
|
val byteValue = when (option) {
|
||||||
|
options[0] -> 0x00
|
||||||
|
options[1] -> 0x01
|
||||||
|
options[2] -> 0x02
|
||||||
|
else -> 0x00
|
||||||
|
}
|
||||||
|
service.aacpManager.sendControlCommand(
|
||||||
|
AACPManager.Companion.ControlCommandIdentifiers.MIC_MODE.value,
|
||||||
|
byteArrayOf(byteValue.toByte())
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
parentHoveredIndex = null
|
||||||
|
},
|
||||||
|
onDragCancel = {
|
||||||
|
parentDragActive = false
|
||||||
|
parentHoveredIndex = null
|
||||||
|
}
|
||||||
|
)
|
||||||
|
},
|
||||||
horizontalArrangement = Arrangement.SpaceBetween,
|
horizontalArrangement = Arrangement.SpaceBetween,
|
||||||
verticalAlignment = Alignment.CenterVertically
|
verticalAlignment = Alignment.CenterVertically
|
||||||
) {
|
) {
|
||||||
@@ -137,9 +233,12 @@ fun MicrophoneSettings() {
|
|||||||
color = textColor,
|
color = textColor,
|
||||||
modifier = Modifier.padding(bottom = 4.dp)
|
modifier = Modifier.padding(bottom = 4.dp)
|
||||||
)
|
)
|
||||||
Box {
|
Box(
|
||||||
|
modifier = Modifier.onGloballyPositioned { coordinates ->
|
||||||
|
boxPosition = coordinates.positionInParent()
|
||||||
|
}
|
||||||
|
) {
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier.clickable { showDropdown = true },
|
|
||||||
verticalAlignment = Alignment.CenterVertically
|
verticalAlignment = Alignment.CenterVertically
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
@@ -154,44 +253,42 @@ fun MicrophoneSettings() {
|
|||||||
tint = textColor.copy(alpha = 0.6f)
|
tint = textColor.copy(alpha = 0.6f)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
DropdownMenu(
|
|
||||||
|
val microphoneAutomaticText = stringResource(R.string.microphone_automatic)
|
||||||
|
val microphoneAlwaysRightText = stringResource(R.string.microphone_always_right)
|
||||||
|
val microphoneAlwaysLeftText = stringResource(R.string.microphone_always_left)
|
||||||
|
|
||||||
|
DragSelectableDropdown(
|
||||||
expanded = showDropdown,
|
expanded = showDropdown,
|
||||||
onDismissRequest = { showDropdown = false }
|
onDismissRequest = {
|
||||||
) {
|
showDropdown = false
|
||||||
DropdownMenuItem(
|
lastDismissTime = System.currentTimeMillis()
|
||||||
text = { Text(stringResource(R.string.microphone_automatic)) },
|
},
|
||||||
onClick = {
|
options = listOf(
|
||||||
selectedMode = "Automatic"
|
microphoneAutomaticText,
|
||||||
showDropdown = false
|
microphoneAlwaysRightText,
|
||||||
service.aacpManager.sendControlCommand(
|
microphoneAlwaysLeftText
|
||||||
AACPManager.Companion.ControlCommandIdentifiers.MIC_MODE.value,
|
),
|
||||||
byteArrayOf(0x00)
|
selectedOption = selectedMode,
|
||||||
)
|
touchOffset = touchOffset,
|
||||||
|
boxPosition = boxPosition,
|
||||||
|
externalHoveredIndex = parentHoveredIndex,
|
||||||
|
externalDragActive = parentDragActive,
|
||||||
|
onOptionSelected = { option ->
|
||||||
|
selectedMode = option
|
||||||
|
showDropdown = false
|
||||||
|
val byteValue = when (option) {
|
||||||
|
microphoneAutomaticText -> 0x00
|
||||||
|
microphoneAlwaysRightText -> 0x01
|
||||||
|
microphoneAlwaysLeftText -> 0x02
|
||||||
|
else -> 0x00
|
||||||
}
|
}
|
||||||
)
|
service.aacpManager.sendControlCommand(
|
||||||
DropdownMenuItem(
|
AACPManager.Companion.ControlCommandIdentifiers.MIC_MODE.value,
|
||||||
text = { Text(stringResource(R.string.microphone_always_right)) },
|
byteArrayOf(byteValue.toByte())
|
||||||
onClick = {
|
)
|
||||||
selectedMode = "Always Right"
|
}
|
||||||
showDropdown = false
|
)
|
||||||
service.aacpManager.sendControlCommand(
|
|
||||||
AACPManager.Companion.ControlCommandIdentifiers.MIC_MODE.value,
|
|
||||||
byteArrayOf(0x01)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
DropdownMenuItem(
|
|
||||||
text = { Text(stringResource(R.string.microphone_always_left)) },
|
|
||||||
onClick = {
|
|
||||||
selectedMode = "Always Left"
|
|
||||||
showDropdown = false
|
|
||||||
service.aacpManager.sendControlCommand(
|
|
||||||
AACPManager.Companion.ControlCommandIdentifiers.MIC_MODE.value,
|
|
||||||
byteArrayOf(0x02)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -201,4 +298,155 @@ fun MicrophoneSettings() {
|
|||||||
@Composable
|
@Composable
|
||||||
fun MicrophoneSettingsPreview() {
|
fun MicrophoneSettingsPreview() {
|
||||||
MicrophoneSettings()
|
MicrophoneSettings()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun DragSelectableDropdown(
|
||||||
|
expanded: Boolean,
|
||||||
|
onDismissRequest: () -> Unit,
|
||||||
|
options: List<String>,
|
||||||
|
selectedOption: String,
|
||||||
|
touchOffset: Offset?,
|
||||||
|
boxPosition: Offset,
|
||||||
|
onOptionSelected: (String) -> Unit,
|
||||||
|
externalHoveredIndex: Int? = null,
|
||||||
|
externalDragActive: Boolean = false,
|
||||||
|
modifier: Modifier = Modifier
|
||||||
|
) {
|
||||||
|
if (expanded) {
|
||||||
|
val relativeOffset = touchOffset?.let { it - boxPosition } ?: Offset.Zero
|
||||||
|
Popup(
|
||||||
|
offset = IntOffset(relativeOffset.x.toInt(), relativeOffset.y.toInt()),
|
||||||
|
onDismissRequest = onDismissRequest
|
||||||
|
) {
|
||||||
|
AnimatedVisibility(
|
||||||
|
visible = true,
|
||||||
|
enter = slideInVertically(initialOffsetY = { -it }) + fadeIn(),
|
||||||
|
exit = slideOutVertically(targetOffsetY = { -it }) + fadeOut()
|
||||||
|
) {
|
||||||
|
Card(
|
||||||
|
modifier = modifier
|
||||||
|
.padding(8.dp)
|
||||||
|
.width(300.dp)
|
||||||
|
.background(
|
||||||
|
if (isSystemInDarkTheme()) Color(0xFF2C2C2E) else Color(0xFFFFFFFF)
|
||||||
|
)
|
||||||
|
.clip(RoundedCornerShape(8.dp)),
|
||||||
|
elevation = CardDefaults.cardElevation(defaultElevation = 4.dp)
|
||||||
|
) {
|
||||||
|
var hoveredIndex by remember { mutableStateOf<Int?>(null) }
|
||||||
|
val itemHeight = 48.dp
|
||||||
|
|
||||||
|
var popupSize by remember { mutableStateOf(IntSize(0, 0)) }
|
||||||
|
var lastDragPosition by remember { mutableStateOf<Offset?>(null) }
|
||||||
|
|
||||||
|
LaunchedEffect(externalHoveredIndex, externalDragActive) {
|
||||||
|
if (externalDragActive) {
|
||||||
|
hoveredIndex = externalHoveredIndex
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.onGloballyPositioned { coordinates ->
|
||||||
|
popupSize = coordinates.size
|
||||||
|
}
|
||||||
|
.pointerInput(popupSize) {
|
||||||
|
detectDragGestures(
|
||||||
|
onDragStart = { offset ->
|
||||||
|
hoveredIndex = (offset.y / itemHeight.toPx()).toInt()
|
||||||
|
lastDragPosition = offset
|
||||||
|
},
|
||||||
|
onDrag = { change, _ ->
|
||||||
|
val y = change.position.y
|
||||||
|
hoveredIndex = (y / itemHeight.toPx()).toInt()
|
||||||
|
lastDragPosition = change.position
|
||||||
|
},
|
||||||
|
onDragEnd = {
|
||||||
|
val pos = lastDragPosition
|
||||||
|
val withinBounds = pos != null &&
|
||||||
|
pos.x >= 0f && pos.y >= 0f &&
|
||||||
|
pos.x <= popupSize.width.toFloat() && pos.y <= popupSize.height.toFloat()
|
||||||
|
|
||||||
|
if (withinBounds) {
|
||||||
|
hoveredIndex?.let { idx ->
|
||||||
|
if (idx in options.indices) {
|
||||||
|
onOptionSelected(options[idx])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onDismissRequest()
|
||||||
|
} else {
|
||||||
|
hoveredIndex = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
options.forEachIndexed { index, text ->
|
||||||
|
val isHovered =
|
||||||
|
if (externalDragActive && externalHoveredIndex != null) {
|
||||||
|
index == externalHoveredIndex
|
||||||
|
} else {
|
||||||
|
index == hoveredIndex
|
||||||
|
}
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.height(itemHeight)
|
||||||
|
.background(
|
||||||
|
if (isHovered) (if (isSystemInDarkTheme()) Color(0xFF3A3A3C) else Color(
|
||||||
|
0xFFD1D1D6
|
||||||
|
)) else Color.Transparent
|
||||||
|
)
|
||||||
|
.clickable(
|
||||||
|
interactionSource = remember { MutableInteractionSource() },
|
||||||
|
indication = null
|
||||||
|
) {
|
||||||
|
onOptionSelected(text)
|
||||||
|
onDismissRequest()
|
||||||
|
}
|
||||||
|
.padding(horizontal = 12.dp),
|
||||||
|
contentAlignment = Alignment.CenterStart
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
horizontalArrangement = Arrangement.SpaceBetween,
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text,
|
||||||
|
color = if (isSystemInDarkTheme()) Color.White else Color.Black
|
||||||
|
)
|
||||||
|
Checkbox(
|
||||||
|
checked = text == selectedOption,
|
||||||
|
onCheckedChange = { onOptionSelected(text) },
|
||||||
|
colors = CheckboxDefaults.colors().copy(
|
||||||
|
checkedCheckmarkColor = Color(0xFF007AFF),
|
||||||
|
uncheckedCheckmarkColor = Color.Transparent,
|
||||||
|
checkedBoxColor = Color.Transparent,
|
||||||
|
uncheckedBoxColor = Color.Transparent,
|
||||||
|
checkedBorderColor = Color.Transparent,
|
||||||
|
uncheckedBorderColor = Color.Transparent,
|
||||||
|
disabledBorderColor = Color.Transparent,
|
||||||
|
disabledCheckedBoxColor = Color.Transparent,
|
||||||
|
disabledUncheckedBoxColor = Color.Transparent,
|
||||||
|
disabledUncheckedBorderColor = Color.Transparent
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (index != options.lastIndex) {
|
||||||
|
HorizontalDivider(
|
||||||
|
thickness = 1.5.dp,
|
||||||
|
color = Color(0x40888888),
|
||||||
|
modifier = Modifier.padding(start = 12.dp, end = 0.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user