mirror of
https://github.com/meshtastic/Meshtastic-Android.git
synced 2026-04-03 21:53:55 -04:00
Merge branch 'master' into dev-factory-reset
This commit is contained in:
@@ -37,12 +37,12 @@ open class BaseActivity: AppCompatActivity(), Logging {
|
||||
}
|
||||
}
|
||||
|
||||
private fun createLocale(language: String):Locale {
|
||||
var langArray = language.split("_")
|
||||
if (langArray.size == 2) {
|
||||
return Locale(langArray[0], langArray[1]);
|
||||
private fun createLocale(language: String): Locale {
|
||||
val langArray = language.split("_")
|
||||
return if (langArray.size == 2) {
|
||||
Locale(langArray[0], langArray[1])
|
||||
} else {
|
||||
return Locale(langArray[0]);
|
||||
Locale(langArray[0])
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -409,11 +409,10 @@ class MainActivity : BaseActivity(), Logging,
|
||||
installSplashScreen()
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
if (preferences.getBoolean("app_intro_completed", false) == false) {
|
||||
if (!preferences.getBoolean("app_intro_completed", false)) {
|
||||
startActivity(Intent(this, AppIntroduction::class.java))
|
||||
}
|
||||
|
||||
|
||||
binding = ActivityMainBinding.inflate(layoutInflater)
|
||||
|
||||
val prefs = UIViewModel.getPreferences(this)
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package com.geeksville.mesh.android
|
||||
|
||||
import android.Manifest
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.NotificationManager
|
||||
import android.bluetooth.BluetoothManager
|
||||
import android.companion.CompanionDeviceManager
|
||||
@@ -19,7 +18,6 @@ import com.geeksville.mesh.MainActivity
|
||||
val Context.bluetoothManager: BluetoothManager? get() = getSystemService(Context.BLUETOOTH_SERVICE) as? BluetoothManager?
|
||||
|
||||
val Context.deviceManager: CompanionDeviceManager?
|
||||
@SuppressLint("InlinedApi")
|
||||
get() {
|
||||
if (GeeksvilleApplication.currentActivity is MainActivity) {
|
||||
val activity = GeeksvilleApplication.currentActivity
|
||||
@@ -47,7 +45,7 @@ fun Context.hasGps(): Boolean =
|
||||
packageManager.hasSystemFeature(PackageManager.FEATURE_LOCATION_GPS)
|
||||
|
||||
/**
|
||||
* return app install source (sideload = null)
|
||||
* return app install source (play store = com.android.vending)
|
||||
*/
|
||||
fun Context.installSource(): String? {
|
||||
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R)
|
||||
|
||||
@@ -71,13 +71,10 @@ class UIViewModel @Inject constructor(
|
||||
private val _allPacketState = MutableStateFlow<List<Packet>>(emptyList())
|
||||
val allPackets: StateFlow<List<Packet>> = _allPacketState
|
||||
|
||||
private val _localConfig = MutableLiveData<LocalOnlyProtos.LocalConfig?>()
|
||||
val localConfig: LiveData<LocalOnlyProtos.LocalConfig?> get() = _localConfig
|
||||
private val _localConfig = MutableLiveData<LocalOnlyProtos.LocalConfig>()
|
||||
val localConfig: LiveData<LocalOnlyProtos.LocalConfig> get() = _localConfig
|
||||
|
||||
private val _quickChatActions =
|
||||
MutableStateFlow<List<com.geeksville.mesh.database.entity.QuickChatAction>>(
|
||||
emptyList()
|
||||
)
|
||||
private val _quickChatActions = MutableStateFlow<List<QuickChatAction>>(emptyList())
|
||||
val quickChatActions: StateFlow<List<QuickChatAction>> = _quickChatActions
|
||||
|
||||
init {
|
||||
|
||||
@@ -61,6 +61,7 @@ class LocalConfigRepository @Inject constructor(
|
||||
if (config.hasWifi()) setWifiConfig(config.wifi)
|
||||
if (config.hasDisplay()) setDisplayConfig(config.display)
|
||||
if (config.hasLora()) setLoraConfig(config.lora)
|
||||
if (config.hasBluetooth()) setBluetoothConfig(config.bluetooth)
|
||||
}
|
||||
|
||||
private suspend fun setDeviceConfig(config: ConfigProtos.Config.DeviceConfig) {
|
||||
@@ -99,6 +100,12 @@ class LocalConfigRepository @Inject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun setBluetoothConfig(config: ConfigProtos.Config.BluetoothConfig) {
|
||||
localConfigStore.updateData { preference ->
|
||||
preference.toBuilder().setBluetooth(config).build()
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun fetchInitialLocalConfig() = localConfigStore.data.first()
|
||||
|
||||
}
|
||||
|
||||
@@ -116,6 +116,7 @@ class AdvancedSettingsFragment : ScreenFragment("Advanced Settings"), Logging {
|
||||
.setNeutralButton(R.string.cancel) { _, _ ->
|
||||
}
|
||||
.setPositiveButton(getString(R.string.okay)) { _, _ ->
|
||||
debug("User clicked requestShutdown")
|
||||
model.requestShutdown()
|
||||
}
|
||||
.show()
|
||||
@@ -127,6 +128,7 @@ class AdvancedSettingsFragment : ScreenFragment("Advanced Settings"), Logging {
|
||||
.setNeutralButton(R.string.cancel) { _, _ ->
|
||||
}
|
||||
.setPositiveButton(getString(R.string.okay)) { _, _ ->
|
||||
debug("User clicked requestReboot")
|
||||
model.requestReboot()
|
||||
}
|
||||
.show()
|
||||
|
||||
@@ -304,49 +304,62 @@ class ChannelFragment : ScreenFragment("Channel"), Logging {
|
||||
}
|
||||
} else {
|
||||
// User just locked it, we should warn and then apply changes to radio
|
||||
MaterialAlertDialogBuilder(requireContext())
|
||||
.setTitle(R.string.change_channel)
|
||||
.setMessage(R.string.are_you_sure_channel)
|
||||
.setNeutralButton(R.string.cancel) { _, _ ->
|
||||
setGUIfromModel()
|
||||
|
||||
model.channels.value?.primaryChannel?.let { oldPrimary ->
|
||||
var newSettings = oldPrimary.settings.toBuilder()
|
||||
val newName = binding.channelNameEdit.text.toString().trim()
|
||||
|
||||
// Find the new modem config
|
||||
val selectedModemPresetString =
|
||||
binding.filledExposedDropdown.editableText.toString()
|
||||
var newModemPreset = getModemPreset(selectedModemPresetString)
|
||||
if (newModemPreset == ConfigProtos.Config.LoRaConfig.ModemPreset.UNRECOGNIZED) // Huh? didn't find it - keep same
|
||||
newModemPreset = oldPrimary.loraConfig.modemPreset
|
||||
|
||||
// Generate a new AES256 key if the user changes channel name or the name is non-default and the settings changed
|
||||
val shouldUseRandomKey =
|
||||
newName != originalName || (newName.isNotEmpty() && newModemPreset != oldPrimary.loraConfig.modemPreset)
|
||||
if (shouldUseRandomKey) {
|
||||
|
||||
// Install a new customized channel
|
||||
debug("ASSIGNING NEW AES256 KEY")
|
||||
val random = SecureRandom()
|
||||
val bytes = ByteArray(32)
|
||||
random.nextBytes(bytes)
|
||||
newSettings.name = newName.take(11) // proto max_size:12
|
||||
newSettings.psk = ByteString.copyFrom(bytes)
|
||||
} else {
|
||||
debug("Switching back to default channel")
|
||||
newSettings = Channel.default.settings.toBuilder()
|
||||
}
|
||||
.setPositiveButton(getString(R.string.accept)) { _, _ ->
|
||||
// Generate a new channel with only the changes the user can change in the GUI
|
||||
model.channels.value?.primaryChannel?.let { oldPrimary ->
|
||||
var newSettings = oldPrimary.settings.toBuilder()
|
||||
val newName = binding.channelNameEdit.text.toString().trim()
|
||||
|
||||
// Find the new modem config
|
||||
val selectedModemPresetString =
|
||||
binding.filledExposedDropdown.editableText.toString()
|
||||
var newModemPreset = getModemPreset(selectedModemPresetString)
|
||||
if (newModemPreset == ConfigProtos.Config.LoRaConfig.ModemPreset.UNRECOGNIZED) // Huh? didn't find it - keep same
|
||||
newModemPreset = oldPrimary.loraConfig.modemPreset
|
||||
// No matter what apply the speed selection from the user
|
||||
val newLoRaConfig = ConfigProtos.Config.LoRaConfig.newBuilder()
|
||||
.setRegion(model.region)
|
||||
.setModemPreset(newModemPreset)
|
||||
|
||||
// Generate a new AES256 key if the user changes channel name or the name is non-default and the settings changed
|
||||
if (newName != originalName || (newName.isNotEmpty() && newModemPreset != oldPrimary.loraConfig.modemPreset)) {
|
||||
val humanName = Channel(newSettings.build(), newLoRaConfig.build()).humanName
|
||||
binding.channelNameEdit.setText(humanName)
|
||||
|
||||
// Install a new customized channel
|
||||
debug("ASSIGNING NEW AES256 KEY")
|
||||
val random = SecureRandom()
|
||||
val bytes = ByteArray(32)
|
||||
random.nextBytes(bytes)
|
||||
newSettings.name = newName.take(11) // proto max_size:12
|
||||
newSettings.psk = ByteString.copyFrom(bytes)
|
||||
} else {
|
||||
debug("Switching back to default channel")
|
||||
newSettings = Channel.default.settings.toBuilder()
|
||||
}
|
||||
val message = buildString {
|
||||
append(getString(R.string.are_you_sure_channel))
|
||||
if (!shouldUseRandomKey)
|
||||
append("\n\n" + getString(R.string.warning_default_psk).format(humanName))
|
||||
}
|
||||
|
||||
// No matter what apply the speed selection from the user
|
||||
val newLoRaConfig = ConfigProtos.Config.LoRaConfig.newBuilder()
|
||||
.setRegion(model.region)
|
||||
.setModemPreset(newModemPreset)
|
||||
|
||||
installSettings(newSettings.build(),newLoRaConfig.build())
|
||||
MaterialAlertDialogBuilder(requireContext())
|
||||
.setTitle(R.string.change_channel)
|
||||
.setMessage(message)
|
||||
.setNeutralButton(R.string.cancel) { _, _ ->
|
||||
setGUIfromModel()
|
||||
}
|
||||
}
|
||||
.show()
|
||||
.setPositiveButton(getString(R.string.accept)) { _, _ ->
|
||||
// Generate a new channel with only the changes the user can change in the GUI
|
||||
|
||||
installSettings(newSettings.build(), newLoRaConfig.build())
|
||||
}
|
||||
.show()
|
||||
}
|
||||
}
|
||||
|
||||
onEditingChanged() // update GUI on what user is allowed to edit/share
|
||||
|
||||
@@ -281,7 +281,17 @@ class SettingsFragment : ScreenFragment("Settings"), Logging {
|
||||
}
|
||||
|
||||
model.localConfig.observe(viewLifecycleOwner) {
|
||||
updateNodeInfo()
|
||||
if (!model.isConnected()) {
|
||||
val configCount = it.allFields.size
|
||||
binding.scanStatusText.text = "Device config ($configCount / 7)"
|
||||
} else updateNodeInfo()
|
||||
}
|
||||
|
||||
model.channels.observe(viewLifecycleOwner) {
|
||||
if (!model.isConnected()) {
|
||||
val channelCount = it?.protobuf?.settingsCount ?: 0
|
||||
binding.scanStatusText.text = "Channels ($channelCount / 8)"
|
||||
}
|
||||
}
|
||||
|
||||
// Also watch myNodeInfo because it might change later
|
||||
|
||||
Reference in New Issue
Block a user