From b093674b6e3130fab760802d05ab0285c2389f1e Mon Sep 17 00:00:00 2001 From: ikits Date: Wed, 3 Jan 2024 00:35:39 +0400 Subject: [PATCH] add mpcore module, settings screen done --- .../devmenu/util/UtilitiesAndData.java | 2 +- devmenu/build.gradle.kts | 5 + .../java/com/megboyzz/devmenu/MainActivity.kt | 6 +- .../java/com/megboyzz/devmenu/ui/Utlil.kt | 22 ++ .../devmenu/ui/components/AnimationSpec.kt | 12 +- .../devmenu/ui/components/ContextMenuState.kt | 36 ++- .../megboyzz/devmenu/ui/components/Files.kt | 2 +- .../devmenu/ui/components/FolderStatusBar.kt | 55 +++++ .../{Scaffold.kt => HomeScaffold.kt} | 35 +-- .../devmenu/ui/components/Settings.kt | 211 ++++++++++++++++++ .../ui/{entities => models}/FsElementModel.kt | 2 +- .../devmenu/ui/models/GameLangModel.kt | 19 ++ .../ui/screens/FileContextMenuScreen.kt | 18 +- .../megboyzz/devmenu/ui/screens/HomeScreen.kt | 30 ++- .../devmenu/ui/screens/SettingsScreen.kt | 11 + devmenu/src/main/res/drawable/download.xml | 9 + devmenu/src/main/res/drawable/folder.xml | 9 + devmenu/src/main/res/drawable/lang.xml | 9 + devmenu/src/main/res/drawable/tracking.xml | 9 + devmenu/src/main/res/drawable/upload.xml | 9 + gradle/libs.versions.toml | 2 + mpcore/.gitignore | 1 + mpcore/build.gradle.kts | 55 +++++ mpcore/consumer-rules.pro | 0 mpcore/proguard-rules.pro | 21 ++ .../mpcore/ExampleInstrumentedTest.kt | 24 ++ mpcore/src/main/AndroidManifest.xml | 4 + mpcore/src/main/cpp/CMakeLists.txt | 10 + mpcore/src/main/cpp/mpcore.cpp | 10 + .../main/java/ru/megboyzz/mpcore/NativeLib.kt | 12 + .../ru/megboyzz/mpcore/ExampleUnitTest.kt | 17 ++ settings.gradle.kts | 1 + 32 files changed, 602 insertions(+), 66 deletions(-) create mode 100644 devmenu/src/main/java/com/megboyzz/devmenu/ui/components/FolderStatusBar.kt rename devmenu/src/main/java/com/megboyzz/devmenu/ui/components/{Scaffold.kt => HomeScaffold.kt} (81%) create mode 100644 devmenu/src/main/java/com/megboyzz/devmenu/ui/components/Settings.kt rename devmenu/src/main/java/com/megboyzz/devmenu/ui/{entities => models}/FsElementModel.kt (82%) create mode 100644 devmenu/src/main/java/com/megboyzz/devmenu/ui/models/GameLangModel.kt create mode 100644 devmenu/src/main/java/com/megboyzz/devmenu/ui/screens/SettingsScreen.kt create mode 100644 devmenu/src/main/res/drawable/download.xml create mode 100644 devmenu/src/main/res/drawable/folder.xml create mode 100644 devmenu/src/main/res/drawable/lang.xml create mode 100644 devmenu/src/main/res/drawable/tracking.xml create mode 100644 devmenu/src/main/res/drawable/upload.xml create mode 100644 mpcore/.gitignore create mode 100644 mpcore/build.gradle.kts create mode 100644 mpcore/consumer-rules.pro create mode 100644 mpcore/proguard-rules.pro create mode 100644 mpcore/src/androidTest/java/ru/megboyzz/mpcore/ExampleInstrumentedTest.kt create mode 100644 mpcore/src/main/AndroidManifest.xml create mode 100644 mpcore/src/main/cpp/CMakeLists.txt create mode 100644 mpcore/src/main/cpp/mpcore.cpp create mode 100644 mpcore/src/main/java/ru/megboyzz/mpcore/NativeLib.kt create mode 100644 mpcore/src/test/java/ru/megboyzz/mpcore/ExampleUnitTest.kt diff --git a/app/src/main/java/com/ea/ironmonkey/devmenu/util/UtilitiesAndData.java b/app/src/main/java/com/ea/ironmonkey/devmenu/util/UtilitiesAndData.java index 378a0af..7b22749 100644 --- a/app/src/main/java/com/ea/ironmonkey/devmenu/util/UtilitiesAndData.java +++ b/app/src/main/java/com/ea/ironmonkey/devmenu/util/UtilitiesAndData.java @@ -63,7 +63,7 @@ public class UtilitiesAndData { public static void printLog(String msg){ try{ if(isLoggerEnabled()) - stream.write(msg.getBytes(StandardCharsets.UTF_8)); + stream.write(msg.getBytes(StandardCharsets.UTF_8)); } catch (IOException e) { Log.wtf(LOG_TAG, "cant write to stream((("); e.printStackTrace(); diff --git a/devmenu/build.gradle.kts b/devmenu/build.gradle.kts index 8aa93bd..4889a0e 100644 --- a/devmenu/build.gradle.kts +++ b/devmenu/build.gradle.kts @@ -32,6 +32,7 @@ android { compileOptions { sourceCompatibility = JavaVersion.VERSION_1_8 targetCompatibility = JavaVersion.VERSION_1_8 + isCoreLibraryDesugaringEnabled = true } kotlinOptions { jvmTarget = "1.8" @@ -71,6 +72,10 @@ dependencies { debugImplementation(libs.ui.tooling) debugImplementation(libs.ui.test.manifest) + coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.0.4") + + implementation(libs.compose.settings.ui.m3) + implementation(libs.voyager.navigator) implementation(libs.voyager.bottomSheetNavigator) implementation(libs.voyager.transitions) diff --git a/devmenu/src/main/java/com/megboyzz/devmenu/MainActivity.kt b/devmenu/src/main/java/com/megboyzz/devmenu/MainActivity.kt index 421a887..f862884 100644 --- a/devmenu/src/main/java/com/megboyzz/devmenu/MainActivity.kt +++ b/devmenu/src/main/java/com/megboyzz/devmenu/MainActivity.kt @@ -4,6 +4,8 @@ import android.content.Intent import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent +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 com.megboyzz.devmenu.ui.components.MainScaffold @@ -34,7 +36,9 @@ class MainActivity : ComponentActivity() { } setContent { - BottomSheetNavigator { + BottomSheetNavigator( + sheetShape = RoundedCornerShape(topStart = 10.dp, topEnd = 10.dp) + ) { Navigator(HomeScreen(::runGame)) } } 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 f5a6eaf..34d25d6 100644 --- a/devmenu/src/main/java/com/megboyzz/devmenu/ui/Utlil.kt +++ b/devmenu/src/main/java/com/megboyzz/devmenu/ui/Utlil.kt @@ -1,5 +1,6 @@ package com.megboyzz.devmenu.ui +import android.annotation.SuppressLint import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.width @@ -8,6 +9,11 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.Dp +import java.text.CharacterIterator +import java.text.SimpleDateFormat +import java.text.StringCharacterIterator +import java.util.Date + @Composable fun Int.asPainter() = painterResource(this) @@ -23,6 +29,22 @@ fun SpacerWidth(width: Dp) = Spacer(Modifier.width(width)) @Composable fun SpacerHeight(height: Dp) = Spacer(Modifier.height(height)) +fun humanReadableByteCountSI(bytes: Long): String { + var b = bytes + if (-1000 < b && b < 1000) { + return "$b B" + } + val ci: CharacterIterator = StringCharacterIterator("kMGTPE") + while (b <= -999950 || b >= 999950) { + b /= 1000 + ci.next() + } + return String.format("%.1f %cB", b / 1000.0, ci.current()) +} + +@SuppressLint("SimpleDateFormat") +fun formatDate(date: Date) = SimpleDateFormat("dd.MM.yyyy HH:mm:ss").format(date) + /** * Возвращает лямбду того типа которая требуется в Composable контексте
diff --git a/devmenu/src/main/java/com/megboyzz/devmenu/ui/components/AnimationSpec.kt b/devmenu/src/main/java/com/megboyzz/devmenu/ui/components/AnimationSpec.kt index c6aac93..e20e5bf 100644 --- a/devmenu/src/main/java/com/megboyzz/devmenu/ui/components/AnimationSpec.kt +++ b/devmenu/src/main/java/com/megboyzz/devmenu/ui/components/AnimationSpec.kt @@ -4,6 +4,8 @@ import androidx.compose.animation.core.tween import androidx.compose.animation.expandIn import androidx.compose.animation.shrinkOut +import androidx.compose.animation.slideInVertically +import androidx.compose.animation.slideOutVertically import androidx.compose.ui.Alignment @@ -15,4 +17,12 @@ val enter = expandIn( val exit = shrinkOut( shrinkTowards = Alignment.CenterStart, animationSpec = tween(250) -) \ No newline at end of file +) + +fun searchFieldEnter(duration: Int) = slideInVertically(animationSpec = tween(durationMillis = duration)) { + -it / 3 +} + +fun searchFieldExit(duration: Int) = slideOutVertically(animationSpec = tween(durationMillis = duration)) { + -it / 3 +} \ No newline at end of file diff --git a/devmenu/src/main/java/com/megboyzz/devmenu/ui/components/ContextMenuState.kt b/devmenu/src/main/java/com/megboyzz/devmenu/ui/components/ContextMenuState.kt index 503e1dc..417e758 100644 --- a/devmenu/src/main/java/com/megboyzz/devmenu/ui/components/ContextMenuState.kt +++ b/devmenu/src/main/java/com/megboyzz/devmenu/ui/components/ContextMenuState.kt @@ -29,8 +29,11 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.painter.Painter import androidx.compose.ui.unit.dp import com.megboyzz.devmenu.R +import com.megboyzz.devmenu.ui.SpacerHeight import com.megboyzz.devmenu.ui.asPainter -import com.megboyzz.devmenu.ui.entities.FsElementModel +import com.megboyzz.devmenu.ui.models.FsElementModel +import com.megboyzz.devmenu.ui.formatDate +import com.megboyzz.devmenu.ui.humanReadableByteCountSI @Composable fun ClickableMenuPosition( @@ -112,9 +115,7 @@ fun FileContextMenu( var state by remember { mutableStateOf(ContextMenuState.Main) } - CoreFileContextMenu { - FsElementInContextMenu(name = fsElementEntity.name, type = fsElementEntity.type) - Divider() + CoreFileContextMenu(fsElementEntity = fsElementEntity) { AnimatedBoxForContextMenuContent(isVisible = state == ContextMenuState.Main){ AnimatedBoxForContextMenuContent(isVisible = innerType == ElementType.isFile) { ClickableMenuPosition( @@ -154,7 +155,7 @@ fun FileContextMenu( ClickableMenuPosition( name = "Свойства", icon = R.drawable.info.asPainter(), - onClick = {} + onClick = { state = ContextMenuState.Props } ) ClickableMenuPosition( name = "Удалить", @@ -181,6 +182,7 @@ fun FileContextMenu( icon = R.drawable.info.asPainter(), withEnd = false, ) + PropsView(fsElementEntity = fsElementEntity) RemoveButton(text = "Назад") { state = ContextMenuState.Main } @@ -188,6 +190,17 @@ fun FileContextMenu( } } +@Composable +fun PropsView( + fsElementEntity: FsElementModel +) { + + Column(verticalArrangement = Arrangement.spacedBy(12.dp)) { + Text(text = "Изменен: ${formatDate(fsElementEntity.date)}") + Text(text = "Размер: ${humanReadableByteCountSI(fsElementEntity.size)} (${fsElementEntity.size} B)") + } +} + @Composable @@ -215,9 +228,8 @@ fun RemoveFileButtonsGroup( Row( horizontalArrangement = Arrangement.spacedBy(12.dp), ) { - val m = Modifier.weight(1f) - RemoveButton(text = "Удалить", onClick = onDelete, modifier = m) - RemoveButton(text = "Отмена", onClick = onCancel, modifier = m) + RemoveButton(text = "Удалить", onClick = onDelete, modifier = Modifier.weight(1f)) + RemoveButton(text = "Отмена", onClick = onCancel, modifier = Modifier.weight(1f)) } } @@ -239,6 +251,7 @@ fun RemoveButton( @Composable fun CoreFileContextMenu( + fsElementEntity: FsElementModel, content: @Composable () -> Unit ) { @@ -264,7 +277,12 @@ fun CoreFileContextMenu( vertical = 32.dp ), ){ - Column(verticalArrangement = Arrangement.spacedBy(20.dp)) { + Column { + Column(verticalArrangement = Arrangement.spacedBy(16.dp)) { + FsElementInContextMenu(name = fsElementEntity.name, type = fsElementEntity.type) + Divider() + SpacerHeight(height = 0.dp) + } content() } } 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 9dbbc8e..051a869 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 @@ -7,7 +7,7 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp -import com.megboyzz.devmenu.ui.entities.FsElementModel +import com.megboyzz.devmenu.ui.models.FsElementModel @Composable fun FsElement( 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 new file mode 100644 index 0000000..0fd4519 --- /dev/null +++ b/devmenu/src/main/java/com/megboyzz/devmenu/ui/components/FolderStatusBar.kt @@ -0,0 +1,55 @@ +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 +import androidx.compose.foundation.lazy.items +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.megboyzz.devmenu.R +import com.megboyzz.devmenu.ui.asPainter + +@Composable +fun CoreBar(folders: List) { + + LazyRow(verticalAlignment = Alignment.CenterVertically) { + items(folders){ + Text( + text = it, + style = MaterialTheme.typography.labelSmall + ) + Image( + painter = R.drawable.enter.asPainter(), + modifier = Modifier + .padding(4.dp) + .size(8.dp), + contentDescription = null + ) + } + } + +} + +@Composable +fun StatusBarInCurFolder( + path: String +) { + if(path.isEmpty()) return + val pathAsArray = path.split("/").filter { it.isNotEmpty() } + CoreBar(folders = pathAsArray) +} + + +@Preview +@Composable +fun CoreBarPrev() { + val path = "/data/data/com.ea.games.nfs13_na/files/var/".split("/").filter { it.isNotEmpty() } + CoreBar(folders = path) +} \ No newline at end of file diff --git a/devmenu/src/main/java/com/megboyzz/devmenu/ui/components/Scaffold.kt b/devmenu/src/main/java/com/megboyzz/devmenu/ui/components/HomeScaffold.kt similarity index 81% rename from devmenu/src/main/java/com/megboyzz/devmenu/ui/components/Scaffold.kt rename to devmenu/src/main/java/com/megboyzz/devmenu/ui/components/HomeScaffold.kt index e4c64fd..3b628d3 100644 --- a/devmenu/src/main/java/com/megboyzz/devmenu/ui/components/Scaffold.kt +++ b/devmenu/src/main/java/com/megboyzz/devmenu/ui/components/HomeScaffold.kt @@ -1,10 +1,5 @@ package com.megboyzz.devmenu.ui.components -import android.widget.Toast -import androidx.compose.animation.AnimatedVisibility -import androidx.compose.animation.core.tween -import androidx.compose.animation.slideInVertically -import androidx.compose.animation.slideOutVertically import androidx.compose.foundation.background import androidx.compose.foundation.border import androidx.compose.foundation.layout.Arrangement @@ -38,7 +33,6 @@ 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.asComposableLambda import com.megboyzz.devmenu.ui.theme.DevMenuTheme @OptIn(ExperimentalMaterial3Api::class) @@ -92,28 +86,15 @@ fun TopBar( val context = LocalContext.current TopAppBar( title = { - Box { - AnimatedVisibility( - visible = isSearching, - enter = slideInVertically(animationSpec = tween(durationMillis = 200)) { - -it / 3 - }, - exit = slideOutVertically(animationSpec = tween(durationMillis = 200)) { - -it / 3 - } - ) { - SearchFileTextField( - value = searchValue, - onValueChange = onSearchValueChanged - ) - } - if(!isSearching) Text("NFSMW DevMenu") - } - + if(isSearching){ + SearchFileTextField( + value = searchValue, + onValueChange = onSearchValueChanged + ) + }else Text("NFSMW DevMenu") }, actions = { SearchButton { - Toast.makeText(context, "hh", Toast.LENGTH_LONG).show() isSearching = !isSearching } SettingsButton(onClick = onSettingsClick) @@ -169,9 +150,7 @@ fun SearchFileTextField( value = value, onValueChange = onValueChange, decorationBox = { innerTextField -> - Box( - - ) { + Box(Modifier.padding(end = 12.dp)) { Row( Modifier .fillMaxWidth() diff --git a/devmenu/src/main/java/com/megboyzz/devmenu/ui/components/Settings.kt b/devmenu/src/main/java/com/megboyzz/devmenu/ui/components/Settings.kt new file mode 100644 index 0000000..82b3ce6 --- /dev/null +++ b/devmenu/src/main/java/com/megboyzz/devmenu/ui/components/Settings.kt @@ -0,0 +1,211 @@ +package com.megboyzz.devmenu.ui.components + +import android.media.audiofx.Equalizer.Settings +import androidx.compose.foundation.layout.Arrangement +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.material.icons.Icons +import androidx.compose.material.icons.filled.ArrowBack +import androidx.compose.material.icons.filled.Settings +import androidx.compose.material.icons.sharp.Home +import androidx.compose.material.icons.sharp.List +import androidx.compose.material.icons.sharp.Notifications +import androidx.compose.material3.AlertDialog +import androidx.compose.material3.Divider +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Text +import androidx.compose.material3.TextButton +import androidx.compose.material3.TopAppBar +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +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.alorma.compose.settings.storage.base.getValue +import com.alorma.compose.settings.storage.base.rememberBooleanSettingState +import com.alorma.compose.settings.storage.base.rememberIntSettingState +import com.alorma.compose.settings.ui.SettingsCheckbox +import com.alorma.compose.settings.ui.SettingsList +import com.alorma.compose.settings.ui.SettingsMenuLink +import com.alorma.compose.settings.ui.SettingsSwitch +import com.megboyzz.devmenu.R +import com.megboyzz.devmenu.ui.SpacerHeight +import com.megboyzz.devmenu.ui.asPainter +import com.megboyzz.devmenu.ui.models.GameLangModel + +@Composable +fun SettingsScaffold( + onBackClick: () -> Unit, + content: @Composable ColumnScope.() -> Unit +) { + Scaffold( + topBar = { SettingsTopBar(onBackClick = onBackClick) }, + ){ + Column { + SpacerHeight(height = it.calculateTopPadding()) + content(this) + } + } +} + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun SettingsTopBar( + onBackClick: () -> Unit +) { + TopAppBar( + navigationIcon = { + IconButton(onClick = onBackClick) { + Icon(imageVector = Icons.Filled.ArrowBack, contentDescription = null) + } + }, + title = { Text("Настройки") } + ) +} + +@Composable +fun LangDialog( + langModel: GameLangModel, + onUpdateLanguage: (GameLangModel) -> Unit +) { + + val items = GameLangModel.values().map { it.name } + + val curItem = items.indexOf(langModel.name) + + val lang = rememberIntSettingState(curItem) + + SettingsList( + icon = { Icon(painter = R.drawable.lang.asPainter(), contentDescription = null) }, + title = { Text(text = "Сменить язык") }, + items = items, + state = lang, + onItemSelected = { index, _ -> + onUpdateLanguage(GameLangModel.values()[index]) + } + ) +} + +@Composable +fun DevMenuOffDialog( + onDevMenuOff: () -> Unit, + onDismiss: () -> Unit, +) { + AlertDialog( + title = { + Text(text = "Выключить DevMenu") + }, + text = { + Text(text = "Уверен что хочешь выключить DevMenu? Чтобы его включить нужно будет создать пустой файл c именем DevMenu в корне кэша игры") + }, + onDismissRequest = onDismiss, + confirmButton = { + TextButton( + onClick = onDevMenuOff + ) { + Text("OK") + } + }, + dismissButton = { + TextButton( + onClick = onDismiss + ) { + Text("Отмена") + } + } + ) +} + + +@Composable +fun SettingsScreenContent( + onBackClick: () -> Unit, + langModel: GameLangModel, + onUpdateLanguage: (GameLangModel) -> Unit, + isTrackingSaveFile: Boolean, + onUpdateTrackingSaveFileState: (Boolean) -> Unit, + onChooseTrackingPathToSave: () -> Unit, + onUploadSaveFile: () -> Unit, + onDownloadSaveFile: () -> Unit, + onDevMenuOff: () -> Unit +) { + + var isDevMenuOffDialog by remember { mutableStateOf(false) } + + if(isDevMenuOffDialog){ + DevMenuOffDialog( + onDevMenuOff = { + onDevMenuOff() + isDevMenuOffDialog =! isDevMenuOffDialog + }, + onDismiss = { isDevMenuOffDialog =! isDevMenuOffDialog } + ) + } + + SettingsScaffold(onBackClick = onBackClick) { + LangDialog(langModel = langModel, onUpdateLanguage = onUpdateLanguage) + Divider() + SettingsSwitch( + icon = { + Icon(painter = R.drawable.tracking.asPainter(), contentDescription = null) + }, + title = { + Text(text = "Отслеживание файла сохранения") + }, + state = rememberBooleanSettingState(isTrackingSaveFile), + onCheckedChange = onUpdateTrackingSaveFileState + ) + SettingsMenuLink( + icon = { Icon(painter = R.drawable.folder.asPainter(), contentDescription = null) }, + title = { Text(text = "Выбрать путь сохранения отслеживаемого сохранения") }, + onClick = onChooseTrackingPathToSave, + ) + Divider() + SettingsMenuLink( + icon = { Icon(painter = R.drawable.download.asPainter(), contentDescription = null) }, + title = { Text(text = "Выгрузить файл сохранения") }, + subtitle = { Text(text = "Получить текущий nfstr_save.sb") }, + onClick = onDownloadSaveFile, + ) + SettingsMenuLink( + icon = { Icon(painter = R.drawable.upload.asPainter(), contentDescription = null) }, + title = { Text(text = "Загрузить файл сохранения") }, + subtitle = { Text(text = "Загрузить в игру nfstr_save.sb") }, + onClick = onUploadSaveFile, + ) + Divider() + SettingsMenuLink( + title = { + Text( + text = "Выключить DevMenu", + color = Color.Red + ) + }, + onClick = { isDevMenuOffDialog =! isDevMenuOffDialog }, + ) + } +} + +@Preview +@Composable +fun SettingsTopBarPreview() { + SettingsScreenContent( + onBackClick = { /*TODO*/ }, + langModel = GameLangModel.System, + onUpdateLanguage = {}, + isTrackingSaveFile = false, + onUpdateTrackingSaveFileState = {}, + onChooseTrackingPathToSave = { /*TODO*/ }, + onUploadSaveFile = { /*TODO*/ }, + onDownloadSaveFile = { /*TODO*/ }, + onDevMenuOff = {}) +} \ No newline at end of file diff --git a/devmenu/src/main/java/com/megboyzz/devmenu/ui/entities/FsElementModel.kt b/devmenu/src/main/java/com/megboyzz/devmenu/ui/models/FsElementModel.kt similarity index 82% rename from devmenu/src/main/java/com/megboyzz/devmenu/ui/entities/FsElementModel.kt rename to devmenu/src/main/java/com/megboyzz/devmenu/ui/models/FsElementModel.kt index 303d277..0b92b39 100644 --- a/devmenu/src/main/java/com/megboyzz/devmenu/ui/entities/FsElementModel.kt +++ b/devmenu/src/main/java/com/megboyzz/devmenu/ui/models/FsElementModel.kt @@ -1,4 +1,4 @@ -package com.megboyzz.devmenu.ui.entities +package com.megboyzz.devmenu.ui.models import com.megboyzz.devmenu.ui.components.ElementType import java.util.Date 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 new file mode 100644 index 0000000..f270738 --- /dev/null +++ b/devmenu/src/main/java/com/megboyzz/devmenu/ui/models/GameLangModel.kt @@ -0,0 +1,19 @@ +package com.megboyzz.devmenu.ui.models + +enum class GameLangModel(private val lang: String) { + System("sys"), + Chinese("cn"), + Dutch("nl"), + English("en"), + French("fr"), + Deutsch("de"), + Italian("it"), + Japanese("ja"), + Korean("kr"), + Portuguese("br"), + Russian("ru"), + Spanish("es"); + + override fun toString() = lang + +} \ 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 aaadbff..ef84bb6 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 @@ -3,22 +3,16 @@ package com.megboyzz.devmenu.ui.screens import androidx.compose.runtime.Composable import cafe.adriel.voyager.core.screen.Screen import com.megboyzz.devmenu.ui.components.FileContextMenu -import com.megboyzz.devmenu.ui.entities.FsElementModel +import com.megboyzz.devmenu.ui.models.FsElementModel class FileContextMenuScreen( private val fsElementModel: FsElementModel, private val onRemoveFile: () -> Unit, ) : Screen { @Composable - override fun Content() { - - - - FileContextMenu( - fsElementEntity = fsElementModel, - onRemoveElement = onRemoveFile, - onUpdateType = {null} - ) - - } + override fun Content() = FileContextMenu( + fsElementEntity = fsElementModel, + onRemoveElement = onRemoveFile, + onUpdateType = {null} + ) } \ 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 2138e07..25fd2c0 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,5 +1,6 @@ package com.megboyzz.devmenu.ui.screens +import androidx.compose.foundation.layout.Column import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf @@ -7,10 +8,11 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import cafe.adriel.voyager.core.screen.Screen import cafe.adriel.voyager.navigator.bottomSheet.LocalBottomSheetNavigator +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.entities.FsElementModel +import com.megboyzz.devmenu.ui.models.FsElementModel import java.util.Date class HomeScreen( @@ -38,18 +40,22 @@ class HomeScreen( searchValue = searchValue, onFloatingButtonClick = onFloatingButtonClick ) { - FsElement( - fsElementEntity = fsElementModel, - onClick = { /*TODO*/ }, - onLongPressClick = { - bottomSheetNavigator.show( - FileContextMenuScreen( - fsElementModel = fsElementModel, - onRemoveFile = {} + Column { + SpacerHeight(height = it.calculateTopPadding()) + FsElement( + fsElementEntity = fsElementModel, + onClick = { /*TODO*/ }, + onLongPressClick = { + bottomSheetNavigator.show( + FileContextMenuScreen( + fsElementModel = fsElementModel, + onRemoveFile = {} + ) ) - ) - } - ) + } + ) + } + } } 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 new file mode 100644 index 0000000..1f0da10 --- /dev/null +++ b/devmenu/src/main/java/com/megboyzz/devmenu/ui/screens/SettingsScreen.kt @@ -0,0 +1,11 @@ +package com.megboyzz.devmenu.ui.screens + +import androidx.compose.runtime.Composable +import cafe.adriel.voyager.core.screen.Screen + +class SettingsScreen : Screen { + @Composable + override fun Content() { + TODO("Not yet implemented") + } +} \ No newline at end of file diff --git a/devmenu/src/main/res/drawable/download.xml b/devmenu/src/main/res/drawable/download.xml new file mode 100644 index 0000000..844165f --- /dev/null +++ b/devmenu/src/main/res/drawable/download.xml @@ -0,0 +1,9 @@ + + + diff --git a/devmenu/src/main/res/drawable/folder.xml b/devmenu/src/main/res/drawable/folder.xml new file mode 100644 index 0000000..d0a9fe7 --- /dev/null +++ b/devmenu/src/main/res/drawable/folder.xml @@ -0,0 +1,9 @@ + + + diff --git a/devmenu/src/main/res/drawable/lang.xml b/devmenu/src/main/res/drawable/lang.xml new file mode 100644 index 0000000..f6e7b46 --- /dev/null +++ b/devmenu/src/main/res/drawable/lang.xml @@ -0,0 +1,9 @@ + + + diff --git a/devmenu/src/main/res/drawable/tracking.xml b/devmenu/src/main/res/drawable/tracking.xml new file mode 100644 index 0000000..8ed1fb1 --- /dev/null +++ b/devmenu/src/main/res/drawable/tracking.xml @@ -0,0 +1,9 @@ + + + diff --git a/devmenu/src/main/res/drawable/upload.xml b/devmenu/src/main/res/drawable/upload.xml new file mode 100644 index 0000000..4f812f7 --- /dev/null +++ b/devmenu/src/main/res/drawable/upload.xml @@ -0,0 +1,9 @@ + + + diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 1c80f76..18af5c6 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,5 +1,6 @@ [versions] agp = "8.1.2" +compose-settings-ui-m3 = "1.0.3" junit-junit = "4.13.2" kotlin = "1.9.21" core-ktx = "1.12.0" @@ -18,6 +19,7 @@ room = "2.6.1" voyager = "1.0.0" [libraries] +compose-settings-ui-m3 = { module = "com.github.alorma:compose-settings-ui-m3", version.ref = "compose-settings-ui-m3" } core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "core-ktx" } junit = { group = "junit", name = "junit", version.ref = "junit" } androidx-test-ext-junit = { group = "androidx.test.ext", name = "junit", version.ref = "androidx-test-ext-junit" } diff --git a/mpcore/.gitignore b/mpcore/.gitignore new file mode 100644 index 0000000..42afabf --- /dev/null +++ b/mpcore/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/mpcore/build.gradle.kts b/mpcore/build.gradle.kts new file mode 100644 index 0000000..2146e56 --- /dev/null +++ b/mpcore/build.gradle.kts @@ -0,0 +1,55 @@ +@Suppress("DSL_SCOPE_VIOLATION") // TODO: Remove once KTIJ-19369 is fixed +plugins { + alias(libs.plugins.androidLibrary) + alias(libs.plugins.kotlinAndroid) +} + +android { + namespace = "ru.megboyzz.mpcore" + compileSdk = 33 + + defaultConfig { + minSdk = 21 + + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + consumerProguardFiles("consumer-rules.pro") + externalNativeBuild { + cmake { + cppFlags("-std=c++17") + } + } + } + + buildTypes { + release { + isMinifyEnabled = false + proguardFiles( + getDefaultProguardFile("proguard-android-optimize.txt"), + "proguard-rules.pro" + ) + } + } + externalNativeBuild { + cmake { + path("src/main/cpp/CMakeLists.txt") + version = "3.22.1" + } + } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 + } + kotlinOptions { + jvmTarget = "1.8" + } +} + +dependencies { + + implementation(libs.core.ktx) + implementation(libs.appcompat) + implementation(libs.material) + testImplementation(libs.junit) + androidTestImplementation(libs.androidx.test.ext.junit) + androidTestImplementation(libs.espresso.core) +} \ No newline at end of file diff --git a/mpcore/consumer-rules.pro b/mpcore/consumer-rules.pro new file mode 100644 index 0000000..e69de29 diff --git a/mpcore/proguard-rules.pro b/mpcore/proguard-rules.pro new file mode 100644 index 0000000..481bb43 --- /dev/null +++ b/mpcore/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/mpcore/src/androidTest/java/ru/megboyzz/mpcore/ExampleInstrumentedTest.kt b/mpcore/src/androidTest/java/ru/megboyzz/mpcore/ExampleInstrumentedTest.kt new file mode 100644 index 0000000..d79a849 --- /dev/null +++ b/mpcore/src/androidTest/java/ru/megboyzz/mpcore/ExampleInstrumentedTest.kt @@ -0,0 +1,24 @@ +package ru.megboyzz.mpcore + +import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.ext.junit.runners.AndroidJUnit4 + +import org.junit.Test +import org.junit.runner.RunWith + +import org.junit.Assert.* + +/** + * Instrumented test, which will execute on an Android device. + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +@RunWith(AndroidJUnit4::class) +class ExampleInstrumentedTest { + @Test + fun useAppContext() { + // Context of the app under test. + val appContext = InstrumentationRegistry.getInstrumentation().targetContext + assertEquals("ru.megboyzz.mpcore.test", appContext.packageName) + } +} \ No newline at end of file diff --git a/mpcore/src/main/AndroidManifest.xml b/mpcore/src/main/AndroidManifest.xml new file mode 100644 index 0000000..a5918e6 --- /dev/null +++ b/mpcore/src/main/AndroidManifest.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/mpcore/src/main/cpp/CMakeLists.txt b/mpcore/src/main/cpp/CMakeLists.txt new file mode 100644 index 0000000..f125423 --- /dev/null +++ b/mpcore/src/main/cpp/CMakeLists.txt @@ -0,0 +1,10 @@ +cmake_minimum_required(VERSION 3.22.1) + +project("mpcore") + +add_library(${CMAKE_PROJECT_NAME} SHARED + mpcore.cpp) + +target_link_libraries(${CMAKE_PROJECT_NAME} + android + log) \ No newline at end of file diff --git a/mpcore/src/main/cpp/mpcore.cpp b/mpcore/src/main/cpp/mpcore.cpp new file mode 100644 index 0000000..be67627 --- /dev/null +++ b/mpcore/src/main/cpp/mpcore.cpp @@ -0,0 +1,10 @@ +#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/java/ru/megboyzz/mpcore/NativeLib.kt b/mpcore/src/main/java/ru/megboyzz/mpcore/NativeLib.kt new file mode 100644 index 0000000..9afb60d --- /dev/null +++ b/mpcore/src/main/java/ru/megboyzz/mpcore/NativeLib.kt @@ -0,0 +1,12 @@ +package ru.megboyzz.mpcore + +class NativeLib { + + external fun stringFromJNI(): String + + companion object { + init { + System.loadLibrary("mpcore") + } + } +} \ No newline at end of file diff --git a/mpcore/src/test/java/ru/megboyzz/mpcore/ExampleUnitTest.kt b/mpcore/src/test/java/ru/megboyzz/mpcore/ExampleUnitTest.kt new file mode 100644 index 0000000..7341df8 --- /dev/null +++ b/mpcore/src/test/java/ru/megboyzz/mpcore/ExampleUnitTest.kt @@ -0,0 +1,17 @@ +package ru.megboyzz.mpcore + +import org.junit.Test + +import org.junit.Assert.* + +/** + * Example local unit test, which will execute on the development machine (host). + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +class ExampleUnitTest { + @Test + fun addition_isCorrect() { + assertEquals(4, 2 + 2) + } +} \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index 7b82154..f7ac2d7 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -23,3 +23,4 @@ rootProject.name = "NFS Most Wanted" include(":app") include(":devmenu") include(":devmenu:domain") +include(":mpcore")