Skip to content

Commit 02f33d7

Browse files
0xadam-brownOpenCode
andcommitted
fix(android): Simplify Buddy recording bubble
Replace the long-press recording tooltip with a pulsing recording bubble and remove the extra stop tooltip UI. Refresh the Buddy API dump after removing the unused Compose helpers. Co-Authored-By: OpenCode <noreply@opencode.ai>
1 parent c3b1ddf commit 02f33d7

2 files changed

Lines changed: 54 additions & 143 deletions

File tree

‎sentry-android-buddy/api/sentry-android-buddy.api‎

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -315,11 +315,8 @@ public final class io/sentry/android/buddy/ComposableSingletons$SentryBuddyUiKt
315315
public final fun getLambda$-218216137$sentry_android_buddy_release ()Lkotlin/jvm/functions/Function3;
316316
public final fun getLambda$-682238859$sentry_android_buddy_release ()Lkotlin/jvm/functions/Function3;
317317
public final fun getLambda$-90711693$sentry_android_buddy_release ()Lkotlin/jvm/functions/Function3;
318-
public final fun getLambda$1040476556$sentry_android_buddy_release ()Lkotlin/jvm/functions/Function3;
319318
public final fun getLambda$1215034671$sentry_android_buddy_release ()Lkotlin/jvm/functions/Function3;
320-
public final fun getLambda$1352873802$sentry_android_buddy_release ()Lkotlin/jvm/functions/Function3;
321319
public final fun getLambda$1525882558$sentry_android_buddy_release ()Lkotlin/jvm/functions/Function3;
322-
public final fun getLambda$1644532347$sentry_android_buddy_release ()Lkotlin/jvm/functions/Function3;
323320
public final fun getLambda$1884831281$sentry_android_buddy_release ()Lkotlin/jvm/functions/Function3;
324321
public final fun getLambda$1892283088$sentry_android_buddy_release ()Lkotlin/jvm/functions/Function3;
325322
public final fun getLambda$356797945$sentry_android_buddy_release ()Lkotlin/jvm/functions/Function3;

‎sentry-android-buddy/src/main/java/io/sentry/android/buddy/SentryBuddyUi.kt‎

