JetBrains / jewel

An implementation of the IntelliJ look and feels in Compose for Desktop
Apache License 2.0
636 stars 30 forks source link

LazyTree - How to add nodes after network call #345

Closed Yashobanta-Kumar-Behera closed 3 months ago

Yashobanta-Kumar-Behera commented 3 months ago
fun ChildrenGeneratorScope<Note>.dirExpander(isDirectory: (Note) -> Unit ) {
    var notes: List<Note>? = null
    runBlocking {
        noteService.getNotesFromStorage(parent.data).collectLatest {
            notes = it.notes
        }
    }
    notes?.forEach { newNote ->
        if (newNote.isDirectory) {
            addNode(newNote) {
                dirExpander(isDirectory)
            }
        } else addLeaf(newNote)
    }
}

I need to load the child nodes after network call completed till then need to show loader in the node which is expanded. Is there any way?

rock3r commented 3 months ago

Please don't spam and directly ping project members with "how do I" questions in the issue tracker. This isn't stack overflow; the issue tracker is to track issues with jewel and not general Compose/CS questions.

Yashobanta-Kumar-Behera commented 3 months ago

But I am using lazy tree of jewel but i can't find any way to generate nodes asynchronously and if coroutine scopes are used then the nodes are not getting updated. What can i do? There are no documentation regarding this in jewel. can you help me that?

rock3r commented 3 months ago

If you're generating the tree in exactly the same way as we do in our sample code, saving it to a state, and the tree doesn't update, please file a bug for that bug with repro steps, expected behaviour, and if possible sample code that reproduces the issue, then we can look into it

Yashobanta-Kumar-Behera commented 3 months ago

The sample code provided in the standalone app it uses static way to build the tree. There are no sample for async.

Yashobanta-Kumar-Behera commented 3 months ago
fun Note.asTree(isDirectory: (Note) -> Unit = {}): Tree<Note> =
    buildTree {
        addNode(this@asTree) {
            dirExpander(isDirectory)
        }
    }

val coroutineScope = CoroutineScope(Dispatchers.Default)

fun ChildrenGeneratorScope<Note>.dirExpander(isDirectory: (Note) -> Unit ) {
    var notes: List<Note>? = null
    coroutineScope.launch {
        noteService.getNotesFromStorage(parent.data).collectLatest {
            notes = it.notes
        }
        notes?.forEach { newNote ->
            if (newNote.isDirectory) {
                addNode(newNote) {
                    dirExpander(isDirectory)
                }
            } else addLeaf(newNote)
        }
    }

}

    val tree by remember { mutableStateOf(rootNote.asTree()) }
    val lazyListState = rememberLazyListState()
    val treeState = remember { TreeState(SelectableLazyListState(lazyListState)) }

        Box(modifier.fillMaxSize().border(1.dp, borderColor, RoundedCornerShape(2.dp))) {
            LazyTree(
                tree = tree,
                treeState = treeState,
                onElementClick = {},
                onElementDoubleClick = { element ->
                    val selectedNote = element.data
                    if (selectedNote.isDirectory) {
                        return@LazyTree
                    }
                    MainViewModel.noteTabs = MainViewModel.noteTabs.toMutableMap().apply {
                        putIfAbsent(
                            selectedNote.path, NoteEditorState(CodeEditor(EditorSettings()), selectedNote)
                    ) }
                    MainViewModel.selectedTabKey = selectedNote.path

                },
            ) { element ->
                Row(Modifier.fillMaxWidth().padding(vertical = 2.dp), verticalAlignment = Alignment.CenterVertically) {
                    val selectedNote = element.data
                    Icon(
                        resource = if (selectedNote.isDirectory) FileIconProvider.getFolderIconPath() else FileIconProvider.getIconPath(FileUtil.getFileExtension(selectedNote.name)),
                        contentDescription = null,
                        iconClass = IconHolder::class.java,
                        modifier = Modifier.size(20.dp).padding(end = 5.dp),
                    )
                    Text(element.data.name, fontSize = 14.sp)
                }
            }

            VerticalScrollbar(
                rememberScrollbarAdapter(noteBrowserState.lazyListState),
                modifier = Modifier.align(Alignment.CenterEnd),
            )
        }

Here is the code sample which i have used

rock3r commented 2 months ago

Modifying trees works fine, I just updated the standalone sample. https://github.com/JetBrains/jewel/commit/ee994e20978e19d079cbfd0bd6c509a2bf154286

The issue is somewhere in your code — check that you're actually setting the new tree value. If you find bugs in Jewel please open a new issue.