Начало savemanager

This commit is contained in:
2025-09-05 18:38:01 +03:00
parent 8c0276c562
commit 1cd5547b04
36 changed files with 786 additions and 97 deletions
+2 -2
View File
@@ -4,10 +4,10 @@
<selectionStates> <selectionStates>
<SelectionState runConfigName="app"> <SelectionState runConfigName="app">
<option name="selectionMode" value="DROPDOWN" /> <option name="selectionMode" value="DROPDOWN" />
<DropdownSelection timestamp="2025-08-28T09:42:35.298333191Z"> <DropdownSelection timestamp="2025-08-28T12:35:54.649730307Z">
<Target type="DEFAULT_BOOT"> <Target type="DEFAULT_BOOT">
<handle> <handle>
<DeviceId pluginId="Default" identifier="serial=192.168.240.112:5555;connection=1b67fee5" /> <DeviceId pluginId="PhysicalDevice" identifier="serial=2B101JEGR07875" />
</handle> </handle>
</Target> </Target>
</DropdownSelection> </DropdownSelection>
+1
View File
@@ -12,6 +12,7 @@
<option value="$PROJECT_DIR$" /> <option value="$PROJECT_DIR$" />
<option value="$PROJECT_DIR$/app" /> <option value="$PROJECT_DIR$/app" />
<option value="$PROJECT_DIR$/mpcore" /> <option value="$PROJECT_DIR$/mpcore" />
<option value="$PROJECT_DIR$/savemanager" />
</set> </set>
</option> </option>
</GradleProjectSettings> </GradleProjectSettings>
-1
View File
@@ -1,4 +1,3 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" /> <component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="ProjectRootManager" version="2" languageLevel="JDK_21" default="true" project-jdk-name="jbr-21" project-jdk-type="JavaSDK"> <component name="ProjectRootManager" version="2" languageLevel="JDK_21" default="true" project-jdk-name="jbr-21" project-jdk-type="JavaSDK">
@@ -3,7 +3,6 @@ package com.ea.ironmonkey
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.app.ActivityManager import android.app.ActivityManager
import android.app.AlertDialog import android.app.AlertDialog
import android.content.DialogInterface
import android.content.Intent import android.content.Intent
import android.content.pm.ActivityInfo import android.content.pm.ActivityInfo
import android.content.pm.PackageManager import android.content.pm.PackageManager
@@ -11,22 +10,14 @@ import android.content.res.AssetManager
import android.content.res.Configuration import android.content.res.Configuration
import android.hardware.SensorManager import android.hardware.SensorManager
import android.media.AudioManager import android.media.AudioManager
import android.net.Uri
import android.opengl.GLES20 import android.opengl.GLES20
import android.os.Build import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.os.Environment
import android.os.Handler import android.os.Handler
import android.os.PowerManager
import android.os.PowerManager.WakeLock import android.os.PowerManager.WakeLock
import android.os.Process
import android.provider.Settings
import android.util.DisplayMetrics import android.util.DisplayMetrics
import android.view.DisplayCutout
import android.view.KeyEvent import android.view.KeyEvent
import android.view.OrientationEventListener
import android.view.View import android.view.View
import android.view.ViewParent
import android.view.WindowManager import android.view.WindowManager
import android.view.inputmethod.InputMethodManager import android.view.inputmethod.InputMethodManager
import android.widget.FrameLayout import android.widget.FrameLayout
@@ -36,17 +27,13 @@ import com.ea.EAMIO.StorageDirectory
import com.ea.ironmonkey.Log.d import com.ea.ironmonkey.Log.d
import com.ea.ironmonkey.Log.i import com.ea.ironmonkey.Log.i
import com.ea.ironmonkey.Log.setEnable import com.ea.ironmonkey.Log.setEnable
import com.ea.ironmonkey.Log.w
import com.ea.ironmonkey.ObbHelper.getObbFileName import com.ea.ironmonkey.ObbHelper.getObbFileName
import com.ea.ironmonkey.domain.AssetLocationType import com.ea.ironmonkey.domain.AssetLocationType
import com.ea.nimble.ApplicationLifecycle import com.ea.nimble.ApplicationLifecycle
import com.ea.nimble.Global import com.ea.nimble.Global
import com.google.gson.annotations.SerializedName
import nfs.mod.mpcore.MultiplayerCore.loadCore import nfs.mod.mpcore.MultiplayerCore.loadCore
import org.fmod.FMODAudioDevice import org.fmod.FMODAudioDevice
import java.io.File import java.io.File
import java.io.FileInputStream
import java.io.FileOutputStream
import java.io.IOException import java.io.IOException
import java.io.InputStream import java.io.InputStream
import java.util.Locale import java.util.Locale
@@ -152,7 +139,7 @@ class GameActivityMain : AppCompatActivity(), DrawFrameListener {
external fun nativeOnPause() external fun nativeOnPause()
external fun nativeOnPhysicalKeyDown(i: Int, i2: Int) external fun nativeOnPhysicalKeyDown(keyCode: Int, scanCode: Int)
external fun nativeOnPhysicalKeyUp(i: Int, i2: Int) external fun nativeOnPhysicalKeyUp(i: Int, i2: Int)
@@ -383,9 +370,6 @@ class GameActivityMain : AppCompatActivity(), DrawFrameListener {
i(TAG, "onPause state=$state") i(TAG, "onPause state=$state")
super.onPause() super.onPause()
mFMODAudioDevice.stop() mFMODAudioDevice.stop()
/*if (mOrientationListener.canDetectOrientation()) {
mOrientationListener.disable()
}*/
gameGLSurfaceView.onPause() gameGLSurfaceView.onPause()
ApplicationLifecycle.onActivityPause(this) ApplicationLifecycle.onActivityPause(this)
nativeOnPause() nativeOnPause()
@@ -465,23 +449,19 @@ class GameActivityMain : AppCompatActivity(), DrawFrameListener {
ApplicationLifecycle.onActivityResult(i, i2, intent, this) ApplicationLifecycle.onActivityResult(i, i2, intent, this)
} }
override fun onKeyDown(i: Int, keyEvent: KeyEvent): Boolean { override fun onKeyDown(keyCode: Int, keyEvent: KeyEvent): Boolean {
super.onKeyDown(i, keyEvent) super.onKeyDown(keyCode, keyEvent)
if (state != 8) { if (state != 8) {
return true return true
} }
if ((i == 4 || i == 108) && keyEvent.getRepeatCount() > 0) { if ((keyCode == 4 || keyCode == 108) && keyEvent.repeatCount > 0) {
return true return true
} }
val scanCode = keyEvent.getScanCode() val scanCode = keyEvent.scanCode
gameGLSurfaceView!!.queueEvent(object : Runnable { gameGLSurfaceView.queueEvent {
// from class: com.ea.ironmonkey.GameActivityMain.3 nativeOnPhysicalKeyDown(keyCode, scanCode)
// java.lang.Runnable }
override fun run() { return !IsSystemKey(keyCode)
this@GameActivityMain.nativeOnPhysicalKeyDown(i, scanCode)
}
})
return !IsSystemKey(i)
} }
override fun onKeyUp(i: Int, keyEvent: KeyEvent): Boolean { override fun onKeyUp(i: Int, keyEvent: KeyEvent): Boolean {
@@ -630,7 +610,7 @@ class GameActivityMain : AppCompatActivity(), DrawFrameListener {
override fun onDrawFrame(gl10: GL10?) { override fun onDrawFrame(gl10: GL10?) {
var inputStream: InputStream? var inputStream: InputStream?
var shouldCleanupSplash = false var shouldCleanupSplash = false
Log.d("state::game", "onDrawFrame state=$state")
// Логирование изменения состояния // Логирование изменения состояния
if (state != laststate) { if (state != laststate) {
Log.d(TAG, "onDrawFrame state=$state") Log.d(TAG, "onDrawFrame state=$state")
@@ -639,7 +619,7 @@ class GameActivityMain : AppCompatActivity(), DrawFrameListener {
when (state) { when (state) {
STATE_SPLASH -> { STATE_SPLASH -> {
splash = SplashScreen(this) //splash = SplashScreen(this)
splash.init( splash.init(
gl10, gl10,
gameRenderer.width, gameRenderer.width,
@@ -650,51 +630,14 @@ class GameActivityMain : AppCompatActivity(), DrawFrameListener {
} }
STATE_SPLASH_PROCESS -> { STATE_SPLASH_PROCESS -> {
if (splashCounter > 0) { splashTimer = System.currentTimeMillis() + 2000
splashCounter-- state = STATE_GAME_START
} else {
splashTimer = System.currentTimeMillis() + 2500
if (!isAssetsReady) {
inputStream = try {
assets.open(DOWNLOAD_PROPERTIES)
} catch (e: Exception) {
null
}
if (inputStream != null) {
handler!!.postDelayed({ }, 20L)
Log.i(TAG, "state ADC start")
state = STATE_ADC_START
} else {
Log.i(TAG, "STATE_GAME_START 1")
state = STATE_GAME_START
}
} else {
Log.i(TAG, "STATE_GAME_START 2")
state = STATE_GAME_START
}
}
}
STATE_ADC_START -> {
Log.i(TAG, "ADC start")
// Здесь должен быть код для обработки ADC start
// state = ... // переходим в следующее состояние
} }
STATE_RESTORE_CONTEXT -> { STATE_RESTORE_CONTEXT -> {
if (splash == null) {
splash = SplashScreen(this)
splash!!.init(
gl10,
gameRenderer!!.width,
gameRenderer!!.height
)
splashDelay = System.currentTimeMillis() + 2000
}
if (splashDelay < System.currentTimeMillis() && hasWindowFocus()) { if (splashDelay < System.currentTimeMillis() && hasWindowFocus()) {
state = if (oldState == STATE_GAME_START) { state = if (oldState == STATE_GAME_START) {
splashTimer = System.currentTimeMillis() + 300 splashTimer = System.currentTimeMillis() + 2000
STATE_GAME_START STATE_GAME_START
} else { } else {
oldState oldState
@@ -707,32 +650,15 @@ class GameActivityMain : AppCompatActivity(), DrawFrameListener {
isAssetsReady = true isAssetsReady = true
nativeOnStart() nativeOnStart()
nativeOnResume() nativeOnResume()
gameRenderer!!.setDrawFrameListener(null) gameRenderer.setDrawFrameListener(null)
shouldCleanupSplash = true shouldCleanupSplash = true
} }
} }
// Добавляем обработку остальных состояний
STATE_GOOGLE_DRM -> {
// Обработка Google DRM
}
STATE_ADC_PROCESS -> {
// Обработка ADC процесса
}
STATE_FULL_START -> {
// Обработка Full start
}
STATE_FULL_PROCESS -> {
// Обработка Full процесса
}
} }
// Очистка экрана // Очистка экрана
GLES20.glClearColor(1.0f, 1.0f, 1.0f, 1.0f) GLES20.glClearColor(1.0f, 0.0f, 0.0f, 1.0f)
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT or GLES20.GL_DEPTH_BUFFER_BIT) //GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT or GLES20.GL_DEPTH_BUFFER_BIT)
// Отрисовка сплеш-скрина если он существует // Отрисовка сплеш-скрина если он существует
splash.draw( splash.draw(
@@ -742,9 +668,9 @@ class GameActivityMain : AppCompatActivity(), DrawFrameListener {
) )
// Очистка сплеш-скрина если нужно // Очистка сплеш-скрина если нужно
if (shouldCleanupSplash) { /*if (shouldCleanupSplash) {
splash.destroy(gl10) splash.destroy(gl10)
} }*/
} }
val totalMemory: Int val totalMemory: Int
@@ -48,7 +48,7 @@ class SplashScreen(private val activity: Activity) {
private var textureId = IntArray(1) private var textureId = IntArray(1)
fun init(gl10: GL10?, width: Int, height: Int) { fun init(gl10: GL10?, width: Int, height: Int) {
Log.i("splash", "Я родился!") Log.i(TAG, "init")
if (!initRenderer()) { if (!initRenderer()) {
destroy(gl10) destroy(gl10)
return return
@@ -236,6 +236,7 @@ class SplashScreen(private val activity: Activity) {
} }
fun destroy(gl10: GL10?) { fun destroy(gl10: GL10?) {
Log.i(TAG, "destroy!")
if (textureId[0] != 0) { if (textureId[0] != 0) {
GLES20.glDeleteTextures(1, textureId, 0) GLES20.glDeleteTextures(1, textureId, 0)
textureId[0] = 0 textureId[0] = 0
+1
View File
@@ -3,4 +3,5 @@ plugins {
alias(libs.plugins.android.application) apply false alias(libs.plugins.android.application) apply false
alias(libs.plugins.kotlin.android) apply false alias(libs.plugins.kotlin.android) apply false
alias(libs.plugins.android.library) apply false alias(libs.plugins.android.library) apply false
alias(libs.plugins.kotlin.compose) apply false
} }
+14
View File
@@ -7,6 +7,9 @@ junitVersion = "1.2.1"
espressoCore = "3.6.1" espressoCore = "3.6.1"
appcompat = "1.7.0" appcompat = "1.7.0"
material = "1.12.0" material = "1.12.0"
lifecycleRuntimeKtx = "2.6.1"
activityCompose = "1.8.0"
composeBom = "2024.09.00"
[libraries] [libraries]
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" } androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
@@ -15,9 +18,20 @@ androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "j
androidx-espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" } androidx-espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" }
androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" } androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" }
material = { group = "com.google.android.material", name = "material", version.ref = "material" } material = { group = "com.google.android.material", name = "material", version.ref = "material" }
androidx-lifecycle-runtime-ktx = { group = "androidx.lifecycle", name = "lifecycle-runtime-ktx", version.ref = "lifecycleRuntimeKtx" }
androidx-activity-compose = { group = "androidx.activity", name = "activity-compose", version.ref = "activityCompose" }
androidx-compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "composeBom" }
androidx-ui = { group = "androidx.compose.ui", name = "ui" }
androidx-ui-graphics = { group = "androidx.compose.ui", name = "ui-graphics" }
androidx-ui-tooling = { group = "androidx.compose.ui", name = "ui-tooling" }
androidx-ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-tooling-preview" }
androidx-ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-manifest" }
androidx-ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-test-junit4" }
androidx-material3 = { group = "androidx.compose.material3", name = "material3" }
[plugins] [plugins]
android-application = { id = "com.android.application", version.ref = "agp" } android-application = { id = "com.android.application", version.ref = "agp" }
android-library = { id = "com.android.library", version.ref = "agp" } android-library = { id = "com.android.library", version.ref = "agp" }
kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
kotlin-compose = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
+244
View File
@@ -68,6 +68,250 @@ bool is_memory_writable(void* addr, size_t size) {
return mprotect((void*)page_start, size, PROT_READ | PROT_WRITE | PROT_EXEC) == 0; return mprotect((void*)page_start, size, PROT_READ | PROT_WRITE | PROT_EXEC) == 0;
} }
#include <iostream>
#include <string>
using namespace std;
// Базовый класс - Животное
class Animal {
protected:
string name;
int age;
public:
// Конструктор
Animal(const string& name, int age) : name(name), age(age) {
cout << "Animal constructor: " << name << endl;
}
// Виртуальный деструктор
virtual ~Animal() {
cout << "Animal destructor: " << name << endl;
}
// Виртуальный метод (будет переопределяться)
virtual void makeSound() const {
cout << name << " makes a generic animal sound" << endl;
}
// Не виртуальный метод (не будет переопределяться)
void sleep() const {
cout << name << " is sleeping" << endl;
}
string getName() const { return name; }
int getAge() const { return age; }
};
// Производный класс - Млекопитающее
class Mammal : public Animal {
protected:
bool hasFur;
public:
// Конструктор
Mammal(const string& name, int age, bool hasFur)
: Animal(name, age), hasFur(hasFur) {
cout << "Mammal constructor: " << name << endl;
}
// Деструктор
~Mammal() override {
cout << "Mammal destructor: " << name << endl;
}
// Переопределение метода
void makeSound() const override {
cout << name << " makes a mammal sound" << endl;
}
// Новый метод
void feedMilk() const {
cout << name << " is feeding milk" << endl;
}
};
// Производный класс - Птица
class Bird : public Animal {
protected:
double wingspan;
public:
// Конструктор
Bird(const string& name, int age, double wingspan)
: Animal(name, age), wingspan(wingspan) {
cout << "Bird constructor: " << name << endl;
}
// Деструктор
~Bird() override {
cout << "Bird destructor: " << name << endl;
}
// Переопределение метода
void makeSound() const override {
cout << name << " chirps" << endl;
}
// Новый метод
void fly() const {
cout << name << " is flying with wingspan " << wingspan << "m" << endl;
}
};
// Производный класс от Млекопитающего - Собака
class Dog : public Mammal {
private:
string breed;
public:
// Конструктор
Dog(const string& name, int age, bool hasFur, const string& breed)
: Mammal(name, age, hasFur), breed(breed) {
cout << "Dog constructor: " << name << endl;
}
// Деструктор
~Dog() override {
cout << "Dog destructor: " << name << endl;
}
// Переопределение метода
void makeSound() const override {
cout << name << " barks: Woof! Woof!" << endl;
}
// Новый метод
void fetch() const {
cout << name << " is fetching the ball" << endl;
}
};
// Производный класс от Млекопитающего - Кошка
class Cat : public Mammal {
private:
int lives;
public:
// Конструктор
Cat(const string& name, int age, bool hasFur, int lives = 9)
: Mammal(name, age, hasFur), lives(lives) {
cout << "Cat constructor: " << name << endl;
}
// Деструктор
~Cat() override {
cout << "Cat destructor: " << name << endl;
}
// Переопределение метода
void makeSound() const override {
cout << name << " meows: Meow! Meow!" << endl;
}
// Новый метод
void purr() const {
cout << name << " is purring" << endl;
}
};
// Производный класс от Птицы - Орел
class Eagle : public Bird {
private:
double visionRange;
public:
// Конструктор
Eagle(const string& name, int age, double wingspan, double visionRange)
: Bird(name, age, wingspan), visionRange(visionRange) {
cout << "Eagle constructor: " << name << endl;
}
// Деструктор
~Eagle() override {
cout << "Eagle destructor: " << name << endl;
}
// Метод НЕ переопределяется (используется версия из Bird)
// void makeSound() const override {...}
// Новый метод
void hunt() const {
cout << name << " is hunting with vision range " << visionRange << "km" << endl;
}
};
// Производный класс от Птицы - Попугай
class Parrot : public Bird {
private:
bool canTalk;
public:
// Конструктор
Parrot(const string& name, int age, double wingspan, bool canTalk)
: Bird(name, age, wingspan), canTalk(canTalk) {
cout << "Parrot constructor: " << name << endl;
}
// Деструктор
~Parrot() override {
cout << "Parrot destructor: " << name << endl;
}
// Переопределение метода
void makeSound() const override {
if (canTalk) {
cout << name << " says: Hello! Polly wants a cracker!" << endl;
} else {
cout << name << " squawks" << endl;
}
}
// Новый метод
void repeat(const string& phrase) const {
if (canTalk) {
cout << name << " repeats: " << phrase << endl;
}
}
};
// Пример использования
int main() {
cout << "=== Creating objects ===" << endl;
Dog dog("Rex", 3, true, "German Shepherd");
Cat cat("Whiskers", 2, true);
Eagle eagle("Thor", 5, 2.1, 3.5);
Parrot parrot("Polly", 1, 0.3, true);
cout << "\n=== Testing methods ===" << endl;
dog.makeSound(); // Переопределен в Dog
dog.fetch(); // Уникальный метод Dog
cat.makeSound(); // Переопределен в Cat
cat.purr(); // Уникальный метод Cat
eagle.makeSound(); // НЕ переопределен - использует версию Bird
eagle.hunt(); // Уникальный метод Eagle
parrot.makeSound(); // Переопределен в Parrot
parrot.repeat("I love C++"); // Уникальный метод Parrot
cout << "\n=== Testing polymorphism ===" << endl;
Animal* animals[] = {&dog, &cat, &eagle, &parrot};
for (Animal* animal : animals) {
animal->makeSound(); // Полиморфный вызов
animal->sleep(); // Не виртуальный метод - всегда Animal::sleep()
}
cout << "\n=== Objects going out of scope ===" << endl;
// Деструкторы будут вызваны автоматически
return 0;
}
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) { JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) {
get_libapp_base(); get_libapp_base();
+1
View File
@@ -0,0 +1 @@
/build
+59
View File
@@ -0,0 +1,59 @@
plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.kotlin.android)
alias(libs.plugins.kotlin.compose)
}
android {
namespace = "ru.megboyzz.nfsmw.save.manager"
compileSdk = 35
defaultConfig {
applicationId = "ru.megboyzz.nfsmw.save.manager"
minSdk = 24
targetSdk = 35
versionCode = 1
versionName = "1.0"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
isMinifyEnabled = false
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
kotlinOptions {
jvmTarget = "11"
}
buildFeatures {
compose = true
}
}
dependencies {
implementation(libs.androidx.core.ktx)
implementation(libs.androidx.lifecycle.runtime.ktx)
implementation(libs.androidx.activity.compose)
implementation(platform(libs.androidx.compose.bom))
implementation(libs.androidx.ui)
implementation(libs.androidx.ui.graphics)
implementation(libs.androidx.ui.tooling.preview)
implementation(libs.androidx.material3)
testImplementation(libs.junit)
androidTestImplementation(libs.androidx.junit)
androidTestImplementation(libs.androidx.espresso.core)
androidTestImplementation(platform(libs.androidx.compose.bom))
androidTestImplementation(libs.androidx.ui.test.junit4)
debugImplementation(libs.androidx.ui.tooling)
debugImplementation(libs.androidx.ui.test.manifest)
}
+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.nfsmw.save.manager
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.nfsmw.save.manager", appContext.packageName)
}
}
+24
View File
@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.NFSMostWanted">
<activity
android:name=".MainActivity"
android:exported="true"
android:label="@string/app_name"
android:theme="@style/Theme.NFSMostWanted">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
@@ -0,0 +1,23 @@
package ru.megboyzz.nfsmw.save.manager
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import ru.megboyzz.nfsmw.save.manager.ui.theme.NFSMostWantedTheme
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContent {
}
}
}
@@ -0,0 +1,11 @@
package ru.megboyzz.nfsmw.save.manager.ui.theme
import androidx.compose.ui.graphics.Color
val Purple80 = Color(0xFFD0BCFF)
val PurpleGrey80 = Color(0xFFCCC2DC)
val Pink80 = Color(0xFFEFB8C8)
val Purple40 = Color(0xFF6650a4)
val PurpleGrey40 = Color(0xFF625b71)
val Pink40 = Color(0xFF7D5260)
@@ -0,0 +1,58 @@
package ru.megboyzz.nfsmw.save.manager.ui.theme
import android.app.Activity
import android.os.Build
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.darkColorScheme
import androidx.compose.material3.dynamicDarkColorScheme
import androidx.compose.material3.dynamicLightColorScheme
import androidx.compose.material3.lightColorScheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.platform.LocalContext
private val DarkColorScheme = darkColorScheme(
primary = Purple80,
secondary = PurpleGrey80,
tertiary = Pink80
)
private val LightColorScheme = lightColorScheme(
primary = Purple40,
secondary = PurpleGrey40,
tertiary = Pink40
/* Other default colors to override
background = Color(0xFFFFFBFE),
surface = Color(0xFFFFFBFE),
onPrimary = Color.White,
onSecondary = Color.White,
onTertiary = Color.White,
onBackground = Color(0xFF1C1B1F),
onSurface = Color(0xFF1C1B1F),
*/
)
@Composable
fun NFSMostWantedTheme(
darkTheme: Boolean = isSystemInDarkTheme(),
// Dynamic color is available on Android 12+
dynamicColor: Boolean = true,
content: @Composable () -> Unit
) {
val colorScheme = when {
dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
val context = LocalContext.current
if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context)
}
darkTheme -> DarkColorScheme
else -> LightColorScheme
}
MaterialTheme(
colorScheme = colorScheme,
typography = Typography,
content = content
)
}
@@ -0,0 +1,34 @@
package ru.megboyzz.nfsmw.save.manager.ui.theme
import androidx.compose.material3.Typography
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.sp
// Set of Material typography styles to start with
val Typography = Typography(
bodyLarge = TextStyle(
fontFamily = FontFamily.Default,
fontWeight = FontWeight.Normal,
fontSize = 16.sp,
lineHeight = 24.sp,
letterSpacing = 0.5.sp
)
/* Other default text styles to override
titleLarge = TextStyle(
fontFamily = FontFamily.Default,
fontWeight = FontWeight.Normal,
fontSize = 22.sp,
lineHeight = 28.sp,
letterSpacing = 0.sp
),
labelSmall = TextStyle(
fontFamily = FontFamily.Default,
fontWeight = FontWeight.Medium,
fontSize = 11.sp,
lineHeight = 16.sp,
letterSpacing = 0.5.sp
)
*/
)
@@ -0,0 +1,170 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path
android:fillColor="#3DDC84"
android:pathData="M0,0h108v108h-108z" />
<path
android:fillColor="#00000000"
android:pathData="M9,0L9,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,0L19,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,0L29,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,0L39,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,0L49,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,0L59,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,0L69,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,0L79,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M89,0L89,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M99,0L99,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,9L108,9"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,19L108,19"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,29L108,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,39L108,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,49L108,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,59L108,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,69L108,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,79L108,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,89L108,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,99L108,99"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,29L89,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,39L89,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,49L89,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,59L89,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,69L89,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,79L89,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,19L29,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,19L39,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,19L49,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,19L59,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,19L69,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,19L79,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
</vector>
@@ -0,0 +1,30 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z">
<aapt:attr name="android:fillColor">
<gradient
android:endX="85.84757"
android:endY="92.4963"
android:startX="42.9492"
android:startY="49.59793"
android:type="linear">
<item
android:color="#44000000"
android:offset="0.0" />
<item
android:color="#00000000"
android:offset="1.0" />
</gradient>
</aapt:attr>
</path>
<path
android:fillColor="#FFFFFF"
android:fillType="nonZero"
android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
android:strokeWidth="1"
android:strokeColor="#00000000" />
</vector>
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background" />
<foreground android:drawable="@drawable/ic_launcher_foreground" />
<monochrome android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon>
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background" />
<foreground android:drawable="@drawable/ic_launcher_foreground" />
<monochrome android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon>
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 982 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="purple_200">#FFBB86FC</color>
<color name="purple_500">#FF6200EE</color>
<color name="purple_700">#FF3700B3</color>
<color name="teal_200">#FF03DAC5</color>
<color name="teal_700">#FF018786</color>
<color name="black">#FF000000</color>
<color name="white">#FFFFFFFF</color>
</resources>
@@ -0,0 +1,3 @@
<resources>
<string name="app_name">NFSMW SaveManager</string>
</resources>
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="Theme.NFSMostWanted" parent="android:Theme.Material.Light.NoActionBar" />
</resources>
@@ -0,0 +1,17 @@
package ru.megboyzz.nfsmw.save.manager
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
@@ -22,3 +22,4 @@ dependencyResolutionManagement {
rootProject.name = "NFS Most Wanted" rootProject.name = "NFS Most Wanted"
include(":app") include(":app")
include(":mpcore") include(":mpcore")
include(":savemanager")