Compose AsyncImage: белый фон для галереи Uri и тематический фон для CameraX UriAndroid

Форум для тех, кто программирует под Android
Ответить
Anonymous
 Compose AsyncImage: белый фон для галереи Uri и тематический фон для CameraX Uri

Сообщение Anonymous »

Когда я открываю PhotoPreview после съемки фотографии камерой, фон в PhotoPreview зависит от текущей темы моего смартфона. Если я открываю PhotoPreview после выбора фотографии из медиа-библиотеки устройства, фоновая тема PhotoPreview всегда белая и не зависит от темы устройства. Почему это происходит?
package com.example.repairkz.ui.features.CameraX

import com.example.repairkz.R
import com.example.repairkz.common.utils.takePhoto
import android.content.Context
import android.graphics.Bitmap
import androidx.camera.core.CameraSelector
import androidx.camera.view.CameraController
import androidx.camera.view.LifecycleCameraController
import androidx.camera.view.PreviewView
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.SwapHoriz
import androidx.compose.material3.BottomSheetScaffold
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.rememberBottomSheetScaffoldState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import android.net.Uri
import android.provider.MediaStore
import android.util.Log
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.compose.foundation.background
import androidx.compose.material.icons.filled.Camera
import androidx.compose.material.icons.filled.Crop
import androidx.compose.material.icons.filled.CrueltyFree
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.getValue
import androidx.compose.runtime.setValue
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.unit.dp
import androidx.compose.ui.viewinterop.AndroidView
import androidx.core.content.ContextCompat
import androidx.lifecycle.compose.LocalLifecycleOwner
import coil.compose.AsyncImage
import com.canhub.cropper.CropImageContract
import com.canhub.cropper.CropImageContractOptions
import com.canhub.cropper.CropImageOptions
import com.canhub.cropper.CropImageView

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun Camera(context: Context, takeNewPhoto: (Uri?) -> Unit) {
val controller = remember {
LifecycleCameraController(context).apply {
setEnabledUseCases(
CameraController.IMAGE_CAPTURE
)
}
}
val scaffoldState = rememberBottomSheetScaffoldState()

var uri = remember { mutableStateOf(null) }

BottomSheetScaffold(
scaffoldState = scaffoldState,
sheetPeekHeight = 0.dp,
sheetContent = {

}
) { paddingValues ->
if (uri.value == null) {
Box(
modifier = Modifier
.fillMaxSize()
.padding(paddingValues)
) {

CameraPreview(
controller = controller,
modifier = Modifier.fillMaxSize()
)

Row(
modifier = Modifier
.fillMaxWidth()
.align(Alignment.BottomCenter)
.padding(16.dp),
horizontalArrangement = Arrangement.SpaceAround
) {
IconButton(
onClick = {
takePhoto(controller, onPhotoTaken = { newUri ->
uri.value = newUri
}, context)
}
) {
Icon(Icons.Default.Camera, null)
}

IconButton(
onClick = {
controller.cameraSelector =
if (controller.cameraSelector == CameraSelector.DEFAULT_BACK_CAMERA) {
CameraSelector.DEFAULT_FRONT_CAMERA
} else {
CameraSelector.DEFAULT_BACK_CAMERA
}
}
) {
Icon(Icons.Default.SwapHoriz, null)
}
}
}

} else {
PhotoPreview(context, uri.value!!, save = { uri ->
takeNewPhoto(uri)
})
}
}
}

@Composable
fun PhotoPreview(
context: Context,
uri: Uri,
save: (Uri?) -> Unit,
) {
var newUri by remember { mutableStateOf(null) }

Box(
modifier = Modifier
.fillMaxSize()
) {
val cropLauncher = rememberLauncherForActivityResult(CropImageContract()) { result ->
if (result.isSuccessful) {
val croppedUri = result.uriContent
newUri = croppedUri
}
}
AsyncImage(
model = newUri ?: uri,
contentDescription = null,
modifier = Modifier
.align(
Alignment.Center
)
.fillMaxSize(),
contentScale = ContentScale.Fit
)
Row(
modifier = Modifier
.fillMaxWidth()
.align(Alignment.BottomCenter)
.padding(16.dp),
horizontalArrangement = Arrangement.SpaceAround
) {
IconButton(
onClick = {
cropLauncher.launch(
CropImageContractOptions(
cropImageOptions = CropImageOptions(
guidelines = CropImageView.Guidelines.ON,
activityBackgroundColor = ContextCompat.getColor(
context,
R.color.crop_background
)
),
uri = uri

)
)

}
) {
Icon(Icons.Default.Crop, null, tint = Color.White)
}
IconButton(
onClick = {
save(newUri ?: uri)
}
) {
Icon(Icons.Default.CrueltyFree, null, tint = Color.White)
}
}
}
}

@Composable
fun CameraPreview(
controller: LifecycleCameraController,
modifier: Modifier,
) {

val lifeCycleOwner = LocalLifecycleOwner.current
AndroidView(
factory = {
PreviewView(it).apply {
this.controller = controller
controller.bindToLifecycle(lifeCycleOwner)
}
},
modifier = modifier
)
}

package com.example.repairkz.Navigation

import android.annotation.SuppressLint
import android.os.Build
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.annotation.RequiresApi
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.remember
import androidx.compose.ui.platform.LocalContext
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.navigation.NavType
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController
import androidx.navigation.navArgument
import androidx.navigation.navigation
import com.example.repairkz.Navigation.Routes.PROFILE_GROUP
import com.example.repairkz.Navigation.profile.profileGraph

