diff options
author | Leonard Kugis <leonard@kug.is> | 2024-01-02 17:53:12 +0100 |
---|---|---|
committer | Leonard Kugis <leonard@kug.is> | 2024-01-02 17:53:12 +0100 |
commit | 5db0bdfdf62ae0915b587399a0ff4ce53bca813b (patch) | |
tree | 538a18ce0adbf6e600ee77a48e51d8c67649b0c6 /app/src/main/java/foundation/e/advancedprivacy/features/location/FakeLocationFragment.kt | |
parent | 298dff2a877680e928b37e3a1336dc7d7aa52dfb (diff) |
Implemented route mode
Diffstat (limited to 'app/src/main/java/foundation/e/advancedprivacy/features/location/FakeLocationFragment.kt')
-rw-r--r-- | app/src/main/java/foundation/e/advancedprivacy/features/location/FakeLocationFragment.kt | 84 |
1 files changed, 84 insertions, 0 deletions
diff --git a/app/src/main/java/foundation/e/advancedprivacy/features/location/FakeLocationFragment.kt b/app/src/main/java/foundation/e/advancedprivacy/features/location/FakeLocationFragment.kt index 7b456d1..b70ae36 100644 --- a/app/src/main/java/foundation/e/advancedprivacy/features/location/FakeLocationFragment.kt +++ b/app/src/main/java/foundation/e/advancedprivacy/features/location/FakeLocationFragment.kt @@ -35,6 +35,10 @@ import androidx.core.widget.addTextChangedListener import androidx.lifecycle.Lifecycle import androidx.lifecycle.lifecycleScope import androidx.lifecycle.repeatOnLifecycle +import android.app.Activity +import android.content.Intent +import androidx.appcompat.app.AppCompatActivity +import androidx.documentfile.provider.DocumentFile import com.google.android.material.textfield.TextInputLayout import com.google.android.material.textfield.TextInputLayout.END_ICON_CUSTOM import com.google.android.material.textfield.TextInputLayout.END_ICON_NONE @@ -60,6 +64,10 @@ import kotlinx.coroutines.delay import kotlinx.coroutines.launch import org.koin.androidx.viewmodel.ext.android.viewModel import timber.log.Timber +import com.google.gson.Gson +import com.google.gson.reflect.TypeToken +import foundation.e.advancedprivacy.domain.entities.FakeLocationCoordinate +import java.io.File class FakeLocationFragment : NavToolbarFragment(R.layout.fragment_fake_location) { @@ -206,6 +214,25 @@ class FakeLocationFragment : NavToolbarFragment(R.layout.fragment_fake_location) } } + private fun validateBounds(inputLayout: TextInputLayout, minValue: Float, maxValue: Float): Boolean { + return try { + val value = inputLayout.editText?.text?.toString()?.toFloat()!! + + if (value > maxValue || value < minValue) { + throw NumberFormatException("value $value is out of bounds") + } + inputLayout.error = null + + inputLayout.setEndIconDrawable(R.drawable.ic_valid) + inputLayout.endIconMode = END_ICON_CUSTOM + true + } catch (e: Exception) { + inputLayout.endIconMode = END_ICON_NONE + inputLayout.error = getString(R.string.location_error_bounds) + false + } + } + private fun validateCoordinate( inputLayout: TextInputLayout, maxValue: Float @@ -261,16 +288,19 @@ class FakeLocationFragment : NavToolbarFragment(R.layout.fragment_fake_location) @Suppress("UNUSED_PARAMETER") private fun onAltitudeTextChanged(editable: Editable?) { + if(!validateBounds(binding.textlayoutAltitude, -100000.0f, 100000.0f)) return updateMockLocationParameters() } @Suppress("UNUSED_PARAMETER") private fun onSpeedTextChanged(editable: Editable?) { + if(!validateBounds(binding.textlayoutSpeed, 0.0f, 299792458.0f)) return updateMockLocationParameters() } @Suppress("UNUSED_PARAMETER") private fun onJitterTextChanged(editable: Editable?) { + if(!validateBounds(binding.textlayoutJitter, 0.0f, 10000000.0f)) return updateMockLocationParameters() } @@ -305,6 +335,35 @@ class FakeLocationFragment : NavToolbarFragment(R.layout.fragment_fake_location) } } + private var route: List<FakeLocationCoordinate>? = null + + private val filePickerLauncher = + registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> + if (result.resultCode == Activity.RESULT_OK) { + result.data?.data?.let { uri -> + if(uri.path != null) { + var routeFile = File(uri.path ?: ".") + //val filePath = selectedFile?.uri?.path ?: "Path not found" + //binding.locationRoutePath.text = "Path: $filePath" + route = Gson().fromJson(routeFile.readText(Charsets.UTF_8), object : TypeToken<List<FakeLocationCoordinate>>() {}.type) + var route_buf = route + route_buf?.let { + viewModel.submitAction(Action.SetRoute(route_buf)) + } + } + } + } + } + + private fun openFilePicker() { + val intent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply { + addCategory(Intent.CATEGORY_OPENABLE) + type = "*/*" + } + + filePickerLauncher.launch(intent) + } + @SuppressLint("ClickableViewAccessibility") private fun bindClickListeners() { binding.radioUseRealLocation.setOnClickListener { @@ -320,6 +379,9 @@ class FakeLocationFragment : NavToolbarFragment(R.layout.fragment_fake_location) ) } } + binding.radioUseRoute.setOnClickListener { + viewModel.submitAction(Action.UseRoute) + } binding.edittextAltitude.addTextChangedListener(afterTextChanged = ::onAltitudeTextChanged) binding.edittextSpeed.addTextChangedListener(afterTextChanged = ::onSpeedTextChanged) @@ -331,6 +393,11 @@ class FakeLocationFragment : NavToolbarFragment(R.layout.fragment_fake_location) binding.edittextJitter.onFocusChangeListener = latLonOnFocusChangeListener binding.edittextLatitude.onFocusChangeListener = latLonOnFocusChangeListener binding.edittextLongitude.onFocusChangeListener = latLonOnFocusChangeListener + + binding.buttonLocationRoutePathSelect.setOnClickListener { openFilePicker() } + binding.checkboxRouteLoop.setOnCheckedChangeListener { _, isChecked -> viewModel.submitAction(Action.SetRouteLoopEnabledAction(isChecked)) } + binding.buttonLocationRouteStart.setOnClickListener { viewModel.submitAction(Action.RouteStartAction) } + binding.buttonLocationRouteStop.setOnClickListener { viewModel.submitAction(Action.RouteStopAction) } } @SuppressLint("MissingPermission") @@ -341,12 +408,23 @@ class FakeLocationFragment : NavToolbarFragment(R.layout.fragment_fake_location) binding.radioUseRealLocation.isChecked = state.mode == LocationMode.REAL_LOCATION + binding.radioUseRoute.isChecked = state.mode == LocationMode.ROUTE + binding.mapView.isEnabled = (state.mode == LocationMode.SPECIFIC_LOCATION) binding.textlayoutAltitude.isVisible = state.mode == LocationMode.SPECIFIC_LOCATION binding.textlayoutSpeed.isVisible = state.mode == LocationMode.SPECIFIC_LOCATION binding.textlayoutJitter.isVisible = state.mode == LocationMode.SPECIFIC_LOCATION + binding.buttonLocationRoutePathSelect.isVisible = state.mode == LocationMode.ROUTE + binding.locationRoutePath.isVisible = state.mode == LocationMode.ROUTE + binding.checkboxRouteLoop.isVisible = state.mode == LocationMode.ROUTE + binding.buttonLocationRouteStart.isVisible = state.mode == LocationMode.ROUTE + binding.buttonLocationRouteStop.isVisible = state.mode == LocationMode.ROUTE + + if(binding.checkboxRouteLoop.isVisible) + binding.checkboxRouteLoop.isChecked = state.loopRoute + if(!binding.edittextAltitude.isFocused) binding.edittextAltitude.setText(state.altitude?.toString()) @@ -379,6 +457,12 @@ class FakeLocationFragment : NavToolbarFragment(R.layout.fragment_fake_location) binding.edittextLatitude.setText(state.specificLatitude?.toString()) binding.edittextLongitude.setText(state.specificLongitude?.toString()) } + + if(route == null) { + binding.locationRoutePath.text = "No valid route selected" + } else { + binding.locationRoutePath.text = "Route valid" + } } @SuppressLint("MissingPermission") |