add mpcore module, settings screen done

This commit is contained in:
2024-01-03 00:35:39 +04:00
parent d078c200fa
commit b093674b6e
32 changed files with 602 additions and 66 deletions
@@ -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();
+5
View File
@@ -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)
@@ -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))
}
}
@@ -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 контексте<br>
@@ -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)
)
)
fun searchFieldEnter(duration: Int) = slideInVertically(animationSpec = tween(durationMillis = duration)) {
-it / 3
}
fun searchFieldExit(duration: Int) = slideOutVertically(animationSpec = tween(durationMillis = duration)) {
-it / 3
}
@@ -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()
}
}
@@ -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(
@@ -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<String>) {
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)
}
@@ -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()
@@ -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 = {})
}
@@ -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
@@ -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
}
@@ -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}
)
}
@@ -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 = {}
)
)
)
}
)
}
)
}
}
}
@@ -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")
}
}
@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="960"
android:viewportHeight="960">
<path
android:fillColor="#FF000000"
android:pathData="M480,640 L280,440l56,-58 104,104v-326h80v326l104,-104 56,58 -200,200ZM240,800q-33,0 -56.5,-23.5T160,720v-120h80v120h480v-120h80v120q0,33 -23.5,56.5T720,800L240,800Z"/>
</vector>
+9
View File
@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="960"
android:viewportHeight="960">
<path
android:fillColor="#FF000000"
android:pathData="M160,800q-33,0 -56.5,-23.5T80,720v-480q0,-33 23.5,-56.5T160,160h240l80,80h320q33,0 56.5,23.5T880,320v400q0,33 -23.5,56.5T800,800L160,800ZM160,720h640v-400L447,320l-80,-80L160,240v480ZM160,720v-480,480Z"/>
</vector>
+9
View File
@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="960"
android:viewportHeight="960">
<path
android:fillColor="#FF000000"
android:pathData="M480,880q-82,0 -155,-31.5t-127.5,-86Q143,708 111.5,635T80,480q0,-83 31.5,-155.5t86,-127Q252,143 325,111.5T480,80q83,0 155.5,31.5t127,86q54.5,54.5 86,127T880,480q0,82 -31.5,155t-86,127.5q-54.5,54.5 -127,86T480,880ZM480,798q26,-36 45,-75t31,-83L404,640q12,44 31,83t45,75ZM376,782q-18,-33 -31.5,-68.5T322,640L204,640q29,50 72.5,87t99.5,55ZM584,782q56,-18 99.5,-55t72.5,-87L638,640q-9,38 -22.5,73.5T584,782ZM170,560h136q-3,-20 -4.5,-39.5T300,480q0,-21 1.5,-40.5T306,400L170,400q-5,20 -7.5,39.5T160,480q0,21 2.5,40.5T170,560ZM386,560h188q3,-20 4.5,-39.5T580,480q0,-21 -1.5,-40.5T574,400L386,400q-3,20 -4.5,39.5T380,480q0,21 1.5,40.5T386,560ZM654,560h136q5,-20 7.5,-39.5T800,480q0,-21 -2.5,-40.5T790,400L654,400q3,20 4.5,39.5T660,480q0,21 -1.5,40.5T654,560ZM638,320h118q-29,-50 -72.5,-87T584,178q18,33 31.5,68.5T638,320ZM404,320h152q-12,-44 -31,-83t-45,-75q-26,36 -45,75t-31,83ZM204,320h118q9,-38 22.5,-73.5T376,178q-56,18 -99.5,55T204,320Z"/>
</vector>
@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="960"
android:viewportHeight="960">
<path
android:fillColor="#FF000000"
android:pathData="M120,840v-80l80,-80v160h-80ZM280,840v-240l80,-80v320h-80ZM440,840v-320l80,81v239h-80ZM600,840v-239l80,-80v319h-80ZM760,840v-400l80,-80v480h-80ZM120,633v-113l280,-280 160,160 280,-280v113L560,513 400,353 120,633Z"/>
</vector>
+9
View File
@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="960"
android:viewportHeight="960">
<path
android:fillColor="#FF000000"
android:pathData="M440,760h80v-167l64,64 56,-57 -160,-160 -160,160 57,56 63,-63v167ZM240,880q-33,0 -56.5,-23.5T160,800v-640q0,-33 23.5,-56.5T240,80h320l240,240v480q0,33 -23.5,56.5T720,880L240,880ZM520,360v-200L240,160v640h480v-440L520,360ZM240,160v200,-200 640,-640Z"/>
</vector>
+2
View File
@@ -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" }
+1
View File
@@ -0,0 +1 @@
/build
+55
View File
@@ -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)
}
View File
+21
View File
@@ -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
@@ -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)
}
}
+4
View File
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
</manifest>
+10
View File
@@ -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)
+10
View File
@@ -0,0 +1,10 @@
#include <jni.h>
#include <string>
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());
}
@@ -0,0 +1,12 @@
package ru.megboyzz.mpcore
class NativeLib {
external fun stringFromJNI(): String
companion object {
init {
System.loadLibrary("mpcore")
}
}
}
@@ -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)
}
}
+1
View File
@@ -23,3 +23,4 @@ rootProject.name = "NFS Most Wanted"
include(":app")
include(":devmenu")
include(":devmenu:domain")
include(":mpcore")