diff --git a/devmenu/.gitignore b/devmenu/.gitignore
new file mode 100644
index 0000000..42afabf
--- /dev/null
+++ b/devmenu/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/devmenu/build.gradle.kts b/devmenu/build.gradle.kts
new file mode 100644
index 0000000..6be7607
--- /dev/null
+++ b/devmenu/build.gradle.kts
@@ -0,0 +1,69 @@
+@Suppress("DSL_SCOPE_VIOLATION") // TODO: Remove once KTIJ-19369 is fixed
+plugins {
+ alias(libs.plugins.androidLibrary)
+ alias(libs.plugins.kotlinAndroid)
+}
+
+android {
+ namespace = "com.megboyzz.devmenu"
+ compileSdk = 34
+
+ defaultConfig {
+ minSdk = 21
+
+ testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
+ consumerProguardFiles("consumer-rules.pro")
+ vectorDrawables {
+ useSupportLibrary = true
+ }
+ }
+
+ buildTypes {
+ release {
+ isMinifyEnabled = false
+ proguardFiles(
+ getDefaultProguardFile("proguard-android-optimize.txt"),
+ "proguard-rules.pro"
+ )
+ }
+ }
+ compileOptions {
+ sourceCompatibility = JavaVersion.VERSION_1_8
+ targetCompatibility = JavaVersion.VERSION_1_8
+ }
+ kotlinOptions {
+ jvmTarget = "1.8"
+ }
+ buildFeatures {
+ compose = true
+ }
+ composeOptions {
+ kotlinCompilerExtensionVersion = "1.5.1"
+ }
+ packaging {
+ resources {
+ excludes += "/META-INF/{AL2.0,LGPL2.1}"
+ }
+ }
+}
+
+dependencies {
+
+ implementation(libs.core.ktx)
+ implementation(libs.appcompat)
+ implementation(libs.material)
+ implementation(libs.lifecycle.runtime.ktx)
+ implementation(libs.activity.compose)
+ implementation(platform(libs.compose.bom))
+ implementation(libs.ui)
+ implementation(libs.ui.graphics)
+ implementation(libs.ui.tooling.preview)
+ implementation(libs.material3)
+ testImplementation(libs.junit)
+ androidTestImplementation(libs.androidx.test.ext.junit)
+ androidTestImplementation(libs.espresso.core)
+ androidTestImplementation(platform(libs.compose.bom))
+ androidTestImplementation(libs.ui.test.junit4)
+ debugImplementation(libs.ui.tooling)
+ debugImplementation(libs.ui.test.manifest)
+}
\ No newline at end of file
diff --git a/devmenu/consumer-rules.pro b/devmenu/consumer-rules.pro
new file mode 100644
index 0000000..e69de29
diff --git a/devmenu/data/.gitignore b/devmenu/data/.gitignore
new file mode 100644
index 0000000..42afabf
--- /dev/null
+++ b/devmenu/data/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/devmenu/data/build.gradle.kts b/devmenu/data/build.gradle.kts
new file mode 100644
index 0000000..6ab1e4a
--- /dev/null
+++ b/devmenu/data/build.gradle.kts
@@ -0,0 +1,44 @@
+@Suppress("DSL_SCOPE_VIOLATION") // TODO: Remove once KTIJ-19369 is fixed
+plugins {
+ alias(libs.plugins.androidLibrary)
+ alias(libs.plugins.kotlinAndroid)
+}
+
+android {
+ namespace = "com.megboyzz.devmenu.data"
+ compileSdk = 34
+
+ defaultConfig {
+ minSdk = 21
+
+ testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
+ consumerProguardFiles("consumer-rules.pro")
+ }
+
+ buildTypes {
+ release {
+ isMinifyEnabled = false
+ proguardFiles(
+ getDefaultProguardFile("proguard-android-optimize.txt"),
+ "proguard-rules.pro"
+ )
+ }
+ }
+ 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/devmenu/data/consumer-rules.pro b/devmenu/data/consumer-rules.pro
new file mode 100644
index 0000000..e69de29
diff --git a/devmenu/data/proguard-rules.pro b/devmenu/data/proguard-rules.pro
new file mode 100644
index 0000000..481bb43
--- /dev/null
+++ b/devmenu/data/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/devmenu/data/src/androidTest/java/com/megboyzz/devmenu/data/ExampleInstrumentedTest.kt b/devmenu/data/src/androidTest/java/com/megboyzz/devmenu/data/ExampleInstrumentedTest.kt
new file mode 100644
index 0000000..a757b3d
--- /dev/null
+++ b/devmenu/data/src/androidTest/java/com/megboyzz/devmenu/data/ExampleInstrumentedTest.kt
@@ -0,0 +1,24 @@
+package com.megboyzz.devmenu.data
+
+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("com.megboyzz.devmenu.data.test", appContext.packageName)
+ }
+}
\ No newline at end of file
diff --git a/devmenu/data/src/main/AndroidManifest.xml b/devmenu/data/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..a5918e6
--- /dev/null
+++ b/devmenu/data/src/main/AndroidManifest.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/devmenu/data/src/main/java/com/megboyzz/devmenu/data/util/SaveFileObserver.kt b/devmenu/data/src/main/java/com/megboyzz/devmenu/data/util/SaveFileObserver.kt
new file mode 100644
index 0000000..50c24ab
--- /dev/null
+++ b/devmenu/data/src/main/java/com/megboyzz/devmenu/data/util/SaveFileObserver.kt
@@ -0,0 +1,22 @@
+package com.megboyzz.devmenu.data.util
+
+import android.os.FileObserver
+import android.util.Log
+import java.io.File
+
+
+class SaveFileObserver(
+ private val source: File,
+ private val destinationFolder: File
+) : FileObserver(source.absolutePath) {
+
+ override fun onEvent(event: Int, path: String?) {
+ if (event and CREATE != 0 || event and MODIFY != 0) {
+ Log.d("FileObserver", "File created or modified: $source")
+ source copyToThe destinationFolder
+ }
+ }
+
+ private infix fun File.copyToThe(destination: File) = this.copyTo(destination)
+}
+
diff --git a/devmenu/data/src/test/java/com/megboyzz/devmenu/data/ExampleUnitTest.kt b/devmenu/data/src/test/java/com/megboyzz/devmenu/data/ExampleUnitTest.kt
new file mode 100644
index 0000000..5b4be67
--- /dev/null
+++ b/devmenu/data/src/test/java/com/megboyzz/devmenu/data/ExampleUnitTest.kt
@@ -0,0 +1,17 @@
+package com.megboyzz.devmenu.data
+
+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/devmenu/domain/.gitignore b/devmenu/domain/.gitignore
new file mode 100644
index 0000000..42afabf
--- /dev/null
+++ b/devmenu/domain/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/devmenu/domain/build.gradle.kts b/devmenu/domain/build.gradle.kts
new file mode 100644
index 0000000..5c30334
--- /dev/null
+++ b/devmenu/domain/build.gradle.kts
@@ -0,0 +1,22 @@
+plugins {
+ id("java-library")
+ alias(libs.plugins.org.jetbrains.kotlin.jvm)
+}
+
+java {
+ sourceCompatibility = JavaVersion.VERSION_17
+ targetCompatibility = JavaVersion.VERSION_17
+}
+
+dependencies {
+ implementation("javax.inject:javax.inject:1")
+ testImplementation("junit:junit:4.13.2")
+ testImplementation("org.mockito:mockito-core:3.12.4")
+ testImplementation("org.mockito.kotlin:mockito-kotlin:3.12.4")
+}
+
+sourceSets {
+ test {
+ java.srcDir("src/test/java") // Путь к исходным файлам тестов на Kotlin
+ }
+}
\ No newline at end of file
diff --git a/devmenu/domain/src/main/java/com/megboyzz/devmenu/domain/entities/Constants.kt b/devmenu/domain/src/main/java/com/megboyzz/devmenu/domain/entities/Constants.kt
new file mode 100644
index 0000000..e1902e1
--- /dev/null
+++ b/devmenu/domain/src/main/java/com/megboyzz/devmenu/domain/entities/Constants.kt
@@ -0,0 +1,3 @@
+package com.megboyzz.devmenu.domain.entities
+
+val devmenuId = "DevMenu"
\ No newline at end of file
diff --git a/devmenu/domain/src/main/java/com/megboyzz/devmenu/domain/entities/FileProps.kt b/devmenu/domain/src/main/java/com/megboyzz/devmenu/domain/entities/FileProps.kt
new file mode 100644
index 0000000..2141304
--- /dev/null
+++ b/devmenu/domain/src/main/java/com/megboyzz/devmenu/domain/entities/FileProps.kt
@@ -0,0 +1,9 @@
+package com.megboyzz.devmenu.domain.entities
+
+import java.util.Date
+
+data class FileProps(
+ val fileName: String,
+ val size: Int,
+ val dateOfCreation: Date
+)
diff --git a/devmenu/domain/src/main/java/com/megboyzz/devmenu/domain/entities/GameLang.kt b/devmenu/domain/src/main/java/com/megboyzz/devmenu/domain/entities/GameLang.kt
new file mode 100644
index 0000000..be09998
--- /dev/null
+++ b/devmenu/domain/src/main/java/com/megboyzz/devmenu/domain/entities/GameLang.kt
@@ -0,0 +1,19 @@
+package com.megboyzz.devmenu.domain.entities
+
+enum class GameLang(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/domain/src/main/java/com/megboyzz/devmenu/domain/entities/Settings.kt b/devmenu/domain/src/main/java/com/megboyzz/devmenu/domain/entities/Settings.kt
new file mode 100644
index 0000000..4a24b89
--- /dev/null
+++ b/devmenu/domain/src/main/java/com/megboyzz/devmenu/domain/entities/Settings.kt
@@ -0,0 +1,8 @@
+package com.megboyzz.devmenu.domain.entities
+
+data class Settings(
+ val enable: Boolean,
+ val trackingInterval: Int,
+ val pathToSaveTrackable: String,
+ val lang: GameLang
+)
diff --git a/devmenu/domain/src/main/java/com/megboyzz/devmenu/domain/entities/SvmwProps.kt b/devmenu/domain/src/main/java/com/megboyzz/devmenu/domain/entities/SvmwProps.kt
new file mode 100644
index 0000000..61866ec
--- /dev/null
+++ b/devmenu/domain/src/main/java/com/megboyzz/devmenu/domain/entities/SvmwProps.kt
@@ -0,0 +1,8 @@
+package com.megboyzz.devmenu.domain.entities
+
+import java.util.Date
+
+data class SvmwProps(
+ val description: String,
+ val date: Date
+)
diff --git a/devmenu/domain/src/main/java/com/megboyzz/devmenu/domain/repository/FilesRepository.kt b/devmenu/domain/src/main/java/com/megboyzz/devmenu/domain/repository/FilesRepository.kt
new file mode 100644
index 0000000..e120983
--- /dev/null
+++ b/devmenu/domain/src/main/java/com/megboyzz/devmenu/domain/repository/FilesRepository.kt
@@ -0,0 +1,14 @@
+package com.megboyzz.devmenu.domain.repository
+
+import com.megboyzz.devmenu.domain.entities.FileProps
+import java.io.File
+
+interface FilesRepository {
+
+ val internalRoot: File
+
+ val externalRoot: File
+
+ fun getFileProps(file: File): FileProps
+
+}
\ No newline at end of file
diff --git a/devmenu/domain/src/main/java/com/megboyzz/devmenu/domain/repository/ReplacementRepository.kt b/devmenu/domain/src/main/java/com/megboyzz/devmenu/domain/repository/ReplacementRepository.kt
new file mode 100644
index 0000000..bbcb249
--- /dev/null
+++ b/devmenu/domain/src/main/java/com/megboyzz/devmenu/domain/repository/ReplacementRepository.kt
@@ -0,0 +1,13 @@
+package com.megboyzz.devmenu.domain.repository
+
+import java.io.File
+
+interface ReplacementRepository {
+
+ suspend fun replaceFile(what: File, to: File): Result
+
+ suspend fun recoverReplacement(replacement: File): Result
+
+ suspend fun getAllReplacements(): List
+
+}
\ No newline at end of file
diff --git a/devmenu/domain/src/main/java/com/megboyzz/devmenu/domain/repository/SaveRepository.kt b/devmenu/domain/src/main/java/com/megboyzz/devmenu/domain/repository/SaveRepository.kt
new file mode 100644
index 0000000..1eec314
--- /dev/null
+++ b/devmenu/domain/src/main/java/com/megboyzz/devmenu/domain/repository/SaveRepository.kt
@@ -0,0 +1,11 @@
+package com.megboyzz.devmenu.domain.repository
+
+import java.io.File
+
+interface SaveRepository {
+
+ suspend fun loadSaveFile(file: File): Boolean
+
+ suspend fun uploadCurrentSaveFile(fileToUpload: File): Boolean
+
+}
\ No newline at end of file
diff --git a/devmenu/domain/src/main/java/com/megboyzz/devmenu/domain/repository/SettingsRepository.kt b/devmenu/domain/src/main/java/com/megboyzz/devmenu/domain/repository/SettingsRepository.kt
new file mode 100644
index 0000000..564f354
--- /dev/null
+++ b/devmenu/domain/src/main/java/com/megboyzz/devmenu/domain/repository/SettingsRepository.kt
@@ -0,0 +1,11 @@
+package com.megboyzz.devmenu.domain.repository
+
+import com.megboyzz.devmenu.domain.entities.Settings
+
+interface SettingsRepository {
+
+ suspend fun getSettings(): Settings
+
+ suspend fun setSettings(settings: Settings)
+
+}
\ No newline at end of file
diff --git a/devmenu/domain/src/main/java/com/megboyzz/devmenu/domain/repository/SvmwRepository.kt b/devmenu/domain/src/main/java/com/megboyzz/devmenu/domain/repository/SvmwRepository.kt
new file mode 100644
index 0000000..6049243
--- /dev/null
+++ b/devmenu/domain/src/main/java/com/megboyzz/devmenu/domain/repository/SvmwRepository.kt
@@ -0,0 +1,20 @@
+package com.megboyzz.devmenu.domain.repository
+
+import com.megboyzz.devmenu.domain.entities.SvmwProps
+import java.io.File
+
+interface SvmwRepository {
+
+ suspend fun createSvmwFromCurrentSaveFileAndSetIt(): Boolean
+
+ suspend fun createSvmwFromCurrentSaveFile(fileToSave: File): Boolean
+
+ suspend fun createSvmw(fileToSave: File, saveFile: File): Boolean
+
+ suspend fun loadSvmw(svmw: File): Boolean
+
+ suspend fun getInfoAboutSvmw(svmw: File): SvmwProps?
+
+ suspend fun getInfoAboutLoadedSvmw(): SvmwProps?
+
+}
\ No newline at end of file
diff --git a/devmenu/domain/src/main/java/com/megboyzz/devmenu/domain/usecases/files/GetExternalFilesUseCase.kt b/devmenu/domain/src/main/java/com/megboyzz/devmenu/domain/usecases/files/GetExternalFilesUseCase.kt
new file mode 100644
index 0000000..d95d575
--- /dev/null
+++ b/devmenu/domain/src/main/java/com/megboyzz/devmenu/domain/usecases/files/GetExternalFilesUseCase.kt
@@ -0,0 +1,11 @@
+package com.megboyzz.devmenu.domain.usecases.files
+
+import com.megboyzz.devmenu.domain.repository.FilesRepository
+import java.io.File
+import javax.inject.Inject
+
+class GetExternalFilesUseCase @Inject constructor(
+ private val filesRepository: FilesRepository
+) {
+ operator fun invoke(childPath: String = ""): File = File(filesRepository.externalRoot, childPath)
+}
\ No newline at end of file
diff --git a/devmenu/domain/src/main/java/com/megboyzz/devmenu/domain/usecases/files/GetFilePropsUseCase.kt b/devmenu/domain/src/main/java/com/megboyzz/devmenu/domain/usecases/files/GetFilePropsUseCase.kt
new file mode 100644
index 0000000..0a40b80
--- /dev/null
+++ b/devmenu/domain/src/main/java/com/megboyzz/devmenu/domain/usecases/files/GetFilePropsUseCase.kt
@@ -0,0 +1,12 @@
+package com.megboyzz.devmenu.domain.usecases.files
+
+import com.megboyzz.devmenu.domain.entities.FileProps
+import com.megboyzz.devmenu.domain.repository.FilesRepository
+import java.io.File
+import javax.inject.Inject
+
+class GetFilePropsUseCase @Inject constructor(
+ private val filesRepository: FilesRepository
+) {
+ operator fun invoke(file: File): FileProps = filesRepository.getFileProps(file)
+}
\ No newline at end of file
diff --git a/devmenu/domain/src/main/java/com/megboyzz/devmenu/domain/usecases/files/GetInternalFilesUseCase.kt b/devmenu/domain/src/main/java/com/megboyzz/devmenu/domain/usecases/files/GetInternalFilesUseCase.kt
new file mode 100644
index 0000000..24c985f
--- /dev/null
+++ b/devmenu/domain/src/main/java/com/megboyzz/devmenu/domain/usecases/files/GetInternalFilesUseCase.kt
@@ -0,0 +1,13 @@
+package com.megboyzz.devmenu.domain.usecases.files
+
+import com.megboyzz.devmenu.domain.repository.FilesRepository
+import java.io.File
+import javax.inject.Inject
+
+class GetInternalFilesUseCase @Inject constructor(
+ private val filesRepository: FilesRepository
+) {
+
+ operator fun invoke(childPath: String = ""): File = File(filesRepository.internalRoot, childPath)
+
+}
\ No newline at end of file
diff --git a/devmenu/domain/src/main/java/com/megboyzz/devmenu/domain/usecases/files/RemoveFileUseCase.kt b/devmenu/domain/src/main/java/com/megboyzz/devmenu/domain/usecases/files/RemoveFileUseCase.kt
new file mode 100644
index 0000000..2dd61b7
--- /dev/null
+++ b/devmenu/domain/src/main/java/com/megboyzz/devmenu/domain/usecases/files/RemoveFileUseCase.kt
@@ -0,0 +1,7 @@
+package com.megboyzz.devmenu.domain.usecases.files
+
+import java.io.File
+
+class RemoveFileUseCase {
+ operator fun invoke(file: File): Boolean = file.delete()
+}
\ No newline at end of file
diff --git a/devmenu/domain/src/main/java/com/megboyzz/devmenu/domain/usecases/files/RemoveInternalDataUseCase.kt b/devmenu/domain/src/main/java/com/megboyzz/devmenu/domain/usecases/files/RemoveInternalDataUseCase.kt
new file mode 100644
index 0000000..d336489
--- /dev/null
+++ b/devmenu/domain/src/main/java/com/megboyzz/devmenu/domain/usecases/files/RemoveInternalDataUseCase.kt
@@ -0,0 +1,14 @@
+package com.megboyzz.devmenu.domain.usecases.files
+
+import com.megboyzz.devmenu.domain.repository.FilesRepository
+import javax.inject.Inject
+
+class RemoveInternalDataUseCase @Inject constructor(
+ private val filesRepository: FilesRepository
+) {
+ operator fun invoke(): Boolean{
+ val listFiles = filesRepository.internalRoot.listFiles() ?: return false
+ listFiles.forEach { it.deleteRecursively() }
+ return true
+ }
+}
\ No newline at end of file
diff --git a/devmenu/domain/src/main/java/com/megboyzz/devmenu/domain/usecases/files/ReplaceFileUseCase.kt b/devmenu/domain/src/main/java/com/megboyzz/devmenu/domain/usecases/files/ReplaceFileUseCase.kt
new file mode 100644
index 0000000..0c69a47
--- /dev/null
+++ b/devmenu/domain/src/main/java/com/megboyzz/devmenu/domain/usecases/files/ReplaceFileUseCase.kt
@@ -0,0 +1,14 @@
+package com.megboyzz.devmenu.domain.usecases.files
+
+import com.megboyzz.devmenu.domain.repository.ReplacementRepository
+import java.io.File
+import javax.inject.Inject
+
+class ReplaceFileUseCase @Inject constructor(
+ private val replacementRepository: ReplacementRepository
+) {
+
+ suspend operator fun invoke(what: File, to: File): Result
+ = replacementRepository.replaceFile(what, to)
+
+}
\ No newline at end of file
diff --git a/devmenu/domain/src/main/java/com/megboyzz/devmenu/domain/usecases/replacement/GetAllReplacedFilesUseCase.kt b/devmenu/domain/src/main/java/com/megboyzz/devmenu/domain/usecases/replacement/GetAllReplacedFilesUseCase.kt
new file mode 100644
index 0000000..ac69349
--- /dev/null
+++ b/devmenu/domain/src/main/java/com/megboyzz/devmenu/domain/usecases/replacement/GetAllReplacedFilesUseCase.kt
@@ -0,0 +1,10 @@
+package com.megboyzz.devmenu.domain.usecases.replacement
+
+import com.megboyzz.devmenu.domain.repository.ReplacementRepository
+import javax.inject.Inject
+
+class GetAllReplacedFilesUseCase @Inject constructor(
+ private val replacementRepository: ReplacementRepository
+) {
+ suspend operator fun invoke() = replacementRepository.getAllReplacements()
+}
\ No newline at end of file
diff --git a/devmenu/domain/src/main/java/com/megboyzz/devmenu/domain/usecases/replacement/RecoverAllReplacementsUseCase.kt b/devmenu/domain/src/main/java/com/megboyzz/devmenu/domain/usecases/replacement/RecoverAllReplacementsUseCase.kt
new file mode 100644
index 0000000..d0b571b
--- /dev/null
+++ b/devmenu/domain/src/main/java/com/megboyzz/devmenu/domain/usecases/replacement/RecoverAllReplacementsUseCase.kt
@@ -0,0 +1,13 @@
+package com.megboyzz.devmenu.domain.usecases.replacement
+
+import javax.inject.Inject
+
+class RecoverAllReplacementsUseCase @Inject constructor(
+ private val getAllReplacedFilesUseCase: GetAllReplacedFilesUseCase,
+ private val recoverReplacementUseCase: RecoverReplacementUseCase
+) {
+ suspend operator fun invoke(){
+ val listReplacedFiles = getAllReplacedFilesUseCase()
+ listReplacedFiles.forEach { recoverReplacementUseCase(it) }
+ }
+}
\ No newline at end of file
diff --git a/devmenu/domain/src/main/java/com/megboyzz/devmenu/domain/usecases/replacement/RecoverReplacementUseCase.kt b/devmenu/domain/src/main/java/com/megboyzz/devmenu/domain/usecases/replacement/RecoverReplacementUseCase.kt
new file mode 100644
index 0000000..265d10b
--- /dev/null
+++ b/devmenu/domain/src/main/java/com/megboyzz/devmenu/domain/usecases/replacement/RecoverReplacementUseCase.kt
@@ -0,0 +1,11 @@
+package com.megboyzz.devmenu.domain.usecases.replacement
+
+import com.megboyzz.devmenu.domain.repository.ReplacementRepository
+import java.io.File
+import javax.inject.Inject
+
+class RecoverReplacementUseCase @Inject constructor(
+ private val replacementRepository: ReplacementRepository
+) {
+ suspend operator fun invoke(replacement: File) = replacementRepository.recoverReplacement(replacement)
+}
\ No newline at end of file
diff --git a/devmenu/domain/src/main/java/com/megboyzz/devmenu/domain/usecases/save/LoadSaveFileUseCase.kt b/devmenu/domain/src/main/java/com/megboyzz/devmenu/domain/usecases/save/LoadSaveFileUseCase.kt
new file mode 100644
index 0000000..4dbb301
--- /dev/null
+++ b/devmenu/domain/src/main/java/com/megboyzz/devmenu/domain/usecases/save/LoadSaveFileUseCase.kt
@@ -0,0 +1,11 @@
+package com.megboyzz.devmenu.domain.usecases.save
+
+import com.megboyzz.devmenu.domain.repository.SaveRepository
+import java.io.File
+import javax.inject.Inject
+
+class LoadSaveFileUseCase @Inject constructor(
+ private val saveRepository: SaveRepository
+) {
+ suspend operator fun invoke(file: File) = if(file.exists()) saveRepository.loadSaveFile(file) else false
+}
\ No newline at end of file
diff --git a/devmenu/domain/src/main/java/com/megboyzz/devmenu/domain/usecases/save/UploadSaveFileUseCase.kt b/devmenu/domain/src/main/java/com/megboyzz/devmenu/domain/usecases/save/UploadSaveFileUseCase.kt
new file mode 100644
index 0000000..1b7d78d
--- /dev/null
+++ b/devmenu/domain/src/main/java/com/megboyzz/devmenu/domain/usecases/save/UploadSaveFileUseCase.kt
@@ -0,0 +1,15 @@
+package com.megboyzz.devmenu.domain.usecases.save
+
+import com.megboyzz.devmenu.domain.repository.SaveRepository
+import java.io.File
+import javax.inject.Inject
+
+class UploadSaveFileUseCase @Inject constructor(
+ private val saveRepository: SaveRepository
+) {
+ suspend operator fun invoke(fileToUpload: File) =
+ if(fileToUpload.exists())
+ saveRepository.uploadCurrentSaveFile(fileToUpload)
+ else
+ false
+}
\ No newline at end of file
diff --git a/devmenu/domain/src/main/java/com/megboyzz/devmenu/domain/usecases/settings/GetSettingsUseCase.kt b/devmenu/domain/src/main/java/com/megboyzz/devmenu/domain/usecases/settings/GetSettingsUseCase.kt
new file mode 100644
index 0000000..e253cef
--- /dev/null
+++ b/devmenu/domain/src/main/java/com/megboyzz/devmenu/domain/usecases/settings/GetSettingsUseCase.kt
@@ -0,0 +1,11 @@
+package com.megboyzz.devmenu.domain.usecases.settings
+
+import com.megboyzz.devmenu.domain.entities.Settings
+import com.megboyzz.devmenu.domain.repository.SettingsRepository
+import javax.inject.Inject
+
+class GetSettingsUseCase @Inject constructor(
+ private val settingsRepository: SettingsRepository
+) {
+ suspend operator fun invoke(): Settings = settingsRepository.getSettings()
+}
\ No newline at end of file
diff --git a/devmenu/domain/src/main/java/com/megboyzz/devmenu/domain/usecases/settings/SetSettingsUseCase.kt b/devmenu/domain/src/main/java/com/megboyzz/devmenu/domain/usecases/settings/SetSettingsUseCase.kt
new file mode 100644
index 0000000..a288672
--- /dev/null
+++ b/devmenu/domain/src/main/java/com/megboyzz/devmenu/domain/usecases/settings/SetSettingsUseCase.kt
@@ -0,0 +1,11 @@
+package com.megboyzz.devmenu.domain.usecases.settings
+
+import com.megboyzz.devmenu.domain.entities.Settings
+import com.megboyzz.devmenu.domain.repository.SettingsRepository
+import javax.inject.Inject
+
+class SetSettingsUseCase @Inject constructor(
+ private val settingsRepository: SettingsRepository
+) {
+ suspend operator fun invoke(settings: Settings) = settingsRepository.setSettings(settings)
+}
\ No newline at end of file
diff --git a/devmenu/domain/src/main/java/com/megboyzz/devmenu/domain/usecases/settings/TurnOffDevMenuUseCase.kt b/devmenu/domain/src/main/java/com/megboyzz/devmenu/domain/usecases/settings/TurnOffDevMenuUseCase.kt
new file mode 100644
index 0000000..d6b1d35
--- /dev/null
+++ b/devmenu/domain/src/main/java/com/megboyzz/devmenu/domain/usecases/settings/TurnOffDevMenuUseCase.kt
@@ -0,0 +1,12 @@
+package com.megboyzz.devmenu.domain.usecases.settings
+
+import com.megboyzz.devmenu.domain.entities.devmenuId
+import com.megboyzz.devmenu.domain.repository.FilesRepository
+import java.io.File
+import javax.inject.Inject
+
+class TurnOffDevMenuUseCase @Inject constructor(
+ private val filesRepository: FilesRepository
+) {
+ operator fun invoke() = File(filesRepository.externalRoot, devmenuId).delete()
+}
\ No newline at end of file
diff --git a/devmenu/domain/src/main/java/com/megboyzz/devmenu/domain/usecases/svmw/CreateSvmwFileUseCase.kt b/devmenu/domain/src/main/java/com/megboyzz/devmenu/domain/usecases/svmw/CreateSvmwFileUseCase.kt
new file mode 100644
index 0000000..ebed805
--- /dev/null
+++ b/devmenu/domain/src/main/java/com/megboyzz/devmenu/domain/usecases/svmw/CreateSvmwFileUseCase.kt
@@ -0,0 +1,27 @@
+package com.megboyzz.devmenu.domain.usecases.svmw
+
+import com.megboyzz.devmenu.domain.repository.SvmwRepository
+import java.io.File
+import javax.inject.Inject
+
+class CreateSvmwFileUseCase @Inject constructor(
+ private val svmwRepository: SvmwRepository
+) {
+
+ suspend operator fun invoke(
+ fileToSave: File? = null,
+ saveFile: File? = null
+ ){
+
+ val a = fileToSave != null
+ val b = saveFile != null
+
+ when {
+ a && b -> svmwRepository.createSvmw(fileToSave!!, saveFile!!)
+ a && !b -> svmwRepository.createSvmwFromCurrentSaveFile(fileToSave!!)
+ !a && !b -> svmwRepository.createSvmwFromCurrentSaveFileAndSetIt()
+ }
+
+ }
+
+}
\ No newline at end of file
diff --git a/devmenu/domain/src/main/java/com/megboyzz/devmenu/domain/usecases/svmw/GetSvmwFilePropsUseCase.kt b/devmenu/domain/src/main/java/com/megboyzz/devmenu/domain/usecases/svmw/GetSvmwFilePropsUseCase.kt
new file mode 100644
index 0000000..d8c65a9
--- /dev/null
+++ b/devmenu/domain/src/main/java/com/megboyzz/devmenu/domain/usecases/svmw/GetSvmwFilePropsUseCase.kt
@@ -0,0 +1,11 @@
+package com.megboyzz.devmenu.domain.usecases.svmw
+
+import com.megboyzz.devmenu.domain.repository.SvmwRepository
+import java.io.File
+import javax.inject.Inject
+
+class GetSvmwFilePropsUseCase @Inject constructor(
+ private val svmwRepository: SvmwRepository
+) {
+ suspend operator fun invoke(file: File) = svmwRepository.getInfoAboutSvmw(file)
+}
\ No newline at end of file
diff --git a/devmenu/domain/src/main/java/com/megboyzz/devmenu/domain/usecases/svmw/GetSvmwPropsUseCase.kt b/devmenu/domain/src/main/java/com/megboyzz/devmenu/domain/usecases/svmw/GetSvmwPropsUseCase.kt
new file mode 100644
index 0000000..48afe3f
--- /dev/null
+++ b/devmenu/domain/src/main/java/com/megboyzz/devmenu/domain/usecases/svmw/GetSvmwPropsUseCase.kt
@@ -0,0 +1,10 @@
+package com.megboyzz.devmenu.domain.usecases.svmw
+
+import com.megboyzz.devmenu.domain.repository.SvmwRepository
+import javax.inject.Inject
+
+class GetSvmwPropsUseCase @Inject constructor(
+ private val svmwRepository: SvmwRepository
+) {
+ suspend operator fun invoke() = svmwRepository.getInfoAboutLoadedSvmw()
+}
\ No newline at end of file
diff --git a/devmenu/domain/src/main/java/com/megboyzz/devmenu/domain/usecases/svmw/LoadSvmwUseCase.kt b/devmenu/domain/src/main/java/com/megboyzz/devmenu/domain/usecases/svmw/LoadSvmwUseCase.kt
new file mode 100644
index 0000000..3c4d4f1
--- /dev/null
+++ b/devmenu/domain/src/main/java/com/megboyzz/devmenu/domain/usecases/svmw/LoadSvmwUseCase.kt
@@ -0,0 +1,11 @@
+package com.megboyzz.devmenu.domain.usecases.svmw
+
+import com.megboyzz.devmenu.domain.repository.SvmwRepository
+import java.io.File
+import javax.inject.Inject
+
+class LoadSvmwUseCase @Inject constructor(
+ private val svmwRepository: SvmwRepository
+) {
+ suspend operator fun invoke(file: File) = if(file.exists()) svmwRepository.loadSvmw(file) else false
+}
\ No newline at end of file
diff --git a/devmenu/domain/src/test/java/UseCaseTest.kt b/devmenu/domain/src/test/java/UseCaseTest.kt
new file mode 100644
index 0000000..8c5501a
--- /dev/null
+++ b/devmenu/domain/src/test/java/UseCaseTest.kt
@@ -0,0 +1,33 @@
+import com.megboyzz.devmenu.domain.repository.FilesRepository
+import com.megboyzz.devmenu.domain.repository.ReplacementRepository
+import com.megboyzz.devmenu.domain.repository.SaveRepository
+import com.megboyzz.devmenu.domain.repository.SettingsRepository
+import com.megboyzz.devmenu.domain.repository.SvmwRepository
+import org.mockito.Mockito.mock
+import org.mockito.Mockito.`when`
+import java.io.File
+import kotlin.coroutines.coroutineContext
+
+class UseCaseTest {
+
+ private val filesRepository = mock(FilesRepository::class.java)
+ private val replacementRepository = mock(ReplacementRepository::class.java)
+ private val saveRepository = mock(SaveRepository::class.java)
+ private val settingsRepository = mock(SettingsRepository::class.java)
+ private val svmwRepository = mock(SvmwRepository::class.java)
+
+ private val externalFile = File("D:\\NFSMW Online\\com.ea.games.nfs13_na")
+ private val internalFile = File("D:\\NFSMW Online")
+
+ init {
+
+ `when`(filesRepository.externalRoot).thenReturn(externalFile)
+ `when`(filesRepository.internalRoot).thenReturn(internalFile)
+
+
+ //`when`(replacementRepository.getAllReplacements()).thenReturn()
+
+
+ }
+
+}
\ No newline at end of file
diff --git a/devmenu/proguard-rules.pro b/devmenu/proguard-rules.pro
new file mode 100644
index 0000000..481bb43
--- /dev/null
+++ b/devmenu/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/devmenu/src/androidTest/java/com/megboyzz/devmenu/ExampleInstrumentedTest.kt b/devmenu/src/androidTest/java/com/megboyzz/devmenu/ExampleInstrumentedTest.kt
new file mode 100644
index 0000000..81aeaca
--- /dev/null
+++ b/devmenu/src/androidTest/java/com/megboyzz/devmenu/ExampleInstrumentedTest.kt
@@ -0,0 +1,24 @@
+package com.megboyzz.devmenu
+
+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("com.megboyzz.devmenu.test", appContext.packageName)
+ }
+}
\ No newline at end of file
diff --git a/devmenu/src/main/AndroidManifest.xml b/devmenu/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..3481e08
--- /dev/null
+++ b/devmenu/src/main/AndroidManifest.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/devmenu/src/main/java/com/megboyzz/devmenu/MainActivity.kt b/devmenu/src/main/java/com/megboyzz/devmenu/MainActivity.kt
new file mode 100644
index 0000000..15110c8
--- /dev/null
+++ b/devmenu/src/main/java/com/megboyzz/devmenu/MainActivity.kt
@@ -0,0 +1,12 @@
+package com.megboyzz.devmenu
+
+import android.os.Bundle
+import androidx.activity.ComponentActivity
+import androidx.activity.compose.setContent
+
+class MainActivity : ComponentActivity() {
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContent {}
+ }
+}
diff --git a/devmenu/src/main/java/com/megboyzz/devmenu/ui/theme/Color.kt b/devmenu/src/main/java/com/megboyzz/devmenu/ui/theme/Color.kt
new file mode 100644
index 0000000..231d948
--- /dev/null
+++ b/devmenu/src/main/java/com/megboyzz/devmenu/ui/theme/Color.kt
@@ -0,0 +1,11 @@
+package com.megboyzz.devmenu.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)
\ No newline at end of file
diff --git a/devmenu/src/main/java/com/megboyzz/devmenu/ui/theme/Theme.kt b/devmenu/src/main/java/com/megboyzz/devmenu/ui/theme/Theme.kt
new file mode 100644
index 0000000..a9fa830
--- /dev/null
+++ b/devmenu/src/main/java/com/megboyzz/devmenu/ui/theme/Theme.kt
@@ -0,0 +1,68 @@
+package com.megboyzz.devmenu.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.runtime.SideEffect
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.toArgb
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.platform.LocalView
+import androidx.core.view.WindowCompat
+
+private val DarkColorScheme = darkColorScheme(
+ primary = Purple80,
+ secondary = PurpleGrey80,
+ tertiary = Pink80
+)
+
+private val LightColorScheme = lightColorScheme(
+ primary = Purple40,
+ secondary = PurpleGrey40,
+ tertiary = Pink40,
+ background = Color(0xFFFFFBFE),
+ surface = Color(0xFFFFFBFE),
+ onPrimary = Color.White,
+ onSecondary = Color.White,
+ onTertiary = Color.White,
+ onBackground = Color(0xFF1C1B1F),
+ onSurface = Color(0xFF1C1B1F),
+)
+
+@Composable
+fun DevMenuTheme(
+ 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
+ }
+ val view = LocalView.current
+ if (!view.isInEditMode) {
+ SideEffect {
+ val window = (view.context as Activity).window
+ window.statusBarColor = colorScheme.primary.toArgb()
+ WindowCompat.getInsetsController(window, view).isAppearanceLightStatusBars = darkTheme
+ }
+ }
+
+ MaterialTheme(
+ colorScheme = colorScheme,
+ typography = Typography,
+ content = content
+ )
+}
\ No newline at end of file
diff --git a/devmenu/src/main/java/com/megboyzz/devmenu/ui/theme/Type.kt b/devmenu/src/main/java/com/megboyzz/devmenu/ui/theme/Type.kt
new file mode 100644
index 0000000..3c110ed
--- /dev/null
+++ b/devmenu/src/main/java/com/megboyzz/devmenu/ui/theme/Type.kt
@@ -0,0 +1,34 @@
+package com.megboyzz.devmenu.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
+ )
+ */
+)
\ No newline at end of file
diff --git a/devmenu/src/main/res/values/strings.xml b/devmenu/src/main/res/values/strings.xml
new file mode 100644
index 0000000..2ca7375
--- /dev/null
+++ b/devmenu/src/main/res/values/strings.xml
@@ -0,0 +1,3 @@
+
+ MainActivity
+
\ No newline at end of file
diff --git a/devmenu/src/main/res/values/themes.xml b/devmenu/src/main/res/values/themes.xml
new file mode 100644
index 0000000..54827a2
--- /dev/null
+++ b/devmenu/src/main/res/values/themes.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/devmenu/src/test/java/com/megboyzz/devmenu/ExampleUnitTest.kt b/devmenu/src/test/java/com/megboyzz/devmenu/ExampleUnitTest.kt
new file mode 100644
index 0000000..849e182
--- /dev/null
+++ b/devmenu/src/test/java/com/megboyzz/devmenu/ExampleUnitTest.kt
@@ -0,0 +1,17 @@
+package com.megboyzz.devmenu
+
+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 5b0dc77..2beff7b 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -21,3 +21,6 @@ dependencyResolutionManagement {
rootProject.name = "NFS Most Wanted"
include(":app")
+include(":devmenu")
+include(":devmenu:domain")
+include(":devmenu:data")