diff --git a/app/src/main/java/com/rada/ui/library/LibraryScreen.kt b/app/src/main/java/com/rada/ui/library/LibraryScreen.kt index 7b128c3..e532e1e 100644 --- a/app/src/main/java/com/rada/ui/library/LibraryScreen.kt +++ b/app/src/main/java/com/rada/ui/library/LibraryScreen.kt @@ -4,7 +4,8 @@ import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.result.contract.ActivityResultContracts import androidx.compose.foundation.background import androidx.compose.foundation.clickable -import androidx.compose.foundation.gestures.detectTapGestures +import androidx.compose.foundation.gestures.awaitEachGesture +import androidx.compose.foundation.gestures.awaitFirstDown import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column @@ -53,17 +54,20 @@ import androidx.compose.material3.TextFieldDefaults import androidx.compose.material3.TopAppBar import androidx.compose.material3.TopAppBarDefaults import androidx.compose.runtime.Composable +import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberUpdatedState import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color +import androidx.compose.ui.input.pointer.PointerEventPass import androidx.compose.ui.input.pointer.pointerInput +import androidx.compose.ui.graphics.Color import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp @@ -178,6 +182,18 @@ fun LibraryScreen( Icon(Icons.Default.Shuffle, contentDescription = "Shuffle play") } } + // Reliable delete path for the selected folder (besides long-press). + if (uiState.selectedPlaylistId != null) { + allPlaylists.firstOrNull { it.id == uiState.selectedPlaylistId }?.let { selected -> + IconButton(onClick = { playlistToDelete = selected }) { + Icon( + Icons.Default.Delete, + contentDescription = "Delete folder", + tint = PremiumTextSecondary, + ) + } + } + } }, colors = TopAppBarDefaults.topAppBarColors( containerColor = MaterialTheme.colorScheme.background, @@ -208,17 +224,38 @@ fun LibraryScreen( } }, ) { + // One shared long-press timer for the folder tabs. The + // per-Tab watcher (pointerInput on the Initial pass) arms + // it on DOWN and disarms on UP/CANCEL/move; the Tab's own + // selectable keeps handling taps normally on the Main pass. + val tabLpHandler = android.os.Handler(android.os.Looper.getMainLooper()) + DisposableEffect(Unit) { + onDispose { tabLpHandler.removeCallbacksAndMessages(null) } + } tabLabels.forEachIndexed { index, label -> Tab( - // Long-press detected at the pointer level: putting - // combinedClickable here would be masked by Tab's own - // selectable semantics and break selection entirely. - modifier = Modifier.pointerInput(index) { - detectTapGestures( - onLongPress = { - if (index > 0) playlistToDelete = filteredPlaylists[index - 1] - }, - ) + modifier = if (index == 0) Modifier else Modifier.pointerInput(index) { + awaitEachGesture { + val down = awaitFirstDown( + requireUnconsumed = false, + pass = PointerEventPass.Initial, + ) + val playlist = filteredPlaylists[index - 1] + val slop = viewConfiguration.touchSlop + val timer = Runnable { playlistToDelete = playlist } + tabLpHandler.removeCallbacks(timer) + tabLpHandler.postDelayed( + timer, + viewConfiguration.longPressTimeoutMillis, + ) + while (true) { + val event = awaitPointerEvent(PointerEventPass.Initial) + val change = event.changes.firstOrNull { it.id == down.id } + if (change == null || !change.pressed) break + if ((change.position - down.position).getDistance() > slop) break + } + tabLpHandler.removeCallbacks(timer) + } }, selected = selectedTabIndex == index, onClick = {