From eefe740b6ffe94745855c933fedc84444ff5c5b9 Mon Sep 17 00:00:00 2001 From: darken Date: Fri, 27 Feb 2026 09:09:50 +0100 Subject: [PATCH] feat(monitor): Add expanded notification with battery progress bars Add distinct expanded (big) notification layouts with visual battery progress bars for dual pods, single pods, and unknown devices. Collapsed views remain unchanged. Status icon containers use fixed width to ensure uniform progress bar lengths across rows. --- .../ui/MonitorNotificationViewFactory.kt | 73 ++++++- .../capod/monitor/ui/MonitorNotifications.kt | 3 +- .../notification_battery_progress.xml | 20 ++ .../monitor_notification_dual_pods_big.xml | 198 ++++++++++++++++++ .../monitor_notification_single_pods_big.xml | 91 ++++++++ ...onitor_notification_unknown_device_big.xml | 20 ++ 6 files changed, 403 insertions(+), 2 deletions(-) create mode 100644 app/src/main/res/drawable/notification_battery_progress.xml create mode 100644 app/src/main/res/layout/monitor_notification_dual_pods_big.xml create mode 100644 app/src/main/res/layout/monitor_notification_single_pods_big.xml create mode 100644 app/src/main/res/layout/monitor_notification_unknown_device_big.xml diff --git a/app/src/main/java/eu/darken/capod/monitor/ui/MonitorNotificationViewFactory.kt b/app/src/main/java/eu/darken/capod/monitor/ui/MonitorNotificationViewFactory.kt index d0439a94..66e2a226 100644 --- a/app/src/main/java/eu/darken/capod/monitor/ui/MonitorNotificationViewFactory.kt +++ b/app/src/main/java/eu/darken/capod/monitor/ui/MonitorNotificationViewFactory.kt @@ -15,6 +15,7 @@ import eu.darken.capod.pods.core.SinglePodDevice import eu.darken.capod.pods.core.formatBatteryPercent import eu.darken.capod.pods.core.getBatteryDrawable import javax.inject.Inject +import kotlin.math.roundToInt class MonitorNotificationViewFactory @Inject constructor( @@ -78,9 +79,79 @@ class MonitorNotificationViewFactory @Inject constructor( private fun createUnknownDevice(device: PodDevice): RemoteViews = RemoteViews( context.packageName, - R.layout.monitor_notification_dual_pods_small + R.layout.monitor_notification_unknown_device_small ).apply { setTextViewText(R.id.device, device.getLabel(context)) } + fun createBigContentView(device: PodDevice): RemoteViews = when (device) { + is DualPodDevice -> createDualPodsBig(device) + is SinglePodDevice -> createSinglePodBig(device) + else -> createUnknownDeviceBig(device) + } + + private fun createDualPodsBig(device: DualPodDevice): RemoteViews = RemoteViews( + context.packageName, + R.layout.monitor_notification_dual_pods_big + ).apply { + // Left + val leftPercent = device.batteryLeftPodPercent + setImageViewResource(R.id.pod_left_icon, device.leftPodIcon) + setProgressBar(R.id.pod_left_progress, 100, percentToInt(leftPercent), false) + setTextViewText(R.id.pod_left_label, formatBatteryPercent(context, leftPercent)) + val isLeftPodCharging = (device as? HasChargeDetectionDual)?.isLeftPodCharging ?: false + setViewVisibility(R.id.pod_left_charging, if (isLeftPodCharging) View.VISIBLE else View.GONE) + val isLeftPodInEar = (device as? HasEarDetectionDual)?.isLeftPodInEar ?: false + setViewVisibility(R.id.pod_left_ear, if (isLeftPodInEar) View.VISIBLE else View.GONE) + + // Case + setViewVisibility(R.id.pod_case_container, if (device is HasCase) View.VISIBLE else View.GONE) + (device as? HasCase)?.let { case -> + setImageViewResource(R.id.pod_case_icon, device.caseIcon) + val casePercent = case.batteryCasePercent + setProgressBar(R.id.pod_case_progress, 100, percentToInt(casePercent), false) + setTextViewText(R.id.pod_case_label, formatBatteryPercent(context, casePercent)) + setViewVisibility(R.id.pod_case_charging, if (case.isCaseCharging) View.VISIBLE else View.GONE) + } + + // Right + val rightPercent = device.batteryRightPodPercent + setImageViewResource(R.id.pod_right_icon, device.rightPodIcon) + setProgressBar(R.id.pod_right_progress, 100, percentToInt(rightPercent), false) + setTextViewText(R.id.pod_right_label, formatBatteryPercent(context, rightPercent)) + val isRightPodCharging = (device as? HasChargeDetectionDual)?.isRightPodCharging ?: false + setViewVisibility(R.id.pod_right_charging, if (isRightPodCharging) View.VISIBLE else View.GONE) + val isRightPodInEar = (device as? HasEarDetectionDual)?.isRightPodInEar ?: false + setViewVisibility(R.id.pod_right_ear, if (isRightPodInEar) View.VISIBLE else View.GONE) + } + + private fun createSinglePodBig(device: SinglePodDevice): RemoteViews = RemoteViews( + context.packageName, + R.layout.monitor_notification_single_pods_big + ).apply { + val headsetPercent = device.batteryHeadsetPercent + setTextViewText(R.id.headphones_label, device.getLabel(context)) + setImageViewResource(R.id.headphones_icon, device.iconRes) + setProgressBar(R.id.headphones_battery_progress, 100, percentToInt(headsetPercent), false) + setTextViewText(R.id.headphones_battery_label, formatBatteryPercent(context, headsetPercent)) + if (device is HasEarDetection) { + setViewVisibility(R.id.headphones_worn, if (device.isBeingWorn) View.VISIBLE else View.GONE) + } + if (device is HasChargeDetectionDual) { + setViewVisibility(R.id.headphones_charging, if (device.isHeadsetBeingCharged) View.VISIBLE else View.GONE) + } + } + + private fun createUnknownDeviceBig(device: PodDevice): RemoteViews = RemoteViews( + context.packageName, + R.layout.monitor_notification_unknown_device_big + ).apply { + setTextViewText(R.id.device, device.getLabel(context)) + } + + private fun percentToInt(percent: Float?): Int { + if (percent == null) return 0 + return (percent * 100).roundToInt().coerceIn(0, 100) + } + } \ No newline at end of file diff --git a/app/src/main/java/eu/darken/capod/monitor/ui/MonitorNotifications.kt b/app/src/main/java/eu/darken/capod/monitor/ui/MonitorNotifications.kt index 6d8730c1..77bed4af 100644 --- a/app/src/main/java/eu/darken/capod/monitor/ui/MonitorNotifications.kt +++ b/app/src/main/java/eu/darken/capod/monitor/ui/MonitorNotifications.kt @@ -128,7 +128,8 @@ class MonitorNotifications @Inject constructor( } setStyle(NotificationCompat.DecoratedCustomViewStyle()) - setCustomBigContentView(notificationViewFactory.createContentView(device)) + setCustomContentView(notificationViewFactory.createContentView(device)) + setCustomBigContentView(notificationViewFactory.createBigContentView(device)) setContentTitle("$batteryText ~ $stateText") setSubText(null) log(TAG, VERBOSE) { "updatingNotification(): $device" } diff --git a/app/src/main/res/drawable/notification_battery_progress.xml b/app/src/main/res/drawable/notification_battery_progress.xml new file mode 100644 index 00000000..ee7373ff --- /dev/null +++ b/app/src/main/res/drawable/notification_battery_progress.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/monitor_notification_dual_pods_big.xml b/app/src/main/res/layout/monitor_notification_dual_pods_big.xml new file mode 100644 index 00000000..8c026fad --- /dev/null +++ b/app/src/main/res/layout/monitor_notification_dual_pods_big.xml @@ -0,0 +1,198 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/monitor_notification_single_pods_big.xml b/app/src/main/res/layout/monitor_notification_single_pods_big.xml new file mode 100644 index 00000000..b5d6bf7f --- /dev/null +++ b/app/src/main/res/layout/monitor_notification_single_pods_big.xml @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/monitor_notification_unknown_device_big.xml b/app/src/main/res/layout/monitor_notification_unknown_device_big.xml new file mode 100644 index 00000000..ada6b253 --- /dev/null +++ b/app/src/main/res/layout/monitor_notification_unknown_device_big.xml @@ -0,0 +1,20 @@ + + + + + +