How to read a file using rememberLauncherForActivityResult in Kotlin Jetpack Compose? - android

So I have this composable which tries to read data from storage,
#Composable
private fun Screen() {
val launcher = rememberLauncherForActivityResult(contract = ActivityResultContracts.StartActivityForResult()) { result ->
val uri = result.data?.data.toString()
if(uri !== null) {
val file = File(uri)
val bytes = file.readBytes()
println(bytes)
}
}
Column() {
Button(onClick = {
val intent = Intent().setType("*/*").setAction(Intent.ACTION_OPEN_DOCUMENT)
launcher.launch(intent)
}) {
Text("Open file")
}
}
}
However, it gives me this error: content:/com.android.providers.downloads.documents/document/raw%3A%2Fstorage%2Femulated%2F0%2FDownload%2FIMG_CEFEFF486A8C-1.jpeg: open failed: ENOENT (No such file or directory). What am I doing wrong here? Please help.

Figured it out,
#Composable
private fun Screen() {
val context = LocalContext.current
val launcher = rememberLauncherForActivityResult(contract = ActivityResultContracts.GetContent()) { result ->
val item = context.contentResolver.openInputStream(result)
val bytes = item?.readBytes()
println(bytes)
item?.close()
}
return Column {
Button(onClick = {
launcher.launch("*/*")
}) {
Text("Open file")
}
}
}

Related

Compose app doesn't load api data after launch

I'm creating a Pokémon app with Jetpack Compose. I'm testing it with two smartphones: Xioami Mi 11T Pro (Android 12) and Xiaomi Mi 8 Lite (Android 10).
Well, when I launch the app in the Mi 8 Lite, it starts correctly, the pokemon list loads perfectly.
But when I launch the app with the Mi 11 T Pro, it doesn't load, nothing shows. I discovered two things:
If I open the Layout Inspector it loads inmediately, without doing anything more...
When the screen is empty (just after launch, before it loads), If I click 1-2 times on the screen it starts to send the request and loads correctly.
Why is this happening?
I attach my ViewModel and my MainActivity.
PokemonListViewModel.kt
#HiltViewModel
class PokemonListViewModel #Inject constructor(
private val repository: PokemonRepositoryImpl
) : ViewModel() {
private var currentPage = 0
var pokemonList = mutableStateOf<List<PokedexListEntry>>(listOf())
var loadError = mutableStateOf("")
var isLoading = mutableStateOf(false)
var endReached = mutableStateOf(false)
private var cachedPokemonList = listOf<PokedexListEntry>()
private var isSearchStarting = true
var isSearching = mutableStateOf(false)
init {
loadPokemonList()
}
// TODO: Search online, not only already loaded pokémon
fun searchPokemonList(query: String) {
val listToSearch = if (isSearchStarting) {
pokemonList.value
} else {
// If we typed at least one character
cachedPokemonList
}
viewModelScope.launch(Dispatchers.Default) {
if (query.isEmpty()) {
pokemonList.value = cachedPokemonList
isSearching.value = false
isSearchStarting = true
return#launch
}
val results = listToSearch.filter {
// Search by name or pokédex number
it.pokemonName.contains(query.trim(), true) ||
it.number.toString() == query.trim()
}
if (isSearchStarting) {
cachedPokemonList = pokemonList.value
isSearchStarting = false
}
// Update entries with the results
pokemonList.value = results
isSearching.value = true
}
}
fun loadPokemonList() {
viewModelScope.launch {
isLoading.value = true
val result = repository.getPokemonList(PAGE_SIZE, currentPage * PAGE_SIZE)
when (result) {
is Resource.Success -> {
endReached.value = currentPage * PAGE_SIZE >= result.data!!.count
val pokedexEntries = result.data.results.mapIndexed { index, entry ->
val number = getPokedexNumber(entry)
val url = getImageUrl(number)
PokedexListEntry(
entry.name.replaceFirstChar(Char::titlecase),
url,
number.toInt()
)
}
currentPage++
loadError.value = ""
isLoading.value = false
pokemonList.value += pokedexEntries
}
is Resource.Error -> {
loadError.value = result.message!!
isLoading.value = false
}
is Resource.Loading -> {
isLoading.value = true
}
}
}
}
private fun getImageUrl(number: String): String {
return "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/${number}.png"
}
private fun getPokedexNumber(entry: Result): String {
return if (entry.url.endsWith("/")) {
entry.url.dropLast(1).takeLastWhile { it.isDigit() }
} else {
entry.url.takeLastWhile { it.isDigit() }
}
}
}
MainActivity.kt
#AndroidEntryPoint
class MainActivity : ComponentActivity() {
private val argPokemonName = "pokemonName"
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
JetpackComposePokedexTheme {
val navController = rememberNavController()
NavHost(navController = navController, startDestination = "pokemon_list_screen") {
composable("pokemon_list_screen") {
PokemonListScreen(navController = navController)
}
composable(
"pokemon_detail_screen/{$argPokemonName}",
arguments = listOf(
navArgument(argPokemonName) {
type = NavType.StringType
}
)
) {
val pokemonName = remember {
it.arguments?.getString(argPokemonName)
}
PokemonDetailScreen(
pokemonName = pokemonName?.lowercase(Locale.ROOT) ?: "",
navController = navController
)
}
}
}
}
}
}
If someone knows why it doesn't load... I suspect that maybe init { } or Hilt injection are doing something that makes init doesn't start or something.
Thanks for your time and help!
Well, it seems is a Xiaomi reported Bug that google won't fix, you can see it here:
https://issuetracker.google.com/issues/227926002
It worked for me adding a little delay before set content and it seems to be working:
lifecycleScope.launch {
delay(300)
setContent {
JetpackComposePokedexTheme {
...
}
}
}
Also you can see: compose NavHost Start the white Screen

