Composable Focus - kotlin

I have a project where we display a graph, this graph is in an Box which is scrollable.
By opening the view, we need to center the root node which causes the problem currently.
Determining the position and setting the values of the states is currently done the following way:
.onGloballyPositioned { coordinates -> scrollBy = coordinates.positionInParent().y - dpstate!!.scrollState.firstVisibleItemScrollOffset
}
.onFocusChanged {
if(it.isFocused ){
print("is focused")
scope.launch { dpstate!!.scrollState.animateScrollBy(scrollBy)
dpstate!!.offsetState.value = Offset(leftX.toFloat(),dpstate!!.offsetState.value.y)
}
}
}
in the modifier of the box.
The state dpstate is an instance of the following:
data class DisplayState(
val scrollState: LazyListState,
val scaleState: MutableState<Float>,
val offsetState: MutableState<Offset>,
val editState: MutableState<Boolean>,
val showInfo:Map<Int, MutableState<Boolean>>,)
Important is, that I need to center by opening it, not by clicking a button.
My try was in the calling code of all of this the following code:
DisposableEffect(Unit){
com.github.tukcps.appel.ui.rendering.focusRequester!!.requestFocus()
onDispose { }
}
There is no exception, it just don't do anything, thanks for your help.

Related

JetPack Compose onClick function