Lines changed: 54 additions & 140 deletions
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,6 @@ private fun SentryBuddyOverlayContent(
147147
var state by remember { mutableStateOf(controller.state) }
148148
var liveFeed by remember { mutableStateOf(controller.liveFeed) }
149149
var nowMs by remember { mutableStateOf(System.currentTimeMillis()) }
150-
var isRecordingHelpOpen by remember { mutableStateOf(false) }
151150
var transientRecordingEvent by remember { mutableStateOf<TransientRecordingEvent?>(null) }
152151
val transientRecordingEventScope = rememberCoroutineScope()
153152
val analysisScope = rememberCoroutineScope()
@@ -238,20 +237,7 @@ private fun SentryBuddyOverlayContent(
238237
else -> dispatch { close() }
239238
}
240239
},
241-
onLongClick = {
242-
if (state is SentryBuddySessionState.Recording) {
243-
isRecordingHelpOpen = true
244-
}
245-
},
246-
onStopAndAnalyze = {
247-
isRecordingHelpOpen = false
248-
dispatch {
249-
stopRecording()
250-
briefRecording()
251-
}
252-
},
253-
onDismissRecordingHelp = { isRecordingHelpOpen = false },
254-
isRecordingHelpOpen = isRecordingHelpOpen,
240+
onLongClick = {},
255241
)
256242
BuddySheet(
257243
state = state,
@@ -276,9 +262,6 @@ private fun BoxScope.BuddyBubble(
276262
transientEvent: TransientRecordingEvent?,
277263
onClick: () -> Unit,
278264
onLongClick: () -> Unit,
279-
onStopAndAnalyze: () -> Unit,
280-
onDismissRecordingHelp: () -> Unit,
281-
isRecordingHelpOpen: Boolean,
282265
) {
283266
val density = LocalDensity.current
284267
val bubbleSizePx = with(density) { BuddyBubbleSize.toPx() }
@@ -289,6 +272,29 @@ private fun BoxScope.BuddyBubble(
289272
val attentionItem = liveFeed.latestUnviewedAdverseItem
290273
val attentionColor = attentionItem?.let { severityColor(it.severity) }
291274
val pulseScale = remember { Animatable(1f) }
275+
val stopTransition = rememberInfiniteTransition(label = "buddy-floating-stop-button")
276+
val stopHaloScale by
277+
stopTransition.animateFloat(
278+
initialValue = 1.0f,
279+
targetValue = 1.14f,
280+
animationSpec =
281+
infiniteRepeatable(
282+
animation = tween(durationMillis = 1400, easing = FastOutSlowInEasing),
283+
repeatMode = RepeatMode.Reverse,
284+
),
285+
label = "buddy-floating-stop-button-halo-scale",
286+
)
287+
val stopHaloAlpha by
288+
stopTransition.animateFloat(
289+
initialValue = 0.12f,
290+
targetValue = 0.28f,
291+
animationSpec =
292+
infiniteRepeatable(
293+
animation = tween(durationMillis = 1400, easing = FastOutSlowInEasing),
294+
repeatMode = RepeatMode.Reverse,
295+
),
296+
label = "buddy-floating-stop-button-halo-alpha",
297+
)
292298
var bubbleOffset by remember { mutableStateOf<Offset?>(null) }
293299

294300
LaunchedEffect(attentionItem?.id) {
@@ -342,20 +348,38 @@ private fun BoxScope.BuddyBubble(
342348
verticalArrangement = Arrangement.spacedBy(8.dp),
343349
) {
344350
Box(
345-
modifier =
346-
Modifier.size(64.dp)
347-
.shadow(10.dp, CircleShape)
348-
.background(bubbleColor, CircleShape)
349-
.border(2.dp, Color.White.copy(alpha = 0.55f), CircleShape)
350-
.pointerInput(maxWidthPx, maxHeightPx) {
351-
detectDragGestures { change, dragAmount ->
352-
change.consume()
353-
bubbleOffset = ((bubbleOffset ?: resolvedOffset) + dragAmount).constrain()
354-
}
355-
}
356-
.combinedClickable(onClick = onClick, onLongClick = onLongClick),
351+
modifier = Modifier.size(64.dp),
357352
contentAlignment = Alignment.Center,
358353
) {
354+
if (isRecording) {
355+
Box(
356+
modifier =
357+
Modifier.size(BuddyBubbleSize * stopHaloScale)
358+
.graphicsLayer { alpha = stopHaloAlpha }
359+
.background(BuddyRed, CircleShape)
360+
)
361+
}
362+
Box(
363+
modifier =
364+
Modifier.size(64.dp)
365+
.shadow(10.dp, CircleShape)
366+
.background(bubbleColor, CircleShape)
367+
.border(2.dp, Color.White.copy(alpha = 0.55f), CircleShape)
368+
.pointerInput(maxWidthPx, maxHeightPx) {
369+
detectDragGestures { change, dragAmount ->
370+
change.consume()
371+
bubbleOffset = ((bubbleOffset ?: resolvedOffset) + dragAmount).constrain()
372+
}
373+
}
374+
.combinedClickable(onClick = onClick, onLongClick = onLongClick),
375+
contentAlignment = Alignment.Center,
376+
) {
377+
if (isRecording) {
378+
StopIcon(tint = Color.White, modifier = Modifier.size(22.dp))
379+
} else {
380+
SentryBuddyGlyph(tint = Color.White, modifier = Modifier.size(30.dp))
381+
}
382+
}
359383
if (attentionColor != null && !isRecording) {
360384
Box(
361385
modifier =
@@ -367,11 +391,6 @@ private fun BoxScope.BuddyBubble(
367391
Modifier.size(BuddyBubbleSize + 10.dp).border(3.dp, attentionColor, CircleShape)
368392
)
369393
}
370-
if (isRecording) {
371-
StopIcon(tint = Color.White, modifier = Modifier.size(22.dp))
372-
} else {
373-
SentryBuddyGlyph(tint = Color.White, modifier = Modifier.size(30.dp))
374-
}
375394
if (liveFeed.unviewedAdverseCount > 0 && !isRecording) {
376395
Text(
377396
text =
@@ -390,14 +409,6 @@ private fun BoxScope.BuddyBubble(
390409
)
391410
}
392411
}
393-
if (isRecording && isRecordingHelpOpen && state is SentryBuddySessionState.Recording) {
394-
RecordingTooltip(
395-
state = state,
396-
nowMs = nowMs,
397-
onStopAndAnalyze = onStopAndAnalyze,
398-
onDismiss = onDismissRecordingHelp,
399-
)
400-
}
401412
elapsed?.let {
402413
Text(
403414
text = it,
@@ -759,103 +770,6 @@ private fun SentryBuddyGlyph(tint: Color, modifier: Modifier = Modifier) {
759770
)
760771
}
761772

762-
@Composable
763-
private fun RecordingTooltip(
764-
state: SentryBuddySessionState.Recording,
765-
nowMs: Long,
766-
onStopAndAnalyze: () -> Unit,
767-
onDismiss: () -> Unit,
768-
) {
769-
val durationMs = nowMs - state.startedAtMs
770-
Card(
771-
modifier = Modifier.width(300.dp).shadow(12.dp, RoundedCornerShape(20.dp)),
772-
colors = CardDefaults.cardColors(containerColor = Color.White),
773-
border = CardDefaults.outlinedCardBorder(),
774-
shape = RoundedCornerShape(20.dp),
775-
) {
776-
Column(modifier = Modifier.padding(16.dp), verticalArrangement = Arrangement.spacedBy(12.dp)) {
777-
Row(
778-
modifier = Modifier.fillMaxWidth(),
779-
horizontalArrangement = Arrangement.SpaceBetween,
780-
verticalAlignment = Alignment.CenterVertically,
781-
) {
782-
Column {
783-
Text("Recording Flow", color = BuddyInk, fontWeight = FontWeight.Bold)
784-
Text(
785-
"Everything stays on device",
786-
color = BuddyMuted,
787-
style = MaterialTheme.typography.bodySmall,
788-
)
789-
}
790-
TextButton(onClick = onDismiss) { Text("Close") }
791-
}
792-
ActiveTimelinePreview(state.intent, durationMs)
793-
BreathingStopButton(onClick = onStopAndAnalyze)
794-
}
795-
}
796-
}
797-
798-
@Composable
799-
private fun BreathingStopButton(onClick: () -> Unit) {
800-
val transition = rememberInfiniteTransition(label = "buddy-stop-button")
801-
val haloScale by
802-
transition.animateFloat(
803-
initialValue = 1.0f,
804-
targetValue = 1.04f,
805-
animationSpec =
806-
infiniteRepeatable(
807-
animation = tween(durationMillis = 1400, easing = FastOutSlowInEasing),
808-
repeatMode = RepeatMode.Reverse,
809-
),
810-
label = "buddy-stop-button-halo-scale",
811-
)
812-
val haloAlpha by
813-
transition.animateFloat(
814-
initialValue = 0.12f,
815-
targetValue = 0.24f,
816-
animationSpec =
817-
infiniteRepeatable(
818-
animation = tween(durationMillis = 1400, easing = FastOutSlowInEasing),
819-
repeatMode = RepeatMode.Reverse,
820-
),
821-
label = "buddy-stop-button-halo-alpha",
822-
)
823-
val shape = RoundedCornerShape(24.dp)
824-
825-
Box(modifier = Modifier.fillMaxWidth().height(48.dp)) {
826-
Box(
827-
modifier =
828-
Modifier.fillMaxSize()
829-
.graphicsLayer {
830-
scaleX = haloScale
831-
scaleY = haloScale
832-
alpha = haloAlpha
833-
}
834-
.background(BuddyRed, shape)
835-
)
836-
Button(
837-
modifier = Modifier.fillMaxSize(),
838-
colors = ButtonDefaults.buttonColors(containerColor = BuddyRed),
839-
shape = shape,
840-
onClick = onClick,
841-
) {
842-
BuddyButtonText("Stop and Analyze")
843-
}
844-
}
845-
}
846-
847-
@Composable
848-
private fun ActiveTimelinePreview(intent: BuddyFlowIntent, durationMs: Long) {
849-
Text("Live Trace", style = MaterialTheme.typography.labelLarge, color = BuddyMuted)
850-
TimelineRows(
851-
items =
852-
listOf(
853-
TimelinePreviewItem(0, "recording_started ${intent.name}", BuddyPurple),
854-
TimelinePreviewItem(durationMs, "recording_in_progress", BuddyRed),
855-
)
856-
)
857-
}
858-
859773
private data class TimelinePreviewItem(val elapsedMs: Long, val label: String, val color: Color)
860774

861775
@Composable

0 commit comments

Comments
 (0)