Collect to list on specific condition or exit - java-stream

if (response.getSubscriber().getGroups() != null) {
List<SPMGetGroupResponse> groupResponses = response.getSubscriber().getGroups()
.stream()
.map(groupId -> callGetGroupAPI(groupId))
.filter(r -> r.getResultCode() == CommonResult.SUCCESS.getResultCode())
.collect(toList());
Is there a way in streams to make the above stop the moment r.getResultCode is not SUCCESSFUL?
the stream equivalent of
List<SPMGetGroupResponse> groupResponses = new ArrayList<>();
for (String groupId : groupIds) {
SPMGetGroupResponse grpResponse = callGetGroupAPI(groupId);
if (grpResponse.getResultCode() == CommonResult.SUCCESS.getResultCode()) {
groupResponses.add(grpResponse);
} else {
break;
}
}

There's no standard way in Java-8 to do this. In Java-9 new operation called takeWhile() was added for this purpose:
List<SPMGetGroupResponse> groupResponses = response.getSubscriber().getGroups()
.stream()
.map(groupId -> callGetGroupAPI(groupId))
.takeWhile(r -> r.getResultCode() == CommonResult.SUCCESS.getResultCode())
.collect(toList());
Some third-party libraries including my library StreamEx backported takeWhile():
List<SPMGetGroupResponse> groupResponses = StreamEx.of(response.getSubscriber().getGroups())
.map(groupId -> callGetGroupAPI(groupId))
.takeWhile(r -> r.getResultCode() == CommonResult.SUCCESS.getResultCode())
.toList();

Related

How to take pictures using only the front camera in jetpack compose?

I am trying to take pictures from front camera using jetpack compose. I tried it using LocalContext.current.getCameraProvider() but it opens only the back camera. I do not want to open the back camera. I tried this to open the camera but I am unable to open the front camera.
I am new to jetpack compose, someone please help me.
This should be the way:
#Composable
fun CameraView(onImageCaptured: (Uri, Boolean) -> Unit, onError: (ImageCaptureException) -> Unit) {
val context = LocalContext.current
var lensFacing by remember { mutableStateOf(CameraSelector.LENS_FACING_BACK) }
val imageCapture: ImageCapture = remember {
ImageCapture.Builder().build()
}
val galleryLauncher = rememberLauncherForActivityResult(
ActivityResultContracts.GetContent()
) { uri: Uri? ->
if (uri != null) onImageCaptured(uri, true)
}
CameraPreviewView(
imageCapture,
lensFacing
) { cameraUIAction ->
when (cameraUIAction) {
is CameraUIAction.OnCameraClick -> {
imageCapture.takePicture(context, lensFacing, onImageCaptured, onError)
}
is CameraUIAction.OnSwitchCameraClick -> {
lensFacing =
if (lensFacing == CameraSelector.LENS_FACING_BACK) CameraSelector.LENS_FACING_FRONT
else
CameraSelector.LENS_FACING_BACK
}
is CameraUIAction.OnGalleryViewClick -> {
if (true == context.getOutputDirectory().listFiles()?.isNotEmpty()) {
galleryLauncher.launch("image/*")
}
}
}
}
}

Android dataStore with flow not get update after edit

I'm use DataStore with flow but I cant get any update on the flow when editing DataStore.
Store.kt
private class IStore(private val context: Context): Store {
val eventIDKey = stringPreferencesKey("EventID")
override suspend fun setEventID(eventID: String) {
context.dataStoreSettings.edit { settings ->
settings[eventIDKey] = eventID
}
}
override fun getEventID(): Flow<String> {
return context.dataStoreSettings.data.map { settings -> settings[eventIDKey].orEmpty() }
}
}
and manipulate getEventID() with data from room database in event service
EventService.kt
fun getSelectedEventLive() = store.getEventID()
.onEach { Log.d("EventService", "income new event id $it") }
.flatMapConcat { if(it.isNotBlank()) eventDao.get(it) else flowOf(null) }
onEach called when I collect the data but when updated it's not called again and need to close and open the app to show the latest data
MainViewModel.kt
val selectedEvent = eventService.getSelectedEventLive()
.stateIn(viewModelScope, SharingStarted.Lazily, null)
and use on Compose with this
val currentEvent by mainViewModel.selectedEvent.collectAsState()
Maybe I doing wrong or maybe there is something I miss?
Usually, you want to use flow.collect {...}, since Flow is cold and need to know that it is being collected to start producing new values.
// MainViewModel.kt
private val _selectedEvent = MutableStateFlow<TypeOfYourEvent>()
val selectedEvent: StateFlow<TypeOfYourEvent> = _selectedEvent
init {
viewModelScope.launch {
getSelectedEventLive().collect { it ->
_selectedEvent.value = it
}
}
}
This example should be fine with your composable's code, you still can collect selectedEvent as state.
Yeah i found the solusion its works if i change the flatMapConcat with flatMapLatest in EventService.kt
fun getSelectedEventLive() = store.getEventID()
.filterNot { it.isBlank() }
.flatMapLatest { eventDao.get(it) }

Handle properly number in Jetpack Compose

How can I properly handle number in text component in jetpack compose (with MVVM pattern)
Please note that the price can be null or have a value (maybe 0 btw)
I have a poor implementation for now, I changed the keyboard like this :
OutlinedTextField(
value = if (vm.viewState.collectAsState().value.price != null) vm.viewState.collectAsState().value.price.toString() else "",
onValueChange = { vm.onProductPriceChange(it) },
label = { Text(stringResource(id = R.string.price)) },
keyboardOptions = KeyboardOptions(
capitalization = KeyboardCapitalization.None,
autoCorrect = true,
keyboardType = KeyboardType.Number
),
)
and for onValueChange :
fun onProductPriceChange(it: Any) {
if (it.toString() == "") {
_viewState.value = _viewState.value.copy(price = null)
} else {
try
{
_viewState.value = _viewState.value.copy(price = it.toString().toDouble())
}
catch (e: NumberFormatException)
{ // dismiss the bad entries
}
}
}
there can be multiple bad output of the user for example write 22..0 (I dismissed them which is a workaround acceptable)
but there are bad behaviour, when you want to write 10, it will convert it to 10.0. it is not huge but it has backwards
when you delete number in the EditText, 10.0 will become 10.0 and then 100.0 and then 10.0 and finally 1.0. btw it is impossible to go back to the null value (for this case, I can consider 0.0 = no value)
I saw that VisualTransformation (https://medium.com/google-developer-experts/hands-on-jetpack-compose-visualtransformation-to-create-a-phone-number-formatter-99b0347fc4f6) could handle my case but the documentation seems complicated
class DoubleVisualTransformation : VisualTransformation {
override fun filter(str: AnnotatedString): TransformedText {
val strNullDouble = str.text.toBigDecimalOrNull()
var transformedString: String
if (str.text == "" || strNullDouble == null)
return TransformedText(AnnotatedString(""), OffsetMapping.Identity)
else if (strNullDouble.toDouble() % 1 == 0.0 && str.text.last() != '.')
transformedString = strNullDouble.toInt().toString()
else
transformedString = str.text
return TransformedText(
text = AnnotatedString(transformedString),
offsetMapping = object : OffsetMapping {
override fun originalToTransformed(offset: Int): Int {
return offset
}
override fun transformedToOriginal(offset: Int): Int {
return offset
}
}
)
}
}
how can I improve the behavior ?
What about not returning a double to your TextField but just the String?
fun onProductPriceChange(it: String) {
if (it == "") {
_viewState.value = _viewState.value.copy(price = null)
} else {
if (it.toDoubleOrNull() != null) {
_viewState.value = _viewState.value.copy(price = it)
}
}
}

Is there <NonBodyParameter> equivalent

I updated Swashbuckle v5 and operation.Parameters() is not valid anymore.Is there any replacement?
{
var apiDescription = context.ApiDescription;
operation.Deprecated |= apiDescription.IsDeprecated();
if (operation.Parameters == null)
{
return;
}
// REF: https://github.com/domaindrivendev/Swashbuckle.AspNetCore/issues/412
// REF: https://github.com/domaindrivendev/Swashbuckle.AspNetCore/pull/413
foreach (var parameter in operation.Parameters<NonBodyParameter>())
{
var description = apiDescription.ParameterDescriptions.First(p => p.Name == parameter.Name);
if (parameter.Description == null)
{
parameter.Description = description.ModelMetadata?.Description;
}
if (parameter.Default == null)
{
parameter.Default = description.DefaultValue;
}
parameter.Required |= description.IsRequired;
}
}
Error CS0307 The property 'OpenApiOperation.Parameters' cannot be used with type arguments
From Swashbuckle.AspNetCore GitHub site
In OpenAPI v3, body parameters are split out into a separate property
called RequestBody. So, I think you may be able to remove OfType
filter entirely as all values in the collection are "non-body"
I think you should be able to use OpenApiParameter.

Implementing Linked List in Kotlin

I've recently started learning Kotlin, so I decided to implement some data structures in it.
So, I've tried implementing a singly linked list:
package datastructures
public class LinkedList {
private data class Node(var nodeValue: Int, var next: Node? = null)
private var head: Node? = null
fun insert(n: Int) {
if(head == null) head = Node(n)
else {
var cur = head
while(cur?.next != null) {
cur = cur?.next
}
cur?.next = Node(n)
}
}
fun print() {
var cur = head
while(cur != null) {
print("${cur.nodeValue} ")
cur = cur?.next
}
}
}
fun main(args: Array<String>) {
val n = LinkedList()
n.insert(5)
n.insert(3)
n.print()
}
and I got the following error:
Error:(22, 13) Kotlin: [Internal Error] org.jetbrains.jet.codegen.CompilationException: Back-end (JVM) Internal error: cannot store to value org.jetbrains.jet.codegen.StackValue$OnStack#a0a447f
Cause: cannot store to value org.jetbrains.jet.codegen.StackValue$OnStack#a0a447f
File being compiled and position: (22,13) in C:/Users/Khaled/IdeaProjects/Kotlin/src/LinkedList.kt
PsiElement: cur?.next = Node(n)
The root cause was thrown at: StackValue.java:75
at org.jetbrains.jet.codegen.ExpressionCodegen.genQualified(ExpressionCodegen.java:243)
at org.jetbrains.jet.codegen.ExpressionCodegen.genStatement(ExpressionCodegen.java:262)
at ...
I've been searching here and in google but I can't figure out what's the problem causing this error
Edit:
So I've tried to re-implement the insert function and use requireNotNull() to avoid having the compiler worry about the null-safety stuff.
Here is the code and it's now working:
fun insert(n: Int) {
if (head == null) head = Node(n)
else {
var cur = head!!
while (cur.next != null) {
cur = cur.next!!
}
cur.next = Node(n)
}
}
I think the problem lies in this line:
cur?.next = Node(n)
The problem is that the compiler doesn't know what to do if cur is null. Currently, this results in internal error, but this may be supported in a future version.
For now, the best solution is to rewrite the code such that the compiler could check that cur is never null. The problem is that the compiler assumes that fields declared as var can change at any time, so their values need to be loaded into local variables before checking for null:
var cur = head
if(cur == null) head = Node(n)
else {
var next = cur.next
while(next != null) {
cur = next
next = cur.next
}
cur.next = Node(n)
}

Resources