import com.example.repairkz.ui.MainWindow
import com.example.repairkz.ui.features.CameraX.Camera
import com.example.repairkz.ui.features.CameraX.PhotoPreview
import com.example.repairkz.ui.features.UserInfo.UserInfo
import com.example.repairkz.ui.features.UserInfo.UserInfoViewModel
import com.example.repairkz.ui.features.UserInfo.UserIntent
import com.example.repairkz.ui.features.UserInfo.UserState
import com.example.repairkz.ui.features.search.SearchScreen
import com.example.repairkz.ui.theme.RepairkzTheme
import com.example.repairkz.ui.features.main.MainViewModel
import com.example.repairkz.ui.features.notifiacton.NotificationViewModel
import com.example.repairkz.ui.features.search.SearchViewModel
import com.example.repairkz.ui.features.settings.SettingsViewModel
import dagger.hilt.android.AndroidEntryPoint

@AndroidEntryPoint
class MainActivity : ComponentActivity() {
@SuppressLint("UnrememberedGetBackStackEntry")
@RequiresApi(Build.VERSION_CODES.O)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContent {

RepairkzTheme {
val navController = rememberNavController()
NavHost(
navController = navController,
startDestination = Routes.MAIN_WINDOW
) {
composable(Routes.MAIN_WINDOW) {
val mainViewModel: MainViewModel = hiltViewModel()
val notificationViewModel: NotificationViewModel = hiltViewModel()
val settingsViewModel: SettingsViewModel = hiltViewModel()
MainWindow(
mainViewModel,
navController,
notificationViewModel,
settingsViewModel
)
}
composable(
route = "${Routes.SEARCH}?pattern={pattern}",
arguments = listOf(
navArgument("pattern") {
type = NavType.IntType
defaultValue = 0
}
)
) {
val searchViewModel: SearchViewModel = hiltViewModel()
SearchScreen(navController, searchViewModel)
}
profileGraph(navController)

}
}
}
}
}

package com.example.repairkz.ui.features.UserInfo

import android.content.Context
import android.content.pm.PackageManager
import com.example.repairkz.R
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.PickVisualMediaRequest
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Camera
import androidx.compose.material.icons.filled.PermMedia
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ModalBottomSheet
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.material3.rememberModalBottomSheetState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.core.content.ContextCompat
import androidx.navigation.NavController
import com.example.repairkz.Navigation.Routes
import com.example.repairkz.common.enums.PhotoSourceEnum
import com.example.repairkz.common.ui.StandartString
import com.example.repairkz.ui.features.profile.common.Cap

private val CAMERAX_PERMISSIONS = arrayOf(
android.Manifest.permission.CAMERA,
)

private fun hasRequiredPermissions(context: Context): Boolean {
return CAMERAX_PERMISSIONS.all {
ContextCompat.checkSelfPermission(
context,
it
) == PackageManager.PERMISSION_GRANTED
}
}

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun UserInfo(userInfoViewModel: UserInfoViewModel, navController: NavController) {
val context = LocalContext.current
val sheetState = rememberModalBottomSheetState()
val uiState = userInfoViewModel.uiState.collectAsState()

val permissionLauncher = rememberLauncherForActivityResult(ActivityResultContracts.RequestPermission()) {

}

val mediaLauncher =
rememberLauncherForActivityResult(ActivityResultContracts.PickVisualMedia()) {
if (it!= null){
userInfoViewModel.handleIntent(UserIntent.GetPhotoFromMedia(uri = it))
navController.navigate(Routes.PHOTO_PREVIEW)
}

}

LaunchedEffect(userInfoViewModel) {
userInfoViewModel.channel.collect { effect ->
when (effect) {
is UserEffects.OpenPhotoPicker -> {
when (effect.typeOfSelect) {

PhotoSourceEnum.CAMERA -> {
if (hasRequiredPermissions(context)){
navController.navigate(Routes.CAMERA)
}else{
permissionLauncher.launch(
CAMERAX_PERMISSIONS[0]
)
}
}
PhotoSourceEnum.GALLERY -> {
mediaLauncher.launch(
PickVisualMediaRequest(mediaType = ActivityResultContracts.PickVisualMedia.ImageOnly, )
)
}
}

}

UserEffects.NavigateToPreview -> {

}
}
}
}

when (val state = uiState.value) {
is UserState.Loading -> {
Column(
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
CircularProgressIndicator()
}
}

is UserState.Error -> {
Column(
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(state.message)
}
}

is UserState.Success -> {
val user = state.userTypes
Surface(
modifier = Modifier.fillMaxSize(),
) {
Column(
modifier = Modifier.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally
) {
Cap(
commonInfo = user.commonInfo,
changeAvatarIntent = { intent -> userInfoViewModel.handleIntent(intent) })
when (user) {
is UserTypes.IsCurrentMaster -> {
Column(
modifier = Modifier.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
Text("Я мастер")
}
}

is UserTypes.IsCurrentUser -> {
Column(
modifier = Modifier.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
Text("Я клиент")
}
}

is UserTypes.IsOtherMaster -> {
Column(
modifier = Modifier.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
Text(user.master.firstName)
}
}
}

}
}
if (state.avatarSheetState) {
ModalBottomSheet(
onDismissRequest = {
userInfoViewModel.handleIntent(UserIntent.CloseSheet)
},
sheetState = sheetState
) {
StandartString(
R.string.from_camera,
intent = {
userInfoViewModel.handleIntent(
UserIntent.ChangeAvatar(
PhotoSourceEnum.CAMERA
)
)
},
icon = Icons.Default.Camera
)
StandartString(
R.string.from_gallery,
intent = {
userInfoViewModel.handleIntent(
UserIntent.ChangeAvatar(
PhotoSourceEnum.GALLERY
)
)
},
icon = Icons.Default.PermMedia
)
}
}
}
}
}


Подробнее здесь: https://stackoverflow.com/questions/798 ... und-for-ca
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «Android»