Skip to content

Commit

Permalink
Add new settings screen to change Sensor Update Frequency (#2317)
Browse files Browse the repository at this point in the history
* Add option for faster sensor updates, and also while charging

* Move settings to its own view, change logic to store in DB

* Set default value

* Try another way

* Try new default method

* Use correct default

* Clean up

* Review comments

* Remove dependency on is_charging sensor

* Switch to a better condition check per review

* Fix db
  • Loading branch information
dshokouhi committed Mar 4, 2022
1 parent 0714d0a commit dda9798
Show file tree
Hide file tree
Showing 18 changed files with 326 additions and 72 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import dagger.hilt.android.HiltAndroidApp
import io.homeassistant.companion.android.common.data.prefs.PrefsRepository
import io.homeassistant.companion.android.common.sensors.LastUpdateManager
import io.homeassistant.companion.android.database.AppDatabase
import io.homeassistant.companion.android.database.settings.SensorUpdateFrequencySetting
import io.homeassistant.companion.android.sensors.SensorReceiver
import io.homeassistant.companion.android.websocket.WebsocketBroadcastReceiver
import io.homeassistant.companion.android.widgets.button.ButtonWidget
Expand Down Expand Up @@ -175,6 +176,14 @@ open class HomeAssistantApplication : Application() {
)
}

// Register for faster sensor updates if enabled
val settingDao = AppDatabase.getInstance(applicationContext).settingsDao().get(0)
if (settingDao != null && (settingDao.sensorUpdateFrequency == SensorUpdateFrequencySetting.FAST_WHILE_CHARGING || settingDao.sensorUpdateFrequency == SensorUpdateFrequencySetting.FAST_ALWAYS))
registerReceiver(
sensorReceiver,
IntentFilter(Intent.ACTION_TIME_TICK)
)

