mirror of
https://github.com/meshtastic/Meshtastic-Android.git
synced 2026-04-20 22:23:37 +00:00
Uses Hilt to get the database initialization off of the main thread. The initial introduction always has a disproportionate fan-out of boilerplate. In this case, all entry points which were using UIViewModel needed to be annotated in order to let the code gen know that they needed to support it. The PacketRepository is injected into things via the main thread (e.g., the MeshService) but due to the lazy declaration, the database isn't hydrated until the DAO is access while on an IO thread.
119 lines
No EOL
5 KiB
Kotlin
119 lines
No EOL
5 KiB
Kotlin
package com.geeksville.mesh.ui
|
|
|
|
import android.os.Bundle
|
|
import android.view.LayoutInflater
|
|
import android.view.View
|
|
import android.view.ViewGroup
|
|
import android.view.inputmethod.EditorInfo
|
|
import androidx.fragment.app.activityViewModels
|
|
import com.geeksville.android.Logging
|
|
import com.geeksville.android.hideKeyboard
|
|
import com.geeksville.mesh.R
|
|
import com.geeksville.mesh.databinding.AdvancedSettingsBinding
|
|
import com.geeksville.mesh.model.ChannelOption
|
|
import com.geeksville.mesh.model.UIViewModel
|
|
import com.geeksville.mesh.service.MeshService
|
|
import com.geeksville.util.exceptionToSnackbar
|
|
import com.google.android.material.snackbar.Snackbar
|
|
import dagger.hilt.android.AndroidEntryPoint
|
|
|
|
@AndroidEntryPoint
|
|
class AdvancedSettingsFragment : ScreenFragment("Advanced Settings"), Logging {
|
|
private val MAX_INT_DEVICE = 0xFFFFFFFF
|
|
private var _binding: AdvancedSettingsBinding? = null
|
|
|
|
private val binding get() = _binding!!
|
|
|
|
private val model: UIViewModel by activityViewModels()
|
|
|
|
override fun onCreateView(
|
|
inflater: LayoutInflater, container: ViewGroup?,
|
|
savedInstanceState: Bundle?
|
|
): View {
|
|
_binding = AdvancedSettingsBinding.inflate(inflater, container, false)
|
|
return binding.root
|
|
}
|
|
|
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
|
super.onViewCreated(view, savedInstanceState)
|
|
|
|
model.radioConfig.observe(viewLifecycleOwner, {
|
|
binding.positionBroadcastPeriodEditText.setText(model.positionBroadcastSecs.toString())
|
|
binding.lsSleepEditText.setText(model.lsSleepSecs.toString())
|
|
binding.positionBroadcastPeriodView.isEnabled = model.locationShare ?: true
|
|
binding.positionBroadcastSwitch.isChecked = model.locationShare ?: true
|
|
binding.lsSleepView.isEnabled = model.isPowerSaving ?: false
|
|
binding.lsSleepSwitch.isChecked = model.isPowerSaving ?: false
|
|
binding.isAlwaysPoweredSwitch.isChecked = model.isAlwaysPowered ?: false
|
|
})
|
|
|
|
model.isConnected.observe(viewLifecycleOwner, { connectionState ->
|
|
val connected = connectionState == MeshService.ConnectionState.CONNECTED
|
|
binding.positionBroadcastPeriodView.isEnabled = connected && model.locationShare ?: true
|
|
binding.lsSleepView.isEnabled = connected && model.isPowerSaving ?: false
|
|
binding.positionBroadcastSwitch.isEnabled = connected
|
|
binding.lsSleepSwitch.isEnabled = connected
|
|
binding.isAlwaysPoweredSwitch.isEnabled = connected
|
|
})
|
|
|
|
binding.positionBroadcastPeriodEditText.on(EditorInfo.IME_ACTION_DONE) {
|
|
val textEdit = binding.positionBroadcastPeriodEditText
|
|
val n = textEdit.text.toString().toIntOrNull()
|
|
val minBroadcastPeriodSecs =
|
|
ChannelOption.fromConfig(model.primaryChannel?.modemConfig)?.minBroadcastPeriodSecs
|
|
?: ChannelOption.defaultMinBroadcastPeriod
|
|
|
|
if (n != null && n < MAX_INT_DEVICE && (n == 0 || n >= minBroadcastPeriodSecs)) {
|
|
exceptionToSnackbar(requireView()) {
|
|
model.positionBroadcastSecs = n
|
|
}
|
|
} else {
|
|
// restore the value in the edit field
|
|
textEdit.setText(model.positionBroadcastSecs.toString())
|
|
val errorText =
|
|
if (n == null || n < 0 || n >= MAX_INT_DEVICE)
|
|
"Bad value: ${textEdit.text.toString()}"
|
|
else
|
|
getString(R.string.broadcast_period_too_small).format(minBroadcastPeriodSecs)
|
|
|
|
Snackbar.make(requireView(), errorText, Snackbar.LENGTH_LONG).show()
|
|
}
|
|
requireActivity().hideKeyboard()
|
|
}
|
|
|
|
binding.positionBroadcastSwitch.setOnCheckedChangeListener { view, isChecked ->
|
|
if (view.isPressed) {
|
|
model.locationShare = isChecked
|
|
debug("User changed locationShare to $isChecked")
|
|
}
|
|
}
|
|
|
|
// TODO - disable all sleep settings for non-ESP32 devices
|
|
binding.lsSleepEditText.on(EditorInfo.IME_ACTION_DONE) {
|
|
val str = binding.lsSleepEditText.text.toString()
|
|
val n = str.toIntOrNull()
|
|
if (n != null && n < MAX_INT_DEVICE && n >= 0) {
|
|
exceptionToSnackbar(requireView()) {
|
|
model.lsSleepSecs = n
|
|
}
|
|
} else {
|
|
Snackbar.make(requireView(), "Bad value: $str", Snackbar.LENGTH_LONG).show()
|
|
}
|
|
requireActivity().hideKeyboard()
|
|
}
|
|
|
|
binding.lsSleepSwitch.setOnCheckedChangeListener { view, isChecked ->
|
|
if (view.isPressed) {
|
|
model.isPowerSaving = isChecked
|
|
debug("User changed isPowerSaving to $isChecked")
|
|
}
|
|
}
|
|
|
|
binding.isAlwaysPoweredSwitch.setOnCheckedChangeListener { view, isChecked ->
|
|
if (view.isPressed) {
|
|
model.isAlwaysPowered = isChecked
|
|
debug("User changed isAlwaysPowered to $isChecked")
|
|
}
|
|
}
|
|
}
|
|
} |