How to upload encrypted image file on google drive from android using Google Drive API

I want to upload the encrypted image file from Android to a user-specific google drive, Also want to Decrypt the image while loading in-app.
Use the following function It will upload encrypted image file on google drive and also downloading the decryption image save it to the app private files folder.
suspend fun uploadFileToGDrive(path: String?, suffix: String?): String {
getDriveService()?.let { googleDriveService ->
try {
if (path != null) {
Log.e("pathGD", path)
}
googleDriveService.fetchOrCreateAppFolder(
context.getString(R.string.application_folder),
preferenceHelper
)
val encryptedData = ImageCrypto().encryptFile("$path")
Log.e("encryptedData", encryptedData)
val actualFile = File(encryptedData)
if (!actualFile.exists()) error("File $actualFile not exists.")
val gFile = com.google.api.services.drive.model.File()
// gFile.name = actualFile.name
val formatter = SimpleDateFormat("yyyyMMddHHmmss")
var dateString = formatter.format(Date())
gFile.name = dateString + suffix
gFile.parents = listOf(preferenceHelper.getFolderId())
val fileContent = FileContent("image/jpeg", actualFile)
val create = googleDriveService.files().create(gFile, fileContent)
.setFields("id, parents")
.execute()
driveFilePathId = create.id
} catch (exception: Exception) {
exception.printStackTrace()
}
} ?: ""
Toast.makeText(context, "Please Log In first!", LENGTH_LONG).show()
return driveFilePathId
}
and I have uploaded encryption and decryption image using AES on my github profile. Please check.
https://github.com/meshramaravind/FileEncryptedAES
And when you display image from google drive. you need to download the image using decryption.
First download the image from google drive function call.
fun downloadFileFromGDrive(id: String) {
getDriveService()?.let { googleDriveService ->
CoroutineScope(Dispatchers.IO).launch {
Log.e("idDownload", id)
val file = File(context.filesDir, "${id}.jpg")
if(!file.exists()) {
try {
val gDriveFile = googleDriveService.Files().get(id).execute()
createDirectoryAndSaveImagePackage(gDriveFile.id)
} catch (e: Exception) {
println("!!! Handle Exception $e")
}
}
}
} ?: ""
//Toast.makeText(context, "Please Log In first!", LENGTH_SHORT).show()
}
and save it to the app private files folder:
fun createDirectoryAndSaveImagePackage(id: String?) {
getDriveService()?.let { googleDriveService ->
CoroutineScope(Dispatchers.IO).launch {
val file = File(context.filesDir, "${id}.jpg")
Log.e("fileEncryptedDirGD", "$file")
try {
val outputStream = FileOutputStream(file)
googleDriveService.files()[id]
.executeMediaAndDownloadTo(outputStream)
if (id != null) {
googleDriveService.readFile(id)
}
val decryptedDataDir = ImageCrypto().decryptFile("$file")
Log.e("decryptedDataDir", decryptedDataDir)
outputStream.flush()
outputStream.close()
} catch (e: Exception) {
e.printStackTrace()
}
}
}
}
and display image jetpack compose.
fun displayImage() {
val fileGD = File(context.filesDir, "${it1}.jpg")
if (fileGD.exists()) {
val decryptedData2 =
ImageCrypto().decryptFile("$fileGD")
val painterBitmap = rememberImagePainter(
data = File(decryptedData2),
builder = {
crossfade(500)
})
val painterState = painterBitmap.state
val painter =
rememberImagePainter(
data = File(decryptedData2),
builder = {
placeholder(R.drawable.placeholder)
error(R.drawable.placeholder)
})
if (painterState is ImagePainter.State.Loading) {
CircularProgressIndicator(
modifier = Modifier.align(Alignment.Center),
color = MaterialTheme.colors.secondary
)
} else {
Image(
painter = painter,
contentScale = ContentScale.Inside,
modifier = Modifier
.width(200.dp)
.height(100.dp)
.padding(PADDING / 2),
contentDescription = null,
)
}
}
}

