/* * Copyright (C) 2025 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.eyedropper.ui.touchscreen import android.content.res.Configuration import android.view.PointerIcon.TYPE_NULL import android.view.PointerIcon.getSystemIcon import androidx.compose.foundation.background import androidx.compose.foundation.focusable import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.systemBars import androidx.compose.foundation.layout.windowInsetsPadding import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.focus.FocusRequester import androidx.compose.ui.focus.focusRequester import androidx.compose.ui.graphics.Color import androidx.compose.ui.input.pointer.PointerIcon import androidx.compose.ui.input.pointer.pointerHoverIcon import androidx.compose.ui.platform.LocalConfiguration import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.colorResource import androidx.lifecycle.viewmodel.compose.viewModel import com.android.eyedropper.R object TouchscreenMainScreenTestTags { const val MAIN_BOX = "main_box" const val SCREENSHOT_RETICLE_BOX = "screenshot_reticle_box" const val CONTROL_BAR_BOX = "control_bar_box" } /** * Main Touchscreen color selection UI: * (1) Fullscreen, edge-to-edge Box that hides cursor and sets insets * (2) Container that orients [ScreenshotWithReticle] & [ControlBar] in a 4:1 size ratio, either * left/right of each other if Landscape mode or above/below each other if Portrait mode. */ @Composable fun TouchscreenMainScreen( viewModel: TouchscreenViewModel = viewModel() ) { val context = LocalContext.current val transparentCursor = remember { PointerIcon(getSystemIcon(context, TYPE_NULL)) } val configuration = LocalConfiguration.current val isLandscape = configuration.orientation == Configuration.ORIENTATION_LANDSCAPE val focusRequester: FocusRequester = remember { FocusRequester() } val onSelectClicked = viewModel.sendColorResult ?: return val onCancelClicked = viewModel.sendAbortResult ?: return // (1) Outermost Box blocks out insets with white background Box( modifier = Modifier .background(Color.White) .fillMaxSize() .windowInsetsPadding(WindowInsets.systemBars) .pointerHoverIcon(transparentCursor) ) { // (2) Main box housing the color picker and apply/cancel bar // TODO: b/435295269 - panel to select between multiple displays Box( modifier = Modifier .fillMaxSize() .focusRequester(focusRequester) .focusable() .background(colorResource(R.color.screenshot_image_view_container_bg_color)) .testTag(TouchscreenMainScreenTestTags.MAIN_BOX) ) { // Landscape -> control bar is a vertical bar on the right end of the screen. // Its buttons are placed at the bottom center of this bar. if (isLandscape) { Row( modifier = Modifier .fillMaxSize() ) { Box( modifier = Modifier .weight(4f) .fillMaxHeight() .testTag(TouchscreenMainScreenTestTags.SCREENSHOT_RETICLE_BOX) ) { ScreenshotWithReticle( viewModel = viewModel, ) } Box( modifier = Modifier .weight(1f) .background(Color.White) .fillMaxHeight() .testTag(TouchscreenMainScreenTestTags.CONTROL_BAR_BOX) ) { ControlBar( isLandscape = true, onSelectClicked = onSelectClicked, onCancelClicked = onCancelClicked, ) } } } // Portrait -> control bar is a horizontal bar on the bottom end of the screen // Its buttons are placed at the bottom right corner else { Column( modifier = Modifier .fillMaxSize() ) { Box( modifier = Modifier .weight(4f) .fillMaxWidth() ) { ScreenshotWithReticle( viewModel = viewModel, ) } Box( modifier = Modifier .weight(1f) .background(Color.White) .fillMaxWidth(), ) { ControlBar( isLandscape = false, onSelectClicked = onSelectClicked, onCancelClicked = onCancelClicked ) } } } } LaunchedEffect(Unit) { focusRequester.requestFocus() } } }