done context menu, and fix controllers in wsa

This commit is contained in:
2023-12-28 00:12:03 +03:00
parent 66d4c573db
commit 9a26865269
9 changed files with 238 additions and 202 deletions
@@ -5,38 +5,25 @@ import android.app.AlertDialog
import android.content.DialogInterface import android.content.DialogInterface
import android.content.Intent import android.content.Intent
import android.content.pm.ActivityInfo import android.content.pm.ActivityInfo
import android.graphics.BitmapFactory
import android.hardware.SensorManager import android.hardware.SensorManager
import android.hardware.input.InputManager
import android.media.AudioManager import android.media.AudioManager
import android.opengl.GLES20 import android.opengl.GLES20
import android.opengl.GLUtils
import android.os.Build import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.os.PowerManager import android.os.PowerManager
import android.os.PowerManager.WakeLock import android.os.PowerManager.WakeLock
import android.util.DisplayMetrics import android.util.DisplayMetrics
import android.util.Log import android.util.Log
import android.view.InputDevice
import android.view.KeyEvent import android.view.KeyEvent
import android.view.MotionEvent import android.view.MotionEvent
import android.view.inputmethod.InputMethodManager import android.view.inputmethod.InputMethodManager
import androidx.activity.ComponentActivity import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.lifecycle.Lifecycle import androidx.lifecycle.Lifecycle
import com.bda.controller.StateEvent
import com.ea.EAIO.EAIO import com.ea.EAIO.EAIO
import com.ea.EAMIO.StorageDirectory import com.ea.EAMIO.StorageDirectory
import com.ea.easp.EASPHandler import com.ea.easp.EASPHandler
import com.ea.games.nfs13_na.BuildConfig import com.ea.games.nfs13_na.BuildConfig
import com.ea.games.nfs13_na.R
import com.ea.nimble.ApplicationLifecycle import com.ea.nimble.ApplicationLifecycle
import com.megboyzz.actionForAllControllers
import com.megboyzz.androidKeyEventToBda
import com.megboyzz.androidMotionEventToBda
import com.megboyzz.createConnectEvent
import com.megboyzz.createDisconnectEvent
import com.megboyzz.registerControllerHandlers
import java.io.BufferedReader import java.io.BufferedReader
import java.io.File import java.io.File
import java.io.FileReader import java.io.FileReader
@@ -299,23 +286,20 @@ class GameActivity : ComponentActivity(), DrawFrameListener {
ApplicationLifecycle.onActivityResult(requestCode, resultCode, data, this) ApplicationLifecycle.onActivityResult(requestCode, resultCode, data, this)
} }
override fun onBackPressed() {
//ApplicationLifecycle.onBackPressed()
}
public override fun onCreate(bundle: Bundle?) { public override fun onCreate(bundle: Bundle?) {
super.onCreate(bundle) super.onCreate(bundle)
registerControllerHandlers( MogaController.registerControllerHandlers(
context = baseContext,
onInputDeviceAdded = { onInputDeviceAdded = {
Log.i("Controller", "controller is connected!") Log.i("Controller", "controller is connected!")
val event = createConnectEvent(it) val event = MogaController.createConnectEvent(it)
MogaController.nativeOnStateEvent(event) MogaController.nativeOnStateEvent(event)
}, },
onInputDeviceRemoved = { onInputDeviceRemoved = {
Log.i("Controller", "controller is disconnected!") Log.i("Controller", "controller is disconnected!")
val event = createDisconnectEvent(it) val event = MogaController.createDisconnectEvent(it)
MogaController.nativeOnStateEvent(event) MogaController.nativeOnStateEvent(event)
}, },
onInputDeviceChanged = { onInputDeviceChanged = {
@@ -393,7 +377,8 @@ class GameActivity : ComponentActivity(), DrawFrameListener {
override fun dispatchGenericMotionEvent(ev: MotionEvent?): Boolean { override fun dispatchGenericMotionEvent(ev: MotionEvent?): Boolean {
Log.i("GameActivity", ev.toString()) Log.i("GameActivity", ev.toString())
MogaController.onMotionEvent(androidMotionEventToBda(ev!!)) if (MogaController.deviceIsController(ev?.deviceId!!))
MogaController.onMotionEvent(MogaController.androidMotionEventToBda(ev))
return super.dispatchGenericMotionEvent(ev) return super.dispatchGenericMotionEvent(ev)
} }
@@ -401,7 +386,8 @@ class GameActivity : ComponentActivity(), DrawFrameListener {
@SuppressLint("RestrictedApi") @SuppressLint("RestrictedApi")
override fun dispatchKeyEvent(event: KeyEvent?): Boolean { override fun dispatchKeyEvent(event: KeyEvent?): Boolean {
MogaController.onKeyEvent(androidKeyEventToBda(event!!)) if (MogaController.deviceIsController(event?.deviceId!!))
MogaController.onKeyEvent(MogaController.androidKeyEventToBda(event))
return super.dispatchKeyEvent(event) return super.dispatchKeyEvent(event)
} }
@@ -409,8 +395,6 @@ class GameActivity : ComponentActivity(), DrawFrameListener {
override fun onDrawFrame(gl10: GL10) { override fun onDrawFrame(gl10: GL10) {
//InputDevice.getDeviceIds()
//InputDevice.getDevice(0).sources
Log.d(this.localClassName, "onDrawFrame state=$state") Log.d(this.localClassName, "onDrawFrame state=$state")
var isStarted = false var isStarted = false
when (state) { when (state) {
@@ -522,8 +506,8 @@ class GameActivity : ComponentActivity(), DrawFrameListener {
gameGLSurfaceView.onResume() gameGLSurfaceView.onResume()
ApplicationLifecycle.onActivityResume(this) ApplicationLifecycle.onActivityResume(this)
nativeOnResume() nativeOnResume()
actionForAllControllers { MogaController.doForAllControllers {
val event = createConnectEvent(it) val event = MogaController.createConnectEvent(it)
MogaController.nativeOnStateEvent(event) MogaController.nativeOnStateEvent(event)
} }
} }
@@ -1,5 +1,10 @@
package com.ea.ironmonkey package com.ea.ironmonkey
import android.content.Context
import android.hardware.input.InputManager
import android.util.Log
import android.view.InputDevice
import androidx.activity.ComponentActivity
import com.bda.controller.ControllerListener import com.bda.controller.ControllerListener
import com.bda.controller.KeyEvent import com.bda.controller.KeyEvent
import com.bda.controller.MotionEvent import com.bda.controller.MotionEvent
@@ -19,4 +24,94 @@ object MogaController : ControllerListener {
override fun onStateEvent(stateEvent: StateEvent) { override fun onStateEvent(stateEvent: StateEvent) {
nativeOnStateEvent(stateEvent) nativeOnStateEvent(stateEvent)
} }
fun doForAllControllers(
action: (Int) -> Unit
){
val deviceIds = InputDevice.getDeviceIds()
deviceIds.forEach {
if(deviceIsController(it)) action(it)
}
}
infix fun Int.isFlag(flag: Int) = this and flag == flag
fun deviceIsController(deviceId: Int): Boolean {
val inputDevice = InputDevice.getDevice(deviceId) ?: return false
Log.i("Controller", inputDevice.toString())
val b = (inputDevice.sources isFlag InputDevice.SOURCE_GAMEPAD) &&
(inputDevice.sources isFlag InputDevice.SOURCE_JOYSTICK)
Log.i("Controller", b.toString())
if(inputDevice.id == -1) return false
return b
}
fun registerControllerHandlers(
context: Context,
onInputDeviceAdded: (Int) -> Unit,
onInputDeviceRemoved: (Int) -> Unit,
onInputDeviceChanged: (Int) -> Unit = {},
){
val inputManager = context.getSystemService(ComponentActivity.INPUT_SERVICE) as InputManager
inputManager.registerInputDeviceListener(object : InputManager.InputDeviceListener {
var lastControllerId: Int = 0;
override fun onInputDeviceAdded(deviceId: Int) {
if(deviceIsController(deviceId)) {
lastControllerId = deviceId
onInputDeviceAdded(deviceId)
}
}
override fun onInputDeviceRemoved(deviceId: Int) {
if(deviceIsController(deviceId) || lastControllerId == deviceId) onInputDeviceRemoved(deviceId)
}
override fun onInputDeviceChanged(deviceId: Int) {
if(deviceIsController(deviceId)) onInputDeviceChanged(deviceId)
}
}, null)
}
fun createDisconnectEvent(deviceId: Int) = StateEvent(
System.currentTimeMillis(),
deviceId,
StateEvent.STATE_UNKNOWN,
StateEvent.ACTION_DISCONNECTED
)
fun createConnectEvent(deviceId: Int) = StateEvent(
System.currentTimeMillis(),
deviceId,
StateEvent.STATE_CONNECTION,
StateEvent.ACTION_CONNECTED
)
fun androidKeyEventToBda(keyEvent: android.view.KeyEvent) = KeyEvent(
keyEvent.eventTime,
keyEvent.deviceId,
keyEvent.keyCode,
keyEvent.action
)
fun androidMotionEventToBda(motionEvent: android.view.MotionEvent) = MotionEvent(
motionEvent.eventTime,
motionEvent.deviceId,
motionEvent.x,
motionEvent.y,
motionEvent.rawX,
motionEvent.rawY,
motionEvent.xPrecision,
motionEvent.yPrecision
)
} }
-91
View File
@@ -1,91 +0,0 @@
package com.megboyzz
import android.content.Context
import android.hardware.input.InputManager
import android.view.InputDevice
import androidx.activity.ComponentActivity
import com.bda.controller.KeyEvent
import com.bda.controller.MotionEvent
import android.view.KeyEvent as androidKeyEvent
import android.view.MotionEvent as androidMotionEvent
import com.bda.controller.StateEvent
fun actionForAllControllers(
action: (Int) -> Unit
){
val deviceIds = InputDevice.getDeviceIds()
deviceIds.forEach {
if(deviceIsController(it)) action(it)
}
}
fun deviceIsController(deviceId: Int): Boolean {
val inputDevice = InputDevice.getDevice(deviceId) ?: return false
return (inputDevice.sources and InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD ||
(inputDevice.sources and InputDevice.SOURCE_JOYSTICK) == InputDevice.SOURCE_JOYSTICK
}
fun Context.registerControllerHandlers(
onInputDeviceAdded: (Int) -> Unit,
onInputDeviceRemoved: (Int) -> Unit,
onInputDeviceChanged: (Int) -> Unit = {},
){
val inputManager = getSystemService(ComponentActivity.INPUT_SERVICE) as InputManager
inputManager.registerInputDeviceListener(object : InputManager.InputDeviceListener {
var lastControllerId: Int = 0;
override fun onInputDeviceAdded(deviceId: Int) {
if(deviceIsController(deviceId)) {
lastControllerId = deviceId
onInputDeviceAdded(deviceId)
}
}
override fun onInputDeviceRemoved(deviceId: Int) {
if(deviceIsController(deviceId) || lastControllerId == deviceId) onInputDeviceRemoved(deviceId)
}
override fun onInputDeviceChanged(deviceId: Int) {
if(deviceIsController(deviceId)) onInputDeviceChanged(deviceId)
}
}, null)
}
fun createDisconnectEvent(deviceId: Int) = StateEvent(
System.currentTimeMillis(),
deviceId,
StateEvent.STATE_UNKNOWN,
StateEvent.ACTION_DISCONNECTED
)
fun createConnectEvent(deviceId: Int) = StateEvent(
System.currentTimeMillis(),
deviceId,
StateEvent.STATE_CONNECTION,
StateEvent.ACTION_CONNECTED
)
fun androidKeyEventToBda(keyEvent: androidKeyEvent) = KeyEvent(
keyEvent.eventTime,
keyEvent.deviceId,
keyEvent.keyCode,
keyEvent.action
)
fun androidMotionEventToBda(motionEvent: androidMotionEvent) = MotionEvent(
motionEvent.eventTime,
motionEvent.deviceId,
motionEvent.x,
motionEvent.y,
motionEvent.rawX,
motionEvent.rawY,
motionEvent.xPrecision,
motionEvent.yPrecision
)
+5
View File
@@ -71,6 +71,11 @@ dependencies {
debugImplementation(libs.ui.tooling) debugImplementation(libs.ui.tooling)
debugImplementation(libs.ui.test.manifest) debugImplementation(libs.ui.test.manifest)
implementation(libs.voyager.navigator)
implementation(libs.voyager.bottomSheetNavigator)
implementation(libs.voyager.transitions)
implementation(libs.voyager.screenModel)
implementation(libs.dagger) implementation(libs.dagger)
kapt(libs.dagger.compiler) kapt(libs.dagger.compiler)
implementation(libs.room) implementation(libs.room)
@@ -4,6 +4,7 @@ import android.content.Intent
import android.os.Bundle import android.os.Bundle
import androidx.activity.ComponentActivity import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent import androidx.activity.compose.setContent
import cafe.adriel.voyager.navigator.bottomSheet.BottomSheetNavigator
import com.megboyzz.devmenu.ui.components.MainScaffold import com.megboyzz.devmenu.ui.components.MainScaffold
class MainActivity : ComponentActivity() { class MainActivity : ComponentActivity() {
@@ -30,6 +31,11 @@ class MainActivity : ComponentActivity() {
} }
setContent { setContent {
BottomSheetNavigator {
}
MainScaffold( MainScaffold(
onSettingsClick = { /*TODO*/ }, onSettingsClick = { /*TODO*/ },
onSearchValueChanged = {}, onSearchValueChanged = {},
@@ -0,0 +1,18 @@
package com.megboyzz.devmenu.ui.components
import androidx.compose.animation.core.tween
import androidx.compose.animation.expandIn
import androidx.compose.animation.shrinkOut
import androidx.compose.ui.Alignment
val enter = expandIn(
expandFrom = Alignment.CenterStart,
animationSpec = tween(250)
)
val exit = shrinkOut(
shrinkTowards = Alignment.CenterStart,
animationSpec = tween(250)
)
@@ -1,26 +1,20 @@
package com.megboyzz.devmenu.ui.components package com.megboyzz.devmenu.ui.components
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.foundation.Image import androidx.compose.foundation.Image
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.BoxScope
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.ColumnScope
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.RowScope
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.wrapContentHeight import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.KeyboardArrowRight
import androidx.compose.material.icons.outlined.Star
import androidx.compose.material3.Button import androidx.compose.material3.Button
import androidx.compose.material3.Divider import androidx.compose.material3.Divider
import androidx.compose.material3.Icon
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Surface
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
@@ -33,7 +27,6 @@ import androidx.compose.ui.draw.clip
import androidx.compose.ui.draw.shadow import androidx.compose.ui.draw.shadow
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.painter.Painter import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.graphics.vector.rememberVectorPainter
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import com.megboyzz.devmenu.R import com.megboyzz.devmenu.R
@@ -68,7 +61,7 @@ fun CoreMenuPosition(
) { ) {
Row( Row(
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(16.dp), horizontalArrangement = Arrangement.spacedBy(20.dp),
) { ) {
Image( Image(
painter = icon, painter = icon,
@@ -87,11 +80,11 @@ fun FsElementInContextMenu(
Row( Row(
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(12.dp) horizontalArrangement = Arrangement.spacedBy(20.dp)
) { ) {
val modifier = Modifier val modifier = Modifier
.size(32.dp) .size(36.dp)
.clip(RoundedCornerShape(10.dp)) .clip(RoundedCornerShape(10.dp))
.shadow(elevation = 6.dp) .shadow(elevation = 6.dp)
@@ -108,33 +101,52 @@ fun FileContextMenu(
name: String, name: String,
type: ElementType, type: ElementType,
onRemoveElement: () -> Unit, onRemoveElement: () -> Unit,
onUpdateType: (ElementType) -> Unit onUpdateType: (ElementType) -> ElementType?
) { ) {
var innerType by remember { mutableStateOf(type) } var innerType by remember { mutableStateOf(type) }
var isMain by remember { mutableStateOf(true) } var isMain by remember { mutableStateOf(true) }
CoreFileContextMenu { CoreFileContextMenu {
Column(verticalArrangement = Arrangement.spacedBy(20.dp)) {
FsElementInContextMenu(name = name, type = type) FsElementInContextMenu(name = name, type = type)
Divider() Divider()
if (isMain) { AnimatedBoxForContextMenuContent(isVisible = isMain){
AnimatedBoxForContextMenuContent(isVisible = innerType == ElementType.isFile) {
ClickableMenuPosition( ClickableMenuPosition(
name = "Заменить", name = "Заменить",
icon = R.drawable.star.asPainter(), icon = R.drawable.star.asPainter(),
onClick = { onClick = {
innerType = ElementType.isReplaced innerType = onUpdateType(ElementType.isReplaced) ?: ElementType.isReplaced
onUpdateType(innerType)
} }
) )
ClickableMenuPosition( ClickableMenuPosition(
name = "Скрыть для игры", name = "Скрыть для игры",
icon = R.drawable.hide.asPainter(), icon = R.drawable.hide.asPainter(),
onClick = { onClick = {
innerType = ElementType.isHidden innerType = onUpdateType(ElementType.isHidden) ?: ElementType.isHidden
} }
) )
}
AnimatedBoxForContextMenuContent(isVisible = innerType == ElementType.isHidden) {
ClickableMenuPosition(
name = "Показать игре",
icon = R.drawable.unhide.asPainter(),
onClick = {
innerType = onUpdateType(ElementType.isFile) ?: ElementType.isFile
}
)
}
AnimatedBoxForContextMenuContent(isVisible = innerType == ElementType.isReplaced) {
ClickableMenuPosition(
name = "Воостановить",
icon = R.drawable.star.asPainter(),
onClick = {
innerType = onUpdateType(ElementType.isFile) ?: ElementType.isFile
}
)
}
ClickableMenuPosition( ClickableMenuPosition(
name = "Свойства", name = "Свойства",
icon = R.drawable.info.asPainter(), icon = R.drawable.info.asPainter(),
@@ -145,7 +157,9 @@ fun FileContextMenu(
icon = R.drawable.trash.asPainter(), icon = R.drawable.trash.asPainter(),
onClick = { isMain = !isMain } onClick = { isMain = !isMain }
) )
}else{ }
AnimatedBoxForContextMenuContent(isVisible = !isMain) {
ClickableMenuPosition( ClickableMenuPosition(
name = "Удалить", name = "Удалить",
icon = R.drawable.trash.asPainter(), icon = R.drawable.trash.asPainter(),
@@ -158,6 +172,22 @@ fun FileContextMenu(
} }
} }
} }
@Composable
fun AnimatedBoxForContextMenuContent(
isVisible: Boolean,
content: @Composable ColumnScope.() -> Unit
) {
AnimatedVisibility(
visible = isVisible,
enter = enter,
exit = exit
) {
Column(
verticalArrangement = Arrangement.spacedBy(12.dp),
content = content
)
}
} }
@Composable @Composable
@@ -174,31 +204,6 @@ fun RemoveFileButtonsGroup(
} }
} }
@Preview
@Composable
fun TwoButtonsRow() {
Surface(
modifier = Modifier.fillMaxWidth()
) {
Row(
modifier = Modifier.fillMaxWidth(),
) {
Button(
onClick = { /* Действие для первой кнопки */ },
modifier = Modifier.weight(1f) // Каждая кнопка занимает равное количество места (50%)
) {
// Ваш текст и стиль для первой кнопки
}
Button(
onClick = { /* Действие для второй кнопки */ },
modifier = Modifier.weight(1f) // Каждая кнопка занимает равное количество места (50%)
) {
// Ваш текст и стиль для второй кнопки
}
}
}
}
@Composable @Composable
fun RemoveButton( fun RemoveButton(
@@ -206,7 +211,6 @@ fun RemoveButton(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
onClick: () -> Unit onClick: () -> Unit
) { ) {
Row() {
Button( Button(
onClick = onClick, onClick = onClick,
shape = RoundedCornerShape(10.dp), shape = RoundedCornerShape(10.dp),
@@ -215,29 +219,38 @@ fun RemoveButton(
Text(text = text) Text(text = text)
} }
} }
}
@Composable @Composable
fun CoreFileContextMenu( fun CoreFileContextMenu(
content: @Composable BoxScope.() -> Unit content: @Composable () -> Unit
) { ) {
val shape = RoundedCornerShape(topStart = 10.dp, topEnd = 10.dp)
Box( Box(
modifier = Modifier modifier = Modifier
.wrapContentHeight() .wrapContentHeight()
.fillMaxWidth() .fillMaxWidth()
//TODO отвязать от цвета //TODO отвязать от цвета
.background(Color.White) .clip(shape)
.clip(RoundedCornerShape(10.dp)), .background(Color.White),
contentAlignment = Alignment.TopCenter contentAlignment = Alignment.TopCenter
) { ) {
Image(
painter = R.drawable.clip.asPainter(),
contentDescription = null,
modifier = Modifier.padding(top = 8.dp)
)
Box( Box(
modifier = Modifier.padding( modifier = Modifier.padding(
horizontal = 32.dp, horizontal = 28.dp,
vertical = 24.dp vertical = 32.dp
), ),
content = content ){
) Column(verticalArrangement = Arrangement.spacedBy(20.dp)) {
content()
}
}
} }
} }
@@ -250,7 +263,7 @@ fun ClicablePreview() {
name = "my_file.txt", name = "my_file.txt",
type = ElementType.isFile, type = ElementType.isFile,
onRemoveElement = {}, onRemoveElement = {},
onUpdateType = {} onUpdateType = {null}
) )
} }
+6
View File
@@ -15,6 +15,7 @@ org-jetbrains-kotlin-jvm = "1.9.0"
ksp = "1.9.21-1.0.15" ksp = "1.9.21-1.0.15"
dagger = "2.46.1" dagger = "2.46.1"
room = "2.6.1" room = "2.6.1"
voyager = "1.0.0"
[libraries] [libraries]
core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "core-ktx" } core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "core-ktx" }
@@ -40,6 +41,11 @@ room = { module = "androidx.room:room-runtime", version.ref = "room" }
room-compiler = { module = "androidx.room:room-compiler", version.ref = "room" } room-compiler = { module = "androidx.room:room-compiler", version.ref = "room" }
room-ktx = { module = "androidx.room:room-ktx", version.ref = "room" } room-ktx = { module = "androidx.room:room-ktx", version.ref = "room" }
voyager-navigator = { module = "cafe.adriel.voyager:voyager-navigator", version.ref = "voyager" }
voyager-screenModel = { module = "cafe.adriel.voyager:voyager-screenmodel", version.ref = "voyager" }
voyager-bottomSheetNavigator = { module = "cafe.adriel.voyager:voyager-bottom-sheet-navigator", version.ref = "voyager" }
voyager-transitions = { module = "cafe.adriel.voyager:voyager-transitions", version.ref = "voyager" }
[plugins] [plugins]
androidApplication = { id = "com.android.application", version.ref = "agp" } androidApplication = { id = "com.android.application", version.ref = "agp" }
kotlinAndroid = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } kotlinAndroid = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }