fix: Better location icon
This commit is contained in:
@@ -1,7 +1,6 @@
|
||||
package me.rhunk.snapenhance.ui.manager.pages.location
|
||||
|
||||
import android.os.Parcel
|
||||
import androidx.compose.foundation.isSystemInDarkTheme
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
@@ -9,13 +8,11 @@ import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Add
|
||||
import androidx.compose.material.icons.filled.DeleteOutline
|
||||
import androidx.compose.material.icons.filled.Edit
|
||||
import androidx.compose.material.icons.filled.EditLocation
|
||||
import androidx.compose.material3.*
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clipToBounds
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
@@ -102,6 +99,7 @@ class BetterLocationRoot : Routes.Route() {
|
||||
}
|
||||
} ?: friendsLocation
|
||||
}
|
||||
|
||||
ElevatedCard(
|
||||
shape = MaterialTheme.shapes.large,
|
||||
modifier = Modifier.padding(top = 32.dp, bottom = 32.dp)
|
||||
@@ -151,24 +149,11 @@ class BetterLocationRoot : Routes.Route() {
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ThemedEditLocationButton(onClick: () -> Unit) {
|
||||
FilledIconButton(
|
||||
modifier = Modifier.size(40.dp),
|
||||
colors = IconButtonDefaults.filledIconButtonColors(
|
||||
containerColor = MaterialTheme.colorScheme.surface,
|
||||
contentColor = if (isSystemInDarkTheme()) Color.White else Color(0xFF151A1A),
|
||||
),
|
||||
onClick = onClick
|
||||
) {
|
||||
Icon(Icons.Default.EditLocation, contentDescription = null)
|
||||
}
|
||||
}
|
||||
|
||||
override val content: @Composable (NavBackStackEntry) -> Unit = {
|
||||
val coordinatesProperty = remember {
|
||||
context.config.root.global.betterLocation.getPropertyPair("coordinates")
|
||||
}
|
||||
|
||||
val updateDispatcher = rememberAsyncUpdateDispatcher()
|
||||
val savedCoordinates = rememberAsyncMutableStateList(
|
||||
defaultValue = listOf(),
|
||||
@@ -179,14 +164,17 @@ class BetterLocationRoot : Routes.Route() {
|
||||
var showMap by remember { mutableStateOf(false) }
|
||||
var addSavedCoordinateDialog by remember { mutableStateOf(false) }
|
||||
var showTeleportDialog by remember { mutableStateOf(false) }
|
||||
|
||||
val marker = remember { mutableStateOf<Marker?>(null) }
|
||||
val mapView = remember { mutableStateOf<MapView?>(null) }
|
||||
var spoofedCoordinates by remember(showTeleportDialog, showMap) { mutableStateOf(coordinatesProperty.value.get() as? Pair<*, *>) }
|
||||
|
||||
fun addSavedCoordinate(id: Int?, locationCoordinates: LocationCoordinates, onSuccess: suspend (id: Int) -> Unit = {}) {
|
||||
context.coroutineScope.launch {
|
||||
onSuccess(context.database.addOrUpdateLocationCoordinate(id, locationCoordinates))
|
||||
}
|
||||
}
|
||||
|
||||
if (showTeleportDialog) {
|
||||
me.rhunk.snapenhance.ui.util.Dialog(
|
||||
properties = DialogProperties(usePlatformDefaultWidth = false),
|
||||
@@ -201,6 +189,7 @@ class BetterLocationRoot : Routes.Route() {
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
@@ -218,6 +207,7 @@ class BetterLocationRoot : Routes.Route() {
|
||||
.fillMaxWidth()
|
||||
.padding(8.dp)
|
||||
)
|
||||
|
||||
if (addSavedCoordinateDialog) {
|
||||
me.rhunk.snapenhance.ui.util.Dialog(
|
||||
onDismissRequest = { addSavedCoordinateDialog = false },
|
||||
@@ -240,6 +230,7 @@ class BetterLocationRoot : Routes.Route() {
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
if (showMap) {
|
||||
me.rhunk.snapenhance.ui.util.Dialog(
|
||||
onDismissRequest = { showMap = false },
|
||||
@@ -258,12 +249,13 @@ class BetterLocationRoot : Routes.Route() {
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
LazyColumn(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.clipToBounds(),
|
||||
contentPadding = PaddingValues(bottom = routes.bottomPadding)
|
||||
.clipToBounds()
|
||||
) {
|
||||
|
||||
item {
|
||||
@Composable
|
||||
fun ConfigToggle(
|
||||
@@ -353,6 +345,7 @@ class BetterLocationRoot : Routes.Route() {
|
||||
val isSelected = spoofedCoordinates == mutableCoordinates.latitude to mutableCoordinates.longitude
|
||||
var showDeleteDialog by remember { mutableStateOf(false) }
|
||||
var showEditDialog by remember { mutableStateOf(false) }
|
||||
|
||||
fun setSpoofedCoordinates() {
|
||||
spoofedCoordinates = mutableCoordinates.latitude to mutableCoordinates.longitude
|
||||
coordinatesProperty.value.setAny(spoofedCoordinates)
|
||||
@@ -360,6 +353,7 @@ class BetterLocationRoot : Routes.Route() {
|
||||
context.config.writeConfig()
|
||||
}
|
||||
}
|
||||
|
||||
if (showDeleteDialog) {
|
||||
me.rhunk.snapenhance.ui.util.Dialog(
|
||||
onDismissRequest = { showDeleteDialog = false },
|
||||
@@ -379,6 +373,7 @@ class BetterLocationRoot : Routes.Route() {
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
if (showEditDialog) {
|
||||
me.rhunk.snapenhance.ui.util.Dialog(
|
||||
onDismissRequest = { showEditDialog = false },
|
||||
@@ -406,6 +401,7 @@ class BetterLocationRoot : Routes.Route() {
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
ElevatedCard(
|
||||
onClick = {
|
||||
mutableCoordinates = coordinates
|
||||
@@ -451,7 +447,7 @@ class BetterLocationRoot : Routes.Route() {
|
||||
FilledIconButton(onClick = {
|
||||
showEditDialog = true
|
||||
}) {
|
||||
Icon(Icons.Default.Edit, contentDescription = "Edit")
|
||||
Icon(Icons.Default.Edit, contentDescription = "Delete")
|
||||
}
|
||||
Spacer(modifier = Modifier.width(4.dp))
|
||||
FilledIconButton(onClick = {
|
||||
@@ -465,4 +461,4 @@ class BetterLocationRoot : Routes.Route() {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,18 @@ import android.location.LocationManager
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.RelativeLayout
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.EditLocation
|
||||
import androidx.compose.material3.FilledIconButton
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButtonDefaults
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.unit.dp
|
||||
import me.rhunk.snapenhance.common.ui.OverlayType
|
||||
import me.rhunk.snapenhance.common.ui.createComposeView
|
||||
import me.rhunk.snapenhance.common.util.protobuf.EditorContext
|
||||
@@ -42,21 +54,26 @@ data class FriendLocation(
|
||||
fun distanceTo(other: FriendLocation): Double {
|
||||
val deltaLat = Math.toRadians(other.latitude - this.latitude)
|
||||
val deltaLong = Math.toRadians(other.longitude - this.longitude)
|
||||
|
||||
val a = sin(deltaLat / 2) * sin(deltaLat / 2) +
|
||||
cos(Math.toRadians(this.latitude)) * cos(Math.toRadians(other.latitude)) *
|
||||
sin(deltaLong / 2) * sin(deltaLong / 2)
|
||||
|
||||
return 6371 * 2 * atan2(sqrt(a), sqrt(1 - a))
|
||||
}
|
||||
}
|
||||
|
||||
class BetterLocation : Feature("Better Location") {
|
||||
val locationHistory = mutableMapOf<String, FriendLocation>()
|
||||
|
||||
private val walkRadius by lazy {
|
||||
context.config.global.betterLocation.walkRadius.getNullable()
|
||||
}
|
||||
|
||||
private val randomWalking by lazy {
|
||||
RandomWalking(walkRadius?.toDoubleOrNull())
|
||||
}
|
||||
|
||||
private fun getLat() : Double {
|
||||
var spoofedLatitude = context.config.global.betterLocation.coordinates.get().first
|
||||
walkRadius?.let {
|
||||
@@ -64,6 +81,7 @@ class BetterLocation : Feature("Better Location") {
|
||||
}
|
||||
return spoofedLatitude
|
||||
}
|
||||
|
||||
private fun getLong() : Double {
|
||||
var spoofedLongitude = context.config.global.betterLocation.coordinates.get().second
|
||||
walkRadius?.let {
|
||||
@@ -71,8 +89,10 @@ class BetterLocation : Feature("Better Location") {
|
||||
}
|
||||
return spoofedLongitude
|
||||
}
|
||||
|
||||
private fun editClientUpdate(editor: EditorContext) {
|
||||
val config = context.config.global.betterLocation
|
||||
|
||||
editor.apply {
|
||||
// SCVSLocationUpdate
|
||||
edit(1) {
|
||||
@@ -83,14 +103,17 @@ class BetterLocation : Feature("Better Location") {
|
||||
addFixed32(1, getLat().toFloat()) // lat
|
||||
addFixed32(2, getLong().toFloat()) // lng
|
||||
}
|
||||
|
||||
if (config.alwaysUpdateLocation.get()) {
|
||||
remove(7)
|
||||
addVarInt(7, System.currentTimeMillis()) // timestamp
|
||||
}
|
||||
}
|
||||
|
||||
if (context.config.global.betterLocation.suspendLocationUpdates.get()) {
|
||||
remove(1)
|
||||
}
|
||||
|
||||
// SCVSDeviceData
|
||||
edit(3) {
|
||||
config.spoofBatteryLevel.getNullable()?.takeIf { it.isNotEmpty() }?.let {
|
||||
@@ -102,12 +125,14 @@ class BetterLocation : Feature("Better Location") {
|
||||
addVarInt(3, 1) // devicePluggedIn
|
||||
}
|
||||
}
|
||||
|
||||
if (config.spoofHeadphones.get()) {
|
||||
remove(4)
|
||||
addVarInt(4, 1) // headphoneOutput
|
||||
remove(6)
|
||||
addVarInt(6, 1) // isOtherAudioPlaying
|
||||
}
|
||||
|
||||
edit(10) {
|
||||
remove(1)
|
||||
addVarInt(1, 4) // type = ALWAYS
|
||||
@@ -117,11 +142,14 @@ class BetterLocation : Feature("Better Location") {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun onLocationEvent(protoReader: ProtoReader) {
|
||||
protoReader.eachBuffer(3, 1) {
|
||||
val clusterId = UUID(getFixed64(1, 1) ?: return@eachBuffer, getFixed64(1, 2) ?: return@eachBuffer).toString()
|
||||
|
||||
val latitude = getFixed32(4)?.let { Float.fromBits(it) }?.toDouble() ?: return@eachBuffer
|
||||
val longitude = getFixed32(5)?.let { Float.fromBits(it) }?.toDouble() ?: return@eachBuffer
|
||||
|
||||
val locality = getString(10)
|
||||
val localityPieces = mutableListOf<String>().also {
|
||||
forEach { index, wire ->
|
||||
@@ -129,6 +157,7 @@ class BetterLocation : Feature("Better Location") {
|
||||
it.add((wire.value as ByteArray).toString(Charsets.UTF_8) )
|
||||
}
|
||||
}
|
||||
|
||||
eachBuffer(7) friend@{
|
||||
val userId = if (contains(1)) UUID(getFixed64(1, 1) ?: return@friend, getFixed64(1, 2) ?: return@friend).toString() else clusterId
|
||||
val friendLocation = FriendLocation(
|
||||
@@ -140,14 +169,17 @@ class BetterLocation : Feature("Better Location") {
|
||||
localityPieces = localityPieces,
|
||||
batteryLevel = getFixed32(13)?.let { Float.fromBits(it) } ?: -1F,
|
||||
)
|
||||
|
||||
locationHistory[userId] = friendLocation
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun openManagementOverlay() {
|
||||
context.bridgeClient.getLocationManager().provideFriendsLocation(
|
||||
locationHistory.values.toList().mapNotNull { locationHistory ->
|
||||
val friendInfo = context.database.getFriendInfo(locationHistory.userId) ?: return@mapNotNull null
|
||||
|
||||
me.rhunk.snapenhance.bridge.location.FriendLocation().also {
|
||||
it.username = friendInfo.mutableUsername ?: return@mapNotNull null
|
||||
it.displayName = friendInfo.displayName
|
||||
@@ -163,9 +195,12 @@ class BetterLocation : Feature("Better Location") {
|
||||
)
|
||||
context.bridgeClient.openOverlay(OverlayType.BETTER_LOCATION)
|
||||
}
|
||||
|
||||
override fun init() {
|
||||
if (context.config.global.betterLocation.globalState != true) return
|
||||
|
||||
val canSpoofLocation = { context.config.global.betterLocation.spoofLocation.get() }
|
||||
|
||||
LocationManager::class.java.apply {
|
||||
hook("isProviderEnabled", HookStage.BEFORE, { canSpoofLocation() }) { it.setResult(true) }
|
||||
hook("isProviderEnabledForUser", HookStage.BEFORE, { canSpoofLocation() }) { it.setResult(true) }
|
||||
@@ -174,7 +209,9 @@ class BetterLocation : Feature("Better Location") {
|
||||
hook("getLatitude", HookStage.BEFORE, { canSpoofLocation() }) { it.setResult(getLat()) }
|
||||
hook("getLongitude", HookStage.BEFORE, { canSpoofLocation() }) { it.setResult(getLong()) }
|
||||
}
|
||||
|
||||
val mapViewId = context.resources.getId("mapview")
|
||||
|
||||
if (context.config.global.betterLocation.showBatteryLevel.get()) {
|
||||
findClass("snap.snap_maps_sdk.nano.SnapMapsSdk\$PublicUserInfo").hook("setDisplayName", HookStage.BEFORE) { param ->
|
||||
val instance = param.thisObject<Any>()
|
||||
@@ -182,26 +219,55 @@ class BetterLocation : Feature("Better Location") {
|
||||
val batteryLevel = locationHistory[userId]?.batteryLevel?.takeIf { it > -1F } ?: return@hook
|
||||
param.setArg(0, param.arg<String>(0) + " (${(batteryLevel * 100).toInt()}%)")
|
||||
}
|
||||
|
||||
findClass("com.snap.map_friend_focus_view.MapFocusViewFriendSectionDataModel").hookConstructor(HookStage.AFTER) { param ->
|
||||
val instance = param.thisObject<Any>()
|
||||
val userId = instance.getObjectField("_userId") as? String ?: return@hookConstructor
|
||||
val batteryLevel = locationHistory[userId]?.batteryLevel?.takeIf { it > -1F } ?: return@hookConstructor
|
||||
|
||||
param.thisObject<Any>().dataBuilder {
|
||||
val prevText = get<String?>("_lastSeen")?.let { " - $it" } ?: ""
|
||||
set("_lastSeen", "(${(batteryLevel * 100).toInt()}%)$prevText")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
context.event.subscribe(AddViewEvent::class) { event ->
|
||||
if (!event.viewClassName.endsWith("MapScreenRoot")) return@subscribe
|
||||
|
||||
event.view.addOnAttachStateChangeListener(object: View.OnAttachStateChangeListener {
|
||||
override fun onViewAttachedToWindow(v: View) {
|
||||
// Overlay Compose UI is now created in the app module only!
|
||||
// No Compose code or theming here in the core module.
|
||||
val mapView = event.view.findViewById<View>(mapViewId) ?: throw IllegalStateException("Map view not found")
|
||||
val view = (mapView.parent as ViewGroup).children().firstOrNull { it is RelativeLayout } as? RelativeLayout ?: throw IllegalStateException("Map view parent not found")
|
||||
|
||||
view.addView(createComposeView(view.context) {
|
||||
val darkTheme = remember { context.androidContext.isDarkTheme() }
|
||||
Box(
|
||||
modifier = Modifier.padding(start = 8.dp)
|
||||
) {
|
||||
FilledIconButton(
|
||||
modifier = Modifier.size(40.dp),
|
||||
colors = IconButtonDefaults.filledIconButtonColors(
|
||||
containerColor = if (darkTheme) Color(0xFF1D1D1D) else Color.White,
|
||||
contentColor = if (darkTheme) Color.White else Color(0xFF151A1A),
|
||||
),
|
||||
onClick = { openManagementOverlay() }
|
||||
) {
|
||||
Icon(Icons.Default.EditLocation, contentDescription = null)
|
||||
}
|
||||
}
|
||||
}.apply {
|
||||
layoutParams = RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT).apply {
|
||||
addRule(RelativeLayout.ALIGN_PARENT_LEFT)
|
||||
setMargins(0, (60 * context.resources.displayMetrics.density).toInt(), 0, 0)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
override fun onViewDetachedFromWindow(v: View) {}
|
||||
})
|
||||
}
|
||||
|
||||
context.event.subscribe(UnaryCallEvent::class) { event ->
|
||||
if (event.uri == "/snapchat.valis.Valis/SendClientUpdate") {
|
||||
event.buffer = ProtoEditor(event.buffer).apply {
|
||||
@@ -213,6 +279,7 @@ class BetterLocation : Feature("Better Location") {
|
||||
}.toByteArray()
|
||||
}
|
||||
}
|
||||
|
||||
context.mappings.useMapper(CallbackMapper::class) {
|
||||
callbacks.getClass("ServerStreamingEventHandler")?.hook("onEvent", HookStage.BEFORE) { param ->
|
||||
val buffer = param.argNullable<ByteBuffer>(1)?.let {
|
||||
@@ -222,11 +289,13 @@ class BetterLocation : Feature("Better Location") {
|
||||
onLocationEvent(ProtoReader(buffer))
|
||||
}
|
||||
}
|
||||
|
||||
findClass("com.snapchat.client.grpc.ClientStreamSendHandler\$CppProxy").hook("send", HookStage.BEFORE) { param ->
|
||||
val array = param.arg<ByteBuffer>(0).let {
|
||||
it.position(0)
|
||||
ByteArray(it.capacity()).also { buffer -> it.get(buffer); it.position(0) }
|
||||
}
|
||||
|
||||
param.setArg(0, ProtoEditor(array).apply {
|
||||
edit {
|
||||
editClientUpdate(this)
|
||||
@@ -236,4 +305,4 @@ class BetterLocation : Feature("Better Location") {
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user