redesign: PurrAura Indicator(thanks to RSR)

This commit is contained in:
particle-box
2026-01-26 13:37:27 +05:30
parent 1401aa90cc
commit 296769af49
30 changed files with 243 additions and 58 deletions

View File

@@ -1,24 +1,8 @@
package me.eternal.purrfectsnap.core.features.impl.global
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Check
import androidx.compose.material.icons.filled.Close
import androidx.compose.material3.Icon
import androidx.compose.material3.Text
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import kotlinx.coroutines.delay
import me.eternal.purrfectsnap.core.features.Feature
import me.eternal.purrfectsnap.core.event.events.impl.NetworkApiRequestEvent
import me.eternal.purrfectsnap.core.event.events.impl.UnaryCallEvent
import me.eternal.purrfectsnap.core.ui.CustomComposable
import me.eternal.purrfectsnap.core.util.dataBuilder
import me.eternal.purrfectsnap.core.util.hook.HookStage
import me.eternal.purrfectsnap.core.util.hook.hook
@@ -32,47 +16,6 @@ class EndpointsBlocker : Feature("EndpointsBlocker") {
@Volatile
private var isInLoginSignup = false
private fun showBypassStatusIndicator(isWorking: Boolean) {
if (context.bridgeClient.getDebugProp("disable_bypass_indicator", "false") == "true") {
return
}
lateinit var composable: CustomComposable
composable = {
Row(
modifier = Modifier
.padding(16.dp)
.align(Alignment.TopCenter)
.background(
color = Color.Black.copy(alpha = 0.8f),
shape = RoundedCornerShape(8.dp)
)
.padding(horizontal = 12.dp, vertical = 8.dp),
verticalAlignment = Alignment.CenterVertically
) {
Icon(
imageVector = if (isWorking) Icons.Filled.Check else Icons.Filled.Close,
contentDescription = null,
tint = if (isWorking) Color.Green else Color.Red,
modifier = Modifier.size(16.dp)
)
Spacer(modifier = Modifier.width(8.dp))
Text(
text = "PurrAura",
color = Color.White,
fontSize = 14.sp
)
}
LaunchedEffect(Unit) {
delay(3000)
context.inAppOverlay.removeCustomComposable(composable)
}
}
context.inAppOverlay.addCustomComposable(composable)
}
override fun init() {
val bypassToggleEnabled = context.bridgeClient.getDebugProp("test_mode", "false") == "true"
@@ -101,7 +44,7 @@ class EndpointsBlocker : Feature("EndpointsBlocker") {
context.log.warn("EndpointsBlocker: native self-test failed, indicator set to inactive")
context.log.warn("EndpointsBlocker: Possible causes - config not loaded or self-test logic failed")
}
showBypassStatusIndicator(healthy)
context.inAppOverlay.showBypassStatusIndicator(healthy)
} else {
context.native.setTestMode(false)
}

View File

@@ -6,6 +6,7 @@ import android.widget.FrameLayout
import androidx.compose.animation.core.Animatable
import androidx.compose.animation.core.LinearEasing
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.animation.core.spring
import androidx.compose.animation.core.tween
import androidx.compose.animation.rememberSplineBasedDecay
import androidx.compose.foundation.BorderStroke
@@ -20,6 +21,8 @@ import androidx.compose.foundation.gestures.anchoredDraggable
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Check
import androidx.compose.material.icons.filled.Close
import androidx.compose.material.icons.outlined.Warning
import androidx.compose.material3.*
import androidx.compose.runtime.*
@@ -33,6 +36,7 @@ import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.dp
@@ -378,4 +382,134 @@ class InAppOverlay(
durationMs = durationMs
))
}
private enum class BypassAnimation { SLIDE_DOWN, ZOOM_IN }
fun showBypassStatusIndicator(isWorking: Boolean) {
if (context.bridgeClient.getDebugProp("disable_bypass_indicator", "false") == "true") {
return
}
val animationType = BypassAnimation.entries.random()
lateinit var composable: CustomComposable
composable = {
var visible by remember { mutableStateOf(false) }
LaunchedEffect(Unit) {
visible = true
delay(3000)
visible = false
delay(400)
context.inAppOverlay.removeCustomComposable(composable)
}
val progress by animateFloatAsState(
targetValue = if (visible) 1f else 0f,
animationSpec = spring(
dampingRatio = 0.7f,
stiffness = 70f
),
label = "progress"
)
val (offsetX, offsetY, scale) = when (animationType) {
BypassAnimation.SLIDE_DOWN -> Triple(0f, -80f * (1f - progress), 1f)
BypassAnimation.ZOOM_IN -> Triple(0f, 0f, progress)
}
Box(
modifier = Modifier
.align(Alignment.TopCenter)
.padding(top = 16.dp)
.graphicsLayer {
translationX = offsetX
translationY = offsetY
scaleX = scale
scaleY = scale
alpha = progress
}
) {
// Use PurrfectSnap UI colors - gradient for active, red tint for inactive
val backgroundColor = if (isWorking) {
Brush.linearGradient(
listOf(
PurrfectOverlayPalette.glowPrimary.copy(alpha = 0.85f),
PurrfectOverlayPalette.glowSecondary.copy(alpha = 0.75f)
)
)
} else {
Brush.linearGradient(
listOf(
Color(0xFFB71C1C).copy(alpha = 0.85f),
Color(0xFFD32F2F).copy(alpha = 0.75f)
)
)
}
val shape = RoundedCornerShape(24.dp)
Surface(
modifier = Modifier
.shadow(
elevation = 12.dp,
shape = shape,
spotColor = if (isWorking) PurrfectOverlayPalette.glowPrimary.copy(alpha = 0.3f) else Color(0xFFB71C1C).copy(alpha = 0.25f),
ambientColor = if (isWorking) PurrfectOverlayPalette.glowSecondary.copy(alpha = 0.2f) else Color(0xFFD32F2F).copy(alpha = 0.18f)
)
.clip(shape)
.background(backgroundColor, shape)
.border(
BorderStroke(
1.dp,
if (isWorking) {
Brush.linearGradient(
listOf(
PurrfectOverlayPalette.glowPrimary.copy(alpha = 0.7f),
PurrfectOverlayPalette.glowSecondary.copy(alpha = 0.6f)
)
)
} else {
Brush.linearGradient(
listOf(
Color(0xFFB71C1C).copy(alpha = 0.7f),
Color(0xFFD32F2F).copy(alpha = 0.6f)
)
)
}
),
shape
),
color = Color.Transparent,
tonalElevation = 0.dp,
shadowElevation = 0.dp
) {
Row(
modifier = Modifier.padding(horizontal = 16.dp, vertical = 10.dp),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(8.dp)
) {
Icon(
imageVector = if (isWorking) Icons.Filled.Check else Icons.Filled.Close,
contentDescription = null,
tint = Color.White,
modifier = Modifier.size(18.dp)
)
Text(
text = if (isWorking)
context.translation.getOrNull("manager.sections.bypass_status.active") ?: "Bypass Active"
else
context.translation.getOrNull("manager.sections.bypass_status.inactive") ?: "Bypass Inactive",
color = Color.White,
fontSize = 14.sp,
fontWeight = FontWeight.Medium
)
}
}
}
}
context.mainActivity?.let { injectOverlay(it) }
customComposables.add(composable)
}
}