mirror of
https://github.com/rhunk/SnapEnhance.git
synced 2025-05-29 13:00:17 +02:00
fix(better_location): suspend location updates
Signed-off-by: rhunk <101876869+rhunk@users.noreply.github.com>
This commit is contained in:
parent
a633f913d3
commit
0688c276bb
@ -255,6 +255,42 @@ class BetterLocationRoot : Routes.Route() {
|
|||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
.clipToBounds()
|
.clipToBounds()
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
item {
|
||||||
|
@Composable
|
||||||
|
fun ConfigToggle(
|
||||||
|
text: String,
|
||||||
|
state: MutableState<Boolean>,
|
||||||
|
onCheckedChange: (Boolean) -> Unit
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier.padding(start = 16.dp, end = 16.dp),
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
|
) {
|
||||||
|
Text(text = text)
|
||||||
|
Spacer(modifier = Modifier.weight(1f))
|
||||||
|
Switch(
|
||||||
|
checked = state.value,
|
||||||
|
onCheckedChange = {
|
||||||
|
state.value = it
|
||||||
|
onCheckedChange(it)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ConfigToggle(
|
||||||
|
translation["spoof_location_toggle"],
|
||||||
|
remember { mutableStateOf(context.config.root.global.betterLocation.spoofLocation.get()) }
|
||||||
|
) {
|
||||||
|
context.config.root.global.betterLocation.spoofLocation.set(it)
|
||||||
|
}
|
||||||
|
ConfigToggle(
|
||||||
|
translation["suspend_location_updates"],
|
||||||
|
remember { mutableStateOf(context.config.root.global.betterLocation.suspendLocationUpdates.get()) }
|
||||||
|
) {
|
||||||
|
context.config.root.global.betterLocation.suspendLocationUpdates.set(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
item {
|
item {
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
@ -271,23 +307,6 @@ class BetterLocationRoot : Routes.Route() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
item {
|
|
||||||
Row(
|
|
||||||
modifier = Modifier.padding(start = 16.dp, end = 16.dp),
|
|
||||||
verticalAlignment = Alignment.CenterVertically
|
|
||||||
) {
|
|
||||||
Text(text = translation["spoof_location_toggle"])
|
|
||||||
Spacer(modifier = Modifier.weight(1f))
|
|
||||||
var isSpoofing by remember { mutableStateOf(context.config.root.global.betterLocation.spoofLocation.get()) }
|
|
||||||
Switch(
|
|
||||||
checked = isSpoofing,
|
|
||||||
onCheckedChange = {
|
|
||||||
isSpoofing = it
|
|
||||||
context.config.root.global.betterLocation.spoofLocation.set(it)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
item {
|
item {
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
|
@ -150,7 +150,7 @@
|
|||||||
"no_files_hint": "Here you can import files for use in Snapchat. Press the button below to import a file."
|
"no_files_hint": "Here you can import files for use in Snapchat. Press the button below to import a file."
|
||||||
},
|
},
|
||||||
"better_location": {
|
"better_location": {
|
||||||
"spoofed_coordinates_title": "Spoofed Coordinates\nLat {latitude}, Lng {longitude}",
|
"spoofed_coordinates_title": "Lat {latitude}, Lng {longitude}",
|
||||||
"save_coordinates_dialog_title": "Save Coordinates",
|
"save_coordinates_dialog_title": "Save Coordinates",
|
||||||
"saved_name_dialog_hint": "Saved Name",
|
"saved_name_dialog_hint": "Saved Name",
|
||||||
"latitude_dialog_hint": "Latitude",
|
"latitude_dialog_hint": "Latitude",
|
||||||
@ -159,6 +159,7 @@
|
|||||||
"choose_location_button": "Choose Location",
|
"choose_location_button": "Choose Location",
|
||||||
"teleport_to_friend_button": "Teleport to Friend",
|
"teleport_to_friend_button": "Teleport to Friend",
|
||||||
"spoof_location_toggle": "Spoof Location",
|
"spoof_location_toggle": "Spoof Location",
|
||||||
|
"suspend_location_updates": "Suspend Location Updates",
|
||||||
"saved_coordinates_title": "Saved Coordinates",
|
"saved_coordinates_title": "Saved Coordinates",
|
||||||
"no_saved_coordinates_hint": "No saved coordinates",
|
"no_saved_coordinates_hint": "No saved coordinates",
|
||||||
"delete_dialog_title": "Delete Saved Coordinate",
|
"delete_dialog_title": "Delete Saved Coordinate",
|
||||||
@ -778,7 +779,7 @@
|
|||||||
},
|
},
|
||||||
"suspend_location_updates": {
|
"suspend_location_updates": {
|
||||||
"name": "Suspend Location Updates",
|
"name": "Suspend Location Updates",
|
||||||
"description": "Adds a button in map settings to suspend location updates"
|
"description": "Prevents your location from being updated"
|
||||||
},
|
},
|
||||||
"spoof_battery_level": {
|
"spoof_battery_level": {
|
||||||
"name": "Spoof Battery Level",
|
"name": "Spoof Battery Level",
|
||||||
@ -1624,9 +1625,6 @@
|
|||||||
"bitmoji_scene_changed": "{username} has changed their Bitmoji scene"
|
"bitmoji_scene_changed": "{username} has changed their Bitmoji scene"
|
||||||
},
|
},
|
||||||
|
|
||||||
"suspend_location_updates": {
|
|
||||||
"switch_text": "Suspend Location Updates"
|
|
||||||
},
|
|
||||||
"material3_strings": {
|
"material3_strings": {
|
||||||
"date_range_picker_start_headline": "From",
|
"date_range_picker_start_headline": "From",
|
||||||
"date_range_picker_end_headline": "To",
|
"date_range_picker_end_headline": "To",
|
||||||
|
@ -30,7 +30,6 @@ enum class InternalFileHandleType(
|
|||||||
CONFIG("config", "config.json"),
|
CONFIG("config", "config.json"),
|
||||||
MAPPINGS("mappings", "mappings.json"),
|
MAPPINGS("mappings", "mappings.json"),
|
||||||
MESSAGE_LOGGER("message_logger", "message_logger.db", isDatabase = true),
|
MESSAGE_LOGGER("message_logger", "message_logger.db", isDatabase = true),
|
||||||
SUSPEND_LOCATION_STATE("suspend_location_state", "suspend_location_state.txt"),
|
|
||||||
PINNED_BEST_FRIEND("pinned_best_friend", "pinned_best_friend.txt");
|
PINNED_BEST_FRIEND("pinned_best_friend", "pinned_best_friend.txt");
|
||||||
|
|
||||||
|
|
||||||
|
@ -20,11 +20,11 @@ class Global : ConfigContainer() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
inner class BetterLocationConfig : ConfigContainer(hasGlobalState = true) {
|
inner class BetterLocationConfig : ConfigContainer(hasGlobalState = true) {
|
||||||
val spoofLocation = boolean("spoof_location") { requireRestart() }
|
val spoofLocation = boolean("spoof_location")
|
||||||
val coordinates = mapCoordinates("coordinates", 0.0 to 0.0) { addFlags(ConfigFlag.SENSITIVE) } // lat, long
|
val coordinates = mapCoordinates("coordinates", 0.0 to 0.0) { addFlags(ConfigFlag.SENSITIVE) } // lat, long
|
||||||
val walkRadius = string("walk_radius") { requireRestart(); inputCheck = { it.toDoubleOrNull()?.isFinite() == true && it.toDouble() >= 0.0 } }
|
val walkRadius = string("walk_radius") { requireRestart(); inputCheck = { it.toDoubleOrNull()?.isFinite() == true && it.toDouble() >= 0.0 } }
|
||||||
val alwaysUpdateLocation = boolean("always_update_location") { requireRestart() }
|
val alwaysUpdateLocation = boolean("always_update_location") { requireRestart() }
|
||||||
val suspendLocationUpdates = boolean("suspend_location_updates") { requireRestart() }
|
val suspendLocationUpdates = boolean("suspend_location_updates")
|
||||||
val spoofBatteryLevel = string("spoof_battery_level") { requireRestart(); inputCheck = { it.isEmpty() || it.toIntOrNull() in 0..100 } }
|
val spoofBatteryLevel = string("spoof_battery_level") { requireRestart(); inputCheck = { it.isEmpty() || it.toIntOrNull() in 0..100 } }
|
||||||
val spoofHeadphones = boolean("spoof_headphones") { requireRestart() }
|
val spoofHeadphones = boolean("spoof_headphones") { requireRestart() }
|
||||||
}
|
}
|
||||||
|
@ -107,7 +107,6 @@ class FeatureManager(
|
|||||||
MessageIndicators(),
|
MessageIndicators(),
|
||||||
EditTextOverride(),
|
EditTextOverride(),
|
||||||
PreventForcedLogout(),
|
PreventForcedLogout(),
|
||||||
SuspendLocationUpdates(),
|
|
||||||
ConversationToolbox(),
|
ConversationToolbox(),
|
||||||
SpotlightCommentsUsername(),
|
SpotlightCommentsUsername(),
|
||||||
OperaViewerParamsOverride(),
|
OperaViewerParamsOverride(),
|
||||||
|
@ -26,7 +26,6 @@ import me.rhunk.snapenhance.core.event.events.impl.AddViewEvent
|
|||||||
import me.rhunk.snapenhance.core.event.events.impl.UnaryCallEvent
|
import me.rhunk.snapenhance.core.event.events.impl.UnaryCallEvent
|
||||||
import me.rhunk.snapenhance.core.features.Feature
|
import me.rhunk.snapenhance.core.features.Feature
|
||||||
import me.rhunk.snapenhance.core.features.FeatureLoadParams
|
import me.rhunk.snapenhance.core.features.FeatureLoadParams
|
||||||
import me.rhunk.snapenhance.core.features.impl.global.SuspendLocationUpdates
|
|
||||||
import me.rhunk.snapenhance.core.util.RandomWalking
|
import me.rhunk.snapenhance.core.util.RandomWalking
|
||||||
import me.rhunk.snapenhance.core.util.hook.HookStage
|
import me.rhunk.snapenhance.core.util.hook.HookStage
|
||||||
import me.rhunk.snapenhance.core.util.hook.hook
|
import me.rhunk.snapenhance.core.util.hook.hook
|
||||||
@ -35,7 +34,6 @@ import me.rhunk.snapenhance.core.util.ktx.isDarkTheme
|
|||||||
import me.rhunk.snapenhance.mapper.impl.CallbackMapper
|
import me.rhunk.snapenhance.mapper.impl.CallbackMapper
|
||||||
import java.nio.ByteBuffer
|
import java.nio.ByteBuffer
|
||||||
import java.util.UUID
|
import java.util.UUID
|
||||||
import kotlin.time.Duration.Companion.days
|
|
||||||
|
|
||||||
data class FriendLocation(
|
data class FriendLocation(
|
||||||
val userId: String,
|
val userId: String,
|
||||||
@ -91,11 +89,10 @@ class BetterLocation : Feature("Better Location", loadParams = FeatureLoadParams
|
|||||||
remove(7)
|
remove(7)
|
||||||
addVarInt(7, System.currentTimeMillis()) // timestamp
|
addVarInt(7, System.currentTimeMillis()) // timestamp
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (context.feature(SuspendLocationUpdates::class).isSuspended()) {
|
if (context.config.global.betterLocation.suspendLocationUpdates.get()) {
|
||||||
remove(7)
|
remove(1)
|
||||||
addVarInt(7, System.currentTimeMillis() - 15.days.inWholeMilliseconds)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// SCVSDeviceData
|
// SCVSDeviceData
|
||||||
@ -172,19 +169,18 @@ class BetterLocation : Feature("Better Location", loadParams = FeatureLoadParams
|
|||||||
override fun init() {
|
override fun init() {
|
||||||
if (context.config.global.betterLocation.globalState != true) return
|
if (context.config.global.betterLocation.globalState != true) return
|
||||||
|
|
||||||
if (context.config.global.betterLocation.spoofLocation.get()) {
|
val canSpoofLocation = { context.config.global.betterLocation.spoofLocation.get() }
|
||||||
LocationManager::class.java.apply {
|
|
||||||
hook("isProviderEnabled", HookStage.BEFORE) { it.setResult(true) }
|
LocationManager::class.java.apply {
|
||||||
hook("isProviderEnabledForUser", HookStage.BEFORE) { it.setResult(true) }
|
hook("isProviderEnabled", HookStage.BEFORE, { canSpoofLocation() }) { it.setResult(true) }
|
||||||
}
|
hook("isProviderEnabledForUser", HookStage.BEFORE, { canSpoofLocation() }) { it.setResult(true) }
|
||||||
Location::class.java.apply {
|
}
|
||||||
hook("getLatitude", HookStage.BEFORE) { it.setResult(getLat()) }
|
Location::class.java.apply {
|
||||||
hook("getLongitude", HookStage.BEFORE) { it.setResult(getLong()) }
|
hook("getLatitude", HookStage.BEFORE, { canSpoofLocation() }) { it.setResult(getLat()) }
|
||||||
}
|
hook("getLongitude", HookStage.BEFORE, { canSpoofLocation() }) { it.setResult(getLong()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
val mapFeaturesRootId = context.resources.getId("map_features_root")
|
val mapFeaturesRootId = context.resources.getId("map_features_root")
|
||||||
val mapLayerSelectorId = context.resources.getId("map_layer_selector")
|
|
||||||
|
|
||||||
context.event.subscribe(AddViewEvent::class) { event ->
|
context.event.subscribe(AddViewEvent::class) { event ->
|
||||||
if (event.view.id != mapFeaturesRootId) return@subscribe
|
if (event.view.id != mapFeaturesRootId) return@subscribe
|
||||||
@ -234,10 +230,10 @@ class BetterLocation : Feature("Better Location", loadParams = FeatureLoadParams
|
|||||||
|
|
||||||
context.mappings.useMapper(CallbackMapper::class) {
|
context.mappings.useMapper(CallbackMapper::class) {
|
||||||
callbacks.getClass("ServerStreamingEventHandler")?.hook("onEvent", HookStage.BEFORE) { param ->
|
callbacks.getClass("ServerStreamingEventHandler")?.hook("onEvent", HookStage.BEFORE) { param ->
|
||||||
val buffer = param.arg<ByteBuffer>(1).let {
|
val buffer = param.argNullable<ByteBuffer>(1)?.let {
|
||||||
it.position(0)
|
it.position(0)
|
||||||
ByteArray(it.capacity()).also { buffer -> it.get(buffer); it.position(0) }
|
ByteArray(it.capacity()).also { buffer -> it.get(buffer); it.position(0) }
|
||||||
}
|
} ?: return@hook
|
||||||
onLocationEvent(ProtoReader(buffer))
|
onLocationEvent(ProtoReader(buffer))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,46 +0,0 @@
|
|||||||
package me.rhunk.snapenhance.core.features.impl.global
|
|
||||||
|
|
||||||
import android.view.ViewGroup
|
|
||||||
import android.widget.Switch
|
|
||||||
import me.rhunk.snapenhance.common.bridge.InternalFileHandleType
|
|
||||||
import me.rhunk.snapenhance.core.event.events.impl.LayoutInflateEvent
|
|
||||||
import me.rhunk.snapenhance.core.features.BridgeFileFeature
|
|
||||||
import me.rhunk.snapenhance.core.features.FeatureLoadParams
|
|
||||||
import me.rhunk.snapenhance.core.ui.ViewAppearanceHelper
|
|
||||||
import me.rhunk.snapenhance.core.util.ktx.getId
|
|
||||||
import me.rhunk.snapenhance.core.util.ktx.getLayoutId
|
|
||||||
|
|
||||||
class SuspendLocationUpdates : BridgeFileFeature(
|
|
||||||
"Suspend Location Updates",
|
|
||||||
loadParams = FeatureLoadParams.ACTIVITY_CREATE_SYNC, bridgeFileType = InternalFileHandleType.SUSPEND_LOCATION_STATE) {
|
|
||||||
fun isSuspended() = exists("true")
|
|
||||||
private fun setSuspended(suspended: Boolean) = setState("true", suspended)
|
|
||||||
|
|
||||||
override fun onActivityCreate() {
|
|
||||||
if (context.config.global.betterLocation.takeIf { it.globalState == true }?.suspendLocationUpdates?.get() != true) return
|
|
||||||
reload()
|
|
||||||
|
|
||||||
val locationSharingSettingsContainerId = context.resources.getLayoutId("v3_screen_location_sharing_settings")
|
|
||||||
val recyclerViewContainerId = context.resources.getId("recycler_view_container")
|
|
||||||
|
|
||||||
context.event.subscribe(LayoutInflateEvent::class) { event ->
|
|
||||||
if (event.layoutId != locationSharingSettingsContainerId) return@subscribe
|
|
||||||
val viewGroup = event.view as? ViewGroup ?: return@subscribe
|
|
||||||
viewGroup.post {
|
|
||||||
val container = viewGroup.findViewById<ViewGroup>(recyclerViewContainerId)
|
|
||||||
container.addView(Switch(event.view.context).apply {
|
|
||||||
isChecked = isSuspended()
|
|
||||||
ViewAppearanceHelper.applyTheme(this)
|
|
||||||
text = this@SuspendLocationUpdates.context.translation["suspend_location_updates.switch_text"]
|
|
||||||
layoutParams = ViewGroup.LayoutParams(
|
|
||||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
|
||||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
|
||||||
)
|
|
||||||
setOnCheckedChangeListener { _, isChecked ->
|
|
||||||
setSuspended(isChecked)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
x
Reference in New Issue
Block a user