// Update widgets when the screen turns on, updates are skipped if widgets were not added
val buttonWidget = ButtonWidget()
val entityWidget = EntityWidget()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ class SensorsSettingsFragment : PreferenceFragmentCompat() {

menu.findItem(R.id.get_help)?.let {
it.isVisible = true
it.intent = Intent(Intent.ACTION_VIEW, Uri.parse("https://companion.home-assistant.io/docs/core/sensors"))
it.intent = Intent(Intent.ACTION_VIEW, Uri.parse("https://companion.home-assistant.io/docs/core/sensors#android-sensors"))
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,33 +1,34 @@
package io.homeassistant.companion.android.settings.websocket
package io.homeassistant.companion.android.settings

import android.app.Application
import androidx.lifecycle.AndroidViewModel
import io.homeassistant.companion.android.BuildConfig
import io.homeassistant.companion.android.database.AppDatabase
import io.homeassistant.companion.android.database.settings.SensorUpdateFrequencySetting
import io.homeassistant.companion.android.database.settings.Setting
import io.homeassistant.companion.android.database.settings.WebsocketSetting
import io.homeassistant.companion.android.websocket.WebsocketManager
import kotlinx.coroutines.flow.Flow
import javax.inject.Inject

class WebsocketSettingViewModel @Inject constructor(
class SettingViewModel @Inject constructor(
application: Application
) : AndroidViewModel(
application
) {
private val settingsDao = AppDatabase.getInstance(application).settingsDao()

fun getWebsocketSetting(id: Int): Setting {
fun getSetting(id: Int): Setting {
var setting = settingsDao.get(id)
if (setting == null) {
setting = Setting(id, if (BuildConfig.FLAVOR == "full") WebsocketSetting.NEVER else WebsocketSetting.ALWAYS)
setting = Setting(id, if (BuildConfig.FLAVOR == "full") WebsocketSetting.NEVER else WebsocketSetting.ALWAYS, SensorUpdateFrequencySetting.NORMAL)
settingsDao.insert(setting)
}
return setting
}

// Once we support more than one instance we can get the setting per instance
fun getWebsocketSettingFlow(id: Int): Flow<Setting> = settingsDao.getFlow(id)
fun getSettingFlow(id: Int): Flow<Setting> = settingsDao.getFlow(id)

fun updateWebsocketSetting(id: Int, setting: WebsocketSetting) {
settingsDao.get(id)?.let {
Expand All @@ -36,4 +37,11 @@ class WebsocketSettingViewModel @Inject constructor(
}
WebsocketManager.start(getApplication())
}

fun updateSensorSetting(id: Int, setting: SensorUpdateFrequencySetting) {
settingsDao.get(id)?.let {
it.sensorUpdateFrequency = setting
settingsDao.update(it)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import io.homeassistant.companion.android.settings.language.LanguagesProvider
import io.homeassistant.companion.android.settings.log.LogFragment
import io.homeassistant.companion.android.settings.notification.NotificationHistoryFragment
import io.homeassistant.companion.android.settings.qs.ManageTilesFragment
import io.homeassistant.companion.android.settings.sensor.SensorUpdateFrequencyFragment
import io.homeassistant.companion.android.settings.shortcuts.ManageShortcutsSettingsFragment
import io.homeassistant.companion.android.settings.ssid.SsidDialogFragment
import io.homeassistant.companion.android.settings.ssid.SsidPreference
Expand Down Expand Up @@ -151,6 +152,16 @@ class SettingsFragment constructor(
.commit()
return@setOnPreferenceClickListener true
}
findPreference<Preference>("sensor_update_frequency")?.let {
it.setOnPreferenceClickListener {
parentFragmentManager
.beginTransaction()
.replace(R.id.content, SensorUpdateFrequencyFragment::class.java, null)
.addToBackStack(getString(commonR.string.sensor_update_frequency))
.commit()
return@setOnPreferenceClickListener true
}
}

findPreference<PreferenceCategory>("widgets")?.isVisible = Build.MODEL != "Quest"
findPreference<PreferenceCategory>("security_category")?.isVisible = Build.MODEL != "Quest"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package io.homeassistant.companion.android.settings.sensor

import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.view.LayoutInflater
import android.view.Menu
import android.view.View
import android.view.ViewGroup
import androidx.compose.runtime.collectAsState
import androidx.compose.ui.platform.ComposeView
import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
import com.google.android.material.composethemeadapter.MdcTheme
import io.homeassistant.companion.android.R
import io.homeassistant.companion.android.settings.SettingViewModel
import io.homeassistant.companion.android.settings.sensor.views.SensorUpdateFrequencyView
import io.homeassistant.companion.android.common.R as commonR

class SensorUpdateFrequencyFragment : Fragment() {

val viewModel: SettingViewModel by viewModels()

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setHasOptionsMenu(true)
}

override fun onPrepareOptionsMenu(menu: Menu) {
super.onPrepareOptionsMenu(menu)

menu.findItem(R.id.get_help)?.let {
it.isVisible = true
it.intent = Intent(Intent.ACTION_VIEW, Uri.parse("https://companion.home-assistant.io/docs/core/sensors#android-sensors"))
}
}

override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
return ComposeView(requireContext()).apply {
setContent {
MdcTheme {
val settings = viewModel.getSettingFlow(0)
.collectAsState(initial = viewModel.getSetting(0))
SensorUpdateFrequencyView(
sensorUpdateFrequency = settings.value.sensorUpdateFrequency,
onSettingChanged = { viewModel.updateSensorSetting(0, it) }
)
}
}
}
}

override fun onResume() {
super.onResume()
activity?.title = getString(commonR.string.sensor_update_frequency)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package io.homeassistant.companion.android.settings.sensor.views

import android.os.Build
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.Divider
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import io.homeassistant.companion.android.common.R
import io.homeassistant.companion.android.common.sensors.SensorWorkerBase
import io.homeassistant.companion.android.database.settings.SensorUpdateFrequencySetting
import io.homeassistant.companion.android.util.compose.InfoNotification
import io.homeassistant.companion.android.util.compose.RadioButtonRow

@Composable
fun SensorUpdateFrequencyView(
sensorUpdateFrequency: SensorUpdateFrequencySetting,
onSettingChanged: (SensorUpdateFrequencySetting) -> Unit
) {
val scrollState = rememberScrollState()
Column(
modifier = Modifier
.padding(20.dp)
.verticalScroll(scrollState)
) {
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.padding(bottom = 20.dp)
) {
Text(stringResource(R.string.sensor_update_frequency_description))
}
Divider()
RadioButtonRow(
text = stringResource(R.string.sensor_update_frequency_normal),
selected = sensorUpdateFrequency == SensorUpdateFrequencySetting.NORMAL,
onClick = { onSettingChanged(SensorUpdateFrequencySetting.NORMAL) }
)
RadioButtonRow(
text = stringResource(R.string.sensor_update_frequency_fast_charging),
selected = sensorUpdateFrequency == SensorUpdateFrequencySetting.FAST_WHILE_CHARGING,
onClick = { onSettingChanged(SensorUpdateFrequencySetting.FAST_WHILE_CHARGING) }
)
RadioButtonRow(
text = stringResource(R.string.sensor_update_frequency_fast_always),
selected = sensorUpdateFrequency == SensorUpdateFrequencySetting.FAST_ALWAYS,
onClick = { onSettingChanged(SensorUpdateFrequencySetting.FAST_ALWAYS) }
)

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
InfoNotification(
infoString = R.string.sensor_update_notification,
channelId = SensorWorkerBase.channelId,
buttonString = R.string.sensor_worker_notification_channel
)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,13 @@ import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
import com.google.android.material.composethemeadapter.MdcTheme
import io.homeassistant.companion.android.R
import io.homeassistant.companion.android.settings.SettingViewModel
import io.homeassistant.companion.android.settings.websocket.views.WebsocketSettingView
import io.homeassistant.companion.android.common.R as commonR

class WebsocketSettingFragment : Fragment() {

val viewModel: WebsocketSettingViewModel by viewModels()
val viewModel: SettingViewModel by viewModels()

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Expand All @@ -42,8 +43,8 @@ class WebsocketSettingFragment : Fragment() {
return ComposeView(requireContext()).apply {
setContent {
MdcTheme {
val settings = viewModel.getWebsocketSettingFlow(0)
.collectAsState(initial = viewModel.getWebsocketSetting(0))
val settings = viewModel.getSettingFlow(0)
.collectAsState(initial = viewModel.getSetting(0))
WebsocketSettingView(
websocketSetting = settings.value.websocketSetting,
onSettingChanged = { viewModel.updateWebsocketSetting(0, it) }
Expand Down
Original file line number Diff line number Diff line change
@@ -1,35 +1,27 @@
package io.homeassistant.companion.android.settings.websocket.views

import android.app.UiModeManager
import android.content.Intent
import android.content.res.Configuration
import android.os.Build
import android.provider.Settings
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.selection.selectable
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.Divider
import androidx.compose.material.Icon
import androidx.compose.material.RadioButton
import androidx.compose.material.Text
import androidx.compose.material.TextButton
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.Info
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.core.content.getSystemService
import io.homeassistant.companion.android.BuildConfig
import io.homeassistant.companion.android.common.R
import io.homeassistant.companion.android.database.settings.WebsocketSetting
import io.homeassistant.companion.android.util.compose.InfoNotification
import io.homeassistant.companion.android.util.compose.RadioButtonRow
import io.homeassistant.companion.android.websocket.WebsocketManager

@Composable
Expand Down Expand Up @@ -73,49 +65,11 @@ fun WebsocketSettingView(
)
val uiManager = context.getSystemService<UiModeManager>()
if (websocketSetting != WebsocketSetting.NEVER && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && uiManager?.currentModeType != Configuration.UI_MODE_TYPE_TELEVISION) {
Icon(
Icons.Outlined.Info,
contentDescription = stringResource(id = R.string.info),
modifier = Modifier.padding(top = 40.dp)
InfoNotification(
infoString = R.string.websocket_persistent_notification,
channelId = WebsocketManager.CHANNEL_ID,
buttonString = R.string.websocket_notification_channel
)
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.padding(top = 20.dp)
) {
Text(
text = stringResource(id = R.string.websocket_persistent_notification),
fontSize = 15.sp
)
}
Row(verticalAlignment = Alignment.CenterVertically) {
TextButton(onClick = {
val intent = Intent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS)
intent.putExtra(Settings.EXTRA_APP_PACKAGE, context.packageName)
intent.putExtra(Settings.EXTRA_CHANNEL_ID, WebsocketManager.CHANNEL_ID)
context.startActivity(intent)
}) {
Text(stringResource(R.string.websocket_notification_channel))
}
}
}
}
}

@Composable
fun RadioButtonRow(
text: String,
selected: Boolean,
onClick: () -> Unit
) {
Row(
modifier = Modifier
.fillMaxWidth()
.selectable(selected = selected, onClick = onClick)
.padding(top = 20.dp, bottom = 20.dp),
verticalAlignment = Alignment.CenterVertically
) {
RadioButton(selected = selected, onClick = onClick)
Text(text)
}
Divider()
}

0 comments on commit dda9798

Please sign in to comment.