Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add new settings screen to change Sensor Update Frequency #2317

Merged
merged 11 commits into from
Mar 4, 2022
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 @@ -37,6 +37,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 @@ -146,6 +147,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()
}