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
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.
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.
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
}
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 !.
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.