LazyPagingItems not collecting for LazyVerticalGrid with Search Query Funtional Paging 3.0 Jetpack Compose - state

I want to update list from paging with search query result,basically I had success to display item paging to lazyverticalgrid without searchQuery variable. The problem is when I click search button from keyboard virtual, the items not update in compose
HomeViewModel.kt
#HiltViewModel
class HomeViewModel #Inject constructor(
savedStateHandle: SavedStateHandle,
private val productRepository: ProductRepository,
private val dataUserDao: DataUserDao
) : ViewModel() {
private val _searchLiveData = savedStateHandle.getLiveData("search", "")
val searchLiveData: LiveData<String> get() = _searchLiveData
private val _productList = MutableStateFlow<PagingData<Product>>(PagingData.empty())
val productList = _productList.asStateFlow()
init {
getDashboard()
getBanner()
searchProduct("") // this work!
}
fun searchProduct(s: String) { // when this execute again with value the product list not recomposed
viewModelScope.launch {
productRepository.getProducts(0, s, "", "").collect { data ->
_productList.value = data
}
}
}
The collectAsLazyPagingItems function for product list is work when search query is empty, but when search query is not empty collectAsLazyPagingItems function is not triggered
ShopScreen.kt
#HomeNavGraph
#Destination
#Composable
fun ShopScreen(
navigator: DestinationsNavigator,
viewModel: HomeViewModel = hiltViewModel()
) {
.....
val lazyGridState = rememberLazyGridState(
val productListItems: LazyPagingItems<Product> =
viewModel.productList.collectAsLazyPagingItems()
Column(
modifier = Modifier
.fillMaxSize()
.padding(horizontal = 16.dp)
) {
...
LazyVerticalGrid(
state = lazyGridState,
columns = GridCells.Adaptive(screenWidth),
verticalArrangement = Arrangement.spacedBy(10.dp),
horizontalArrangement = Arrangement.spacedBy(8.dp),
contentPadding = PaddingValues(vertical = 16.dp)
) {
Log.e("TAG", "ShopScreen: ${state.productList.size}")
items(productListItems.itemCount) { index ->
CardProductShopGrid(product = productListItems[index]!!, onClick = {})
}
}
}
}
}

Related

Why Int attributes are not being saved in DynamoDB when using AWS SDK 2.x?

I added an Int attribute in my class named isAlsoActor but it doesn't get saved in DynamoDB. Here is the class I'm trying to save in Dynamo:
package me.brunosantana.dto
import com.fasterxml.jackson.annotation.JsonInclude
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbAttribute
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbBean
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbIgnore
import software.amazon.awssdk.services.dynamodb.model.AttributeValue
private const val TYPE = "ARTIST"
#DynamoDbBean
//#JsonInclude(JsonInclude.Include.NON_EMPTY)
data class Artist(
#get:DynamoDbAttribute("ArtistName")
var name: String,
#get:DynamoDbAttribute("Nationality")
var nationality: String,
#get:DynamoDbAttribute(value = "IsAwardWinner")
var isAwardWinner: Boolean,
#get:DynamoDbAttribute(value = "IsAlsoActor")
var isAlsoActor: Int,
#get:DynamoDbIgnore
val songs: MutableList<Song> = mutableListOf()
): DynamoBaseModel(
pkType = "artist",
pkId = name.lowercase().replace(" ", "_"),
sk = "artist#${name.lowercase().replace(" ", "_")}",
gsi1pk = "type#artist",
gsi1sk = "type#artist",
) {
constructor(
name: String,
nationality: String,
isAwardWinner: Boolean,
isAlsoActor: Int
) :
this(
name = name,
nationality = nationality,
isAwardWinner = isAwardWinner,
isAlsoActor = isAlsoActor,
songs = mutableListOf()
)
#Deprecated(message = "Intended to be used only by AWS SDK")
constructor() :
this(
name = "",
nationality = "",
isAwardWinner = false,
isAlsoActor = 0,
songs = mutableListOf()
)
#DynamoDbAttribute("Type")
fun getType(): String {
return TYPE
}
fun setType(type: String) {
// Do nothing, this setter is just to make the AWS SDK 2.x happy
}
fun addAllSongs(songs: MutableList<Song>){
this.songs.addAll(songs)
}
companion object {
fun attributeMapToArtist(attributeMap: Map<String, AttributeValue>): Artist {
val name = attributeMap["ArtistName"]!!.s()
val nationality = attributeMap["Nationality"]!!.s()
val isAwardWinner = attributeMap["IsAwardWinner"]?.bool() ?: false
val isAlsoActor = attributeMap["IsAlsoActor"]?.n()?.toInt() ?: 0
val versionTimestamp = attributeMap["VersionTimestamp"]?.s()
val artist = Artist(
name = name,
nationality = nationality,
isAwardWinner = isAwardWinner,
isAlsoActor = isAlsoActor)
artist.versionTimestamp = versionTimestamp
return artist
}
}
}
Here is the code responsible for saving it in Dynamo (it's using putItem):
fun saveModel(model: DynamoBaseModel){
val pk = "${model.pkType}#${model.pkId}"
val existingModel = findByPkAndSk(pk, model.sk)
val existingVersion = existingModel?.versionTimestamp
val incomingVersion = model.versionTimestamp!!
try {
when(model){
is Artist -> {
save(model, incomingVersion, existingVersion, true)
}
is Song -> {
save(model, incomingVersion, existingVersion, true)
}
}
}catch (e: DynamoDbException){
e.printStackTrace()
}
}
fun findByPkAndSk(pk: String, sk: String): DynamoBaseModel? {
val tableName = "music"
val pkAttribute = AttributeValue.builder().s(pk).build()
val skAttribute = AttributeValue.builder().s(sk).build()
val queryReq = QueryRequest.builder()
.tableName(tableName)
.consistentRead(false)
.keyConditionExpression("pk = :pk and sk = :sk")
.expressionAttributeValues(mapOf(":pk" to pkAttribute, ":sk" to skAttribute))
.build()
try {
val queryResponse: QueryResponse = client.query(queryReq)
queryResponse.items().firstOrNull {
return when(it["Type"]!!.s()) {
"ARTIST" -> Artist.attributeMapToArtist(it)
"SONG" -> Song.attributeMapToSong(it)
else -> throw Exception("Not found")
}
}
} catch (e: DynamoDbException) {
System.err.println(e.message)
}
return null
}
private final inline fun <reified T> save(model: T, incomingVersion: String, existingVersion: String?, versioningCheck: Boolean){
println("incoming: $incomingVersion existing: $existingVersion")
val musicTable: DynamoDbTable<T> =
enhancedClient.table("music", TableSchema.fromBean(T::class.java))
if(versioningCheck){
if(existingVersion == null){
println("no existing version")
musicTable.putItem(model)
}else{
val incomingDate = DateUtils.convertStringToZonedDateTime(incomingVersion)
val existingDate = DateUtils.convertStringToZonedDateTime(existingVersion)
if(DateUtils.isIncomingDateNewer(incomingDate, existingDate)){
println("override")
musicTable.putItem(model) //check how to override properly
}else{
println("Skip. $incomingVersion is older than $existingVersion")
}
}
}else{
println("check disabled")
musicTable.putItem(model)
}
}
Does anyone have any idea why it's not saving the Int attribute? It saves the item in the table, but the Int attribute does not appear there.
Thank you.

Return list outside ForEach loop return only last item in Kotlin

I need to return all list items, in forEach it works fine, outside the loop it only returns the last item.
fun scanAndConvertFile(): String {
val scanner = Scanner(System.`in`)
print("Enter path to file to convert: ")
val fileName: String = scanner.nextLine()
val bufferedReader: BufferedReader = File(fileName).bufferedReader()
var result = bufferedReader.use { it.readText() }
val header = result.substring(0, result.indexOf(":61:"))
val body = result.substring(result.indexOf(":61:"), result.lastIndexOf(":61:220131C6"))
val footer = result.substring(result.lastIndexOf(":61:220131C6"), result.length)
var list = body.split(":61:")
list = list.filter { it.isNotEmpty() }
list = list.map {
":61:$it"
}
list.forEach() {
val part1 = it.substring(0, it.indexOf("?20"))
var part2ToBePasted = it.substring(it.indexOf("?20"), it.indexOf("?00"))
part2ToBePasted = part2ToBePasted.drop(3)
val part3 = it.substring(it.indexOf("?00"), it.indexOf("?27"))
var part4ToPast = it.substring(it.indexOf("?27"), it.indexOf("?28"))
part4ToPast = part4ToPast.drop(3)
val part5 = it.substring(it.indexOf("?28"), it.length)
list = if(part4ToPast.equals("")) {
listOf(part1.plus("?20").plus(part2ToBePasted).plus(part3).plus("?27").plus(part4ToPast).plus(part5))
} else {
listOf(part1.plus("?20").plus(part4ToPast).plus(part3).plus("?27").plus(part4ToPast).plus(part5))
}
// println(list) - works good
}
val converted = header.plus(list).plus(footer)
// println(converted) - print only last element of list
return converted
}
I tried to clean up your code a little (with no guarantee of course since I do not have any test data):
fun scanAndConvertFile(): String {
print("Enter path to file to convert: ")
val fileName: String = Scanner(System.`in`).nextLine()
val bufferedReader: BufferedReader = File(fileName).bufferedReader()
val result = bufferedReader.use { it.readText() }
val header = result.substring(0, result.indexOf(":61:"))
val footer = result.substring(result.lastIndexOf(":61:220131C6"), result.length)
val list = result
.substring(result.indexOf(":61:"), result.lastIndexOf(":61:220131C6"))
.split(":61:")
.filter { it.isNotEmpty() }
.map { ":61:$it" }
.map {
val indexOf00 = it.indexOf("?00")
val indexOf20 = it.indexOf("?20")
val indexOf27 = it.indexOf("?27")
val indexOf28 = it.indexOf("?28")
val substring27to28 = it.substring(indexOf27, indexOf28).drop(3)
it.substring(0, indexOf20)
.plus("?20")
.plus(if (substring27to28 == "") it.substring(indexOf20, indexOf00).drop(3) else substring27to28)
.plus(it.substring(indexOf00, indexOf27))
.plus("?27")
.plus(substring27to28)
.plus(it.substring(indexOf28, it.length))
}
return header.plus(list).plus(footer)
}
Basically you need to use map instead of forEach to return a list. map is used to transform each element of a list, while with forEach you do something to or with each element, but no list is returned.

recycler adapter is not updating on calling notifydatasetchanged()

I passed a list to the adapter from an activity and on calling notifydatasetchanged, recycler view is still empty, It is not updating the view.
var list : ArrayList<StationBean> = ArrayList()
override fun getItemCount(): Int {
return list.size
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
return ViewHolder(LayoutInflater.from(context).inflate(R.layout.stations_adapter, parent, false))
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.stationsName.text = list.get(position).stationName
holder.cityName.text = list.get(position).latitude.toString()
}
fun add_data(data : StationsListDataClass)
{
list = data.stationBeanList
notifyDataSetChanged()
Log.d("List", list.toString())
}
}
////// . Setting the adapter .
private var adapter: StationsListAdapter = StationsListAdapter(this)
recycler_view_stationsList.apply {
layoutManager = LinearLayoutManager(this.context)
this.adapter = adapter
}
///// Layout File
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recycler_view_stationsList"
android:scrollbars="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="visible"
/>
// . Main Activity Full Code , I used inject for calling presenter,The main problem is in the setRecycler function
#Inject
lateinit var stationsListPresenter: StationsListPresenter
private lateinit var station_adapter: StationsListAdapter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_stations_list)
setupRecycler()
stationsListPresenter.downLoadStationsListUsingRetrofit()
}
private fun setupRecycler()
{
val recyclerView : RecyclerView = findViewById(R.id.recycler_view_stations_list)
recyclerView.apply {
layoutManager = LinearLayoutManager(this#StationsListActivity) // replace MainActivity with your activity name
station_adapter = StationsListAdapter(this#StationsListActivity)
}
recyclerView.adapter = station_adapter
}
override fun addNewsToRecyclerView(stationsList: StationsListDataClass)
{
station_adapter.add_data(stationsList)
}
override fun makeInjection(activityComponent: ActivityComponent) {
activityComponent.inject(this)
}
The View is still empty after calling notifydatasetchanged()
and I am not getting any error.
The List have around 800 objects.
Recycler View is showing null pointer exception, even after binding view using findviewbyID
Please post your xml layout and/or setting up recycler view code. Maybe there is no LayoutManager set. You may set it in xml or in the activity/fragment:
recyclerView.setLayoutManager(new LinearLayoutManager(this));
also try clearing your list in add_data()
list.clear()
list.addAll(..)
And modify your add_data function like this
fun add_data(data : StationsListDataClass){
list.clear()
list.addAll(data.stationBeanList)
notifyDataSetChanged()
Log.d("List", list.toString())
}
Update
Modify your setupRecycler like below
private fun setupRecycler(){
var recyclerView = findViewById(R.id.recycler_view_stations_list)
station_adapter = StationsListAdapter(this#StationsListActivity)
val layoutManager = LinearLayoutManager(this#StationsListActivity)
recyclerView?.layoutManager = layoutManager
recyclerView?.adapter = station_adapter
}

How to add dynamic values to field injections list with custom trigger to camunda properties panel?

I have two questions here
Is it possible to add dynamic lists values to field injection list input ?
Can I create a trigger for this so this can be initiated from any other input selection say a class selection will populate all fields
I was just looking into FieldInjection.js whether that can be extented for the same
Can someone please provide a hint or direction for this ?
Thanks.
For anyone interested in the answer, I was able to achieve the above goal by changing the set function of the Java Class select input as folllowing
few imports
var extensionElementsHelper = require('../../../../helper/ExtensionElementsHelper'),
elementHelper = require('../../../../helper/ElementHelper')
var CAMUNDA_FIELD_EXTENSION_ELEMENT = 'camunda:Field';
function getExtensionFields(bo) {
return bo && extensionElementsHelper.getExtensionElements(bo, CAMUNDA_FIELD_EXTENSION_ELEMENT) || [];
}
then changing the set function to create extension element and push the field values as :
set: function(element, values, node) {
var bo = getBusinessObject(element);
var type = getImplementationType(element);
var attr = getAttribute(type);
var prop = {}
var commands = [];
prop[attr] = values.delegate || '';
var extensionElements = getExtensionFields(bo);
//remove any extension elements existing before
extensionElements.forEach(function(ele){
commands.push(extensionElementsHelper.removeEntry(getBusinessObject(element), element, ele));
});
if(prop[attr] !== ""){
var extensionElements = elementHelper.createElement('bpmn:ExtensionElements', { values: [] }, bo, bpmnFactory);
commands.push(cmdHelper.updateBusinessObject(element, bo, { extensionElements: extensionElements }));
var arrProperties = ["private org.camunda.bpm.engine.delegate.Expression com.cfe.extensions.SampleJavaDelegate.varOne","private org.camunda.bpm.engine.delegate.Expression com.cfe.extensions.SampleJavaDelegate.varTwo"]
var newFieldElem = "";
arrProperties.forEach(function(prop){
var eachProp = {
name:"",
string:"",
expression:""
}
var type = prop.split(" ")[1].split(".").reverse()[0];
var val = prop.split(" ")[2].split(".").reverse()[0];
eachProp.name = val;
if( type == "String"){
eachProp.string = "${" + val +" }"
}else if( type == "Expression"){
eachProp.expression = "${" + val +" }"
}
newFieldElem = elementHelper.createElement(CAMUNDA_FIELD_EXTENSION_ELEMENT, eachProp, extensionElements, bpmnFactory);
commands.push(cmdHelper.addElementsTolist(element, extensionElements, 'values', [ newFieldElem ]));
});
}
commands.push(cmdHelper.updateBusinessObject(element, bo, prop));
return commands;
}
Cheers !.

MongoDB Map Reduce C#

I am currently doing a map-reduce with the c# driver in Mongo.
I have got it working where the JSON is as follows:
{ "_id" : CSUUID("ef53b163-699c-462f-9135-b81bad115635"), "value" : { "firstname" : "Joe", "lastname" : "Bloggs", "groupName" : "System Wide Access" } }
What I want to do is flatten this object so as I don't have an Id and Value field, I only want the actual properties that are in my read model class.
Here is my code as it is currently:
const string mapUserGroupMember = #"function ()
{
var output = {groupId:this.GroupId, firstname:this.Forename, lastname:this.Surname, groupName:null}
emit(this.GroupId, output);
}";
const string mapUserGroupName = #"function ()
{
var output = {groupId:this._id, firstname:null, lastname:null, groupName:this.Name}
emit(this._id, output);
}";
var reduceF = #"function(key, values) {
var results = {firstname:null, lastname:null , groupName:null};
values.forEach(function(v){
if(results.firstname ==null){
results.firstname = v.firstname
}
if(results.lastname ==null){
results.lastname = v.lastname
}
if(results.groupName ==null){
results.groupName = v.groupName
}
});
return results;
};";
var groupMemberCollection = database.GetCollection("UserGroupMemberReadModel");
var groupNameCollection = database.GetCollection("UserGroupNameReadModel");
var options = new MapReduceOptionsBuilder();
options.SetOutput(MapReduceOutput.Reduce("MergedData"));
var results = groupNameCollection.MapReduce(mapUserGroupName, reduceF, options);
results = groupMemberCollection.MapReduce(mapUserGroupMember, reduceF, options);
I want to be able to call var collection = database.GetCollection("MergedData").AsQueryable<ReadModel>();
Any help would be appreciated.