Please try to tolerate my inexperience.
I'm practicing Jetpack Compose navigation. I making an app that displays a set of card in a LazyHorizontalGrid format, and when clicked it navigates to a screen (destination) containing details of the card, depending on which card is clicked.
Here's what I mean:
I want to navigate to a screen (destination) that describe a particular "Favorite Collections" when clicked, depending on which is clicked.
I was following a tutorial on youtube, but I got lost when he was using Companion Object on a new activity (i.e having multiple activity in a single project and navigating by intent), since that's not recommended I'm not doing that, so I don't know where to put my Companion Object.
RecyclerView in Jetpack Compose - Jetpack Compose For Beginners #7
As I get errors when I try to put the Companion Object in the file of the Screen I'm trying to navigate to, error; Modifier 'companion' is not applicable inside 'file', or In a Composable in the file, then I get this error; Unresolved reference: companion.
This is the screen I'm trying to navigate to (let's call it; DetailScreen);
#Composable
fun DisplayHomeInfo(){
WelcomeText()
HomeInfoDetails(homeInfo = )
}
#Composable
fun WelcomeText() {
Text(
text = "Welcome, to Home Information",
style = MaterialTheme.typography.h3,
modifier = Modifier.padding(horizontal = 12.dp, vertical = 18.dp)
)
}
#Composable
fun HomeInfoDetails(homeInfo: HomeInfo) {
Card(
modifier = Modifier
.padding(10.dp)
.clip(CircleShape),
elevation = 10.dp,
) {
....
This is the screen I'm trying to navigate from;
#Composable
fun HomeScreen(onHomeCardClick: () -> Unit) {
HomeContentScreen(onHomeCardClick = onHomeCardClick)
}
....
Data class I want to load on the detail screen;
data class HomeInfo(
val id: Int,
val title: String,
val sex: String,
val age: Int,
val description: String,
val homeInfoImageId: Int = 0
)
And this is the Object I want to match with the data;
object HomeInfoModel {
val homeInfoModelList = listOf(
HomeInfo(
id = 1,
title = "Monty",
sex = "Male",
age = 14,
description = "Monty enjoys chicken treats and cuddling while watching Seinfeld.",
homeInfoImageId = R.drawable.ab1_inversions
),
...
)
}
To summarize everything, MY QUESTION is how do I pass the data to the detailScreen, and show each card details, depending on the card clicked.
Please I understand my explanation is not very clear, and I'll be more than happy to clarify anything.
No information is too small, I will appreciate any help. Thanks a lot in advance.

How to retrigger focusRequester.requestFocus() when coming back to a composable?

I have a MyBasicTextField in a composable to request user input:
#Composable
fun MyBasicTextField() {
val keyboardController = LocalSoftwareKeyboardController.current
val focusRequester = remember{ FocusRequester() }
BasicTextField(
modifier = Modifier
.focusRequester(focusRequester),
keyboardActions = keyboardActions ?: KeyboardActions(onAny = { keyboardController?.hide() }),
)
LaunchedEffect(Unit) {
focusRequester.requestFocus()
}
}
The keyboard automatically slides in when showing this composable, always.
But wherever MyBasicTextField is used:
I tap on a LinkifiedText to leave and open a browser to show link
I tap BACK
and come back to previous MyBasicTextField screen, the keyboard is not shown
also the focusRequester.requestFocus() is not triggered again when coming back
How can I solve my issue?
Create a top-level variable in your activity, then modify it from within the onStart overridden method. Use that variable as the key for LaunchedEffect in place of Unit. That variable basically keeps track of when the user enters the app.
var userIn by mutableStateOf (true)
In your Composable,
Launched effect(userIn){
if(userIn && isKeyboardShown){
...
}
}
Boring,
You can use my answer here as well, but instead of incrmenting the launchKey every time it's called, only increment the launchKey once user clicks on the browser link, that way it will not pop up during other re-compositions.

How to trigger PC Keyboard inputs in Kotlin Desktop Compose

I am going to develop a POS system using Kotlin Jetpack Compose and I wanna know how to trigger keyboard input events inside my project.
In Compose Desktop You can listen for key events using onKeyEvent Window parameter:
Window(
onCloseRequest = ::exitApplication,
visible = visible,
onKeyEvent = {
if (it.isCtrlPressed && it.key == Key.A) {
println("Ctrl + A is pressed")
true
} else {
// let other handlers receive this event
false
}
}
) {
App()
}
An other options, which will also work for Compose in Android, is using Modifier.onKeyEvent. As documentation says:
will allow it to intercept hardware key events when it (or one of its children) is focused.
So you need to make an item or one of its children focusable and focused. Check out more about focus in compose in this article
To do this you need a FocusRequester, in my example I'm asking focus when view renders using LaunchedEffect.
For the future note, that if user taps on a text field, or an other focusable element will gain focus, your view will loose it. If this focused view is inside your view with onKeyEvent handler, it still gonna work.
An empty box cannot become focused, so you need to add some size with a modifier. It still will be invisible:
val requester = remember { FocusRequester() }
Box(
Modifier
.onKeyEvent {
if (it.isCtrlPressed && it.key == Key.A) {
println("Ctrl + A is pressed")
true
} else {
// let other handlers receive this event
false
}
}
.focusRequester(requester)
.focusable()
.size(10.dp)
)
LaunchedEffect(Unit) {
requester.requestFocus()
}
Alternatively just add content to Box so it will stretch and .size modifier won't be needed anymore
Following the second option of the Philip answer is possible to get a strange behavior when you set the focus and, for some reason, click inside application window. Doing this, is possible "lost" the focus and the key events are not propper handled.
In order to avoid this the suggestion is manually handle this problem by adding a click/tap modifier, which just specifies that when detect a click/tap the requester requests the focus again. See below:
val requester = FocusRequester()
Box(
Modifier
//pointer input handles [onPress] to force focus to the [requester]
.pointerInput(key1 = true) {
detectTapGestures(onPress = {
requester.requestFocus()
})
}
.onKeyEvent {
if (it.isCtrlPressed && it.key == Key.A) {
println("Ctrl + A is pressed")
true
} else {
// let other handlers receive this event
false
}
}
.focusRequester(requester)
.focusable()
.fillMaxSize()
.background(Color.Cyan)
)
LaunchedEffect(Unit) {
requester.requestFocus()
}

How to open (enter) SettingsFragment or any Fragment on Android (Kotlin)

I am learning Android programing, and I can not figure it out how to open settings fragment when button is clicked.
This fragment is not in the navigation map, so it is not possible to connect them in navigation and to use findNavController().navigate(actionFromTo)
As explained on developer guide: https://developer.android.com/guide/topics/ui/settings
I have created fragment:
class PreferencesFragment : PreferenceFragmentCompat() {
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
setPreferencesFromResource(R.xml.preferences, rootKey)
}
}
What I need to write in click listener to enter settings fragment?
Click listener is:
binding.buttonSettings.setOnClickListener {
}
I have tried with to use code in developers guide:
binding.buttonSettings.setOnClickListener {
val fragmentManager: FragmentManager? = activity?.supportFragmentManager
fragmentManager?.beginTransaction()?.replace(R.id.preferencesFragment, PreferencesFragment())?.commit()
}
But program crashes when button is pressed, with error:
No view found for...
The issue seems to be the content ID you want to replace, therefore you need to pass the current content ID you want to replace
see below code, use android.R.id.content instead of R.id.preferencesFragment
binding.buttonSettings.setOnClickListener {
val fragmentManager: FragmentManager? = activity?.supportFragmentManager
fragmentManager?.beginTransaction()?.replace(android.R.id.content, PreferencesFragment())?.commit()
}

How to create a paint application like Messenger's emoji paint on captured photo in Kotlin

So I'm making an app which needs to paint garland, light bulbs and other decoration. I have a code which will make an imageview on Action_Move but the app crashes. see the code below
fun drawLights(){
val listener = View.OnTouchListener(function = { view, motionEvent ->
val x = motionEvent.getX()
val y = motionEvent.getY()
when (motionEvent.action){
MotionEvent.ACTION_DOWN -> {
Toast.makeText(this,"Action Down",Toast.LENGTH_SHORT).show()
}
MotionEvent.ACTION_MOVE -> {
Toast.makeText(this, "Moving", Toast.LENGTH_SHORT).show()
////Imageview Creation Here using late init var
}
MotionEvent.ACTION_UP -> {
Toast.makeText(this,"Done" ,Toast.LENGTH_SHORT).show()
}
}
true
})
edit_Canvas.setOnTouchListener(listener)
}
Does anyone here know any blog related to this or already resolved this problem? Thanks!
You need to look for topics on drawing on the Android Canvas. There are lots of sample codes out there
This one's from the official documentation in drawing on the Canvas https://developer.android.com/training/custom-views/custom-drawing