diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index 5ab6347..f59bde2 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -96,6 +96,7 @@ dependencies {
implementation(libs.ui.graphics)
implementation(libs.ui.tooling.preview)
implementation(libs.material3)
+ implementation(project(mapOf("path" to ":mpcore")))
testImplementation(libs.junit.v412)
//testImplementation(libs.junit)
androidTestImplementation(libs.androidx.test.ext.junit)
diff --git a/app/src/main/java/com/ea/ironmonkey/GameActivity.kt b/app/src/main/java/com/ea/ironmonkey/GameActivity.kt
index 0098c8f..940dab5 100644
--- a/app/src/main/java/com/ea/ironmonkey/GameActivity.kt
+++ b/app/src/main/java/com/ea/ironmonkey/GameActivity.kt
@@ -24,6 +24,7 @@ import com.ea.EAMIO.StorageDirectory
import com.ea.easp.EASPHandler
import com.ea.games.nfs13_na.BuildConfig
import com.ea.nimble.ApplicationLifecycle
+import ru.megboyzz.mpcore.NativeLib
import java.io.BufferedReader
import java.io.File
import java.io.FileReader
@@ -42,6 +43,7 @@ class GameActivity : ComponentActivity(), DrawFrameListener {
init {
System.loadLibrary("nimble")
System.loadLibrary("app")
+ System.loadLibrary("mpcore")
}
private var splashDelay: Long = 0
diff --git a/app/src/main/jniLibs/armeabi-v7a/libapp.so b/app/src/main/jniLibs/armeabi-v7a/libapp.so
index d674c64..a9fe392 100644
Binary files a/app/src/main/jniLibs/armeabi-v7a/libapp.so and b/app/src/main/jniLibs/armeabi-v7a/libapp.so differ
diff --git a/devmenu/domain/src/main/java/com/megboyzz/devmenu/domain/entities/GameLang.kt b/devmenu/domain/src/main/java/com/megboyzz/devmenu/domain/entities/GameLang.kt
index be09998..1c5aa26 100644
--- a/devmenu/domain/src/main/java/com/megboyzz/devmenu/domain/entities/GameLang.kt
+++ b/devmenu/domain/src/main/java/com/megboyzz/devmenu/domain/entities/GameLang.kt
@@ -1,6 +1,6 @@
package com.megboyzz.devmenu.domain.entities
-enum class GameLang(private val lang: String) {
+enum class GameLang(val lang: String) {
System("sys"),
Chinese("cn"),
Dutch("nl"),
diff --git a/devmenu/domain/src/main/java/com/megboyzz/devmenu/domain/usecases/settings/GetGameLangUseCase.kt b/devmenu/domain/src/main/java/com/megboyzz/devmenu/domain/usecases/settings/GetGameLangUseCase.kt
new file mode 100644
index 0000000..99e4964
--- /dev/null
+++ b/devmenu/domain/src/main/java/com/megboyzz/devmenu/domain/usecases/settings/GetGameLangUseCase.kt
@@ -0,0 +1,14 @@
+package com.megboyzz.devmenu.domain.usecases.settings
+
+import com.megboyzz.devmenu.domain.entities.GameLang
+import com.megboyzz.devmenu.domain.repository.SettingsRepository
+import javax.inject.Inject
+
+class GetGameLangUseCase @Inject constructor(
+ private val settingsRepository: SettingsRepository
+) {
+
+ operator fun invoke() = settingsRepository.gameLang
+
+}
+
diff --git a/devmenu/domain/src/main/java/com/megboyzz/devmenu/domain/usecases/settings/GetTrackingStateUseCase.kt b/devmenu/domain/src/main/java/com/megboyzz/devmenu/domain/usecases/settings/GetTrackingStateUseCase.kt
new file mode 100644
index 0000000..b987811
--- /dev/null
+++ b/devmenu/domain/src/main/java/com/megboyzz/devmenu/domain/usecases/settings/GetTrackingStateUseCase.kt
@@ -0,0 +1,13 @@
+package com.megboyzz.devmenu.domain.usecases.settings
+
+import com.megboyzz.devmenu.domain.entities.TrackingData
+import com.megboyzz.devmenu.domain.repository.TrackingRepository
+import javax.inject.Inject
+
+class GetTrackingStateUseCase @Inject constructor(
+ private val trackingRepository: TrackingRepository
+) {
+
+ operator fun invoke() = trackingRepository.trackingData
+
+}
\ No newline at end of file
diff --git a/devmenu/src/main/java/com/megboyzz/devmenu/MainActivity.kt b/devmenu/src/main/java/com/megboyzz/devmenu/MainActivity.kt
index f862884..c613ed1 100644
--- a/devmenu/src/main/java/com/megboyzz/devmenu/MainActivity.kt
+++ b/devmenu/src/main/java/com/megboyzz/devmenu/MainActivity.kt
@@ -8,6 +8,7 @@ import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.ui.unit.dp
import cafe.adriel.voyager.navigator.Navigator
import cafe.adriel.voyager.navigator.bottomSheet.BottomSheetNavigator
+import cafe.adriel.voyager.transitions.SlideTransition
import com.megboyzz.devmenu.ui.components.MainScaffold
import com.megboyzz.devmenu.ui.screens.HomeScreen
@@ -39,7 +40,9 @@ class MainActivity : ComponentActivity() {
BottomSheetNavigator(
sheetShape = RoundedCornerShape(topStart = 10.dp, topEnd = 10.dp)
) {
- Navigator(HomeScreen(::runGame))
+ Navigator(HomeScreen(::runGame)) {
+ SlideTransition(it)
+ }
}
}
}
diff --git a/devmenu/src/main/java/com/megboyzz/devmenu/di/components/SettingsUseCaseComponent.kt b/devmenu/src/main/java/com/megboyzz/devmenu/di/components/SettingsUseCaseComponent.kt
index fb090ed..6a025d1 100644
--- a/devmenu/src/main/java/com/megboyzz/devmenu/di/components/SettingsUseCaseComponent.kt
+++ b/devmenu/src/main/java/com/megboyzz/devmenu/di/components/SettingsUseCaseComponent.kt
@@ -3,6 +3,8 @@ package com.megboyzz.devmenu.di.components
import android.content.Context
import com.megboyzz.devmenu.di.modules.DatabaseModule
import com.megboyzz.devmenu.di.modules.RepositoryModule
+import com.megboyzz.devmenu.domain.usecases.settings.GetGameLangUseCase
+import com.megboyzz.devmenu.domain.usecases.settings.GetTrackingStateUseCase
import com.megboyzz.devmenu.domain.usecases.settings.RemoveGameDataUseCase
import com.megboyzz.devmenu.domain.usecases.settings.SetGameLangUseCase
import com.megboyzz.devmenu.domain.usecases.settings.SetTrackingSaveFileUseCase
@@ -24,8 +26,12 @@ interface SettingsUseCaseComponent {
val setGameLangUseCase: SetGameLangUseCase
+ val getGameLangUseCase: GetGameLangUseCase
+
val setTrackingSaveFileUseCase: SetTrackingSaveFileUseCase
+ val getTrackingStateUseCase: GetTrackingStateUseCase
+
val turnOffDevMenuUseCase: TurnOffDevMenuUseCase
@Component.Builder
diff --git a/devmenu/src/main/java/com/megboyzz/devmenu/repositories/SettingsRepositoryImpl.kt b/devmenu/src/main/java/com/megboyzz/devmenu/repositories/SettingsRepositoryImpl.kt
index b9ef077..6406554 100644
--- a/devmenu/src/main/java/com/megboyzz/devmenu/repositories/SettingsRepositoryImpl.kt
+++ b/devmenu/src/main/java/com/megboyzz/devmenu/repositories/SettingsRepositoryImpl.kt
@@ -29,7 +29,7 @@ class SettingsRepositoryImpl @Inject constructor(
if(!localeFile.exists()){
localeFile.createNewFile()
- localeFile.writeBytes(byteArrayOf(0x02, 0x0) + systemLang.name.toByteArray())
+ localeFile.writeBytes(byteArrayOf(0x02, 0x0) + systemLang.lang.toByteArray())
return systemLang
}
@@ -40,7 +40,7 @@ class SettingsRepositoryImpl @Inject constructor(
if(!localeFile.exists()) localeFile.createNewFile()
- localeFile.writeBytes(byteArrayOf(0x02, 0x0) + value.name.toByteArray())
+ localeFile.writeBytes(byteArrayOf(0x02, 0x0) + value.lang.toByteArray())
}
diff --git a/devmenu/src/main/java/com/megboyzz/devmenu/repositories/TrackingRepositoryImpl.kt b/devmenu/src/main/java/com/megboyzz/devmenu/repositories/TrackingRepositoryImpl.kt
index 7359006..374a1e2 100644
--- a/devmenu/src/main/java/com/megboyzz/devmenu/repositories/TrackingRepositoryImpl.kt
+++ b/devmenu/src/main/java/com/megboyzz/devmenu/repositories/TrackingRepositoryImpl.kt
@@ -29,7 +29,7 @@ class TrackingRepositoryImpl @Inject constructor(
override var trackingData: TrackingData
get() {
val enabled = sharedPreferences.getBoolean(trackingStateKey, false)
- val path = sharedPreferences.getString(trackingStateKey, defaultPathToSave)?: defaultPathToSave
+ val path = sharedPreferences.getString(trackingSavePath, defaultPathToSave)?: defaultPathToSave
return TrackingData(
enabled = enabled,
diff --git a/devmenu/src/main/java/com/megboyzz/devmenu/ui/Utlil.kt b/devmenu/src/main/java/com/megboyzz/devmenu/ui/Utlil.kt
index 34d25d6..3ba6d3c 100644
--- a/devmenu/src/main/java/com/megboyzz/devmenu/ui/Utlil.kt
+++ b/devmenu/src/main/java/com/megboyzz/devmenu/ui/Utlil.kt
@@ -1,14 +1,19 @@
package com.megboyzz.devmenu.ui
import android.annotation.SuppressLint
+import android.content.Context
+import androidx.activity.ComponentActivity
+import androidx.activity.OnBackPressedCallback
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.width
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.DisposableEffect
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.Dp
+import com.megboyzz.devmenu.MainActivity
import java.text.CharacterIterator
import java.text.SimpleDateFormat
import java.text.StringCharacterIterator
@@ -46,7 +51,39 @@ fun humanReadableByteCountSI(bytes: Long): String {
fun formatDate(date: Date) = SimpleDateFormat("dd.MM.yyyy HH:mm:ss").format(date)
+fun Context.getInternalAppDataDirectory() = "/data/data/${packageName}"
+
+fun Context.getExternalAppDataDirectory(): String {
+ val externalDir = getExternalFilesDir(null)
+ return externalDir?.absolutePath ?: ""
+}
+
+@Composable
+fun Context.registerOnBackPressedAction(
+ action: () -> Unit
+) {
+ val context = this
+ DisposableEffect(this) {
+ val callback = object : OnBackPressedCallback(true) {
+ override fun handleOnBackPressed() {
+
+ action()
+ }
+
+ }
+ (context as ComponentActivity).onBackPressedDispatcher.addCallback(callback)
+
+ // Отменяем обратный вызов при уничтожении DisposableEffect
+ onDispose {
+ callback.remove()
+ }
+ }
+
+}
+
/**
+ * ## Неработает((
+ *
* Возвращает лямбду того типа которая требуется в Composable контексте
* например есть функция
*
@@ -62,5 +99,4 @@ fun formatDate(date: Date) = SimpleDateFormat("dd.MM.yyyy HH:mm:ss").format(date
*
* example(a = SomeType().asComposableLambda)
*/
-val T.asComposableLambda: @Composable () -> T
- get() = { this }
\ No newline at end of file
+val T.asComposableLambda: @Composable () -> T get() = { this }
\ No newline at end of file
diff --git a/devmenu/src/main/java/com/megboyzz/devmenu/ui/components/Files.kt b/devmenu/src/main/java/com/megboyzz/devmenu/ui/components/Files.kt
index 051a869..f5a1019 100644
--- a/devmenu/src/main/java/com/megboyzz/devmenu/ui/components/Files.kt
+++ b/devmenu/src/main/java/com/megboyzz/devmenu/ui/components/Files.kt
@@ -6,6 +6,7 @@ import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
+import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import com.megboyzz.devmenu.ui.models.FsElementModel
@@ -13,7 +14,7 @@ import com.megboyzz.devmenu.ui.models.FsElementModel
fun FsElement(
fsElementEntity: FsElementModel,
onClick: () -> Unit,
- onLongPressClick: () -> Unit
+ onLongPressClick: () -> Unit = {}
) {
Column(
@@ -25,6 +26,9 @@ fun FsElement(
)
) {
FsElementIcon(type = fsElementEntity.type)
- Text(text = fsElementEntity.name)
+ Text(
+ text = fsElementEntity.name,
+ textAlign = TextAlign.Center
+ )
}
}
\ No newline at end of file
diff --git a/devmenu/src/main/java/com/megboyzz/devmenu/ui/components/FolderStatusBar.kt b/devmenu/src/main/java/com/megboyzz/devmenu/ui/components/FolderStatusBar.kt
index 0fd4519..f065914 100644
--- a/devmenu/src/main/java/com/megboyzz/devmenu/ui/components/FolderStatusBar.kt
+++ b/devmenu/src/main/java/com/megboyzz/devmenu/ui/components/FolderStatusBar.kt
@@ -1,7 +1,6 @@
package com.megboyzz.devmenu.ui.components
import androidx.compose.foundation.Image
-import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.lazy.LazyRow
@@ -39,10 +38,20 @@ fun CoreBar(folders: List) {
@Composable
fun StatusBarInCurFolder(
- path: String
+ path: String,
+ internalPath: String = "",
+ externalPath: String = ""
) {
if(path.isEmpty()) return
- val pathAsArray = path.split("/").filter { it.isNotEmpty() }
+ var pathProcess = path
+
+ if(internalPath.isNotEmpty() && pathProcess.contains(internalPath))
+ pathProcess = path.replace(internalPath, "Внутренее хранилище")
+
+ if(externalPath.isNotEmpty() && pathProcess.contains(externalPath))
+ pathProcess = path.replace(externalPath, "Внешнее хранилище")
+
+ val pathAsArray = pathProcess.split("/").filter { it.isNotEmpty() }
CoreBar(folders = pathAsArray)
}
diff --git a/devmenu/src/main/java/com/megboyzz/devmenu/ui/components/HomeScaffold.kt b/devmenu/src/main/java/com/megboyzz/devmenu/ui/components/HomeScaffold.kt
index 3b628d3..1a6729f 100644
--- a/devmenu/src/main/java/com/megboyzz/devmenu/ui/components/HomeScaffold.kt
+++ b/devmenu/src/main/java/com/megboyzz/devmenu/ui/components/HomeScaffold.kt
@@ -4,6 +4,8 @@ import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.ColumnScope
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
@@ -33,6 +35,7 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
+import com.megboyzz.devmenu.ui.SpacerHeight
import com.megboyzz.devmenu.ui.theme.DevMenuTheme
@OptIn(ExperimentalMaterial3Api::class)
@@ -42,7 +45,7 @@ fun MainScaffold(
searchValue: String,
onSearchValueChanged: (String) -> Unit,
onFloatingButtonClick: () -> Unit,
- content: @Composable (PaddingValues) -> Unit
+ content: @Composable ColumnScope.() -> Unit
) {
var searchValue by remember { mutableStateOf(searchValue) }
@@ -66,11 +69,13 @@ fun MainScaffold(
shape = CircleShape,
content = {Icon(imageVector = Icons.Default.PlayArrow, contentDescription = null)}
)
- },
-
- content = content
-
- )
+ }
+ ){
+ Column {
+ SpacerHeight(height = it.calculateTopPadding())
+ content()
+ }
+ }
}
diff --git a/devmenu/src/main/java/com/megboyzz/devmenu/ui/models/GameLangModel.kt b/devmenu/src/main/java/com/megboyzz/devmenu/ui/models/GameLangModel.kt
index f270738..e07a8be 100644
--- a/devmenu/src/main/java/com/megboyzz/devmenu/ui/models/GameLangModel.kt
+++ b/devmenu/src/main/java/com/megboyzz/devmenu/ui/models/GameLangModel.kt
@@ -1,5 +1,7 @@
package com.megboyzz.devmenu.ui.models
+import com.megboyzz.devmenu.domain.entities.GameLang
+
enum class GameLangModel(private val lang: String) {
System("sys"),
Chinese("cn"),
@@ -16,4 +18,8 @@ enum class GameLangModel(private val lang: String) {
override fun toString() = lang
-}
\ No newline at end of file
+ fun toDomain() = GameLang.values()[ordinal]
+
+}
+
+fun GameLang.toModel() = GameLangModel.values()[ordinal]
\ No newline at end of file
diff --git a/devmenu/src/main/java/com/megboyzz/devmenu/ui/screenmodels/HomeScreenModel.kt b/devmenu/src/main/java/com/megboyzz/devmenu/ui/screenmodels/HomeScreenModel.kt
new file mode 100644
index 0000000..33954c1
--- /dev/null
+++ b/devmenu/src/main/java/com/megboyzz/devmenu/ui/screenmodels/HomeScreenModel.kt
@@ -0,0 +1,125 @@
+package com.megboyzz.devmenu.ui.screenmodels
+
+import android.content.Context
+import android.util.Log
+import cafe.adriel.voyager.core.model.ScreenModel
+import cafe.adriel.voyager.core.model.screenModelScope
+import com.megboyzz.devmenu.ui.components.ElementType
+import com.megboyzz.devmenu.ui.getExternalAppDataDirectory
+import com.megboyzz.devmenu.ui.getInternalAppDataDirectory
+import com.megboyzz.devmenu.ui.models.FsElementModel
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.launch
+import java.io.File
+import java.util.Date
+
+class HomeScreenModel(
+ private val context: Context
+): ScreenModel {
+
+ private val TAG = this::class.simpleName
+
+ private val internalRef = FsElementModel(
+ "Внутренне хранилище",
+ ElementType.isDir,
+ 0,
+ Date()
+ )
+
+ private val externalRef = FsElementModel(
+ "Внешнее хранилище",
+ ElementType.isDir,
+ 0,
+ Date()
+ )
+
+ private val rootFs = listOf(
+ internalRef,
+ externalRef
+ )
+
+ val currentFolder = MutableStateFlow("")
+
+ val folderFiles = MutableStateFlow(listOf(internalRef, externalRef))
+
+
+ private fun isRoot() = currentFolder.value.isEmpty()
+
+ private fun getElements(path: String): List{
+ val here = File(path)
+ return if(here.exists()){
+ here.listFiles()!!.map {
+ FsElementModel(
+ name = it.name,
+ type = if(it.isFile) ElementType.isFile else ElementType.isDir,
+ size = it.length(),
+ date = Date(it.lastModified())
+ )
+ }
+ }else listOf()
+ }
+
+ fun enterRoot(){
+ screenModelScope.launch(Dispatchers.IO) {
+ currentFolder.emit("")
+ folderFiles.emit(rootFs)
+ }
+ }
+
+ fun enterFolder(elementModel: FsElementModel) {
+ if(isRoot()){
+ when(elementModel){
+ externalRef -> enterTheExternal()
+ internalRef -> enterTheInternal()
+ else -> Log.e(TAG, "enterFolder: error path! ${elementModel.name}")
+ }
+ }else{
+ screenModelScope.launch(Dispatchers.IO) {
+ currentFolder.emit(currentFolder.value + "/" + elementModel.name)
+ folderFiles.emit(getElements(currentFolder.value))
+ }
+ }
+ }
+
+ fun backFolder(){
+
+ val path = File(currentFolder.value)
+
+ val internal = context.getInternalAppDataDirectory()
+ val external = context.getExternalAppDataDirectory()
+
+ if(path.exists()){
+ screenModelScope.launch(Dispatchers.IO) {
+ when(currentFolder.value){
+
+ context.getInternalAppDataDirectory(), context.getExternalAppDataDirectory() -> enterRoot()
+ else -> {
+ currentFolder.emit(path.parentFile.absolutePath)
+ folderFiles.emit(getElements(currentFolder.value))
+ }
+ }
+ }
+ }
+
+
+ }
+
+
+ private fun enterTheInternal(){
+ screenModelScope.launch(Dispatchers.IO) {
+ currentFolder.emit(context.getInternalAppDataDirectory())
+ folderFiles.emit(getElements(currentFolder.value))
+ }
+ }
+
+ private fun enterTheExternal(){
+ screenModelScope.launch(Dispatchers.IO) {
+ currentFolder.emit(context.getExternalAppDataDirectory())
+ folderFiles.emit(getElements(currentFolder.value))
+ }
+ }
+
+
+
+}
\ No newline at end of file
diff --git a/devmenu/src/main/java/com/megboyzz/devmenu/ui/screenmodels/SettingsScreenModel.kt b/devmenu/src/main/java/com/megboyzz/devmenu/ui/screenmodels/SettingsScreenModel.kt
new file mode 100644
index 0000000..a075ba8
--- /dev/null
+++ b/devmenu/src/main/java/com/megboyzz/devmenu/ui/screenmodels/SettingsScreenModel.kt
@@ -0,0 +1,62 @@
+package com.megboyzz.devmenu.ui.screenmodels
+
+import android.content.Context
+import cafe.adriel.voyager.core.model.ScreenModel
+import cafe.adriel.voyager.core.model.screenModelScope
+import com.megboyzz.devmenu.App
+import com.megboyzz.devmenu.MainActivity
+import com.megboyzz.devmenu.ui.models.GameLangModel
+import com.megboyzz.devmenu.ui.models.toModel
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.launch
+
+class SettingsScreenModel(
+ context: Context
+): ScreenModel {
+
+ private val settingsUseCaseComponent = (((context as MainActivity).application) as App).settingsUseCaseComponent
+
+ val gameLangModel = MutableStateFlow(settingsUseCaseComponent.getGameLangUseCase().toModel())
+
+ val trackingIsEnabled = MutableStateFlow(false)
+
+ init {
+
+ screenModelScope.launch(Dispatchers.IO) {
+ update()
+ }
+
+ }
+
+ private suspend fun update() {
+ gameLangModel.emit(settingsUseCaseComponent.getGameLangUseCase().toModel())
+ trackingIsEnabled.emit(settingsUseCaseComponent.getTrackingStateUseCase().enabled)
+ }
+
+ fun changeLang(gameLangModel: GameLangModel){
+ screenModelScope.launch(Dispatchers.IO) {
+ settingsUseCaseComponent.setGameLangUseCase(gameLangModel.toDomain())
+ update()
+ }
+ }
+
+ fun changeTrackingState(state: Boolean) {
+ screenModelScope.launch(Dispatchers.IO) {
+ val trackingData = settingsUseCaseComponent.getTrackingStateUseCase()
+ trackingData.copy(enabled = state)
+ settingsUseCaseComponent.setTrackingSaveFileUseCase(trackingData.enabled, trackingData.pathToSave)
+ update()
+ }
+ }
+
+ fun changeTrackingPath(path: String) {
+ screenModelScope.launch(Dispatchers.IO) {
+ val state = settingsUseCaseComponent.getTrackingStateUseCase()
+ state.copy(pathToSave = path)
+ settingsUseCaseComponent.setTrackingSaveFileUseCase(state.enabled, state.pathToSave)
+ update()
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/devmenu/src/main/java/com/megboyzz/devmenu/ui/screens/FileContextMenuScreen.kt b/devmenu/src/main/java/com/megboyzz/devmenu/ui/screens/FileContextMenuScreen.kt
index ef84bb6..da34929 100644
--- a/devmenu/src/main/java/com/megboyzz/devmenu/ui/screens/FileContextMenuScreen.kt
+++ b/devmenu/src/main/java/com/megboyzz/devmenu/ui/screens/FileContextMenuScreen.kt
@@ -2,17 +2,19 @@ package com.megboyzz.devmenu.ui.screens
import androidx.compose.runtime.Composable
import cafe.adriel.voyager.core.screen.Screen
+import com.megboyzz.devmenu.ui.components.ElementType
import com.megboyzz.devmenu.ui.components.FileContextMenu
import com.megboyzz.devmenu.ui.models.FsElementModel
class FileContextMenuScreen(
private val fsElementModel: FsElementModel,
private val onRemoveFile: () -> Unit,
+ private val onUpdateType: (ElementType) -> ElementType?
) : Screen {
@Composable
override fun Content() = FileContextMenu(
fsElementEntity = fsElementModel,
onRemoveElement = onRemoveFile,
- onUpdateType = {null}
+ onUpdateType = onUpdateType
)
}
\ No newline at end of file
diff --git a/devmenu/src/main/java/com/megboyzz/devmenu/ui/screens/HomeScreen.kt b/devmenu/src/main/java/com/megboyzz/devmenu/ui/screens/HomeScreen.kt
index 25fd2c0..57924a2 100644
--- a/devmenu/src/main/java/com/megboyzz/devmenu/ui/screens/HomeScreen.kt
+++ b/devmenu/src/main/java/com/megboyzz/devmenu/ui/screens/HomeScreen.kt
@@ -1,61 +1,115 @@
package com.megboyzz.devmenu.ui.screens
+import android.annotation.SuppressLint
+import androidx.activity.OnBackPressedCallback
+import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.lazy.grid.GridCells
+import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
+import androidx.compose.foundation.lazy.grid.items
+import androidx.compose.material3.Button
+import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.DisposableEffect
+import androidx.compose.runtime.collectAsState
+import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.unit.dp
+import cafe.adriel.voyager.core.model.rememberScreenModel
import cafe.adriel.voyager.core.screen.Screen
+import cafe.adriel.voyager.navigator.LocalNavigator
import cafe.adriel.voyager.navigator.bottomSheet.LocalBottomSheetNavigator
+import com.megboyzz.devmenu.MainActivity
import com.megboyzz.devmenu.ui.SpacerHeight
import com.megboyzz.devmenu.ui.components.ElementType
import com.megboyzz.devmenu.ui.components.FsElement
import com.megboyzz.devmenu.ui.components.MainScaffold
+import com.megboyzz.devmenu.ui.components.StatusBarInCurFolder
+import com.megboyzz.devmenu.ui.getExternalAppDataDirectory
+import com.megboyzz.devmenu.ui.getInternalAppDataDirectory
import com.megboyzz.devmenu.ui.models.FsElementModel
+import com.megboyzz.devmenu.ui.registerOnBackPressedAction
+import com.megboyzz.devmenu.ui.screenmodels.HomeScreenModel
import java.util.Date
class HomeScreen(
private val onFloatingButtonClick: () -> Unit
): Screen {
+ @SuppressLint("StateFlowValueCalledInComposition")
@Composable
override fun Content() {
+ val context = LocalContext.current
+
val bottomSheetNavigator = LocalBottomSheetNavigator.current
- var searchValue by remember{ mutableStateOf("") }
+ val navigator = LocalNavigator.current
- val fsElementModel = FsElementModel(
- name = "my_txt.txt",
- type = ElementType.isHidden,
- size = 123,
- date = Date()
- )
+ var searchValue by remember { mutableStateOf("") }
+ val homeScreenModel = rememberScreenModel { HomeScreenModel(context) }
+ val fsState by homeScreenModel.folderFiles.collectAsState()
+
+ val currentFolder by homeScreenModel.currentFolder.collectAsState()
+
+ context.registerOnBackPressedAction {
+ homeScreenModel.backFolder()
+ }
MainScaffold(
- onSettingsClick = { /*TODO Переход к настройкам */ },
+ onSettingsClick = { navigator?.push(SettingsScreen()) },
onSearchValueChanged = { searchValue = it },
searchValue = searchValue,
onFloatingButtonClick = onFloatingButtonClick
) {
- Column {
- SpacerHeight(height = it.calculateTopPadding())
- FsElement(
- fsElementEntity = fsElementModel,
- onClick = { /*TODO*/ },
- onLongPressClick = {
- bottomSheetNavigator.show(
- FileContextMenuScreen(
- fsElementModel = fsElementModel,
- onRemoveFile = {}
- )
- )
- }
+
+ Column(
+ modifier = Modifier.padding(horizontal = 20.dp)
+ ) {
+
+ StatusBarInCurFolder(
+ path = currentFolder,
+ externalPath = context.getExternalAppDataDirectory(),
+ internalPath = context.getInternalAppDataDirectory()
)
}
+ val filteredList by remember(searchValue, fsState) {
+ derivedStateOf {
+ fsState.filter { it.name.contains(searchValue, ignoreCase = true) }
+ }
+ }
+
+ LazyVerticalGrid(
+ columns = GridCells.Adaptive(80.dp),
+ horizontalArrangement = Arrangement.spacedBy(40.dp),
+ verticalArrangement = Arrangement.spacedBy(40.dp),
+ contentPadding = PaddingValues(20.dp)
+ ){
+
+ items(filteredList){
+ FsElement(
+ fsElementEntity = it,
+ onClick = { homeScreenModel.enterFolder(it) },
+ onLongPressClick = {
+ bottomSheetNavigator.show(FileContextMenuScreen(
+ fsElementModel = it,
+ onRemoveFile = {},
+ onUpdateType = {null}
+ ))
+ }
+ )
+ }
+ }
+
}
}
diff --git a/devmenu/src/main/java/com/megboyzz/devmenu/ui/screens/SettingsScreen.kt b/devmenu/src/main/java/com/megboyzz/devmenu/ui/screens/SettingsScreen.kt
index 1f0da10..e930b38 100644
--- a/devmenu/src/main/java/com/megboyzz/devmenu/ui/screens/SettingsScreen.kt
+++ b/devmenu/src/main/java/com/megboyzz/devmenu/ui/screens/SettingsScreen.kt
@@ -1,11 +1,41 @@
package com.megboyzz.devmenu.ui.screens
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.collectAsState
+import androidx.compose.runtime.getValue
+import androidx.compose.ui.platform.LocalContext
+import cafe.adriel.voyager.core.model.rememberScreenModel
import cafe.adriel.voyager.core.screen.Screen
+import cafe.adriel.voyager.navigator.LocalNavigator
+import com.megboyzz.devmenu.ui.components.SettingsScreenContent
+import com.megboyzz.devmenu.ui.models.GameLangModel
+import com.megboyzz.devmenu.ui.screenmodels.SettingsScreenModel
class SettingsScreen : Screen {
@Composable
override fun Content() {
- TODO("Not yet implemented")
+
+ val navigator = LocalNavigator.current
+
+ val context = LocalContext.current
+
+ val settingsScreenModel = rememberScreenModel { SettingsScreenModel(context) }
+
+ val curLang by settingsScreenModel.gameLangModel.collectAsState()
+
+ val trackingEnabled by settingsScreenModel.trackingIsEnabled.collectAsState()
+
+ SettingsScreenContent(
+ onBackClick = { navigator?.pop() },
+ langModel = curLang,
+ onUpdateLanguage = { settingsScreenModel.changeLang(it) },
+ isTrackingSaveFile = trackingEnabled,
+ onUpdateTrackingSaveFileState = { settingsScreenModel.changeTrackingState(it) },
+ onChooseTrackingPathToSave = { },
+ onUploadSaveFile = { /*TODO*/ },
+ onDownloadSaveFile = { /*TODO*/ },
+ onDevMenuOff = {
+
+ })
}
}
\ No newline at end of file
diff --git a/mpcore/build.gradle.kts b/mpcore/build.gradle.kts
index 2146e56..bcb033c 100644
--- a/mpcore/build.gradle.kts
+++ b/mpcore/build.gradle.kts
@@ -6,11 +6,15 @@ plugins {
android {
namespace = "ru.megboyzz.mpcore"
- compileSdk = 33
+ compileSdk = 34
defaultConfig {
minSdk = 21
+ ndk {
+ abiFilters.add("armeabi-v7a")
+ }
+
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles("consumer-rules.pro")
externalNativeBuild {
diff --git a/mpcore/src/main/cpp/CMakeLists.txt b/mpcore/src/main/cpp/CMakeLists.txt
index f125423..a710fa2 100644
--- a/mpcore/src/main/cpp/CMakeLists.txt
+++ b/mpcore/src/main/cpp/CMakeLists.txt
@@ -3,7 +3,9 @@ cmake_minimum_required(VERSION 3.22.1)
project("mpcore")
add_library(${CMAKE_PROJECT_NAME} SHARED
- mpcore.cpp)
+ main.cpp
+ util/util.cpp
+ util/armhook.cpp)
target_link_libraries(${CMAKE_PROJECT_NAME}
android
diff --git a/mpcore/src/main/cpp/main.cpp b/mpcore/src/main/cpp/main.cpp
new file mode 100644
index 0000000..d581ada
--- /dev/null
+++ b/mpcore/src/main/cpp/main.cpp
@@ -0,0 +1,73 @@
+#include
+#include
+#include
+#include
+#include
+#include
+#include "main.h"
+#include "util/util.h"
+
+#include "util/armhook.h"
+
+uintptr_t libapp = 0;
+
+int (*print_internal_log)(int a1, const char *a2, ...);
+
+void pending_thread(){
+
+ Log("Hello from thread!");
+ std::this_thread::sleep_for(std::chrono::milliseconds(10000));
+
+
+ int unk = APP_ADDR(0x00E4B8EC);
+ print_internal_log(unk, "Hello!");
+
+ unProtect(APP_ADDR(0x00E4A738));
+
+
+}
+
+
+jint JNI_OnLoad(JavaVM *vm, void *reserved){
+
+ libapp = FindLibrary("libapp.so");
+ Log("Hello! my base addr is 0x%08x", libapp);
+
+ //InitHookStuff();
+
+ //unProtect(APP_ADDR(0x00A522C4));
+ //*(int *)APP_ADDR(0x00A522C4) = 0xE320F000;
+
+ //WriteMemory(APP_ADDR(0x00E4BA94), (uintptr_t)"my_tag", 6);
+ raise(SIGSTOP);
+
+ return JNI_VERSION_1_6;
+}
+
+/*
+
+Log("Hello! my base addr is 0x%08x", libapp);
+ Log("Address i wanna to get 0x%08x", APP_ADDR(0xC8C9D8));
+
+ const char* str = (char *)APP_ADDR(0xC8C9D8);
+
+ Log("i found it! %s", str);
+
+ unProtect(APP_ADDR(0xC8C9D8));
+
+ WriteMemory(APP_ADDR(0xC8C9D8), (uintptr_t)"APPLICATION_NO", 14);
+
+ str = (char *)APP_ADDR(0xC8C9D8);
+
+ Log("i change it! %s", str);
+
+ //makeNOP(APP_ADDR(0x00652EB4), 2);
+ //makeNOP(APP_ADDR(0x00652E3C), 2);
+
+ unProtect(APP_ADDR(0x00652EB4));
+ *(char *)APP_ADDR(0x00652EB4) = 0xE320F000;
+
+ unProtect(APP_ADDR(0x00652E3C));
+ *(char *)APP_ADDR(0x00652E3C) = 0xE320F000;
+
+ */
diff --git a/mpcore/src/main/cpp/main.h b/mpcore/src/main/cpp/main.h
new file mode 100644
index 0000000..f5ac598
--- /dev/null
+++ b/mpcore/src/main/cpp/main.h
@@ -0,0 +1,6 @@
+
+//Основная ссылка на начало основного процесса - libapp.so
+extern uintptr_t libapp;
+
+//Макрос для ссылок внутри памяти процесса
+#define APP_ADDR(addr) (libapp + (addr))
diff --git a/mpcore/src/main/cpp/mpcore.cpp b/mpcore/src/main/cpp/mpcore.cpp
deleted file mode 100644
index be67627..0000000
--- a/mpcore/src/main/cpp/mpcore.cpp
+++ /dev/null
@@ -1,10 +0,0 @@
-#include
-#include
-
-extern "C" JNIEXPORT jstring JNICALL
-Java_ru_megboyzz_mpcore_NativeLib_stringFromJNI(
- JNIEnv* env,
- jobject /* this */) {
- std::string hello = "Hello from C++";
- return env->NewStringUTF(hello.c_str());
-}
\ No newline at end of file
diff --git a/mpcore/src/main/cpp/util/armhook.cpp b/mpcore/src/main/cpp/util/armhook.cpp
new file mode 100644
index 0000000..9477908
--- /dev/null
+++ b/mpcore/src/main/cpp/util/armhook.cpp
@@ -0,0 +1,198 @@
+#include // system api
+#include // assert()
+#include // dlopen
+#include
+#include
+#include
+#include "armhook.h"
+#include "util.h"
+#include "../main.h"
+
+uintptr_t mmap_start = 0;
+uintptr_t mmap_end = 0;
+uintptr_t memlib_start = 0;
+uintptr_t memlib_end = 0;
+
+//#define PAGE_SIZE 0x8124
+
+#define HOOK_PROC "\x01\xB4\x01\xB4\x01\x48\x01\x90\x01\xBD\x00\xBF\x00\x00\x00\x00"
+
+
+void unProtect(uintptr_t ptr, size_t dwSize)
+{
+ if(mprotect(reinterpret_cast(ptr & 0xFFFFF000), PAGE_SIZE, PROT_WRITE | PROT_READ | PROT_EXEC) == -1)
+ {
+ const auto err = errno;
+
+ if(err == EACCES)
+ {
+ mprotect(reinterpret_cast(ptr & 0xFFFFF000), PAGE_SIZE, PROT_WRITE | PROT_READ);
+ return;
+ }
+ }
+}
+
+
+void makeNOP(uintptr_t addr, unsigned int count)
+{
+ Log("Hello from makeNOP!");
+ unProtect(addr);
+
+ for(uintptr_t ptr = addr; ptr != (addr+(count * 2)); ptr += 2)
+ {
+ Log("Hello from loop makeNOP!");
+ *(char*)ptr = 0x00;
+ *(char*)(ptr+1) = 0x46;
+ }
+
+ cacheflush(addr, (uintptr_t)(addr + count * 2), 0);
+}
+
+void WriteMemory(uintptr_t dest, uintptr_t src, size_t size)
+{
+ unProtect(dest);
+ memcpy((void*)dest, (void*)src, size);
+ cacheflush(dest, dest+size, 0);
+}
+void WriteMemory(uintptr_t dest, void* src, size_t size)
+{
+ unProtect(dest);
+ memcpy((void*)dest, src, size);
+ cacheflush(dest, dest+size, 0);
+}
+void SetPointer(uintptr_t addr, void* value)
+{
+ WriteMemory(addr, &value, sizeof(value));
+}
+void ReadMemory(uintptr_t dest, uintptr_t src, size_t size)
+{
+ unProtect(src);
+ memcpy((void*)dest, (void*)src, size);
+}
+
+
+void InitHookStuff()
+{
+ memlib_start = APP_ADDR(0x000A1B44);
+ memlib_end = memlib_start + 0x1A36;
+
+ mmap_start = (uintptr_t)mmap(0, PAGE_SIZE, PROT_WRITE | PROT_READ | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ int code = mprotect((void*)(mmap_start & 0xFFFFF000), PAGE_SIZE, PROT_READ | PROT_EXEC | PROT_WRITE);
+ mmap_end = (mmap_start + PAGE_SIZE);
+
+ /*const auto err = errno;
+
+ Log("Status is %d && %d", err, code);
+
+ Log("mmap_stat = 0x%08x", mmap_start);
+ Log("mmap_end = 0x%08x", mmap_end);
+
+ Log("memlib_start = 0x%08x", memlib_start);
+ Log("memlib_end = 0x%08x", memlib_end);*/
+
+ //unProtect(APP_ADDR(0x1800AC));
+
+}
+
+void makeJMP(uintptr_t func, uintptr_t addr)
+{
+ uint32_t code = ((addr - func - 4) >> 12) & 0x7FF | 0xF000 | ((((addr - func - 4) >> 1) & 0x7FF | 0xB800) << 16);
+ WriteMemory(func, (uintptr_t)&code, 4);
+}
+
+void makeBLX(uintptr_t func, uintptr_t addr)
+{
+ uint32_t code = ((addr - func - 4) >> 12) & 0x7FF | ((addr - func - 4) << 15) | 0xF800F000;
+ WriteMemory(func, (uintptr_t)&code, 4);
+}
+
+void WriteHookProc(uintptr_t addr, uintptr_t func)
+{
+ char code[16];
+
+ memcpy(code, HOOK_PROC, 16);
+ *(uint32_t*)&code[12] = (func | 1);
+
+ WriteMemory(addr, (uintptr_t)code, 16);
+}
+
+void InstallBLXHook(uintptr_t addr, uintptr_t func)
+{
+ // memlib_start = 0
+ // memlib_end = 10
+
+ if(memlib_end < (memlib_start + 0x10) || mmap_end < (mmap_start + 0x20))
+ {
+ std::terminate();
+ }
+
+ makeBLX(addr, func);
+ WriteHookProc(addr, func);
+
+ memlib_start += 16;
+}
+
+void InstallJMPHook(uintptr_t addr, uintptr_t func)
+{
+
+ if(memlib_end < (memlib_start + 0x10) || mmap_end < (mmap_start + 0x20))
+ {
+ std::terminate();
+ }
+
+ makeJMP(addr, func);
+ WriteHookProc(addr, func);
+
+ memlib_start += 16;
+}
+
+void InstallHook(uintptr_t addr, uintptr_t func, uintptr_t *orig)
+{
+
+ if(memlib_end < (memlib_start + 0x10) || mmap_end < (mmap_start + 0x20))
+ {
+ Log("FAILED!");
+ std::terminate();
+ }
+
+ ReadMemory(mmap_start, addr, 4);
+ WriteHookProc(mmap_start+4, addr+4);
+ *orig = mmap_start+1;
+ mmap_start += 32;
+
+ makeJMP(addr, memlib_start);
+ WriteHookProc(memlib_start, func);
+ memlib_start += 16;
+}
+
+void RedirectCall(uintptr_t addr, uintptr_t func)
+{
+ makeJMP(addr, memlib_start);
+ WriteHookProc(memlib_start, func);
+ memlib_start += 16;
+}
+
+void InstallMethodHook(uintptr_t addr, uintptr_t func)
+{
+ unProtect(addr);
+ *(uintptr_t*)addr = func;
+}
+
+void CodeInject(uintptr_t addr, uintptr_t func, int reg)
+{
+
+ char injectCode[12];
+
+ injectCode[0] = 0x01;
+ injectCode[1] = 0xA0 + reg;
+ injectCode[2] = (0x08 * reg) + reg;
+ injectCode[3] = 0x68;
+ injectCode[4] = 0x87 + (0x08 * reg);
+ injectCode[5] = 0x46;
+ injectCode[6] = injectCode[4];
+ injectCode[7] = injectCode[5];
+
+ *(uintptr_t*)&injectCode[8] = func;
+
+ WriteMemory(addr, (uintptr_t)injectCode, 12);
+}
\ No newline at end of file
diff --git a/mpcore/src/main/cpp/util/armhook.h b/mpcore/src/main/cpp/util/armhook.h
new file mode 100644
index 0000000..f32db9c
--- /dev/null
+++ b/mpcore/src/main/cpp/util/armhook.h
@@ -0,0 +1,35 @@
+#pragma once
+
+#include
+
+extern uintptr_t mmap_start;
+extern uintptr_t mmap_end;
+extern uintptr_t memlib_start;
+extern uintptr_t memlib_end;
+
+void unProtect(uintptr_t ptr, size_t dwSize = 100);
+
+void WriteMemory(uintptr_t dest, uintptr_t src, size_t size);
+void ReadMemory(uintptr_t dest, uintptr_t src, size_t size);
+
+void makeNOP(uintptr_t addr, unsigned int count);
+void makeJMP(uintptr_t func, uintptr_t addr);
+void makeBLX(uintptr_t func, uintptr_t addr);
+
+void InitHookStuff();
+
+void InstallHook(uintptr_t addr, uintptr_t func, uintptr_t *orig);
+void InstallMethodHook(uintptr_t addr, uintptr_t func);
+void InstallJMPHook(uintptr_t addr, uintptr_t func);
+void InstallBLXHook(uintptr_t addr, uintptr_t func);
+
+void CodeInject(uintptr_t addr, uintptr_t func, int reg);
+
+void WriteMemory(uintptr_t dest, void* src, size_t size);
+void SetPointer(uintptr_t addr, void* value);
+
+template
+static Ret CallFunction(unsigned int address, Args... args)
+{
+ return reinterpret_cast(address)(args...);
+}
\ No newline at end of file
diff --git a/mpcore/src/main/cpp/util/util.cpp b/mpcore/src/main/cpp/util/util.cpp
new file mode 100644
index 0000000..b805cc9
--- /dev/null
+++ b/mpcore/src/main/cpp/util/util.cpp
@@ -0,0 +1,52 @@
+#include
+#include
+#include
+#include
+#include "util.h"
+
+uintptr_t FindLibrary(const char *lib_name) {
+ char filename[0xFF] = {0},
+ buffer[2048] = {0};
+ FILE *fp = 0;
+ uintptr_t address = 0;
+
+ sprintf(filename, "/proc/%d/maps", getpid());
+
+ fp = fopen(filename, "rt");
+ if (fp == nullptr) {
+ Log("ERROR: can't open file %s", filename);
+ goto done;
+ }
+
+
+ while (fgets(buffer, sizeof(buffer), fp)) {
+ if (strstr(buffer, lib_name)) {
+ address = (uintptr_t) strtoul(buffer, 0, 16);
+ break;
+ }
+ }
+ done:
+
+ if (fp)
+ fclose(fp);
+
+ return address;
+}
+
+void Log(const char *fmt, ...) {
+ char buffer[0xFF];
+ static FILE *flLog = nullptr;
+
+ memset(buffer, 0, sizeof(buffer));
+
+ va_list arg;
+ va_start(arg, fmt);
+ vsnprintf(buffer, sizeof(buffer), fmt, arg);
+ va_end(arg);
+
+ __android_log_write(ANDROID_LOG_INFO, "mpcore_log", buffer);
+
+ if (flLog == nullptr) return;
+ fprintf(flLog, "%s\n", buffer);
+ fflush(flLog);
+}
\ No newline at end of file
diff --git a/mpcore/src/main/cpp/util/util.h b/mpcore/src/main/cpp/util/util.h
new file mode 100644
index 0000000..899b21c
--- /dev/null
+++ b/mpcore/src/main/cpp/util/util.h
@@ -0,0 +1,5 @@
+#pragma once
+
+uintptr_t FindLibrary(const char* lib_name);
+
+void Log(const char *fmt, ...);
\ No newline at end of file
diff --git a/mpcore/src/main/java/ru/megboyzz/mpcore/NativeLib.kt b/mpcore/src/main/java/ru/megboyzz/mpcore/NativeLib.kt
index 9afb60d..8e3991e 100644
--- a/mpcore/src/main/java/ru/megboyzz/mpcore/NativeLib.kt
+++ b/mpcore/src/main/java/ru/megboyzz/mpcore/NativeLib.kt
@@ -2,11 +2,10 @@ package ru.megboyzz.mpcore
class NativeLib {
- external fun stringFromJNI(): String
-
companion object {
init {
- System.loadLibrary("mpcore")
+ //System.loadLibrary("mpcore")
}
}
+
}
\ No newline at end of file