diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index bcdf0ae0b..b71182a06 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -121,7 +121,7 @@ android:name="com.geeksville.mesh.MainActivity" android:label="@string/app_name" android:screenOrientation="portrait" - android:windowSoftInputMode="stateAlwaysHidden" + android:windowSoftInputMode="stateAlwaysHidden|adjustPan" android:theme="@style/AppTheme.NoActionBar"> diff --git a/app/src/main/java/com/geeksville/mesh/model/UIState.kt b/app/src/main/java/com/geeksville/mesh/model/UIState.kt index 40ee1f4ed..37e02dcb2 100644 --- a/app/src/main/java/com/geeksville/mesh/model/UIState.kt +++ b/app/src/main/java/com/geeksville/mesh/model/UIState.kt @@ -102,6 +102,49 @@ class UIViewModel(app: Application) : AndroidViewModel(app), Logging { val radioConfig = object : MutableLiveData(null) { } + var positionBroadcastSecs: Int? + get() { + radioConfig.value?.preferences?.let { + if (it.locationShare == MeshProtos.LocationSharing.LocDisabled) return 0 + if (it.positionBroadcastSecs > 0) return it.positionBroadcastSecs + // These default values are borrowed from the device code. + if (it.isRouter) return 60 * 60 + return 15 * 60 + } + return null + } + set(value) { + val config = radioConfig.value + if (value != null && config != null) { + val builder = config.toBuilder() + if (value > 0) { + builder.preferencesBuilder.positionBroadcastSecs = value + builder.preferencesBuilder.locationShare = + MeshProtos.LocationSharing.LocEnabled + } else + builder.preferencesBuilder.locationShare = + MeshProtos.LocationSharing.LocDisabled + + setRadioConfig(builder.build()) + } + } + + var lsSleepSecs: Int? + get() { + radioConfig.value?.preferences?.let { + return it.lsSecs + } + return null + } + set(value) { + val config = radioConfig.value + if (value != null && config != null) { + val builder = config.toBuilder() + builder.preferencesBuilder.lsSecs = value + setRadioConfig(builder.build()) + } + } + /// hardware info about our local device val myNodeInfo = object : MutableLiveData(null) {} diff --git a/app/src/main/java/com/geeksville/mesh/ui/SettingsFragment.kt b/app/src/main/java/com/geeksville/mesh/ui/SettingsFragment.kt index fdf4ce85c..004340bd0 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/SettingsFragment.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/SettingsFragment.kt @@ -30,6 +30,7 @@ import com.geeksville.android.Logging import com.geeksville.android.hideKeyboard import com.geeksville.android.isGooglePlayAvailable import com.geeksville.mesh.MainActivity +import com.geeksville.mesh.MeshProtos import com.geeksville.mesh.R import com.geeksville.mesh.android.bluetoothManager import com.geeksville.mesh.android.usbManager @@ -461,7 +462,7 @@ class BTScanModel(app: Application) : AndroidViewModel(app), Logging { @SuppressLint("NewApi") class SettingsFragment : ScreenFragment("Settings"), Logging { - + private val MAX_INT_DEVICE = 0xFFFFFFFF private var _binding: SettingsFragmentBinding? = null // This property is only valid between onCreateView and onDestroyView. @@ -573,15 +574,25 @@ class SettingsFragment : ScreenFragment("Settings"), Logging { /// Setup the ui widgets unrelated to BLE scanning private fun initCommonUI() { - model.ownerName.observe(viewLifecycleOwner, Observer { name -> + model.ownerName.observe(viewLifecycleOwner, { name -> binding.usernameEditText.setText(name) }) + model.radioConfig.observe(viewLifecycleOwner, { _ -> + binding.positionBroadcastPeriodEditText.setText(model.positionBroadcastSecs.toString()) + binding.lsSleepEditText.setText(model.lsSleepSecs.toString()) + }) + // Only let user edit their name or set software update while connected to a radio - model.isConnected.observe(viewLifecycleOwner, Observer { connected -> - binding.usernameView.isEnabled = connected == MeshService.ConnectionState.CONNECTED - if (connected == MeshService.ConnectionState.DISCONNECTED) + model.isConnected.observe(viewLifecycleOwner, Observer { connectionState -> + val connected = connectionState == MeshService.ConnectionState.CONNECTED + binding.usernameView.isEnabled = connected + binding.positionBroadcastPeriodView.isEnabled = connected + binding.lsSleepView.isEnabled = connected + + if (connectionState == MeshService.ConnectionState.DISCONNECTED) model.ownerName.value = "" + initNodeInfo() }) @@ -599,7 +610,28 @@ class SettingsFragment : ScreenFragment("Settings"), Logging { val n = binding.usernameEditText.text.toString().trim() if (n.isNotEmpty()) model.setOwner(n) + requireActivity().hideKeyboard() + } + binding.positionBroadcastPeriodEditText.on(EditorInfo.IME_ACTION_DONE) { + val str = binding.positionBroadcastPeriodEditText.text.toString() + val n = str.toIntOrNull() + if (n != null && n <= MAX_INT_DEVICE && n >= 0) { + model.positionBroadcastSecs = n + } else { + binding.scanStatusText.text = "Bad value: $str" + } + requireActivity().hideKeyboard() + } + + 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) { + model.lsSleepSecs = n + } else { + binding.scanStatusText.text = "Bad value: $str" + } requireActivity().hideKeyboard() } diff --git a/app/src/main/res/layout/settings_fragment.xml b/app/src/main/res/layout/settings_fragment.xml index b15dc757d..97a82dd09 100644 --- a/app/src/main/res/layout/settings_fragment.xml +++ b/app/src/main/res/layout/settings_fragment.xml @@ -1,6 +1,7 @@ @@ -19,6 +20,7 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/deviceRadioGroup" /> + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 3c3b111cb..b96c0e298 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -83,4 +83,6 @@ message reception time message reception state Message delivery status + Broadcast position period (in seconds), 0 - disable + Device sleep period (in seconds)