McEna
11/30/2023, 7:58 AMPablichjenkov
11/30/2023, 8:03 AMMcEna
11/30/2023, 8:03 AM@Composable
fun Render(viewModel: MLSearchViewModel = MLSearchViewModel()){
    val time = getTimeMillis()
    val name = "start_${time}"
    EventTracer.instance.trace(name, "mainview", time)
    val searchTerms = remember { mutableStateOf<String>("") }
    val searchResult = viewModel.searchStateFlow.collectAsState()
    if(searchResult.value.success && searchTerms.value.isNotBlank()){
        EventTracer.instance.trace("search_${searchTerms.value}", "mainview", getTimeMillis())
    }
    MainView.MyApp( {
        if(it.isNotBlank()){
            EventTracer.instance.trace("search_$it", "mainview", getTimeMillis())
            viewModel.loadSearch(it)
        }
        searchTerms.value = it
    }, {
        MainView.ItemList(searchResult.value.data.results)
    })
    EventTracer.instance.trace(name, "mainview", getTimeMillis())
}McEna
11/30/2023, 8:04 AMMcEna
11/30/2023, 8:04 AM@Composable
fun MyApp(onSearch: (String) -> Unit, content: @Composable () -> Unit) {
    MaterialTheme {
        Scaffold(
            topBar = {
                TopBarWithSearch(onSearch)
            }
        ) { innerPadding ->
            content()
        }
    }
}McEna
11/30/2023, 8:04 AMMcEna
11/30/2023, 8:04 AM@OptIn(ExperimentalComposeUiApi::class)
@Composable
fun TopBarWithSearch(onSearch: (String) -> Unit) {
    var text by remember { mutableStateOf("") }
    val keyboardController = LocalSoftwareKeyboardController.current
    val focusManager = LocalFocusManager.current
    TopAppBar(
        title = { Text("My App") },
        navigationIcon = {
            IconButton(onClick = {
                EventTracer.instance.write()
            }) {
                Icon(<http://Icons.Filled.Menu|Icons.Filled.Menu>, contentDescription = "Navigation Drawer Button")
            }
        },
        actions = {
            TextField(
                value = text,
                onValueChange = { text = it },
                label = { Text("Search") },
                leadingIcon = { Icon(Icons.Filled.Search, contentDescription = null) },
                modifier = Modifier.fillMaxWidth(),
                keyboardOptions = KeyboardOptions(imeAction = ImeAction.Search),
                keyboardActions = KeyboardActions(
                    onSearch = {
                        onSearch(text)
                        keyboardController?.hide()
                        focusManager.clearFocus()
                    }
                )
            )
        }
    )
}McEna
11/30/2023, 8:05 AMMcEna
11/30/2023, 8:05 AM@Composable
fun ItemList(mlItems : List<Results>){
    LazyColumn(modifier = Modifier.padding(4.dp)) {
        items(mlItems, key = {it.id!!}){ item ->
            val bookmarked = remember { mutableStateOf(false) }
            Card(
                shape = RoundedCornerShape(4.dp),
                modifier = Modifier
                    .fillMaxWidth()
                    .padding(4.dp)
            ) {
                val time = getTimeMillis()
                val args = mutableMapOf<String, String>().apply {
                    item.id?.let {
                        this["itemId"] = it
                    }
                }
                val safeId = if(item.id != null){
                    item.id!!
                } else {
                    ""
                }
                val categories = mutableListOf<String>("mainview", safeId)
                EventTracer.instance.trace("render${item.id}_$time", categories, time, 0, 0, args)
                Row(verticalAlignment = Alignment.CenterVertically) {
                        Box(modifier = Modifier.size(120.dp)) {
                        val firstImage = if(item.thumbnail != null){
                            item.thumbnail
                        } else {
                            ""
                        }
                        ImageLoader.getInstance()!!.load(firstImage)
                        FloatingActionButton(
                            onClick = {
                                bookmarked.value = !bookmarked.value
                            },
                            modifier = Modifier.align(Alignment.TopEnd).then(Modifier.size(20.dp, 20.dp))
                        ) {
                            if(bookmarked.value){
                                Icon(Icons.Filled.Favorite, contentDescription = null)
                            } else {
                                Icon(Icons.Outlined.FavoriteBorder, contentDescription = null)
                            }
                        }
                    }
                    Column(modifier = Modifier.padding(start = 8.dp)) {
                        Text(text = "${item.title}", style = MaterialTheme.typography.body1)
                        Spacer(modifier = Modifier.height(3.dp))
                        Text(text = "${item.price}", style = MaterialTheme.typography.h6)
                        Spacer(modifier = Modifier.height(2.dp))
                        Text(text = "${item.address?.cityName}", style = MaterialTheme.typography.body2)
                        Spacer(modifier = Modifier.height(1.dp))
                        Text(text = "${item.condition}", style = MaterialTheme.typography.body2)
                        Spacer(Modifier.weight(1f))
                        Text(text = "${item.installments?.amount} X ${item.installments?.quantity}", style = MaterialTheme.typography.body1)
                    }
                }
                EventTracer.instance.trace("render${item.id}_$time", categories, getTimeMillis(), 0 ,0, args)
            }
        }
    }
}McEna
11/30/2023, 8:06 AMImageLoader.getInstance()!!.load(firstImage)
return an Image after downloading & creating an ImageBitmapMcEna
11/30/2023, 8:06 AM@Composable
actual fun loadNetwork(imageUri: String, modifier: Modifier) {
    val bitmapState: MutableState<LoadedFile?> = remember { mutableStateOf(null) }
    if(bitmapState.value?.isAddressEqual(imageUri) != true){
        jobScope.getScope().launch {
            NSURL.URLWithString(imageUri)?.let { url ->
                val request = NSMutableURLRequest.requestWithURL(url)
                request.setHTTPMethod("GET")
                val task = NSURLSession.sharedSession.dataTaskWithRequest(request) { data , res, err ->
                    jobScope.getScope().launch {
                        data?.let {
                            val image = UIImage(it).toImageBitmap()
                            withContext(Dispatchers.Main) {
                                bitmapState.value = LoadedFile(imageUri).apply {
                                    this.bitmap = image
                                }
                            }
                        }
                    }
                }
                task.resume()
            }
        }
    }
    if(bitmapState.value?.bitmap!=null){
        Image(
            bitmap = bitmapState.value!!.bitmap!!,
            contentDescription = null,
            contentScale = ContentScale.Fit,
            modifier = modifier.then(Modifier.fillMaxSize())
        )
    }
}McEna
11/30/2023, 8:07 AMMcEna
11/30/2023, 8:08 AMPablichjenkov
11/30/2023, 12:21 PM@Composable
Render (viewModel: MLSearchViewModel = MLSearchViewModel())
try
@Composable
Render (viewModel: MLSearchViewModel)
I don't see where you call Render() but you  should host the ViewModel outside otherwise you will be creating a new instance on each recomposition.