Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions app/src/main/kotlin/com/google/ai/sample/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,12 @@ import android.content.SharedPreferences
import android.content.pm.PackageManager
import android.net.Uri
import android.os.Build
import android.graphics.Rect
import android.os.Bundle
import android.provider.Settings
import android.util.Log
import android.view.View
import android.view.ViewTreeObserver
import android.widget.Toast
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
Expand Down Expand Up @@ -70,6 +73,11 @@ import kotlinx.coroutines.launch

class MainActivity : ComponentActivity() {

// Keyboard Visibility
private val _isKeyboardOpen = MutableStateFlow(false)
val isKeyboardOpen: StateFlow<Boolean> = _isKeyboardOpen.asStateFlow()
private var onGlobalLayoutListener: ViewTreeObserver.OnGlobalLayoutListener? = null

private var photoReasoningViewModel: PhotoReasoningViewModel? = null
private lateinit var apiKeyManager: ApiKeyManager
private var showApiKeyDialog by mutableStateOf(false)
Expand Down Expand Up @@ -286,6 +294,26 @@ class MainActivity : ComponentActivity() {
// Initial check for accessibility service status
refreshAccessibilityServiceStatus()

// Keyboard visibility listener
val rootView = findViewById<View>(android.R.id.content)
onGlobalLayoutListener = ViewTreeObserver.OnGlobalLayoutListener {
val rect = Rect()
rootView.getWindowVisibleDisplayFrame(rect)
val screenHeight = rootView.rootView.height
val keypadHeight = screenHeight - rect.bottom
if (keypadHeight > screenHeight * 0.15) { // 0.15 ratio is a common threshold
if (!_isKeyboardOpen.value) {
_isKeyboardOpen.value = true
Log.d(TAG, "Keyboard visible")
}
} else {
if (_isKeyboardOpen.value) {
_isKeyboardOpen.value = false
Log.d(TAG, "Keyboard hidden")
}
}
}
rootView.viewTreeObserver.addOnGlobalLayoutListener(onGlobalLayoutListener)

Log.d(TAG, "onCreate: Calling setContent.")
setContent {
Expand Down Expand Up @@ -752,6 +780,11 @@ class MainActivity : ComponentActivity() {
billingClient.endConnection()
Log.d(TAG, "onDestroy: BillingClient connection ended.")
}
// Remove keyboard listener
onGlobalLayoutListener?.let {
findViewById<View>(android.R.id.content).viewTreeObserver.removeOnGlobalLayoutListener(it)
Log.d(TAG, "onDestroy: Keyboard layout listener removed.")
}
if (this == instance) {
instance = null
Log.d(TAG, "onDestroy: MainActivity instance cleared.")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import android.graphics.drawable.BitmapDrawable
import android.net.Uri
import android.provider.Settings
import android.widget.Toast // Added for Toast message
import androidx.activity.compose.BackHandler
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.PickVisualMediaRequest
import androidx.activity.result.contract.ActivityResultContracts
Expand Down Expand Up @@ -49,9 +50,11 @@ import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.onFocusChanged
import androidx.compose.ui.draw.drawBehind
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
Expand Down Expand Up @@ -88,6 +91,7 @@ internal fun PhotoReasoningRoute(

// Observe the accessibility service status from MainActivity
val isAccessibilityServiceEffectivelyEnabled by mainActivity?.isAccessibilityServiceEnabledFlow?.collectAsState() ?: mutableStateOf(false)
val isKeyboardOpen by mainActivity?.isKeyboardOpen?.collectAsState() ?: mutableStateOf(false)

// Launcher for opening accessibility settings
val accessibilitySettingsLauncher = rememberLauncherForActivityResult(
Expand Down Expand Up @@ -168,7 +172,8 @@ internal fun PhotoReasoningRoute(
val vm = it.getPhotoReasoningViewModel()
vm?.clearChatHistory(context)
}
}
},
isKeyboardOpen = isKeyboardOpen
)
}

Expand All @@ -183,12 +188,20 @@ fun PhotoReasoningScreen(
onReasonClicked: (String, List<Uri>) -> Unit = { _, _ -> },
isAccessibilityServiceEnabled: Boolean = false,
onEnableAccessibilityService: () -> Unit = {},
onClearChatHistory: () -> Unit = {}
onClearChatHistory: () -> Unit = {},
isKeyboardOpen: Boolean
) {
var userQuestion by rememberSaveable { mutableStateOf("") }
val imageUris = rememberSaveable(saver = UriSaver()) { mutableStateListOf() }
var isSystemMessageFocused by rememberSaveable { mutableStateOf(false) }
val listState = rememberLazyListState()
val context = LocalContext.current // Get context for Toast
val focusManager = LocalFocusManager.current

BackHandler(enabled = isSystemMessageFocused && !isKeyboardOpen) {
focusManager.clearFocus() // Clear focus first
isSystemMessageFocused = false // Then update the state that controls height
}

val pickMedia = rememberLauncherForActivityResult(
ActivityResultContracts.PickVisualMedia()
Expand Down Expand Up @@ -223,15 +236,23 @@ fun PhotoReasoningScreen(
color = MaterialTheme.colorScheme.onPrimaryContainer
)
Spacer(modifier = Modifier.height(8.dp))
val systemMessageHeight = when {
isSystemMessageFocused && isKeyboardOpen -> 450.dp // Changed from 600.dp
isSystemMessageFocused && !isKeyboardOpen -> 1000.dp
else -> 120.dp
}
val currentMinLines = if (systemMessageHeight == 120.dp) 3 else 1
val currentMaxLines = if (systemMessageHeight == 120.dp) 5 else Int.MAX_VALUE
OutlinedTextField(
value = systemMessage,
onValueChange = onSystemMessageChanged,
placeholder = { Text("Enter a system message here that will be sent with every request") },
modifier = Modifier
.fillMaxWidth()
.height(120.dp),
maxLines = 5,
minLines = 3
.height(systemMessageHeight)
.onFocusChanged { focusState -> isSystemMessageFocused = focusState.isFocused },
minLines = currentMinLines,
maxLines = currentMaxLines
)
}
}
Expand Down Expand Up @@ -633,13 +654,14 @@ fun PhotoReasoningScreenPreviewWithContent() {
text = "I am here to help you. What do you want to know?",
participant = PhotoParticipant.MODEL
)
)
),
isKeyboardOpen = false
)
}

@Composable
@Preview(showSystemUi = true)
fun PhotoReasoningScreenPreviewEmpty() {
PhotoReasoningScreen()
PhotoReasoningScreen(isKeyboardOpen = false)
}