@@ -402,26 +402,6 @@ fun DownsideTabCard(
402402 .fillMaxHeight()
403403 .offset { IntOffset (0 , animatedOffsetY.roundToInt()) }
404404 .graphicsLayer { alpha = cardAlpha }
405- .pointerInput(tab.id) {
406- detectVerticalDragGestures(
407- onDragEnd = {
408- if (abs(offsetY) > 160f ) {
409- haptic.performHapticFeedback(HapticFeedbackType .LongPress )
410- onClose()
411- } else {
412- offsetY = 0f
413- }
414- },
415- onDragCancel = {
416- offsetY = 0f
417- },
418- onVerticalDrag = { change, dragAmount ->
419- change.consume()
420- offsetY + = dragAmount
421- }
422- )
423- }
424- .clickable(onClick = onClick)
425405 .testTag(" tab_card_${tab.id} " )
426406 ) {
427407 Column (
@@ -451,90 +431,113 @@ fun DownsideTabCard(
451431 .fillMaxWidth()
452432 .padding(horizontal = 4 .dp, vertical = 2 .dp)
453433 ) {
454- // Site Icon Badge
455- Surface (
456- shape = CircleShape ,
457- color = when {
458- isYouTube -> Color (0xFFFF0000 ).copy(alpha = 0.15f )
459- isHome -> profileColor.copy(alpha = 0.15f )
460- else -> MaterialTheme .colorScheme.primary.copy(alpha = 0.15f )
461- },
462- modifier = Modifier .size(24 .dp)
434+ // Tapping badge or title selects this tab
435+ Row (
436+ verticalAlignment = Alignment .CenterVertically ,
437+ modifier = Modifier
438+ .weight(1f )
439+ .clip(RoundedCornerShape (8 .dp))
440+ .clickable(onClick = onClick)
441+ .padding(vertical = 4 .dp, horizontal = 2 .dp)
463442 ) {
464- Box (contentAlignment = Alignment .Center ) {
465- when {
466- isYouTube -> {
467- Icon (
468- imageVector = Icons .Filled .PlayArrow ,
469- contentDescription = null ,
470- tint = Color (0xFFFF0000 ),
471- modifier = Modifier .size(15 .dp)
472- )
473- }
474- isHome -> {
475- Icon (
476- imageVector = Icons .Default .Home ,
477- contentDescription = null ,
478- tint = profileColor,
479- modifier = Modifier .size(14 .dp)
480- )
481- }
482- tab.isPrivate -> {
483- Icon (
484- imageVector = Icons .Default .VpnKey ,
485- contentDescription = null ,
486- tint = Color (0xFF9333EA ),
487- modifier = Modifier .size(13 .dp)
488- )
489- }
490- else -> {
491- Text (
492- text = domain.firstOrNull()?.uppercase() ? : " W" ,
493- fontSize = 12 .sp,
494- fontWeight = FontWeight .Bold ,
495- color = MaterialTheme .colorScheme.primary
496- )
443+ // Site Icon Badge
444+ Surface (
445+ shape = CircleShape ,
446+ color = when {
447+ isYouTube -> Color (0xFFFF0000 ).copy(alpha = 0.15f )
448+ isHome -> profileColor.copy(alpha = 0.15f )
449+ else -> MaterialTheme .colorScheme.primary.copy(alpha = 0.15f )
450+ },
451+ modifier = Modifier .size(24 .dp)
452+ ) {
453+ Box (contentAlignment = Alignment .Center ) {
454+ when {
455+ isYouTube -> {
456+ Icon (
457+ imageVector = Icons .Filled .PlayArrow ,
458+ contentDescription = null ,
459+ tint = Color (0xFFFF0000 ),
460+ modifier = Modifier .size(15 .dp)
461+ )
462+ }
463+ isHome -> {
464+ Icon (
465+ imageVector = Icons .Default .Home ,
466+ contentDescription = null ,
467+ tint = profileColor,
468+ modifier = Modifier .size(14 .dp)
469+ )
470+ }
471+ tab.isPrivate -> {
472+ Icon (
473+ imageVector = Icons .Default .VpnKey ,
474+ contentDescription = null ,
475+ tint = Color (0xFF9333EA ),
476+ modifier = Modifier .size(13 .dp)
477+ )
478+ }
479+ else -> {
480+ Text (
481+ text = domain.firstOrNull()?.uppercase() ? : " W" ,
482+ fontSize = 12 .sp,
483+ fontWeight = FontWeight .Bold ,
484+ color = MaterialTheme .colorScheme.primary
485+ )
486+ }
497487 }
498488 }
499489 }
490+
491+ Spacer (modifier = Modifier .width(8 .dp))
492+
493+ // Title
494+ Text (
495+ text = when {
496+ isHome -> " Home"
497+ tab.title.isNotBlank() -> tab.title
498+ else -> domain
499+ },
500+ fontSize = 13 .sp,
501+ fontWeight = if (isActive) FontWeight .Bold else FontWeight .SemiBold ,
502+ color = MaterialTheme .colorScheme.onSurface,
503+ maxLines = 1 ,
504+ overflow = TextOverflow .Ellipsis ,
505+ modifier = Modifier .weight(1f )
506+ )
500507 }
501508
502- Spacer (modifier = Modifier .width(8 .dp))
503-
504- // Title
505- Text (
506- text = when {
507- isHome -> " Home"
508- tab.title.isNotBlank() -> tab.title
509- else -> domain
510- },
511- fontSize = 13 .sp,
512- fontWeight = if (isActive) FontWeight .Bold else FontWeight .SemiBold ,
513- color = MaterialTheme .colorScheme.onSurface,
514- maxLines = 1 ,
515- overflow = TextOverflow .Ellipsis ,
516- modifier = Modifier .weight(1f )
517- )
509+ Spacer (modifier = Modifier .width(4 .dp))
518510
519- // Close tab button
520- IconButton (
521- onClick = onClose,
511+ // Close tab button with dedicated 36dp touch target and clear hit boundary
512+ Surface (
513+ shape = CircleShape ,
514+ color = MaterialTheme .colorScheme.surfaceVariant.copy(alpha = 0.7f ),
522515 modifier = Modifier
523- .size(24 .dp)
516+ .size(36 .dp)
517+ .clip(CircleShape )
518+ .clickable(
519+ role = androidx.compose.ui.semantics.Role .Button ,
520+ onClick = {
521+ haptic.performHapticFeedback(HapticFeedbackType .LongPress )
522+ onClose()
523+ }
524+ )
524525 .testTag(" close_tab_${tab.id} " )
525526 ) {
526- Icon (
527- imageVector = Icons .Default .Close ,
528- contentDescription = " Close Tab" ,
529- tint = MaterialTheme .colorScheme.onSurfaceVariant.copy(alpha = 0.8f ),
530- modifier = Modifier .size(16 .dp)
531- )
527+ Box (contentAlignment = Alignment .Center ) {
528+ Icon (
529+ imageVector = Icons .Default .Close ,
530+ contentDescription = " Close Tab" ,
531+ tint = MaterialTheme .colorScheme.onSurfaceVariant,
532+ modifier = Modifier .size(18 .dp)
533+ )
534+ }
532535 }
533536 }
534537
535538 Spacer (modifier = Modifier .height(8 .dp))
536539
537- // Body: High quality preview surface
540+ // Body: High quality preview surface (tapping opens tab, swiping vertically dismisses tab)
538541 Surface (
539542 shape = RoundedCornerShape (16 .dp),
540543 color = MaterialTheme .colorScheme.surface,
@@ -545,6 +548,27 @@ fun DownsideTabCard(
545548 modifier = Modifier
546549 .fillMaxWidth()
547550 .weight(1f )
551+ .clip(RoundedCornerShape (16 .dp))
552+ .pointerInput(tab.id) {
553+ detectVerticalDragGestures(
554+ onDragEnd = {
555+ if (abs(offsetY) > 160f ) {
556+ haptic.performHapticFeedback(HapticFeedbackType .LongPress )
557+ onClose()
558+ } else {
559+ offsetY = 0f
560+ }
561+ },
562+ onDragCancel = {
563+ offsetY = 0f
564+ },
565+ onVerticalDrag = { change, dragAmount ->
566+ change.consume()
567+ offsetY + = dragAmount
568+ }
569+ )
570+ }
571+ .clickable(onClick = onClick)
548572 ) {
549573 if (isHome) {
550574 // Mini Home Page representation
0 commit comments