Fix Settings UI reactivity, resolve compiler warnings, update .gitignore

- Make screen capture permission and battery optimization states reactive
- Add lifecycle observer to refresh battery status on resume
- Add lifecycle-runtime-compose dependency for non-deprecated LocalLifecycleOwner
- Replace deprecated LocalLifecycleOwner import
- Remove unused REQUEST_CODE constant
- Use KTX createBitmap() and bitmap[x,y] extensions
- Add misc.xml and junie.xml to .gitignore
This commit is contained in:
Somasundaram Mahesh
2026-02-18 07:47:28 +05:30
parent 792b42974f
commit 5207e4ea9b
6 changed files with 32 additions and 15 deletions

View File

@@ -64,6 +64,7 @@ dependencies {
// Lifecycle service
implementation(libs.lifecycle.service)
implementation(libs.lifecycle.runtime.compose)
// Navigation
implementation(libs.navigation.compose)

View File

@@ -1,9 +1,12 @@
package com.thisux.droidclaw.capture
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.graphics.Bitmap
import android.graphics.PixelFormat
import androidx.core.graphics.createBitmap
import androidx.core.graphics.get
import android.hardware.display.DisplayManager
import android.hardware.display.VirtualDisplay
import android.media.ImageReader
@@ -19,16 +22,19 @@ class ScreenCaptureManager(private val context: Context) {
companion object {
private const val TAG = "ScreenCapture"
const val REQUEST_CODE = 1001
val isAvailable = MutableStateFlow(false)
// Stores MediaProjection consent for use by ConnectionService
var consentResultCode: Int? = null
var consentData: Intent? = null
// Expose consent as state so UI can react immediately
val hasConsentState = MutableStateFlow(false)
fun storeConsent(resultCode: Int, data: Intent?) {
consentResultCode = resultCode
consentData = data
hasConsentState.value = (resultCode == Activity.RESULT_OK && data != null)
}
fun hasConsent(): Boolean = consentResultCode != null && consentData != null
@@ -86,7 +92,7 @@ class ScreenCaptureManager(private val context: Context) {
val rowStride = planes[0].rowStride
val rowPadding = rowStride - pixelStride * image.width
val bitmap = Bitmap.createBitmap(
val bitmap = createBitmap(
image.width + rowPadding / pixelStride,
image.height,
Bitmap.Config.ARGB_8888
@@ -119,7 +125,7 @@ class ScreenCaptureManager(private val context: Context) {
bitmap.width - 1 to bitmap.height - 1,
bitmap.width / 2 to bitmap.height / 2
)
return points.all { (x, y) -> bitmap.getPixel(x, y) == android.graphics.Color.BLACK }
return points.all { (x, y) -> bitmap[x, y] == android.graphics.Color.BLACK }
}
fun release() {

View File

@@ -26,6 +26,7 @@ import androidx.compose.material3.OutlinedButton
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
@@ -36,8 +37,11 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.lifecycle.compose.LocalLifecycleOwner
import androidx.compose.ui.text.input.PasswordVisualTransformation
import androidx.compose.ui.unit.dp
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleEventObserver
import com.thisux.droidclaw.DroidClawApp
import com.thisux.droidclaw.accessibility.DroidClawAccessibilityService
import com.thisux.droidclaw.capture.ScreenCaptureManager
@@ -58,8 +62,21 @@ fun SettingsScreen() {
val isAccessibilityEnabled by DroidClawAccessibilityService.isRunning.collectAsState()
val isCaptureAvailable by ScreenCaptureManager.isAvailable.collectAsState()
val hasCaptureConsent = isCaptureAvailable || ScreenCaptureManager.hasConsent()
val isBatteryExempt = remember { BatteryOptimization.isIgnoringBatteryOptimizations(context) }
val hasConsent by ScreenCaptureManager.hasConsentState.collectAsState()
val hasCaptureConsent = isCaptureAvailable || hasConsent
var isBatteryExempt by remember { mutableStateOf(BatteryOptimization.isIgnoringBatteryOptimizations(context)) }
val lifecycleOwner = LocalLifecycleOwner.current
DisposableEffect(lifecycleOwner) {
val observer = LifecycleEventObserver { _, event ->
if (event == Lifecycle.Event.ON_RESUME) {
isBatteryExempt = BatteryOptimization.isIgnoringBatteryOptimizations(context)
}
}
lifecycleOwner.lifecycle.addObserver(observer)
onDispose { lifecycleOwner.lifecycle.removeObserver(observer) }
}
val projectionLauncher = rememberLauncherForActivityResult(
ActivityResultContracts.StartActivityForResult()