diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index f32435df433..cfc804f9089 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -143,6 +143,19 @@
android:resource="@xml/entity_widget_info" />
+
+
+
+
+
+
+
+
+
+
@@ -206,6 +219,13 @@
+
+
+
+
+
diff --git a/app/src/main/java/io/homeassistant/companion/android/settings/widgets/ManageWidgetsViewModel.kt b/app/src/main/java/io/homeassistant/companion/android/settings/widgets/ManageWidgetsViewModel.kt
index 87917e40d88..cc1046fc17f 100755
--- a/app/src/main/java/io/homeassistant/companion/android/settings/widgets/ManageWidgetsViewModel.kt
+++ b/app/src/main/java/io/homeassistant/companion/android/settings/widgets/ManageWidgetsViewModel.kt
@@ -13,6 +13,7 @@ import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel
import io.homeassistant.companion.android.database.widget.ButtonWidgetDao
import io.homeassistant.companion.android.database.widget.CameraWidgetDao
+import io.homeassistant.companion.android.database.widget.HistoryWidgetDao
import io.homeassistant.companion.android.database.widget.MediaPlayerControlsWidgetDao
import io.homeassistant.companion.android.database.widget.StaticWidgetDao
import io.homeassistant.companion.android.database.widget.TemplateWidgetDao
@@ -24,6 +25,7 @@ import kotlinx.coroutines.launch
class ManageWidgetsViewModel @Inject constructor(
buttonWidgetDao: ButtonWidgetDao,
cameraWidgetDao: CameraWidgetDao,
+ historyWidgetDao: HistoryWidgetDao,
staticWidgetDao: StaticWidgetDao,
mediaPlayerControlsWidgetDao: MediaPlayerControlsWidgetDao,
templateWidgetDao: TemplateWidgetDao,
@@ -38,6 +40,7 @@ class ManageWidgetsViewModel @Inject constructor(
val buttonWidgetList = buttonWidgetDao.getAllFlow().collectAsState()
val cameraWidgetList = cameraWidgetDao.getAllFlow().collectAsState()
+ val historyWidgetList = historyWidgetDao.getAllFlow().collectAsState()
val staticWidgetList = staticWidgetDao.getAllFlow().collectAsState()
val mediaWidgetList = mediaPlayerControlsWidgetDao.getAllFlow().collectAsState()
val templateWidgetList = templateWidgetDao.getAllFlow().collectAsState()
diff --git a/app/src/main/java/io/homeassistant/companion/android/settings/widgets/views/ManageWidgetsView.kt b/app/src/main/java/io/homeassistant/companion/android/settings/widgets/views/ManageWidgetsView.kt
index d1c6575d4b9..9c20874b649 100755
--- a/app/src/main/java/io/homeassistant/companion/android/settings/widgets/views/ManageWidgetsView.kt
+++ b/app/src/main/java/io/homeassistant/companion/android/settings/widgets/views/ManageWidgetsView.kt
@@ -42,6 +42,7 @@ import io.homeassistant.companion.android.util.compose.MdcAlertDialog
import io.homeassistant.companion.android.widgets.button.ButtonWidgetConfigureActivity
import io.homeassistant.companion.android.widgets.camera.CameraWidgetConfigureActivity
import io.homeassistant.companion.android.widgets.entity.EntityWidgetConfigureActivity
+import io.homeassistant.companion.android.widgets.history.HistoryWidgetConfigureActivity
import io.homeassistant.companion.android.widgets.mediaplayer.MediaPlayerControlsWidgetConfigureActivity
import io.homeassistant.companion.android.widgets.template.TemplateWidgetConfigureActivity
@@ -50,7 +51,8 @@ enum class WidgetType(val widgetIcon: IIcon) {
CAMERA(CommunityMaterial.Icon.cmd_camera_image),
STATE(CommunityMaterial.Icon3.cmd_shape),
MEDIA(CommunityMaterial.Icon3.cmd_play_box_multiple),
- TEMPLATE(CommunityMaterial.Icon.cmd_code_braces);
+ TEMPLATE(CommunityMaterial.Icon.cmd_code_braces),
+ HISTORY(CommunityMaterial.Icon3.cmd_sun_clock);
fun configureActivity() = when (this) {
BUTTON -> ButtonWidgetConfigureActivity::class.java
@@ -58,6 +60,7 @@ enum class WidgetType(val widgetIcon: IIcon) {
MEDIA -> MediaPlayerControlsWidgetConfigureActivity::class.java
STATE -> EntityWidgetConfigureActivity::class.java
TEMPLATE -> TemplateWidgetConfigureActivity::class.java
+ HISTORY -> HistoryWidgetConfigureActivity::class.java
}
}
@@ -81,6 +84,7 @@ fun ManageWidgetsView(
val availableWidgets = listOf(
stringResource(R.string.widget_button_image_description) to WidgetType.BUTTON,
stringResource(R.string.widget_camera_description) to WidgetType.CAMERA,
+ stringResource(R.string.widget_history_description) to WidgetType.HISTORY,
stringResource(R.string.widget_static_image_description) to WidgetType.STATE,
stringResource(R.string.widget_media_player_description) to WidgetType.MEDIA,
stringResource(R.string.template_widget) to WidgetType.TEMPLATE
@@ -110,7 +114,7 @@ fun ManageWidgetsView(
) {
if (viewModel.buttonWidgetList.value.isEmpty() && viewModel.staticWidgetList.value.isEmpty() &&
viewModel.mediaWidgetList.value.isEmpty() && viewModel.templateWidgetList.value.isEmpty() &&
- viewModel.cameraWidgetList.value.isEmpty()
+ viewModel.cameraWidgetList.value.isEmpty() && viewModel.historyWidgetList.value.isEmpty()
) {
item {
EmptyState(
@@ -135,6 +139,12 @@ fun ManageWidgetsView(
title = R.string.camera_widgets,
widgetLabel = { item -> item.entityId }
)
+ widgetItems(
+ viewModel.historyWidgetList.value,
+ widgetType = WidgetType.HISTORY,
+ title = R.string.history_widgets,
+ widgetLabel = { item -> item.entityId }
+ )
widgetItems(
viewModel.staticWidgetList.value,
widgetType = WidgetType.STATE,
diff --git a/app/src/main/java/io/homeassistant/companion/android/widgets/history/HistoryWidget.kt b/app/src/main/java/io/homeassistant/companion/android/widgets/history/HistoryWidget.kt
new file mode 100644
index 00000000000..3c443b3613c
--- /dev/null
+++ b/app/src/main/java/io/homeassistant/companion/android/widgets/history/HistoryWidget.kt
@@ -0,0 +1,256 @@
+package io.homeassistant.companion.android.widgets.history
+
+import android.app.PendingIntent
+import android.appwidget.AppWidgetManager
+import android.content.ComponentName
+import android.content.Context
+import android.content.Intent
+import android.graphics.Color
+import android.os.Bundle
+import android.util.Log
+import android.util.TypedValue
+import android.view.View
+import android.widget.RemoteViews
+import androidx.core.content.ContextCompat
+import androidx.core.graphics.toColorInt
+import androidx.core.os.BundleCompat
+import com.google.android.material.color.DynamicColors
+import dagger.hilt.android.AndroidEntryPoint
+import io.homeassistant.companion.android.R
+import io.homeassistant.companion.android.common.R as commonR
+import io.homeassistant.companion.android.common.data.integration.Entity
+import io.homeassistant.companion.android.common.data.integration.canSupportPrecision
+import io.homeassistant.companion.android.common.data.integration.friendlyName
+import io.homeassistant.companion.android.common.data.integration.friendlyState
+import io.homeassistant.companion.android.common.data.websocket.impl.entities.EntityRegistryOptions
+import io.homeassistant.companion.android.database.widget.HistoryWidgetDao
+import io.homeassistant.companion.android.database.widget.HistoryWidgetEntity
+import io.homeassistant.companion.android.database.widget.WidgetBackgroundType
+import io.homeassistant.companion.android.util.getAttribute
+import io.homeassistant.companion.android.widgets.BaseWidgetProvider
+import java.time.LocalDateTime
+import java.time.format.DateTimeFormatter
+import javax.inject.Inject
+import kotlinx.coroutines.launch
+
+@AndroidEntryPoint
+class HistoryWidget : BaseWidgetProvider() {
+
+ companion object {
+ private const val TAG = "HistoryWidget"
+
+ internal const val EXTRA_SERVER_ID = "EXTRA_SERVER_ID"
+ internal const val EXTRA_ENTITY_ID = "EXTRA_ENTITY_ID"
+ internal const val EXTRA_LABEL = "EXTRA_LABEL"
+ internal const val EXTRA_TEXT_SIZE = "EXTRA_TEXT_SIZE"
+ internal const val EXTRA_BACKGROUND_TYPE = "EXTRA_BACKGROUND_TYPE"
+ internal const val EXTRA_TEXT_COLOR = "EXTRA_TEXT_COLOR"
+ internal const val DEFAULT_TEXT_SIZE = 30F
+ internal const val DEFAULT_ENTITY_ID_SEPARATOR = ","
+
+ private data class ResolvedText(val text: CharSequence?, val exception: Boolean = false)
+ }
+
+ @Inject
+ lateinit var historyWidgetDao: HistoryWidgetDao
+
+ override fun getWidgetProvider(context: Context): ComponentName =
+ ComponentName(context, HistoryWidget::class.java)
+
+ override suspend fun getWidgetRemoteViews(context: Context, appWidgetId: Int, suggestedEntity: Entity