Unable to get OTP from sms broadcast

I created a two screen verification app where in the first screen you enter the Phone Number and in the second screen you need to type the OTP. Android has broadcast service to automatically detect the otp but this is isn't working. I took reference from here and here. My code is:
#Composable
fun VerifyScreen(
navHostController: NavHostController,
viewModel: LoginViewModel = hiltViewModel(),
number: String,
onClick: (otp: String) -> Unit,
) {
val otp = viewModel.otp.value
SmsRetrieverUserConsentBroadcast { _, code -> viewModel.onEvent(UserDataEvent.EnteredOTP(code)) }
MindYugTheme {
Scaffold(
topBar = {
IconButton(
onClick = { navHostController.navigateUp() },
) {
Icon(
imageVector = Icons.Outlined.ArrowBackIos,
contentDescription = "back",
tint = MaterialTheme.colors.secondary
)
}
},
) {
val phoneNumber = buildAnnotatedString {
withStyle(style = SpanStyle(color = Color(0xFFFFFFFF))) {
append("$number ")
}
pushStringAnnotation(
tag = "resend",// provide tag which will then be provided when you click the text
annotation = "resend"
)
withStyle(style = SpanStyle(color = Color(0xFFB5B4ED))) {
append("RESEND")
}
pop()
}
Column(
modifier = Modifier.padding(16.dp),
horizontalAlignment = Alignment.CenterHorizontally,
) {
Text(
modifier = Modifier.align(Alignment.Start),
text = "Verify",
style = Typography.h4
)
Spacer(modifier = Modifier.height(16.dp))
OTPTextFields(
length = 6
) { getOpt ->
otp.text = getOpt
}
Spacer(modifier = Modifier.height(16.dp))
Text(text = "Please enter the OTP sent to:")
// Text(text = number)
ClickableText(text = phoneNumber, onClick = { offset ->
phoneNumber.getStringAnnotations(
tag = "resend",
start = offset,
end = offset
).firstOrNull()?.let {
Log.d("tag", "clicked")
}
})
Spacer(modifier = Modifier.height(24.dp))
GradientButton(onClick = {
navHostController.navigate(Screen.EnterNameScreen.route)
onClick(otp.text)
}) {
// otpVerification(otp, context)
Text(text = "Next")
}
}
}
}
}
#Composable
fun SmsRetrieverUserConsentBroadcast(
smsCodeLength: Int = 6,
onSmsReceived: (message: String, code: String) -> Unit,
) {
val context = LocalContext.current
var shouldRegisterReceiver by remember { mutableStateOf(false) }
LaunchedEffect(Unit) {
SmsRetriever.getClient(context)
.startSmsUserConsent(null)
.addOnSuccessListener {
shouldRegisterReceiver = true
}
}
val launcher =
rememberLauncherForActivityResult(ActivityResultContracts.StartActivityForResult()) {
if (it?.resultCode == Activity.RESULT_OK && it.data != null) {
val message: String? = it.data!!.getStringExtra(SmsRetriever.EXTRA_SMS_MESSAGE)
message?.let {
val verificationCode = getVerificationCodeFromSms(message, smsCodeLength)
onSmsReceived(message, verificationCode)
}
shouldRegisterReceiver = false
} else {
}
}
if (shouldRegisterReceiver) {
SystemBroadcastReceiver(
systemAction = SmsRetriever.SMS_RETRIEVED_ACTION,
broadCastPermission = SmsRetriever.SEND_PERMISSION,
) { intent ->
if (intent != null && SmsRetriever.SMS_RETRIEVED_ACTION == intent.action) {
val extras = intent.extras
val smsRetrieverStatus = extras?.get(SmsRetriever.EXTRA_STATUS) as Status
when (smsRetrieverStatus.statusCode) {
CommonStatusCodes.SUCCESS -> {
// Get consent intent
val consentIntent =
extras.getParcelable<Intent>(SmsRetriever.EXTRA_CONSENT_INTENT)
try {
// Start activity to show consent dialog to user, activity must be started in
// 5 minutes, otherwise you'll receive another TIMEOUT intent
launcher.launch(consentIntent)
} catch (e: ActivityNotFoundException) {
// Timber.e(e, "Activity Not found for SMS consent API")
}
}
CommonStatusCodes.TIMEOUT -> {
}
}
}
}
}
}
#Composable
fun SystemBroadcastReceiver(
systemAction: String,
broadCastPermission: String,
onSystemEvent: (intent: Intent?) -> Unit
) {
// Grab the current context in this part of the UI tree
val context = LocalContext.current
// Safely use the latest onSystemEvent lambda passed to the function
val currentOnSystemEvent by rememberUpdatedState(onSystemEvent)
// If either context or systemAction changes, unregister and register again
DisposableEffect(context, systemAction) {
val intentFilter = IntentFilter(systemAction)
val broadcast = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
onSystemEvent(intent)
}
}
context.registerReceiver(broadcast, intentFilter)
// When the effect leaves the Composition, remove the callback
onDispose {
context.unregisterReceiver(broadcast)
}
}
DisposableEffect(context, broadCastPermission) {
val intentFilter = IntentFilter(broadCastPermission)
val broadcast = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
onSystemEvent(intent)
}
}
context.registerReceiver(broadcast, intentFilter)
// When the effect leaves the Composition, remove the callback
onDispose {
context.unregisterReceiver(broadcast)
}
}
}
internal fun getVerificationCodeFromSms(sms: String, smsCodeLength: Int): String =
sms.filter { it.isDigit() }
.substring(0 until smsCodeLength)
The error I'm getting is:
java.lang.RuntimeException: Error receiving broadcast Intent { act=com.google.android.gms.auth.api.phone.SMS_RETRIEVED flg=0x200010 pkg=com.mindyug.app (has extras) } in com.google.android.gms.internal.firebase-auth-api.zzvl#f0a6f7b
at android.app.LoadedApk$ReceiverDispatcher$Args.lambda$getRunnable$0$LoadedApk$ReceiverDispatcher$Args(LoadedApk.java:1581)
at android.app.-$$Lambda$LoadedApk$ReceiverDispatcher$Args$_BumDX2UKsnxLVrE6UJsJZkotuA.run(Unknown Source:2)
at android.os.Handler.handleCallback(Handler.java:938)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:233)
at android.app.ActivityThread.main(ActivityThread.java:8063)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:631)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:978)
Caused by: java.lang.NullPointerException: Attempt to invoke interface method 'int java.lang.CharSequence.length()' on a null object reference
at java.util.regex.Matcher.reset(Matcher.java:256)
at java.util.regex.Matcher.<init>(Matcher.java:167)
at java.util.regex.Pattern.matcher(Pattern.java:1027)
at com.google.android.gms.internal.firebase-auth-api.zzvn.zzb(com.google.firebase:firebase-auth##21.0.1:1)
at com.google.android.gms.internal.firebase-auth-api.zzvl.onReceive(com.google.firebase:firebase-auth##21.0.1:8)
at android.app.LoadedApk$ReceiverDispatcher$Args.lambda$getRunnable$0$LoadedApk$ReceiverDispatcher$Args(LoadedApk.java:1566)
at android.app.-$$Lambda$LoadedApk$ReceiverDispatcher$Args$_BumDX2UKsnxLVrE6UJsJZkotuA.run(Unknown Source:2) 
at android.os.Handler.handleCallback(Handler.java:938) 
at android.os.Handler.dispatchMessage(Handler.java:99) 
at android.os.Looper.loop(Looper.java:233) 
at android.app.ActivityThread.main(ActivityThread.java:8063) 

Problem with state in jetpackCompose and Flow

I have a problem for now in JetpackCompose.
The problem is, when I'm collecting the Data from a flow, the value is getting fetched from firebase like there is a listener and the data's changing everytime. But tthat's not that.
I don't know what is the real problem!
FirebaseSrcNav
suspend fun getName(uid: String): Flow<Resource.Success<Any?>> = flow {
val query = userCollection.document(uid)
val snapshot = query.get().await().get("username")
emit(Resource.success(snapshot))
}
NavRepository
suspend fun getName(uid: String) = firebase.getName(uid)
HomeViewModel
fun getName(uid: String): MutableStateFlow<Any?> {
val name = MutableStateFlow<Any?>(null)
viewModelScope.launch {
navRepository.getName(uid).collect { nameState ->
when (nameState) {
is Resource.Success -> {
name.value = nameState.data
//_posts.value = state.data
loading.value = false
}
is Resource.Failure<*> -> {
Log.e(nameState.throwable, nameState.throwable)
}
}
}
}
return name
}
The probleme is in HomeScreen I think, when I'm calling the collectasState().value.
HomeScreen
val state = rememberLazyListState()
LazyColumn(
state = state,
verticalArrangement = Arrangement.spacedBy(10.dp)
) {
items(post) { post ->
//val difference = homeViewModel.getDateTime(homeViewModel.getTimestamp())
val date = homeViewModel.getDateTime(post.timeStamp!!)
val name = homeViewModel.getName(post.postAuthor_id.toString()).collectAsState().value
QuestionCard(
name = name.toString(),
date = date!!,
image = "",
text = post.postText!!,
like = 0,
response = 0,
topic = post.topic!!
)
}
}
I can't post video but if you need an image, imagine a textField where the test is alternating between "null" and "MyName" every 0.005 second.
Check official documentation.
https://developer.android.com/kotlin/flow
Flow is asynchronous
On viewModel
private val _name = MutableStateFlow<String>("")
val name: StateFlow<String>
get() = _name
fun getName(uid: String) {
viewModelScope.launch {
//asyn call
navRepository.getName(uid).collect { nameState ->
when (nameState) {
is Resource.Success -> {
name.value = nameState.data
}
is Resource.Failure<*> -> {
//manager error
Log.e(nameState.throwable, nameState.throwable)
}
}
}
}
}
on your view
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
...
lifecycleScope.launch {
viewModel.name.collect { name -> handlename
}
}
}

Androidx datastore test: Ensure that you are only creating a single instance of datastore for this file

Currently, I am writing some test for my proto datastore. The only problem I have here is that I can't call a specific function because then my test fails / crashes. I find this very confusing, because all my other functions seem to work, except resetDatastore
Here is my code:
Repository
private companion object {
private const val SHOP_FILTER_PRODUCT_DATASTORE: String = "shop_filter_product_datastore_test"
private const val SHOP_FILTER_LIST_DATASTORE: String = "shop_filter_list_datastore_test"
private const val SHOP_FILTER_BTN_DATASTORE: String = "shop_filter_btn_datastore_test"
}
private val testNonVolatileProductDataStore = context.createDataStore(
fileName = SHOP_FILTER_PRODUCT_DATASTORE,
serializer = ShopFilterProductSerializer
)
private val testNonVolatileListDataStore = context.createDataStore(
fileName = SHOP_FILTER_LIST_DATASTORE,
serializer = ShopFilterListSerializer
)
private val testNonVolatileBtnDataStore = context.createDataStore(
fileName = SHOP_FILTER_BTN_DATASTORE,
serializer = ShopFilterBtnSerializer
)
override suspend fun setValueProduct(newProduct: ShopFilterTempHolder) {
if (newProduct.id == null || newProduct.mQuery == null) return
testNonVolatileProductDataStore.updateData { preferences ->
preferences.toBuilder().apply {
positionId = newProduct.id!!
query = newProduct.mQuery
}.build()
}
}
override suspend fun setValueList(newList: ShopFilterTempHolder) {
if (newList.id == null || newList.mQuery == null) return
testNonVolatileListDataStore.updateData { preferences ->
preferences.toBuilder().apply {
positionId = newList.id!!
query = newList.mQuery
mQueryDirection = newList.mQueryDirection
}.build()
}
}
override suspend fun setShopFilterBtn(value: Boolean) {
testNonVolatileBtnDataStore.updateData { preferences ->
preferences.toBuilder().apply {
isChecked = value
}.build()
}
}
override suspend fun peekProductValue(): ShopFilterTempHolder {
val temp = shopFilterProduct.first()
return ShopFilterTempHolder(temp.positionId, temp.query)
}
override suspend fun peekListValue(): ShopFilterTempHolder {
val temp = shopFilterList.first()
return ShopFilterTempHolder(temp.positionId, temp.query, temp.mQueryDirection)
}
override suspend fun peekBtnValue(): Boolean = mappedShopFilterBtn.first()
override suspend fun resetDatastore() {
testNonVolatileProductDataStore.updateData { preferences ->
preferences.toBuilder().apply {
positionId = Constants.SHOP_FILTER_DEFAULT_PRODUCT_ID
query = Constants.SHOP_FILTER_DEFAULT_PRODUCT_QUERY
}.build()
}
testNonVolatileListDataStore.updateData { preferences ->
preferences.toBuilder().apply {
positionId = Constants.SHOP_FILTER_DEFAULT_LIST_ID
query = Constants.SHOP_FILTER_DEFAULT_LIST_QUERY
mQueryDirection = Constants.SHOP_FILTER_DEFAULT_LIST_QUERY_DIRECTION
}.build()
}
testNonVolatileBtnDataStore.updateData { preferences ->
preferences.toBuilder().apply {
isChecked = true
}.build()
}
}
Test
#Test
fun `values should be set to default`() = runBlocking {
val newBtn = false
val newList = ShopFilterTempHolder(0, "testString", 0)
val newProduct = ShopFilterTempHolder(0, "testString", 0)
shopFilterValidator.tempBtnFilterValue = newBtn
shopFilterValidator.tempListFilter = newList
shopFilterValidator.tempProductFilter = newProduct
shopFilterValidator.setNewBtnFilter()
shopFilterValidator.setNewListFilter()
shopFilterValidator.setNewProductFilter()
assertEquals(newProduct, shopFilterDataStoreRepository.peekProductValue())
assertEquals(newList, shopFilterDataStoreRepository.peekListValue())
assertEquals(newBtn, shopFilterDataStoreRepository.peekBtnValue())
shopFilterValidator.deleteAllValues()
assertEquals(defautTempProductFilter, shopFilterDataStoreRepository.peekProductValue())
assertEquals(defaultTempListFilter, shopFilterDataStoreRepository.peekListValue())
assertEquals(defaultTempBtnFilterValue, shopFilterDataStoreRepository.peekBtnValue())
}
Stacktrace
Exception in thread "DefaultDispatcher-worker-2 #coroutine#5" java.io.IOException: Unable to rename C:\Users\Censored\AppData\Local\Temp\robolectric-Method_values_should_be_set_to_default1366629743868428403\com.example.app-dataDir\files\datastore\shop_filter_product_datastore_test.tmp.This likely means that there are multiple instances of DataStore for this file. Ensure that you are only creating a single instance of datastore for this file.
at androidx.datastore.core.SingleProcessDataStore.writeData$datastore_core(SingleProcessDataStore.kt:303)
at androidx.datastore.core.SingleProcessDataStore.transformAndWrite(SingleProcessDataStore.kt:280)
at androidx.datastore.core.SingleProcessDataStore$actor$1.invokeSuspend(SingleProcessDataStore.kt:165)
(Coroutine boundary)
at kotlinx.coroutines.CompletableDeferredImpl.await(CompletableDeferred.kt:86)
at androidx.datastore.core.SingleProcessDataStore$updateData$2.invokeSuspend(SingleProcessDataStore.kt:96)
at androidx.datastore.core.SingleProcessDataStore.updateData(SingleProcessDataStore.kt:96)
at com.example.app.repository.FakeDataStoreRepositoryImpl.deleteDataStore(FakeDataStoreRepositoryImpl.kt:86)
at com.example.app.data.models.validator.ShopFilterValidator$deleteAllValues$1.invokeSuspend(ShopFilterValidator.kt:80)
not sure if that could help you, but in my case the problem occurred when running tests on Windows machine and wasn't there when switching to Linux or executing the test on the emulator instead

Categories

Resources