diff --git a/.editorconfig b/.editorconfig index 45db7af9a4..a55befd7a9 100644 --- a/.editorconfig +++ b/.editorconfig @@ -4,6 +4,6 @@ ktlint_function_naming_ignore_when_annotated_with = Composable ktlint_ignore_back_ticked_identifier = true ktlint_code_style = intellij_idea # Use IntelliJ style because it has trailing commas -[app/src/main/java/io/github/sds100/keymapper/util/ui/compose/icons/*.{kt,kts}] +[base/src/main/java/io/github/sds100/keymapper/base/utils/ui/compose/icons/*.{kt,kts}] ktlint_standard_property-naming = disabled ktlint_standard_backing-property-naming = disabled \ No newline at end of file diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index b0a1c1f356..a2027703b1 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -21,7 +21,7 @@ jobs: uses: android-actions/setup-android@v2 - name: Unit tests - run: bash ./gradlew testFreeDebugUnitTest + run: bash ./gradlew testDebugUnitTest style: name: Code style check @@ -96,10 +96,10 @@ jobs: run: bundle exec fastlane testing - name: set apk name env - run: echo "APK_NAME=$(basename app/build/outputs/apk/free/ci/*.apk .apk)" >> $GITHUB_ENV + run: echo "APK_NAME=$(basename app/build/outputs/apk/ci/*.apk .apk)" >> $GITHUB_ENV - name: Upload APK uses: actions/upload-artifact@v4 with: name: ${{ env.APK_NAME }} - path: app/build/outputs/apk/free/ci/${{ env.APK_NAME }}.apk + path: app/build/outputs/apk/ci/${{ env.APK_NAME }}.apk diff --git a/.github/workflows/testing.yml b/.github/workflows/testing.yml index 7bef735539..fd1b749380 100644 --- a/.github/workflows/testing.yml +++ b/.github/workflows/testing.yml @@ -27,7 +27,7 @@ jobs: uses: android-actions/setup-android@v2 - name: Unit tests - run: bash ./gradlew testFreeDebugUnitTest + run: bash ./gradlew testDebugUnitTest style: name: Code style check diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000000..74b4435ffe --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +KeyMapperFoss \ No newline at end of file diff --git a/.idea/material_theme_project_new.xml b/.idea/material_theme_project_new.xml new file mode 100644 index 0000000000..fd844d9451 --- /dev/null +++ b/.idea/material_theme_project_new.xml @@ -0,0 +1,13 @@ + + + + + + \ No newline at end of file diff --git a/.idea/navEditor.xml b/.idea/navEditor.xml new file mode 100644 index 0000000000..7dbf723192 --- /dev/null +++ b/.idea/navEditor.xml @@ -0,0 +1,257 @@ + + + + + + \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index be4801e662..2bebdb6e56 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -## [3.1.2](https://github.com/sds100/KeyMapper/releases/tag/v3.1.2) +## [3.2.0](https://github.com/sds100/KeyMapper/releases/tag/v3.2.0) #### TO BE RELEASED @@ -15,6 +15,7 @@ - #1686 (more fixes) do not show some screens behind system bars on the left/right side of the device. - #1701 optimize the trigger screen for smaller screens so elements are less cut off. - #1699 Do not highlight a floating button as if it is pressed after triggering a key event action from it. +- Button to copy the key map UID to the clipboard is invisible on small screens. ## [3.1.1](https://github.com/sds100/KeyMapper/releases/tag/v3.1.1) diff --git a/api/.gitignore b/api/.gitignore new file mode 100644 index 0000000000..42afabfd2a --- /dev/null +++ b/api/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/api/build.gradle.kts b/api/build.gradle.kts new file mode 100644 index 0000000000..046ff33114 --- /dev/null +++ b/api/build.gradle.kts @@ -0,0 +1,50 @@ +plugins { + alias(libs.plugins.android.library) + alias(libs.plugins.kotlin.android) + alias(libs.plugins.google.devtools.ksp) + alias(libs.plugins.jlleitschuh.gradle.ktlint) + alias(libs.plugins.dagger.hilt.android) +} + +android { + namespace = "io.github.sds100.keymapper.api" + compileSdk = libs.versions.compile.sdk.get().toInt() + + defaultConfig { + minSdk = libs.versions.min.sdk.get().toInt() + + consumerProguardFiles("consumer-rules.pro") + } + + buildTypes { + release { + isMinifyEnabled = true + proguardFiles( + getDefaultProguardFile("proguard-android-optimize.txt"), + "proguard-rules.pro", + ) + } + } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 + } + kotlinOptions { + jvmTarget = "11" + } + + buildFeatures { + aidl = true + } +} + +dependencies { + implementation(project(":common")) + implementation(project(":base")) + implementation(project(":system")) + + implementation(libs.jakewharton.timber) + + implementation(libs.dagger.hilt.android) + ksp(libs.dagger.hilt.android.compiler) +} diff --git a/app/src/test/resources/backup-manager-test/empty.json b/api/consumer-rules.pro similarity index 100% rename from app/src/test/resources/backup-manager-test/empty.json rename to api/consumer-rules.pro diff --git a/api/proguard-rules.pro b/api/proguard-rules.pro new file mode 100644 index 0000000000..481bb43481 --- /dev/null +++ b/api/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/api/src/main/AndroidManifest.xml b/api/src/main/AndroidManifest.xml new file mode 100644 index 0000000000..b3e73b7e65 --- /dev/null +++ b/api/src/main/AndroidManifest.xml @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/java/io/github/sds100/keymapper/api/Api.kt b/api/src/main/java/io/github/sds100/keymapper/api/Api.kt similarity index 92% rename from app/src/main/java/io/github/sds100/keymapper/api/Api.kt rename to api/src/main/java/io/github/sds100/keymapper/api/Api.kt index e14b0c974b..3c51a8126f 100644 --- a/app/src/main/java/io/github/sds100/keymapper/api/Api.kt +++ b/api/src/main/java/io/github/sds100/keymapper/api/Api.kt @@ -1,8 +1,5 @@ package io.github.sds100.keymapper.api -/** - * Created by sds100 on 17/06/2021. - */ object Api { // Do not use the package name for debug/ci builds const val ACTION_TRIGGER_KEYMAP_BY_UID = diff --git a/api/src/main/java/io/github/sds100/keymapper/api/ApiHiltModule.kt b/api/src/main/java/io/github/sds100/keymapper/api/ApiHiltModule.kt new file mode 100644 index 0000000000..aaf5e6ce4b --- /dev/null +++ b/api/src/main/java/io/github/sds100/keymapper/api/ApiHiltModule.kt @@ -0,0 +1,16 @@ +package io.github.sds100.keymapper.api + +import dagger.Binds +import dagger.Module +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent +import io.github.sds100.keymapper.system.apps.KeyMapShortcutActivityIntentBuilder + +@Module +@InstallIn(SingletonComponent::class) +abstract class ApiHiltModule { + @Binds + abstract fun bindKeyMapShortcutActivityIntentBuilder( + impl: KeyMapShortcutActivityIntentBuilderImpl, + ): KeyMapShortcutActivityIntentBuilder +} diff --git a/app/src/main/java/io/github/sds100/keymapper/api/KeyEventRelayService.kt b/api/src/main/java/io/github/sds100/keymapper/api/KeyEventRelayService.kt similarity index 92% rename from app/src/main/java/io/github/sds100/keymapper/api/KeyEventRelayService.kt rename to api/src/main/java/io/github/sds100/keymapper/api/KeyEventRelayService.kt index 333f14932d..58c49939e5 100644 --- a/app/src/main/java/io/github/sds100/keymapper/api/KeyEventRelayService.kt +++ b/api/src/main/java/io/github/sds100/keymapper/api/KeyEventRelayService.kt @@ -8,7 +8,6 @@ import android.os.IBinder import android.os.IBinder.DeathRecipient import android.view.KeyEvent import android.view.MotionEvent -import io.github.sds100.keymapper.system.inputmethod.KeyMapperImeHelper import timber.log.Timber import java.util.concurrent.ConcurrentHashMap @@ -31,16 +30,29 @@ class KeyEventRelayService : Service() { const val ACTION_REBIND_RELAY_SERVICE = "io.github.sds100.keymapper.ACTION_REBIND_RELAY_SERVICE" - const val CALLBACK_ID_ACCESSIBILITY_SERVICE = "accessibility_service" - const val CALLBACK_ID_INPUT_METHOD = "input_method" - /** * Used when a client registers a callback without specifying an ID. */ private const val CALLBACK_ID_DEFAULT = "default" + + const val KEY_MAPPER_GUI_IME_PACKAGE = + "io.github.sds100.keymapper.inputmethod.latin" + + private const val KEY_MAPPER_LEANBACK_IME_PACKAGE = + "io.github.sds100.keymapper.inputmethod.leanback" + + private const val KEY_MAPPER_HACKERS_KEYBOARD_PACKAGE = + "io.github.sds100.keymapper.inputmethod.hackers" } - val permittedPackages = KeyMapperImeHelper.KEY_MAPPER_IME_PACKAGE_LIST + val permittedPackages by lazy { + arrayOf( + packageName, + KEY_MAPPER_GUI_IME_PACKAGE, + KEY_MAPPER_LEANBACK_IME_PACKAGE, + KEY_MAPPER_HACKERS_KEYBOARD_PACKAGE, + ) + } private val binderInterface: IKeyEventRelayService = object : IKeyEventRelayService.Stub() { override fun sendKeyEvent( diff --git a/api/src/main/java/io/github/sds100/keymapper/api/KeyMapShortcutActivityIntentBuilderImpl.kt b/api/src/main/java/io/github/sds100/keymapper/api/KeyMapShortcutActivityIntentBuilderImpl.kt new file mode 100644 index 0000000000..f6d8faae4f --- /dev/null +++ b/api/src/main/java/io/github/sds100/keymapper/api/KeyMapShortcutActivityIntentBuilderImpl.kt @@ -0,0 +1,22 @@ +package io.github.sds100.keymapper.api + +import android.content.Context +import android.content.Intent +import android.os.Bundle +import dagger.hilt.android.qualifiers.ApplicationContext +import io.github.sds100.keymapper.system.apps.KeyMapShortcutActivityIntentBuilder +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class KeyMapShortcutActivityIntentBuilderImpl @Inject constructor( + @ApplicationContext private val ctx: Context, +) : KeyMapShortcutActivityIntentBuilder { + override fun build(intentAction: String, intentExtras: Bundle): Intent { + return Intent(ctx, LaunchKeyMapShortcutActivity::class.java).apply { + action = intentAction + + putExtras(intentExtras) + } + } +} diff --git a/api/src/main/java/io/github/sds100/keymapper/api/LaunchKeyMapShortcutActivity.kt b/api/src/main/java/io/github/sds100/keymapper/api/LaunchKeyMapShortcutActivity.kt new file mode 100644 index 0000000000..32e269e42b --- /dev/null +++ b/api/src/main/java/io/github/sds100/keymapper/api/LaunchKeyMapShortcutActivity.kt @@ -0,0 +1,58 @@ +package io.github.sds100.keymapper.api + +import android.content.Intent +import android.os.Bundle +import android.widget.Toast +import androidx.activity.ComponentActivity +import dagger.hilt.android.AndroidEntryPoint +import io.github.sds100.keymapper.base.R +import io.github.sds100.keymapper.system.accessibility.AccessibilityServiceAdapter +import io.github.sds100.keymapper.system.accessibility.AccessibilityServiceState +import javax.inject.Inject + +// DON'T MOVE THIS CLASS TO A DIFFERENT PACKAGE BECAUSE IT BREAKS THE API +/** + * Use basic Activity, NOT AppCompatActivity so the NoDisplay theme works. Otherwise an + * exception may be thrown because the theme doesn't extend AppCompat. + */ + +@AndroidEntryPoint +class LaunchKeyMapShortcutActivity : ComponentActivity() { + + @Inject + lateinit var accessibilityServiceAdapter: AccessibilityServiceAdapter + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + val accessibilityServiceState = accessibilityServiceAdapter.state.value + + when (accessibilityServiceState) { + AccessibilityServiceState.ENABLED -> + if (intent.action == Api.ACTION_TRIGGER_KEYMAP_BY_UID) { + Intent(Api.ACTION_TRIGGER_KEYMAP_BY_UID).apply { + setPackage(packageName) + + val uuid = intent.getStringExtra(Api.EXTRA_KEYMAP_UID) + putExtra(Api.EXTRA_KEYMAP_UID, uuid) + + sendBroadcast(this) + } + } + + AccessibilityServiceState.CRASHED -> Toast.makeText( + this, + R.string.error_accessibility_service_crashed, + Toast.LENGTH_SHORT, + ).show() + + AccessibilityServiceState.DISABLED -> Toast.makeText( + this, + R.string.error_accessibility_service_disabled, + Toast.LENGTH_SHORT, + ).show() + } + + finish() + } +} diff --git a/app/src/main/java/io/github/sds100/keymapper/api/PauseMappingsBroadcastReceiver.kt b/api/src/main/java/io/github/sds100/keymapper/api/PauseMappingsBroadcastReceiver.kt similarity index 73% rename from app/src/main/java/io/github/sds100/keymapper/api/PauseMappingsBroadcastReceiver.kt rename to api/src/main/java/io/github/sds100/keymapper/api/PauseMappingsBroadcastReceiver.kt index 662687d589..8cabcafc4c 100644 --- a/app/src/main/java/io/github/sds100/keymapper/api/PauseMappingsBroadcastReceiver.kt +++ b/api/src/main/java/io/github/sds100/keymapper/api/PauseMappingsBroadcastReceiver.kt @@ -3,21 +3,21 @@ package io.github.sds100.keymapper.api import android.content.BroadcastReceiver import android.content.Context import android.content.Intent -import io.github.sds100.keymapper.UseCases -import io.github.sds100.keymapper.util.firstBlocking - -/** - * Created by sds100 on 17/06/2021. - */ +import dagger.hilt.android.AndroidEntryPoint +import io.github.sds100.keymapper.base.keymaps.PauseKeyMapsUseCase +import io.github.sds100.keymapper.common.utils.firstBlocking +import javax.inject.Inject // DON'T MOVE THIS CLASS TO A DIFFERENT PACKAGE BECAUSE IT BREAKS THE API +@AndroidEntryPoint class PauseMappingsBroadcastReceiver : BroadcastReceiver() { + @Inject + lateinit var useCase: PauseKeyMapsUseCase + override fun onReceive(context: Context?, intent: Intent?) { context ?: return - val useCase = UseCases.pauseKeyMaps(context) - when (intent?.action) { Api.ACTION_PAUSE_MAPPINGS -> useCase.pause() Api.ACTION_RESUME_MAPPINGS -> useCase.resume() diff --git a/app/src/main/java/io/github/sds100/keymapper/api/TriggerKeyMapsBroadcastReceiver.kt b/api/src/main/java/io/github/sds100/keymapper/api/TriggerKeyMapsBroadcastReceiver.kt similarity index 55% rename from app/src/main/java/io/github/sds100/keymapper/api/TriggerKeyMapsBroadcastReceiver.kt rename to api/src/main/java/io/github/sds100/keymapper/api/TriggerKeyMapsBroadcastReceiver.kt index ffb5e42468..12b0acdf8e 100644 --- a/app/src/main/java/io/github/sds100/keymapper/api/TriggerKeyMapsBroadcastReceiver.kt +++ b/api/src/main/java/io/github/sds100/keymapper/api/TriggerKeyMapsBroadcastReceiver.kt @@ -3,25 +3,32 @@ package io.github.sds100.keymapper.api import android.content.BroadcastReceiver import android.content.Context import android.content.Intent -import io.github.sds100.keymapper.ServiceLocator -import io.github.sds100.keymapper.util.ServiceEvent +import dagger.hilt.android.AndroidEntryPoint +import io.github.sds100.keymapper.base.keymaps.TriggerKeyMapEvent +import io.github.sds100.keymapper.system.accessibility.AccessibilityServiceAdapter +import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch +import javax.inject.Inject // DON'T MOVE THIS CLASS TO A DIFFERENT PACKAGE BECAUSE IT BREAKS THE API +@AndroidEntryPoint class TriggerKeyMapsBroadcastReceiver : BroadcastReceiver() { + @Inject + lateinit var serviceAdapter: AccessibilityServiceAdapter + + @Inject + lateinit var coroutineScope: CoroutineScope + override fun onReceive(context: Context?, intent: Intent?) { context ?: return intent ?: return - val serviceAdapter = ServiceLocator.accessibilityServiceAdapter(context) - val scope = ServiceLocator.appCoroutineScope(context) - when (intent.action) { Api.ACTION_TRIGGER_KEYMAP_BY_UID -> { intent.getStringExtra(Api.EXTRA_KEYMAP_UID)?.let { uid -> - scope.launch { - serviceAdapter.send(ServiceEvent.TriggerKeyMap(uid)) + coroutineScope.launch { + serviceAdapter.send(TriggerKeyMapEvent(uid)) } } } diff --git a/app/build.gradle b/app/build.gradle deleted file mode 100644 index aad6da2e5a..0000000000 --- a/app/build.gradle +++ /dev/null @@ -1,282 +0,0 @@ -apply plugin: "com.android.application" -apply plugin: "kotlin-android" -apply plugin: "kotlin-kapt" -apply plugin: "com.google.devtools.ksp" -apply plugin: "androidx.navigation.safeargs.kotlin" -apply plugin: "kotlinx-serialization" -apply plugin: "org.jetbrains.kotlin.plugin.parcelize" -apply plugin: "org.jlleitschuh.gradle.ktlint" -apply plugin: "org.jetbrains.kotlin.plugin.compose" -apply plugin: "androidx.room" - -android { - - namespace "io.github.sds100.keymapper" - compileSdk 35 - buildToolsVersion = "35.0.0" - - def versionProperties = new Properties() - file("version.properties").withInputStream { versionProperties.load(it) } - - defaultConfig { - applicationId "io.github.sds100.keymapper" - minSdkVersion 21 - targetSdkVersion 35 - versionCode versionProperties.getProperty("VERSION_CODE").toInteger() - versionName versionProperties.getProperty("VERSION_NAME") - multiDexEnabled true - - vectorDrawables.useSupportLibrary = true - testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" - - javaCompileOptions { - annotationProcessorOptions { - arguments = ["room.schemaLocation": "$projectDir/schemas".toString()] - } - } - } - - signingConfigs { - release { - storeFile file("keystore.jks") - storePassword System.getenv("KEYSTORE_PASSWORD") - keyAlias "keymapper" - keyPassword System.getenv("KEY_PASSWORD") - } - } - - buildTypes { - - release { - minifyEnabled true - proguardFiles getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro" - signingConfig signingConfigs.release - } - - debug { - applicationIdSuffix ".debug" - versionNameSuffix "-debug" - } - - debug_release { - // Extend from debug build type so compose Live Edit and rapid building works - initWith debug - - // Do not alter the package name so can test revenuecat and billing while developing. - applicationIdSuffix "" - - /* - This is required because the splitties library does not have a debug_release build type. - */ - matchingFallbacks = ["debug"] - } - - ci { - minifyEnabled true - shrinkResources true - - /* - This is required because the splitties library does not have a ci build type. - */ - matchingFallbacks = ["debug"] - - applicationIdSuffix ".ci" - versionNameSuffix "-ci." + versionProperties.getProperty("VERSION_NUM") - - proguardFiles getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro" - - signingConfig signingConfigs.debug - } - } - - flavorDimensions = ["pro"] - productFlavors { - free { - dimension "pro" - } - pro { - dimension "pro" - - File file = rootProject.file("local.properties") - String keyName = "REVENUECAT_API_KEY" - - if (file.exists()) { - def localProperties = new Properties() - localProperties.load(new FileInputStream(file)) - if (localProperties.containsKey(keyName)) { - buildConfigField("String", keyName, localProperties[keyName]) - } - } - } - } - - buildFeatures { - dataBinding true - viewBinding true - aidl true - buildConfig true - compose true - } - - compileOptions { - // Required for desugaring new Java time API on lower than API 26 - coreLibraryDesugaringEnabled = true - - sourceCompatibility JavaVersion.VERSION_17 - targetCompatibility JavaVersion.VERSION_17 - } - - kotlinOptions { - jvmTarget = "17" - } - - kapt { - correctErrorTypes = true - } - - composeOptions { - kotlinCompilerExtensionVersion "1.5.10" - } - - sourceSets { - androidTest { - assets.srcDirs += files("$projectDir/schemas".toString()) - resources.srcDirs += ["src/test/resources"] - } - - test { - java.srcDirs += ["src/pro/test/java"] - } - } - - applicationVariants.configureEach { variant -> - variant.outputs.configureEach { - outputFileName = "keymapper-${variant.versionName}.apk" - } - } - - room { - schemaDirectory "$projectDir/schemas" - } -} - -dependencies { - implementation fileTree(include: ["*.jar"], dir: "libs") - - compileOnly project(":systemstubs") - - def room_version = "2.7.1" - def coroutinesVersion = "1.9.0" - def nav_version = '2.9.0' - def epoxy_version = "4.6.2" - def splitties_version = "3.0.0" - def multidex_version = "2.0.1" - def shizuku_version = "13.1.5" - - // kotlin stuff - implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutinesVersion" - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" - implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.8.0" - - // random stuff - implementation "com.google.android.material:material:1.13.0-alpha13" - implementation "com.github.salomonbrys.kotson:kotson:2.5.0" - implementation "com.airbnb.android:epoxy:$epoxy_version" - implementation "com.airbnb.android:epoxy-databinding:$epoxy_version" - kapt "com.airbnb.android:epoxy-processor:$epoxy_version" - implementation "com.jakewharton.timber:timber:5.0.1" - implementation "net.lingala.zip4j:zip4j:2.8.0" - implementation "com.anggrayudi:storage:0.8.1" - implementation "com.github.MFlisar:DragSelectRecyclerView:0.3" - implementation "com.google.android.flexbox:flexbox:3.0.0" - implementation "dev.rikka.shizuku:api:$shizuku_version" - implementation "dev.rikka.shizuku:provider:$shizuku_version" - implementation "org.lsposed.hiddenapibypass:hiddenapibypass:4.3" - proImplementation 'com.revenuecat.purchases:purchases:8.17.1' - proImplementation "com.airbnb.android:lottie-compose:6.6.3" - implementation("com.squareup.okhttp3:okhttp:4.12.0") - coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.1.5") - implementation 'com.canopas.intro-showcase-view:introshowcaseview:2.0.2' - - // splitties - implementation "com.louiscad.splitties:splitties-bitflags:$splitties_version" - implementation "com.louiscad.splitties:splitties-alertdialog-appcompat-coroutines:$splitties_version" - implementation("com.louiscad.splitties:splitties-alertdialog-material:$splitties_version") - implementation "com.louiscad.splitties:splitties-snackbar:$splitties_version" - implementation "com.louiscad.splitties:splitties-toast:$splitties_version" - implementation "com.louiscad.splitties:splitties-mainthread:$splitties_version" - - // androidx - implementation "androidx.legacy:legacy-support-core-ui:1.0.0" - implementation "androidx.core:core-ktx:1.16.0" - - implementation "androidx.activity:activity-ktx:1.10.1" - implementation "androidx.fragment:fragment-ktx:1.8.6" - implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.9.0" - implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.9.0" - implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.9.0" - implementation "androidx.room:room-ktx:$room_version" - implementation "androidx.navigation:navigation-fragment-ktx:$nav_version" - implementation "androidx.navigation:navigation-ui-ktx:$nav_version" - implementation "androidx.multidex:multidex:$multidex_version" - implementation "androidx.appcompat:appcompat:1.7.0" - implementation "androidx.recyclerview:recyclerview:1.4.0" - implementation "androidx.preference:preference-ktx:1.2.1" - implementation "androidx.constraintlayout:constraintlayout:2.2.1" - implementation "androidx.lifecycle:lifecycle-extensions:2.2.0" - implementation "androidx.room:room-runtime:$room_version" - implementation "androidx.viewpager2:viewpager2:1.1.0" - implementation "androidx.datastore:datastore-preferences:1.2.0-alpha02" - implementation "androidx.core:core-splashscreen:1.0.1" - implementation "androidx.activity:activity-compose:1.10.1" - implementation "androidx.navigation:navigation-compose:2.9.0" - implementation "androidx.navigation:navigation-fragment-compose:2.9.0" - ksp "androidx.room:room-compiler:$room_version" - - // Compose - // Downgrade compose BOM version because there is a crash. Do not use 2025.05.00 - Dependency composeBom = platform('androidx.compose:compose-bom:2025.04.01') - implementation composeBom - implementation 'androidx.compose.foundation:foundation' - implementation "androidx.compose.ui:ui-android" - implementation "androidx.compose.material3:material3-android" - implementation "androidx.compose.ui:ui-tooling-preview-android" - implementation "androidx.compose.material:material-icons-extended-android" - implementation 'androidx.compose.material3.adaptive:adaptive-android' - implementation "androidx.compose.material3.adaptive:adaptive-navigation" - implementation "com.google.accompanist:accompanist-drawablepainter:0.35.0-alpha" - implementation "androidx.activity:activity-compose:1.10.1" - debugImplementation "androidx.compose.ui:ui-tooling" - debug_releaseImplementation "androidx.compose.ui:ui-tooling" - -// debugImplementation "com.squareup.leakcanary:leakcanary-android:2.6" - - def junitVersion = "4.13.2" - def androidXTestExtKotlinRunnerVersion = "1.2.1" - def espressoVersion = "3.6.1" - def androidXTestCoreVersion = "1.6.1" - - // Dependencies for local unit tests - testImplementation "junit:junit:$junitVersion" - testImplementation "org.hamcrest:hamcrest-all:1.3" - testImplementation "androidx.test.ext:junit-ktx:$androidXTestExtKotlinRunnerVersion" - testImplementation "androidx.test:core-ktx:1.6.1" - testImplementation "org.robolectric:robolectric:4.14.1" - testImplementation "androidx.arch.core:core-testing:2.2.0" - testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutinesVersion" - testImplementation "pl.pragmatists:JUnitParams:1.1.1" - testImplementation "org.mockito.kotlin:mockito-kotlin:4.0.0" - testImplementation "org.mockito:mockito-core:5.15.2" - testImplementation "org.mockito:mockito-inline:5.2.0" - - androidTestImplementation "androidx.test.ext:junit:$androidXTestExtKotlinRunnerVersion" - androidTestImplementation "androidx.test.espresso:espresso-core:$espressoVersion" - androidTestImplementation "androidx.arch.core:core-testing:2.2.0" - androidTestImplementation "androidx.test.espresso:espresso-contrib:$espressoVersion" - androidTestImplementation "junit:junit:$junitVersion" - androidTestImplementation "androidx.navigation:navigation-testing:$nav_version" - androidTestImplementation "android.arch.persistence.room:testing:1.1.1" - androidTestImplementation "org.mockito:mockito-android:4.6.1" - debugImplementation "androidx.fragment:fragment-testing:1.8.6" - implementation "androidx.test:core:$androidXTestCoreVersion" -} \ No newline at end of file diff --git a/app/build.gradle.kts b/app/build.gradle.kts new file mode 100644 index 0000000000..9f3e80bb1f --- /dev/null +++ b/app/build.gradle.kts @@ -0,0 +1,180 @@ +@file:Suppress("UnstableApiUsage") + +import java.util.Properties + +plugins { + alias(libs.plugins.android.application) + alias(libs.plugins.kotlin.android) + alias(libs.plugins.kotlin.compose) + alias(libs.plugins.kotlin.kapt) + alias(libs.plugins.kotlin.serialization) + alias(libs.plugins.kotlin.parcelize) + alias(libs.plugins.androidx.navigation.safeargs.kotlin) + alias(libs.plugins.google.devtools.ksp) + alias(libs.plugins.jlleitschuh.gradle.ktlint) + alias(libs.plugins.dagger.hilt.android) +} + +android { + namespace = "io.github.sds100.keymapper" + compileSdk = libs.versions.compile.sdk.get().toInt() + buildToolsVersion = libs.versions.build.tools.get() + + val versionProperties = Properties().apply { + project.file("version.properties").inputStream().use { load(it) } + } + + defaultConfig { + applicationId = "io.github.sds100.keymapper" + minSdk = libs.versions.min.sdk.get().toInt() + targetSdk = libs.versions.target.sdk.get().toInt() + + versionCode = versionProperties.getProperty("VERSION_CODE").toInt() + versionName = versionProperties.getProperty("VERSION_NAME") + multiDexEnabled = true + + vectorDrawables.useSupportLibrary = true + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + } + + signingConfigs { + create("release") { + storeFile = file("keystore.jks") + storePassword = System.getenv("KEYSTORE_PASSWORD") + keyAlias = "keymapper" + keyPassword = System.getenv("KEY_PASSWORD") + } + } + + buildTypes { + release { + isMinifyEnabled = true + proguardFiles( + getDefaultProguardFile("proguard-android-optimize.txt"), + "proguard-rules.pro", + ) + signingConfig = signingConfigs.getByName("release") + versionNameSuffix = "-foss" + } + + debug { + applicationIdSuffix = ".debug" + versionNameSuffix = "-foss-debug" + } + + create("debug_release") { + initWith(getByName("debug")) + applicationIdSuffix = "" // Reset from debug + matchingFallbacks.add("debug") + } + + create("ci") { + isMinifyEnabled = true + // shrinkResources is now part of isMinifyEnabled in newer AGP, + // but let's keep explicit if an older AGP interpretation is in mind. + // If build fails, this might need adjustment. + // For AGP 8.x, shrinkResources is controlled by isMinifyEnabled. + // Explicitly setting it might be deprecated or have no effect. + // I'll assume it implies full R8 shrinkage. + // shrinkResources = true // This property might not exist directly here in KTS for AGP 8+ + // Instead, you rely on isMinifyEnabled and Proguard rules. + + matchingFallbacks.add("debug") + applicationIdSuffix = ".ci" + versionNameSuffix = "-foss-ci.${versionProperties.getProperty("VERSION_NUM")}" + proguardFiles( + getDefaultProguardFile("proguard-android-optimize.txt"), + "proguard-rules.pro", + ) + signingConfig = signingConfigs.getByName("debug") // Assuming debug signing for CI + } + } + + buildFeatures { + dataBinding = true + aidl = true + buildConfig = true + compose = true + } + + compileOptions { + isCoreLibraryDesugaringEnabled = true + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 + } + + kotlinOptions { + jvmTarget = "11" + } + + kapt { + correctErrorTypes = true + } + + composeOptions { + kotlinCompilerExtensionVersion = libs.versions.compose.compiler.get() + } + + sourceSets { + getByName("androidTest") { + assets.srcDirs(files("$projectDir/schemas")) + resources.srcDirs("src/test/resources") + } + getByName("test") { + java.srcDirs("src/pro/test/java") + } + } + + applicationVariants.all { + outputs.all { + val output = this as com.android.build.gradle.internal.api.BaseVariantOutputImpl + output.outputFileName = "keymapper-foss-${'$'}{variant.versionName}.apk" + } + } +} + +dependencies { + implementation(fileTree(mapOf("include" to listOf("*.jar"), "dir" to "libs"))) + + implementation(project(":common")) + implementation(project(":base")) + implementation(project(":api")) + implementation(project(":data")) + implementation(project(":system")) + compileOnly(project(":systemstubs")) + + coreLibraryDesugaring(libs.desugar.jdk.libs) + + // Other + implementation(libs.jakewharton.timber) + + // Androidx + 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.multidex) + implementation(libs.androidx.appcompat) + implementation(libs.bundles.androidx.navigation) + + // Compose + implementation(platform(libs.androidx.compose.bom)) + implementation(libs.androidx.compose.foundation) + implementation(libs.androidx.compose.ui.android) + implementation(libs.androidx.compose.material3) + implementation(libs.androidx.compose.ui.tooling.preview) + implementation(libs.androidx.compose.material.icons.extended) + implementation(libs.androidx.compose.material3.adaptive) + implementation(libs.androidx.compose.material3.adaptive.navigation) + implementation(libs.androidx.hilt.navigation.compose) + implementation(libs.google.accompanist.drawablepainter) + implementation(libs.androidx.compose.ui.tooling) + + // Dagger + implementation(libs.dagger.hilt.android) + ksp(libs.dagger.hilt.android.compiler) + + debugImplementation(libs.androidx.ui.tooling) + + testImplementation(libs.junit) +} diff --git a/app/src/androidTest/java/io/github/sds100/keymapper/AppDatabaseMigrationTest.kt b/app/src/androidTest/java/io/github/sds100/keymapper/AppDatabaseMigrationTest.kt deleted file mode 100644 index 83dc9f3ce9..0000000000 --- a/app/src/androidTest/java/io/github/sds100/keymapper/AppDatabaseMigrationTest.kt +++ /dev/null @@ -1,858 +0,0 @@ -package io.github.sds100.keymapper - -import androidx.datastore.preferences.core.PreferenceDataStoreFactory -import androidx.datastore.preferences.core.edit -import androidx.datastore.preferences.core.stringPreferencesKey -import androidx.room.migration.Migration -import androidx.room.testing.MigrationTestHelper -import androidx.sqlite.db.SupportSQLiteDatabase -import androidx.sqlite.db.framework.FrameworkSQLiteOpenHelperFactory -import androidx.test.espresso.matcher.ViewMatchers -import androidx.test.ext.junit.runners.AndroidJUnit4 -import androidx.test.platform.app.InstrumentationRegistry -import com.github.salomonbrys.kotson.get -import com.google.gson.Gson -import com.google.gson.JsonArray -import com.google.gson.JsonElement -import com.google.gson.JsonParseException -import com.google.gson.JsonParser -import io.github.sds100.keymapper.data.db.AppDatabase -import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.MainScope -import kotlinx.coroutines.runBlocking -import org.hamcrest.Matchers -import org.junit.Before -import org.junit.Rule -import org.junit.Test -import org.junit.runner.RunWith -import java.io.File -import java.io.IOException - -/** - * Created by sds100 on 05/06/20. - */ -@ExperimentalCoroutinesApi -@RunWith(AndroidJUnit4::class) -class AppDatabaseMigrationTest { - companion object { - private const val TEST_DB_NAME = "migration_test" - - private val MIGRATION_1_2_TEST_DATA = arrayOf( - arrayOf(1, "[]", 0, 1, "NULL", "NULL", "NULL"), - arrayOf(2, "[{\"keys\":[25]}]", 4, 1, "APP", "com.android.chrome", "[]"), - arrayOf(3, "[{\"keys\":[25,24]}]", 0, 1, "KEY", "24", "[]"), - arrayOf(4, "[{\"keys\":[25,24]}]", 0, 1, "KEYCODE", "24", "[]"), - arrayOf( - 5, - "[{\"keys\":[25,24]},{\"keys\":[25]}]", - 0, - 1, - "SYSTEM_ACTION", - "toggle_flashlight", - "[{\"data\":\"option_lens_back\",\"id\":\"extra_flash\"}]", - ), - arrayOf(6, "[{\"keys\":[4]}]", 3, 1, "SYSTEM_ACTION", "volume_mute", "[]"), - ) - - private val MIGRATION_1_2_EXPECTED_DATA = arrayOf( - arrayOf(1, "{\"extras\":[],\"keys\":[],\"mode\":1}", "[]", "[]", 1, 0, "NULL", 1), - arrayOf( - 2, - "{\"extras\":[],\"keys\":[{\"clickType\":0,\"deviceId\":\"io.github.sds100.keymapper.ANY_DEVICE\",\"keyCode\":25}],\"mode\":1}", - "[{\"data\":\"com.android.chrome\",\"extras\":[],\"flags\":0,\"type\":\"APP\"}]", - "[]", - 1, - 1, - "NULL", - 1, - ), - arrayOf( - 3, - "{\"extras\":[],\"keys\":[{\"clickType\":0,\"deviceId\":\"io.github.sds100.keymapper.ANY_DEVICE\",\"keyCode\":25},{\"clickType\":0,\"deviceId\":\"io.github.sds100.keymapper.ANY_DEVICE\",\"keyCode\":24}],\"mode\":0}", - "[{\"data\":\"24\",\"extras\":[],\"flags\":0,\"type\":\"KEY_EVENT\"}]", - "[]", - 1, - 0, - "NULL", - 1, - ), - arrayOf( - 4, - "{\"extras\":[],\"keys\":[{\"clickType\":0,\"deviceId\":\"io.github.sds100.keymapper.ANY_DEVICE\",\"keyCode\":25},{\"clickType\":0,\"deviceId\":\"io.github.sds100.keymapper.ANY_DEVICE\",\"keyCode\":24}],\"mode\":0}", - "[{\"data\":\"24\",\"extras\":[],\"flags\":0,\"type\":\"KEY_EVENT\"}]", - "[]", - 1, - 0, - "NULL", - 1, - ), - arrayOf( - 5, - "{\"extras\":[],\"keys\":[{\"clickType\":0,\"deviceId\":\"io.github.sds100.keymapper.ANY_DEVICE\",\"keyCode\":25},{\"clickType\":0,\"deviceId\":\"io.github.sds100.keymapper.ANY_DEVICE\",\"keyCode\":24}],\"mode\":0}", - "[{\"data\":\"toggle_flashlight\",\"extras\":[{\"data\":\"option_lens_back\",\"id\":\"extra_flash\"}],\"flags\":0,\"type\":\"SYSTEM_ACTION\"}]", - "[]", - 1, - 0, - "NULL", - 1, - ), - arrayOf( - 6, - "{\"extras\":[],\"keys\":[{\"clickType\":0,\"deviceId\":\"io.github.sds100.keymapper.ANY_DEVICE\",\"keyCode\":25}],\"mode\":1}", - "[{\"data\":\"toggle_flashlight\",\"extras\":[{\"data\":\"option_lens_back\",\"id\":\"extra_flash\"}],\"flags\":0,\"type\":\"SYSTEM_ACTION\"}]", - "[]", - 1, - 0, - "NULL", - 1, - ), - arrayOf( - 7, - "{\"extras\":[],\"keys\":[{\"clickType\":1,\"deviceId\":\"io.github.sds100.keymapper.ANY_DEVICE\",\"keyCode\":4}],\"mode\":1}", - "[{\"data\":\"volume_mute\",\"extras\":[],\"flags\":1,\"type\":\"SYSTEM_ACTION\"}]", - "[]", - 1, - 0, - "NULL", - 1, - ), - ) - - private val MIGRATION_2_3_TEST_DATA = arrayOf( - arrayOf( - 1, - "{\"extras\":[{\"data\":\"610\",\"id\":\"extra_repeat_delay\"}],\"keys\":[{\"clickType\":0,\"deviceId\":\"io.github.sds100.keymapper.THIS_DEVICE\",\"keyCode\":25}],\"mode\":1}", - "[{\"data\":\"10\",\"extras\":[],\"flags\":0,\"type\":\"KEY_EVENT\"}]", - "[]", - 1, - 1, - "NULL", - 1, - ), - arrayOf(2, "{\"extras\":[],\"keys\":[],\"mode\":1}", "[]", "[]", 1, 0, "NULL", 1), - arrayOf( - 3, - "{\"extras\":[],\"keys\":[{\"clickType\":0,\"deviceId\":\"io.github.sds100.keymapper.THIS_DEVICE\",\"keyCode\":25},{\"clickType\":0,\"deviceId\":\"io.github.sds100.keymapper.THIS_DEVICE\",\"keyCode\":24}],\"mode\":0}", - "[{\"data\":\"enable_mobile_data\",\"extras\":[],\"flags\":0,\"type\":\"SYSTEM_ACTION\"}]", - "[]", - 1, - 0, - "NULL", - 1, - ), - arrayOf( - 4, - "{\"extras\":[],\"keys\":[{\"clickType\":1,\"deviceId\":\"io.github.sds100.keymapper.THIS_DEVICE\",\"keyCode\":25},{\"clickType\":1,\"deviceId\":\"io.github.sds100.keymapper.THIS_DEVICE\",\"keyCode\":24}],\"mode\":0}", - "[{\"data\":\"14\",\"extras\":[],\"flags\":0,\"type\":\"KEY_EVENT\"}]", - "[]", - 1, - 0, - "NULL", - 1, - ), - ) - - private val MIGRATION_2_3_EXPECTED_DATA = arrayOf( - arrayOf( - 1, - "{\"extras\":[{\"data\":\"610\",\"id\":\"extra_repeat_delay\"}],\"keys\":[{\"clickType\":0,\"deviceId\":\"io.github.sds100.keymapper.THIS_DEVICE\",\"keyCode\":25}],\"mode\":1}", - "[{\"data\":\"10\",\"extras\":[],\"flags\":0,\"type\":\"KEY_EVENT\"}]", - "[]", - 1, - 17, - "NULL", - 1, - ), - arrayOf(2, "{\"extras\":[],\"keys\":[],\"mode\":1}", "[]", "[]", 1, 0, "NULL", 1), - arrayOf( - 3, - "{\"extras\":[],\"keys\":[{\"clickType\":0,\"deviceId\":\"io.github.sds100.keymapper.THIS_DEVICE\",\"keyCode\":25},{\"clickType\":0,\"deviceId\":\"io.github.sds100.keymapper.THIS_DEVICE\",\"keyCode\":24}],\"mode\":0}", - "[{\"data\":\"enable_mobile_data\",\"extras\":[],\"flags\":0,\"type\":\"SYSTEM_ACTION\"}]", - "[]", - 1, - 0, - "NULL", - 1, - ), - arrayOf( - 4, - "{\"extras\":[],\"keys\":[{\"clickType\":1,\"deviceId\":\"io.github.sds100.keymapper.THIS_DEVICE\",\"keyCode\":25},{\"clickType\":1,\"deviceId\":\"io.github.sds100.keymapper.THIS_DEVICE\",\"keyCode\":24}],\"mode\":0}", - "[{\"data\":\"14\",\"extras\":[],\"flags\":0,\"type\":\"KEY_EVENT\"}]", - "[]", - 1, - 16, - "NULL", - 1, - ), - ) - - private val MIGRATION_3_4_TEST_DATA = arrayOf( - arrayOf( - 1, - "{\"extras\":[{\"data\":\"610\",\"id\":\"extra_repeat_delay\"}],\"keys\":[{\"clickType\":0,\"deviceId\":\"io.github.sds100.keymapper.THIS_DEVICE\",\"keyCode\":25}],\"mode\":1}", - "[{\"data\":\"10\",\"extras\":[],\"flags\":0,\"type\":\"KEY_EVENT\"}]", - "[]", - 1, - 17, - "NULL", - 1, - ), - arrayOf(2, "{\"extras\":[],\"keys\":[],\"mode\":1}", "[]", "[]", 1, 0, "NULL", 1), - arrayOf( - 3, - "{\"extras\":[],\"keys\":[{\"clickType\":0,\"deviceId\":\"io.github.sds100.keymapper.THIS_DEVICE\",\"keyCode\":25},{\"clickType\":0,\"deviceId\":\"io.github.sds100.keymapper.THIS_DEVICE\",\"keyCode\":24}],\"mode\":0}", - "[{\"data\":\"enable_mobile_data\",\"extras\":[],\"flags\":0,\"type\":\"SYSTEM_ACTION\"}]", - "[]", - 1, - 0, - "NULL", - 1, - ), - arrayOf( - 4, - "{\"extras\":[],\"keys\":[{\"clickType\":1,\"deviceId\":\"io.github.sds100.keymapper.THIS_DEVICE\",\"keyCode\":25},{\"clickType\":1,\"deviceId\":\"io.github.sds100.keymapper.THIS_DEVICE\",\"keyCode\":24}],\"mode\":0}", - "[{\"data\":\"14\",\"extras\":[],\"flags\":0,\"type\":\"KEY_EVENT\"}]", - "[]", - 1, - 16, - "NULL", - 1, - ), - ) - - private val MIGRATION_3_4_EXPECTED_DATA = arrayOf( - arrayOf( - 1, - "{\"extras\":[{\"data\":\"610\",\"id\":\"extra_repeat_delay\"}],\"keys\":[{\"clickType\":0,\"deviceId\":\"io.github.sds100.keymapper.THIS_DEVICE\",\"keyCode\":25}],\"mode\":2}", - "[{\"data\":\"10\",\"extras\":[],\"flags\":0,\"type\":\"KEY_EVENT\"}]", - "[]", - 1, - 17, - "NULL", - 1, - ), - arrayOf(2, "{\"extras\":[],\"keys\":[],\"mode\":2}", "[]", "[]", 1, 0, "NULL", 1), - arrayOf( - 3, - "{\"extras\":[],\"keys\":[{\"clickType\":0,\"deviceId\":\"io.github.sds100.keymapper.THIS_DEVICE\",\"keyCode\":25},{\"clickType\":0,\"deviceId\":\"io.github.sds100.keymapper.THIS_DEVICE\",\"keyCode\":24}],\"mode\":0}", - "[{\"data\":\"enable_mobile_data\",\"extras\":[],\"flags\":0,\"type\":\"SYSTEM_ACTION\"}]", - "[]", - 1, - 0, - "NULL", - 1, - ), - arrayOf( - 4, - "{\"extras\":[],\"keys\":[{\"clickType\":1,\"deviceId\":\"io.github.sds100.keymapper.THIS_DEVICE\",\"keyCode\":25},{\"clickType\":1,\"deviceId\":\"io.github.sds100.keymapper.THIS_DEVICE\",\"keyCode\":24}],\"mode\":0}", - "[{\"data\":\"14\",\"extras\":[],\"flags\":0,\"type\":\"KEY_EVENT\"}]", - "[]", - 1, - 16, - "NULL", - 1, - ), - ) - - private val MIGRATION_4_5_TEST_DATA = arrayOf( - arrayOf( - 1, - "{\"extras\":[],\"keys\":[{\"clickType\":0,\"deviceId\":\"io.github.sds100.keymapper.THIS_DEVICE\",\"keyCode\":25},{\"clickType\":0,\"deviceId\":\"io.github.sds100.keymapper.THIS_DEVICE\",\"keyCode\":24}],\"mode\":0}", - "[{\"data\":\"volume_up\",\"extras\":[],\"flags\":1,\"type\":\"SYSTEM_ACTION\"},{\"data\":\"com.android.settings\",\"extras\":[],\"flags\":0,\"type\":\"APP\"}]", - "[]", - 1, - 16, - "NULL", - 1, - ), - arrayOf( - 2, - "{\"extras\":[{\"data\":\"5000\",\"id\":\"extra_hold_down_until_repeat_delay\"},{\"data\":\"575\",\"id\":\"extra_repeat_delay\"},{\"data\":\"365\",\"id\":\"extra_vibration_duration\"}],\"keys\":[{\"clickType\":0,\"deviceId\":\"io.github.sds100.keymapper.THIS_DEVICE\",\"keyCode\":25}],\"mode\":2}", - "[{\"data\":\"7\",\"extras\":[],\"flags\":0,\"type\":\"KEY_EVENT\"}]", - "[]", - 1, - 19, - "NULL", - 1, - ), - ) - - private val MIGRATION_4_5_EXPECTED_DATA = arrayOf( - arrayOf( - 1, - "{\"extras\":[],\"keys\":[{\"clickType\":0,\"deviceId\":\"io.github.sds100.keymapper.THIS_DEVICE\",\"keyCode\":25},{\"clickType\":0,\"deviceId\":\"io.github.sds100.keymapper.THIS_DEVICE\",\"keyCode\":24}],\"mode\":0}", - "[{\"data\":\"volume_up\",\"extras\":[],\"flags\":5,\"type\":\"SYSTEM_ACTION\"},{\"data\":\"com.android.settings\",\"extras\":[],\"flags\":4,\"type\":\"APP\"}]", - "[]", - 1, - 0, - "NULL", - 1, - ), - arrayOf( - 2, - "{\"extras\":[{\"data\":\"365\",\"id\":\"extra_vibration_duration\"}],\"keys\":[{\"clickType\":0,\"deviceId\":\"io.github.sds100.keymapper.THIS_DEVICE\",\"keyCode\":25}],\"mode\":2}", - "[{\"data\":\"7\",\"extras\":[{\"data\":\"5000\",\"id\":\"extra_hold_down_until_repeat_delay\"},{\"data\":\"575\",\"id\":\"extra_repeat_delay\"}],\"flags\":6,\"type\":\"KEY_EVENT\"}]", - "[]", - 1, - 1, - "NULL", - 1, - ), - ) - - private val MIGRATION_5_6_TEST_DATA = arrayOf( - arrayOf( - 1, - "{\"extras\":[{\"data\":\"2930\",\"id\":\"extra_sequence_trigger_timeout\"},{\"data\":\"1840\",\"id\":\"extra_long_press_delay\"},{\"data\":\"3580\",\"id\":\"extra_double_press_timeout\"},{\"data\":\"390\",\"id\":\"extra_vibration_duration\"}],\"keys\":[{\"clickType\":1,\"deviceId\":\"io.github.sds100.keymapper.THIS_DEVICE\",\"keyCode\":25},{\"clickType\":2,\"deviceId\":\"io.github.sds100.keymapper.THIS_DEVICE\",\"keyCode\":24}],\"mode\":1}", - "[{\"data\":\"volume_up\",\"extras\":[],\"flags\":1,\"type\":\"SYSTEM_ACTION\"}]", - "[]", - 1, - 5, - "NULL", - 1, - ), - ) - - private val MIGRATION_5_6_EXPECTED_DATA = arrayOf( - arrayOf( - 1, - "{\"extras\":[{\"data\":\"2930\",\"id\":\"extra_sequence_trigger_timeout\"},{\"data\":\"1840\",\"id\":\"extra_long_press_delay\"},{\"data\":\"3580\",\"id\":\"extra_double_press_timeout\"},{\"data\":\"390\",\"id\":\"extra_vibration_duration\"}],\"flags\":5,\"keys\":[{\"clickType\":1,\"deviceId\":\"io.github.sds100.keymapper.THIS_DEVICE\",\"keyCode\":25},{\"clickType\":2,\"deviceId\":\"io.github.sds100.keymapper.THIS_DEVICE\",\"keyCode\":24}],\"mode\":1}", - "[{\"data\":\"volume_up\",\"extras\":[],\"flags\":1,\"type\":\"SYSTEM_ACTION\"}]", - "[]", - 1, - 0, - "NULL", - 1, - ), - ) - - private val MIGRATION_9_10_TEST_DATA = arrayOf( - arrayOf( - 1, - "{\"extras\":[],\"flags\":0,\"keys\":[],\"mode\":2}", - "[{\"data\":\"com.google.android.contacts\",\"extras\":[],\"flags\":2,\"type\":\"APP\",\"uid\":\"dc2d8c69-aaa5-4471-b981-17cba7677c1a\"}]", - "[]", - 1, - 0, - "", - 1, - "d314e9e8-fac9-43e7-b540-0b9c0bfb4238", - ), - arrayOf( - 2, - "{\"extras\":[],\"flags\":1,\"keys\":[{\"clickType\":0,\"deviceId\":\"io.github.sds100.keymapper.THIS_DEVICE\",\"flags\":0,\"keyCode\":25,\"uid\":\"9d5d6f0b-1b9a-44ba-9406-1caaacea05de\"}],\"mode\":2}", - "[{\"data\":\"com.discord\",\"extras\":[],\"flags\":2,\"type\":\"APP\",\"uid\":\"86c78374-59ce-4050-94a4-299f4778658f\"}]", - "[]", - 1, - 0, - "", - 1, - "b854ece7-2f0e-45c4-9cf3-bb5aa4fad288", - ), - arrayOf( - 3, - "{\"extras\":[],\"flags\":0,\"keys\":[],\"mode\":2}", - "[{\"data\":\"com.google.android.vr.home\",\"extras\":[],\"flags\":2,\"type\":\"APP\",\"uid\":\"ca5b18ee-2673-4443-b2a7-cedef2c455b2\"},{\"data\":\"com.google.android.calendar\",\"extras\":[],\"flags\":0,\"type\":\"APP\",\"uid\":\"d274a5a8-f48e-4fbf-acbd-ed3c4b4ff377\"},{\"data\":\"enable_mobile_data\",\"extras\":[],\"flags\":2,\"type\":\"SYSTEM_ACTION\",\"uid\":\"f6b2afc5-4265-403d-8a0f-4eacf245286f\"}]", - "[]", - 1, - 0, - "", - 1, - "75ab7552-c175-4df4-9f50-1a9b86e717cc", - ), - ) - - private val MIGRATION_9_10_EXPECTED_DATA = arrayOf( - arrayOf( - 1, - "{\"extras\":[],\"flags\":16,\"keys\":[],\"mode\":2}", - "[{\"data\":\"com.google.android.contacts\",\"extras\":[],\"flags\":0,\"type\":\"APP\",\"uid\":\"dc2d8c69-aaa5-4471-b981-17cba7677c1a\"}]", - "[]", - 1, - 0, - "", - 1, - "d314e9e8-fac9-43e7-b540-0b9c0bfb4238", - ), - arrayOf( - 2, - "{\"extras\":[],\"flags\":17,\"keys\":[{\"clickType\":0,\"deviceId\":\"io.github.sds100.keymapper.THIS_DEVICE\",\"flags\":0,\"keyCode\":25,\"uid\":\"9d5d6f0b-1b9a-44ba-9406-1caaacea05de\"}],\"mode\":2}", - "[{\"data\":\"com.discord\",\"extras\":[],\"flags\":0,\"type\":\"APP\",\"uid\":\"86c78374-59ce-4050-94a4-299f4778658f\"}]", - "[]", - 1, - 0, - "", - 1, - "b854ece7-2f0e-45c4-9cf3-bb5aa4fad288", - ), - arrayOf( - 3, - "{\"extras\":[],\"flags\":16,\"keys\":[],\"mode\":2}", - "[{\"data\":\"com.google.android.vr.home\",\"extras\":[],\"flags\":0,\"type\":\"APP\",\"uid\":\"ca5b18ee-2673-4443-b2a7-cedef2c455b2\"},{\"data\":\"com.google.android.calendar\",\"extras\":[],\"flags\":0,\"type\":\"APP\",\"uid\":\"d274a5a8-f48e-4fbf-acbd-ed3c4b4ff377\"},{\"data\":\"enable_mobile_data\",\"extras\":[],\"flags\":0,\"type\":\"SYSTEM_ACTION\",\"uid\":\"f6b2afc5-4265-403d-8a0f-4eacf245286f\"}]", - "[]", - 1, - 0, - "", - 1, - "75ab7552-c175-4df4-9f50-1a9b86e717cc", - ), - ) - } - - @get:Rule - val helper: MigrationTestHelper = MigrationTestHelper( - InstrumentationRegistry.getInstrumentation(), - AppDatabase::class.java.canonicalName, - FrameworkSQLiteOpenHelperFactory(), - ) - - private val coroutineScope = MainScope() - - private lateinit var jsonParser: JsonParser - private lateinit var gson: Gson - - @Before - fun init() { - jsonParser = JsonParser() - gson = Gson() - } - - /** - * issue #612 - */ - @Test - @Throws(IOException::class) - fun migrate11to12() { - val legacyFingerprintMapsDataStore = PreferenceDataStoreFactory.create( - corruptionHandler = null, - migrations = emptyList(), - scope = coroutineScope, - produceFile = { File.createTempFile("test", ".preferences_pb") }, - ) - - val testDataFileName = "migration-11-12-test-data.json" - val expectedDataFileName = "migration-11-12-expected-data.json" - val testDataJson = getJsonFileText(testDataFileName) - - runBlocking { - val rootElement = jsonParser.parse(testDataJson) - - legacyFingerprintMapsDataStore.edit { preferences -> - preferences.putAll( - stringPreferencesKey("swipe_down") to gson.toJson(rootElement["fingerprint_swipe_down"]), - stringPreferencesKey("swipe_up") to gson.toJson(rootElement["fingerprint_swipe_up"]), - stringPreferencesKey("swipe_left") to gson.toJson(rootElement["fingerprint_swipe_left"]), - stringPreferencesKey("swipe_right") to gson.toJson(rootElement["fingerprint_swipe_right"]), - ) - } - } - - val fromVersion = 11 - val toVersion = 12 - val migration = AppDatabase.RoomMigration11To12(legacyFingerprintMapsDataStore) - val keyMapColumnNameToJsonNameMap = mapOf( - "id" to "id", - "trigger" to "trigger", - "action_list" to "actionList", - "constraint_list" to "constraintList", - "constraint_mode" to "constraintMode", - "flags" to "flags", - "folder_name" to "folderName", - "is_enabled" to "isEnabled", - "uid" to "uid", - ) - val fingerprintMapColumnNameToJsonNameMap = mapOf( - "id" to "id", - "action_list" to "action_list", - "constraint_list" to "constraints", - "constraint_mode" to "constraint_mode", - "extras" to "extras", - "flags" to "flags", - "is_enabled" to "enabled", - ) - - // do this without using the test() method because fingerprint maps are stored differently in test file - - helper.createDatabase(TEST_DB_NAME, fromVersion).apply { - val keyMapJsonArray = getKeyMapListJsonFromFile(testDataFileName) - insertMappingListJsonIntoDatabase( - this, - keyMapJsonArray, - keyMapColumnNameToJsonNameMap, - "keymaps", - ) - - val deviceInfoJsonArray = jsonParser.parse(testDataJson)["device_info"].asJsonArray - - deviceInfoJsonArray.forEach { element -> - - val descriptor = element["descriptor"].asString - val name = element["name"].asString - - this.execSQL( - """ - INSERT INTO deviceinfo (descriptor, name) VALUES ('$descriptor', '$name') - """, - ) - } - // dont insert test data fingerprintmaps into database because they weren't in version 11 - } - - val db = helper.runMigrationsAndValidate(TEST_DB_NAME, toVersion, true, migration) - - val expectedKeyMapJsonList = - getKeyMapListJsonFromFile(expectedDataFileName).map { element -> - - val values = keyMapColumnNameToJsonNameMap.values.map { key -> - element.convertValueToJson(key).convertJsonValueToSqlValue() - } - - values.toTypedArray() - } - - testColumnsMatch(db, tableName = "keymaps", expectedKeyMapJsonList.toTypedArray()) - - val expectedFingerprintMapJsonList = - getFingerprintMapListJsonFromFile(expectedDataFileName).map { element -> - val values = fingerprintMapColumnNameToJsonNameMap.values.map { key -> - element.convertValueToJson(key).convertJsonValueToSqlValue() - } - - values.toTypedArray() - } - - testColumnsMatch( - db, - tableName = "fingerprintmaps", - expectedFingerprintMapJsonList.toTypedArray(), - ) - } - - /** - * issue #621 - */ - @Test - @Throws(IOException::class) - fun migrate10to11() { - test( - fromVersion = 10, - toVersion = 11, - migration = AppDatabase.MIGRATION_10_11, - testDataFileName = "migration-10-11-test-data.json", - expectedDataFileName = "migration-10-11-expected-data.json", - keyMapColumnNameToJsonNameMap = mapOf( - "id" to "id", - "trigger" to "trigger", - "action_list" to "actionList", - "constraint_list" to "constraintList", - "constraint_mode" to "constraintMode", - "flags" to "flags", - "folder_name" to "folderName", - "is_enabled" to "isEnabled", - "uid" to "uid", - ), - ) - } - - @Suppress("VARIABLE_WITH_REDUNDANT_INITIALIZER") - @Test - @Throws(IOException::class) - fun migrate9to10() { - var db = helper.createDatabase(TEST_DB_NAME, 9).apply { - MIGRATION_9_10_TEST_DATA.forEach { row -> - - execSQL( - """ - INSERT INTO keymaps (id, trigger, action_list, constraint_list, constraint_mode, flags, folder_name, is_enabled, uid) - VALUES (${row.joinToString { "'$it'" }}) - """, - ) - } - close() - } - - db = helper.runMigrationsAndValidate(TEST_DB_NAME, 10, true, AppDatabase.MIGRATION_9_10) - - testColumnsMatch(db, tableName = "keymaps", MIGRATION_9_10_EXPECTED_DATA) - } - - @Suppress("VARIABLE_WITH_REDUNDANT_INITIALIZER") - @Test - @Throws(IOException::class) - fun migrate5to6() { - var db = helper.createDatabase(TEST_DB_NAME, 5).apply { - MIGRATION_5_6_TEST_DATA.forEach { row -> - - execSQL( - """ - INSERT INTO keymaps (id, trigger, action_list, constraint_list, constraint_mode, flags, folder_name, is_enabled) - VALUES (${row.joinToString { "'$it'" }}) - """, - ) - } - close() - } - - db = helper.runMigrationsAndValidate(TEST_DB_NAME, 6, true, AppDatabase.MIGRATION_5_6) - - testColumnsMatch(db, tableName = "keymaps", MIGRATION_5_6_EXPECTED_DATA) - } - - @Suppress("VARIABLE_WITH_REDUNDANT_INITIALIZER") - @Test - @Throws(IOException::class) - fun migrate4to5() { - var db = helper.createDatabase(TEST_DB_NAME, 4).apply { - MIGRATION_4_5_TEST_DATA.forEach { row -> - - execSQL( - """ - INSERT INTO keymaps (id, trigger, action_list, constraint_list, constraint_mode, flags, folder_name, is_enabled) - VALUES (${row.joinToString { "'$it'" }}) - """, - ) - } - close() - } - - db = helper.runMigrationsAndValidate(TEST_DB_NAME, 5, true, AppDatabase.MIGRATION_4_5) - - testColumnsMatch(db, tableName = "keymaps", MIGRATION_4_5_EXPECTED_DATA) - } - - @Suppress("VARIABLE_WITH_REDUNDANT_INITIALIZER") - @Test - @Throws(IOException::class) - fun migrate3to4() { - var db = helper.createDatabase(TEST_DB_NAME, 3).apply { - MIGRATION_3_4_TEST_DATA.forEach { row -> - - execSQL( - """ - INSERT INTO keymaps (id, trigger, action_list, constraint_list, constraint_mode, flags, folder_name, is_enabled) - VALUES (${row.joinToString { "'$it'" }}) - """, - ) - } - close() - } - - db = helper.runMigrationsAndValidate(TEST_DB_NAME, 4, true, AppDatabase.MIGRATION_3_4) - - testColumnsMatch(db, tableName = "keymaps", MIGRATION_3_4_EXPECTED_DATA) - } - - @Suppress("VARIABLE_WITH_REDUNDANT_INITIALIZER") - @Test - @Throws(IOException::class) - fun migrate2to3() { - var db = helper.createDatabase(TEST_DB_NAME, 2).apply { - MIGRATION_2_3_TEST_DATA.forEach { row -> - - execSQL( - """ - INSERT INTO keymaps (id, trigger, action_list, constraint_list, constraint_mode, flags, folder_name, is_enabled) - VALUES (${row.joinToString { "'$it'" }}) - """, - ) - } - close() - } - - db = helper.runMigrationsAndValidate(TEST_DB_NAME, 3, true, AppDatabase.MIGRATION_2_3) - - testColumnsMatch(db, tableName = "keymaps", MIGRATION_2_3_EXPECTED_DATA) - } - - @Suppress("VARIABLE_WITH_REDUNDANT_INITIALIZER") - @Test - @Throws(IOException::class) - fun migrate1to2() { - var db = helper.createDatabase(TEST_DB_NAME, 1).apply { - MIGRATION_1_2_TEST_DATA.forEach { row -> - - execSQL( - """ - INSERT INTO keymaps (id, trigger_list, flags, is_enabled, action_type, action_data, action_extras) - VALUES (${row.joinToString { "'$it'" }}) - """, - ) - } - - close() - } - - db = helper.runMigrationsAndValidate(TEST_DB_NAME, 2, true, AppDatabase.MIGRATION_1_2) - testColumnsMatch(db, tableName = "keymaps", MIGRATION_1_2_EXPECTED_DATA) - } - - private fun test( - fromVersion: Int, - toVersion: Int, - migration: Migration, - testDataFileName: String, - expectedDataFileName: String, - keyMapColumnNameToJsonNameMap: Map, - fingerprintMapColumnNameToJsonNameMap: Map? = null, - ) { - helper.createDatabase(TEST_DB_NAME, fromVersion).apply { - val keyMapJsonArray = getKeyMapListJsonFromFile(testDataFileName) - insertMappingListJsonIntoDatabase( - this, - keyMapJsonArray, - keyMapColumnNameToJsonNameMap, - "keymaps", - ) - - if (fingerprintMapColumnNameToJsonNameMap != null) { - val fingerprintMapJsonArray = getFingerprintMapListJsonFromFile(testDataFileName) - insertMappingListJsonIntoDatabase( - this, - fingerprintMapJsonArray, - fingerprintMapColumnNameToJsonNameMap, - "fingerprintmaps", - ) - } - } - - val db = helper.runMigrationsAndValidate(TEST_DB_NAME, toVersion, true, migration) - - val expectedKeyMapJsonList = - getKeyMapListJsonFromFile(expectedDataFileName).map { element -> - - val values = keyMapColumnNameToJsonNameMap.values.map { key -> - element.convertValueToJson(key).convertJsonValueToSqlValue() - } - - values.toTypedArray() - } - - testColumnsMatch(db, tableName = "keymaps", expectedKeyMapJsonList.toTypedArray()) - - if (fingerprintMapColumnNameToJsonNameMap != null) { - val expectedFingerprintMapJsonList = - getFingerprintMapListJsonFromFile(expectedDataFileName).map { element -> - val values = fingerprintMapColumnNameToJsonNameMap.values.map { key -> - element.convertValueToJson(key).convertJsonValueToSqlValue() - } - - values.toTypedArray() - } - - testColumnsMatch( - db, - tableName = "fingerprintmaps", - expectedFingerprintMapJsonList.toTypedArray(), - ) - } - } - - private fun insertMappingListJsonIntoDatabase( - database: SupportSQLiteDatabase, - mappingListJson: JsonArray, - columnNameToJsonMap: Map, - tableName: String, - ) { - mappingListJson.forEach { element -> - val jsonElementNames = columnNameToJsonMap.values - - val values = jsonElementNames.map { key -> - element.convertValueToJson(key).convertJsonValueToSqlValue() - } - - database.execSQL( - """ - INSERT INTO $tableName (${columnNameToJsonMap.keys.joinToString()}) - VALUES (${values.joinToString { "'$it'" }}) - """, - ) - } - } - - private fun String?.convertJsonValueToSqlValue() = - when { - this == null -> "NULL" - this == "true" -> 1 - this == "false" -> 0 - this.toIntOrNull() != null -> this.toInt() - else -> this - } - - private fun JsonElement.convertValueToJson(key: String) = try { - gson.toJson(this[key]) - } catch (e: NoSuchElementException) { - null - } - - private fun getKeyMapListJsonFromFile(fileName: String): JsonArray { - val json = getJsonFileText(fileName) - - val rootElement = jsonParser.parse(json) - - return rootElement["keymap_list"].asJsonArray - } - - private fun getFingerprintMapListJsonFromFile(fileName: String): JsonArray { - val json = getJsonFileText(fileName) - - val rootElement = jsonParser.parse(json) - - return rootElement["fingerprint_map_list"].asJsonArray - } - - private fun getJsonFileText(fileName: String): String { - val inputStream = - this.javaClass.classLoader!!.getResourceAsStream("json-migration-test/$fileName") - return inputStream.bufferedReader().use { it.readText() } - } - - private fun testColumnsMatch( - db: SupportSQLiteDatabase, - tableName: String, - expectedData: Array>, - ) { - val cursor = db.query("SELECT * FROM $tableName") - - ViewMatchers.assertThat("Check the logcat", cursor.count, Matchers.`is`(expectedData.size)) - - while (cursor.moveToNext()) { - val row = cursor.position - val expectedColumnValues: Array = expectedData[row] - - cursor.columnNames.forEachIndexed { columnIndex, columnName -> - - val expectedColumnValue = expectedColumnValues[columnIndex] - - val columnValue: Any = when (expectedColumnValue) { - is Int -> cursor.getInt(columnIndex) - is String -> cursor.getString(columnIndex) - else -> throw Exception("Don't know how to get this type ${expectedColumnValue::class.simpleName} from cursor") - } - - when (expectedColumnValue) { - is Int -> ViewMatchers.assertThat( - "$columnName at row $row doesn't match", - columnValue, - Matchers.`is`(expectedColumnValue), - ) - is String -> { - try { - JsonTestUtils.compareBothWays( - element = jsonParser.parse(expectedColumnValue), - elementName = "expected $columnName at row $row", - other = jsonParser.parse(columnValue as String), - otherName = "migrated $columnName at row $row", - ) - } catch (e: JsonParseException) { - ViewMatchers.assertThat( - "$columnName at row $row doesn't match", - columnValue, - Matchers.`is`(expectedColumnValue), - ) - } - } - } - } - } - } -} diff --git a/app/src/debug/res/values/strings.xml b/app/src/debug/res/values/strings.xml index 0e97b14435..bc42450e26 100644 --- a/app/src/debug/res/values/strings.xml +++ b/app/src/debug/res/values/strings.xml @@ -1,5 +1,5 @@ - Key Mapper Debug + Key Mapper Debug Key Mapper Debug Basic Input Method \ No newline at end of file diff --git a/app/src/free/java/io/github/sds100/keymapper/MainActivity.kt b/app/src/free/java/io/github/sds100/keymapper/MainActivity.kt deleted file mode 100644 index 51dddd9b2e..0000000000 --- a/app/src/free/java/io/github/sds100/keymapper/MainActivity.kt +++ /dev/null @@ -1,3 +0,0 @@ -package io.github.sds100.keymapper - -class MainActivity : BaseMainActivity() diff --git a/app/src/free/java/io/github/sds100/keymapper/floating/FloatingLayoutsScreen.kt b/app/src/free/java/io/github/sds100/keymapper/floating/FloatingLayoutsScreen.kt deleted file mode 100644 index ed0f903e9e..0000000000 --- a/app/src/free/java/io/github/sds100/keymapper/floating/FloatingLayoutsScreen.kt +++ /dev/null @@ -1,15 +0,0 @@ -package io.github.sds100.keymapper.floating - -import androidx.compose.foundation.lazy.LazyListState -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import androidx.navigation.NavHostController - -@Composable -fun FloatingLayoutsScreen( - modifier: Modifier = Modifier, - viewModel: ListFloatingLayoutsViewModel, - navController: NavHostController, - lazyListState: LazyListState, -) { -} diff --git a/app/src/free/java/io/github/sds100/keymapper/floating/ListFloatingLayoutsUseCase.kt b/app/src/free/java/io/github/sds100/keymapper/floating/ListFloatingLayoutsUseCase.kt deleted file mode 100644 index 5a1a8786de..0000000000 --- a/app/src/free/java/io/github/sds100/keymapper/floating/ListFloatingLayoutsUseCase.kt +++ /dev/null @@ -1,23 +0,0 @@ -package io.github.sds100.keymapper.floating - -import io.github.sds100.keymapper.data.repositories.FloatingLayoutRepository -import io.github.sds100.keymapper.data.repositories.PreferenceRepository -import io.github.sds100.keymapper.purchasing.PurchasingManager -import io.github.sds100.keymapper.system.accessibility.ServiceAdapter -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.flowOf - -interface ListFloatingLayoutsUseCase { - val showFloatingLayouts: Flow -} - -class ListFloatingLayoutsUseCaseImpl( - private val repository: FloatingLayoutRepository, - private val purchasingManager: PurchasingManager, - private val serviceAdapter: ServiceAdapter, - private val preferences: PreferenceRepository, -) : ListFloatingLayoutsUseCase, - PurchasingManager by purchasingManager { - - override val showFloatingLayouts: Flow = flowOf(false) -} diff --git a/app/src/free/java/io/github/sds100/keymapper/floating/ListFloatingLayoutsViewModel.kt b/app/src/free/java/io/github/sds100/keymapper/floating/ListFloatingLayoutsViewModel.kt deleted file mode 100644 index f3e8a9dd9a..0000000000 --- a/app/src/free/java/io/github/sds100/keymapper/floating/ListFloatingLayoutsViewModel.kt +++ /dev/null @@ -1,26 +0,0 @@ -package io.github.sds100.keymapper.floating - -import io.github.sds100.keymapper.util.ui.PopupViewModel -import io.github.sds100.keymapper.util.ui.PopupViewModelImpl -import io.github.sds100.keymapper.util.ui.ResourceProvider -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.StateFlow - -class ListFloatingLayoutsViewModel( - val coroutineScope: CoroutineScope, - val useCase: ListFloatingLayoutsUseCase, - resourceProvider: ResourceProvider, -) : PopupViewModel by PopupViewModelImpl() { - val state: StateFlow = MutableStateFlow(FloatingLayoutsState.NotPurchased) - val showFabText: Boolean = false - - fun onNewLayoutClick() { - } -} - -sealed class FloatingLayoutsState { - data object Loading : FloatingLayoutsState() - data object NotPurchased : FloatingLayoutsState() - data object Purchased : FloatingLayoutsState() -} diff --git a/app/src/free/java/io/github/sds100/keymapper/home/HomeFloatingLayoutsScreen.kt b/app/src/free/java/io/github/sds100/keymapper/home/HomeFloatingLayoutsScreen.kt deleted file mode 100644 index aca43b669c..0000000000 --- a/app/src/free/java/io/github/sds100/keymapper/home/HomeFloatingLayoutsScreen.kt +++ /dev/null @@ -1,18 +0,0 @@ -package io.github.sds100.keymapper.home - -import androidx.compose.material3.SnackbarHostState -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import androidx.compose.ui.unit.Dp -import androidx.navigation.NavHostController -import io.github.sds100.keymapper.floating.ListFloatingLayoutsViewModel - -@Composable -fun HomeFloatingLayoutsScreen( - modifier: Modifier = Modifier, - viewModel: ListFloatingLayoutsViewModel, - navController: NavHostController, - snackbarState: SnackbarHostState, - fabBottomPadding: Dp, -) { -} diff --git a/app/src/free/java/io/github/sds100/keymapper/purchasing/PurchasingManagerImpl.kt b/app/src/free/java/io/github/sds100/keymapper/purchasing/PurchasingManagerImpl.kt deleted file mode 100644 index 88a2d9a5ee..0000000000 --- a/app/src/free/java/io/github/sds100/keymapper/purchasing/PurchasingManagerImpl.kt +++ /dev/null @@ -1,33 +0,0 @@ -package io.github.sds100.keymapper.purchasing - -import android.content.Context -import io.github.sds100.keymapper.util.Error -import io.github.sds100.keymapper.util.Result -import io.github.sds100.keymapper.util.State -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.MutableSharedFlow -import kotlinx.coroutines.flow.MutableStateFlow - -class PurchasingManagerImpl( - context: Context, - private val coroutineScope: CoroutineScope, -) : PurchasingManager { - override val onCompleteProductPurchase: MutableSharedFlow = MutableSharedFlow() - override val purchases: Flow>>> = - MutableStateFlow(State.Data(Error.PurchasingNotImplemented)) - - override suspend fun launchPurchasingFlow(product: ProductId): Result { - return Error.PurchasingNotImplemented - } - - override suspend fun getProductPrice(product: ProductId): Result { - return Error.PurchasingNotImplemented - } - - override suspend fun isPurchased(product: ProductId): Result { - return Error.PurchasingNotImplemented - } - - override fun refresh() {} -} diff --git a/app/src/free/java/io/github/sds100/keymapper/system/accessibility/AccessibilityServiceController.kt b/app/src/free/java/io/github/sds100/keymapper/system/accessibility/AccessibilityServiceController.kt deleted file mode 100644 index 44c0fcc963..0000000000 --- a/app/src/free/java/io/github/sds100/keymapper/system/accessibility/AccessibilityServiceController.kt +++ /dev/null @@ -1,51 +0,0 @@ -package io.github.sds100.keymapper.system.accessibility - -import io.github.sds100.keymapper.actions.PerformActionsUseCase -import io.github.sds100.keymapper.constraints.DetectConstraintsUseCase -import io.github.sds100.keymapper.data.repositories.AccessibilityNodeRepository -import io.github.sds100.keymapper.data.repositories.PreferenceRepository -import io.github.sds100.keymapper.keymaps.FingerprintGesturesSupportedUseCase -import io.github.sds100.keymapper.keymaps.PauseKeyMapsUseCase -import io.github.sds100.keymapper.keymaps.detection.DetectKeyMapsUseCase -import io.github.sds100.keymapper.reroutekeyevents.RerouteKeyEventsUseCase -import io.github.sds100.keymapper.system.devices.DevicesAdapter -import io.github.sds100.keymapper.system.inputmethod.InputMethodAdapter -import io.github.sds100.keymapper.system.root.SuAdapter -import io.github.sds100.keymapper.util.ServiceEvent -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.flow.MutableSharedFlow -import kotlinx.coroutines.flow.SharedFlow - -class AccessibilityServiceController( - coroutineScope: CoroutineScope, - accessibilityService: MyAccessibilityService, - inputEvents: SharedFlow, - outputEvents: MutableSharedFlow, - detectConstraintsUseCase: DetectConstraintsUseCase, - performActionsUseCase: PerformActionsUseCase, - detectKeyMapsUseCase: DetectKeyMapsUseCase, - fingerprintGesturesSupportedUseCase: FingerprintGesturesSupportedUseCase, - rerouteKeyEventsUseCase: RerouteKeyEventsUseCase, - pauseKeyMapsUseCase: PauseKeyMapsUseCase, - devicesAdapter: DevicesAdapter, - suAdapter: SuAdapter, - inputMethodAdapter: InputMethodAdapter, - settingsRepository: PreferenceRepository, - nodeRepository: AccessibilityNodeRepository, -) : BaseAccessibilityServiceController( - coroutineScope, - accessibilityService, - inputEvents, - outputEvents, - detectConstraintsUseCase, - performActionsUseCase, - detectKeyMapsUseCase, - fingerprintGesturesSupportedUseCase, - rerouteKeyEventsUseCase, - pauseKeyMapsUseCase, - devicesAdapter, - suAdapter, - inputMethodAdapter, - settingsRepository, - nodeRepository, -) diff --git a/app/src/free/java/io/github/sds100/keymapper/trigger/AssistantTriggerSetupBottomSheet.kt b/app/src/free/java/io/github/sds100/keymapper/trigger/AssistantTriggerSetupBottomSheet.kt deleted file mode 100644 index 8c3c7cbd59..0000000000 --- a/app/src/free/java/io/github/sds100/keymapper/trigger/AssistantTriggerSetupBottomSheet.kt +++ /dev/null @@ -1,9 +0,0 @@ -package io.github.sds100.keymapper.trigger - -import androidx.compose.runtime.Composable - -@Composable -fun HandleAssistantTriggerSetupBottomSheet( - viewModel: ConfigTriggerViewModel, -) { -} diff --git a/app/src/free/java/io/github/sds100/keymapper/trigger/ConfigTriggerViewModel.kt b/app/src/free/java/io/github/sds100/keymapper/trigger/ConfigTriggerViewModel.kt deleted file mode 100644 index 89a8da1b07..0000000000 --- a/app/src/free/java/io/github/sds100/keymapper/trigger/ConfigTriggerViewModel.kt +++ /dev/null @@ -1,37 +0,0 @@ -package io.github.sds100.keymapper.trigger - -import io.github.sds100.keymapper.keymaps.ConfigKeyMapUseCase -import io.github.sds100.keymapper.keymaps.CreateKeyMapShortcutUseCase -import io.github.sds100.keymapper.keymaps.DisplayKeyMapUseCase -import io.github.sds100.keymapper.keymaps.FingerprintGesturesSupportedUseCase -import io.github.sds100.keymapper.onboarding.OnboardingUseCase -import io.github.sds100.keymapper.purchasing.PurchasingManager -import io.github.sds100.keymapper.util.ui.ResourceProvider -import kotlinx.coroutines.CoroutineScope - -class ConfigTriggerViewModel( - coroutineScope: CoroutineScope, - onboarding: OnboardingUseCase, - config: ConfigKeyMapUseCase, - recordTrigger: RecordTriggerUseCase, - createKeyMapShortcut: CreateKeyMapShortcutUseCase, - displayKeyMap: DisplayKeyMapUseCase, - resourceProvider: ResourceProvider, - purchasingManager: PurchasingManager, - setupGuiKeyboardUseCase: SetupGuiKeyboardUseCase, - fingerprintGesturesSupported: FingerprintGesturesSupportedUseCase, -) : BaseConfigTriggerViewModel( - coroutineScope, - onboarding, - config, - recordTrigger, - createKeyMapShortcut, - displayKeyMap, - purchasingManager, - setupGuiKeyboardUseCase, - fingerprintGesturesSupported, - resourceProvider, -) { - fun onEditFloatingButtonClick() {} - fun onEditFloatingLayoutClick() {} -} diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 1f8d932dfb..fd3a99ee47 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -2,78 +2,13 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + tools:ignore="GoogleAppIndexingWarning,MissingTvBanner"> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/java/io/github/sds100/keymapper/ActivityViewModel.kt b/app/src/main/java/io/github/sds100/keymapper/ActivityViewModel.kt deleted file mode 100644 index 8fefdddbe4..0000000000 --- a/app/src/main/java/io/github/sds100/keymapper/ActivityViewModel.kt +++ /dev/null @@ -1,44 +0,0 @@ -package io.github.sds100.keymapper - -import androidx.lifecycle.ViewModel -import androidx.lifecycle.ViewModelProvider -import androidx.lifecycle.viewModelScope -import io.github.sds100.keymapper.util.ui.NavigationViewModel -import io.github.sds100.keymapper.util.ui.NavigationViewModelImpl -import io.github.sds100.keymapper.util.ui.PopupViewModel -import io.github.sds100.keymapper.util.ui.PopupViewModelImpl -import io.github.sds100.keymapper.util.ui.ResourceProvider -import io.github.sds100.keymapper.util.ui.ViewModelHelper -import kotlinx.coroutines.launch - -/** - * Created by sds100 on 23/07/2021. - */ -class ActivityViewModel( - resourceProvider: ResourceProvider, -) : ViewModel(), - ResourceProvider by resourceProvider, - PopupViewModel by PopupViewModelImpl(), - NavigationViewModel by NavigationViewModelImpl() { - - var handledActivityLaunchIntent: Boolean = false - var previousNightMode: Int? = null - - fun onCantFindAccessibilitySettings() { - viewModelScope.launch { - ViewModelHelper.handleCantFindAccessibilitySettings( - resourceProvider = this@ActivityViewModel, - popupViewModel = this@ActivityViewModel, - ) - } - } - - @Suppress("UNCHECKED_CAST") - class Factory( - private val resourceProvider: ResourceProvider, - ) : ViewModelProvider.NewInstanceFactory() { - - override fun create(modelClass: Class): T = - ActivityViewModel(resourceProvider) as T - } -} diff --git a/app/src/main/java/io/github/sds100/keymapper/AppHiltModule.kt b/app/src/main/java/io/github/sds100/keymapper/AppHiltModule.kt new file mode 100644 index 0000000000..286adf22ad --- /dev/null +++ b/app/src/main/java/io/github/sds100/keymapper/AppHiltModule.kt @@ -0,0 +1,60 @@ +package io.github.sds100.keymapper + +import android.os.Build +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent +import io.github.sds100.keymapper.base.purchasing.PurchasingManager +import io.github.sds100.keymapper.common.BuildConfigProvider +import io.github.sds100.keymapper.common.KeyMapperClassProvider +import io.github.sds100.keymapper.common.utils.DefaultDispatcherProvider +import io.github.sds100.keymapper.common.utils.DispatcherProvider +import io.github.sds100.keymapper.purchasing.PurchasingManagerImpl +import io.github.sds100.keymapper.system.accessibility.MyAccessibilityService +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.MainScope +import javax.inject.Singleton + +@Module +@InstallIn(SingletonComponent::class) +class AppHiltModule { + @Singleton + @Provides + fun provideCoroutineScope(): CoroutineScope = MainScope() + + @Provides + @Singleton + fun provideDispatchers(): DispatcherProvider = DefaultDispatcherProvider() + + @Singleton + @Provides + fun provideBuildConfigProvider(): BuildConfigProvider = object : BuildConfigProvider { + override val minApi: Int + get() = Build.VERSION_CODES.LOLLIPOP + override val maxApi: Int + get() = 1000 + override val packageName: String + get() = BuildConfig.APPLICATION_ID + override val version: String + get() = BuildConfig.VERSION_NAME + override val versionCode: Int + get() = BuildConfig.VERSION_CODE + } + + @Singleton + @Provides + fun provideClassProvider(): KeyMapperClassProvider = object : KeyMapperClassProvider { + override fun getMainActivity(): Class<*> { + return MainActivity::class.java + } + + override fun getAccessibilityService(): Class<*> { + return MyAccessibilityService::class.java + } + } + + @Provides + @Singleton + fun providePurchasingManager(): PurchasingManager = PurchasingManagerImpl() +} diff --git a/app/src/main/java/io/github/sds100/keymapper/Constants.kt b/app/src/main/java/io/github/sds100/keymapper/Constants.kt deleted file mode 100644 index 7ba1f736d8..0000000000 --- a/app/src/main/java/io/github/sds100/keymapper/Constants.kt +++ /dev/null @@ -1,15 +0,0 @@ -package io.github.sds100.keymapper - -import android.os.Build - -/** - * Created by sds100 on 22/11/2018. - */ -object Constants { - const val MIN_API = Build.VERSION_CODES.LOLLIPOP - const val MAX_API = 1000 - const val PACKAGE_NAME = BuildConfig.APPLICATION_ID - const val VERSION = BuildConfig.VERSION_NAME - const val VERSION_CODE = BuildConfig.VERSION_CODE - const val MIN_API_FLOATING_BUTTONS = Build.VERSION_CODES.R -} diff --git a/app/src/main/java/io/github/sds100/keymapper/KeyMapperApp.kt b/app/src/main/java/io/github/sds100/keymapper/KeyMapperApp.kt index 5519d434ce..eb29f31ee0 100644 --- a/app/src/main/java/io/github/sds100/keymapper/KeyMapperApp.kt +++ b/app/src/main/java/io/github/sds100/keymapper/KeyMapperApp.kt @@ -1,320 +1,13 @@ package io.github.sds100.keymapper import android.annotation.SuppressLint -import android.content.Intent -import android.os.Build -import android.os.UserManager -import android.util.Log -import androidx.appcompat.app.AppCompatDelegate -import androidx.core.content.getSystemService -import androidx.lifecycle.Lifecycle -import androidx.lifecycle.LifecycleObserver -import androidx.lifecycle.OnLifecycleEvent -import androidx.lifecycle.ProcessLifecycleOwner -import androidx.multidex.MultiDexApplication -import io.github.sds100.keymapper.actions.uielement.InteractUiElementController -import io.github.sds100.keymapper.data.Keys -import io.github.sds100.keymapper.data.entities.LogEntryEntity -import io.github.sds100.keymapper.logging.KeyMapperLoggingTree -import io.github.sds100.keymapper.purchasing.PurchasingManagerImpl -import io.github.sds100.keymapper.settings.ThemeUtils -import io.github.sds100.keymapper.shizuku.ShizukuAdapterImpl -import io.github.sds100.keymapper.system.AndroidSystemFeatureAdapter -import io.github.sds100.keymapper.system.accessibility.AccessibilityServiceAdapter -import io.github.sds100.keymapper.system.airplanemode.AndroidAirplaneModeAdapter -import io.github.sds100.keymapper.system.apps.AndroidAppShortcutAdapter -import io.github.sds100.keymapper.system.apps.AndroidPackageManagerAdapter -import io.github.sds100.keymapper.system.bluetooth.AndroidBluetoothAdapter -import io.github.sds100.keymapper.system.camera.AndroidCameraAdapter -import io.github.sds100.keymapper.system.clipboard.AndroidClipboardAdapter -import io.github.sds100.keymapper.system.devices.AndroidDevicesAdapter -import io.github.sds100.keymapper.system.display.AndroidDisplayAdapter -import io.github.sds100.keymapper.system.files.AndroidFileAdapter -import io.github.sds100.keymapper.system.inputmethod.AndroidInputMethodAdapter -import io.github.sds100.keymapper.system.inputmethod.AutoSwitchImeController -import io.github.sds100.keymapper.system.inputmethod.ShowHideInputMethodUseCaseImpl -import io.github.sds100.keymapper.system.intents.IntentAdapterImpl -import io.github.sds100.keymapper.system.leanback.LeanbackAdapterImpl -import io.github.sds100.keymapper.system.lock.AndroidLockScreenAdapter -import io.github.sds100.keymapper.system.media.AndroidMediaAdapter -import io.github.sds100.keymapper.system.network.AndroidNetworkAdapter -import io.github.sds100.keymapper.system.nfc.AndroidNfcAdapter -import io.github.sds100.keymapper.system.notifications.AndroidNotificationAdapter -import io.github.sds100.keymapper.system.notifications.ManageNotificationsUseCaseImpl -import io.github.sds100.keymapper.system.notifications.NotificationController -import io.github.sds100.keymapper.system.notifications.NotificationReceiverAdapter -import io.github.sds100.keymapper.system.permissions.AndroidPermissionAdapter -import io.github.sds100.keymapper.system.permissions.AutoGrantPermissionController -import io.github.sds100.keymapper.system.permissions.Permission -import io.github.sds100.keymapper.system.phone.AndroidPhoneAdapter -import io.github.sds100.keymapper.system.popup.AndroidToastAdapter -import io.github.sds100.keymapper.system.power.AndroidPowerAdapter -import io.github.sds100.keymapper.system.ringtones.AndroidRingtoneAdapter -import io.github.sds100.keymapper.system.root.SuAdapterImpl -import io.github.sds100.keymapper.system.url.AndroidOpenUrlAdapter -import io.github.sds100.keymapper.system.vibrator.AndroidVibratorAdapter -import io.github.sds100.keymapper.system.volume.AndroidVolumeAdapter -import io.github.sds100.keymapper.trigger.RecordTriggerController -import io.github.sds100.keymapper.util.ui.ResourceProviderImpl -import kotlinx.coroutines.MainScope -import kotlinx.coroutines.flow.collectLatest -import kotlinx.coroutines.flow.launchIn -import kotlinx.coroutines.flow.map -import kotlinx.coroutines.flow.onEach -import kotlinx.coroutines.launch -import kotlinx.coroutines.runBlocking -import splitties.toast.toast -import timber.log.Timber -import java.util.Calendar +import dagger.hilt.android.HiltAndroidApp +import io.github.sds100.keymapper.base.BaseKeyMapperApp -/** - * Created by sds100 on 19/05/2020. - */ @SuppressLint("LogNotTimber") -class KeyMapperApp : MultiDexApplication() { - private val tag = KeyMapperApp::class.simpleName - - val appCoroutineScope = MainScope() - - val notificationAdapter by lazy { AndroidNotificationAdapter(this, appCoroutineScope) } - - lateinit var notificationController: NotificationController - lateinit var autoSwitchImeController: AutoSwitchImeController - - val resourceProvider by lazy { ResourceProviderImpl(this, appCoroutineScope) } - - val bluetoothMonitor by lazy { AndroidBluetoothAdapter(this, appCoroutineScope) } - - val packageManagerAdapter by lazy { - AndroidPackageManagerAdapter( - this, - appCoroutineScope, - ) - } - - val inputMethodAdapter by lazy { - AndroidInputMethodAdapter( - this, - appCoroutineScope, - accessibilityServiceAdapter, - permissionAdapter, - suAdapter, - ) - } - val devicesAdapter by lazy { - AndroidDevicesAdapter( - this, - bluetoothMonitor, - permissionAdapter, - appCoroutineScope, - ) - } - val cameraAdapter by lazy { AndroidCameraAdapter(this) } - val permissionAdapter by lazy { - AndroidPermissionAdapter( - this, - appCoroutineScope, - suAdapter, - notificationReceiverAdapter, - ServiceLocator.settingsRepository(this), - packageManagerAdapter, - ) - } - - val systemFeatureAdapter by lazy { AndroidSystemFeatureAdapter(this) } - val accessibilityServiceAdapter by lazy { AccessibilityServiceAdapter(this, appCoroutineScope) } - val notificationReceiverAdapter by lazy { NotificationReceiverAdapter(this, appCoroutineScope) } - val appShortcutAdapter by lazy { AndroidAppShortcutAdapter(this) } - val fileAdapter by lazy { AndroidFileAdapter(this) } - val popupMessageAdapter by lazy { AndroidToastAdapter(this) } - val vibratorAdapter by lazy { AndroidVibratorAdapter(this) } - val displayAdapter by lazy { AndroidDisplayAdapter(this, coroutineScope = appCoroutineScope) } - val audioAdapter by lazy { AndroidVolumeAdapter(this) } - val suAdapter by lazy { - SuAdapterImpl( - appCoroutineScope, - ServiceLocator.settingsRepository(this), - ) - } - val phoneAdapter by lazy { AndroidPhoneAdapter(this, appCoroutineScope) } - val intentAdapter by lazy { IntentAdapterImpl(this) } - val mediaAdapter by lazy { AndroidMediaAdapter(this, appCoroutineScope) } - val lockScreenAdapter by lazy { AndroidLockScreenAdapter(this) } - val airplaneModeAdapter by lazy { AndroidAirplaneModeAdapter(this, suAdapter) } - val networkAdapter by lazy { AndroidNetworkAdapter(this, suAdapter) } - val nfcAdapter by lazy { AndroidNfcAdapter(this, suAdapter) } - val openUrlAdapter by lazy { AndroidOpenUrlAdapter(this) } - val clipboardAdapter by lazy { AndroidClipboardAdapter(this) } - val shizukuAdapter by lazy { ShizukuAdapterImpl(appCoroutineScope, packageManagerAdapter) } - val leanbackAdapter by lazy { LeanbackAdapterImpl(this) } - val powerAdapter by lazy { AndroidPowerAdapter(this) } - - val recordTriggerController by lazy { - RecordTriggerController(appCoroutineScope, accessibilityServiceAdapter) - } - - val interactUiElementController by lazy { - InteractUiElementController( - appCoroutineScope, - accessibilityServiceAdapter, - ServiceLocator.accessibilityNodeRepository(this), - packageManagerAdapter, - ) - } - - val autoGrantPermissionController by lazy { - AutoGrantPermissionController( - appCoroutineScope, - permissionAdapter, - popupMessageAdapter, - resourceProvider, - ) - } - - val purchasingManager: PurchasingManagerImpl by lazy { - PurchasingManagerImpl(this.applicationContext, appCoroutineScope) - } - - val ringtoneManagerAdapter: AndroidRingtoneAdapter by lazy { - AndroidRingtoneAdapter(this) - } - - private val loggingTree by lazy { - KeyMapperLoggingTree( - appCoroutineScope, - ServiceLocator.settingsRepository(this), - ServiceLocator.logRepository(this), - ) - } - - private val processLifecycleOwner by lazy { ProcessLifecycleOwner.get() } - - private val userManager: UserManager? by lazy { getSystemService() } - - private val initLock: Any = Any() - private var initialized = false - - override fun onCreate() { - val priorExceptionHandler = Thread.getDefaultUncaughtExceptionHandler() - - Log.i(tag, "KeyMapperApp: OnCreate") - - Thread.setDefaultUncaughtExceptionHandler { thread, exception -> - // log in a blocking manner and always log regardless of whether the setting is turned on - val entry = LogEntryEntity( - id = 0, - time = Calendar.getInstance().timeInMillis, - severity = LogEntryEntity.SEVERITY_ERROR, - message = exception.stackTraceToString(), - ) - - runBlocking { - ServiceLocator.logRepository(this@KeyMapperApp).insertSuspend(entry) - } - - priorExceptionHandler?.uncaughtException(thread, exception) - } - - super.onCreate() - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && userManager?.isUserUnlocked == false) { - Log.i(tag, "KeyMapperApp: Delay init because locked.") - // If the device is still encrypted and locked do not initialize anything that - // may potentially need the encrypted app storage like databases. - return - } - - synchronized(initLock) { - init() - initialized = true - } - } - - fun onBootUnlocked() { - synchronized(initLock) { - if (!initialized) { - init() - } - initialized = true - } - } - - private fun init() { - Log.i(tag, "KeyMapperApp: Init") - - ServiceLocator.settingsRepository(this).get(Keys.darkTheme) - .map { it?.toIntOrNull() } - .map { - when (it) { - ThemeUtils.DARK -> AppCompatDelegate.MODE_NIGHT_YES - ThemeUtils.LIGHT -> AppCompatDelegate.MODE_NIGHT_NO - else -> AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM - } - } - .onEach { mode -> AppCompatDelegate.setDefaultNightMode(mode) } - .launchIn(appCoroutineScope) - - if (BuildConfig.BUILD_TYPE == "debug" || BuildConfig.BUILD_TYPE == "debug_release") { - Timber.plant(Timber.DebugTree()) - } - - Timber.plant(loggingTree) - - notificationController = NotificationController( - appCoroutineScope, - ManageNotificationsUseCaseImpl( - ServiceLocator.settingsRepository(this), - notificationAdapter, - suAdapter, - permissionAdapter, - ), - UseCases.pauseKeyMaps(this), - UseCases.showImePicker(this), - UseCases.controlAccessibilityService(this), - UseCases.toggleCompatibleIme(this), - ShowHideInputMethodUseCaseImpl(ServiceLocator.accessibilityServiceAdapter(this)), - UseCases.onboarding(this), - ServiceLocator.resourceProvider(this), - ) - - autoSwitchImeController = AutoSwitchImeController( - appCoroutineScope, - ServiceLocator.settingsRepository(this), - ServiceLocator.inputMethodAdapter(this), - UseCases.pauseKeyMaps(this), - devicesAdapter, - popupMessageAdapter, - resourceProvider, - ServiceLocator.accessibilityServiceAdapter(this), - ) - - processLifecycleOwner.lifecycle.addObserver(object : LifecycleObserver { - @OnLifecycleEvent(Lifecycle.Event.ON_RESUME) - fun onResume() { - // when the user returns to the app let everything know that the permissions could have changed - notificationController.onOpenApp() - - if (BuildConfig.DEBUG && permissionAdapter.isGranted(Permission.WRITE_SECURE_SETTINGS)) { - accessibilityServiceAdapter.start() - } - } - }) - - appCoroutineScope.launch { - notificationController.openApp.collectLatest { intentAction -> - Intent(this@KeyMapperApp, MainActivity::class.java).apply { - action = intentAction - flags = Intent.FLAG_ACTIVITY_NEW_TASK - - startActivity(this) - } - } - } - - notificationController.showToast.onEach { - toast(it) - }.launchIn(appCoroutineScope) - - autoGrantPermissionController.start() +@HiltAndroidApp +class KeyMapperApp : BaseKeyMapperApp() { + override fun getMainActivityClass(): Class<*> { + return MainActivity::class.java } } diff --git a/app/src/main/java/io/github/sds100/keymapper/MainActivity.kt b/app/src/main/java/io/github/sds100/keymapper/MainActivity.kt new file mode 100644 index 0000000000..d48551a3dc --- /dev/null +++ b/app/src/main/java/io/github/sds100/keymapper/MainActivity.kt @@ -0,0 +1,43 @@ +package io.github.sds100.keymapper + +import android.os.Bundle +import androidx.databinding.DataBindingUtil +import androidx.navigation.fragment.FragmentNavigator +import androidx.navigation.fragment.NavHostFragment +import dagger.hilt.android.AndroidEntryPoint +import io.github.sds100.keymapper.base.BaseMainActivity +import io.github.sds100.keymapper.base.R +import io.github.sds100.keymapper.base.databinding.ActivityMainBinding +import io.github.sds100.keymapper.base.utils.ui.DialogProvider +import io.github.sds100.keymapper.base.utils.ui.showDialogs +import javax.inject.Inject + +@AndroidEntryPoint +class MainActivity : BaseMainActivity() { + + @Inject + lateinit var dialogProvider: DialogProvider + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + val binding = + DataBindingUtil.setContentView(this, R.layout.activity_main) + + val navController = binding.container.getFragment().navController + val fragmentNavigator = + navController.navigatorProvider.getNavigator(FragmentNavigator::class.java) + + val homeDest = fragmentNavigator.createDestination().apply { + id = R.id.home_fragment + setClassName(MainFragment::class.java.name) + } + + navController.graph = navController.navInflater.inflate(R.navigation.nav_base_app).apply { + addDestination(homeDest) + setStartDestination(R.id.home_fragment) + } + + dialogProvider.showDialogs(this, binding.coordinatorLayout) + } +} diff --git a/app/src/main/java/io/github/sds100/keymapper/MainFragment.kt b/app/src/main/java/io/github/sds100/keymapper/MainFragment.kt new file mode 100644 index 0000000000..ccd1e61eee --- /dev/null +++ b/app/src/main/java/io/github/sds100/keymapper/MainFragment.kt @@ -0,0 +1,152 @@ +package io.github.sds100.keymapper + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.compose.foundation.layout.WindowInsets +import androidx.compose.foundation.layout.WindowInsetsSides +import androidx.compose.foundation.layout.add +import androidx.compose.foundation.layout.displayCutout +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.only +import androidx.compose.foundation.layout.systemBars +import androidx.compose.foundation.layout.windowInsetsPadding +import androidx.compose.material3.SnackbarHostState +import androidx.compose.runtime.remember +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.ViewCompositionStrategy +import androidx.compose.ui.unit.dp +import androidx.fragment.app.Fragment +import androidx.hilt.navigation.compose.hiltViewModel +import androidx.navigation.NavGraphBuilder +import androidx.navigation.compose.composable +import androidx.navigation.compose.rememberNavController +import dagger.hilt.android.AndroidEntryPoint +import io.github.sds100.keymapper.base.BaseMainNavHost +import io.github.sds100.keymapper.base.actions.ChooseActionScreen +import io.github.sds100.keymapper.base.actions.ChooseActionViewModel +import io.github.sds100.keymapper.base.compose.KeyMapperTheme +import io.github.sds100.keymapper.base.databinding.FragmentComposeBinding +import io.github.sds100.keymapper.base.home.HomeKeyMapListScreen +import io.github.sds100.keymapper.base.utils.navigation.NavDestination +import io.github.sds100.keymapper.base.utils.navigation.NavigationProviderImpl +import io.github.sds100.keymapper.base.utils.navigation.SetupNavigation +import io.github.sds100.keymapper.base.utils.navigation.handleRouteArgs +import io.github.sds100.keymapper.base.utils.navigation.setupFragmentNavigation +import io.github.sds100.keymapper.base.utils.ui.DialogProviderImpl +import io.github.sds100.keymapper.home.HomeViewModel +import io.github.sds100.keymapper.keymaps.ConfigKeyMapScreen +import io.github.sds100.keymapper.keymaps.ConfigKeyMapViewModel +import javax.inject.Inject + +@AndroidEntryPoint +class MainFragment : Fragment() { + + @Inject + lateinit var navigationProvider: NavigationProviderImpl + + @Inject + lateinit var dialogProvider: DialogProviderImpl + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + navigationProvider.setupFragmentNavigation(this) + } + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle?, + ): View { + FragmentComposeBinding.inflate(inflater, container, false).apply { + composeView.apply { + // Dispose of the Composition when the view's LifecycleOwner + // is destroyed + setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed) + setContent { + val navController = rememberNavController() + SetupNavigation(navigationProvider, navController) + + KeyMapperTheme { + BaseMainNavHost( + modifier = Modifier + .windowInsetsPadding( + WindowInsets.systemBars.only(sides = WindowInsetsSides.Horizontal) + .add(WindowInsets.displayCutout.only(sides = WindowInsetsSides.Horizontal)), + ), + navController = navController, + composableDestinations = { + composableDestinations() + }, + ) + } + } + } + return this.root + } + } + + private fun NavGraphBuilder.composableDestinations() { + composable { + val snackbarState = remember { SnackbarHostState() } + val viewModel: HomeViewModel = hiltViewModel() + + HomeKeyMapListScreen( + modifier = Modifier.fillMaxSize(), + viewModel = viewModel.keyMapListViewModel, + snackbarState = snackbarState, + onSettingsClick = viewModel::launchSettings, + onAboutClick = viewModel::launchAbout, + finishActivity = { + requireActivity().finish() + }, + fabBottomPadding = 0.dp, + ) + } + + composable { backStackEntry -> + val viewModel: ConfigKeyMapViewModel = hiltViewModel() + + backStackEntry.handleRouteArgs { args -> + viewModel.loadNewKeyMap(groupUid = args.groupUid) + + if (args.showAdvancedTriggers) { + viewModel.configTriggerViewModel.showAdvancedTriggersBottomSheet = true + } + } + + ConfigKeyMapScreen( + modifier = Modifier.fillMaxSize(), + viewModel = viewModel, + ) + } + + composable { backStackEntry -> + val viewModel: ConfigKeyMapViewModel = hiltViewModel() + + backStackEntry.handleRouteArgs { args -> + viewModel.loadKeyMap(uid = args.keyMapUid) + + if (args.showAdvancedTriggers) { + viewModel.configTriggerViewModel.showAdvancedTriggersBottomSheet = true + } + } + + ConfigKeyMapScreen( + modifier = Modifier.fillMaxSize(), + viewModel = viewModel, + ) + } + + composable { + val viewModel: ChooseActionViewModel = hiltViewModel() + + ChooseActionScreen( + modifier = Modifier.fillMaxSize(), + viewModel = viewModel, + ) + } + } +} diff --git a/app/src/main/java/io/github/sds100/keymapper/ServiceLocator.kt b/app/src/main/java/io/github/sds100/keymapper/ServiceLocator.kt deleted file mode 100755 index 030d056d9a..0000000000 --- a/app/src/main/java/io/github/sds100/keymapper/ServiceLocator.kt +++ /dev/null @@ -1,324 +0,0 @@ -package io.github.sds100.keymapper - -import android.content.Context -import androidx.datastore.preferences.preferencesDataStore -import androidx.room.Room -import io.github.sds100.keymapper.actions.sound.SoundsManager -import io.github.sds100.keymapper.actions.sound.SoundsManagerImpl -import io.github.sds100.keymapper.backup.BackupManager -import io.github.sds100.keymapper.backup.BackupManagerImpl -import io.github.sds100.keymapper.data.db.AppDatabase -import io.github.sds100.keymapper.data.repositories.AccessibilityNodeRepository -import io.github.sds100.keymapper.data.repositories.AccessibilityNodeRepositoryImpl -import io.github.sds100.keymapper.data.repositories.FloatingButtonRepository -import io.github.sds100.keymapper.data.repositories.FloatingLayoutRepository -import io.github.sds100.keymapper.data.repositories.GroupRepository -import io.github.sds100.keymapper.data.repositories.PreferenceRepository -import io.github.sds100.keymapper.data.repositories.RoomFloatingButtonRepository -import io.github.sds100.keymapper.data.repositories.RoomFloatingLayoutRepository -import io.github.sds100.keymapper.data.repositories.RoomGroupRepository -import io.github.sds100.keymapper.data.repositories.RoomKeyMapRepository -import io.github.sds100.keymapper.data.repositories.RoomLogRepository -import io.github.sds100.keymapper.data.repositories.SettingsPreferenceRepository -import io.github.sds100.keymapper.keymaps.ConfigKeyMapUseCaseController -import io.github.sds100.keymapper.logging.LogRepository -import io.github.sds100.keymapper.purchasing.PurchasingManagerImpl -import io.github.sds100.keymapper.shizuku.ShizukuAdapter -import io.github.sds100.keymapper.system.accessibility.AccessibilityServiceAdapter -import io.github.sds100.keymapper.system.airplanemode.AirplaneModeAdapter -import io.github.sds100.keymapper.system.apps.AppShortcutAdapter -import io.github.sds100.keymapper.system.apps.PackageManagerAdapter -import io.github.sds100.keymapper.system.bluetooth.BluetoothAdapter -import io.github.sds100.keymapper.system.camera.CameraAdapter -import io.github.sds100.keymapper.system.clipboard.ClipboardAdapter -import io.github.sds100.keymapper.system.devices.DevicesAdapter -import io.github.sds100.keymapper.system.display.AndroidDisplayAdapter -import io.github.sds100.keymapper.system.files.FileAdapter -import io.github.sds100.keymapper.system.inputmethod.InputMethodAdapter -import io.github.sds100.keymapper.system.intents.IntentAdapter -import io.github.sds100.keymapper.system.leanback.LeanbackAdapter -import io.github.sds100.keymapper.system.lock.LockScreenAdapter -import io.github.sds100.keymapper.system.media.AndroidMediaAdapter -import io.github.sds100.keymapper.system.network.NetworkAdapter -import io.github.sds100.keymapper.system.nfc.NfcAdapter -import io.github.sds100.keymapper.system.notifications.AndroidNotificationAdapter -import io.github.sds100.keymapper.system.notifications.NotificationController -import io.github.sds100.keymapper.system.notifications.NotificationReceiverAdapter -import io.github.sds100.keymapper.system.permissions.AndroidPermissionAdapter -import io.github.sds100.keymapper.system.permissions.SystemFeatureAdapter -import io.github.sds100.keymapper.system.phone.PhoneAdapter -import io.github.sds100.keymapper.system.popup.PopupMessageAdapter -import io.github.sds100.keymapper.system.power.PowerAdapter -import io.github.sds100.keymapper.system.ringtones.RingtoneAdapter -import io.github.sds100.keymapper.system.root.SuAdapter -import io.github.sds100.keymapper.system.url.OpenUrlAdapter -import io.github.sds100.keymapper.system.vibrator.VibratorAdapter -import io.github.sds100.keymapper.system.volume.VolumeAdapter -import io.github.sds100.keymapper.util.ui.ResourceProviderImpl -import kotlinx.coroutines.CoroutineScope - -/** - * Created by sds100 on 17/05/2020. - */ -object ServiceLocator { - - private var database: AppDatabase? = null - - private fun database(context: Context): AppDatabase { - synchronized(this) { - return database ?: createDatabase(context.applicationContext).also { - this.database = it - } - } - } - - @Volatile - private var roomKeymapRepository: RoomKeyMapRepository? = null - - fun roomKeyMapRepository(context: Context): RoomKeyMapRepository { - synchronized(this) { - return roomKeymapRepository ?: RoomKeyMapRepository( - database(context).keyMapDao(), - database(context).fingerprintMapDao(), - (context.applicationContext as KeyMapperApp).appCoroutineScope, - ).also { - this.roomKeymapRepository = it - } - } - } - - @Volatile - private var settingsRepository: PreferenceRepository? = null - - fun settingsRepository(context: Context): PreferenceRepository { - synchronized(this) { - return settingsRepository ?: SettingsPreferenceRepository( - context.applicationContext, - (context.applicationContext as KeyMapperApp).appCoroutineScope, - ).also { - this.settingsRepository = it - } - } - } - - @Volatile - private var logRepository: LogRepository? = null - - fun logRepository(context: Context): LogRepository { - synchronized(this) { - return logRepository ?: RoomLogRepository( - (context.applicationContext as KeyMapperApp).appCoroutineScope, - database(context).logEntryDao(), - ).also { - this.logRepository = it - } - } - } - - @Volatile - private var floatingLayoutRepository: FloatingLayoutRepository? = null - - fun floatingLayoutRepository(context: Context): FloatingLayoutRepository { - synchronized(this) { - return floatingLayoutRepository ?: RoomFloatingLayoutRepository( - database(context).floatingLayoutDao(), - (context.applicationContext as KeyMapperApp).appCoroutineScope, - ).also { - this.floatingLayoutRepository = it - } - } - } - - @Volatile - private var floatingButtonRepository: FloatingButtonRepository? = null - - fun floatingButtonRepository(context: Context): FloatingButtonRepository { - synchronized(this) { - return floatingButtonRepository ?: RoomFloatingButtonRepository( - database(context).floatingButtonDao(), - (context.applicationContext as KeyMapperApp).appCoroutineScope, - ).also { - this.floatingButtonRepository = it - } - } - } - - @Volatile - private var groupRepository: GroupRepository? = null - - fun groupRepository(context: Context): GroupRepository { - synchronized(this) { - return groupRepository ?: RoomGroupRepository( - database(context).groupDao(), - (context.applicationContext as KeyMapperApp).appCoroutineScope, - ).also { - this.groupRepository = it - } - } - } - - @Volatile - private var backupManager: BackupManager? = null - - fun backupManager(context: Context): BackupManager { - synchronized(this) { - return backupManager ?: createBackupManager(context).also { - this.backupManager = it - } - } - } - - private fun createBackupManager(context: Context): BackupManager = backupManager ?: BackupManagerImpl( - (context.applicationContext as KeyMapperApp).appCoroutineScope, - fileAdapter(context), - roomKeyMapRepository(context), - settingsRepository(context), - floatingLayoutRepository(context), - floatingButtonRepository(context), - groupRepository(context), - soundsManager(context), - ) - - @Volatile - private var soundsManager: SoundsManager? = null - - fun soundsManager(context: Context): SoundsManager { - synchronized(this) { - return soundsManager ?: SoundsManagerImpl( - (context.applicationContext as KeyMapperApp).appCoroutineScope, - fileAdapter(context), - ).also { - this.soundsManager = it - } - } - } - - @Volatile - private var configKeyMapsController: ConfigKeyMapUseCaseController? = null - - fun configKeyMapsController(ctx: Context): ConfigKeyMapUseCaseController { - synchronized(this) { - return configKeyMapsController - ?: createConfigKeyMapsController(ctx).also { - configKeyMapsController = it - } - } - } - - private fun createConfigKeyMapsController(ctx: Context): ConfigKeyMapUseCaseController { - return ConfigKeyMapUseCaseController( - appCoroutineScope(ctx), - roomKeyMapRepository(ctx), - devicesAdapter(ctx), - settingsRepository(ctx), - floatingLayoutRepository(ctx), - floatingButtonRepository(ctx), - accessibilityServiceAdapter(ctx), - ) - } - - @Volatile - private var accessibilityNodeRepository: AccessibilityNodeRepository? = null - - fun accessibilityNodeRepository(context: Context): AccessibilityNodeRepository { - synchronized(this) { - return accessibilityNodeRepository ?: AccessibilityNodeRepositoryImpl( - (context.applicationContext as KeyMapperApp).appCoroutineScope, - database(context).accessibilityNodeDao(), - ).also { - this.accessibilityNodeRepository = it - } - } - } - - fun fileAdapter(context: Context): FileAdapter = (context.applicationContext as KeyMapperApp).fileAdapter - - fun inputMethodAdapter(context: Context): InputMethodAdapter = (context.applicationContext as KeyMapperApp).inputMethodAdapter - - fun devicesAdapter(context: Context): DevicesAdapter = (context.applicationContext as KeyMapperApp).devicesAdapter - - fun bluetoothAdapter(context: Context): BluetoothAdapter = (context.applicationContext as KeyMapperApp).bluetoothMonitor - - fun notificationController(context: Context): NotificationController = (context.applicationContext as KeyMapperApp).notificationController - - fun resourceProvider(context: Context): ResourceProviderImpl = (context.applicationContext as KeyMapperApp).resourceProvider - - fun packageManagerAdapter(context: Context): PackageManagerAdapter = (context.applicationContext as KeyMapperApp).packageManagerAdapter - - fun cameraAdapter(context: Context): CameraAdapter = (context.applicationContext as KeyMapperApp).cameraAdapter - - fun permissionAdapter(context: Context): AndroidPermissionAdapter = (context.applicationContext as KeyMapperApp).permissionAdapter - - fun systemFeatureAdapter(context: Context): SystemFeatureAdapter = (context.applicationContext as KeyMapperApp).systemFeatureAdapter - - fun accessibilityServiceAdapter(context: Context): AccessibilityServiceAdapter = (context.applicationContext as KeyMapperApp).accessibilityServiceAdapter - - fun notificationReceiverAdapter(context: Context): NotificationReceiverAdapter = (context.applicationContext as KeyMapperApp).notificationReceiverAdapter - - fun appShortcutAdapter(context: Context): AppShortcutAdapter = (context.applicationContext as KeyMapperApp).appShortcutAdapter - - fun notificationAdapter(context: Context): AndroidNotificationAdapter = (context.applicationContext as KeyMapperApp).notificationAdapter - - fun popupMessageAdapter(context: Context): PopupMessageAdapter = (context.applicationContext as KeyMapperApp).popupMessageAdapter - - fun vibratorAdapter(context: Context): VibratorAdapter = (context.applicationContext as KeyMapperApp).vibratorAdapter - - fun displayAdapter(context: Context): AndroidDisplayAdapter = (context.applicationContext as KeyMapperApp).displayAdapter - - fun audioAdapter(context: Context): VolumeAdapter = (context.applicationContext as KeyMapperApp).audioAdapter - - fun suAdapter(context: Context): SuAdapter = (context.applicationContext as KeyMapperApp).suAdapter - - fun intentAdapter(context: Context): IntentAdapter = (context.applicationContext as KeyMapperApp).intentAdapter - - fun phoneAdapter(context: Context): PhoneAdapter = (context.applicationContext as KeyMapperApp).phoneAdapter - - fun mediaAdapter(context: Context): AndroidMediaAdapter = (context.applicationContext as KeyMapperApp).mediaAdapter - - fun lockScreenAdapter(context: Context): LockScreenAdapter = (context.applicationContext as KeyMapperApp).lockScreenAdapter - - fun airplaneModeAdapter(context: Context): AirplaneModeAdapter = (context.applicationContext as KeyMapperApp).airplaneModeAdapter - - fun networkAdapter(context: Context): NetworkAdapter = (context.applicationContext as KeyMapperApp).networkAdapter - - fun nfcAdapter(context: Context): NfcAdapter = (context.applicationContext as KeyMapperApp).nfcAdapter - - fun openUrlAdapter(context: Context): OpenUrlAdapter = (context.applicationContext as KeyMapperApp).openUrlAdapter - - fun clipboardAdapter(context: Context): ClipboardAdapter = (context.applicationContext as KeyMapperApp).clipboardAdapter - - fun shizukuAdapter(context: Context): ShizukuAdapter = (context.applicationContext as KeyMapperApp).shizukuAdapter - - fun leanbackAdapter(context: Context): LeanbackAdapter = (context.applicationContext as KeyMapperApp).leanbackAdapter - - fun powerAdapter(context: Context): PowerAdapter = (context.applicationContext as KeyMapperApp).powerAdapter - - fun appCoroutineScope(context: Context): CoroutineScope = (context.applicationContext as KeyMapperApp).appCoroutineScope - - fun purchasingManager(context: Context): PurchasingManagerImpl = (context.applicationContext as KeyMapperApp).purchasingManager - - fun ringtoneAdapter(context: Context): RingtoneAdapter = (context.applicationContext as KeyMapperApp).ringtoneManagerAdapter - - private fun createDatabase(context: Context): AppDatabase = Room.databaseBuilder( - context.applicationContext, - AppDatabase::class.java, - AppDatabase.DATABASE_NAME, - ).addMigrations( - AppDatabase.MIGRATION_1_2, - AppDatabase.MIGRATION_2_3, - AppDatabase.MIGRATION_3_4, - AppDatabase.MIGRATION_4_5, - AppDatabase.MIGRATION_5_6, - AppDatabase.MIGRATION_6_7, - AppDatabase.MIGRATION_7_8, - AppDatabase.MIGRATION_8_9, - AppDatabase.MIGRATION_9_10, - AppDatabase.MIGRATION_10_11, - AppDatabase.RoomMigration11To12(context.applicationContext.legacyFingerprintMapDataStore), - AppDatabase.MIGRATION_12_13, - AppDatabase.MIGRATION_13_14, - AppDatabase.MIGRATION_17_18, - ).build() - - private val Context.legacyFingerprintMapDataStore by preferencesDataStore("fingerprint_gestures") -} diff --git a/app/src/main/java/io/github/sds100/keymapper/UseCases.kt b/app/src/main/java/io/github/sds100/keymapper/UseCases.kt deleted file mode 100644 index d57d0bf37b..0000000000 --- a/app/src/main/java/io/github/sds100/keymapper/UseCases.kt +++ /dev/null @@ -1,222 +0,0 @@ -package io.github.sds100.keymapper - -import android.content.Context -import io.github.sds100.keymapper.actions.CreateActionUseCaseImpl -import io.github.sds100.keymapper.actions.GetActionErrorUseCaseImpl -import io.github.sds100.keymapper.actions.PerformActionsUseCaseImpl -import io.github.sds100.keymapper.api.KeyEventRelayServiceWrapper -import io.github.sds100.keymapper.constraints.DetectConstraintsUseCaseImpl -import io.github.sds100.keymapper.constraints.GetConstraintErrorUseCaseImpl -import io.github.sds100.keymapper.floating.ListFloatingLayoutsUseCase -import io.github.sds100.keymapper.floating.ListFloatingLayoutsUseCaseImpl -import io.github.sds100.keymapper.keymaps.ConfigKeyMapUseCase -import io.github.sds100.keymapper.keymaps.CreateKeyMapShortcutUseCaseImpl -import io.github.sds100.keymapper.keymaps.DisplayKeyMapUseCase -import io.github.sds100.keymapper.keymaps.DisplayKeyMapUseCaseImpl -import io.github.sds100.keymapper.keymaps.FingerprintGesturesSupportedUseCaseImpl -import io.github.sds100.keymapper.keymaps.PauseKeyMapsUseCaseImpl -import io.github.sds100.keymapper.keymaps.detection.DetectKeyMapsUseCaseImpl -import io.github.sds100.keymapper.onboarding.OnboardingUseCaseImpl -import io.github.sds100.keymapper.reroutekeyevents.RerouteKeyEventsUseCaseImpl -import io.github.sds100.keymapper.shizuku.ShizukuInputEventInjector -import io.github.sds100.keymapper.sorting.SortKeyMapsUseCase -import io.github.sds100.keymapper.sorting.SortKeyMapsUseCaseImpl -import io.github.sds100.keymapper.system.Shell -import io.github.sds100.keymapper.system.accessibility.ControlAccessibilityServiceUseCase -import io.github.sds100.keymapper.system.accessibility.ControlAccessibilityServiceUseCaseImpl -import io.github.sds100.keymapper.system.accessibility.IAccessibilityService -import io.github.sds100.keymapper.system.accessibility.MyAccessibilityService -import io.github.sds100.keymapper.system.apps.DisplayAppsUseCase -import io.github.sds100.keymapper.system.apps.DisplayAppsUseCaseImpl -import io.github.sds100.keymapper.system.inputmethod.ImeInputEventInjectorImpl -import io.github.sds100.keymapper.system.inputmethod.ShowInputMethodPickerUseCase -import io.github.sds100.keymapper.system.inputmethod.ShowInputMethodPickerUseCaseImpl -import io.github.sds100.keymapper.system.inputmethod.ToggleCompatibleImeUseCaseImpl - -/** - * Created by sds100 on 03/03/2021. - */ -object UseCases { - - fun listFloatingLayouts(ctx: Context): ListFloatingLayoutsUseCase = ListFloatingLayoutsUseCaseImpl( - ServiceLocator.floatingLayoutRepository(ctx), - ServiceLocator.purchasingManager(ctx), - ServiceLocator.accessibilityServiceAdapter(ctx), - ServiceLocator.settingsRepository(ctx), - ) - - fun displayPackages(ctx: Context): DisplayAppsUseCase = DisplayAppsUseCaseImpl( - ServiceLocator.packageManagerAdapter(ctx), - ) - - fun displayKeyMap(ctx: Context): DisplayKeyMapUseCase = DisplayKeyMapUseCaseImpl( - ServiceLocator.permissionAdapter(ctx), - ServiceLocator.inputMethodAdapter(ctx), - ServiceLocator.packageManagerAdapter(ctx), - ServiceLocator.settingsRepository(ctx), - ServiceLocator.accessibilityServiceAdapter(ctx), - ServiceLocator.settingsRepository(ctx), - ServiceLocator.purchasingManager(ctx), - ServiceLocator.ringtoneAdapter(ctx), - getActionError(ctx), - getConstraintError(ctx), - ) - - fun configKeyMap(ctx: Context): ConfigKeyMapUseCase = ServiceLocator.configKeyMapsController(ctx) - - fun getActionError(ctx: Context) = GetActionErrorUseCaseImpl( - ServiceLocator.packageManagerAdapter(ctx), - ServiceLocator.inputMethodAdapter(ctx), - ServiceLocator.permissionAdapter(ctx), - ServiceLocator.systemFeatureAdapter(ctx), - ServiceLocator.cameraAdapter(ctx), - ServiceLocator.soundsManager(ctx), - ServiceLocator.shizukuAdapter(ctx), - ServiceLocator.ringtoneAdapter(ctx), - ) - - fun getConstraintError(ctx: Context) = GetConstraintErrorUseCaseImpl( - ServiceLocator.packageManagerAdapter(ctx), - ServiceLocator.permissionAdapter(ctx), - ServiceLocator.systemFeatureAdapter(ctx), - ServiceLocator.inputMethodAdapter(ctx), - ServiceLocator.cameraAdapter(ctx), - ) - - fun onboarding(ctx: Context) = OnboardingUseCaseImpl( - ServiceLocator.settingsRepository(ctx), - ServiceLocator.fileAdapter(ctx), - ServiceLocator.leanbackAdapter(ctx), - ServiceLocator.shizukuAdapter(ctx), - ServiceLocator.permissionAdapter(ctx), - ServiceLocator.packageManagerAdapter(ctx), - ServiceLocator.purchasingManager(ctx), - ServiceLocator.roomKeyMapRepository(ctx), - ) - - fun createKeymapShortcut(ctx: Context) = CreateKeyMapShortcutUseCaseImpl( - ServiceLocator.appShortcutAdapter(ctx), - ServiceLocator.resourceProvider(ctx), - ) - - fun fingerprintGesturesSupported(ctx: Context) = FingerprintGesturesSupportedUseCaseImpl(ServiceLocator.settingsRepository(ctx)) - - fun pauseKeyMaps(ctx: Context) = PauseKeyMapsUseCaseImpl( - ServiceLocator.settingsRepository(ctx), - ServiceLocator.mediaAdapter(ctx), - ServiceLocator.ringtoneAdapter(ctx), - ) - - fun showImePicker(ctx: Context): ShowInputMethodPickerUseCase = ShowInputMethodPickerUseCaseImpl( - ServiceLocator.inputMethodAdapter(ctx), - ) - - fun controlAccessibilityService(ctx: Context): ControlAccessibilityServiceUseCase = ControlAccessibilityServiceUseCaseImpl( - ServiceLocator.accessibilityServiceAdapter(ctx), - ServiceLocator.permissionAdapter(ctx), - ) - - fun toggleCompatibleIme(ctx: Context) = ToggleCompatibleImeUseCaseImpl( - ServiceLocator.inputMethodAdapter(ctx), - ) - - fun detectConstraints(service: MyAccessibilityService) = DetectConstraintsUseCaseImpl( - service, - ServiceLocator.mediaAdapter(service), - ServiceLocator.devicesAdapter(service), - ServiceLocator.displayAdapter(service), - ServiceLocator.cameraAdapter(service), - ServiceLocator.networkAdapter(service), - ServiceLocator.inputMethodAdapter(service), - ServiceLocator.lockScreenAdapter(service), - ServiceLocator.phoneAdapter(service), - ServiceLocator.powerAdapter(service), - ) - - fun performActions( - ctx: Context, - service: IAccessibilityService, - keyEventRelayService: KeyEventRelayServiceWrapper, - ) = PerformActionsUseCaseImpl( - (ctx.applicationContext as KeyMapperApp).appCoroutineScope, - service, - ServiceLocator.inputMethodAdapter(ctx), - ServiceLocator.fileAdapter(ctx), - ServiceLocator.suAdapter(ctx), - Shell, - ServiceLocator.intentAdapter(ctx), - getActionError(ctx), - keyMapperImeMessenger(ctx, keyEventRelayService), - ShizukuInputEventInjector(), - ServiceLocator.packageManagerAdapter(ctx), - ServiceLocator.appShortcutAdapter(ctx), - ServiceLocator.popupMessageAdapter(ctx), - ServiceLocator.devicesAdapter(ctx), - ServiceLocator.phoneAdapter(ctx), - ServiceLocator.audioAdapter(ctx), - ServiceLocator.cameraAdapter(ctx), - ServiceLocator.displayAdapter(ctx), - ServiceLocator.lockScreenAdapter(ctx), - ServiceLocator.mediaAdapter(ctx), - ServiceLocator.airplaneModeAdapter(ctx), - ServiceLocator.networkAdapter(ctx), - ServiceLocator.bluetoothAdapter(ctx), - ServiceLocator.nfcAdapter(ctx), - ServiceLocator.openUrlAdapter(ctx), - ServiceLocator.resourceProvider(ctx), - ServiceLocator.settingsRepository(ctx), - ServiceLocator.soundsManager(ctx), - ServiceLocator.permissionAdapter(ctx), - ServiceLocator.notificationReceiverAdapter(ctx), - ServiceLocator.ringtoneAdapter(ctx), - ) - - fun detectKeyMaps( - ctx: Context, - service: IAccessibilityService, - keyEventRelayService: KeyEventRelayServiceWrapper, - ) = DetectKeyMapsUseCaseImpl( - ServiceLocator.roomKeyMapRepository(ctx), - ServiceLocator.floatingButtonRepository(ctx), - ServiceLocator.groupRepository(ctx), - ServiceLocator.settingsRepository(ctx), - ServiceLocator.suAdapter(ctx), - ServiceLocator.displayAdapter(ctx), - ServiceLocator.audioAdapter(ctx), - keyMapperImeMessenger(ctx, keyEventRelayService), - service, - ShizukuInputEventInjector(), - ServiceLocator.popupMessageAdapter(ctx), - ServiceLocator.permissionAdapter(ctx), - ServiceLocator.resourceProvider(ctx), - ServiceLocator.vibratorAdapter(ctx), - ServiceLocator.appCoroutineScope(ctx), - ) - - fun rerouteKeyEvents(ctx: Context, keyEventRelayService: KeyEventRelayServiceWrapper) = RerouteKeyEventsUseCaseImpl( - ServiceLocator.inputMethodAdapter(ctx), - keyMapperImeMessenger(ctx, keyEventRelayService), - ServiceLocator.settingsRepository(ctx), - ) - - fun createAction(ctx: Context) = CreateActionUseCaseImpl( - ServiceLocator.inputMethodAdapter(ctx), - ServiceLocator.systemFeatureAdapter(ctx), - ServiceLocator.cameraAdapter(ctx), - ServiceLocator.permissionAdapter(ctx), - ) - - private fun keyMapperImeMessenger( - ctx: Context, - keyEventRelayService: KeyEventRelayServiceWrapper, - ) = ImeInputEventInjectorImpl( - ctx, - keyEventRelayService, - ServiceLocator.inputMethodAdapter(ctx), - ) - - fun sortKeyMapsUseCase(ctx: Context): SortKeyMapsUseCase = SortKeyMapsUseCaseImpl( - ServiceLocator.settingsRepository(ctx), - displayKeyMap(ctx), - ) -} diff --git a/app/src/main/java/io/github/sds100/keymapper/actions/ChooseActionFragment.kt b/app/src/main/java/io/github/sds100/keymapper/actions/ChooseActionFragment.kt deleted file mode 100644 index 8bc9c8f483..0000000000 --- a/app/src/main/java/io/github/sds100/keymapper/actions/ChooseActionFragment.kt +++ /dev/null @@ -1,103 +0,0 @@ -package io.github.sds100.keymapper.actions - -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import androidx.compose.foundation.layout.WindowInsets -import androidx.compose.foundation.layout.WindowInsetsSides -import androidx.compose.foundation.layout.add -import androidx.compose.foundation.layout.displayCutout -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.only -import androidx.compose.foundation.layout.systemBars -import androidx.compose.foundation.layout.windowInsetsPadding -import androidx.compose.ui.Modifier -import androidx.compose.ui.platform.ViewCompositionStrategy -import androidx.core.os.bundleOf -import androidx.fragment.app.Fragment -import androidx.fragment.app.setFragmentResult -import androidx.fragment.app.viewModels -import androidx.lifecycle.Lifecycle -import androidx.lifecycle.withStateAtLeast -import androidx.navigation.findNavController -import androidx.navigation.fragment.findNavController -import androidx.navigation.fragment.navArgs -import io.github.sds100.keymapper.compose.KeyMapperTheme -import io.github.sds100.keymapper.databinding.FragmentComposeBinding -import io.github.sds100.keymapper.util.Inject -import io.github.sds100.keymapper.util.launchRepeatOnLifecycle -import io.github.sds100.keymapper.util.ui.setupNavigation -import io.github.sds100.keymapper.util.ui.showPopups -import io.github.sds100.keymapper.util.viewLifecycleScope -import kotlinx.coroutines.flow.collectLatest -import kotlinx.coroutines.launch -import kotlinx.serialization.json.Json - -class ChooseActionFragment : Fragment() { - - companion object { - const val EXTRA_ACTION = "extra_action" - } - - private val args: ChooseActionFragmentArgs by navArgs() - - private val viewModel by viewModels { - Inject.chooseActionViewModel(requireContext()) - } - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - - viewModel.setupNavigation(this) - - launchRepeatOnLifecycle(Lifecycle.State.CREATED) { - viewModel.returnAction.collectLatest { action -> - viewLifecycleScope.launch { - withStateAtLeast(Lifecycle.State.RESUMED) { - setFragmentResult( - args.requestKey, - bundleOf(EXTRA_ACTION to Json.encodeToString(action)), - ) - findNavController().navigateUp() - } - } - } - } - } - - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle?, - ): View { - FragmentComposeBinding.inflate(inflater, container, false).apply { - composeView.apply { - // Dispose of the Composition when the view's LifecycleOwner - // is destroyed - setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed) - setContent { - KeyMapperTheme { - ChooseActionScreen( - modifier = Modifier - .fillMaxSize() - .windowInsetsPadding( - WindowInsets.systemBars.only(sides = WindowInsetsSides.Horizontal) - .add(WindowInsets.displayCutout.only(sides = WindowInsetsSides.Horizontal)), - ), - viewModel = viewModel, - onNavigateBack = findNavController()::navigateUp, - ) - } - } - } - return this.root - } - } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - - viewModel.showPopups(this, view) - } -} diff --git a/app/src/main/java/io/github/sds100/keymapper/actions/DisplayActionUseCase.kt b/app/src/main/java/io/github/sds100/keymapper/actions/DisplayActionUseCase.kt deleted file mode 100644 index 4166825086..0000000000 --- a/app/src/main/java/io/github/sds100/keymapper/actions/DisplayActionUseCase.kt +++ /dev/null @@ -1,18 +0,0 @@ -package io.github.sds100.keymapper.actions - -import android.graphics.drawable.Drawable -import io.github.sds100.keymapper.util.Error -import io.github.sds100.keymapper.util.Result -import kotlinx.coroutines.flow.Flow - -interface DisplayActionUseCase : GetActionErrorUseCase { - val showDeviceDescriptors: Flow - fun getAppName(packageName: String): Result - fun getAppIcon(packageName: String): Result - fun getInputMethodLabel(imeId: String): Result - fun getRingtoneLabel(uri: String): Result - suspend fun fixError(error: Error) - fun neverShowDndTriggerError() - fun startAccessibilityService(): Boolean - fun restartAccessibilityService(): Boolean -} diff --git a/app/src/main/java/io/github/sds100/keymapper/actions/TestActionUseCase.kt b/app/src/main/java/io/github/sds100/keymapper/actions/TestActionUseCase.kt deleted file mode 100644 index 6d4dd00ca1..0000000000 --- a/app/src/main/java/io/github/sds100/keymapper/actions/TestActionUseCase.kt +++ /dev/null @@ -1,20 +0,0 @@ -package io.github.sds100.keymapper.actions - -import io.github.sds100.keymapper.system.accessibility.ServiceAdapter -import io.github.sds100.keymapper.util.Result -import io.github.sds100.keymapper.util.ServiceEvent - -/** - * Created by sds100 on 20/02/2021. - */ - -class TestActionUseCaseImpl( - private val serviceAdapter: ServiceAdapter, -) : TestActionUseCase { - override suspend fun invoke(action: ActionData): Result<*> = - serviceAdapter.send(ServiceEvent.TestAction(action)) -} - -interface TestActionUseCase { - suspend operator fun invoke(action: ActionData): Result<*> -} diff --git a/app/src/main/java/io/github/sds100/keymapper/actions/sound/ChooseSoundFileUseCase.kt b/app/src/main/java/io/github/sds100/keymapper/actions/sound/ChooseSoundFileUseCase.kt deleted file mode 100644 index 2e365bf23b..0000000000 --- a/app/src/main/java/io/github/sds100/keymapper/actions/sound/ChooseSoundFileUseCase.kt +++ /dev/null @@ -1,40 +0,0 @@ -package io.github.sds100.keymapper.actions.sound - -import io.github.sds100.keymapper.system.files.FileAdapter -import io.github.sds100.keymapper.util.Error -import io.github.sds100.keymapper.util.Result -import io.github.sds100.keymapper.util.Success -import kotlinx.coroutines.flow.StateFlow - -/** - * Created by sds100 on 25/06/2021. - */ - -class ChooseSoundFileUseCaseImpl( - private val fileAdapter: FileAdapter, - private val soundsManager: SoundsManager, -) : ChooseSoundFileUseCase { - override val soundFiles = soundsManager.soundFiles - - override suspend fun saveSound(uri: String): Result = soundsManager.saveNewSound(uri) - - override fun getSoundFileName(uri: String): Result { - val name = fileAdapter.getFileFromUri(uri).name - - return if (name == null) { - Error.NoFileName - } else { - Success(name) - } - } -} - -interface ChooseSoundFileUseCase { - - /** - * @return the sound file uid - */ - suspend fun saveSound(uri: String): Result - val soundFiles: StateFlow> - fun getSoundFileName(uri: String): Result -} diff --git a/app/src/main/java/io/github/sds100/keymapper/actions/sound/SoundFileInfo.kt b/app/src/main/java/io/github/sds100/keymapper/actions/sound/SoundFileInfo.kt deleted file mode 100644 index 5178df7542..0000000000 --- a/app/src/main/java/io/github/sds100/keymapper/actions/sound/SoundFileInfo.kt +++ /dev/null @@ -1,6 +0,0 @@ -package io.github.sds100.keymapper.actions.sound - -/** - * Created by sds100 on 25/06/2021. - */ -data class SoundFileInfo(val uid: String, val name: String) diff --git a/app/src/main/java/io/github/sds100/keymapper/actions/uielement/InteractUiElementFragment.kt b/app/src/main/java/io/github/sds100/keymapper/actions/uielement/InteractUiElementFragment.kt deleted file mode 100644 index c8f0f24c10..0000000000 --- a/app/src/main/java/io/github/sds100/keymapper/actions/uielement/InteractUiElementFragment.kt +++ /dev/null @@ -1,102 +0,0 @@ -package io.github.sds100.keymapper.actions.uielement - -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import androidx.compose.foundation.layout.WindowInsets -import androidx.compose.foundation.layout.WindowInsetsSides -import androidx.compose.foundation.layout.add -import androidx.compose.foundation.layout.displayCutout -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.only -import androidx.compose.foundation.layout.systemBars -import androidx.compose.foundation.layout.windowInsetsPadding -import androidx.compose.ui.Modifier -import androidx.compose.ui.platform.ViewCompositionStrategy -import androidx.core.os.bundleOf -import androidx.fragment.app.Fragment -import androidx.fragment.app.setFragmentResult -import androidx.fragment.app.viewModels -import androidx.lifecycle.Lifecycle -import androidx.lifecycle.withStateAtLeast -import androidx.navigation.findNavController -import androidx.navigation.fragment.findNavController -import androidx.navigation.fragment.navArgs -import io.github.sds100.keymapper.compose.KeyMapperTheme -import io.github.sds100.keymapper.databinding.FragmentComposeBinding -import io.github.sds100.keymapper.util.Inject -import io.github.sds100.keymapper.util.launchRepeatOnLifecycle -import io.github.sds100.keymapper.util.ui.showPopups -import io.github.sds100.keymapper.util.viewLifecycleScope -import kotlinx.coroutines.flow.collectLatest -import kotlinx.coroutines.launch -import kotlinx.serialization.json.Json - -class InteractUiElementFragment : Fragment() { - - companion object { - const val EXTRA_ACTION = "extra_action" - } - - private val args: InteractUiElementFragmentArgs by navArgs() - - private val viewModel by viewModels { - Inject.interactUiElementViewModel(requireContext()) - } - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - - args.action?.let { argsAction -> viewModel.loadAction(Json.decodeFromString(argsAction)) } - - launchRepeatOnLifecycle(Lifecycle.State.CREATED) { - viewModel.returnAction.collectLatest { action -> - viewLifecycleScope.launch { - withStateAtLeast(Lifecycle.State.RESUMED) { - setFragmentResult( - args.requestKey, - bundleOf(EXTRA_ACTION to Json.encodeToString(action)), - ) - findNavController().navigateUp() - } - } - } - } - } - - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle?, - ): View { - FragmentComposeBinding.inflate(inflater, container, false).apply { - composeView.apply { - // Dispose of the Composition when the view's LifecycleOwner - // is destroyed - setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed) - setContent { - KeyMapperTheme { - InteractUiElementScreen( - modifier = Modifier - .fillMaxSize() - .windowInsetsPadding( - WindowInsets.systemBars.only(sides = WindowInsetsSides.Horizontal) - .add(WindowInsets.displayCutout.only(sides = WindowInsetsSides.Horizontal)), - ), - viewModel = viewModel, - navigateBack = findNavController()::navigateUp, - ) - } - } - } - return this.root - } - } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - - viewModel.showPopups(this, view) - } -} diff --git a/app/src/main/java/io/github/sds100/keymapper/api/LaunchKeyMapShortcutActivity.kt b/app/src/main/java/io/github/sds100/keymapper/api/LaunchKeyMapShortcutActivity.kt deleted file mode 100644 index b83fec2085..0000000000 --- a/app/src/main/java/io/github/sds100/keymapper/api/LaunchKeyMapShortcutActivity.kt +++ /dev/null @@ -1,47 +0,0 @@ -package io.github.sds100.keymapper.api - -import android.app.Activity -import android.content.Intent -import android.os.Bundle -import io.github.sds100.keymapper.Constants -import io.github.sds100.keymapper.R -import io.github.sds100.keymapper.ServiceLocator -import io.github.sds100.keymapper.system.accessibility.ServiceState -import splitties.toast.toast - -/** - * Created by sds100 on 08/09/20. - */ - -// DON'T MOVE THIS CLASS TO A DIFFERENT PACKAGE BECAUSE IT BREAKS THE API -/** - * Use basic Activity, NOT AppCompatActivity so the NoDisplay theme works. Otherwise an - * exception may be thrown because the theme doesn't extend AppCompat. - */ -class LaunchKeyMapShortcutActivity : Activity() { - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - - val accessibilityServiceState = ServiceLocator.accessibilityServiceAdapter(this).state.value - - when (accessibilityServiceState) { - ServiceState.ENABLED -> - if (intent.action == Api.ACTION_TRIGGER_KEYMAP_BY_UID) { - Intent(Api.ACTION_TRIGGER_KEYMAP_BY_UID).apply { - setPackage(Constants.PACKAGE_NAME) - - val uuid = intent.getStringExtra(Api.EXTRA_KEYMAP_UID) - putExtra(Api.EXTRA_KEYMAP_UID, uuid) - - sendBroadcast(this) - } - } - - ServiceState.CRASHED -> toast(R.string.error_accessibility_service_crashed) - ServiceState.DISABLED -> toast(R.string.error_accessibility_service_disabled) - } - - finish() - } -} diff --git a/app/src/main/java/io/github/sds100/keymapper/constraints/ChooseConstraintFragment.kt b/app/src/main/java/io/github/sds100/keymapper/constraints/ChooseConstraintFragment.kt deleted file mode 100644 index 727bd91534..0000000000 --- a/app/src/main/java/io/github/sds100/keymapper/constraints/ChooseConstraintFragment.kt +++ /dev/null @@ -1,103 +0,0 @@ -package io.github.sds100.keymapper.constraints - -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import androidx.compose.foundation.layout.WindowInsets -import androidx.compose.foundation.layout.WindowInsetsSides -import androidx.compose.foundation.layout.add -import androidx.compose.foundation.layout.displayCutout -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.only -import androidx.compose.foundation.layout.systemBars -import androidx.compose.foundation.layout.windowInsetsPadding -import androidx.compose.ui.Modifier -import androidx.compose.ui.platform.ViewCompositionStrategy -import androidx.core.os.bundleOf -import androidx.fragment.app.Fragment -import androidx.fragment.app.setFragmentResult -import androidx.fragment.app.viewModels -import androidx.lifecycle.Lifecycle -import androidx.lifecycle.withStateAtLeast -import androidx.navigation.findNavController -import androidx.navigation.fragment.findNavController -import androidx.navigation.fragment.navArgs -import io.github.sds100.keymapper.compose.KeyMapperTheme -import io.github.sds100.keymapper.databinding.FragmentComposeBinding -import io.github.sds100.keymapper.util.Inject -import io.github.sds100.keymapper.util.launchRepeatOnLifecycle -import io.github.sds100.keymapper.util.ui.setupNavigation -import io.github.sds100.keymapper.util.ui.showPopups -import io.github.sds100.keymapper.util.viewLifecycleScope -import kotlinx.coroutines.flow.collectLatest -import kotlinx.coroutines.launch -import kotlinx.serialization.json.Json - -class ChooseConstraintFragment : Fragment() { - - companion object { - const val EXTRA_CONSTRAINT = "extra_constraint" - } - - private val navArgs by navArgs() - - private val viewModel: ChooseConstraintViewModel by viewModels { - Inject.chooseConstraintListViewModel(requireContext()) - } - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - - viewModel.setupNavigation(this) - - launchRepeatOnLifecycle(Lifecycle.State.CREATED) { - viewModel.returnResult.collectLatest { constraint -> - viewLifecycleScope.launch { - withStateAtLeast(Lifecycle.State.RESUMED) { - setFragmentResult( - navArgs.requestKey, - bundleOf(EXTRA_CONSTRAINT to Json.encodeToString(constraint)), - ) - findNavController().navigateUp() - } - } - } - } - } - - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle?, - ): View { - FragmentComposeBinding.inflate(inflater, container, false).apply { - composeView.apply { - // Dispose of the Composition when the view's LifecycleOwner - // is destroyed - setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed) - setContent { - KeyMapperTheme { - ChooseConstraintScreen( - modifier = Modifier - .fillMaxSize() - .windowInsetsPadding( - WindowInsets.systemBars.only(sides = WindowInsetsSides.Horizontal) - .add(WindowInsets.displayCutout.only(sides = WindowInsetsSides.Horizontal)), - ), - viewModel = viewModel, - onNavigateBack = findNavController()::navigateUp, - ) - } - } - } - return this.root - } - } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - - viewModel.showPopups(this, view) - } -} diff --git a/app/src/main/java/io/github/sds100/keymapper/constraints/ConstraintMode.kt b/app/src/main/java/io/github/sds100/keymapper/constraints/ConstraintMode.kt deleted file mode 100644 index ddc7a85d6c..0000000000 --- a/app/src/main/java/io/github/sds100/keymapper/constraints/ConstraintMode.kt +++ /dev/null @@ -1,9 +0,0 @@ -package io.github.sds100.keymapper.constraints - -/** - * Created by sds100 on 03/03/2021. - */ -enum class ConstraintMode { - AND, - OR, -} diff --git a/app/src/main/java/io/github/sds100/keymapper/constraints/DisplayConstraintUseCase.kt b/app/src/main/java/io/github/sds100/keymapper/constraints/DisplayConstraintUseCase.kt deleted file mode 100644 index 6b5bec73ee..0000000000 --- a/app/src/main/java/io/github/sds100/keymapper/constraints/DisplayConstraintUseCase.kt +++ /dev/null @@ -1,13 +0,0 @@ -package io.github.sds100.keymapper.constraints - -import android.graphics.drawable.Drawable -import io.github.sds100.keymapper.util.Error -import io.github.sds100.keymapper.util.Result - -interface DisplayConstraintUseCase : GetConstraintErrorUseCase { - fun getAppName(packageName: String): Result - fun getAppIcon(packageName: String): Result - fun getInputMethodLabel(imeId: String): Result - fun neverShowDndTriggerError() - suspend fun fixError(error: Error) -} diff --git a/app/src/main/java/io/github/sds100/keymapper/groups/GroupListItemModel.kt b/app/src/main/java/io/github/sds100/keymapper/groups/GroupListItemModel.kt deleted file mode 100644 index 9f53a1da74..0000000000 --- a/app/src/main/java/io/github/sds100/keymapper/groups/GroupListItemModel.kt +++ /dev/null @@ -1,5 +0,0 @@ -package io.github.sds100.keymapper.groups - -import io.github.sds100.keymapper.util.ui.compose.ComposeIconInfo - -data class GroupListItemModel(val uid: String, val name: String, val icon: ComposeIconInfo? = null) diff --git a/app/src/main/java/io/github/sds100/keymapper/home/HomeDestination.kt b/app/src/main/java/io/github/sds100/keymapper/home/HomeDestination.kt deleted file mode 100644 index 33d985c64f..0000000000 --- a/app/src/main/java/io/github/sds100/keymapper/home/HomeDestination.kt +++ /dev/null @@ -1,6 +0,0 @@ -package io.github.sds100.keymapper.home - -sealed class HomeDestination(val route: String) { - data object KeyMaps : HomeDestination("key_maps") - data object FloatingButtons : HomeDestination("floating_buttons") -} diff --git a/app/src/main/java/io/github/sds100/keymapper/home/HomeFragment.kt b/app/src/main/java/io/github/sds100/keymapper/home/HomeFragment.kt deleted file mode 100644 index 5ba4a8c508..0000000000 --- a/app/src/main/java/io/github/sds100/keymapper/home/HomeFragment.kt +++ /dev/null @@ -1,98 +0,0 @@ -package io.github.sds100.keymapper.home - -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import androidx.compose.foundation.layout.WindowInsets -import androidx.compose.foundation.layout.WindowInsetsSides -import androidx.compose.foundation.layout.add -import androidx.compose.foundation.layout.displayCutout -import androidx.compose.foundation.layout.only -import androidx.compose.foundation.layout.systemBars -import androidx.compose.foundation.layout.windowInsetsPadding -import androidx.compose.ui.Modifier -import androidx.compose.ui.platform.ViewCompositionStrategy -import androidx.fragment.app.Fragment -import androidx.fragment.app.activityViewModels -import androidx.navigation.findNavController -import io.github.sds100.keymapper.ActivityViewModel -import io.github.sds100.keymapper.BaseMainActivity -import io.github.sds100.keymapper.NavAppDirections -import io.github.sds100.keymapper.ServiceLocator -import io.github.sds100.keymapper.compose.KeyMapperTheme -import io.github.sds100.keymapper.databinding.FragmentComposeBinding -import io.github.sds100.keymapper.util.Inject -import io.github.sds100.keymapper.util.ui.setupNavigation -import io.github.sds100.keymapper.util.ui.showPopups - -class HomeFragment : Fragment() { - - private val homeViewModel: HomeViewModel by activityViewModels { - Inject.homeViewModel(requireContext()) - } - - val activityViewModel: ActivityViewModel by activityViewModels { - ActivityViewModel.Factory(ServiceLocator.resourceProvider(requireContext())) - } - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - - homeViewModel.setupNavigation(this) - homeViewModel.keyMapListViewModel.setupNavigation(this) - } - - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle?, - ): View { - val startDestination = - if (!activityViewModel.handledActivityLaunchIntent && - requireActivity().intent?.action == BaseMainActivity.ACTION_USE_FLOATING_BUTTONS - ) { - activityViewModel.handledActivityLaunchIntent = true - HomeDestination.FloatingButtons - } else { - HomeDestination.KeyMaps - } - - FragmentComposeBinding.inflate(inflater, container, false).apply { - composeView.apply { - // Dispose of the Composition when the view's LifecycleOwner - // is destroyed - setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed) - setContent { - KeyMapperTheme { - HomeScreen( - modifier = Modifier - .windowInsetsPadding( - WindowInsets.systemBars.only(sides = WindowInsetsSides.Horizontal) - .add(WindowInsets.displayCutout.only(sides = WindowInsetsSides.Horizontal)), - ), - viewModel = homeViewModel, - onSettingsClick = { - findNavController().navigate(NavAppDirections.toSettingsFragment()) - }, - onAboutClick = { - findNavController().navigate(NavAppDirections.actionGlobalAboutFragment()) - }, - finishActivity = requireActivity()::finish, - startDestination = startDestination, - ) - } - } - } - return this.root - } - } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - - homeViewModel.showPopups(this, view) - homeViewModel.keyMapListViewModel.showPopups(this, view) - homeViewModel.listFloatingLayoutsViewModel.showPopups(this, view) - } -} diff --git a/app/src/main/java/io/github/sds100/keymapper/home/HomeScreen.kt b/app/src/main/java/io/github/sds100/keymapper/home/HomeScreen.kt deleted file mode 100644 index b8ffce2f7a..0000000000 --- a/app/src/main/java/io/github/sds100/keymapper/home/HomeScreen.kt +++ /dev/null @@ -1,189 +0,0 @@ -package io.github.sds100.keymapper.home - -import androidx.compose.animation.AnimatedVisibility -import androidx.compose.animation.EnterTransition -import androidx.compose.animation.ExitTransition -import androidx.compose.animation.slideInVertically -import androidx.compose.animation.slideOutVertically -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.padding -import androidx.compose.material3.Badge -import androidx.compose.material3.BadgedBox -import androidx.compose.material3.Icon -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.NavigationBar -import androidx.compose.material3.NavigationBarItem -import androidx.compose.material3.SnackbarHostState -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.remember -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.text.style.TextOverflow -import androidx.compose.ui.unit.dp -import androidx.lifecycle.compose.collectAsStateWithLifecycle -import androidx.navigation.NavDestination.Companion.hierarchy -import androidx.navigation.NavGraph.Companion.findStartDestination -import androidx.navigation.NavHostController -import androidx.navigation.compose.NavHost -import androidx.navigation.compose.composable -import androidx.navigation.compose.currentBackStackEntryAsState -import androidx.navigation.compose.rememberNavController -import io.github.sds100.keymapper.util.ui.SelectionState - -@Composable -fun HomeScreen( - modifier: Modifier = Modifier, - viewModel: HomeViewModel, - onSettingsClick: () -> Unit, - onAboutClick: () -> Unit, - finishActivity: () -> Unit, - startDestination: HomeDestination = HomeDestination.KeyMaps, -) { - val navController = rememberNavController() - val navBarItems by viewModel.navBarItems.collectAsStateWithLifecycle() - - val snackbarState = remember { SnackbarHostState() } - val selectionState by viewModel.keyMapListViewModel.multiSelectProvider.state.collectAsStateWithLifecycle() - - HomeScreen( - modifier = modifier, - isSelectingKeyMaps = selectionState is SelectionState.Selecting, - startDestination = startDestination, - navController = navController, - navBarItems = navBarItems, - keyMapsContent = { - HomeKeyMapListScreen( - viewModel = viewModel.keyMapListViewModel, - snackbarState = snackbarState, - onSettingsClick = onSettingsClick, - onAboutClick = onAboutClick, - finishActivity = finishActivity, - fabBottomPadding = if (navBarItems.size == 1) { - 0.dp - } else { - 80.dp - }, - ) - }, - floatingButtonsContent = { - HomeFloatingLayoutsScreen( - viewModel = viewModel.listFloatingLayoutsViewModel, - navController = navController, - snackbarState = snackbarState, - fabBottomPadding = if (navBarItems.size == 1) { - 0.dp - } else { - 80.dp - }, - ) - }, - ) -} - -@Composable -private fun HomeScreen( - modifier: Modifier = Modifier, - isSelectingKeyMaps: Boolean, - startDestination: HomeDestination = HomeDestination.KeyMaps, - navController: NavHostController, - navBarItems: List, - keyMapsContent: @Composable () -> Unit, - floatingButtonsContent: @Composable () -> Unit, -) { - val navBackStackEntry by navController.currentBackStackEntryAsState() - val currentDestination = navBackStackEntry?.destination - - Column(modifier) { - Box(contentAlignment = Alignment.BottomCenter) { - NavHost( - modifier = Modifier.fillMaxSize(), - contentAlignment = Alignment.TopCenter, - navController = navController, - startDestination = startDestination.route, - // use no animations because otherwise the transition freezes - // when quickly navigating to another page while the transition is still happening. - enterTransition = { EnterTransition.None }, - exitTransition = { ExitTransition.None }, - ) { - composable(HomeDestination.KeyMaps.route) { - keyMapsContent() - } - composable(HomeDestination.FloatingButtons.route) { - floatingButtonsContent() - } - } - - this@Column.AnimatedVisibility( - visible = !isSelectingKeyMaps && navBarItems.size > 1, - enter = slideInVertically { it }, - exit = slideOutVertically { it }, - ) { - NavigationBar { - navBarItems.forEach { item -> - NavigationBarItem( - icon = { - if (item.badge == null) { - Icon(item.icon, contentDescription = null) - } else { - BadgedBox( - badge = { - Badge( - modifier = Modifier - .height(22.dp) - .padding(start = 10.dp), - containerColor = MaterialTheme.colorScheme.primary, - contentColor = MaterialTheme.colorScheme.onPrimary, - ) { - Text( - modifier = Modifier.padding(horizontal = 2.dp), - text = item.badge, - style = MaterialTheme.typography.labelLarge, - ) - } - }, - ) { - Icon(item.icon, contentDescription = null) - } - } - }, - label = { - Text( - item.label, - maxLines = 1, - overflow = TextOverflow.Ellipsis, - ) - }, - selected = currentDestination?.hierarchy?.any { it.route == item.destination.route } == true, - onClick = { - // don't do anything if clicking on the current - // destination because this results in some ugly animations. - if (currentDestination?.route == item.destination.route) { - return@NavigationBarItem - } - - navController.navigate(item.destination.route) { - // Pop up to the start destination of the graph to - // avoid building up a large stack of destinations - // on the back stack as users select items - popUpTo(navController.graph.findStartDestination().id) { - saveState = true - } - // Avoid multiple copies of the same destination when - // reselecting the same item - launchSingleTop = true - // Restore state when re-selecting a previously selected item - restoreState = true - } - }, - ) - } - } - } - } - } -} diff --git a/app/src/main/java/io/github/sds100/keymapper/home/HomeTab.kt b/app/src/main/java/io/github/sds100/keymapper/home/HomeTab.kt deleted file mode 100644 index 264083953c..0000000000 --- a/app/src/main/java/io/github/sds100/keymapper/home/HomeTab.kt +++ /dev/null @@ -1,9 +0,0 @@ -package io.github.sds100.keymapper.home - -/** - * Created by sds100 on 02/04/2021. - */ -enum class HomeTab { - KEY_EVENTS, - FINGERPRINT_MAPS, -} diff --git a/app/src/main/java/io/github/sds100/keymapper/home/HomeViewModel.kt b/app/src/main/java/io/github/sds100/keymapper/home/HomeViewModel.kt index 6044fad6cf..0c2f3dc906 100644 --- a/app/src/main/java/io/github/sds100/keymapper/home/HomeViewModel.kt +++ b/app/src/main/java/io/github/sds100/keymapper/home/HomeViewModel.kt @@ -1,44 +1,22 @@ package io.github.sds100.keymapper.home -import android.os.Build -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.outlined.BubbleChart -import androidx.compose.material.icons.outlined.Keyboard -import androidx.compose.ui.graphics.vector.ImageVector -import androidx.lifecycle.ViewModel -import androidx.lifecycle.ViewModelProvider -import androidx.lifecycle.viewModelScope -import io.github.sds100.keymapper.Constants -import io.github.sds100.keymapper.R -import io.github.sds100.keymapper.backup.BackupRestoreMappingsUseCase -import io.github.sds100.keymapper.floating.ListFloatingLayoutsUseCase -import io.github.sds100.keymapper.floating.ListFloatingLayoutsViewModel -import io.github.sds100.keymapper.keymaps.KeyMapListViewModel -import io.github.sds100.keymapper.keymaps.ListKeyMapsUseCase -import io.github.sds100.keymapper.keymaps.PauseKeyMapsUseCase -import io.github.sds100.keymapper.onboarding.OnboardingUseCase -import io.github.sds100.keymapper.sorting.SortKeyMapsUseCase -import io.github.sds100.keymapper.system.inputmethod.ShowInputMethodPickerUseCase -import io.github.sds100.keymapper.trigger.SetupGuiKeyboardUseCase -import io.github.sds100.keymapper.util.ui.DialogResponse -import io.github.sds100.keymapper.util.ui.NavigationViewModel -import io.github.sds100.keymapper.util.ui.NavigationViewModelImpl -import io.github.sds100.keymapper.util.ui.PopupUi -import io.github.sds100.keymapper.util.ui.PopupViewModel -import io.github.sds100.keymapper.util.ui.PopupViewModelImpl -import io.github.sds100.keymapper.util.ui.ResourceProvider -import io.github.sds100.keymapper.util.ui.showPopup -import kotlinx.coroutines.flow.SharingStarted -import kotlinx.coroutines.flow.StateFlow -import kotlinx.coroutines.flow.combine -import kotlinx.coroutines.flow.first -import kotlinx.coroutines.flow.stateIn -import kotlinx.coroutines.launch - -/** - * Created by sds100 on 18/01/21. - */ -class HomeViewModel( +import dagger.hilt.android.lifecycle.HiltViewModel +import io.github.sds100.keymapper.base.backup.BackupRestoreMappingsUseCase +import io.github.sds100.keymapper.base.home.BaseHomeViewModel +import io.github.sds100.keymapper.base.home.ShowHomeScreenAlertsUseCase +import io.github.sds100.keymapper.base.keymaps.ListKeyMapsUseCase +import io.github.sds100.keymapper.base.keymaps.PauseKeyMapsUseCase +import io.github.sds100.keymapper.base.onboarding.OnboardingUseCase +import io.github.sds100.keymapper.base.sorting.SortKeyMapsUseCase +import io.github.sds100.keymapper.base.system.inputmethod.ShowInputMethodPickerUseCase +import io.github.sds100.keymapper.base.trigger.SetupGuiKeyboardUseCase +import io.github.sds100.keymapper.base.utils.navigation.NavigationProvider +import io.github.sds100.keymapper.base.utils.ui.DialogProvider +import io.github.sds100.keymapper.base.utils.ui.ResourceProvider +import javax.inject.Inject + +@HiltViewModel +class HomeViewModel @Inject constructor( private val listKeyMaps: ListKeyMapsUseCase, private val pauseKeyMaps: PauseKeyMapsUseCase, private val backupRestore: BackupRestoreMappingsUseCase, @@ -47,178 +25,19 @@ class HomeViewModel( resourceProvider: ResourceProvider, private val setupGuiKeyboard: SetupGuiKeyboardUseCase, private val sortKeyMaps: SortKeyMapsUseCase, - private val listFloatingLayouts: ListFloatingLayoutsUseCase, private val showInputMethodPickerUseCase: ShowInputMethodPickerUseCase, -) : ViewModel(), - ResourceProvider by resourceProvider, - PopupViewModel by PopupViewModelImpl(), - NavigationViewModel by NavigationViewModelImpl() { - - val navBarItems: StateFlow> = - combine( - listFloatingLayouts.showFloatingLayouts, - onboarding.hasViewedAdvancedTriggers, - transform = ::buildNavBarItems, - ) - .stateIn( - viewModelScope, - SharingStarted.Eagerly, - buildNavBarItems( - showFloatingLayouts = false, - viewedAdvancedTriggers = false, - ), - ) - - val keyMapListViewModel by lazy { - KeyMapListViewModel( - viewModelScope, - listKeyMaps, - resourceProvider, - setupGuiKeyboard, - sortKeyMaps, - showAlertsUseCase, - pauseKeyMaps, - backupRestore, - showInputMethodPickerUseCase, - onboarding, - ) - } - - val listFloatingLayoutsViewModel by lazy { - ListFloatingLayoutsViewModel( - viewModelScope, - listFloatingLayouts, - resourceProvider, - ) - } - - init { - viewModelScope.launch { - onboarding.showWhatsNew.collect { showWhatsNew -> - if (showWhatsNew) { - showWhatsNewDialog() - } - } - } - - viewModelScope.launch { - if (setupGuiKeyboard.isInstalled.first() && !setupGuiKeyboard.isCompatibleVersion.first()) { - showUpgradeGuiKeyboardDialog() - } - } - } - - private fun buildNavBarItems( - showFloatingLayouts: Boolean, - viewedAdvancedTriggers: Boolean, - ): List { - val items = mutableListOf() - items.add( - HomeNavBarItem( - HomeDestination.KeyMaps, - getString(R.string.home_nav_bar_key_maps), - icon = Icons.Outlined.Keyboard, - badge = null, - ), - ) - - if (showFloatingLayouts && Build.VERSION.SDK_INT >= Constants.MIN_API_FLOATING_BUTTONS) { - items.add( - HomeNavBarItem( - HomeDestination.FloatingButtons, - getString(R.string.home_nav_bar_floating_buttons), - icon = Icons.Outlined.BubbleChart, - badge = if (viewedAdvancedTriggers) { - null - } else { - getString(R.string.button_advanced_triggers_badge) - }, - ), - ) - } - - return items - } - - private suspend fun showWhatsNewDialog() { - val dialog = PopupUi.Dialog( - title = getString(R.string.whats_new), - message = onboarding.getWhatsNewText(), - positiveButtonText = getString(R.string.pos_ok), - neutralButtonText = getString(R.string.neutral_changelog), - ) - - // don't return if they dismiss the dialog because this is common behaviour. - val response = showPopup("whats-new", dialog) - - if (response == DialogResponse.NEUTRAL) { - showPopup("url_changelog", PopupUi.OpenUrl(getString(R.string.url_changelog))) - } - - onboarding.showedWhatsNew() - } - - private suspend fun showUpgradeGuiKeyboardDialog() { - val dialog = PopupUi.Dialog( - title = getString(R.string.dialog_upgrade_gui_keyboard_title), - message = getString(R.string.dialog_upgrade_gui_keyboard_message), - positiveButtonText = getString(R.string.dialog_upgrade_gui_keyboard_positive), - negativeButtonText = getString(R.string.dialog_upgrade_gui_keyboard_neutral), - ) - - val response = showPopup("upgrade_gui_keyboard", dialog) - - if (response == DialogResponse.POSITIVE) { - showPopup( - "gui_keyboard_play_store", - PopupUi.OpenUrl(getString(R.string.url_play_store_keymapper_gui_keyboard)), - ) - } - } - - @Suppress("UNCHECKED_CAST") - class Factory( - private val listKeyMaps: ListKeyMapsUseCase, - private val pauseMappings: PauseKeyMapsUseCase, - private val backupRestore: BackupRestoreMappingsUseCase, - private val showAlertsUseCase: ShowHomeScreenAlertsUseCase, - private val onboarding: OnboardingUseCase, - private val resourceProvider: ResourceProvider, - private val setupGuiKeyboard: SetupGuiKeyboardUseCase, - private val sortKeyMaps: SortKeyMapsUseCase, - private val listFloatingLayouts: ListFloatingLayoutsUseCase, - private val showInputMethodPickerUseCase: ShowInputMethodPickerUseCase, - ) : ViewModelProvider.NewInstanceFactory() { - - override fun create(modelClass: Class): T = HomeViewModel( - listKeyMaps, - pauseMappings, - backupRestore, - showAlertsUseCase, - onboarding, - resourceProvider, - setupGuiKeyboard, - sortKeyMaps, - listFloatingLayouts, - showInputMethodPickerUseCase, - ) as T - } -} - -enum class SelectedKeyMapsEnabled { - ALL, - NONE, - MIXED, -} - -data class HomeWarningListItem( - val id: String, - val text: String, -) - -data class HomeNavBarItem( - val destination: HomeDestination, - val label: String, - val icon: ImageVector, - val badge: String? = null, + navigationProvider: NavigationProvider, + dialogProvider: DialogProvider, +) : BaseHomeViewModel( + listKeyMaps, + pauseKeyMaps, + backupRestore, + showAlertsUseCase, + onboarding, + resourceProvider, + setupGuiKeyboard, + sortKeyMaps, + showInputMethodPickerUseCase, + navigationProvider, + dialogProvider, ) diff --git a/app/src/main/java/io/github/sds100/keymapper/keymaps/ClickType.kt b/app/src/main/java/io/github/sds100/keymapper/keymaps/ClickType.kt deleted file mode 100644 index 3a259bd68e..0000000000 --- a/app/src/main/java/io/github/sds100/keymapper/keymaps/ClickType.kt +++ /dev/null @@ -1,10 +0,0 @@ -package io.github.sds100.keymapper.keymaps - -/** - * Created by sds100 on 21/02/2021. - */ -enum class ClickType { - SHORT_PRESS, - LONG_PRESS, - DOUBLE_PRESS, -} diff --git a/app/src/main/java/io/github/sds100/keymapper/keymaps/ConfigKeyMapFragment.kt b/app/src/main/java/io/github/sds100/keymapper/keymaps/ConfigKeyMapFragment.kt deleted file mode 100644 index 20e9fc683e..0000000000 --- a/app/src/main/java/io/github/sds100/keymapper/keymaps/ConfigKeyMapFragment.kt +++ /dev/null @@ -1,113 +0,0 @@ -package io.github.sds100.keymapper.keymaps - -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import androidx.compose.foundation.layout.WindowInsets -import androidx.compose.foundation.layout.WindowInsetsSides -import androidx.compose.foundation.layout.add -import androidx.compose.foundation.layout.displayCutout -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.only -import androidx.compose.foundation.layout.systemBars -import androidx.compose.foundation.layout.windowInsetsPadding -import androidx.compose.ui.Modifier -import androidx.compose.ui.platform.ViewCompositionStrategy -import androidx.fragment.app.Fragment -import androidx.navigation.findNavController -import androidx.navigation.fragment.navArgs -import androidx.navigation.navGraphViewModels -import io.github.sds100.keymapper.R -import io.github.sds100.keymapper.compose.KeyMapperTheme -import io.github.sds100.keymapper.databinding.FragmentComposeBinding -import io.github.sds100.keymapper.util.Inject -import io.github.sds100.keymapper.util.ui.setupNavigation -import io.github.sds100.keymapper.util.ui.showPopups - -class ConfigKeyMapFragment : Fragment() { - - private val args by navArgs() - - private val viewModel: ConfigKeyMapViewModel by navGraphViewModels(R.id.nav_config_keymap) { - Inject.configKeyMapViewModel(requireContext()) - } - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - - // only load the keymap if opening this fragment for the first time - if (savedInstanceState == null) { - args.keyMapUid.also { keyMapUid -> - if (keyMapUid == null) { - viewModel.loadNewKeymap( - args.newFloatingButtonTriggerKey, - groupUid = args.groupUid, - ) - } else { - viewModel.loadKeyMap(keyMapUid) - } - } - - if (args.showAdvancedTriggers) { - viewModel.configTriggerViewModel.showAdvancedTriggersBottomSheet = true - } - } - - viewModel.configTriggerViewModel.setupNavigation(this) - viewModel.configActionsViewModel.setupNavigation(this) - viewModel.configConstraintsViewModel.setupNavigation(this) - } - - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle?, - ): View { - FragmentComposeBinding.inflate(inflater, container, false).apply { - composeView.apply { - // Dispose of the Composition when the view's LifecycleOwner - // is destroyed - setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed) - setContent { - KeyMapperTheme { - ConfigKeyMapScreen( - modifier = Modifier - .windowInsetsPadding( - WindowInsets.systemBars.only(sides = WindowInsetsSides.Horizontal) - .add(WindowInsets.displayCutout.only(sides = WindowInsetsSides.Horizontal)), - ) - .fillMaxSize(), - viewModel = viewModel, - navigateBack = findNavController()::navigateUp, - ) - } - } - } - return this.root - } - } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - - viewModel.configTriggerViewModel.showPopups(this, view) - viewModel.configTriggerViewModel.optionsViewModel.showPopups(this, view) - viewModel.configActionsViewModel.showPopups(this, view) - viewModel.configConstraintsViewModel.showPopups(this, view) - } - - override fun onSaveInstanceState(outState: Bundle) { - viewModel.saveState(outState) - - super.onSaveInstanceState(outState) - } - - override fun onViewStateRestored(savedInstanceState: Bundle?) { - super.onViewStateRestored(savedInstanceState) - - savedInstanceState ?: return - - viewModel.restoreState(savedInstanceState) - } -} diff --git a/app/src/main/java/io/github/sds100/keymapper/keymaps/ConfigKeyMapScreen.kt b/app/src/main/java/io/github/sds100/keymapper/keymaps/ConfigKeyMapScreen.kt index f70a0998e8..61e36a3624 100644 --- a/app/src/main/java/io/github/sds100/keymapper/keymaps/ConfigKeyMapScreen.kt +++ b/app/src/main/java/io/github/sds100/keymapper/keymaps/ConfigKeyMapScreen.kt @@ -1,76 +1,26 @@ package io.github.sds100.keymapper.keymaps -import androidx.activity.compose.BackHandler -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.BoxWithConstraints -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.displayCutoutPadding -import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.width -import androidx.compose.foundation.pager.HorizontalPager -import androidx.compose.foundation.pager.rememberPagerState -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.automirrored.rounded.ArrowBack -import androidx.compose.material.icons.automirrored.rounded.HelpOutline -import androidx.compose.material.icons.rounded.Check -import androidx.compose.material3.AlertDialog -import androidx.compose.material3.BottomAppBar -import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.ExtendedFloatingActionButton -import androidx.compose.material3.FloatingActionButtonDefaults -import androidx.compose.material3.Icon -import androidx.compose.material3.IconButton -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.OutlinedCard -import androidx.compose.material3.PrimaryScrollableTabRow -import androidx.compose.material3.PrimaryTabRow -import androidx.compose.material3.Scaffold -import androidx.compose.material3.SnackbarHost import androidx.compose.material3.SnackbarHostState -import androidx.compose.material3.Switch -import androidx.compose.material3.Tab -import androidx.compose.material3.Text -import androidx.compose.material3.TextButton import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember -import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue -import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.platform.LocalUriHandler -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.tooling.preview.Devices -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.unit.Dp -import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle -import com.canopas.lib.showcase.IntroShowcase -import io.github.sds100.keymapper.R -import io.github.sds100.keymapper.actions.ActionsScreen -import io.github.sds100.keymapper.compose.KeyMapperTheme -import io.github.sds100.keymapper.constraints.ConstraintsScreen -import io.github.sds100.keymapper.onboarding.OnboardingTapTarget +import io.github.sds100.keymapper.base.actions.ActionsScreen +import io.github.sds100.keymapper.base.constraints.ConstraintsScreen +import io.github.sds100.keymapper.base.keymaps.BaseConfigKeyMapScreen +import io.github.sds100.keymapper.base.keymaps.KeyMapOptionsScreen +import io.github.sds100.keymapper.base.utils.ui.UnsavedChangesDialog import io.github.sds100.keymapper.trigger.TriggerScreen -import io.github.sds100.keymapper.util.ui.compose.KeyMapperTapTarget -import io.github.sds100.keymapper.util.ui.compose.keyMapperShowcaseStyle -import io.github.sds100.keymapper.util.ui.compose.openUriSafe -import kotlinx.coroutines.launch @Composable fun ConfigKeyMapScreen( modifier: Modifier = Modifier, viewModel: ConfigKeyMapViewModel, - navigateBack: () -> Unit, ) { val isKeyMapEnabled by viewModel.isEnabled.collectAsStateWithLifecycle() val showActionTapTarget by viewModel.showActionsTapTarget.collectAsStateWithLifecycle() @@ -81,16 +31,16 @@ fun ConfigKeyMapScreen( var showBackDialog by rememberSaveable { mutableStateOf(false) } if (showBackDialog) { - BackDialog( + UnsavedChangesDialog( onDismiss = { showBackDialog = false }, onDiscardClick = { showBackDialog = false - navigateBack() + viewModel.onBackClick() }, ) } - ConfigKeyMapScreen( + BaseConfigKeyMapScreen( modifier = modifier, isKeyMapEnabled = isKeyMapEnabled, onKeyMapEnabledChange = viewModel::onEnabledChanged, @@ -117,13 +67,10 @@ fun ConfigKeyMapScreen( if (viewModel.isKeyMapEdited) { showBackDialog = true } else { - navigateBack() + viewModel.onBackClick() } }, - onDoneClick = { - viewModel.save() - navigateBack() - }, + onDoneClick = viewModel::onDoneClick, snackbarHostState = snackbarHostState, showActionTapTarget = showActionTapTarget, onActionTapTargetCompleted = viewModel::onActionTapTargetCompleted, @@ -132,571 +79,3 @@ fun ConfigKeyMapScreen( onSkipTutorialClick = viewModel::onSkipTutorialClick, ) } - -@OptIn(ExperimentalMaterial3Api::class) -@Composable -private fun ConfigKeyMapScreen( - modifier: Modifier = Modifier, - isKeyMapEnabled: Boolean, - onKeyMapEnabledChange: (Boolean) -> Unit = {}, - triggerScreen: @Composable () -> Unit, - actionScreen: @Composable () -> Unit, - constraintsScreen: @Composable () -> Unit, - optionsScreen: @Composable () -> Unit, - onBackClick: () -> Unit = {}, - onDoneClick: () -> Unit = {}, - snackbarHostState: SnackbarHostState = SnackbarHostState(), - showActionTapTarget: Boolean = false, - onActionTapTargetCompleted: () -> Unit = {}, - showConstraintTapTarget: Boolean = false, - onConstraintTapTargetCompleted: () -> Unit = {}, - onSkipTutorialClick: () -> Unit = {}, -) { - val scope = rememberCoroutineScope() - val triggerHelpUrl = stringResource(R.string.url_trigger_guide) - val actionsHelpUrl = stringResource(R.string.url_action_guide) - val constraintsHelpUrl = stringResource(R.string.url_constraints_guide) - val optionsHelpUrl = stringResource(R.string.url_trigger_options_guide) - - var currentTab: ConfigKeyMapTab? by remember { mutableStateOf(null) } - val uriHandler = LocalUriHandler.current - val ctx = LocalContext.current - - BackHandler(onBack = onBackClick) - - Scaffold( - modifier.displayCutoutPadding(), - snackbarHost = { SnackbarHost(snackbarHostState) }, - bottomBar = { - ConfigKeyMapAppBar( - isKeyMapEnabled = isKeyMapEnabled, - onKeyMapEnabledChange = onKeyMapEnabledChange, - onBackClick = onBackClick, - onDoneClick = onDoneClick, - showHelpButton = currentTab == ConfigKeyMapTab.TRIGGER || - currentTab == ConfigKeyMapTab.ACTIONS || - currentTab == ConfigKeyMapTab.CONSTRAINTS || - currentTab == ConfigKeyMapTab.OPTIONS, - onHelpClick = { - val url = when (currentTab) { - ConfigKeyMapTab.TRIGGER -> triggerHelpUrl - ConfigKeyMapTab.ACTIONS -> actionsHelpUrl - ConfigKeyMapTab.CONSTRAINTS -> constraintsHelpUrl - ConfigKeyMapTab.OPTIONS -> optionsHelpUrl - else -> return@ConfigKeyMapAppBar - } - - if (url.isNotEmpty()) { - uriHandler.openUriSafe(ctx, url) - } - }, - ) - }, - ) { innerPadding -> - BoxWithConstraints(modifier = Modifier.padding(innerPadding)) { - val tabs = determineTabs(maxWidth, maxHeight) - val isVerticalTwoScreen = maxWidth < 720.dp - val pagerState = rememberPagerState(pageCount = { tabs.size }, initialPage = 0) - currentTab = tabs.getOrNull(pagerState.targetPage) - - Column(Modifier.fillMaxSize()) { - if (tabs.size > 1) { - @Composable - fun Tabs() { - for ((index, tab) in tabs.withIndex()) { - val tapTarget: OnboardingTapTarget? = when { - showActionTapTarget && tab == ConfigKeyMapTab.ACTIONS -> OnboardingTapTarget.CHOOSE_ACTION - showConstraintTapTarget && (tab == ConfigKeyMapTab.CONSTRAINTS || tab == ConfigKeyMapTab.CONSTRAINTS_AND_OPTIONS) -> OnboardingTapTarget.CHOOSE_CONSTRAINT - else -> null - } - - IntroShowcase( - showIntroShowCase = tapTarget != null, - onShowCaseCompleted = if (tapTarget == OnboardingTapTarget.CHOOSE_ACTION) onActionTapTargetCompleted else onConstraintTapTargetCompleted, - dismissOnClickOutside = true, - ) { - var tabModifier: Modifier = Modifier - - if (tapTarget != null) { - tabModifier = tabModifier.introShowCaseTarget( - index = 0, - style = keyMapperShowcaseStyle(), - ) { - KeyMapperTapTarget( - tapTarget = tapTarget, - onSkipClick = onSkipTutorialClick, - ) - } - } - - Tab( - modifier = tabModifier, - selected = pagerState.targetPage == index, - text = { - Text( - text = getTabTitle(tab), - maxLines = 1, - ) - }, - onClick = { - scope.launch { - pagerState.animateScrollToPage( - tabs.indexOf(tab), - ) - } - }, - ) - } - } - } - - if (this@BoxWithConstraints.maxWidth < 500.dp) { - PrimaryScrollableTabRow( - selectedTabIndex = pagerState.targetPage, - divider = {}, - edgePadding = 16.dp, - contentColor = MaterialTheme.colorScheme.onSurface, - ) { - Tabs() - } - } else { - PrimaryTabRow( - selectedTabIndex = pagerState.targetPage, - divider = {}, - contentColor = MaterialTheme.colorScheme.onSurface, - ) { - Tabs() - } - } - } - - HorizontalPager( - modifier = Modifier.fillMaxSize(), - state = pagerState, - ) { pageIndex -> - when (tabs[pageIndex]) { - ConfigKeyMapTab.TRIGGER -> triggerScreen() - ConfigKeyMapTab.ACTIONS -> actionScreen() - ConfigKeyMapTab.CONSTRAINTS -> constraintsScreen() - ConfigKeyMapTab.OPTIONS -> optionsScreen() - ConfigKeyMapTab.TRIGGER_AND_ACTIONS -> { - if (isVerticalTwoScreen) { - VerticalTwoScreens( - topTitle = stringResource(R.string.tab_trigger), - topHelpUrl = triggerHelpUrl, - topScreen = triggerScreen, - bottomTitle = stringResource(R.string.tab_actions), - bottomHelpUrl = actionsHelpUrl, - bottomScreen = actionScreen, - ) - } else { - HorizontalTwoScreens( - leftTitle = stringResource(R.string.tab_trigger), - leftHelpUrl = triggerHelpUrl, - leftScreen = triggerScreen, - rightTitle = stringResource(R.string.tab_actions), - rightHelpUrl = actionsHelpUrl, - rightScreen = actionScreen, - ) - } - } - - ConfigKeyMapTab.CONSTRAINTS_AND_OPTIONS -> { - if (isVerticalTwoScreen) { - VerticalTwoScreens( - topTitle = stringResource(R.string.tab_constraints), - topHelpUrl = constraintsHelpUrl, - topScreen = constraintsScreen, - bottomTitle = stringResource(R.string.tab_options), - bottomHelpUrl = optionsHelpUrl, - bottomScreen = optionsScreen, - ) - } else { - HorizontalTwoScreens( - leftTitle = stringResource(R.string.tab_constraints), - leftHelpUrl = constraintsHelpUrl, - leftScreen = constraintsScreen, - rightTitle = stringResource(R.string.tab_options), - rightHelpUrl = optionsHelpUrl, - rightScreen = optionsScreen, - ) - } - } - - ConfigKeyMapTab.ALL -> FourScreens( - topLeftTitle = stringResource(R.string.tab_trigger), - topLeftHelpUrl = triggerHelpUrl, - topLeftScreen = triggerScreen, - topRightTitle = stringResource(R.string.tab_actions), - topRightHelpUrl = actionsHelpUrl, - topRightScreen = actionScreen, - bottomLeftTitle = stringResource(R.string.tab_constraints), - bottomLeftHelpUrl = constraintsHelpUrl, - bottomLeftScreen = constraintsScreen, - bottomRightTitle = stringResource(R.string.tab_options), - bottomRightHelpUrl = optionsHelpUrl, - bottomRightScreen = optionsScreen, - ) - } - } - } - } - } -} - -@Composable -private fun ConfigKeyMapAppBar( - modifier: Modifier = Modifier, - isKeyMapEnabled: Boolean, - onKeyMapEnabledChange: (Boolean) -> Unit = {}, - showHelpButton: Boolean, - onHelpClick: () -> Unit, - onBackClick: () -> Unit, - onDoneClick: () -> Unit, -) { - BottomAppBar( - modifier = modifier, - floatingActionButton = { - ExtendedFloatingActionButton( - onClick = onDoneClick, - text = { Text(stringResource(R.string.button_done)) }, - icon = { - Icon(Icons.Rounded.Check, stringResource(R.string.button_done)) - }, - elevation = FloatingActionButtonDefaults.bottomAppBarFabElevation(), - ) - }, - actions = { - IconButton(onClick = onBackClick) { - Icon(Icons.AutoMirrored.Rounded.ArrowBack, stringResource(R.string.action_go_back)) - } - - Spacer(modifier = Modifier.width(8.dp)) - - val text = if (isKeyMapEnabled) { - stringResource(R.string.switch_enabled) - } else { - stringResource(R.string.switch_disabled) - } - - Text( - text = text, - style = MaterialTheme.typography.labelLarge, - ) - - Spacer(modifier = Modifier.width(16.dp)) - - Switch( - checked = isKeyMapEnabled, - onCheckedChange = onKeyMapEnabledChange, - ) - - Spacer(modifier = Modifier.weight(1f)) - - if (showHelpButton) { - IconButton(onClick = onHelpClick) { - Icon( - Icons.AutoMirrored.Rounded.HelpOutline, - stringResource(R.string.action_help), - ) - } - } - - Spacer(modifier = Modifier.width(8.dp)) - }, - ) -} - -@Composable -private fun VerticalTwoScreens( - modifier: Modifier = Modifier, - topTitle: String, - topHelpUrl: String, - topScreen: @Composable () -> Unit, - bottomTitle: String, - bottomHelpUrl: String, - bottomScreen: @Composable () -> Unit, -) { - Column(modifier = modifier) { - Spacer(modifier = Modifier.height(8.dp)) - ScreenCard( - Modifier - .weight(1f) - .fillMaxWidth() - .padding(horizontal = 8.dp), - topTitle, - topHelpUrl, - topScreen, - ) - Spacer(modifier = Modifier.height(8.dp)) - ScreenCard( - Modifier - .weight(1f) - .fillMaxWidth() - .padding(horizontal = 8.dp), - bottomTitle, - bottomHelpUrl, - bottomScreen, - ) - Spacer(modifier = Modifier.height(8.dp)) - } -} - -@Composable -private fun HorizontalTwoScreens( - modifier: Modifier = Modifier, - leftTitle: String, - leftHelpUrl: String, - leftScreen: @Composable () -> Unit, - rightTitle: String, - rightHelpUrl: String, - rightScreen: @Composable () -> Unit, -) { - Column(modifier = modifier) { - Spacer(modifier = Modifier.height(8.dp)) - Row(Modifier.weight(1f)) { - ScreenCard( - Modifier - .weight(1f) - .fillMaxHeight() - .padding(start = 8.dp), - leftTitle, - leftHelpUrl, - leftScreen, - ) - Spacer(modifier = Modifier.width(8.dp)) - ScreenCard( - Modifier - .weight(1f) - .fillMaxHeight() - .padding(end = 8.dp), - rightTitle, - rightHelpUrl, - rightScreen, - ) - } - Spacer(modifier = Modifier.height(8.dp)) - } -} - -@Composable -fun FourScreens( - modifier: Modifier = Modifier, - topLeftTitle: String, - topLeftHelpUrl: String, - topLeftScreen: @Composable () -> Unit, - topRightTitle: String, - topRightHelpUrl: String, - topRightScreen: @Composable () -> Unit, - bottomLeftTitle: String, - bottomLeftHelpUrl: String, - bottomLeftScreen: @Composable () -> Unit, - bottomRightTitle: String, - bottomRightHelpUrl: String, - bottomRightScreen: @Composable () -> Unit, -) { - Column(modifier = modifier) { - Spacer(modifier = Modifier.height(8.dp)) - Row(Modifier.weight(1f)) { - ScreenCard( - Modifier - .weight(1f) - .fillMaxHeight() - .padding(start = 8.dp), - topLeftTitle, - topLeftHelpUrl, - topLeftScreen, - ) - Spacer(modifier = Modifier.width(8.dp)) - ScreenCard( - Modifier - .weight(1f) - .fillMaxHeight() - .padding(end = 8.dp), - topRightTitle, - topRightHelpUrl, - topRightScreen, - ) - } - Spacer(modifier = Modifier.height(8.dp)) - Row(Modifier.weight(1f)) { - ScreenCard( - Modifier - .weight(1f) - .fillMaxHeight() - .padding(start = 8.dp), - bottomLeftTitle, - bottomLeftHelpUrl, - bottomLeftScreen, - ) - Spacer(modifier = Modifier.width(8.dp)) - ScreenCard( - Modifier - .weight(1f) - .fillMaxHeight() - .padding(end = 8.dp), - bottomRightTitle, - bottomRightHelpUrl, - bottomRightScreen, - ) - } - Spacer(modifier = Modifier.height(8.dp)) - } -} - -@Composable -private fun ScreenCard( - modifier: Modifier = Modifier, - title: String, - helpUrl: String, - screen: @Composable () -> Unit, -) { - val uriHandler = LocalUriHandler.current - val ctx = LocalContext.current - - OutlinedCard(modifier = modifier) { - Column { - Row( - modifier = Modifier.fillMaxWidth(), - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.SpaceBetween, - ) { - Text( - modifier = Modifier.padding(horizontal = 16.dp), - text = title, - style = MaterialTheme.typography.titleSmall, - color = MaterialTheme.colorScheme.primary, - ) - - IconButton(onClick = { uriHandler.openUriSafe(ctx, helpUrl) }) { - Icon( - Icons.AutoMirrored.Rounded.HelpOutline, - contentDescription = stringResource(R.string.button_help), - ) - } - } - - screen() - } - } -} - -@Composable -private fun BackDialog( - onDismiss: () -> Unit, - onDiscardClick: () -> Unit, -) { - AlertDialog( - onDismissRequest = onDismiss, - title = { Text(stringResource(R.string.dialog_title_unsaved_changes)) }, - text = { Text(stringResource(R.string.dialog_message_unsaved_changes)) }, - confirmButton = { - TextButton(onClick = onDiscardClick) { Text(stringResource(R.string.pos_discard_changes)) } - }, - dismissButton = { - TextButton(onClick = onDismiss) { Text(stringResource(R.string.neg_keep_editing)) } - }, - ) -} - -private fun determineTabs(maxWidth: Dp, maxHeight: Dp): List { - return when { - maxWidth >= 800.dp && maxHeight >= 800.dp -> listOf(ConfigKeyMapTab.ALL) - - (maxWidth >= 1000.dp && maxHeight >= 450.dp) || - (maxWidth >= 450.dp && maxHeight >= 1000.dp) -> listOf( - ConfigKeyMapTab.TRIGGER_AND_ACTIONS, - ConfigKeyMapTab.CONSTRAINTS_AND_OPTIONS, - ) - - else -> listOf( - ConfigKeyMapTab.TRIGGER, - ConfigKeyMapTab.ACTIONS, - ConfigKeyMapTab.CONSTRAINTS, - ConfigKeyMapTab.OPTIONS, - ) - } -} - -@Composable -private fun getTabTitle(tab: ConfigKeyMapTab): String { - return when (tab) { - ConfigKeyMapTab.TRIGGER -> stringResource(R.string.tab_trigger) - ConfigKeyMapTab.ACTIONS -> stringResource(R.string.tab_actions) - ConfigKeyMapTab.CONSTRAINTS -> stringResource(R.string.tab_constraints) - ConfigKeyMapTab.OPTIONS -> stringResource(R.string.tab_options) - ConfigKeyMapTab.TRIGGER_AND_ACTIONS -> stringResource(R.string.tab_trigger_and_actions) - ConfigKeyMapTab.CONSTRAINTS_AND_OPTIONS -> stringResource(R.string.tab_constraints_and_more) - ConfigKeyMapTab.ALL -> "" - } -} - -private enum class ConfigKeyMapTab { - TRIGGER, - ACTIONS, - CONSTRAINTS, - OPTIONS, - TRIGGER_AND_ACTIONS, - CONSTRAINTS_AND_OPTIONS, - ALL, -} - -@Preview(device = Devices.PIXEL, showSystemUi = true) -@Composable -private fun SmallScreenPreview() { - KeyMapperTheme { - ConfigKeyMapScreen( - modifier = Modifier.fillMaxSize(), - isKeyMapEnabled = false, - triggerScreen = {}, - actionScreen = {}, - constraintsScreen = {}, - optionsScreen = {}, - ) - } -} - -@Preview(device = Devices.NEXUS_7_2013, showSystemUi = true) -@Composable -private fun MediumScreenPreview() { - KeyMapperTheme { - ConfigKeyMapScreen( - modifier = Modifier.fillMaxSize(), - isKeyMapEnabled = true, - triggerScreen = {}, - actionScreen = {}, - constraintsScreen = {}, - optionsScreen = {}, - ) - } -} - -@Preview(device = Devices.FOLDABLE, showSystemUi = true) -@Composable -private fun MediumScreenLandscapePreview() { - KeyMapperTheme { - ConfigKeyMapScreen( - modifier = Modifier.fillMaxSize(), - isKeyMapEnabled = true, - triggerScreen = {}, - actionScreen = {}, - constraintsScreen = {}, - optionsScreen = {}, - ) - } -} - -@Preview(device = Devices.NEXUS_10, showSystemUi = true) -@Composable -private fun LargeScreenPreview() { - KeyMapperTheme { - ConfigKeyMapScreen( - modifier = Modifier.fillMaxSize(), - isKeyMapEnabled = true, - triggerScreen = {}, - actionScreen = {}, - constraintsScreen = {}, - optionsScreen = {}, - ) - } -} diff --git a/app/src/main/java/io/github/sds100/keymapper/keymaps/ConfigKeyMapViewModel.kt b/app/src/main/java/io/github/sds100/keymapper/keymaps/ConfigKeyMapViewModel.kt index f86292155e..046f5cee1c 100644 --- a/app/src/main/java/io/github/sds100/keymapper/keymaps/ConfigKeyMapViewModel.kt +++ b/app/src/main/java/io/github/sds100/keymapper/keymaps/ConfigKeyMapViewModel.kt @@ -1,181 +1,81 @@ package io.github.sds100.keymapper.keymaps -import android.os.Bundle -import androidx.lifecycle.ViewModel -import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.viewModelScope -import io.github.sds100.keymapper.actions.ConfigActionsViewModel -import io.github.sds100.keymapper.actions.CreateActionUseCase -import io.github.sds100.keymapper.actions.TestActionUseCase -import io.github.sds100.keymapper.constraints.ConfigConstraintsViewModel -import io.github.sds100.keymapper.onboarding.OnboardingTapTarget -import io.github.sds100.keymapper.onboarding.OnboardingUseCase -import io.github.sds100.keymapper.purchasing.PurchasingManager +import dagger.hilt.android.lifecycle.HiltViewModel +import io.github.sds100.keymapper.base.actions.ConfigActionsViewModel +import io.github.sds100.keymapper.base.actions.CreateActionUseCase +import io.github.sds100.keymapper.base.actions.TestActionUseCase +import io.github.sds100.keymapper.base.constraints.ConfigConstraintsViewModel +import io.github.sds100.keymapper.base.keymaps.BaseConfigKeyMapViewModel +import io.github.sds100.keymapper.base.keymaps.ConfigKeyMapUseCase +import io.github.sds100.keymapper.base.keymaps.CreateKeyMapShortcutUseCase +import io.github.sds100.keymapper.base.keymaps.DisplayKeyMapUseCase +import io.github.sds100.keymapper.base.keymaps.FingerprintGesturesSupportedUseCase +import io.github.sds100.keymapper.base.onboarding.OnboardingUseCase +import io.github.sds100.keymapper.base.purchasing.PurchasingManager +import io.github.sds100.keymapper.base.trigger.RecordTriggerUseCase +import io.github.sds100.keymapper.base.trigger.SetupGuiKeyboardUseCase +import io.github.sds100.keymapper.base.utils.navigation.NavigationProvider +import io.github.sds100.keymapper.base.utils.ui.DialogProvider +import io.github.sds100.keymapper.base.utils.ui.ResourceProvider import io.github.sds100.keymapper.trigger.ConfigTriggerViewModel -import io.github.sds100.keymapper.trigger.RecordTriggerUseCase -import io.github.sds100.keymapper.trigger.SetupGuiKeyboardUseCase -import io.github.sds100.keymapper.ui.utils.getJsonSerializable -import io.github.sds100.keymapper.ui.utils.putJsonSerializable -import io.github.sds100.keymapper.util.dataOrNull -import io.github.sds100.keymapper.util.firstBlocking -import io.github.sds100.keymapper.util.ifIsData -import io.github.sds100.keymapper.util.ui.ResourceProvider -import kotlinx.coroutines.flow.SharingStarted -import kotlinx.coroutines.flow.StateFlow -import kotlinx.coroutines.flow.combine -import kotlinx.coroutines.flow.map -import kotlinx.coroutines.flow.stateIn -import kotlinx.coroutines.launch +import javax.inject.Inject -/** - * Created by sds100 on 22/11/20. - */ - -class ConfigKeyMapViewModel( - private val config: ConfigKeyMapUseCase, - private val testAction: TestActionUseCase, - private val onboarding: OnboardingUseCase, - private val recordTrigger: RecordTriggerUseCase, - private val createKeyMapShortcut: CreateKeyMapShortcutUseCase, - private val displayMapping: DisplayKeyMapUseCase, +@HiltViewModel +class ConfigKeyMapViewModel @Inject constructor( + display: DisplayKeyMapUseCase, + config: ConfigKeyMapUseCase, + onboarding: OnboardingUseCase, createActionUseCase: CreateActionUseCase, - resourceProvider: ResourceProvider, + testActionUseCase: TestActionUseCase, + recordTriggerUseCase: RecordTriggerUseCase, + createKeyMapShortcutUseCase: CreateKeyMapShortcutUseCase, purchasingManager: PurchasingManager, setupGuiKeyboardUseCase: SetupGuiKeyboardUseCase, - fingerprintGesturesSupported: FingerprintGesturesSupportedUseCase, -) : ViewModel(), - ResourceProvider by resourceProvider { - - companion object { - private const val STATE_KEY = "config_keymap" - } - - val configActionsViewModel = ConfigActionsViewModel( - viewModelScope, - displayMapping, - createActionUseCase, - testAction, - config, - onboarding, - resourceProvider, - ) - - val configTriggerViewModel = ConfigTriggerViewModel( - viewModelScope, - onboarding, - config, - recordTrigger, - createKeyMapShortcut, - displayMapping, - resourceProvider, - purchasingManager, - setupGuiKeyboardUseCase, - fingerprintGesturesSupported, + fingerprintGesturesSupportedUseCase: FingerprintGesturesSupportedUseCase, + resourceProvider: ResourceProvider, + navigationProvider: NavigationProvider, + dialogProvider: DialogProvider, +) : BaseConfigKeyMapViewModel( + config = config, + onboarding = onboarding, + navigationProvider = navigationProvider, + dialogProvider = dialogProvider, +) { + override val configActionsViewModel: ConfigActionsViewModel = ConfigActionsViewModel( + coroutineScope = viewModelScope, + displayAction = display, + createAction = createActionUseCase, + testAction = testActionUseCase, + config = config, + onboarding = onboarding, + resourceProvider = resourceProvider, + navigationProvider = navigationProvider, + dialogProvider = dialogProvider, ) - val configConstraintsViewModel = ConfigConstraintsViewModel( - viewModelScope, - config, - displayMapping, - resourceProvider, + override val configTriggerViewModel: ConfigTriggerViewModel = ConfigTriggerViewModel( + coroutineScope = viewModelScope, + onboarding = onboarding, + config = config, + recordTrigger = recordTriggerUseCase, + createKeyMapShortcut = createKeyMapShortcutUseCase, + displayKeyMap = display, + purchasingManager = purchasingManager, + setupGuiKeyboard = setupGuiKeyboardUseCase, + fingerprintGesturesSupported = fingerprintGesturesSupportedUseCase, + resourceProvider = resourceProvider, + navigationProvider = navigationProvider, + dialogProvider = dialogProvider, ) - val isEnabled: StateFlow = config.keyMap - .map { state -> state.dataOrNull()?.isEnabled ?: true } - .stateIn(viewModelScope, SharingStarted.Eagerly, true) - - val isKeyMapEdited: Boolean - get() = config.isEdited - - val showActionsTapTarget: StateFlow = - combine( - onboarding.showTapTarget(OnboardingTapTarget.CHOOSE_ACTION), - config.keyMap, - ) { showTapTarget, keyMapState -> - // Show the choose action tap target if they have recorded a key. - showTapTarget && keyMapState.dataOrNull()?.trigger?.keys?.isNotEmpty() ?: false - }.stateIn(viewModelScope, SharingStarted.Lazily, false) - - val showConstraintsTapTarget: StateFlow = - combine( - onboarding.showTapTarget(OnboardingTapTarget.CHOOSE_CONSTRAINT), - config.keyMap, - ) { showTapTarget, keyMapState -> - // Show the choose constraint tap target if they have added an action. - showTapTarget && keyMapState.dataOrNull()?.actionList?.isNotEmpty() ?: false - }.stateIn(viewModelScope, SharingStarted.Lazily, false) - - fun save() = config.save() - - fun saveState(outState: Bundle) { - config.keyMap.firstBlocking().ifIsData { - outState.putJsonSerializable(STATE_KEY, it) - } - } - - fun restoreState(state: Bundle) { - val keyMap = state.getJsonSerializable(STATE_KEY) ?: KeyMap() - config.restoreState(keyMap) - } - - fun loadNewKeymap(floatingButtonUid: String? = null, groupUid: String?) { - config.loadNewKeyMap(groupUid) - if (floatingButtonUid != null) { - viewModelScope.launch { - config.addFloatingButtonTriggerKey(floatingButtonUid) - } - } - } - - fun loadKeyMap(uid: String) { - viewModelScope.launch { - config.loadKeyMap(uid) - } - } - - fun onEnabledChanged(enabled: Boolean) { - config.setEnabled(enabled) - } - - fun onActionTapTargetCompleted() { - onboarding.completedTapTarget(OnboardingTapTarget.CHOOSE_ACTION) - } - - fun onConstraintTapTargetCompleted() { - onboarding.completedTapTarget(OnboardingTapTarget.CHOOSE_CONSTRAINT) - } - - fun onSkipTutorialClick() { - onboarding.skipTapTargetOnboarding() - } - - class Factory( - private val config: ConfigKeyMapUseCase, - private val testAction: TestActionUseCase, - private val onboard: OnboardingUseCase, - private val recordTrigger: RecordTriggerUseCase, - private val createKeyMapShortcut: CreateKeyMapShortcutUseCase, - private val displayMapping: DisplayKeyMapUseCase, - private val createActionUseCase: CreateActionUseCase, - private val resourceProvider: ResourceProvider, - private val purchasingManager: PurchasingManager, - private val setupGuiKeyboardUseCase: SetupGuiKeyboardUseCase, - private val fingerprintGesturesSupported: FingerprintGesturesSupportedUseCase, - ) : ViewModelProvider.Factory { - - @Suppress("UNCHECKED_CAST") - override fun create(modelClass: Class) = ConfigKeyMapViewModel( - config, - testAction, - onboard, - recordTrigger, - createKeyMapShortcut, - displayMapping, - createActionUseCase, - resourceProvider, - purchasingManager, - setupGuiKeyboardUseCase, - fingerprintGesturesSupported, - ) as T - } + override val configConstraintsViewModel: ConfigConstraintsViewModel = + ConfigConstraintsViewModel( + coroutineScope = viewModelScope, + config = config, + displayConstraint = display, + resourceProvider = resourceProvider, + navigationProvider = navigationProvider, + dialogProvider = dialogProvider, + ) } diff --git a/app/src/main/java/io/github/sds100/keymapper/keymaps/CreateKeyMapShortcutActivity.kt b/app/src/main/java/io/github/sds100/keymapper/keymaps/CreateKeyMapShortcutActivity.kt deleted file mode 100644 index 48d0e35783..0000000000 --- a/app/src/main/java/io/github/sds100/keymapper/keymaps/CreateKeyMapShortcutActivity.kt +++ /dev/null @@ -1,74 +0,0 @@ -package io.github.sds100.keymapper.keymaps - -import android.os.Bundle -import androidx.activity.SystemBarStyle -import androidx.activity.compose.setContent -import androidx.activity.enableEdgeToEdge -import androidx.activity.viewModels -import androidx.appcompat.app.AppCompatActivity -import androidx.compose.ui.graphics.toArgb -import androidx.lifecycle.Lifecycle -import androidx.navigation.findNavController -import io.github.sds100.keymapper.R -import io.github.sds100.keymapper.ServiceLocator -import io.github.sds100.keymapper.compose.ComposeColors -import io.github.sds100.keymapper.compose.KeyMapperTheme -import io.github.sds100.keymapper.system.permissions.RequestPermissionDelegate -import io.github.sds100.keymapper.util.Inject -import io.github.sds100.keymapper.util.launchRepeatOnLifecycle -import kotlinx.coroutines.flow.collectLatest - -/** - * Created by sds100 on 08/09/20. - */ - -class CreateKeyMapShortcutActivity : AppCompatActivity() { - - private val viewModel by viewModels { - Inject.createActionShortcutViewModel(this) - } - - private lateinit var requestPermissionDelegate: RequestPermissionDelegate - - override fun onCreate(savedInstanceState: Bundle?) { - enableEdgeToEdge( - statusBarStyle = SystemBarStyle.auto( - ComposeColors.surfaceContainerLight.toArgb(), - ComposeColors.surfaceContainerDark.toArgb(), - ), - navigationBarStyle = SystemBarStyle.auto( - ComposeColors.surfaceContainerLight.toArgb(), - ComposeColors.surfaceContainerDark.toArgb(), - ), - ) - super.onCreate(savedInstanceState) - - setContent { - KeyMapperTheme { - CreateKeyMapShortcutScreen( - viewModel = viewModel, - finishActivity = { finish() }, - ) - } - } - - requestPermissionDelegate = RequestPermissionDelegate(this, showDialogs = true) - - launchRepeatOnLifecycle(Lifecycle.State.STARTED) { - ServiceLocator.permissionAdapter(this@CreateKeyMapShortcutActivity).request - .collectLatest { permission -> - requestPermissionDelegate.requestPermission( - permission, - findNavController(R.id.container), - ) - } - } - - launchRepeatOnLifecycle(Lifecycle.State.STARTED) { - viewModel.returnIntentResult.collectLatest { intent -> - setResult(RESULT_OK, intent) - finish() - } - } - } -} diff --git a/app/src/main/java/io/github/sds100/keymapper/keymaps/CreateKeyMapShortcutUseCase.kt b/app/src/main/java/io/github/sds100/keymapper/keymaps/CreateKeyMapShortcutUseCase.kt deleted file mode 100644 index 6d6fb7e9ed..0000000000 --- a/app/src/main/java/io/github/sds100/keymapper/keymaps/CreateKeyMapShortcutUseCase.kt +++ /dev/null @@ -1,86 +0,0 @@ -package io.github.sds100.keymapper.keymaps - -import android.content.Intent -import android.graphics.drawable.Drawable -import androidx.core.os.bundleOf -import io.github.sds100.keymapper.R -import io.github.sds100.keymapper.api.Api -import io.github.sds100.keymapper.system.apps.AppShortcutAdapter -import io.github.sds100.keymapper.util.Result -import io.github.sds100.keymapper.util.ui.ResourceProvider - -/** - * Created by sds100 on 23/03/2021. - */ - -class CreateKeyMapShortcutUseCaseImpl( - private val adapter: AppShortcutAdapter, - resourceProvider: ResourceProvider, -) : CreateKeyMapShortcutUseCase, - ResourceProvider by resourceProvider { - - override val isSupported: Boolean - get() = adapter.areLauncherShortcutsSupported - - override fun pinShortcut( - keyMapUid: String, - shortcutLabel: String, - icon: Drawable?, - ): Result<*> { - val shortcut = if (icon == null) { - adapter.createLauncherShortcut( - iconResId = R.mipmap.ic_launcher_round, - label = shortcutLabel, - intentAction = Api.ACTION_TRIGGER_KEYMAP_BY_UID, - bundleOf(Api.EXTRA_KEYMAP_UID to keyMapUid), - ) - } else { - adapter.createLauncherShortcut( - icon = icon, - label = shortcutLabel, - intentAction = Api.ACTION_TRIGGER_KEYMAP_BY_UID, - bundleOf(Api.EXTRA_KEYMAP_UID to keyMapUid), - ) - } - return adapter.pinShortcut(shortcut) - } - - override fun createIntent( - keyMapUid: String, - shortcutLabel: String, - icon: Drawable?, - ): Intent { - val shortcut = if (icon == null) { - adapter.createLauncherShortcut( - iconResId = R.mipmap.ic_launcher_round, - label = shortcutLabel, - intentAction = Api.ACTION_TRIGGER_KEYMAP_BY_UID, - bundleOf(Api.EXTRA_KEYMAP_UID to keyMapUid), - ) - } else { - adapter.createLauncherShortcut( - icon = icon, - label = shortcutLabel, - intentAction = Api.ACTION_TRIGGER_KEYMAP_BY_UID, - bundleOf(Api.EXTRA_KEYMAP_UID to keyMapUid), - ) - } - return adapter.createShortcutResultIntent(shortcut) - } -} - -interface CreateKeyMapShortcutUseCase { - val isSupported: Boolean - - fun pinShortcut( - keyMapUid: String, - shortcutLabel: String, - icon: Drawable?, - ): Result<*> - - fun createIntent( - keyMapUid: String, - shortcutLabel: String, - icon: Drawable?, - ): Intent -} diff --git a/app/src/main/java/io/github/sds100/keymapper/keymaps/KeyMapGroup.kt b/app/src/main/java/io/github/sds100/keymapper/keymaps/KeyMapGroup.kt deleted file mode 100644 index 32a4a17028..0000000000 --- a/app/src/main/java/io/github/sds100/keymapper/keymaps/KeyMapGroup.kt +++ /dev/null @@ -1,11 +0,0 @@ -package io.github.sds100.keymapper.keymaps - -import io.github.sds100.keymapper.groups.Group -import io.github.sds100.keymapper.util.State - -data class KeyMapGroup( - val group: Group?, - val subGroups: List, - val parents: List, - val keyMaps: State>, -) diff --git a/app/src/main/java/io/github/sds100/keymapper/keymaps/ShortcutModel.kt b/app/src/main/java/io/github/sds100/keymapper/keymaps/ShortcutModel.kt deleted file mode 100644 index b55b82446d..0000000000 --- a/app/src/main/java/io/github/sds100/keymapper/keymaps/ShortcutModel.kt +++ /dev/null @@ -1,9 +0,0 @@ -package io.github.sds100.keymapper.keymaps - -import io.github.sds100.keymapper.util.ui.compose.ComposeIconInfo - -data class ShortcutModel( - val icon: ComposeIconInfo, - val text: String, - val data: T, -) diff --git a/app/src/main/java/io/github/sds100/keymapper/keymaps/detection/DetectKeyMapModel.kt b/app/src/main/java/io/github/sds100/keymapper/keymaps/detection/DetectKeyMapModel.kt deleted file mode 100644 index 7023705558..0000000000 --- a/app/src/main/java/io/github/sds100/keymapper/keymaps/detection/DetectKeyMapModel.kt +++ /dev/null @@ -1,9 +0,0 @@ -package io.github.sds100.keymapper.keymaps.detection - -import io.github.sds100.keymapper.constraints.ConstraintState -import io.github.sds100.keymapper.keymaps.KeyMap - -data class DetectKeyMapModel( - val keyMap: KeyMap, - val groupConstraintStates: List = emptyList(), -) diff --git a/app/src/main/java/io/github/sds100/keymapper/logging/LogSeverity.kt b/app/src/main/java/io/github/sds100/keymapper/logging/LogSeverity.kt deleted file mode 100644 index 225fcf2e00..0000000000 --- a/app/src/main/java/io/github/sds100/keymapper/logging/LogSeverity.kt +++ /dev/null @@ -1,10 +0,0 @@ -package io.github.sds100.keymapper.logging - -/** - * Created by sds100 on 13/05/2021. - */ -enum class LogSeverity { - ERROR, - INFO, - DEBUG, -} diff --git a/app/src/main/java/io/github/sds100/keymapper/purchasing/PurchasingManager.kt b/app/src/main/java/io/github/sds100/keymapper/purchasing/PurchasingManager.kt deleted file mode 100644 index 7ad6b4c003..0000000000 --- a/app/src/main/java/io/github/sds100/keymapper/purchasing/PurchasingManager.kt +++ /dev/null @@ -1,15 +0,0 @@ -package io.github.sds100.keymapper.purchasing - -import io.github.sds100.keymapper.util.Result -import io.github.sds100.keymapper.util.State -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.MutableSharedFlow - -interface PurchasingManager { - val onCompleteProductPurchase: MutableSharedFlow - val purchases: Flow>>> - suspend fun launchPurchasingFlow(product: ProductId): Result - suspend fun getProductPrice(product: ProductId): Result - suspend fun isPurchased(product: ProductId): Result - fun refresh() -} diff --git a/app/src/main/java/io/github/sds100/keymapper/purchasing/PurchasingManagerImpl.kt b/app/src/main/java/io/github/sds100/keymapper/purchasing/PurchasingManagerImpl.kt new file mode 100644 index 0000000000..0011982ba9 --- /dev/null +++ b/app/src/main/java/io/github/sds100/keymapper/purchasing/PurchasingManagerImpl.kt @@ -0,0 +1,30 @@ +package io.github.sds100.keymapper.purchasing + +import io.github.sds100.keymapper.base.purchasing.ProductId +import io.github.sds100.keymapper.base.purchasing.PurchasingError +import io.github.sds100.keymapper.base.purchasing.PurchasingManager +import io.github.sds100.keymapper.common.utils.KMResult +import io.github.sds100.keymapper.common.utils.State +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.MutableStateFlow + +class PurchasingManagerImpl : PurchasingManager { + override val onCompleteProductPurchase: MutableSharedFlow = MutableSharedFlow() + override val purchases: Flow>>> = + MutableStateFlow(State.Data(PurchasingError.PurchasingNotImplemented)) + + override suspend fun launchPurchasingFlow(product: ProductId): KMResult { + return PurchasingError.PurchasingNotImplemented + } + + override suspend fun getProductPrice(product: ProductId): KMResult { + return PurchasingError.PurchasingNotImplemented + } + + override suspend fun isPurchased(product: ProductId): KMResult { + return PurchasingError.PurchasingNotImplemented + } + + override fun refresh() {} +} diff --git a/app/src/main/java/io/github/sds100/keymapper/system/BuildUtils.kt b/app/src/main/java/io/github/sds100/keymapper/system/BuildUtils.kt deleted file mode 100644 index 6ab2e09f90..0000000000 --- a/app/src/main/java/io/github/sds100/keymapper/system/BuildUtils.kt +++ /dev/null @@ -1,54 +0,0 @@ -package io.github.sds100.keymapper.system - -import android.os.Build -import android.os.Build.VERSION_CODES.JELLY_BEAN -import android.os.Build.VERSION_CODES.JELLY_BEAN_MR1 -import android.os.Build.VERSION_CODES.JELLY_BEAN_MR2 -import android.os.Build.VERSION_CODES.KITKAT -import android.os.Build.VERSION_CODES.LOLLIPOP -import android.os.Build.VERSION_CODES.LOLLIPOP_MR1 -import android.os.Build.VERSION_CODES.M -import android.os.Build.VERSION_CODES.N -import android.os.Build.VERSION_CODES.N_MR1 -import android.os.Build.VERSION_CODES.O -import android.os.Build.VERSION_CODES.O_MR1 -import android.os.Build.VERSION_CODES.P -import android.os.Build.VERSION_CODES.Q -import android.os.Build.VERSION_CODES.R -import android.os.Build.VERSION_CODES.S -import android.os.Build.VERSION_CODES.S_V2 -import android.os.Build.VERSION_CODES.TIRAMISU -import android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE - -/** - * Created by sds100 on 12/01/2019. - */ - -object BuildUtils { - /** - * @return the name of the android version for each [Build.VERSION_CODES] after the minimum api for this app. - * - * E.g 28 = "Pie 9.0" - */ - fun getSdkVersionName(version: Int): String = when (version) { - JELLY_BEAN -> "Jelly Bean 4.1" - JELLY_BEAN_MR1 -> "Jelly Bean 4.2" - JELLY_BEAN_MR2 -> "Jelly Bean 4.3" - KITKAT -> "KitKat 4.4" - LOLLIPOP -> "Lollipop 5.0" - LOLLIPOP_MR1 -> "Lollipop 5.1" - M -> "Marshmallow 6.0" - N -> "Nougat 7.0" - N_MR1 -> "Nougat 7.1" - O -> "Oreo 8.0" - O_MR1 -> "Oreo 8.1" - P -> "Pie 9.0" - Q -> "10" - R -> "11" - S -> "12" - S_V2 -> "12L" - TIRAMISU -> "13" - UPSIDE_DOWN_CAKE -> "14" - else -> "API $version" - } -} diff --git a/app/src/main/java/io/github/sds100/keymapper/system/accessibility/AccessibilityNodeAction.kt b/app/src/main/java/io/github/sds100/keymapper/system/accessibility/AccessibilityNodeAction.kt deleted file mode 100644 index 12af5f515c..0000000000 --- a/app/src/main/java/io/github/sds100/keymapper/system/accessibility/AccessibilityNodeAction.kt +++ /dev/null @@ -1,6 +0,0 @@ -package io.github.sds100.keymapper.system.accessibility - -/** - * Created by sds100 on 24/04/2021. - */ -data class AccessibilityNodeAction(val action: Int, val extras: Map = emptyMap()) diff --git a/app/src/main/java/io/github/sds100/keymapper/system/accessibility/AccessibilityServiceController.kt b/app/src/main/java/io/github/sds100/keymapper/system/accessibility/AccessibilityServiceController.kt new file mode 100644 index 0000000000..6bc72f0bbe --- /dev/null +++ b/app/src/main/java/io/github/sds100/keymapper/system/accessibility/AccessibilityServiceController.kt @@ -0,0 +1,48 @@ +package io.github.sds100.keymapper.system.accessibility + +import dagger.assisted.Assisted +import dagger.assisted.AssistedFactory +import dagger.assisted.AssistedInject +import io.github.sds100.keymapper.base.actions.PerformActionsUseCaseImpl +import io.github.sds100.keymapper.base.constraints.DetectConstraintsUseCaseImpl +import io.github.sds100.keymapper.base.keymaps.FingerprintGesturesSupportedUseCase +import io.github.sds100.keymapper.base.keymaps.PauseKeyMapsUseCase +import io.github.sds100.keymapper.base.keymaps.detection.DetectKeyMapsUseCaseImpl +import io.github.sds100.keymapper.base.reroutekeyevents.RerouteKeyEventsController +import io.github.sds100.keymapper.base.system.accessibility.AccessibilityNodeRecorder +import io.github.sds100.keymapper.base.system.accessibility.BaseAccessibilityServiceController +import io.github.sds100.keymapper.data.repositories.PreferenceRepository +import io.github.sds100.keymapper.system.devices.DevicesAdapter +import io.github.sds100.keymapper.system.root.SuAdapter + +class AccessibilityServiceController @AssistedInject constructor( + @Assisted + private val service: MyAccessibilityService, + rerouteKeyEventsControllerFactory: RerouteKeyEventsController.Factory, + accessibilityNodeRecorderFactory: AccessibilityNodeRecorder.Factory, + performActionsUseCaseFactory: PerformActionsUseCaseImpl.Factory, + detectKeyMapsUseCaseFactory: DetectKeyMapsUseCaseImpl.Factory, + detectConstraintsUseCaseFactory: DetectConstraintsUseCaseImpl.Factory, + fingerprintGesturesSupported: FingerprintGesturesSupportedUseCase, + pauseKeyMapsUseCase: PauseKeyMapsUseCase, + devicesAdapter: DevicesAdapter, + suAdapter: SuAdapter, + settingsRepository: PreferenceRepository, +) : BaseAccessibilityServiceController( + service = service, + rerouteKeyEventsControllerFactory = rerouteKeyEventsControllerFactory, + accessibilityNodeRecorderFactory = accessibilityNodeRecorderFactory, + performActionsUseCaseFactory = performActionsUseCaseFactory, + detectKeyMapsUseCaseFactory = detectKeyMapsUseCaseFactory, + detectConstraintsUseCaseFactory = detectConstraintsUseCaseFactory, + fingerprintGesturesSupported = fingerprintGesturesSupported, + pauseKeyMapsUseCase = pauseKeyMapsUseCase, + devicesAdapter = devicesAdapter, + suAdapter = suAdapter, + settingsRepository = settingsRepository, +) { + @AssistedFactory + interface Factory { + fun create(service: MyAccessibilityService): AccessibilityServiceController + } +} diff --git a/app/src/main/java/io/github/sds100/keymapper/system/accessibility/MyAccessibilityService.kt b/app/src/main/java/io/github/sds100/keymapper/system/accessibility/MyAccessibilityService.kt index 0610083100..6d470eb0a7 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/accessibility/MyAccessibilityService.kt +++ b/app/src/main/java/io/github/sds100/keymapper/system/accessibility/MyAccessibilityService.kt @@ -1,247 +1,33 @@ package io.github.sds100.keymapper.system.accessibility -import android.accessibilityservice.AccessibilityService -import android.accessibilityservice.FingerprintGestureController -import android.accessibilityservice.GestureDescription -import android.accessibilityservice.GestureDescription.StrokeDescription -import android.annotation.SuppressLint -import android.app.ActivityManager import android.content.Intent -import android.content.res.Configuration -import android.graphics.Path -import android.graphics.Point -import android.os.Build -import android.view.KeyEvent -import android.view.MotionEvent -import android.view.accessibility.AccessibilityEvent -import androidx.core.content.getSystemService -import androidx.core.os.bundleOf -import androidx.lifecycle.Lifecycle -import androidx.lifecycle.LifecycleOwner -import androidx.lifecycle.LifecycleRegistry -import androidx.savedstate.SavedStateRegistry -import androidx.savedstate.SavedStateRegistryController -import androidx.savedstate.SavedStateRegistryOwner -import io.github.sds100.keymapper.R -import io.github.sds100.keymapper.actions.pinchscreen.PinchScreenType -import io.github.sds100.keymapper.api.IKeyEventRelayServiceCallback -import io.github.sds100.keymapper.api.KeyEventRelayService -import io.github.sds100.keymapper.api.KeyEventRelayServiceWrapperImpl -import io.github.sds100.keymapper.keymaps.FingerprintGestureType -import io.github.sds100.keymapper.system.devices.InputDeviceUtils -import io.github.sds100.keymapper.system.inputevents.MyKeyEvent -import io.github.sds100.keymapper.system.inputevents.MyMotionEvent -import io.github.sds100.keymapper.trigger.KeyEventDetectionSource -import io.github.sds100.keymapper.util.Error -import io.github.sds100.keymapper.util.Inject -import io.github.sds100.keymapper.util.InputEventType -import io.github.sds100.keymapper.util.MathUtils -import io.github.sds100.keymapper.util.Result -import io.github.sds100.keymapper.util.Success -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.update +import dagger.hilt.android.AndroidEntryPoint +import io.github.sds100.keymapper.base.system.accessibility.BaseAccessibilityService +import io.github.sds100.keymapper.base.system.accessibility.BaseAccessibilityServiceController import timber.log.Timber +import javax.inject.Inject -/** - * Created by sds100 on 05/04/2020. - */ +@AndroidEntryPoint +class MyAccessibilityService : BaseAccessibilityService() { -class MyAccessibilityService : - AccessibilityService(), - LifecycleOwner, - IAccessibilityService, - SavedStateRegistryOwner { + @Inject + lateinit var controllerFactory: AccessibilityServiceController.Factory - // virtual distance between fingers on multitouch gestures - private val fingerGestureDistance = 10L + private var controller: AccessibilityServiceController? = null - private var lifecycleRegistry: LifecycleRegistry = LifecycleRegistry(this) - private var savedStateRegistryController: SavedStateRegistryController? = - SavedStateRegistryController.create(this) - override val savedStateRegistry: SavedStateRegistry - get() = savedStateRegistryController!!.savedStateRegistry - - private var fingerprintGestureCallback: FingerprintGestureController.FingerprintGestureCallback? = - null - - override val rootNode: AccessibilityNodeModel? - get() { - return rootInActiveWindow?.toModel() - } - - private val _activeWindowPackage: MutableStateFlow = MutableStateFlow(null) - override val activeWindowPackage: Flow = _activeWindowPackage - - override val isFingerprintGestureDetectionAvailable: Boolean - get() = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - fingerprintGestureController.isGestureDetectionAvailable - } else { - false - } - - private val _isKeyboardHidden by lazy { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - MutableStateFlow(softKeyboardController.showMode == SHOW_MODE_HIDDEN) - } else { - MutableStateFlow(false) - } - } - - override val isKeyboardHidden: Flow - get() = _isKeyboardHidden - - override var serviceFlags: Int? - get() = serviceInfo?.flags - set(value) { - if (serviceInfo != null && value != null) { - serviceInfo = serviceInfo.apply { - flags = value - } - } - } - - override var serviceFeedbackType: Int? - get() = serviceInfo?.feedbackType - set(value) { - if (serviceInfo != null && value != null) { - serviceInfo = serviceInfo.apply { - feedbackType = value - } - } - } - - override var serviceEventTypes: Int? - get() = serviceInfo?.eventTypes - set(value) { - if (serviceInfo != null && value != null) { - serviceInfo = serviceInfo.apply { - eventTypes = value - } - } - } - - override var notificationTimeout: Long? - get() = serviceInfo?.notificationTimeout - set(value) { - if (serviceInfo != null && value != null) { - serviceInfo = serviceInfo.apply { - notificationTimeout = value - } - } - } - - private val relayServiceCallback: IKeyEventRelayServiceCallback = - object : IKeyEventRelayServiceCallback.Stub() { - override fun onKeyEvent(event: KeyEvent?): Boolean { - event ?: return false - - val device = event.device?.let { InputDeviceUtils.createInputDeviceInfo(it) } - - if (controller != null) { - return controller!!.onKeyEventFromIme( - MyKeyEvent( - keyCode = event.keyCode, - action = event.action, - metaState = event.metaState, - scanCode = event.scanCode, - device = device, - repeatCount = event.repeatCount, - source = event.source, - ), - ) - } - - return false - } - - override fun onMotionEvent(event: MotionEvent?): Boolean { - event ?: return false - - if (controller != null) { - return controller!!.onMotionEventFromIme(MyMotionEvent.fromMotionEvent(event)) - } - - return false - } - } - - private val keyEventRelayServiceWrapper: KeyEventRelayServiceWrapperImpl by lazy { - KeyEventRelayServiceWrapperImpl( - ctx = this, - id = KeyEventRelayService.CALLBACK_ID_ACCESSIBILITY_SERVICE, - callback = relayServiceCallback, - ) - } - - var controller: AccessibilityServiceController? = null - - override fun onCreate() { - super.onCreate() - Timber.i("Accessibility service: onCreate") - - savedStateRegistryController?.performAttach() - savedStateRegistryController?.performRestore(null) - - lifecycleRegistry.currentState = Lifecycle.State.CREATED - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - softKeyboardController.addOnShowModeChangedListener { _, showMode -> - when (showMode) { - SHOW_MODE_AUTO -> _isKeyboardHidden.value = false - SHOW_MODE_HIDDEN -> _isKeyboardHidden.value = true - } - } - } - - keyEventRelayServiceWrapper.onCreate() + override fun getController(): BaseAccessibilityServiceController? { + return controller } override fun onServiceConnected() { super.onServiceConnected() - Timber.i("Accessibility service: onServiceConnected") - lifecycleRegistry.currentState = Lifecycle.State.STARTED - - setTheme(R.style.AppTheme) - - _activeWindowPackage.update { rootInActiveWindow?.packageName?.toString() } /* I would put this in onCreate but for some reason on some devices getting the application context would return null */ if (controller == null) { - controller = Inject.accessibilityServiceController(this, keyEventRelayServiceWrapper) - } - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - fingerprintGestureCallback = - object : FingerprintGestureController.FingerprintGestureCallback() { - override fun onGestureDetected(gesture: Int) { - super.onGestureDetected(gesture) - - val id: FingerprintGestureType = when (gesture) { - FingerprintGestureController.FINGERPRINT_GESTURE_SWIPE_DOWN -> - FingerprintGestureType.SWIPE_DOWN - - FingerprintGestureController.FINGERPRINT_GESTURE_SWIPE_UP -> - FingerprintGestureType.SWIPE_UP - - FingerprintGestureController.FINGERPRINT_GESTURE_SWIPE_LEFT -> - FingerprintGestureType.SWIPE_LEFT - - FingerprintGestureController.FINGERPRINT_GESTURE_SWIPE_RIGHT -> - FingerprintGestureType.SWIPE_RIGHT - - else -> return - } - controller?.onFingerprintGesture(id) - } - } - - fingerprintGestureCallback?.let { - fingerprintGestureController.registerFingerprintGestureCallback(it, null) - } + controller = controllerFactory.create(this) } controller?.onServiceConnected() @@ -258,327 +44,6 @@ class MyAccessibilityService : controller?.onDestroy() controller = null - lifecycleRegistry.currentState = Lifecycle.State.DESTROYED - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - fingerprintGestureController - .unregisterFingerprintGestureCallback(fingerprintGestureCallback) - } - - keyEventRelayServiceWrapper.onDestroy() - - Timber.i("Accessibility service: onDestroy") - super.onDestroy() } - - override fun onConfigurationChanged(newConfig: Configuration) { - super.onConfigurationChanged(newConfig) - - controller?.onConfigurationChanged(newConfig) - } - - override fun onTrimMemory(level: Int) { - val memoryInfo = ActivityManager.MemoryInfo() - getSystemService()?.getMemoryInfo(memoryInfo) - - Timber.i("Accessibility service: onLowMemory, total: ${memoryInfo.totalMem}, available: ${memoryInfo.availMem}, is low memory: ${memoryInfo.lowMemory}, threshold: ${memoryInfo.threshold}") - - super.onTrimMemory(level) - } - - override fun onAccessibilityEvent(event: AccessibilityEvent?) { - event ?: return - - if (event.eventType == AccessibilityEvent.TYPE_WINDOWS_CHANGED) { - _activeWindowPackage.update { rootInActiveWindow?.packageName?.toString() } - } - - controller?.onAccessibilityEvent(event) - } - - override fun onKeyEvent(event: KeyEvent?): Boolean { - event ?: return super.onKeyEvent(event) - - val device = if (event.device == null) { - null - } else { - InputDeviceUtils.createInputDeviceInfo(event.device) - } - - if (controller != null) { - return controller!!.onKeyEvent( - MyKeyEvent( - keyCode = event.keyCode, - action = event.action, - metaState = event.metaState, - scanCode = event.scanCode, - device = device, - repeatCount = event.repeatCount, - source = event.source, - ), - KeyEventDetectionSource.ACCESSIBILITY_SERVICE, - ) - } - - return false - } - - override val lifecycle: Lifecycle - get() = lifecycleRegistry - - override fun hideKeyboard() { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - softKeyboardController.showMode = SHOW_MODE_HIDDEN - } - } - - override fun showKeyboard() { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - softKeyboardController.showMode = SHOW_MODE_AUTO - } - } - - override fun switchIme(imeId: String) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { - softKeyboardController.switchToInputMethod(imeId) - } - } - - override fun performActionOnNode( - findNode: (node: AccessibilityNodeModel) -> Boolean, - performAction: (node: AccessibilityNodeModel) -> AccessibilityNodeAction?, - ): Result<*> { - val node = rootInActiveWindow.findNodeRecursively { - findNode(it.toModel()) - } - - if (node == null) { - return Error.FailedToFindAccessibilityNode - } - - val (action, extras) = performAction(node.toModel()) ?: return Success(Unit) - - node.performAction(action, bundleOf(*extras.toList().toTypedArray())) - node.recycle() - - return Success(Unit) - } - - override fun doGlobalAction(action: Int): Result<*> { - val success = performGlobalAction(action) - - if (success) { - return Success(Unit) - } else { - return Error.FailedToPerformAccessibilityGlobalAction(action) - } - } - - override fun tapScreen(x: Int, y: Int, inputEventType: InputEventType): Result<*> { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - val duration = 1L // ms - - val path = Path().apply { - moveTo(x.toFloat(), y.toFloat()) - } - - val strokeDescription = - when { - inputEventType == InputEventType.DOWN && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O -> - StrokeDescription( - path, - 0, - duration, - true, - ) - - inputEventType == InputEventType.UP && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O -> - StrokeDescription( - path, - 59999, - duration, - false, - ) - - else -> StrokeDescription(path, 0, duration) - } - - strokeDescription.let { - val gestureDescription = GestureDescription.Builder().apply { - addStroke(it) - }.build() - - val success = dispatchGesture(gestureDescription, null, null) - - return if (success) { - Success(Unit) - } else { - Error.FailedToDispatchGesture - } - } - } - - return Error.SdkVersionTooLow(Build.VERSION_CODES.N) - } - - override fun swipeScreen( - xStart: Int, - yStart: Int, - xEnd: Int, - yEnd: Int, - fingerCount: Int, - duration: Int, - inputEventType: InputEventType, - ): Result<*> { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - if (fingerCount >= GestureDescription.getMaxStrokeCount()) { - return Error.GestureStrokeCountTooHigh - } - if (duration >= GestureDescription.getMaxGestureDuration()) { - return Error.GestureDurationTooHigh - } - - val pStart = Point(xStart, yStart) - val pEnd = Point(xEnd, yEnd) - - val gestureBuilder = GestureDescription.Builder() - - if (fingerCount == 1) { - val p = Path() - p.moveTo(pStart.x.toFloat(), pStart.y.toFloat()) - p.lineTo(pEnd.x.toFloat(), pEnd.y.toFloat()) - gestureBuilder.addStroke(StrokeDescription(p, 0, duration.toLong())) - } else { - // segments between fingers - val segmentCount = fingerCount - 1 - // the line of the perpendicular line which will be created to place the virtual fingers on it - val perpendicularLineLength = (fingerGestureDistance * fingerCount).toInt() - - // the length of each segment between fingers - val segmentLength = perpendicularLineLength / segmentCount - // perpendicular line of the start swipe point - val perpendicularLineStart = MathUtils.getPerpendicularOfLine( - pStart, - pEnd, - perpendicularLineLength, - ) - // perpendicular line of the end swipe point - val perpendicularLineEnd = MathUtils.getPerpendicularOfLine( - pEnd, - pStart, - perpendicularLineLength, - true, - ) - - // this is the angle between start and end point to rotate all virtual fingers on the perpendicular lines in the same direction - val angle = - MathUtils.angleBetweenPoints(Point(xStart, yStart), Point(xEnd, yEnd)) - 90 - - // create the virtual fingers - for (index in 0..segmentCount) { - // offset of each finger - val fingerOffsetLength = index * segmentLength * 2 - // move the coordinates of the current virtual finger on the perpendicular line for the start coordinates - val startFingerCoordinateWithOffset = - MathUtils.movePointByDistanceAndAngle( - perpendicularLineStart.start, - fingerOffsetLength, - angle, - ) - // move the coordinates of the current virtual finger on the perpendicular line for the end coordinates - val endFingerCoordinateWithOffset = - MathUtils.movePointByDistanceAndAngle( - perpendicularLineEnd.start, - fingerOffsetLength, - angle, - ) - - // create a path for each finger, move the the coordinates on the perpendicular line and draw it to the end coordinates of the perpendicular line of the end swipe point - val p = Path() - p.moveTo( - startFingerCoordinateWithOffset.x.toFloat(), - startFingerCoordinateWithOffset.y.toFloat(), - ) - p.lineTo( - endFingerCoordinateWithOffset.x.toFloat(), - endFingerCoordinateWithOffset.y.toFloat(), - ) - - gestureBuilder.addStroke(StrokeDescription(p, 0, duration.toLong())) - } - } - - val success = dispatchGesture(gestureBuilder.build(), null, null) - - return if (success) { - Success(Unit) - } else { - Error.FailedToDispatchGesture - } - } - - return Error.SdkVersionTooLow(Build.VERSION_CODES.N) - } - - override fun pinchScreen( - x: Int, - y: Int, - distance: Int, - pinchType: PinchScreenType, - fingerCount: Int, - duration: Int, - inputEventType: InputEventType, - ): Result<*> { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - if (fingerCount >= GestureDescription.getMaxStrokeCount()) { - return Error.GestureStrokeCountTooHigh - } - if (duration >= GestureDescription.getMaxGestureDuration()) { - return Error.GestureDurationTooHigh - } - - val gestureBuilder = GestureDescription.Builder() - val distributedPoints: List = - MathUtils.distributePointsOnCircle(Point(x, y), distance.toFloat() / 2, fingerCount) - - for (index in distributedPoints.indices) { - val p = Path() - if (pinchType == PinchScreenType.PINCH_IN) { - p.moveTo(x.toFloat(), y.toFloat()) - p.lineTo( - distributedPoints[index].x.toFloat(), - distributedPoints[index].y.toFloat(), - ) - } else { - p.moveTo( - distributedPoints[index].x.toFloat(), - distributedPoints[index].y.toFloat(), - ) - p.lineTo(x.toFloat(), y.toFloat()) - } - - gestureBuilder.addStroke(StrokeDescription(p, 0, duration.toLong())) - } - - val success = dispatchGesture(gestureBuilder.build(), null, null) - - return if (success) { - Success(Unit) - } else { - Error.FailedToDispatchGesture - } - } - - return Error.SdkVersionTooLow(Build.VERSION_CODES.N) - } - - override fun findFocussedNode(focus: Int): AccessibilityNodeModel? = findFocus(focus)?.toModel() - - override fun setInputMethodEnabled(imeId: String, enabled: Boolean) { - @SuppressLint("CheckResult") - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { - softKeyboardController.setInputMethodEnabled(imeId, enabled) - } - } } diff --git a/app/src/main/java/io/github/sds100/keymapper/system/airplanemode/AirplaneModeAdapter.kt b/app/src/main/java/io/github/sds100/keymapper/system/airplanemode/AirplaneModeAdapter.kt deleted file mode 100644 index f4ce8d93b6..0000000000 --- a/app/src/main/java/io/github/sds100/keymapper/system/airplanemode/AirplaneModeAdapter.kt +++ /dev/null @@ -1,12 +0,0 @@ -package io.github.sds100.keymapper.system.airplanemode - -import io.github.sds100.keymapper.util.Result - -/** - * Created by sds100 on 24/04/2021. - */ -interface AirplaneModeAdapter { - fun isEnabled(): Boolean - fun enable(): Result<*> - fun disable(): Result<*> -} diff --git a/app/src/main/java/io/github/sds100/keymapper/system/apps/DisplayAppsUseCase.kt b/app/src/main/java/io/github/sds100/keymapper/system/apps/DisplayAppsUseCase.kt deleted file mode 100644 index 22abf49a84..0000000000 --- a/app/src/main/java/io/github/sds100/keymapper/system/apps/DisplayAppsUseCase.kt +++ /dev/null @@ -1,35 +0,0 @@ -package io.github.sds100.keymapper.system.apps - -import android.graphics.drawable.Drawable -import io.github.sds100.keymapper.util.Result -import io.github.sds100.keymapper.util.State -import kotlinx.coroutines.flow.Flow - -/** - * Created by sds100 on 04/04/2021. - */ - -class DisplayAppsUseCaseImpl( - private val adapter: PackageManagerAdapter, -) : DisplayAppsUseCase { - override val installedPackages: Flow>> = adapter.installedPackages - - override fun getAppName(packageName: String): Result = adapter.getAppName(packageName) - - override fun getAppIcon(packageName: String): Result = adapter.getAppIcon(packageName) - - override fun getActivityLabel(packageName: String, activityClass: String): Result = - adapter.getActivityLabel(packageName, activityClass) - - override fun getActivityIcon(packageName: String, activityClass: String): Result = - adapter.getActivityIcon(packageName, activityClass) -} - -interface DisplayAppsUseCase { - val installedPackages: Flow>> - - fun getActivityLabel(packageName: String, activityClass: String): Result - fun getActivityIcon(packageName: String, activityClass: String): Result - fun getAppName(packageName: String): Result - fun getAppIcon(packageName: String): Result -} diff --git a/app/src/main/java/io/github/sds100/keymapper/system/camera/CameraLensUtils.kt b/app/src/main/java/io/github/sds100/keymapper/system/camera/CameraLensUtils.kt deleted file mode 100644 index 80f7090f2d..0000000000 --- a/app/src/main/java/io/github/sds100/keymapper/system/camera/CameraLensUtils.kt +++ /dev/null @@ -1,13 +0,0 @@ -package io.github.sds100.keymapper.system.camera - -import io.github.sds100.keymapper.R - -/** - * Created by sds100 on 23/03/2021. - */ -object CameraLensUtils { - fun getLabel(lens: CameraLens) = when (lens) { - CameraLens.FRONT -> R.string.lens_front - CameraLens.BACK -> R.string.lens_back - } -} diff --git a/app/src/main/java/io/github/sds100/keymapper/system/display/OrientationUtils.kt b/app/src/main/java/io/github/sds100/keymapper/system/display/OrientationUtils.kt deleted file mode 100644 index fc3607627e..0000000000 --- a/app/src/main/java/io/github/sds100/keymapper/system/display/OrientationUtils.kt +++ /dev/null @@ -1,15 +0,0 @@ -package io.github.sds100.keymapper.system.display - -import io.github.sds100.keymapper.R - -/** - * Created by sds100 on 23/03/2021. - */ -object OrientationUtils { - fun getLabel(orientation: Orientation) = when (orientation) { - Orientation.ORIENTATION_0 -> R.string.orientation_0 - Orientation.ORIENTATION_90 -> R.string.orientation_90 - Orientation.ORIENTATION_180 -> R.string.orientation_180 - Orientation.ORIENTATION_270 -> R.string.orientation_270 - } -} diff --git a/app/src/main/java/io/github/sds100/keymapper/system/inputmethod/ShowHideInputMethodUseCase.kt b/app/src/main/java/io/github/sds100/keymapper/system/inputmethod/ShowHideInputMethodUseCase.kt deleted file mode 100644 index feb12d0e2a..0000000000 --- a/app/src/main/java/io/github/sds100/keymapper/system/inputmethod/ShowHideInputMethodUseCase.kt +++ /dev/null @@ -1,37 +0,0 @@ -package io.github.sds100.keymapper.system.inputmethod - -import io.github.sds100.keymapper.system.accessibility.ServiceAdapter -import io.github.sds100.keymapper.util.ServiceEvent -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.mapNotNull -import kotlinx.coroutines.runBlocking - -/** - * Created by sds100 on 16/04/2021. - */ - -class ShowHideInputMethodUseCaseImpl( - private val serviceAdapter: ServiceAdapter, -) : ShowHideInputMethodUseCase { - override val onHiddenChange: Flow = serviceAdapter.eventReceiver.mapNotNull { - when (it) { - ServiceEvent.OnHideKeyboardEvent -> true - ServiceEvent.OnShowKeyboardEvent -> false - else -> null - } - } - - override fun show() { - runBlocking { serviceAdapter.send(ServiceEvent.ShowKeyboard) } - } - - override fun hide() { - runBlocking { serviceAdapter.send(ServiceEvent.HideKeyboard) } - } -} - -interface ShowHideInputMethodUseCase { - val onHiddenChange: Flow - fun show() - fun hide() -} diff --git a/app/src/main/java/io/github/sds100/keymapper/system/inputmethod/ToggleCompatibleImeUseCase.kt b/app/src/main/java/io/github/sds100/keymapper/system/inputmethod/ToggleCompatibleImeUseCase.kt deleted file mode 100644 index 86e559f13e..0000000000 --- a/app/src/main/java/io/github/sds100/keymapper/system/inputmethod/ToggleCompatibleImeUseCase.kt +++ /dev/null @@ -1,26 +0,0 @@ -package io.github.sds100.keymapper.system.inputmethod - -import io.github.sds100.keymapper.util.Result -import kotlinx.coroutines.flow.Flow - -/** - * Created by sds100 on 16/04/2021. - */ - -class ToggleCompatibleImeUseCaseImpl( - private val inputMethodAdapter: InputMethodAdapter, -) : ToggleCompatibleImeUseCase { - private val keyMapperImeHelper = KeyMapperImeHelper(inputMethodAdapter) - - override val sufficientPermissions: Flow = - inputMethodAdapter.isUserInputRequiredToChangeIme - - override suspend fun toggle(): Result = - keyMapperImeHelper.toggleCompatibleInputMethod() -} - -interface ToggleCompatibleImeUseCase { - val sufficientPermissions: Flow - - suspend fun toggle(): Result -} diff --git a/app/src/main/java/io/github/sds100/keymapper/system/nfc/NfcAdapter.kt b/app/src/main/java/io/github/sds100/keymapper/system/nfc/NfcAdapter.kt deleted file mode 100644 index 68e0286fff..0000000000 --- a/app/src/main/java/io/github/sds100/keymapper/system/nfc/NfcAdapter.kt +++ /dev/null @@ -1,12 +0,0 @@ -package io.github.sds100.keymapper.system.nfc - -import io.github.sds100.keymapper.util.Result - -/** - * Created by sds100 on 24/04/2021. - */ -interface NfcAdapter { - fun isEnabled(): Boolean - fun enable(): Result<*> - fun disable(): Result<*> -} diff --git a/app/src/main/java/io/github/sds100/keymapper/system/popup/AndroidToastAdapter.kt b/app/src/main/java/io/github/sds100/keymapper/system/popup/AndroidToastAdapter.kt deleted file mode 100644 index 633fdb5424..0000000000 --- a/app/src/main/java/io/github/sds100/keymapper/system/popup/AndroidToastAdapter.kt +++ /dev/null @@ -1,15 +0,0 @@ -package io.github.sds100.keymapper.system.popup - -import android.content.Context -import splitties.toast.toast - -/** - * Created by sds100 on 17/04/2021. - */ -class AndroidToastAdapter(context: Context) : PopupMessageAdapter { - private val ctx: Context = context.applicationContext - - override fun showPopupMessage(message: String) { - ctx.toast(message) - } -} diff --git a/app/src/main/java/io/github/sds100/keymapper/system/popup/PopupMessageAdapter.kt b/app/src/main/java/io/github/sds100/keymapper/system/popup/PopupMessageAdapter.kt deleted file mode 100644 index 6f0fc56638..0000000000 --- a/app/src/main/java/io/github/sds100/keymapper/system/popup/PopupMessageAdapter.kt +++ /dev/null @@ -1,8 +0,0 @@ -package io.github.sds100.keymapper.system.popup - -/** - * Created by sds100 on 17/04/2021. - */ -interface PopupMessageAdapter { - fun showPopupMessage(message: String) -} diff --git a/app/src/main/java/io/github/sds100/keymapper/system/shell/ShellAdapter.kt b/app/src/main/java/io/github/sds100/keymapper/system/shell/ShellAdapter.kt deleted file mode 100644 index 553bc744bd..0000000000 --- a/app/src/main/java/io/github/sds100/keymapper/system/shell/ShellAdapter.kt +++ /dev/null @@ -1,11 +0,0 @@ -package io.github.sds100.keymapper.system.shell - -import io.github.sds100.keymapper.util.Result - -/** - * Created by sds100 on 21/04/2021. - */ - -interface ShellAdapter { - fun execute(command: String): Result<*> -} diff --git a/app/src/main/java/io/github/sds100/keymapper/system/url/AndroidOpenUrlAdapter.kt b/app/src/main/java/io/github/sds100/keymapper/system/url/AndroidOpenUrlAdapter.kt deleted file mode 100644 index 6109d32e98..0000000000 --- a/app/src/main/java/io/github/sds100/keymapper/system/url/AndroidOpenUrlAdapter.kt +++ /dev/null @@ -1,14 +0,0 @@ -package io.github.sds100.keymapper.system.url - -import android.content.Context -import io.github.sds100.keymapper.util.Result - -/** - * Created by sds100 on 24/04/2021. - */ -class AndroidOpenUrlAdapter(context: Context) : OpenUrlAdapter { - - private val ctx = context.applicationContext - - override fun openUrl(url: String): Result<*> = UrlUtils.openUrl(ctx, url) -} diff --git a/app/src/main/java/io/github/sds100/keymapper/system/url/OpenUrlAdapter.kt b/app/src/main/java/io/github/sds100/keymapper/system/url/OpenUrlAdapter.kt deleted file mode 100644 index a6c01f428d..0000000000 --- a/app/src/main/java/io/github/sds100/keymapper/system/url/OpenUrlAdapter.kt +++ /dev/null @@ -1,10 +0,0 @@ -package io.github.sds100.keymapper.system.url - -import io.github.sds100.keymapper.util.Result - -/** - * Created by sds100 on 24/04/2021. - */ -interface OpenUrlAdapter { - fun openUrl(url: String): Result<*> -} diff --git a/app/src/free/java/io/github/sds100/keymapper/trigger/AdvancedTriggersBottomSheet.kt b/app/src/main/java/io/github/sds100/keymapper/trigger/AdvancedTriggersBottomSheet.kt similarity index 98% rename from app/src/free/java/io/github/sds100/keymapper/trigger/AdvancedTriggersBottomSheet.kt rename to app/src/main/java/io/github/sds100/keymapper/trigger/AdvancedTriggersBottomSheet.kt index dc1abbe1d9..cc85192142 100644 --- a/app/src/free/java/io/github/sds100/keymapper/trigger/AdvancedTriggersBottomSheet.kt +++ b/app/src/main/java/io/github/sds100/keymapper/trigger/AdvancedTriggersBottomSheet.kt @@ -29,8 +29,8 @@ import androidx.compose.ui.text.font.FontStyle import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp -import io.github.sds100.keymapper.R -import io.github.sds100.keymapper.compose.KeyMapperTheme +import io.github.sds100.keymapper.base.R +import io.github.sds100.keymapper.base.compose.KeyMapperTheme import kotlinx.coroutines.launch @OptIn(ExperimentalMaterial3Api::class) diff --git a/app/src/main/java/io/github/sds100/keymapper/trigger/ConfigTriggerViewModel.kt b/app/src/main/java/io/github/sds100/keymapper/trigger/ConfigTriggerViewModel.kt new file mode 100644 index 0000000000..1654023097 --- /dev/null +++ b/app/src/main/java/io/github/sds100/keymapper/trigger/ConfigTriggerViewModel.kt @@ -0,0 +1,48 @@ +package io.github.sds100.keymapper.trigger + +import io.github.sds100.keymapper.base.keymaps.ConfigKeyMapUseCase +import io.github.sds100.keymapper.base.keymaps.CreateKeyMapShortcutUseCase +import io.github.sds100.keymapper.base.keymaps.DisplayKeyMapUseCase +import io.github.sds100.keymapper.base.keymaps.FingerprintGesturesSupportedUseCase +import io.github.sds100.keymapper.base.onboarding.OnboardingUseCase +import io.github.sds100.keymapper.base.purchasing.PurchasingManager +import io.github.sds100.keymapper.base.trigger.BaseConfigTriggerViewModel +import io.github.sds100.keymapper.base.trigger.RecordTriggerUseCase +import io.github.sds100.keymapper.base.trigger.SetupGuiKeyboardUseCase +import io.github.sds100.keymapper.base.utils.navigation.NavigationProvider +import io.github.sds100.keymapper.base.utils.ui.DialogProvider +import io.github.sds100.keymapper.base.utils.ui.ResourceProvider +import kotlinx.coroutines.CoroutineScope +import javax.inject.Inject + +class ConfigTriggerViewModel @Inject constructor( + private val coroutineScope: CoroutineScope, + private val onboarding: OnboardingUseCase, + private val config: ConfigKeyMapUseCase, + private val recordTrigger: RecordTriggerUseCase, + private val createKeyMapShortcut: CreateKeyMapShortcutUseCase, + private val displayKeyMap: DisplayKeyMapUseCase, + private val purchasingManager: PurchasingManager, + private val setupGuiKeyboard: SetupGuiKeyboardUseCase, + private val fingerprintGesturesSupported: FingerprintGesturesSupportedUseCase, + resourceProvider: ResourceProvider, + navigationProvider: NavigationProvider, + dialogProvider: DialogProvider, +) : BaseConfigTriggerViewModel( + coroutineScope = coroutineScope, + onboarding = onboarding, + config = config, + recordTrigger = recordTrigger, + createKeyMapShortcut = createKeyMapShortcut, + displayKeyMap = displayKeyMap, + purchasingManager = purchasingManager, + setupGuiKeyboard = setupGuiKeyboard, + fingerprintGesturesSupported = fingerprintGesturesSupported, + resourceProvider = resourceProvider, + navigationProvider = navigationProvider, + dialogProvider = dialogProvider, +) { + override fun onEditFloatingButtonClick() {} + + override fun onEditFloatingLayoutClick() {} +} diff --git a/app/src/main/java/io/github/sds100/keymapper/trigger/TriggerScreen.kt b/app/src/main/java/io/github/sds100/keymapper/trigger/TriggerScreen.kt index edbf72bd54..6c1da6cf77 100644 --- a/app/src/main/java/io/github/sds100/keymapper/trigger/TriggerScreen.kt +++ b/app/src/main/java/io/github/sds100/keymapper/trigger/TriggerScreen.kt @@ -1,63 +1,16 @@ package io.github.sds100.keymapper.trigger -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.PaddingValues -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.fillMaxHeight -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.systemBarsPadding -import androidx.compose.foundation.layout.widthIn -import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.foundation.lazy.itemsIndexed -import androidx.compose.foundation.lazy.rememberLazyListState -import androidx.compose.foundation.rememberScrollState -import androidx.compose.foundation.verticalScroll -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.rounded.Fingerprint -import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Surface -import androidx.compose.material3.Text -import androidx.compose.material3.adaptive.currentWindowAdaptiveInfo import androidx.compose.material3.rememberModalBottomSheetState import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.style.TextAlign -import androidx.compose.ui.tooling.preview.Devices -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.unit.dp -import androidx.lifecycle.compose.collectAsStateWithLifecycle -import androidx.window.core.layout.WindowHeightSizeClass -import androidx.window.core.layout.WindowWidthSizeClass -import io.github.sds100.keymapper.R -import io.github.sds100.keymapper.compose.KeyMapperTheme -import io.github.sds100.keymapper.keymaps.ClickType -import io.github.sds100.keymapper.keymaps.ShortcutModel -import io.github.sds100.keymapper.keymaps.ShortcutRow -import io.github.sds100.keymapper.util.State -import io.github.sds100.keymapper.util.ui.LinkType -import io.github.sds100.keymapper.util.ui.compose.ComposeIconInfo -import io.github.sds100.keymapper.util.ui.compose.DraggableItem -import io.github.sds100.keymapper.util.ui.compose.RadioButtonText -import io.github.sds100.keymapper.util.ui.compose.rememberDragDropState +import io.github.sds100.keymapper.base.trigger.BaseTriggerScreen @OptIn(ExperimentalMaterial3Api::class) @Composable fun TriggerScreen(modifier: Modifier = Modifier, viewModel: ConfigTriggerViewModel) { val sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true) - val setupGuiKeyboardState by viewModel.setupGuiKeyboardState.collectAsStateWithLifecycle() - val recordTriggerState by viewModel.recordTriggerState.collectAsStateWithLifecycle() - - HandleAssistantTriggerSetupBottomSheet(viewModel = viewModel) if (viewModel.showAdvancedTriggersBottomSheet) { AdvancedTriggersBottomSheet( @@ -70,643 +23,5 @@ fun TriggerScreen(modifier: Modifier = Modifier, viewModel: ConfigTriggerViewMod ) } - if (viewModel.showDpadTriggerSetupBottomSheet) { - DpadTriggerSetupBottomSheet( - modifier = Modifier.systemBarsPadding(), - onDismissRequest = { - viewModel.showDpadTriggerSetupBottomSheet = false - }, - guiKeyboardState = setupGuiKeyboardState, - onEnableKeyboardClick = viewModel::onEnableGuiKeyboardClick, - onChooseKeyboardClick = viewModel::onChooseGuiKeyboardClick, - onNeverShowAgainClick = viewModel::onNeverShowSetupDpadClick, - sheetState = sheetState, - ) - } - - if (viewModel.showNoKeysRecordedBottomSheet) { - NoKeysRecordedBottomSheet( - modifier = Modifier.systemBarsPadding(), - onDismissRequest = { - viewModel.showNoKeysRecordedBottomSheet = false - }, - viewModel = viewModel, - sheetState = sheetState, - ) - } - - val triggerKeyOptionsState by viewModel.triggerKeyOptionsState.collectAsStateWithLifecycle() - - if (triggerKeyOptionsState != null) { - TriggerKeyOptionsBottomSheet( - modifier = Modifier.systemBarsPadding(), - sheetState = sheetState, - state = triggerKeyOptionsState!!, - onDismissRequest = viewModel::onDismissTriggerKeyOptions, - onCheckDoNotRemap = viewModel::onCheckDoNotRemap, - onSelectClickType = viewModel::onSelectKeyClickType, - onSelectDevice = viewModel::onSelectTriggerKeyDevice, - onSelectAssistantType = viewModel::onSelectTriggerKeyAssistantType, - onEditFloatingButtonClick = viewModel::onEditFloatingButtonClick, - onEditFloatingLayoutClick = viewModel::onEditFloatingLayoutClick, - onSelectFingerprintGestureType = viewModel::onSelectFingerprintGestureType, - ) - } - - val configState by viewModel.state.collectAsStateWithLifecycle() - - when (val state = configState) { - is State.Loading -> Loading(modifier = modifier) - is State.Data -> { - if (isHorizontalLayout()) { - TriggerScreenHorizontal( - modifier = modifier, - configState = state.data, - recordTriggerState = recordTriggerState, - onRemoveClick = viewModel::onRemoveKeyClick, - onEditClick = viewModel::onTriggerKeyOptionsClick, - onRecordTriggerClick = viewModel::onRecordTriggerButtonClick, - onAdvancedTriggersClick = viewModel::onAdvancedTriggersClick, - onSelectClickType = viewModel::onClickTypeRadioButtonChecked, - onSelectParallelMode = viewModel::onParallelRadioButtonChecked, - onSelectSequenceMode = viewModel::onSequenceRadioButtonChecked, - onMoveTriggerKey = viewModel::onMoveTriggerKey, - onFixErrorClick = viewModel::onTriggerErrorClick, - onClickShortcut = viewModel::onClickTriggerKeyShortcut, - onRecordTriggerTapTargetCompleted = viewModel::onRecordTriggerTapTargetCompleted, - onSkipTapTarget = viewModel::onSkipTapTargetClick, - onAdvancedTriggerTapTargetCompleted = viewModel::onAdvancedTriggersTapTargetCompleted, - ) - } else { - TriggerScreenVertical( - modifier = modifier, - configState = state.data, - recordTriggerState = recordTriggerState, - onRemoveClick = viewModel::onRemoveKeyClick, - onEditClick = viewModel::onTriggerKeyOptionsClick, - onRecordTriggerClick = viewModel::onRecordTriggerButtonClick, - onAdvancedTriggersClick = viewModel::onAdvancedTriggersClick, - onSelectClickType = viewModel::onClickTypeRadioButtonChecked, - onSelectParallelMode = viewModel::onParallelRadioButtonChecked, - onSelectSequenceMode = viewModel::onSequenceRadioButtonChecked, - onMoveTriggerKey = viewModel::onMoveTriggerKey, - onFixErrorClick = viewModel::onTriggerErrorClick, - onClickShortcut = viewModel::onClickTriggerKeyShortcut, - onRecordTriggerTapTargetCompleted = viewModel::onRecordTriggerTapTargetCompleted, - onSkipTapTarget = viewModel::onSkipTapTargetClick, - onAdvancedTriggerTapTargetCompleted = viewModel::onAdvancedTriggersTapTargetCompleted, - ) - } - } - } -} - -@Composable -private fun isHorizontalLayout(): Boolean { - val windowSizeClass = currentWindowAdaptiveInfo().windowSizeClass - - return windowSizeClass.windowHeightSizeClass == WindowHeightSizeClass.COMPACT -} - -@Composable -private fun isVerticalCompactLayout(): Boolean { - val windowSizeClass = currentWindowAdaptiveInfo().windowSizeClass - - return windowSizeClass.windowHeightSizeClass == WindowHeightSizeClass.COMPACT && windowSizeClass.windowWidthSizeClass == WindowWidthSizeClass.COMPACT -} - -@Composable -private fun Loading(modifier: Modifier = Modifier) { - Box(modifier = modifier, contentAlignment = Alignment.Center) { - CircularProgressIndicator() - } -} - -@Composable -private fun TriggerScreenVertical( - modifier: Modifier = Modifier, - configState: ConfigTriggerState, - recordTriggerState: RecordTriggerState, - onRemoveClick: (String) -> Unit = {}, - onEditClick: (String) -> Unit = {}, - onSelectClickType: (ClickType) -> Unit = {}, - onSelectParallelMode: () -> Unit = {}, - onSelectSequenceMode: () -> Unit = {}, - onRecordTriggerClick: () -> Unit = {}, - onAdvancedTriggersClick: () -> Unit = {}, - onMoveTriggerKey: (fromIndex: Int, toIndex: Int) -> Unit = { _, _ -> }, - onFixErrorClick: (TriggerError) -> Unit = {}, - onClickShortcut: (TriggerKeyShortcut) -> Unit = {}, - onRecordTriggerTapTargetCompleted: () -> Unit = {}, - onSkipTapTarget: () -> Unit = {}, - onAdvancedTriggerTapTargetCompleted: () -> Unit = {}, -) { - Surface(modifier = modifier) { - Column { - when (configState) { - is ConfigTriggerState.Empty -> { - Column( - modifier = Modifier - .weight(1f) - .verticalScroll(state = rememberScrollState()), - verticalArrangement = Arrangement.Center, - ) { - Text( - modifier = Modifier.padding(32.dp), - text = stringResource(R.string.triggers_recyclerview_placeholder), - textAlign = TextAlign.Center, - ) - - if (configState.shortcuts.isNotEmpty()) { - Column(horizontalAlignment = Alignment.CenterHorizontally) { - Text( - text = stringResource(R.string.trigger_shortcuts_header), - style = MaterialTheme.typography.titleSmall, - ) - - Spacer(Modifier.height(8.dp)) - - ShortcutRow( - modifier = Modifier - .padding(horizontal = 32.dp) - .fillMaxWidth(), - shortcuts = configState.shortcuts, - onClick = onClickShortcut, - ) - } - } - } - } - - is ConfigTriggerState.Loaded -> { - val isCompact = isVerticalCompactLayout() - Spacer(Modifier.height(8.dp)) - - TriggerList( - modifier = Modifier.weight(1f), - triggerList = configState.triggerKeys, - shortcuts = configState.shortcuts, - isReorderingEnabled = configState.isReorderingEnabled, - onEditClick = onEditClick, - onRemoveClick = onRemoveClick, - onMove = onMoveTriggerKey, - onClickShortcut = onClickShortcut, - onFixErrorClick = onFixErrorClick, - ) - - if (configState.clickTypeButtons.isNotEmpty()) { - ClickTypeRadioGroup( - modifier = Modifier.padding(horizontal = 8.dp), - clickTypes = configState.clickTypeButtons, - checkedClickType = configState.checkedClickType, - onSelectClickType = onSelectClickType, - maxLines = if (isCompact) 1 else 2, - ) - } - - if (configState.triggerModeButtonsVisible) { - if (!isCompact) { - Text( - modifier = Modifier.padding(horizontal = 8.dp), - text = stringResource(R.string.press_dot_dot_dot), - style = MaterialTheme.typography.labelLarge, - ) - } - - TriggerModeRadioGroup( - modifier = Modifier.padding(horizontal = 8.dp), - mode = configState.checkedTriggerMode, - isEnabled = configState.triggerModeButtonsEnabled, - onSelectParallelMode = onSelectParallelMode, - onSelectSequenceMode = onSelectSequenceMode, - maxLines = if (isCompact) 1 else 2, - ) - } - } - } - - RecordTriggerButtonRow( - modifier = Modifier - .fillMaxWidth() - .padding(start = 8.dp, end = 8.dp, bottom = 8.dp), - onRecordTriggerClick = onRecordTriggerClick, - recordTriggerState = recordTriggerState, - onAdvancedTriggersClick = onAdvancedTriggersClick, - showRecordTriggerTapTarget = (configState as? ConfigTriggerState.Empty)?.showRecordTriggerTapTarget - ?: false, - onRecordTriggerTapTargetCompleted = onRecordTriggerTapTargetCompleted, - onSkipTapTarget = onSkipTapTarget, - showAdvancedTriggerTapTarget = configState.showAdvancedTriggersTapTarget, - onAdvancedTriggerTapTargetCompleted = onAdvancedTriggerTapTargetCompleted, - ) - } - } -} - -@Composable -private fun TriggerScreenHorizontal( - modifier: Modifier = Modifier, - configState: ConfigTriggerState, - recordTriggerState: RecordTriggerState, - onRemoveClick: (String) -> Unit = {}, - onEditClick: (String) -> Unit = {}, - onSelectClickType: (ClickType) -> Unit = {}, - onSelectParallelMode: () -> Unit = {}, - onSelectSequenceMode: () -> Unit = {}, - onRecordTriggerClick: () -> Unit = {}, - onAdvancedTriggersClick: () -> Unit = {}, - onMoveTriggerKey: (fromIndex: Int, toIndex: Int) -> Unit = { _, _ -> }, - onFixErrorClick: (TriggerError) -> Unit = {}, - onClickShortcut: (TriggerKeyShortcut) -> Unit = {}, - onRecordTriggerTapTargetCompleted: () -> Unit = {}, - onSkipTapTarget: () -> Unit = {}, - onAdvancedTriggerTapTargetCompleted: () -> Unit = {}, -) { - Surface(modifier = modifier) { - when (configState) { - is ConfigTriggerState.Empty -> Row { - Text( - modifier = Modifier - .widthIn(max = 400.dp) - .padding(32.dp) - .verticalScroll(state = rememberScrollState()), - text = stringResource(R.string.triggers_recyclerview_placeholder), - textAlign = TextAlign.Center, - ) - Column { - if (configState.shortcuts.isNotEmpty()) { - Column( - modifier = Modifier - .weight(1f) - .verticalScroll(state = rememberScrollState()), - horizontalAlignment = Alignment.CenterHorizontally, - verticalArrangement = Arrangement.Center, - ) { - Text( - text = stringResource(R.string.trigger_shortcuts_header), - style = MaterialTheme.typography.titleSmall, - ) - - Spacer(Modifier.height(8.dp)) - - ShortcutRow( - modifier = Modifier - .padding(horizontal = 32.dp) - .fillMaxWidth(), - shortcuts = configState.shortcuts, - onClick = onClickShortcut, - ) - } - } - - RecordTriggerButtonRow( - modifier = Modifier.padding(start = 8.dp, end = 8.dp, bottom = 8.dp), - onRecordTriggerClick = onRecordTriggerClick, - recordTriggerState = recordTriggerState, - onAdvancedTriggersClick = onAdvancedTriggersClick, - showRecordTriggerTapTarget = (configState as? ConfigTriggerState.Empty)?.showRecordTriggerTapTarget - ?: false, - onRecordTriggerTapTargetCompleted = onRecordTriggerTapTargetCompleted, - onSkipTapTarget = onSkipTapTarget, - showAdvancedTriggerTapTarget = configState.showAdvancedTriggersTapTarget, - ) - } - } - - is ConfigTriggerState.Loaded -> Row { - TriggerList( - modifier = Modifier - .fillMaxHeight() - .widthIn(max = 400.dp), - triggerList = configState.triggerKeys, - shortcuts = configState.shortcuts, - isReorderingEnabled = configState.isReorderingEnabled, - onEditClick = onEditClick, - onRemoveClick = onRemoveClick, - onMove = onMoveTriggerKey, - onClickShortcut = onClickShortcut, - onFixErrorClick = onFixErrorClick, - ) - - Spacer(Modifier.height(8.dp)) - - Column( - modifier = Modifier.fillMaxHeight(), - verticalArrangement = Arrangement.Bottom, - ) { - Column( - modifier = Modifier - .weight(1f) - .verticalScroll(rememberScrollState()), - ) { - if (configState.clickTypeButtons.isNotEmpty()) { - ClickTypeRadioGroup( - modifier = Modifier.padding(horizontal = 8.dp), - clickTypes = configState.clickTypeButtons, - checkedClickType = configState.checkedClickType, - onSelectClickType = onSelectClickType, - ) - } - - Text( - modifier = Modifier.padding(horizontal = 8.dp), - text = stringResource(R.string.press_dot_dot_dot), - style = MaterialTheme.typography.labelLarge, - ) - - if (configState.triggerModeButtonsVisible) { - TriggerModeRadioGroup( - modifier = Modifier.padding(horizontal = 8.dp), - mode = configState.checkedTriggerMode, - isEnabled = configState.triggerModeButtonsEnabled, - onSelectParallelMode = onSelectParallelMode, - onSelectSequenceMode = onSelectSequenceMode, - ) - } - } - - RecordTriggerButtonRow( - modifier = Modifier.padding(start = 8.dp, end = 8.dp, bottom = 8.dp), - onRecordTriggerClick = onRecordTriggerClick, - recordTriggerState = recordTriggerState, - onAdvancedTriggersClick = onAdvancedTriggersClick, - showRecordTriggerTapTarget = false, - onRecordTriggerTapTargetCompleted = onRecordTriggerTapTargetCompleted, - onSkipTapTarget = onSkipTapTarget, - showAdvancedTriggerTapTarget = configState.showAdvancedTriggersTapTarget, - onAdvancedTriggerTapTargetCompleted = onAdvancedTriggerTapTargetCompleted, - ) - } - } - } - } -} - -@Composable -private fun TriggerList( - modifier: Modifier = Modifier, - triggerList: List, - shortcuts: Set>, - isReorderingEnabled: Boolean, - onRemoveClick: (String) -> Unit, - onEditClick: (String) -> Unit, - onFixErrorClick: (TriggerError) -> Unit, - onMove: (fromIndex: Int, toIndex: Int) -> Unit, - onClickShortcut: (TriggerKeyShortcut) -> Unit, -) { - val lazyListState = rememberLazyListState() - val dragDropState = rememberDragDropState( - lazyListState = lazyListState, - onMove = onMove, - // Do not drag and drop the row of shortcuts - ignoreLastItems = if (shortcuts.isEmpty()) { - 0 - } else { - 1 - }, - ) - - // Use dragContainer rather than .draggable() modifier because that causes - // dragging the first item to be always be dropped in the next position. - LazyColumn( - modifier = modifier, - state = lazyListState, - contentPadding = PaddingValues(vertical = 8.dp), - ) { - itemsIndexed( - triggerList, - key = { _, item -> item.id }, - contentType = { _, _ -> "key" }, - ) { index, model -> - DraggableItem( - dragDropState = dragDropState, - index = index, - ) { isDragging -> - TriggerKeyListItem( - modifier = Modifier.fillMaxWidth(), - model = model, - index = index, - isDraggingEnabled = triggerList.size > 1, - isDragging = isDragging, - isReorderingEnabled = isReorderingEnabled, - dragDropState = dragDropState, - onEditClick = { onEditClick(model.id) }, - onRemoveClick = { onRemoveClick(model.id) }, - onFixClick = onFixErrorClick, - ) - } - } - - if (shortcuts.isNotEmpty()) { - item(key = "shortcuts", contentType = "shortcuts") { - Column(horizontalAlignment = Alignment.CenterHorizontally) { - Text( - text = stringResource(R.string.trigger_shortcuts_header), - style = MaterialTheme.typography.titleSmall, - ) - - Spacer(Modifier.height(8.dp)) - - ShortcutRow( - modifier = Modifier - .fillMaxWidth() - .padding(horizontal = 32.dp), - shortcuts = shortcuts, - onClick = { onClickShortcut(it) }, - ) - } - } - } - } -} - -@Composable -private fun ClickTypeRadioGroup( - modifier: Modifier = Modifier, - clickTypes: Set, - checkedClickType: ClickType?, - onSelectClickType: (ClickType) -> Unit, - maxLines: Int = 2, -) { - Column(modifier = modifier) { - Row(modifier = Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) { - if (clickTypes.contains(ClickType.SHORT_PRESS)) { - RadioButtonText( - modifier = Modifier.weight(1f), - isSelected = checkedClickType == ClickType.SHORT_PRESS, - text = stringResource(R.string.radio_button_short_press), - onSelected = { onSelectClickType(ClickType.SHORT_PRESS) }, - maxLines = maxLines, - ) - } - if (clickTypes.contains(ClickType.LONG_PRESS)) { - RadioButtonText( - modifier = Modifier.weight(1f), - isSelected = checkedClickType == ClickType.LONG_PRESS, - text = stringResource(R.string.radio_button_long_press), - onSelected = { onSelectClickType(ClickType.LONG_PRESS) }, - maxLines = maxLines, - ) - } - if (clickTypes.contains(ClickType.DOUBLE_PRESS)) { - RadioButtonText( - modifier = Modifier.weight(1f), - isSelected = checkedClickType == ClickType.DOUBLE_PRESS, - text = stringResource(R.string.radio_button_double_press), - onSelected = { onSelectClickType(ClickType.DOUBLE_PRESS) }, - maxLines = maxLines, - ) - } - } - } -} - -@Composable -private fun TriggerModeRadioGroup( - modifier: Modifier = Modifier, - mode: TriggerMode, - isEnabled: Boolean, - onSelectParallelMode: () -> Unit, - onSelectSequenceMode: () -> Unit, - maxLines: Int = 2, -) { - Column(modifier = modifier) { - Row(modifier = Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) { - RadioButtonText( - modifier = Modifier.weight(1f), - isSelected = mode is TriggerMode.Parallel, - isEnabled = isEnabled, - text = stringResource(R.string.radio_button_parallel), - onSelected = onSelectParallelMode, - maxLines = maxLines, - ) - RadioButtonText( - modifier = Modifier.weight(1f), - isSelected = mode == TriggerMode.Sequence, - isEnabled = isEnabled, - text = stringResource(R.string.radio_button_sequence), - onSelected = onSelectSequenceMode, - maxLines = maxLines, - ) - } - } -} - -private val sampleList = listOf( - TriggerKeyListItemModel.KeyCode( - id = "id1", - keyName = "Volume Up", - clickType = ClickType.SHORT_PRESS, - extraInfo = "External Keyboard", - linkType = LinkType.ARROW, - error = null, - ), - TriggerKeyListItemModel.FloatingButton( - id = "id2", - buttonName = "😎", - layoutName = "Gaming", - clickType = ClickType.DOUBLE_PRESS, - linkType = LinkType.ARROW, - error = null, - ), - TriggerKeyListItemModel.Assistant( - id = "id3", - assistantType = AssistantTriggerType.DEVICE, - clickType = ClickType.DOUBLE_PRESS, - linkType = LinkType.HIDDEN, - error = null, - ), -) - -private val previewState = ConfigTriggerState.Loaded( - triggerKeys = sampleList, - isReorderingEnabled = true, - clickTypeButtons = setOf( - ClickType.SHORT_PRESS, - ClickType.LONG_PRESS, - ClickType.DOUBLE_PRESS, - ), - checkedClickType = ClickType.LONG_PRESS, - checkedTriggerMode = TriggerMode.Sequence, - triggerModeButtonsEnabled = true, - triggerModeButtonsVisible = true, - shortcuts = setOf( - ShortcutModel( - icon = ComposeIconInfo.Vector(Icons.Rounded.Fingerprint), - text = "Fingerprint gesture", - data = TriggerKeyShortcut.FINGERPRINT_GESTURE, - ), - ), -) - -@Preview(device = Devices.PIXEL) -@Composable -private fun VerticalPreview() { - KeyMapperTheme { - TriggerScreenVertical( - configState = previewState, - recordTriggerState = RecordTriggerState.Idle, - ) - } -} - -@Preview(heightDp = 400, widthDp = 300) -@Composable -private fun VerticalPreviewTiny() { - KeyMapperTheme { - TriggerScreenVertical( - configState = previewState, - recordTriggerState = RecordTriggerState.Idle, - ) - } -} - -@Preview(device = Devices.PIXEL) -@Composable -private fun VerticalEmptyPreview() { - KeyMapperTheme { - TriggerScreenVertical( - configState = ConfigTriggerState.Empty( - shortcuts = setOf( - ShortcutModel( - icon = ComposeIconInfo.Vector(Icons.Rounded.Fingerprint), - text = "Fingerprint gesture", - data = TriggerKeyShortcut.FINGERPRINT_GESTURE, - ), - ), - ), - recordTriggerState = RecordTriggerState.Idle, - ) - } -} - -@Preview(widthDp = 800, heightDp = 300) -@Composable -private fun HorizontalPreview() { - KeyMapperTheme { - TriggerScreenHorizontal( - configState = previewState, - recordTriggerState = RecordTriggerState.Idle, - ) - } -} - -@Preview(widthDp = 800, heightDp = 300) -@Composable -private fun HorizontalEmptyPreview() { - KeyMapperTheme { - TriggerScreenHorizontal( - configState = ConfigTriggerState.Empty( - shortcuts = setOf( - ShortcutModel( - icon = ComposeIconInfo.Vector(Icons.Rounded.Fingerprint), - text = "Fingerprint gesture", - data = TriggerKeyShortcut.FINGERPRINT_GESTURE, - ), - ), - - ), - recordTriggerState = RecordTriggerState.Idle, - ) - } + BaseTriggerScreen(modifier, viewModel) } diff --git a/app/src/main/java/io/github/sds100/keymapper/util/ErrorUtils.kt b/app/src/main/java/io/github/sds100/keymapper/util/ErrorUtils.kt deleted file mode 100644 index 8a047e25b0..0000000000 --- a/app/src/main/java/io/github/sds100/keymapper/util/ErrorUtils.kt +++ /dev/null @@ -1,184 +0,0 @@ -package io.github.sds100.keymapper.util - -import android.content.pm.PackageManager -import io.github.sds100.keymapper.R -import io.github.sds100.keymapper.purchasing.ProductId -import io.github.sds100.keymapper.system.BuildUtils -import io.github.sds100.keymapper.util.ui.ResourceProvider - -/** - * Created by sds100 on 29/02/2020. - */ - -fun Error.getFullMessage(resourceProvider: ResourceProvider): String = when (this) { - is Error.PermissionDenied -> - Error.PermissionDenied.getMessageForPermission( - resourceProvider, - permission, - ) - - is Error.AppNotFound -> resourceProvider.getString( - R.string.error_app_isnt_installed, - packageName, - ) - - is Error.AppDisabled -> resourceProvider.getString( - R.string.error_app_is_disabled_package_name, - this.packageName, - ) - - is Error.NoCompatibleImeEnabled -> resourceProvider.getString(R.string.error_key_mapper_ime_service_disabled) - is Error.NoCompatibleImeChosen -> resourceProvider.getString(R.string.error_ime_must_be_chosen) - is Error.SystemFeatureNotSupported -> when (this.feature) { - PackageManager.FEATURE_NFC -> resourceProvider.getString(R.string.error_system_feature_nfc_unsupported) - PackageManager.FEATURE_CAMERA -> resourceProvider.getString(R.string.error_system_feature_camera_unsupported) - PackageManager.FEATURE_FINGERPRINT -> resourceProvider.getString(R.string.error_system_feature_fingerprint_unsupported) - PackageManager.FEATURE_WIFI -> resourceProvider.getString(R.string.error_system_feature_wifi_unsupported) - PackageManager.FEATURE_BLUETOOTH -> resourceProvider.getString(R.string.error_system_feature_bluetooth_unsupported) - PackageManager.FEATURE_DEVICE_ADMIN -> resourceProvider.getString(R.string.error_system_feature_device_admin_unsupported) - PackageManager.FEATURE_CAMERA_FLASH -> resourceProvider.getString(R.string.error_system_feature_camera_flash_unsupported) - PackageManager.FEATURE_TELEPHONY -> resourceProvider.getString(R.string.error_system_feature_telephony_unsupported) - else -> throw Exception("Don't know how to get error message for this system feature ${this.feature}") - } - - is Error.ExtraNotFound -> resourceProvider.getString(R.string.error_extra_not_found, extraId) - is Error.SdkVersionTooLow -> resourceProvider.getString( - R.string.error_sdk_version_too_low, - BuildUtils.getSdkVersionName(minSdk), - ) - - is Error.SdkVersionTooHigh -> resourceProvider.getString( - R.string.error_sdk_version_too_high, - BuildUtils.getSdkVersionName(maxSdk), - ) - - is Error.InputMethodNotFound -> resourceProvider.getString( - R.string.error_ime_not_found, - imeLabel, - ) - - is Error.FrontFlashNotFound -> resourceProvider.getString(R.string.error_front_flash_not_found) - is Error.BackFlashNotFound -> resourceProvider.getString(R.string.error_back_flash_not_found) - is Error.DeviceNotFound -> resourceProvider.getString(R.string.error_device_not_found) - is Error.Exception -> exception.toString() - is Error.EmptyJson -> resourceProvider.getString(R.string.error_empty_json) - is Error.InvalidNumber -> resourceProvider.getString(R.string.error_invalid_number) - is Error.NumberTooSmall -> resourceProvider.getString(R.string.error_number_too_small, min) - is Error.NumberTooBig -> resourceProvider.getString(R.string.error_number_too_big, max) - is Error.EmptyText -> resourceProvider.getString(R.string.error_cant_be_empty) - Error.BackupVersionTooNew -> resourceProvider.getString(R.string.error_backup_version_too_new) - Error.NoIncompatibleKeyboardsInstalled -> resourceProvider.getString(R.string.error_no_incompatible_input_methods_installed) - Error.NoMediaSessions -> resourceProvider.getString(R.string.error_no_media_sessions) - Error.NoVoiceAssistant -> resourceProvider.getString(R.string.error_voice_assistant_not_found) - Error.AccessibilityServiceDisabled -> resourceProvider.getString(R.string.error_accessibility_service_disabled) - Error.LauncherShortcutsNotSupported -> resourceProvider.getString(R.string.error_launcher_shortcuts_not_supported) - Error.AccessibilityServiceCrashed -> resourceProvider.getString(R.string.error_accessibility_service_crashed) - Error.CantFindImeSettings -> resourceProvider.getString(R.string.error_cant_find_ime_settings) - Error.CantShowImePickerInBackground -> resourceProvider.getString(R.string.error_cant_show_ime_picker_in_background) - Error.FailedToFindAccessibilityNode -> resourceProvider.getString(R.string.error_failed_to_find_accessibility_node) - is Error.FailedToPerformAccessibilityGlobalAction -> resourceProvider.getString( - R.string.error_failed_to_perform_accessibility_global_action, - action, - ) - - Error.FailedToDispatchGesture -> resourceProvider.getString(R.string.error_failed_to_dispatch_gesture) - Error.AppShortcutCantBeOpened -> resourceProvider.getString(R.string.error_opening_app_shortcut) - Error.InsufficientPermissionsToOpenAppShortcut -> resourceProvider.getString(R.string.error_keymapper_doesnt_have_permission_app_shortcut) - Error.NoAppToPhoneCall -> resourceProvider.getString(R.string.error_no_app_to_phone_call) - - Error.CameraInUse -> resourceProvider.getString(R.string.error_camera_in_use) - Error.CameraError -> resourceProvider.getString(R.string.error_camera_error) - Error.CameraDisabled -> resourceProvider.getString(R.string.error_camera_disabled) - Error.CameraDisconnected -> resourceProvider.getString(R.string.error_camera_disconnected) - Error.MaxCamerasInUse -> resourceProvider.getString(R.string.error_max_cameras_in_use) - Error.CameraVariableFlashlightStrengthUnsupported -> resourceProvider.getString(R.string.error_variable_flashlight_strength_unsupported) - - is Error.FailedToModifySystemSetting -> resourceProvider.getString( - R.string.error_failed_to_modify_system_setting, - setting, - ) - - is Error.ImeDisabled -> resourceProvider.getString(R.string.error_ime_disabled, this.ime.label) - Error.FailedToChangeIme -> resourceProvider.getString(R.string.error_failed_to_change_ime) - Error.NoCameraApp -> resourceProvider.getString(R.string.error_no_camera_app) - Error.NoDeviceAssistant -> resourceProvider.getString(R.string.error_no_device_assistant) - Error.NoSettingsApp -> resourceProvider.getString(R.string.error_no_settings_app) - Error.NoAppToOpenUrl -> resourceProvider.getString(R.string.error_no_app_to_open_url) - - Error.CantFindSoundFile -> resourceProvider.getString(R.string.error_cant_find_sound_file) - is Error.CorruptJsonFile -> reason - - is Error.CannotCreateFileInTarget -> resourceProvider.getString( - R.string.error_file_access_denied, - uri, - ) - - Error.FileOperationCancelled -> resourceProvider.getString(R.string.error_file_operation_cancelled) - is Error.NoSpaceLeftOnTarget -> resourceProvider.getString( - R.string.error_no_space_left_at_target, - uri, - ) - - is Error.NotADirectory -> resourceProvider.getString(R.string.error_not_a_directory, uri) - is Error.NotAFile -> resourceProvider.getString(R.string.error_not_a_file, uri) - is Error.SourceFileNotFound -> resourceProvider.getString( - R.string.error_source_file_not_found, - uri, - ) - - Error.StoragePermissionDenied -> resourceProvider.getString(R.string.error_storage_permission_denied) - Error.TargetDirectoryMatchesSourceDirectory -> resourceProvider.getString(R.string.error_matching_source_and_target_paths) - is Error.TargetDirectoryNotFound -> resourceProvider.getString( - R.string.error_directory_not_found, - uri, - ) - - is Error.TargetFileNotFound -> resourceProvider.getString( - R.string.error_target_file_not_found, - uri, - ) - - Error.UnknownIOError -> resourceProvider.getString(R.string.error_io_error) - Error.ShizukuNotStarted -> resourceProvider.getString(R.string.error_shizuku_not_started) - Error.NoFileName -> resourceProvider.getString(R.string.error_no_file_name) - Error.CantDetectKeyEventsInPhoneCall -> resourceProvider.getString(R.string.trigger_error_cant_detect_in_phone_call_explanation) - Error.GestureStrokeCountTooHigh -> resourceProvider.getString(R.string.trigger_error_gesture_stroke_count_too_high) - Error.GestureDurationTooHigh -> resourceProvider.getString(R.string.trigger_error_gesture_duration_too_high) - - Error.PurchasingError.Cancelled -> resourceProvider.getString(R.string.purchasing_error_cancelled) - Error.PurchasingError.NetworkError -> resourceProvider.getString(R.string.purchasing_error_network) - Error.PurchasingError.ProductNotFound -> resourceProvider.getString(R.string.purchasing_error_product_not_found) - Error.PurchasingError.StoreProblem -> resourceProvider.getString(R.string.purchasing_error_store_problem) - Error.PurchasingError.PaymentPending -> resourceProvider.getString(R.string.purchasing_error_payment_pending) - Error.PurchasingError.PurchaseInvalid -> resourceProvider.getString(R.string.purchasing_error_purchase_invalid) - is Error.PurchasingError.Unexpected -> this.message - - is Error.ProductNotPurchased -> when (this.product) { - ProductId.ASSISTANT_TRIGGER -> resourceProvider.getString(R.string.purchasing_error_assistant_not_purchased_home_screen) - ProductId.FLOATING_BUTTONS -> resourceProvider.getString(R.string.purchasing_error_floating_buttons_not_purchased_home_screen) - } - - Error.PurchasingNotImplemented -> resourceProvider.getString(R.string.purchasing_error_not_implemented) - Error.DpadTriggerImeNotSelected -> resourceProvider.getString(R.string.trigger_error_dpad_ime_not_selected) - Error.InvalidBackup -> resourceProvider.getString(R.string.error_invalid_backup) - Error.MalformedUrl -> resourceProvider.getString(R.string.error_malformed_url) - Error.UiElementNotFound -> resourceProvider.getString(R.string.error_ui_element_not_found) -} - -val Error.isFixable: Boolean - get() = when (this) { - is Error.AppNotFound, - is Error.AppDisabled, - Error.NoCompatibleImeEnabled, - Error.NoCompatibleImeChosen, - is Error.ImeDisabled, - Error.AccessibilityServiceDisabled, - Error.AccessibilityServiceCrashed, - is Error.PermissionDenied, - is Error.ShizukuNotStarted, - is Error.CantDetectKeyEventsInPhoneCall, - - -> true - - else -> false - } diff --git a/app/src/main/java/io/github/sds100/keymapper/util/Inject.kt b/app/src/main/java/io/github/sds100/keymapper/util/Inject.kt deleted file mode 100644 index 3ad39fcfac..0000000000 --- a/app/src/main/java/io/github/sds100/keymapper/util/Inject.kt +++ /dev/null @@ -1,260 +0,0 @@ -package io.github.sds100.keymapper.util - -import android.content.Context -import androidx.lifecycle.lifecycleScope -import io.github.sds100.keymapper.KeyMapperApp -import io.github.sds100.keymapper.ServiceLocator -import io.github.sds100.keymapper.UseCases -import io.github.sds100.keymapper.actions.ChooseActionViewModel -import io.github.sds100.keymapper.actions.TestActionUseCaseImpl -import io.github.sds100.keymapper.actions.keyevent.ChooseKeyCodeViewModel -import io.github.sds100.keymapper.actions.keyevent.ConfigKeyEventActionViewModel -import io.github.sds100.keymapper.actions.keyevent.ConfigKeyEventUseCaseImpl -import io.github.sds100.keymapper.actions.pinchscreen.PinchPickDisplayCoordinateViewModel -import io.github.sds100.keymapper.actions.sound.ChooseSoundFileUseCaseImpl -import io.github.sds100.keymapper.actions.sound.ChooseSoundFileViewModel -import io.github.sds100.keymapper.actions.swipescreen.SwipePickDisplayCoordinateViewModel -import io.github.sds100.keymapper.actions.tapscreen.PickDisplayCoordinateViewModel -import io.github.sds100.keymapper.actions.uielement.InteractUiElementViewModel -import io.github.sds100.keymapper.api.KeyEventRelayServiceWrapper -import io.github.sds100.keymapper.backup.BackupRestoreMappingsUseCaseImpl -import io.github.sds100.keymapper.constraints.ChooseConstraintViewModel -import io.github.sds100.keymapper.constraints.CreateConstraintUseCaseImpl -import io.github.sds100.keymapper.home.HomeViewModel -import io.github.sds100.keymapper.home.ShowHomeScreenAlertsUseCaseImpl -import io.github.sds100.keymapper.keymaps.ConfigKeyMapViewModel -import io.github.sds100.keymapper.keymaps.CreateKeyMapShortcutViewModel -import io.github.sds100.keymapper.keymaps.FingerprintGesturesSupportedUseCaseImpl -import io.github.sds100.keymapper.keymaps.ListKeyMapsUseCaseImpl -import io.github.sds100.keymapper.logging.DisplayLogUseCaseImpl -import io.github.sds100.keymapper.logging.LogViewModel -import io.github.sds100.keymapper.settings.ConfigSettingsUseCaseImpl -import io.github.sds100.keymapper.settings.SettingsViewModel -import io.github.sds100.keymapper.sorting.SortKeyMapsUseCaseImpl -import io.github.sds100.keymapper.system.accessibility.AccessibilityServiceController -import io.github.sds100.keymapper.system.accessibility.MyAccessibilityService -import io.github.sds100.keymapper.system.apps.ChooseActivityViewModel -import io.github.sds100.keymapper.system.apps.ChooseAppShortcutViewModel -import io.github.sds100.keymapper.system.apps.ChooseAppViewModel -import io.github.sds100.keymapper.system.apps.DisplayAppShortcutsUseCaseImpl -import io.github.sds100.keymapper.system.bluetooth.ChooseBluetoothDeviceUseCaseImpl -import io.github.sds100.keymapper.system.bluetooth.ChooseBluetoothDeviceViewModel -import io.github.sds100.keymapper.system.inputmethod.ShowInputMethodPickerUseCaseImpl -import io.github.sds100.keymapper.system.intents.ConfigIntentViewModel -import io.github.sds100.keymapper.trigger.SetupGuiKeyboardUseCaseImpl - -/** - * Created by sds100 on 26/01/2020. - */ - -object Inject { - - fun chooseActionViewModel(ctx: Context): ChooseActionViewModel.Factory = ChooseActionViewModel.Factory( - UseCases.createAction(ctx), - ServiceLocator.resourceProvider(ctx), - ) - - fun chooseAppViewModel(context: Context): ChooseAppViewModel.Factory = ChooseAppViewModel.Factory( - UseCases.displayPackages(context), - ) - - fun chooseActivityViewModel(context: Context): ChooseActivityViewModel.Factory = ChooseActivityViewModel.Factory( - UseCases.displayPackages(context), - ) - - fun chooseAppShortcutViewModel(context: Context): ChooseAppShortcutViewModel.Factory = ChooseAppShortcutViewModel.Factory( - DisplayAppShortcutsUseCaseImpl( - ServiceLocator.appShortcutAdapter(context), - ), - ServiceLocator.resourceProvider(context), - ) - - fun chooseConstraintListViewModel(ctx: Context): ChooseConstraintViewModel.Factory = ChooseConstraintViewModel.Factory( - CreateConstraintUseCaseImpl( - ServiceLocator.networkAdapter(ctx), - ServiceLocator.inputMethodAdapter(ctx), - ServiceLocator.settingsRepository(ctx), - ServiceLocator.cameraAdapter(ctx), - ), - ServiceLocator.resourceProvider(ctx), - ) - - fun configKeyEventViewModel( - context: Context, - ): ConfigKeyEventActionViewModel.Factory { - val useCase = ConfigKeyEventUseCaseImpl( - preferenceRepository = ServiceLocator.settingsRepository(context), - devicesAdapter = ServiceLocator.devicesAdapter(context), - ) - return ConfigKeyEventActionViewModel.Factory( - useCase, - ServiceLocator.resourceProvider(context), - ) - } - - fun chooseKeyCodeViewModel(): ChooseKeyCodeViewModel.Factory = ChooseKeyCodeViewModel.Factory() - - fun configIntentViewModel(ctx: Context): ConfigIntentViewModel.Factory = ConfigIntentViewModel.Factory(ServiceLocator.resourceProvider(ctx)) - - fun soundFileActionTypeViewModel(ctx: Context): ChooseSoundFileViewModel.Factory = ChooseSoundFileViewModel.Factory( - ServiceLocator.resourceProvider(ctx), - ChooseSoundFileUseCaseImpl( - ServiceLocator.fileAdapter(ctx), - ServiceLocator.soundsManager(ctx), - ), - ) - - fun tapCoordinateActionTypeViewModel(context: Context): PickDisplayCoordinateViewModel.Factory = PickDisplayCoordinateViewModel.Factory( - ServiceLocator.resourceProvider(context), - ) - - fun swipeCoordinateActionTypeViewModel(context: Context): SwipePickDisplayCoordinateViewModel.Factory = SwipePickDisplayCoordinateViewModel.Factory( - ServiceLocator.resourceProvider(context), - ) - - fun pinchCoordinateActionTypeViewModel(context: Context): PinchPickDisplayCoordinateViewModel.Factory = PinchPickDisplayCoordinateViewModel.Factory( - ServiceLocator.resourceProvider(context), - ) - - fun configKeyMapViewModel( - ctx: Context, - ): ConfigKeyMapViewModel.Factory = ConfigKeyMapViewModel.Factory( - UseCases.configKeyMap(ctx), - TestActionUseCaseImpl(ServiceLocator.accessibilityServiceAdapter(ctx)), - UseCases.onboarding(ctx), - (ctx.applicationContext as KeyMapperApp).recordTriggerController, - UseCases.createKeymapShortcut(ctx), - UseCases.displayKeyMap(ctx), - UseCases.createAction(ctx), - ServiceLocator.resourceProvider(ctx), - ServiceLocator.purchasingManager(ctx), - SetupGuiKeyboardUseCaseImpl( - ServiceLocator.inputMethodAdapter(ctx), - ServiceLocator.packageManagerAdapter(ctx), - ), - FingerprintGesturesSupportedUseCaseImpl(ServiceLocator.settingsRepository(ctx)), - ) - - fun createActionShortcutViewModel( - ctx: Context, - ): CreateKeyMapShortcutViewModel.Factory = CreateKeyMapShortcutViewModel.Factory( - UseCases.configKeyMap(ctx), - ListKeyMapsUseCaseImpl( - ServiceLocator.roomKeyMapRepository(ctx), - ServiceLocator.groupRepository(ctx), - ServiceLocator.floatingButtonRepository(ctx), - ServiceLocator.fileAdapter(ctx), - ServiceLocator.backupManager(ctx), - ServiceLocator.resourceProvider(ctx), - UseCases.displayKeyMap(ctx), - ), - UseCases.createKeymapShortcut(ctx), - ServiceLocator.resourceProvider(ctx), - ) - - fun homeViewModel(ctx: Context): HomeViewModel.Factory = HomeViewModel.Factory( - ListKeyMapsUseCaseImpl( - ServiceLocator.roomKeyMapRepository(ctx), - ServiceLocator.groupRepository(ctx), - ServiceLocator.floatingButtonRepository(ctx), - ServiceLocator.fileAdapter(ctx), - ServiceLocator.backupManager(ctx), - ServiceLocator.resourceProvider(ctx), - UseCases.displayKeyMap(ctx), - ), - UseCases.pauseKeyMaps(ctx), - BackupRestoreMappingsUseCaseImpl( - ServiceLocator.fileAdapter(ctx), - ServiceLocator.backupManager(ctx), - ), - ShowHomeScreenAlertsUseCaseImpl( - ServiceLocator.settingsRepository(ctx), - ServiceLocator.permissionAdapter(ctx), - ServiceLocator.accessibilityServiceAdapter(ctx), - UseCases.pauseKeyMaps(ctx), - ), - UseCases.onboarding(ctx), - ServiceLocator.resourceProvider(ctx), - SetupGuiKeyboardUseCaseImpl( - ServiceLocator.inputMethodAdapter(ctx), - ServiceLocator.packageManagerAdapter(ctx), - ), - SortKeyMapsUseCaseImpl( - ServiceLocator.settingsRepository(ctx), - UseCases.displayKeyMap(ctx), - ), - UseCases.listFloatingLayouts(ctx), - ShowInputMethodPickerUseCaseImpl(ServiceLocator.inputMethodAdapter(ctx)), - ) - - fun settingsViewModel(context: Context): SettingsViewModel.Factory = SettingsViewModel.Factory( - ConfigSettingsUseCaseImpl( - ServiceLocator.settingsRepository(context), - ServiceLocator.permissionAdapter(context), - ServiceLocator.inputMethodAdapter(context), - ServiceLocator.soundsManager(context), - ServiceLocator.suAdapter(context), - ServiceLocator.packageManagerAdapter(context), - ServiceLocator.shizukuAdapter(context), - ServiceLocator.devicesAdapter(context), - ), - ServiceLocator.resourceProvider(context), - ) - - fun accessibilityServiceController( - service: MyAccessibilityService, - keyEventRelayService: KeyEventRelayServiceWrapper, - ): AccessibilityServiceController = AccessibilityServiceController( - coroutineScope = service.lifecycleScope, - accessibilityService = service, - inputEvents = ServiceLocator.accessibilityServiceAdapter(service).eventsToService, - outputEvents = ServiceLocator.accessibilityServiceAdapter(service).eventReceiver, - detectConstraintsUseCase = UseCases.detectConstraints(service), - performActionsUseCase = UseCases.performActions( - ctx = service, - service = service, - keyEventRelayService = keyEventRelayService, - ), - detectKeyMapsUseCase = UseCases.detectKeyMaps( - ctx = service, - service = service, - keyEventRelayService = keyEventRelayService, - ), - fingerprintGesturesSupportedUseCase = UseCases.fingerprintGesturesSupported(service), - pauseKeyMapsUseCase = UseCases.pauseKeyMaps(service), - devicesAdapter = ServiceLocator.devicesAdapter(service), - suAdapter = ServiceLocator.suAdapter(service), - rerouteKeyEventsUseCase = UseCases.rerouteKeyEvents( - ctx = service, - keyEventRelayService = keyEventRelayService, - ), - inputMethodAdapter = ServiceLocator.inputMethodAdapter(service), - settingsRepository = ServiceLocator.settingsRepository(service), - nodeRepository = ServiceLocator.accessibilityNodeRepository(service), - ) - - fun chooseBluetoothDeviceViewModel(ctx: Context): ChooseBluetoothDeviceViewModel.Factory = ChooseBluetoothDeviceViewModel.Factory( - ChooseBluetoothDeviceUseCaseImpl( - ServiceLocator.devicesAdapter(ctx), - ServiceLocator.permissionAdapter(ctx), - ), - ServiceLocator.resourceProvider(ctx), - ) - - fun logViewModel(ctx: Context): LogViewModel.Factory = LogViewModel.Factory( - DisplayLogUseCaseImpl( - ServiceLocator.logRepository(ctx), - ServiceLocator.resourceProvider(ctx), - ServiceLocator.clipboardAdapter(ctx), - ServiceLocator.fileAdapter(ctx), - ), - ServiceLocator.resourceProvider(ctx), - ) - - fun interactUiElementViewModel( - ctx: Context, - ): InteractUiElementViewModel.Factory = InteractUiElementViewModel.Factory( - (ctx.applicationContext as KeyMapperApp).interactUiElementController, - resourceProvider = ServiceLocator.resourceProvider(ctx), - ) -} diff --git a/app/src/main/java/io/github/sds100/keymapper/util/InputEventType.kt b/app/src/main/java/io/github/sds100/keymapper/util/InputEventType.kt deleted file mode 100644 index fb6769cffd..0000000000 --- a/app/src/main/java/io/github/sds100/keymapper/util/InputEventType.kt +++ /dev/null @@ -1,10 +0,0 @@ -package io.github.sds100.keymapper.util - -/** - * Created by sds100 on 28/07/20. - */ -enum class InputEventType { - DOWN_UP, - DOWN, - UP, -} diff --git a/app/src/main/java/io/github/sds100/keymapper/util/LoggingUtils.kt b/app/src/main/java/io/github/sds100/keymapper/util/LoggingUtils.kt deleted file mode 100644 index b5d0f02ef0..0000000000 --- a/app/src/main/java/io/github/sds100/keymapper/util/LoggingUtils.kt +++ /dev/null @@ -1,19 +0,0 @@ -package io.github.sds100.keymapper.util - -import timber.log.Timber -import kotlin.system.measureTimeMillis - -/** - * Created by sds100 on 19/01/21. - */ - -inline fun logMeasureTimeMillis(block: () -> T): T { - val result: T - val time = measureTimeMillis { - result = block.invoke() - } - - Timber.e("$time ms") - - return result -} diff --git a/app/src/main/java/io/github/sds100/keymapper/util/Result.kt b/app/src/main/java/io/github/sds100/keymapper/util/Result.kt deleted file mode 100644 index 8fe8251769..0000000000 --- a/app/src/main/java/io/github/sds100/keymapper/util/Result.kt +++ /dev/null @@ -1,225 +0,0 @@ -package io.github.sds100.keymapper.util - -import io.github.sds100.keymapper.R -import io.github.sds100.keymapper.purchasing.ProductId -import io.github.sds100.keymapper.system.inputmethod.ImeInfo -import io.github.sds100.keymapper.system.permissions.Permission -import io.github.sds100.keymapper.util.ui.ResourceProvider - -/** - * Created by sds100 on 26/02/2020. - */ - -/** - * Inspired from @antonyharfield great example! - */ - -sealed class Result - -data class Success(val value: T) : Result() - -sealed class Error : Result() { - data class Exception(val exception: java.lang.Exception) : Error() - data class SystemFeatureNotSupported(val feature: String) : Error() - data class ExtraNotFound(val extraId: String) : Error() - data class SdkVersionTooLow(val minSdk: Int) : Error() - data class SdkVersionTooHigh(val maxSdk: Int) : Error() - data class InputMethodNotFound(val imeLabel: String) : Error() - data object NoVoiceAssistant : Error() - data object NoDeviceAssistant : Error() - data object NoCameraApp : Error() - data object NoSettingsApp : Error() - data object FrontFlashNotFound : Error() - data object BackFlashNotFound : Error() - data class ImeDisabled(val ime: ImeInfo) : Error() - data class DeviceNotFound(val descriptor: String) : Error() - data object InvalidNumber : Error() - data class NumberTooBig(val max: Int) : Error() - data class NumberTooSmall(val min: Int) : Error() - data object EmptyText : Error() - data object NoIncompatibleKeyboardsInstalled : Error() - data object NoMediaSessions : Error() - data object BackupVersionTooNew : Error() - data object LauncherShortcutsNotSupported : Error() - - data class AppNotFound(val packageName: String) : Error() - data class AppDisabled(val packageName: String) : Error() - data object AppShortcutCantBeOpened : Error() - data object InsufficientPermissionsToOpenAppShortcut : Error() - data object NoCompatibleImeEnabled : Error() - data object NoCompatibleImeChosen : Error() - - data object AccessibilityServiceDisabled : Error() - data object AccessibilityServiceCrashed : Error() - - data object CantShowImePickerInBackground : Error() - data object CantFindImeSettings : Error() - data object GestureStrokeCountTooHigh : Error() - data object GestureDurationTooHigh : Error() - - data class PermissionDenied(val permission: Permission) : Error() { - companion object { - - fun getMessageForPermission( - resourceProvider: ResourceProvider, - permission: Permission, - ): String { - val resId = when (permission) { - Permission.WRITE_SETTINGS -> R.string.error_action_requires_write_settings_permission - Permission.CAMERA -> R.string.error_action_requires_camera_permission - Permission.DEVICE_ADMIN -> R.string.error_need_to_enable_device_admin - Permission.READ_PHONE_STATE -> R.string.error_action_requires_read_phone_state_permission - Permission.ACCESS_NOTIFICATION_POLICY -> R.string.error_action_notification_policy_permission - Permission.WRITE_SECURE_SETTINGS -> R.string.error_need_write_secure_settings_permission - Permission.NOTIFICATION_LISTENER -> R.string.error_denied_notification_listener_service_permission - Permission.CALL_PHONE -> R.string.error_denied_call_phone_permission - Permission.ROOT -> R.string.error_requires_root - Permission.IGNORE_BATTERY_OPTIMISATION -> R.string.error_battery_optimisation_enabled - Permission.SHIZUKU -> R.string.error_shizuku_permission_denied - Permission.ACCESS_FINE_LOCATION -> R.string.error_access_fine_location_permission_denied - Permission.ANSWER_PHONE_CALL -> R.string.error_answer_end_phone_call_permission_denied - Permission.FIND_NEARBY_DEVICES -> R.string.error_find_nearby_devices_permission_denied - Permission.POST_NOTIFICATIONS -> R.string.error_notifications_permission_denied - } - - return resourceProvider.getString(resId) - } - } - } - - data object FailedToFindAccessibilityNode : Error() - data class FailedToPerformAccessibilityGlobalAction(val action: Int) : Error() - data object FailedToDispatchGesture : Error() - - data object CameraInUse : Error() - data object CameraDisconnected : Error() - data object CameraDisabled : Error() - data object MaxCamerasInUse : Error() - data object CameraError : Error() - data object CameraVariableFlashlightStrengthUnsupported : Error() - - data class FailedToModifySystemSetting(val setting: String) : Error() - data object FailedToChangeIme : Error() - data object NoAppToOpenUrl : Error() - data object NoAppToPhoneCall : Error() - - data class NotAFile(val uri: String) : Error() - data class NotADirectory(val uri: String) : Error() - data object StoragePermissionDenied : Error() - data class CannotCreateFileInTarget(val uri: String) : Error() - data class SourceFileNotFound(val uri: String) : Error() - data class TargetFileNotFound(val uri: String) : Error() - data class TargetDirectoryNotFound(val uri: String) : Error() - data object UnknownIOError : Error() - data object FileOperationCancelled : Error() - data object TargetDirectoryMatchesSourceDirectory : Error() - data class NoSpaceLeftOnTarget(val uri: String) : Error() - data object NoFileName : Error() - data object InvalidBackup : Error() - - data object EmptyJson : Error() - data object CantFindSoundFile : Error() - data class CorruptJsonFile(val reason: String) : Error() - - data object ShizukuNotStarted : Error() - data object CantDetectKeyEventsInPhoneCall : Error() - - // This is returned from the PurchasingManager on FOSS builds that don't - // have the pro features implemented. - data object PurchasingNotImplemented : Error() - - data class ProductNotPurchased(val product: ProductId) : Error() - - sealed class PurchasingError : Error() { - data object ProductNotFound : PurchasingError() - data object Cancelled : PurchasingError() - data object StoreProblem : PurchasingError() - data object NetworkError : PurchasingError() - data object PaymentPending : PurchasingError() - data object PurchaseInvalid : PurchasingError() - data class Unexpected(val message: String) : PurchasingError() - } - - /** - * DPAD triggers require a Key Mapper keyboard to be selected. - */ - data object DpadTriggerImeNotSelected : Error() - data object MalformedUrl : Error() - - data object UiElementNotFound : Error() -} - -inline fun Result.onSuccess(f: (T) -> Unit): Result { - if (this is Success) { - f(this.value) - } - - return this -} - -inline fun Result.onFailure(f: (error: Error) -> U): Result { - if (this is Error) { - f(this) - } - - return this -} - -inline infix fun Result.then(f: (T) -> Result) = when (this) { - is Success -> f(this.value) - is Error -> this -} - -suspend infix fun Result.suspendThen(f: suspend (T) -> Result) = when (this) { - is Success -> f(this.value) - is Error -> this -} - -inline infix fun Result.otherwise(f: (error: Error) -> Result) = when (this) { - is Success -> this - is Error -> f(this) -} - -inline fun Result.resolve( - onSuccess: (value: T) -> U, - onFailure: (error: Error) -> U, -) = when (this) { - is Success -> onSuccess(this.value) - is Error -> onFailure(this) -} - -inline infix fun Result.valueIfFailure(f: (error: Error) -> T): T = when (this) { - is Success -> this.value - is Error -> f(this) -} - -fun Result.errorOrNull(): Error? { - when (this) { - is Error -> return this - else -> Unit - } - - return null -} - -fun Result.valueOrNull(): T? { - when (this) { - is Success -> return this.value - else -> Unit - } - - return null -} - -val Result.isError: Boolean - get() = this is Error - -val Result.isSuccess: Boolean - get() = this is Success - -fun Result.handle(onSuccess: (value: T) -> U, onError: (error: Error) -> U): U = when (this) { - is Success -> onSuccess(value) - is Error -> onError(this) -} - -fun T.success() = Success(this) diff --git a/app/src/main/java/io/github/sds100/keymapper/util/ServiceEvent.kt b/app/src/main/java/io/github/sds100/keymapper/util/ServiceEvent.kt deleted file mode 100644 index 2cbc56b280..0000000000 --- a/app/src/main/java/io/github/sds100/keymapper/util/ServiceEvent.kt +++ /dev/null @@ -1,85 +0,0 @@ -package io.github.sds100.keymapper.util - -import android.os.Parcelable -import io.github.sds100.keymapper.actions.ActionData -import io.github.sds100.keymapper.system.accessibility.RecordAccessibilityNodeState -import io.github.sds100.keymapper.system.devices.InputDeviceInfo -import io.github.sds100.keymapper.trigger.KeyEventDetectionSource -import kotlinx.parcelize.Parcelize -import kotlinx.serialization.Serializable - -@Serializable -sealed class ServiceEvent { - - @Serializable - data class Ping(val key: String) : ServiceEvent() - - @Serializable - data class Pong(val key: String) : ServiceEvent() - - @Parcelize - @Serializable - data class RecordedTriggerKey( - val keyCode: Int, - val device: InputDeviceInfo?, - val detectionSource: KeyEventDetectionSource, - ) : ServiceEvent(), - Parcelable - - @Serializable - object StartRecordingTrigger : ServiceEvent() - - @Serializable - object StopRecordingTrigger : ServiceEvent() - - @Serializable - data class OnIncrementRecordTriggerTimer(val timeLeft: Int) : ServiceEvent() - - @Serializable - object OnStoppedRecordingTrigger : ServiceEvent() - - @Serializable - object OnHideKeyboardEvent : ServiceEvent() - - @Serializable - object OnShowKeyboardEvent : ServiceEvent() - - @Serializable - object HideKeyboard : ServiceEvent() - - @Serializable - object ShowKeyboard : ServiceEvent() - - @Serializable - data class TestAction(val action: ActionData) : ServiceEvent() - - @Serializable - data class ChangeIme(val imeId: String) : ServiceEvent() - - @Serializable - object DisableService : ServiceEvent() - - @Serializable - object DismissLastNotification : ServiceEvent() - - @Serializable - object DismissAllNotifications : ServiceEvent() - - @Serializable - data class OnInputFocusChange(val isFocussed: Boolean) : ServiceEvent() - - @Serializable - data class TriggerKeyMap(val uid: String) : ServiceEvent() - - @Serializable - data class EnableInputMethod(val imeId: String) : ServiceEvent() - - @Serializable - data object StartRecordingNodes : ServiceEvent() - - @Serializable - data object StopRecordingNodes : ServiceEvent() - - @Serializable - data class OnRecordNodeStateChanged(val state: RecordAccessibilityNodeState) : ServiceEvent() -} diff --git a/app/src/main/java/io/github/sds100/keymapper/util/ui/ISearchable.kt b/app/src/main/java/io/github/sds100/keymapper/util/ui/ISearchable.kt deleted file mode 100644 index f74bcfac2b..0000000000 --- a/app/src/main/java/io/github/sds100/keymapper/util/ui/ISearchable.kt +++ /dev/null @@ -1,8 +0,0 @@ -package io.github.sds100.keymapper.util.ui - -/** - * Created by sds100 on 13/01/21. - */ -interface ISearchable { - fun getSearchableString(): String -} diff --git a/app/src/main/java/io/github/sds100/keymapper/util/ui/ListItem.kt b/app/src/main/java/io/github/sds100/keymapper/util/ui/ListItem.kt deleted file mode 100644 index 25ba907c59..0000000000 --- a/app/src/main/java/io/github/sds100/keymapper/util/ui/ListItem.kt +++ /dev/null @@ -1,5 +0,0 @@ -package io.github.sds100.keymapper.util.ui - -interface ListItem { - val id: String -} diff --git a/app/src/main/java/io/github/sds100/keymapper/util/ui/NavResult.kt b/app/src/main/java/io/github/sds100/keymapper/util/ui/NavResult.kt deleted file mode 100644 index f89f8efa7b..0000000000 --- a/app/src/main/java/io/github/sds100/keymapper/util/ui/NavResult.kt +++ /dev/null @@ -1,6 +0,0 @@ -package io.github.sds100.keymapper.util.ui - -/** - * Created by sds100 on 23/03/2021. - */ -data class NavResult(val key: String, val result: Any?) diff --git a/app/src/main/java/io/github/sds100/keymapper/util/ui/NavigateEvent.kt b/app/src/main/java/io/github/sds100/keymapper/util/ui/NavigateEvent.kt deleted file mode 100644 index 0f3d9f354f..0000000000 --- a/app/src/main/java/io/github/sds100/keymapper/util/ui/NavigateEvent.kt +++ /dev/null @@ -1,6 +0,0 @@ -package io.github.sds100.keymapper.util.ui - -/** - * Created by sds100 on 25/07/2021. - */ -data class NavigateEvent(val key: String, val destination: NavDestination<*>) diff --git a/app/src/main/java/io/github/sds100/keymapper/util/ui/NavigationViewModel.kt b/app/src/main/java/io/github/sds100/keymapper/util/ui/NavigationViewModel.kt deleted file mode 100644 index 510eb75792..0000000000 --- a/app/src/main/java/io/github/sds100/keymapper/util/ui/NavigationViewModel.kt +++ /dev/null @@ -1,340 +0,0 @@ -package io.github.sds100.keymapper.util.ui - -import android.os.Bundle -import androidx.core.os.bundleOf -import androidx.fragment.app.Fragment -import androidx.fragment.app.clearFragmentResultListener -import androidx.fragment.app.setFragmentResultListener -import androidx.lifecycle.lifecycleScope -import androidx.navigation.fragment.findNavController -import io.github.sds100.keymapper.NavAppDirections -import io.github.sds100.keymapper.actions.ActionData -import io.github.sds100.keymapper.actions.ChooseActionFragment -import io.github.sds100.keymapper.actions.keyevent.ChooseKeyCodeFragment -import io.github.sds100.keymapper.actions.keyevent.ConfigKeyEventActionFragment -import io.github.sds100.keymapper.actions.pinchscreen.PinchPickCoordinateResult -import io.github.sds100.keymapper.actions.pinchscreen.PinchPickDisplayCoordinateFragment -import io.github.sds100.keymapper.actions.sound.ChooseSoundFileFragment -import io.github.sds100.keymapper.actions.swipescreen.SwipePickCoordinateResult -import io.github.sds100.keymapper.actions.swipescreen.SwipePickDisplayCoordinateFragment -import io.github.sds100.keymapper.actions.tapscreen.PickCoordinateResult -import io.github.sds100.keymapper.actions.tapscreen.PickDisplayCoordinateFragment -import io.github.sds100.keymapper.actions.uielement.InteractUiElementFragment -import io.github.sds100.keymapper.constraints.ChooseConstraintFragment -import io.github.sds100.keymapper.constraints.Constraint -import io.github.sds100.keymapper.system.apps.ActivityInfo -import io.github.sds100.keymapper.system.apps.ChooseActivityFragment -import io.github.sds100.keymapper.system.apps.ChooseAppFragment -import io.github.sds100.keymapper.system.apps.ChooseAppShortcutFragment -import io.github.sds100.keymapper.system.apps.ChooseAppShortcutResult -import io.github.sds100.keymapper.system.bluetooth.BluetoothDeviceInfo -import io.github.sds100.keymapper.system.bluetooth.ChooseBluetoothDeviceFragment -import io.github.sds100.keymapper.system.intents.ConfigIntentFragment -import io.github.sds100.keymapper.system.intents.ConfigIntentResult -import io.github.sds100.keymapper.ui.utils.getJsonSerializable -import kotlinx.coroutines.flow.MutableSharedFlow -import kotlinx.coroutines.flow.SharedFlow -import kotlinx.coroutines.flow.asSharedFlow -import kotlinx.coroutines.flow.dropWhile -import kotlinx.coroutines.flow.first -import kotlinx.coroutines.flow.launchIn -import kotlinx.coroutines.flow.map -import kotlinx.coroutines.flow.merge -import kotlinx.coroutines.flow.onEach -import kotlinx.coroutines.runBlocking -import kotlinx.serialization.json.Json - -/** - * Created by sds100 on 25/07/2021. - */ - -class NavigationViewModelImpl : NavigationViewModel { - private val _onNavResult by lazy { MutableSharedFlow() } - override val onNavResult by lazy { _onNavResult.asSharedFlow() } - - private val _navigate = MutableSharedFlow() - override val navigate = _navigate.asSharedFlow() - - override suspend fun navigate(event: NavigateEvent) { - // wait for the view to collect so navigating can happen - _navigate.subscriptionCount.first { it > 0 } - - _navigate.emit(event) - } - - override fun onNavResult(result: NavResult) { - runBlocking { _onNavResult.emit(result) } - } -} - -interface NavigationViewModel { - val navigate: SharedFlow - val onNavResult: SharedFlow - - fun onNavResult(result: NavResult) - suspend fun navigate(event: NavigateEvent) -} - -suspend inline fun NavigationViewModel.navigate( - key: String, - destination: NavDestination, -): R? { - navigate(NavigateEvent(key, destination)) - - /* - This ensures only one job for a dialog is active at once by cancelling previous jobs when a new - dialog is shown with the same key - */ - return merge( - navigate.dropWhile { it.key != key }.map { null }, - onNavResult.dropWhile { it.result !is R? && it.key != key }.map { it.result }, - ).first() as R? -} - -/** - * Must call in fragment's onCreate - */ -fun NavigationViewModel.setupNavigation(fragment: Fragment) { - val navigationSavedStateKey = "navigation:${this.javaClass.name}" - - val pendingResultsKeysExtra = "pending_results_keys" - val pendingResultsDestinationsExtra = "pending_results_destinations" - - /** - * Maps request keys to their destination. - */ - val pendingResults = mutableMapOf() - - fragment.savedStateRegistry.registerSavedStateProvider(navigationSavedStateKey) { - bundleOf( - pendingResultsKeysExtra to pendingResults.keys.toTypedArray(), - pendingResultsDestinationsExtra to pendingResults.values.toTypedArray(), - ) - } - - fragment.savedStateRegistry.consumeRestoredStateForKey(navigationSavedStateKey) - ?.let { bundle -> - val oldPendingResultsKeys: Array = - bundle.getStringArray(pendingResultsKeysExtra)!! - - val oldPendingResultsDestinations: Array = - bundle.getStringArray(pendingResultsDestinationsExtra)!! - - oldPendingResultsKeys.forEachIndexed { i, requestKey -> - val destination = oldPendingResultsDestinations[i] - - pendingResults[requestKey] = destination - - fragment.setFragmentResultListener(requestKey) { _, bundle -> - sendNavResultFromBundle(requestKey, destination, bundle) - } - } - } - - navigate.onEach { event -> - val (requestKey, destination) = event - - pendingResults[requestKey] = destination.id - - fragment.clearFragmentResultListener(requestKey) - - fragment.setFragmentResultListener(requestKey) { _, bundle -> - pendingResults.remove(event.key) - sendNavResultFromBundle(event.key, event.destination.id, bundle) - } - - val direction = when (destination) { - is NavDestination.ChooseApp -> NavAppDirections.chooseApp( - destination.allowHiddenApps, - requestKey, - ) - - NavDestination.ChooseAppShortcut -> NavAppDirections.chooseAppShortcut(requestKey) - NavDestination.ChooseKeyCode -> NavAppDirections.chooseKeyCode(requestKey) - is NavDestination.ConfigKeyEventAction -> { - val json = destination.action?.let { - Json.encodeToString(it) - } - - NavAppDirections.configKeyEvent(requestKey, json) - } - - is NavDestination.PickCoordinate -> { - val json = destination.result?.let { - Json.encodeToString(it) - } - - NavAppDirections.pickDisplayCoordinate(requestKey, json) - } - - is NavDestination.PickSwipeCoordinate -> { - val json = destination.result?.let { - Json.encodeToString(it) - } - - NavAppDirections.swipePickDisplayCoordinate(requestKey, json) - } - - is NavDestination.PickPinchCoordinate -> { - val json = destination.result?.let { - Json.encodeToString(it) - } - - NavAppDirections.pinchPickDisplayCoordinate(requestKey, json) - } - - is NavDestination.ConfigIntent -> { - val json = destination.result?.let { - Json.encodeToString(it) - } - - NavAppDirections.configIntent(requestKey, json) - } - - is NavDestination.ChooseActivity -> NavAppDirections.chooseActivity(requestKey) - is NavDestination.ChooseSound -> NavAppDirections.chooseSoundFile(requestKey) - NavDestination.ChooseAction -> NavAppDirections.toChooseActionFragment(requestKey) - is NavDestination.ChooseConstraint -> NavAppDirections.chooseConstraint( - requestKey = requestKey, - ) - - is NavDestination.ChooseBluetoothDevice -> NavAppDirections.chooseBluetoothDevice( - requestKey, - ) - - NavDestination.About -> NavAppDirections.actionGlobalAboutFragment() - NavDestination.Settings -> NavAppDirections.toSettingsFragment() - - is NavDestination.ConfigKeyMap -> when (destination) { - is NavDestination.ConfigKeyMap.New -> - NavAppDirections.actionToConfigKeymap( - groupUid = destination.groupUid, - showAdvancedTriggers = destination.showAdvancedTriggers, - ) - - is NavDestination.ConfigKeyMap.Open -> - NavAppDirections.actionToConfigKeymap( - keyMapUid = destination.keyMapUid, - showAdvancedTriggers = destination.showAdvancedTriggers, - ) - } - - is NavDestination.ChooseFloatingLayout -> NavAppDirections.toChooseFloatingLayoutFragment() - NavDestination.ShizukuSettings -> NavAppDirections.toShizukuSettingsFragment() - is NavDestination.ConfigFloatingButton -> NavAppDirections.toConfigFloatingButton( - destination.buttonUid, - ) - - is NavDestination.InteractUiElement -> NavAppDirections.interactUiElement( - requestKey = requestKey, - action = destination.action?.let { Json.encodeToString(destination.action) }, - ) - } - - fragment.findNavController().navigate(direction) - }.launchIn(fragment.lifecycleScope) -} - -fun NavigationViewModel.sendNavResultFromBundle( - requestKey: String, - destinationId: String, - bundle: Bundle, -) { - when (destinationId) { - NavDestination.ID_CHOOSE_APP -> { - val packageName = bundle.getString(ChooseAppFragment.EXTRA_PACKAGE_NAME) - - onNavResult(NavResult(requestKey, packageName!!)) - } - - NavDestination.ID_CHOOSE_APP_SHORTCUT -> { - val result = bundle.getJsonSerializable( - ChooseAppShortcutFragment.EXTRA_RESULT, - ) - - onNavResult(NavResult(requestKey, result)) - } - - NavDestination.ID_KEY_CODE -> { - val keyCode = bundle.getInt(ChooseKeyCodeFragment.EXTRA_KEYCODE) - - onNavResult(NavResult(requestKey, keyCode)) - } - - NavDestination.ID_KEY_EVENT -> { - val json = bundle.getString(ConfigKeyEventActionFragment.EXTRA_RESULT)!! - val keyEventAction = Json.decodeFromString(json) - - onNavResult(NavResult(requestKey, keyEventAction)) - } - - NavDestination.ID_PICK_COORDINATE -> { - val json = bundle.getString(PickDisplayCoordinateFragment.EXTRA_RESULT)!! - val result = Json.decodeFromString(json) - - onNavResult(NavResult(requestKey, result)) - } - - NavDestination.ID_PICK_SWIPE_COORDINATE -> { - val json = bundle.getString(SwipePickDisplayCoordinateFragment.EXTRA_RESULT)!! - val result = Json.decodeFromString(json) - - onNavResult(NavResult(requestKey, result)) - } - - NavDestination.ID_PICK_PINCH_COORDINATE -> { - val json = bundle.getString(PinchPickDisplayCoordinateFragment.EXTRA_RESULT)!! - val result = Json.decodeFromString(json) - - onNavResult(NavResult(requestKey, result)) - } - - NavDestination.ID_CONFIG_INTENT -> { - val json = bundle.getString(ConfigIntentFragment.EXTRA_RESULT)!! - val result = Json.decodeFromString(json) - - onNavResult(NavResult(requestKey, result)) - } - - NavDestination.ID_CHOOSE_ACTIVITY -> { - val json = bundle.getString(ChooseActivityFragment.EXTRA_RESULT)!! - val result = Json.decodeFromString(json) - - onNavResult(NavResult(requestKey, result)) - } - - NavDestination.ID_CHOOSE_SOUND -> { - val json = bundle.getString(ChooseSoundFileFragment.EXTRA_RESULT)!! - val result = Json.decodeFromString(json) - - onNavResult(NavResult(requestKey, result)) - } - - NavDestination.ID_CHOOSE_ACTION -> { - val json = bundle.getString(ChooseActionFragment.EXTRA_ACTION)!! - val action = Json.decodeFromString(json) - - onNavResult(NavResult(requestKey, action)) - } - - NavDestination.ID_CHOOSE_CONSTRAINT -> { - val json = bundle.getString(ChooseConstraintFragment.EXTRA_CONSTRAINT)!! - val constraint = Json.decodeFromString(json) - - onNavResult(NavResult(requestKey, constraint)) - } - - NavDestination.ID_CHOOSE_BLUETOOTH_DEVICE -> { - val address = bundle.getString(ChooseBluetoothDeviceFragment.EXTRA_ADDRESS)!! - val name = bundle.getString(ChooseBluetoothDeviceFragment.EXTRA_NAME)!! - - onNavResult(NavResult(requestKey, BluetoothDeviceInfo(address, name))) - } - - NavDestination.ID_INTERACT_UI_ELEMENT_ACTION -> { - val json = bundle.getString(InteractUiElementFragment.EXTRA_ACTION)!! - val result = Json.decodeFromString(json) - onNavResult(NavResult(requestKey, result)) - } - } -} diff --git a/app/src/main/java/io/github/sds100/keymapper/util/ui/OnPopupResponseEvent.kt b/app/src/main/java/io/github/sds100/keymapper/util/ui/OnPopupResponseEvent.kt deleted file mode 100644 index bcf274a7d4..0000000000 --- a/app/src/main/java/io/github/sds100/keymapper/util/ui/OnPopupResponseEvent.kt +++ /dev/null @@ -1,6 +0,0 @@ -package io.github.sds100.keymapper.util.ui - -/** - * Created by sds100 on 23/03/2021. - */ -data class OnPopupResponseEvent(val key: String, val response: Any?) diff --git a/app/src/main/java/io/github/sds100/keymapper/util/ui/ShowPopupEvent.kt b/app/src/main/java/io/github/sds100/keymapper/util/ui/ShowPopupEvent.kt deleted file mode 100644 index fdf17c5ce7..0000000000 --- a/app/src/main/java/io/github/sds100/keymapper/util/ui/ShowPopupEvent.kt +++ /dev/null @@ -1,6 +0,0 @@ -package io.github.sds100.keymapper.util.ui - -/** - * Created by sds100 on 23/03/2021. - */ -data class ShowPopupEvent(val key: String, val ui: PopupUi<*>) diff --git a/app/src/main/java/io/github/sds100/keymapper/util/ui/SnackBarUtils.kt b/app/src/main/java/io/github/sds100/keymapper/util/ui/SnackBarUtils.kt deleted file mode 100644 index c7e283e2a5..0000000000 --- a/app/src/main/java/io/github/sds100/keymapper/util/ui/SnackBarUtils.kt +++ /dev/null @@ -1,62 +0,0 @@ -package io.github.sds100.keymapper.util.ui - -import androidx.coordinatorlayout.widget.CoordinatorLayout -import io.github.sds100.keymapper.R -import kotlinx.coroutines.suspendCancellableCoroutine -import splitties.snackbar.action -import splitties.snackbar.longSnack -import splitties.snackbar.onDismiss -import splitties.snackbar.snack -import kotlin.coroutines.resume - -/** - * Created by sds100 on 06/04/2021. - */ -object SnackBarUtils { - - suspend fun show( - view: CoordinatorLayout, - text: String, - actionText: String? = null, - long: Boolean = false, - ) = - suspendCancellableCoroutine { continuation -> - - val snackBar = if (long) { - view.longSnack(text) { - if (actionText != null) { - action(actionText) { - if (!continuation.isCompleted) { - continuation.resume(Unit) - } - } - } - - anchorView = view.findViewById(R.id.fab) - } - } else { - view.snack(text) { - if (actionText != null) { - action(actionText) { - if (!continuation.isCompleted) { - continuation.resume(Unit) - } - } - } - - anchorView = view.findViewById(R.id.fab) - } - } - - // if there is no action then there is no point waiting for a user response - if (actionText == null) { - continuation.resume(null) - } - - snackBar.onDismiss { - if (!continuation.isCompleted) { - continuation.resume(null) - } - } - } -} diff --git a/app/src/main/java/io/github/sds100/keymapper/util/ui/compose/icons/KeyMapperIcons.kt b/app/src/main/java/io/github/sds100/keymapper/util/ui/compose/icons/KeyMapperIcons.kt deleted file mode 100644 index 343b292720..0000000000 --- a/app/src/main/java/io/github/sds100/keymapper/util/ui/compose/icons/KeyMapperIcons.kt +++ /dev/null @@ -1,3 +0,0 @@ -package io.github.sds100.keymapper.util.ui.compose.icons - -object KeyMapperIcons diff --git a/app/src/main/res/menu/menu_config_mapping.xml b/app/src/main/res/menu/menu_config_mapping.xml deleted file mode 100644 index f1dce6e2aa..0000000000 --- a/app/src/main/res/menu/menu_config_mapping.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/navigation/nav_config_keymap.xml b/app/src/main/res/navigation/nav_config_keymap.xml deleted file mode 100644 index 4ea4136136..0000000000 --- a/app/src/main/res/navigation/nav_config_keymap.xml +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/values-ar/strings.xml b/app/src/main/res/values-ar/strings.xml deleted file mode 100644 index 1d669e715e..0000000000 --- a/app/src/main/res/values-ar/strings.xml +++ /dev/null @@ -1,74 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/values-cs/strings.xml b/app/src/main/res/values-cs/strings.xml deleted file mode 100644 index 1d669e715e..0000000000 --- a/app/src/main/res/values-cs/strings.xml +++ /dev/null @@ -1,74 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml deleted file mode 100644 index 1d669e715e..0000000000 --- a/app/src/main/res/values-de/strings.xml +++ /dev/null @@ -1,74 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml deleted file mode 100644 index 1d669e715e..0000000000 --- a/app/src/main/res/values-es/strings.xml +++ /dev/null @@ -1,74 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml deleted file mode 100644 index 1d669e715e..0000000000 --- a/app/src/main/res/values-fr/strings.xml +++ /dev/null @@ -1,74 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/values-hu/strings.xml b/app/src/main/res/values-hu/strings.xml deleted file mode 100644 index 96247417f6..0000000000 --- a/app/src/main/res/values-hu/strings.xml +++ /dev/null @@ -1,75 +0,0 @@ - - - Engedd el a kulcsokat! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/values-id/strings.xml b/app/src/main/res/values-id/strings.xml deleted file mode 100644 index 1d669e715e..0000000000 --- a/app/src/main/res/values-id/strings.xml +++ /dev/null @@ -1,74 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/values-ka/strings.xml b/app/src/main/res/values-ka/strings.xml deleted file mode 100644 index 1d669e715e..0000000000 --- a/app/src/main/res/values-ka/strings.xml +++ /dev/null @@ -1,74 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml deleted file mode 100644 index 1d669e715e..0000000000 --- a/app/src/main/res/values-ko/strings.xml +++ /dev/null @@ -1,74 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml deleted file mode 100644 index 1d669e715e..0000000000 --- a/app/src/main/res/values-pl/strings.xml +++ /dev/null @@ -1,74 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/values-pt/strings.xml b/app/src/main/res/values-pt/strings.xml deleted file mode 100644 index 1d669e715e..0000000000 --- a/app/src/main/res/values-pt/strings.xml +++ /dev/null @@ -1,74 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml deleted file mode 100644 index 1d669e715e..0000000000 --- a/app/src/main/res/values-ru/strings.xml +++ /dev/null @@ -1,74 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/values-sk/strings.xml b/app/src/main/res/values-sk/strings.xml deleted file mode 100644 index 1d669e715e..0000000000 --- a/app/src/main/res/values-sk/strings.xml +++ /dev/null @@ -1,74 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml deleted file mode 100644 index 1d669e715e..0000000000 --- a/app/src/main/res/values-uk/strings.xml +++ /dev/null @@ -1,74 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/values-vi/strings.xml b/app/src/main/res/values-vi/strings.xml deleted file mode 100644 index 1d669e715e..0000000000 --- a/app/src/main/res/values-vi/strings.xml +++ /dev/null @@ -1,74 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml deleted file mode 100644 index 1d669e715e..0000000000 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ /dev/null @@ -1,74 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml deleted file mode 100644 index 1d669e715e..0000000000 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ /dev/null @@ -1,74 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/src/test/java/io/github/sds100/keymapper/util/JsonTestUtils.kt b/app/src/test/java/io/github/sds100/keymapper/util/JsonTestUtils.kt deleted file mode 100644 index 71e2d52856..0000000000 --- a/app/src/test/java/io/github/sds100/keymapper/util/JsonTestUtils.kt +++ /dev/null @@ -1,88 +0,0 @@ -package io.github.sds100.keymapper.util - -import com.github.salomonbrys.kotson.contains -import com.github.salomonbrys.kotson.forEach -import com.github.salomonbrys.kotson.get -import com.google.gson.JsonArray -import com.google.gson.JsonElement -import com.google.gson.JsonObject -import com.google.gson.JsonPrimitive -import org.hamcrest.MatcherAssert.assertThat -import org.hamcrest.core.Is.`is` -import org.junit.Assert - -/** - * Created by sds100 on 25/01/21. - */ -object JsonTestUtils { - private const val NAME_SEPARATOR = '/' - - fun compareBothWays(element: JsonElement, elementName: String, other: JsonElement, otherName: String) { - compare("", element, elementName, other, otherName) - compare("", other, elementName, element, elementName) - } - - private fun compare(parentNamePath: String = "", element: JsonElement, elementName: String, rootToCompare: JsonElement, rootName: String) { - when (element) { - is JsonObject -> { - element.forEach { name, jsonElement -> - val newPath = if (parentNamePath.isBlank()) { - name - } else { - "$parentNamePath$NAME_SEPARATOR$name" - } - - compare(newPath, jsonElement, elementName, rootToCompare, rootName) - } - } - - is JsonArray -> { - val pathToArrayToCompare = parentNamePath.split(NAME_SEPARATOR) - var arrayToCompare: JsonArray? = null - - var parentElement: JsonElement = rootToCompare - pathToArrayToCompare.forEach { - if (it == "") return@forEach - - parentElement = parentElement[it] - } - - if (parentElement is JsonArray) { - arrayToCompare = parentElement as JsonArray - } - - Assert.assertNotNull("can't find array $elementName/$parentNamePath in $rootName", arrayToCompare) - arrayToCompare ?: return - - element.forEachIndexed { index, arrayElement -> - val validIndex = index <= arrayToCompare.toList().lastIndex - - assertThat("$rootName/${pathToArrayToCompare.last()} doesn't contain $arrayElement at $index index", validIndex) - - compare("", arrayElement, "$elementName/${pathToArrayToCompare.last()}", arrayToCompare[index]!!, "$rootName/${pathToArrayToCompare.last()}") - } - } - - is JsonPrimitive -> { - val names = parentNamePath.split(NAME_SEPARATOR) - var parentElement: JsonElement = rootToCompare - - if (names == listOf("")) { - assertThat("$elementName/:$element doesn't match $rootName/:$parentElement", (parentElement), `is`(element)) - } else { - names.forEachIndexed { index, name -> - if (parentElement is JsonObject) { - assertThat("$elementName/$parentNamePath not found in $rootName", (parentElement as JsonObject).contains(name)) - } - - parentElement = parentElement[name] - - if (index == names.lastIndex) { - assertThat("$elementName/$parentNamePath:$element doesn't match $rootName/$parentNamePath:$parentElement", (parentElement as JsonPrimitive), `is`(element)) - } - } - } - } - } - } -} diff --git a/app/version.properties b/app/version.properties index 9702277f1d..67a33d0fe4 100644 --- a/app/version.properties +++ b/app/version.properties @@ -1,3 +1,3 @@ -VERSION_NAME=3.1.2 +VERSION_NAME=3.2.0 VERSION_CODE=122 VERSION_NUM=0 \ No newline at end of file diff --git a/base/.gitignore b/base/.gitignore new file mode 100644 index 0000000000..42afabfd2a --- /dev/null +++ b/base/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/base/build.gradle.kts b/base/build.gradle.kts new file mode 100644 index 0000000000..7464caa89b --- /dev/null +++ b/base/build.gradle.kts @@ -0,0 +1,154 @@ +import java.util.Properties + +plugins { + alias(libs.plugins.android.library) + alias(libs.plugins.kotlin.android) + alias(libs.plugins.kotlin.compose) + alias(libs.plugins.kotlin.kapt) + alias(libs.plugins.kotlin.serialization) + alias(libs.plugins.kotlin.parcelize) + alias(libs.plugins.androidx.navigation.safeargs.kotlin) + alias(libs.plugins.google.devtools.ksp) + alias(libs.plugins.jlleitschuh.gradle.ktlint) + alias(libs.plugins.dagger.hilt.android) +} + +android { + namespace = "io.github.sds100.keymapper.base" + compileSdk = libs.versions.compile.sdk.get().toInt() + + val versionProperties = Properties().apply { + project.file("../app/version.properties").inputStream().use { load(it) } + } + + defaultConfig { + minSdk = libs.versions.min.sdk.get().toInt() + + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + consumerProguardFiles("consumer-rules.pro") + + buildConfigField( + "Integer", + "VERSION_CODE", + versionProperties.getProperty("VERSION_CODE"), + ) + } + + buildTypes { + release { + isMinifyEnabled = true + proguardFiles( + getDefaultProguardFile("proguard-android-optimize.txt"), + "proguard-rules.pro", + ) + } + } + + buildFeatures { + dataBinding = true + viewBinding = true + aidl = true + buildConfig = true + compose = true + } + + compileOptions { + isCoreLibraryDesugaringEnabled = true + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 + } + + kotlinOptions { + jvmTarget = "11" + } + + kapt { + correctErrorTypes = true + } + + composeOptions { + kotlinCompilerExtensionVersion = libs.versions.compose.compiler.get() + } +} + +dependencies { + implementation(project(":common")) + implementation(project(":data")) + implementation(project(":system")) + implementation(project(":systemstubs")) + + // kotlin stuff + implementation(libs.kotlinx.coroutines.android) + implementation(libs.kotlinx.serialization.json) + + // random stuff + implementation(libs.google.android.material) + implementation(libs.kotson) + implementation(libs.airbnb.epoxy) + implementation(libs.airbnb.epoxy.databinding) + debugImplementation(libs.androidx.ui.tooling) + kapt(libs.airbnb.epoxy.processor) + implementation(libs.jakewharton.timber) + implementation(libs.anggrayudi.storage) + implementation(libs.github.mflisar.dragselectrecyclerview) + implementation(libs.google.flexbox) + implementation(libs.squareup.okhttp) + coreLibraryDesugaring(libs.desugar.jdk.libs) + implementation(libs.canopas.introshowcaseview) + implementation(libs.dagger.hilt.android) + ksp(libs.dagger.hilt.android.compiler) + implementation(libs.bundles.splitties) + + // androidx + implementation(libs.androidx.legacy.support.core.ui) + implementation(libs.androidx.core.ktx) + implementation(libs.androidx.activity.ktx) + implementation(libs.androidx.fragment.ktx) + implementation(libs.bundles.androidx.lifecycle) + implementation(libs.bundles.androidx.navigation) + implementation(libs.androidx.multidex) + implementation(libs.androidx.appcompat) + implementation(libs.androidx.recyclerview) + implementation(libs.androidx.preference.ktx) + implementation(libs.androidx.constraintlayout) + implementation(libs.androidx.lifecycle.extensions) // Note: Deprecated + implementation(libs.androidx.viewpager2) + implementation(libs.androidx.datastore.preferences) + implementation(libs.androidx.core.splashscreen) + implementation(libs.androidx.hilt.navigation.compose) + + // Compose + implementation(platform(libs.androidx.compose.bom)) + implementation(libs.androidx.compose.foundation) + implementation(libs.androidx.compose.ui.android) + implementation(libs.androidx.compose.material3) + implementation(libs.androidx.compose.ui.tooling.preview) + implementation(libs.androidx.compose.material.icons.extended) + implementation(libs.androidx.compose.material3.adaptive) + implementation(libs.androidx.compose.material3.adaptive.navigation) + implementation(libs.google.accompanist.drawablepainter) + implementation(libs.androidx.compose.ui.tooling) + + // Tests + + testImplementation(libs.junit) + testImplementation(libs.hamcrest.all) + testImplementation(libs.androidx.junit.ktx) // androidx.test.ext:junit-ktx + testImplementation(libs.androidx.test.core.ktx) + testImplementation(libs.androidx.test.core) + testImplementation(libs.robolectric) + testImplementation(libs.androidx.arch.core.testing) + testImplementation(libs.kotlinx.coroutines.test) + testImplementation(libs.junit.params) + testImplementation(libs.mockito.kotlin) + testImplementation(libs.mockito.core) + testImplementation(libs.mockito.inline) + testDebugImplementation(libs.androidx.fragment.testing) + + // Dependencies for Android instrumented tests + androidTestImplementation(libs.androidx.test.ext.junit) // androidx.test.ext:junit + androidTestImplementation(libs.junit) // Repeated, fine + androidTestImplementation(libs.androidx.navigation.testing) + androidTestImplementation(libs.androidx.room.testing.legacy) + androidTestImplementation(libs.mockito.android) +} diff --git a/app/src/test/resources/backup-manager-test/restore-all.zip/sounds/sound.ogg b/base/consumer-rules.pro similarity index 100% rename from app/src/test/resources/backup-manager-test/restore-all.zip/sounds/sound.ogg rename to base/consumer-rules.pro diff --git a/base/proguard-rules.pro b/base/proguard-rules.pro new file mode 100644 index 0000000000..e69de29bb2 diff --git a/base/src/main/AndroidManifest.xml b/base/src/main/AndroidManifest.xml new file mode 100644 index 0000000000..bf276a36b2 --- /dev/null +++ b/base/src/main/AndroidManifest.xml @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/assets/whats-new.txt b/base/src/main/assets/whats-new.txt similarity index 100% rename from app/src/main/assets/whats-new.txt rename to base/src/main/assets/whats-new.txt diff --git a/base/src/main/java/io/github/sds100/keymapper/base/ActivityViewModel.kt b/base/src/main/java/io/github/sds100/keymapper/base/ActivityViewModel.kt new file mode 100644 index 0000000000..a8b48bb2b9 --- /dev/null +++ b/base/src/main/java/io/github/sds100/keymapper/base/ActivityViewModel.kt @@ -0,0 +1,34 @@ +package io.github.sds100.keymapper.base + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import dagger.hilt.android.lifecycle.HiltViewModel +import io.github.sds100.keymapper.base.utils.navigation.NavigationProvider +import io.github.sds100.keymapper.base.utils.navigation.NavigationProviderImpl +import io.github.sds100.keymapper.base.utils.ui.DialogProvider +import io.github.sds100.keymapper.base.utils.ui.ResourceProvider +import io.github.sds100.keymapper.base.utils.ui.ViewModelHelper +import kotlinx.coroutines.launch +import javax.inject.Inject + +@HiltViewModel +class ActivityViewModel @Inject constructor( + resourceProvider: ResourceProvider, + dialogProvider: DialogProvider, +) : ViewModel(), + ResourceProvider by resourceProvider, + DialogProvider by dialogProvider, + NavigationProvider by NavigationProviderImpl() { + + var handledActivityLaunchIntent: Boolean = false + var previousNightMode: Int? = null + + fun onCantFindAccessibilitySettings() { + viewModelScope.launch { + ViewModelHelper.handleCantFindAccessibilitySettings( + resourceProvider = this@ActivityViewModel, + dialogProvider = this@ActivityViewModel, + ) + } + } +} diff --git a/base/src/main/java/io/github/sds100/keymapper/base/BaseKeyMapperApp.kt b/base/src/main/java/io/github/sds100/keymapper/base/BaseKeyMapperApp.kt new file mode 100644 index 0000000000..62d85ba466 --- /dev/null +++ b/base/src/main/java/io/github/sds100/keymapper/base/BaseKeyMapperApp.kt @@ -0,0 +1,190 @@ +package io.github.sds100.keymapper.base + +import android.annotation.SuppressLint +import android.content.Intent +import android.os.Build +import android.os.UserManager +import android.util.Log +import android.widget.Toast +import androidx.appcompat.app.AppCompatDelegate +import androidx.core.content.getSystemService +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.LifecycleObserver +import androidx.lifecycle.OnLifecycleEvent +import androidx.lifecycle.ProcessLifecycleOwner +import androidx.multidex.MultiDexApplication +import io.github.sds100.keymapper.base.logging.KeyMapperLoggingTree +import io.github.sds100.keymapper.base.settings.ThemeUtils +import io.github.sds100.keymapper.base.system.accessibility.AccessibilityServiceAdapterImpl +import io.github.sds100.keymapper.base.system.inputmethod.AutoSwitchImeController +import io.github.sds100.keymapper.base.system.notifications.NotificationController +import io.github.sds100.keymapper.base.system.permissions.AutoGrantPermissionController +import io.github.sds100.keymapper.data.Keys +import io.github.sds100.keymapper.data.entities.LogEntryEntity +import io.github.sds100.keymapper.data.repositories.LogRepository +import io.github.sds100.keymapper.data.repositories.SettingsPreferenceRepository +import io.github.sds100.keymapper.system.apps.AndroidPackageManagerAdapter +import io.github.sds100.keymapper.system.devices.AndroidDevicesAdapter +import io.github.sds100.keymapper.system.permissions.AndroidPermissionAdapter +import io.github.sds100.keymapper.system.permissions.Permission +import io.github.sds100.keymapper.system.root.SuAdapterImpl +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.collectLatest +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.launch +import kotlinx.coroutines.runBlocking +import timber.log.Timber +import java.util.Calendar +import javax.inject.Inject + +@SuppressLint("LogNotTimber") +abstract class BaseKeyMapperApp : MultiDexApplication() { + private val tag = BaseKeyMapperApp::class.simpleName + + @Inject + lateinit var appCoroutineScope: CoroutineScope + + @Inject + lateinit var notificationController: NotificationController + + @Inject + lateinit var autoSwitchImeController: AutoSwitchImeController + + @Inject + lateinit var packageManagerAdapter: AndroidPackageManagerAdapter + + @Inject + lateinit var devicesAdapter: AndroidDevicesAdapter + + @Inject + lateinit var permissionAdapter: AndroidPermissionAdapter + + @Inject + lateinit var accessibilityServiceAdapter: AccessibilityServiceAdapterImpl + + @Inject + lateinit var suAdapter: SuAdapterImpl + + @Inject + lateinit var autoGrantPermissionController: AutoGrantPermissionController + + @Inject + lateinit var loggingTree: KeyMapperLoggingTree + + @Inject + lateinit var settingsRepository: SettingsPreferenceRepository + + @Inject + lateinit var logRepository: LogRepository + + private val processLifecycleOwner by lazy { ProcessLifecycleOwner.get() } + + private val userManager: UserManager? by lazy { getSystemService() } + + private val initLock: Any = Any() + private var initialized = false + + override fun onCreate() { + val priorExceptionHandler = Thread.getDefaultUncaughtExceptionHandler() + + Log.i(tag, "KeyMapperApp: OnCreate") + + Thread.setDefaultUncaughtExceptionHandler { thread, exception -> + // log in a blocking manner and always log regardless of whether the setting is turned on + val entry = LogEntryEntity( + id = 0, + time = Calendar.getInstance().timeInMillis, + severity = LogEntryEntity.SEVERITY_ERROR, + message = exception.stackTraceToString(), + ) + + runBlocking { + logRepository.insertSuspend(entry) + } + + priorExceptionHandler?.uncaughtException(thread, exception) + } + + super.onCreate() + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && userManager?.isUserUnlocked == false) { + Log.i(tag, "KeyMapperApp: Delay init because locked.") + // If the device is still encrypted and locked do not initialize anything that + // may potentially need the encrypted app storage like databases. + return + } + + synchronized(initLock) { + init() + initialized = true + } + } + + fun onBootUnlocked() { + synchronized(initLock) { + if (!initialized) { + init() + } + initialized = true + } + } + + private fun init() { + Log.i(tag, "KeyMapperApp: Init") + + settingsRepository.get(Keys.darkTheme) + .map { it?.toIntOrNull() } + .map { + when (it) { + ThemeUtils.DARK -> AppCompatDelegate.MODE_NIGHT_YES + ThemeUtils.LIGHT -> AppCompatDelegate.MODE_NIGHT_NO + else -> AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM + } + } + .onEach { mode -> AppCompatDelegate.setDefaultNightMode(mode) } + .launchIn(appCoroutineScope) + + if (BuildConfig.BUILD_TYPE == "debug" || BuildConfig.BUILD_TYPE == "debug_release") { + Timber.plant(Timber.DebugTree()) + } + + Timber.plant(loggingTree) + + notificationController.init() + + autoSwitchImeController.init() + + processLifecycleOwner.lifecycle.addObserver(object : LifecycleObserver { + @OnLifecycleEvent(Lifecycle.Event.ON_RESUME) + fun onResume() { + // when the user returns to the app let everything know that the permissions could have changed + notificationController.onOpenApp() + + if (BuildConfig.DEBUG && permissionAdapter.isGranted(Permission.WRITE_SECURE_SETTINGS)) { + accessibilityServiceAdapter.start() + } + } + }) + + appCoroutineScope.launch { + notificationController.openApp.collectLatest { intentAction -> + Intent(this@BaseKeyMapperApp, getMainActivityClass()).apply { + action = intentAction + flags = Intent.FLAG_ACTIVITY_NEW_TASK + + startActivity(this) + } + } + } + + notificationController.showToast.onEach { toast -> + Toast.makeText(this, toast, Toast.LENGTH_SHORT).show() + }.launchIn(appCoroutineScope) + + autoGrantPermissionController.start() + } + + abstract fun getMainActivityClass(): Class<*> +} diff --git a/app/src/main/java/io/github/sds100/keymapper/BaseMainActivity.kt b/base/src/main/java/io/github/sds100/keymapper/base/BaseMainActivity.kt similarity index 72% rename from app/src/main/java/io/github/sds100/keymapper/BaseMainActivity.kt rename to base/src/main/java/io/github/sds100/keymapper/base/BaseMainActivity.kt index 8aed150c4f..6c6dae42eb 100644 --- a/app/src/main/java/io/github/sds100/keymapper/BaseMainActivity.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/BaseMainActivity.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper +package io.github.sds100.keymapper.base import android.content.BroadcastReceiver import android.content.Context @@ -17,7 +17,6 @@ import androidx.compose.ui.graphics.toArgb import androidx.core.content.ContextCompat import androidx.core.content.IntentCompat import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen -import androidx.databinding.DataBindingUtil import androidx.lifecycle.Lifecycle import androidx.lifecycle.flowWithLifecycle import androidx.lifecycle.lifecycleScope @@ -26,59 +25,69 @@ import androidx.navigation.findNavController import com.anggrayudi.storage.extension.openInputStream import com.anggrayudi.storage.extension.openOutputStream import com.anggrayudi.storage.extension.toDocumentFile -import io.github.sds100.keymapper.Constants.PACKAGE_NAME -import io.github.sds100.keymapper.compose.ComposeColors -import io.github.sds100.keymapper.databinding.ActivityMainBinding -import io.github.sds100.keymapper.system.accessibility.AccessibilityServiceAdapter +import io.github.sds100.keymapper.base.compose.ComposeColors +import io.github.sds100.keymapper.base.onboarding.OnboardingUseCase +import io.github.sds100.keymapper.base.system.accessibility.AccessibilityServiceAdapterImpl +import io.github.sds100.keymapper.base.system.permissions.RequestPermissionDelegate +import io.github.sds100.keymapper.base.trigger.RecordTriggerController +import io.github.sds100.keymapper.base.utils.ui.ResourceProviderImpl +import io.github.sds100.keymapper.base.utils.ui.launchRepeatOnLifecycle +import io.github.sds100.keymapper.common.BuildConfigProvider import io.github.sds100.keymapper.system.files.FileUtils import io.github.sds100.keymapper.system.inputevents.MyMotionEvent +import io.github.sds100.keymapper.system.notifications.NotificationReceiverAdapterImpl import io.github.sds100.keymapper.system.permissions.AndroidPermissionAdapter -import io.github.sds100.keymapper.system.permissions.RequestPermissionDelegate -import io.github.sds100.keymapper.trigger.RecordTriggerController -import io.github.sds100.keymapper.util.launchRepeatOnLifecycle -import io.github.sds100.keymapper.util.ui.showPopups +import io.github.sds100.keymapper.system.shizuku.ShizukuAdapter import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch import timber.log.Timber - -/** - * Created by sds100 on 19/02/2020. - */ +import javax.inject.Inject abstract class BaseMainActivity : AppCompatActivity() { companion object { const val ACTION_SHOW_ACCESSIBILITY_SETTINGS_NOT_FOUND_DIALOG = - "$PACKAGE_NAME.ACTION_SHOW_ACCESSIBILITY_SETTINGS_NOT_FOUND_DIALOG" + "${BuildConfig.LIBRARY_PACKAGE_NAME}.ACTION_SHOW_ACCESSIBILITY_SETTINGS_NOT_FOUND_DIALOG" const val ACTION_USE_FLOATING_BUTTONS = - "$PACKAGE_NAME.ACTION_USE_FLOATING_BUTTONS" + "${BuildConfig.LIBRARY_PACKAGE_NAME}.ACTION_USE_FLOATING_BUTTONS" - const val ACTION_SAVE_FILE = "$PACKAGE_NAME.ACTION_SAVE_FILE" - const val EXTRA_FILE_URI = "$PACKAGE_NAME.EXTRA_FILE_URI" + const val ACTION_SAVE_FILE = "${BuildConfig.LIBRARY_PACKAGE_NAME}.ACTION_SAVE_FILE" + const val EXTRA_FILE_URI = "${BuildConfig.LIBRARY_PACKAGE_NAME}.EXTRA_FILE_URI" } - private val permissionAdapter: AndroidPermissionAdapter by lazy { - ServiceLocator.permissionAdapter(this) - } + @Inject + lateinit var permissionAdapter: AndroidPermissionAdapter - val serviceAdapter: AccessibilityServiceAdapter by lazy { - ServiceLocator.accessibilityServiceAdapter(this) - } + @Inject + lateinit var serviceAdapter: AccessibilityServiceAdapterImpl - val viewModel by viewModels { - ActivityViewModel.Factory(ServiceLocator.resourceProvider(this)) - } + @Inject + lateinit var resourceProvider: ResourceProviderImpl + + @Inject + lateinit var onboardingUseCase: OnboardingUseCase + + @Inject + lateinit var recordTriggerController: RecordTriggerController + + @Inject + lateinit var notificationReceiverAdapter: NotificationReceiverAdapterImpl + + @Inject + lateinit var shizukuAdapter: ShizukuAdapter + + @Inject + lateinit var buildConfigProvider: BuildConfigProvider + + private lateinit var requestPermissionDelegate: RequestPermissionDelegate private val currentNightMode: Int get() = resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK - private lateinit var requestPermissionDelegate: RequestPermissionDelegate - private val recordTriggerController: RecordTriggerController by lazy { - (applicationContext as KeyMapperApp).recordTriggerController - } + val viewModel by viewModels() private var originalFileUri: Uri? = null @@ -124,17 +133,19 @@ abstract class BaseMainActivity : AppCompatActivity() { super.onCreate(savedInstanceState) if (viewModel.previousNightMode != currentNightMode) { - ServiceLocator.resourceProvider(this).onThemeChange() + resourceProvider.onThemeChange() } - val binding = - DataBindingUtil.setContentView(this, R.layout.activity_main) - - viewModel.showPopups(this, binding.coordinatorLayout) - - requestPermissionDelegate = RequestPermissionDelegate(this, showDialogs = true) + requestPermissionDelegate = RequestPermissionDelegate( + this, + showDialogs = true, + permissionAdapter, + notificationReceiverAdapter = notificationReceiverAdapter, + buildConfigProvider = buildConfigProvider, + shizukuAdapter = shizukuAdapter, + ) - ServiceLocator.permissionAdapter(this@BaseMainActivity).request + permissionAdapter.request .flowWithLifecycle(lifecycle, Lifecycle.State.STARTED) .onEach { permission -> requestPermissionDelegate.requestPermission( @@ -174,18 +185,18 @@ abstract class BaseMainActivity : AppCompatActivity() { override fun onResume() { super.onResume() - Timber.i("MainActivity: onResume. Version: ${Constants.VERSION}") + Timber.i("MainActivity: onResume. Version: ${buildConfigProvider.version} ${buildConfigProvider.versionCode}") // This must be after onResume to ensure all the fragment lifecycles' have also // resumed which are observing these events. // This is checked here and not in KeyMapperApp's lifecycle observer because // the activities have not necessarily resumed at that point. permissionAdapter.onPermissionsChanged() - serviceAdapter.updateWhetherServiceIsEnabled() + serviceAdapter.invalidateState() } override fun onDestroy() { - UseCases.onboarding(this).shownAppIntro = true + onboardingUseCase.shownAppIntro = true viewModel.previousNightMode = currentNightMode unregisterReceiver(broadcastReceiver) diff --git a/base/src/main/java/io/github/sds100/keymapper/base/BaseMainNavHost.kt b/base/src/main/java/io/github/sds100/keymapper/base/BaseMainNavHost.kt new file mode 100644 index 0000000000..4589823952 --- /dev/null +++ b/base/src/main/java/io/github/sds100/keymapper/base/BaseMainNavHost.kt @@ -0,0 +1,59 @@ +package io.github.sds100.keymapper.base + +import androidx.compose.animation.AnimatedContentTransitionScope +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.hilt.navigation.compose.hiltViewModel +import androidx.navigation.NavGraphBuilder +import androidx.navigation.NavHostController +import androidx.navigation.compose.NavHost +import androidx.navigation.compose.composable +import io.github.sds100.keymapper.base.actions.uielement.InteractUiElementScreen +import io.github.sds100.keymapper.base.actions.uielement.InteractUiElementViewModel +import io.github.sds100.keymapper.base.constraints.ChooseConstraintScreen +import io.github.sds100.keymapper.base.constraints.ChooseConstraintViewModel +import io.github.sds100.keymapper.base.utils.navigation.NavDestination +import io.github.sds100.keymapper.base.utils.navigation.handleRouteArgs +import kotlinx.serialization.json.Json + +@Composable +fun BaseMainNavHost( + modifier: Modifier = Modifier, + navController: NavHostController, + composableDestinations: NavGraphBuilder.() -> Unit = {}, +) { + NavHost( + modifier = modifier, + navController = navController, + startDestination = NavDestination.Home, + enterTransition = { slideIntoContainer(towards = AnimatedContentTransitionScope.SlideDirection.Left) }, + exitTransition = { slideOutOfContainer(towards = AnimatedContentTransitionScope.SlideDirection.Right) }, + popEnterTransition = { slideIntoContainer(towards = AnimatedContentTransitionScope.SlideDirection.Right) }, + popExitTransition = { slideOutOfContainer(towards = AnimatedContentTransitionScope.SlideDirection.Right) }, + ) { + composable { backStackEntry -> + val viewModel: InteractUiElementViewModel = hiltViewModel() + + backStackEntry.handleRouteArgs { destination -> + destination.actionJson?.let { viewModel.loadAction(Json.decodeFromString(it)) } + } + + InteractUiElementScreen( + modifier = Modifier.fillMaxSize(), + viewModel = viewModel, + ) + } + + composable { + val viewModel: ChooseConstraintViewModel = hiltViewModel() + + ChooseConstraintScreen( + modifier = Modifier.fillMaxSize(), + viewModel = viewModel, + ) + } + + composableDestinations() + } +} diff --git a/base/src/main/java/io/github/sds100/keymapper/base/BaseSingletonHiltModule.kt b/base/src/main/java/io/github/sds100/keymapper/base/BaseSingletonHiltModule.kt new file mode 100644 index 0000000000..55a0ffabfe --- /dev/null +++ b/base/src/main/java/io/github/sds100/keymapper/base/BaseSingletonHiltModule.kt @@ -0,0 +1,137 @@ +package io.github.sds100.keymapper.base + +import dagger.Binds +import dagger.Module +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent +import io.github.sds100.keymapper.base.actions.GetActionErrorUseCase +import io.github.sds100.keymapper.base.actions.GetActionErrorUseCaseImpl +import io.github.sds100.keymapper.base.actions.sound.SoundsManager +import io.github.sds100.keymapper.base.actions.sound.SoundsManagerImpl +import io.github.sds100.keymapper.base.actions.uielement.InteractUiElementController +import io.github.sds100.keymapper.base.actions.uielement.InteractUiElementUseCase +import io.github.sds100.keymapper.base.backup.BackupManager +import io.github.sds100.keymapper.base.backup.BackupManagerImpl +import io.github.sds100.keymapper.base.constraints.GetConstraintErrorUseCase +import io.github.sds100.keymapper.base.constraints.GetConstraintErrorUseCaseImpl +import io.github.sds100.keymapper.base.keymaps.ConfigKeyMapUseCase +import io.github.sds100.keymapper.base.keymaps.ConfigKeyMapUseCaseController +import io.github.sds100.keymapper.base.keymaps.FingerprintGesturesSupportedUseCase +import io.github.sds100.keymapper.base.keymaps.FingerprintGesturesSupportedUseCaseImpl +import io.github.sds100.keymapper.base.keymaps.PauseKeyMapsUseCase +import io.github.sds100.keymapper.base.keymaps.PauseKeyMapsUseCaseImpl +import io.github.sds100.keymapper.base.onboarding.OnboardingUseCase +import io.github.sds100.keymapper.base.onboarding.OnboardingUseCaseImpl +import io.github.sds100.keymapper.base.system.accessibility.AccessibilityServiceAdapterImpl +import io.github.sds100.keymapper.base.system.accessibility.ControlAccessibilityServiceUseCase +import io.github.sds100.keymapper.base.system.accessibility.ControlAccessibilityServiceUseCaseImpl +import io.github.sds100.keymapper.base.system.inputmethod.ShowHideInputMethodUseCase +import io.github.sds100.keymapper.base.system.inputmethod.ShowHideInputMethodUseCaseImpl +import io.github.sds100.keymapper.base.system.inputmethod.ShowInputMethodPickerUseCase +import io.github.sds100.keymapper.base.system.inputmethod.ShowInputMethodPickerUseCaseImpl +import io.github.sds100.keymapper.base.system.inputmethod.ToggleCompatibleImeUseCase +import io.github.sds100.keymapper.base.system.inputmethod.ToggleCompatibleImeUseCaseImpl +import io.github.sds100.keymapper.base.system.notifications.AndroidNotificationAdapter +import io.github.sds100.keymapper.base.system.notifications.ManageNotificationsUseCase +import io.github.sds100.keymapper.base.system.notifications.ManageNotificationsUseCaseImpl +import io.github.sds100.keymapper.base.trigger.RecordTriggerController +import io.github.sds100.keymapper.base.trigger.RecordTriggerUseCase +import io.github.sds100.keymapper.base.utils.navigation.NavigationProvider +import io.github.sds100.keymapper.base.utils.navigation.NavigationProviderImpl +import io.github.sds100.keymapper.base.utils.ui.DialogProvider +import io.github.sds100.keymapper.base.utils.ui.DialogProviderImpl +import io.github.sds100.keymapper.base.utils.ui.ResourceProvider +import io.github.sds100.keymapper.base.utils.ui.ResourceProviderImpl +import io.github.sds100.keymapper.common.utils.DefaultUuidGenerator +import io.github.sds100.keymapper.common.utils.UuidGenerator +import io.github.sds100.keymapper.system.accessibility.AccessibilityServiceAdapter +import io.github.sds100.keymapper.system.notifications.NotificationAdapter +import javax.inject.Singleton + +@Module +@InstallIn(SingletonComponent::class) +abstract class BaseSingletonHiltModule { + @Singleton + @Binds + abstract fun provideNotificationAdapter(impl: AndroidNotificationAdapter): NotificationAdapter + + @Singleton + @Binds + abstract fun provideAccessibilityAdapter(impl: AccessibilityServiceAdapterImpl): AccessibilityServiceAdapter + + @Singleton + @Binds + abstract fun provideResourceProvider(impl: ResourceProviderImpl): ResourceProvider + + @Singleton + @Binds + abstract fun provideOnboardingUseCase(impl: OnboardingUseCaseImpl): OnboardingUseCase + + @Binds + @Singleton + abstract fun bindPauseKeyMapsUseCase(impl: PauseKeyMapsUseCaseImpl): PauseKeyMapsUseCase + + @Binds + @Singleton + abstract fun bindShowInputMethodPickerUseCase(impl: ShowInputMethodPickerUseCaseImpl): ShowInputMethodPickerUseCase + + @Binds + @Singleton + abstract fun bindControlAccessibilityServiceUseCase(impl: ControlAccessibilityServiceUseCaseImpl): ControlAccessibilityServiceUseCase + + @Binds + @Singleton + abstract fun bindToggleCompatibleImeUseCase(impl: ToggleCompatibleImeUseCaseImpl): ToggleCompatibleImeUseCase + + @Binds + @Singleton + abstract fun bindInteractUiElementUseCase(impl: InteractUiElementController): InteractUiElementUseCase + + @Binds + @Singleton + abstract fun bindShowHideInputMethodUseCase(impl: ShowHideInputMethodUseCaseImpl): ShowHideInputMethodUseCase + + @Binds + @Singleton + abstract fun bindBackupManager(impl: BackupManagerImpl): BackupManager + + @Binds + @Singleton + abstract fun bindSoundsManager(impl: SoundsManagerImpl): SoundsManager + + @Binds + @Singleton + abstract fun bindConfigKeyMapUseCase(impl: ConfigKeyMapUseCaseController): ConfigKeyMapUseCase + + @Binds + @Singleton + abstract fun bindRecordTriggerUseCase(impl: RecordTriggerController): RecordTriggerUseCase + + @Binds + @Singleton + abstract fun bindFingerprintGesturesSupportedUseCase(impl: FingerprintGesturesSupportedUseCaseImpl): FingerprintGesturesSupportedUseCase + + @Binds + @Singleton + abstract fun bindGetActionErrorUseCase(impl: GetActionErrorUseCaseImpl): GetActionErrorUseCase + + @Binds + @Singleton + abstract fun bindGetConstraintErrorUseCase(impl: GetConstraintErrorUseCaseImpl): GetConstraintErrorUseCase + + @Binds + @Singleton + abstract fun bindManageNotificationsUseCase(impl: ManageNotificationsUseCaseImpl): ManageNotificationsUseCase + + @Binds + @Singleton + abstract fun bindUuidGenerator(impl: DefaultUuidGenerator): UuidGenerator + + @Binds + @Singleton + abstract fun bindNavigationProvider(impl: NavigationProviderImpl): NavigationProvider + + @Binds + @Singleton + abstract fun bindDialogProvider(impl: DialogProviderImpl): DialogProvider +} diff --git a/base/src/main/java/io/github/sds100/keymapper/base/BaseViewModelHiltModule.kt b/base/src/main/java/io/github/sds100/keymapper/base/BaseViewModelHiltModule.kt new file mode 100644 index 0000000000..526b59f6e7 --- /dev/null +++ b/base/src/main/java/io/github/sds100/keymapper/base/BaseViewModelHiltModule.kt @@ -0,0 +1,113 @@ +package io.github.sds100.keymapper.base + +import dagger.Binds +import dagger.Module +import dagger.hilt.InstallIn +import dagger.hilt.android.components.ViewModelComponent +import dagger.hilt.android.scopes.ViewModelScoped +import io.github.sds100.keymapper.base.actions.CreateActionUseCase +import io.github.sds100.keymapper.base.actions.CreateActionUseCaseImpl +import io.github.sds100.keymapper.base.actions.TestActionUseCase +import io.github.sds100.keymapper.base.actions.TestActionUseCaseImpl +import io.github.sds100.keymapper.base.actions.keyevent.ConfigKeyEventUseCase +import io.github.sds100.keymapper.base.actions.keyevent.ConfigKeyEventUseCaseImpl +import io.github.sds100.keymapper.base.actions.sound.ChooseSoundFileUseCase +import io.github.sds100.keymapper.base.actions.sound.ChooseSoundFileUseCaseImpl +import io.github.sds100.keymapper.base.backup.BackupRestoreMappingsUseCase +import io.github.sds100.keymapper.base.backup.BackupRestoreMappingsUseCaseImpl +import io.github.sds100.keymapper.base.constraints.CreateConstraintUseCase +import io.github.sds100.keymapper.base.constraints.CreateConstraintUseCaseImpl +import io.github.sds100.keymapper.base.home.ShowHomeScreenAlertsUseCase +import io.github.sds100.keymapper.base.home.ShowHomeScreenAlertsUseCaseImpl +import io.github.sds100.keymapper.base.keymaps.CreateKeyMapShortcutUseCase +import io.github.sds100.keymapper.base.keymaps.CreateKeyMapShortcutUseCaseImpl +import io.github.sds100.keymapper.base.keymaps.DisplayKeyMapUseCase +import io.github.sds100.keymapper.base.keymaps.DisplayKeyMapUseCaseImpl +import io.github.sds100.keymapper.base.keymaps.ListKeyMapsUseCase +import io.github.sds100.keymapper.base.keymaps.ListKeyMapsUseCaseImpl +import io.github.sds100.keymapper.base.logging.DisplayLogUseCase +import io.github.sds100.keymapper.base.logging.DisplayLogUseCaseImpl +import io.github.sds100.keymapper.base.settings.ConfigSettingsUseCase +import io.github.sds100.keymapper.base.settings.ConfigSettingsUseCaseImpl +import io.github.sds100.keymapper.base.sorting.SortKeyMapsUseCase +import io.github.sds100.keymapper.base.sorting.SortKeyMapsUseCaseImpl +import io.github.sds100.keymapper.base.system.apps.DisplayAppShortcutsUseCase +import io.github.sds100.keymapper.base.system.apps.DisplayAppShortcutsUseCaseImpl +import io.github.sds100.keymapper.base.system.apps.DisplayAppsUseCase +import io.github.sds100.keymapper.base.system.apps.DisplayAppsUseCaseImpl +import io.github.sds100.keymapper.base.system.bluetooth.ChooseBluetoothDeviceUseCase +import io.github.sds100.keymapper.base.system.bluetooth.ChooseBluetoothDeviceUseCaseImpl +import io.github.sds100.keymapper.base.trigger.SetupGuiKeyboardUseCase +import io.github.sds100.keymapper.base.trigger.SetupGuiKeyboardUseCaseImpl + +@Module +@InstallIn(ViewModelComponent::class) +abstract class BaseViewModelHiltModule { + @Binds + @ViewModelScoped + abstract fun bindDisplayKeyMapUseCase(impl: DisplayKeyMapUseCaseImpl): DisplayKeyMapUseCase + + @Binds + @ViewModelScoped + abstract fun bindListKeyMapsUseCase(impl: ListKeyMapsUseCaseImpl): ListKeyMapsUseCase + + @Binds + @ViewModelScoped + abstract fun bindBackupRestoreMappingsUseCase(impl: BackupRestoreMappingsUseCaseImpl): BackupRestoreMappingsUseCase + + @Binds + @ViewModelScoped + abstract fun bindShowHomeScreenAlertsUseCase(impl: ShowHomeScreenAlertsUseCaseImpl): ShowHomeScreenAlertsUseCase + + @Binds + @ViewModelScoped + abstract fun bindSortKeyMapsUseCase(impl: SortKeyMapsUseCaseImpl): SortKeyMapsUseCase + + @Binds + @ViewModelScoped + abstract fun bindDisplayLogUseCase(impl: DisplayLogUseCaseImpl): DisplayLogUseCase + + @Binds + @ViewModelScoped + abstract fun bindConfigSettingsUseCase(impl: ConfigSettingsUseCaseImpl): ConfigSettingsUseCase + + @Binds + @ViewModelScoped + abstract fun bindChooseBluetoothDeviceUseCase(impl: ChooseBluetoothDeviceUseCaseImpl): ChooseBluetoothDeviceUseCase + + @Binds + @ViewModelScoped + abstract fun bindChooseSoundFileUseCase(impl: ChooseSoundFileUseCaseImpl): ChooseSoundFileUseCase + + @Binds + @ViewModelScoped + abstract fun bindConfigKeyEventUseCase(impl: ConfigKeyEventUseCaseImpl): ConfigKeyEventUseCase + + @Binds + @ViewModelScoped + abstract fun bindDisplayAppShortcutsUseCase(impl: DisplayAppShortcutsUseCaseImpl): DisplayAppShortcutsUseCase + + @Binds + @ViewModelScoped + abstract fun bindDisplayAppsUseCase(impl: DisplayAppsUseCaseImpl): DisplayAppsUseCase + + @Binds + @ViewModelScoped + abstract fun bindTestActionUseCase(impl: TestActionUseCaseImpl): TestActionUseCase + + @Binds + @ViewModelScoped + abstract fun bindCreateKeyMapShortcutUseCase(impl: CreateKeyMapShortcutUseCaseImpl): CreateKeyMapShortcutUseCase + + @Binds + @ViewModelScoped + abstract fun bindSetupGuiKeyboardUseCase(impl: SetupGuiKeyboardUseCaseImpl): SetupGuiKeyboardUseCase + + @Binds + @ViewModelScoped + abstract fun bindCreateActionUseCase(impl: CreateActionUseCaseImpl): CreateActionUseCase + + @Binds + @ViewModelScoped + abstract fun bindCreateConstraintUseCase(impl: CreateConstraintUseCaseImpl): CreateConstraintUseCase +} diff --git a/app/src/main/java/io/github/sds100/keymapper/system/BootBroadcastReceiver.kt b/base/src/main/java/io/github/sds100/keymapper/base/BootBroadcastReceiver.kt similarity index 61% rename from app/src/main/java/io/github/sds100/keymapper/system/BootBroadcastReceiver.kt rename to base/src/main/java/io/github/sds100/keymapper/base/BootBroadcastReceiver.kt index c61aab628b..247b5282bc 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/BootBroadcastReceiver.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/BootBroadcastReceiver.kt @@ -1,20 +1,15 @@ -package io.github.sds100.keymapper.system +package io.github.sds100.keymapper.base import android.content.BroadcastReceiver import android.content.Context import android.content.Intent -import io.github.sds100.keymapper.KeyMapperApp - -/** - * Created by sds100 on 24/03/2019. - */ class BootBroadcastReceiver : BroadcastReceiver() { override fun onReceive(context: Context?, intent: Intent?) { context ?: return if (intent?.action == Intent.ACTION_LOCKED_BOOT_COMPLETED) { - (context.applicationContext as? KeyMapperApp)?.onBootUnlocked() + (context.applicationContext as? BaseKeyMapperApp)?.onBootUnlocked() } } } diff --git a/base/src/main/java/io/github/sds100/keymapper/base/Constants.kt b/base/src/main/java/io/github/sds100/keymapper/base/Constants.kt new file mode 100644 index 0000000000..d5f8c15086 --- /dev/null +++ b/base/src/main/java/io/github/sds100/keymapper/base/Constants.kt @@ -0,0 +1,8 @@ +package io.github.sds100.keymapper.base + +import android.os.Build + +object Constants { + const val MIN_API: Int = Build.VERSION_CODES.LOLLIPOP + const val MAX_API: Int = 1000 +} diff --git a/app/src/main/java/io/github/sds100/keymapper/about/AboutFragment.kt b/base/src/main/java/io/github/sds100/keymapper/base/about/AboutFragment.kt similarity index 81% rename from app/src/main/java/io/github/sds100/keymapper/about/AboutFragment.kt rename to base/src/main/java/io/github/sds100/keymapper/base/about/AboutFragment.kt index 7c994503ae..cabec8079b 100644 --- a/app/src/main/java/io/github/sds100/keymapper/about/AboutFragment.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/about/AboutFragment.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.about +package io.github.sds100.keymapper.base.about import android.os.Bundle import android.view.LayoutInflater @@ -10,15 +10,17 @@ import androidx.core.view.WindowInsetsCompat import androidx.core.view.updatePadding import androidx.fragment.app.Fragment import androidx.navigation.fragment.findNavController -import io.github.sds100.keymapper.Constants -import io.github.sds100.keymapper.databinding.FragmentAboutBinding - -/** - * Created by sds100 on 05/04/2020. - */ +import dagger.hilt.android.AndroidEntryPoint +import io.github.sds100.keymapper.base.databinding.FragmentAboutBinding +import io.github.sds100.keymapper.common.BuildConfigProvider +import javax.inject.Inject +@AndroidEntryPoint class AboutFragment : Fragment() { + @Inject + lateinit var buildConfigProvider: BuildConfigProvider + /** * Scoped to the lifecycle of the fragment's view (between onCreateView and onDestroyView) */ @@ -57,7 +59,7 @@ class AboutFragment : Fragment() { onBackPressed() } - version = "${Constants.VERSION} ${Constants.VERSION_CODE}" + version = "${buildConfigProvider.version} ${buildConfigProvider.versionCode}" } } diff --git a/app/src/main/java/io/github/sds100/keymapper/actions/Action.kt b/base/src/main/java/io/github/sds100/keymapper/base/actions/Action.kt similarity index 94% rename from app/src/main/java/io/github/sds100/keymapper/actions/Action.kt rename to base/src/main/java/io/github/sds100/keymapper/base/actions/Action.kt index e8e1050ea7..ca071be8d2 100644 --- a/app/src/main/java/io/github/sds100/keymapper/actions/Action.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/actions/Action.kt @@ -1,21 +1,17 @@ -package io.github.sds100.keymapper.actions - +package io.github.sds100.keymapper.base.actions + +import io.github.sds100.keymapper.base.keymaps.KeyMap +import io.github.sds100.keymapper.common.utils.hasFlag +import io.github.sds100.keymapper.common.utils.success +import io.github.sds100.keymapper.common.utils.then +import io.github.sds100.keymapper.common.utils.valueOrNull +import io.github.sds100.keymapper.common.utils.withFlag import io.github.sds100.keymapper.data.entities.ActionEntity import io.github.sds100.keymapper.data.entities.EntityExtra import io.github.sds100.keymapper.data.entities.getData -import io.github.sds100.keymapper.keymaps.KeyMap -import io.github.sds100.keymapper.util.success -import io.github.sds100.keymapper.util.then -import io.github.sds100.keymapper.util.valueOrNull import kotlinx.serialization.Serializable -import splitties.bitflags.hasFlag -import splitties.bitflags.withFlag import java.util.UUID -/** - * Created by sds100 on 09/03/2021. - */ - @Serializable data class Action( val uid: String = UUID.randomUUID().toString(), diff --git a/app/src/main/java/io/github/sds100/keymapper/actions/ActionCategory.kt b/base/src/main/java/io/github/sds100/keymapper/base/actions/ActionCategory.kt similarity index 72% rename from app/src/main/java/io/github/sds100/keymapper/actions/ActionCategory.kt rename to base/src/main/java/io/github/sds100/keymapper/base/actions/ActionCategory.kt index c6dfed43a6..55bf05e5d3 100644 --- a/app/src/main/java/io/github/sds100/keymapper/actions/ActionCategory.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/actions/ActionCategory.kt @@ -1,8 +1,5 @@ -package io.github.sds100.keymapper.actions +package io.github.sds100.keymapper.base.actions -/** - * Created by sds100 on 23/03/2021. - */ enum class ActionCategory { APPS, INPUT, diff --git a/app/src/main/java/io/github/sds100/keymapper/actions/ActionData.kt b/base/src/main/java/io/github/sds100/keymapper/base/actions/ActionData.kt similarity index 99% rename from app/src/main/java/io/github/sds100/keymapper/actions/ActionData.kt rename to base/src/main/java/io/github/sds100/keymapper/base/actions/ActionData.kt index 7889ee4f2a..37437eccb4 100644 --- a/app/src/main/java/io/github/sds100/keymapper/actions/ActionData.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/actions/ActionData.kt @@ -1,9 +1,9 @@ -package io.github.sds100.keymapper.actions +package io.github.sds100.keymapper.base.actions -import io.github.sds100.keymapper.actions.pinchscreen.PinchScreenType -import io.github.sds100.keymapper.actions.uielement.NodeInteractionType +import io.github.sds100.keymapper.common.utils.NodeInteractionType +import io.github.sds100.keymapper.common.utils.Orientation +import io.github.sds100.keymapper.common.utils.PinchScreenType import io.github.sds100.keymapper.system.camera.CameraLens -import io.github.sds100.keymapper.system.display.Orientation import io.github.sds100.keymapper.system.intents.IntentExtraModel import io.github.sds100.keymapper.system.intents.IntentTarget import io.github.sds100.keymapper.system.network.HttpMethod diff --git a/app/src/main/java/io/github/sds100/keymapper/actions/ActionDataEntityMapper.kt b/base/src/main/java/io/github/sds100/keymapper/base/actions/ActionDataEntityMapper.kt similarity index 98% rename from app/src/main/java/io/github/sds100/keymapper/actions/ActionDataEntityMapper.kt rename to base/src/main/java/io/github/sds100/keymapper/base/actions/ActionDataEntityMapper.kt index b56a2856ee..3ea9be3414 100644 --- a/app/src/main/java/io/github/sds100/keymapper/actions/ActionDataEntityMapper.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/actions/ActionDataEntityMapper.kt @@ -1,8 +1,16 @@ -package io.github.sds100.keymapper.actions +package io.github.sds100.keymapper.base.actions import androidx.core.net.toUri -import io.github.sds100.keymapper.actions.pinchscreen.PinchScreenType -import io.github.sds100.keymapper.actions.uielement.NodeInteractionType +import io.github.sds100.keymapper.common.utils.KMError +import io.github.sds100.keymapper.common.utils.KMResult +import io.github.sds100.keymapper.common.utils.NodeInteractionType +import io.github.sds100.keymapper.common.utils.PinchScreenType +import io.github.sds100.keymapper.common.utils.Success +import io.github.sds100.keymapper.common.utils.getKey +import io.github.sds100.keymapper.common.utils.hasFlag +import io.github.sds100.keymapper.common.utils.success +import io.github.sds100.keymapper.common.utils.then +import io.github.sds100.keymapper.common.utils.valueOrNull import io.github.sds100.keymapper.data.db.typeconverter.ConstantTypeConverters import io.github.sds100.keymapper.data.db.typeconverter.NodeInteractionTypeSetTypeConverter import io.github.sds100.keymapper.data.entities.ActionEntity @@ -15,19 +23,7 @@ import io.github.sds100.keymapper.system.network.HttpMethod import io.github.sds100.keymapper.system.volume.DndMode import io.github.sds100.keymapper.system.volume.RingerMode import io.github.sds100.keymapper.system.volume.VolumeStream -import io.github.sds100.keymapper.util.Error -import io.github.sds100.keymapper.util.Result -import io.github.sds100.keymapper.util.Success -import io.github.sds100.keymapper.util.getKey -import io.github.sds100.keymapper.util.success -import io.github.sds100.keymapper.util.then -import io.github.sds100.keymapper.util.valueOrNull import kotlinx.serialization.json.Json -import splitties.bitflags.hasFlag - -/** - * Created by sds100 on 13/03/2021. - */ object ActionDataEntityMapper { @@ -613,10 +609,10 @@ object ActionDataEntityMapper { } } - private fun convertNodeInteractionType(string: String): Result = try { + private fun convertNodeInteractionType(string: String): KMResult = try { Success(NodeInteractionType.valueOf(string)) } catch (e: IllegalArgumentException) { - Error.Exception(e) + KMError.Exception(e) } fun toEntity(data: ActionData): ActionEntity { diff --git a/app/src/main/java/io/github/sds100/keymapper/actions/ActionErrorSnapshot.kt b/base/src/main/java/io/github/sds100/keymapper/base/actions/ActionErrorSnapshot.kt similarity index 76% rename from app/src/main/java/io/github/sds100/keymapper/actions/ActionErrorSnapshot.kt rename to base/src/main/java/io/github/sds100/keymapper/base/actions/ActionErrorSnapshot.kt index 11c4129b8c..a70eaa68b5 100644 --- a/app/src/main/java/io/github/sds100/keymapper/actions/ActionErrorSnapshot.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/actions/ActionErrorSnapshot.kt @@ -1,19 +1,21 @@ -package io.github.sds100.keymapper.actions - -import io.github.sds100.keymapper.actions.sound.SoundsManager -import io.github.sds100.keymapper.shizuku.ShizukuAdapter +package io.github.sds100.keymapper.base.actions + +import io.github.sds100.keymapper.base.actions.sound.SoundsManager +import io.github.sds100.keymapper.base.system.inputmethod.KeyMapperImeHelper +import io.github.sds100.keymapper.common.BuildConfigProvider +import io.github.sds100.keymapper.common.utils.KMError +import io.github.sds100.keymapper.common.utils.onFailure +import io.github.sds100.keymapper.common.utils.onSuccess +import io.github.sds100.keymapper.system.SystemError import io.github.sds100.keymapper.system.apps.PackageManagerAdapter import io.github.sds100.keymapper.system.camera.CameraAdapter import io.github.sds100.keymapper.system.camera.CameraLens import io.github.sds100.keymapper.system.inputmethod.InputMethodAdapter -import io.github.sds100.keymapper.system.inputmethod.KeyMapperImeHelper import io.github.sds100.keymapper.system.permissions.Permission import io.github.sds100.keymapper.system.permissions.PermissionAdapter import io.github.sds100.keymapper.system.permissions.SystemFeatureAdapter import io.github.sds100.keymapper.system.ringtones.RingtoneAdapter -import io.github.sds100.keymapper.util.Error -import io.github.sds100.keymapper.util.onFailure -import io.github.sds100.keymapper.util.onSuccess +import io.github.sds100.keymapper.system.shizuku.ShizukuAdapter class LazyActionErrorSnapshot( private val packageManager: PackageManagerAdapter, @@ -24,13 +26,14 @@ class LazyActionErrorSnapshot( private val soundsManager: SoundsManager, shizukuAdapter: ShizukuAdapter, private val ringtoneAdapter: RingtoneAdapter, + buildConfigProvider: BuildConfigProvider, ) : ActionErrorSnapshot, IsActionSupportedUseCase by IsActionSupportedUseCaseImpl( systemFeatureAdapter, cameraAdapter, permissionAdapter, ) { - private val keyMapperImeHelper = KeyMapperImeHelper(inputMethodAdapter) + private val keyMapperImeHelper = KeyMapperImeHelper(inputMethodAdapter, buildConfigProvider.packageName) private val isCompatibleImeEnabled by lazy { keyMapperImeHelper.isCompatibleImeEnabled() } private val isCompatibleImeChosen by lazy { keyMapperImeHelper.isCompatibleImeChosen() } @@ -50,7 +53,7 @@ class LazyActionErrorSnapshot( } } - override fun getError(action: ActionData): Error? { + override fun getError(action: ActionData): KMError? { val isSupportedError = isSupported(action.id) if (isSupportedError != null) { @@ -60,26 +63,26 @@ class LazyActionErrorSnapshot( if (action.canUseShizukuToPerform() && isShizukuInstalled) { if (!(action.canUseImeToPerform() && isCompatibleImeChosen)) { when { - !isShizukuStarted -> return Error.ShizukuNotStarted + !isShizukuStarted -> return KMError.ShizukuNotStarted - !isPermissionGranted(Permission.SHIZUKU) -> return Error.PermissionDenied( + !isPermissionGranted(Permission.SHIZUKU) -> return SystemError.PermissionDenied( Permission.SHIZUKU, ) } } } else if (action.canUseImeToPerform()) { if (!isCompatibleImeEnabled) { - return Error.NoCompatibleImeEnabled + return KMError.NoCompatibleImeEnabled } if (!isCompatibleImeChosen) { - return Error.NoCompatibleImeChosen + return KMError.NoCompatibleImeChosen } } ActionUtils.getRequiredPermissions(action.id).forEach { permission -> if (!isPermissionGranted(permission)) { - return Error.PermissionDenied(permission) + return SystemError.PermissionDenied(permission) } } @@ -98,7 +101,7 @@ class LazyActionErrorSnapshot( if ( action.useShell && !isPermissionGranted(Permission.ROOT) ) { - return Error.PermissionDenied(Permission.ROOT) + return SystemError.PermissionDenied(Permission.ROOT) } is ActionData.Sound.SoundFile -> { @@ -109,21 +112,21 @@ class LazyActionErrorSnapshot( is ActionData.Sound.Ringtone -> { if (!ringtoneAdapter.exists(action.uri)) { - return Error.CantFindSoundFile + return KMError.CantFindSoundFile } } is ActionData.VoiceAssistant -> { if (!isVoiceAssistantInstalled) { - return Error.NoVoiceAssistant + return KMError.NoVoiceAssistant } } is ActionData.Flashlight -> if (!flashLenses.contains(action.lens)) { return when (action.lens) { - CameraLens.FRONT -> Error.FrontFlashNotFound - CameraLens.BACK -> Error.BackFlashNotFound + CameraLens.FRONT -> KMError.FrontFlashNotFound + CameraLens.BACK -> KMError.BackFlashNotFound } } @@ -138,15 +141,15 @@ class LazyActionErrorSnapshot( return null } - private fun getAppError(packageName: String): Error? { + private fun getAppError(packageName: String): KMError? { packageManager.isAppEnabled(packageName).onSuccess { isEnabled -> if (!isEnabled) { - return Error.AppDisabled(packageName) + return KMError.AppDisabled(packageName) } } if (!packageManager.isAppInstalled(packageName)) { - return Error.AppNotFound(packageName) + return KMError.AppNotFound(packageName) } return null @@ -164,5 +167,5 @@ class LazyActionErrorSnapshot( } interface ActionErrorSnapshot { - fun getError(action: ActionData): Error? + fun getError(action: ActionData): KMError? } diff --git a/app/src/main/java/io/github/sds100/keymapper/actions/ActionId.kt b/base/src/main/java/io/github/sds100/keymapper/base/actions/ActionId.kt similarity index 96% rename from app/src/main/java/io/github/sds100/keymapper/actions/ActionId.kt rename to base/src/main/java/io/github/sds100/keymapper/base/actions/ActionId.kt index 80840e9949..b8034aa84b 100644 --- a/app/src/main/java/io/github/sds100/keymapper/actions/ActionId.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/actions/ActionId.kt @@ -1,8 +1,5 @@ -package io.github.sds100.keymapper.actions +package io.github.sds100.keymapper.base.actions -/** - * Created by sds100 on 15/03/2021. - */ enum class ActionId { APP, APP_SHORTCUT, diff --git a/app/src/main/java/io/github/sds100/keymapper/actions/ActionListItem.kt b/base/src/main/java/io/github/sds100/keymapper/base/actions/ActionListItem.kt similarity index 97% rename from app/src/main/java/io/github/sds100/keymapper/actions/ActionListItem.kt rename to base/src/main/java/io/github/sds100/keymapper/base/actions/ActionListItem.kt index 92276cfeb8..f842381aae 100644 --- a/app/src/main/java/io/github/sds100/keymapper/actions/ActionListItem.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/actions/ActionListItem.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.actions +package io.github.sds100.keymapper.base.actions import androidx.compose.foundation.gestures.Orientation import androidx.compose.foundation.gestures.draggable @@ -43,11 +43,11 @@ import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import com.google.accompanist.drawablepainter.rememberDrawablePainter -import io.github.sds100.keymapper.R -import io.github.sds100.keymapper.util.drawable -import io.github.sds100.keymapper.util.ui.LinkType -import io.github.sds100.keymapper.util.ui.compose.ComposeIconInfo -import io.github.sds100.keymapper.util.ui.compose.DragDropState +import io.github.sds100.keymapper.base.R +import io.github.sds100.keymapper.base.utils.ui.LinkType +import io.github.sds100.keymapper.base.utils.ui.compose.ComposeIconInfo +import io.github.sds100.keymapper.base.utils.ui.compose.DragDropState +import io.github.sds100.keymapper.base.utils.ui.drawable @Composable fun ActionListItem( diff --git a/app/src/main/java/io/github/sds100/keymapper/actions/ActionOptionsBottomSheet.kt b/base/src/main/java/io/github/sds100/keymapper/base/actions/ActionOptionsBottomSheet.kt similarity index 96% rename from app/src/main/java/io/github/sds100/keymapper/actions/ActionOptionsBottomSheet.kt rename to base/src/main/java/io/github/sds100/keymapper/base/actions/ActionOptionsBottomSheet.kt index 4a8de35bf8..fac1d4ae7c 100644 --- a/app/src/main/java/io/github/sds100/keymapper/actions/ActionOptionsBottomSheet.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/actions/ActionOptionsBottomSheet.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.actions +package io.github.sds100.keymapper.base.actions import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box @@ -37,15 +37,15 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp -import io.github.sds100.keymapper.R -import io.github.sds100.keymapper.compose.KeyMapperTheme -import io.github.sds100.keymapper.util.ui.SliderMaximums -import io.github.sds100.keymapper.util.ui.SliderMinimums -import io.github.sds100.keymapper.util.ui.SliderStepSizes -import io.github.sds100.keymapper.util.ui.compose.CheckBoxText -import io.github.sds100.keymapper.util.ui.compose.RadioButtonText -import io.github.sds100.keymapper.util.ui.compose.SliderOptionText -import io.github.sds100.keymapper.util.ui.compose.openUriSafe +import io.github.sds100.keymapper.base.R +import io.github.sds100.keymapper.base.compose.KeyMapperTheme +import io.github.sds100.keymapper.base.utils.ui.SliderMaximums +import io.github.sds100.keymapper.base.utils.ui.SliderMinimums +import io.github.sds100.keymapper.base.utils.ui.SliderStepSizes +import io.github.sds100.keymapper.base.utils.ui.compose.CheckBoxText +import io.github.sds100.keymapper.base.utils.ui.compose.RadioButtonText +import io.github.sds100.keymapper.base.utils.ui.compose.SliderOptionText +import io.github.sds100.keymapper.base.utils.ui.compose.openUriSafe import kotlinx.coroutines.launch @OptIn(ExperimentalMaterial3Api::class) diff --git a/app/src/main/java/io/github/sds100/keymapper/actions/ActionUiHelper.kt b/base/src/main/java/io/github/sds100/keymapper/base/actions/ActionUiHelper.kt similarity index 93% rename from app/src/main/java/io/github/sds100/keymapper/actions/ActionUiHelper.kt rename to base/src/main/java/io/github/sds100/keymapper/base/actions/ActionUiHelper.kt index 723084996b..b9a0b61f5e 100644 --- a/app/src/main/java/io/github/sds100/keymapper/actions/ActionUiHelper.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/actions/ActionUiHelper.kt @@ -1,27 +1,27 @@ -package io.github.sds100.keymapper.actions +package io.github.sds100.keymapper.base.actions import android.os.Build import android.view.KeyEvent import androidx.compose.material.icons.Icons import androidx.compose.material.icons.outlined.Android -import io.github.sds100.keymapper.R -import io.github.sds100.keymapper.actions.pinchscreen.PinchScreenType -import io.github.sds100.keymapper.keymaps.KeyMap +import io.github.sds100.keymapper.base.R +import io.github.sds100.keymapper.base.keymaps.KeyMap +import io.github.sds100.keymapper.base.utils.DndModeStrings +import io.github.sds100.keymapper.base.utils.InputEventStrings +import io.github.sds100.keymapper.base.utils.RingerModeStrings +import io.github.sds100.keymapper.base.utils.VolumeStreamStrings +import io.github.sds100.keymapper.base.utils.ui.IconInfo +import io.github.sds100.keymapper.base.utils.ui.ResourceProvider +import io.github.sds100.keymapper.base.utils.ui.TintType +import io.github.sds100.keymapper.base.utils.ui.compose.ComposeIconInfo +import io.github.sds100.keymapper.common.utils.Orientation +import io.github.sds100.keymapper.common.utils.PinchScreenType +import io.github.sds100.keymapper.common.utils.handle +import io.github.sds100.keymapper.common.utils.hasFlag +import io.github.sds100.keymapper.common.utils.toPercentString import io.github.sds100.keymapper.system.camera.CameraLens import io.github.sds100.keymapper.system.devices.InputDeviceUtils -import io.github.sds100.keymapper.system.display.OrientationUtils -import io.github.sds100.keymapper.system.inputevents.InputEventUtils import io.github.sds100.keymapper.system.intents.IntentTarget -import io.github.sds100.keymapper.system.volume.DndModeUtils -import io.github.sds100.keymapper.system.volume.RingerModeUtils -import io.github.sds100.keymapper.system.volume.VolumeStreamUtils -import io.github.sds100.keymapper.util.handle -import io.github.sds100.keymapper.util.toPercentString -import io.github.sds100.keymapper.util.ui.IconInfo -import io.github.sds100.keymapper.util.ui.ResourceProvider -import io.github.sds100.keymapper.util.ui.TintType -import io.github.sds100.keymapper.util.ui.compose.ComposeIconInfo -import splitties.bitflags.hasFlag class ActionUiHelper( displayActionUseCase: DisplayActionUseCase, @@ -50,9 +50,9 @@ class ActionUiHelper( getString(R.string.description_keyevent_through_shell, keyCodeString) } else { val metaStateString = buildString { - InputEventUtils.MODIFIER_LABELS.entries.forEach { - val modifier = it.key - val labelRes = it.value + for (label in InputEventStrings.MODIFIER_LABELS.entries) { + val modifier = label.key + val labelRes = label.value if (action.metaState.hasFlag(modifier)) { append("${getString(labelRes)} + ") @@ -90,7 +90,7 @@ class ActionUiHelper( } is ActionData.DoNotDisturb.Enable -> { - val dndModeString = getString(DndModeUtils.getLabel(action.dndMode)) + val dndModeString = getString(DndModeStrings.getLabel(action.dndMode)) getString( R.string.action_enable_dnd_mode_formatted, dndModeString, @@ -98,7 +98,7 @@ class ActionUiHelper( } is ActionData.DoNotDisturb.Toggle -> { - val dndModeString = getString(DndModeUtils.getLabel(action.dndMode)) + val dndModeString = getString(DndModeStrings.getLabel(action.dndMode)) getString( R.string.action_toggle_dnd_mode_formatted, dndModeString, @@ -108,7 +108,7 @@ class ActionUiHelper( ActionData.DoNotDisturb.Disable -> getString(R.string.action_disable_dnd_mode) is ActionData.Volume.SetRingerMode -> { - val ringerModeString = getString(RingerModeUtils.getLabel(action.ringerMode)) + val ringerModeString = getString(RingerModeStrings.getLabel(action.ringerMode)) getString(R.string.action_change_ringer_mode_formatted, ringerModeString) } @@ -120,7 +120,7 @@ class ActionUiHelper( when (action) { is ActionData.Volume.Stream -> { val streamString = getString( - VolumeStreamUtils.getLabel(action.volumeStream), + VolumeStreamStrings.getLabel(action.volumeStream), ) if (action.showVolumeUi) { @@ -190,7 +190,7 @@ class ActionUiHelper( is ActionData.Volume.SetRingerMode -> { val ringerModeString = - getString(RingerModeUtils.getLabel(action.ringerMode)) + getString(RingerModeStrings.getLabel(action.ringerMode)) string = getString( R.string.action_change_ringer_mode_formatted, @@ -502,8 +502,13 @@ class ActionUiHelper( ActionData.OpenSettings -> getString(R.string.action_open_settings) is ActionData.Rotation.CycleRotations -> { - val orientationStrings = action.orientations.map { - getString(OrientationUtils.getLabel(it)) + val orientationStrings = action.orientations.map { orientation -> + when (orientation) { + Orientation.ORIENTATION_0 -> R.string.orientation_0 + Orientation.ORIENTATION_90 -> R.string.orientation_90 + Orientation.ORIENTATION_180 -> R.string.orientation_180 + Orientation.ORIENTATION_270 -> R.string.orientation_270 + } } getString( diff --git a/app/src/main/java/io/github/sds100/keymapper/actions/ActionUtils.kt b/base/src/main/java/io/github/sds100/keymapper/base/actions/ActionUtils.kt similarity index 98% rename from app/src/main/java/io/github/sds100/keymapper/actions/ActionUtils.kt rename to base/src/main/java/io/github/sds100/keymapper/base/actions/ActionUtils.kt index f7833f70f0..638274e2d5 100644 --- a/app/src/main/java/io/github/sds100/keymapper/actions/ActionUtils.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/actions/ActionUtils.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.actions +package io.github.sds100.keymapper.base.actions import android.content.pm.PackageManager import android.os.Build @@ -71,22 +71,18 @@ import androidx.compose.material.icons.rounded.ContentPaste import androidx.compose.material.icons.rounded.Wifi import androidx.compose.material.icons.rounded.WifiOff import androidx.compose.ui.graphics.vector.ImageVector -import io.github.sds100.keymapper.Constants -import io.github.sds100.keymapper.R +import io.github.sds100.keymapper.base.Constants +import io.github.sds100.keymapper.base.R +import io.github.sds100.keymapper.base.utils.ui.compose.icons.HomeIotDevice +import io.github.sds100.keymapper.base.utils.ui.compose.icons.InstantMix +import io.github.sds100.keymapper.base.utils.ui.compose.icons.JumpToElement +import io.github.sds100.keymapper.base.utils.ui.compose.icons.KeyMapperIcons +import io.github.sds100.keymapper.base.utils.ui.compose.icons.MatchWord +import io.github.sds100.keymapper.base.utils.ui.compose.icons.NfcOff +import io.github.sds100.keymapper.base.utils.ui.compose.icons.TextSelectEnd +import io.github.sds100.keymapper.base.utils.ui.compose.icons.TopPanelClose +import io.github.sds100.keymapper.base.utils.ui.compose.icons.TopPanelOpen import io.github.sds100.keymapper.system.permissions.Permission -import io.github.sds100.keymapper.util.ui.compose.icons.HomeIotDevice -import io.github.sds100.keymapper.util.ui.compose.icons.InstantMix -import io.github.sds100.keymapper.util.ui.compose.icons.JumpToElement -import io.github.sds100.keymapper.util.ui.compose.icons.KeyMapperIcons -import io.github.sds100.keymapper.util.ui.compose.icons.MatchWord -import io.github.sds100.keymapper.util.ui.compose.icons.NfcOff -import io.github.sds100.keymapper.util.ui.compose.icons.TextSelectEnd -import io.github.sds100.keymapper.util.ui.compose.icons.TopPanelClose -import io.github.sds100.keymapper.util.ui.compose.icons.TopPanelOpen - -/** - * Created by sds100 on 16/03/2021. - */ object ActionUtils { diff --git a/app/src/main/java/io/github/sds100/keymapper/actions/ActionsScreen.kt b/base/src/main/java/io/github/sds100/keymapper/base/actions/ActionsScreen.kt similarity index 93% rename from app/src/main/java/io/github/sds100/keymapper/actions/ActionsScreen.kt rename to base/src/main/java/io/github/sds100/keymapper/base/actions/ActionsScreen.kt index e53596658e..14eadb9da1 100644 --- a/app/src/main/java/io/github/sds100/keymapper/actions/ActionsScreen.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/actions/ActionsScreen.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.actions +package io.github.sds100.keymapper.base.actions import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box @@ -37,16 +37,16 @@ import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle -import io.github.sds100.keymapper.R -import io.github.sds100.keymapper.compose.KeyMapperTheme -import io.github.sds100.keymapper.keymaps.ShortcutModel -import io.github.sds100.keymapper.keymaps.ShortcutRow +import io.github.sds100.keymapper.base.R +import io.github.sds100.keymapper.base.compose.KeyMapperTheme +import io.github.sds100.keymapper.base.keymaps.ShortcutModel +import io.github.sds100.keymapper.base.keymaps.ShortcutRow +import io.github.sds100.keymapper.base.utils.ui.LinkType +import io.github.sds100.keymapper.base.utils.ui.compose.ComposeIconInfo +import io.github.sds100.keymapper.base.utils.ui.compose.DraggableItem +import io.github.sds100.keymapper.base.utils.ui.compose.rememberDragDropState +import io.github.sds100.keymapper.common.utils.State import io.github.sds100.keymapper.system.camera.CameraLens -import io.github.sds100.keymapper.util.State -import io.github.sds100.keymapper.util.ui.LinkType -import io.github.sds100.keymapper.util.ui.compose.ComposeIconInfo -import io.github.sds100.keymapper.util.ui.compose.DraggableItem -import io.github.sds100.keymapper.util.ui.compose.rememberDragDropState import kotlinx.coroutines.flow.update @OptIn(ExperimentalMaterial3Api::class) @@ -125,7 +125,7 @@ private fun ActionsScreen( State.Loading -> Loading() is State.Data -> Surface(modifier = modifier) { Column { - when (state.data) { + when (val data = state.data) { is ConfigActionsState.Empty -> { Column( modifier = Modifier.weight(1f), @@ -140,7 +140,7 @@ private fun ActionsScreen( textAlign = TextAlign.Center, ) - if (state.data.shortcuts.isNotEmpty()) { + if (data.shortcuts.isNotEmpty()) { Text( text = stringResource(R.string.recently_used_actions), style = MaterialTheme.typography.titleSmall, @@ -152,7 +152,7 @@ private fun ActionsScreen( modifier = Modifier .padding(horizontal = 32.dp) .fillMaxWidth(), - shortcuts = state.data.shortcuts, + shortcuts = data.shortcuts, onClick = onClickShortcut, ) } @@ -162,7 +162,7 @@ private fun ActionsScreen( is ConfigActionsState.Loaded -> { Spacer(Modifier.height(8.dp)) - if (state.data.actions.isNotEmpty()) { + if (data.actions.isNotEmpty()) { Spacer(Modifier.height(8.dp)) Text( @@ -176,9 +176,9 @@ private fun ActionsScreen( ActionList( modifier = Modifier.weight(1f), - actionList = state.data.actions, - shortcuts = state.data.shortcuts, - isReorderingEnabled = state.data.isReorderingEnabled, + actionList = data.actions, + shortcuts = data.shortcuts, + isReorderingEnabled = data.isReorderingEnabled, onRemoveClick = { actionToDelete = it showDeleteDialog = true diff --git a/app/src/main/java/io/github/sds100/keymapper/actions/ChooseActionScreen.kt b/base/src/main/java/io/github/sds100/keymapper/base/actions/ChooseActionScreen.kt similarity index 93% rename from app/src/main/java/io/github/sds100/keymapper/actions/ChooseActionScreen.kt rename to base/src/main/java/io/github/sds100/keymapper/base/actions/ChooseActionScreen.kt index 34cc3a8616..fce1f2f42c 100644 --- a/app/src/main/java/io/github/sds100/keymapper/actions/ChooseActionScreen.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/actions/ChooseActionScreen.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.actions +package io.github.sds100.keymapper.base.actions import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box @@ -20,7 +20,6 @@ import androidx.compose.material.icons.rounded.Bluetooth import androidx.compose.material.icons.rounded.Wifi import androidx.compose.material3.BottomAppBar import androidx.compose.material3.CircularProgressIndicator -import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold import androidx.compose.material3.Surface @@ -38,22 +37,21 @@ import androidx.compose.ui.tooling.preview.Devices import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle -import io.github.sds100.keymapper.R -import io.github.sds100.keymapper.compose.KeyMapperTheme -import io.github.sds100.keymapper.util.State -import io.github.sds100.keymapper.util.ui.compose.ComposeIconInfo -import io.github.sds100.keymapper.util.ui.compose.SearchAppBarActions -import io.github.sds100.keymapper.util.ui.compose.SimpleListItemFixedHeight -import io.github.sds100.keymapper.util.ui.compose.SimpleListItemGroup -import io.github.sds100.keymapper.util.ui.compose.SimpleListItemHeader -import io.github.sds100.keymapper.util.ui.compose.SimpleListItemModel +import io.github.sds100.keymapper.base.R +import io.github.sds100.keymapper.base.compose.KeyMapperTheme +import io.github.sds100.keymapper.base.utils.ui.compose.ComposeIconInfo +import io.github.sds100.keymapper.base.utils.ui.compose.SearchAppBarActions +import io.github.sds100.keymapper.base.utils.ui.compose.SimpleListItemFixedHeight +import io.github.sds100.keymapper.base.utils.ui.compose.SimpleListItemGroup +import io.github.sds100.keymapper.base.utils.ui.compose.SimpleListItemHeader +import io.github.sds100.keymapper.base.utils.ui.compose.SimpleListItemModel +import io.github.sds100.keymapper.common.utils.State import kotlinx.coroutines.flow.update @Composable fun ChooseActionScreen( modifier: Modifier = Modifier, viewModel: ChooseActionViewModel, - onNavigateBack: () -> Unit, ) { val state by viewModel.groups.collectAsStateWithLifecycle() val query by viewModel.searchQuery.collectAsStateWithLifecycle() @@ -69,11 +67,10 @@ fun ChooseActionScreen( onQueryChange = { newQuery -> viewModel.searchQuery.update { newQuery } }, onCloseSearch = { viewModel.searchQuery.update { null } }, onClickAction = viewModel::onListItemClick, - onNavigateBack = onNavigateBack, + onNavigateBack = viewModel::onNavigateBack, ) } -@OptIn(ExperimentalMaterial3Api::class) @Composable private fun ChooseActionScreen( modifier: Modifier = Modifier, diff --git a/app/src/main/java/io/github/sds100/keymapper/actions/ChooseActionViewModel.kt b/base/src/main/java/io/github/sds100/keymapper/base/actions/ChooseActionViewModel.kt similarity index 75% rename from app/src/main/java/io/github/sds100/keymapper/actions/ChooseActionViewModel.kt rename to base/src/main/java/io/github/sds100/keymapper/base/actions/ChooseActionViewModel.kt index 10ea36c237..895035c7d8 100644 --- a/app/src/main/java/io/github/sds100/keymapper/actions/ChooseActionViewModel.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/actions/ChooseActionViewModel.kt @@ -1,25 +1,23 @@ -package io.github.sds100.keymapper.actions +package io.github.sds100.keymapper.base.actions import androidx.lifecycle.ViewModel -import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.viewModelScope -import io.github.sds100.keymapper.R +import dagger.hilt.android.lifecycle.HiltViewModel +import io.github.sds100.keymapper.base.R +import io.github.sds100.keymapper.base.utils.containsQuery +import io.github.sds100.keymapper.base.utils.getFullMessage +import io.github.sds100.keymapper.base.utils.navigation.NavigationProvider +import io.github.sds100.keymapper.base.utils.ui.DialogModel +import io.github.sds100.keymapper.base.utils.ui.DialogProvider +import io.github.sds100.keymapper.base.utils.ui.DialogResponse +import io.github.sds100.keymapper.base.utils.ui.ResourceProvider +import io.github.sds100.keymapper.base.utils.ui.compose.ComposeIconInfo +import io.github.sds100.keymapper.base.utils.ui.compose.SimpleListItemGroup +import io.github.sds100.keymapper.base.utils.ui.compose.SimpleListItemModel +import io.github.sds100.keymapper.base.utils.ui.showDialog +import io.github.sds100.keymapper.common.utils.State +import io.github.sds100.keymapper.system.SystemError import io.github.sds100.keymapper.system.permissions.Permission -import io.github.sds100.keymapper.util.Error -import io.github.sds100.keymapper.util.State -import io.github.sds100.keymapper.util.containsQuery -import io.github.sds100.keymapper.util.getFullMessage -import io.github.sds100.keymapper.util.ui.DialogResponse -import io.github.sds100.keymapper.util.ui.NavigationViewModel -import io.github.sds100.keymapper.util.ui.NavigationViewModelImpl -import io.github.sds100.keymapper.util.ui.PopupUi -import io.github.sds100.keymapper.util.ui.PopupViewModel -import io.github.sds100.keymapper.util.ui.PopupViewModelImpl -import io.github.sds100.keymapper.util.ui.ResourceProvider -import io.github.sds100.keymapper.util.ui.compose.ComposeIconInfo -import io.github.sds100.keymapper.util.ui.compose.SimpleListItemGroup -import io.github.sds100.keymapper.util.ui.compose.SimpleListItemModel -import io.github.sds100.keymapper.util.ui.showPopup import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted @@ -27,20 +25,21 @@ import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.filterNotNull import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.map -import kotlinx.coroutines.flow.shareIn import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch +import kotlinx.serialization.json.Json +import javax.inject.Inject -/** - * Created by sds100 on 22/07/2021. - */ -class ChooseActionViewModel( +@HiltViewModel +class ChooseActionViewModel @Inject constructor( private val useCase: CreateActionUseCase, resourceProvider: ResourceProvider, + navigationProvider: NavigationProvider, + dialogProvider: DialogProvider, ) : ViewModel(), ResourceProvider by resourceProvider, - PopupViewModel by PopupViewModelImpl(), - NavigationViewModel by NavigationViewModelImpl() { + DialogProvider by dialogProvider, + NavigationProvider by navigationProvider { companion object { private val CATEGORY_ORDER = arrayOf( @@ -66,9 +65,6 @@ class ChooseActionViewModel( private val allGroupedListItems: List by lazy { buildListGroups() } - val returnAction = createActionDelegate.actionResult.filterNotNull() - .shareIn(viewModelScope, SharingStarted.Eagerly) - val searchQuery = MutableStateFlow(null) val groups: StateFlow>> = @@ -87,19 +83,33 @@ class ChooseActionViewModel( State.Data(groups) }.flowOn(Dispatchers.Default).stateIn(viewModelScope, SharingStarted.Eagerly, State.Loading) + init { + viewModelScope.launch { + createActionDelegate.actionResult.filterNotNull().collect { action -> + popBackStackWithResult(Json.encodeToString(action)) + } + } + } + fun onListItemClick(id: String) { viewModelScope.launch { val actionId = ActionId.valueOf(id) val approvedMessage = showMessageForAction(actionId) if (!approvedMessage) { - showMessageForAction(actionId) + return@launch } createActionDelegate.createAction(actionId) } } + fun onNavigateBack() { + viewModelScope.launch { + popBackStack() + } + } + private fun buildListGroups(): List = buildList { val listItems = buildListItems(ActionId.entries) @@ -142,7 +152,7 @@ class ChooseActionViewModel( val icon = ActionUtils.getComposeIcon(actionId) val subtitle = when { - error == Error.PermissionDenied(Permission.ROOT) -> getString(R.string.choose_action_warning_requires_root) + error == SystemError.PermissionDenied(Permission.ROOT) -> getString(R.string.choose_action_warning_requires_root) error != null -> error.getFullMessage(this@ChooseActionViewModel) else -> null } @@ -166,9 +176,9 @@ class ChooseActionViewModel( private suspend fun showMessageForAction(id: ActionId): Boolean { // See issue #1379 if (id == ActionId.APP) { - val response = showPopup( + val response = showDialog( "show_app_action_warning_dialog", - PopupUi.Dialog( + DialogModel.Alert( message = getString(R.string.action_open_app_dialog_message), title = getString(R.string.action_open_app_dialog_title), positiveButtonText = getString(R.string.action_open_app_dialog_read_more_button), @@ -177,9 +187,9 @@ class ChooseActionViewModel( ) if (response == DialogResponse.POSITIVE) { - showPopup( + showDialog( "app_action_permission_info", - PopupUi.OpenUrl(getString(R.string.url_action_guide)), + DialogModel.OpenUrl(getString(R.string.url_action_guide)), ) return false } else { @@ -210,9 +220,9 @@ class ChooseActionViewModel( } if (messageToShow != null) { - val response = showPopup( + val response = showDialog( "show_action_message", - PopupUi.Ok(message = getString(messageToShow)), + DialogModel.Ok(message = getString(messageToShow)), ) return response != null @@ -220,13 +230,4 @@ class ChooseActionViewModel( return true } - - @Suppress("UNCHECKED_CAST") - class Factory( - private val useCase: CreateActionUseCase, - private val resourceProvider: ResourceProvider, - ) : ViewModelProvider.NewInstanceFactory() { - - override fun create(modelClass: Class): T = ChooseActionViewModel(useCase, resourceProvider) as T - } } diff --git a/app/src/main/java/io/github/sds100/keymapper/actions/ConfigActionsViewModel.kt b/base/src/main/java/io/github/sds100/keymapper/base/actions/ConfigActionsViewModel.kt similarity index 87% rename from app/src/main/java/io/github/sds100/keymapper/actions/ConfigActionsViewModel.kt rename to base/src/main/java/io/github/sds100/keymapper/base/actions/ConfigActionsViewModel.kt index dfe362ff0b..766d12cfe3 100644 --- a/app/src/main/java/io/github/sds100/keymapper/actions/ConfigActionsViewModel.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/actions/ConfigActionsViewModel.kt @@ -1,32 +1,31 @@ -package io.github.sds100.keymapper.actions - -import io.github.sds100.keymapper.R -import io.github.sds100.keymapper.keymaps.ConfigKeyMapUseCase -import io.github.sds100.keymapper.keymaps.KeyMap -import io.github.sds100.keymapper.keymaps.ShortcutModel -import io.github.sds100.keymapper.onboarding.OnboardingUseCase +package io.github.sds100.keymapper.base.actions + +import io.github.sds100.keymapper.base.R +import io.github.sds100.keymapper.base.keymaps.ConfigKeyMapUseCase +import io.github.sds100.keymapper.base.keymaps.KeyMap +import io.github.sds100.keymapper.base.keymaps.ShortcutModel +import io.github.sds100.keymapper.base.onboarding.OnboardingUseCase +import io.github.sds100.keymapper.base.utils.getFullMessage +import io.github.sds100.keymapper.base.utils.isFixable +import io.github.sds100.keymapper.base.utils.navigation.NavDestination +import io.github.sds100.keymapper.base.utils.navigation.NavigationProvider +import io.github.sds100.keymapper.base.utils.navigation.navigate +import io.github.sds100.keymapper.base.utils.ui.ChooseAppStoreModel +import io.github.sds100.keymapper.base.utils.ui.DialogModel +import io.github.sds100.keymapper.base.utils.ui.DialogProvider +import io.github.sds100.keymapper.base.utils.ui.DialogResponse +import io.github.sds100.keymapper.base.utils.ui.LinkType +import io.github.sds100.keymapper.base.utils.ui.ResourceProvider +import io.github.sds100.keymapper.base.utils.ui.ViewModelHelper +import io.github.sds100.keymapper.base.utils.ui.compose.ComposeIconInfo +import io.github.sds100.keymapper.base.utils.ui.showDialog +import io.github.sds100.keymapper.common.utils.KMError +import io.github.sds100.keymapper.common.utils.State +import io.github.sds100.keymapper.common.utils.dataOrNull +import io.github.sds100.keymapper.common.utils.mapData +import io.github.sds100.keymapper.common.utils.onFailure +import io.github.sds100.keymapper.system.SystemError import io.github.sds100.keymapper.system.permissions.Permission -import io.github.sds100.keymapper.util.Error -import io.github.sds100.keymapper.util.State -import io.github.sds100.keymapper.util.dataOrNull -import io.github.sds100.keymapper.util.getFullMessage -import io.github.sds100.keymapper.util.isFixable -import io.github.sds100.keymapper.util.mapData -import io.github.sds100.keymapper.util.onFailure -import io.github.sds100.keymapper.util.ui.ChooseAppStoreModel -import io.github.sds100.keymapper.util.ui.DialogResponse -import io.github.sds100.keymapper.util.ui.LinkType -import io.github.sds100.keymapper.util.ui.NavDestination -import io.github.sds100.keymapper.util.ui.NavigationViewModel -import io.github.sds100.keymapper.util.ui.NavigationViewModelImpl -import io.github.sds100.keymapper.util.ui.PopupUi -import io.github.sds100.keymapper.util.ui.PopupViewModel -import io.github.sds100.keymapper.util.ui.PopupViewModelImpl -import io.github.sds100.keymapper.util.ui.ResourceProvider -import io.github.sds100.keymapper.util.ui.ViewModelHelper -import io.github.sds100.keymapper.util.ui.compose.ComposeIconInfo -import io.github.sds100.keymapper.util.ui.navigate -import io.github.sds100.keymapper.util.ui.showPopup import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted @@ -41,10 +40,6 @@ import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch -/** - * Created by sds100 on 22/11/20. - */ - class ConfigActionsViewModel( private val coroutineScope: CoroutineScope, private val displayAction: DisplayActionUseCase, @@ -53,10 +48,12 @@ class ConfigActionsViewModel( private val config: ConfigKeyMapUseCase, private val onboarding: OnboardingUseCase, resourceProvider: ResourceProvider, + navigationProvider: NavigationProvider, + dialogProvider: DialogProvider, ) : ActionOptionsBottomSheetCallback, ResourceProvider by resourceProvider, - PopupViewModel by PopupViewModelImpl(), - NavigationViewModel by NavigationViewModelImpl() { + DialogProvider by dialogProvider, + NavigationProvider by navigationProvider { val createActionDelegate = CreateActionDelegate(coroutineScope, createAction, this, this, this) @@ -115,11 +112,11 @@ class ConfigActionsViewModel( val error = actionErrorSnapshot.filterNotNull().first().getError(actionData) ?: return@launch - if (error == Error.PermissionDenied(Permission.ACCESS_NOTIFICATION_POLICY)) { + if (error == SystemError.PermissionDenied(Permission.ACCESS_NOTIFICATION_POLICY)) { coroutineScope.launch { ViewModelHelper.showDialogExplainingDndAccessBeingUnavailable( resourceProvider = this@ConfigActionsViewModel, - popupViewModel = this@ConfigActionsViewModel, + dialogProvider = this@ConfigActionsViewModel, neverShowDndTriggerErrorAgain = { displayAction.neverShowDndTriggerError() }, fixError = { displayAction.fixError(error) }, ) @@ -127,7 +124,7 @@ class ConfigActionsViewModel( } else { ViewModelHelper.showFixErrorDialog( resourceProvider = this@ConfigActionsViewModel, - popupViewModel = this@ConfigActionsViewModel, + dialogProvider = this@ConfigActionsViewModel, error, ) { displayAction.fixError(error) @@ -254,18 +251,18 @@ class ConfigActionsViewModel( private suspend fun attemptTestAction(actionData: ActionData) { testAction.invoke(actionData).onFailure { error -> - if (error is Error.AccessibilityServiceDisabled) { + if (error is KMError.AccessibilityServiceDisabled) { ViewModelHelper.handleAccessibilityServiceStoppedDialog( resourceProvider = this, - popupViewModel = this, + dialogProvider = this, startService = displayAction::startAccessibilityService, ) } - if (error is Error.AccessibilityServiceCrashed) { + if (error is KMError.AccessibilityServiceCrashed) { ViewModelHelper.handleAccessibilityServiceCrashedDialog( resourceProvider = this, - popupViewModel = this, + dialogProvider = this, restartService = displayAction::restartAccessibilityService, ) } @@ -278,7 +275,7 @@ class ConfigActionsViewModel( githubLink = getString(R.string.url_github_keymapper_leanback_keyboard), ) - val dialog = PopupUi.ChooseAppStore( + val dialog = DialogModel.ChooseAppStore( title = getString(R.string.dialog_title_install_leanback_keyboard), message = getString(R.string.dialog_message_install_leanback_keyboard), appStoreModel, @@ -286,7 +283,7 @@ class ConfigActionsViewModel( negativeButtonText = getString(R.string.neg_cancel), ) - val response = showPopup("download_leanback_ime", dialog) ?: return + val response = showDialog("download_leanback_ime", dialog) ?: return if (response == DialogResponse.POSITIVE) { onboarding.neverShowGuiKeyboardPromptsAgain() @@ -298,7 +295,7 @@ class ConfigActionsViewModel( githubLink = getString(R.string.url_github_keymapper_gui_keyboard), ) - val dialog = PopupUi.ChooseAppStore( + val dialog = DialogModel.ChooseAppStore( title = getString(R.string.dialog_title_install_gui_keyboard), message = getString(R.string.dialog_message_install_gui_keyboard), appStoreModel, @@ -306,7 +303,7 @@ class ConfigActionsViewModel( negativeButtonText = getString(R.string.neg_cancel), ) - val response = showPopup("download_gui_keyboard", dialog) ?: return + val response = showDialog("download_gui_keyboard", dialog) ?: return if (response == DialogResponse.POSITIVE) { onboarding.neverShowGuiKeyboardPromptsAgain() @@ -316,7 +313,7 @@ class ConfigActionsViewModel( private suspend fun promptToInstallShizukuOrGuiKeyboard() { if (onboarding.isTvDevice()) { - val chooseSolutionDialog = PopupUi.Dialog( + val chooseSolutionDialog = DialogModel.Alert( title = getText(R.string.dialog_title_install_shizuku_or_leanback_keyboard), message = getText(R.string.dialog_message_install_shizuku_or_leanback_keyboard), positiveButtonText = getString(R.string.dialog_button_install_shizuku), @@ -325,7 +322,7 @@ class ConfigActionsViewModel( ) val chooseSolutionResponse = - showPopup("choose_solution", chooseSolutionDialog) ?: return + showDialog("choose_solution", chooseSolutionDialog) ?: return when (chooseSolutionResponse) { // install shizuku @@ -343,7 +340,7 @@ class ConfigActionsViewModel( // download leanback keyboard DialogResponse.NEGATIVE -> { - val chooseAppStoreDialog = PopupUi.ChooseAppStore( + val chooseAppStoreDialog = DialogModel.ChooseAppStore( title = getString(R.string.dialog_title_choose_download_leanback_keyboard), message = getString(R.string.dialog_message_choose_download_leanback_keyboard), model = ChooseAppStoreModel( @@ -353,7 +350,7 @@ class ConfigActionsViewModel( negativeButtonText = getString(R.string.neg_cancel), ) - val response = showPopup("install_leanback_keyboard", chooseAppStoreDialog) + val response = showDialog("install_leanback_keyboard", chooseAppStoreDialog) if (response == DialogResponse.POSITIVE) { onboarding.neverShowGuiKeyboardPromptsAgain() @@ -361,7 +358,7 @@ class ConfigActionsViewModel( } } } else { - val chooseSolutionDialog = PopupUi.Dialog( + val chooseSolutionDialog = DialogModel.Alert( title = getText(R.string.dialog_title_install_shizuku_or_gui_keyboard), message = getText(R.string.dialog_message_install_shizuku_or_gui_keyboard), positiveButtonText = getString(R.string.dialog_button_install_shizuku), @@ -370,7 +367,7 @@ class ConfigActionsViewModel( ) val chooseSolutionResponse = - showPopup("choose_solution", chooseSolutionDialog) ?: return + showDialog("choose_solution", chooseSolutionDialog) ?: return when (chooseSolutionResponse) { // install shizuku @@ -388,7 +385,7 @@ class ConfigActionsViewModel( // download gui keyboard DialogResponse.NEGATIVE -> { - val chooseAppStoreDialog = PopupUi.ChooseAppStore( + val chooseAppStoreDialog = DialogModel.ChooseAppStore( title = getString(R.string.dialog_title_choose_download_gui_keyboard), message = getString(R.string.dialog_message_choose_download_gui_keyboard), model = ChooseAppStoreModel( @@ -400,7 +397,7 @@ class ConfigActionsViewModel( negativeButtonText = getString(R.string.neg_cancel), ) - val response = showPopup("install_gui_keyboard", chooseAppStoreDialog) + val response = showDialog("install_gui_keyboard", chooseAppStoreDialog) if (response == DialogResponse.POSITIVE) { onboarding.neverShowGuiKeyboardPromptsAgain() @@ -454,7 +451,7 @@ class ConfigActionsViewModel( } val icon: ComposeIconInfo = uiHelper.getIcon(action.data) - val error: Error? = errorSnapshot.getError(action.data) + val error: KMError? = errorSnapshot.getError(action.data) val extraInfo = buildString { val midDot = getString(R.string.middot) diff --git a/app/src/main/java/io/github/sds100/keymapper/actions/CreateActionDelegate.kt b/base/src/main/java/io/github/sds100/keymapper/base/actions/CreateActionDelegate.kt similarity index 88% rename from app/src/main/java/io/github/sds100/keymapper/actions/CreateActionDelegate.kt rename to base/src/main/java/io/github/sds100/keymapper/base/actions/CreateActionDelegate.kt index e034b3e9f8..5d5cd0d305 100644 --- a/app/src/main/java/io/github/sds100/keymapper/actions/CreateActionDelegate.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/actions/CreateActionDelegate.kt @@ -1,53 +1,48 @@ -package io.github.sds100.keymapper.actions +package io.github.sds100.keymapper.base.actions import android.text.InputType import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue -import io.github.sds100.keymapper.R -import io.github.sds100.keymapper.actions.pinchscreen.PinchPickCoordinateResult -import io.github.sds100.keymapper.actions.swipescreen.SwipePickCoordinateResult -import io.github.sds100.keymapper.actions.tapscreen.PickCoordinateResult +import io.github.sds100.keymapper.base.R +import io.github.sds100.keymapper.base.actions.pinchscreen.PinchPickCoordinateResult +import io.github.sds100.keymapper.base.actions.swipescreen.SwipePickCoordinateResult +import io.github.sds100.keymapper.base.actions.tapscreen.PickCoordinateResult +import io.github.sds100.keymapper.base.system.intents.ConfigIntentResult +import io.github.sds100.keymapper.base.utils.DndModeStrings +import io.github.sds100.keymapper.base.utils.RingerModeStrings +import io.github.sds100.keymapper.base.utils.VolumeStreamStrings +import io.github.sds100.keymapper.base.utils.navigation.NavDestination +import io.github.sds100.keymapper.base.utils.navigation.NavigationProvider +import io.github.sds100.keymapper.base.utils.navigation.navigate +import io.github.sds100.keymapper.base.utils.ui.DialogModel +import io.github.sds100.keymapper.base.utils.ui.DialogProvider +import io.github.sds100.keymapper.base.utils.ui.MultiChoiceItem +import io.github.sds100.keymapper.base.utils.ui.ResourceProvider +import io.github.sds100.keymapper.base.utils.ui.showDialog +import io.github.sds100.keymapper.common.utils.Orientation import io.github.sds100.keymapper.system.camera.CameraLens -import io.github.sds100.keymapper.system.camera.CameraLensUtils -import io.github.sds100.keymapper.system.display.Orientation -import io.github.sds100.keymapper.system.display.OrientationUtils -import io.github.sds100.keymapper.system.intents.ConfigIntentResult import io.github.sds100.keymapper.system.network.HttpMethod import io.github.sds100.keymapper.system.volume.DndMode -import io.github.sds100.keymapper.system.volume.DndModeUtils import io.github.sds100.keymapper.system.volume.RingerMode -import io.github.sds100.keymapper.system.volume.RingerModeUtils import io.github.sds100.keymapper.system.volume.VolumeStream -import io.github.sds100.keymapper.system.volume.VolumeStreamUtils -import io.github.sds100.keymapper.util.ui.MultiChoiceItem -import io.github.sds100.keymapper.util.ui.NavDestination -import io.github.sds100.keymapper.util.ui.NavigationViewModel -import io.github.sds100.keymapper.util.ui.PopupUi -import io.github.sds100.keymapper.util.ui.PopupViewModel -import io.github.sds100.keymapper.util.ui.ResourceProvider -import io.github.sds100.keymapper.util.ui.navigate -import io.github.sds100.keymapper.util.ui.showPopup import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch - -/** - * Created by sds100 on 26/07/2021. - */ +import kotlinx.serialization.json.Json class CreateActionDelegate( private val coroutineScope: CoroutineScope, private val useCase: CreateActionUseCase, - popupViewModel: PopupViewModel, - navigationViewModelImpl: NavigationViewModel, + dialogProvider: DialogProvider, + navigationProvider: NavigationProvider, resourceProvider: ResourceProvider, ) : ResourceProvider by resourceProvider, - PopupViewModel by popupViewModel, - NavigationViewModel by navigationViewModelImpl { + DialogProvider by dialogProvider, + NavigationProvider by navigationProvider { val actionResult: MutableStateFlow = MutableStateFlow(null) var enableFlashlightActionState: EnableFlashlightActionState? by mutableStateOf(null) @@ -168,7 +163,7 @@ class CreateActionDelegate( } val imeId = - showPopup("choose_ime", PopupUi.SingleChoice(items)) ?: return null + showDialog("choose_ime", DialogModel.SingleChoice(items)) ?: return null val imeName = inputMethods.single { it.id == imeId }.label return ActionData.SwitchKeyboard(imeId, imeName) @@ -254,9 +249,9 @@ class CreateActionDelegate( ), ) - val showVolumeUiDialog = PopupUi.MultiChoice(items = dialogItems) + val showVolumeUiDialog = DialogModel.MultiChoice(items = dialogItems) - val chosenFlags = showPopup("show_volume_ui", showVolumeUiDialog) ?: return null + val chosenFlags = showDialog("show_volume_ui", showVolumeUiDialog) ?: return null val showVolumeUi = chosenFlags.contains(showVolumeUiId) @@ -293,17 +288,17 @@ class CreateActionDelegate( ), ) - val showVolumeUiDialog = PopupUi.MultiChoice(items = dialogItems) + val showVolumeUiDialog = DialogModel.MultiChoice(items = dialogItems) val chosenFlags = - showPopup("show_volume_ui", showVolumeUiDialog) ?: return null + showDialog("show_volume_ui", showVolumeUiDialog) ?: return null val showVolumeUi = chosenFlags.contains(showVolumeUiId) - val items = VolumeStream.values() - .map { it to getString(VolumeStreamUtils.getLabel(it)) } + val items = VolumeStream.entries + .map { it to getString(VolumeStreamStrings.getLabel(it)) } - val stream = showPopup("pick_volume_stream", PopupUi.SingleChoice(items)) + val stream = showDialog("pick_volume_stream", DialogModel.SingleChoice(items)) ?: return null val action = when (actionId) { @@ -320,11 +315,11 @@ class CreateActionDelegate( } ActionId.CHANGE_RINGER_MODE -> { - val items = RingerMode.values() - .map { it to getString(RingerModeUtils.getLabel(it)) } + val items = RingerMode.entries + .map { it to getString(RingerModeStrings.getLabel(it)) } val ringerMode = - showPopup("pick_ringer_mode", PopupUi.SingleChoice(items)) + showDialog("pick_ringer_mode", DialogModel.SingleChoice(items)) ?: return null return ActionData.Volume.SetRingerMode(ringerMode) @@ -334,11 +329,11 @@ class CreateActionDelegate( ActionId.TOGGLE_DND_MODE, ActionId.ENABLE_DND_MODE, -> { - val items = DndMode.values() - .map { it to getString(DndModeUtils.getLabel(it)) } + val items = DndMode.entries + .map { it to getString(DndModeStrings.getLabel(it)) } val dndMode = - showPopup("pick_dnd_mode", PopupUi.SingleChoice(items)) + showDialog("pick_dnd_mode", DialogModel.SingleChoice(items)) ?: return null val action = when (actionId) { @@ -360,15 +355,22 @@ class CreateActionDelegate( false } + val label = when (orientation) { + Orientation.ORIENTATION_0 -> R.string.orientation_0 + Orientation.ORIENTATION_90 -> R.string.orientation_90 + Orientation.ORIENTATION_180 -> R.string.orientation_180 + Orientation.ORIENTATION_270 -> R.string.orientation_270 + } + MultiChoiceItem( orientation, - getString(OrientationUtils.getLabel(orientation)), + getString(label), isChecked, ) } val orientations = - showPopup("pick_orientations", PopupUi.MultiChoice(items)) ?: return null + showDialog("pick_orientations", DialogModel.MultiChoice(items)) ?: return null return ActionData.Rotation.CycleRotations(orientations) } @@ -445,14 +447,17 @@ class CreateActionDelegate( ActionId.DISABLE_FLASHLIGHT, -> { - val items = useCase.getFlashlightLenses().map { - it to getString(CameraLensUtils.getLabel(it)) + val items = useCase.getFlashlightLenses().map { lens -> + when (lens) { + CameraLens.FRONT -> lens to getString(R.string.lens_front) + CameraLens.BACK -> lens to getString(R.string.lens_back) + } } if (items.size == 1) { return ActionData.Flashlight.Disable(items.first().first) } else { - val lens = showPopup("pick_lens", PopupUi.SingleChoice(items)) + val lens = showDialog("pick_lens", DialogModel.SingleChoice(items)) ?: return null return ActionData.Flashlight.Disable(lens) @@ -484,8 +489,7 @@ class CreateActionDelegate( ActionId.KEY_CODE -> { val keyCode = - navigate("choose_key_code", NavDestination.ChooseKeyCode) - ?: return null + navigate("choose_key_code", NavDestination.ChooseKeyCode) ?: return null return ActionData.InputKeyEvent(keyCode = keyCode) } @@ -610,9 +614,9 @@ class CreateActionDelegate( "" } - val text = showPopup( + val text = showDialog( "create_text_action", - PopupUi.Text( + DialogModel.Text( hint = getString(R.string.hint_create_text_action), allowEmpty = false, text = oldText, @@ -629,9 +633,9 @@ class CreateActionDelegate( "" } - val text = showPopup( + val text = showDialog( "create_url_action", - PopupUi.Text( + DialogModel.Text( hint = getString(R.string.hint_create_url_action), allowEmpty = false, inputType = InputType.TYPE_TEXT_VARIATION_URI, @@ -674,9 +678,9 @@ class CreateActionDelegate( "" } - val text = showPopup( + val text = showDialog( "create_phone_call_action", - PopupUi.Text( + DialogModel.Text( hint = getString(R.string.hint_create_phone_call_action), allowEmpty = false, inputType = InputType.TYPE_CLASS_PHONE, @@ -802,7 +806,7 @@ class CreateActionDelegate( return navigate( "config_interact_ui_element_action", - NavDestination.InteractUiElement(oldAction), + NavDestination.InteractUiElement(oldAction?.let { Json.encodeToString(it) }), ) } } diff --git a/app/src/main/java/io/github/sds100/keymapper/actions/CreateActionUseCase.kt b/base/src/main/java/io/github/sds100/keymapper/base/actions/CreateActionUseCase.kt similarity index 95% rename from app/src/main/java/io/github/sds100/keymapper/actions/CreateActionUseCase.kt rename to base/src/main/java/io/github/sds100/keymapper/base/actions/CreateActionUseCase.kt index 37ddcecac2..90ba5f6d72 100644 --- a/app/src/main/java/io/github/sds100/keymapper/actions/CreateActionUseCase.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/actions/CreateActionUseCase.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.actions +package io.github.sds100.keymapper.base.actions import io.github.sds100.keymapper.system.camera.CameraAdapter import io.github.sds100.keymapper.system.camera.CameraFlashInfo @@ -10,12 +10,9 @@ import io.github.sds100.keymapper.system.permissions.SystemFeatureAdapter import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.merge +import javax.inject.Inject -/** - * Created by sds100 on 25/07/2021. - */ - -class CreateActionUseCaseImpl( +class CreateActionUseCaseImpl @Inject constructor( private val inputMethodAdapter: InputMethodAdapter, private val systemFeatureAdapter: SystemFeatureAdapter, private val cameraAdapter: CameraAdapter, diff --git a/base/src/main/java/io/github/sds100/keymapper/base/actions/DisplayActionUseCase.kt b/base/src/main/java/io/github/sds100/keymapper/base/actions/DisplayActionUseCase.kt new file mode 100644 index 0000000000..ceb8958484 --- /dev/null +++ b/base/src/main/java/io/github/sds100/keymapper/base/actions/DisplayActionUseCase.kt @@ -0,0 +1,18 @@ +package io.github.sds100.keymapper.base.actions + +import android.graphics.drawable.Drawable +import io.github.sds100.keymapper.common.utils.KMError +import io.github.sds100.keymapper.common.utils.KMResult +import kotlinx.coroutines.flow.Flow + +interface DisplayActionUseCase : GetActionErrorUseCase { + val showDeviceDescriptors: Flow + fun getAppName(packageName: String): KMResult + fun getAppIcon(packageName: String): KMResult + fun getInputMethodLabel(imeId: String): KMResult + fun getRingtoneLabel(uri: String): KMResult + suspend fun fixError(error: KMError) + fun neverShowDndTriggerError() + fun startAccessibilityService(): Boolean + fun restartAccessibilityService(): Boolean +} diff --git a/app/src/main/java/io/github/sds100/keymapper/actions/FlashlightActionBottomSheet.kt b/base/src/main/java/io/github/sds100/keymapper/base/actions/FlashlightActionBottomSheet.kt similarity index 98% rename from app/src/main/java/io/github/sds100/keymapper/actions/FlashlightActionBottomSheet.kt rename to base/src/main/java/io/github/sds100/keymapper/base/actions/FlashlightActionBottomSheet.kt index 1482dd5327..13b4490d76 100644 --- a/app/src/main/java/io/github/sds100/keymapper/actions/FlashlightActionBottomSheet.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/actions/FlashlightActionBottomSheet.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.actions +package io.github.sds100.keymapper.base.actions import android.os.Build import androidx.compose.animation.AnimatedContent @@ -46,13 +46,13 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp -import io.github.sds100.keymapper.R -import io.github.sds100.keymapper.compose.KeyMapperTheme +import io.github.sds100.keymapper.base.R +import io.github.sds100.keymapper.base.compose.KeyMapperTheme +import io.github.sds100.keymapper.base.utils.ui.compose.KeyMapperSliderThumb +import io.github.sds100.keymapper.base.utils.ui.compose.OptionsHeaderRow +import io.github.sds100.keymapper.base.utils.ui.compose.RadioButtonText import io.github.sds100.keymapper.system.camera.CameraFlashInfo import io.github.sds100.keymapper.system.camera.CameraLens -import io.github.sds100.keymapper.util.ui.compose.KeyMapperSliderThumb -import io.github.sds100.keymapper.util.ui.compose.OptionsHeaderRow -import io.github.sds100.keymapper.util.ui.compose.RadioButtonText import kotlinx.coroutines.launch import kotlin.math.roundToInt diff --git a/app/src/main/java/io/github/sds100/keymapper/actions/GetActionErrorUseCase.kt b/base/src/main/java/io/github/sds100/keymapper/base/actions/GetActionErrorUseCase.kt similarity index 77% rename from app/src/main/java/io/github/sds100/keymapper/actions/GetActionErrorUseCase.kt rename to base/src/main/java/io/github/sds100/keymapper/base/actions/GetActionErrorUseCase.kt index ce8a18b9e1..d165b5025b 100644 --- a/app/src/main/java/io/github/sds100/keymapper/actions/GetActionErrorUseCase.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/actions/GetActionErrorUseCase.kt @@ -1,22 +1,26 @@ -package io.github.sds100.keymapper.actions +package io.github.sds100.keymapper.base.actions -import io.github.sds100.keymapper.actions.sound.SoundsManager -import io.github.sds100.keymapper.shizuku.ShizukuAdapter +import io.github.sds100.keymapper.base.actions.sound.SoundsManager +import io.github.sds100.keymapper.common.BuildConfigProvider import io.github.sds100.keymapper.system.apps.PackageManagerAdapter import io.github.sds100.keymapper.system.camera.CameraAdapter import io.github.sds100.keymapper.system.inputmethod.InputMethodAdapter import io.github.sds100.keymapper.system.permissions.PermissionAdapter import io.github.sds100.keymapper.system.permissions.SystemFeatureAdapter import io.github.sds100.keymapper.system.ringtones.RingtoneAdapter +import io.github.sds100.keymapper.system.shizuku.ShizukuAdapter import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.channelFlow import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.drop import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.merge +import javax.inject.Inject +import javax.inject.Singleton -class GetActionErrorUseCaseImpl( - private val packageManager: PackageManagerAdapter, +@Singleton +class GetActionErrorUseCaseImpl @Inject constructor( + private val packageManagerAdapter: PackageManagerAdapter, private val inputMethodAdapter: InputMethodAdapter, private val permissionAdapter: PermissionAdapter, private val systemFeatureAdapter: SystemFeatureAdapter, @@ -24,6 +28,7 @@ class GetActionErrorUseCaseImpl( private val soundsManager: SoundsManager, private val shizukuAdapter: ShizukuAdapter, private val ringtoneAdapter: RingtoneAdapter, + private val buildConfigProvider: BuildConfigProvider, ) : GetActionErrorUseCase { private val invalidateActionErrors = merge( @@ -34,7 +39,7 @@ class GetActionErrorUseCaseImpl( soundsManager.soundFiles.drop(1).map { }, shizukuAdapter.isStarted.drop(1).map { }, shizukuAdapter.isInstalled.drop(1).map { }, - packageManager.onPackagesChanged, + packageManagerAdapter.onPackagesChanged, ) override val actionErrorSnapshot: Flow = channelFlow { @@ -46,7 +51,7 @@ class GetActionErrorUseCaseImpl( } private fun createSnapshot(): ActionErrorSnapshot = LazyActionErrorSnapshot( - packageManager, + packageManagerAdapter, inputMethodAdapter, permissionAdapter, systemFeatureAdapter, @@ -54,6 +59,7 @@ class GetActionErrorUseCaseImpl( soundsManager, shizukuAdapter, ringtoneAdapter, + buildConfigProvider, ) } diff --git a/app/src/main/java/io/github/sds100/keymapper/actions/HoldDownMode.kt b/base/src/main/java/io/github/sds100/keymapper/base/actions/HoldDownMode.kt similarity index 61% rename from app/src/main/java/io/github/sds100/keymapper/actions/HoldDownMode.kt rename to base/src/main/java/io/github/sds100/keymapper/base/actions/HoldDownMode.kt index 886b5a2d68..cf10c89e7e 100644 --- a/app/src/main/java/io/github/sds100/keymapper/actions/HoldDownMode.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/actions/HoldDownMode.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.actions +package io.github.sds100.keymapper.base.actions enum class HoldDownMode { TRIGGER_RELEASED, diff --git a/app/src/main/java/io/github/sds100/keymapper/actions/HttpRequestBottomSheet.kt b/base/src/main/java/io/github/sds100/keymapper/base/actions/HttpRequestBottomSheet.kt similarity index 98% rename from app/src/main/java/io/github/sds100/keymapper/actions/HttpRequestBottomSheet.kt rename to base/src/main/java/io/github/sds100/keymapper/base/actions/HttpRequestBottomSheet.kt index 15d0063245..696b6f2f9f 100644 --- a/app/src/main/java/io/github/sds100/keymapper/actions/HttpRequestBottomSheet.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/actions/HttpRequestBottomSheet.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.actions +package io.github.sds100.keymapper.base.actions import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column @@ -37,10 +37,10 @@ import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp -import io.github.sds100.keymapper.R -import io.github.sds100.keymapper.compose.KeyMapperTheme +import io.github.sds100.keymapper.base.R +import io.github.sds100.keymapper.base.compose.KeyMapperTheme +import io.github.sds100.keymapper.base.utils.ui.compose.KeyMapperDropdownMenu import io.github.sds100.keymapper.system.network.HttpMethod -import io.github.sds100.keymapper.util.ui.compose.KeyMapperDropdownMenu import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch import okhttp3.HttpUrl.Companion.toHttpUrlOrNull diff --git a/app/src/main/java/io/github/sds100/keymapper/actions/IsActionSupportedUseCase.kt b/base/src/main/java/io/github/sds100/keymapper/base/actions/IsActionSupportedUseCase.kt similarity index 73% rename from app/src/main/java/io/github/sds100/keymapper/actions/IsActionSupportedUseCase.kt rename to base/src/main/java/io/github/sds100/keymapper/base/actions/IsActionSupportedUseCase.kt index b488ea686a..db65db77d6 100644 --- a/app/src/main/java/io/github/sds100/keymapper/actions/IsActionSupportedUseCase.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/actions/IsActionSupportedUseCase.kt @@ -1,13 +1,14 @@ -package io.github.sds100.keymapper.actions +package io.github.sds100.keymapper.base.actions import android.content.pm.PackageManager import android.os.Build +import io.github.sds100.keymapper.common.utils.KMError +import io.github.sds100.keymapper.system.SystemError import io.github.sds100.keymapper.system.camera.CameraAdapter import io.github.sds100.keymapper.system.camera.CameraLens import io.github.sds100.keymapper.system.permissions.Permission import io.github.sds100.keymapper.system.permissions.PermissionAdapter import io.github.sds100.keymapper.system.permissions.SystemFeatureAdapter -import io.github.sds100.keymapper.util.Error class IsActionSupportedUseCaseImpl( private val adapter: SystemFeatureAdapter, @@ -15,24 +16,24 @@ class IsActionSupportedUseCaseImpl( private val permissionAdapter: PermissionAdapter, ) : IsActionSupportedUseCase { - override fun isSupported(id: ActionId): Error? { + override fun isSupported(id: ActionId): KMError? { if (Build.VERSION.SDK_INT != 0) { val minApi = ActionUtils.getMinApi(id) if (Build.VERSION.SDK_INT < minApi) { - return Error.SdkVersionTooLow(minApi) + return KMError.SdkVersionTooLow(minApi) } val maxApi = ActionUtils.getMaxApi(id) if (Build.VERSION.SDK_INT > maxApi) { - return Error.SdkVersionTooHigh(maxApi) + return KMError.SdkVersionTooHigh(maxApi) } } ActionUtils.getRequiredSystemFeatures(id).forEach { feature -> if (!adapter.hasSystemFeature(feature)) { - return Error.SystemFeatureNotSupported(feature) + return KMError.SystemFeatureNotSupported(feature) } } @@ -40,7 +41,7 @@ class IsActionSupportedUseCaseImpl( if (cameraAdapter.getFlashInfo(CameraLens.BACK) == null && cameraAdapter.getFlashInfo(CameraLens.FRONT) == null ) { - return Error.SystemFeatureNotSupported(PackageManager.FEATURE_CAMERA_FLASH) + return KMError.SystemFeatureNotSupported(PackageManager.FEATURE_CAMERA_FLASH) } } @@ -48,7 +49,7 @@ class IsActionSupportedUseCaseImpl( if (cameraAdapter.getFlashInfo(CameraLens.BACK)?.supportsVariableStrength != true && cameraAdapter.getFlashInfo(CameraLens.FRONT)?.supportsVariableStrength != true ) { - return Error.CameraVariableFlashlightStrengthUnsupported + return KMError.CameraVariableFlashlightStrengthUnsupported } } @@ -56,7 +57,7 @@ class IsActionSupportedUseCaseImpl( .contains(Permission.ROOT) && !permissionAdapter.isGranted(Permission.ROOT) ) { - return Error.PermissionDenied(Permission.ROOT) + return SystemError.PermissionDenied(Permission.ROOT) } return null @@ -64,5 +65,5 @@ class IsActionSupportedUseCaseImpl( } interface IsActionSupportedUseCase { - fun isSupported(id: ActionId): Error? + fun isSupported(id: ActionId): KMError? } diff --git a/app/src/main/java/io/github/sds100/keymapper/actions/PerformActionsUseCase.kt b/base/src/main/java/io/github/sds100/keymapper/base/actions/PerformActionsUseCase.kt similarity index 77% rename from app/src/main/java/io/github/sds100/keymapper/actions/PerformActionsUseCase.kt rename to base/src/main/java/io/github/sds100/keymapper/base/actions/PerformActionsUseCase.kt index 11d66a7ae0..f90722be3c 100644 --- a/app/src/main/java/io/github/sds100/keymapper/actions/PerformActionsUseCase.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/actions/PerformActionsUseCase.kt @@ -1,19 +1,40 @@ -package io.github.sds100.keymapper.actions +package io.github.sds100.keymapper.base.actions import android.accessibilityservice.AccessibilityService import android.os.Build import android.view.InputDevice import android.view.KeyEvent import android.view.accessibility.AccessibilityNodeInfo -import io.github.sds100.keymapper.R -import io.github.sds100.keymapper.actions.sound.SoundsManager +import dagger.assisted.Assisted +import dagger.assisted.AssistedFactory +import dagger.assisted.AssistedInject +import io.github.sds100.keymapper.base.R +import io.github.sds100.keymapper.base.actions.sound.SoundsManager +import io.github.sds100.keymapper.base.system.accessibility.AccessibilityNodeAction +import io.github.sds100.keymapper.base.system.accessibility.AccessibilityNodeModel +import io.github.sds100.keymapper.base.system.accessibility.IAccessibilityService +import io.github.sds100.keymapper.base.system.inputmethod.ImeInputEventInjector +import io.github.sds100.keymapper.base.system.navigation.OpenMenuHelper +import io.github.sds100.keymapper.base.utils.getFullMessage +import io.github.sds100.keymapper.base.utils.ui.ResourceProvider +import io.github.sds100.keymapper.common.utils.InputEventType +import io.github.sds100.keymapper.common.utils.KMError +import io.github.sds100.keymapper.common.utils.KMResult +import io.github.sds100.keymapper.common.utils.Orientation +import io.github.sds100.keymapper.common.utils.Success +import io.github.sds100.keymapper.common.utils.dataOrNull +import io.github.sds100.keymapper.common.utils.firstBlocking +import io.github.sds100.keymapper.common.utils.getWordBoundaries +import io.github.sds100.keymapper.common.utils.ifIsData +import io.github.sds100.keymapper.common.utils.onFailure +import io.github.sds100.keymapper.common.utils.onSuccess +import io.github.sds100.keymapper.common.utils.otherwise +import io.github.sds100.keymapper.common.utils.success +import io.github.sds100.keymapper.common.utils.then +import io.github.sds100.keymapper.common.utils.withFlag import io.github.sds100.keymapper.data.Keys import io.github.sds100.keymapper.data.PreferenceDefaults import io.github.sds100.keymapper.data.repositories.PreferenceRepository -import io.github.sds100.keymapper.system.accessibility.AccessibilityNodeAction -import io.github.sds100.keymapper.system.accessibility.AccessibilityNodeModel -import io.github.sds100.keymapper.system.accessibility.IAccessibilityService -import io.github.sds100.keymapper.system.accessibility.ServiceAdapter import io.github.sds100.keymapper.system.airplanemode.AirplaneModeAdapter import io.github.sds100.keymapper.system.apps.AppShortcutAdapter import io.github.sds100.keymapper.system.apps.PackageManagerAdapter @@ -21,48 +42,31 @@ import io.github.sds100.keymapper.system.bluetooth.BluetoothAdapter import io.github.sds100.keymapper.system.camera.CameraAdapter import io.github.sds100.keymapper.system.devices.DevicesAdapter import io.github.sds100.keymapper.system.display.DisplayAdapter -import io.github.sds100.keymapper.system.display.Orientation import io.github.sds100.keymapper.system.files.FileAdapter import io.github.sds100.keymapper.system.files.FileUtils -import io.github.sds100.keymapper.system.inputevents.InputEventInjector import io.github.sds100.keymapper.system.inputevents.InputEventUtils -import io.github.sds100.keymapper.system.inputmethod.ImeInputEventInjector import io.github.sds100.keymapper.system.inputmethod.InputKeyModel import io.github.sds100.keymapper.system.inputmethod.InputMethodAdapter import io.github.sds100.keymapper.system.intents.IntentAdapter import io.github.sds100.keymapper.system.intents.IntentTarget import io.github.sds100.keymapper.system.lock.LockScreenAdapter import io.github.sds100.keymapper.system.media.MediaAdapter -import io.github.sds100.keymapper.system.navigation.OpenMenuHelper import io.github.sds100.keymapper.system.network.NetworkAdapter import io.github.sds100.keymapper.system.nfc.NfcAdapter +import io.github.sds100.keymapper.system.notifications.NotificationReceiverAdapter +import io.github.sds100.keymapper.system.notifications.NotificationServiceEvent import io.github.sds100.keymapper.system.permissions.Permission import io.github.sds100.keymapper.system.permissions.PermissionAdapter import io.github.sds100.keymapper.system.phone.PhoneAdapter -import io.github.sds100.keymapper.system.popup.PopupMessageAdapter +import io.github.sds100.keymapper.system.popup.ToastAdapter import io.github.sds100.keymapper.system.ringtones.RingtoneAdapter import io.github.sds100.keymapper.system.root.SuAdapter import io.github.sds100.keymapper.system.shell.ShellAdapter +import io.github.sds100.keymapper.system.shizuku.ShizukuInputEventInjector import io.github.sds100.keymapper.system.url.OpenUrlAdapter import io.github.sds100.keymapper.system.volume.RingerMode import io.github.sds100.keymapper.system.volume.VolumeAdapter import io.github.sds100.keymapper.system.volume.VolumeStream -import io.github.sds100.keymapper.util.Error -import io.github.sds100.keymapper.util.InputEventType -import io.github.sds100.keymapper.util.Result -import io.github.sds100.keymapper.util.ServiceEvent -import io.github.sds100.keymapper.util.Success -import io.github.sds100.keymapper.util.dataOrNull -import io.github.sds100.keymapper.util.firstBlocking -import io.github.sds100.keymapper.util.getFullMessage -import io.github.sds100.keymapper.util.getWordBoundaries -import io.github.sds100.keymapper.util.ifIsData -import io.github.sds100.keymapper.util.onFailure -import io.github.sds100.keymapper.util.onSuccess -import io.github.sds100.keymapper.util.otherwise -import io.github.sds100.keymapper.util.success -import io.github.sds100.keymapper.util.then -import io.github.sds100.keymapper.util.ui.ResourceProvider import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.delay import kotlinx.coroutines.flow.Flow @@ -71,30 +75,26 @@ import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn -import splitties.bitflags.withFlag import timber.log.Timber -/** - * Created by sds100 on 14/02/21. - */ - -class PerformActionsUseCaseImpl( - private val coroutineScope: CoroutineScope, - private val accessibilityService: IAccessibilityService, +class PerformActionsUseCaseImpl @AssistedInject constructor( + private val appCoroutineScope: CoroutineScope, + @Assisted + private val service: IAccessibilityService, private val inputMethodAdapter: InputMethodAdapter, private val fileAdapter: FileAdapter, private val suAdapter: SuAdapter, - private val shellAdapter: ShellAdapter, + private val shell: ShellAdapter, private val intentAdapter: IntentAdapter, - private val getActionError: GetActionErrorUseCase, - private val imeInputEventInjector: ImeInputEventInjector, - private val shizukuInputEventInjector: InputEventInjector, + private val getActionErrorUseCase: GetActionErrorUseCase, + @Assisted + private val keyMapperImeMessenger: ImeInputEventInjector, private val packageManagerAdapter: PackageManagerAdapter, private val appShortcutAdapter: AppShortcutAdapter, - private val popupMessageAdapter: PopupMessageAdapter, - private val deviceAdapter: DevicesAdapter, + private val toastAdapter: ToastAdapter, + private val devicesAdapter: DevicesAdapter, private val phoneAdapter: PhoneAdapter, - private val volumeAdapter: VolumeAdapter, + private val audioAdapter: VolumeAdapter, private val cameraAdapter: CameraAdapter, private val displayAdapter: DisplayAdapter, private val lockScreenAdapter: LockScreenAdapter, @@ -105,20 +105,30 @@ class PerformActionsUseCaseImpl( private val nfcAdapter: NfcAdapter, private val openUrlAdapter: OpenUrlAdapter, private val resourceProvider: ResourceProvider, - private val preferenceRepository: PreferenceRepository, private val soundsManager: SoundsManager, private val permissionAdapter: PermissionAdapter, - private val notificationReceiverAdapter: ServiceAdapter, + private val notificationReceiverAdapter: NotificationReceiverAdapter, private val ringtoneAdapter: RingtoneAdapter, + private val settingsRepository: PreferenceRepository, ) : PerformActionsUseCase { + @AssistedFactory + interface Factory { + fun create( + accessibilityService: IAccessibilityService, + imeInputEventInjector: ImeInputEventInjector, + ): PerformActionsUseCaseImpl + } + + private val shizukuInputEventInjector: ShizukuInputEventInjector = ShizukuInputEventInjector() + private val openMenuHelper by lazy { OpenMenuHelper( suAdapter, - accessibilityService, + service, shizukuInputEventInjector, permissionAdapter, - coroutineScope, + appCoroutineScope, ) } @@ -127,7 +137,7 @@ class PerformActionsUseCaseImpl( */ private val inputKeyEventsWithShizuku: StateFlow = permissionAdapter.isGrantedFlow(Permission.SHIZUKU) - .stateIn(coroutineScope, SharingStarted.Eagerly, false) + .stateIn(appCoroutineScope, SharingStarted.Eagerly, false) override suspend fun perform( action: ActionData, @@ -137,7 +147,7 @@ class PerformActionsUseCaseImpl( /** * Is null if the action is being performed asynchronously */ - val result: Result<*> + val result: KMResult<*> when (action) { is ActionData.App -> { @@ -179,7 +189,7 @@ class PerformActionsUseCaseImpl( action.useShell -> suAdapter.execute("input keyevent ${model.keyCode}") else -> { - imeInputEventInjector.inputKeyEvent(model) + keyMapperImeMessenger.inputKeyEvent(model) Success(Unit) } @@ -191,19 +201,19 @@ class PerformActionsUseCaseImpl( } is ActionData.DoNotDisturb.Enable -> { - result = volumeAdapter.enableDndMode(action.dndMode) + result = audioAdapter.enableDndMode(action.dndMode) } is ActionData.DoNotDisturb.Toggle -> { - result = if (volumeAdapter.isDndEnabled()) { - volumeAdapter.disableDndMode() + result = if (audioAdapter.isDndEnabled()) { + audioAdapter.disableDndMode() } else { - volumeAdapter.enableDndMode(action.dndMode) + audioAdapter.enableDndMode(action.dndMode) } } is ActionData.Volume.SetRingerMode -> { - result = volumeAdapter.setRingerMode(action.ringerMode) + result = audioAdapter.setRingerMode(action.ringerMode) } is ActionData.ControlMediaForApp.FastForward -> { @@ -286,50 +296,50 @@ class PerformActionsUseCaseImpl( R.string.toast_chose_keyboard, it.label, ) - popupMessageAdapter.showPopupMessage(message) + toastAdapter.show(message) } } is ActionData.Volume.Down -> { - result = volumeAdapter.lowerVolume(showVolumeUi = action.showVolumeUi) + result = audioAdapter.lowerVolume(showVolumeUi = action.showVolumeUi) } is ActionData.Volume.Up -> { - result = volumeAdapter.raiseVolume(showVolumeUi = action.showVolumeUi) + result = audioAdapter.raiseVolume(showVolumeUi = action.showVolumeUi) } is ActionData.Volume.Mute -> { - result = volumeAdapter.muteVolume(showVolumeUi = action.showVolumeUi) + result = audioAdapter.muteVolume(showVolumeUi = action.showVolumeUi) } is ActionData.Volume.Stream.Decrease -> { - result = volumeAdapter.lowerVolume( + result = audioAdapter.lowerVolume( stream = action.volumeStream, showVolumeUi = action.showVolumeUi, ) } is ActionData.Volume.Stream.Increase -> { - result = volumeAdapter.raiseVolume( + result = audioAdapter.raiseVolume( stream = action.volumeStream, showVolumeUi = action.showVolumeUi, ) } is ActionData.Volume.ToggleMute -> { - result = volumeAdapter.toggleMuteVolume(showVolumeUi = action.showVolumeUi) + result = audioAdapter.toggleMuteVolume(showVolumeUi = action.showVolumeUi) } is ActionData.Volume.UnMute -> { - result = volumeAdapter.unmuteVolume(showVolumeUi = action.showVolumeUi) + result = audioAdapter.unmuteVolume(showVolumeUi = action.showVolumeUi) } is ActionData.TapScreen -> { - result = accessibilityService.tapScreen(action.x, action.y, inputEventType) + result = service.tapScreen(action.x, action.y, inputEventType) } is ActionData.SwipeScreen -> { - result = accessibilityService.swipeScreen( + result = service.swipeScreen( action.xStart, action.yStart, action.xEnd, @@ -341,7 +351,7 @@ class PerformActionsUseCaseImpl( } is ActionData.PinchScreen -> { - result = accessibilityService.pinchScreen( + result = service.pinchScreen( action.x, action.y, action.distance, @@ -353,7 +363,7 @@ class PerformActionsUseCaseImpl( } is ActionData.Text -> { - imeInputEventInjector.inputText(action.text) + keyMapperImeMessenger.inputText(action.text) result = Success(Unit) } @@ -483,42 +493,42 @@ class PerformActionsUseCaseImpl( } is ActionData.Volume.CycleRingerMode -> { - result = when (volumeAdapter.ringerMode) { - RingerMode.NORMAL -> volumeAdapter.setRingerMode(RingerMode.VIBRATE) - RingerMode.VIBRATE -> volumeAdapter.setRingerMode(RingerMode.SILENT) - RingerMode.SILENT -> volumeAdapter.setRingerMode(RingerMode.NORMAL) + result = when (audioAdapter.ringerMode) { + RingerMode.NORMAL -> audioAdapter.setRingerMode(RingerMode.VIBRATE) + RingerMode.VIBRATE -> audioAdapter.setRingerMode(RingerMode.SILENT) + RingerMode.SILENT -> audioAdapter.setRingerMode(RingerMode.NORMAL) } } is ActionData.Volume.CycleVibrateRing -> { - result = when (volumeAdapter.ringerMode) { - RingerMode.NORMAL -> volumeAdapter.setRingerMode(RingerMode.VIBRATE) - RingerMode.VIBRATE -> volumeAdapter.setRingerMode(RingerMode.NORMAL) - RingerMode.SILENT -> volumeAdapter.setRingerMode(RingerMode.NORMAL) + result = when (audioAdapter.ringerMode) { + RingerMode.NORMAL -> audioAdapter.setRingerMode(RingerMode.VIBRATE) + RingerMode.VIBRATE -> audioAdapter.setRingerMode(RingerMode.NORMAL) + RingerMode.SILENT -> audioAdapter.setRingerMode(RingerMode.NORMAL) } } is ActionData.DoNotDisturb.Disable -> { - result = volumeAdapter.disableDndMode() + result = audioAdapter.disableDndMode() } is ActionData.StatusBar.ExpandNotifications -> { val globalAction = AccessibilityService.GLOBAL_ACTION_NOTIFICATIONS - result = accessibilityService.doGlobalAction(globalAction).otherwise { - shellAdapter.execute("cmd statusbar expand-notifications") + result = service.doGlobalAction(globalAction).otherwise { + shell.execute("cmd statusbar expand-notifications") } } is ActionData.StatusBar.ToggleNotifications -> { result = - if (accessibilityService.rootNode?.packageName == "com.android.systemui") { + if (service.rootNode?.packageName == "com.android.systemui") { closeStatusBarShade() } else { val globalAction = AccessibilityService.GLOBAL_ACTION_NOTIFICATIONS - accessibilityService.doGlobalAction(globalAction).otherwise { - shellAdapter.execute("cmd statusbar expand-notifications") + service.doGlobalAction(globalAction).otherwise { + shell.execute("cmd statusbar expand-notifications") } } } @@ -527,20 +537,20 @@ class PerformActionsUseCaseImpl( val globalAction = AccessibilityService.GLOBAL_ACTION_QUICK_SETTINGS result = - accessibilityService.doGlobalAction(globalAction).otherwise { - shellAdapter.execute("cmd statusbar expand-settings") + service.doGlobalAction(globalAction).otherwise { + shell.execute("cmd statusbar expand-settings") } } is ActionData.StatusBar.ToggleQuickSettings -> { result = - if (accessibilityService.rootNode?.packageName == "com.android.systemui") { + if (service.rootNode?.packageName == "com.android.systemui") { closeStatusBarShade() } else { val globalAction = AccessibilityService.GLOBAL_ACTION_QUICK_SETTINGS - accessibilityService.doGlobalAction(globalAction).otherwise { - shellAdapter.execute("cmd statusbar expand-settings") + service.doGlobalAction(globalAction).otherwise { + shell.execute("cmd statusbar expand-settings") } } } @@ -591,32 +601,32 @@ class PerformActionsUseCaseImpl( is ActionData.GoBack -> { result = - accessibilityService.doGlobalAction(AccessibilityService.GLOBAL_ACTION_BACK) + service.doGlobalAction(AccessibilityService.GLOBAL_ACTION_BACK) } is ActionData.GoHome -> { result = - accessibilityService.doGlobalAction(AccessibilityService.GLOBAL_ACTION_HOME) + service.doGlobalAction(AccessibilityService.GLOBAL_ACTION_HOME) } is ActionData.OpenRecents -> { result = - accessibilityService.doGlobalAction(AccessibilityService.GLOBAL_ACTION_RECENTS) + service.doGlobalAction(AccessibilityService.GLOBAL_ACTION_RECENTS) } is ActionData.ToggleSplitScreen -> { result = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - accessibilityService.doGlobalAction(AccessibilityService.GLOBAL_ACTION_TOGGLE_SPLIT_SCREEN) + service.doGlobalAction(AccessibilityService.GLOBAL_ACTION_TOGGLE_SPLIT_SCREEN) } else { - Error.SdkVersionTooLow(minSdk = Build.VERSION_CODES.N) + KMError.SdkVersionTooLow(minSdk = Build.VERSION_CODES.N) } } is ActionData.GoLastApp -> { - accessibilityService.doGlobalAction(AccessibilityService.GLOBAL_ACTION_RECENTS) + service.doGlobalAction(AccessibilityService.GLOBAL_ACTION_RECENTS) delay(100) result = - accessibilityService.doGlobalAction(AccessibilityService.GLOBAL_ACTION_RECENTS) + service.doGlobalAction(AccessibilityService.GLOBAL_ACTION_RECENTS) } is ActionData.OpenMenu -> { @@ -648,30 +658,30 @@ class PerformActionsUseCaseImpl( if (inputKeyEventsWithShizuku.value) { shizukuInputEventInjector.inputKeyEvent(keyModel) } else { - imeInputEventInjector.inputKeyEvent(keyModel) + keyMapperImeMessenger.inputKeyEvent(keyModel) } result = Success(Unit) } is ActionData.ToggleKeyboard -> { - val isHidden = accessibilityService.isKeyboardHidden.firstBlocking() + val isHidden = service.isKeyboardHidden.firstBlocking() if (isHidden) { - accessibilityService.showKeyboard() + service.showKeyboard() } else { - accessibilityService.hideKeyboard() + service.hideKeyboard() } result = Success(Unit) } is ActionData.ShowKeyboard -> { - accessibilityService.showKeyboard() + service.showKeyboard() result = Success(Unit) } is ActionData.HideKeyboard -> { - accessibilityService.hideKeyboard() + service.hideKeyboard() result = Success(Unit) } @@ -680,25 +690,25 @@ class PerformActionsUseCaseImpl( } is ActionData.CutText -> { - result = accessibilityService.performActionOnNode({ it.isFocused }) { + result = service.performActionOnNode({ it.isFocused }) { AccessibilityNodeAction(AccessibilityNodeInfo.ACTION_CUT) } } is ActionData.CopyText -> { - result = accessibilityService.performActionOnNode({ it.isFocused }) { + result = service.performActionOnNode({ it.isFocused }) { AccessibilityNodeAction(AccessibilityNodeInfo.ACTION_COPY) } } is ActionData.PasteText -> { - result = accessibilityService.performActionOnNode({ it.isFocused }) { + result = service.performActionOnNode({ it.isFocused }) { AccessibilityNodeAction(AccessibilityNodeInfo.ACTION_PASTE) } } is ActionData.SelectWordAtCursor -> { - result = accessibilityService.performActionOnNode({ it.isFocused }) { node -> + result = service.performActionOnNode({ it.isFocused }) { node -> // it is at the cursor position if they both return the same value if (node.textSelectionStart == node.textSelectionEnd) { val cursorPosition = node.textSelectionStart @@ -752,7 +762,7 @@ class PerformActionsUseCaseImpl( // Wait 3 seconds so the message isn't shown in the screenshot. delay(3000) - popupMessageAdapter.showPopupMessage( + toastAdapter.show( resourceProvider.getString( R.string.toast_screenshot_taken, ), @@ -760,7 +770,7 @@ class PerformActionsUseCaseImpl( } } else { result = - accessibilityService.doGlobalAction(AccessibilityService.GLOBAL_ACTION_TAKE_SCREENSHOT) + service.doGlobalAction(AccessibilityService.GLOBAL_ACTION_TAKE_SCREENSHOT) } } @@ -780,7 +790,7 @@ class PerformActionsUseCaseImpl( result = if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) { suAdapter.execute("input keyevent ${KeyEvent.KEYCODE_POWER}") } else { - accessibilityService.doGlobalAction(AccessibilityService.GLOBAL_ACTION_LOCK_SCREEN) + service.doGlobalAction(AccessibilityService.GLOBAL_ACTION_LOCK_SCREEN) } } @@ -802,19 +812,21 @@ class PerformActionsUseCaseImpl( is ActionData.ShowPowerMenu -> { result = - accessibilityService.doGlobalAction(AccessibilityService.GLOBAL_ACTION_POWER_DIALOG) + service.doGlobalAction(AccessibilityService.GLOBAL_ACTION_POWER_DIALOG) } is ActionData.Volume.ShowDialog -> { - result = volumeAdapter.showVolumeUi() + result = audioAdapter.showVolumeUi() } ActionData.DismissAllNotifications -> { - result = notificationReceiverAdapter.send(ServiceEvent.DismissAllNotifications) + result = + notificationReceiverAdapter.send(NotificationServiceEvent.DismissAllNotifications) } ActionData.DismissLastNotification -> { - result = notificationReceiverAdapter.send(ServiceEvent.DismissLastNotification) + result = + notificationReceiverAdapter.send(NotificationServiceEvent.DismissLastNotification) } ActionData.AnswerCall -> { @@ -845,22 +857,22 @@ class PerformActionsUseCaseImpl( } is ActionData.InteractUiElement -> { - if (accessibilityService.activeWindowPackage.first() != action.packageName) { - result = Error.UiElementNotFound + if (service.activeWindowPackage.first() != action.packageName) { + result = KMError.UiElementNotFound } else { - result = accessibilityService.performActionOnNode( + result = service.performActionOnNode( findNode = { node -> matchAccessibilityNode(node, action) }, performAction = { AccessibilityNodeAction(action = action.nodeAction.accessibilityActionId) }, - ).otherwise { Error.UiElementNotFound } + ).otherwise { KMError.UiElementNotFound } } } } when (result) { is Success -> Timber.d("Performed action $action, input event type: $inputEventType, key meta state: $keyMetaState") - is Error -> Timber.d( + is KMError -> Timber.d( "Failed to perform action $action, reason: ${result.getFullMessage(resourceProvider)}, action: $action, input event type: $inputEventType, key meta state: $keyMetaState", ) } @@ -869,21 +881,21 @@ class PerformActionsUseCaseImpl( } override fun getErrorSnapshot(): ActionErrorSnapshot { - return getActionError.actionErrorSnapshot.firstBlocking() + return getActionErrorUseCase.actionErrorSnapshot.firstBlocking() } override val defaultRepeatDelay: Flow = - preferenceRepository.get(Keys.defaultRepeatDelay) + settingsRepository.get(Keys.defaultRepeatDelay) .map { it ?: PreferenceDefaults.REPEAT_DELAY } .map { it.toLong() } override val defaultRepeatRate: Flow = - preferenceRepository.get(Keys.defaultRepeatRate) + settingsRepository.get(Keys.defaultRepeatRate) .map { it ?: PreferenceDefaults.REPEAT_RATE } .map { it.toLong() } override val defaultHoldDownDuration: Flow = - preferenceRepository.get(Keys.defaultHoldDownDuration) + settingsRepository.get(Keys.defaultHoldDownDuration) .map { it ?: PreferenceDefaults.HOLD_DOWN_DURATION } .map { it.toLong() } @@ -892,7 +904,7 @@ class PerformActionsUseCaseImpl( // automatically select a game controller as the input device for game controller key events if (InputEventUtils.isGamepadKeyCode(action.keyCode)) { - deviceAdapter.connectedInputDevices.value.ifIsData { inputDevices -> + devicesAdapter.connectedInputDevices.value.ifIsData { inputDevices -> val device = inputDevices.find { it.isGameController } if (device != null) { @@ -904,7 +916,7 @@ class PerformActionsUseCaseImpl( return 0 } - val inputDevices = deviceAdapter.connectedInputDevices.value + val inputDevices = devicesAdapter.connectedInputDevices.value val devicesWithSameDescriptor = inputDevices.dataOrNull() @@ -924,7 +936,7 @@ class PerformActionsUseCaseImpl( code. if none do then use the first one */ val deviceThatHasKey = devicesWithSameDescriptor.singleOrNull { - deviceAdapter.deviceHasKey(it.id, action.keyCode) + devicesAdapter.deviceHasKey(it.id, action.keyCode) } val device = deviceThatHasKey @@ -934,18 +946,18 @@ class PerformActionsUseCaseImpl( return device.id } - private fun closeStatusBarShade(): Result<*> { + private fun closeStatusBarShade(): KMResult<*> { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { - return accessibilityService + return service .doGlobalAction(AccessibilityService.GLOBAL_ACTION_DISMISS_NOTIFICATION_SHADE) } else { - return shellAdapter.execute("cmd statusbar collapse") + return shell.execute("cmd statusbar collapse") } } - private fun Result<*>.showErrorMessageOnFail() { + private fun KMResult<*>.showErrorMessageOnFail() { onFailure { - popupMessageAdapter.showPopupMessage(it.getFullMessage(resourceProvider)) + toastAdapter.show(it.getFullMessage(resourceProvider)) } } diff --git a/app/src/main/java/io/github/sds100/keymapper/actions/RepeatMode.kt b/base/src/main/java/io/github/sds100/keymapper/base/actions/RepeatMode.kt similarity index 52% rename from app/src/main/java/io/github/sds100/keymapper/actions/RepeatMode.kt rename to base/src/main/java/io/github/sds100/keymapper/base/actions/RepeatMode.kt index 5a6abc9631..e9eeb2ae76 100644 --- a/app/src/main/java/io/github/sds100/keymapper/actions/RepeatMode.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/actions/RepeatMode.kt @@ -1,8 +1,5 @@ -package io.github.sds100.keymapper.actions +package io.github.sds100.keymapper.base.actions -/** - * Created by sds100 on 15/05/2021. - */ enum class RepeatMode { TRIGGER_RELEASED, LIMIT_REACHED, diff --git a/base/src/main/java/io/github/sds100/keymapper/base/actions/TestActionEvent.kt b/base/src/main/java/io/github/sds100/keymapper/base/actions/TestActionEvent.kt new file mode 100644 index 0000000000..f6e061950d --- /dev/null +++ b/base/src/main/java/io/github/sds100/keymapper/base/actions/TestActionEvent.kt @@ -0,0 +1,7 @@ +package io.github.sds100.keymapper.base.actions + +import io.github.sds100.keymapper.system.accessibility.AccessibilityServiceEvent +import kotlinx.serialization.Serializable + +@Serializable +data class TestActionEvent(val action: ActionData) : AccessibilityServiceEvent() diff --git a/base/src/main/java/io/github/sds100/keymapper/base/actions/TestActionUseCase.kt b/base/src/main/java/io/github/sds100/keymapper/base/actions/TestActionUseCase.kt new file mode 100644 index 0000000000..5459f60f53 --- /dev/null +++ b/base/src/main/java/io/github/sds100/keymapper/base/actions/TestActionUseCase.kt @@ -0,0 +1,15 @@ +package io.github.sds100.keymapper.base.actions + +import io.github.sds100.keymapper.common.utils.KMResult +import io.github.sds100.keymapper.system.accessibility.AccessibilityServiceAdapter +import javax.inject.Inject + +class TestActionUseCaseImpl @Inject constructor( + private val serviceAdapter: AccessibilityServiceAdapter, +) : TestActionUseCase { + override suspend fun invoke(action: ActionData): KMResult<*> = serviceAdapter.send(TestActionEvent(action)) +} + +interface TestActionUseCase { + suspend operator fun invoke(action: ActionData): KMResult<*> +} diff --git a/app/src/main/java/io/github/sds100/keymapper/actions/keyevent/ChooseKeyCodeFragment.kt b/base/src/main/java/io/github/sds100/keymapper/base/actions/keyevent/ChooseKeyCodeFragment.kt similarity index 70% rename from app/src/main/java/io/github/sds100/keymapper/actions/keyevent/ChooseKeyCodeFragment.kt rename to base/src/main/java/io/github/sds100/keymapper/base/actions/keyevent/ChooseKeyCodeFragment.kt index 06ef9ba635..20ee488091 100644 --- a/app/src/main/java/io/github/sds100/keymapper/actions/keyevent/ChooseKeyCodeFragment.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/actions/keyevent/ChooseKeyCodeFragment.kt @@ -1,24 +1,21 @@ -package io.github.sds100.keymapper.actions.keyevent +package io.github.sds100.keymapper.base.actions.keyevent import androidx.fragment.app.viewModels import androidx.lifecycle.Lifecycle import androidx.navigation.fragment.navArgs import com.airbnb.epoxy.EpoxyRecyclerView -import io.github.sds100.keymapper.databinding.FragmentSimpleRecyclerviewBinding -import io.github.sds100.keymapper.simple -import io.github.sds100.keymapper.util.Inject -import io.github.sds100.keymapper.util.State -import io.github.sds100.keymapper.util.launchRepeatOnLifecycle -import io.github.sds100.keymapper.util.ui.RecyclerViewUtils -import io.github.sds100.keymapper.util.ui.SimpleListItemOld -import io.github.sds100.keymapper.util.ui.SimpleRecyclerViewFragment +import dagger.hilt.android.AndroidEntryPoint +import io.github.sds100.keymapper.base.databinding.FragmentSimpleRecyclerviewBinding +import io.github.sds100.keymapper.base.simple +import io.github.sds100.keymapper.base.utils.ui.RecyclerViewUtils +import io.github.sds100.keymapper.base.utils.ui.SimpleListItemOld +import io.github.sds100.keymapper.base.utils.ui.SimpleRecyclerViewFragment +import io.github.sds100.keymapper.base.utils.ui.launchRepeatOnLifecycle +import io.github.sds100.keymapper.common.utils.State import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.collectLatest -/** - * Created by sds100 on 30/03/2020. - */ - +@AndroidEntryPoint class ChooseKeyCodeFragment : SimpleRecyclerViewFragment() { companion object { const val EXTRA_KEYCODE = "extra_keycode" @@ -28,9 +25,8 @@ class ChooseKeyCodeFragment : SimpleRecyclerViewFragment() { override var searchStateKey: String? = SEARCH_STATE_KEY private val args: ChooseKeyCodeFragmentArgs by navArgs() - private val viewModel: ChooseKeyCodeViewModel by viewModels { - Inject.chooseKeyCodeViewModel() - } + + private val viewModel: ChooseKeyCodeViewModel by viewModels() override val listItems: Flow>> get() = viewModel.state @@ -40,7 +36,7 @@ class ChooseKeyCodeFragment : SimpleRecyclerViewFragment() { RecyclerViewUtils.applySimpleListItemDecorations(binding.epoxyRecyclerView) - viewLifecycleOwner.launchRepeatOnLifecycle(Lifecycle.State.RESUMED) { + viewLifecycleOwner.launchRepeatOnLifecycle(Lifecycle.State.CREATED) { viewModel.returnResult.collectLatest { returnResult(EXTRA_KEYCODE to it) } diff --git a/app/src/main/java/io/github/sds100/keymapper/actions/keyevent/ChooseKeyCodeViewModel.kt b/base/src/main/java/io/github/sds100/keymapper/base/actions/keyevent/ChooseKeyCodeViewModel.kt similarity index 75% rename from app/src/main/java/io/github/sds100/keymapper/actions/keyevent/ChooseKeyCodeViewModel.kt rename to base/src/main/java/io/github/sds100/keymapper/base/actions/keyevent/ChooseKeyCodeViewModel.kt index d6eed56979..67987c742a 100644 --- a/app/src/main/java/io/github/sds100/keymapper/actions/keyevent/ChooseKeyCodeViewModel.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/actions/keyevent/ChooseKeyCodeViewModel.kt @@ -1,14 +1,14 @@ -package io.github.sds100.keymapper.actions.keyevent +package io.github.sds100.keymapper.base.actions.keyevent import android.view.KeyEvent import androidx.lifecycle.ViewModel -import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.viewModelScope +import dagger.hilt.android.lifecycle.HiltViewModel +import io.github.sds100.keymapper.base.utils.filterByQuery +import io.github.sds100.keymapper.base.utils.ui.DefaultSimpleListItem +import io.github.sds100.keymapper.base.utils.ui.SimpleListItemOld +import io.github.sds100.keymapper.common.utils.State import io.github.sds100.keymapper.system.inputevents.InputEventUtils -import io.github.sds100.keymapper.util.State -import io.github.sds100.keymapper.util.filterByQuery -import io.github.sds100.keymapper.util.ui.DefaultSimpleListItem -import io.github.sds100.keymapper.util.ui.SimpleListItemOld import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow @@ -19,12 +19,10 @@ import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.flow import kotlinx.coroutines.launch import kotlinx.coroutines.withContext +import javax.inject.Inject -/** - * Created by sds100 on 31/03/2020. - */ - -class ChooseKeyCodeViewModel : ViewModel() { +@HiltViewModel +class ChooseKeyCodeViewModel @Inject constructor() : ViewModel() { val searchQuery = MutableStateFlow(null) @@ -67,10 +65,4 @@ class ChooseKeyCodeViewModel : ViewModel() { _returnResult.emit(id.toInt()) } } - - @Suppress("UNCHECKED_CAST") - class Factory : ViewModelProvider.NewInstanceFactory() { - - override fun create(modelClass: Class): T = ChooseKeyCodeViewModel() as T - } } diff --git a/app/src/main/java/io/github/sds100/keymapper/actions/keyevent/ConfigKeyEventActionFragment.kt b/base/src/main/java/io/github/sds100/keymapper/base/actions/keyevent/ConfigKeyEventActionFragment.kt similarity index 89% rename from app/src/main/java/io/github/sds100/keymapper/actions/keyevent/ConfigKeyEventActionFragment.kt rename to base/src/main/java/io/github/sds100/keymapper/base/actions/keyevent/ConfigKeyEventActionFragment.kt index 1f6dfcf81d..4f2b33a30b 100644 --- a/app/src/main/java/io/github/sds100/keymapper/actions/keyevent/ConfigKeyEventActionFragment.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/actions/keyevent/ConfigKeyEventActionFragment.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.actions.keyevent +package io.github.sds100.keymapper.base.actions.keyevent import android.os.Bundle import android.view.LayoutInflater @@ -16,21 +16,18 @@ import androidx.fragment.app.viewModels import androidx.lifecycle.Lifecycle import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.navArgs -import io.github.sds100.keymapper.R -import io.github.sds100.keymapper.databinding.FragmentConfigKeyEventBinding -import io.github.sds100.keymapper.ui.utils.putJsonSerializable -import io.github.sds100.keymapper.util.Inject -import io.github.sds100.keymapper.util.launchRepeatOnLifecycle -import io.github.sds100.keymapper.util.str -import io.github.sds100.keymapper.util.ui.configuredCheckBox -import io.github.sds100.keymapper.util.ui.setupNavigation +import dagger.hilt.android.AndroidEntryPoint +import io.github.sds100.keymapper.base.R +import io.github.sds100.keymapper.base.databinding.FragmentConfigKeyEventBinding +import io.github.sds100.keymapper.base.utils.navigation.setupFragmentNavigation +import io.github.sds100.keymapper.base.utils.ui.configuredCheckBox +import io.github.sds100.keymapper.base.utils.ui.launchRepeatOnLifecycle +import io.github.sds100.keymapper.base.utils.ui.str +import io.github.sds100.keymapper.common.utils.putJsonSerializable import kotlinx.coroutines.flow.collectLatest import kotlinx.serialization.json.Json -/** - * Created by sds100 on 30/03/2020. - */ - +@AndroidEntryPoint class ConfigKeyEventActionFragment : Fragment() { companion object { const val EXTRA_RESULT = "extra_result" @@ -40,9 +37,7 @@ class ConfigKeyEventActionFragment : Fragment() { private val requestKey: String by lazy { args.requestKey } - private val viewModel: ConfigKeyEventActionViewModel by viewModels { - Inject.configKeyEventViewModel(requireContext()) - } + private val viewModel: ConfigKeyEventActionViewModel by viewModels() /** * Scoped to the lifecycle of the fragment's view (between onCreateView and onDestroyView) @@ -62,7 +57,7 @@ class ConfigKeyEventActionFragment : Fragment() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - viewModel.setupNavigation(this) + viewModel.setupFragmentNavigation(this) if (args.keyEventAction != null) { viewModel.loadAction(Json.decodeFromString(args.keyEventAction!!)) diff --git a/app/src/main/java/io/github/sds100/keymapper/actions/keyevent/ConfigKeyEventActionViewModel.kt b/base/src/main/java/io/github/sds100/keymapper/base/actions/keyevent/ConfigKeyEventActionViewModel.kt similarity index 78% rename from app/src/main/java/io/github/sds100/keymapper/actions/keyevent/ConfigKeyEventActionViewModel.kt rename to base/src/main/java/io/github/sds100/keymapper/base/actions/keyevent/ConfigKeyEventActionViewModel.kt index 30d1236f18..02fd7545a0 100644 --- a/app/src/main/java/io/github/sds100/keymapper/actions/keyevent/ConfigKeyEventActionViewModel.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/actions/keyevent/ConfigKeyEventActionViewModel.kt @@ -1,30 +1,33 @@ -package io.github.sds100.keymapper.actions.keyevent +package io.github.sds100.keymapper.base.actions.keyevent import android.annotation.SuppressLint import android.view.KeyEvent import androidx.lifecycle.ViewModel -import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.viewModelScope -import io.github.sds100.keymapper.R -import io.github.sds100.keymapper.actions.ActionData +import dagger.hilt.android.lifecycle.HiltViewModel +import io.github.sds100.keymapper.base.R +import io.github.sds100.keymapper.base.actions.ActionData +import io.github.sds100.keymapper.base.utils.InputEventStrings +import io.github.sds100.keymapper.base.utils.getFullMessage +import io.github.sds100.keymapper.base.utils.navigation.NavDestination +import io.github.sds100.keymapper.base.utils.navigation.NavigationProvider +import io.github.sds100.keymapper.base.utils.navigation.NavigationProviderImpl +import io.github.sds100.keymapper.base.utils.navigation.navigate +import io.github.sds100.keymapper.base.utils.ui.CheckBoxListItem +import io.github.sds100.keymapper.base.utils.ui.ResourceProvider +import io.github.sds100.keymapper.common.utils.KMError +import io.github.sds100.keymapper.common.utils.KMResult +import io.github.sds100.keymapper.common.utils.Success +import io.github.sds100.keymapper.common.utils.errorOrNull +import io.github.sds100.keymapper.common.utils.handle +import io.github.sds100.keymapper.common.utils.hasFlag +import io.github.sds100.keymapper.common.utils.isSuccess +import io.github.sds100.keymapper.common.utils.minusFlag +import io.github.sds100.keymapper.common.utils.success +import io.github.sds100.keymapper.common.utils.valueOrNull +import io.github.sds100.keymapper.common.utils.withFlag import io.github.sds100.keymapper.system.devices.InputDeviceInfo import io.github.sds100.keymapper.system.devices.InputDeviceUtils -import io.github.sds100.keymapper.system.inputevents.InputEventUtils -import io.github.sds100.keymapper.util.Error -import io.github.sds100.keymapper.util.Result -import io.github.sds100.keymapper.util.Success -import io.github.sds100.keymapper.util.errorOrNull -import io.github.sds100.keymapper.util.getFullMessage -import io.github.sds100.keymapper.util.handle -import io.github.sds100.keymapper.util.isSuccess -import io.github.sds100.keymapper.util.success -import io.github.sds100.keymapper.util.ui.CheckBoxListItem -import io.github.sds100.keymapper.util.ui.NavDestination -import io.github.sds100.keymapper.util.ui.NavigationViewModel -import io.github.sds100.keymapper.util.ui.NavigationViewModelImpl -import io.github.sds100.keymapper.util.ui.ResourceProvider -import io.github.sds100.keymapper.util.ui.navigate -import io.github.sds100.keymapper.util.valueOrNull import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted @@ -34,20 +37,15 @@ import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch -import splitties.bitflags.hasFlag -import splitties.bitflags.minusFlag -import splitties.bitflags.withFlag +import javax.inject.Inject -/** - * Created by sds100 on 30/03/2020. - */ - -class ConfigKeyEventActionViewModel( +@HiltViewModel +class ConfigKeyEventActionViewModel @Inject constructor( private val useCase: ConfigKeyEventUseCase, - resourceProvider: ResourceProvider, + private val resourceProvider: ResourceProvider, ) : ViewModel(), ResourceProvider by resourceProvider, - NavigationViewModel by NavigationViewModelImpl() { + NavigationProvider by NavigationProviderImpl() { private val keyEventState = MutableStateFlow(KeyEventState()) @@ -115,8 +113,8 @@ class ConfigKeyEventActionViewModel( fun onKeyCodeTextChanged(text: String) { val keyCodeState = when { - text.isBlank() -> Error.EmptyText - text.toIntOrNull() == null -> Error.InvalidNumber + text.isBlank() -> KMError.EmptyText + text.toIntOrNull() == null -> KMError.InvalidNumber else -> text.toInt().success() } @@ -192,7 +190,7 @@ class ConfigKeyEventActionViewModel( onError = { "" }, ) - val modifierListItems = InputEventUtils.MODIFIER_LABELS.map { (modifier, label) -> + val modifierListItems = InputEventStrings.MODIFIER_LABELS.map { (modifier, label) -> CheckBoxListItem( id = modifier.toString(), label = getString(label), @@ -238,17 +236,8 @@ class ConfigKeyEventActionViewModel( ) } - @Suppress("UNCHECKED_CAST") - class Factory( - private val useCase: ConfigKeyEventUseCase, - private val resourceProvider: ResourceProvider, - ) : ViewModelProvider.NewInstanceFactory() { - - override fun create(modelClass: Class): T = ConfigKeyEventActionViewModel(useCase, resourceProvider) as T - } - private data class KeyEventState( - val keyCode: Result = Error.EmptyText, + val keyCode: KMResult = KMError.EmptyText, val chosenDevice: InputDeviceInfo? = null, val useShell: Boolean = false, val metaState: Int = 0, diff --git a/app/src/main/java/io/github/sds100/keymapper/actions/keyevent/ConfigKeyEventUseCase.kt b/base/src/main/java/io/github/sds100/keymapper/base/actions/keyevent/ConfigKeyEventUseCase.kt similarity index 83% rename from app/src/main/java/io/github/sds100/keymapper/actions/keyevent/ConfigKeyEventUseCase.kt rename to base/src/main/java/io/github/sds100/keymapper/base/actions/keyevent/ConfigKeyEventUseCase.kt index a5c13e898a..a304220fab 100644 --- a/app/src/main/java/io/github/sds100/keymapper/actions/keyevent/ConfigKeyEventUseCase.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/actions/keyevent/ConfigKeyEventUseCase.kt @@ -1,18 +1,15 @@ -package io.github.sds100.keymapper.actions.keyevent +package io.github.sds100.keymapper.base.actions.keyevent +import io.github.sds100.keymapper.common.utils.State import io.github.sds100.keymapper.data.Keys import io.github.sds100.keymapper.data.repositories.PreferenceRepository import io.github.sds100.keymapper.system.devices.DevicesAdapter import io.github.sds100.keymapper.system.devices.InputDeviceInfo -import io.github.sds100.keymapper.util.State import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.map +import javax.inject.Inject -/** - * Created by sds100 on 01/05/2021. - */ - -class ConfigKeyEventUseCaseImpl( +class ConfigKeyEventUseCaseImpl @Inject constructor( private val preferenceRepository: PreferenceRepository, private val devicesAdapter: DevicesAdapter, ) : ConfigKeyEventUseCase { diff --git a/app/src/main/java/io/github/sds100/keymapper/actions/pinchscreen/PinchPickCoordinateResult.kt b/base/src/main/java/io/github/sds100/keymapper/base/actions/pinchscreen/PinchPickCoordinateResult.kt similarity index 68% rename from app/src/main/java/io/github/sds100/keymapper/actions/pinchscreen/PinchPickCoordinateResult.kt rename to base/src/main/java/io/github/sds100/keymapper/base/actions/pinchscreen/PinchPickCoordinateResult.kt index b790c293b1..b3624183d4 100644 --- a/app/src/main/java/io/github/sds100/keymapper/actions/pinchscreen/PinchPickCoordinateResult.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/actions/pinchscreen/PinchPickCoordinateResult.kt @@ -1,12 +1,8 @@ -package io.github.sds100.keymapper.actions.pinchscreen +package io.github.sds100.keymapper.base.actions.pinchscreen +import io.github.sds100.keymapper.common.utils.PinchScreenType import kotlinx.serialization.Serializable -enum class PinchScreenType { - PINCH_IN, - PINCH_OUT, -} - @Serializable data class PinchPickCoordinateResult( val x: Int, diff --git a/app/src/main/java/io/github/sds100/keymapper/actions/pinchscreen/PinchPickDisplayCoordinateFragment.kt b/base/src/main/java/io/github/sds100/keymapper/base/actions/pinchscreen/PinchPickDisplayCoordinateFragment.kt similarity index 90% rename from app/src/main/java/io/github/sds100/keymapper/actions/pinchscreen/PinchPickDisplayCoordinateFragment.kt rename to base/src/main/java/io/github/sds100/keymapper/base/actions/pinchscreen/PinchPickDisplayCoordinateFragment.kt index 654619d14b..8ed81bd516 100644 --- a/app/src/main/java/io/github/sds100/keymapper/actions/pinchscreen/PinchPickDisplayCoordinateFragment.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/actions/pinchscreen/PinchPickDisplayCoordinateFragment.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.actions.pinchscreen +package io.github.sds100.keymapper.base.actions.pinchscreen import android.annotation.SuppressLint import android.graphics.Bitmap @@ -21,17 +21,16 @@ import androidx.fragment.app.viewModels import androidx.lifecycle.Lifecycle import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.navArgs -import io.github.sds100.keymapper.R -import io.github.sds100.keymapper.databinding.FragmentPinchPickCoordinatesBinding +import dagger.hilt.android.AndroidEntryPoint +import io.github.sds100.keymapper.base.R +import io.github.sds100.keymapper.base.databinding.FragmentPinchPickCoordinatesBinding +import io.github.sds100.keymapper.base.utils.ui.launchRepeatOnLifecycle +import io.github.sds100.keymapper.base.utils.ui.str import io.github.sds100.keymapper.system.files.FileUtils -import io.github.sds100.keymapper.util.Inject -import io.github.sds100.keymapper.util.launchRepeatOnLifecycle -import io.github.sds100.keymapper.util.str -import io.github.sds100.keymapper.util.ui.showPopups import kotlinx.coroutines.flow.collectLatest -import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json +@AndroidEntryPoint class PinchPickDisplayCoordinateFragment : Fragment() { companion object { const val EXTRA_RESULT = "extra_result" @@ -41,9 +40,7 @@ class PinchPickDisplayCoordinateFragment : Fragment() { private val requestKey: String by lazy { args.requestKey } private var pinchTypesDisplayValues = mutableListOf() - private val viewModel: PinchPickDisplayCoordinateViewModel by viewModels { - Inject.pinchCoordinateActionTypeViewModel(requireContext()) - } + private val viewModel: PinchPickDisplayCoordinateViewModel by viewModels() private val screenshotLauncher = registerForActivityResult(ActivityResultContracts.GetContent()) { uri -> @@ -113,7 +110,6 @@ class PinchPickDisplayCoordinateFragment : Fragment() { android.R.layout.simple_spinner_dropdown_item, pinchTypesDisplayValues, ) - viewModel.showPopups(this, binding) requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner) { findNavController().navigateUp() diff --git a/app/src/main/java/io/github/sds100/keymapper/actions/pinchscreen/PinchPickDisplayCoordinateViewModel.kt b/base/src/main/java/io/github/sds100/keymapper/base/actions/pinchscreen/PinchPickDisplayCoordinateViewModel.kt similarity index 89% rename from app/src/main/java/io/github/sds100/keymapper/actions/pinchscreen/PinchPickDisplayCoordinateViewModel.kt rename to base/src/main/java/io/github/sds100/keymapper/base/actions/pinchscreen/PinchPickDisplayCoordinateViewModel.kt index 5cff836fe5..4450f70f65 100644 --- a/app/src/main/java/io/github/sds100/keymapper/actions/pinchscreen/PinchPickDisplayCoordinateViewModel.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/actions/pinchscreen/PinchPickDisplayCoordinateViewModel.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.actions.pinchscreen +package io.github.sds100.keymapper.base.actions.pinchscreen import android.accessibilityservice.GestureDescription import android.graphics.Bitmap @@ -7,14 +7,14 @@ import android.os.Build import android.view.View import android.widget.AdapterView import androidx.lifecycle.ViewModel -import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.viewModelScope -import io.github.sds100.keymapper.R -import io.github.sds100.keymapper.util.ui.PopupUi -import io.github.sds100.keymapper.util.ui.PopupViewModel -import io.github.sds100.keymapper.util.ui.PopupViewModelImpl -import io.github.sds100.keymapper.util.ui.ResourceProvider -import io.github.sds100.keymapper.util.ui.showPopup +import dagger.hilt.android.lifecycle.HiltViewModel +import io.github.sds100.keymapper.base.R +import io.github.sds100.keymapper.base.utils.ui.DialogModel +import io.github.sds100.keymapper.base.utils.ui.DialogProvider +import io.github.sds100.keymapper.base.utils.ui.ResourceProvider +import io.github.sds100.keymapper.base.utils.ui.showDialog +import io.github.sds100.keymapper.common.utils.PinchScreenType import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted @@ -25,13 +25,16 @@ import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch +import javax.inject.Inject import kotlin.math.roundToInt -class PinchPickDisplayCoordinateViewModel( +@HiltViewModel +class PinchPickDisplayCoordinateViewModel @Inject constructor( resourceProvider: ResourceProvider, + dialogProvider: DialogProvider, ) : ViewModel(), ResourceProvider by resourceProvider, - PopupViewModel by PopupViewModelImpl() { + DialogProvider by dialogProvider { private val pinchTypes = arrayOf(PinchScreenType.PINCH_IN.name, PinchScreenType.PINCH_OUT.name) @@ -160,11 +163,11 @@ class PinchPickDisplayCoordinateViewModel( (displaySize.y != newBitmap.width && displaySize.x != newBitmap.height) ) { viewModelScope.launch { - val snackBar = PopupUi.SnackBar( + val snackBar = DialogModel.SnackBar( message = getString(R.string.toast_incorrect_screenshot_resolution), ) - showPopup("incorrect_resolution", snackBar) + showDialog("incorrect_resolution", snackBar) } return @@ -224,9 +227,9 @@ class PinchPickDisplayCoordinateViewModel( val fingerCount = fingerCount.value ?: return@launch val duration = duration.value ?: return@launch - val description = showPopup( + val description = showDialog( "coordinate_description", - PopupUi.Text( + DialogModel.Text( getString(R.string.hint_tap_coordinate_title), allowEmpty = true, text = description.value ?: "", @@ -269,13 +272,4 @@ class PinchPickDisplayCoordinateViewModel( super.onCleared() } - - @Suppress("UNCHECKED_CAST") - class Factory( - private val resourceProvider: ResourceProvider, - ) : ViewModelProvider.NewInstanceFactory() { - - override fun create(modelClass: Class): T = - PinchPickDisplayCoordinateViewModel(resourceProvider) as T - } } diff --git a/app/src/main/java/io/github/sds100/keymapper/actions/sound/ChooseSoundFileFragment.kt b/base/src/main/java/io/github/sds100/keymapper/base/actions/sound/ChooseSoundFileFragment.kt similarity index 91% rename from app/src/main/java/io/github/sds100/keymapper/actions/sound/ChooseSoundFileFragment.kt rename to base/src/main/java/io/github/sds100/keymapper/base/actions/sound/ChooseSoundFileFragment.kt index 9584e52bd0..ab1088467b 100644 --- a/app/src/main/java/io/github/sds100/keymapper/actions/sound/ChooseSoundFileFragment.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/actions/sound/ChooseSoundFileFragment.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.actions.sound +package io.github.sds100.keymapper.base.actions.sound import android.app.Activity import android.content.Intent @@ -21,21 +21,17 @@ import androidx.fragment.app.viewModels import androidx.lifecycle.Lifecycle import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.navArgs -import io.github.sds100.keymapper.databinding.FragmentChooseSoundFileBinding -import io.github.sds100.keymapper.simple +import dagger.hilt.android.AndroidEntryPoint +import io.github.sds100.keymapper.base.databinding.FragmentChooseSoundFileBinding +import io.github.sds100.keymapper.base.simple +import io.github.sds100.keymapper.base.utils.ui.launchRepeatOnLifecycle import io.github.sds100.keymapper.system.files.FileUtils -import io.github.sds100.keymapper.util.Inject -import io.github.sds100.keymapper.util.launchRepeatOnLifecycle -import io.github.sds100.keymapper.util.ui.showPopups import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.filterNotNull import kotlinx.coroutines.flow.update import kotlinx.serialization.json.Json -/** - * Created by sds100 on 22/06/2021. - */ - +@AndroidEntryPoint class ChooseSoundFileFragment : Fragment() { companion object { const val EXTRA_RESULT = "extra_sound_file_result" @@ -44,9 +40,7 @@ class ChooseSoundFileFragment : Fragment() { private val args: ChooseSoundFileFragmentArgs by navArgs() private val requestKey: String by lazy { args.requestKey } - private val viewModel: ChooseSoundFileViewModel by viewModels { - Inject.soundFileActionTypeViewModel(requireContext()) - } + private val viewModel: ChooseSoundFileViewModel by viewModels() private val chooseSoundFileLauncher = registerForActivityResult(ActivityResultContracts.GetContent()) { @@ -98,7 +92,6 @@ class ChooseSoundFileFragment : Fragment() { } binding.viewModel = viewModel - viewModel.showPopups(this, binding) viewLifecycleOwner.launchRepeatOnLifecycle(Lifecycle.State.RESUMED) { viewModel.chooseSoundFile.collectLatest { diff --git a/base/src/main/java/io/github/sds100/keymapper/base/actions/sound/ChooseSoundFileUseCase.kt b/base/src/main/java/io/github/sds100/keymapper/base/actions/sound/ChooseSoundFileUseCase.kt new file mode 100644 index 0000000000..7f6566006d --- /dev/null +++ b/base/src/main/java/io/github/sds100/keymapper/base/actions/sound/ChooseSoundFileUseCase.kt @@ -0,0 +1,37 @@ +package io.github.sds100.keymapper.base.actions.sound + +import io.github.sds100.keymapper.common.utils.KMError +import io.github.sds100.keymapper.common.utils.KMResult +import io.github.sds100.keymapper.common.utils.Success +import io.github.sds100.keymapper.system.files.FileAdapter +import kotlinx.coroutines.flow.StateFlow +import javax.inject.Inject + +class ChooseSoundFileUseCaseImpl @Inject constructor( + private val fileAdapter: FileAdapter, + private val soundsManager: SoundsManager, +) : ChooseSoundFileUseCase { + override val soundFiles = soundsManager.soundFiles + + override suspend fun saveSound(uri: String): KMResult = soundsManager.saveNewSound(uri) + + override fun getSoundFileName(uri: String): KMResult { + val name = fileAdapter.getFileFromUri(uri).name + + return if (name == null) { + KMError.NoFileName + } else { + Success(name) + } + } +} + +interface ChooseSoundFileUseCase { + + /** + * @return the sound file uid + */ + suspend fun saveSound(uri: String): KMResult + val soundFiles: StateFlow> + fun getSoundFileName(uri: String): KMResult +} diff --git a/app/src/main/java/io/github/sds100/keymapper/actions/sound/ChooseSoundFileViewModel.kt b/base/src/main/java/io/github/sds100/keymapper/base/actions/sound/ChooseSoundFileViewModel.kt similarity index 65% rename from app/src/main/java/io/github/sds100/keymapper/actions/sound/ChooseSoundFileViewModel.kt rename to base/src/main/java/io/github/sds100/keymapper/base/actions/sound/ChooseSoundFileViewModel.kt index 4967227dd6..f858528742 100644 --- a/app/src/main/java/io/github/sds100/keymapper/actions/sound/ChooseSoundFileViewModel.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/actions/sound/ChooseSoundFileViewModel.kt @@ -1,20 +1,19 @@ -package io.github.sds100.keymapper.actions.sound +package io.github.sds100.keymapper.base.actions.sound import androidx.lifecycle.ViewModel -import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.viewModelScope -import io.github.sds100.keymapper.R -import io.github.sds100.keymapper.actions.ActionData -import io.github.sds100.keymapper.util.getFullMessage -import io.github.sds100.keymapper.util.onFailure -import io.github.sds100.keymapper.util.onSuccess -import io.github.sds100.keymapper.util.ui.DefaultSimpleListItem -import io.github.sds100.keymapper.util.ui.PopupUi -import io.github.sds100.keymapper.util.ui.PopupViewModel -import io.github.sds100.keymapper.util.ui.PopupViewModelImpl -import io.github.sds100.keymapper.util.ui.ResourceProvider -import io.github.sds100.keymapper.util.ui.showPopup -import io.github.sds100.keymapper.util.valueOrNull +import dagger.hilt.android.lifecycle.HiltViewModel +import io.github.sds100.keymapper.base.R +import io.github.sds100.keymapper.base.actions.ActionData +import io.github.sds100.keymapper.base.utils.getFullMessage +import io.github.sds100.keymapper.base.utils.ui.DefaultSimpleListItem +import io.github.sds100.keymapper.base.utils.ui.DialogModel +import io.github.sds100.keymapper.base.utils.ui.DialogProvider +import io.github.sds100.keymapper.base.utils.ui.ResourceProvider +import io.github.sds100.keymapper.base.utils.ui.showDialog +import io.github.sds100.keymapper.common.utils.onFailure +import io.github.sds100.keymapper.common.utils.onSuccess +import io.github.sds100.keymapper.common.utils.valueOrNull import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted @@ -24,15 +23,15 @@ import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch +import javax.inject.Inject -/** - * Created by sds100 on 31/03/2020. - */ -class ChooseSoundFileViewModel( +@HiltViewModel +class ChooseSoundFileViewModel @Inject constructor( resourceProvider: ResourceProvider, + dialogProvider: DialogProvider, private val useCase: ChooseSoundFileUseCase, ) : ViewModel(), - PopupViewModel by PopupViewModelImpl(), + DialogProvider by dialogProvider, ResourceProvider by resourceProvider { private val _chooseSoundFile = MutableSharedFlow() @@ -67,13 +66,13 @@ class ChooseSoundFileViewModel( viewModelScope.launch { val soundFileInfo = useCase.soundFiles.value.find { it.uid == id } ?: return@launch - val dialog = PopupUi.Text( + val dialog = DialogModel.Text( hint = getString(R.string.hint_sound_file_description), allowEmpty = false, text = soundFileInfo.name, ) - val soundDescription = showPopup("file_description", dialog) ?: return@launch + val soundDescription = showDialog("file_description", dialog) ?: return@launch returnResult.update { ActionData.Sound.SoundFile( @@ -88,13 +87,13 @@ class ChooseSoundFileViewModel( viewModelScope.launch { val fileName = useCase.getSoundFileName(uri).valueOrNull() ?: return@launch - val dialog = PopupUi.Text( + val dialog = DialogModel.Text( hint = getString(R.string.hint_sound_file_description), allowEmpty = false, text = fileName, ) - val soundDescription = showPopup("file_description", dialog) + val soundDescription = showDialog("file_description", dialog) soundDescription ?: return@launch @@ -107,8 +106,8 @@ class ChooseSoundFileViewModel( ) } }.onFailure { error -> - val toast = PopupUi.Toast(error.getFullMessage(this@ChooseSoundFileViewModel)) - showPopup("failed_toast", toast) + val toast = DialogModel.Toast(error.getFullMessage(this@ChooseSoundFileViewModel)) + showDialog("failed_toast", toast) } } } @@ -118,13 +117,4 @@ class ChooseSoundFileViewModel( returnResult.update { ActionData.Sound.Ringtone(uri) } } } - - @Suppress("UNCHECKED_CAST") - class Factory( - private val resourceProvider: ResourceProvider, - private val useCase: ChooseSoundFileUseCase, - ) : ViewModelProvider.NewInstanceFactory() { - - override fun create(modelClass: Class): T = ChooseSoundFileViewModel(resourceProvider, useCase) as T - } } diff --git a/base/src/main/java/io/github/sds100/keymapper/base/actions/sound/SoundFileInfo.kt b/base/src/main/java/io/github/sds100/keymapper/base/actions/sound/SoundFileInfo.kt new file mode 100644 index 0000000000..a6faa7bf34 --- /dev/null +++ b/base/src/main/java/io/github/sds100/keymapper/base/actions/sound/SoundFileInfo.kt @@ -0,0 +1,3 @@ +package io.github.sds100.keymapper.base.actions.sound + +data class SoundFileInfo(val uid: String, val name: String) diff --git a/app/src/main/java/io/github/sds100/keymapper/actions/sound/SoundsManager.kt b/base/src/main/java/io/github/sds100/keymapper/base/actions/sound/SoundsManager.kt similarity index 69% rename from app/src/main/java/io/github/sds100/keymapper/actions/sound/SoundsManager.kt rename to base/src/main/java/io/github/sds100/keymapper/base/actions/sound/SoundsManager.kt index 8df6a65e38..a9ead62745 100644 --- a/app/src/main/java/io/github/sds100/keymapper/actions/sound/SoundsManager.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/actions/sound/SoundsManager.kt @@ -1,25 +1,24 @@ -package io.github.sds100.keymapper.actions.sound - +package io.github.sds100.keymapper.base.actions.sound + +import io.github.sds100.keymapper.common.utils.KMError +import io.github.sds100.keymapper.common.utils.KMResult +import io.github.sds100.keymapper.common.utils.Success +import io.github.sds100.keymapper.common.utils.onFailure +import io.github.sds100.keymapper.common.utils.onSuccess +import io.github.sds100.keymapper.common.utils.then import io.github.sds100.keymapper.system.files.FileAdapter import io.github.sds100.keymapper.system.files.IFile -import io.github.sds100.keymapper.util.Error -import io.github.sds100.keymapper.util.Result -import io.github.sds100.keymapper.util.Success -import io.github.sds100.keymapper.util.onFailure -import io.github.sds100.keymapper.util.onSuccess -import io.github.sds100.keymapper.util.then import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.launch import timber.log.Timber import java.util.UUID +import javax.inject.Inject +import javax.inject.Singleton -/** - * Created by sds100 on 24/06/2021. - */ - -class SoundsManagerImpl( +@Singleton +class SoundsManagerImpl @Inject constructor( private val coroutineScope: CoroutineScope, private val fileAdapter: FileAdapter, ) : SoundsManager { @@ -35,7 +34,7 @@ class SoundsManagerImpl( } } - override suspend fun saveNewSound(uri: String): Result { + override suspend fun saveNewSound(uri: String): KMResult { val uid = UUID.randomUUID().toString() val soundFile = fileAdapter.getFileFromUri(uri) @@ -48,13 +47,13 @@ class SoundsManagerImpl( .then { Success(uid) } .onSuccess { updateSoundFilesFlow() } .onFailure { - if (it is Error.Exception) { + if (it is KMError.Exception) { Timber.d(it.exception) } } } - override suspend fun restoreSound(file: IFile): Result<*> { + override suspend fun restoreSound(file: IFile): KMResult<*> { val soundsDir = fileAdapter.getPrivateFile(SOUNDS_DIR_NAME) soundsDir.createDirectory() @@ -69,20 +68,20 @@ class SoundsManagerImpl( } } - override fun getSound(uid: String): Result { + override fun getSound(uid: String): KMResult { val soundsDir = fileAdapter.getPrivateFile(SOUNDS_DIR_NAME) soundsDir.createDirectory() val matchingFile = soundsDir.listFiles()!!.find { it.name?.contains(uid) == true } if (matchingFile == null) { - return Error.CantFindSoundFile + return KMError.CantFindSoundFile } else { return Success(matchingFile) } } - override fun deleteSound(uid: String): Result<*> = getSound(uid) + override fun deleteSound(uid: String): KMResult<*> = getSound(uid) .then { Success(it.delete()) } .onSuccess { updateSoundFilesFlow() } @@ -106,12 +105,11 @@ class SoundsManagerImpl( .map { getSoundFileInfo(it.name!!) } } - private fun createSoundCopyFileName(originalSoundFile: IFile, uid: String): String = - buildString { - append(originalSoundFile.baseName) - append("_$uid") - append(".${originalSoundFile.extension}") - } + private fun createSoundCopyFileName(originalSoundFile: IFile, uid: String): String = buildString { + append(originalSoundFile.baseName) + append("_$uid") + append(".${originalSoundFile.extension}") + } } interface SoundsManager { @@ -120,8 +118,8 @@ interface SoundsManager { /** * @return the sound file uid */ - suspend fun saveNewSound(uri: String): Result - suspend fun restoreSound(file: IFile): Result<*> - fun getSound(uid: String): Result - fun deleteSound(uid: String): Result<*> + suspend fun saveNewSound(uri: String): KMResult + suspend fun restoreSound(file: IFile): KMResult<*> + fun getSound(uid: String): KMResult + fun deleteSound(uid: String): KMResult<*> } diff --git a/app/src/main/java/io/github/sds100/keymapper/actions/swipescreen/SwipePickCoordinateResult.kt b/base/src/main/java/io/github/sds100/keymapper/base/actions/swipescreen/SwipePickCoordinateResult.kt similarity index 81% rename from app/src/main/java/io/github/sds100/keymapper/actions/swipescreen/SwipePickCoordinateResult.kt rename to base/src/main/java/io/github/sds100/keymapper/base/actions/swipescreen/SwipePickCoordinateResult.kt index 0efe4ec64e..7f084200d0 100644 --- a/app/src/main/java/io/github/sds100/keymapper/actions/swipescreen/SwipePickCoordinateResult.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/actions/swipescreen/SwipePickCoordinateResult.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.actions.swipescreen +package io.github.sds100.keymapper.base.actions.swipescreen import kotlinx.serialization.Serializable diff --git a/app/src/main/java/io/github/sds100/keymapper/actions/swipescreen/SwipePickDisplayCoordinateFragment.kt b/base/src/main/java/io/github/sds100/keymapper/base/actions/swipescreen/SwipePickDisplayCoordinateFragment.kt similarity index 91% rename from app/src/main/java/io/github/sds100/keymapper/actions/swipescreen/SwipePickDisplayCoordinateFragment.kt rename to base/src/main/java/io/github/sds100/keymapper/base/actions/swipescreen/SwipePickDisplayCoordinateFragment.kt index cfebafa3a9..888ae4826f 100644 --- a/app/src/main/java/io/github/sds100/keymapper/actions/swipescreen/SwipePickDisplayCoordinateFragment.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/actions/swipescreen/SwipePickDisplayCoordinateFragment.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.actions.swipescreen +package io.github.sds100.keymapper.base.actions.swipescreen import android.annotation.SuppressLint import android.graphics.Bitmap @@ -20,15 +20,14 @@ import androidx.fragment.app.viewModels import androidx.lifecycle.Lifecycle import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.navArgs -import io.github.sds100.keymapper.databinding.FragmentSwipePickCoordinatesBinding +import dagger.hilt.android.AndroidEntryPoint +import io.github.sds100.keymapper.base.databinding.FragmentSwipePickCoordinatesBinding +import io.github.sds100.keymapper.base.utils.ui.launchRepeatOnLifecycle import io.github.sds100.keymapper.system.files.FileUtils -import io.github.sds100.keymapper.util.Inject -import io.github.sds100.keymapper.util.launchRepeatOnLifecycle -import io.github.sds100.keymapper.util.ui.showPopups import kotlinx.coroutines.flow.collectLatest -import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json +@AndroidEntryPoint class SwipePickDisplayCoordinateFragment : Fragment() { companion object { const val EXTRA_RESULT = "extra_result" @@ -37,9 +36,7 @@ class SwipePickDisplayCoordinateFragment : Fragment() { private val args: SwipePickDisplayCoordinateFragmentArgs by navArgs() private val requestKey: String by lazy { args.requestKey } - private val viewModel: SwipePickDisplayCoordinateViewModel by viewModels { - Inject.swipeCoordinateActionTypeViewModel(requireContext()) - } + private val viewModel: SwipePickDisplayCoordinateViewModel by viewModels() private val screenshotLauncher = registerForActivityResult(ActivityResultContracts.GetContent()) { uri -> @@ -99,8 +96,6 @@ class SwipePickDisplayCoordinateFragment : Fragment() { binding.viewModel = viewModel - viewModel.showPopups(this, binding) - requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner) { findNavController().navigateUp() } diff --git a/app/src/main/java/io/github/sds100/keymapper/actions/swipescreen/SwipePickDisplayCoordinateViewModel.kt b/base/src/main/java/io/github/sds100/keymapper/base/actions/swipescreen/SwipePickDisplayCoordinateViewModel.kt similarity index 89% rename from app/src/main/java/io/github/sds100/keymapper/actions/swipescreen/SwipePickDisplayCoordinateViewModel.kt rename to base/src/main/java/io/github/sds100/keymapper/base/actions/swipescreen/SwipePickDisplayCoordinateViewModel.kt index 6fbfe7cf64..c5afe9ad3f 100644 --- a/app/src/main/java/io/github/sds100/keymapper/actions/swipescreen/SwipePickDisplayCoordinateViewModel.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/actions/swipescreen/SwipePickDisplayCoordinateViewModel.kt @@ -1,18 +1,17 @@ -package io.github.sds100.keymapper.actions.swipescreen +package io.github.sds100.keymapper.base.actions.swipescreen import android.accessibilityservice.GestureDescription import android.graphics.Bitmap import android.graphics.Point import android.os.Build import androidx.lifecycle.ViewModel -import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.viewModelScope -import io.github.sds100.keymapper.R -import io.github.sds100.keymapper.util.ui.PopupUi -import io.github.sds100.keymapper.util.ui.PopupViewModel -import io.github.sds100.keymapper.util.ui.PopupViewModelImpl -import io.github.sds100.keymapper.util.ui.ResourceProvider -import io.github.sds100.keymapper.util.ui.showPopup +import dagger.hilt.android.lifecycle.HiltViewModel +import io.github.sds100.keymapper.base.R +import io.github.sds100.keymapper.base.utils.ui.DialogModel +import io.github.sds100.keymapper.base.utils.ui.DialogProvider +import io.github.sds100.keymapper.base.utils.ui.ResourceProvider +import io.github.sds100.keymapper.base.utils.ui.showDialog import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted @@ -23,6 +22,7 @@ import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch +import javax.inject.Inject import kotlin.math.roundToInt enum class ScreenshotTouchType { @@ -30,11 +30,13 @@ enum class ScreenshotTouchType { END, } -class SwipePickDisplayCoordinateViewModel( +@HiltViewModel +class SwipePickDisplayCoordinateViewModel @Inject constructor( resourceProvider: ResourceProvider, + dialogProvider: DialogProvider, ) : ViewModel(), ResourceProvider by resourceProvider, - PopupViewModel by PopupViewModelImpl() { + DialogProvider by dialogProvider { val screenshotTouchTypeStart = ScreenshotTouchType.START val screenshotTouchTypeEnd = ScreenshotTouchType.END @@ -162,11 +164,11 @@ class SwipePickDisplayCoordinateViewModel( (displaySize.y != newBitmap.width && displaySize.x != newBitmap.height) ) { viewModelScope.launch { - val snackBar = PopupUi.SnackBar( + val snackBar = DialogModel.SnackBar( message = getString(R.string.toast_incorrect_screenshot_resolution), ) - showPopup("incorrect_resolution", snackBar) + showDialog("incorrect_resolution", snackBar) } return @@ -231,9 +233,9 @@ class SwipePickDisplayCoordinateViewModel( val fingerCount = fingerCount.value ?: return@launch val duration = duration.value ?: return@launch - val description = showPopup( + val description = showDialog( "coordinate_description", - PopupUi.Text( + DialogModel.Text( getString(R.string.hint_tap_coordinate_title), allowEmpty = true, text = description.value ?: "", @@ -272,13 +274,4 @@ class SwipePickDisplayCoordinateViewModel( super.onCleared() } - - @Suppress("UNCHECKED_CAST") - class Factory( - private val resourceProvider: ResourceProvider, - ) : ViewModelProvider.NewInstanceFactory() { - - override fun create(modelClass: Class): T = - SwipePickDisplayCoordinateViewModel(resourceProvider) as T - } } diff --git a/app/src/main/java/io/github/sds100/keymapper/actions/tapscreen/PickCoordinateImageView.kt b/base/src/main/java/io/github/sds100/keymapper/base/actions/tapscreen/PickCoordinateImageView.kt similarity index 90% rename from app/src/main/java/io/github/sds100/keymapper/actions/tapscreen/PickCoordinateImageView.kt rename to base/src/main/java/io/github/sds100/keymapper/base/actions/tapscreen/PickCoordinateImageView.kt index 04e72d5bdc..fcbd125cf2 100644 --- a/app/src/main/java/io/github/sds100/keymapper/actions/tapscreen/PickCoordinateImageView.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/actions/tapscreen/PickCoordinateImageView.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.actions.tapscreen +package io.github.sds100.keymapper.base.actions.tapscreen import android.content.Context import android.graphics.Canvas @@ -7,14 +7,11 @@ import android.graphics.Point import android.util.AttributeSet import android.view.MotionEvent import androidx.appcompat.widget.AppCompatImageView -import io.github.sds100.keymapper.R -import io.github.sds100.keymapper.util.color +import io.github.sds100.keymapper.base.R +import io.github.sds100.keymapper.base.utils.ui.color import kotlinx.coroutines.flow.MutableStateFlow import kotlin.math.roundToInt -/** - * Created by sds100 on 08/08/20. - */ class PickCoordinateImageView( context: Context, attrs: AttributeSet?, diff --git a/app/src/main/java/io/github/sds100/keymapper/actions/tapscreen/PickCoordinateResult.kt b/base/src/main/java/io/github/sds100/keymapper/base/actions/tapscreen/PickCoordinateResult.kt similarity index 58% rename from app/src/main/java/io/github/sds100/keymapper/actions/tapscreen/PickCoordinateResult.kt rename to base/src/main/java/io/github/sds100/keymapper/base/actions/tapscreen/PickCoordinateResult.kt index cdb05e20b3..8c45352d20 100644 --- a/app/src/main/java/io/github/sds100/keymapper/actions/tapscreen/PickCoordinateResult.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/actions/tapscreen/PickCoordinateResult.kt @@ -1,9 +1,6 @@ -package io.github.sds100.keymapper.actions.tapscreen +package io.github.sds100.keymapper.base.actions.tapscreen import kotlinx.serialization.Serializable -/** - * Created by sds100 on 25/03/2021. - */ @Serializable data class PickCoordinateResult(val x: Int, val y: Int, val description: String) diff --git a/app/src/main/java/io/github/sds100/keymapper/actions/tapscreen/PickDisplayCoordinateFragment.kt b/base/src/main/java/io/github/sds100/keymapper/base/actions/tapscreen/PickDisplayCoordinateFragment.kt similarity index 90% rename from app/src/main/java/io/github/sds100/keymapper/actions/tapscreen/PickDisplayCoordinateFragment.kt rename to base/src/main/java/io/github/sds100/keymapper/base/actions/tapscreen/PickDisplayCoordinateFragment.kt index 173e483c29..1de00aca0f 100644 --- a/app/src/main/java/io/github/sds100/keymapper/actions/tapscreen/PickDisplayCoordinateFragment.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/actions/tapscreen/PickDisplayCoordinateFragment.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.actions.tapscreen +package io.github.sds100.keymapper.base.actions.tapscreen import android.annotation.SuppressLint import android.graphics.Bitmap @@ -20,19 +20,14 @@ import androidx.fragment.app.viewModels import androidx.lifecycle.Lifecycle import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.navArgs -import io.github.sds100.keymapper.databinding.FragmentPickCoordinateBinding +import dagger.hilt.android.AndroidEntryPoint +import io.github.sds100.keymapper.base.databinding.FragmentPickCoordinateBinding +import io.github.sds100.keymapper.base.utils.ui.launchRepeatOnLifecycle import io.github.sds100.keymapper.system.files.FileUtils -import io.github.sds100.keymapper.util.Inject -import io.github.sds100.keymapper.util.launchRepeatOnLifecycle -import io.github.sds100.keymapper.util.ui.showPopups import kotlinx.coroutines.flow.collectLatest -import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json -/** - * Created by sds100 on 30/03/2020. - */ - +@AndroidEntryPoint class PickDisplayCoordinateFragment : Fragment() { companion object { const val EXTRA_RESULT = "extra_result" @@ -41,9 +36,7 @@ class PickDisplayCoordinateFragment : Fragment() { private val args: PickDisplayCoordinateFragmentArgs by navArgs() private val requestKey: String by lazy { args.requestKey } - private val viewModel: PickDisplayCoordinateViewModel by viewModels { - Inject.tapCoordinateActionTypeViewModel(requireContext()) - } + private val viewModel: PickDisplayCoordinateViewModel by viewModels() private val screenshotLauncher = registerForActivityResult(ActivityResultContracts.GetContent()) { uri -> @@ -103,8 +96,6 @@ class PickDisplayCoordinateFragment : Fragment() { binding.viewModel = viewModel - viewModel.showPopups(this, binding) - requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner) { findNavController().navigateUp() } diff --git a/app/src/main/java/io/github/sds100/keymapper/actions/tapscreen/PickDisplayCoordinateViewModel.kt b/base/src/main/java/io/github/sds100/keymapper/base/actions/tapscreen/PickDisplayCoordinateViewModel.kt similarity index 78% rename from app/src/main/java/io/github/sds100/keymapper/actions/tapscreen/PickDisplayCoordinateViewModel.kt rename to base/src/main/java/io/github/sds100/keymapper/base/actions/tapscreen/PickDisplayCoordinateViewModel.kt index 98a8be7e09..86afc6dc0f 100644 --- a/app/src/main/java/io/github/sds100/keymapper/actions/tapscreen/PickDisplayCoordinateViewModel.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/actions/tapscreen/PickDisplayCoordinateViewModel.kt @@ -1,16 +1,15 @@ -package io.github.sds100.keymapper.actions.tapscreen +package io.github.sds100.keymapper.base.actions.tapscreen import android.graphics.Bitmap import android.graphics.Point import androidx.lifecycle.ViewModel -import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.viewModelScope -import io.github.sds100.keymapper.R -import io.github.sds100.keymapper.util.ui.PopupUi -import io.github.sds100.keymapper.util.ui.PopupViewModel -import io.github.sds100.keymapper.util.ui.PopupViewModelImpl -import io.github.sds100.keymapper.util.ui.ResourceProvider -import io.github.sds100.keymapper.util.ui.showPopup +import dagger.hilt.android.lifecycle.HiltViewModel +import io.github.sds100.keymapper.base.R +import io.github.sds100.keymapper.base.utils.ui.DialogModel +import io.github.sds100.keymapper.base.utils.ui.DialogProvider +import io.github.sds100.keymapper.base.utils.ui.ResourceProvider +import io.github.sds100.keymapper.base.utils.ui.showDialog import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted @@ -21,17 +20,16 @@ import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch +import javax.inject.Inject import kotlin.math.roundToInt -/** - * Created by sds100 on 03/08/20. - */ - -class PickDisplayCoordinateViewModel( +@HiltViewModel +class PickDisplayCoordinateViewModel @Inject constructor( resourceProvider: ResourceProvider, + dialogProvider: DialogProvider, ) : ViewModel(), ResourceProvider by resourceProvider, - PopupViewModel by PopupViewModelImpl() { + DialogProvider by dialogProvider { private val x = MutableStateFlow(null) private val y = MutableStateFlow(null) @@ -69,11 +67,11 @@ class PickDisplayCoordinateViewModel( (displaySize.y != newBitmap.width && displaySize.x != newBitmap.height) ) { viewModelScope.launch { - val snackBar = PopupUi.SnackBar( + val snackBar = DialogModel.SnackBar( message = getString(R.string.toast_incorrect_screenshot_resolution), ) - showPopup("incorrect_resolution", snackBar) + showDialog("incorrect_resolution", snackBar) } return @@ -109,9 +107,9 @@ class PickDisplayCoordinateViewModel( val x = x.value ?: return@launch val y = y.value ?: return@launch - val description = showPopup( + val description = showDialog( "coordinate_description", - PopupUi.Text( + DialogModel.Text( getString(R.string.hint_tap_coordinate_title), allowEmpty = true, text = description.value ?: "", @@ -136,13 +134,4 @@ class PickDisplayCoordinateViewModel( super.onCleared() } - - @Suppress("UNCHECKED_CAST") - class Factory( - private val resourceProvider: ResourceProvider, - ) : ViewModelProvider.NewInstanceFactory() { - - override fun create(modelClass: Class): T = - PickDisplayCoordinateViewModel(resourceProvider) as T - } } diff --git a/app/src/main/java/io/github/sds100/keymapper/actions/uielement/ChooseUiElementScreen.kt b/base/src/main/java/io/github/sds100/keymapper/base/actions/uielement/ChooseUiElementScreen.kt similarity index 96% rename from app/src/main/java/io/github/sds100/keymapper/actions/uielement/ChooseUiElementScreen.kt rename to base/src/main/java/io/github/sds100/keymapper/base/actions/uielement/ChooseUiElementScreen.kt index 340f304358..7da4fd9033 100644 --- a/app/src/main/java/io/github/sds100/keymapper/actions/uielement/ChooseUiElementScreen.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/actions/uielement/ChooseUiElementScreen.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.actions.uielement +package io.github.sds100.keymapper.base.actions.uielement import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box @@ -49,13 +49,14 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.window.core.layout.WindowHeightSizeClass import androidx.window.core.layout.WindowWidthSizeClass -import io.github.sds100.keymapper.R -import io.github.sds100.keymapper.compose.KeyMapperTheme -import io.github.sds100.keymapper.util.State -import io.github.sds100.keymapper.util.ui.compose.CheckBoxText -import io.github.sds100.keymapper.util.ui.compose.KeyMapperDropdownMenu -import io.github.sds100.keymapper.util.ui.compose.SearchAppBarActions -import io.github.sds100.keymapper.util.ui.compose.WindowSizeClassExt.compareTo +import io.github.sds100.keymapper.base.R +import io.github.sds100.keymapper.base.compose.KeyMapperTheme +import io.github.sds100.keymapper.base.utils.ui.compose.CheckBoxText +import io.github.sds100.keymapper.base.utils.ui.compose.KeyMapperDropdownMenu +import io.github.sds100.keymapper.base.utils.ui.compose.SearchAppBarActions +import io.github.sds100.keymapper.base.utils.ui.compose.WindowSizeClassExt.compareTo +import io.github.sds100.keymapper.common.utils.NodeInteractionType +import io.github.sds100.keymapper.common.utils.State @Composable fun ChooseElementScreen( diff --git a/app/src/main/java/io/github/sds100/keymapper/actions/uielement/InteractUiElementScreen.kt b/base/src/main/java/io/github/sds100/keymapper/base/actions/uielement/InteractUiElementScreen.kt similarity index 95% rename from app/src/main/java/io/github/sds100/keymapper/actions/uielement/InteractUiElementScreen.kt rename to base/src/main/java/io/github/sds100/keymapper/base/actions/uielement/InteractUiElementScreen.kt index 7ff879f499..30c0d792c5 100644 --- a/app/src/main/java/io/github/sds100/keymapper/actions/uielement/InteractUiElementScreen.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/actions/uielement/InteractUiElementScreen.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.actions.uielement +package io.github.sds100.keymapper.base.actions.uielement import androidx.activity.compose.BackHandler import androidx.compose.animation.AnimatedContentTransitionScope @@ -69,19 +69,20 @@ import androidx.navigation.compose.rememberNavController import androidx.window.core.layout.WindowHeightSizeClass import androidx.window.core.layout.WindowWidthSizeClass import com.google.accompanist.drawablepainter.rememberDrawablePainter -import io.github.sds100.keymapper.R -import io.github.sds100.keymapper.compose.KeyMapperTheme -import io.github.sds100.keymapper.compose.LocalCustomColorsPalette -import io.github.sds100.keymapper.system.apps.ChooseAppScreen -import io.github.sds100.keymapper.util.State -import io.github.sds100.keymapper.util.drawable -import io.github.sds100.keymapper.util.ui.compose.ComposeIconInfo -import io.github.sds100.keymapper.util.ui.compose.KeyMapperDropdownMenu -import io.github.sds100.keymapper.util.ui.compose.OptionsHeaderRow -import io.github.sds100.keymapper.util.ui.compose.WindowSizeClassExt.compareTo -import io.github.sds100.keymapper.util.ui.compose.icons.AdGroup -import io.github.sds100.keymapper.util.ui.compose.icons.JumpToElement -import io.github.sds100.keymapper.util.ui.compose.icons.KeyMapperIcons +import io.github.sds100.keymapper.base.R +import io.github.sds100.keymapper.base.compose.KeyMapperTheme +import io.github.sds100.keymapper.base.compose.LocalCustomColorsPalette +import io.github.sds100.keymapper.base.system.apps.ChooseAppScreen +import io.github.sds100.keymapper.base.utils.ui.compose.ComposeIconInfo +import io.github.sds100.keymapper.base.utils.ui.compose.KeyMapperDropdownMenu +import io.github.sds100.keymapper.base.utils.ui.compose.OptionsHeaderRow +import io.github.sds100.keymapper.base.utils.ui.compose.WindowSizeClassExt.compareTo +import io.github.sds100.keymapper.base.utils.ui.compose.icons.AdGroup +import io.github.sds100.keymapper.base.utils.ui.compose.icons.JumpToElement +import io.github.sds100.keymapper.base.utils.ui.compose.icons.KeyMapperIcons +import io.github.sds100.keymapper.base.utils.ui.drawable +import io.github.sds100.keymapper.common.utils.NodeInteractionType +import io.github.sds100.keymapper.common.utils.State import kotlinx.coroutines.flow.update private const val DEST_LANDING = "landing" @@ -92,7 +93,6 @@ private const val DEST_SELECT_ELEMENT = "select_element" fun InteractUiElementScreen( modifier: Modifier = Modifier, viewModel: InteractUiElementViewModel, - navigateBack: () -> Unit, ) { val navController = rememberNavController() @@ -107,7 +107,7 @@ fun InteractUiElementScreen( val onBackClick = { if (!navController.navigateUp()) { - navigateBack() + viewModel.onBackClick() } } @@ -381,11 +381,11 @@ private fun RecordingSection( openSelectAppScreen: () -> Unit = {}, ) { Column(modifier = modifier) { - when (state) { + when (val state = state) { is State.Data -> { - val interactionCount: Int = when (state.data) { - is RecordUiElementState.CountingDown -> state.data.interactionCount - is RecordUiElementState.Recorded -> state.data.interactionCount + val interactionCount: Int = when (val data = state.data) { + is RecordUiElementState.CountingDown -> data.interactionCount + is RecordUiElementState.Recorded -> data.interactionCount RecordUiElementState.Empty -> 0 } diff --git a/app/src/main/java/io/github/sds100/keymapper/actions/uielement/InteractUiElementUseCase.kt b/base/src/main/java/io/github/sds100/keymapper/base/actions/uielement/InteractUiElementUseCase.kt similarity index 64% rename from app/src/main/java/io/github/sds100/keymapper/actions/uielement/InteractUiElementUseCase.kt rename to base/src/main/java/io/github/sds100/keymapper/base/actions/uielement/InteractUiElementUseCase.kt index 9a325f22f3..e97be98810 100644 --- a/app/src/main/java/io/github/sds100/keymapper/actions/uielement/InteractUiElementUseCase.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/actions/uielement/InteractUiElementUseCase.kt @@ -1,16 +1,16 @@ -package io.github.sds100.keymapper.actions.uielement +package io.github.sds100.keymapper.base.actions.uielement import android.graphics.drawable.Drawable +import io.github.sds100.keymapper.base.system.accessibility.RecordAccessibilityNodeEvent +import io.github.sds100.keymapper.base.system.accessibility.RecordAccessibilityNodeState +import io.github.sds100.keymapper.common.utils.KMResult +import io.github.sds100.keymapper.common.utils.State +import io.github.sds100.keymapper.common.utils.mapData +import io.github.sds100.keymapper.common.utils.onFailure import io.github.sds100.keymapper.data.entities.AccessibilityNodeEntity import io.github.sds100.keymapper.data.repositories.AccessibilityNodeRepository -import io.github.sds100.keymapper.system.accessibility.RecordAccessibilityNodeState -import io.github.sds100.keymapper.system.accessibility.ServiceAdapter +import io.github.sds100.keymapper.system.accessibility.AccessibilityServiceAdapter import io.github.sds100.keymapper.system.apps.PackageManagerAdapter -import io.github.sds100.keymapper.util.Result -import io.github.sds100.keymapper.util.ServiceEvent -import io.github.sds100.keymapper.util.State -import io.github.sds100.keymapper.util.mapData -import io.github.sds100.keymapper.util.onFailure import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow @@ -20,10 +20,13 @@ import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.update +import javax.inject.Inject +import javax.inject.Singleton -class InteractUiElementController( +@Singleton +class InteractUiElementController @Inject constructor( private val coroutineScope: CoroutineScope, - private val serviceAdapter: ServiceAdapter, + private val serviceAdapter: AccessibilityServiceAdapter, private val nodeRepository: AccessibilityNodeRepository, private val packageManagerAdapter: PackageManagerAdapter, ) : InteractUiElementUseCase { @@ -41,7 +44,7 @@ class InteractUiElementController( init { serviceAdapter.eventReceiver - .filterIsInstance() + .filterIsInstance() .onEach { event -> recordState.update { event.state } } .launchIn(coroutineScope) } @@ -58,17 +61,17 @@ class InteractUiElementController( return nodeRepository.get(id) } - override fun getAppName(packageName: String): Result = packageManagerAdapter.getAppName(packageName) + override fun getAppName(packageName: String): KMResult = packageManagerAdapter.getAppName(packageName) - override fun getAppIcon(packageName: String): Result = packageManagerAdapter.getAppIcon(packageName) + override fun getAppIcon(packageName: String): KMResult = packageManagerAdapter.getAppIcon(packageName) - override suspend fun startRecording(): Result<*> { + override suspend fun startRecording(): KMResult<*> { nodeRepository.deleteAll() - return serviceAdapter.send(ServiceEvent.StartRecordingNodes) + return serviceAdapter.send(RecordAccessibilityNodeEvent.StartRecordingNodes) } override suspend fun stopRecording() { - serviceAdapter.send(ServiceEvent.StopRecordingNodes).onFailure { + serviceAdapter.send(RecordAccessibilityNodeEvent.StopRecordingNodes).onFailure { recordState.update { RecordAccessibilityNodeState.Idle } } } @@ -86,10 +89,10 @@ interface InteractUiElementUseCase { fun getInteractionsByPackage(packageName: String): Flow>> suspend fun getInteractionById(id: Long): AccessibilityNodeEntity? - fun getAppName(packageName: String): Result - fun getAppIcon(packageName: String): Result + fun getAppName(packageName: String): KMResult + fun getAppIcon(packageName: String): KMResult - suspend fun startRecording(): Result<*> + suspend fun startRecording(): KMResult<*> suspend fun stopRecording() fun startService(): Boolean diff --git a/app/src/main/java/io/github/sds100/keymapper/actions/uielement/InteractUiElementViewModel.kt b/base/src/main/java/io/github/sds100/keymapper/base/actions/uielement/InteractUiElementViewModel.kt similarity index 88% rename from app/src/main/java/io/github/sds100/keymapper/actions/uielement/InteractUiElementViewModel.kt rename to base/src/main/java/io/github/sds100/keymapper/base/actions/uielement/InteractUiElementViewModel.kt index 67dcac391c..b6d3f180a4 100644 --- a/app/src/main/java/io/github/sds100/keymapper/actions/uielement/InteractUiElementViewModel.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/actions/uielement/InteractUiElementViewModel.kt @@ -1,38 +1,36 @@ -package io.github.sds100.keymapper.actions.uielement +package io.github.sds100.keymapper.base.actions.uielement import androidx.compose.material.icons.Icons import androidx.compose.material.icons.rounded.Android import androidx.lifecycle.ViewModel -import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.viewModelScope -import io.github.sds100.keymapper.R -import io.github.sds100.keymapper.actions.ActionData +import dagger.hilt.android.lifecycle.HiltViewModel +import io.github.sds100.keymapper.base.R +import io.github.sds100.keymapper.base.actions.ActionData +import io.github.sds100.keymapper.base.system.accessibility.RecordAccessibilityNodeState +import io.github.sds100.keymapper.base.utils.containsQuery +import io.github.sds100.keymapper.base.utils.navigation.NavigationProvider +import io.github.sds100.keymapper.base.utils.ui.DialogProvider +import io.github.sds100.keymapper.base.utils.ui.ResourceProvider +import io.github.sds100.keymapper.base.utils.ui.ViewModelHelper +import io.github.sds100.keymapper.base.utils.ui.compose.ComposeIconInfo +import io.github.sds100.keymapper.base.utils.ui.compose.SimpleListItemModel +import io.github.sds100.keymapper.common.utils.KMError +import io.github.sds100.keymapper.common.utils.NodeInteractionType +import io.github.sds100.keymapper.common.utils.State +import io.github.sds100.keymapper.common.utils.Success +import io.github.sds100.keymapper.common.utils.dataOrNull +import io.github.sds100.keymapper.common.utils.ifIsData +import io.github.sds100.keymapper.common.utils.mapData +import io.github.sds100.keymapper.common.utils.onFailure +import io.github.sds100.keymapper.common.utils.then +import io.github.sds100.keymapper.common.utils.valueOrNull import io.github.sds100.keymapper.data.entities.AccessibilityNodeEntity -import io.github.sds100.keymapper.system.accessibility.RecordAccessibilityNodeState -import io.github.sds100.keymapper.util.Error -import io.github.sds100.keymapper.util.State -import io.github.sds100.keymapper.util.Success -import io.github.sds100.keymapper.util.containsQuery -import io.github.sds100.keymapper.util.dataOrNull -import io.github.sds100.keymapper.util.ifIsData -import io.github.sds100.keymapper.util.mapData -import io.github.sds100.keymapper.util.onFailure -import io.github.sds100.keymapper.util.then -import io.github.sds100.keymapper.util.ui.PopupViewModel -import io.github.sds100.keymapper.util.ui.PopupViewModelImpl -import io.github.sds100.keymapper.util.ui.ResourceProvider -import io.github.sds100.keymapper.util.ui.ViewModelHelper -import io.github.sds100.keymapper.util.ui.compose.ComposeIconInfo -import io.github.sds100.keymapper.util.ui.compose.SimpleListItemModel -import io.github.sds100.keymapper.util.valueOrNull import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.SharedFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow -import kotlinx.coroutines.flow.asSharedFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.filterNotNull @@ -42,17 +40,20 @@ import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch +import kotlinx.serialization.json.Json import java.util.Locale +import javax.inject.Inject -class InteractUiElementViewModel( +@HiltViewModel +class InteractUiElementViewModel @Inject constructor( private val useCase: InteractUiElementUseCase, - private val resourceProvider: ResourceProvider, + resourceProvider: ResourceProvider, + dialogProvider: DialogProvider, + navigationProvider: NavigationProvider, ) : ViewModel(), - ResourceProvider by resourceProvider, - PopupViewModel by PopupViewModelImpl() { - - private val _returnAction: MutableSharedFlow = MutableSharedFlow() - val returnAction: SharedFlow = _returnAction.asSharedFlow() + NavigationProvider by navigationProvider, + DialogProvider by dialogProvider, + ResourceProvider by resourceProvider { val recordState: StateFlow> = combine( useCase.recordState, @@ -250,7 +251,13 @@ class InteractUiElementViewModel( ) viewModelScope.launch { - _returnAction.emit(action) + popBackStackWithResult(Json.encodeToString(action)) + } + } + + fun onBackClick() { + viewModelScope.launch { + popBackStack() } } @@ -338,13 +345,13 @@ class InteractUiElementViewModel( private suspend fun startRecording() { useCase.startRecording().onFailure { error -> - if (error == Error.AccessibilityServiceDisabled) { + if (error == KMError.AccessibilityServiceDisabled) { ViewModelHelper.handleAccessibilityServiceStoppedDialog( this, this, startService = { useCase.startService() }, ) - } else if (error == Error.AccessibilityServiceCrashed) { + } else if (error == KMError.AccessibilityServiceCrashed) { ViewModelHelper.handleAccessibilityServiceCrashedDialog( this, this, @@ -408,16 +415,6 @@ class InteractUiElementViewModel( NodeInteractionType.COLLAPSE -> getString(R.string.action_interact_ui_element_interaction_type_collapse) } } - - @Suppress("UNCHECKED_CAST") - class Factory( - private val useCase: InteractUiElementUseCase, - private val resourceProvider: ResourceProvider, - ) : ViewModelProvider.NewInstanceFactory() { - override fun create(modelClass: Class): T { - return InteractUiElementViewModel(useCase, resourceProvider) as T - } - } } data class SelectedUiElementState( diff --git a/app/src/main/java/io/github/sds100/keymapper/backup/BackupContent.kt b/base/src/main/java/io/github/sds100/keymapper/base/backup/BackupContent.kt similarity index 98% rename from app/src/main/java/io/github/sds100/keymapper/backup/BackupContent.kt rename to base/src/main/java/io/github/sds100/keymapper/base/backup/BackupContent.kt index 07a71956d1..da11d2b829 100644 --- a/app/src/main/java/io/github/sds100/keymapper/backup/BackupContent.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/backup/BackupContent.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.backup +package io.github.sds100.keymapper.base.backup import com.google.gson.annotations.SerializedName import io.github.sds100.keymapper.data.entities.FloatingButtonEntity diff --git a/app/src/main/java/io/github/sds100/keymapper/backup/BackupManager.kt b/base/src/main/java/io/github/sds100/keymapper/base/backup/BackupManager.kt similarity index 91% rename from app/src/main/java/io/github/sds100/keymapper/backup/BackupManager.kt rename to base/src/main/java/io/github/sds100/keymapper/base/backup/BackupManager.kt index bb82002476..84a81aa5ff 100644 --- a/app/src/main/java/io/github/sds100/keymapper/backup/BackupManager.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/backup/BackupManager.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.backup +package io.github.sds100.keymapper.base.backup import com.github.salomonbrys.kotson.byInt import com.github.salomonbrys.kotson.byNullableArray @@ -14,8 +14,20 @@ import com.google.gson.JsonArray import com.google.gson.JsonParser import com.google.gson.JsonSyntaxException import com.google.gson.stream.MalformedJsonException -import io.github.sds100.keymapper.Constants -import io.github.sds100.keymapper.actions.sound.SoundsManager +import io.github.sds100.keymapper.base.actions.sound.SoundsManager +import io.github.sds100.keymapper.common.BuildConfigProvider +import io.github.sds100.keymapper.common.utils.DefaultDispatcherProvider +import io.github.sds100.keymapper.common.utils.DefaultUuidGenerator +import io.github.sds100.keymapper.common.utils.DispatcherProvider +import io.github.sds100.keymapper.common.utils.KMError +import io.github.sds100.keymapper.common.utils.KMResult +import io.github.sds100.keymapper.common.utils.State +import io.github.sds100.keymapper.common.utils.Success +import io.github.sds100.keymapper.common.utils.TreeNode +import io.github.sds100.keymapper.common.utils.UuidGenerator +import io.github.sds100.keymapper.common.utils.breadFirstTraversal +import io.github.sds100.keymapper.common.utils.onFailure +import io.github.sds100.keymapper.common.utils.then import io.github.sds100.keymapper.data.Keys import io.github.sds100.keymapper.data.PreferenceDefaults import io.github.sds100.keymapper.data.db.AppDatabase @@ -42,23 +54,11 @@ import io.github.sds100.keymapper.data.migration.fingerprintmaps.FingerprintToKe import io.github.sds100.keymapper.data.repositories.FloatingButtonRepository import io.github.sds100.keymapper.data.repositories.FloatingLayoutRepository import io.github.sds100.keymapper.data.repositories.GroupRepository +import io.github.sds100.keymapper.data.repositories.KeyMapRepository import io.github.sds100.keymapper.data.repositories.PreferenceRepository import io.github.sds100.keymapper.data.repositories.RepositoryUtils -import io.github.sds100.keymapper.keymaps.KeyMapRepository import io.github.sds100.keymapper.system.files.FileAdapter import io.github.sds100.keymapper.system.files.IFile -import io.github.sds100.keymapper.util.DefaultDispatcherProvider -import io.github.sds100.keymapper.util.DefaultUuidGenerator -import io.github.sds100.keymapper.util.DispatcherProvider -import io.github.sds100.keymapper.util.Error -import io.github.sds100.keymapper.util.Result -import io.github.sds100.keymapper.util.State -import io.github.sds100.keymapper.util.Success -import io.github.sds100.keymapper.util.TreeNode -import io.github.sds100.keymapper.util.UuidGenerator -import io.github.sds100.keymapper.util.breadFirstTraversal -import io.github.sds100.keymapper.util.onFailure -import io.github.sds100.keymapper.util.then import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableSharedFlow @@ -74,12 +74,11 @@ import java.io.IOException import java.io.InputStream import java.util.LinkedList import java.util.UUID +import javax.inject.Inject +import javax.inject.Singleton -/** - * Created by sds100 on 16/03/2021. - */ - -class BackupManagerImpl( +@Singleton +class BackupManagerImpl @Inject constructor( private val coroutineScope: CoroutineScope, private val fileAdapter: FileAdapter, private val keyMapRepository: KeyMapRepository, @@ -88,9 +87,9 @@ class BackupManagerImpl( private val floatingButtonRepository: FloatingButtonRepository, private val groupRepository: GroupRepository, private val soundsManager: SoundsManager, - private val throwExceptions: Boolean = false, private val dispatchers: DispatcherProvider = DefaultDispatcherProvider(), private val uuidGenerator: UuidGenerator = DefaultUuidGenerator(), + private val buildConfigProvider: BuildConfigProvider, ) : BackupManager { companion object { @@ -108,7 +107,7 @@ class BackupManagerImpl( private const val TEMP_RESTORE_ROOT_DIR = "restore_temp" } - override val onAutomaticBackupResult = MutableSharedFlow>() + override val onAutomaticBackupResult = MutableSharedFlow>() private val gson: Gson by lazy { GsonBuilder() @@ -151,7 +150,7 @@ class BackupManagerImpl( } } - override suspend fun backupKeyMaps(output: IFile, keyMapIds: List): Result { + override suspend fun backupKeyMaps(output: IFile, keyMapIds: List): KMResult { return withContext(dispatchers.default()) { val allKeyMaps = keyMapRepository.keyMapList .filterIsInstance>>() @@ -165,7 +164,7 @@ class BackupManagerImpl( } } - override suspend fun backupEverything(output: IFile): Result { + override suspend fun backupEverything(output: IFile): KMResult { return withContext(dispatchers.io()) { val keyMaps = keyMapRepository.keyMapList @@ -184,7 +183,7 @@ class BackupManagerImpl( } } - override suspend fun getBackupContent(file: IFile): Result { + override suspend fun getBackupContent(file: IFile): KMResult { return extractFile(file).then { extractedDir -> val dataJsonFile = fileAdapter.getFile(extractedDir, DATA_JSON_FILE_NAME) @@ -192,20 +191,20 @@ class BackupManagerImpl( val inputStream = dataJsonFile.inputStream() if (inputStream == null) { - return Error.UnknownIOError + return KMError.UnknownIOError } return parseBackupContent(inputStream) } } - private suspend fun parseBackupContent(jsonFile: InputStream): Result = withContext(dispatchers.io()) { + private suspend fun parseBackupContent(jsonFile: InputStream): KMResult = withContext(dispatchers.io()) { try { val rootElement = jsonFile.bufferedReader().use { val element = JsonParser().parse(it) if (element.isJsonNull) { - return@withContext Error.EmptyJson + return@withContext KMError.EmptyJson } element.asJsonObject @@ -214,12 +213,12 @@ class BackupManagerImpl( val backupDbVersion = rootElement.get(BackupContent.NAME_DB_VERSION).nullInt ?: 9 val backupAppVersion = rootElement.get(BackupContent.NAME_APP_VERSION).nullInt - if (backupAppVersion != null && backupAppVersion > Constants.VERSION_CODE) { - return@withContext Error.BackupVersionTooNew + if (backupAppVersion != null && backupAppVersion > buildConfigProvider.versionCode) { + return@withContext KMError.BackupVersionTooNew } if (backupDbVersion > AppDatabase.DATABASE_VERSION) { - return@withContext Error.BackupVersionTooNew + return@withContext KMError.BackupVersionTooNew } val keyMapListJsonArray by rootElement.byNullableArray(BackupContent.NAME_KEYMAP_LIST) @@ -344,7 +343,7 @@ class BackupManagerImpl( } if (backupVersionTooNew) { - return@withContext Error.BackupVersionTooNew + return@withContext KMError.BackupVersionTooNew } } @@ -388,23 +387,19 @@ class BackupManagerImpl( return@withContext Success(content) } catch (e: MalformedJsonException) { - return@withContext Error.CorruptJsonFile(e.message ?: "") + return@withContext KMError.CorruptJsonFile(e.message ?: "") } catch (e: JsonSyntaxException) { - return@withContext Error.CorruptJsonFile(e.message ?: "") + return@withContext KMError.CorruptJsonFile(e.message ?: "") } catch (e: NoSuchElementException) { - return@withContext Error.CorruptJsonFile(e.message ?: "") + return@withContext KMError.CorruptJsonFile(e.message ?: "") } catch (e: Exception) { Timber.e(e) - if (throwExceptions) { - throw e - } - - return@withContext Error.Exception(e) + return@withContext KMError.Exception(e) } } - override suspend fun restore(file: IFile, restoreType: RestoreType): Result<*> { + override suspend fun restore(file: IFile, restoreType: RestoreType): KMResult<*> { return extractFile(file).then { extractedDir -> val dataJsonFile = fileAdapter.getFile(extractedDir, DATA_JSON_FILE_NAME) @@ -412,7 +407,7 @@ class BackupManagerImpl( val inputStream = dataJsonFile.inputStream() if (inputStream == null) { - return@then Error.UnknownIOError + return@then KMError.UnknownIOError } val soundDir = fileAdapter.getFile(extractedDir, SOUNDS_DIR_NAME) @@ -432,7 +427,7 @@ class BackupManagerImpl( /** * @return the directory with the extracted contents. */ - private suspend fun extractFile(file: IFile): Result { + private suspend fun extractFile(file: IFile): KMResult { val restoreUuid = uuidGenerator.random() val zipDestination = @@ -451,7 +446,7 @@ class BackupManagerImpl( return Success(zipDestination) } catch (e: IOException) { - return Error.UnknownIOError + return KMError.UnknownIOError } } @@ -460,7 +455,7 @@ class BackupManagerImpl( backupContent: BackupContent, soundFiles: List, currentTime: Long, - ): Result<*> { + ): KMResult<*> { try { // MUST come before restoring key maps so it is possible to // validate that each key map's group exists in the repository. @@ -557,19 +552,15 @@ class BackupManagerImpl( return Success(Unit) } catch (e: MalformedJsonException) { - return Error.CorruptJsonFile(e.message ?: "") + return KMError.CorruptJsonFile(e.message ?: "") } catch (e: JsonSyntaxException) { - return Error.CorruptJsonFile(e.message ?: "") + return KMError.CorruptJsonFile(e.message ?: "") } catch (e: NoSuchElementException) { - return Error.CorruptJsonFile(e.message ?: "") + return KMError.CorruptJsonFile(e.message ?: "") } catch (e: Exception) { Timber.e(e) - if (throwExceptions) { - throw e - } - - return Error.Exception(e) + return KMError.Exception(e) } } @@ -692,7 +683,7 @@ class BackupManagerImpl( keyMapList: List = emptyList(), extraGroups: List = emptyList(), extraLayouts: List = emptyList(), - ): Result { + ): KMResult { return withContext(dispatchers.io()) { val backupUid = uuidGenerator.random() @@ -742,11 +733,7 @@ class BackupManagerImpl( } catch (e: Exception) { Timber.e(e) - if (throwExceptions) { - throw e - } - - return@withContext Error.Exception(e) + return@withContext KMError.Exception(e) } } } @@ -807,7 +794,7 @@ class BackupManagerImpl( val backupContent = BackupContent( AppDatabase.DATABASE_VERSION, - Constants.VERSION_CODE, + buildConfigProvider.versionCode, keyMapList, defaultLongPressDelay = preferenceRepository @@ -848,18 +835,18 @@ class BackupManagerImpl( } interface BackupManager { - val onAutomaticBackupResult: Flow> + val onAutomaticBackupResult: Flow> - suspend fun getBackupContent(file: IFile): Result + suspend fun getBackupContent(file: IFile): KMResult /** * @return the URI to the back up */ - suspend fun backupKeyMaps(output: IFile, keyMapIds: List): Result + suspend fun backupKeyMaps(output: IFile, keyMapIds: List): KMResult /** * @return the URI to the back up file which can then be used for sharing. */ - suspend fun backupEverything(output: IFile): Result - suspend fun restore(file: IFile, restoreType: RestoreType): Result<*> + suspend fun backupEverything(output: IFile): KMResult + suspend fun restore(file: IFile, restoreType: RestoreType): KMResult<*> } diff --git a/app/src/main/java/io/github/sds100/keymapper/backup/BackupRestoreMappingsUseCase.kt b/base/src/main/java/io/github/sds100/keymapper/base/backup/BackupRestoreMappingsUseCase.kt similarity index 64% rename from app/src/main/java/io/github/sds100/keymapper/backup/BackupRestoreMappingsUseCase.kt rename to base/src/main/java/io/github/sds100/keymapper/base/backup/BackupRestoreMappingsUseCase.kt index c41c0e5887..da5ff0cca0 100644 --- a/app/src/main/java/io/github/sds100/keymapper/backup/BackupRestoreMappingsUseCase.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/backup/BackupRestoreMappingsUseCase.kt @@ -1,25 +1,22 @@ -package io.github.sds100.keymapper.backup +package io.github.sds100.keymapper.base.backup +import io.github.sds100.keymapper.common.utils.KMResult +import io.github.sds100.keymapper.common.utils.Success +import io.github.sds100.keymapper.common.utils.onFailure +import io.github.sds100.keymapper.common.utils.then import io.github.sds100.keymapper.system.files.FileAdapter -import io.github.sds100.keymapper.util.Result -import io.github.sds100.keymapper.util.Success -import io.github.sds100.keymapper.util.onFailure -import io.github.sds100.keymapper.util.then import kotlinx.coroutines.flow.Flow import timber.log.Timber +import javax.inject.Inject -/** - * Created by sds100 on 16/04/2021. - */ - -class BackupRestoreMappingsUseCaseImpl( +class BackupRestoreMappingsUseCaseImpl @Inject constructor( private val fileAdapter: FileAdapter, private val backupManager: BackupManager, ) : BackupRestoreMappingsUseCase { - override val onAutomaticBackupResult: Flow> = backupManager.onAutomaticBackupResult + override val onAutomaticBackupResult: Flow> = backupManager.onAutomaticBackupResult - override suspend fun backupEverything(): Result { + override suspend fun backupEverything(): KMResult { val fileName = BackupUtils.createBackupFileName() // Share in private files so the share sheet can show the file name. This is some quirk @@ -33,13 +30,13 @@ class BackupRestoreMappingsUseCaseImpl( } } - override suspend fun restoreKeyMaps(uri: String, restoreType: RestoreType): Result<*> { + override suspend fun restoreKeyMaps(uri: String, restoreType: RestoreType): KMResult<*> { val file = fileAdapter.getFileFromUri(uri) return backupManager.restore(file, restoreType = restoreType) .onFailure { Timber.e(it.toString()) } } - override suspend fun getKeyMapCountInBackup(uri: String): Result { + override suspend fun getKeyMapCountInBackup(uri: String): KMResult { val file = fileAdapter.getFileFromUri(uri) return backupManager.getBackupContent(file) .then { Success(it.keyMapList?.size ?: 0) } @@ -48,9 +45,9 @@ class BackupRestoreMappingsUseCaseImpl( } interface BackupRestoreMappingsUseCase { - val onAutomaticBackupResult: Flow> - suspend fun backupEverything(): Result - suspend fun restoreKeyMaps(uri: String, restoreType: RestoreType): Result<*> + val onAutomaticBackupResult: Flow> + suspend fun backupEverything(): KMResult + suspend fun restoreKeyMaps(uri: String, restoreType: RestoreType): KMResult<*> - suspend fun getKeyMapCountInBackup(uri: String): Result + suspend fun getKeyMapCountInBackup(uri: String): KMResult } diff --git a/app/src/main/java/io/github/sds100/keymapper/backup/BackupUtils.kt b/base/src/main/java/io/github/sds100/keymapper/base/backup/BackupUtils.kt similarity index 86% rename from app/src/main/java/io/github/sds100/keymapper/backup/BackupUtils.kt rename to base/src/main/java/io/github/sds100/keymapper/base/backup/BackupUtils.kt index 528c12f228..439f672b95 100644 --- a/app/src/main/java/io/github/sds100/keymapper/backup/BackupUtils.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/backup/BackupUtils.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.backup +package io.github.sds100.keymapper.base.backup import io.github.sds100.keymapper.system.files.FileUtils diff --git a/app/src/main/java/io/github/sds100/keymapper/backup/ImportExportState.kt b/base/src/main/java/io/github/sds100/keymapper/base/backup/ImportExportState.kt similarity index 90% rename from app/src/main/java/io/github/sds100/keymapper/backup/ImportExportState.kt rename to base/src/main/java/io/github/sds100/keymapper/base/backup/ImportExportState.kt index 248d22ed4c..a570129d85 100644 --- a/app/src/main/java/io/github/sds100/keymapper/backup/ImportExportState.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/backup/ImportExportState.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.backup +package io.github.sds100.keymapper.base.backup sealed class ImportExportState { data object Idle : ImportExportState() diff --git a/app/src/main/java/io/github/sds100/keymapper/backup/RestoreKeyMapsActivity.kt b/base/src/main/java/io/github/sds100/keymapper/base/backup/RestoreKeyMapsActivity.kt similarity index 86% rename from app/src/main/java/io/github/sds100/keymapper/backup/RestoreKeyMapsActivity.kt rename to base/src/main/java/io/github/sds100/keymapper/base/backup/RestoreKeyMapsActivity.kt index ffc0c32ee1..d15e1970b4 100644 --- a/app/src/main/java/io/github/sds100/keymapper/backup/RestoreKeyMapsActivity.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/backup/RestoreKeyMapsActivity.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.backup +package io.github.sds100.keymapper.base.backup import android.content.Intent import android.os.Bundle @@ -16,23 +16,20 @@ import androidx.compose.ui.res.pluralStringResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle -import io.github.sds100.keymapper.MainActivity -import io.github.sds100.keymapper.R -import io.github.sds100.keymapper.ServiceLocator -import io.github.sds100.keymapper.compose.KeyMapperTheme -import io.github.sds100.keymapper.util.ui.compose.CustomDialogContent - +import dagger.hilt.android.AndroidEntryPoint +import io.github.sds100.keymapper.base.R +import io.github.sds100.keymapper.base.compose.KeyMapperTheme +import io.github.sds100.keymapper.base.utils.ui.compose.CustomDialogContent +import io.github.sds100.keymapper.common.KeyMapperClassProvider +import javax.inject.Inject + +@AndroidEntryPoint class RestoreKeyMapsActivity : ComponentActivity() { - private val viewModel by viewModels { - RestoreKeyMapsViewModel.Factory( - useCase = BackupRestoreMappingsUseCaseImpl( - fileAdapter = ServiceLocator.fileAdapter(this), - backupManager = ServiceLocator.backupManager(this), - ), - resourceProvider = ServiceLocator.resourceProvider(this), - ) - } + @Inject + lateinit var classProvider: KeyMapperClassProvider + + private val viewModel by viewModels() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -62,7 +59,7 @@ class RestoreKeyMapsActivity : ComponentActivity() { else -> "" } - val text = when (val state = state) { + val text = when (state) { is ImportExportState.ConfirmImport -> stringResource(R.string.home_importing_dialog_text) else -> null } @@ -77,7 +74,7 @@ class RestoreKeyMapsActivity : ComponentActivity() { TextButton(onClick = { finish() - Intent(ctx, MainActivity::class.java).apply { + Intent(ctx, classProvider.getMainActivity()).apply { addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) startActivity(this) } diff --git a/app/src/main/java/io/github/sds100/keymapper/backup/RestoreKeyMapsViewModel.kt b/base/src/main/java/io/github/sds100/keymapper/base/backup/RestoreKeyMapsViewModel.kt similarity index 70% rename from app/src/main/java/io/github/sds100/keymapper/backup/RestoreKeyMapsViewModel.kt rename to base/src/main/java/io/github/sds100/keymapper/base/backup/RestoreKeyMapsViewModel.kt index 7f3f25ab7a..44cb892887 100644 --- a/app/src/main/java/io/github/sds100/keymapper/backup/RestoreKeyMapsViewModel.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/backup/RestoreKeyMapsViewModel.kt @@ -1,18 +1,20 @@ -package io.github.sds100.keymapper.backup +package io.github.sds100.keymapper.base.backup import androidx.lifecycle.ViewModel -import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.viewModelScope -import io.github.sds100.keymapper.util.getFullMessage -import io.github.sds100.keymapper.util.onFailure -import io.github.sds100.keymapper.util.onSuccess -import io.github.sds100.keymapper.util.ui.ResourceProvider +import dagger.hilt.android.lifecycle.HiltViewModel +import io.github.sds100.keymapper.base.utils.getFullMessage +import io.github.sds100.keymapper.base.utils.ui.ResourceProvider +import io.github.sds100.keymapper.common.utils.onFailure +import io.github.sds100.keymapper.common.utils.onSuccess import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.launch +import javax.inject.Inject -class RestoreKeyMapsViewModel( +@HiltViewModel +class RestoreKeyMapsViewModel @Inject constructor( private val useCase: BackupRestoreMappingsUseCase, resourceProvider: ResourceProvider, ) : ViewModel(), @@ -47,13 +49,4 @@ class RestoreKeyMapsViewModel( } } } - - @Suppress("UNCHECKED_CAST") - class Factory( - private val useCase: BackupRestoreMappingsUseCase, - private val resourceProvider: ResourceProvider, - ) : ViewModelProvider.NewInstanceFactory() { - - override fun create(modelClass: Class): T = RestoreKeyMapsViewModel(useCase, resourceProvider) as T - } } diff --git a/app/src/main/java/io/github/sds100/keymapper/backup/RestoreType.kt b/base/src/main/java/io/github/sds100/keymapper/base/backup/RestoreType.kt similarity index 53% rename from app/src/main/java/io/github/sds100/keymapper/backup/RestoreType.kt rename to base/src/main/java/io/github/sds100/keymapper/base/backup/RestoreType.kt index cc74fcccde..f19fdfb04f 100644 --- a/app/src/main/java/io/github/sds100/keymapper/backup/RestoreType.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/backup/RestoreType.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.backup +package io.github.sds100.keymapper.base.backup enum class RestoreType { APPEND, diff --git a/app/src/main/java/io/github/sds100/keymapper/compose/ComposeColors.kt b/base/src/main/java/io/github/sds100/keymapper/base/compose/ComposeColors.kt similarity index 98% rename from app/src/main/java/io/github/sds100/keymapper/compose/ComposeColors.kt rename to base/src/main/java/io/github/sds100/keymapper/base/compose/ComposeColors.kt index 6d677359e4..7746f70135 100644 --- a/app/src/main/java/io/github/sds100/keymapper/compose/ComposeColors.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/compose/ComposeColors.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.compose +package io.github.sds100.keymapper.base.compose import androidx.compose.ui.graphics.Color diff --git a/app/src/main/java/io/github/sds100/keymapper/compose/ComposeCustomColors.kt b/base/src/main/java/io/github/sds100/keymapper/base/compose/ComposeCustomColors.kt similarity index 96% rename from app/src/main/java/io/github/sds100/keymapper/compose/ComposeCustomColors.kt rename to base/src/main/java/io/github/sds100/keymapper/base/compose/ComposeCustomColors.kt index 2c1000f6bf..49d7638df8 100644 --- a/app/src/main/java/io/github/sds100/keymapper/compose/ComposeCustomColors.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/compose/ComposeCustomColors.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.compose +package io.github.sds100.keymapper.base.compose import androidx.compose.runtime.Immutable import androidx.compose.ui.graphics.Color diff --git a/app/src/main/java/io/github/sds100/keymapper/compose/ComposeTheme.kt b/base/src/main/java/io/github/sds100/keymapper/base/compose/ComposeTheme.kt similarity index 99% rename from app/src/main/java/io/github/sds100/keymapper/compose/ComposeTheme.kt rename to base/src/main/java/io/github/sds100/keymapper/base/compose/ComposeTheme.kt index cfd8d6b41d..b289192ec1 100755 --- a/app/src/main/java/io/github/sds100/keymapper/compose/ComposeTheme.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/compose/ComposeTheme.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.compose +package io.github.sds100.keymapper.base.compose import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.material3.MaterialTheme diff --git a/app/src/main/java/io/github/sds100/keymapper/constraints/ChooseConstraintScreen.kt b/base/src/main/java/io/github/sds100/keymapper/base/constraints/ChooseConstraintScreen.kt similarity index 95% rename from app/src/main/java/io/github/sds100/keymapper/constraints/ChooseConstraintScreen.kt rename to base/src/main/java/io/github/sds100/keymapper/base/constraints/ChooseConstraintScreen.kt index 958b557d29..bfaeaa36a9 100644 --- a/app/src/main/java/io/github/sds100/keymapper/constraints/ChooseConstraintScreen.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/constraints/ChooseConstraintScreen.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.constraints +package io.github.sds100.keymapper.base.constraints import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box @@ -45,19 +45,18 @@ import androidx.compose.ui.tooling.preview.Devices import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle -import io.github.sds100.keymapper.R -import io.github.sds100.keymapper.compose.KeyMapperTheme -import io.github.sds100.keymapper.util.State -import io.github.sds100.keymapper.util.ui.compose.ComposeIconInfo -import io.github.sds100.keymapper.util.ui.compose.SimpleListItemFixedHeight -import io.github.sds100.keymapper.util.ui.compose.SimpleListItemModel +import io.github.sds100.keymapper.base.R +import io.github.sds100.keymapper.base.compose.KeyMapperTheme +import io.github.sds100.keymapper.base.utils.ui.compose.ComposeIconInfo +import io.github.sds100.keymapper.base.utils.ui.compose.SimpleListItemFixedHeight +import io.github.sds100.keymapper.base.utils.ui.compose.SimpleListItemModel +import io.github.sds100.keymapper.common.utils.State import kotlinx.coroutines.flow.update @Composable fun ChooseConstraintScreen( modifier: Modifier = Modifier, viewModel: ChooseConstraintViewModel, - onNavigateBack: () -> Unit, ) { val listItems by viewModel.listItems.collectAsStateWithLifecycle() val query by viewModel.searchQuery.collectAsStateWithLifecycle() @@ -71,7 +70,7 @@ fun ChooseConstraintScreen( onQueryChange = { newQuery -> viewModel.searchQuery.update { newQuery } }, onCloseSearch = { viewModel.searchQuery.update { null } }, onClickAction = viewModel::onListItemClick, - onNavigateBack = onNavigateBack, + onNavigateBack = viewModel::onNavigateBack, ) } diff --git a/app/src/main/java/io/github/sds100/keymapper/constraints/ChooseConstraintViewModel.kt b/base/src/main/java/io/github/sds100/keymapper/base/constraints/ChooseConstraintViewModel.kt similarity index 69% rename from app/src/main/java/io/github/sds100/keymapper/constraints/ChooseConstraintViewModel.kt rename to base/src/main/java/io/github/sds100/keymapper/base/constraints/ChooseConstraintViewModel.kt index ef87621a6e..6bf2901ee9 100644 --- a/app/src/main/java/io/github/sds100/keymapper/constraints/ChooseConstraintViewModel.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/constraints/ChooseConstraintViewModel.kt @@ -1,51 +1,48 @@ -package io.github.sds100.keymapper.constraints +package io.github.sds100.keymapper.base.constraints import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue import androidx.lifecycle.ViewModel -import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.viewModelScope -import io.github.sds100.keymapper.R +import dagger.hilt.android.lifecycle.HiltViewModel +import io.github.sds100.keymapper.base.R +import io.github.sds100.keymapper.base.utils.containsQuery +import io.github.sds100.keymapper.base.utils.getFullMessage +import io.github.sds100.keymapper.base.utils.navigation.NavDestination +import io.github.sds100.keymapper.base.utils.navigation.NavigationProvider +import io.github.sds100.keymapper.base.utils.navigation.navigate +import io.github.sds100.keymapper.base.utils.ui.DialogModel +import io.github.sds100.keymapper.base.utils.ui.DialogProvider +import io.github.sds100.keymapper.base.utils.ui.ResourceProvider +import io.github.sds100.keymapper.base.utils.ui.compose.SimpleListItemModel +import io.github.sds100.keymapper.base.utils.ui.showDialog +import io.github.sds100.keymapper.common.utils.Orientation +import io.github.sds100.keymapper.common.utils.State import io.github.sds100.keymapper.system.camera.CameraLens -import io.github.sds100.keymapper.system.camera.CameraLensUtils -import io.github.sds100.keymapper.system.display.Orientation -import io.github.sds100.keymapper.util.State -import io.github.sds100.keymapper.util.containsQuery -import io.github.sds100.keymapper.util.getFullMessage -import io.github.sds100.keymapper.util.ui.NavDestination -import io.github.sds100.keymapper.util.ui.NavigationViewModel -import io.github.sds100.keymapper.util.ui.NavigationViewModelImpl -import io.github.sds100.keymapper.util.ui.PopupUi -import io.github.sds100.keymapper.util.ui.PopupViewModel -import io.github.sds100.keymapper.util.ui.PopupViewModelImpl -import io.github.sds100.keymapper.util.ui.ResourceProvider -import io.github.sds100.keymapper.util.ui.compose.SimpleListItemModel -import io.github.sds100.keymapper.util.ui.navigate -import io.github.sds100.keymapper.util.ui.showPopup import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow -import kotlinx.coroutines.flow.asSharedFlow import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch +import kotlinx.serialization.json.Json +import javax.inject.Inject -/** - * Created by sds100 on 21/03/2020. - */ - -class ChooseConstraintViewModel( +@HiltViewModel +class ChooseConstraintViewModel @Inject constructor( private val useCase: CreateConstraintUseCase, + dialogProvider: DialogProvider, + navigationProvider: NavigationProvider, resourceProvider: ResourceProvider, ) : ViewModel(), ResourceProvider by resourceProvider, - PopupViewModel by PopupViewModelImpl(), - NavigationViewModel by NavigationViewModelImpl() { + DialogProvider by dialogProvider, + NavigationProvider by navigationProvider { companion object { private val ALL_CONSTRAINTS_ORDERED: Array = arrayOf( @@ -96,8 +93,7 @@ class ChooseConstraintViewModel( ) } - private val _returnResult = MutableSharedFlow() - val returnResult = _returnResult.asSharedFlow() + private val returnResult = MutableSharedFlow() private val allListItems: List by lazy { buildListItems() } @@ -111,15 +107,29 @@ class ChooseConstraintViewModel( var timeConstraintState: Constraint.Time? by mutableStateOf(null) + init { + viewModelScope.launch { + returnResult.collect { constraint -> + popBackStackWithResult(Json.encodeToString(constraint)) + } + } + } + fun onDoneConfigTimeConstraintClick() { timeConstraintState?.let { constraint -> viewModelScope.launch { - _returnResult.emit(constraint) + returnResult.emit(constraint) timeConstraintState = null } } } + fun onNavigateBack() { + viewModelScope.launch { + popBackStack() + } + } + fun onListItemClick(id: String) { viewModelScope.launch { when (val constraintType = ConstraintId.valueOf(id)) { @@ -129,8 +139,8 @@ class ChooseConstraintViewModel( ConstraintId.APP_NOT_PLAYING_MEDIA, -> onSelectAppConstraint(constraintType) - ConstraintId.MEDIA_PLAYING -> _returnResult.emit(Constraint.MediaPlaying()) - ConstraintId.MEDIA_NOT_PLAYING -> _returnResult.emit(Constraint.NoMediaPlaying()) + ConstraintId.MEDIA_PLAYING -> returnResult.emit(Constraint.MediaPlaying()) + ConstraintId.MEDIA_NOT_PLAYING -> returnResult.emit(Constraint.NoMediaPlaying()) ConstraintId.BT_DEVICE_CONNECTED, ConstraintId.BT_DEVICE_DISCONNECTED, @@ -142,35 +152,35 @@ class ChooseConstraintViewModel( ConstraintId.SCREEN_OFF -> onSelectScreenOffConstraint() ConstraintId.ORIENTATION_PORTRAIT -> - _returnResult.emit(Constraint.OrientationPortrait()) + returnResult.emit(Constraint.OrientationPortrait()) ConstraintId.ORIENTATION_LANDSCAPE -> - _returnResult.emit(Constraint.OrientationLandscape()) + returnResult.emit(Constraint.OrientationLandscape()) ConstraintId.ORIENTATION_0 -> - _returnResult.emit(Constraint.OrientationCustom(orientation = Orientation.ORIENTATION_0)) + returnResult.emit(Constraint.OrientationCustom(orientation = Orientation.ORIENTATION_0)) ConstraintId.ORIENTATION_90 -> - _returnResult.emit(Constraint.OrientationCustom(orientation = Orientation.ORIENTATION_90)) + returnResult.emit(Constraint.OrientationCustom(orientation = Orientation.ORIENTATION_90)) ConstraintId.ORIENTATION_180 -> - _returnResult.emit(Constraint.OrientationCustom(orientation = Orientation.ORIENTATION_180)) + returnResult.emit(Constraint.OrientationCustom(orientation = Orientation.ORIENTATION_180)) ConstraintId.ORIENTATION_270 -> - _returnResult.emit(Constraint.OrientationCustom(orientation = Orientation.ORIENTATION_270)) + returnResult.emit(Constraint.OrientationCustom(orientation = Orientation.ORIENTATION_270)) ConstraintId.FLASHLIGHT_ON -> { val lens = chooseFlashlightLens() ?: return@launch - _returnResult.emit(Constraint.FlashlightOn(lens = lens)) + returnResult.emit(Constraint.FlashlightOn(lens = lens)) } ConstraintId.FLASHLIGHT_OFF -> { val lens = chooseFlashlightLens() ?: return@launch - _returnResult.emit(Constraint.FlashlightOff(lens = lens)) + returnResult.emit(Constraint.FlashlightOff(lens = lens)) } - ConstraintId.WIFI_ON -> _returnResult.emit(Constraint.WifiOn()) - ConstraintId.WIFI_OFF -> _returnResult.emit(Constraint.WifiOff()) + ConstraintId.WIFI_ON -> returnResult.emit(Constraint.WifiOn()) + ConstraintId.WIFI_OFF -> returnResult.emit(Constraint.WifiOff()) ConstraintId.WIFI_CONNECTED, ConstraintId.WIFI_DISCONNECTED, @@ -183,31 +193,31 @@ class ChooseConstraintViewModel( -> onSelectImeChosenConstraint(constraintType) ConstraintId.DEVICE_IS_LOCKED -> - _returnResult.emit(Constraint.DeviceIsLocked()) + returnResult.emit(Constraint.DeviceIsLocked()) ConstraintId.DEVICE_IS_UNLOCKED -> - _returnResult.emit(Constraint.DeviceIsUnlocked()) + returnResult.emit(Constraint.DeviceIsUnlocked()) ConstraintId.IN_PHONE_CALL -> - _returnResult.emit(Constraint.InPhoneCall()) + returnResult.emit(Constraint.InPhoneCall()) ConstraintId.NOT_IN_PHONE_CALL -> - _returnResult.emit(Constraint.NotInPhoneCall()) + returnResult.emit(Constraint.NotInPhoneCall()) ConstraintId.PHONE_RINGING -> - _returnResult.emit(Constraint.PhoneRinging()) + returnResult.emit(Constraint.PhoneRinging()) ConstraintId.CHARGING -> - _returnResult.emit(Constraint.Charging()) + returnResult.emit(Constraint.Charging()) ConstraintId.DISCHARGING -> - _returnResult.emit(Constraint.Discharging()) + returnResult.emit(Constraint.Discharging()) ConstraintId.LOCK_SCREEN_SHOWING -> - _returnResult.emit(Constraint.LockScreenShowing()) + returnResult.emit(Constraint.LockScreenShowing()) ConstraintId.LOCK_SCREEN_NOT_SHOWING -> - _returnResult.emit(Constraint.LockScreenNotShowing()) + returnResult.emit(Constraint.LockScreenNotShowing()) ConstraintId.TIME -> { timeConstraintState = Constraint.Time( @@ -222,17 +232,21 @@ class ChooseConstraintViewModel( } private suspend fun chooseFlashlightLens(): CameraLens? { - val items = useCase.getFlashlightLenses().map { - it to getString(CameraLensUtils.getLabel(it)) + val items = useCase.getFlashlightLenses().map { lens -> + val label = when (lens) { + CameraLens.FRONT -> R.string.lens_front + CameraLens.BACK -> R.string.lens_back + } + lens to getString(label) } if (items.size == 1) { return items.first().first } - val dialog = PopupUi.SingleChoice(items) + val dialog = DialogModel.SingleChoice(items) - val cameraLens = showPopup("choose_flashlight_lens", dialog) + val cameraLens = showDialog("choose_flashlight_lens", dialog) return cameraLens } @@ -264,14 +278,14 @@ class ChooseConstraintViewModel( if (knownSSIDs == null) { val savedWifiSSIDs = useCase.getSavedWifiSSIDs().first() - val dialog = PopupUi.Text( + val dialog = DialogModel.Text( hint = getString(R.string.hint_wifi_ssid), allowEmpty = true, message = getString(R.string.constraint_wifi_message_cant_list_networks), autoCompleteEntries = savedWifiSSIDs, ) - val ssidText = showPopup("type_ssid", dialog) ?: return + val ssidText = showDialog("type_ssid", dialog) ?: return if (ssidText.isBlank()) { chosenSSID = null @@ -289,7 +303,7 @@ class ChooseConstraintViewModel( val items = listOf(anySSIDItem).plus(ssidItems) val chosenItem = - showPopup("choose_ssid", PopupUi.SingleChoice(items)) ?: return + showDialog("choose_ssid", DialogModel.SingleChoice(items)) ?: return if (chosenItem == anySSIDItem.first) { chosenSSID = null @@ -300,10 +314,10 @@ class ChooseConstraintViewModel( when (type) { ConstraintId.WIFI_CONNECTED -> - _returnResult.emit(Constraint.WifiConnected(ssid = chosenSSID)) + returnResult.emit(Constraint.WifiConnected(ssid = chosenSSID)) ConstraintId.WIFI_DISCONNECTED -> - _returnResult.emit(Constraint.WifiDisconnected(ssid = chosenSSID)) + returnResult.emit(Constraint.WifiDisconnected(ssid = chosenSSID)) else -> Unit } @@ -312,15 +326,15 @@ class ChooseConstraintViewModel( private suspend fun onSelectImeChosenConstraint(type: ConstraintId) { val inputMethods = useCase.getEnabledInputMethods() val items = inputMethods.map { it.id to it.label } - val dialog = PopupUi.SingleChoice(items = items) + val dialog = DialogModel.SingleChoice(items = items) - val result = showPopup("choose_input_method", dialog) ?: return + val result = showDialog("choose_input_method", dialog) ?: return val imeInfo = inputMethods.single { it.id == result } when (type) { ConstraintId.IME_CHOSEN -> - _returnResult.emit( + returnResult.emit( Constraint.ImeChosen( imeId = imeInfo.id, imeLabel = imeInfo.label, @@ -328,7 +342,7 @@ class ChooseConstraintViewModel( ) ConstraintId.IME_NOT_CHOSEN -> - _returnResult.emit( + returnResult.emit( Constraint.ImeNotChosen( imeId = imeInfo.id, imeLabel = imeInfo.label, @@ -340,31 +354,31 @@ class ChooseConstraintViewModel( } private suspend fun onSelectScreenOnConstraint() { - val response = showPopup( + val response = showDialog( "screen_on_constraint_limitation", - PopupUi.Ok(getString(R.string.dialog_message_screen_constraints_limitation)), + DialogModel.Ok(getString(R.string.dialog_message_screen_constraints_limitation)), ) response ?: return - _returnResult.emit(Constraint.ScreenOn()) + returnResult.emit(Constraint.ScreenOn()) } private suspend fun onSelectScreenOffConstraint() { - val response = showPopup( + val response = showDialog( "screen_on_constraint_limitation", - PopupUi.Ok(getString(R.string.dialog_message_screen_constraints_limitation)), + DialogModel.Ok(getString(R.string.dialog_message_screen_constraints_limitation)), ) response ?: return - _returnResult.emit(Constraint.ScreenOff()) + returnResult.emit(Constraint.ScreenOff()) } private suspend fun onSelectBluetoothConstraint(type: ConstraintId) { - val response = showPopup( + val response = showDialog( "bluetooth_device_constraint_limitation", - PopupUi.Ok(getString(R.string.dialog_message_bt_constraint_limitation)), + DialogModel.Ok(getString(R.string.dialog_message_bt_constraint_limitation)), ) response ?: return @@ -388,7 +402,7 @@ class ChooseConstraintViewModel( else -> throw IllegalArgumentException("Don't know how to create $type constraint after choosing app") } - _returnResult.emit(constraint) + returnResult.emit(constraint) } private suspend fun onSelectAppConstraint(type: ConstraintId) { @@ -419,15 +433,6 @@ class ChooseConstraintViewModel( else -> throw IllegalArgumentException("Don't know how to create $type constraint after choosing app") } - _returnResult.emit(constraint) - } - - @Suppress("UNCHECKED_CAST") - class Factory( - private val isSupported: CreateConstraintUseCase, - private val resourceProvider: ResourceProvider, - ) : ViewModelProvider.NewInstanceFactory() { - - override fun create(modelClass: Class): T = ChooseConstraintViewModel(isSupported, resourceProvider) as T + returnResult.emit(constraint) } } diff --git a/app/src/main/java/io/github/sds100/keymapper/constraints/ConfigConstraintsViewModel.kt b/base/src/main/java/io/github/sds100/keymapper/base/constraints/ConfigConstraintsViewModel.kt similarity index 79% rename from app/src/main/java/io/github/sds100/keymapper/constraints/ConfigConstraintsViewModel.kt rename to base/src/main/java/io/github/sds100/keymapper/base/constraints/ConfigConstraintsViewModel.kt index f4512555ab..a2d941bbbd 100644 --- a/app/src/main/java/io/github/sds100/keymapper/constraints/ConfigConstraintsViewModel.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/constraints/ConfigConstraintsViewModel.kt @@ -1,26 +1,25 @@ -package io.github.sds100.keymapper.constraints +package io.github.sds100.keymapper.base.constraints import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue -import io.github.sds100.keymapper.keymaps.ConfigKeyMapUseCase -import io.github.sds100.keymapper.keymaps.ShortcutModel +import io.github.sds100.keymapper.base.keymaps.ConfigKeyMapUseCase +import io.github.sds100.keymapper.base.keymaps.ShortcutModel +import io.github.sds100.keymapper.base.utils.getFullMessage +import io.github.sds100.keymapper.base.utils.isFixable +import io.github.sds100.keymapper.base.utils.navigation.NavDestination +import io.github.sds100.keymapper.base.utils.navigation.NavigationProvider +import io.github.sds100.keymapper.base.utils.navigation.navigate +import io.github.sds100.keymapper.base.utils.ui.DialogProvider +import io.github.sds100.keymapper.base.utils.ui.ResourceProvider +import io.github.sds100.keymapper.base.utils.ui.ViewModelHelper +import io.github.sds100.keymapper.base.utils.ui.compose.ComposeIconInfo +import io.github.sds100.keymapper.common.utils.KMError +import io.github.sds100.keymapper.common.utils.State +import io.github.sds100.keymapper.common.utils.dataOrNull +import io.github.sds100.keymapper.common.utils.mapData +import io.github.sds100.keymapper.system.SystemError import io.github.sds100.keymapper.system.permissions.Permission -import io.github.sds100.keymapper.util.Error -import io.github.sds100.keymapper.util.State -import io.github.sds100.keymapper.util.dataOrNull -import io.github.sds100.keymapper.util.getFullMessage -import io.github.sds100.keymapper.util.isFixable -import io.github.sds100.keymapper.util.mapData -import io.github.sds100.keymapper.util.ui.NavDestination -import io.github.sds100.keymapper.util.ui.NavigationViewModel -import io.github.sds100.keymapper.util.ui.NavigationViewModelImpl -import io.github.sds100.keymapper.util.ui.PopupViewModel -import io.github.sds100.keymapper.util.ui.PopupViewModelImpl -import io.github.sds100.keymapper.util.ui.ResourceProvider -import io.github.sds100.keymapper.util.ui.ViewModelHelper -import io.github.sds100.keymapper.util.ui.compose.ComposeIconInfo -import io.github.sds100.keymapper.util.ui.navigate import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted @@ -35,18 +34,16 @@ import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch -/** - * Created by sds100 on 29/11/20. - */ - class ConfigConstraintsViewModel( private val coroutineScope: CoroutineScope, private val config: ConfigKeyMapUseCase, private val displayConstraint: DisplayConstraintUseCase, resourceProvider: ResourceProvider, + navigationProvider: NavigationProvider, + dialogProvider: DialogProvider, ) : ResourceProvider by resourceProvider, - PopupViewModel by PopupViewModelImpl(), - NavigationViewModel by NavigationViewModelImpl() { + DialogProvider by dialogProvider, + NavigationProvider by navigationProvider { private val uiHelper = ConstraintUiHelper(displayConstraint, resourceProvider) @@ -108,11 +105,11 @@ class ConfigConstraintsViewModel( val error = constraintErrorSnapshot.filterNotNull().first().getError(constraint) ?: return@launch - if (error == Error.PermissionDenied(Permission.ACCESS_NOTIFICATION_POLICY)) { + if (error == SystemError.PermissionDenied(Permission.ACCESS_NOTIFICATION_POLICY)) { coroutineScope.launch { ViewModelHelper.showDialogExplainingDndAccessBeingUnavailable( resourceProvider = this@ConfigConstraintsViewModel, - popupViewModel = this@ConfigConstraintsViewModel, + dialogProvider = this@ConfigConstraintsViewModel, neverShowDndTriggerErrorAgain = { displayConstraint.neverShowDndTriggerError() }, fixError = { displayConstraint.fixError(error) }, ) @@ -120,7 +117,7 @@ class ConfigConstraintsViewModel( } else { ViewModelHelper.showFixErrorDialog( resourceProvider = this@ConfigConstraintsViewModel, - popupViewModel = this@ConfigConstraintsViewModel, + dialogProvider = this@ConfigConstraintsViewModel, error, ) { displayConstraint.fixError(error) @@ -163,7 +160,7 @@ class ConfigConstraintsViewModel( val constraintList = state.constraints.mapIndexed { index, constraint -> val title: String = uiHelper.getTitle(constraint) val icon: ComposeIconInfo = uiHelper.getIcon(constraint) - val error: Error? = errorSnapshot.getError(constraint) + val error: KMError? = errorSnapshot.getError(constraint) ConstraintListItemModel( id = constraint.uid, diff --git a/app/src/main/java/io/github/sds100/keymapper/constraints/Constraint.kt b/base/src/main/java/io/github/sds100/keymapper/base/constraints/Constraint.kt similarity index 98% rename from app/src/main/java/io/github/sds100/keymapper/constraints/Constraint.kt rename to base/src/main/java/io/github/sds100/keymapper/base/constraints/Constraint.kt index ccb07858b0..d949ee114b 100644 --- a/app/src/main/java/io/github/sds100/keymapper/constraints/Constraint.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/constraints/Constraint.kt @@ -1,20 +1,16 @@ -package io.github.sds100.keymapper.constraints +package io.github.sds100.keymapper.base.constraints +import io.github.sds100.keymapper.common.utils.Orientation +import io.github.sds100.keymapper.common.utils.getKey +import io.github.sds100.keymapper.common.utils.valueOrNull import io.github.sds100.keymapper.data.entities.ConstraintEntity import io.github.sds100.keymapper.data.entities.EntityExtra import io.github.sds100.keymapper.data.entities.getData import io.github.sds100.keymapper.system.camera.CameraLens -import io.github.sds100.keymapper.system.display.Orientation -import io.github.sds100.keymapper.util.getKey -import io.github.sds100.keymapper.util.valueOrNull import kotlinx.serialization.Serializable import java.time.LocalTime import java.util.UUID -/** - * Created by sds100 on 03/03/2021. - */ - @Serializable sealed class Constraint { abstract val uid: String diff --git a/app/src/main/java/io/github/sds100/keymapper/constraints/ConstraintDependency.kt b/base/src/main/java/io/github/sds100/keymapper/base/constraints/ConstraintDependency.kt similarity index 86% rename from app/src/main/java/io/github/sds100/keymapper/constraints/ConstraintDependency.kt rename to base/src/main/java/io/github/sds100/keymapper/base/constraints/ConstraintDependency.kt index 98c879b38d..916eec0ae6 100644 --- a/app/src/main/java/io/github/sds100/keymapper/constraints/ConstraintDependency.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/constraints/ConstraintDependency.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.constraints +package io.github.sds100.keymapper.base.constraints enum class ConstraintDependency { FOREGROUND_APP, diff --git a/app/src/main/java/io/github/sds100/keymapper/constraints/ConstraintErrorSnapshot.kt b/base/src/main/java/io/github/sds100/keymapper/base/constraints/ConstraintErrorSnapshot.kt similarity index 72% rename from app/src/main/java/io/github/sds100/keymapper/constraints/ConstraintErrorSnapshot.kt rename to base/src/main/java/io/github/sds100/keymapper/base/constraints/ConstraintErrorSnapshot.kt index be1ab76e8f..6820372ab5 100644 --- a/app/src/main/java/io/github/sds100/keymapper/constraints/ConstraintErrorSnapshot.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/constraints/ConstraintErrorSnapshot.kt @@ -1,7 +1,10 @@ -package io.github.sds100.keymapper.constraints +package io.github.sds100.keymapper.base.constraints import android.content.pm.PackageManager import android.os.Build +import io.github.sds100.keymapper.common.utils.KMError +import io.github.sds100.keymapper.common.utils.onSuccess +import io.github.sds100.keymapper.system.SystemError import io.github.sds100.keymapper.system.apps.PackageManagerAdapter import io.github.sds100.keymapper.system.camera.CameraAdapter import io.github.sds100.keymapper.system.camera.CameraLens @@ -9,8 +12,6 @@ import io.github.sds100.keymapper.system.inputmethod.InputMethodAdapter import io.github.sds100.keymapper.system.permissions.Permission import io.github.sds100.keymapper.system.permissions.PermissionAdapter import io.github.sds100.keymapper.system.permissions.SystemFeatureAdapter -import io.github.sds100.keymapper.util.Error -import io.github.sds100.keymapper.util.onSuccess class LazyConstraintErrorSnapshot( private val packageManager: PackageManagerAdapter, @@ -34,14 +35,14 @@ class LazyConstraintErrorSnapshot( } } - override fun getError(constraint: Constraint): Error? { + override fun getError(constraint: Constraint): KMError? { when (constraint) { is Constraint.AppInForeground -> return getAppError(constraint.packageName) is Constraint.AppNotInForeground -> return getAppError(constraint.packageName) is Constraint.AppPlayingMedia -> { if (!isPermissionGranted(Permission.NOTIFICATION_LISTENER)) { - return Error.PermissionDenied(Permission.NOTIFICATION_LISTENER) + return SystemError.PermissionDenied(Permission.NOTIFICATION_LISTENER) } return getAppError(constraint.packageName) @@ -49,7 +50,7 @@ class LazyConstraintErrorSnapshot( is Constraint.AppNotPlayingMedia -> { if (!isPermissionGranted(Permission.NOTIFICATION_LISTENER)) { - return Error.PermissionDenied(Permission.NOTIFICATION_LISTENER) + return SystemError.PermissionDenied(Permission.NOTIFICATION_LISTENER) } return getAppError(constraint.packageName) @@ -57,7 +58,7 @@ class LazyConstraintErrorSnapshot( Constraint.MediaPlaying, Constraint.NoMediaPlaying -> { if (!isPermissionGranted(Permission.NOTIFICATION_LISTENER)) { - return Error.PermissionDenied(Permission.NOTIFICATION_LISTENER) + return SystemError.PermissionDenied(Permission.NOTIFICATION_LISTENER) } } @@ -65,11 +66,11 @@ class LazyConstraintErrorSnapshot( is Constraint.BtDeviceDisconnected, -> { if (!systemFeatureAdapter.hasSystemFeature(PackageManager.FEATURE_BLUETOOTH)) { - return Error.SystemFeatureNotSupported(PackageManager.FEATURE_BLUETOOTH) + return KMError.SystemFeatureNotSupported(PackageManager.FEATURE_BLUETOOTH) } if (!isPermissionGranted(Permission.FIND_NEARBY_DEVICES)) { - return Error.PermissionDenied(Permission.FIND_NEARBY_DEVICES) + return SystemError.PermissionDenied(Permission.FIND_NEARBY_DEVICES) } } @@ -78,50 +79,50 @@ class LazyConstraintErrorSnapshot( Constraint.OrientationPortrait, -> if (!isPermissionGranted(Permission.WRITE_SETTINGS)) { - return Error.PermissionDenied(Permission.WRITE_SETTINGS) + return SystemError.PermissionDenied(Permission.WRITE_SETTINGS) } is Constraint.FlashlightOn -> { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { - return Error.SdkVersionTooLow(minSdk = Build.VERSION_CODES.M) + return KMError.SdkVersionTooLow(minSdk = Build.VERSION_CODES.M) } if (!flashLenses.contains(constraint.lens)) { return when (constraint.lens) { - CameraLens.FRONT -> Error.FrontFlashNotFound - CameraLens.BACK -> Error.BackFlashNotFound + CameraLens.FRONT -> KMError.FrontFlashNotFound + CameraLens.BACK -> KMError.BackFlashNotFound } } } is Constraint.FlashlightOff -> { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { - return Error.SdkVersionTooLow(minSdk = Build.VERSION_CODES.M) + return KMError.SdkVersionTooLow(minSdk = Build.VERSION_CODES.M) } if (!flashLenses.contains(constraint.lens)) { return when (constraint.lens) { - CameraLens.FRONT -> Error.FrontFlashNotFound - CameraLens.BACK -> Error.BackFlashNotFound + CameraLens.FRONT -> KMError.FrontFlashNotFound + CameraLens.BACK -> KMError.BackFlashNotFound } } } is Constraint.WifiConnected, is Constraint.WifiDisconnected -> { if (!isPermissionGranted(Permission.ACCESS_FINE_LOCATION)) { - return Error.PermissionDenied(Permission.ACCESS_FINE_LOCATION) + return SystemError.PermissionDenied(Permission.ACCESS_FINE_LOCATION) } } is Constraint.ImeChosen -> { if (inputMethods.none { it.id == constraint.imeId }) { - return Error.InputMethodNotFound(constraint.imeLabel) + return KMError.InputMethodNotFound(constraint.imeLabel) } } is Constraint.InPhoneCall, is Constraint.PhoneRinging, is Constraint.NotInPhoneCall -> { if (!isPermissionGranted(Permission.READ_PHONE_STATE)) { - return Error.PermissionDenied(Permission.READ_PHONE_STATE) + return SystemError.PermissionDenied(Permission.READ_PHONE_STATE) } } @@ -131,15 +132,15 @@ class LazyConstraintErrorSnapshot( return null } - private fun getAppError(packageName: String): Error? { + private fun getAppError(packageName: String): KMError? { packageManager.isAppEnabled(packageName).onSuccess { isEnabled -> if (!isEnabled) { - return Error.AppDisabled(packageName) + return KMError.AppDisabled(packageName) } } if (!packageManager.isAppInstalled(packageName)) { - return Error.AppNotFound(packageName) + return KMError.AppNotFound(packageName) } return null @@ -157,5 +158,5 @@ class LazyConstraintErrorSnapshot( } interface ConstraintErrorSnapshot { - fun getError(constraint: Constraint): Error? + fun getError(constraint: Constraint): KMError? } diff --git a/app/src/main/java/io/github/sds100/keymapper/constraints/ConstraintId.kt b/base/src/main/java/io/github/sds100/keymapper/base/constraints/ConstraintId.kt similarity index 94% rename from app/src/main/java/io/github/sds100/keymapper/constraints/ConstraintId.kt rename to base/src/main/java/io/github/sds100/keymapper/base/constraints/ConstraintId.kt index b015752aca..6ff99f2b54 100644 --- a/app/src/main/java/io/github/sds100/keymapper/constraints/ConstraintId.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/constraints/ConstraintId.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.constraints +package io.github.sds100.keymapper.base.constraints import kotlinx.serialization.Serializable diff --git a/app/src/main/java/io/github/sds100/keymapper/constraints/ConstraintListItem.kt b/base/src/main/java/io/github/sds100/keymapper/base/constraints/ConstraintListItem.kt similarity index 97% rename from app/src/main/java/io/github/sds100/keymapper/constraints/ConstraintListItem.kt rename to base/src/main/java/io/github/sds100/keymapper/base/constraints/ConstraintListItem.kt index e59fe299e3..51d88a1ade 100644 --- a/app/src/main/java/io/github/sds100/keymapper/constraints/ConstraintListItem.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/constraints/ConstraintListItem.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.constraints +package io.github.sds100.keymapper.base.constraints import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.IntrinsicSize @@ -34,9 +34,9 @@ import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import com.google.accompanist.drawablepainter.rememberDrawablePainter -import io.github.sds100.keymapper.R -import io.github.sds100.keymapper.util.drawable -import io.github.sds100.keymapper.util.ui.compose.ComposeIconInfo +import io.github.sds100.keymapper.base.R +import io.github.sds100.keymapper.base.utils.ui.compose.ComposeIconInfo +import io.github.sds100.keymapper.base.utils.ui.drawable @Composable fun ConstraintListItem( diff --git a/app/src/main/java/io/github/sds100/keymapper/constraints/ConstraintListItemModel.kt b/base/src/main/java/io/github/sds100/keymapper/base/constraints/ConstraintListItemModel.kt similarity index 70% rename from app/src/main/java/io/github/sds100/keymapper/constraints/ConstraintListItemModel.kt rename to base/src/main/java/io/github/sds100/keymapper/base/constraints/ConstraintListItemModel.kt index e5e2ccbd09..39f2ca17a2 100644 --- a/app/src/main/java/io/github/sds100/keymapper/constraints/ConstraintListItemModel.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/constraints/ConstraintListItemModel.kt @@ -1,6 +1,6 @@ -package io.github.sds100.keymapper.constraints +package io.github.sds100.keymapper.base.constraints -import io.github.sds100.keymapper.util.ui.compose.ComposeIconInfo +import io.github.sds100.keymapper.base.utils.ui.compose.ComposeIconInfo data class ConstraintListItemModel( val id: String, diff --git a/base/src/main/java/io/github/sds100/keymapper/base/constraints/ConstraintMode.kt b/base/src/main/java/io/github/sds100/keymapper/base/constraints/ConstraintMode.kt new file mode 100644 index 0000000000..985191d18d --- /dev/null +++ b/base/src/main/java/io/github/sds100/keymapper/base/constraints/ConstraintMode.kt @@ -0,0 +1,6 @@ +package io.github.sds100.keymapper.base.constraints + +enum class ConstraintMode { + AND, + OR, +} diff --git a/app/src/main/java/io/github/sds100/keymapper/constraints/ConstraintSnapshot.kt b/base/src/main/java/io/github/sds100/keymapper/base/constraints/ConstraintSnapshot.kt similarity index 96% rename from app/src/main/java/io/github/sds100/keymapper/constraints/ConstraintSnapshot.kt rename to base/src/main/java/io/github/sds100/keymapper/base/constraints/ConstraintSnapshot.kt index 5a813bc92a..e5803e9b0a 100644 --- a/app/src/main/java/io/github/sds100/keymapper/constraints/ConstraintSnapshot.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/constraints/ConstraintSnapshot.kt @@ -1,13 +1,14 @@ -package io.github.sds100.keymapper.constraints +package io.github.sds100.keymapper.base.constraints import android.media.AudioManager import android.os.Build -import io.github.sds100.keymapper.system.accessibility.IAccessibilityService +import io.github.sds100.keymapper.base.system.accessibility.IAccessibilityService +import io.github.sds100.keymapper.common.utils.Orientation +import io.github.sds100.keymapper.common.utils.firstBlocking import io.github.sds100.keymapper.system.bluetooth.BluetoothDeviceInfo import io.github.sds100.keymapper.system.camera.CameraAdapter import io.github.sds100.keymapper.system.devices.DevicesAdapter import io.github.sds100.keymapper.system.display.DisplayAdapter -import io.github.sds100.keymapper.system.display.Orientation import io.github.sds100.keymapper.system.inputmethod.InputMethodAdapter import io.github.sds100.keymapper.system.lock.LockScreenAdapter import io.github.sds100.keymapper.system.media.MediaAdapter @@ -15,14 +16,9 @@ import io.github.sds100.keymapper.system.network.NetworkAdapter import io.github.sds100.keymapper.system.phone.CallState import io.github.sds100.keymapper.system.phone.PhoneAdapter import io.github.sds100.keymapper.system.power.PowerAdapter -import io.github.sds100.keymapper.util.firstBlocking import timber.log.Timber import java.time.LocalTime -/** - * Created by sds100 on 08/05/2021.f - */ - /** * This allows constraints to be checked lazily because some system calls take a significant amount of time. */ diff --git a/app/src/main/java/io/github/sds100/keymapper/constraints/ConstraintState.kt b/base/src/main/java/io/github/sds100/keymapper/base/constraints/ConstraintState.kt similarity index 67% rename from app/src/main/java/io/github/sds100/keymapper/constraints/ConstraintState.kt rename to base/src/main/java/io/github/sds100/keymapper/base/constraints/ConstraintState.kt index 0998f7871a..ad284ccdb2 100644 --- a/app/src/main/java/io/github/sds100/keymapper/constraints/ConstraintState.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/constraints/ConstraintState.kt @@ -1,11 +1,7 @@ -package io.github.sds100.keymapper.constraints +package io.github.sds100.keymapper.base.constraints import kotlinx.serialization.Serializable -/** - * Created by sds100 on 04/04/2021. - */ - @Serializable data class ConstraintState( val constraints: Set = emptySet(), diff --git a/app/src/main/java/io/github/sds100/keymapper/constraints/ConstraintUiHelper.kt b/base/src/main/java/io/github/sds100/keymapper/base/constraints/ConstraintUiHelper.kt similarity index 93% rename from app/src/main/java/io/github/sds100/keymapper/constraints/ConstraintUiHelper.kt rename to base/src/main/java/io/github/sds100/keymapper/base/constraints/ConstraintUiHelper.kt index 223b606c77..e1db1b1f0e 100644 --- a/app/src/main/java/io/github/sds100/keymapper/constraints/ConstraintUiHelper.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/constraints/ConstraintUiHelper.kt @@ -1,21 +1,17 @@ -package io.github.sds100.keymapper.constraints +package io.github.sds100.keymapper.base.constraints import androidx.compose.material.icons.Icons import androidx.compose.material.icons.rounded.Android -import io.github.sds100.keymapper.R +import io.github.sds100.keymapper.base.R +import io.github.sds100.keymapper.base.utils.ui.ResourceProvider +import io.github.sds100.keymapper.base.utils.ui.compose.ComposeIconInfo +import io.github.sds100.keymapper.common.utils.Orientation +import io.github.sds100.keymapper.common.utils.TimeUtils +import io.github.sds100.keymapper.common.utils.handle +import io.github.sds100.keymapper.common.utils.valueIfFailure import io.github.sds100.keymapper.system.camera.CameraLens -import io.github.sds100.keymapper.system.display.Orientation -import io.github.sds100.keymapper.util.TimeUtils -import io.github.sds100.keymapper.util.handle -import io.github.sds100.keymapper.util.ui.ResourceProvider -import io.github.sds100.keymapper.util.ui.compose.ComposeIconInfo -import io.github.sds100.keymapper.util.valueIfFailure import java.time.format.FormatStyle -/** - * Created by sds100 on 18/03/2021. - */ - class ConstraintUiHelper( displayConstraintUseCase: DisplayConstraintUseCase, resourceProvider: ResourceProvider, diff --git a/app/src/main/java/io/github/sds100/keymapper/constraints/ConstraintUtils.kt b/base/src/main/java/io/github/sds100/keymapper/base/constraints/ConstraintUtils.kt similarity index 97% rename from app/src/main/java/io/github/sds100/keymapper/constraints/ConstraintUtils.kt rename to base/src/main/java/io/github/sds100/keymapper/base/constraints/ConstraintUtils.kt index db5e3421e9..8ea3d1f352 100644 --- a/app/src/main/java/io/github/sds100/keymapper/constraints/ConstraintUtils.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/constraints/ConstraintUtils.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.constraints +package io.github.sds100.keymapper.base.constraints import androidx.compose.material.icons.Icons import androidx.compose.material.icons.outlined.Battery2Bar @@ -24,8 +24,8 @@ import androidx.compose.material.icons.outlined.Timer import androidx.compose.material.icons.outlined.Wifi import androidx.compose.material.icons.outlined.WifiOff import androidx.compose.material.icons.rounded.Android -import io.github.sds100.keymapper.R -import io.github.sds100.keymapper.util.ui.compose.ComposeIconInfo +import io.github.sds100.keymapper.base.R +import io.github.sds100.keymapper.base.utils.ui.compose.ComposeIconInfo object ConstraintUtils { diff --git a/app/src/main/java/io/github/sds100/keymapper/constraints/ConstraintsScreen.kt b/base/src/main/java/io/github/sds100/keymapper/base/constraints/ConstraintsScreen.kt similarity index 92% rename from app/src/main/java/io/github/sds100/keymapper/constraints/ConstraintsScreen.kt rename to base/src/main/java/io/github/sds100/keymapper/base/constraints/ConstraintsScreen.kt index 8c5d50b219..fa5e20ad28 100644 --- a/app/src/main/java/io/github/sds100/keymapper/constraints/ConstraintsScreen.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/constraints/ConstraintsScreen.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.constraints +package io.github.sds100.keymapper.base.constraints import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box @@ -37,15 +37,15 @@ import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle -import io.github.sds100.keymapper.R -import io.github.sds100.keymapper.compose.KeyMapperTheme -import io.github.sds100.keymapper.keymaps.ShortcutModel -import io.github.sds100.keymapper.keymaps.ShortcutRow +import io.github.sds100.keymapper.base.R +import io.github.sds100.keymapper.base.compose.KeyMapperTheme +import io.github.sds100.keymapper.base.keymaps.ShortcutModel +import io.github.sds100.keymapper.base.keymaps.ShortcutRow +import io.github.sds100.keymapper.base.utils.ui.compose.ComposeIconInfo +import io.github.sds100.keymapper.base.utils.ui.compose.RadioButtonText +import io.github.sds100.keymapper.base.utils.ui.drawable +import io.github.sds100.keymapper.common.utils.State import io.github.sds100.keymapper.system.camera.CameraLens -import io.github.sds100.keymapper.util.State -import io.github.sds100.keymapper.util.drawable -import io.github.sds100.keymapper.util.ui.compose.ComposeIconInfo -import io.github.sds100.keymapper.util.ui.compose.RadioButtonText @Composable fun ConstraintsScreen( @@ -111,11 +111,11 @@ private fun ConstraintsScreen( ) } - when (state) { + when (val state = state) { State.Loading -> Loading() is State.Data -> Surface(modifier = modifier) { Column { - when (state.data) { + when (val data = state.data) { is ConfigConstraintsState.Empty -> { Column( modifier = Modifier.weight(1f), @@ -130,7 +130,7 @@ private fun ConstraintsScreen( textAlign = TextAlign.Center, ) - if (state.data.shortcuts.isNotEmpty()) { + if (data.shortcuts.isNotEmpty()) { Text( text = stringResource(R.string.recently_used_constraints), style = MaterialTheme.typography.titleSmall, @@ -142,7 +142,7 @@ private fun ConstraintsScreen( modifier = Modifier .padding(horizontal = 32.dp) .fillMaxWidth(), - shortcuts = state.data.shortcuts, + shortcuts = data.shortcuts, onClick = onClickShortcut, ) } @@ -152,7 +152,7 @@ private fun ConstraintsScreen( is ConfigConstraintsState.Loaded -> { Spacer(Modifier.height(8.dp)) - if (state.data.constraintList.isNotEmpty()) { + if (data.constraintList.isNotEmpty()) { Spacer(Modifier.height(8.dp)) Text( @@ -166,8 +166,8 @@ private fun ConstraintsScreen( ConstraintList( modifier = Modifier.weight(1f), - constraintList = state.data.constraintList, - shortcuts = state.data.shortcuts, + constraintList = data.constraintList, + shortcuts = data.shortcuts, onRemoveClick = { constraintToDelete = it showDeleteDialog = true @@ -176,12 +176,12 @@ private fun ConstraintsScreen( onClickShortcut = onClickShortcut, ) - if (state.data.constraintList.size > 1) { + if (data.constraintList.size > 1) { ConstraintModeRow( modifier = Modifier .fillMaxWidth() .padding(horizontal = 8.dp), - mode = state.data.selectedMode, + mode = data.selectedMode, onSelectMode = onSelectMode, ) } diff --git a/app/src/main/java/io/github/sds100/keymapper/constraints/CreateConstraintUseCase.kt b/base/src/main/java/io/github/sds100/keymapper/base/constraints/CreateConstraintUseCase.kt similarity index 83% rename from app/src/main/java/io/github/sds100/keymapper/constraints/CreateConstraintUseCase.kt rename to base/src/main/java/io/github/sds100/keymapper/base/constraints/CreateConstraintUseCase.kt index 761af23fc4..9b8dcfb652 100644 --- a/app/src/main/java/io/github/sds100/keymapper/constraints/CreateConstraintUseCase.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/constraints/CreateConstraintUseCase.kt @@ -1,7 +1,8 @@ -package io.github.sds100.keymapper.constraints +package io.github.sds100.keymapper.base.constraints import android.content.pm.PackageManager import android.os.Build +import io.github.sds100.keymapper.common.utils.KMError import io.github.sds100.keymapper.data.Keys import io.github.sds100.keymapper.data.repositories.PreferenceRepository import io.github.sds100.keymapper.system.camera.CameraAdapter @@ -9,39 +10,35 @@ import io.github.sds100.keymapper.system.camera.CameraLens import io.github.sds100.keymapper.system.inputmethod.ImeInfo import io.github.sds100.keymapper.system.inputmethod.InputMethodAdapter import io.github.sds100.keymapper.system.network.NetworkAdapter -import io.github.sds100.keymapper.util.Error import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.map +import javax.inject.Inject -/** - * Created by sds100 on 06/07/2021. - */ - -class CreateConstraintUseCaseImpl( +class CreateConstraintUseCaseImpl @Inject constructor( private val networkAdapter: NetworkAdapter, private val inputMethodAdapter: InputMethodAdapter, private val preferenceRepository: PreferenceRepository, private val cameraAdapter: CameraAdapter, ) : CreateConstraintUseCase { - override fun isSupported(constraint: ConstraintId): Error? { + override fun isSupported(constraint: ConstraintId): KMError? { when (constraint) { ConstraintId.FLASHLIGHT_ON, ConstraintId.FLASHLIGHT_OFF -> { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { - return Error.SdkVersionTooLow(minSdk = Build.VERSION_CODES.M) + return KMError.SdkVersionTooLow(minSdk = Build.VERSION_CODES.M) } if (cameraAdapter.getFlashInfo(CameraLens.BACK) == null && cameraAdapter.getFlashInfo(CameraLens.FRONT) == null ) { - return Error.SystemFeatureNotSupported(PackageManager.FEATURE_CAMERA_FLASH) + return KMError.SystemFeatureNotSupported(PackageManager.FEATURE_CAMERA_FLASH) } } ConstraintId.DEVICE_IS_LOCKED, ConstraintId.DEVICE_IS_UNLOCKED -> if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP_MR1) { - return Error.SdkVersionTooLow(minSdk = Build.VERSION_CODES.LOLLIPOP_MR1) + return KMError.SdkVersionTooLow(minSdk = Build.VERSION_CODES.LOLLIPOP_MR1) } else -> Unit @@ -84,7 +81,7 @@ class CreateConstraintUseCaseImpl( } interface CreateConstraintUseCase { - fun isSupported(constraint: ConstraintId): Error? + fun isSupported(constraint: ConstraintId): KMError? fun getKnownWiFiSSIDs(): List? fun getEnabledInputMethods(): List diff --git a/app/src/main/java/io/github/sds100/keymapper/constraints/DetectConstraintsUseCase.kt b/base/src/main/java/io/github/sds100/keymapper/base/constraints/DetectConstraintsUseCase.kt similarity index 88% rename from app/src/main/java/io/github/sds100/keymapper/constraints/DetectConstraintsUseCase.kt rename to base/src/main/java/io/github/sds100/keymapper/base/constraints/DetectConstraintsUseCase.kt index dc42fff24b..89888bba02 100644 --- a/app/src/main/java/io/github/sds100/keymapper/constraints/DetectConstraintsUseCase.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/constraints/DetectConstraintsUseCase.kt @@ -1,7 +1,10 @@ -package io.github.sds100.keymapper.constraints +package io.github.sds100.keymapper.base.constraints import android.os.Build -import io.github.sds100.keymapper.system.accessibility.IAccessibilityService +import dagger.assisted.Assisted +import dagger.assisted.AssistedFactory +import dagger.assisted.AssistedInject +import io.github.sds100.keymapper.base.system.accessibility.IAccessibilityService import io.github.sds100.keymapper.system.camera.CameraAdapter import io.github.sds100.keymapper.system.camera.CameraLens import io.github.sds100.keymapper.system.devices.DevicesAdapter @@ -17,11 +20,8 @@ import kotlinx.coroutines.flow.emptyFlow import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.merge -/** - * Created by sds100 on 17/04/2021. - */ - -class DetectConstraintsUseCaseImpl( +class DetectConstraintsUseCaseImpl @AssistedInject constructor( + @Assisted private val accessibilityService: IAccessibilityService, private val mediaAdapter: MediaAdapter, private val devicesAdapter: DevicesAdapter, @@ -34,6 +34,13 @@ class DetectConstraintsUseCaseImpl( private val powerAdapter: PowerAdapter, ) : DetectConstraintsUseCase { + @AssistedFactory + interface Factory { + fun create( + accessibilityService: IAccessibilityService, + ): DetectConstraintsUseCaseImpl + } + override fun getSnapshot(): ConstraintSnapshot = LazyConstraintSnapshot( accessibilityService, mediaAdapter, diff --git a/base/src/main/java/io/github/sds100/keymapper/base/constraints/DisplayConstraintUseCase.kt b/base/src/main/java/io/github/sds100/keymapper/base/constraints/DisplayConstraintUseCase.kt new file mode 100644 index 0000000000..890ce8cbc3 --- /dev/null +++ b/base/src/main/java/io/github/sds100/keymapper/base/constraints/DisplayConstraintUseCase.kt @@ -0,0 +1,13 @@ +package io.github.sds100.keymapper.base.constraints + +import android.graphics.drawable.Drawable +import io.github.sds100.keymapper.common.utils.KMError +import io.github.sds100.keymapper.common.utils.KMResult + +interface DisplayConstraintUseCase : GetConstraintErrorUseCase { + fun getAppName(packageName: String): KMResult + fun getAppIcon(packageName: String): KMResult + fun getInputMethodLabel(imeId: String): KMResult + fun neverShowDndTriggerError() + suspend fun fixError(error: KMError) +} diff --git a/app/src/main/java/io/github/sds100/keymapper/constraints/GetConstraintErrorUseCase.kt b/base/src/main/java/io/github/sds100/keymapper/base/constraints/GetConstraintErrorUseCase.kt similarity index 82% rename from app/src/main/java/io/github/sds100/keymapper/constraints/GetConstraintErrorUseCase.kt rename to base/src/main/java/io/github/sds100/keymapper/base/constraints/GetConstraintErrorUseCase.kt index 0d2667029b..c1a6cbcd03 100644 --- a/app/src/main/java/io/github/sds100/keymapper/constraints/GetConstraintErrorUseCase.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/constraints/GetConstraintErrorUseCase.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.constraints +package io.github.sds100.keymapper.base.constraints import io.github.sds100.keymapper.system.apps.PackageManagerAdapter import io.github.sds100.keymapper.system.camera.CameraAdapter @@ -11,9 +11,12 @@ import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.drop import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.merge +import javax.inject.Inject +import javax.inject.Singleton -class GetConstraintErrorUseCaseImpl( - private val packageManager: PackageManagerAdapter, +@Singleton +class GetConstraintErrorUseCaseImpl @Inject constructor( + private val packageManagerAdapter: PackageManagerAdapter, private val permissionAdapter: PermissionAdapter, private val systemFeatureAdapter: SystemFeatureAdapter, private val inputMethodAdapter: InputMethodAdapter, @@ -22,7 +25,7 @@ class GetConstraintErrorUseCaseImpl( private val invalidateConstraintErrors = merge( permissionAdapter.onPermissionsUpdate, inputMethodAdapter.inputMethods.drop(1).map { }, - packageManager.onPackagesChanged, + packageManagerAdapter.onPackagesChanged, ) override val constraintErrorSnapshot: Flow = channelFlow { @@ -34,7 +37,7 @@ class GetConstraintErrorUseCaseImpl( } private fun createSnapshot(): ConstraintErrorSnapshot = LazyConstraintErrorSnapshot( - packageManager, + packageManagerAdapter, permissionAdapter, systemFeatureAdapter, inputMethodAdapter, diff --git a/app/src/main/java/io/github/sds100/keymapper/constraints/TimeConstraintBottomSheet.kt b/base/src/main/java/io/github/sds100/keymapper/base/constraints/TimeConstraintBottomSheet.kt similarity index 97% rename from app/src/main/java/io/github/sds100/keymapper/constraints/TimeConstraintBottomSheet.kt rename to base/src/main/java/io/github/sds100/keymapper/base/constraints/TimeConstraintBottomSheet.kt index f59740fddd..f99472093b 100644 --- a/app/src/main/java/io/github/sds100/keymapper/constraints/TimeConstraintBottomSheet.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/constraints/TimeConstraintBottomSheet.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.constraints +package io.github.sds100.keymapper.base.constraints import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column @@ -41,10 +41,10 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp -import io.github.sds100.keymapper.R -import io.github.sds100.keymapper.compose.KeyMapperTheme -import io.github.sds100.keymapper.util.TimeUtils -import io.github.sds100.keymapper.util.ui.compose.OptionsHeaderRow +import io.github.sds100.keymapper.base.R +import io.github.sds100.keymapper.base.compose.KeyMapperTheme +import io.github.sds100.keymapper.base.utils.ui.compose.OptionsHeaderRow +import io.github.sds100.keymapper.common.utils.TimeUtils import kotlinx.coroutines.launch import java.time.format.FormatStyle diff --git a/app/src/main/java/io/github/sds100/keymapper/floating/FloatingButtonAppearance.kt b/base/src/main/java/io/github/sds100/keymapper/base/floating/FloatingButtonAppearance.kt similarity index 91% rename from app/src/main/java/io/github/sds100/keymapper/floating/FloatingButtonAppearance.kt rename to base/src/main/java/io/github/sds100/keymapper/base/floating/FloatingButtonAppearance.kt index 973025ca96..39031918a4 100644 --- a/app/src/main/java/io/github/sds100/keymapper/floating/FloatingButtonAppearance.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/floating/FloatingButtonAppearance.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.floating +package io.github.sds100.keymapper.base.floating import kotlinx.serialization.Serializable diff --git a/app/src/main/java/io/github/sds100/keymapper/floating/FloatingButtonData.kt b/base/src/main/java/io/github/sds100/keymapper/base/floating/FloatingButtonData.kt similarity index 92% rename from app/src/main/java/io/github/sds100/keymapper/floating/FloatingButtonData.kt rename to base/src/main/java/io/github/sds100/keymapper/base/floating/FloatingButtonData.kt index f8a19fe376..84a9c5535e 100644 --- a/app/src/main/java/io/github/sds100/keymapper/floating/FloatingButtonData.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/floating/FloatingButtonData.kt @@ -1,11 +1,11 @@ -package io.github.sds100.keymapper.floating +package io.github.sds100.keymapper.base.floating +import io.github.sds100.keymapper.base.floating.FloatingButtonData.Location +import io.github.sds100.keymapper.common.utils.Orientation +import io.github.sds100.keymapper.common.utils.SizeKM +import io.github.sds100.keymapper.common.utils.getKey import io.github.sds100.keymapper.data.db.typeconverter.ConstantTypeConverters import io.github.sds100.keymapper.data.entities.FloatingButtonEntity -import io.github.sds100.keymapper.floating.FloatingButtonData.Location -import io.github.sds100.keymapper.system.display.Orientation -import io.github.sds100.keymapper.util.SizeKM -import io.github.sds100.keymapper.util.getKey import kotlinx.serialization.Serializable import java.util.UUID diff --git a/app/src/main/java/io/github/sds100/keymapper/floating/FloatingLayoutData.kt b/base/src/main/java/io/github/sds100/keymapper/base/floating/FloatingLayoutData.kt similarity index 95% rename from app/src/main/java/io/github/sds100/keymapper/floating/FloatingLayoutData.kt rename to base/src/main/java/io/github/sds100/keymapper/base/floating/FloatingLayoutData.kt index 150536bfc4..675d207917 100644 --- a/app/src/main/java/io/github/sds100/keymapper/floating/FloatingLayoutData.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/floating/FloatingLayoutData.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.floating +package io.github.sds100.keymapper.base.floating import io.github.sds100.keymapper.data.entities.FloatingLayoutEntity import io.github.sds100.keymapper.data.entities.FloatingLayoutEntityWithButtons diff --git a/app/src/main/java/io/github/sds100/keymapper/groups/DeleteGroupDialog.kt b/base/src/main/java/io/github/sds100/keymapper/base/groups/DeleteGroupDialog.kt similarity index 94% rename from app/src/main/java/io/github/sds100/keymapper/groups/DeleteGroupDialog.kt rename to base/src/main/java/io/github/sds100/keymapper/base/groups/DeleteGroupDialog.kt index 29155760f1..ff6e8ca867 100644 --- a/app/src/main/java/io/github/sds100/keymapper/groups/DeleteGroupDialog.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/groups/DeleteGroupDialog.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.groups +package io.github.sds100.keymapper.base.groups import androidx.compose.material3.AlertDialog import androidx.compose.material3.MaterialTheme @@ -8,7 +8,7 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextOverflow -import io.github.sds100.keymapper.R +import io.github.sds100.keymapper.base.R @Composable fun DeleteGroupDialog( diff --git a/app/src/main/java/io/github/sds100/keymapper/groups/Group.kt b/base/src/main/java/io/github/sds100/keymapper/base/groups/Group.kt similarity index 82% rename from app/src/main/java/io/github/sds100/keymapper/groups/Group.kt rename to base/src/main/java/io/github/sds100/keymapper/base/groups/Group.kt index 6633399388..0ca10b7535 100644 --- a/app/src/main/java/io/github/sds100/keymapper/groups/Group.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/groups/Group.kt @@ -1,8 +1,8 @@ -package io.github.sds100.keymapper.groups +package io.github.sds100.keymapper.base.groups -import io.github.sds100.keymapper.constraints.ConstraintEntityMapper -import io.github.sds100.keymapper.constraints.ConstraintModeEntityMapper -import io.github.sds100.keymapper.constraints.ConstraintState +import io.github.sds100.keymapper.base.constraints.ConstraintEntityMapper +import io.github.sds100.keymapper.base.constraints.ConstraintModeEntityMapper +import io.github.sds100.keymapper.base.constraints.ConstraintState import io.github.sds100.keymapper.data.entities.GroupEntity data class Group( diff --git a/app/src/main/java/io/github/sds100/keymapper/groups/GroupBreadcrumbRow.kt b/base/src/main/java/io/github/sds100/keymapper/base/groups/GroupBreadcrumbRow.kt similarity index 97% rename from app/src/main/java/io/github/sds100/keymapper/groups/GroupBreadcrumbRow.kt rename to base/src/main/java/io/github/sds100/keymapper/base/groups/GroupBreadcrumbRow.kt index 70ff333357..d3ece625dc 100644 --- a/app/src/main/java/io/github/sds100/keymapper/groups/GroupBreadcrumbRow.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/groups/GroupBreadcrumbRow.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.groups +package io.github.sds100.keymapper.base.groups import androidx.compose.foundation.horizontalScroll import androidx.compose.foundation.layout.BoxWithConstraints @@ -24,7 +24,7 @@ import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp -import io.github.sds100.keymapper.R +import io.github.sds100.keymapper.base.R @Composable fun GroupBreadcrumbRow( diff --git a/app/src/main/java/io/github/sds100/keymapper/groups/GroupConstraintRow.kt b/base/src/main/java/io/github/sds100/keymapper/base/groups/GroupConstraintRow.kt similarity index 95% rename from app/src/main/java/io/github/sds100/keymapper/groups/GroupConstraintRow.kt rename to base/src/main/java/io/github/sds100/keymapper/base/groups/GroupConstraintRow.kt index 6ba5aeb4ef..890a61d6c4 100644 --- a/app/src/main/java/io/github/sds100/keymapper/groups/GroupConstraintRow.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/groups/GroupConstraintRow.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.groups +package io.github.sds100.keymapper.base.groups import androidx.compose.foundation.BorderStroke import androidx.compose.foundation.layout.Arrangement @@ -38,14 +38,13 @@ import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import com.google.accompanist.drawablepainter.rememberDrawablePainter -import io.github.sds100.keymapper.Constants -import io.github.sds100.keymapper.R -import io.github.sds100.keymapper.compose.KeyMapperTheme -import io.github.sds100.keymapper.constraints.ConstraintMode -import io.github.sds100.keymapper.util.Error -import io.github.sds100.keymapper.util.drawable -import io.github.sds100.keymapper.util.ui.compose.ComposeChipModel -import io.github.sds100.keymapper.util.ui.compose.ComposeIconInfo +import io.github.sds100.keymapper.base.R +import io.github.sds100.keymapper.base.compose.KeyMapperTheme +import io.github.sds100.keymapper.base.constraints.ConstraintMode +import io.github.sds100.keymapper.base.utils.ui.compose.ComposeChipModel +import io.github.sds100.keymapper.base.utils.ui.compose.ComposeIconInfo +import io.github.sds100.keymapper.base.utils.ui.drawable +import io.github.sds100.keymapper.common.utils.KMError @Composable fun GroupConstraintRow( @@ -55,7 +54,7 @@ fun GroupConstraintRow( parentConstraintCount: Int, onNewConstraintClick: () -> Unit = {}, onRemoveConstraintClick: (String) -> Unit = {}, - onFixConstraintClick: (Error) -> Unit = {}, + onFixConstraintClick: (KMError) -> Unit = {}, enabled: Boolean = true, ) { BoxWithConstraints(modifier = modifier) { @@ -359,7 +358,7 @@ private fun PreviewMultipleItems() { ComposeChipModel.Error( id = "2", text = "Key Mapper not found", - error = Error.AppNotFound(Constants.PACKAGE_NAME), + error = KMError.AppNotFound("io.github.sds100.keymapper"), ), ), mode = ConstraintMode.AND, diff --git a/app/src/main/java/io/github/sds100/keymapper/groups/GroupFamily.kt b/base/src/main/java/io/github/sds100/keymapper/base/groups/GroupFamily.kt similarity index 70% rename from app/src/main/java/io/github/sds100/keymapper/groups/GroupFamily.kt rename to base/src/main/java/io/github/sds100/keymapper/base/groups/GroupFamily.kt index e6e7a790e4..afd78e9231 100644 --- a/app/src/main/java/io/github/sds100/keymapper/groups/GroupFamily.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/groups/GroupFamily.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.groups +package io.github.sds100.keymapper.base.groups data class GroupFamily( val group: Group?, diff --git a/base/src/main/java/io/github/sds100/keymapper/base/groups/GroupListItemModel.kt b/base/src/main/java/io/github/sds100/keymapper/base/groups/GroupListItemModel.kt new file mode 100644 index 0000000000..446bfffc55 --- /dev/null +++ b/base/src/main/java/io/github/sds100/keymapper/base/groups/GroupListItemModel.kt @@ -0,0 +1,5 @@ +package io.github.sds100.keymapper.base.groups + +import io.github.sds100.keymapper.base.utils.ui.compose.ComposeIconInfo + +data class GroupListItemModel(val uid: String, val name: String, val icon: ComposeIconInfo? = null) diff --git a/app/src/main/java/io/github/sds100/keymapper/groups/GroupRow.kt b/base/src/main/java/io/github/sds100/keymapper/base/groups/GroupRow.kt similarity index 97% rename from app/src/main/java/io/github/sds100/keymapper/groups/GroupRow.kt rename to base/src/main/java/io/github/sds100/keymapper/base/groups/GroupRow.kt index 49f36f5762..6a384f04a8 100644 --- a/app/src/main/java/io/github/sds100/keymapper/groups/GroupRow.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/groups/GroupRow.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.groups +package io.github.sds100.keymapper.base.groups import androidx.compose.animation.AnimatedContent import androidx.compose.animation.animateContentSize @@ -42,10 +42,10 @@ import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import com.google.accompanist.drawablepainter.rememberDrawablePainter -import io.github.sds100.keymapper.R -import io.github.sds100.keymapper.compose.KeyMapperTheme -import io.github.sds100.keymapper.util.drawable -import io.github.sds100.keymapper.util.ui.compose.ComposeIconInfo +import io.github.sds100.keymapper.base.R +import io.github.sds100.keymapper.base.compose.KeyMapperTheme +import io.github.sds100.keymapper.base.utils.ui.compose.ComposeIconInfo +import io.github.sds100.keymapper.base.utils.ui.drawable @Composable fun GroupRow( diff --git a/base/src/main/java/io/github/sds100/keymapper/base/home/BaseHomeViewModel.kt b/base/src/main/java/io/github/sds100/keymapper/base/home/BaseHomeViewModel.kt new file mode 100644 index 0000000000..47e7d65a73 --- /dev/null +++ b/base/src/main/java/io/github/sds100/keymapper/base/home/BaseHomeViewModel.kt @@ -0,0 +1,133 @@ +package io.github.sds100.keymapper.base.home + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import io.github.sds100.keymapper.base.R +import io.github.sds100.keymapper.base.backup.BackupRestoreMappingsUseCase +import io.github.sds100.keymapper.base.keymaps.KeyMapListViewModel +import io.github.sds100.keymapper.base.keymaps.ListKeyMapsUseCase +import io.github.sds100.keymapper.base.keymaps.PauseKeyMapsUseCase +import io.github.sds100.keymapper.base.onboarding.OnboardingUseCase +import io.github.sds100.keymapper.base.sorting.SortKeyMapsUseCase +import io.github.sds100.keymapper.base.system.inputmethod.ShowInputMethodPickerUseCase +import io.github.sds100.keymapper.base.trigger.SetupGuiKeyboardUseCase +import io.github.sds100.keymapper.base.utils.navigation.NavDestination +import io.github.sds100.keymapper.base.utils.navigation.NavigationProvider +import io.github.sds100.keymapper.base.utils.navigation.navigate +import io.github.sds100.keymapper.base.utils.ui.DialogModel +import io.github.sds100.keymapper.base.utils.ui.DialogProvider +import io.github.sds100.keymapper.base.utils.ui.DialogResponse +import io.github.sds100.keymapper.base.utils.ui.ResourceProvider +import io.github.sds100.keymapper.base.utils.ui.showDialog +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.launch + +abstract class BaseHomeViewModel( + private val listKeyMaps: ListKeyMapsUseCase, + private val pauseKeyMaps: PauseKeyMapsUseCase, + private val backupRestore: BackupRestoreMappingsUseCase, + private val showAlertsUseCase: ShowHomeScreenAlertsUseCase, + private val onboarding: OnboardingUseCase, + resourceProvider: ResourceProvider, + private val setupGuiKeyboard: SetupGuiKeyboardUseCase, + private val sortKeyMaps: SortKeyMapsUseCase, + private val showInputMethodPickerUseCase: ShowInputMethodPickerUseCase, + navigationProvider: NavigationProvider, + dialogProvider: DialogProvider, +) : ViewModel(), + ResourceProvider by resourceProvider, + DialogProvider by dialogProvider, + NavigationProvider by navigationProvider { + + val keyMapListViewModel by lazy { + KeyMapListViewModel( + viewModelScope, + listKeyMaps, + resourceProvider, + setupGuiKeyboard, + sortKeyMaps, + showAlertsUseCase, + pauseKeyMaps, + backupRestore, + showInputMethodPickerUseCase, + onboarding, + navigationProvider, + dialogProvider, + ) + } + + init { + viewModelScope.launch { + onboarding.showWhatsNew.collect { showWhatsNew -> + if (showWhatsNew) { + showWhatsNewDialog() + } + } + } + + viewModelScope.launch { + if (setupGuiKeyboard.isInstalled.first() && !setupGuiKeyboard.isCompatibleVersion.first()) { + showUpgradeGuiKeyboardDialog() + } + } + } + + fun launchSettings() { + viewModelScope.launch { + navigate("settings", NavDestination.Settings) + } + } + + fun launchAbout() { + viewModelScope.launch { + navigate("about", NavDestination.About) + } + } + + private suspend fun showWhatsNewDialog() { + val dialog = DialogModel.Alert( + title = getString(R.string.whats_new), + message = onboarding.getWhatsNewText(), + positiveButtonText = getString(R.string.pos_ok), + neutralButtonText = getString(R.string.neutral_changelog), + ) + + // don't return if they dismiss the dialog because this is common behaviour. + val response = showDialog("whats-new", dialog) + + if (response == DialogResponse.NEUTRAL) { + showDialog("url_changelog", DialogModel.OpenUrl(getString(R.string.url_changelog))) + } + + onboarding.showedWhatsNew() + } + + private suspend fun showUpgradeGuiKeyboardDialog() { + val dialog = DialogModel.Alert( + title = getString(R.string.dialog_upgrade_gui_keyboard_title), + message = getString(R.string.dialog_upgrade_gui_keyboard_message), + positiveButtonText = getString(R.string.dialog_upgrade_gui_keyboard_positive), + negativeButtonText = getString(R.string.dialog_upgrade_gui_keyboard_neutral), + ) + + val response = showDialog("upgrade_gui_keyboard", dialog) + + if (response == DialogResponse.POSITIVE) { + showDialog( + "gui_keyboard_play_store", + DialogModel.OpenUrl(getString(R.string.url_play_store_keymapper_gui_keyboard)), + ) + } + } +} + +enum class SelectedKeyMapsEnabled { + ALL, + NONE, + MIXED, +} + +data class HomeWarningListItem( + val id: String, + val text: String, +) diff --git a/app/src/main/java/io/github/sds100/keymapper/home/DeleteKeyMapsDialog.kt b/base/src/main/java/io/github/sds100/keymapper/base/home/DeleteKeyMapsDialog.kt similarity index 94% rename from app/src/main/java/io/github/sds100/keymapper/home/DeleteKeyMapsDialog.kt rename to base/src/main/java/io/github/sds100/keymapper/base/home/DeleteKeyMapsDialog.kt index 70d7772c34..86ff062ecb 100644 --- a/app/src/main/java/io/github/sds100/keymapper/home/DeleteKeyMapsDialog.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/home/DeleteKeyMapsDialog.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.home +package io.github.sds100.keymapper.base.home import androidx.compose.material3.AlertDialog import androidx.compose.material3.MaterialTheme @@ -8,7 +8,7 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.res.pluralStringResource import androidx.compose.ui.res.stringResource -import io.github.sds100.keymapper.R +import io.github.sds100.keymapper.base.R @Composable fun DeleteKeyMapsDialog( diff --git a/app/src/main/java/io/github/sds100/keymapper/home/HomeKeyMapListScreen.kt b/base/src/main/java/io/github/sds100/keymapper/base/home/HomeKeyMapListScreen.kt similarity index 93% rename from app/src/main/java/io/github/sds100/keymapper/home/HomeKeyMapListScreen.kt rename to base/src/main/java/io/github/sds100/keymapper/base/home/HomeKeyMapListScreen.kt index c7f448d788..1b4175e7c8 100644 --- a/app/src/main/java/io/github/sds100/keymapper/home/HomeKeyMapListScreen.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/home/HomeKeyMapListScreen.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.home +package io.github.sds100.keymapper.base.home import androidx.activity.compose.LocalActivity import androidx.activity.compose.rememberLauncherForActivityResult @@ -53,31 +53,31 @@ import androidx.compose.ui.unit.dp import androidx.core.net.toUri import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.canopas.lib.showcase.IntroShowcase -import io.github.sds100.keymapper.R -import io.github.sds100.keymapper.backup.ImportExportState -import io.github.sds100.keymapper.backup.RestoreType -import io.github.sds100.keymapper.compose.KeyMapperTheme -import io.github.sds100.keymapper.constraints.ConstraintMode -import io.github.sds100.keymapper.groups.GroupListItemModel -import io.github.sds100.keymapper.keymaps.KeyMapAppBarState -import io.github.sds100.keymapper.keymaps.KeyMapList -import io.github.sds100.keymapper.keymaps.KeyMapListViewModel -import io.github.sds100.keymapper.onboarding.OnboardingTapTarget -import io.github.sds100.keymapper.sorting.SortBottomSheet +import io.github.sds100.keymapper.base.R +import io.github.sds100.keymapper.base.backup.ImportExportState +import io.github.sds100.keymapper.base.backup.RestoreType +import io.github.sds100.keymapper.base.compose.KeyMapperTheme +import io.github.sds100.keymapper.base.constraints.ConstraintMode +import io.github.sds100.keymapper.base.groups.GroupListItemModel +import io.github.sds100.keymapper.base.keymaps.KeyMapAppBarState +import io.github.sds100.keymapper.base.keymaps.KeyMapList +import io.github.sds100.keymapper.base.keymaps.KeyMapListViewModel +import io.github.sds100.keymapper.base.onboarding.OnboardingTapTarget +import io.github.sds100.keymapper.base.sorting.SortBottomSheet +import io.github.sds100.keymapper.base.trigger.DpadTriggerSetupBottomSheet +import io.github.sds100.keymapper.base.trigger.KeyMapListItemModel +import io.github.sds100.keymapper.base.trigger.TriggerError +import io.github.sds100.keymapper.base.utils.ShareUtils +import io.github.sds100.keymapper.base.utils.ui.compose.CollapsableFloatingActionButton +import io.github.sds100.keymapper.base.utils.ui.compose.ComposeChipModel +import io.github.sds100.keymapper.base.utils.ui.compose.ComposeIconInfo +import io.github.sds100.keymapper.base.utils.ui.compose.KeyMapperTapTarget +import io.github.sds100.keymapper.base.utils.ui.compose.keyMapperShowcaseStyle +import io.github.sds100.keymapper.base.utils.ui.compose.openUriSafe +import io.github.sds100.keymapper.base.utils.ui.drawable +import io.github.sds100.keymapper.common.utils.KMError +import io.github.sds100.keymapper.common.utils.State import io.github.sds100.keymapper.system.files.FileUtils -import io.github.sds100.keymapper.trigger.DpadTriggerSetupBottomSheet -import io.github.sds100.keymapper.trigger.KeyMapListItemModel -import io.github.sds100.keymapper.trigger.TriggerError -import io.github.sds100.keymapper.util.Error -import io.github.sds100.keymapper.util.ShareUtils -import io.github.sds100.keymapper.util.State -import io.github.sds100.keymapper.util.drawable -import io.github.sds100.keymapper.util.ui.compose.CollapsableFloatingActionButton -import io.github.sds100.keymapper.util.ui.compose.ComposeChipModel -import io.github.sds100.keymapper.util.ui.compose.ComposeIconInfo -import io.github.sds100.keymapper.util.ui.compose.KeyMapperTapTarget -import io.github.sds100.keymapper.util.ui.compose.keyMapperShowcaseStyle -import io.github.sds100.keymapper.util.ui.compose.openUriSafe @OptIn(ExperimentalMaterial3Api::class) @Composable @@ -306,7 +306,7 @@ fun HandleImportExportState( setIdleState: () -> Unit, onConfirmImport: (RestoreType) -> Unit, ) { - when (state) { + when (val state = state) { is ImportExportState.Error -> { val text = stringResource(R.string.home_export_error_snackbar, state.error) LaunchedEffect(state) { @@ -332,7 +332,13 @@ fun HandleImportExportState( is ImportExportState.FinishedExport -> { snackbarState.currentSnackbarData?.dismiss() - LocalActivity.current?.let { ShareUtils.shareFile(it, state.uri.toUri()) } + LocalActivity.current?.let { + ShareUtils.shareFile( + it, + state.uri.toUri(), + packageName = LocalContext.current.packageName, + ) + } setIdleState() } @@ -381,7 +387,7 @@ private fun sampleList(): List { ComposeChipModel.Error( id = "1", text = "Input KEYCODE_0 • Repeat until released", - error = Error.NoCompatibleImeChosen, + error = KMError.NoCompatibleImeChosen, ), ComposeChipModel.Normal( id = "2", @@ -404,7 +410,7 @@ private fun sampleList(): List { ComposeChipModel.Error( id = "1", "Key Mapper is playing media", - error = Error.AppNotFound(""), + error = KMError.AppNotFound(""), ), ), options = listOf("Vibrate"), diff --git a/base/src/main/java/io/github/sds100/keymapper/base/home/HomeTab.kt b/base/src/main/java/io/github/sds100/keymapper/base/home/HomeTab.kt new file mode 100644 index 0000000000..22e8c6cb54 --- /dev/null +++ b/base/src/main/java/io/github/sds100/keymapper/base/home/HomeTab.kt @@ -0,0 +1,6 @@ +package io.github.sds100.keymapper.base.home + +enum class HomeTab { + KEY_EVENTS, + FINGERPRINT_MAPS, +} diff --git a/app/src/main/java/io/github/sds100/keymapper/home/HomeWarningList.kt b/base/src/main/java/io/github/sds100/keymapper/base/home/HomeWarningList.kt similarity index 96% rename from app/src/main/java/io/github/sds100/keymapper/home/HomeWarningList.kt rename to base/src/main/java/io/github/sds100/keymapper/base/home/HomeWarningList.kt index 28007d2deb..d59d88fb5e 100644 --- a/app/src/main/java/io/github/sds100/keymapper/home/HomeWarningList.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/home/HomeWarningList.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.home +package io.github.sds100.keymapper.base.home import androidx.compose.foundation.BorderStroke import androidx.compose.foundation.layout.Arrangement @@ -21,7 +21,7 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp -import io.github.sds100.keymapper.R +import io.github.sds100.keymapper.base.R @Composable fun HomeWarningList( diff --git a/app/src/main/java/io/github/sds100/keymapper/home/ImportDialog.kt b/base/src/main/java/io/github/sds100/keymapper/base/home/ImportDialog.kt similarity index 92% rename from app/src/main/java/io/github/sds100/keymapper/home/ImportDialog.kt rename to base/src/main/java/io/github/sds100/keymapper/base/home/ImportDialog.kt index 0a0ba913b6..dfcb7ed9fb 100644 --- a/app/src/main/java/io/github/sds100/keymapper/home/ImportDialog.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/home/ImportDialog.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.home +package io.github.sds100.keymapper.base.home import androidx.compose.material3.AlertDialog import androidx.compose.material3.MaterialTheme @@ -9,8 +9,8 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.res.pluralStringResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview -import io.github.sds100.keymapper.R -import io.github.sds100.keymapper.compose.KeyMapperTheme +import io.github.sds100.keymapper.base.R +import io.github.sds100.keymapper.base.compose.KeyMapperTheme @Composable fun ImportDialog( diff --git a/app/src/main/java/io/github/sds100/keymapper/home/KeyMapListAppBar.kt b/base/src/main/java/io/github/sds100/keymapper/base/home/KeyMapListAppBar.kt similarity index 96% rename from app/src/main/java/io/github/sds100/keymapper/home/KeyMapListAppBar.kt rename to base/src/main/java/io/github/sds100/keymapper/base/home/KeyMapListAppBar.kt index ea4f429031..b85c8e1c4e 100644 --- a/app/src/main/java/io/github/sds100/keymapper/home/KeyMapListAppBar.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/home/KeyMapListAppBar.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.home +package io.github.sds100.keymapper.base.home import androidx.activity.compose.BackHandler import androidx.compose.animation.AnimatedContent @@ -90,24 +90,23 @@ import androidx.compose.ui.text.input.TextFieldValue import androidx.compose.ui.text.input.VisualTransformation import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp -import io.github.sds100.keymapper.Constants -import io.github.sds100.keymapper.R -import io.github.sds100.keymapper.compose.KeyMapperTheme -import io.github.sds100.keymapper.compose.LocalCustomColorsPalette -import io.github.sds100.keymapper.constraints.ConstraintMode -import io.github.sds100.keymapper.groups.DeleteGroupDialog -import io.github.sds100.keymapper.groups.GroupBreadcrumbRow -import io.github.sds100.keymapper.groups.GroupConstraintRow -import io.github.sds100.keymapper.groups.GroupListItemModel -import io.github.sds100.keymapper.groups.GroupRow -import io.github.sds100.keymapper.keymaps.KeyMapAppBarState -import io.github.sds100.keymapper.util.Error -import io.github.sds100.keymapper.util.drawable -import io.github.sds100.keymapper.util.ui.compose.ComposeChipModel -import io.github.sds100.keymapper.util.ui.compose.ComposeIconInfo -import io.github.sds100.keymapper.util.ui.compose.RadioButtonText -import io.github.sds100.keymapper.util.ui.compose.icons.Import -import io.github.sds100.keymapper.util.ui.compose.icons.KeyMapperIcons +import io.github.sds100.keymapper.base.R +import io.github.sds100.keymapper.base.compose.KeyMapperTheme +import io.github.sds100.keymapper.base.compose.LocalCustomColorsPalette +import io.github.sds100.keymapper.base.constraints.ConstraintMode +import io.github.sds100.keymapper.base.groups.DeleteGroupDialog +import io.github.sds100.keymapper.base.groups.GroupBreadcrumbRow +import io.github.sds100.keymapper.base.groups.GroupConstraintRow +import io.github.sds100.keymapper.base.groups.GroupListItemModel +import io.github.sds100.keymapper.base.groups.GroupRow +import io.github.sds100.keymapper.base.keymaps.KeyMapAppBarState +import io.github.sds100.keymapper.base.utils.ui.compose.ComposeChipModel +import io.github.sds100.keymapper.base.utils.ui.compose.ComposeIconInfo +import io.github.sds100.keymapper.base.utils.ui.compose.RadioButtonText +import io.github.sds100.keymapper.base.utils.ui.compose.icons.Import +import io.github.sds100.keymapper.base.utils.ui.compose.icons.KeyMapperIcons +import io.github.sds100.keymapper.base.utils.ui.drawable +import io.github.sds100.keymapper.common.utils.KMError import kotlinx.coroutines.launch @Composable @@ -135,7 +134,7 @@ fun KeyMapListAppBar( onNewConstraintClick: () -> Unit = {}, onRemoveConstraintClick: (String) -> Unit = {}, onConstraintModeChanged: (ConstraintMode) -> Unit = {}, - onFixConstraintClick: (Error) -> Unit = {}, + onFixConstraintClick: (KMError) -> Unit = {}, ) { BackHandler(onBack = onBackClick) @@ -427,7 +426,7 @@ private fun ChildGroupAppBar( onNewConstraintClick: () -> Unit = {}, onRemoveConstraintClick: (String) -> Unit = {}, onConstraintModeChanged: (ConstraintMode) -> Unit = {}, - onFixConstraintClick: (Error) -> Unit = {}, + onFixConstraintClick: (KMError) -> Unit = {}, actions: @Composable RowScope.() -> Unit = {}, ) { // Make custom top app bar because the height can not be set to fix the text field error in. @@ -923,7 +922,7 @@ private fun constraintsSampleList(): List { ComposeChipModel.Error( id = "2", text = "Key Mapper not found", - error = Error.AppNotFound(Constants.PACKAGE_NAME), + error = KMError.AppNotFound("io.github.sds100.keymapper"), ), ) } diff --git a/app/src/main/java/io/github/sds100/keymapper/home/SelectionBottomSheet.kt b/base/src/main/java/io/github/sds100/keymapper/base/home/SelectionBottomSheet.kt similarity index 95% rename from app/src/main/java/io/github/sds100/keymapper/home/SelectionBottomSheet.kt rename to base/src/main/java/io/github/sds100/keymapper/base/home/SelectionBottomSheet.kt index 9add3884a7..f3f32f02cc 100644 --- a/app/src/main/java/io/github/sds100/keymapper/home/SelectionBottomSheet.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/home/SelectionBottomSheet.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.home +package io.github.sds100.keymapper.base.home import androidx.compose.foundation.clickable import androidx.compose.foundation.horizontalScroll @@ -38,13 +38,13 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp -import io.github.sds100.keymapper.R -import io.github.sds100.keymapper.compose.KeyMapperTheme -import io.github.sds100.keymapper.groups.GroupBreadcrumbRow -import io.github.sds100.keymapper.groups.GroupListItemModel -import io.github.sds100.keymapper.groups.GroupRow -import io.github.sds100.keymapper.util.drawable -import io.github.sds100.keymapper.util.ui.compose.ComposeIconInfo +import io.github.sds100.keymapper.base.R +import io.github.sds100.keymapper.base.compose.KeyMapperTheme +import io.github.sds100.keymapper.base.groups.GroupBreadcrumbRow +import io.github.sds100.keymapper.base.groups.GroupListItemModel +import io.github.sds100.keymapper.base.groups.GroupRow +import io.github.sds100.keymapper.base.utils.ui.compose.ComposeIconInfo +import io.github.sds100.keymapper.base.utils.ui.drawable @OptIn(ExperimentalMaterial3Api::class) @Composable diff --git a/app/src/main/java/io/github/sds100/keymapper/home/ShowHomeScreenAlertsUseCase.kt b/base/src/main/java/io/github/sds100/keymapper/base/home/ShowHomeScreenAlertsUseCase.kt similarity index 81% rename from app/src/main/java/io/github/sds100/keymapper/home/ShowHomeScreenAlertsUseCase.kt rename to base/src/main/java/io/github/sds100/keymapper/base/home/ShowHomeScreenAlertsUseCase.kt index 1f21e50589..91566c5df7 100644 --- a/app/src/main/java/io/github/sds100/keymapper/home/ShowHomeScreenAlertsUseCase.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/home/ShowHomeScreenAlertsUseCase.kt @@ -1,24 +1,21 @@ -package io.github.sds100.keymapper.home +package io.github.sds100.keymapper.base.home +import io.github.sds100.keymapper.base.keymaps.PauseKeyMapsUseCase import io.github.sds100.keymapper.data.Keys import io.github.sds100.keymapper.data.repositories.PreferenceRepository -import io.github.sds100.keymapper.keymaps.PauseKeyMapsUseCase -import io.github.sds100.keymapper.system.accessibility.ServiceAdapter -import io.github.sds100.keymapper.system.accessibility.ServiceState +import io.github.sds100.keymapper.system.accessibility.AccessibilityServiceAdapter +import io.github.sds100.keymapper.system.accessibility.AccessibilityServiceState import io.github.sds100.keymapper.system.permissions.Permission import io.github.sds100.keymapper.system.permissions.PermissionAdapter import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.map +import javax.inject.Inject -/** - * Created by sds100 on 04/04/2021. - */ - -class ShowHomeScreenAlertsUseCaseImpl( +class ShowHomeScreenAlertsUseCaseImpl @Inject constructor( private val preferences: PreferenceRepository, private val permissions: PermissionAdapter, - private val accessibilityServiceAdapter: ServiceAdapter, + private val accessibilityServiceAdapter: AccessibilityServiceAdapter, private val pauseKeyMapsUseCase: PauseKeyMapsUseCase, ) : ShowHomeScreenAlertsUseCase { override val hideAlerts: Flow = @@ -32,7 +29,8 @@ class ShowHomeScreenAlertsUseCaseImpl( override val isLoggingEnabled: Flow = preferences.get(Keys.log).map { it == true } - override val accessibilityServiceState: Flow = accessibilityServiceAdapter.state + override val accessibilityServiceState: Flow = + accessibilityServiceAdapter.state override fun disableBatteryOptimisation() { permissions.request(Permission.IGNORE_BATTERY_OPTIMISATION) @@ -72,7 +70,7 @@ class ShowHomeScreenAlertsUseCaseImpl( } interface ShowHomeScreenAlertsUseCase { - val accessibilityServiceState: Flow + val accessibilityServiceState: Flow fun startAccessibilityService(): Boolean fun restartAccessibilityService(): Boolean fun acknowledgeCrashed() diff --git a/base/src/main/java/io/github/sds100/keymapper/base/keymaps/BaseConfigKeyMapScreen.kt b/base/src/main/java/io/github/sds100/keymapper/base/keymaps/BaseConfigKeyMapScreen.kt new file mode 100644 index 0000000000..06517591d7 --- /dev/null +++ b/base/src/main/java/io/github/sds100/keymapper/base/keymaps/BaseConfigKeyMapScreen.kt @@ -0,0 +1,610 @@ +package io.github.sds100.keymapper.base.keymaps + +import androidx.activity.compose.BackHandler +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.BoxWithConstraints +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.displayCutoutPadding +import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.pager.HorizontalPager +import androidx.compose.foundation.pager.rememberPagerState +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.automirrored.rounded.ArrowBack +import androidx.compose.material.icons.automirrored.rounded.HelpOutline +import androidx.compose.material.icons.rounded.Check +import androidx.compose.material3.BottomAppBar +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.ExtendedFloatingActionButton +import androidx.compose.material3.FloatingActionButtonDefaults +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.OutlinedCard +import androidx.compose.material3.PrimaryScrollableTabRow +import androidx.compose.material3.PrimaryTabRow +import androidx.compose.material3.Scaffold +import androidx.compose.material3.SnackbarHost +import androidx.compose.material3.SnackbarHostState +import androidx.compose.material3.Switch +import androidx.compose.material3.Tab +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.LocalUriHandler +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Devices +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.dp +import com.canopas.lib.showcase.IntroShowcase +import io.github.sds100.keymapper.base.R +import io.github.sds100.keymapper.base.compose.KeyMapperTheme +import io.github.sds100.keymapper.base.onboarding.OnboardingTapTarget +import io.github.sds100.keymapper.base.utils.ui.compose.KeyMapperTapTarget +import io.github.sds100.keymapper.base.utils.ui.compose.keyMapperShowcaseStyle +import io.github.sds100.keymapper.base.utils.ui.compose.openUriSafe +import kotlinx.coroutines.launch + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun BaseConfigKeyMapScreen( + modifier: Modifier = Modifier, + isKeyMapEnabled: Boolean, + onKeyMapEnabledChange: (Boolean) -> Unit = {}, + triggerScreen: @Composable () -> Unit, + actionScreen: @Composable () -> Unit, + constraintsScreen: @Composable () -> Unit, + optionsScreen: @Composable () -> Unit, + onBackClick: () -> Unit = {}, + onDoneClick: () -> Unit = {}, + snackbarHostState: SnackbarHostState = SnackbarHostState(), + showActionTapTarget: Boolean = false, + onActionTapTargetCompleted: () -> Unit = {}, + showConstraintTapTarget: Boolean = false, + onConstraintTapTargetCompleted: () -> Unit = {}, + onSkipTutorialClick: () -> Unit = {}, +) { + val scope = rememberCoroutineScope() + val triggerHelpUrl = stringResource(R.string.url_trigger_guide) + val actionsHelpUrl = stringResource(R.string.url_action_guide) + val constraintsHelpUrl = stringResource(R.string.url_constraints_guide) + val optionsHelpUrl = stringResource(R.string.url_trigger_options_guide) + + var currentTab: ConfigKeyMapTab? by remember { mutableStateOf(null) } + val uriHandler = LocalUriHandler.current + val ctx = LocalContext.current + + BackHandler(onBack = onBackClick) + + Scaffold( + modifier.displayCutoutPadding(), + snackbarHost = { SnackbarHost(snackbarHostState) }, + bottomBar = { + ConfigKeyMapAppBar( + isKeyMapEnabled = isKeyMapEnabled, + onKeyMapEnabledChange = onKeyMapEnabledChange, + onBackClick = onBackClick, + onDoneClick = onDoneClick, + showHelpButton = currentTab == ConfigKeyMapTab.TRIGGER || + currentTab == ConfigKeyMapTab.ACTIONS || + currentTab == ConfigKeyMapTab.CONSTRAINTS || + currentTab == ConfigKeyMapTab.OPTIONS, + onHelpClick = { + val url = when (currentTab) { + ConfigKeyMapTab.TRIGGER -> triggerHelpUrl + ConfigKeyMapTab.ACTIONS -> actionsHelpUrl + ConfigKeyMapTab.CONSTRAINTS -> constraintsHelpUrl + ConfigKeyMapTab.OPTIONS -> optionsHelpUrl + else -> return@ConfigKeyMapAppBar + } + + if (url.isNotEmpty()) { + uriHandler.openUriSafe(ctx, url) + } + }, + ) + }, + ) { innerPadding -> + BoxWithConstraints(modifier = Modifier.padding(innerPadding)) { + val tabs = determineTabs(maxWidth, maxHeight) + val isVerticalTwoScreen = maxWidth < 720.dp + val pagerState = rememberPagerState(pageCount = { tabs.size }, initialPage = 0) + currentTab = tabs.getOrNull(pagerState.targetPage) + + Column(Modifier.fillMaxSize()) { + if (tabs.size > 1) { + @Composable + fun Tabs() { + for ((index, tab) in tabs.withIndex()) { + val tapTarget: OnboardingTapTarget? = when { + showActionTapTarget && tab == ConfigKeyMapTab.ACTIONS -> OnboardingTapTarget.CHOOSE_ACTION + showConstraintTapTarget && (tab == ConfigKeyMapTab.CONSTRAINTS || tab == ConfigKeyMapTab.CONSTRAINTS_AND_OPTIONS) -> OnboardingTapTarget.CHOOSE_CONSTRAINT + else -> null + } + + IntroShowcase( + showIntroShowCase = tapTarget != null, + onShowCaseCompleted = if (tapTarget == OnboardingTapTarget.CHOOSE_ACTION) onActionTapTargetCompleted else onConstraintTapTargetCompleted, + dismissOnClickOutside = true, + ) { + var tabModifier: Modifier = Modifier + + if (tapTarget != null) { + tabModifier = tabModifier.introShowCaseTarget( + index = 0, + style = keyMapperShowcaseStyle(), + ) { + KeyMapperTapTarget( + tapTarget = tapTarget, + onSkipClick = onSkipTutorialClick, + ) + } + } + + Tab( + modifier = tabModifier, + selected = pagerState.targetPage == index, + text = { + Text( + text = getTabTitle(tab), + maxLines = 1, + ) + }, + onClick = { + scope.launch { + pagerState.animateScrollToPage( + tabs.indexOf(tab), + ) + } + }, + ) + } + } + } + + if (this@BoxWithConstraints.maxWidth < 500.dp) { + PrimaryScrollableTabRow( + selectedTabIndex = pagerState.targetPage, + divider = {}, + edgePadding = 16.dp, + contentColor = MaterialTheme.colorScheme.onSurface, + ) { + Tabs() + } + } else { + PrimaryTabRow( + selectedTabIndex = pagerState.targetPage, + divider = {}, + contentColor = MaterialTheme.colorScheme.onSurface, + ) { + Tabs() + } + } + } + + HorizontalPager( + modifier = Modifier.fillMaxSize(), + state = pagerState, + ) { pageIndex -> + when (tabs[pageIndex]) { + ConfigKeyMapTab.TRIGGER -> triggerScreen() + ConfigKeyMapTab.ACTIONS -> actionScreen() + ConfigKeyMapTab.CONSTRAINTS -> constraintsScreen() + ConfigKeyMapTab.OPTIONS -> optionsScreen() + ConfigKeyMapTab.TRIGGER_AND_ACTIONS -> { + if (isVerticalTwoScreen) { + VerticalTwoScreens( + topTitle = stringResource(R.string.tab_trigger), + topHelpUrl = triggerHelpUrl, + topScreen = triggerScreen, + bottomTitle = stringResource(R.string.tab_actions), + bottomHelpUrl = actionsHelpUrl, + bottomScreen = actionScreen, + ) + } else { + HorizontalTwoScreens( + leftTitle = stringResource(R.string.tab_trigger), + leftHelpUrl = triggerHelpUrl, + leftScreen = triggerScreen, + rightTitle = stringResource(R.string.tab_actions), + rightHelpUrl = actionsHelpUrl, + rightScreen = actionScreen, + ) + } + } + + ConfigKeyMapTab.CONSTRAINTS_AND_OPTIONS -> { + if (isVerticalTwoScreen) { + VerticalTwoScreens( + topTitle = stringResource(R.string.tab_constraints), + topHelpUrl = constraintsHelpUrl, + topScreen = constraintsScreen, + bottomTitle = stringResource(R.string.tab_options), + bottomHelpUrl = optionsHelpUrl, + bottomScreen = optionsScreen, + ) + } else { + HorizontalTwoScreens( + leftTitle = stringResource(R.string.tab_constraints), + leftHelpUrl = constraintsHelpUrl, + leftScreen = constraintsScreen, + rightTitle = stringResource(R.string.tab_options), + rightHelpUrl = optionsHelpUrl, + rightScreen = optionsScreen, + ) + } + } + + ConfigKeyMapTab.ALL -> FourScreens( + topLeftTitle = stringResource(R.string.tab_trigger), + topLeftHelpUrl = triggerHelpUrl, + topLeftScreen = triggerScreen, + topRightTitle = stringResource(R.string.tab_actions), + topRightHelpUrl = actionsHelpUrl, + topRightScreen = actionScreen, + bottomLeftTitle = stringResource(R.string.tab_constraints), + bottomLeftHelpUrl = constraintsHelpUrl, + bottomLeftScreen = constraintsScreen, + bottomRightTitle = stringResource(R.string.tab_options), + bottomRightHelpUrl = optionsHelpUrl, + bottomRightScreen = optionsScreen, + ) + } + } + } + } + } +} + +@Composable +private fun ConfigKeyMapAppBar( + modifier: Modifier = Modifier, + isKeyMapEnabled: Boolean, + onKeyMapEnabledChange: (Boolean) -> Unit = {}, + showHelpButton: Boolean, + onHelpClick: () -> Unit, + onBackClick: () -> Unit, + onDoneClick: () -> Unit, +) { + BottomAppBar( + modifier = modifier, + floatingActionButton = { + ExtendedFloatingActionButton( + onClick = onDoneClick, + text = { Text(stringResource(R.string.button_done)) }, + icon = { + Icon(Icons.Rounded.Check, stringResource(R.string.button_done)) + }, + elevation = FloatingActionButtonDefaults.bottomAppBarFabElevation(), + ) + }, + actions = { + IconButton(onClick = onBackClick) { + Icon(Icons.AutoMirrored.Rounded.ArrowBack, stringResource(R.string.action_go_back)) + } + + Spacer(modifier = Modifier.width(8.dp)) + + val text = if (isKeyMapEnabled) { + stringResource(R.string.switch_enabled) + } else { + stringResource(R.string.switch_disabled) + } + + Text( + text = text, + style = MaterialTheme.typography.labelLarge, + ) + + Spacer(modifier = Modifier.width(16.dp)) + + Switch( + checked = isKeyMapEnabled, + onCheckedChange = onKeyMapEnabledChange, + ) + + Spacer(modifier = Modifier.weight(1f)) + + if (showHelpButton) { + IconButton(onClick = onHelpClick) { + Icon( + Icons.AutoMirrored.Rounded.HelpOutline, + stringResource(R.string.action_help), + ) + } + } + + Spacer(modifier = Modifier.width(8.dp)) + }, + ) +} + +@Composable +private fun VerticalTwoScreens( + modifier: Modifier = Modifier, + topTitle: String, + topHelpUrl: String, + topScreen: @Composable () -> Unit, + bottomTitle: String, + bottomHelpUrl: String, + bottomScreen: @Composable () -> Unit, +) { + Column(modifier = modifier) { + Spacer(modifier = Modifier.height(8.dp)) + ScreenCard( + Modifier + .weight(1f) + .fillMaxWidth() + .padding(horizontal = 8.dp), + topTitle, + topHelpUrl, + topScreen, + ) + Spacer(modifier = Modifier.height(8.dp)) + ScreenCard( + Modifier + .weight(1f) + .fillMaxWidth() + .padding(horizontal = 8.dp), + bottomTitle, + bottomHelpUrl, + bottomScreen, + ) + Spacer(modifier = Modifier.height(8.dp)) + } +} + +@Composable +private fun HorizontalTwoScreens( + modifier: Modifier = Modifier, + leftTitle: String, + leftHelpUrl: String, + leftScreen: @Composable () -> Unit, + rightTitle: String, + rightHelpUrl: String, + rightScreen: @Composable () -> Unit, +) { + Column(modifier = modifier) { + Spacer(modifier = Modifier.height(8.dp)) + Row(Modifier.weight(1f)) { + ScreenCard( + Modifier + .weight(1f) + .fillMaxHeight() + .padding(start = 8.dp), + leftTitle, + leftHelpUrl, + leftScreen, + ) + Spacer(modifier = Modifier.width(8.dp)) + ScreenCard( + Modifier + .weight(1f) + .fillMaxHeight() + .padding(end = 8.dp), + rightTitle, + rightHelpUrl, + rightScreen, + ) + } + Spacer(modifier = Modifier.height(8.dp)) + } +} + +@Composable +fun FourScreens( + modifier: Modifier = Modifier, + topLeftTitle: String, + topLeftHelpUrl: String, + topLeftScreen: @Composable () -> Unit, + topRightTitle: String, + topRightHelpUrl: String, + topRightScreen: @Composable () -> Unit, + bottomLeftTitle: String, + bottomLeftHelpUrl: String, + bottomLeftScreen: @Composable () -> Unit, + bottomRightTitle: String, + bottomRightHelpUrl: String, + bottomRightScreen: @Composable () -> Unit, +) { + Column(modifier = modifier) { + Spacer(modifier = Modifier.height(8.dp)) + Row(Modifier.weight(1f)) { + ScreenCard( + Modifier + .weight(1f) + .fillMaxHeight() + .padding(start = 8.dp), + topLeftTitle, + topLeftHelpUrl, + topLeftScreen, + ) + Spacer(modifier = Modifier.width(8.dp)) + ScreenCard( + Modifier + .weight(1f) + .fillMaxHeight() + .padding(end = 8.dp), + topRightTitle, + topRightHelpUrl, + topRightScreen, + ) + } + Spacer(modifier = Modifier.height(8.dp)) + Row(Modifier.weight(1f)) { + ScreenCard( + Modifier + .weight(1f) + .fillMaxHeight() + .padding(start = 8.dp), + bottomLeftTitle, + bottomLeftHelpUrl, + bottomLeftScreen, + ) + Spacer(modifier = Modifier.width(8.dp)) + ScreenCard( + Modifier + .weight(1f) + .fillMaxHeight() + .padding(end = 8.dp), + bottomRightTitle, + bottomRightHelpUrl, + bottomRightScreen, + ) + } + Spacer(modifier = Modifier.height(8.dp)) + } +} + +@Composable +private fun ScreenCard( + modifier: Modifier = Modifier, + title: String, + helpUrl: String, + screen: @Composable () -> Unit, +) { + val uriHandler = LocalUriHandler.current + val ctx = LocalContext.current + + OutlinedCard(modifier = modifier) { + Column { + Row( + modifier = Modifier.fillMaxWidth(), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.SpaceBetween, + ) { + Text( + modifier = Modifier.padding(horizontal = 16.dp), + text = title, + style = MaterialTheme.typography.titleSmall, + color = MaterialTheme.colorScheme.primary, + ) + + IconButton(onClick = { uriHandler.openUriSafe(ctx, helpUrl) }) { + Icon( + Icons.AutoMirrored.Rounded.HelpOutline, + contentDescription = stringResource(R.string.button_help), + ) + } + } + + screen() + } + } +} + +private fun determineTabs(maxWidth: Dp, maxHeight: Dp): List { + return when { + maxWidth >= 800.dp && maxHeight >= 800.dp -> listOf(ConfigKeyMapTab.ALL) + + (maxWidth >= 1000.dp && maxHeight >= 450.dp) || + (maxWidth >= 450.dp && maxHeight >= 1000.dp) -> listOf( + ConfigKeyMapTab.TRIGGER_AND_ACTIONS, + ConfigKeyMapTab.CONSTRAINTS_AND_OPTIONS, + ) + + else -> listOf( + ConfigKeyMapTab.TRIGGER, + ConfigKeyMapTab.ACTIONS, + ConfigKeyMapTab.CONSTRAINTS, + ConfigKeyMapTab.OPTIONS, + ) + } +} + +@Composable +private fun getTabTitle(tab: ConfigKeyMapTab): String { + return when (tab) { + ConfigKeyMapTab.TRIGGER -> stringResource(R.string.tab_trigger) + ConfigKeyMapTab.ACTIONS -> stringResource(R.string.tab_actions) + ConfigKeyMapTab.CONSTRAINTS -> stringResource(R.string.tab_constraints) + ConfigKeyMapTab.OPTIONS -> stringResource(R.string.tab_options) + ConfigKeyMapTab.TRIGGER_AND_ACTIONS -> stringResource(R.string.tab_trigger_and_actions) + ConfigKeyMapTab.CONSTRAINTS_AND_OPTIONS -> stringResource(R.string.tab_constraints_and_more) + ConfigKeyMapTab.ALL -> "" + } +} + +private enum class ConfigKeyMapTab { + TRIGGER, + ACTIONS, + CONSTRAINTS, + OPTIONS, + TRIGGER_AND_ACTIONS, + CONSTRAINTS_AND_OPTIONS, + ALL, +} + +@Preview(device = Devices.PIXEL, showSystemUi = true) +@Composable +private fun SmallScreenPreview() { + KeyMapperTheme { + BaseConfigKeyMapScreen( + modifier = Modifier.fillMaxSize(), + isKeyMapEnabled = false, + triggerScreen = {}, + actionScreen = {}, + constraintsScreen = {}, + optionsScreen = {}, + ) + } +} + +@Preview(device = Devices.NEXUS_7_2013, showSystemUi = true) +@Composable +private fun MediumScreenPreview() { + KeyMapperTheme { + BaseConfigKeyMapScreen( + modifier = Modifier.fillMaxSize(), + isKeyMapEnabled = true, + triggerScreen = {}, + actionScreen = {}, + constraintsScreen = {}, + optionsScreen = {}, + ) + } +} + +@Preview(device = Devices.FOLDABLE, showSystemUi = true) +@Composable +private fun MediumScreenLandscapePreview() { + KeyMapperTheme { + BaseConfigKeyMapScreen( + modifier = Modifier.fillMaxSize(), + isKeyMapEnabled = true, + triggerScreen = {}, + actionScreen = {}, + constraintsScreen = {}, + optionsScreen = {}, + ) + } +} + +@Preview(device = Devices.NEXUS_10, showSystemUi = true) +@Composable +private fun LargeScreenPreview() { + KeyMapperTheme { + BaseConfigKeyMapScreen( + modifier = Modifier.fillMaxSize(), + isKeyMapEnabled = true, + triggerScreen = {}, + actionScreen = {}, + constraintsScreen = {}, + optionsScreen = {}, + ) + } +} diff --git a/base/src/main/java/io/github/sds100/keymapper/base/keymaps/BaseConfigKeyMapViewModel.kt b/base/src/main/java/io/github/sds100/keymapper/base/keymaps/BaseConfigKeyMapViewModel.kt new file mode 100644 index 0000000000..7dd8d9d1f4 --- /dev/null +++ b/base/src/main/java/io/github/sds100/keymapper/base/keymaps/BaseConfigKeyMapViewModel.kt @@ -0,0 +1,102 @@ +package io.github.sds100.keymapper.base.keymaps + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import io.github.sds100.keymapper.base.actions.ConfigActionsViewModel +import io.github.sds100.keymapper.base.constraints.ConfigConstraintsViewModel +import io.github.sds100.keymapper.base.onboarding.OnboardingTapTarget +import io.github.sds100.keymapper.base.onboarding.OnboardingUseCase +import io.github.sds100.keymapper.base.trigger.BaseConfigTriggerViewModel +import io.github.sds100.keymapper.base.utils.navigation.NavigationProvider +import io.github.sds100.keymapper.base.utils.ui.DialogProvider +import io.github.sds100.keymapper.common.utils.dataOrNull +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.stateIn +import kotlinx.coroutines.launch + +abstract class BaseConfigKeyMapViewModel( + private val config: ConfigKeyMapUseCase, + private val onboarding: OnboardingUseCase, + navigationProvider: NavigationProvider, + dialogProvider: DialogProvider, +) : ViewModel(), + NavigationProvider by navigationProvider, + DialogProvider by dialogProvider { + + abstract val configActionsViewModel: ConfigActionsViewModel + abstract val configTriggerViewModel: BaseConfigTriggerViewModel + abstract val configConstraintsViewModel: ConfigConstraintsViewModel + + val isEnabled: StateFlow = config.keyMap + .map { state -> state.dataOrNull()?.isEnabled ?: true } + .stateIn(viewModelScope, SharingStarted.Eagerly, true) + + val isKeyMapEdited: Boolean + get() = config.isEdited + + val showActionsTapTarget: StateFlow = + combine( + onboarding.showTapTarget(OnboardingTapTarget.CHOOSE_ACTION), + config.keyMap, + ) { showTapTarget, keyMapState -> + // Show the choose action tap target if they have recorded a key. + showTapTarget && keyMapState.dataOrNull()?.trigger?.keys?.isNotEmpty() ?: false + }.stateIn(viewModelScope, SharingStarted.Lazily, false) + + val showConstraintsTapTarget: StateFlow = + combine( + onboarding.showTapTarget(OnboardingTapTarget.CHOOSE_CONSTRAINT), + config.keyMap, + ) { showTapTarget, keyMapState -> + // Show the choose constraint tap target if they have added an action. + showTapTarget && keyMapState.dataOrNull()?.actionList?.isNotEmpty() ?: false + }.stateIn(viewModelScope, SharingStarted.Lazily, false) + + fun onDoneClick() { + config.save() + + viewModelScope.launch { + popBackStack() + } + } + + fun loadNewKeyMap(floatingButtonUid: String? = null, groupUid: String?) { + config.loadNewKeyMap(groupUid) + if (floatingButtonUid != null) { + viewModelScope.launch { + config.addFloatingButtonTriggerKey(floatingButtonUid) + } + } + } + + fun loadKeyMap(uid: String) { + viewModelScope.launch { + config.loadKeyMap(uid) + } + } + + fun onBackClick() { + viewModelScope.launch { + popBackStack() + } + } + + fun onEnabledChanged(enabled: Boolean) { + config.setEnabled(enabled) + } + + fun onActionTapTargetCompleted() { + onboarding.completedTapTarget(OnboardingTapTarget.CHOOSE_ACTION) + } + + fun onConstraintTapTargetCompleted() { + onboarding.completedTapTarget(OnboardingTapTarget.CHOOSE_CONSTRAINT) + } + + fun onSkipTutorialClick() { + onboarding.skipTapTargetOnboarding() + } +} diff --git a/base/src/main/java/io/github/sds100/keymapper/base/keymaps/ClickType.kt b/base/src/main/java/io/github/sds100/keymapper/base/keymaps/ClickType.kt new file mode 100644 index 0000000000..260acb2d0e --- /dev/null +++ b/base/src/main/java/io/github/sds100/keymapper/base/keymaps/ClickType.kt @@ -0,0 +1,7 @@ +package io.github.sds100.keymapper.base.keymaps + +enum class ClickType { + SHORT_PRESS, + LONG_PRESS, + DOUBLE_PRESS, +} diff --git a/app/src/main/java/io/github/sds100/keymapper/keymaps/ConfigKeyMapOptionsViewModel.kt b/base/src/main/java/io/github/sds100/keymapper/base/keymaps/ConfigKeyMapOptionsViewModel.kt similarity index 87% rename from app/src/main/java/io/github/sds100/keymapper/keymaps/ConfigKeyMapOptionsViewModel.kt rename to base/src/main/java/io/github/sds100/keymapper/base/keymaps/ConfigKeyMapOptionsViewModel.kt index 0a9daa209b..9067eabe14 100644 --- a/app/src/main/java/io/github/sds100/keymapper/keymaps/ConfigKeyMapOptionsViewModel.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/keymaps/ConfigKeyMapOptionsViewModel.kt @@ -1,20 +1,19 @@ -package io.github.sds100.keymapper.keymaps +package io.github.sds100.keymapper.base.keymaps import android.graphics.Color import android.graphics.drawable.Drawable -import io.github.sds100.keymapper.R -import io.github.sds100.keymapper.actions.ActionUiHelper -import io.github.sds100.keymapper.util.State -import io.github.sds100.keymapper.util.dataOrNull -import io.github.sds100.keymapper.util.getFullMessage -import io.github.sds100.keymapper.util.mapData -import io.github.sds100.keymapper.util.onFailure -import io.github.sds100.keymapper.util.ui.PopupUi -import io.github.sds100.keymapper.util.ui.PopupViewModel -import io.github.sds100.keymapper.util.ui.PopupViewModelImpl -import io.github.sds100.keymapper.util.ui.ResourceProvider -import io.github.sds100.keymapper.util.ui.TintType -import io.github.sds100.keymapper.util.ui.showPopup +import io.github.sds100.keymapper.base.R +import io.github.sds100.keymapper.base.actions.ActionUiHelper +import io.github.sds100.keymapper.base.utils.getFullMessage +import io.github.sds100.keymapper.base.utils.ui.DialogModel +import io.github.sds100.keymapper.base.utils.ui.DialogProvider +import io.github.sds100.keymapper.base.utils.ui.ResourceProvider +import io.github.sds100.keymapper.base.utils.ui.TintType +import io.github.sds100.keymapper.base.utils.ui.showDialog +import io.github.sds100.keymapper.common.utils.State +import io.github.sds100.keymapper.common.utils.dataOrNull +import io.github.sds100.keymapper.common.utils.mapData +import io.github.sds100.keymapper.common.utils.onFailure import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow @@ -29,9 +28,10 @@ class ConfigKeyMapOptionsViewModel( private val config: ConfigKeyMapUseCase, private val displayUseCase: DisplayKeyMapUseCase, private val createKeyMapShortcut: CreateKeyMapShortcutUseCase, + private val dialogProvider: DialogProvider, resourceProvider: ResourceProvider, ) : ResourceProvider by resourceProvider, - PopupViewModel by PopupViewModelImpl(), + DialogProvider by dialogProvider, KeyMapOptionsCallback { private val actionUiHelper = ActionUiHelper(displayUseCase, resourceProvider) @@ -113,9 +113,9 @@ class ConfigKeyMapOptionsViewModel( icon = null } - val shortcutName = showPopup( + val shortcutName = showDialog( key, - PopupUi.Text( + DialogModel.Text( getString(R.string.hint_shortcut_name), allowEmpty = false, text = defaultShortcutName, @@ -125,11 +125,11 @@ class ConfigKeyMapOptionsViewModel( val result = createKeyMapShortcut.pinShortcut(keyMapUid, shortcutName, icon) result.onFailure { error -> - val snackBar = PopupUi.SnackBar( + val snackBar = DialogModel.SnackBar( message = error.getFullMessage(this@ConfigKeyMapOptionsViewModel), ) - showPopup("create_shortcut_result", snackBar) + showDialog("create_shortcut_result", snackBar) } } } diff --git a/app/src/main/java/io/github/sds100/keymapper/keymaps/ConfigKeyMapUseCase.kt b/base/src/main/java/io/github/sds100/keymapper/base/keymaps/ConfigKeyMapUseCase.kt similarity index 93% rename from app/src/main/java/io/github/sds100/keymapper/keymaps/ConfigKeyMapUseCase.kt rename to base/src/main/java/io/github/sds100/keymapper/base/keymaps/ConfigKeyMapUseCase.kt index a53db4df8d..9622f48373 100644 --- a/app/src/main/java/io/github/sds100/keymapper/keymaps/ConfigKeyMapUseCase.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/keymaps/ConfigKeyMapUseCase.kt @@ -1,38 +1,41 @@ -package io.github.sds100.keymapper.keymaps +package io.github.sds100.keymapper.base.keymaps import android.database.sqlite.SQLiteConstraintException -import io.github.sds100.keymapper.actions.Action -import io.github.sds100.keymapper.actions.ActionData -import io.github.sds100.keymapper.actions.RepeatMode -import io.github.sds100.keymapper.constraints.Constraint -import io.github.sds100.keymapper.constraints.ConstraintMode -import io.github.sds100.keymapper.constraints.ConstraintState +import io.github.sds100.keymapper.base.actions.Action +import io.github.sds100.keymapper.base.actions.ActionData +import io.github.sds100.keymapper.base.actions.RepeatMode +import io.github.sds100.keymapper.base.constraints.Constraint +import io.github.sds100.keymapper.base.constraints.ConstraintMode +import io.github.sds100.keymapper.base.constraints.ConstraintState +import io.github.sds100.keymapper.base.floating.FloatingButtonEntityMapper +import io.github.sds100.keymapper.base.system.accessibility.FingerprintGestureType +import io.github.sds100.keymapper.base.trigger.AssistantTriggerKey +import io.github.sds100.keymapper.base.trigger.AssistantTriggerType +import io.github.sds100.keymapper.base.trigger.FingerprintTriggerKey +import io.github.sds100.keymapper.base.trigger.FloatingButtonKey +import io.github.sds100.keymapper.base.trigger.KeyCodeTriggerKey +import io.github.sds100.keymapper.base.trigger.KeyEventDetectionSource +import io.github.sds100.keymapper.base.trigger.Trigger +import io.github.sds100.keymapper.base.trigger.TriggerKey +import io.github.sds100.keymapper.base.trigger.TriggerKeyDevice +import io.github.sds100.keymapper.base.trigger.TriggerMode +import io.github.sds100.keymapper.common.utils.KMResult +import io.github.sds100.keymapper.common.utils.State +import io.github.sds100.keymapper.common.utils.dataOrNull +import io.github.sds100.keymapper.common.utils.firstBlocking +import io.github.sds100.keymapper.common.utils.ifIsData +import io.github.sds100.keymapper.common.utils.moveElement import io.github.sds100.keymapper.data.Keys import io.github.sds100.keymapper.data.entities.FloatingButtonEntityWithLayout import io.github.sds100.keymapper.data.repositories.FloatingButtonRepository import io.github.sds100.keymapper.data.repositories.FloatingLayoutRepository +import io.github.sds100.keymapper.data.repositories.KeyMapRepository import io.github.sds100.keymapper.data.repositories.PreferenceRepository -import io.github.sds100.keymapper.floating.FloatingButtonEntityMapper -import io.github.sds100.keymapper.system.accessibility.ServiceAdapter +import io.github.sds100.keymapper.system.accessibility.AccessibilityServiceAdapter +import io.github.sds100.keymapper.system.accessibility.AccessibilityServiceEvent import io.github.sds100.keymapper.system.devices.DevicesAdapter import io.github.sds100.keymapper.system.devices.InputDeviceUtils import io.github.sds100.keymapper.system.inputevents.InputEventUtils -import io.github.sds100.keymapper.trigger.AssistantTriggerKey -import io.github.sds100.keymapper.trigger.AssistantTriggerType -import io.github.sds100.keymapper.trigger.FingerprintTriggerKey -import io.github.sds100.keymapper.trigger.FloatingButtonKey -import io.github.sds100.keymapper.trigger.KeyEventDetectionSource -import io.github.sds100.keymapper.trigger.Trigger -import io.github.sds100.keymapper.trigger.TriggerKey -import io.github.sds100.keymapper.trigger.TriggerKeyDevice -import io.github.sds100.keymapper.trigger.TriggerMode -import io.github.sds100.keymapper.util.Result -import io.github.sds100.keymapper.util.ServiceEvent -import io.github.sds100.keymapper.util.State -import io.github.sds100.keymapper.util.dataOrNull -import io.github.sds100.keymapper.util.firstBlocking -import io.github.sds100.keymapper.util.ifIsData -import io.github.sds100.keymapper.util.moveElement import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.Flow @@ -50,18 +53,18 @@ import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import kotlinx.serialization.json.Json import java.util.LinkedList +import javax.inject.Inject +import javax.inject.Singleton -/** - * Created by sds100 on 16/02/2021. - */ -class ConfigKeyMapUseCaseController( +@Singleton +class ConfigKeyMapUseCaseController @Inject constructor( private val coroutineScope: CoroutineScope, private val keyMapRepository: KeyMapRepository, private val devicesAdapter: DevicesAdapter, private val preferenceRepository: PreferenceRepository, private val floatingLayoutRepository: FloatingLayoutRepository, private val floatingButtonRepository: FloatingButtonRepository, - private val serviceAdapter: ServiceAdapter, + private val serviceAdapter: AccessibilityServiceAdapter, ) : ConfigKeyMapUseCase, GetDefaultKeyMapOptionsUseCase by GetDefaultKeyMapOptionsUseCaseImpl( coroutineScope, @@ -363,7 +366,7 @@ class ConfigKeyMapUseCaseController( // Check whether the trigger already contains the key because if so // then it must be converted to a sequence trigger. val containsKey = trigger.keys - .mapNotNull { it as? io.github.sds100.keymapper.trigger.KeyCodeTriggerKey } + .mapNotNull { it as? KeyCodeTriggerKey } .any { keyToCompare -> keyToCompare.keyCode == keyCode && keyToCompare.device.isSameDevice(device) } @@ -375,7 +378,7 @@ class ConfigKeyMapUseCaseController( consumeKeyEvent = false } - val triggerKey = io.github.sds100.keymapper.trigger.KeyCodeTriggerKey( + val triggerKey = KeyCodeTriggerKey( keyCode = keyCode, device = device, clickType = clickType, @@ -449,10 +452,11 @@ class ConfigKeyMapUseCaseController( when (key) { // You can't mix assistant trigger types in a parallel trigger because there is no notion of a "down" key event, which means they can't be pressed at the same time is AssistantTriggerKey, is FingerprintTriggerKey -> 0 - is io.github.sds100.keymapper.trigger.KeyCodeTriggerKey -> Pair( + is KeyCodeTriggerKey -> Pair( key.keyCode, key.device, ) + is FloatingButtonKey -> key.buttonUid } } @@ -552,7 +556,7 @@ class ConfigKeyMapUseCaseController( override fun setTriggerKeyDevice(keyUid: String, device: TriggerKeyDevice) { editTriggerKey(keyUid) { key -> - if (key is io.github.sds100.keymapper.trigger.KeyCodeTriggerKey) { + if (key is KeyCodeTriggerKey) { key.copy(device = device) } else { key @@ -562,7 +566,7 @@ class ConfigKeyMapUseCaseController( override fun setTriggerKeyConsumeKeyEvent(keyUid: String, consumeKeyEvent: Boolean) { editTriggerKey(keyUid) { key -> - if (key is io.github.sds100.keymapper.trigger.KeyCodeTriggerKey) { + if (key is KeyCodeTriggerKey) { key.copy(consumeEvent = consumeKeyEvent) } else { key @@ -788,7 +792,7 @@ class ConfigKeyMapUseCaseController( false } else { trigger.keys - .mapNotNull { it as? io.github.sds100.keymapper.trigger.KeyCodeTriggerKey } + .mapNotNull { it as? KeyCodeTriggerKey } .any { InputEventUtils.isDpadKeyCode(it.keyCode) } } @@ -869,7 +873,7 @@ class ConfigKeyMapUseCaseController( return floatingLayoutRepository.count() } - override suspend fun sendServiceEvent(event: ServiceEvent): Result<*> { + override suspend fun sendServiceEvent(event: AccessibilityServiceEvent): KMResult<*> { return serviceAdapter.send(event) } @@ -986,7 +990,7 @@ interface ConfigKeyMapUseCase : GetDefaultKeyMapOptionsUseCase { fun removeConstraint(id: String) fun setAndMode() fun setOrMode() - suspend fun sendServiceEvent(event: ServiceEvent): Result<*> + suspend fun sendServiceEvent(event: AccessibilityServiceEvent): KMResult<*> // trigger fun addKeyCodeTriggerKey( diff --git a/base/src/main/java/io/github/sds100/keymapper/base/keymaps/CreateKeyMapShortcutActivity.kt b/base/src/main/java/io/github/sds100/keymapper/base/keymaps/CreateKeyMapShortcutActivity.kt new file mode 100644 index 0000000000..66b9d37eed --- /dev/null +++ b/base/src/main/java/io/github/sds100/keymapper/base/keymaps/CreateKeyMapShortcutActivity.kt @@ -0,0 +1,108 @@ +package io.github.sds100.keymapper.base.keymaps + +import android.os.Bundle +import androidx.activity.SystemBarStyle +import androidx.activity.compose.setContent +import androidx.activity.enableEdgeToEdge +import androidx.activity.viewModels +import androidx.appcompat.app.AppCompatActivity +import androidx.compose.ui.graphics.toArgb +import androidx.lifecycle.Lifecycle +import androidx.navigation.findNavController +import dagger.hilt.android.AndroidEntryPoint +import io.github.sds100.keymapper.base.R +import io.github.sds100.keymapper.base.compose.ComposeColors +import io.github.sds100.keymapper.base.compose.KeyMapperTheme +import io.github.sds100.keymapper.base.onboarding.OnboardingUseCase +import io.github.sds100.keymapper.base.system.accessibility.AccessibilityServiceAdapterImpl +import io.github.sds100.keymapper.base.system.permissions.RequestPermissionDelegate +import io.github.sds100.keymapper.base.trigger.RecordTriggerController +import io.github.sds100.keymapper.base.utils.ui.ResourceProviderImpl +import io.github.sds100.keymapper.base.utils.ui.launchRepeatOnLifecycle +import io.github.sds100.keymapper.common.BuildConfigProvider +import io.github.sds100.keymapper.system.notifications.NotificationReceiverAdapterImpl +import io.github.sds100.keymapper.system.permissions.AndroidPermissionAdapter +import io.github.sds100.keymapper.system.shizuku.ShizukuAdapter +import kotlinx.coroutines.flow.collectLatest +import javax.inject.Inject + +@AndroidEntryPoint +class CreateKeyMapShortcutActivity : AppCompatActivity() { + + @Inject + lateinit var permissionAdapter: AndroidPermissionAdapter + + @Inject + lateinit var serviceAdapter: AccessibilityServiceAdapterImpl + + @Inject + lateinit var resourceProvider: ResourceProviderImpl + + @Inject + lateinit var onboardingUseCase: OnboardingUseCase + + @Inject + lateinit var recordTriggerController: RecordTriggerController + + @Inject + lateinit var notificationReceiverAdapter: NotificationReceiverAdapterImpl + + @Inject + lateinit var shizukuAdapter: ShizukuAdapter + + @Inject + lateinit var buildConfigProvider: BuildConfigProvider + + private lateinit var requestPermissionDelegate: RequestPermissionDelegate + + private val viewModel by viewModels() + + override fun onCreate(savedInstanceState: Bundle?) { + enableEdgeToEdge( + statusBarStyle = SystemBarStyle.auto( + ComposeColors.surfaceContainerLight.toArgb(), + ComposeColors.surfaceContainerDark.toArgb(), + ), + navigationBarStyle = SystemBarStyle.auto( + ComposeColors.surfaceContainerLight.toArgb(), + ComposeColors.surfaceContainerDark.toArgb(), + ), + ) + super.onCreate(savedInstanceState) + + setContent { + KeyMapperTheme { + CreateKeyMapShortcutScreen( + viewModel = viewModel, + finishActivity = { finish() }, + ) + } + } + + requestPermissionDelegate = RequestPermissionDelegate( + this, + showDialogs = true, + permissionAdapter, + notificationReceiverAdapter = notificationReceiverAdapter, + buildConfigProvider = buildConfigProvider, + shizukuAdapter = shizukuAdapter, + ) + + launchRepeatOnLifecycle(Lifecycle.State.STARTED) { + permissionAdapter.request + .collectLatest { permission -> + requestPermissionDelegate.requestPermission( + permission, + findNavController(R.id.container), + ) + } + } + + launchRepeatOnLifecycle(Lifecycle.State.STARTED) { + viewModel.returnIntentResult.collectLatest { intent -> + setResult(RESULT_OK, intent) + finish() + } + } + } +} diff --git a/app/src/main/java/io/github/sds100/keymapper/keymaps/CreateKeyMapShortcutScreen.kt b/base/src/main/java/io/github/sds100/keymapper/base/keymaps/CreateKeyMapShortcutScreen.kt similarity index 88% rename from app/src/main/java/io/github/sds100/keymapper/keymaps/CreateKeyMapShortcutScreen.kt rename to base/src/main/java/io/github/sds100/keymapper/base/keymaps/CreateKeyMapShortcutScreen.kt index 2857e9e4bb..366566c45a 100644 --- a/app/src/main/java/io/github/sds100/keymapper/keymaps/CreateKeyMapShortcutScreen.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/keymaps/CreateKeyMapShortcutScreen.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.keymaps +package io.github.sds100.keymapper.base.keymaps import androidx.activity.compose.BackHandler import androidx.compose.animation.AnimatedContent @@ -11,7 +11,6 @@ import androidx.compose.material.icons.automirrored.rounded.ArrowBack import androidx.compose.material.icons.outlined.Add import androidx.compose.material.icons.outlined.FlashlightOn import androidx.compose.material.icons.outlined.Lock -import androidx.compose.material3.AlertDialog import androidx.compose.material3.CenterAlignedTopAppBar import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Icon @@ -37,21 +36,21 @@ import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle -import io.github.sds100.keymapper.Constants -import io.github.sds100.keymapper.R -import io.github.sds100.keymapper.compose.KeyMapperTheme -import io.github.sds100.keymapper.constraints.ConstraintMode -import io.github.sds100.keymapper.groups.GroupBreadcrumbRow -import io.github.sds100.keymapper.groups.GroupListItemModel -import io.github.sds100.keymapper.groups.GroupRow -import io.github.sds100.keymapper.trigger.KeyMapListItemModel -import io.github.sds100.keymapper.trigger.TriggerError -import io.github.sds100.keymapper.util.Error -import io.github.sds100.keymapper.util.State -import io.github.sds100.keymapper.util.drawable -import io.github.sds100.keymapper.util.ui.compose.ComposeChipModel -import io.github.sds100.keymapper.util.ui.compose.ComposeIconInfo -import io.github.sds100.keymapper.util.ui.compose.CustomDialog +import io.github.sds100.keymapper.base.R +import io.github.sds100.keymapper.base.compose.KeyMapperTheme +import io.github.sds100.keymapper.base.constraints.ConstraintMode +import io.github.sds100.keymapper.base.groups.GroupBreadcrumbRow +import io.github.sds100.keymapper.base.groups.GroupListItemModel +import io.github.sds100.keymapper.base.groups.GroupRow +import io.github.sds100.keymapper.base.trigger.KeyMapListItemModel +import io.github.sds100.keymapper.base.trigger.TriggerError +import io.github.sds100.keymapper.base.utils.ui.UnsavedChangesDialog +import io.github.sds100.keymapper.base.utils.ui.compose.ComposeChipModel +import io.github.sds100.keymapper.base.utils.ui.compose.ComposeIconInfo +import io.github.sds100.keymapper.base.utils.ui.compose.CustomDialog +import io.github.sds100.keymapper.base.utils.ui.drawable +import io.github.sds100.keymapper.common.utils.KMError +import io.github.sds100.keymapper.common.utils.State @Composable fun CreateKeyMapShortcutScreen( @@ -93,7 +92,7 @@ private fun CreateKeyMapShortcutScreen( var showBackDialog by rememberSaveable { mutableStateOf(false) } if (showBackDialog) { - BackDialog( + UnsavedChangesDialog( onDismiss = { showBackDialog = false }, onDiscardClick = finishActivity, ) @@ -204,24 +203,6 @@ private fun CreateKeyMapShortcutScreen( } } -@Composable -private fun BackDialog( - onDismiss: () -> Unit, - onDiscardClick: () -> Unit, -) { - AlertDialog( - onDismissRequest = onDismiss, - title = { Text(stringResource(R.string.dialog_title_unsaved_changes)) }, - text = { Text(stringResource(R.string.dialog_message_unsaved_changes)) }, - confirmButton = { - TextButton(onClick = onDiscardClick) { Text(stringResource(R.string.pos_discard_changes)) } - }, - dismissButton = { - TextButton(onClick = onDismiss) { Text(stringResource(R.string.neg_keep_editing)) } - }, - ) -} - @Composable private fun ShortcutNameDialog( onSaveClick: (name: String) -> Unit = { }, @@ -287,7 +268,7 @@ private fun keyMapSampleList(): List { ComposeChipModel.Error( id = "1", text = "Input KEYCODE_0 • Repeat until released", - error = Error.NoCompatibleImeChosen, + error = KMError.NoCompatibleImeChosen, ), ComposeChipModel.Normal( id = "2", @@ -310,7 +291,7 @@ private fun keyMapSampleList(): List { ComposeChipModel.Error( id = "1", "Key Mapper is playing media", - error = Error.AppNotFound(""), + error = KMError.AppNotFound("io.github.sds100.keymapper"), ), ), options = listOf("Vibrate"), @@ -353,7 +334,7 @@ private fun constraintsSampleList(): List { ComposeChipModel.Error( id = "2", text = "Key Mapper not found", - error = Error.AppNotFound(Constants.PACKAGE_NAME), + error = KMError.AppNotFound("io.github.sds100.keymapper"), ), ) } @@ -440,14 +421,6 @@ private fun PreviewEmpty() { } } -@Preview -@Composable -private fun BackDialogPreview() { - KeyMapperTheme { - BackDialog(onDismiss = {}, onDiscardClick = {}) - } -} - @Preview @Composable private fun ShortcutNameDialogPreview() { diff --git a/base/src/main/java/io/github/sds100/keymapper/base/keymaps/CreateKeyMapShortcutUseCase.kt b/base/src/main/java/io/github/sds100/keymapper/base/keymaps/CreateKeyMapShortcutUseCase.kt new file mode 100644 index 0000000000..563b7bff63 --- /dev/null +++ b/base/src/main/java/io/github/sds100/keymapper/base/keymaps/CreateKeyMapShortcutUseCase.kt @@ -0,0 +1,87 @@ +package io.github.sds100.keymapper.base.keymaps + +import android.content.Intent +import android.graphics.drawable.Drawable +import androidx.core.os.bundleOf +import io.github.sds100.keymapper.base.R +import io.github.sds100.keymapper.base.utils.ui.ResourceProvider +import io.github.sds100.keymapper.common.utils.KMResult +import io.github.sds100.keymapper.system.apps.AppShortcutAdapter +import javax.inject.Inject + +class CreateKeyMapShortcutUseCaseImpl @Inject constructor( + private val appShortcutAdapter: AppShortcutAdapter, + private val resourceProvider: ResourceProvider, +) : CreateKeyMapShortcutUseCase { + + companion object { + private const val ACTION_TRIGGER_KEYMAP_BY_UID = + "io.github.sds100.keymapper.ACTION_TRIGGER_KEYMAP_BY_UID" + private const val EXTRA_KEYMAP_UID = "io.github.sds100.keymapper.EXTRA_KEYMAP_UID" + } + + override val isSupported: Boolean + get() = appShortcutAdapter.areLauncherShortcutsSupported + + override fun pinShortcut( + keyMapUid: String, + shortcutLabel: String, + icon: Drawable?, + ): KMResult<*> { + val shortcut = if (icon == null) { + appShortcutAdapter.createLauncherShortcut( + iconResId = R.mipmap.ic_launcher_round, + label = shortcutLabel, + intentAction = ACTION_TRIGGER_KEYMAP_BY_UID, + bundleOf(EXTRA_KEYMAP_UID to keyMapUid), + ) + } else { + appShortcutAdapter.createLauncherShortcut( + icon = icon, + label = shortcutLabel, + intentAction = ACTION_TRIGGER_KEYMAP_BY_UID, + bundleOf(EXTRA_KEYMAP_UID to keyMapUid), + ) + } + return appShortcutAdapter.pinShortcut(shortcut) + } + + override fun createIntent( + keyMapUid: String, + shortcutLabel: String, + icon: Drawable?, + ): Intent { + val shortcut = if (icon == null) { + appShortcutAdapter.createLauncherShortcut( + iconResId = R.mipmap.ic_launcher_round, + label = shortcutLabel, + intentAction = ACTION_TRIGGER_KEYMAP_BY_UID, + bundleOf(EXTRA_KEYMAP_UID to keyMapUid), + ) + } else { + appShortcutAdapter.createLauncherShortcut( + icon = icon, + label = shortcutLabel, + intentAction = ACTION_TRIGGER_KEYMAP_BY_UID, + bundleOf(EXTRA_KEYMAP_UID to keyMapUid), + ) + } + return appShortcutAdapter.createShortcutResultIntent(shortcut) + } +} + +interface CreateKeyMapShortcutUseCase { + val isSupported: Boolean + + fun pinShortcut( + keyMapUid: String, + shortcutLabel: String, + icon: Drawable?, + ): KMResult<*> + + fun createIntent( + keyMapUid: String, + shortcutLabel: String, + icon: Drawable?, + ): Intent +} diff --git a/app/src/main/java/io/github/sds100/keymapper/keymaps/CreateKeyMapShortcutViewModel.kt b/base/src/main/java/io/github/sds100/keymapper/base/keymaps/CreateKeyMapShortcutViewModel.kt similarity index 77% rename from app/src/main/java/io/github/sds100/keymapper/keymaps/CreateKeyMapShortcutViewModel.kt rename to base/src/main/java/io/github/sds100/keymapper/base/keymaps/CreateKeyMapShortcutViewModel.kt index bba8984ef3..086e330619 100644 --- a/app/src/main/java/io/github/sds100/keymapper/keymaps/CreateKeyMapShortcutViewModel.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/keymaps/CreateKeyMapShortcutViewModel.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.keymaps +package io.github.sds100.keymapper.base.keymaps import android.content.Intent import android.graphics.Color @@ -7,21 +7,21 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue import androidx.lifecycle.ViewModel -import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.viewModelScope -import io.github.sds100.keymapper.actions.ActionErrorSnapshot -import io.github.sds100.keymapper.actions.ActionUiHelper -import io.github.sds100.keymapper.constraints.ConstraintErrorSnapshot -import io.github.sds100.keymapper.constraints.ConstraintMode -import io.github.sds100.keymapper.constraints.ConstraintUiHelper -import io.github.sds100.keymapper.groups.GroupListItemModel -import io.github.sds100.keymapper.trigger.KeyMapListItemModel -import io.github.sds100.keymapper.trigger.TriggerErrorSnapshot -import io.github.sds100.keymapper.util.State -import io.github.sds100.keymapper.util.mapData -import io.github.sds100.keymapper.util.ui.ResourceProvider -import io.github.sds100.keymapper.util.ui.TintType -import io.github.sds100.keymapper.util.ui.compose.ComposeIconInfo +import dagger.hilt.android.lifecycle.HiltViewModel +import io.github.sds100.keymapper.base.actions.ActionErrorSnapshot +import io.github.sds100.keymapper.base.actions.ActionUiHelper +import io.github.sds100.keymapper.base.constraints.ConstraintErrorSnapshot +import io.github.sds100.keymapper.base.constraints.ConstraintMode +import io.github.sds100.keymapper.base.constraints.ConstraintUiHelper +import io.github.sds100.keymapper.base.groups.GroupListItemModel +import io.github.sds100.keymapper.base.trigger.KeyMapListItemModel +import io.github.sds100.keymapper.base.trigger.TriggerErrorSnapshot +import io.github.sds100.keymapper.base.utils.ui.ResourceProvider +import io.github.sds100.keymapper.base.utils.ui.TintType +import io.github.sds100.keymapper.base.utils.ui.compose.ComposeIconInfo +import io.github.sds100.keymapper.common.utils.State +import io.github.sds100.keymapper.common.utils.mapData import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asSharedFlow @@ -31,17 +31,15 @@ import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.filterNotNull import kotlinx.coroutines.flow.first import kotlinx.coroutines.launch +import javax.inject.Inject -/** - * Created by sds100 on 08/09/20. - */ -class CreateKeyMapShortcutViewModel( - private val configKeyMapUseCase: ConfigKeyMapUseCase, +@HiltViewModel +class CreateKeyMapShortcutViewModel @Inject constructor( + private val config: ConfigKeyMapUseCase, private val listKeyMaps: ListKeyMapsUseCase, - private val createShortcutUseCase: CreateKeyMapShortcutUseCase, - resourceProvider: ResourceProvider, -) : ViewModel(), - ResourceProvider by resourceProvider { + private val createKeyMapShortcut: CreateKeyMapShortcutUseCase, + private val resourceProvider: ResourceProvider, +) : ViewModel() { private val actionUiHelper = ActionUiHelper(listKeyMaps, resourceProvider) private val constraintUiHelper = ConstraintUiHelper( listKeyMaps, @@ -158,16 +156,16 @@ class CreateKeyMapShortcutViewModel( if (state.keyMaps !is State.Data) return@launch - configKeyMapUseCase.loadKeyMap(uid) - configKeyMapUseCase.setTriggerFromOtherAppsEnabled(true) + config.loadKeyMap(uid) + config.setTriggerFromOtherAppsEnabled(true) - val keyMapState = configKeyMapUseCase.keyMap.first() + val keyMapState = config.keyMap.first() if (keyMapState !is State.Data) return@launch val keyMap = keyMapState.data - val key = "create_launcher_shortcut" + "create_launcher_shortcut" val defaultShortcutName: String val icon: Drawable? @@ -208,13 +206,13 @@ class CreateKeyMapShortcutViewModel( return@launch } - val intent = createShortcutUseCase.createIntent( + val intent = createKeyMapShortcut.createIntent( keyMapUid = keyMap.uid, shortcutLabel = shortcutName, icon = icon, ) - configKeyMapUseCase.save() + config.save() _returnIntentResult.emit(intent) } @@ -231,20 +229,4 @@ class CreateKeyMapShortcutViewModel( listKeyMaps.popGroup() } } - - class Factory( - private val configKeyMapUseCase: ConfigKeyMapUseCase, - private val listUseCase: ListKeyMapsUseCase, - private val createShortcutUseCase: CreateKeyMapShortcutUseCase, - private val resourceProvider: ResourceProvider, - ) : ViewModelProvider.Factory { - - @Suppress("UNCHECKED_CAST") - override fun create(modelClass: Class) = CreateKeyMapShortcutViewModel( - configKeyMapUseCase, - listUseCase, - createShortcutUseCase, - resourceProvider, - ) as T - } } diff --git a/app/src/main/java/io/github/sds100/keymapper/keymaps/DisplayKeyMapUseCase.kt b/base/src/main/java/io/github/sds100/keymapper/base/keymaps/DisplayKeyMapUseCase.kt similarity index 53% rename from app/src/main/java/io/github/sds100/keymapper/keymaps/DisplayKeyMapUseCase.kt rename to base/src/main/java/io/github/sds100/keymapper/base/keymaps/DisplayKeyMapUseCase.kt index b26f655037..d4632d4e2b 100644 --- a/app/src/main/java/io/github/sds100/keymapper/keymaps/DisplayKeyMapUseCase.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/keymaps/DisplayKeyMapUseCase.kt @@ -1,32 +1,36 @@ -package io.github.sds100.keymapper.keymaps +package io.github.sds100.keymapper.base.keymaps import android.graphics.drawable.Drawable -import io.github.sds100.keymapper.actions.DisplayActionUseCase -import io.github.sds100.keymapper.actions.GetActionErrorUseCase -import io.github.sds100.keymapper.constraints.DisplayConstraintUseCase -import io.github.sds100.keymapper.constraints.GetConstraintErrorUseCase +import dagger.hilt.android.scopes.ViewModelScoped +import io.github.sds100.keymapper.base.actions.DisplayActionUseCase +import io.github.sds100.keymapper.base.actions.GetActionErrorUseCase +import io.github.sds100.keymapper.base.constraints.DisplayConstraintUseCase +import io.github.sds100.keymapper.base.constraints.GetConstraintErrorUseCase +import io.github.sds100.keymapper.base.purchasing.ProductId +import io.github.sds100.keymapper.base.purchasing.PurchasingError +import io.github.sds100.keymapper.base.purchasing.PurchasingManager +import io.github.sds100.keymapper.base.system.inputmethod.KeyMapperImeHelper +import io.github.sds100.keymapper.base.trigger.TriggerError +import io.github.sds100.keymapper.base.trigger.TriggerErrorSnapshot +import io.github.sds100.keymapper.common.BuildConfigProvider +import io.github.sds100.keymapper.common.utils.KMError +import io.github.sds100.keymapper.common.utils.KMResult +import io.github.sds100.keymapper.common.utils.State +import io.github.sds100.keymapper.common.utils.Success +import io.github.sds100.keymapper.common.utils.dataOrNull +import io.github.sds100.keymapper.common.utils.otherwise +import io.github.sds100.keymapper.common.utils.then +import io.github.sds100.keymapper.common.utils.valueIfFailure import io.github.sds100.keymapper.data.Keys import io.github.sds100.keymapper.data.repositories.PreferenceRepository -import io.github.sds100.keymapper.purchasing.ProductId -import io.github.sds100.keymapper.purchasing.PurchasingManager -import io.github.sds100.keymapper.shizuku.ShizukuUtils -import io.github.sds100.keymapper.system.accessibility.ServiceAdapter +import io.github.sds100.keymapper.system.SystemError +import io.github.sds100.keymapper.system.accessibility.AccessibilityServiceAdapter import io.github.sds100.keymapper.system.apps.PackageManagerAdapter import io.github.sds100.keymapper.system.inputmethod.InputMethodAdapter -import io.github.sds100.keymapper.system.inputmethod.KeyMapperImeHelper import io.github.sds100.keymapper.system.permissions.Permission import io.github.sds100.keymapper.system.permissions.PermissionAdapter import io.github.sds100.keymapper.system.ringtones.RingtoneAdapter -import io.github.sds100.keymapper.trigger.TriggerError -import io.github.sds100.keymapper.trigger.TriggerErrorSnapshot -import io.github.sds100.keymapper.util.Error -import io.github.sds100.keymapper.util.Result -import io.github.sds100.keymapper.util.State -import io.github.sds100.keymapper.util.Success -import io.github.sds100.keymapper.util.dataOrNull -import io.github.sds100.keymapper.util.otherwise -import io.github.sds100.keymapper.util.then -import io.github.sds100.keymapper.util.valueIfFailure +import io.github.sds100.keymapper.system.shizuku.ShizukuUtils import kotlinx.coroutines.TimeoutCancellationException import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.callbackFlow @@ -36,29 +40,28 @@ import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onStart import kotlinx.coroutines.withTimeout +import javax.inject.Inject -/** - * Created by sds100 on 04/04/2021. - */ - -class DisplayKeyMapUseCaseImpl( +@ViewModelScoped +class DisplayKeyMapUseCaseImpl @Inject constructor( private val permissionAdapter: PermissionAdapter, private val inputMethodAdapter: InputMethodAdapter, - private val packageManager: PackageManagerAdapter, - private val preferenceRepository: PreferenceRepository, - private val accessibilityServiceAdapter: ServiceAdapter, - private val preferences: PreferenceRepository, + private val packageManagerAdapter: PackageManagerAdapter, + private val settingsRepository: PreferenceRepository, + private val accessibilityServiceAdapter: AccessibilityServiceAdapter, private val purchasingManager: PurchasingManager, private val ringtoneAdapter: RingtoneAdapter, - getActionError: GetActionErrorUseCase, - getConstraintError: GetConstraintErrorUseCase, + private val getActionErrorUseCase: GetActionErrorUseCase, + private val getConstraintErrorUseCase: GetConstraintErrorUseCase, + private val buildConfigProvider: BuildConfigProvider, ) : DisplayKeyMapUseCase, - GetActionErrorUseCase by getActionError, - GetConstraintErrorUseCase by getConstraintError { - private val keyMapperImeHelper = KeyMapperImeHelper(inputMethodAdapter) + GetActionErrorUseCase by getActionErrorUseCase, + GetConstraintErrorUseCase by getConstraintErrorUseCase { + private val keyMapperImeHelper = + KeyMapperImeHelper(inputMethodAdapter, buildConfigProvider.packageName) private val showDpadImeSetupError: Flow = - preferences.get(Keys.neverShowDpadImeTriggerError).map { neverShow -> + settingsRepository.get(Keys.neverShowDpadImeTriggerError).map { neverShow -> if (neverShow == null) { true } else { @@ -70,10 +73,10 @@ class DisplayKeyMapUseCaseImpl( * This waits for the purchases to be processed with a timeout so the UI doesn't * say there are no purchases while it is loading. */ - private val purchasesFlow: Flow>>> = callbackFlow { + private val purchasesFlow: Flow>>> = callbackFlow { try { val value = withTimeout(5000L) { - purchasingManager.purchases.filterIsInstance>>>() + purchasingManager.purchases.filterIsInstance>>>() .first() } @@ -104,7 +107,7 @@ class DisplayKeyMapUseCaseImpl( } override val showTriggerKeyboardIconExplanation: Flow = - preferences.get(Keys.neverShowTriggerKeyboardIconExplanation).map { neverShow -> + settingsRepository.get(Keys.neverShowTriggerKeyboardIconExplanation).map { neverShow -> if (neverShow == null) { true } else { @@ -113,14 +116,14 @@ class DisplayKeyMapUseCaseImpl( } override val showDeviceDescriptors: Flow = - preferenceRepository.get(Keys.showDeviceDescriptors).map { it == true } + settingsRepository.get(Keys.showDeviceDescriptors).map { it == true } override fun neverShowTriggerKeyboardIconExplanation() { - preferences.set(Keys.neverShowTriggerKeyboardIconExplanation, true) + settingsRepository.set(Keys.neverShowTriggerKeyboardIconExplanation, true) } override fun neverShowDpadImeSetupError() { - preferences.set(Keys.neverShowDpadImeTriggerError, true) + settingsRepository.set(Keys.neverShowDpadImeTriggerError, true) } override suspend fun isFloatingButtonsPurchased(): Boolean { @@ -129,19 +132,24 @@ class DisplayKeyMapUseCaseImpl( override suspend fun fixTriggerError(error: TriggerError) { when (error) { - TriggerError.DND_ACCESS_DENIED -> fixError(Error.PermissionDenied(Permission.ACCESS_NOTIFICATION_POLICY)) - TriggerError.SCREEN_OFF_ROOT_DENIED -> fixError(Error.PermissionDenied(Permission.ROOT)) - TriggerError.CANT_DETECT_IN_PHONE_CALL -> fixError(Error.CantDetectKeyEventsInPhoneCall) + TriggerError.DND_ACCESS_DENIED -> fixError(SystemError.PermissionDenied(Permission.ACCESS_NOTIFICATION_POLICY)) + TriggerError.SCREEN_OFF_ROOT_DENIED -> fixError( + SystemError.PermissionDenied( + Permission.ROOT, + ), + ) + + TriggerError.CANT_DETECT_IN_PHONE_CALL -> fixError(KMError.CantDetectKeyEventsInPhoneCall) TriggerError.ASSISTANT_TRIGGER_NOT_PURCHASED -> fixError( - Error.ProductNotPurchased( + PurchasingError.ProductNotPurchased( ProductId.ASSISTANT_TRIGGER, ), ) - TriggerError.DPAD_IME_NOT_SELECTED -> fixError(Error.DpadTriggerImeNotSelected) + TriggerError.DPAD_IME_NOT_SELECTED -> fixError(KMError.DpadTriggerImeNotSelected) TriggerError.FLOATING_BUTTON_DELETED -> {} TriggerError.FLOATING_BUTTONS_NOT_PURCHASED -> fixError( - Error.ProductNotPurchased( + PurchasingError.ProductNotPurchased( ProductId.FLOATING_BUTTONS, ), ) @@ -150,26 +158,27 @@ class DisplayKeyMapUseCaseImpl( } } - override fun getAppName(packageName: String): Result = packageManager.getAppName(packageName) + override fun getAppName(packageName: String): KMResult = packageManagerAdapter.getAppName(packageName) - override fun getAppIcon(packageName: String): Result = packageManager.getAppIcon(packageName) + override fun getAppIcon(packageName: String): KMResult = packageManagerAdapter.getAppIcon(packageName) - override fun getInputMethodLabel(imeId: String): Result = inputMethodAdapter.getInfoById(imeId).then { Success(it.label) } + override fun getInputMethodLabel(imeId: String): KMResult = + inputMethodAdapter.getInfoById(imeId).then { Success(it.label) } - override suspend fun fixError(error: Error) { + override suspend fun fixError(error: KMError) { when (error) { - is Error.AppDisabled -> packageManager.enableApp(error.packageName) - is Error.AppNotFound -> packageManager.downloadApp(error.packageName) - Error.NoCompatibleImeChosen -> + is KMError.AppDisabled -> packageManagerAdapter.enableApp(error.packageName) + is KMError.AppNotFound -> packageManagerAdapter.downloadApp(error.packageName) + KMError.NoCompatibleImeChosen -> keyMapperImeHelper.chooseCompatibleInputMethod().otherwise { inputMethodAdapter.showImePicker(fromForeground = true) } - Error.NoCompatibleImeEnabled -> keyMapperImeHelper.enableCompatibleInputMethods() - is Error.ImeDisabled -> inputMethodAdapter.enableIme(error.ime.id) - is Error.PermissionDenied -> permissionAdapter.request(error.permission) - is Error.ShizukuNotStarted -> packageManager.openApp(ShizukuUtils.SHIZUKU_PACKAGE) - is Error.CantDetectKeyEventsInPhoneCall -> { + KMError.NoCompatibleImeEnabled -> keyMapperImeHelper.enableCompatibleInputMethods() + is SystemError.ImeDisabled -> inputMethodAdapter.enableIme(error.ime.id) + is SystemError.PermissionDenied -> permissionAdapter.request(error.permission) + is KMError.ShizukuNotStarted -> packageManagerAdapter.openApp(ShizukuUtils.SHIZUKU_PACKAGE) + is KMError.CantDetectKeyEventsInPhoneCall -> { if (!keyMapperImeHelper.isCompatibleImeEnabled()) { keyMapperImeHelper.enableCompatibleInputMethods() } @@ -191,10 +200,10 @@ class DisplayKeyMapUseCaseImpl( override fun restartAccessibilityService(): Boolean = accessibilityServiceAdapter.restart() override fun neverShowDndTriggerError() { - preferenceRepository.set(Keys.neverShowDndAccessError, true) + settingsRepository.set(Keys.neverShowDndAccessError, true) } - override fun getRingtoneLabel(uri: String): Result { + override fun getRingtoneLabel(uri: String): KMResult { return ringtoneAdapter.getLabel(uri) } } diff --git a/app/src/main/java/io/github/sds100/keymapper/keymaps/FingerprintGesturesSupportedUseCase.kt b/base/src/main/java/io/github/sds100/keymapper/base/keymaps/FingerprintGesturesSupportedUseCase.kt similarity index 82% rename from app/src/main/java/io/github/sds100/keymapper/keymaps/FingerprintGesturesSupportedUseCase.kt rename to base/src/main/java/io/github/sds100/keymapper/base/keymaps/FingerprintGesturesSupportedUseCase.kt index 3052d0afce..84b2792f31 100644 --- a/app/src/main/java/io/github/sds100/keymapper/keymaps/FingerprintGesturesSupportedUseCase.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/keymaps/FingerprintGesturesSupportedUseCase.kt @@ -1,15 +1,15 @@ -package io.github.sds100.keymapper.keymaps +package io.github.sds100.keymapper.base.keymaps import android.os.Build import io.github.sds100.keymapper.data.Keys import io.github.sds100.keymapper.data.repositories.PreferenceRepository import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.map +import javax.inject.Inject +import javax.inject.Singleton -/** - * Created by sds100 on 02/04/2021. - */ -class FingerprintGesturesSupportedUseCaseImpl( +@Singleton +class FingerprintGesturesSupportedUseCaseImpl @Inject constructor( private val preferenceRepository: PreferenceRepository, ) : FingerprintGesturesSupportedUseCase { override val isSupported: Flow = diff --git a/app/src/main/java/io/github/sds100/keymapper/keymaps/GetDefaultKeyMapOptionsUseCase.kt b/base/src/main/java/io/github/sds100/keymapper/base/keymaps/GetDefaultKeyMapOptionsUseCase.kt similarity index 98% rename from app/src/main/java/io/github/sds100/keymapper/keymaps/GetDefaultKeyMapOptionsUseCase.kt rename to base/src/main/java/io/github/sds100/keymapper/base/keymaps/GetDefaultKeyMapOptionsUseCase.kt index db17acfe03..11e3b89199 100644 --- a/app/src/main/java/io/github/sds100/keymapper/keymaps/GetDefaultKeyMapOptionsUseCase.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/keymaps/GetDefaultKeyMapOptionsUseCase.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.keymaps +package io.github.sds100.keymapper.base.keymaps import io.github.sds100.keymapper.data.Keys import io.github.sds100.keymapper.data.PreferenceDefaults diff --git a/app/src/main/java/io/github/sds100/keymapper/keymaps/KeyMap.kt b/base/src/main/java/io/github/sds100/keymapper/base/keymaps/KeyMap.kt similarity index 82% rename from app/src/main/java/io/github/sds100/keymapper/keymaps/KeyMap.kt rename to base/src/main/java/io/github/sds100/keymapper/base/keymaps/KeyMap.kt index 0e33d254ee..c0e05384aa 100644 --- a/app/src/main/java/io/github/sds100/keymapper/keymaps/KeyMap.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/keymaps/KeyMap.kt @@ -1,26 +1,22 @@ -package io.github.sds100.keymapper.keymaps +package io.github.sds100.keymapper.base.keymaps import android.view.KeyEvent -import io.github.sds100.keymapper.actions.Action -import io.github.sds100.keymapper.actions.ActionData -import io.github.sds100.keymapper.actions.ActionEntityMapper -import io.github.sds100.keymapper.actions.canBeHeldDown -import io.github.sds100.keymapper.constraints.ConstraintEntityMapper -import io.github.sds100.keymapper.constraints.ConstraintModeEntityMapper -import io.github.sds100.keymapper.constraints.ConstraintState +import io.github.sds100.keymapper.base.actions.Action +import io.github.sds100.keymapper.base.actions.ActionData +import io.github.sds100.keymapper.base.actions.ActionEntityMapper +import io.github.sds100.keymapper.base.actions.canBeHeldDown +import io.github.sds100.keymapper.base.constraints.ConstraintEntityMapper +import io.github.sds100.keymapper.base.constraints.ConstraintModeEntityMapper +import io.github.sds100.keymapper.base.constraints.ConstraintState +import io.github.sds100.keymapper.base.keymaps.detection.KeyMapController +import io.github.sds100.keymapper.base.trigger.Trigger +import io.github.sds100.keymapper.base.trigger.TriggerEntityMapper +import io.github.sds100.keymapper.base.trigger.TriggerKey import io.github.sds100.keymapper.data.entities.FloatingButtonEntityWithLayout import io.github.sds100.keymapper.data.entities.KeyMapEntity -import io.github.sds100.keymapper.keymaps.detection.KeyMapController -import io.github.sds100.keymapper.trigger.Trigger -import io.github.sds100.keymapper.trigger.TriggerEntityMapper -import io.github.sds100.keymapper.trigger.TriggerKey import kotlinx.serialization.Serializable import java.util.UUID -/** - * Created by sds100 on 03/03/2021. - */ - @Serializable data class KeyMap( val dbId: Long? = null, @@ -71,7 +67,7 @@ fun KeyMap.requiresImeKeyEventForwarding(): Boolean { actionList.any { it.data is ActionData.AnswerCall || it.data is ActionData.EndCall } val hasVolumeKeys = trigger.keys - .mapNotNull { it as? io.github.sds100.keymapper.trigger.KeyCodeTriggerKey } + .mapNotNull { it as? io.github.sds100.keymapper.base.trigger.KeyCodeTriggerKey } .any { it.keyCode == KeyEvent.KEYCODE_VOLUME_DOWN || it.keyCode == KeyEvent.KEYCODE_VOLUME_UP @@ -87,7 +83,7 @@ fun KeyMap.requiresImeKeyEventForwarding(): Boolean { * is incoming. */ fun KeyMap.requiresImeKeyEventForwardingInPhoneCall(triggerKey: TriggerKey): Boolean { - if (triggerKey !is io.github.sds100.keymapper.trigger.KeyCodeTriggerKey) { + if (triggerKey !is io.github.sds100.keymapper.base.trigger.KeyCodeTriggerKey) { return false } @@ -95,7 +91,7 @@ fun KeyMap.requiresImeKeyEventForwardingInPhoneCall(triggerKey: TriggerKey): Boo actionList.any { it.data is ActionData.AnswerCall || it.data is ActionData.EndCall } val hasVolumeKeys = trigger.keys - .mapNotNull { it as? io.github.sds100.keymapper.trigger.KeyCodeTriggerKey } + .mapNotNull { it as? io.github.sds100.keymapper.base.trigger.KeyCodeTriggerKey } .any { it.keyCode == KeyEvent.KEYCODE_VOLUME_DOWN || it.keyCode == KeyEvent.KEYCODE_VOLUME_UP diff --git a/app/src/main/java/io/github/sds100/keymapper/keymaps/KeyMapAppBarState.kt b/base/src/main/java/io/github/sds100/keymapper/base/keymaps/KeyMapAppBarState.kt similarity index 71% rename from app/src/main/java/io/github/sds100/keymapper/keymaps/KeyMapAppBarState.kt rename to base/src/main/java/io/github/sds100/keymapper/base/keymaps/KeyMapAppBarState.kt index 1a7dd98598..d2b56debf0 100644 --- a/app/src/main/java/io/github/sds100/keymapper/keymaps/KeyMapAppBarState.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/keymaps/KeyMapAppBarState.kt @@ -1,10 +1,10 @@ -package io.github.sds100.keymapper.keymaps +package io.github.sds100.keymapper.base.keymaps -import io.github.sds100.keymapper.constraints.ConstraintMode -import io.github.sds100.keymapper.groups.GroupListItemModel -import io.github.sds100.keymapper.home.HomeWarningListItem -import io.github.sds100.keymapper.home.SelectedKeyMapsEnabled -import io.github.sds100.keymapper.util.ui.compose.ComposeChipModel +import io.github.sds100.keymapper.base.constraints.ConstraintMode +import io.github.sds100.keymapper.base.groups.GroupListItemModel +import io.github.sds100.keymapper.base.home.HomeWarningListItem +import io.github.sds100.keymapper.base.home.SelectedKeyMapsEnabled +import io.github.sds100.keymapper.base.utils.ui.compose.ComposeChipModel sealed class KeyMapAppBarState { data class RootGroup( diff --git a/base/src/main/java/io/github/sds100/keymapper/base/keymaps/KeyMapGroup.kt b/base/src/main/java/io/github/sds100/keymapper/base/keymaps/KeyMapGroup.kt new file mode 100644 index 0000000000..8ddf927570 --- /dev/null +++ b/base/src/main/java/io/github/sds100/keymapper/base/keymaps/KeyMapGroup.kt @@ -0,0 +1,11 @@ +package io.github.sds100.keymapper.base.keymaps + +import io.github.sds100.keymapper.base.groups.Group +import io.github.sds100.keymapper.common.utils.State + +data class KeyMapGroup( + val group: Group?, + val subGroups: List, + val parents: List, + val keyMaps: State>, +) diff --git a/app/src/main/java/io/github/sds100/keymapper/keymaps/KeyMapListItemCreator.kt b/base/src/main/java/io/github/sds100/keymapper/base/keymaps/KeyMapListItemCreator.kt similarity index 85% rename from app/src/main/java/io/github/sds100/keymapper/keymaps/KeyMapListItemCreator.kt rename to base/src/main/java/io/github/sds100/keymapper/base/keymaps/KeyMapListItemCreator.kt index 7e99b73df8..bfed5a0afb 100644 --- a/app/src/main/java/io/github/sds100/keymapper/keymaps/KeyMapListItemCreator.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/keymaps/KeyMapListItemCreator.kt @@ -1,31 +1,32 @@ -package io.github.sds100.keymapper.keymaps +package io.github.sds100.keymapper.base.keymaps import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.outlined.ArrowForward import androidx.compose.material.icons.outlined.Add -import io.github.sds100.keymapper.R -import io.github.sds100.keymapper.actions.ActionErrorSnapshot -import io.github.sds100.keymapper.actions.ActionUiHelper -import io.github.sds100.keymapper.constraints.ConstraintErrorSnapshot -import io.github.sds100.keymapper.constraints.ConstraintState -import io.github.sds100.keymapper.constraints.ConstraintUiHelper +import io.github.sds100.keymapper.base.R +import io.github.sds100.keymapper.base.actions.ActionErrorSnapshot +import io.github.sds100.keymapper.base.actions.ActionUiHelper +import io.github.sds100.keymapper.base.constraints.ConstraintErrorSnapshot +import io.github.sds100.keymapper.base.constraints.ConstraintState +import io.github.sds100.keymapper.base.constraints.ConstraintUiHelper +import io.github.sds100.keymapper.base.system.accessibility.FingerprintGestureType +import io.github.sds100.keymapper.base.trigger.AssistantTriggerKey +import io.github.sds100.keymapper.base.trigger.AssistantTriggerType +import io.github.sds100.keymapper.base.trigger.FingerprintTriggerKey +import io.github.sds100.keymapper.base.trigger.FloatingButtonKey +import io.github.sds100.keymapper.base.trigger.KeyEventDetectionSource +import io.github.sds100.keymapper.base.trigger.KeyMapListItemModel +import io.github.sds100.keymapper.base.trigger.Trigger +import io.github.sds100.keymapper.base.trigger.TriggerErrorSnapshot +import io.github.sds100.keymapper.base.trigger.TriggerKeyDevice +import io.github.sds100.keymapper.base.trigger.TriggerMode +import io.github.sds100.keymapper.base.utils.InputEventStrings +import io.github.sds100.keymapper.base.utils.isFixable +import io.github.sds100.keymapper.base.utils.ui.ResourceProvider +import io.github.sds100.keymapper.base.utils.ui.compose.ComposeChipModel +import io.github.sds100.keymapper.base.utils.ui.compose.ComposeIconInfo +import io.github.sds100.keymapper.common.utils.KMError import io.github.sds100.keymapper.system.devices.InputDeviceUtils -import io.github.sds100.keymapper.system.inputevents.InputEventUtils -import io.github.sds100.keymapper.trigger.AssistantTriggerKey -import io.github.sds100.keymapper.trigger.AssistantTriggerType -import io.github.sds100.keymapper.trigger.FingerprintTriggerKey -import io.github.sds100.keymapper.trigger.FloatingButtonKey -import io.github.sds100.keymapper.trigger.KeyEventDetectionSource -import io.github.sds100.keymapper.trigger.KeyMapListItemModel -import io.github.sds100.keymapper.trigger.Trigger -import io.github.sds100.keymapper.trigger.TriggerErrorSnapshot -import io.github.sds100.keymapper.trigger.TriggerKeyDevice -import io.github.sds100.keymapper.trigger.TriggerMode -import io.github.sds100.keymapper.util.Error -import io.github.sds100.keymapper.util.isFixable -import io.github.sds100.keymapper.util.ui.ResourceProvider -import io.github.sds100.keymapper.util.ui.compose.ComposeChipModel -import io.github.sds100.keymapper.util.ui.compose.ComposeIconInfo class KeyMapListItemCreator( private val displayMapping: DisplayKeyMapUseCase, @@ -55,7 +56,7 @@ class KeyMapListItemCreator( val triggerKeys = keyMap.trigger.keys.map { key -> when (key) { is AssistantTriggerKey -> assistantTriggerKeyName(key) - is io.github.sds100.keymapper.trigger.KeyCodeTriggerKey -> keyCodeTriggerKeyName( + is io.github.sds100.keymapper.base.trigger.KeyCodeTriggerKey -> keyCodeTriggerKeyName( key, showDeviceDescriptors, ) @@ -147,7 +148,7 @@ class KeyMapListItemCreator( } val icon: ComposeIconInfo = actionUiHelper.getIcon(action.data) - val error: Error? = errorSnapshot.getError(action.data) + val error: KMError? = errorSnapshot.getError(action.data) val chip = if (error == null) { ComposeChipModel.Normal(id = action.uid, text = chipText, icon = icon) @@ -166,7 +167,7 @@ class KeyMapListItemCreator( for (constraint in constraintState.constraints) { val text: String = constraintUiHelper.getTitle(constraint) val icon: ComposeIconInfo = constraintUiHelper.getIcon(constraint) - val error: Error? = errorSnapshot.getError(constraint) + val error: KMError? = errorSnapshot.getError(constraint) val chip: ComposeChipModel = if (error == null) { ComposeChipModel.Normal( @@ -241,7 +242,7 @@ class KeyMapListItemCreator( } private fun keyCodeTriggerKeyName( - key: io.github.sds100.keymapper.trigger.KeyCodeTriggerKey, + key: io.github.sds100.keymapper.base.trigger.KeyCodeTriggerKey, showDeviceDescriptors: Boolean, ): String = buildString { when (key.clickType) { @@ -250,7 +251,7 @@ class KeyMapListItemCreator( else -> Unit } - append(InputEventUtils.keyCodeToString(key.keyCode)) + append(InputEventStrings.keyCodeToString(key.keyCode)) val deviceName = when (key.device) { is TriggerKeyDevice.Internal -> null diff --git a/app/src/main/java/io/github/sds100/keymapper/keymaps/KeyMapListScreen.kt b/base/src/main/java/io/github/sds100/keymapper/base/keymaps/KeyMapListScreen.kt similarity index 95% rename from app/src/main/java/io/github/sds100/keymapper/keymaps/KeyMapListScreen.kt rename to base/src/main/java/io/github/sds100/keymapper/base/keymaps/KeyMapListScreen.kt index b36da5e53c..c18452592d 100644 --- a/app/src/main/java/io/github/sds100/keymapper/keymaps/KeyMapListScreen.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/keymaps/KeyMapListScreen.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.keymaps +package io.github.sds100.keymapper.base.keymaps import androidx.compose.foundation.combinedClickable import androidx.compose.foundation.layout.Arrangement @@ -53,18 +53,18 @@ import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import com.google.accompanist.drawablepainter.rememberDrawablePainter -import io.github.sds100.keymapper.R -import io.github.sds100.keymapper.compose.KeyMapperTheme -import io.github.sds100.keymapper.constraints.ConstraintMode -import io.github.sds100.keymapper.trigger.KeyMapListItemModel -import io.github.sds100.keymapper.trigger.TriggerError -import io.github.sds100.keymapper.util.Error -import io.github.sds100.keymapper.util.State -import io.github.sds100.keymapper.util.drawable -import io.github.sds100.keymapper.util.ui.compose.CompactChip -import io.github.sds100.keymapper.util.ui.compose.ComposeChipModel -import io.github.sds100.keymapper.util.ui.compose.ComposeIconInfo -import io.github.sds100.keymapper.util.ui.compose.ErrorCompactChip +import io.github.sds100.keymapper.base.R +import io.github.sds100.keymapper.base.compose.KeyMapperTheme +import io.github.sds100.keymapper.base.constraints.ConstraintMode +import io.github.sds100.keymapper.base.trigger.KeyMapListItemModel +import io.github.sds100.keymapper.base.trigger.TriggerError +import io.github.sds100.keymapper.base.utils.ui.compose.CompactChip +import io.github.sds100.keymapper.base.utils.ui.compose.ComposeChipModel +import io.github.sds100.keymapper.base.utils.ui.compose.ComposeIconInfo +import io.github.sds100.keymapper.base.utils.ui.compose.ErrorCompactChip +import io.github.sds100.keymapper.base.utils.ui.drawable +import io.github.sds100.keymapper.common.utils.KMError +import io.github.sds100.keymapper.common.utils.State @Composable fun KeyMapList( @@ -76,7 +76,7 @@ fun KeyMapList( onClickKeyMap: (String) -> Unit = {}, onLongClickKeyMap: (String) -> Unit = {}, onSelectedChange: (String, Boolean) -> Unit = { _, _ -> }, - onFixClick: (Error) -> Unit = {}, + onFixClick: (KMError) -> Unit = {}, onTriggerErrorClick: (TriggerError) -> Unit = {}, bottomListPadding: Dp = 100.dp, ) { @@ -154,7 +154,7 @@ private fun LoadedKeyMapList( onClickKeyMap: (String) -> Unit, onLongClickKeyMap: (String) -> Unit, onSelectedChange: (String, Boolean) -> Unit, - onFixClick: (Error) -> Unit, + onFixClick: (KMError) -> Unit, onTriggerErrorClick: (TriggerError) -> Unit, bottomListPadding: Dp, ) { @@ -210,7 +210,7 @@ private fun KeyMapListItem( onClickKeyMap: () -> Unit, onLongClickKeyMap: () -> Unit, onSelectedChange: (Boolean) -> Unit, - onFixClick: (Error) -> Unit, + onFixClick: (KMError) -> Unit, onTriggerErrorClick: (TriggerError) -> Unit, ) { OutlinedCard( @@ -443,7 +443,7 @@ private fun OptionsDescription( @Composable private fun ActionConstraintChip( model: ComposeChipModel, - onFixClick: (Error) -> Unit, + onFixClick: (KMError) -> Unit, ) { when (model) { is ComposeChipModel.Normal -> { @@ -513,7 +513,7 @@ private fun sampleList(): List { ComposeChipModel.Error( id = "1", text = "Input KEYCODE_0 • Repeat until released", - error = Error.NoCompatibleImeChosen, + error = KMError.NoCompatibleImeChosen, ), ComposeChipModel.Normal( id = "2", @@ -536,7 +536,7 @@ private fun sampleList(): List { ComposeChipModel.Error( id = "1", "Key Mapper is playing media", - error = Error.AppNotFound(""), + error = KMError.AppNotFound(""), ), ), options = listOf("Vibrate"), diff --git a/app/src/main/java/io/github/sds100/keymapper/keymaps/KeyMapListState.kt b/base/src/main/java/io/github/sds100/keymapper/base/keymaps/KeyMapListState.kt similarity index 51% rename from app/src/main/java/io/github/sds100/keymapper/keymaps/KeyMapListState.kt rename to base/src/main/java/io/github/sds100/keymapper/base/keymaps/KeyMapListState.kt index 44f6139227..16189cadba 100644 --- a/app/src/main/java/io/github/sds100/keymapper/keymaps/KeyMapListState.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/keymaps/KeyMapListState.kt @@ -1,7 +1,7 @@ -package io.github.sds100.keymapper.keymaps +package io.github.sds100.keymapper.base.keymaps -import io.github.sds100.keymapper.trigger.KeyMapListItemModel -import io.github.sds100.keymapper.util.State +import io.github.sds100.keymapper.base.trigger.KeyMapListItemModel +import io.github.sds100.keymapper.common.utils.State data class KeyMapListState( val appBarState: KeyMapAppBarState, diff --git a/app/src/main/java/io/github/sds100/keymapper/keymaps/KeyMapListViewModel.kt b/base/src/main/java/io/github/sds100/keymapper/base/keymaps/KeyMapListViewModel.kt similarity index 85% rename from app/src/main/java/io/github/sds100/keymapper/keymaps/KeyMapListViewModel.kt rename to base/src/main/java/io/github/sds100/keymapper/base/keymaps/KeyMapListViewModel.kt index 9ce55cb086..90c49ecea1 100644 --- a/app/src/main/java/io/github/sds100/keymapper/keymaps/KeyMapListViewModel.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/keymaps/KeyMapListViewModel.kt @@ -1,59 +1,57 @@ -package io.github.sds100.keymapper.keymaps +package io.github.sds100.keymapper.base.keymaps import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue -import io.github.sds100.keymapper.R -import io.github.sds100.keymapper.actions.ActionErrorSnapshot -import io.github.sds100.keymapper.backup.BackupRestoreMappingsUseCase -import io.github.sds100.keymapper.backup.ImportExportState -import io.github.sds100.keymapper.backup.RestoreType -import io.github.sds100.keymapper.constraints.ConstraintErrorSnapshot -import io.github.sds100.keymapper.constraints.ConstraintMode -import io.github.sds100.keymapper.constraints.ConstraintUiHelper -import io.github.sds100.keymapper.groups.Group -import io.github.sds100.keymapper.groups.GroupFamily -import io.github.sds100.keymapper.groups.GroupListItemModel -import io.github.sds100.keymapper.home.HomeWarningListItem -import io.github.sds100.keymapper.home.SelectedKeyMapsEnabled -import io.github.sds100.keymapper.home.ShowHomeScreenAlertsUseCase -import io.github.sds100.keymapper.onboarding.OnboardingTapTarget -import io.github.sds100.keymapper.onboarding.OnboardingUseCase -import io.github.sds100.keymapper.sorting.SortKeyMapsUseCase -import io.github.sds100.keymapper.sorting.SortViewModel -import io.github.sds100.keymapper.system.accessibility.ServiceState -import io.github.sds100.keymapper.system.inputmethod.ShowInputMethodPickerUseCase +import io.github.sds100.keymapper.base.R +import io.github.sds100.keymapper.base.actions.ActionErrorSnapshot +import io.github.sds100.keymapper.base.backup.BackupRestoreMappingsUseCase +import io.github.sds100.keymapper.base.backup.ImportExportState +import io.github.sds100.keymapper.base.backup.RestoreType +import io.github.sds100.keymapper.base.constraints.ConstraintErrorSnapshot +import io.github.sds100.keymapper.base.constraints.ConstraintMode +import io.github.sds100.keymapper.base.constraints.ConstraintUiHelper +import io.github.sds100.keymapper.base.groups.Group +import io.github.sds100.keymapper.base.groups.GroupFamily +import io.github.sds100.keymapper.base.groups.GroupListItemModel +import io.github.sds100.keymapper.base.home.HomeWarningListItem +import io.github.sds100.keymapper.base.home.SelectedKeyMapsEnabled +import io.github.sds100.keymapper.base.home.ShowHomeScreenAlertsUseCase +import io.github.sds100.keymapper.base.onboarding.OnboardingTapTarget +import io.github.sds100.keymapper.base.onboarding.OnboardingUseCase +import io.github.sds100.keymapper.base.sorting.SortKeyMapsUseCase +import io.github.sds100.keymapper.base.sorting.SortViewModel +import io.github.sds100.keymapper.base.system.inputmethod.ShowInputMethodPickerUseCase +import io.github.sds100.keymapper.base.trigger.KeyMapListItemModel +import io.github.sds100.keymapper.base.trigger.SetupGuiKeyboardState +import io.github.sds100.keymapper.base.trigger.SetupGuiKeyboardUseCase +import io.github.sds100.keymapper.base.trigger.TriggerError +import io.github.sds100.keymapper.base.trigger.TriggerErrorSnapshot +import io.github.sds100.keymapper.base.utils.getFullMessage +import io.github.sds100.keymapper.base.utils.navigation.NavDestination +import io.github.sds100.keymapper.base.utils.navigation.NavigationProvider +import io.github.sds100.keymapper.base.utils.navigation.navigate +import io.github.sds100.keymapper.base.utils.ui.DialogModel +import io.github.sds100.keymapper.base.utils.ui.DialogProvider +import io.github.sds100.keymapper.base.utils.ui.DialogResponse +import io.github.sds100.keymapper.base.utils.ui.MultiSelectProvider +import io.github.sds100.keymapper.base.utils.ui.ResourceProvider +import io.github.sds100.keymapper.base.utils.ui.SelectionState +import io.github.sds100.keymapper.base.utils.ui.ViewModelHelper +import io.github.sds100.keymapper.base.utils.ui.compose.ComposeIconInfo +import io.github.sds100.keymapper.base.utils.ui.showDialog +import io.github.sds100.keymapper.common.utils.KMError +import io.github.sds100.keymapper.common.utils.KMResult +import io.github.sds100.keymapper.common.utils.State +import io.github.sds100.keymapper.common.utils.Success +import io.github.sds100.keymapper.common.utils.dataOrNull +import io.github.sds100.keymapper.common.utils.ifIsData +import io.github.sds100.keymapper.common.utils.mapData +import io.github.sds100.keymapper.common.utils.onFailure +import io.github.sds100.keymapper.common.utils.onSuccess +import io.github.sds100.keymapper.system.SystemError +import io.github.sds100.keymapper.system.accessibility.AccessibilityServiceState import io.github.sds100.keymapper.system.permissions.Permission -import io.github.sds100.keymapper.trigger.KeyMapListItemModel -import io.github.sds100.keymapper.trigger.SetupGuiKeyboardState -import io.github.sds100.keymapper.trigger.SetupGuiKeyboardUseCase -import io.github.sds100.keymapper.trigger.TriggerError -import io.github.sds100.keymapper.trigger.TriggerErrorSnapshot -import io.github.sds100.keymapper.util.Error -import io.github.sds100.keymapper.util.Result -import io.github.sds100.keymapper.util.State -import io.github.sds100.keymapper.util.Success -import io.github.sds100.keymapper.util.dataOrNull -import io.github.sds100.keymapper.util.getFullMessage -import io.github.sds100.keymapper.util.ifIsData -import io.github.sds100.keymapper.util.mapData -import io.github.sds100.keymapper.util.onFailure -import io.github.sds100.keymapper.util.onSuccess -import io.github.sds100.keymapper.util.ui.DialogResponse -import io.github.sds100.keymapper.util.ui.MultiSelectProvider -import io.github.sds100.keymapper.util.ui.NavDestination -import io.github.sds100.keymapper.util.ui.NavigateEvent -import io.github.sds100.keymapper.util.ui.NavigationViewModel -import io.github.sds100.keymapper.util.ui.NavigationViewModelImpl -import io.github.sds100.keymapper.util.ui.PopupUi -import io.github.sds100.keymapper.util.ui.PopupViewModel -import io.github.sds100.keymapper.util.ui.PopupViewModelImpl -import io.github.sds100.keymapper.util.ui.ResourceProvider -import io.github.sds100.keymapper.util.ui.SelectionState -import io.github.sds100.keymapper.util.ui.ViewModelHelper -import io.github.sds100.keymapper.util.ui.compose.ComposeIconInfo -import io.github.sds100.keymapper.util.ui.navigate -import io.github.sds100.keymapper.util.ui.showPopup import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -86,9 +84,11 @@ class KeyMapListViewModel( private val backupRestore: BackupRestoreMappingsUseCase, private val showInputMethodPickerUseCase: ShowInputMethodPickerUseCase, private val onboarding: OnboardingUseCase, -) : PopupViewModel by PopupViewModelImpl(), + private val navigationProvider: NavigationProvider, + private val dialogProvider: DialogProvider, +) : DialogProvider by dialogProvider, ResourceProvider by resourceProvider, - NavigationViewModel by NavigationViewModelImpl() { + NavigationProvider by navigationProvider { private companion object { const val ID_ACCESSIBILITY_SERVICE_DISABLED_LIST_ITEM = "accessibility_service_disabled" @@ -103,18 +103,23 @@ class KeyMapListViewModel( val multiSelectProvider: MultiSelectProvider = MultiSelectProvider() - private val listItemCreator = KeyMapListItemCreator(listKeyMaps, resourceProvider) + private val listItemCreator = + KeyMapListItemCreator( + listKeyMaps, + resourceProvider, + ) private val constraintUiHelper = ConstraintUiHelper(listKeyMaps, resourceProvider) - private val initialState = KeyMapListState( - appBarState = KeyMapAppBarState.RootGroup( - subGroups = emptyList(), - warnings = emptyList(), - isPaused = false, - ), - listItems = State.Loading, - showCreateKeyMapTapTarget = false, - ) + private val initialState = + KeyMapListState( + appBarState = KeyMapAppBarState.RootGroup( + subGroups = emptyList(), + warnings = emptyList(), + isPaused = false, + ), + listItems = State.Loading, + showCreateKeyMapTapTarget = false, + ) private val _state: MutableStateFlow = MutableStateFlow(initialState) val state = _state.asStateFlow() @@ -163,7 +168,7 @@ class KeyMapListViewModel( buildList { when (serviceState) { - ServiceState.CRASHED -> + AccessibilityServiceState.CRASHED -> add( HomeWarningListItem( ID_ACCESSIBILITY_SERVICE_CRASHED_LIST_ITEM, @@ -171,7 +176,7 @@ class KeyMapListViewModel( ), ) - ServiceState.DISABLED -> + AccessibilityServiceState.DISABLED -> add( HomeWarningListItem( ID_ACCESSIBILITY_SERVICE_DISABLED_LIST_ITEM, @@ -179,7 +184,7 @@ class KeyMapListViewModel( ), ) - ServiceState.ENABLED -> {} + AccessibilityServiceState.ENABLED -> {} } if (isBatteryOptimised) { @@ -341,7 +346,12 @@ class KeyMapListViewModel( } } - _state.value = KeyMapListState(appBarState, listState, showCreateKeyMapTapTarget) + _state.value = + KeyMapListState( + appBarState, + listState, + showCreateKeyMapTapTarget, + ) } } @@ -477,7 +487,7 @@ class KeyMapListViewModel( } } else { coroutineScope.launch { - navigate("config_key_map", NavDestination.ConfigKeyMap.Open(uid)) + navigate("config_key_map", NavDestination.OpenKeyMap(uid)) } } } @@ -485,7 +495,6 @@ class KeyMapListViewModel( fun onKeyMapCardLongClick(uid: String) { if (multiSelectProvider.state.value is SelectionState.NotSelecting) { coroutineScope.launch { - val currentGroupUid = listKeyMaps.keyMapGroup.first().group?.uid multiSelectProvider.startSelecting() multiSelectProvider.select(uid) } @@ -510,7 +519,7 @@ class KeyMapListViewModel( TriggerError.DND_ACCESS_DENIED -> { ViewModelHelper.showDialogExplainingDndAccessBeingUnavailable( resourceProvider = this@KeyMapListViewModel, - popupViewModel = this@KeyMapListViewModel, + dialogProvider = this@KeyMapListViewModel, neverShowDndTriggerErrorAgain = { listKeyMaps.neverShowDndTriggerError() }, fixError = { listKeyMaps.fixTriggerError(error) }, ) @@ -523,7 +532,7 @@ class KeyMapListViewModel( TriggerError.ASSISTANT_TRIGGER_NOT_PURCHASED, TriggerError.FLOATING_BUTTONS_NOT_PURCHASED -> { navigate( "purchase_advanced_trigger", - NavDestination.ConfigKeyMap.New( + NavDestination.NewKeyMap( groupUid = null, showAdvancedTriggers = true, ), @@ -537,13 +546,13 @@ class KeyMapListViewModel( } } - fun onFixClick(error: Error) { + fun onFixClick(error: KMError) { coroutineScope.launch { when (error) { - Error.PermissionDenied(Permission.ACCESS_NOTIFICATION_POLICY) -> { + SystemError.PermissionDenied(Permission.ACCESS_NOTIFICATION_POLICY) -> { ViewModelHelper.showDialogExplainingDndAccessBeingUnavailable( resourceProvider = this@KeyMapListViewModel, - popupViewModel = this@KeyMapListViewModel, + dialogProvider = this@KeyMapListViewModel, neverShowDndTriggerErrorAgain = { listKeyMaps.neverShowDndTriggerError() }, fixError = { listKeyMaps.fixError(error) }, ) @@ -552,7 +561,7 @@ class KeyMapListViewModel( else -> { ViewModelHelper.showFixErrorDialog( resourceProvider = this@KeyMapListViewModel, - popupViewModel = this@KeyMapListViewModel, + dialogProvider = this@KeyMapListViewModel, error, ) { listKeyMaps.fixError(error) @@ -669,7 +678,7 @@ class KeyMapListViewModel( val explanationResponse = ViewModelHelper.showAccessibilityServiceExplanationDialog( resourceProvider = this@KeyMapListViewModel, - popupViewModel = this@KeyMapListViewModel, + dialogProvider = this@KeyMapListViewModel, ) if (explanationResponse != DialogResponse.POSITIVE) { @@ -679,7 +688,7 @@ class KeyMapListViewModel( if (!showAlertsUseCase.startAccessibilityService()) { ViewModelHelper.handleCantFindAccessibilitySettings( resourceProvider = this@KeyMapListViewModel, - popupViewModel = this@KeyMapListViewModel, + dialogProvider = this@KeyMapListViewModel, ) } } @@ -687,7 +696,7 @@ class KeyMapListViewModel( ID_ACCESSIBILITY_SERVICE_CRASHED_LIST_ITEM -> ViewModelHelper.handleKeyMapperCrashedDialog( resourceProvider = this@KeyMapListViewModel, - popupViewModel = this@KeyMapListViewModel, + dialogProvider = this@KeyMapListViewModel, restartService = showAlertsUseCase::restartAccessibilityService, ignoreCrashed = showAlertsUseCase::acknowledgeCrashed, ) @@ -700,7 +709,7 @@ class KeyMapListViewModel( } private suspend fun showNotificationPermissionAlertDialog() { - val dialog = PopupUi.Dialog( + val dialog = DialogModel.Alert( title = getString(R.string.dialog_title_request_notification_permission), message = getText(R.string.dialog_message_request_notification_permission), positiveButtonText = getString(R.string.pos_turn_on), @@ -708,7 +717,7 @@ class KeyMapListViewModel( neutralButtonText = getString(R.string.pos_never_show_again), ) - val dialogResponse = showPopup("notification_permission_alert", dialog) + val dialogResponse = showDialog("notification_permission_alert", dialog) if (dialogResponse == DialogResponse.POSITIVE) { showAlertsUseCase.requestNotificationPermission() @@ -880,10 +889,8 @@ class KeyMapListViewModel( val groupUid = listKeyMaps.keyMapGroup.first().group?.uid navigate( - NavigateEvent( - "config_key_map", - NavDestination.ConfigKeyMap.New(groupUid = groupUid), - ), + "config_new_key_map", + NavDestination.NewKeyMap(groupUid = groupUid), ) } } @@ -892,14 +899,14 @@ class KeyMapListViewModel( showInputMethodPickerUseCase.show(fromForeground = true) } - private suspend fun onAutomaticBackupResult(result: Result<*>) { + private suspend fun onAutomaticBackupResult(result: KMResult<*>) { when (result) { is Success -> {} - is Error -> { - val response = showPopup( + is KMError -> { + val response = showDialog( "automatic_backup_error", - PopupUi.Dialog( + DialogModel.Alert( title = getString(R.string.toast_automatic_backup_failed), message = result.getFullMessage(this), positiveButtonText = getString(R.string.pos_ok), diff --git a/app/src/main/java/io/github/sds100/keymapper/keymaps/KeyMapOptionsScreen.kt b/base/src/main/java/io/github/sds100/keymapper/base/keymaps/KeyMapOptionsScreen.kt similarity index 94% rename from app/src/main/java/io/github/sds100/keymapper/keymaps/KeyMapOptionsScreen.kt rename to base/src/main/java/io/github/sds100/keymapper/base/keymaps/KeyMapOptionsScreen.kt index 87c6a00c5c..e2a06d926d 100644 --- a/app/src/main/java/io/github/sds100/keymapper/keymaps/KeyMapOptionsScreen.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/keymaps/KeyMapOptionsScreen.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.keymaps +package io.github.sds100.keymapper.base.keymaps import android.content.ClipData import androidx.compose.animation.AnimatedVisibility @@ -41,15 +41,15 @@ import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle -import io.github.sds100.keymapper.R -import io.github.sds100.keymapper.compose.KeyMapperTheme -import io.github.sds100.keymapper.util.State -import io.github.sds100.keymapper.util.ui.SliderMaximums -import io.github.sds100.keymapper.util.ui.SliderMinimums -import io.github.sds100.keymapper.util.ui.SliderStepSizes -import io.github.sds100.keymapper.util.ui.compose.CheckBoxText -import io.github.sds100.keymapper.util.ui.compose.SliderOptionText -import io.github.sds100.keymapper.util.ui.compose.openUriSafe +import io.github.sds100.keymapper.base.R +import io.github.sds100.keymapper.base.compose.KeyMapperTheme +import io.github.sds100.keymapper.base.utils.ui.SliderMaximums +import io.github.sds100.keymapper.base.utils.ui.SliderMinimums +import io.github.sds100.keymapper.base.utils.ui.SliderStepSizes +import io.github.sds100.keymapper.base.utils.ui.compose.CheckBoxText +import io.github.sds100.keymapper.base.utils.ui.compose.SliderOptionText +import io.github.sds100.keymapper.base.utils.ui.compose.openUriSafe +import io.github.sds100.keymapper.common.utils.State import kotlinx.coroutines.launch @Composable @@ -276,7 +276,9 @@ private fun TriggerFromOtherAppsSection( horizontalArrangement = Arrangement.SpaceBetween, ) { Text( - modifier = Modifier.padding(horizontal = 16.dp), + modifier = Modifier + .padding(horizontal = 16.dp) + .weight(1f), text = keyMapUid, maxLines = 1, overflow = TextOverflow.Ellipsis, @@ -390,7 +392,7 @@ private fun Preview() { screenOffTrigger = false, triggerFromOtherApps = true, - keyMapUid = "00000-00000-00000", + keyMapUid = "00000-00000-00000-0000000000000000000000000000000000", isLauncherShortcutButtonEnabled = false, showToast = true, diff --git a/app/src/main/java/io/github/sds100/keymapper/keymaps/ListKeyMapsUseCase.kt b/base/src/main/java/io/github/sds100/keymapper/base/keymaps/ListKeyMapsUseCase.kt similarity index 89% rename from app/src/main/java/io/github/sds100/keymapper/keymaps/ListKeyMapsUseCase.kt rename to base/src/main/java/io/github/sds100/keymapper/base/keymaps/ListKeyMapsUseCase.kt index 8fc9f47b8b..d1dc791061 100644 --- a/app/src/main/java/io/github/sds100/keymapper/keymaps/ListKeyMapsUseCase.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/keymaps/ListKeyMapsUseCase.kt @@ -1,27 +1,28 @@ -package io.github.sds100.keymapper.keymaps +package io.github.sds100.keymapper.base.keymaps import android.database.sqlite.SQLiteConstraintException -import io.github.sds100.keymapper.R -import io.github.sds100.keymapper.backup.BackupManager -import io.github.sds100.keymapper.backup.BackupManagerImpl -import io.github.sds100.keymapper.backup.BackupUtils -import io.github.sds100.keymapper.constraints.Constraint -import io.github.sds100.keymapper.constraints.ConstraintEntityMapper -import io.github.sds100.keymapper.constraints.ConstraintMode -import io.github.sds100.keymapper.constraints.ConstraintModeEntityMapper +import io.github.sds100.keymapper.base.R +import io.github.sds100.keymapper.base.backup.BackupManager +import io.github.sds100.keymapper.base.backup.BackupManagerImpl +import io.github.sds100.keymapper.base.backup.BackupUtils +import io.github.sds100.keymapper.base.constraints.Constraint +import io.github.sds100.keymapper.base.constraints.ConstraintEntityMapper +import io.github.sds100.keymapper.base.constraints.ConstraintMode +import io.github.sds100.keymapper.base.constraints.ConstraintModeEntityMapper +import io.github.sds100.keymapper.base.groups.Group +import io.github.sds100.keymapper.base.groups.GroupEntityMapper +import io.github.sds100.keymapper.base.groups.GroupFamily +import io.github.sds100.keymapper.base.utils.ui.ResourceProvider +import io.github.sds100.keymapper.common.utils.KMResult +import io.github.sds100.keymapper.common.utils.State +import io.github.sds100.keymapper.common.utils.Success +import io.github.sds100.keymapper.common.utils.dataOrNull import io.github.sds100.keymapper.data.entities.GroupEntity import io.github.sds100.keymapper.data.repositories.FloatingButtonRepository import io.github.sds100.keymapper.data.repositories.GroupRepository +import io.github.sds100.keymapper.data.repositories.KeyMapRepository import io.github.sds100.keymapper.data.repositories.RepositoryUtils -import io.github.sds100.keymapper.groups.Group -import io.github.sds100.keymapper.groups.GroupEntityMapper -import io.github.sds100.keymapper.groups.GroupFamily import io.github.sds100.keymapper.system.files.FileAdapter -import io.github.sds100.keymapper.util.Result -import io.github.sds100.keymapper.util.State -import io.github.sds100.keymapper.util.Success -import io.github.sds100.keymapper.util.dataOrNull -import io.github.sds100.keymapper.util.ui.ResourceProvider import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.Flow @@ -36,12 +37,10 @@ import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.update import kotlinx.coroutines.withContext import java.util.LinkedList +import javax.inject.Inject -/** - * Created by sds100 on 16/04/2021. - */ @OptIn(ExperimentalCoroutinesApi::class) -class ListKeyMapsUseCaseImpl( +class ListKeyMapsUseCaseImpl @Inject constructor( private val keyMapRepository: KeyMapRepository, private val groupRepository: GroupRepository, private val floatingButtonRepository: FloatingButtonRepository, @@ -231,13 +230,14 @@ class ListKeyMapsUseCaseImpl( override suspend fun popGroup() { val currentGroupUid = keyMapListGroupUid.value ?: return val currentGroup = groupRepository.getGroup(currentGroupUid) + val parentUid = currentGroup?.parentUid // If stuck in a non existent group, or the parent is null then pop to the root. - if (currentGroup?.parentUid == null) { + if (parentUid == null) { setCurrentGroup(null) } else { // Check if the group exists. - val group = groupRepository.getGroup(currentGroup.parentUid) ?: return + val group = groupRepository.getGroup(parentUid) ?: return setCurrentGroup(group.uid) } } @@ -342,7 +342,7 @@ class ListKeyMapsUseCaseImpl( keyMapRepository.duplicate(*uid) } - override suspend fun backupKeyMaps(vararg uid: String): Result { + override suspend fun backupKeyMaps(vararg uid: String): KMResult { val fileName = BackupUtils.createBackupFileName() // Share in private files so the share sheet can show the file name. This is some quirk @@ -380,5 +380,5 @@ interface ListKeyMapsUseCase : DisplayKeyMapUseCase { fun enableKeyMap(vararg uid: String) fun disableKeyMap(vararg uid: String) fun duplicateKeyMap(vararg uid: String) - suspend fun backupKeyMaps(vararg uid: String): Result + suspend fun backupKeyMaps(vararg uid: String): KMResult } diff --git a/app/src/main/java/io/github/sds100/keymapper/keymaps/PauseKeyMapsUseCase.kt b/base/src/main/java/io/github/sds100/keymapper/base/keymaps/PauseKeyMapsUseCase.kt similarity index 86% rename from app/src/main/java/io/github/sds100/keymapper/keymaps/PauseKeyMapsUseCase.kt rename to base/src/main/java/io/github/sds100/keymapper/base/keymaps/PauseKeyMapsUseCase.kt index b5acf2b422..dd05855e78 100644 --- a/app/src/main/java/io/github/sds100/keymapper/keymaps/PauseKeyMapsUseCase.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/keymaps/PauseKeyMapsUseCase.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.keymaps +package io.github.sds100.keymapper.base.keymaps import io.github.sds100.keymapper.data.Keys import io.github.sds100.keymapper.data.repositories.PreferenceRepository @@ -7,12 +7,11 @@ import io.github.sds100.keymapper.system.ringtones.RingtoneAdapter import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.map import timber.log.Timber +import javax.inject.Inject +import javax.inject.Singleton -/** - * Created by sds100 on 16/04/2021. - */ - -class PauseKeyMapsUseCaseImpl( +@Singleton +class PauseKeyMapsUseCaseImpl @Inject constructor( private val preferenceRepository: PreferenceRepository, private val mediaAdapter: MediaAdapter, private val ringtoneAdapter: RingtoneAdapter, diff --git a/base/src/main/java/io/github/sds100/keymapper/base/keymaps/ShortcutModel.kt b/base/src/main/java/io/github/sds100/keymapper/base/keymaps/ShortcutModel.kt new file mode 100644 index 0000000000..3d964bcf9a --- /dev/null +++ b/base/src/main/java/io/github/sds100/keymapper/base/keymaps/ShortcutModel.kt @@ -0,0 +1,9 @@ +package io.github.sds100.keymapper.base.keymaps + +import io.github.sds100.keymapper.base.utils.ui.compose.ComposeIconInfo + +data class ShortcutModel( + val icon: ComposeIconInfo, + val text: String, + val data: T, +) diff --git a/app/src/main/java/io/github/sds100/keymapper/keymaps/ShortcutRow.kt b/base/src/main/java/io/github/sds100/keymapper/base/keymaps/ShortcutRow.kt similarity index 93% rename from app/src/main/java/io/github/sds100/keymapper/keymaps/ShortcutRow.kt rename to base/src/main/java/io/github/sds100/keymapper/base/keymaps/ShortcutRow.kt index 6653732dcd..256a1781f8 100644 --- a/app/src/main/java/io/github/sds100/keymapper/keymaps/ShortcutRow.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/keymaps/ShortcutRow.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.keymaps +package io.github.sds100.keymapper.base.keymaps import androidx.compose.foundation.BorderStroke import androidx.compose.foundation.layout.Arrangement @@ -24,11 +24,11 @@ import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import com.google.accompanist.drawablepainter.rememberDrawablePainter -import io.github.sds100.keymapper.R -import io.github.sds100.keymapper.compose.KeyMapperTheme -import io.github.sds100.keymapper.trigger.TriggerKeyShortcut -import io.github.sds100.keymapper.util.drawable -import io.github.sds100.keymapper.util.ui.compose.ComposeIconInfo +import io.github.sds100.keymapper.base.R +import io.github.sds100.keymapper.base.compose.KeyMapperTheme +import io.github.sds100.keymapper.base.trigger.TriggerKeyShortcut +import io.github.sds100.keymapper.base.utils.ui.compose.ComposeIconInfo +import io.github.sds100.keymapper.base.utils.ui.drawable @Composable fun ShortcutRow( diff --git a/app/src/main/java/io/github/sds100/keymapper/keymaps/SimpleMappingController.kt b/base/src/main/java/io/github/sds100/keymapper/base/keymaps/SimpleMappingController.kt similarity index 92% rename from app/src/main/java/io/github/sds100/keymapper/keymaps/SimpleMappingController.kt rename to base/src/main/java/io/github/sds100/keymapper/base/keymaps/SimpleMappingController.kt index 7ea2439531..d014eb0196 100644 --- a/app/src/main/java/io/github/sds100/keymapper/keymaps/SimpleMappingController.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/keymaps/SimpleMappingController.kt @@ -1,13 +1,13 @@ -package io.github.sds100.keymapper.keymaps - -import io.github.sds100.keymapper.actions.Action -import io.github.sds100.keymapper.actions.PerformActionsUseCase -import io.github.sds100.keymapper.actions.RepeatMode -import io.github.sds100.keymapper.constraints.DetectConstraintsUseCase -import io.github.sds100.keymapper.constraints.isSatisfied +package io.github.sds100.keymapper.base.keymaps + +import io.github.sds100.keymapper.base.actions.Action +import io.github.sds100.keymapper.base.actions.PerformActionsUseCase +import io.github.sds100.keymapper.base.actions.RepeatMode +import io.github.sds100.keymapper.base.constraints.DetectConstraintsUseCase +import io.github.sds100.keymapper.base.constraints.isSatisfied +import io.github.sds100.keymapper.base.keymaps.detection.DetectKeyMapsUseCase +import io.github.sds100.keymapper.common.utils.InputEventType import io.github.sds100.keymapper.data.PreferenceDefaults -import io.github.sds100.keymapper.keymaps.detection.DetectKeyMapsUseCase -import io.github.sds100.keymapper.util.InputEventType import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineStart import kotlinx.coroutines.Job diff --git a/base/src/main/java/io/github/sds100/keymapper/base/keymaps/TriggerKeyMapEvent.kt b/base/src/main/java/io/github/sds100/keymapper/base/keymaps/TriggerKeyMapEvent.kt new file mode 100644 index 0000000000..14abba054c --- /dev/null +++ b/base/src/main/java/io/github/sds100/keymapper/base/keymaps/TriggerKeyMapEvent.kt @@ -0,0 +1,7 @@ +package io.github.sds100.keymapper.base.keymaps + +import io.github.sds100.keymapper.system.accessibility.AccessibilityServiceEvent +import kotlinx.serialization.Serializable + +@Serializable +data class TriggerKeyMapEvent(val uid: String) : AccessibilityServiceEvent() diff --git a/base/src/main/java/io/github/sds100/keymapper/base/keymaps/detection/DetectKeyMapModel.kt b/base/src/main/java/io/github/sds100/keymapper/base/keymaps/detection/DetectKeyMapModel.kt new file mode 100644 index 0000000000..127f2021dd --- /dev/null +++ b/base/src/main/java/io/github/sds100/keymapper/base/keymaps/detection/DetectKeyMapModel.kt @@ -0,0 +1,9 @@ +package io.github.sds100.keymapper.base.keymaps.detection + +import io.github.sds100.keymapper.base.constraints.ConstraintState +import io.github.sds100.keymapper.base.keymaps.KeyMap + +data class DetectKeyMapModel( + val keyMap: KeyMap, + val groupConstraintStates: List = emptyList(), +) diff --git a/app/src/main/java/io/github/sds100/keymapper/keymaps/detection/DetectKeyMapsUseCase.kt b/base/src/main/java/io/github/sds100/keymapper/base/keymaps/detection/DetectKeyMapsUseCase.kt similarity index 83% rename from app/src/main/java/io/github/sds100/keymapper/keymaps/detection/DetectKeyMapsUseCase.kt rename to base/src/main/java/io/github/sds100/keymapper/base/keymaps/detection/DetectKeyMapsUseCase.kt index 83d7d6b6ef..fb3fc72e1f 100644 --- a/app/src/main/java/io/github/sds100/keymapper/keymaps/detection/DetectKeyMapsUseCase.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/keymaps/detection/DetectKeyMapsUseCase.kt @@ -1,38 +1,41 @@ -package io.github.sds100.keymapper.keymaps.detection +package io.github.sds100.keymapper.base.keymaps.detection import android.accessibilityservice.AccessibilityService import android.os.SystemClock import android.view.InputDevice import android.view.KeyEvent -import io.github.sds100.keymapper.R -import io.github.sds100.keymapper.constraints.ConstraintState +import dagger.assisted.Assisted +import dagger.assisted.AssistedFactory +import dagger.assisted.AssistedInject +import io.github.sds100.keymapper.base.R +import io.github.sds100.keymapper.base.constraints.ConstraintState +import io.github.sds100.keymapper.base.groups.Group +import io.github.sds100.keymapper.base.groups.GroupEntityMapper +import io.github.sds100.keymapper.base.keymaps.KeyMap +import io.github.sds100.keymapper.base.keymaps.KeyMapEntityMapper +import io.github.sds100.keymapper.base.system.accessibility.IAccessibilityService +import io.github.sds100.keymapper.base.system.inputmethod.ImeInputEventInjector +import io.github.sds100.keymapper.base.system.navigation.OpenMenuHelper +import io.github.sds100.keymapper.base.trigger.FingerprintTriggerKey +import io.github.sds100.keymapper.base.utils.ui.ResourceProvider +import io.github.sds100.keymapper.common.utils.InputEventType +import io.github.sds100.keymapper.common.utils.State +import io.github.sds100.keymapper.common.utils.dataOrNull import io.github.sds100.keymapper.data.Keys import io.github.sds100.keymapper.data.PreferenceDefaults import io.github.sds100.keymapper.data.repositories.FloatingButtonRepository import io.github.sds100.keymapper.data.repositories.GroupRepository +import io.github.sds100.keymapper.data.repositories.KeyMapRepository import io.github.sds100.keymapper.data.repositories.PreferenceRepository -import io.github.sds100.keymapper.groups.Group -import io.github.sds100.keymapper.groups.GroupEntityMapper -import io.github.sds100.keymapper.keymaps.KeyMap -import io.github.sds100.keymapper.keymaps.KeyMapEntityMapper -import io.github.sds100.keymapper.keymaps.KeyMapRepository -import io.github.sds100.keymapper.system.accessibility.IAccessibilityService import io.github.sds100.keymapper.system.display.DisplayAdapter -import io.github.sds100.keymapper.system.inputevents.InputEventInjector -import io.github.sds100.keymapper.system.inputmethod.ImeInputEventInjector import io.github.sds100.keymapper.system.inputmethod.InputKeyModel -import io.github.sds100.keymapper.system.navigation.OpenMenuHelper import io.github.sds100.keymapper.system.permissions.Permission import io.github.sds100.keymapper.system.permissions.PermissionAdapter -import io.github.sds100.keymapper.system.popup.PopupMessageAdapter +import io.github.sds100.keymapper.system.popup.ToastAdapter import io.github.sds100.keymapper.system.root.SuAdapter +import io.github.sds100.keymapper.system.shizuku.ShizukuInputEventInjector import io.github.sds100.keymapper.system.vibrator.VibratorAdapter import io.github.sds100.keymapper.system.volume.VolumeAdapter -import io.github.sds100.keymapper.trigger.FingerprintTriggerKey -import io.github.sds100.keymapper.util.InputEventType -import io.github.sds100.keymapper.util.State -import io.github.sds100.keymapper.util.dataOrNull -import io.github.sds100.keymapper.util.ui.ResourceProvider import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.Flow @@ -43,11 +46,11 @@ import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking import timber.log.Timber -/** - * Created by sds100 on 17/04/2021. - */ - -class DetectKeyMapsUseCaseImpl( +class DetectKeyMapsUseCaseImpl @AssistedInject constructor( + @Assisted + private val imeInputEventInjector: ImeInputEventInjector, + @Assisted + private val accessibilityService: IAccessibilityService, private val keyMapRepository: KeyMapRepository, private val floatingButtonRepository: FloatingButtonRepository, private val groupRepository: GroupRepository, @@ -55,16 +58,23 @@ class DetectKeyMapsUseCaseImpl( private val suAdapter: SuAdapter, private val displayAdapter: DisplayAdapter, private val volumeAdapter: VolumeAdapter, - private val imeInputEventInjector: ImeInputEventInjector, - private val accessibilityService: IAccessibilityService, - private val shizukuInputEventInjector: InputEventInjector, - private val popupMessageAdapter: PopupMessageAdapter, + private val toastAdapter: ToastAdapter, private val permissionAdapter: PermissionAdapter, private val resourceProvider: ResourceProvider, private val vibrator: VibratorAdapter, + @Assisted private val coroutineScope: CoroutineScope, ) : DetectKeyMapsUseCase { + @AssistedFactory + interface Factory { + fun create( + accessibilityService: IAccessibilityService, + coroutineScope: CoroutineScope, + imeInputEventInjector: ImeInputEventInjector, + ): DetectKeyMapsUseCaseImpl + } + companion object { fun processKeyMapsAndGroups( keyMaps: List, @@ -164,6 +174,8 @@ class DetectKeyMapsUseCaseImpl( override val currentTime: Long get() = SystemClock.elapsedRealtime() + private val shizukuInputEventInjector = ShizukuInputEventInjector() + private val openMenuHelper = OpenMenuHelper( suAdapter, accessibilityService, @@ -181,7 +193,7 @@ class DetectKeyMapsUseCaseImpl( .map { it.toLong() } override fun showTriggeredToast() { - popupMessageAdapter.showPopupMessage(resourceProvider.getString(R.string.toast_triggered_keymap)) + toastAdapter.show(resourceProvider.getString(R.string.toast_triggered_keymap)) } override fun vibrate(duration: Long) { diff --git a/app/src/main/java/io/github/sds100/keymapper/keymaps/detection/DetectScreenOffKeyEventsController.kt b/base/src/main/java/io/github/sds100/keymapper/base/keymaps/detection/DetectScreenOffKeyEventsController.kt similarity index 96% rename from app/src/main/java/io/github/sds100/keymapper/keymaps/detection/DetectScreenOffKeyEventsController.kt rename to base/src/main/java/io/github/sds100/keymapper/base/keymaps/detection/DetectScreenOffKeyEventsController.kt index a492fe2ec7..bd56ca6ef0 100644 --- a/app/src/main/java/io/github/sds100/keymapper/keymaps/detection/DetectScreenOffKeyEventsController.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/keymaps/detection/DetectScreenOffKeyEventsController.kt @@ -1,14 +1,14 @@ -package io.github.sds100.keymapper.keymaps.detection +package io.github.sds100.keymapper.base.keymaps.detection import android.view.InputDevice import android.view.KeyEvent +import io.github.sds100.keymapper.common.utils.State +import io.github.sds100.keymapper.common.utils.valueOrNull import io.github.sds100.keymapper.system.devices.DevicesAdapter import io.github.sds100.keymapper.system.devices.InputDeviceInfo import io.github.sds100.keymapper.system.inputevents.InputEventUtils import io.github.sds100.keymapper.system.inputevents.MyKeyEvent import io.github.sds100.keymapper.system.root.SuAdapter -import io.github.sds100.keymapper.util.State -import io.github.sds100.keymapper.util.valueOrNull import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job @@ -17,9 +17,6 @@ import kotlinx.coroutines.isActive import kotlinx.coroutines.launch import timber.log.Timber -/** - * Created by sds100 on 21/06/2020. - */ class DetectScreenOffKeyEventsController( private val suAdapter: SuAdapter, private val devicesAdapter: DevicesAdapter, diff --git a/app/src/main/java/io/github/sds100/keymapper/keymaps/detection/DpadMotionEventTracker.kt b/base/src/main/java/io/github/sds100/keymapper/base/keymaps/detection/DpadMotionEventTracker.kt similarity index 96% rename from app/src/main/java/io/github/sds100/keymapper/keymaps/detection/DpadMotionEventTracker.kt rename to base/src/main/java/io/github/sds100/keymapper/base/keymaps/detection/DpadMotionEventTracker.kt index adc5cc98a3..0da1229d11 100644 --- a/app/src/main/java/io/github/sds100/keymapper/keymaps/detection/DpadMotionEventTracker.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/keymaps/detection/DpadMotionEventTracker.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.keymaps.detection +package io.github.sds100.keymapper.base.keymaps.detection import android.view.InputDevice import android.view.KeyEvent @@ -33,7 +33,7 @@ class DpadMotionEventTracker { * @return whether to consume the key event. */ fun onKeyEvent(event: MyKeyEvent): Boolean { - event.device ?: return false + val device = event.device ?: return false if (!InputEventUtils.isDpadKeyCode(event.keyCode)) { return false @@ -47,7 +47,7 @@ class DpadMotionEventTracker { else -> return false } - val dpadState = dpadState[event.device.descriptor] ?: return false + val dpadState = dpadState[device.descriptor] ?: return false if (dpadState == 0) { return false diff --git a/app/src/free/java/io/github/sds100/keymapper/keymaps/detection/KeyMapController.kt b/base/src/main/java/io/github/sds100/keymapper/base/keymaps/detection/KeyMapController.kt similarity index 90% rename from app/src/free/java/io/github/sds100/keymapper/keymaps/detection/KeyMapController.kt rename to base/src/main/java/io/github/sds100/keymapper/base/keymaps/detection/KeyMapController.kt index 5857156523..cc4f4ad3d1 100644 --- a/app/src/free/java/io/github/sds100/keymapper/keymaps/detection/KeyMapController.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/keymaps/detection/KeyMapController.kt @@ -1,33 +1,38 @@ -package io.github.sds100.keymapper.keymaps.detection +package io.github.sds100.keymapper.base.keymaps.detection import android.view.KeyEvent import androidx.collection.SparseArrayCompat import androidx.collection.keyIterator import androidx.collection.valueIterator -import io.github.sds100.keymapper.actions.Action -import io.github.sds100.keymapper.actions.ActionData -import io.github.sds100.keymapper.actions.PerformActionsUseCase -import io.github.sds100.keymapper.constraints.ConstraintSnapshot -import io.github.sds100.keymapper.constraints.ConstraintState -import io.github.sds100.keymapper.constraints.DetectConstraintsUseCase -import io.github.sds100.keymapper.constraints.isSatisfied +import io.github.sds100.keymapper.base.actions.Action +import io.github.sds100.keymapper.base.actions.ActionData +import io.github.sds100.keymapper.base.actions.PerformActionsUseCase +import io.github.sds100.keymapper.base.constraints.ConstraintSnapshot +import io.github.sds100.keymapper.base.constraints.ConstraintState +import io.github.sds100.keymapper.base.constraints.DetectConstraintsUseCase +import io.github.sds100.keymapper.base.constraints.isSatisfied +import io.github.sds100.keymapper.base.keymaps.ClickType +import io.github.sds100.keymapper.base.system.accessibility.FingerprintGestureType +import io.github.sds100.keymapper.base.trigger.AssistantTriggerKey +import io.github.sds100.keymapper.base.trigger.AssistantTriggerType +import io.github.sds100.keymapper.base.trigger.FingerprintTriggerKey +import io.github.sds100.keymapper.base.trigger.FloatingButtonKey +import io.github.sds100.keymapper.base.trigger.KeyCodeTriggerKey +import io.github.sds100.keymapper.base.trigger.KeyEventDetectionSource +import io.github.sds100.keymapper.base.trigger.Trigger +import io.github.sds100.keymapper.base.trigger.TriggerKey +import io.github.sds100.keymapper.base.trigger.TriggerKeyDevice +import io.github.sds100.keymapper.base.trigger.TriggerMode +import io.github.sds100.keymapper.common.utils.InputEventType +import io.github.sds100.keymapper.common.utils.KMError +import io.github.sds100.keymapper.common.utils.KMResult +import io.github.sds100.keymapper.common.utils.minusFlag +import io.github.sds100.keymapper.common.utils.withFlag import io.github.sds100.keymapper.data.PreferenceDefaults import io.github.sds100.keymapper.data.entities.ActionEntity -import io.github.sds100.keymapper.keymaps.ClickType -import io.github.sds100.keymapper.keymaps.FingerprintGestureType import io.github.sds100.keymapper.system.inputevents.InputEventUtils import io.github.sds100.keymapper.system.inputevents.MyKeyEvent import io.github.sds100.keymapper.system.inputevents.MyMotionEvent -import io.github.sds100.keymapper.trigger.FingerprintTriggerKey -import io.github.sds100.keymapper.trigger.KeyCodeTriggerKey -import io.github.sds100.keymapper.trigger.KeyEventDetectionSource -import io.github.sds100.keymapper.trigger.Trigger -import io.github.sds100.keymapper.trigger.TriggerKey -import io.github.sds100.keymapper.trigger.TriggerKeyDevice -import io.github.sds100.keymapper.trigger.TriggerMode -import io.github.sds100.keymapper.util.Error -import io.github.sds100.keymapper.util.InputEventType -import io.github.sds100.keymapper.util.Result import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Job import kotlinx.coroutines.delay @@ -36,12 +41,6 @@ import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch -import splitties.bitflags.minusFlag -import splitties.bitflags.withFlag - -/** - * Created by sds100 on 05/05/2020. - */ class KeyMapController( private val coroutineScope: CoroutineScope, @@ -69,9 +68,6 @@ class KeyMapController( trigger.mode is TriggerMode.Parallel } - /** - * A cached copy of the keymaps in the database - */ private fun loadKeyMaps(value: List) { actionMap.clear() @@ -119,47 +115,45 @@ class KeyMapController( for ((triggerIndex, model) in validKeyMaps.withIndex()) { val keyMap = model.keyMap // TRIGGER STUFF - keyMap.trigger.keys - .filter { it is KeyCodeTriggerKey || it is FingerprintTriggerKey } - .forEachIndexed { keyIndex, key -> - if (key is KeyCodeTriggerKey && key.detectionSource == KeyEventDetectionSource.INPUT_METHOD && key.consumeEvent) { - triggerKeysThatSendRepeatedKeyEvents.add(key) - } - - if (keyMap.trigger.mode == TriggerMode.Sequence && - key.clickType == ClickType.LONG_PRESS && - key is KeyCodeTriggerKey - ) { - if (keyMap.trigger.keys.size > 1) { - longPressSequenceTriggerKeys.add(key) - } - } + keyMap.trigger.keys.forEachIndexed { keyIndex, key -> + if (key is KeyCodeTriggerKey && key.detectionSource == KeyEventDetectionSource.INPUT_METHOD && key.consumeEvent) { + triggerKeysThatSendRepeatedKeyEvents.add(key) + } - if (keyMap.trigger.mode !is TriggerMode.Parallel && - key.clickType == ClickType.DOUBLE_PRESS - ) { - doublePressKeys.add(TriggerKeyLocation(triggerIndex, keyIndex)) + if (keyMap.trigger.mode == TriggerMode.Sequence && + key.clickType == ClickType.LONG_PRESS && + key is KeyCodeTriggerKey + ) { + if (keyMap.trigger.keys.size > 1) { + longPressSequenceTriggerKeys.add(key) } + } - when (key) { - is KeyCodeTriggerKey -> when (key.device) { - TriggerKeyDevice.Internal -> { - detectInternalEvents = true - } + if (keyMap.trigger.mode !is TriggerMode.Parallel && + key.clickType == ClickType.DOUBLE_PRESS + ) { + doublePressKeys.add(TriggerKeyLocation(triggerIndex, keyIndex)) + } - TriggerKeyDevice.Any -> { - detectInternalEvents = true - detectExternalEvents = true - } + when (key) { + is KeyCodeTriggerKey -> when (key.device) { + TriggerKeyDevice.Internal -> { + detectInternalEvents = true + } - is TriggerKeyDevice.External -> { - detectExternalEvents = true - } + TriggerKeyDevice.Any -> { + detectInternalEvents = true + detectExternalEvents = true } - else -> {} + is TriggerKeyDevice.External -> { + detectExternalEvents = true + } } + + else -> {} } + } val encodedActionList = encodeActionList(keyMap.actionList) @@ -648,6 +642,7 @@ class KeyMapController( deviceId = device.id, scanCode = keyEvent.scanCode, repeatCount = keyEvent.repeatCount, + source = keyEvent.source, ) } else { KeyCodeEvent( @@ -657,6 +652,7 @@ class KeyMapController( deviceId = device?.id ?: 0, scanCode = keyEvent.scanCode, repeatCount = keyEvent.repeatCount, + source = keyEvent.source, ) } @@ -726,11 +722,21 @@ class KeyMapController( // consume the event if the trigger contains this keycode. for (key in triggerKeys) { when { + key is AssistantTriggerKey && event is AssistantEvent -> + if (key.consumeEvent) { + consumeEvent = true + } + key is FingerprintTriggerKey && event is FingerprintGestureEvent -> if (key.consumeEvent) { consumeEvent = true } + key is FloatingButtonKey && event is FloatingButtonEvent -> + if (key.consumeEvent) { + consumeEvent = true + } + key is KeyCodeTriggerKey && event is KeyCodeEvent -> if (key.keyCode == event.keyCode && key.consumeEvent) { consumeEvent = true @@ -773,7 +779,7 @@ class KeyMapController( /* cache whether an action can be performed to avoid repeatedly checking when multiple triggers have the same action */ - val canActionBePerformed = SparseArrayCompat>() + val canActionBePerformed = SparseArrayCompat>() /* loop through triggers in a different loop first to increment the last matched index. @@ -804,7 +810,7 @@ class KeyMapController( canActionBePerformed.put(actionKey, result) continue@triggerLoop } - } else if (canActionBePerformed[actionKey] is Error) { + } else if (canActionBePerformed[actionKey] is KMError) { continue@triggerLoop } } @@ -942,15 +948,21 @@ class KeyMapController( keyCodesToImitateUpAction.add(event.keyCode) useCase.imitateButtonPress( - event.keyCode, - metaStateFromKeyEvent.withFlag(metaStateFromActions), - event.deviceId, - InputEventType.DOWN, - event.scanCode, + keyCode = event.keyCode, + metaState = metaStateFromKeyEvent.withFlag(metaStateFromActions), + deviceId = event.deviceId, + inputEventType = InputEventType.DOWN, + scanCode = event.scanCode, + source = event.source, ) coroutineScope.launch { - repeatImitatingKey(event.keyCode, event.deviceId, event.scanCode) + repeatImitatingKey( + keyCode = event.keyCode, + deviceId = event.deviceId, + scanCode = event.scanCode, + source = event.source, + ) } } @@ -1096,9 +1108,9 @@ class KeyMapController( triggers[eventLocation.triggerIndex].keys[eventLocation.keyIndex] val triggerIndex = eventLocation.triggerIndex - val constraintStates = triggerConstraints[triggerIndex] + val constraintState = triggerConstraints[triggerIndex] - if (!constraintSnapshot.isSatisfied(*constraintStates)) continue + if (!constraintSnapshot.isSatisfied(*constraintState)) continue if (lastMatchedEventIndices[triggerIndex] != eventLocation.keyIndex - 1) continue @@ -1146,10 +1158,10 @@ class KeyMapController( triggerLoop@ for (triggerIndex in sequenceTriggers) { val trigger = triggers[triggerIndex] - val constraintStates = triggerConstraints[triggerIndex] + val constraintState = triggerConstraints[triggerIndex] val lastMatchedEventIndex = lastMatchedEventIndices[triggerIndex] - if (!constraintSnapshot.isSatisfied(*constraintStates)) continue + if (!constraintSnapshot.isSatisfied(*constraintState)) continue // the index of the next event to match in the trigger val nextIndex = lastMatchedEventIndex + 1 @@ -1428,6 +1440,7 @@ class KeyMapController( event.keyCode, inputEventType = InputEventType.DOWN_UP, scanCode = event.scanCode, + source = event.source, ) } } @@ -1447,11 +1460,12 @@ class KeyMapController( } useCase.imitateButtonPress( - event.keyCode, - metaStateFromKeyEvent.withFlag(metaStateFromActions), - event.deviceId, - keyEventAction, - event.scanCode, + keyCode = event.keyCode, + metaState = metaStateFromKeyEvent.withFlag(metaStateFromActions), + deviceId = event.deviceId, + inputEventType = keyEventAction, + scanCode = event.scanCode, + source = event.source, ) keyCodesToImitateUpAction.remove(event.keyCode) @@ -1460,12 +1474,28 @@ class KeyMapController( return consumeEvent } + fun onAssistantEvent(type: AssistantTriggerType) { + val event = AssistantEvent(type, clickType = null) + onKeyDown(event) + onKeyUp(event) + } + fun onFingerprintGesture(type: FingerprintGestureType) { val event = FingerprintGestureEvent(type, clickType = null) onKeyDown(event) onKeyUp(event) } + fun onFloatingButtonDown(buttonUid: String) { + val event = FloatingButtonEvent(buttonUid, clickType = null) + onKeyDown(event) + } + + fun onFloatingButtonUp(buttonUid: String) { + val event = FloatingButtonEvent(buttonUid, clickType = null) + onKeyUp(event) + } + fun reset() { lastMatchedEventIndices = IntArray(triggers.size) { -1 } @@ -1523,10 +1553,6 @@ class KeyMapController( performActionsOnFailedDoublePress.clear() - if (showToast) { - useCase.showTriggeredToast() - } - detectedTriggerIndexes.forEach { triggerIndex -> parallelTriggerActionPerformers[triggerIndex]?.onTriggered( calledOnTriggerRelease = true, @@ -1566,16 +1592,22 @@ class KeyMapController( throw Exception("Action $action not in the action map!") } - private suspend fun repeatImitatingKey(keyCode: Int, deviceId: Int, scanCode: Int) { + private suspend fun repeatImitatingKey( + keyCode: Int, + deviceId: Int, + scanCode: Int, + source: Int, + ) { delay(400) while (keyCodesToImitateUpAction.contains(keyCode)) { useCase.imitateButtonPress( - keyCode, - metaStateFromKeyEvent.withFlag(metaStateFromActions), - deviceId, - InputEventType.DOWN, - scanCode, + keyCode = keyCode, + metaState = metaStateFromKeyEvent.withFlag(metaStateFromActions), + deviceId = deviceId, + inputEventType = InputEventType.DOWN, + scanCode = scanCode, + source = source, ) // use down action because this is what Android does delay(50) @@ -1660,8 +1692,16 @@ class KeyMapController( event.descriptor == null && this.clickType == event.clickType } + } else if (this is AssistantTriggerKey && event is AssistantEvent) { + return if (this.type == AssistantTriggerType.ANY || event.type == AssistantTriggerType.ANY) { + this.clickType == event.clickType + } else { + this.type == event.type && this.clickType == event.clickType + } } else if (this is FingerprintTriggerKey && event is FingerprintGestureEvent) { return this.type == event.type && this.clickType == event.clickType + } else if (this is FloatingButtonKey && event is FloatingButtonEvent) { + return this.buttonUid == event.buttonUid && this.clickType == event.clickType } else { return false } @@ -1684,6 +1724,10 @@ class KeyMapController( otherKey.device == TriggerKeyDevice.Internal && this.clickType == otherKey.clickType } + } else if (this is AssistantTriggerKey && otherKey is AssistantTriggerKey) { + return this.type == otherKey.type && this.clickType == otherKey.clickType + } else if (this is FloatingButtonKey && otherKey is FloatingButtonKey) { + return this.buttonUid == otherKey.buttonUid && this.clickType == otherKey.clickType } else if (this is FingerprintTriggerKey && otherKey is FingerprintTriggerKey) { return this.type == otherKey.type && this.clickType == otherKey.clickType } else { @@ -1747,6 +1791,8 @@ class KeyMapController( fun setClickType(clickType: ClickType?): Event = when (this) { is KeyCodeEvent -> this.copy(clickType = clickType) + is AssistantEvent -> this.copy(clickType = clickType) + is FloatingButtonEvent -> this.copy(clickType = clickType) is FingerprintGestureEvent -> this.copy(clickType = clickType) } } @@ -1761,6 +1807,12 @@ class KeyMapController( val deviceId: Int, val scanCode: Int, val repeatCount: Int, + val source: Int, + ) : Event() + + private data class AssistantEvent( + val type: AssistantTriggerType, + override val clickType: ClickType?, ) : Event() private data class FingerprintGestureEvent( @@ -1768,5 +1820,10 @@ class KeyMapController( override val clickType: ClickType?, ) : Event() + private data class FloatingButtonEvent( + val buttonUid: String, + override val clickType: ClickType?, + ) : Event() + private data class TriggerKeyLocation(val triggerIndex: Int, val keyIndex: Int) } diff --git a/base/src/main/java/io/github/sds100/keymapper/base/keymaps/detection/KeyPressedCallback.kt b/base/src/main/java/io/github/sds100/keymapper/base/keymaps/detection/KeyPressedCallback.kt new file mode 100644 index 0000000000..cada80083c --- /dev/null +++ b/base/src/main/java/io/github/sds100/keymapper/base/keymaps/detection/KeyPressedCallback.kt @@ -0,0 +1,6 @@ +package io.github.sds100.keymapper.base.keymaps.detection + +interface KeyPressedCallback { + fun onDownEvent(button: T) + fun onUpEvent(button: T) +} diff --git a/app/src/main/java/io/github/sds100/keymapper/keymaps/detection/ParallelTriggerActionPerformer.kt b/base/src/main/java/io/github/sds100/keymapper/base/keymaps/detection/ParallelTriggerActionPerformer.kt similarity index 94% rename from app/src/main/java/io/github/sds100/keymapper/keymaps/detection/ParallelTriggerActionPerformer.kt rename to base/src/main/java/io/github/sds100/keymapper/base/keymaps/detection/ParallelTriggerActionPerformer.kt index 0050a51d0d..dcdac06267 100644 --- a/app/src/main/java/io/github/sds100/keymapper/keymaps/detection/ParallelTriggerActionPerformer.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/keymaps/detection/ParallelTriggerActionPerformer.kt @@ -1,12 +1,12 @@ -package io.github.sds100.keymapper.keymaps.detection +package io.github.sds100.keymapper.base.keymaps.detection -import io.github.sds100.keymapper.actions.Action -import io.github.sds100.keymapper.actions.ActionData -import io.github.sds100.keymapper.actions.PerformActionsUseCase -import io.github.sds100.keymapper.actions.RepeatMode +import io.github.sds100.keymapper.base.actions.Action +import io.github.sds100.keymapper.base.actions.ActionData +import io.github.sds100.keymapper.base.actions.PerformActionsUseCase +import io.github.sds100.keymapper.base.actions.RepeatMode +import io.github.sds100.keymapper.common.utils.InputEventType import io.github.sds100.keymapper.data.PreferenceDefaults import io.github.sds100.keymapper.system.inputevents.InputEventUtils -import io.github.sds100.keymapper.util.InputEventType import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Job import kotlinx.coroutines.delay @@ -16,9 +16,6 @@ import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.isActive import kotlinx.coroutines.launch -/** - * Created by sds100 on 16/06/2021. - */ class ParallelTriggerActionPerformer( private val coroutineScope: CoroutineScope, private val useCase: PerformActionsUseCase, diff --git a/app/src/main/java/io/github/sds100/keymapper/keymaps/detection/SequenceTriggerActionPerformer.kt b/base/src/main/java/io/github/sds100/keymapper/base/keymaps/detection/SequenceTriggerActionPerformer.kt similarity index 80% rename from app/src/main/java/io/github/sds100/keymapper/keymaps/detection/SequenceTriggerActionPerformer.kt rename to base/src/main/java/io/github/sds100/keymapper/base/keymaps/detection/SequenceTriggerActionPerformer.kt index aa04286de1..a040f7f860 100644 --- a/app/src/main/java/io/github/sds100/keymapper/keymaps/detection/SequenceTriggerActionPerformer.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/keymaps/detection/SequenceTriggerActionPerformer.kt @@ -1,16 +1,13 @@ -package io.github.sds100.keymapper.keymaps.detection +package io.github.sds100.keymapper.base.keymaps.detection -import io.github.sds100.keymapper.actions.Action -import io.github.sds100.keymapper.actions.PerformActionsUseCase -import io.github.sds100.keymapper.util.InputEventType +import io.github.sds100.keymapper.base.actions.Action +import io.github.sds100.keymapper.base.actions.PerformActionsUseCase +import io.github.sds100.keymapper.common.utils.InputEventType import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Job import kotlinx.coroutines.delay import kotlinx.coroutines.launch -/** - * Created by sds100 on 16/06/2021. - */ class SequenceTriggerActionPerformer( private val coroutineScope: CoroutineScope, private val useCase: PerformActionsUseCase, diff --git a/app/src/main/java/io/github/sds100/keymapper/keymaps/detection/TriggerKeyMapFromOtherAppsController.kt b/base/src/main/java/io/github/sds100/keymapper/base/keymaps/detection/TriggerKeyMapFromOtherAppsController.kt similarity index 77% rename from app/src/main/java/io/github/sds100/keymapper/keymaps/detection/TriggerKeyMapFromOtherAppsController.kt rename to base/src/main/java/io/github/sds100/keymapper/base/keymaps/detection/TriggerKeyMapFromOtherAppsController.kt index e780051f67..c9d04b1f0d 100644 --- a/app/src/main/java/io/github/sds100/keymapper/keymaps/detection/TriggerKeyMapFromOtherAppsController.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/keymaps/detection/TriggerKeyMapFromOtherAppsController.kt @@ -1,17 +1,14 @@ -package io.github.sds100.keymapper.keymaps.detection +package io.github.sds100.keymapper.base.keymaps.detection -import io.github.sds100.keymapper.actions.PerformActionsUseCase -import io.github.sds100.keymapper.constraints.DetectConstraintsUseCase -import io.github.sds100.keymapper.keymaps.KeyMap -import io.github.sds100.keymapper.keymaps.SimpleMappingController +import io.github.sds100.keymapper.base.actions.PerformActionsUseCase +import io.github.sds100.keymapper.base.constraints.DetectConstraintsUseCase +import io.github.sds100.keymapper.base.keymaps.KeyMap +import io.github.sds100.keymapper.base.keymaps.SimpleMappingController import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.launch import timber.log.Timber -/** - * Created by sds100 on 11/12/20. - */ class TriggerKeyMapFromOtherAppsController( coroutineScope: CoroutineScope, detectKeyMapsUseCase: DetectKeyMapsUseCase, @@ -23,7 +20,6 @@ class TriggerKeyMapFromOtherAppsController( performActionsUseCase, detectConstraintsUseCase, ) { - private var keyMapList = emptyList() init { diff --git a/app/src/main/java/io/github/sds100/keymapper/logging/DisplayLogUseCase.kt b/base/src/main/java/io/github/sds100/keymapper/base/logging/DisplayLogUseCase.kt similarity index 79% rename from app/src/main/java/io/github/sds100/keymapper/logging/DisplayLogUseCase.kt rename to base/src/main/java/io/github/sds100/keymapper/base/logging/DisplayLogUseCase.kt index 6aab805835..0ffde83f82 100644 --- a/app/src/main/java/io/github/sds100/keymapper/logging/DisplayLogUseCase.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/logging/DisplayLogUseCase.kt @@ -1,23 +1,21 @@ -package io.github.sds100.keymapper.logging - -import io.github.sds100.keymapper.R +package io.github.sds100.keymapper.base.logging + +import io.github.sds100.keymapper.base.R +import io.github.sds100.keymapper.base.utils.ui.ResourceProvider +import io.github.sds100.keymapper.common.utils.State +import io.github.sds100.keymapper.common.utils.ifIsData +import io.github.sds100.keymapper.common.utils.mapData +import io.github.sds100.keymapper.data.repositories.LogRepository import io.github.sds100.keymapper.system.clipboard.ClipboardAdapter import io.github.sds100.keymapper.system.files.FileAdapter -import io.github.sds100.keymapper.util.State -import io.github.sds100.keymapper.util.ifIsData -import io.github.sds100.keymapper.util.mapData -import io.github.sds100.keymapper.util.ui.ResourceProvider import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.map +import javax.inject.Inject -/** - * Created by sds100 on 13/05/2021. - */ - -class DisplayLogUseCaseImpl( +class DisplayLogUseCaseImpl @Inject constructor( private val repository: LogRepository, private val resourceProvider: ResourceProvider, private val clipboardAdapter: ClipboardAdapter, diff --git a/app/src/main/java/io/github/sds100/keymapper/logging/KeyMapperLoggingTree.kt b/base/src/main/java/io/github/sds100/keymapper/base/logging/KeyMapperLoggingTree.kt similarity index 92% rename from app/src/main/java/io/github/sds100/keymapper/logging/KeyMapperLoggingTree.kt rename to base/src/main/java/io/github/sds100/keymapper/base/logging/KeyMapperLoggingTree.kt index 5eebe70af8..861b6522df 100644 --- a/app/src/main/java/io/github/sds100/keymapper/logging/KeyMapperLoggingTree.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/logging/KeyMapperLoggingTree.kt @@ -1,8 +1,9 @@ -package io.github.sds100.keymapper.logging +package io.github.sds100.keymapper.base.logging import android.util.Log import io.github.sds100.keymapper.data.Keys import io.github.sds100.keymapper.data.entities.LogEntryEntity +import io.github.sds100.keymapper.data.repositories.LogRepository import io.github.sds100.keymapper.data.repositories.PreferenceRepository import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers @@ -17,11 +18,9 @@ import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.stateIn import timber.log.Timber import java.util.Calendar +import javax.inject.Inject -/** - * Created by sds100 on 13/05/2021. - */ -class KeyMapperLoggingTree( +class KeyMapperLoggingTree @Inject constructor( private val coroutineScope: CoroutineScope, preferenceRepository: PreferenceRepository, private val logRepository: LogRepository, diff --git a/app/src/main/java/io/github/sds100/keymapper/logging/LogEntry.kt b/base/src/main/java/io/github/sds100/keymapper/base/logging/LogEntry.kt similarity index 57% rename from app/src/main/java/io/github/sds100/keymapper/logging/LogEntry.kt rename to base/src/main/java/io/github/sds100/keymapper/base/logging/LogEntry.kt index 33d3208092..3d3d4a941b 100644 --- a/app/src/main/java/io/github/sds100/keymapper/logging/LogEntry.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/logging/LogEntry.kt @@ -1,8 +1,5 @@ -package io.github.sds100.keymapper.logging +package io.github.sds100.keymapper.base.logging -/** - * Created by sds100 on 13/05/2021. - */ data class LogEntry( val id: Int, val time: Long, diff --git a/app/src/main/java/io/github/sds100/keymapper/logging/LogEntryEntityMapper.kt b/base/src/main/java/io/github/sds100/keymapper/base/logging/LogEntryEntityMapper.kt similarity index 92% rename from app/src/main/java/io/github/sds100/keymapper/logging/LogEntryEntityMapper.kt rename to base/src/main/java/io/github/sds100/keymapper/base/logging/LogEntryEntityMapper.kt index d63ce782fd..0e3d6f301d 100644 --- a/app/src/main/java/io/github/sds100/keymapper/logging/LogEntryEntityMapper.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/logging/LogEntryEntityMapper.kt @@ -1,10 +1,7 @@ -package io.github.sds100.keymapper.logging +package io.github.sds100.keymapper.base.logging import io.github.sds100.keymapper.data.entities.LogEntryEntity -/** - * Created by sds100 on 13/05/2021. - */ object LogEntryEntityMapper { fun toEntity(model: LogEntry): LogEntryEntity { val severity = when (model.severity) { diff --git a/app/src/main/java/io/github/sds100/keymapper/logging/LogEntryListItem.kt b/base/src/main/java/io/github/sds100/keymapper/base/logging/LogEntryListItem.kt similarity index 52% rename from app/src/main/java/io/github/sds100/keymapper/logging/LogEntryListItem.kt rename to base/src/main/java/io/github/sds100/keymapper/base/logging/LogEntryListItem.kt index 4cd2da5bd5..5dcd1551d8 100644 --- a/app/src/main/java/io/github/sds100/keymapper/logging/LogEntryListItem.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/logging/LogEntryListItem.kt @@ -1,10 +1,7 @@ -package io.github.sds100.keymapper.logging +package io.github.sds100.keymapper.base.logging -import io.github.sds100.keymapper.util.ui.TintType +import io.github.sds100.keymapper.base.utils.ui.TintType -/** - * Created by sds100 on 14/05/2021. - */ data class LogEntryListItem( val id: Int, val time: String, diff --git a/app/src/main/java/io/github/sds100/keymapper/logging/LogFragment.kt b/base/src/main/java/io/github/sds100/keymapper/base/logging/LogFragment.kt similarity index 89% rename from app/src/main/java/io/github/sds100/keymapper/logging/LogFragment.kt rename to base/src/main/java/io/github/sds100/keymapper/base/logging/LogFragment.kt index 50760f51d0..5c84b9c89e 100644 --- a/app/src/main/java/io/github/sds100/keymapper/logging/LogFragment.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/logging/LogFragment.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.logging +package io.github.sds100.keymapper.base.logging import android.content.Intent import android.os.Bundle @@ -14,26 +14,21 @@ import com.airbnb.epoxy.EpoxyRecyclerView import com.airbnb.epoxy.TypedEpoxyController import com.michaelflisar.dragselectrecyclerview.DragSelectTouchListener import com.michaelflisar.dragselectrecyclerview.DragSelectionProcessor -import io.github.sds100.keymapper.R -import io.github.sds100.keymapper.databinding.FragmentSimpleRecyclerviewBinding -import io.github.sds100.keymapper.logEntry +import dagger.hilt.android.AndroidEntryPoint +import io.github.sds100.keymapper.base.R +import io.github.sds100.keymapper.base.databinding.FragmentSimpleRecyclerviewBinding +import io.github.sds100.keymapper.base.logEntry +import io.github.sds100.keymapper.base.utils.ui.SimpleRecyclerViewFragment +import io.github.sds100.keymapper.base.utils.ui.launchRepeatOnLifecycle +import io.github.sds100.keymapper.common.utils.State import io.github.sds100.keymapper.system.files.FileUtils -import io.github.sds100.keymapper.util.Inject -import io.github.sds100.keymapper.util.State -import io.github.sds100.keymapper.util.launchRepeatOnLifecycle -import io.github.sds100.keymapper.util.ui.SimpleRecyclerViewFragment -import io.github.sds100.keymapper.util.ui.showPopups import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.collectLatest -/** - * Created by sds100 on 13/05/2021. - */ +@AndroidEntryPoint class LogFragment : SimpleRecyclerViewFragment() { - private val viewModel by viewModels { - Inject.logViewModel(requireContext()) - } + private val viewModel: LogViewModel by viewModels() override val listItems: Flow>> get() = viewModel.listItems @@ -60,8 +55,6 @@ class LogFragment : SimpleRecyclerViewFragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - viewModel.showPopups(this, binding) - getBottomAppBar(binding)?.setOnMenuItemClickListener { menuItem -> viewModel.onMenuItemClick(menuItem.itemId) true @@ -103,8 +96,6 @@ class LogFragment : SimpleRecyclerViewFragment() { dragSelectTouchListener = DragSelectTouchListener() .withSelectListener(dragSelectionProcessor) - binding.epoxyRecyclerView.addOnItemTouchListener(dragSelectTouchListener) - binding.epoxyRecyclerView.setController(recyclerViewController) } diff --git a/base/src/main/java/io/github/sds100/keymapper/base/logging/LogSeverity.kt b/base/src/main/java/io/github/sds100/keymapper/base/logging/LogSeverity.kt new file mode 100644 index 0000000000..e90e7993da --- /dev/null +++ b/base/src/main/java/io/github/sds100/keymapper/base/logging/LogSeverity.kt @@ -0,0 +1,7 @@ +package io.github.sds100.keymapper.base.logging + +enum class LogSeverity { + ERROR, + INFO, + DEBUG, +} diff --git a/app/src/main/java/io/github/sds100/keymapper/logging/LogUtils.kt b/base/src/main/java/io/github/sds100/keymapper/base/logging/LogUtils.kt similarity index 89% rename from app/src/main/java/io/github/sds100/keymapper/logging/LogUtils.kt rename to base/src/main/java/io/github/sds100/keymapper/base/logging/LogUtils.kt index 6182f6ef9c..93b19ffaad 100644 --- a/app/src/main/java/io/github/sds100/keymapper/logging/LogUtils.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/logging/LogUtils.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.logging +package io.github.sds100.keymapper.base.logging import io.github.sds100.keymapper.data.entities.LogEntryEntity import io.github.sds100.keymapper.system.files.FileUtils @@ -6,9 +6,6 @@ import java.text.SimpleDateFormat import java.util.Date import java.util.Locale -/** - * Created by sds100 on 14/05/2021. - */ object LogUtils { val DATE_FORMAT get() = SimpleDateFormat("MM/dd HH:mm:ss.SSS", Locale.getDefault()) diff --git a/app/src/main/java/io/github/sds100/keymapper/logging/LogViewModel.kt b/base/src/main/java/io/github/sds100/keymapper/base/logging/LogViewModel.kt similarity index 82% rename from app/src/main/java/io/github/sds100/keymapper/logging/LogViewModel.kt rename to base/src/main/java/io/github/sds100/keymapper/base/logging/LogViewModel.kt index 7abb75231b..61959f6990 100644 --- a/app/src/main/java/io/github/sds100/keymapper/logging/LogViewModel.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/logging/LogViewModel.kt @@ -1,21 +1,20 @@ -package io.github.sds100.keymapper.logging +package io.github.sds100.keymapper.base.logging import androidx.lifecycle.ViewModel -import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.viewModelScope import com.michaelflisar.dragselectrecyclerview.DragSelectionProcessor -import io.github.sds100.keymapper.R -import io.github.sds100.keymapper.util.State -import io.github.sds100.keymapper.util.ifIsData -import io.github.sds100.keymapper.util.mapData -import io.github.sds100.keymapper.util.ui.MultiSelectProvider -import io.github.sds100.keymapper.util.ui.PopupUi -import io.github.sds100.keymapper.util.ui.PopupViewModel -import io.github.sds100.keymapper.util.ui.PopupViewModelImpl -import io.github.sds100.keymapper.util.ui.ResourceProvider -import io.github.sds100.keymapper.util.ui.SelectionState -import io.github.sds100.keymapper.util.ui.TintType -import io.github.sds100.keymapper.util.ui.showPopup +import dagger.hilt.android.lifecycle.HiltViewModel +import io.github.sds100.keymapper.base.R +import io.github.sds100.keymapper.base.utils.ui.DialogModel +import io.github.sds100.keymapper.base.utils.ui.DialogProvider +import io.github.sds100.keymapper.base.utils.ui.MultiSelectProvider +import io.github.sds100.keymapper.base.utils.ui.ResourceProvider +import io.github.sds100.keymapper.base.utils.ui.SelectionState +import io.github.sds100.keymapper.base.utils.ui.TintType +import io.github.sds100.keymapper.base.utils.ui.showDialog +import io.github.sds100.keymapper.common.utils.State +import io.github.sds100.keymapper.common.utils.ifIsData +import io.github.sds100.keymapper.common.utils.mapData import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow @@ -31,16 +30,15 @@ import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch import java.util.Date +import javax.inject.Inject -/** - * Created by sds100 on 14/05/2021. - */ - -class LogViewModel( +@HiltViewModel +class LogViewModel @Inject constructor( private val useCase: DisplayLogUseCase, resourceProvider: ResourceProvider, + dialogProvider: DialogProvider, ) : ViewModel(), - PopupViewModel by PopupViewModelImpl(), + DialogProvider by dialogProvider, ResourceProvider by resourceProvider { private val multiSelectProvider: MultiSelectProvider = MultiSelectProvider() @@ -128,7 +126,7 @@ class LogViewModel( R.id.action_clear -> useCase.clearLog() R.id.action_copy -> { useCase.copyToClipboard(getSelectedLogEntries()) - showPopup("copied", PopupUi.Toast(getString(R.string.toast_copied_log))) + showDialog("copied", DialogModel.Toast(getString(R.string.toast_copied_log))) } R.id.action_short_messages -> { @@ -198,15 +196,6 @@ class LogViewModel( isSelected = isSelected, ) } - - class Factory( - private val useCase: DisplayLogUseCase, - private val resourceProvider: ResourceProvider, - ) : ViewModelProvider.Factory { - - @Suppress("UNCHECKED_CAST") - override fun create(modelClass: Class) = LogViewModel(useCase, resourceProvider) as T - } } enum class LogAppBarState { diff --git a/app/src/main/java/io/github/sds100/keymapper/onboarding/OnboardingTapTarget.kt b/base/src/main/java/io/github/sds100/keymapper/base/onboarding/OnboardingTapTarget.kt similarity index 91% rename from app/src/main/java/io/github/sds100/keymapper/onboarding/OnboardingTapTarget.kt rename to base/src/main/java/io/github/sds100/keymapper/base/onboarding/OnboardingTapTarget.kt index b24f1b41db..a65de34e57 100644 --- a/app/src/main/java/io/github/sds100/keymapper/onboarding/OnboardingTapTarget.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/onboarding/OnboardingTapTarget.kt @@ -1,7 +1,7 @@ -package io.github.sds100.keymapper.onboarding +package io.github.sds100.keymapper.base.onboarding import androidx.annotation.StringRes -import io.github.sds100.keymapper.R +import io.github.sds100.keymapper.base.R enum class OnboardingTapTarget( @StringRes val titleRes: Int, diff --git a/app/src/main/java/io/github/sds100/keymapper/onboarding/OnboardingUseCase.kt b/base/src/main/java/io/github/sds100/keymapper/base/onboarding/OnboardingUseCase.kt similarity index 80% rename from app/src/main/java/io/github/sds100/keymapper/onboarding/OnboardingUseCase.kt rename to base/src/main/java/io/github/sds100/keymapper/base/onboarding/OnboardingUseCase.kt index 3bd5309ca0..d01fa193b0 100644 --- a/app/src/main/java/io/github/sds100/keymapper/onboarding/OnboardingUseCase.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/onboarding/OnboardingUseCase.kt @@ -1,40 +1,40 @@ -package io.github.sds100.keymapper.onboarding +package io.github.sds100.keymapper.base.onboarding import androidx.datastore.preferences.core.Preferences -import io.github.sds100.keymapper.Constants -import io.github.sds100.keymapper.actions.ActionData -import io.github.sds100.keymapper.actions.canUseImeToPerform -import io.github.sds100.keymapper.actions.canUseShizukuToPerform +import io.github.sds100.keymapper.base.actions.ActionData +import io.github.sds100.keymapper.base.actions.canUseImeToPerform +import io.github.sds100.keymapper.base.actions.canUseShizukuToPerform +import io.github.sds100.keymapper.base.purchasing.ProductId +import io.github.sds100.keymapper.base.purchasing.PurchasingManager +import io.github.sds100.keymapper.base.system.inputmethod.KeyMapperImeHelper +import io.github.sds100.keymapper.base.utils.VersionHelper +import io.github.sds100.keymapper.common.BuildConfigProvider +import io.github.sds100.keymapper.common.utils.KMResult +import io.github.sds100.keymapper.common.utils.State +import io.github.sds100.keymapper.common.utils.handle import io.github.sds100.keymapper.data.Keys import io.github.sds100.keymapper.data.entities.KeyMapEntity +import io.github.sds100.keymapper.data.repositories.KeyMapRepository import io.github.sds100.keymapper.data.repositories.PreferenceRepository -import io.github.sds100.keymapper.keymaps.KeyMapRepository -import io.github.sds100.keymapper.purchasing.ProductId -import io.github.sds100.keymapper.purchasing.PurchasingManager -import io.github.sds100.keymapper.shizuku.ShizukuAdapter -import io.github.sds100.keymapper.shizuku.ShizukuUtils +import io.github.sds100.keymapper.data.utils.PrefDelegate import io.github.sds100.keymapper.system.apps.PackageManagerAdapter import io.github.sds100.keymapper.system.files.FileAdapter -import io.github.sds100.keymapper.system.inputmethod.KeyMapperImeHelper import io.github.sds100.keymapper.system.leanback.LeanbackAdapter import io.github.sds100.keymapper.system.permissions.Permission import io.github.sds100.keymapper.system.permissions.PermissionAdapter -import io.github.sds100.keymapper.util.PrefDelegate -import io.github.sds100.keymapper.util.Result -import io.github.sds100.keymapper.util.State -import io.github.sds100.keymapper.util.VersionHelper -import io.github.sds100.keymapper.util.handle +import io.github.sds100.keymapper.system.shizuku.ShizukuAdapter +import io.github.sds100.keymapper.system.shizuku.ShizukuUtils import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.filterIsInstance import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.map +import javax.inject.Inject +import javax.inject.Singleton -/** - * Created by sds100 on 14/02/21. - */ -class OnboardingUseCaseImpl( - private val preferences: PreferenceRepository, +@Singleton +class OnboardingUseCaseImpl @Inject constructor( + private val settingsRepository: PreferenceRepository, private val fileAdapter: FileAdapter, private val leanbackAdapter: LeanbackAdapter, private val shizukuAdapter: ShizukuAdapter, @@ -42,13 +42,14 @@ class OnboardingUseCaseImpl( private val packageManagerAdapter: PackageManagerAdapter, private val purchasingManager: PurchasingManager, private val keyMapRepository: KeyMapRepository, -) : PreferenceRepository by preferences, + private val buildConfigProvider: BuildConfigProvider, +) : PreferenceRepository by settingsRepository, OnboardingUseCase { override var shownAppIntro by PrefDelegate(Keys.shownAppIntro, false) override suspend fun showInstallGuiKeyboardPrompt(action: ActionData): Boolean { - val acknowledged = preferences.get(Keys.acknowledgedGuiKeyboard).first() + val acknowledged = settingsRepository.get(Keys.acknowledgedGuiKeyboard).first() val isGuiKeyboardInstalled = packageManagerAdapter.isAppInstalled(KeyMapperImeHelper.KEY_MAPPER_GUI_IME_PACKAGE) @@ -65,7 +66,7 @@ class OnboardingUseCaseImpl( action.canUseShizukuToPerform() override fun neverShowGuiKeyboardPromptsAgain() { - preferences.set(Keys.acknowledgedGuiKeyboard, true) + settingsRepository.set(Keys.acknowledgedGuiKeyboard, true) } override var shownParallelTriggerOrderExplanation by PrefDelegate( @@ -82,10 +83,10 @@ class OnboardingUseCaseImpl( ) override val showWhatsNew = get(Keys.lastInstalledVersionCodeHomeScreen) - .map { (it ?: -1) < Constants.VERSION_CODE } + .map { (it ?: -1) < buildConfigProvider.versionCode } override fun showedWhatsNew() { - set(Keys.lastInstalledVersionCodeHomeScreen, Constants.VERSION_CODE) + set(Keys.lastInstalledVersionCodeHomeScreen, buildConfigProvider.versionCode) } override fun getWhatsNewText(): String = with(fileAdapter.openAsset("whats-new.txt").bufferedReader()) { @@ -109,13 +110,13 @@ class OnboardingUseCaseImpl( } override fun showedFloatingButtonFeatureNotification() { - set(Keys.lastInstalledVersionCodeBackground, Constants.VERSION_CODE) + set(Keys.lastInstalledVersionCodeBackground, buildConfigProvider.versionCode) } override fun isTvDevice(): Boolean = leanbackAdapter.isTvDevice() override val promptForShizukuPermission: Flow = combine( - preferences.get(Keys.shownShizukuPermissionPrompt), + settingsRepository.get(Keys.shownShizukuPermissionPrompt), shizukuAdapter.isInstalled, permissionAdapter.isGrantedFlow(Permission.SHIZUKU), ) { @@ -130,7 +131,7 @@ class OnboardingUseCaseImpl( get() = shizukuAdapter.isInstalled.value override val showNoKeysDetectedBottomSheet: Flow = - preferences.get(Keys.neverShowNoKeysRecordedError).map { neverShow -> + settingsRepository.get(Keys.neverShowNoKeysRecordedError).map { neverShow -> if (neverShow == null) { true } else { @@ -139,7 +140,7 @@ class OnboardingUseCaseImpl( } override fun neverShowNoKeysRecordedBottomSheet() { - preferences.set(Keys.neverShowNoKeysRecordedError, true) + settingsRepository.set(Keys.neverShowNoKeysRecordedError, true) } override val hasViewedAdvancedTriggers: Flow = @@ -154,8 +155,8 @@ class OnboardingUseCaseImpl( if (tapTarget == OnboardingTapTarget.ADVANCED_TRIGGERS) { return combine( - preferences.get(shownKey).map { it ?: false }, - purchasingManager.purchases.filterIsInstance>>>(), + settingsRepository.get(shownKey).map { it ?: false }, + purchasingManager.purchases.filterIsInstance>>>(), keyMapRepository.keyMapList.filterIsInstance>>(), ) { isShown, purchases, keyMapList -> // Only show the tap target for advanced triggers if it has not already been shown @@ -171,8 +172,8 @@ class OnboardingUseCaseImpl( } } else { return combine( - preferences.get(shownKey).map { it ?: false }, - preferences.get(Keys.skipTapTargetTutorial).map { it ?: false }, + settingsRepository.get(shownKey).map { it ?: false }, + settingsRepository.get(Keys.skipTapTargetTutorial).map { it ?: false }, keyMapRepository.keyMapList.filterIsInstance>>(), ) { isShown, skipTapTarget, keyMapList -> showTutorialTapTarget(tapTarget, isShown, skipTapTarget, keyMapList.data) @@ -182,7 +183,7 @@ class OnboardingUseCaseImpl( override fun completedTapTarget(tapTarget: OnboardingTapTarget) { val key = getTapTargetKey(tapTarget) - preferences.set(key, true) + settingsRepository.set(key, true) } private fun getTapTargetKey(tapTarget: OnboardingTapTarget): Preferences.Key { @@ -226,7 +227,7 @@ class OnboardingUseCaseImpl( } override fun skipTapTargetOnboarding() { - preferences.set(Keys.skipTapTargetTutorial, true) + settingsRepository.set(Keys.skipTapTargetTutorial, true) } } diff --git a/app/src/main/java/io/github/sds100/keymapper/package-info.java b/base/src/main/java/io/github/sds100/keymapper/base/package-info.java similarity index 78% rename from app/src/main/java/io/github/sds100/keymapper/package-info.java rename to base/src/main/java/io/github/sds100/keymapper/base/package-info.java index 391ca62e91..f3df0af949 100644 --- a/app/src/main/java/io/github/sds100/keymapper/package-info.java +++ b/base/src/main/java/io/github/sds100/keymapper/base/package-info.java @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper; +package io.github.sds100.keymapper.base; import com.airbnb.epoxy.EpoxyDataBindingPattern; diff --git a/app/src/main/java/io/github/sds100/keymapper/purchasing/ProductId.kt b/base/src/main/java/io/github/sds100/keymapper/base/purchasing/ProductId.kt similarity index 79% rename from app/src/main/java/io/github/sds100/keymapper/purchasing/ProductId.kt rename to base/src/main/java/io/github/sds100/keymapper/base/purchasing/ProductId.kt index ca745fe7bc..e5fe69ec36 100644 --- a/app/src/main/java/io/github/sds100/keymapper/purchasing/ProductId.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/purchasing/ProductId.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.purchasing +package io.github.sds100.keymapper.base.purchasing enum class ProductId(val packageId: String, val entitlementId: String) { ASSISTANT_TRIGGER("assistant_trigger", "assistant_trigger"), diff --git a/base/src/main/java/io/github/sds100/keymapper/base/purchasing/PurchasingError.kt b/base/src/main/java/io/github/sds100/keymapper/base/purchasing/PurchasingError.kt new file mode 100644 index 0000000000..f1cee2affe --- /dev/null +++ b/base/src/main/java/io/github/sds100/keymapper/base/purchasing/PurchasingError.kt @@ -0,0 +1,19 @@ +package io.github.sds100.keymapper.base.purchasing + +import io.github.sds100.keymapper.common.utils.KMError + +sealed class PurchasingError : KMError() { + data object PurchasingNotImplemented : PurchasingError() + + data class ProductNotPurchased(val product: ProductId) : PurchasingError() + + sealed class PurchasingProcessError : PurchasingError() { + data object ProductNotFound : PurchasingProcessError() + data object Cancelled : PurchasingProcessError() + data object StoreProblem : PurchasingProcessError() + data object NetworkError : PurchasingProcessError() + data object PaymentPending : PurchasingProcessError() + data object PurchaseInvalid : PurchasingProcessError() + data class Unexpected(val message: String) : PurchasingProcessError() + } +} diff --git a/base/src/main/java/io/github/sds100/keymapper/base/purchasing/PurchasingManager.kt b/base/src/main/java/io/github/sds100/keymapper/base/purchasing/PurchasingManager.kt new file mode 100644 index 0000000000..2ddfb3f0f7 --- /dev/null +++ b/base/src/main/java/io/github/sds100/keymapper/base/purchasing/PurchasingManager.kt @@ -0,0 +1,15 @@ +package io.github.sds100.keymapper.base.purchasing + +import io.github.sds100.keymapper.common.utils.KMResult +import io.github.sds100.keymapper.common.utils.State +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableSharedFlow + +interface PurchasingManager { + val onCompleteProductPurchase: MutableSharedFlow + val purchases: Flow>>> + suspend fun launchPurchasingFlow(product: ProductId): KMResult + suspend fun getProductPrice(product: ProductId): KMResult + suspend fun isPurchased(product: ProductId): KMResult + fun refresh() +} diff --git a/app/src/main/java/io/github/sds100/keymapper/reroutekeyevents/RerouteKeyEventsController.kt b/base/src/main/java/io/github/sds100/keymapper/base/reroutekeyevents/RerouteKeyEventsController.kt similarity index 78% rename from app/src/main/java/io/github/sds100/keymapper/reroutekeyevents/RerouteKeyEventsController.kt rename to base/src/main/java/io/github/sds100/keymapper/base/reroutekeyevents/RerouteKeyEventsController.kt index e1a27137a7..05331b8032 100644 --- a/app/src/main/java/io/github/sds100/keymapper/reroutekeyevents/RerouteKeyEventsController.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/reroutekeyevents/RerouteKeyEventsController.kt @@ -1,29 +1,42 @@ -package io.github.sds100.keymapper.reroutekeyevents +package io.github.sds100.keymapper.base.reroutekeyevents import android.view.KeyEvent +import dagger.assisted.Assisted +import dagger.assisted.AssistedFactory +import dagger.assisted.AssistedInject +import io.github.sds100.keymapper.base.system.inputmethod.ImeInputEventInjector +import io.github.sds100.keymapper.common.utils.InputEventType import io.github.sds100.keymapper.system.devices.InputDeviceInfo import io.github.sds100.keymapper.system.inputevents.MyKeyEvent import io.github.sds100.keymapper.system.inputmethod.InputKeyModel -import io.github.sds100.keymapper.util.InputEventType import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Job import kotlinx.coroutines.delay import kotlinx.coroutines.isActive import kotlinx.coroutines.launch -/** - * Created by sds100 on 27/04/2021. - */ - /** * This is used for the feature created in issue #618 to fix the device IDs of key events * on Android 11. There was a bug in the system where enabling an accessibility service * would reset the device ID of key events to -1. */ -class RerouteKeyEventsController( +class RerouteKeyEventsController @AssistedInject constructor( + @Assisted private val coroutineScope: CoroutineScope, - private val useCase: RerouteKeyEventsUseCase, + @Assisted + private val keyMapperImeMessenger: ImeInputEventInjector, + private val useCaseFactory: RerouteKeyEventsUseCaseImpl.Factory, ) { + @AssistedFactory + interface Factory { + fun create( + coroutineScope: CoroutineScope, + keyMapperImeMessenger: ImeInputEventInjector, + ): RerouteKeyEventsController + } + + private val useCase = useCaseFactory.create(keyMapperImeMessenger) + /** * The job of the key that should be repeating. This should be a down key event for the last * key that has been pressed down. diff --git a/app/src/main/java/io/github/sds100/keymapper/reroutekeyevents/RerouteKeyEventsUseCase.kt b/base/src/main/java/io/github/sds100/keymapper/base/reroutekeyevents/RerouteKeyEventsUseCase.kt similarity index 63% rename from app/src/main/java/io/github/sds100/keymapper/reroutekeyevents/RerouteKeyEventsUseCase.kt rename to base/src/main/java/io/github/sds100/keymapper/base/reroutekeyevents/RerouteKeyEventsUseCase.kt index 2d50fd4b7c..83e7af7e95 100644 --- a/app/src/main/java/io/github/sds100/keymapper/reroutekeyevents/RerouteKeyEventsUseCase.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/reroutekeyevents/RerouteKeyEventsUseCase.kt @@ -1,38 +1,52 @@ -package io.github.sds100.keymapper.reroutekeyevents +package io.github.sds100.keymapper.base.reroutekeyevents import android.os.Build +import dagger.assisted.Assisted +import dagger.assisted.AssistedFactory +import dagger.assisted.AssistedInject +import io.github.sds100.keymapper.base.system.inputmethod.ImeInputEventInjector +import io.github.sds100.keymapper.base.system.inputmethod.KeyMapperImeHelper +import io.github.sds100.keymapper.common.BuildConfigProvider +import io.github.sds100.keymapper.common.utils.firstBlocking import io.github.sds100.keymapper.data.Keys import io.github.sds100.keymapper.data.repositories.PreferenceRepository -import io.github.sds100.keymapper.system.inputmethod.ImeInputEventInjector import io.github.sds100.keymapper.system.inputmethod.InputKeyModel import io.github.sds100.keymapper.system.inputmethod.InputMethodAdapter -import io.github.sds100.keymapper.system.inputmethod.KeyMapperImeHelper -import io.github.sds100.keymapper.util.firstBlocking import kotlinx.coroutines.flow.map import kotlinx.coroutines.runBlocking -/** - * Created by sds100 on 27/04/2021. - */ - /** * This is used for the feature created in issue #618 to fix the device IDs of key events * on Android 11. There was a bug in the system where enabling an accessibility service * would reset the device ID of key events to -1. */ -class RerouteKeyEventsUseCaseImpl( +class RerouteKeyEventsUseCaseImpl @AssistedInject constructor( + @Assisted + private val keyMapperImeMessenger: ImeInputEventInjector, private val inputMethodAdapter: InputMethodAdapter, - private val imeInputEventInjector: ImeInputEventInjector, private val preferenceRepository: PreferenceRepository, + private val buildConfigProvider: BuildConfigProvider, ) : RerouteKeyEventsUseCase { + @AssistedFactory + interface Factory { + fun create( + keyMapperImeMessenger: ImeInputEventInjector, + ): RerouteKeyEventsUseCaseImpl + } + private val rerouteKeyEvents = preferenceRepository.get(Keys.rerouteKeyEvents).map { it ?: false } private val devicesToRerouteKeyEvents = preferenceRepository.get(Keys.devicesToRerouteKeyEvents).map { it ?: emptyList() } - private val imeHelper by lazy { KeyMapperImeHelper(inputMethodAdapter) } + private val imeHelper by lazy { + KeyMapperImeHelper( + inputMethodAdapter, + buildConfigProvider.packageName, + ) + } override fun shouldRerouteKeyEvent(descriptor: String?): Boolean { if (Build.VERSION.SDK_INT != Build.VERSION_CODES.R) { @@ -51,7 +65,7 @@ class RerouteKeyEventsUseCaseImpl( override fun inputKeyEvent(keyModel: InputKeyModel) { // It is safe to run the ime injector on the main thread. runBlocking { - imeInputEventInjector.inputKeyEvent(keyModel) + keyMapperImeMessenger.inputKeyEvent(keyModel) } } } diff --git a/app/src/main/java/io/github/sds100/keymapper/settings/Android11BugWorkaroundSettingsFragment.kt b/base/src/main/java/io/github/sds100/keymapper/base/settings/Android11BugWorkaroundSettingsFragment.kt similarity index 87% rename from app/src/main/java/io/github/sds100/keymapper/settings/Android11BugWorkaroundSettingsFragment.kt rename to base/src/main/java/io/github/sds100/keymapper/base/settings/Android11BugWorkaroundSettingsFragment.kt index 890cf8e1f3..f82b8f2e84 100644 --- a/app/src/main/java/io/github/sds100/keymapper/settings/Android11BugWorkaroundSettingsFragment.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/settings/Android11BugWorkaroundSettingsFragment.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.settings +package io.github.sds100.keymapper.base.settings import android.os.Bundle import android.view.View @@ -6,22 +6,21 @@ import androidx.lifecycle.Lifecycle import androidx.preference.Preference import androidx.preference.SwitchPreference import androidx.preference.isEmpty -import io.github.sds100.keymapper.R +import dagger.hilt.android.AndroidEntryPoint +import io.github.sds100.keymapper.base.R +import io.github.sds100.keymapper.base.utils.ui.ChooseAppStoreModel +import io.github.sds100.keymapper.base.utils.ui.DialogModel +import io.github.sds100.keymapper.base.utils.ui.drawable +import io.github.sds100.keymapper.base.utils.ui.launchRepeatOnLifecycle +import io.github.sds100.keymapper.base.utils.ui.showDialog +import io.github.sds100.keymapper.base.utils.ui.str +import io.github.sds100.keymapper.base.utils.ui.viewLifecycleScope import io.github.sds100.keymapper.data.Keys import io.github.sds100.keymapper.system.leanback.LeanbackUtils import io.github.sds100.keymapper.system.url.UrlUtils -import io.github.sds100.keymapper.util.drawable -import io.github.sds100.keymapper.util.launchRepeatOnLifecycle -import io.github.sds100.keymapper.util.str -import io.github.sds100.keymapper.util.ui.ChooseAppStoreModel -import io.github.sds100.keymapper.util.ui.PopupUi -import io.github.sds100.keymapper.util.ui.showPopup -import io.github.sds100.keymapper.util.viewLifecycleScope import kotlinx.coroutines.flow.collectLatest -/** - * Created by sds100 on 18/07/2021. - */ +@AndroidEntryPoint class Android11BugWorkaroundSettingsFragment : BaseSettingsFragment() { companion object { @@ -84,7 +83,7 @@ class Android11BugWorkaroundSettingsFragment : BaseSettingsFragment() { setOnPreferenceClickListener { viewLifecycleScope.launchWhenResumed { if (isTvDevice) { - val chooseAppStoreDialog = PopupUi.ChooseAppStore( + val chooseAppStoreDialog = DialogModel.ChooseAppStore( title = getString(R.string.dialog_title_choose_download_leanback_keyboard), message = getString(R.string.dialog_message_choose_download_leanback_keyboard), model = ChooseAppStoreModel( @@ -93,9 +92,9 @@ class Android11BugWorkaroundSettingsFragment : BaseSettingsFragment() { negativeButtonText = str(R.string.neg_cancel), ) - viewModel.showPopup("download_leanback_ime", chooseAppStoreDialog) + viewModel.showDialog("download_leanback_ime", chooseAppStoreDialog) } else { - val chooseAppStoreDialog = PopupUi.ChooseAppStore( + val chooseAppStoreDialog = DialogModel.ChooseAppStore( title = getString(R.string.dialog_title_choose_download_gui_keyboard), message = getString(R.string.dialog_message_choose_download_gui_keyboard), model = ChooseAppStoreModel( @@ -106,7 +105,7 @@ class Android11BugWorkaroundSettingsFragment : BaseSettingsFragment() { negativeButtonText = str(R.string.neg_cancel), ) - viewModel.showPopup("download_gui_keyboard", chooseAppStoreDialog) + viewModel.showDialog("download_gui_keyboard", chooseAppStoreDialog) } } diff --git a/app/src/main/java/io/github/sds100/keymapper/settings/AutomaticallyChangeImeSettings.kt b/base/src/main/java/io/github/sds100/keymapper/base/settings/AutomaticallyChangeImeSettings.kt similarity index 92% rename from app/src/main/java/io/github/sds100/keymapper/settings/AutomaticallyChangeImeSettings.kt rename to base/src/main/java/io/github/sds100/keymapper/base/settings/AutomaticallyChangeImeSettings.kt index 333715a7ac..a52487e9f3 100644 --- a/app/src/main/java/io/github/sds100/keymapper/settings/AutomaticallyChangeImeSettings.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/settings/AutomaticallyChangeImeSettings.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.settings +package io.github.sds100.keymapper.base.settings import android.os.Build import android.os.Bundle @@ -7,16 +7,13 @@ import androidx.annotation.RequiresApi import androidx.preference.Preference import androidx.preference.SwitchPreferenceCompat import androidx.preference.isEmpty -import io.github.sds100.keymapper.R +import io.github.sds100.keymapper.base.R +import io.github.sds100.keymapper.base.system.notifications.NotificationController +import io.github.sds100.keymapper.base.utils.ui.viewLifecycleScope import io.github.sds100.keymapper.data.Keys import io.github.sds100.keymapper.data.PreferenceDefaults -import io.github.sds100.keymapper.system.notifications.NotificationController import io.github.sds100.keymapper.system.notifications.NotificationUtils -import io.github.sds100.keymapper.util.viewLifecycleScope -/** - * Created by sds100 on 19/07/2021. - */ class AutomaticallyChangeImeSettings : BaseSettingsFragment() { override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { @@ -132,8 +129,8 @@ class AutomaticallyChangeImeSettings : BaseSettingsFragment() { } NotificationUtils.openChannelSettings( - requireContext(), - NotificationController.CHANNEL_TOGGLE_KEYBOARD, + ctx = requireContext(), + channelId = NotificationController.CHANNEL_TOGGLE_KEYBOARD, ) } } diff --git a/app/src/main/java/io/github/sds100/keymapper/settings/BaseSettingsFragment.kt b/base/src/main/java/io/github/sds100/keymapper/base/settings/BaseSettingsFragment.kt similarity index 78% rename from app/src/main/java/io/github/sds100/keymapper/settings/BaseSettingsFragment.kt rename to base/src/main/java/io/github/sds100/keymapper/base/settings/BaseSettingsFragment.kt index 9c4518ac69..8bdfdbcbec 100644 --- a/app/src/main/java/io/github/sds100/keymapper/settings/BaseSettingsFragment.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/settings/BaseSettingsFragment.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.settings +package io.github.sds100.keymapper.base.settings import android.os.Bundle import android.view.View @@ -6,24 +6,19 @@ import androidx.activity.addCallback import androidx.core.view.ViewCompat import androidx.core.view.WindowInsetsCompat import androidx.core.view.updatePadding -import androidx.fragment.app.activityViewModels +import androidx.fragment.app.viewModels import androidx.navigation.fragment.findNavController import androidx.preference.PreferenceFragmentCompat import com.google.android.material.bottomappbar.BottomAppBar -import io.github.sds100.keymapper.R +import dagger.hilt.android.AndroidEntryPoint +import io.github.sds100.keymapper.base.R +import io.github.sds100.keymapper.base.utils.ui.str import io.github.sds100.keymapper.system.url.UrlUtils -import io.github.sds100.keymapper.util.Inject -import io.github.sds100.keymapper.util.str -import io.github.sds100.keymapper.util.ui.showPopups -/** - * Created by sds100 on 20/07/2021. - */ +@AndroidEntryPoint abstract class BaseSettingsFragment : PreferenceFragmentCompat() { - val viewModel by activityViewModels { - Inject.settingsViewModel(requireContext()) - } + protected val viewModel: SettingsViewModel by viewModels() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) @@ -57,8 +52,6 @@ abstract class BaseSettingsFragment : PreferenceFragmentCompat() { } } } - - viewModel.showPopups(this, view) } private fun onBackPressed() { diff --git a/app/src/main/java/io/github/sds100/keymapper/settings/ConfigSettingsUseCase.kt b/base/src/main/java/io/github/sds100/keymapper/base/settings/ConfigSettingsUseCase.kt similarity index 86% rename from app/src/main/java/io/github/sds100/keymapper/settings/ConfigSettingsUseCase.kt rename to base/src/main/java/io/github/sds100/keymapper/base/settings/ConfigSettingsUseCase.kt index fbc4707022..bc67b9be08 100644 --- a/app/src/main/java/io/github/sds100/keymapper/settings/ConfigSettingsUseCase.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/settings/ConfigSettingsUseCase.kt @@ -1,34 +1,33 @@ -package io.github.sds100.keymapper.settings +package io.github.sds100.keymapper.base.settings import androidx.datastore.preferences.core.Preferences -import io.github.sds100.keymapper.actions.sound.SoundFileInfo -import io.github.sds100.keymapper.actions.sound.SoundsManager +import io.github.sds100.keymapper.base.actions.sound.SoundFileInfo +import io.github.sds100.keymapper.base.actions.sound.SoundsManager +import io.github.sds100.keymapper.base.system.inputmethod.KeyMapperImeHelper +import io.github.sds100.keymapper.common.BuildConfigProvider +import io.github.sds100.keymapper.common.utils.KMResult +import io.github.sds100.keymapper.common.utils.State import io.github.sds100.keymapper.data.Keys import io.github.sds100.keymapper.data.PreferenceDefaults import io.github.sds100.keymapper.data.repositories.PreferenceRepository -import io.github.sds100.keymapper.shizuku.ShizukuAdapter -import io.github.sds100.keymapper.shizuku.ShizukuUtils import io.github.sds100.keymapper.system.apps.PackageManagerAdapter import io.github.sds100.keymapper.system.devices.DevicesAdapter import io.github.sds100.keymapper.system.devices.InputDeviceInfo import io.github.sds100.keymapper.system.inputmethod.ImeInfo import io.github.sds100.keymapper.system.inputmethod.InputMethodAdapter -import io.github.sds100.keymapper.system.inputmethod.KeyMapperImeHelper import io.github.sds100.keymapper.system.permissions.Permission import io.github.sds100.keymapper.system.permissions.PermissionAdapter import io.github.sds100.keymapper.system.root.SuAdapter -import io.github.sds100.keymapper.util.Result -import io.github.sds100.keymapper.util.State +import io.github.sds100.keymapper.system.shizuku.ShizukuAdapter +import io.github.sds100.keymapper.system.shizuku.ShizukuUtils import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.channelFlow import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.map +import javax.inject.Inject -/** - * Created by sds100 on 14/02/2021. - */ -class ConfigSettingsUseCaseImpl( +class ConfigSettingsUseCaseImpl @Inject constructor( private val preferences: PreferenceRepository, private val permissionAdapter: PermissionAdapter, private val inputMethodAdapter: InputMethodAdapter, @@ -37,9 +36,15 @@ class ConfigSettingsUseCaseImpl( private val packageManagerAdapter: PackageManagerAdapter, private val shizukuAdapter: ShizukuAdapter, private val devicesAdapter: DevicesAdapter, + private val buildConfigProvider: BuildConfigProvider, ) : ConfigSettingsUseCase { - private val imeHelper by lazy { KeyMapperImeHelper(inputMethodAdapter) } + private val imeHelper by lazy { + KeyMapperImeHelper( + inputMethodAdapter, + buildConfigProvider.packageName, + ) + } override val isRootGranted: Flow = suAdapter.isGranted @@ -85,9 +90,9 @@ class ConfigSettingsUseCaseImpl( imeHelper.enableCompatibleInputMethods() } - override suspend fun chooseCompatibleIme(): Result = imeHelper.chooseCompatibleInputMethod() + override suspend fun chooseCompatibleIme(): KMResult = imeHelper.chooseCompatibleInputMethod() - override suspend fun showImePicker(): Result<*> = inputMethodAdapter.showImePicker(fromForeground = true) + override suspend fun showImePicker(): KMResult<*> = inputMethodAdapter.showImePicker(fromForeground = true) override fun getPreference(key: Preferences.Key) = preferences.get(key) @@ -191,8 +196,8 @@ interface ConfigSettingsUseCase { val isCompatibleImeChosen: Flow val isCompatibleImeEnabled: Flow suspend fun enableCompatibleIme() - suspend fun chooseCompatibleIme(): Result - suspend fun showImePicker(): Result<*> + suspend fun chooseCompatibleIme(): KMResult + suspend fun showImePicker(): KMResult<*> val defaultLongPressDelay: Flow val defaultDoublePressDelay: Flow diff --git a/app/src/main/java/io/github/sds100/keymapper/settings/DefaultOptionsSettingsFragment.kt b/base/src/main/java/io/github/sds100/keymapper/base/settings/DefaultOptionsSettingsFragment.kt similarity index 95% rename from app/src/main/java/io/github/sds100/keymapper/settings/DefaultOptionsSettingsFragment.kt rename to base/src/main/java/io/github/sds100/keymapper/base/settings/DefaultOptionsSettingsFragment.kt index 02b7b1c918..051ba20271 100644 --- a/app/src/main/java/io/github/sds100/keymapper/settings/DefaultOptionsSettingsFragment.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/settings/DefaultOptionsSettingsFragment.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.settings +package io.github.sds100.keymapper.base.settings import android.os.Bundle import android.view.View @@ -6,18 +6,15 @@ import androidx.lifecycle.Lifecycle import androidx.preference.Preference import androidx.preference.SeekBarPreference import androidx.preference.isEmpty -import io.github.sds100.keymapper.R +import io.github.sds100.keymapper.base.R +import io.github.sds100.keymapper.base.utils.ui.SliderMaximums +import io.github.sds100.keymapper.base.utils.ui.SliderMinimums +import io.github.sds100.keymapper.base.utils.ui.launchRepeatOnLifecycle +import io.github.sds100.keymapper.base.utils.ui.viewLifecycleScope import io.github.sds100.keymapper.data.Keys import io.github.sds100.keymapper.data.PreferenceDefaults -import io.github.sds100.keymapper.util.launchRepeatOnLifecycle -import io.github.sds100.keymapper.util.ui.SliderMaximums -import io.github.sds100.keymapper.util.ui.SliderMinimums -import io.github.sds100.keymapper.util.viewLifecycleScope import kotlinx.coroutines.flow.collectLatest -/** - * Created by sds100 on 16/07/2021. - */ class DefaultOptionsSettingsFragment : BaseSettingsFragment() { override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { diff --git a/app/src/main/java/io/github/sds100/keymapper/settings/ImePickerSettingsFragment.kt b/base/src/main/java/io/github/sds100/keymapper/base/settings/ImePickerSettingsFragment.kt similarity index 92% rename from app/src/main/java/io/github/sds100/keymapper/settings/ImePickerSettingsFragment.kt rename to base/src/main/java/io/github/sds100/keymapper/base/settings/ImePickerSettingsFragment.kt index 2e9e85cd3e..84a58b17ba 100644 --- a/app/src/main/java/io/github/sds100/keymapper/settings/ImePickerSettingsFragment.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/settings/ImePickerSettingsFragment.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.settings +package io.github.sds100.keymapper.base.settings import android.os.Build import android.os.Bundle @@ -7,15 +7,12 @@ import androidx.annotation.RequiresApi import androidx.preference.Preference import androidx.preference.SwitchPreferenceCompat import androidx.preference.isEmpty -import io.github.sds100.keymapper.R +import io.github.sds100.keymapper.base.R +import io.github.sds100.keymapper.base.system.notifications.NotificationController +import io.github.sds100.keymapper.base.utils.ui.viewLifecycleScope import io.github.sds100.keymapper.data.Keys -import io.github.sds100.keymapper.system.notifications.NotificationController import io.github.sds100.keymapper.system.notifications.NotificationUtils -import io.github.sds100.keymapper.util.viewLifecycleScope -/** - * Created by sds100 on 18/07/2021. - */ class ImePickerSettingsFragment : BaseSettingsFragment() { override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { diff --git a/app/src/main/java/io/github/sds100/keymapper/settings/MainSettingsFragment.kt b/base/src/main/java/io/github/sds100/keymapper/base/settings/MainSettingsFragment.kt similarity index 96% rename from app/src/main/java/io/github/sds100/keymapper/settings/MainSettingsFragment.kt rename to base/src/main/java/io/github/sds100/keymapper/base/settings/MainSettingsFragment.kt index 5c887d835e..072e8cedb7 100644 --- a/app/src/main/java/io/github/sds100/keymapper/settings/MainSettingsFragment.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/settings/MainSettingsFragment.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.settings +package io.github.sds100.keymapper.base.settings import android.annotation.SuppressLint import android.content.ActivityNotFoundException @@ -15,28 +15,25 @@ import androidx.preference.Preference import androidx.preference.PreferenceCategory import androidx.preference.SwitchPreferenceCompat import androidx.preference.isEmpty -import io.github.sds100.keymapper.R -import io.github.sds100.keymapper.backup.BackupUtils +import io.github.sds100.keymapper.base.R +import io.github.sds100.keymapper.base.backup.BackupUtils +import io.github.sds100.keymapper.base.system.notifications.NotificationController +import io.github.sds100.keymapper.base.utils.ui.launchRepeatOnLifecycle +import io.github.sds100.keymapper.base.utils.ui.str +import io.github.sds100.keymapper.base.utils.ui.strArray +import io.github.sds100.keymapper.base.utils.ui.viewLifecycleScope +import io.github.sds100.keymapper.common.utils.firstBlocking import io.github.sds100.keymapper.data.Keys import io.github.sds100.keymapper.data.PreferenceDefaults -import io.github.sds100.keymapper.shizuku.ShizukuUtils import io.github.sds100.keymapper.system.files.FileUtils -import io.github.sds100.keymapper.system.notifications.NotificationController import io.github.sds100.keymapper.system.notifications.NotificationUtils -import io.github.sds100.keymapper.util.firstBlocking -import io.github.sds100.keymapper.util.launchRepeatOnLifecycle -import io.github.sds100.keymapper.util.str -import io.github.sds100.keymapper.util.strArray -import io.github.sds100.keymapper.util.viewLifecycleScope +import io.github.sds100.keymapper.system.shizuku.ShizukuUtils import kotlinx.coroutines.flow.collectLatest import splitties.alertdialog.appcompat.alertDialog import splitties.alertdialog.appcompat.messageResource import splitties.alertdialog.appcompat.negativeButton import splitties.alertdialog.appcompat.positiveButton -/** - * Created by sds100 on 16/07/2021. - */ class MainSettingsFragment : BaseSettingsFragment() { companion object { diff --git a/app/src/main/java/io/github/sds100/keymapper/settings/SettingsUtils.kt b/base/src/main/java/io/github/sds100/keymapper/base/settings/SettingsUtils.kt similarity index 84% rename from app/src/main/java/io/github/sds100/keymapper/settings/SettingsUtils.kt rename to base/src/main/java/io/github/sds100/keymapper/base/settings/SettingsUtils.kt index c97537870c..d1728bdb56 100644 --- a/app/src/main/java/io/github/sds100/keymapper/settings/SettingsUtils.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/settings/SettingsUtils.kt @@ -1,14 +1,11 @@ -package io.github.sds100.keymapper.settings +package io.github.sds100.keymapper.base.settings import android.content.Context import androidx.annotation.StringRes import androidx.datastore.preferences.core.Preferences import androidx.preference.Preference -import io.github.sds100.keymapper.R +import io.github.sds100.keymapper.base.R -/** - * Created by sds100 on 18/07/2021. - */ object SettingsUtils { fun createChooseDevicesPreference( diff --git a/app/src/main/java/io/github/sds100/keymapper/settings/SettingsViewModel.kt b/base/src/main/java/io/github/sds100/keymapper/base/settings/SettingsViewModel.kt similarity index 70% rename from app/src/main/java/io/github/sds100/keymapper/settings/SettingsViewModel.kt rename to base/src/main/java/io/github/sds100/keymapper/base/settings/SettingsViewModel.kt index 6c96e76939..34d20d304a 100644 --- a/app/src/main/java/io/github/sds100/keymapper/settings/SettingsViewModel.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/settings/SettingsViewModel.kt @@ -1,40 +1,39 @@ -package io.github.sds100.keymapper.settings +package io.github.sds100.keymapper.base.settings import androidx.datastore.preferences.core.Preferences import androidx.lifecycle.ViewModel -import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.viewModelScope -import io.github.sds100.keymapper.R -import io.github.sds100.keymapper.util.SharedPrefsDataStoreWrapper -import io.github.sds100.keymapper.util.State -import io.github.sds100.keymapper.util.getFullMessage -import io.github.sds100.keymapper.util.onFailure -import io.github.sds100.keymapper.util.onSuccess -import io.github.sds100.keymapper.util.otherwise -import io.github.sds100.keymapper.util.ui.DialogResponse -import io.github.sds100.keymapper.util.ui.MultiChoiceItem -import io.github.sds100.keymapper.util.ui.PopupUi -import io.github.sds100.keymapper.util.ui.PopupViewModel -import io.github.sds100.keymapper.util.ui.PopupViewModelImpl -import io.github.sds100.keymapper.util.ui.ResourceProvider -import io.github.sds100.keymapper.util.ui.showPopup +import dagger.hilt.android.lifecycle.HiltViewModel +import io.github.sds100.keymapper.base.R +import io.github.sds100.keymapper.base.utils.getFullMessage +import io.github.sds100.keymapper.base.utils.ui.DialogModel +import io.github.sds100.keymapper.base.utils.ui.DialogProvider +import io.github.sds100.keymapper.base.utils.ui.DialogResponse +import io.github.sds100.keymapper.base.utils.ui.MultiChoiceItem +import io.github.sds100.keymapper.base.utils.ui.ResourceProvider +import io.github.sds100.keymapper.base.utils.ui.showDialog +import io.github.sds100.keymapper.common.utils.State +import io.github.sds100.keymapper.common.utils.onFailure +import io.github.sds100.keymapper.common.utils.onSuccess +import io.github.sds100.keymapper.common.utils.otherwise +import io.github.sds100.keymapper.data.utils.SharedPrefsDataStoreWrapper import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch +import javax.inject.Inject -/** - * Created by sds100 on 19/01/21. - */ -class SettingsViewModel( +@HiltViewModel +class SettingsViewModel @Inject constructor( private val useCase: ConfigSettingsUseCase, - resourceProvider: ResourceProvider, + private val resourceProvider: ResourceProvider, + dialogProvider: DialogProvider, + val sharedPrefsDataStoreWrapper: SharedPrefsDataStoreWrapper, ) : ViewModel(), - PopupViewModel by PopupViewModelImpl(), + DialogProvider by dialogProvider, ResourceProvider by resourceProvider { - val sharedPrefsDataStoreWrapper = SharedPrefsDataStoreWrapper(useCase) val automaticBackupLocation = useCase.automaticBackupLocation @@ -79,21 +78,21 @@ class SettingsViewModel( .chooseCompatibleIme() .onSuccess { ime -> val snackBar = - PopupUi.SnackBar( + DialogModel.SnackBar( message = getString( R.string.toast_chose_keyboard, ime.label, ), ) - showPopup("chose_ime_success", snackBar) + showDialog("chose_ime_success", snackBar) } .otherwise { useCase.showImePicker() } .onFailure { error -> val snackBar = - PopupUi.SnackBar(message = error.getFullMessage(this@SettingsViewModel)) - showPopup("chose_ime_error", snackBar) + DialogModel.SnackBar(message = error.getFullMessage(this@SettingsViewModel)) + showDialog("chose_ime_error", snackBar) } } } @@ -103,15 +102,15 @@ class SettingsViewModel( val soundFiles = useCase.getSoundFiles() if (soundFiles.isEmpty()) { - showPopup("no sound files", PopupUi.Toast(getString(R.string.toast_no_sound_files))) + showDialog("no sound files", DialogModel.Toast(getString(R.string.toast_no_sound_files))) return@launch } - val dialog = PopupUi.MultiChoice( + val dialog = DialogModel.MultiChoice( items = soundFiles.map { MultiChoiceItem(it.uid, it.name) }, ) - val selectedFiles = showPopup("select_sound_files_to_delete", dialog) ?: return@launch + val selectedFiles = showDialog("select_sound_files_to_delete", dialog) ?: return@launch useCase.deleteSoundFiles(selectedFiles) } @@ -157,16 +156,16 @@ class SettingsViewModel( .filter { it.isExternal } if (externalDevices.isEmpty()) { - val dialog = PopupUi.Dialog( + val dialog = DialogModel.Alert( message = getString(R.string.dialog_message_settings_no_external_devices_connected), positiveButtonText = getString(R.string.pos_ok), ) - showPopup("no_external_devices", dialog) + showDialog("no_external_devices", dialog) } else { val checkedDevices = useCase.getPreference(prefKey).first() ?: emptySet() - val dialog = PopupUi.MultiChoice( + val dialog = DialogModel.MultiChoice( items = externalDevices.map { device -> MultiChoiceItem( id = device.descriptor, @@ -176,7 +175,7 @@ class SettingsViewModel( }, ) - val newCheckedDevices = showPopup("choose_device", dialog) ?: return@launch + val newCheckedDevices = showDialog("choose_device", dialog) ?: return@launch useCase.setPreference(prefKey, newCheckedDevices.toSet()) } @@ -184,18 +183,18 @@ class SettingsViewModel( } fun onCreateBackupFileActivityNotFound() { - val dialog = PopupUi.Dialog( + val dialog = DialogModel.Alert( message = getString(R.string.dialog_message_no_app_found_to_create_file), positiveButtonText = getString(R.string.pos_ok), ) viewModelScope.launch { - showPopup("create_document_activity_not_found", dialog) + showDialog("create_document_activity_not_found", dialog) } } fun onResetAllSettingsClick() { - val dialog = PopupUi.Dialog( + val dialog = DialogModel.Alert( title = getString(R.string.dialog_title_reset_settings), message = getString(R.string.dialog_message_reset_settings), positiveButtonText = getString(R.string.pos_button_reset_settings), @@ -203,23 +202,11 @@ class SettingsViewModel( ) viewModelScope.launch { - val response = showPopup("reset_settings_dialog", dialog) + val response = showDialog("reset_settings_dialog", dialog) if (response == DialogResponse.POSITIVE) { useCase.resetAllSettings() } } } - - @Suppress("UNCHECKED_CAST") - class Factory( - private val configSettingsUseCase: ConfigSettingsUseCase, - private val resourceProvider: ResourceProvider, - ) : ViewModelProvider.NewInstanceFactory() { - - override fun create(modelClass: Class): T = SettingsViewModel( - configSettingsUseCase, - resourceProvider, - ) as T - } } diff --git a/app/src/main/java/io/github/sds100/keymapper/settings/ShizukuSettingsFragment.kt b/base/src/main/java/io/github/sds100/keymapper/base/settings/ShizukuSettingsFragment.kt similarity index 93% rename from app/src/main/java/io/github/sds100/keymapper/settings/ShizukuSettingsFragment.kt rename to base/src/main/java/io/github/sds100/keymapper/base/settings/ShizukuSettingsFragment.kt index 2c533acfc8..d55063e4f9 100644 --- a/app/src/main/java/io/github/sds100/keymapper/settings/ShizukuSettingsFragment.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/settings/ShizukuSettingsFragment.kt @@ -1,23 +1,20 @@ -package io.github.sds100.keymapper.settings +package io.github.sds100.keymapper.base.settings import android.os.Bundle import android.view.View import androidx.lifecycle.Lifecycle import androidx.preference.Preference import androidx.preference.isEmpty -import io.github.sds100.keymapper.R +import io.github.sds100.keymapper.base.R +import io.github.sds100.keymapper.base.utils.ui.drawable +import io.github.sds100.keymapper.base.utils.ui.launchRepeatOnLifecycle +import io.github.sds100.keymapper.base.utils.ui.str +import io.github.sds100.keymapper.base.utils.ui.viewLifecycleScope import io.github.sds100.keymapper.system.url.UrlUtils -import io.github.sds100.keymapper.util.drawable -import io.github.sds100.keymapper.util.launchRepeatOnLifecycle -import io.github.sds100.keymapper.util.str -import io.github.sds100.keymapper.util.viewLifecycleScope import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.launchIn -/** - * Created by sds100 on 18/07/2021. - */ class ShizukuSettingsFragment : BaseSettingsFragment() { override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { diff --git a/app/src/main/java/io/github/sds100/keymapper/settings/ThemeUtils.kt b/base/src/main/java/io/github/sds100/keymapper/base/settings/ThemeUtils.kt similarity index 60% rename from app/src/main/java/io/github/sds100/keymapper/settings/ThemeUtils.kt rename to base/src/main/java/io/github/sds100/keymapper/base/settings/ThemeUtils.kt index 83a6a98994..63d6110cf6 100644 --- a/app/src/main/java/io/github/sds100/keymapper/settings/ThemeUtils.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/settings/ThemeUtils.kt @@ -1,8 +1,4 @@ -package io.github.sds100.keymapper.settings - -/** - * Created by sds100 on 14/02/2021. - */ +package io.github.sds100.keymapper.base.settings object ThemeUtils { const val DARK = 0 diff --git a/app/src/main/java/io/github/sds100/keymapper/sorting/SortBottomSheetContent.kt b/base/src/main/java/io/github/sds100/keymapper/base/sorting/SortBottomSheetContent.kt similarity index 98% rename from app/src/main/java/io/github/sds100/keymapper/sorting/SortBottomSheetContent.kt rename to base/src/main/java/io/github/sds100/keymapper/base/sorting/SortBottomSheetContent.kt index fbfedd964e..066a14a68d 100644 --- a/app/src/main/java/io/github/sds100/keymapper/sorting/SortBottomSheetContent.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/sorting/SortBottomSheetContent.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.sorting +package io.github.sds100.keymapper.base.sorting import androidx.compose.animation.AnimatedContent import androidx.compose.animation.AnimatedVisibility @@ -68,10 +68,10 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.IntOffset import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle -import io.github.sds100.keymapper.R -import io.github.sds100.keymapper.compose.KeyMapperTheme -import io.github.sds100.keymapper.util.ui.compose.DraggableItem -import io.github.sds100.keymapper.util.ui.compose.rememberDragDropState +import io.github.sds100.keymapper.base.R +import io.github.sds100.keymapper.base.compose.KeyMapperTheme +import io.github.sds100.keymapper.base.utils.ui.compose.DraggableItem +import io.github.sds100.keymapper.base.utils.ui.compose.rememberDragDropState import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch @@ -180,6 +180,7 @@ private fun SortBottomSheetContent( ) { // Use fully qualified name due to quirky overload resolution. The compiler will // otherwise tell you to use it in a column or row scope. + @Suppress("RemoveRedundantQualifierName") androidx.compose.animation.AnimatedVisibility( modifier = Modifier.align(Alignment.CenterStart), visible = !showHelp, diff --git a/app/src/main/java/io/github/sds100/keymapper/sorting/SortField.kt b/base/src/main/java/io/github/sds100/keymapper/base/sorting/SortField.kt similarity index 74% rename from app/src/main/java/io/github/sds100/keymapper/sorting/SortField.kt rename to base/src/main/java/io/github/sds100/keymapper/base/sorting/SortField.kt index f7831ad790..aac5250d86 100644 --- a/app/src/main/java/io/github/sds100/keymapper/sorting/SortField.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/sorting/SortField.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.sorting +package io.github.sds100.keymapper.base.sorting import kotlinx.serialization.Serializable diff --git a/app/src/main/java/io/github/sds100/keymapper/sorting/SortFieldOrder.kt b/base/src/main/java/io/github/sds100/keymapper/base/sorting/SortFieldOrder.kt similarity index 76% rename from app/src/main/java/io/github/sds100/keymapper/sorting/SortFieldOrder.kt rename to base/src/main/java/io/github/sds100/keymapper/base/sorting/SortFieldOrder.kt index d006a8b385..503f8136e8 100644 --- a/app/src/main/java/io/github/sds100/keymapper/sorting/SortFieldOrder.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/sorting/SortFieldOrder.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.sorting +package io.github.sds100.keymapper.base.sorting import kotlinx.serialization.Serializable diff --git a/app/src/main/java/io/github/sds100/keymapper/sorting/SortKeyMapsUseCase.kt b/base/src/main/java/io/github/sds100/keymapper/base/sorting/SortKeyMapsUseCase.kt similarity index 84% rename from app/src/main/java/io/github/sds100/keymapper/sorting/SortKeyMapsUseCase.kt rename to base/src/main/java/io/github/sds100/keymapper/base/sorting/SortKeyMapsUseCase.kt index 03b9ca6835..3f8bf662b7 100644 --- a/app/src/main/java/io/github/sds100/keymapper/sorting/SortKeyMapsUseCase.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/sorting/SortKeyMapsUseCase.kt @@ -1,20 +1,21 @@ -package io.github.sds100.keymapper.sorting - +package io.github.sds100.keymapper.base.sorting + +import io.github.sds100.keymapper.base.keymaps.DisplayKeyMapUseCase +import io.github.sds100.keymapper.base.keymaps.KeyMap +import io.github.sds100.keymapper.base.sorting.comparators.KeyMapActionsComparator +import io.github.sds100.keymapper.base.sorting.comparators.KeyMapConstraintsComparator +import io.github.sds100.keymapper.base.sorting.comparators.KeyMapOptionsComparator +import io.github.sds100.keymapper.base.sorting.comparators.KeyMapTriggerComparator import io.github.sds100.keymapper.data.Keys import io.github.sds100.keymapper.data.repositories.PreferenceRepository -import io.github.sds100.keymapper.keymaps.DisplayKeyMapUseCase -import io.github.sds100.keymapper.keymaps.KeyMap -import io.github.sds100.keymapper.sorting.comparators.KeyMapActionsComparator -import io.github.sds100.keymapper.sorting.comparators.KeyMapConstraintsComparator -import io.github.sds100.keymapper.sorting.comparators.KeyMapOptionsComparator -import io.github.sds100.keymapper.sorting.comparators.KeyMapTriggerComparator import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.map import kotlinx.serialization.json.Json +import javax.inject.Inject -class SortKeyMapsUseCaseImpl( +class SortKeyMapsUseCaseImpl @Inject constructor( private val preferenceRepository: PreferenceRepository, - private val displaySimpleMappingUseCase: DisplayKeyMapUseCase, + private val displayKeyMapUseCase: DisplayKeyMapUseCase, ) : SortKeyMapsUseCase { override val showHelp = preferenceRepository.get(Keys.sortShowHelp).map { it ?: true } @@ -72,9 +73,9 @@ class SortKeyMapsUseCaseImpl( return when (sortFieldOrder.field) { SortField.TRIGGER -> KeyMapTriggerComparator(reverseOrder) - SortField.ACTIONS -> KeyMapActionsComparator(displaySimpleMappingUseCase, reverseOrder) + SortField.ACTIONS -> KeyMapActionsComparator(displayKeyMapUseCase, reverseOrder) SortField.CONSTRAINTS -> KeyMapConstraintsComparator( - displaySimpleMappingUseCase, + displayKeyMapUseCase, reverseOrder, ) diff --git a/app/src/main/java/io/github/sds100/keymapper/sorting/SortOrder.kt b/base/src/main/java/io/github/sds100/keymapper/base/sorting/SortOrder.kt similarity index 86% rename from app/src/main/java/io/github/sds100/keymapper/sorting/SortOrder.kt rename to base/src/main/java/io/github/sds100/keymapper/base/sorting/SortOrder.kt index 60130d549d..6f52942675 100644 --- a/app/src/main/java/io/github/sds100/keymapper/sorting/SortOrder.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/sorting/SortOrder.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.sorting +package io.github.sds100.keymapper.base.sorting import kotlinx.serialization.Serializable diff --git a/app/src/main/java/io/github/sds100/keymapper/sorting/SortViewModel.kt b/base/src/main/java/io/github/sds100/keymapper/base/sorting/SortViewModel.kt similarity index 97% rename from app/src/main/java/io/github/sds100/keymapper/sorting/SortViewModel.kt rename to base/src/main/java/io/github/sds100/keymapper/base/sorting/SortViewModel.kt index 70cdbb1181..fd7ab6ed4a 100644 --- a/app/src/main/java/io/github/sds100/keymapper/sorting/SortViewModel.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/sorting/SortViewModel.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.sorting +package io.github.sds100.keymapper.base.sorting import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.MutableStateFlow diff --git a/app/src/main/java/io/github/sds100/keymapper/sorting/comparators/KeyMapActionsComparator.kt b/base/src/main/java/io/github/sds100/keymapper/base/sorting/comparators/KeyMapActionsComparator.kt similarity index 87% rename from app/src/main/java/io/github/sds100/keymapper/sorting/comparators/KeyMapActionsComparator.kt rename to base/src/main/java/io/github/sds100/keymapper/base/sorting/comparators/KeyMapActionsComparator.kt index 479b5a3922..53ffdbb46f 100644 --- a/app/src/main/java/io/github/sds100/keymapper/sorting/comparators/KeyMapActionsComparator.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/sorting/comparators/KeyMapActionsComparator.kt @@ -1,11 +1,11 @@ -package io.github.sds100.keymapper.sorting.comparators +package io.github.sds100.keymapper.base.sorting.comparators -import io.github.sds100.keymapper.actions.ActionData -import io.github.sds100.keymapper.actions.DisplayActionUseCase -import io.github.sds100.keymapper.keymaps.KeyMap -import io.github.sds100.keymapper.util.Result -import io.github.sds100.keymapper.util.Success -import io.github.sds100.keymapper.util.valueOrNull +import io.github.sds100.keymapper.base.actions.ActionData +import io.github.sds100.keymapper.base.actions.DisplayActionUseCase +import io.github.sds100.keymapper.base.keymaps.KeyMap +import io.github.sds100.keymapper.common.utils.KMResult +import io.github.sds100.keymapper.common.utils.Success +import io.github.sds100.keymapper.common.utils.valueOrNull class KeyMapActionsComparator( private val displayActions: DisplayActionUseCase, @@ -63,7 +63,7 @@ class KeyMapActionsComparator( result } - private fun getSecondarySortField(action: ActionData): Result { + private fun getSecondarySortField(action: ActionData): KMResult { return when (action) { is ActionData.App -> displayActions.getAppName(action.packageName) is ActionData.AppShortcut -> Success(action.shortcutTitle) diff --git a/app/src/main/java/io/github/sds100/keymapper/sorting/comparators/KeyMapConstraintsComparator.kt b/base/src/main/java/io/github/sds100/keymapper/base/sorting/comparators/KeyMapConstraintsComparator.kt similarity index 90% rename from app/src/main/java/io/github/sds100/keymapper/sorting/comparators/KeyMapConstraintsComparator.kt rename to base/src/main/java/io/github/sds100/keymapper/base/sorting/comparators/KeyMapConstraintsComparator.kt index 036e4ec9af..0f9f9a0987 100644 --- a/app/src/main/java/io/github/sds100/keymapper/sorting/comparators/KeyMapConstraintsComparator.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/sorting/comparators/KeyMapConstraintsComparator.kt @@ -1,12 +1,12 @@ -package io.github.sds100.keymapper.sorting.comparators - -import io.github.sds100.keymapper.constraints.Constraint -import io.github.sds100.keymapper.constraints.DisplayConstraintUseCase -import io.github.sds100.keymapper.keymaps.KeyMap -import io.github.sds100.keymapper.util.Result -import io.github.sds100.keymapper.util.Success -import io.github.sds100.keymapper.util.then -import io.github.sds100.keymapper.util.valueOrNull +package io.github.sds100.keymapper.base.sorting.comparators + +import io.github.sds100.keymapper.base.constraints.Constraint +import io.github.sds100.keymapper.base.constraints.DisplayConstraintUseCase +import io.github.sds100.keymapper.base.keymaps.KeyMap +import io.github.sds100.keymapper.common.utils.KMResult +import io.github.sds100.keymapper.common.utils.Success +import io.github.sds100.keymapper.common.utils.then +import io.github.sds100.keymapper.common.utils.valueOrNull import java.time.LocalDate import java.time.ZoneOffset @@ -85,7 +85,7 @@ class KeyMapConstraintsComparator( return constraint.id.ordinal.compareTo(otherConstraint.id.ordinal) } - private fun getSecondarySortField(constraint: Constraint): Result { + private fun getSecondarySortField(constraint: Constraint): KMResult { return when (constraint) { is Constraint.AppInForeground -> displayConstraints.getAppName(constraint.packageName) is Constraint.AppNotInForeground -> displayConstraints.getAppName(constraint.packageName) diff --git a/app/src/main/java/io/github/sds100/keymapper/sorting/comparators/KeyMapOptionsComparator.kt b/base/src/main/java/io/github/sds100/keymapper/base/sorting/comparators/KeyMapOptionsComparator.kt similarity index 88% rename from app/src/main/java/io/github/sds100/keymapper/sorting/comparators/KeyMapOptionsComparator.kt rename to base/src/main/java/io/github/sds100/keymapper/base/sorting/comparators/KeyMapOptionsComparator.kt index 27cf6c9ed4..448e860b59 100644 --- a/app/src/main/java/io/github/sds100/keymapper/sorting/comparators/KeyMapOptionsComparator.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/sorting/comparators/KeyMapOptionsComparator.kt @@ -1,6 +1,6 @@ -package io.github.sds100.keymapper.sorting.comparators +package io.github.sds100.keymapper.base.sorting.comparators -import io.github.sds100.keymapper.keymaps.KeyMap +import io.github.sds100.keymapper.base.keymaps.KeyMap class KeyMapOptionsComparator( /** diff --git a/app/src/main/java/io/github/sds100/keymapper/sorting/comparators/KeyMapTriggerComparator.kt b/base/src/main/java/io/github/sds100/keymapper/base/sorting/comparators/KeyMapTriggerComparator.kt similarity index 93% rename from app/src/main/java/io/github/sds100/keymapper/sorting/comparators/KeyMapTriggerComparator.kt rename to base/src/main/java/io/github/sds100/keymapper/base/sorting/comparators/KeyMapTriggerComparator.kt index 47ef0131aa..70768d8b16 100644 --- a/app/src/main/java/io/github/sds100/keymapper/sorting/comparators/KeyMapTriggerComparator.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/sorting/comparators/KeyMapTriggerComparator.kt @@ -1,6 +1,6 @@ -package io.github.sds100.keymapper.sorting.comparators +package io.github.sds100.keymapper.base.sorting.comparators -import io.github.sds100.keymapper.keymaps.KeyMap +import io.github.sds100.keymapper.base.keymaps.KeyMap class KeyMapTriggerComparator( /** diff --git a/base/src/main/java/io/github/sds100/keymapper/base/system/accessibility/AccessibilityNodeAction.kt b/base/src/main/java/io/github/sds100/keymapper/base/system/accessibility/AccessibilityNodeAction.kt new file mode 100644 index 0000000000..398366d7cb --- /dev/null +++ b/base/src/main/java/io/github/sds100/keymapper/base/system/accessibility/AccessibilityNodeAction.kt @@ -0,0 +1,3 @@ +package io.github.sds100.keymapper.base.system.accessibility + +data class AccessibilityNodeAction(val action: Int, val extras: Map = emptyMap()) diff --git a/app/src/main/java/io/github/sds100/keymapper/system/accessibility/AccessibilityNodeModel.kt b/base/src/main/java/io/github/sds100/keymapper/base/system/accessibility/AccessibilityNodeModel.kt similarity index 85% rename from app/src/main/java/io/github/sds100/keymapper/system/accessibility/AccessibilityNodeModel.kt rename to base/src/main/java/io/github/sds100/keymapper/base/system/accessibility/AccessibilityNodeModel.kt index 08f5a14e04..c7957bf444 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/accessibility/AccessibilityNodeModel.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/system/accessibility/AccessibilityNodeModel.kt @@ -1,12 +1,9 @@ -package io.github.sds100.keymapper.system.accessibility +package io.github.sds100.keymapper.base.system.accessibility import android.os.Build import androidx.annotation.RequiresApi import kotlinx.serialization.Serializable -/** - * Created by sds100 on 21/04/2021. - */ @Serializable data class AccessibilityNodeModel( val packageName: String?, diff --git a/app/src/main/java/io/github/sds100/keymapper/system/accessibility/AccessibilityNodeRecorder.kt b/base/src/main/java/io/github/sds100/keymapper/base/system/accessibility/AccessibilityNodeRecorder.kt similarity index 90% rename from app/src/main/java/io/github/sds100/keymapper/system/accessibility/AccessibilityNodeRecorder.kt rename to base/src/main/java/io/github/sds100/keymapper/base/system/accessibility/AccessibilityNodeRecorder.kt index becc2fcf78..769d70a7da 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/accessibility/AccessibilityNodeRecorder.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/system/accessibility/AccessibilityNodeRecorder.kt @@ -1,21 +1,29 @@ -package io.github.sds100.keymapper.system.accessibility +package io.github.sds100.keymapper.base.system.accessibility -import android.accessibilityservice.AccessibilityService import android.os.Build import android.os.CountDownTimer import android.view.accessibility.AccessibilityEvent import android.view.accessibility.AccessibilityNodeInfo -import io.github.sds100.keymapper.actions.uielement.NodeInteractionType +import dagger.assisted.Assisted +import dagger.assisted.AssistedFactory +import dagger.assisted.AssistedInject +import io.github.sds100.keymapper.common.utils.NodeInteractionType import io.github.sds100.keymapper.data.entities.AccessibilityNodeEntity import io.github.sds100.keymapper.data.repositories.AccessibilityNodeRepository import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.update -class AccessibilityNodeRecorder( +class AccessibilityNodeRecorder @AssistedInject constructor( + @Assisted + private val service: BaseAccessibilityService, private val nodeRepository: AccessibilityNodeRepository, - private val service: AccessibilityService, ) { + @AssistedFactory + interface Factory { + fun create(service: BaseAccessibilityService): AccessibilityNodeRecorder + } + companion object { private const val RECORD_DURATION = 60000L } diff --git a/app/src/main/java/io/github/sds100/keymapper/system/accessibility/AccessibilityServiceAdapter.kt b/base/src/main/java/io/github/sds100/keymapper/base/system/accessibility/AccessibilityServiceAdapterImpl.kt similarity index 74% rename from app/src/main/java/io/github/sds100/keymapper/system/accessibility/AccessibilityServiceAdapter.kt rename to base/src/main/java/io/github/sds100/keymapper/base/system/accessibility/AccessibilityServiceAdapterImpl.kt index 55b25836ee..01cb749de0 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/accessibility/AccessibilityServiceAdapter.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/system/accessibility/AccessibilityServiceAdapterImpl.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.system.accessibility +package io.github.sds100.keymapper.base.system.accessibility import android.content.ActivityNotFoundException import android.content.Context @@ -9,18 +9,21 @@ import android.os.Build import android.os.Handler import android.os.Looper import android.provider.Settings -import io.github.sds100.keymapper.Constants -import io.github.sds100.keymapper.ServiceLocator +import dagger.hilt.android.qualifiers.ApplicationContext +import io.github.sds100.keymapper.common.BuildConfigProvider +import io.github.sds100.keymapper.common.KeyMapperClassProvider +import io.github.sds100.keymapper.common.utils.KMError +import io.github.sds100.keymapper.common.utils.KMResult +import io.github.sds100.keymapper.common.utils.Success +import io.github.sds100.keymapper.common.utils.onFailure +import io.github.sds100.keymapper.common.utils.onSuccess import io.github.sds100.keymapper.system.JobSchedulerHelper import io.github.sds100.keymapper.system.SettingsUtils +import io.github.sds100.keymapper.system.accessibility.AccessibilityServiceAdapter +import io.github.sds100.keymapper.system.accessibility.AccessibilityServiceEvent +import io.github.sds100.keymapper.system.accessibility.AccessibilityServiceState import io.github.sds100.keymapper.system.permissions.Permission import io.github.sds100.keymapper.system.permissions.PermissionAdapter -import io.github.sds100.keymapper.util.Error -import io.github.sds100.keymapper.util.Result -import io.github.sds100.keymapper.util.ServiceEvent -import io.github.sds100.keymapper.util.Success -import io.github.sds100.keymapper.util.onFailure -import io.github.sds100.keymapper.util.onSuccess import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.delay import kotlinx.coroutines.flow.MutableSharedFlow @@ -32,23 +35,24 @@ import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch import kotlinx.coroutines.withTimeoutOrNull import timber.log.Timber +import javax.inject.Inject +import javax.inject.Singleton -/** - * Created by sds100 on 17/03/2021. - */ -class AccessibilityServiceAdapter( - context: Context, +@Singleton +class AccessibilityServiceAdapterImpl @Inject constructor( + @ApplicationContext context: Context, private val coroutineScope: CoroutineScope, -) : ServiceAdapter { + private val permissionAdapter: PermissionAdapter, + private val buildConfigProvider: BuildConfigProvider, + private val classProvider: KeyMapperClassProvider, +) : AccessibilityServiceAdapter { private val ctx = context.applicationContext - override val eventReceiver = MutableSharedFlow() + override val eventReceiver = MutableSharedFlow() - val eventsToService = MutableSharedFlow() + val eventsToService = MutableSharedFlow() - override val state = MutableStateFlow(ServiceState.DISABLED) - - private val permissionAdapter: PermissionAdapter by lazy { ServiceLocator.permissionAdapter(ctx) } + override val state = MutableStateFlow(AccessibilityServiceState.DISABLED) init { // use job scheduler because there is there is a much shorter delay when the app is in the background @@ -78,23 +82,23 @@ class AccessibilityServiceAdapter( }.launchIn(coroutineScope) } - override fun sendAsync(event: ServiceEvent) { + override fun sendAsync(event: AccessibilityServiceEvent) { coroutineScope.launch { eventsToService.emit(event) } } - override suspend fun send(event: ServiceEvent): Result<*> { + override suspend fun send(event: AccessibilityServiceEvent): KMResult<*> { state.value = getState() - if (state.value == ServiceState.DISABLED) { + if (state.value == AccessibilityServiceState.DISABLED) { Timber.e("Failed to send event to accessibility service because disabled: $event") - return Error.AccessibilityServiceDisabled + return KMError.AccessibilityServiceDisabled } - if (state.value == ServiceState.CRASHED) { + if (state.value == AccessibilityServiceState.CRASHED) { Timber.e("Failed to send event to accessibility service because crashed: $event") - return Error.AccessibilityServiceCrashed + return KMError.AccessibilityServiceCrashed } coroutineScope.launch { @@ -123,11 +127,11 @@ class AccessibilityServiceAdapter( delay(100) Timber.d("Ping service to check if crashed") - eventsToService.emit(ServiceEvent.Ping(key)) + eventsToService.emit(AccessibilityServiceEvent.Ping(key)) } - val pong: ServiceEvent.Pong? = withTimeoutOrNull(2000L) { - eventReceiver.first { it == ServiceEvent.Pong(key) } as ServiceEvent.Pong? + val pong: AccessibilityServiceEvent.Pong? = withTimeoutOrNull(2000L) { + eventReceiver.first { it == AccessibilityServiceEvent.Pong(key) } as AccessibilityServiceEvent.Pong? } if (pong == null) { @@ -195,7 +199,7 @@ class AccessibilityServiceAdapter( private suspend fun disableServiceSuspend() { // disableSelf method only exists in 7.0.0+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - send(ServiceEvent.DisableService).onSuccess { + send(AccessibilityServiceEvent.DisableService).onSuccess { Timber.i("Disabling service by calling disableSelf()") return @@ -214,9 +218,9 @@ class AccessibilityServiceAdapter( enabledServices ?: return - val className = MyAccessibilityService::class.java.name + val className = classProvider.getAccessibilityService().name - val keyMapperEntry = "${Constants.PACKAGE_NAME}/$className" + val keyMapperEntry = "${buildConfigProvider.packageName}/$className" val newEnabledServices = if (enabledServices.contains(keyMapperEntry)) { val services = enabledServices.split(':').toMutableList() @@ -245,13 +249,13 @@ class AccessibilityServiceAdapter( val pingJob = coroutineScope.launch { repeat(20) { - eventsToService.emit(ServiceEvent.Ping(key)) + eventsToService.emit(AccessibilityServiceEvent.Ping(key)) delay(100) } } - val pong: ServiceEvent.Pong? = withTimeoutOrNull(2000L) { - eventReceiver.first { it == ServiceEvent.Pong(key) } as ServiceEvent.Pong? + val pong: AccessibilityServiceEvent.Pong? = withTimeoutOrNull(2000L) { + eventReceiver.first { it == AccessibilityServiceEvent.Pong(key) } as AccessibilityServiceEvent.Pong? } pingJob.cancel() @@ -265,15 +269,15 @@ class AccessibilityServiceAdapter( override fun acknowledgeCrashed() { state.update { old -> - if (old == ServiceState.CRASHED) { - ServiceState.DISABLED + if (old == AccessibilityServiceState.CRASHED) { + AccessibilityServiceState.DISABLED } else { - ServiceState.ENABLED + AccessibilityServiceState.ENABLED } } } - fun updateWhetherServiceIsEnabled() { + override fun invalidateState() { coroutineScope.launch { state.value = getState() } @@ -288,9 +292,9 @@ class AccessibilityServiceAdapter( Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, ) - val className = MyAccessibilityService::class.java.name + val className = classProvider.getAccessibilityService().name - val keyMapperEntry = "${Constants.PACKAGE_NAME}/$className" + val keyMapperEntry = "${buildConfigProvider.packageName}/$className" val newEnabledServices = when { enabledServices.isNullOrBlank() -> keyMapperEntry @@ -312,7 +316,7 @@ class AccessibilityServiceAdapter( } } - private suspend fun getState(): ServiceState { + private suspend fun getState(): AccessibilityServiceState { /* get a list of all the enabled accessibility services. * The AccessibilityManager.getEnabledAccessibilityServices() method just returns an empty * list. :(*/ @@ -322,7 +326,7 @@ class AccessibilityServiceAdapter( ) if (settingValue == null) { - return ServiceState.DISABLED + return AccessibilityServiceState.DISABLED } // it can be null if the user has never interacted with accessibility settings before @@ -337,9 +341,9 @@ class AccessibilityServiceAdapter( val isEnabled = settingValue.split(':').any { it.split('/')[0] == ctx.packageName } return when { - !isEnabled -> ServiceState.DISABLED - isCrashed() && isEnabled -> ServiceState.CRASHED - else -> ServiceState.ENABLED + !isEnabled -> AccessibilityServiceState.DISABLED + isCrashed() && isEnabled -> AccessibilityServiceState.CRASHED + else -> AccessibilityServiceState.ENABLED } } } diff --git a/app/src/main/java/io/github/sds100/keymapper/system/accessibility/AccessibilityUtils.kt b/base/src/main/java/io/github/sds100/keymapper/base/system/accessibility/AccessibilityServiceUtils.kt similarity index 92% rename from app/src/main/java/io/github/sds100/keymapper/system/accessibility/AccessibilityUtils.kt rename to base/src/main/java/io/github/sds100/keymapper/base/system/accessibility/AccessibilityServiceUtils.kt index 773486c357..900f46c2bf 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/accessibility/AccessibilityUtils.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/system/accessibility/AccessibilityServiceUtils.kt @@ -1,12 +1,8 @@ -package io.github.sds100.keymapper.system.accessibility +package io.github.sds100.keymapper.base.system.accessibility import android.os.Build import android.view.accessibility.AccessibilityNodeInfo -/** - * Created by sds100 on 06/08/2019. - */ - /** * @return The node to find. Returns null if the node doesn't match the predicate */ diff --git a/base/src/main/java/io/github/sds100/keymapper/base/system/accessibility/BaseAccessibilityService.kt b/base/src/main/java/io/github/sds100/keymapper/base/system/accessibility/BaseAccessibilityService.kt new file mode 100644 index 0000000000..a39025a574 --- /dev/null +++ b/base/src/main/java/io/github/sds100/keymapper/base/system/accessibility/BaseAccessibilityService.kt @@ -0,0 +1,581 @@ +package io.github.sds100.keymapper.base.system.accessibility + +import android.accessibilityservice.AccessibilityService +import android.accessibilityservice.FingerprintGestureController +import android.accessibilityservice.GestureDescription +import android.accessibilityservice.GestureDescription.StrokeDescription +import android.app.ActivityManager +import android.content.Intent +import android.content.res.Configuration +import android.graphics.Path +import android.graphics.Point +import android.os.Build +import android.view.KeyEvent +import android.view.MotionEvent +import android.view.accessibility.AccessibilityEvent +import androidx.core.content.getSystemService +import androidx.core.os.bundleOf +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.LifecycleOwner +import androidx.lifecycle.LifecycleRegistry +import androidx.savedstate.SavedStateRegistry +import androidx.savedstate.SavedStateRegistryController +import androidx.savedstate.SavedStateRegistryOwner +import dagger.hilt.android.AndroidEntryPoint +import io.github.sds100.keymapper.api.IKeyEventRelayServiceCallback +import io.github.sds100.keymapper.base.R +import io.github.sds100.keymapper.base.system.inputmethod.ImeInputEventInjectorImpl +import io.github.sds100.keymapper.base.trigger.KeyEventDetectionSource +import io.github.sds100.keymapper.common.utils.InputEventType +import io.github.sds100.keymapper.common.utils.KMError +import io.github.sds100.keymapper.common.utils.KMResult +import io.github.sds100.keymapper.common.utils.MathUtils +import io.github.sds100.keymapper.common.utils.PinchScreenType +import io.github.sds100.keymapper.common.utils.Success +import io.github.sds100.keymapper.system.devices.InputDeviceUtils +import io.github.sds100.keymapper.system.inputevents.MyKeyEvent +import io.github.sds100.keymapper.system.inputevents.MyMotionEvent +import io.github.sds100.keymapper.system.inputmethod.InputMethodAdapter +import io.github.sds100.keymapper.system.inputmethod.KeyEventRelayServiceWrapperImpl +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.update +import timber.log.Timber +import javax.inject.Inject + +@AndroidEntryPoint +abstract class BaseAccessibilityService : + AccessibilityService(), + LifecycleOwner, + IAccessibilityService, + SavedStateRegistryOwner { + + companion object { + + private const val CALLBACK_ID_ACCESSIBILITY_SERVICE = "accessibility_service" + } + + @Inject + lateinit var accessibilityServiceAdapter: AccessibilityServiceAdapterImpl + + @Inject + lateinit var inputMethodAdapter: InputMethodAdapter + + private var lifecycleRegistry: LifecycleRegistry = LifecycleRegistry(this) + private var savedStateRegistryController: SavedStateRegistryController? = + SavedStateRegistryController.create(this) + override val savedStateRegistry: SavedStateRegistry + get() = savedStateRegistryController!!.savedStateRegistry + + private var fingerprintGestureCallback: FingerprintGestureController.FingerprintGestureCallback? = + null + + override val rootNode: AccessibilityNodeModel? + get() { + return rootInActiveWindow?.toModel() + } + + private val _activeWindowPackage: MutableStateFlow = MutableStateFlow(null) + override val activeWindowPackage: Flow = _activeWindowPackage + + override val isFingerprintGestureDetectionAvailable: Boolean + get() = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + fingerprintGestureController.isGestureDetectionAvailable + } else { + false + } + + private val _isKeyboardHidden by lazy { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + MutableStateFlow(softKeyboardController.showMode == SHOW_MODE_HIDDEN) + } else { + MutableStateFlow(false) + } + } + + override val isKeyboardHidden: Flow + get() = _isKeyboardHidden + + override fun switchIme(imeId: String) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + softKeyboardController.switchToInputMethod(imeId) + } + } + + override var serviceFlags: Int? + get() = serviceInfo?.flags + set(value) { + if (serviceInfo != null && value != null) { + serviceInfo = serviceInfo.apply { + flags = value + } + } + } + + override var serviceFeedbackType: Int? + get() = serviceInfo?.feedbackType + set(value) { + if (serviceInfo != null && value != null) { + serviceInfo = serviceInfo.apply { + feedbackType = value + } + } + } + + override var serviceEventTypes: Int? + get() = serviceInfo?.eventTypes + set(value) { + if (serviceInfo != null && value != null) { + serviceInfo = serviceInfo.apply { + eventTypes = value + } + } + } + + override var notificationTimeout: Long? + get() = serviceInfo?.notificationTimeout + set(value) { + if (serviceInfo != null && value != null) { + serviceInfo = serviceInfo.apply { + notificationTimeout = value + } + } + } + + private val relayServiceCallback: IKeyEventRelayServiceCallback = + object : IKeyEventRelayServiceCallback.Stub() { + override fun onKeyEvent(event: KeyEvent?): Boolean { + event ?: return false + + val device = event.device?.let { InputDeviceUtils.createInputDeviceInfo(it) } + + return getController() + ?.onKeyEventFromIme( + MyKeyEvent( + keyCode = event.keyCode, + action = event.action, + metaState = event.metaState, + scanCode = event.scanCode, + device = device, + repeatCount = event.repeatCount, + source = event.source, + ), + ) ?: false + } + + override fun onMotionEvent(event: MotionEvent?): Boolean { + event ?: return false + + return getController() + ?.onMotionEventFromIme(MyMotionEvent.fromMotionEvent(event)) + ?: return false + } + } + + val keyEventRelayServiceWrapper: KeyEventRelayServiceWrapperImpl by lazy { + KeyEventRelayServiceWrapperImpl( + ctx = this, + id = CALLBACK_ID_ACCESSIBILITY_SERVICE, + servicePackageName = packageName, + callback = relayServiceCallback, + ) + } + + val imeInputEventInjector by lazy { + ImeInputEventInjectorImpl( + this, + keyEventRelayService = keyEventRelayServiceWrapper, + inputMethodAdapter = inputMethodAdapter, + ) + } + + override val lifecycle: Lifecycle + get() = lifecycleRegistry + + abstract fun getController(): BaseAccessibilityServiceController? + + override fun onCreate() { + super.onCreate() + Timber.i("Accessibility service: onCreate") + + savedStateRegistryController?.performAttach() + savedStateRegistryController?.performRestore(null) + + lifecycleRegistry.currentState = Lifecycle.State.CREATED + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + softKeyboardController.addOnShowModeChangedListener { _, showMode -> + when (showMode) { + SHOW_MODE_AUTO -> _isKeyboardHidden.value = false + SHOW_MODE_HIDDEN -> _isKeyboardHidden.value = true + } + } + } + + keyEventRelayServiceWrapper.onCreate() + } + + override fun onServiceConnected() { + super.onServiceConnected() + + Timber.i("Accessibility service: onServiceConnected") + lifecycleRegistry.currentState = Lifecycle.State.STARTED + + setTheme(R.style.AppTheme) + + _activeWindowPackage.update { rootInActiveWindow?.packageName?.toString() } + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + fingerprintGestureCallback = + object : FingerprintGestureController.FingerprintGestureCallback() { + override fun onGestureDetected(gesture: Int) { + super.onGestureDetected(gesture) + + val id: FingerprintGestureType = when (gesture) { + FingerprintGestureController.FINGERPRINT_GESTURE_SWIPE_DOWN -> + FingerprintGestureType.SWIPE_DOWN + + FingerprintGestureController.FINGERPRINT_GESTURE_SWIPE_UP -> + FingerprintGestureType.SWIPE_UP + + FingerprintGestureController.FINGERPRINT_GESTURE_SWIPE_LEFT -> + FingerprintGestureType.SWIPE_LEFT + + FingerprintGestureController.FINGERPRINT_GESTURE_SWIPE_RIGHT -> + FingerprintGestureType.SWIPE_RIGHT + + else -> return + } + getController()?.onFingerprintGesture(id) + } + } + + fingerprintGestureCallback?.let { + fingerprintGestureController.registerFingerprintGestureCallback(it, null) + } + } + } + + override fun onUnbind(intent: Intent?): Boolean { + Timber.i("Accessibility service: onUnbind") + return super.onUnbind(intent) + } + + override fun onInterrupt() {} + + override fun onDestroy() { + lifecycleRegistry.currentState = Lifecycle.State.DESTROYED + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + fingerprintGestureController + .unregisterFingerprintGestureCallback(fingerprintGestureCallback) + } + + keyEventRelayServiceWrapper.onDestroy() + + Timber.i("Accessibility service: onDestroy") + + super.onDestroy() + } + + override fun onConfigurationChanged(newConfig: Configuration) { + super.onConfigurationChanged(newConfig) + + getController()?.onConfigurationChanged(newConfig) + } + + override fun onTrimMemory(level: Int) { + val memoryInfo = ActivityManager.MemoryInfo() + getSystemService()?.getMemoryInfo(memoryInfo) + + Timber.i("Accessibility service: onLowMemory, total: ${memoryInfo.totalMem}, available: ${memoryInfo.availMem}, is low memory: ${memoryInfo.lowMemory}, threshold: ${memoryInfo.threshold}") + + super.onTrimMemory(level) + } + + override fun onAccessibilityEvent(event: AccessibilityEvent?) { + event ?: return + + if (event.eventType == AccessibilityEvent.TYPE_WINDOWS_CHANGED) { + _activeWindowPackage.update { rootInActiveWindow?.packageName?.toString() } + } + + getController()?.onAccessibilityEvent(event) + } + + override fun onKeyEvent(event: KeyEvent?): Boolean { + event ?: return super.onKeyEvent(event) + + val device = if (event.device == null) { + null + } else { + InputDeviceUtils.createInputDeviceInfo(event.device) + } + + return getController()?.onKeyEvent( + MyKeyEvent( + keyCode = event.keyCode, + action = event.action, + metaState = event.metaState, + scanCode = event.scanCode, + device = device, + repeatCount = event.repeatCount, + source = event.source, + ), + KeyEventDetectionSource.ACCESSIBILITY_SERVICE, + ) ?: false + } + + override fun findFocussedNode(focus: Int): AccessibilityNodeModel? { + return findFocus(focus)?.toModel() + } + + override fun setInputMethodEnabled(imeId: String, enabled: Boolean) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + softKeyboardController.setInputMethodEnabled(imeId, enabled) + } + } + + override fun hideKeyboard() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + softKeyboardController.showMode = SHOW_MODE_HIDDEN + } + } + + override fun showKeyboard() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + softKeyboardController.showMode = SHOW_MODE_AUTO + } + } + + override fun doGlobalAction(action: Int): KMResult<*> { + val success = performGlobalAction(action) + + if (success) { + return Success(Unit) + } else { + return KMError.FailedToPerformAccessibilityGlobalAction(action) + } + } + + override fun tapScreen(x: Int, y: Int, inputEventType: InputEventType): KMResult<*> { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + val duration = 1L // ms + + val path = Path().apply { + moveTo(x.toFloat(), y.toFloat()) + } + + val strokeDescription = + when { + inputEventType == InputEventType.DOWN && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O -> + StrokeDescription( + path, + 0, + duration, + true, + ) + + inputEventType == InputEventType.UP && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O -> + StrokeDescription( + path, + 59999, + duration, + false, + ) + + else -> StrokeDescription(path, 0, duration) + } + + strokeDescription.let { + val gestureDescription = GestureDescription.Builder().apply { + addStroke(it) + }.build() + + val success = dispatchGesture(gestureDescription, null, null) + + return if (success) { + Success(Unit) + } else { + KMError.FailedToDispatchGesture + } + } + } + + return KMError.SdkVersionTooLow(Build.VERSION_CODES.N) + } + + override fun swipeScreen( + xStart: Int, + yStart: Int, + xEnd: Int, + yEnd: Int, + fingerCount: Int, + duration: Int, + inputEventType: InputEventType, + ): KMResult<*> { + // virtual distance between fingers on multitouch gestures + val fingerGestureDistance = 10L + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + if (fingerCount >= GestureDescription.getMaxStrokeCount()) { + return KMError.GestureStrokeCountTooHigh + } + if (duration >= GestureDescription.getMaxGestureDuration()) { + return KMError.GestureDurationTooHigh + } + + val pStart = Point(xStart, yStart) + val pEnd = Point(xEnd, yEnd) + + val gestureBuilder = GestureDescription.Builder() + + if (fingerCount == 1) { + val p = Path() + p.moveTo(pStart.x.toFloat(), pStart.y.toFloat()) + p.lineTo(pEnd.x.toFloat(), pEnd.y.toFloat()) + gestureBuilder.addStroke(StrokeDescription(p, 0, duration.toLong())) + } else { + // segments between fingers + val segmentCount = fingerCount - 1 + // the line of the perpendicular line which will be created to place the virtual fingers on it + val perpendicularLineLength = (fingerGestureDistance * fingerCount).toInt() + + // the length of each segment between fingers + val segmentLength = perpendicularLineLength / segmentCount + // perpendicular line of the start swipe point + val perpendicularLineStart = MathUtils.getPerpendicularOfLine( + pStart, + pEnd, + perpendicularLineLength, + ) + // perpendicular line of the end swipe point + val perpendicularLineEnd = MathUtils.getPerpendicularOfLine( + pEnd, + pStart, + perpendicularLineLength, + true, + ) + + // this is the angle between start and end point to rotate all virtual fingers on the perpendicular lines in the same direction + val angle = + MathUtils.angleBetweenPoints(Point(xStart, yStart), Point(xEnd, yEnd)) - 90 + + // create the virtual fingers + for (index in 0..segmentCount) { + // offset of each finger + val fingerOffsetLength = index * segmentLength * 2 + // move the coordinates of the current virtual finger on the perpendicular line for the start coordinates + val startFingerCoordinateWithOffset = + MathUtils.movePointByDistanceAndAngle( + perpendicularLineStart.start, + fingerOffsetLength, + angle, + ) + // move the coordinates of the current virtual finger on the perpendicular line for the end coordinates + val endFingerCoordinateWithOffset = + MathUtils.movePointByDistanceAndAngle( + perpendicularLineEnd.start, + fingerOffsetLength, + angle, + ) + + // create a path for each finger, move the the coordinates on the perpendicular line and draw it to the end coordinates of the perpendicular line of the end swipe point + val p = Path() + p.moveTo( + startFingerCoordinateWithOffset.x.toFloat(), + startFingerCoordinateWithOffset.y.toFloat(), + ) + p.lineTo( + endFingerCoordinateWithOffset.x.toFloat(), + endFingerCoordinateWithOffset.y.toFloat(), + ) + + gestureBuilder.addStroke(StrokeDescription(p, 0, duration.toLong())) + } + } + + val success = dispatchGesture(gestureBuilder.build(), null, null) + + return if (success) { + Success(Unit) + } else { + KMError.FailedToDispatchGesture + } + } + + return KMError.SdkVersionTooLow(Build.VERSION_CODES.N) + } + + override fun pinchScreen( + x: Int, + y: Int, + distance: Int, + pinchType: PinchScreenType, + fingerCount: Int, + duration: Int, + inputEventType: InputEventType, + ): KMResult<*> { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + if (fingerCount >= GestureDescription.getMaxStrokeCount()) { + return KMError.GestureStrokeCountTooHigh + } + if (duration >= GestureDescription.getMaxGestureDuration()) { + return KMError.GestureDurationTooHigh + } + + val gestureBuilder = GestureDescription.Builder() + val distributedPoints: List = + MathUtils.distributePointsOnCircle(Point(x, y), distance.toFloat() / 2, fingerCount) + + for (index in distributedPoints.indices) { + val p = Path() + if (pinchType == PinchScreenType.PINCH_IN) { + p.moveTo(x.toFloat(), y.toFloat()) + p.lineTo( + distributedPoints[index].x.toFloat(), + distributedPoints[index].y.toFloat(), + ) + } else { + p.moveTo( + distributedPoints[index].x.toFloat(), + distributedPoints[index].y.toFloat(), + ) + p.lineTo(x.toFloat(), y.toFloat()) + } + + gestureBuilder.addStroke(StrokeDescription(p, 0, duration.toLong())) + } + + val success = dispatchGesture(gestureBuilder.build(), null, null) + + return if (success) { + Success(Unit) + } else { + KMError.FailedToDispatchGesture + } + } + + return KMError.SdkVersionTooLow(Build.VERSION_CODES.N) + } + + override fun performActionOnNode( + findNode: (node: AccessibilityNodeModel) -> Boolean, + performAction: (node: AccessibilityNodeModel) -> AccessibilityNodeAction?, + ): KMResult<*> { + val node = rootInActiveWindow.findNodeRecursively { + findNode(it.toModel()) + } + + if (node == null) { + return KMError.FailedToFindAccessibilityNode + } + + val (action, extras) = performAction(node.toModel()) ?: return Success(Unit) + + node.performAction(action, bundleOf(*extras.toList().toTypedArray())) + node.recycle() + + return Success(Unit) + } +} diff --git a/app/src/main/java/io/github/sds100/keymapper/system/accessibility/BaseAccessibilityServiceController.kt b/base/src/main/java/io/github/sds100/keymapper/base/system/accessibility/BaseAccessibilityServiceController.kt similarity index 74% rename from app/src/main/java/io/github/sds100/keymapper/system/accessibility/BaseAccessibilityServiceController.kt rename to base/src/main/java/io/github/sds100/keymapper/base/system/accessibility/BaseAccessibilityServiceController.kt index 73931e1160..121afbadaa 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/accessibility/BaseAccessibilityServiceController.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/system/accessibility/BaseAccessibilityServiceController.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.system.accessibility +package io.github.sds100.keymapper.base.system.accessibility import android.accessibilityservice.AccessibilityServiceInfo import android.content.res.Configuration @@ -6,33 +6,35 @@ import android.os.Build import android.view.KeyEvent import android.view.accessibility.AccessibilityEvent import android.view.accessibility.AccessibilityNodeInfo -import io.github.sds100.keymapper.actions.ActionData -import io.github.sds100.keymapper.actions.PerformActionsUseCase -import io.github.sds100.keymapper.constraints.DetectConstraintsUseCase +import androidx.lifecycle.lifecycleScope +import io.github.sds100.keymapper.base.actions.ActionData +import io.github.sds100.keymapper.base.actions.PerformActionsUseCaseImpl +import io.github.sds100.keymapper.base.actions.TestActionEvent +import io.github.sds100.keymapper.base.constraints.DetectConstraintsUseCaseImpl +import io.github.sds100.keymapper.base.keymaps.FingerprintGesturesSupportedUseCase +import io.github.sds100.keymapper.base.keymaps.PauseKeyMapsUseCase +import io.github.sds100.keymapper.base.keymaps.TriggerKeyMapEvent +import io.github.sds100.keymapper.base.keymaps.detection.DetectKeyMapsUseCaseImpl +import io.github.sds100.keymapper.base.keymaps.detection.DetectScreenOffKeyEventsController +import io.github.sds100.keymapper.base.keymaps.detection.DpadMotionEventTracker +import io.github.sds100.keymapper.base.keymaps.detection.KeyMapController +import io.github.sds100.keymapper.base.keymaps.detection.TriggerKeyMapFromOtherAppsController +import io.github.sds100.keymapper.base.reroutekeyevents.RerouteKeyEventsController +import io.github.sds100.keymapper.base.trigger.KeyEventDetectionSource +import io.github.sds100.keymapper.base.trigger.RecordTriggerEvent +import io.github.sds100.keymapper.common.utils.firstBlocking +import io.github.sds100.keymapper.common.utils.hasFlag +import io.github.sds100.keymapper.common.utils.minusFlag +import io.github.sds100.keymapper.common.utils.withFlag import io.github.sds100.keymapper.data.Keys import io.github.sds100.keymapper.data.PreferenceDefaults -import io.github.sds100.keymapper.data.repositories.AccessibilityNodeRepository import io.github.sds100.keymapper.data.repositories.PreferenceRepository -import io.github.sds100.keymapper.keymaps.FingerprintGestureType -import io.github.sds100.keymapper.keymaps.FingerprintGesturesSupportedUseCase -import io.github.sds100.keymapper.keymaps.PauseKeyMapsUseCase -import io.github.sds100.keymapper.keymaps.detection.DetectKeyMapsUseCase -import io.github.sds100.keymapper.keymaps.detection.DetectScreenOffKeyEventsController -import io.github.sds100.keymapper.keymaps.detection.DpadMotionEventTracker -import io.github.sds100.keymapper.keymaps.detection.KeyMapController -import io.github.sds100.keymapper.keymaps.detection.TriggerKeyMapFromOtherAppsController -import io.github.sds100.keymapper.reroutekeyevents.RerouteKeyEventsController -import io.github.sds100.keymapper.reroutekeyevents.RerouteKeyEventsUseCase +import io.github.sds100.keymapper.system.accessibility.AccessibilityServiceEvent import io.github.sds100.keymapper.system.devices.DevicesAdapter import io.github.sds100.keymapper.system.inputevents.InputEventUtils import io.github.sds100.keymapper.system.inputevents.MyKeyEvent import io.github.sds100.keymapper.system.inputevents.MyMotionEvent -import io.github.sds100.keymapper.system.inputmethod.InputMethodAdapter import io.github.sds100.keymapper.system.root.SuAdapter -import io.github.sds100.keymapper.trigger.KeyEventDetectionSource -import io.github.sds100.keymapper.util.ServiceEvent -import io.github.sds100.keymapper.util.firstBlocking -import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job import kotlinx.coroutines.delay @@ -54,99 +56,101 @@ import kotlinx.coroutines.flow.update import kotlinx.coroutines.isActive import kotlinx.coroutines.launch import kotlinx.coroutines.withContext -import splitties.bitflags.hasFlag -import splitties.bitflags.minusFlag -import splitties.bitflags.withFlag import timber.log.Timber -/** - * Created by sds100 on 17/04/2021. - */ abstract class BaseAccessibilityServiceController( - private val coroutineScope: CoroutineScope, - private val service: MyAccessibilityService, - private val inputEvents: SharedFlow, - private val outputEvents: MutableSharedFlow, - private val detectConstraintsUseCase: DetectConstraintsUseCase, - private val performActionsUseCase: PerformActionsUseCase, - private val detectKeyMapsUseCase: DetectKeyMapsUseCase, + private val service: BaseAccessibilityService, + private val rerouteKeyEventsControllerFactory: RerouteKeyEventsController.Factory, + private val accessibilityNodeRecorderFactory: AccessibilityNodeRecorder.Factory, + private val performActionsUseCaseFactory: PerformActionsUseCaseImpl.Factory, + private val detectKeyMapsUseCaseFactory: DetectKeyMapsUseCaseImpl.Factory, + private val detectConstraintsUseCaseFactory: DetectConstraintsUseCaseImpl.Factory, private val fingerprintGesturesSupported: FingerprintGesturesSupportedUseCase, - rerouteKeyEventsUseCase: RerouteKeyEventsUseCase, private val pauseKeyMapsUseCase: PauseKeyMapsUseCase, private val devicesAdapter: DevicesAdapter, private val suAdapter: SuAdapter, - private val inputMethodAdapter: InputMethodAdapter, private val settingsRepository: PreferenceRepository, - private val nodeRepository: AccessibilityNodeRepository, ) { - companion object { + /** * How long should the accessibility service record a trigger in seconds. */ private const val RECORD_TRIGGER_TIMER_LENGTH = 5 - private const val DEFAULT_NOTIFICATION_TIMEOUT = 200L } - private val triggerKeyMapFromOtherAppsController = TriggerKeyMapFromOtherAppsController( - coroutineScope, + private val performActionsUseCase = performActionsUseCaseFactory.create( + accessibilityService = service, + imeInputEventInjector = service.imeInputEventInjector, + ) + + private val detectKeyMapsUseCase = detectKeyMapsUseCaseFactory.create( + accessibilityService = service, + coroutineScope = service.lifecycleScope, + imeInputEventInjector = service.imeInputEventInjector, + ) + + val detectConstraintsUseCase = detectConstraintsUseCaseFactory.create(service) + + val keyMapController = KeyMapController( + service.lifecycleScope, detectKeyMapsUseCase, performActionsUseCase, detectConstraintsUseCase, ) - val keyMapController = KeyMapController( - coroutineScope, + val triggerKeyMapFromOtherAppsController = TriggerKeyMapFromOtherAppsController( + service.lifecycleScope, detectKeyMapsUseCase, performActionsUseCase, detectConstraintsUseCase, ) - private val rerouteKeyEventsController = RerouteKeyEventsController( - coroutineScope, - rerouteKeyEventsUseCase, + val rerouteKeyEventsController = rerouteKeyEventsControllerFactory.create( + service.lifecycleScope, + service.imeInputEventInjector, ) - private val accessibilityNodeRecorder: AccessibilityNodeRecorder = - AccessibilityNodeRecorder(nodeRepository, service) + val accessibilityNodeRecorder = accessibilityNodeRecorderFactory.create(service) + + private val detectScreenOffKeyEventsController = DetectScreenOffKeyEventsController( + suAdapter, + devicesAdapter, + ) { event -> + if (!isPaused.value) { + withContext(Dispatchers.Main.immediate) { + keyMapController.onKeyEvent(event) + } + } + } private var recordingTriggerJob: Job? = null + private val recordingTrigger: Boolean get() = recordingTriggerJob != null && recordingTriggerJob?.isActive == true + private val recordDpadMotionEventTracker: DpadMotionEventTracker = DpadMotionEventTracker() - val isPaused: StateFlow = pauseKeyMapsUseCase.isPaused - .stateIn(coroutineScope, SharingStarted.Eagerly, false) + val isPaused: StateFlow = + pauseKeyMapsUseCase.isPaused + .stateIn(service.lifecycleScope, SharingStarted.Eagerly, false) private val screenOffTriggersEnabled: StateFlow = detectKeyMapsUseCase.detectScreenOffTriggers - .stateIn(coroutineScope, SharingStarted.Eagerly, false) + .stateIn(service.lifecycleScope, SharingStarted.Eagerly, false) private val changeImeOnInputFocusFlow: StateFlow = settingsRepository .get(Keys.changeImeOnInputFocus) .map { it ?: PreferenceDefaults.CHANGE_IME_ON_INPUT_FOCUS } .stateIn( - coroutineScope, + service.lifecycleScope, SharingStarted.Lazily, PreferenceDefaults.CHANGE_IME_ON_INPUT_FOCUS, ) - private val detectScreenOffKeyEventsController = - DetectScreenOffKeyEventsController( - suAdapter, - devicesAdapter, - ) { event -> - - if (!isPaused.value) { - withContext(Dispatchers.Main.immediate) { - keyMapController.onKeyEvent(event) - } - } - } - private val initialServiceFlags: Int by lazy { var flags = AccessibilityServiceInfo.FLAG_REQUEST_FILTER_KEY_EVENTS .withFlag(AccessibilityServiceInfo.FLAG_REPORT_VIEW_IDS) @@ -184,35 +188,39 @@ abstract class BaseAccessibilityServiceController( private val serviceNotificationTimeout: MutableStateFlow = MutableStateFlow(DEFAULT_NOTIFICATION_TIMEOUT) - init { + private val inputEvents: SharedFlow = + service.accessibilityServiceAdapter.eventsToService + private val outputEvents: MutableSharedFlow = + service.accessibilityServiceAdapter.eventReceiver + init { serviceFlags.onEach { flags -> // check that it isn't null because this can only be called once the service is bound if (service.serviceFlags != null) { service.serviceFlags = flags } - }.launchIn(coroutineScope) + }.launchIn(service.lifecycleScope) serviceFeedbackType.onEach { feedbackType -> // check that it isn't null because this can only be called once the service is bound if (service.serviceFeedbackType != null) { service.serviceFeedbackType = feedbackType } - }.launchIn(coroutineScope) + }.launchIn(service.lifecycleScope) serviceEventTypes.onEach { eventTypes -> // check that it isn't null because this can only be called once the service is bound if (service.serviceEventTypes != null) { service.serviceEventTypes = eventTypes } - }.launchIn(coroutineScope) + }.launchIn(service.lifecycleScope) serviceNotificationTimeout.onEach { timeout -> // check that it isn't null because this can only be called once the service is bound if (service.notificationTimeout != null) { service.notificationTimeout = timeout } - }.launchIn(coroutineScope) + }.launchIn(service.lifecycleScope) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { combine( @@ -224,37 +232,37 @@ abstract class BaseAccessibilityServiceController( } else { denyFingerprintGestureDetection() } - }.launchIn(coroutineScope) + }.launchIn(service.lifecycleScope) } pauseKeyMapsUseCase.isPaused.distinctUntilChanged().onEach { keyMapController.reset() triggerKeyMapFromOtherAppsController.reset() - }.launchIn(coroutineScope) + }.launchIn(service.lifecycleScope) detectKeyMapsUseCase.isScreenOn.onEach { isScreenOn -> if (!isScreenOn) { if (screenOffTriggersEnabled.value) { - detectScreenOffKeyEventsController.startListening(coroutineScope) + detectScreenOffKeyEventsController.startListening(service.lifecycleScope) } } else { detectScreenOffKeyEventsController.stopListening() } - }.launchIn(coroutineScope) + }.launchIn(service.lifecycleScope) inputEvents.onEach { onEventFromUi(it) - }.launchIn(coroutineScope) + }.launchIn(service.lifecycleScope) service.isKeyboardHidden .drop(1) // Don't send it when collecting initially .onEach { isHidden -> if (isHidden) { - outputEvents.emit(ServiceEvent.OnHideKeyboardEvent) + outputEvents.emit(AccessibilityServiceEvent.OnHideKeyboardEvent) } else { - outputEvents.emit(ServiceEvent.OnShowKeyboardEvent) + outputEvents.emit(AccessibilityServiceEvent.OnShowKeyboardEvent) } - }.launchIn(coroutineScope) + }.launchIn(service.lifecycleScope) combine( pauseKeyMapsUseCase.isPaused, @@ -275,11 +283,11 @@ abstract class BaseAccessibilityServiceController( } else { disableAccessibilityVolumeStream() } - }.launchIn(coroutineScope) + }.launchIn(service.lifecycleScope) - coroutineScope.launch { + service.lifecycleScope.launch { accessibilityNodeRecorder.recordState.collectLatest { state -> - outputEvents.emit(ServiceEvent.OnRecordNodeStateChanged(state)) + outputEvents.emit(RecordAccessibilityNodeEvent.OnRecordNodeStateChanged(state)) } } @@ -289,7 +297,7 @@ abstract class BaseAccessibilityServiceController( val recordNodeEvents = AccessibilityEvent.TYPE_VIEW_FOCUSED or AccessibilityEvent.TYPE_VIEW_CLICKED - coroutineScope.launch { + service.lifecycleScope.launch { combine( changeImeOnInputFocusFlow, accessibilityNodeRecorder.recordState, @@ -394,9 +402,9 @@ abstract class BaseAccessibilityServiceController( val uniqueEvent: MyKeyEvent = getUniqueEvent(event) - coroutineScope.launch { + service.lifecycleScope.launch { outputEvents.emit( - ServiceEvent.RecordedTriggerKey( + RecordTriggerEvent.RecordedTriggerKey( uniqueEvent.keyCode, uniqueEvent.device, detectionSource, @@ -473,9 +481,9 @@ abstract class BaseAccessibilityServiceController( if (keyEvent.action == KeyEvent.ACTION_DOWN) { Timber.d("Recorded motion event ${KeyEvent.keyCodeToString(keyEvent.keyCode)}") - coroutineScope.launch { + service.lifecycleScope.launch { outputEvents.emit( - ServiceEvent.RecordedTriggerKey( + RecordTriggerEvent.RecordedTriggerKey( keyEvent.keyCode, keyEvent.device, KeyEventDetectionSource.INPUT_METHOD, @@ -512,13 +520,13 @@ abstract class BaseAccessibilityServiceController( if (focussedNode?.isEditable == true && focussedNode.isFocused) { Timber.d("Got input focus") - coroutineScope.launch { - outputEvents.emit(ServiceEvent.OnInputFocusChange(isFocussed = true)) + service.lifecycleScope.launch { + outputEvents.emit(AccessibilityServiceEvent.OnInputFocusChange(isFocussed = true)) } } else { Timber.d("Lost input focus") - coroutineScope.launch { - outputEvents.emit(ServiceEvent.OnInputFocusChange(isFocussed = false)) + service.lifecycleScope.launch { + outputEvents.emit(AccessibilityServiceEvent.OnInputFocusChange(isFocussed = false)) } } } @@ -532,16 +540,16 @@ abstract class BaseAccessibilityServiceController( triggerKeyMapFromOtherAppsController.onDetected(uid) } - open fun onEventFromUi(event: ServiceEvent) { + open fun onEventFromUi(event: AccessibilityServiceEvent) { Timber.d("Service received event from UI: $event") when (event) { - is ServiceEvent.StartRecordingTrigger -> + is RecordTriggerEvent.StartRecordingTrigger -> if (!recordingTrigger) { recordDpadMotionEventTracker.reset() recordingTriggerJob = recordTriggerJob() } - is ServiceEvent.StopRecordingTrigger -> { + is RecordTriggerEvent.StopRecordingTrigger -> { val wasRecordingTrigger = recordingTrigger recordingTriggerJob?.cancel() @@ -549,40 +557,40 @@ abstract class BaseAccessibilityServiceController( recordDpadMotionEventTracker.reset() if (wasRecordingTrigger) { - coroutineScope.launch { - outputEvents.emit(ServiceEvent.OnStoppedRecordingTrigger) + service.lifecycleScope.launch { + outputEvents.emit(RecordTriggerEvent.OnStoppedRecordingTrigger) } } } - is ServiceEvent.TestAction -> coroutineScope.launch { + is TestActionEvent -> service.lifecycleScope.launch { performActionsUseCase.perform( event.action, ) } - is ServiceEvent.Ping -> coroutineScope.launch { - outputEvents.emit(ServiceEvent.Pong(event.key)) + is AccessibilityServiceEvent.Ping -> service.lifecycleScope.launch { + outputEvents.emit(AccessibilityServiceEvent.Pong(event.key)) } - is ServiceEvent.HideKeyboard -> service.hideKeyboard() - is ServiceEvent.ShowKeyboard -> service.showKeyboard() - is ServiceEvent.ChangeIme -> service.switchIme(event.imeId) - is ServiceEvent.DisableService -> if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + is AccessibilityServiceEvent.HideKeyboard -> service.hideKeyboard() + is AccessibilityServiceEvent.ShowKeyboard -> service.showKeyboard() + is AccessibilityServiceEvent.ChangeIme -> service.switchIme(event.imeId) + is AccessibilityServiceEvent.DisableService -> if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { service.disableSelf() } - is ServiceEvent.TriggerKeyMap -> triggerKeyMapFromIntent(event.uid) + is TriggerKeyMapEvent -> triggerKeyMapFromIntent(event.uid) - is ServiceEvent.EnableInputMethod -> if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + is AccessibilityServiceEvent.EnableInputMethod -> if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { service.setInputMethodEnabled(event.imeId, true) } - is ServiceEvent.StartRecordingNodes -> { + is RecordAccessibilityNodeEvent.StartRecordingNodes -> { accessibilityNodeRecorder.startRecording() } - is ServiceEvent.StopRecordingNodes -> { + is RecordAccessibilityNodeEvent.StopRecordingNodes -> { accessibilityNodeRecorder.stopRecording() } @@ -590,17 +598,17 @@ abstract class BaseAccessibilityServiceController( } } - private fun recordTriggerJob() = coroutineScope.launch { + private fun recordTriggerJob() = service.lifecycleScope.launch { repeat(RECORD_TRIGGER_TIMER_LENGTH) { iteration -> if (isActive) { val timeLeft = RECORD_TRIGGER_TIMER_LENGTH - iteration - outputEvents.emit(ServiceEvent.OnIncrementRecordTriggerTimer(timeLeft)) + outputEvents.emit(RecordTriggerEvent.OnIncrementRecordTriggerTimer(timeLeft)) delay(1000) } } - outputEvents.emit(ServiceEvent.OnStoppedRecordingTrigger) + outputEvents.emit(RecordTriggerEvent.OnStoppedRecordingTrigger) } private fun requestFingerprintGestureDetection() { diff --git a/app/src/main/java/io/github/sds100/keymapper/system/accessibility/ControlAccessibilityServiceUseCase.kt b/base/src/main/java/io/github/sds100/keymapper/base/system/accessibility/ControlAccessibilityServiceUseCase.kt similarity index 69% rename from app/src/main/java/io/github/sds100/keymapper/system/accessibility/ControlAccessibilityServiceUseCase.kt rename to base/src/main/java/io/github/sds100/keymapper/base/system/accessibility/ControlAccessibilityServiceUseCase.kt index 406bd1f7c4..ae32bebf39 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/accessibility/ControlAccessibilityServiceUseCase.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/system/accessibility/ControlAccessibilityServiceUseCase.kt @@ -1,18 +1,19 @@ -package io.github.sds100.keymapper.system.accessibility +package io.github.sds100.keymapper.base.system.accessibility +import io.github.sds100.keymapper.system.accessibility.AccessibilityServiceAdapter +import io.github.sds100.keymapper.system.accessibility.AccessibilityServiceState import io.github.sds100.keymapper.system.permissions.Permission import io.github.sds100.keymapper.system.permissions.PermissionAdapter import kotlinx.coroutines.flow.Flow +import javax.inject.Inject +import javax.inject.Singleton -/** - * Created by sds100 on 16/04/2021. - */ - -class ControlAccessibilityServiceUseCaseImpl( - private val adapter: ServiceAdapter, +@Singleton +class ControlAccessibilityServiceUseCaseImpl @Inject constructor( + private val adapter: AccessibilityServiceAdapter, private val permissionAdapter: PermissionAdapter, ) : ControlAccessibilityServiceUseCase { - override val serviceState: Flow = adapter.state + override val serviceState: Flow = adapter.state /** * @return true if the service could be started of if the accessibility settings could be @@ -39,7 +40,7 @@ class ControlAccessibilityServiceUseCaseImpl( } interface ControlAccessibilityServiceUseCase { - val serviceState: Flow + val serviceState: Flow fun startService(): Boolean fun restartService(): Boolean fun stopService() diff --git a/app/src/main/java/io/github/sds100/keymapper/keymaps/FingerprintGestureType.kt b/base/src/main/java/io/github/sds100/keymapper/base/system/accessibility/FingerprintGestureType.kt similarity index 62% rename from app/src/main/java/io/github/sds100/keymapper/keymaps/FingerprintGestureType.kt rename to base/src/main/java/io/github/sds100/keymapper/base/system/accessibility/FingerprintGestureType.kt index b0d65cc8a5..40019e7f16 100644 --- a/app/src/main/java/io/github/sds100/keymapper/keymaps/FingerprintGestureType.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/system/accessibility/FingerprintGestureType.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.keymaps +package io.github.sds100.keymapper.base.system.accessibility enum class FingerprintGestureType { SWIPE_DOWN, diff --git a/app/src/main/java/io/github/sds100/keymapper/system/accessibility/IAccessibilityService.kt b/base/src/main/java/io/github/sds100/keymapper/base/system/accessibility/IAccessibilityService.kt similarity index 78% rename from app/src/main/java/io/github/sds100/keymapper/system/accessibility/IAccessibilityService.kt rename to base/src/main/java/io/github/sds100/keymapper/base/system/accessibility/IAccessibilityService.kt index 4e45865eb9..c62a1c8b05 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/accessibility/IAccessibilityService.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/system/accessibility/IAccessibilityService.kt @@ -1,19 +1,16 @@ -package io.github.sds100.keymapper.system.accessibility +package io.github.sds100.keymapper.base.system.accessibility import android.os.Build import androidx.annotation.RequiresApi -import io.github.sds100.keymapper.actions.pinchscreen.PinchScreenType -import io.github.sds100.keymapper.util.InputEventType -import io.github.sds100.keymapper.util.Result +import io.github.sds100.keymapper.common.utils.InputEventType +import io.github.sds100.keymapper.common.utils.KMResult +import io.github.sds100.keymapper.common.utils.PinchScreenType import kotlinx.coroutines.flow.Flow -/** - * Created by sds100 on 17/04/2021. - */ interface IAccessibilityService { - fun doGlobalAction(action: Int): Result<*> + fun doGlobalAction(action: Int): KMResult<*> - fun tapScreen(x: Int, y: Int, inputEventType: InputEventType): Result<*> + fun tapScreen(x: Int, y: Int, inputEventType: InputEventType): KMResult<*> fun swipeScreen( xStart: Int, @@ -23,7 +20,7 @@ interface IAccessibilityService { fingerCount: Int, duration: Int, inputEventType: InputEventType, - ): Result<*> + ): KMResult<*> fun pinchScreen( x: Int, @@ -33,7 +30,7 @@ interface IAccessibilityService { fingerCount: Int, duration: Int, inputEventType: InputEventType, - ): Result<*> + ): KMResult<*> val isFingerprintGestureDetectionAvailable: Boolean @@ -45,7 +42,7 @@ interface IAccessibilityService { fun performActionOnNode( findNode: (node: AccessibilityNodeModel) -> Boolean, performAction: (node: AccessibilityNodeModel) -> AccessibilityNodeAction?, - ): Result<*> + ): KMResult<*> val rootNode: AccessibilityNodeModel? val activeWindowPackage: Flow diff --git a/base/src/main/java/io/github/sds100/keymapper/base/system/accessibility/RecordAccessibilityNodeEvent.kt b/base/src/main/java/io/github/sds100/keymapper/base/system/accessibility/RecordAccessibilityNodeEvent.kt new file mode 100644 index 0000000000..2665f76624 --- /dev/null +++ b/base/src/main/java/io/github/sds100/keymapper/base/system/accessibility/RecordAccessibilityNodeEvent.kt @@ -0,0 +1,15 @@ +package io.github.sds100.keymapper.base.system.accessibility + +import io.github.sds100.keymapper.system.accessibility.AccessibilityServiceEvent +import kotlinx.serialization.Serializable + +sealed class RecordAccessibilityNodeEvent : AccessibilityServiceEvent() { + @Serializable + data object StartRecordingNodes : RecordAccessibilityNodeEvent() + + @Serializable + data object StopRecordingNodes : RecordAccessibilityNodeEvent() + + @Serializable + data class OnRecordNodeStateChanged(val state: RecordAccessibilityNodeState) : RecordAccessibilityNodeEvent() +} diff --git a/app/src/main/java/io/github/sds100/keymapper/system/accessibility/RecordAccessibilityNodeState.kt b/base/src/main/java/io/github/sds100/keymapper/base/system/accessibility/RecordAccessibilityNodeState.kt similarity index 83% rename from app/src/main/java/io/github/sds100/keymapper/system/accessibility/RecordAccessibilityNodeState.kt rename to base/src/main/java/io/github/sds100/keymapper/base/system/accessibility/RecordAccessibilityNodeState.kt index ea1e26d091..f7e8dac342 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/accessibility/RecordAccessibilityNodeState.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/system/accessibility/RecordAccessibilityNodeState.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.system.accessibility +package io.github.sds100.keymapper.base.system.accessibility import kotlinx.serialization.Serializable diff --git a/app/src/main/java/io/github/sds100/keymapper/system/apps/AppActivityListItem.kt b/base/src/main/java/io/github/sds100/keymapper/base/system/apps/AppActivityListItem.kt similarity index 68% rename from app/src/main/java/io/github/sds100/keymapper/system/apps/AppActivityListItem.kt rename to base/src/main/java/io/github/sds100/keymapper/base/system/apps/AppActivityListItem.kt index 336414ff65..c20076d8be 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/apps/AppActivityListItem.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/system/apps/AppActivityListItem.kt @@ -1,12 +1,10 @@ -package io.github.sds100.keymapper.system.apps +package io.github.sds100.keymapper.base.system.apps -import io.github.sds100.keymapper.util.ui.IconInfo -import io.github.sds100.keymapper.util.ui.SimpleListItemOld -import io.github.sds100.keymapper.util.ui.TintType +import io.github.sds100.keymapper.base.utils.ui.IconInfo +import io.github.sds100.keymapper.base.utils.ui.SimpleListItemOld +import io.github.sds100.keymapper.base.utils.ui.TintType +import io.github.sds100.keymapper.system.apps.ActivityInfo -/** - * Created by sds100 on 27/01/2020. - */ data class AppActivityListItem( val appName: String, val activityInfo: ActivityInfo, diff --git a/app/src/main/java/io/github/sds100/keymapper/system/apps/AppShortcutListItem.kt b/base/src/main/java/io/github/sds100/keymapper/base/system/apps/AppShortcutListItem.kt similarity index 61% rename from app/src/main/java/io/github/sds100/keymapper/system/apps/AppShortcutListItem.kt rename to base/src/main/java/io/github/sds100/keymapper/base/system/apps/AppShortcutListItem.kt index b167c98e25..6d3dcb3f82 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/apps/AppShortcutListItem.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/system/apps/AppShortcutListItem.kt @@ -1,12 +1,9 @@ -package io.github.sds100.keymapper.system.apps +package io.github.sds100.keymapper.base.system.apps -import io.github.sds100.keymapper.util.ui.IconInfo -import io.github.sds100.keymapper.util.ui.SimpleListItemOld -import io.github.sds100.keymapper.util.ui.TintType - -/** - * Created by sds100 on 29/03/2020. - */ +import io.github.sds100.keymapper.base.utils.ui.IconInfo +import io.github.sds100.keymapper.base.utils.ui.SimpleListItemOld +import io.github.sds100.keymapper.base.utils.ui.TintType +import io.github.sds100.keymapper.system.apps.AppShortcutInfo data class AppShortcutListItem( val shortcutInfo: AppShortcutInfo, diff --git a/app/src/main/java/io/github/sds100/keymapper/system/apps/ChooseActivityFragment.kt b/base/src/main/java/io/github/sds100/keymapper/base/system/apps/ChooseActivityFragment.kt similarity index 69% rename from app/src/main/java/io/github/sds100/keymapper/system/apps/ChooseActivityFragment.kt rename to base/src/main/java/io/github/sds100/keymapper/base/system/apps/ChooseActivityFragment.kt index 0bcfffbfe1..abafafef52 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/apps/ChooseActivityFragment.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/system/apps/ChooseActivityFragment.kt @@ -1,21 +1,18 @@ -package io.github.sds100.keymapper.system.apps +package io.github.sds100.keymapper.base.system.apps -import androidx.fragment.app.activityViewModels +import androidx.fragment.app.viewModels import androidx.navigation.fragment.navArgs import com.airbnb.epoxy.EpoxyRecyclerView -import io.github.sds100.keymapper.databinding.FragmentSimpleRecyclerviewBinding -import io.github.sds100.keymapper.simple -import io.github.sds100.keymapper.util.Inject -import io.github.sds100.keymapper.util.State -import io.github.sds100.keymapper.util.ui.RecyclerViewUtils -import io.github.sds100.keymapper.util.ui.SimpleRecyclerViewFragment +import dagger.hilt.android.AndroidEntryPoint +import io.github.sds100.keymapper.base.databinding.FragmentSimpleRecyclerviewBinding +import io.github.sds100.keymapper.base.simple +import io.github.sds100.keymapper.base.utils.ui.RecyclerViewUtils +import io.github.sds100.keymapper.base.utils.ui.SimpleRecyclerViewFragment +import io.github.sds100.keymapper.common.utils.State import kotlinx.coroutines.flow.Flow -import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json -/** - * Created by sds100 on 22/02/2020. - */ +@AndroidEntryPoint class ChooseActivityFragment : SimpleRecyclerViewFragment() { companion object { @@ -27,9 +24,7 @@ class ChooseActivityFragment : SimpleRecyclerViewFragment() private val args: ChooseActivityFragmentArgs by navArgs() - private val viewModel: ChooseActivityViewModel by activityViewModels { - Inject.chooseActivityViewModel(requireContext()) - } + private val viewModel: ChooseActivityViewModel by viewModels() override val listItems: Flow>> get() = viewModel.listItems diff --git a/app/src/main/java/io/github/sds100/keymapper/system/apps/ChooseActivityViewModel.kt b/base/src/main/java/io/github/sds100/keymapper/base/system/apps/ChooseActivityViewModel.kt similarity index 76% rename from app/src/main/java/io/github/sds100/keymapper/system/apps/ChooseActivityViewModel.kt rename to base/src/main/java/io/github/sds100/keymapper/base/system/apps/ChooseActivityViewModel.kt index 28b18cfa82..579bb48d4b 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/apps/ChooseActivityViewModel.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/system/apps/ChooseActivityViewModel.kt @@ -1,13 +1,13 @@ -package io.github.sds100.keymapper.system.apps +package io.github.sds100.keymapper.base.system.apps import androidx.lifecycle.ViewModel -import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.viewModelScope -import io.github.sds100.keymapper.util.State -import io.github.sds100.keymapper.util.filterByQuery -import io.github.sds100.keymapper.util.ui.IconInfo -import io.github.sds100.keymapper.util.ui.TintType -import io.github.sds100.keymapper.util.valueOrNull +import dagger.hilt.android.lifecycle.HiltViewModel +import io.github.sds100.keymapper.base.utils.filterByQuery +import io.github.sds100.keymapper.base.utils.ui.IconInfo +import io.github.sds100.keymapper.base.utils.ui.TintType +import io.github.sds100.keymapper.common.utils.State +import io.github.sds100.keymapper.common.utils.valueOrNull import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow @@ -17,11 +17,12 @@ import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.map +import javax.inject.Inject -/** - * Created by sds100 on 27/01/2020. - */ -class ChooseActivityViewModel(private val useCase: DisplayAppsUseCase) : ViewModel() { +@HiltViewModel +class ChooseActivityViewModel @Inject constructor( + private val useCase: DisplayAppsUseCase, +) : ViewModel() { val searchQuery = MutableStateFlow(null) @@ -76,13 +77,4 @@ class ChooseActivityViewModel(private val useCase: DisplayAppsUseCase) : ViewMod } }.flowOn(Dispatchers.Default).launchIn(viewModelScope) } - - class Factory( - private val useCase: DisplayAppsUseCase, - ) : ViewModelProvider.Factory { - - @Suppress("UNCHECKED_CAST") - override fun create(modelClass: Class) = - ChooseActivityViewModel(useCase) as T - } } diff --git a/app/src/main/java/io/github/sds100/keymapper/system/apps/ChooseAppFragment.kt b/base/src/main/java/io/github/sds100/keymapper/base/system/apps/ChooseAppFragment.kt similarity index 79% rename from app/src/main/java/io/github/sds100/keymapper/system/apps/ChooseAppFragment.kt rename to base/src/main/java/io/github/sds100/keymapper/base/system/apps/ChooseAppFragment.kt index f22b4924ae..60de372248 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/apps/ChooseAppFragment.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/system/apps/ChooseAppFragment.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.system.apps +package io.github.sds100.keymapper.base.system.apps import android.os.Bundle import android.view.LayoutInflater @@ -8,21 +8,19 @@ import androidx.fragment.app.viewModels import androidx.lifecycle.Lifecycle import androidx.navigation.fragment.navArgs import com.airbnb.epoxy.EpoxyRecyclerView -import io.github.sds100.keymapper.databinding.FragmentChooseAppBinding -import io.github.sds100.keymapper.simple -import io.github.sds100.keymapper.util.Inject -import io.github.sds100.keymapper.util.State -import io.github.sds100.keymapper.util.launchRepeatOnLifecycle -import io.github.sds100.keymapper.util.ui.RecyclerViewFragment -import io.github.sds100.keymapper.util.ui.RecyclerViewUtils -import io.github.sds100.keymapper.util.ui.SimpleListItemOld +import dagger.hilt.android.AndroidEntryPoint +import io.github.sds100.keymapper.base.databinding.FragmentChooseAppBinding +import io.github.sds100.keymapper.base.simple +import io.github.sds100.keymapper.base.utils.ui.RecyclerViewFragment +import io.github.sds100.keymapper.base.utils.ui.RecyclerViewUtils +import io.github.sds100.keymapper.base.utils.ui.SimpleListItemOld +import io.github.sds100.keymapper.base.utils.ui.launchRepeatOnLifecycle +import io.github.sds100.keymapper.common.utils.State import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.map -/** - * Created by sds100 on 22/02/2020. - */ +@AndroidEntryPoint class ChooseAppFragment : RecyclerViewFragment() { companion object { @@ -34,9 +32,7 @@ class ChooseAppFragment : RecyclerViewFragment>> get() = viewModel.state.map { it.listItems } @@ -50,7 +46,7 @@ class ChooseAppFragment : RecyclerViewFragment() { companion object { @@ -38,9 +34,7 @@ class ChooseAppShortcutFragment : SimpleRecyclerViewFragment>> get() = viewModel.state @@ -66,8 +60,6 @@ class ChooseAppShortcutFragment : SimpleRecyclerViewFragment(null) @@ -106,9 +105,9 @@ class ChooseAppShortcutViewModel internal constructor( if (intentShortcutName != null) { shortcutName = intentShortcutName } else { - shortcutName = showPopup( + shortcutName = showDialog( "create_shortcut_name", - PopupUi.Text( + DialogModel.Text( hint = getString(R.string.hint_shortcut_name), allowEmpty = false, ), @@ -124,17 +123,4 @@ class ChooseAppShortcutViewModel internal constructor( ) } } - - class Factory( - private val useCase: DisplayAppShortcutsUseCase, - private val resourceProvider: ResourceProvider, - ) : ViewModelProvider.Factory { - - @Suppress("UNCHECKED_CAST") - override fun create(modelClass: Class) = - ChooseAppShortcutViewModel( - useCase, - resourceProvider, - ) as T - } } diff --git a/app/src/main/java/io/github/sds100/keymapper/system/apps/ChooseAppViewModel.kt b/base/src/main/java/io/github/sds100/keymapper/base/system/apps/ChooseAppViewModel.kt similarity index 83% rename from app/src/main/java/io/github/sds100/keymapper/system/apps/ChooseAppViewModel.kt rename to base/src/main/java/io/github/sds100/keymapper/base/system/apps/ChooseAppViewModel.kt index 58bdbba039..4339359584 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/apps/ChooseAppViewModel.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/system/apps/ChooseAppViewModel.kt @@ -1,15 +1,16 @@ -package io.github.sds100.keymapper.system.apps +package io.github.sds100.keymapper.base.system.apps import androidx.lifecycle.ViewModel -import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.viewModelScope -import io.github.sds100.keymapper.util.State -import io.github.sds100.keymapper.util.filterByQuery -import io.github.sds100.keymapper.util.mapData -import io.github.sds100.keymapper.util.ui.DefaultSimpleListItem -import io.github.sds100.keymapper.util.ui.IconInfo -import io.github.sds100.keymapper.util.ui.SimpleListItemOld -import io.github.sds100.keymapper.util.valueOrNull +import dagger.hilt.android.lifecycle.HiltViewModel +import io.github.sds100.keymapper.base.utils.filterByQuery +import io.github.sds100.keymapper.base.utils.ui.DefaultSimpleListItem +import io.github.sds100.keymapper.base.utils.ui.IconInfo +import io.github.sds100.keymapper.base.utils.ui.SimpleListItemOld +import io.github.sds100.keymapper.common.utils.State +import io.github.sds100.keymapper.common.utils.mapData +import io.github.sds100.keymapper.common.utils.valueOrNull +import io.github.sds100.keymapper.system.apps.PackageInfo import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow @@ -24,12 +25,10 @@ import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.toList import kotlinx.coroutines.launch import java.util.Locale +import javax.inject.Inject -/** - * Created by sds100 on 27/01/2020. - */ - -class ChooseAppViewModel( +@HiltViewModel +class ChooseAppViewModel @Inject constructor( private val useCase: DisplayAppsUseCase, ) : ViewModel() { @@ -132,15 +131,6 @@ class ChooseAppViewModel( }.flowOn(Dispatchers.Default) .toList() .sortedBy { it.title.lowercase(Locale.getDefault()) } - - class Factory( - private val useCase: DisplayAppsUseCase, - ) : ViewModelProvider.Factory { - - @Suppress("UNCHECKED_CAST") - override fun create(modelClass: Class) = - ChooseAppViewModel(useCase) as T - } } data class AppListState( diff --git a/app/src/main/java/io/github/sds100/keymapper/system/apps/DisplayAppShortcutsUseCase.kt b/base/src/main/java/io/github/sds100/keymapper/base/system/apps/DisplayAppShortcutsUseCase.kt similarity index 52% rename from app/src/main/java/io/github/sds100/keymapper/system/apps/DisplayAppShortcutsUseCase.kt rename to base/src/main/java/io/github/sds100/keymapper/base/system/apps/DisplayAppShortcutsUseCase.kt index b36cf185b4..ed74512319 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/apps/DisplayAppShortcutsUseCase.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/system/apps/DisplayAppShortcutsUseCase.kt @@ -1,30 +1,29 @@ -package io.github.sds100.keymapper.system.apps +package io.github.sds100.keymapper.base.system.apps import android.graphics.drawable.Drawable -import io.github.sds100.keymapper.util.Result -import io.github.sds100.keymapper.util.State +import io.github.sds100.keymapper.common.utils.KMResult +import io.github.sds100.keymapper.common.utils.State +import io.github.sds100.keymapper.system.apps.AppShortcutAdapter +import io.github.sds100.keymapper.system.apps.AppShortcutInfo import kotlinx.coroutines.flow.Flow +import javax.inject.Inject -/** - * Created by sds100 on 04/04/2021. - */ - -class DisplayAppShortcutsUseCaseImpl( +class DisplayAppShortcutsUseCaseImpl @Inject constructor( private val appShortcutAdapter: AppShortcutAdapter, ) : DisplayAppShortcutsUseCase { override val shortcuts: Flow>> = appShortcutAdapter.installedAppShortcuts - override fun getShortcutName(appShortcutInfo: AppShortcutInfo): Result = + override fun getShortcutName(appShortcutInfo: AppShortcutInfo): KMResult = appShortcutAdapter.getShortcutName(appShortcutInfo) - override fun getShortcutIcon(appShortcutInfo: AppShortcutInfo): Result = + override fun getShortcutIcon(appShortcutInfo: AppShortcutInfo): KMResult = appShortcutAdapter.getShortcutIcon(appShortcutInfo) } interface DisplayAppShortcutsUseCase { val shortcuts: Flow>> - fun getShortcutName(appShortcutInfo: AppShortcutInfo): Result - fun getShortcutIcon(appShortcutInfo: AppShortcutInfo): Result + fun getShortcutName(appShortcutInfo: AppShortcutInfo): KMResult + fun getShortcutIcon(appShortcutInfo: AppShortcutInfo): KMResult } diff --git a/base/src/main/java/io/github/sds100/keymapper/base/system/apps/DisplayAppsUseCase.kt b/base/src/main/java/io/github/sds100/keymapper/base/system/apps/DisplayAppsUseCase.kt new file mode 100644 index 0000000000..a0d651f115 --- /dev/null +++ b/base/src/main/java/io/github/sds100/keymapper/base/system/apps/DisplayAppsUseCase.kt @@ -0,0 +1,32 @@ +package io.github.sds100.keymapper.base.system.apps + +import android.graphics.drawable.Drawable +import io.github.sds100.keymapper.common.utils.KMResult +import io.github.sds100.keymapper.common.utils.State +import io.github.sds100.keymapper.system.apps.PackageInfo +import io.github.sds100.keymapper.system.apps.PackageManagerAdapter +import kotlinx.coroutines.flow.Flow +import javax.inject.Inject + +class DisplayAppsUseCaseImpl @Inject constructor( + private val adapter: PackageManagerAdapter, +) : DisplayAppsUseCase { + override val installedPackages: Flow>> = adapter.installedPackages + + override fun getAppName(packageName: String): KMResult = adapter.getAppName(packageName) + + override fun getAppIcon(packageName: String): KMResult = adapter.getAppIcon(packageName) + + override fun getActivityLabel(packageName: String, activityClass: String): KMResult = adapter.getActivityLabel(packageName, activityClass) + + override fun getActivityIcon(packageName: String, activityClass: String): KMResult = adapter.getActivityIcon(packageName, activityClass) +} + +interface DisplayAppsUseCase { + val installedPackages: Flow>> + + fun getActivityLabel(packageName: String, activityClass: String): KMResult + fun getActivityIcon(packageName: String, activityClass: String): KMResult + fun getAppName(packageName: String): KMResult + fun getAppIcon(packageName: String): KMResult +} diff --git a/app/src/main/java/io/github/sds100/keymapper/system/bluetooth/ChooseBluetoothDeviceFragment.kt b/base/src/main/java/io/github/sds100/keymapper/base/system/bluetooth/ChooseBluetoothDeviceFragment.kt similarity index 74% rename from app/src/main/java/io/github/sds100/keymapper/system/bluetooth/ChooseBluetoothDeviceFragment.kt rename to base/src/main/java/io/github/sds100/keymapper/base/system/bluetooth/ChooseBluetoothDeviceFragment.kt index 65e6aee4fd..57b4061d54 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/bluetooth/ChooseBluetoothDeviceFragment.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/system/bluetooth/ChooseBluetoothDeviceFragment.kt @@ -1,26 +1,22 @@ -package io.github.sds100.keymapper.system.bluetooth +package io.github.sds100.keymapper.base.system.bluetooth import androidx.fragment.app.viewModels import androidx.lifecycle.Lifecycle import androidx.navigation.fragment.navArgs import com.airbnb.epoxy.EpoxyRecyclerView -import io.github.sds100.keymapper.databinding.FragmentSimpleRecyclerviewBinding -import io.github.sds100.keymapper.fixError -import io.github.sds100.keymapper.simple -import io.github.sds100.keymapper.util.Inject -import io.github.sds100.keymapper.util.State -import io.github.sds100.keymapper.util.launchRepeatOnLifecycle -import io.github.sds100.keymapper.util.ui.ListItem -import io.github.sds100.keymapper.util.ui.RecyclerViewUtils -import io.github.sds100.keymapper.util.ui.SimpleListItemOld -import io.github.sds100.keymapper.util.ui.SimpleRecyclerViewFragment -import io.github.sds100.keymapper.util.ui.TextListItem +import io.github.sds100.keymapper.base.databinding.FragmentSimpleRecyclerviewBinding +import io.github.sds100.keymapper.base.fixError +import io.github.sds100.keymapper.base.simple +import io.github.sds100.keymapper.base.utils.ui.ListItem +import io.github.sds100.keymapper.base.utils.ui.RecyclerViewUtils +import io.github.sds100.keymapper.base.utils.ui.SimpleListItemOld +import io.github.sds100.keymapper.base.utils.ui.SimpleRecyclerViewFragment +import io.github.sds100.keymapper.base.utils.ui.TextListItem +import io.github.sds100.keymapper.base.utils.ui.launchRepeatOnLifecycle +import io.github.sds100.keymapper.common.utils.State import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.collectLatest -/** - * Created by sds100 on 22/02/2020. - */ class ChooseBluetoothDeviceFragment : SimpleRecyclerViewFragment() { companion object { @@ -30,9 +26,7 @@ class ChooseBluetoothDeviceFragment : SimpleRecyclerViewFragment() { private val args: ChooseBluetoothDeviceFragmentArgs by navArgs() - private val viewModel: ChooseBluetoothDeviceViewModel by viewModels { - Inject.chooseBluetoothDeviceViewModel(requireContext()) - } + private val viewModel: ChooseBluetoothDeviceViewModel by viewModels() override val listItems: Flow>> get() = viewModel.listItems diff --git a/app/src/main/java/io/github/sds100/keymapper/system/bluetooth/ChooseBluetoothDeviceUseCase.kt b/base/src/main/java/io/github/sds100/keymapper/base/system/bluetooth/ChooseBluetoothDeviceUseCase.kt similarity index 81% rename from app/src/main/java/io/github/sds100/keymapper/system/bluetooth/ChooseBluetoothDeviceUseCase.kt rename to base/src/main/java/io/github/sds100/keymapper/base/system/bluetooth/ChooseBluetoothDeviceUseCase.kt index 51df3fa171..ada7e5d7cc 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/bluetooth/ChooseBluetoothDeviceUseCase.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/system/bluetooth/ChooseBluetoothDeviceUseCase.kt @@ -1,16 +1,14 @@ -package io.github.sds100.keymapper.system.bluetooth +package io.github.sds100.keymapper.base.system.bluetooth +import io.github.sds100.keymapper.system.bluetooth.BluetoothDeviceInfo import io.github.sds100.keymapper.system.devices.DevicesAdapter import io.github.sds100.keymapper.system.permissions.Permission import io.github.sds100.keymapper.system.permissions.PermissionAdapter import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.StateFlow +import javax.inject.Inject -/** - * Created by sds100 on 07/04/2021. - */ - -class ChooseBluetoothDeviceUseCaseImpl( +class ChooseBluetoothDeviceUseCaseImpl @Inject constructor( private val devicesAdapter: DevicesAdapter, private val permissionAdapter: PermissionAdapter, ) : ChooseBluetoothDeviceUseCase { diff --git a/app/src/main/java/io/github/sds100/keymapper/system/bluetooth/ChooseBluetoothDeviceViewModel.kt b/base/src/main/java/io/github/sds100/keymapper/base/system/bluetooth/ChooseBluetoothDeviceViewModel.kt similarity index 66% rename from app/src/main/java/io/github/sds100/keymapper/system/bluetooth/ChooseBluetoothDeviceViewModel.kt rename to base/src/main/java/io/github/sds100/keymapper/base/system/bluetooth/ChooseBluetoothDeviceViewModel.kt index 876b235604..9b3e10f725 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/bluetooth/ChooseBluetoothDeviceViewModel.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/system/bluetooth/ChooseBluetoothDeviceViewModel.kt @@ -1,16 +1,16 @@ -package io.github.sds100.keymapper.system.bluetooth +package io.github.sds100.keymapper.base.system.bluetooth import androidx.lifecycle.ViewModel -import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.viewModelScope -import io.github.sds100.keymapper.R -import io.github.sds100.keymapper.util.State -import io.github.sds100.keymapper.util.ui.DefaultSimpleListItem -import io.github.sds100.keymapper.util.ui.ListItem -import io.github.sds100.keymapper.util.ui.PopupViewModel -import io.github.sds100.keymapper.util.ui.PopupViewModelImpl -import io.github.sds100.keymapper.util.ui.ResourceProvider -import io.github.sds100.keymapper.util.ui.TextListItem +import dagger.hilt.android.lifecycle.HiltViewModel +import io.github.sds100.keymapper.base.R +import io.github.sds100.keymapper.base.utils.ui.DefaultSimpleListItem +import io.github.sds100.keymapper.base.utils.ui.DialogProvider +import io.github.sds100.keymapper.base.utils.ui.ListItem +import io.github.sds100.keymapper.base.utils.ui.ResourceProvider +import io.github.sds100.keymapper.base.utils.ui.TextListItem +import io.github.sds100.keymapper.common.utils.State +import io.github.sds100.keymapper.system.bluetooth.BluetoothDeviceInfo import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow @@ -19,16 +19,16 @@ import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.launch +import javax.inject.Inject -/** - * Created by sds100 on 07/04/2021. - */ -class ChooseBluetoothDeviceViewModel( - val useCase: ChooseBluetoothDeviceUseCase, - resourceProvider: ResourceProvider, +@HiltViewModel +class ChooseBluetoothDeviceViewModel @Inject constructor( + private val useCase: ChooseBluetoothDeviceUseCase, + private val resourceProvider: ResourceProvider, + dialogProvider: DialogProvider, ) : ViewModel(), ResourceProvider by resourceProvider, - PopupViewModel by PopupViewModelImpl() { + DialogProvider by dialogProvider { private val _caption = MutableStateFlow(null) val caption: StateFlow = _caption @@ -81,17 +81,4 @@ class ChooseBluetoothDeviceViewModel( _returnResult.emit(deviceInfo) } } - - class Factory( - private val useCase: ChooseBluetoothDeviceUseCase, - private val resourceProvider: ResourceProvider, - ) : ViewModelProvider.Factory { - - @Suppress("UNCHECKED_CAST") - override fun create(modelClass: Class) = - ChooseBluetoothDeviceViewModel( - useCase, - resourceProvider, - ) as T - } } diff --git a/app/src/main/java/io/github/sds100/keymapper/system/inputmethod/AutoSwitchImeController.kt b/base/src/main/java/io/github/sds100/keymapper/base/system/inputmethod/AutoSwitchImeController.kt similarity index 77% rename from app/src/main/java/io/github/sds100/keymapper/system/inputmethod/AutoSwitchImeController.kt rename to base/src/main/java/io/github/sds100/keymapper/base/system/inputmethod/AutoSwitchImeController.kt index cf1a2dcca1..3cedb56284 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/inputmethod/AutoSwitchImeController.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/system/inputmethod/AutoSwitchImeController.kt @@ -1,40 +1,41 @@ -package io.github.sds100.keymapper.system.inputmethod - -import io.github.sds100.keymapper.R +package io.github.sds100.keymapper.base.system.inputmethod + +import io.github.sds100.keymapper.base.R +import io.github.sds100.keymapper.base.keymaps.PauseKeyMapsUseCase +import io.github.sds100.keymapper.base.utils.getFullMessage +import io.github.sds100.keymapper.base.utils.ui.ResourceProvider +import io.github.sds100.keymapper.common.BuildConfigProvider +import io.github.sds100.keymapper.common.utils.Success +import io.github.sds100.keymapper.common.utils.onFailure +import io.github.sds100.keymapper.common.utils.onSuccess +import io.github.sds100.keymapper.common.utils.otherwise import io.github.sds100.keymapper.data.Keys import io.github.sds100.keymapper.data.PreferenceDefaults import io.github.sds100.keymapper.data.repositories.PreferenceRepository -import io.github.sds100.keymapper.keymaps.PauseKeyMapsUseCase -import io.github.sds100.keymapper.system.accessibility.ServiceAdapter +import io.github.sds100.keymapper.data.utils.PrefDelegate +import io.github.sds100.keymapper.system.accessibility.AccessibilityServiceAdapter +import io.github.sds100.keymapper.system.accessibility.AccessibilityServiceEvent import io.github.sds100.keymapper.system.devices.DevicesAdapter -import io.github.sds100.keymapper.system.popup.PopupMessageAdapter -import io.github.sds100.keymapper.util.PrefDelegate -import io.github.sds100.keymapper.util.ServiceEvent -import io.github.sds100.keymapper.util.Success -import io.github.sds100.keymapper.util.getFullMessage -import io.github.sds100.keymapper.util.onFailure -import io.github.sds100.keymapper.util.onSuccess -import io.github.sds100.keymapper.util.otherwise -import io.github.sds100.keymapper.util.ui.ResourceProvider +import io.github.sds100.keymapper.system.inputmethod.InputMethodAdapter +import io.github.sds100.keymapper.system.popup.ToastAdapter import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import timber.log.Timber +import javax.inject.Inject -/** - * Created by sds100 on 20/04/2021. - */ -class AutoSwitchImeController( +class AutoSwitchImeController @Inject constructor( private val coroutineScope: CoroutineScope, private val preferenceRepository: PreferenceRepository, private val inputMethodAdapter: InputMethodAdapter, private val pauseKeyMapsUseCase: PauseKeyMapsUseCase, private val devicesAdapter: DevicesAdapter, - private val popupMessageAdapter: PopupMessageAdapter, + private val toastAdapter: ToastAdapter, private val resourceProvider: ResourceProvider, - private val accessibilityServiceAdapter: ServiceAdapter, + private val accessibilityServiceAdapter: AccessibilityServiceAdapter, + private val buildConfigProvider: BuildConfigProvider, ) : PreferenceRepository by preferenceRepository { - private val imeHelper = KeyMapperImeHelper(inputMethodAdapter) + private val imeHelper = KeyMapperImeHelper(inputMethodAdapter, buildConfigProvider.packageName) private val devicesThatToggleKeyboard by PrefDelegate(Keys.devicesThatChangeIme, emptySet()) @@ -54,7 +55,7 @@ class AutoSwitchImeController( private var showToast: Boolean = PreferenceDefaults.SHOW_TOAST_WHEN_AUTO_CHANGE_IME - init { + fun init() { pauseKeyMapsUseCase.isPaused.onEach { isPaused -> if (!toggleKeyboardOnToggleKeymaps) return@onEach @@ -96,7 +97,7 @@ class AutoSwitchImeController( accessibilityServiceAdapter.eventReceiver.onEach { event -> when (event) { - is ServiceEvent.OnInputFocusChange -> { + is AccessibilityServiceEvent.OnInputFocusChange -> { if (!changeImeOnInputFocus) { return@onEach } @@ -126,7 +127,7 @@ class AutoSwitchImeController( if (showToast) { val message = resourceProvider.getString(R.string.toast_chose_keyboard, ime.label) - popupMessageAdapter.showPopupMessage(message) + toastAdapter.show(message) } } .otherwise { @@ -137,7 +138,7 @@ class AutoSwitchImeController( } } .onFailure { error -> - popupMessageAdapter.showPopupMessage(error.getFullMessage(resourceProvider)) + toastAdapter.show(error.getFullMessage(resourceProvider)) } } @@ -152,7 +153,7 @@ class AutoSwitchImeController( if (showToast) { val message = resourceProvider.getString(R.string.toast_chose_keyboard, ime.label) - popupMessageAdapter.showPopupMessage(message) + toastAdapter.show(message) } } .otherwise { @@ -163,7 +164,7 @@ class AutoSwitchImeController( } } .onFailure { error -> - popupMessageAdapter.showPopupMessage(error.getFullMessage(resourceProvider)) + toastAdapter.show(error.getFullMessage(resourceProvider)) } } } diff --git a/app/src/main/java/io/github/sds100/keymapper/system/inputmethod/ImeInputEventInjector.kt b/base/src/main/java/io/github/sds100/keymapper/base/system/inputmethod/ImeInputEventInjector.kt similarity index 90% rename from app/src/main/java/io/github/sds100/keymapper/system/inputmethod/ImeInputEventInjector.kt rename to base/src/main/java/io/github/sds100/keymapper/base/system/inputmethod/ImeInputEventInjector.kt index e5ce73abdd..db7abdfcde 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/inputmethod/ImeInputEventInjector.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/system/inputmethod/ImeInputEventInjector.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.system.inputmethod +package io.github.sds100.keymapper.base.system.inputmethod import android.content.Context import android.content.Intent @@ -6,22 +6,19 @@ import android.os.Build import android.os.SystemClock import android.view.KeyCharacterMap import android.view.KeyEvent -import io.github.sds100.keymapper.api.KeyEventRelayService -import io.github.sds100.keymapper.api.KeyEventRelayServiceWrapper +import io.github.sds100.keymapper.common.utils.InputEventType import io.github.sds100.keymapper.system.inputevents.InputEventInjector -import io.github.sds100.keymapper.util.InputEventType +import io.github.sds100.keymapper.system.inputmethod.InputKeyModel +import io.github.sds100.keymapper.system.inputmethod.InputMethodAdapter +import io.github.sds100.keymapper.system.inputmethod.KeyEventRelayServiceWrapper import timber.log.Timber -/** - * Created by sds100 on 21/04/2021. - */ - /** * This class handles communicating with the Key Mapper input method services * so key events and text can be inputted. */ class ImeInputEventInjectorImpl( - context: Context, + private val ctx: Context, private val keyEventRelayService: KeyEventRelayServiceWrapper, private val inputMethodAdapter: InputMethodAdapter, ) : ImeInputEventInjector { @@ -41,9 +38,9 @@ class ImeInputEventInjectorImpl( "io.github.sds100.keymapper.inputmethod.EXTRA_KEY_EVENT" private const val KEY_MAPPER_INPUT_METHOD_EXTRA_TEXT = "io.github.sds100.keymapper.inputmethod.EXTRA_TEXT" - } - private val ctx = context.applicationContext + private const val CALLBACK_ID_INPUT_METHOD = "input_method" + } override suspend fun inputKeyEvent(model: InputKeyModel) { Timber.d("Inject key event with input method ${KeyEvent.keyCodeToString(model.keyCode)}, $model") @@ -99,14 +96,14 @@ class ImeInputEventInjectorImpl( keyEventRelayService.sendKeyEvent( downKeyEvent, imePackageName, - KeyEventRelayService.CALLBACK_ID_INPUT_METHOD, + CALLBACK_ID_INPUT_METHOD, ) val upKeyEvent = createInjectedKeyEvent(eventTime, KeyEvent.ACTION_UP, model) keyEventRelayService.sendKeyEvent( upKeyEvent, imePackageName, - KeyEventRelayService.CALLBACK_ID_INPUT_METHOD, + CALLBACK_ID_INPUT_METHOD, ) } @@ -115,7 +112,7 @@ class ImeInputEventInjectorImpl( keyEventRelayService.sendKeyEvent( downKeyEvent, imePackageName, - KeyEventRelayService.CALLBACK_ID_INPUT_METHOD, + CALLBACK_ID_INPUT_METHOD, ) } @@ -124,7 +121,7 @@ class ImeInputEventInjectorImpl( keyEventRelayService.sendKeyEvent( upKeyEvent, imePackageName, - KeyEventRelayService.CALLBACK_ID_INPUT_METHOD, + CALLBACK_ID_INPUT_METHOD, ) } } @@ -179,7 +176,7 @@ class ImeInputEventInjectorImpl( keyEventRelayService.sendKeyEvent( e, imePackageName, - KeyEventRelayService.CALLBACK_ID_INPUT_METHOD, + CALLBACK_ID_INPUT_METHOD, ) } @@ -199,7 +196,7 @@ class ImeInputEventInjectorImpl( keyEventRelayService.sendKeyEvent( event, imePackageName, - KeyEventRelayService.CALLBACK_ID_INPUT_METHOD, + CALLBACK_ID_INPUT_METHOD, ) } } diff --git a/app/src/main/java/io/github/sds100/keymapper/system/inputmethod/KeyMapperImeHelper.kt b/base/src/main/java/io/github/sds100/keymapper/base/system/inputmethod/KeyMapperImeHelper.kt similarity index 51% rename from app/src/main/java/io/github/sds100/keymapper/system/inputmethod/KeyMapperImeHelper.kt rename to base/src/main/java/io/github/sds100/keymapper/base/system/inputmethod/KeyMapperImeHelper.kt index e62df2ad11..16ae6f195c 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/inputmethod/KeyMapperImeHelper.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/system/inputmethod/KeyMapperImeHelper.kt @@ -1,21 +1,21 @@ -package io.github.sds100.keymapper.system.inputmethod - -import io.github.sds100.keymapper.Constants -import io.github.sds100.keymapper.util.Error -import io.github.sds100.keymapper.util.Result -import io.github.sds100.keymapper.util.Success -import io.github.sds100.keymapper.util.firstBlocking -import io.github.sds100.keymapper.util.onSuccess -import io.github.sds100.keymapper.util.suspendThen -import io.github.sds100.keymapper.util.then +package io.github.sds100.keymapper.base.system.inputmethod + +import io.github.sds100.keymapper.common.utils.KMError +import io.github.sds100.keymapper.common.utils.KMResult +import io.github.sds100.keymapper.common.utils.Success +import io.github.sds100.keymapper.common.utils.firstBlocking +import io.github.sds100.keymapper.common.utils.onSuccess +import io.github.sds100.keymapper.common.utils.suspendThen +import io.github.sds100.keymapper.common.utils.then +import io.github.sds100.keymapper.system.inputmethod.ImeInfo +import io.github.sds100.keymapper.system.inputmethod.InputMethodAdapter import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.map -/** - * Created by sds100 on 16/03/2021. - */ - -class KeyMapperImeHelper(private val imeAdapter: InputMethodAdapter) { +class KeyMapperImeHelper( + private val imeAdapter: InputMethodAdapter, + private val packageName: String, +) { companion object { const val KEY_MAPPER_GUI_IME_PACKAGE = "io.github.sds100.keymapper.inputmethod.latin" @@ -26,43 +26,43 @@ class KeyMapperImeHelper(private val imeAdapter: InputMethodAdapter) { private const val KEY_MAPPER_HACKERS_KEYBOARD_PACKAGE = "io.github.sds100.keymapper.inputmethod.hackers" - val KEY_MAPPER_IME_PACKAGE_LIST = arrayOf( - Constants.PACKAGE_NAME, - KEY_MAPPER_GUI_IME_PACKAGE, - KEY_MAPPER_LEANBACK_IME_PACKAGE, - KEY_MAPPER_HACKERS_KEYBOARD_PACKAGE, - ) - const val MIN_SUPPORTED_GUI_KEYBOARD_VERSION_CODE: Int = 20 } + private val keyMapperImePackageList = arrayOf( + packageName, + KEY_MAPPER_GUI_IME_PACKAGE, + KEY_MAPPER_LEANBACK_IME_PACKAGE, + KEY_MAPPER_HACKERS_KEYBOARD_PACKAGE, + ) + val isCompatibleImeEnabledFlow: Flow = imeAdapter.inputMethods .map { containsCompatibleIme(it) } suspend fun enableCompatibleInputMethods() { - KEY_MAPPER_IME_PACKAGE_LIST.forEach { packageName -> + keyMapperImePackageList.forEach { packageName -> imeAdapter.getInfoByPackageName(packageName).onSuccess { imeAdapter.enableIme(it.id) } } } - suspend fun chooseCompatibleInputMethod(): Result = getLastUsedCompatibleImeId().suspendThen { + suspend fun chooseCompatibleInputMethod(): KMResult = getLastUsedCompatibleImeId().suspendThen { imeAdapter.chooseImeWithoutUserInput(it) } - suspend fun chooseLastUsedIncompatibleInputMethod(): Result = getLastUsedIncompatibleImeId().then { + suspend fun chooseLastUsedIncompatibleInputMethod(): KMResult = getLastUsedIncompatibleImeId().then { imeAdapter.chooseImeWithoutUserInput(it) } - suspend fun toggleCompatibleInputMethod(): Result = if (isCompatibleImeChosen()) { + suspend fun toggleCompatibleInputMethod(): KMResult = if (isCompatibleImeChosen()) { chooseLastUsedIncompatibleInputMethod() } else { chooseCompatibleInputMethod() } - fun isCompatibleImeChosen(): Boolean = imeAdapter.chosenIme.value?.packageName in KEY_MAPPER_IME_PACKAGE_LIST + fun isCompatibleImeChosen(): Boolean = imeAdapter.chosenIme.value?.packageName in keyMapperImePackageList fun isCompatibleImeEnabled(): Boolean = imeAdapter.inputMethods .map { containsCompatibleIme(it) } @@ -70,11 +70,11 @@ class KeyMapperImeHelper(private val imeAdapter: InputMethodAdapter) { private fun containsCompatibleIme(imeList: List): Boolean = imeList .filter { it.isEnabled } - .any { it.packageName in KEY_MAPPER_IME_PACKAGE_LIST } + .any { it.packageName in keyMapperImePackageList } - private fun getLastUsedCompatibleImeId(): Result { + private fun getLastUsedCompatibleImeId(): KMResult { for (ime in imeAdapter.inputMethodHistory.firstBlocking()) { - if (ime.packageName in KEY_MAPPER_IME_PACKAGE_LIST && ime.isEnabled) { + if (ime.packageName in keyMapperImePackageList && ime.isEnabled) { return Success(ime.id) } } @@ -85,22 +85,22 @@ class KeyMapperImeHelper(private val imeAdapter: InputMethodAdapter) { } } - return imeAdapter.getInfoByPackageName(Constants.PACKAGE_NAME).then { ime -> + return imeAdapter.getInfoByPackageName(packageName).then { ime -> if (ime.isEnabled) { Success(ime.id) } else { - Error.NoCompatibleImeEnabled + KMError.NoCompatibleImeEnabled } } } - private fun getLastUsedIncompatibleImeId(): Result { + private fun getLastUsedIncompatibleImeId(): KMResult { for (ime in imeAdapter.inputMethodHistory.firstBlocking()) { - if (ime.packageName !in KEY_MAPPER_IME_PACKAGE_LIST) { + if (ime.packageName !in keyMapperImePackageList) { return Success(ime.id) } } - return Error.NoIncompatibleKeyboardsInstalled + return KMError.NoIncompatibleKeyboardsInstalled } } diff --git a/base/src/main/java/io/github/sds100/keymapper/base/system/inputmethod/ShowHideInputMethodUseCase.kt b/base/src/main/java/io/github/sds100/keymapper/base/system/inputmethod/ShowHideInputMethodUseCase.kt new file mode 100644 index 0000000000..3fe64c9677 --- /dev/null +++ b/base/src/main/java/io/github/sds100/keymapper/base/system/inputmethod/ShowHideInputMethodUseCase.kt @@ -0,0 +1,34 @@ +package io.github.sds100.keymapper.base.system.inputmethod + +import io.github.sds100.keymapper.system.accessibility.AccessibilityServiceAdapter +import io.github.sds100.keymapper.system.accessibility.AccessibilityServiceEvent +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.mapNotNull +import kotlinx.coroutines.runBlocking +import javax.inject.Inject + +class ShowHideInputMethodUseCaseImpl @Inject constructor( + private val serviceAdapter: AccessibilityServiceAdapter, +) : ShowHideInputMethodUseCase { + override val onHiddenChange: Flow = serviceAdapter.eventReceiver.mapNotNull { + when (it) { + AccessibilityServiceEvent.OnHideKeyboardEvent -> true + AccessibilityServiceEvent.OnShowKeyboardEvent -> false + else -> null + } + } + + override fun show() { + runBlocking { serviceAdapter.send(AccessibilityServiceEvent.ShowKeyboard) } + } + + override fun hide() { + runBlocking { serviceAdapter.send(AccessibilityServiceEvent.HideKeyboard) } + } +} + +interface ShowHideInputMethodUseCase { + val onHiddenChange: Flow + fun show() + fun hide() +} diff --git a/app/src/main/java/io/github/sds100/keymapper/system/inputmethod/ShowInputMethodPickerUseCase.kt b/base/src/main/java/io/github/sds100/keymapper/base/system/inputmethod/ShowInputMethodPickerUseCase.kt similarity index 58% rename from app/src/main/java/io/github/sds100/keymapper/system/inputmethod/ShowInputMethodPickerUseCase.kt rename to base/src/main/java/io/github/sds100/keymapper/base/system/inputmethod/ShowInputMethodPickerUseCase.kt index fb37c9da79..38caa71748 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/inputmethod/ShowInputMethodPickerUseCase.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/system/inputmethod/ShowInputMethodPickerUseCase.kt @@ -1,10 +1,9 @@ -package io.github.sds100.keymapper.system.inputmethod +package io.github.sds100.keymapper.base.system.inputmethod -/** - * Created by sds100 on 16/04/2021. - */ +import io.github.sds100.keymapper.system.inputmethod.InputMethodAdapter +import javax.inject.Inject -class ShowInputMethodPickerUseCaseImpl( +class ShowInputMethodPickerUseCaseImpl @Inject constructor( private val inputMethodAdapter: InputMethodAdapter, ) : ShowInputMethodPickerUseCase { override fun show(fromForeground: Boolean) { diff --git a/base/src/main/java/io/github/sds100/keymapper/base/system/inputmethod/ToggleCompatibleImeUseCase.kt b/base/src/main/java/io/github/sds100/keymapper/base/system/inputmethod/ToggleCompatibleImeUseCase.kt new file mode 100644 index 0000000000..f73ed91346 --- /dev/null +++ b/base/src/main/java/io/github/sds100/keymapper/base/system/inputmethod/ToggleCompatibleImeUseCase.kt @@ -0,0 +1,29 @@ +package io.github.sds100.keymapper.base.system.inputmethod + +import io.github.sds100.keymapper.common.BuildConfigProvider +import io.github.sds100.keymapper.common.utils.KMResult +import io.github.sds100.keymapper.system.inputmethod.ImeInfo +import io.github.sds100.keymapper.system.inputmethod.InputMethodAdapter +import kotlinx.coroutines.flow.Flow +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class ToggleCompatibleImeUseCaseImpl @Inject constructor( + private val inputMethodAdapter: InputMethodAdapter, + private val buildConfigProvider: BuildConfigProvider, +) : ToggleCompatibleImeUseCase { + private val keyMapperImeHelper = + KeyMapperImeHelper(inputMethodAdapter, buildConfigProvider.packageName) + + override val sufficientPermissions: Flow = + inputMethodAdapter.isUserInputRequiredToChangeIme + + override suspend fun toggle(): KMResult = keyMapperImeHelper.toggleCompatibleInputMethod() +} + +interface ToggleCompatibleImeUseCase { + val sufficientPermissions: Flow + + suspend fun toggle(): KMResult +} diff --git a/app/src/main/java/io/github/sds100/keymapper/system/intents/ConfigIntentFragment.kt b/base/src/main/java/io/github/sds100/keymapper/base/system/intents/ConfigIntentFragment.kt similarity index 87% rename from app/src/main/java/io/github/sds100/keymapper/system/intents/ConfigIntentFragment.kt rename to base/src/main/java/io/github/sds100/keymapper/base/system/intents/ConfigIntentFragment.kt index 6102a544d6..d55d39aa69 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/intents/ConfigIntentFragment.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/system/intents/ConfigIntentFragment.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.system.intents +package io.github.sds100.keymapper.base.system.intents import android.os.Bundle import android.text.Editable @@ -18,22 +18,20 @@ import androidx.lifecycle.Lifecycle import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.navArgs import com.airbnb.epoxy.EpoxyController -import io.github.sds100.keymapper.databinding.FragmentConfigIntentBinding -import io.github.sds100.keymapper.databinding.ListItemIntentExtraBoolBinding -import io.github.sds100.keymapper.intentExtraBool -import io.github.sds100.keymapper.intentExtraGeneric -import io.github.sds100.keymapper.util.Inject -import io.github.sds100.keymapper.util.launchRepeatOnLifecycle -import io.github.sds100.keymapper.util.ui.setupNavigation -import io.github.sds100.keymapper.util.ui.showPopups +import dagger.hilt.android.AndroidEntryPoint +import io.github.sds100.keymapper.base.databinding.FragmentConfigIntentBinding +import io.github.sds100.keymapper.base.databinding.ListItemIntentExtraBoolBinding +import io.github.sds100.keymapper.base.intentExtraBool +import io.github.sds100.keymapper.base.intentExtraGeneric +import io.github.sds100.keymapper.base.utils.navigation.setupFragmentNavigation +import io.github.sds100.keymapper.base.utils.ui.launchRepeatOnLifecycle +import io.github.sds100.keymapper.system.intents.BoolIntentExtraListItem +import io.github.sds100.keymapper.system.intents.GenericIntentExtraListItem +import io.github.sds100.keymapper.system.intents.IntentExtraListItem import kotlinx.coroutines.flow.collectLatest -import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json -/** - * Created by sds100 on 30/03/2020. - */ - +@AndroidEntryPoint class ConfigIntentFragment : Fragment() { companion object { const val EXTRA_RESULT = "extra_config_intent_result" @@ -42,9 +40,7 @@ class ConfigIntentFragment : Fragment() { private val args: ConfigIntentFragmentArgs by navArgs() private val requestKey: String by lazy { args.requestKey } - private val viewModel: ConfigIntentViewModel by viewModels { - Inject.configIntentViewModel(requireContext()) - } + private val viewModel: ConfigIntentViewModel by viewModels() /** * Scoped to the lifecycle of the fragment's view (between onCreateView and onDestroyView) @@ -73,7 +69,7 @@ class ConfigIntentFragment : Fragment() { viewModel.loadResult(Json.decodeFromString(it)) } - viewModel.setupNavigation(this) + viewModel.setupFragmentNavigation(this) } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { @@ -88,8 +84,6 @@ class ConfigIntentFragment : Fragment() { binding.viewModel = viewModel - viewModel.showPopups(this, binding) - requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner) { findNavController().navigateUp() } diff --git a/app/src/main/java/io/github/sds100/keymapper/system/intents/ConfigIntentResult.kt b/base/src/main/java/io/github/sds100/keymapper/base/system/intents/ConfigIntentResult.kt similarity index 53% rename from app/src/main/java/io/github/sds100/keymapper/system/intents/ConfigIntentResult.kt rename to base/src/main/java/io/github/sds100/keymapper/base/system/intents/ConfigIntentResult.kt index 9035a73464..4c5f349253 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/intents/ConfigIntentResult.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/system/intents/ConfigIntentResult.kt @@ -1,11 +1,9 @@ -package io.github.sds100.keymapper.system.intents +package io.github.sds100.keymapper.base.system.intents +import io.github.sds100.keymapper.system.intents.IntentExtraModel +import io.github.sds100.keymapper.system.intents.IntentTarget import kotlinx.serialization.Serializable -/** - * Created by sds100 on 20/04/2021. - */ - @Serializable data class ConfigIntentResult( val uri: String, diff --git a/app/src/main/java/io/github/sds100/keymapper/system/intents/ConfigIntentViewModel.kt b/base/src/main/java/io/github/sds100/keymapper/base/system/intents/ConfigIntentViewModel.kt similarity index 75% rename from app/src/main/java/io/github/sds100/keymapper/system/intents/ConfigIntentViewModel.kt rename to base/src/main/java/io/github/sds100/keymapper/base/system/intents/ConfigIntentViewModel.kt index ff52743b60..a6bca470c0 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/intents/ConfigIntentViewModel.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/system/intents/ConfigIntentViewModel.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.system.intents +package io.github.sds100.keymapper.base.system.intents import android.content.Intent import android.os.Build @@ -6,21 +6,47 @@ import android.os.Bundle import android.text.InputType import androidx.core.net.toUri import androidx.lifecycle.ViewModel -import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.viewModelScope -import io.github.sds100.keymapper.R +import dagger.hilt.android.lifecycle.HiltViewModel +import io.github.sds100.keymapper.base.R +import io.github.sds100.keymapper.base.utils.getExampleStringRes +import io.github.sds100.keymapper.base.utils.getLabelStringRes +import io.github.sds100.keymapper.base.utils.navigation.NavDestination +import io.github.sds100.keymapper.base.utils.navigation.NavigationProvider +import io.github.sds100.keymapper.base.utils.navigation.NavigationProviderImpl +import io.github.sds100.keymapper.base.utils.navigation.navigate +import io.github.sds100.keymapper.base.utils.ui.DialogModel +import io.github.sds100.keymapper.base.utils.ui.DialogProvider +import io.github.sds100.keymapper.base.utils.ui.DialogResponse +import io.github.sds100.keymapper.base.utils.ui.MultiChoiceItem +import io.github.sds100.keymapper.base.utils.ui.ResourceProvider +import io.github.sds100.keymapper.base.utils.ui.showDialog +import io.github.sds100.keymapper.common.utils.hasFlag +import io.github.sds100.keymapper.common.utils.withFlag import io.github.sds100.keymapper.system.apps.ActivityInfo -import io.github.sds100.keymapper.util.ui.DialogResponse -import io.github.sds100.keymapper.util.ui.MultiChoiceItem -import io.github.sds100.keymapper.util.ui.NavDestination -import io.github.sds100.keymapper.util.ui.NavigationViewModel -import io.github.sds100.keymapper.util.ui.NavigationViewModelImpl -import io.github.sds100.keymapper.util.ui.PopupUi -import io.github.sds100.keymapper.util.ui.PopupViewModel -import io.github.sds100.keymapper.util.ui.PopupViewModelImpl -import io.github.sds100.keymapper.util.ui.ResourceProvider -import io.github.sds100.keymapper.util.ui.navigate -import io.github.sds100.keymapper.util.ui.showPopup +import io.github.sds100.keymapper.system.intents.BoolArrayExtraType +import io.github.sds100.keymapper.system.intents.BoolExtraType +import io.github.sds100.keymapper.system.intents.BoolIntentExtraListItem +import io.github.sds100.keymapper.system.intents.ByteArrayExtraType +import io.github.sds100.keymapper.system.intents.ByteExtraType +import io.github.sds100.keymapper.system.intents.CharArrayExtraType +import io.github.sds100.keymapper.system.intents.CharExtraType +import io.github.sds100.keymapper.system.intents.DoubleArrayExtraType +import io.github.sds100.keymapper.system.intents.DoubleExtraType +import io.github.sds100.keymapper.system.intents.FloatArrayExtraType +import io.github.sds100.keymapper.system.intents.FloatExtraType +import io.github.sds100.keymapper.system.intents.GenericIntentExtraListItem +import io.github.sds100.keymapper.system.intents.IntArrayExtraType +import io.github.sds100.keymapper.system.intents.IntExtraType +import io.github.sds100.keymapper.system.intents.IntentExtraListItem +import io.github.sds100.keymapper.system.intents.IntentExtraModel +import io.github.sds100.keymapper.system.intents.IntentTarget +import io.github.sds100.keymapper.system.intents.LongArrayExtraType +import io.github.sds100.keymapper.system.intents.LongExtraType +import io.github.sds100.keymapper.system.intents.ShortArrayExtraType +import io.github.sds100.keymapper.system.intents.ShortExtraType +import io.github.sds100.keymapper.system.intents.StringArrayExtraType +import io.github.sds100.keymapper.system.intents.StringExtraType import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow @@ -32,39 +58,37 @@ import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch -import splitties.bitflags.hasFlag -import splitties.bitflags.withFlag +import javax.inject.Inject -/** - * Created by sds100 on 01/01/21. - */ - -class ConfigIntentViewModel(resourceProvider: ResourceProvider) : - ViewModel(), +@HiltViewModel +class ConfigIntentViewModel @Inject constructor( + private val resourceProvider: ResourceProvider, + dialogProvider: DialogProvider, +) : ViewModel(), ResourceProvider by resourceProvider, - PopupViewModel by PopupViewModelImpl(), - NavigationViewModel by NavigationViewModelImpl() { + DialogProvider by dialogProvider, + NavigationProvider by NavigationProviderImpl() { companion object { private val EXTRA_TYPES = arrayOf( - BoolExtraType(), - BoolArrayExtraType(), - IntExtraType(), - IntArrayExtraType(), - StringExtraType(), - StringArrayExtraType(), - LongExtraType(), - LongArrayExtraType(), - ByteExtraType(), - ByteArrayExtraType(), - DoubleExtraType(), - DoubleArrayExtraType(), - CharExtraType(), - CharArrayExtraType(), - FloatExtraType(), - FloatArrayExtraType(), - ShortExtraType(), - ShortArrayExtraType(), + BoolExtraType, + BoolArrayExtraType, + IntExtraType, + IntArrayExtraType, + StringExtraType, + StringArrayExtraType, + LongExtraType, + LongArrayExtraType, + ByteExtraType, + ByteArrayExtraType, + DoubleExtraType, + DoubleArrayExtraType, + CharExtraType, + CharArrayExtraType, + FloatExtraType, + FloatArrayExtraType, + ShortExtraType, + ShortArrayExtraType, ) val availableIntentFlags: List> = @@ -296,14 +320,14 @@ class ConfigIntentViewModel(resourceProvider: ResourceProvider) : fun onAddExtraClick() { viewModelScope.launch { - val items = EXTRA_TYPES.map { it to getString(it.labelStringRes) } + val items = EXTRA_TYPES.map { it to getString(it.getLabelStringRes()) } - val dialog = PopupUi.SingleChoice(items) + val dialog = DialogModel.SingleChoice(items) - val extraType = showPopup("add_extra", dialog) ?: return@launch + val extraType = showDialog("add_extra", dialog) ?: return@launch val modelValue = when (extraType) { - is BoolExtraType -> "true" + BoolExtraType -> "true" else -> "" } @@ -316,16 +340,16 @@ class ConfigIntentViewModel(resourceProvider: ResourceProvider) : fun onShowExtraExampleClick(listItem: IntentExtraListItem) { viewModelScope.launch { if (listItem is GenericIntentExtraListItem) { - val dialog = PopupUi.Ok(message = listItem.exampleString) - showPopup("extra_example", dialog) + val dialog = DialogModel.Ok(message = listItem.exampleString) + showDialog("extra_example", dialog) } } } fun onShowCategoriesExampleClick() { viewModelScope.launch { - val dialog = PopupUi.Ok(message = getString(R.string.intent_categories_example)) - showPopup("categories_example", dialog) + val dialog = DialogModel.Ok(message = getString(R.string.intent_categories_example)) + showDialog("categories_example", dialog) } } @@ -342,9 +366,9 @@ class ConfigIntentViewModel(resourceProvider: ResourceProvider) : MultiChoiceItem(intentFlagInt, intentFlagText, isChecked) } - val dialog = PopupUi.MultiChoice(items = dialogItems) + val dialog = DialogModel.MultiChoice(items = dialogItems) - val selectedFlags = showPopup("set_flags", dialog) ?: return@launch + val selectedFlags = showDialog("set_flags", dialog) ?: return@launch var newFlags = 0 @@ -393,22 +417,22 @@ class ConfigIntentViewModel(resourceProvider: ResourceProvider) : val value = extrasBundle.get(key) ?: continue val extraType = when (value) { - is Boolean -> BoolExtraType() - is BooleanArray -> BoolArrayExtraType() - is Int -> IntExtraType() - is IntArray -> IntArrayExtraType() - is Long -> LongExtraType() - is LongArrayExtraType -> LongArrayExtraType() - is Byte -> ByteExtraType() - is ByteArrayExtraType -> ByteArrayExtraType() - is Double -> DoubleExtraType() - is DoubleArray -> DoubleArrayExtraType() - is Float -> FloatExtraType() - is FloatArray -> FloatArrayExtraType() - is Short -> ShortExtraType() - is ShortArray -> ShortArrayExtraType() - is String -> StringExtraType() - is Array<*> -> StringArrayExtraType() + is Boolean -> BoolExtraType + is BooleanArray -> BoolArrayExtraType + is Int -> IntExtraType + is IntArray -> IntArrayExtraType + is Long -> LongExtraType + is LongArrayExtraType -> LongArrayExtraType + is Byte -> ByteExtraType + is ByteArrayExtraType -> ByteArrayExtraType + is Double -> DoubleExtraType + is DoubleArray -> DoubleArrayExtraType + is Float -> FloatExtraType + is FloatArray -> FloatArrayExtraType + is Short -> ShortExtraType + is ShortArray -> ShortArrayExtraType + is String -> StringExtraType + is Array<*> -> StringArrayExtraType else -> throw IllegalArgumentException("Don't know how to convert this extra (${value.javaClass.name}) to an IntentExtraType") } @@ -431,18 +455,18 @@ class ConfigIntentViewModel(resourceProvider: ResourceProvider) : fun onShowFlagsExampleClick() { viewModelScope.launch { - val dialog = PopupUi.Dialog( + val dialog = DialogModel.Alert( message = getString(R.string.intent_flags_example), positiveButtonText = getString(R.string.pos_ok), neutralButtonText = getString(R.string.neutral_intent_docs), ) - val response = showPopup("flags_example", dialog) ?: return@launch + val response = showDialog("flags_example", dialog) ?: return@launch if (response == DialogResponse.NEUTRAL) { - showPopup( + showDialog( "url_intent_flags", - PopupUi.OpenUrl(getString(R.string.url_intent_set_flags_help)), + DialogModel.OpenUrl(getString(R.string.url_intent_set_flags_help)), ) } } @@ -511,22 +535,13 @@ class ConfigIntentViewModel(resourceProvider: ResourceProvider) : GenericIntentExtraListItem( uid, - getString(type.labelStringRes), + getString(type.getLabelStringRes()), name, value, isValidValue, - getString(type.exampleStringRes), + getString(type.getExampleStringRes()), inputType, ) } } - - @Suppress("UNCHECKED_CAST") - class Factory( - private val resourceProvider: ResourceProvider, - ) : ViewModelProvider.NewInstanceFactory() { - - override fun create(modelClass: Class): T = - ConfigIntentViewModel(resourceProvider) as T - } } diff --git a/app/src/main/java/io/github/sds100/keymapper/system/navigation/OpenMenuHelper.kt b/base/src/main/java/io/github/sds100/keymapper/base/system/navigation/OpenMenuHelper.kt similarity index 73% rename from app/src/main/java/io/github/sds100/keymapper/system/navigation/OpenMenuHelper.kt rename to base/src/main/java/io/github/sds100/keymapper/base/system/navigation/OpenMenuHelper.kt index 0864806c2d..78120f505d 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/navigation/OpenMenuHelper.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/system/navigation/OpenMenuHelper.kt @@ -1,24 +1,21 @@ -package io.github.sds100.keymapper.system.navigation +package io.github.sds100.keymapper.base.system.navigation import android.view.KeyEvent import androidx.core.view.accessibility.AccessibilityNodeInfoCompat -import io.github.sds100.keymapper.system.accessibility.AccessibilityNodeAction -import io.github.sds100.keymapper.system.accessibility.IAccessibilityService +import io.github.sds100.keymapper.base.system.accessibility.AccessibilityNodeAction +import io.github.sds100.keymapper.base.system.accessibility.IAccessibilityService +import io.github.sds100.keymapper.common.utils.InputEventType +import io.github.sds100.keymapper.common.utils.KMResult +import io.github.sds100.keymapper.common.utils.firstBlocking +import io.github.sds100.keymapper.common.utils.success import io.github.sds100.keymapper.system.inputevents.InputEventInjector import io.github.sds100.keymapper.system.inputmethod.InputKeyModel import io.github.sds100.keymapper.system.permissions.Permission import io.github.sds100.keymapper.system.permissions.PermissionAdapter import io.github.sds100.keymapper.system.root.SuAdapter -import io.github.sds100.keymapper.util.InputEventType -import io.github.sds100.keymapper.util.Result -import io.github.sds100.keymapper.util.firstBlocking -import io.github.sds100.keymapper.util.success import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch -/** - * Created by sds100 on 21/04/2021. - */ class OpenMenuHelper( private val suAdapter: SuAdapter, private val accessibilityService: IAccessibilityService, @@ -31,7 +28,7 @@ class OpenMenuHelper( private const val OVERFLOW_MENU_CONTENT_DESCRIPTION = "More options" } - fun openMenu(): Result<*> { + fun openMenu(): KMResult<*> { when { permissionAdapter.isGranted(Permission.SHIZUKU) -> { val inputKeyModel = InputKeyModel( @@ -51,7 +48,9 @@ class OpenMenuHelper( else -> { accessibilityService.performActionOnNode({ it.contentDescription == OVERFLOW_MENU_CONTENT_DESCRIPTION }) { - AccessibilityNodeAction(AccessibilityNodeInfoCompat.ACTION_CLICK) + AccessibilityNodeAction( + AccessibilityNodeInfoCompat.ACTION_CLICK, + ) } return success() diff --git a/app/src/main/java/io/github/sds100/keymapper/system/notifications/AndroidNotificationAdapter.kt b/base/src/main/java/io/github/sds100/keymapper/base/system/notifications/AndroidNotificationAdapter.kt similarity index 80% rename from app/src/main/java/io/github/sds100/keymapper/system/notifications/AndroidNotificationAdapter.kt rename to base/src/main/java/io/github/sds100/keymapper/base/system/notifications/AndroidNotificationAdapter.kt index 9f13818dc3..dbae0c9ee3 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/notifications/AndroidNotificationAdapter.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/system/notifications/AndroidNotificationAdapter.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.system.notifications +package io.github.sds100.keymapper.base.system.notifications import android.app.NotificationChannel import android.app.PendingIntent @@ -8,19 +8,25 @@ import android.os.Build import androidx.core.app.NotificationCompat import androidx.core.app.NotificationManagerCompat import com.google.android.material.color.DynamicColors -import io.github.sds100.keymapper.MainActivity -import io.github.sds100.keymapper.R -import io.github.sds100.keymapper.util.color +import dagger.hilt.android.qualifiers.ApplicationContext +import io.github.sds100.keymapper.base.R +import io.github.sds100.keymapper.base.utils.ui.color +import io.github.sds100.keymapper.common.KeyMapperClassProvider +import io.github.sds100.keymapper.system.notifications.NotificationAdapter +import io.github.sds100.keymapper.system.notifications.NotificationChannelModel +import io.github.sds100.keymapper.system.notifications.NotificationIntentType +import io.github.sds100.keymapper.system.notifications.NotificationModel import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.launch +import javax.inject.Inject +import javax.inject.Singleton -/** - * Created by sds100 on 17/04/2021. - */ -class AndroidNotificationAdapter( - context: Context, +@Singleton +class AndroidNotificationAdapter @Inject constructor( + @ApplicationContext private val context: Context, private val coroutineScope: CoroutineScope, + private val classProvider: KeyMapperClassProvider, ) : NotificationAdapter { private val ctx = context.applicationContext @@ -38,7 +44,7 @@ class AndroidNotificationAdapter( setContentText(notification.text) if (notification.onClickAction != null) { - val pendingIntent = createActionIntent(notification.onClickAction) + val pendingIntent = createActionIntent(notification.onClickAction!!) setContentIntent(pendingIntent) } @@ -112,7 +118,7 @@ class AndroidNotificationAdapter( } is NotificationIntentType.MainActivity -> { - val intent = Intent(ctx, MainActivity::class.java).apply { + val intent = Intent(ctx, classProvider.getMainActivity()).apply { action = intentType.customIntentAction ?: Intent.ACTION_MAIN } diff --git a/app/src/main/java/io/github/sds100/keymapper/system/notifications/ManageNotificationsUseCase.kt b/base/src/main/java/io/github/sds100/keymapper/base/system/notifications/ManageNotificationsUseCase.kt similarity index 90% rename from app/src/main/java/io/github/sds100/keymapper/system/notifications/ManageNotificationsUseCase.kt rename to base/src/main/java/io/github/sds100/keymapper/base/system/notifications/ManageNotificationsUseCase.kt index 63ffafbdab..3d699686ef 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/notifications/ManageNotificationsUseCase.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/system/notifications/ManageNotificationsUseCase.kt @@ -1,20 +1,20 @@ -package io.github.sds100.keymapper.system.notifications +package io.github.sds100.keymapper.base.system.notifications import android.os.Build import io.github.sds100.keymapper.data.Keys import io.github.sds100.keymapper.data.repositories.PreferenceRepository +import io.github.sds100.keymapper.system.notifications.NotificationAdapter +import io.github.sds100.keymapper.system.notifications.NotificationChannelModel +import io.github.sds100.keymapper.system.notifications.NotificationModel import io.github.sds100.keymapper.system.permissions.Permission import io.github.sds100.keymapper.system.permissions.PermissionAdapter import io.github.sds100.keymapper.system.root.SuAdapter import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.map +import javax.inject.Inject -/** - * Created by sds100 on 14/02/21. - */ - -class ManageNotificationsUseCaseImpl( +class ManageNotificationsUseCaseImpl @Inject constructor( private val preferences: PreferenceRepository, private val notificationAdapter: NotificationAdapter, private val suAdapter: SuAdapter, diff --git a/app/src/main/java/io/github/sds100/keymapper/system/notifications/NotificationClickReceiver.kt b/base/src/main/java/io/github/sds100/keymapper/base/system/notifications/NotificationClickReceiver.kt similarity index 65% rename from app/src/main/java/io/github/sds100/keymapper/system/notifications/NotificationClickReceiver.kt rename to base/src/main/java/io/github/sds100/keymapper/base/system/notifications/NotificationClickReceiver.kt index f6cbf53b7b..0558a8ad5f 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/notifications/NotificationClickReceiver.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/system/notifications/NotificationClickReceiver.kt @@ -1,20 +1,22 @@ -package io.github.sds100.keymapper.system.notifications +package io.github.sds100.keymapper.base.system.notifications import android.content.BroadcastReceiver import android.content.Context import android.content.Intent import android.os.Build -import io.github.sds100.keymapper.ServiceLocator - -/** - * Created by sds100 on 24/03/2019. - */ +import dagger.hilt.android.AndroidEntryPoint +import javax.inject.Inject +@AndroidEntryPoint class NotificationClickReceiver : BroadcastReceiver() { + + @Inject + lateinit var notificationAdapter: AndroidNotificationAdapter + override fun onReceive(context: Context, intent: Intent?) { intent ?: return - ServiceLocator.notificationAdapter(context).onReceiveNotificationActionIntent(intent) + notificationAdapter.onReceiveNotificationActionIntent(intent) // dismiss the notification drawer after tapping on the notification. This is deprecated on S+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) { diff --git a/app/src/main/java/io/github/sds100/keymapper/system/notifications/NotificationController.kt b/base/src/main/java/io/github/sds100/keymapper/base/system/notifications/NotificationController.kt similarity index 78% rename from app/src/main/java/io/github/sds100/keymapper/system/notifications/NotificationController.kt rename to base/src/main/java/io/github/sds100/keymapper/base/system/notifications/NotificationController.kt index 15005576bb..4a25132dae 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/notifications/NotificationController.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/system/notifications/NotificationController.kt @@ -1,24 +1,27 @@ -package io.github.sds100.keymapper.system.notifications +package io.github.sds100.keymapper.base.system.notifications import android.provider.Settings import androidx.core.app.NotificationCompat import androidx.core.app.NotificationManagerCompat -import io.github.sds100.keymapper.BaseMainActivity -import io.github.sds100.keymapper.Constants -import io.github.sds100.keymapper.R -import io.github.sds100.keymapper.keymaps.PauseKeyMapsUseCase -import io.github.sds100.keymapper.onboarding.OnboardingUseCase -import io.github.sds100.keymapper.system.accessibility.ControlAccessibilityServiceUseCase -import io.github.sds100.keymapper.system.accessibility.ServiceState -import io.github.sds100.keymapper.system.inputmethod.ShowHideInputMethodUseCase -import io.github.sds100.keymapper.system.inputmethod.ShowInputMethodPickerUseCase -import io.github.sds100.keymapper.system.inputmethod.ToggleCompatibleImeUseCase -import io.github.sds100.keymapper.util.DefaultDispatcherProvider -import io.github.sds100.keymapper.util.DispatcherProvider -import io.github.sds100.keymapper.util.getFullMessage -import io.github.sds100.keymapper.util.onFailure -import io.github.sds100.keymapper.util.onSuccess -import io.github.sds100.keymapper.util.ui.ResourceProvider +import io.github.sds100.keymapper.base.BaseMainActivity +import io.github.sds100.keymapper.base.R +import io.github.sds100.keymapper.base.keymaps.PauseKeyMapsUseCase +import io.github.sds100.keymapper.base.onboarding.OnboardingUseCase +import io.github.sds100.keymapper.base.system.accessibility.ControlAccessibilityServiceUseCase +import io.github.sds100.keymapper.base.system.inputmethod.ShowHideInputMethodUseCase +import io.github.sds100.keymapper.base.system.inputmethod.ShowInputMethodPickerUseCase +import io.github.sds100.keymapper.base.system.inputmethod.ToggleCompatibleImeUseCase +import io.github.sds100.keymapper.base.utils.getFullMessage +import io.github.sds100.keymapper.base.utils.ui.ResourceProvider +import io.github.sds100.keymapper.common.BuildConfigProvider +import io.github.sds100.keymapper.common.utils.DefaultDispatcherProvider +import io.github.sds100.keymapper.common.utils.DispatcherProvider +import io.github.sds100.keymapper.common.utils.onFailure +import io.github.sds100.keymapper.common.utils.onSuccess +import io.github.sds100.keymapper.system.accessibility.AccessibilityServiceState +import io.github.sds100.keymapper.system.notifications.NotificationChannelModel +import io.github.sds100.keymapper.system.notifications.NotificationIntentType +import io.github.sds100.keymapper.system.notifications.NotificationModel import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.SharedFlow @@ -29,12 +32,11 @@ import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch +import javax.inject.Inject +import javax.inject.Singleton -/** - * Created by sds100 on 24/03/2019. - */ - -class NotificationController( +@Singleton +class NotificationController @Inject constructor( private val coroutineScope: CoroutineScope, private val manageNotifications: ManageNotificationsUseCase, private val pauseMappings: PauseKeyMapsUseCase, @@ -45,6 +47,7 @@ class NotificationController( private val onboardingUseCase: OnboardingUseCase, private val resourceProvider: ResourceProvider, private val dispatchers: DispatcherProvider = DefaultDispatcherProvider(), + private val buildConfigProvider: BuildConfigProvider, ) : ResourceProvider by resourceProvider { companion object { @@ -67,31 +70,32 @@ class NotificationController( @Deprecated("Removed in 2.0. This channel shouldn't exist") private const val CHANNEL_ID_PERSISTENT = "channel_persistent" + } - private const val ACTION_RESUME_MAPPINGS = - "${Constants.PACKAGE_NAME}.ACTION_RESUME_MAPPINGS" + private val actionResumeMappings = + "${buildConfigProvider.packageName}.ACTION_RESUME_MAPPINGS" - private const val ACTION_PAUSE_MAPPINGS = "${Constants.PACKAGE_NAME}.ACTION_PAUSE_MAPPINGS" + private val actionPauseMappings = "${buildConfigProvider.packageName}.ACTION_PAUSE_MAPPINGS" - private const val ACTION_START_SERVICE = - "${Constants.PACKAGE_NAME}.ACTION_START_ACCESSIBILITY_SERVICE" + private val actionStartService = + "${buildConfigProvider.packageName}.ACTION_START_ACCESSIBILITY_SERVICE" - private const val ACTION_RESTART_SERVICE = - "${Constants.PACKAGE_NAME}.ACTION_RESTART_ACCESSIBILITY_SERVICE" + private val actionRestartService = + "${buildConfigProvider.packageName}.ACTION_RESTART_ACCESSIBILITY_SERVICE" - private const val ACTION_STOP_SERVICE = - "${Constants.PACKAGE_NAME}.ACTION_STOP_ACCESSIBILITY_SERVICE" + private val actionStopService = + "${buildConfigProvider.packageName}.ACTION_STOP_ACCESSIBILITY_SERVICE" - private const val ACTION_DISMISS_TOGGLE_MAPPINGS = - "${Constants.PACKAGE_NAME}.ACTION_DISMISS_TOGGLE_MAPPINGS" + private val actionDismissToggleMappings = + "${buildConfigProvider.packageName}.ACTION_DISMISS_TOGGLE_MAPPINGS" - private const val ACTION_SHOW_IME_PICKER = - "${Constants.PACKAGE_NAME}.ACTION_SHOW_IME_PICKER" - private const val ACTION_SHOW_KEYBOARD = "${Constants.PACKAGE_NAME}.ACTION_SHOW_KEYBOARD" + private val actionShowImePicker = + "${buildConfigProvider.packageName}.ACTION_SHOW_IME_PICKER" - private const val ACTION_TOGGLE_KEYBOARD = - "${Constants.PACKAGE_NAME}.ACTION_TOGGLE_KEYBOARD" - } + private val actionShowKeyboard = "${buildConfigProvider.packageName}.ACTION_SHOW_KEYBOARD" + + private val actionToggleKeyboard = + "${buildConfigProvider.packageName}.ACTION_TOGGLE_KEYBOARD" /** * Open the app and use the String as the Intent action. @@ -102,7 +106,7 @@ class NotificationController( private val _showToast = MutableSharedFlow() val showToast = _showToast.asSharedFlow() - init { + fun init() { manageNotifications.deleteChannel(CHANNEL_ID_WARNINGS) manageNotifications.deleteChannel(CHANNEL_ID_PERSISTENT) @@ -188,16 +192,16 @@ class NotificationController( manageNotifications.onActionClick.onEach { actionId -> when (actionId) { - ACTION_RESUME_MAPPINGS -> pauseMappings.resume() - ACTION_PAUSE_MAPPINGS -> pauseMappings.pause() - ACTION_START_SERVICE -> attemptStartAccessibilityService() - ACTION_RESTART_SERVICE -> attemptRestartAccessibilityService() - ACTION_STOP_SERVICE -> controlAccessibilityService.stopService() - - ACTION_DISMISS_TOGGLE_MAPPINGS -> manageNotifications.dismiss(ID_TOGGLE_MAPPINGS) - ACTION_SHOW_IME_PICKER -> showImePicker.show(fromForeground = false) - ACTION_SHOW_KEYBOARD -> hideInputMethod.show() - ACTION_TOGGLE_KEYBOARD -> toggleCompatibleIme.toggle().onSuccess { + actionResumeMappings -> pauseMappings.resume() + actionPauseMappings -> pauseMappings.pause() + actionStartService -> attemptStartAccessibilityService() + actionRestartService -> attemptRestartAccessibilityService() + actionStopService -> controlAccessibilityService.stopService() + + actionDismissToggleMappings -> manageNotifications.dismiss(ID_TOGGLE_MAPPINGS) + actionShowImePicker -> showImePicker.show(fromForeground = false) + actionShowKeyboard -> hideInputMethod.show() + actionToggleKeyboard -> toggleCompatibleIme.toggle().onSuccess { _showToast.emit(getString(R.string.toast_chose_keyboard, it.label)) }.onFailure { _showToast.emit(it.getFullMessage(this)) @@ -236,7 +240,7 @@ class NotificationController( private fun invalidateToggleMappingsNotification( show: Boolean, - serviceState: ServiceState, + serviceState: AccessibilityServiceState, areMappingsPaused: Boolean, ) { manageNotifications.createChannel( @@ -253,7 +257,7 @@ class NotificationController( } when (serviceState) { - ServiceState.ENABLED -> { + AccessibilityServiceState.ENABLED -> { if (areMappingsPaused) { manageNotifications.show(mappingsPausedNotification()) } else { @@ -261,10 +265,10 @@ class NotificationController( } } - ServiceState.CRASHED -> + AccessibilityServiceState.CRASHED -> manageNotifications.show(accessibilityServiceCrashedNotification()) - ServiceState.DISABLED -> + AccessibilityServiceState.DISABLED -> manageNotifications.show(accessibilityServiceDisabledNotification()) } } @@ -273,7 +277,7 @@ class NotificationController( val stopServiceAction = if (controlAccessibilityService.isUserInteractionRequired()) { NotificationIntentType.Activity(Settings.ACTION_ACCESSIBILITY_SETTINGS) } else { - NotificationIntentType.Broadcast(ACTION_STOP_SERVICE) + NotificationIntentType.Broadcast(actionStopService) } return NotificationModel( @@ -289,11 +293,11 @@ class NotificationController( actions = listOf( NotificationModel.Action( getString(R.string.notification_action_resume), - NotificationIntentType.Broadcast(ACTION_RESUME_MAPPINGS), + NotificationIntentType.Broadcast(actionResumeMappings), ), NotificationModel.Action( getString(R.string.notification_action_dismiss), - NotificationIntentType.Broadcast(ACTION_DISMISS_TOGGLE_MAPPINGS), + NotificationIntentType.Broadcast(actionDismissToggleMappings), ), NotificationModel.Action( getString(R.string.notification_action_stop_acc_service), @@ -310,7 +314,7 @@ class NotificationController( val stopServiceAction = if (controlAccessibilityService.isUserInteractionRequired()) { NotificationIntentType.Activity(Settings.ACTION_ACCESSIBILITY_SETTINGS) } else { - NotificationIntentType.Broadcast(ACTION_STOP_SERVICE) + NotificationIntentType.Broadcast(actionStopService) } return NotificationModel( @@ -326,11 +330,11 @@ class NotificationController( actions = listOf( NotificationModel.Action( getString(R.string.notification_action_pause), - NotificationIntentType.Broadcast(ACTION_PAUSE_MAPPINGS), + NotificationIntentType.Broadcast(actionPauseMappings), ), NotificationModel.Action( getString(R.string.notification_action_dismiss), - NotificationIntentType.Broadcast(ACTION_DISMISS_TOGGLE_MAPPINGS), + NotificationIntentType.Broadcast(actionDismissToggleMappings), ), NotificationModel.Action( getString(R.string.notification_action_stop_acc_service), @@ -347,7 +351,7 @@ class NotificationController( val onClickAction = if (controlAccessibilityService.isUserInteractionRequired()) { NotificationIntentType.Activity(Settings.ACTION_ACCESSIBILITY_SETTINGS) } else { - NotificationIntentType.Broadcast(ACTION_START_SERVICE) + NotificationIntentType.Broadcast(actionStartService) } return NotificationModel( @@ -363,7 +367,7 @@ class NotificationController( actions = listOf( NotificationModel.Action( getString(R.string.notification_action_dismiss), - NotificationIntentType.Broadcast(ACTION_DISMISS_TOGGLE_MAPPINGS), + NotificationIntentType.Broadcast(actionDismissToggleMappings), ), ), ) @@ -376,7 +380,7 @@ class NotificationController( val onClickAction = if (controlAccessibilityService.isUserInteractionRequired()) { NotificationIntentType.Activity(Settings.ACTION_ACCESSIBILITY_SETTINGS) } else { - NotificationIntentType.Broadcast(ACTION_RESTART_SERVICE) + NotificationIntentType.Broadcast(actionRestartService) } return NotificationModel( @@ -405,7 +409,7 @@ class NotificationController( title = getString(R.string.notification_ime_persistent_title), text = getString(R.string.notification_ime_persistent_text), icon = R.drawable.ic_notification_keyboard, - onClickAction = NotificationIntentType.Broadcast(ACTION_SHOW_IME_PICKER), + onClickAction = NotificationIntentType.Broadcast(actionShowImePicker), showOnLockscreen = false, onGoing = true, priority = NotificationCompat.PRIORITY_MIN, @@ -423,7 +427,7 @@ class NotificationController( actions = listOf( NotificationModel.Action( getString(R.string.notification_toggle_keyboard_action), - intentType = NotificationIntentType.Broadcast(ACTION_TOGGLE_KEYBOARD), + intentType = NotificationIntentType.Broadcast(actionToggleKeyboard), ), ), ) @@ -434,7 +438,7 @@ class NotificationController( title = getString(R.string.notification_keyboard_hidden_title), text = getString(R.string.notification_keyboard_hidden_text), icon = R.drawable.ic_notification_keyboard_hide, - onClickAction = NotificationIntentType.Broadcast(ACTION_SHOW_KEYBOARD), + onClickAction = NotificationIntentType.Broadcast(actionShowKeyboard), showOnLockscreen = false, onGoing = true, priority = NotificationCompat.PRIORITY_LOW, diff --git a/app/src/main/java/io/github/sds100/keymapper/system/permissions/AutoGrantPermissionController.kt b/base/src/main/java/io/github/sds100/keymapper/base/system/permissions/AutoGrantPermissionController.kt similarity index 67% rename from app/src/main/java/io/github/sds100/keymapper/system/permissions/AutoGrantPermissionController.kt rename to base/src/main/java/io/github/sds100/keymapper/base/system/permissions/AutoGrantPermissionController.kt index 865b165f81..e00c42515d 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/permissions/AutoGrantPermissionController.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/system/permissions/AutoGrantPermissionController.kt @@ -1,21 +1,21 @@ -package io.github.sds100.keymapper.system.permissions +package io.github.sds100.keymapper.base.system.permissions import android.Manifest -import io.github.sds100.keymapper.R -import io.github.sds100.keymapper.system.popup.PopupMessageAdapter -import io.github.sds100.keymapper.util.onSuccess -import io.github.sds100.keymapper.util.ui.ResourceProvider +import io.github.sds100.keymapper.base.R +import io.github.sds100.keymapper.base.utils.ui.ResourceProvider +import io.github.sds100.keymapper.common.utils.onSuccess +import io.github.sds100.keymapper.system.permissions.Permission +import io.github.sds100.keymapper.system.permissions.PermissionAdapter +import io.github.sds100.keymapper.system.popup.ToastAdapter import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.launchIn +import javax.inject.Inject -/** - * Created by sds100 on 12/09/2021. - */ -class AutoGrantPermissionController( +class AutoGrantPermissionController @Inject constructor( private val coroutineScope: CoroutineScope, private val permissionAdapter: PermissionAdapter, - private val popupAdapter: PopupMessageAdapter, + private val popupAdapter: ToastAdapter, private val resourceProvider: ResourceProvider, ) { @@ -35,7 +35,7 @@ class AutoGrantPermissionController( R.string.toast_granted_itself_write_secure_settings_with_shizuku } - popupAdapter.showPopupMessage(resourceProvider.getString(stringRes)) + popupAdapter.show(resourceProvider.getString(stringRes)) } } }.launchIn(coroutineScope) diff --git a/app/src/main/java/io/github/sds100/keymapper/system/permissions/RequestPermissionDelegate.kt b/base/src/main/java/io/github/sds100/keymapper/base/system/permissions/RequestPermissionDelegate.kt similarity index 82% rename from app/src/main/java/io/github/sds100/keymapper/system/permissions/RequestPermissionDelegate.kt rename to base/src/main/java/io/github/sds100/keymapper/base/system/permissions/RequestPermissionDelegate.kt index e3f4b247bb..4b3c3d8dbd 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/permissions/RequestPermissionDelegate.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/system/permissions/RequestPermissionDelegate.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.system.permissions +package io.github.sds100.keymapper.base.system.permissions import android.Manifest import android.app.admin.DevicePolicyManager @@ -8,21 +8,23 @@ import android.content.Intent import android.net.Uri import android.os.Build import android.provider.Settings +import android.widget.Toast import androidx.activity.result.contract.ActivityResultContracts import androidx.annotation.RequiresApi import androidx.appcompat.app.AppCompatActivity import androidx.core.app.ActivityCompat import androidx.navigation.NavController -import io.github.sds100.keymapper.Constants -import io.github.sds100.keymapper.NavAppDirections -import io.github.sds100.keymapper.R -import io.github.sds100.keymapper.ServiceLocator -import io.github.sds100.keymapper.shizuku.ShizukuUtils +import io.github.sds100.keymapper.base.NavBaseAppDirections +import io.github.sds100.keymapper.base.R +import io.github.sds100.keymapper.base.utils.ui.str +import io.github.sds100.keymapper.common.BuildConfigProvider import io.github.sds100.keymapper.system.DeviceAdmin -import io.github.sds100.keymapper.system.accessibility.ServiceAdapter +import io.github.sds100.keymapper.system.notifications.NotificationReceiverAdapterImpl +import io.github.sds100.keymapper.system.permissions.AndroidPermissionAdapter +import io.github.sds100.keymapper.system.permissions.Permission +import io.github.sds100.keymapper.system.shizuku.ShizukuAdapter +import io.github.sds100.keymapper.system.shizuku.ShizukuUtils import io.github.sds100.keymapper.system.url.UrlUtils -import io.github.sds100.keymapper.util.str -import rikka.shizuku.Shizuku import splitties.alertdialog.appcompat.messageResource import splitties.alertdialog.appcompat.negativeButton import splitties.alertdialog.appcompat.neutralButton @@ -30,23 +32,23 @@ import splitties.alertdialog.appcompat.okButton import splitties.alertdialog.appcompat.positiveButton import splitties.alertdialog.appcompat.titleResource import splitties.alertdialog.material.materialAlertDialog -import splitties.toast.longToast -import splitties.toast.toast -/** - * Created by sds100 on 13/04/2021. - */ class RequestPermissionDelegate( private val activity: AppCompatActivity, val showDialogs: Boolean, + private val permissionAdapter: AndroidPermissionAdapter, + private val notificationReceiverAdapter: NotificationReceiverAdapterImpl, + private val buildConfigProvider: BuildConfigProvider, + private val shizukuAdapter: ShizukuAdapter, ) { + private val startActivityForResultLauncher = activity.activityResultRegistry.register( "start_activity", activity, ActivityResultContracts.StartActivityForResult(), ) { - ServiceLocator.permissionAdapter(activity).onPermissionsChanged() + permissionAdapter.onPermissionsChanged() } private val requestPermissionLauncher = @@ -55,17 +57,9 @@ class RequestPermissionDelegate( activity, ActivityResultContracts.RequestPermission(), ) { - ServiceLocator.permissionAdapter(activity).onPermissionsChanged() + permissionAdapter.onPermissionsChanged() } - private val permissionAdapter: PermissionAdapter by lazy { - ServiceLocator.permissionAdapter(activity) - } - - private val notificationReceiverAdapter: ServiceAdapter by lazy { - ServiceLocator.notificationReceiverAdapter(activity) - } - fun requestPermission(permission: Permission, navController: NavController?) { when (permission) { Permission.WRITE_SETTINGS -> requestWriteSettings() @@ -90,9 +84,7 @@ class RequestPermissionDelegate( Permission.SHIZUKU -> if (ShizukuUtils.isSupportedForSdkVersion()) { - if (Shizuku.getBinder() != null) { - Shizuku.requestPermission(AndroidPermissionAdapter.REQUEST_CODE_SHIZUKU_PERMISSION) - } + shizukuAdapter.requestPermission() } Permission.ACCESS_FINE_LOCATION -> @@ -109,7 +101,7 @@ class RequestPermissionDelegate( // open the notification settings to turn it on manually. if (showRationale) { Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS).apply { - putExtra(Settings.EXTRA_APP_PACKAGE, Constants.PACKAGE_NAME) + putExtra(Settings.EXTRA_APP_PACKAGE, buildConfigProvider.packageName) activity.startActivity(this) } @@ -135,7 +127,11 @@ class RequestPermissionDelegate( try { startActivityForResultLauncher.launch(intent) } catch (e: Exception) { - toast(R.string.error_cant_find_dnd_access_settings) + Toast.makeText( + activity, + R.string.error_cant_find_dnd_access_settings, + Toast.LENGTH_SHORT, + ).show() } } } @@ -143,7 +139,7 @@ class RequestPermissionDelegate( private fun requestWriteSettings() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS).apply { - data = Uri.parse("package:${Constants.PACKAGE_NAME}") + data = Uri.parse("package:${buildConfigProvider.packageName}") addFlags( Intent.FLAG_ACTIVITY_NEW_TASK @@ -156,7 +152,11 @@ class RequestPermissionDelegate( try { activity.startActivity(this) } catch (e: Exception) { - toast(R.string.error_cant_find_write_settings_page) + Toast.makeText( + activity, + R.string.error_cant_find_write_settings_page, + Toast.LENGTH_SHORT, + ).show() } } } @@ -198,7 +198,7 @@ class RequestPermissionDelegate( setIcon(R.drawable.ic_baseline_warning_24) okButton { - navController.navigate(NavAppDirections.toSettingsFragment()) + navController.navigate(NavBaseAppDirections.toSettingsFragment()) } negativeButton(R.string.neg_cancel) { it.cancel() } @@ -206,7 +206,7 @@ class RequestPermissionDelegate( show() } } else { - navController.navigate(NavAppDirections.toSettingsFragment()) + navController.navigate(NavBaseAppDirections.toSettingsFragment()) } } @@ -276,12 +276,16 @@ class RequestPermissionDelegate( try { val intent = Intent( Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS, - Uri.parse("package:${Constants.PACKAGE_NAME}"), + Uri.parse("package:${buildConfigProvider.packageName}"), ) activity.startActivity(intent) } catch (e: ActivityNotFoundException) { - activity.longToast(R.string.error_battery_optimisation_activity_not_found) + Toast.makeText( + activity, + R.string.error_battery_optimisation_activity_not_found, + Toast.LENGTH_LONG, + ).show() } } } diff --git a/app/src/main/java/io/github/sds100/keymapper/system/tiles/ToggleKeyMapperKeyboardTile.kt b/base/src/main/java/io/github/sds100/keymapper/base/tiles/ToggleKeyMapperKeyboardTile.kt similarity index 59% rename from app/src/main/java/io/github/sds100/keymapper/system/tiles/ToggleKeyMapperKeyboardTile.kt rename to base/src/main/java/io/github/sds100/keymapper/base/tiles/ToggleKeyMapperKeyboardTile.kt index fa7cdf770f..2351c04bf6 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/tiles/ToggleKeyMapperKeyboardTile.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/tiles/ToggleKeyMapperKeyboardTile.kt @@ -1,35 +1,38 @@ -package io.github.sds100.keymapper.system.tiles +package io.github.sds100.keymapper.base.tiles import android.graphics.drawable.Icon import android.os.Build import android.service.quicksettings.Tile import android.service.quicksettings.TileService +import android.widget.Toast import androidx.annotation.RequiresApi import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.LifecycleRegistry import androidx.lifecycle.lifecycleScope -import io.github.sds100.keymapper.R -import io.github.sds100.keymapper.ServiceLocator -import io.github.sds100.keymapper.UseCases -import io.github.sds100.keymapper.util.getFullMessage -import io.github.sds100.keymapper.util.launchRepeatOnLifecycle -import io.github.sds100.keymapper.util.onFailure -import io.github.sds100.keymapper.util.onSuccess -import io.github.sds100.keymapper.util.str +import dagger.hilt.android.AndroidEntryPoint +import io.github.sds100.keymapper.base.R +import io.github.sds100.keymapper.base.system.inputmethod.ToggleCompatibleImeUseCase +import io.github.sds100.keymapper.base.utils.getFullMessage +import io.github.sds100.keymapper.base.utils.ui.ResourceProvider +import io.github.sds100.keymapper.base.utils.ui.launchRepeatOnLifecycle +import io.github.sds100.keymapper.base.utils.ui.str +import io.github.sds100.keymapper.common.utils.onFailure +import io.github.sds100.keymapper.common.utils.onSuccess import kotlinx.coroutines.flow.first -import splitties.toast.toast +import javax.inject.Inject -/** - * Created by sds100 on 12/06/2020. - */ @RequiresApi(Build.VERSION_CODES.N) +@AndroidEntryPoint class ToggleKeyMapperKeyboardTile : TileService(), LifecycleOwner { - private val useCase by lazy { UseCases.toggleCompatibleIme(this) } - private val resourceProvider by lazy { ServiceLocator.resourceProvider(this) } + @Inject + lateinit var useCase: ToggleCompatibleImeUseCase + + @Inject + lateinit var resourceProvider: ResourceProvider private lateinit var lifecycleRegistry: LifecycleRegistry @@ -77,14 +80,26 @@ class ToggleKeyMapperKeyboardTile : lifecycleScope.launchWhenStarted { if (!useCase.sufficientPermissions.first()) { - toast(R.string.error_insufficient_permissions) + Toast.makeText( + this@ToggleKeyMapperKeyboardTile, + R.string.error_insufficient_permissions, + Toast.LENGTH_SHORT, + ).show() return@launchWhenStarted } useCase.toggle().onSuccess { - toast(resourceProvider.getString(R.string.toast_chose_keyboard, it.label)) + Toast.makeText( + this@ToggleKeyMapperKeyboardTile, + str(R.string.toast_chose_keyboard, it.label), + Toast.LENGTH_SHORT, + ).show() }.onFailure { - toast(it.getFullMessage(resourceProvider)) + Toast.makeText( + this@ToggleKeyMapperKeyboardTile, + it.getFullMessage(resourceProvider), + Toast.LENGTH_SHORT, + ).show() } } } diff --git a/app/src/main/java/io/github/sds100/keymapper/system/tiles/ToggleMappingsTile.kt b/base/src/main/java/io/github/sds100/keymapper/base/tiles/ToggleMappingsTile.kt similarity index 81% rename from app/src/main/java/io/github/sds100/keymapper/system/tiles/ToggleMappingsTile.kt rename to base/src/main/java/io/github/sds100/keymapper/base/tiles/ToggleMappingsTile.kt index 7763983b09..7de0a99014 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/tiles/ToggleMappingsTile.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/tiles/ToggleMappingsTile.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.system.tiles +package io.github.sds100.keymapper.base.tiles import android.graphics.drawable.Icon import android.os.Build @@ -8,27 +8,29 @@ import androidx.annotation.RequiresApi import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.LifecycleRegistry -import io.github.sds100.keymapper.R -import io.github.sds100.keymapper.ServiceLocator -import io.github.sds100.keymapper.UseCases -import io.github.sds100.keymapper.system.accessibility.ServiceState -import io.github.sds100.keymapper.util.firstBlocking -import io.github.sds100.keymapper.util.launchRepeatOnLifecycle -import io.github.sds100.keymapper.util.str +import dagger.hilt.android.AndroidEntryPoint +import io.github.sds100.keymapper.base.R +import io.github.sds100.keymapper.base.keymaps.PauseKeyMapsUseCase +import io.github.sds100.keymapper.base.utils.ui.launchRepeatOnLifecycle +import io.github.sds100.keymapper.base.utils.ui.str +import io.github.sds100.keymapper.common.utils.firstBlocking +import io.github.sds100.keymapper.system.accessibility.AccessibilityServiceAdapter +import io.github.sds100.keymapper.system.accessibility.AccessibilityServiceState import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.combine - -/** - * Created by sds100 on 12/06/2020. - */ +import javax.inject.Inject @RequiresApi(Build.VERSION_CODES.N) +@AndroidEntryPoint class ToggleMappingsTile : TileService(), LifecycleOwner { - private val serviceAdapter by lazy { ServiceLocator.accessibilityServiceAdapter(this) } - private val useCase by lazy { UseCases.pauseKeyMaps(this) } + @Inject + lateinit var serviceAdapter: AccessibilityServiceAdapter + + @Inject + lateinit var useCase: PauseKeyMapsUseCase private lateinit var lifecycleRegistry: LifecycleRegistry @@ -55,12 +57,12 @@ class ToggleMappingsTile : } private fun updateQsTilePreSdk29( - serviceState: ServiceState, + serviceState: AccessibilityServiceState, ctx: ToggleMappingsTile, isPaused: Boolean, ) { when { - serviceState == ServiceState.DISABLED -> { + serviceState == AccessibilityServiceState.DISABLED -> { qsTile.label = str(R.string.tile_service_disabled) qsTile.contentDescription = str(R.string.tile_accessibility_service_disabled_content_description) @@ -88,12 +90,12 @@ class ToggleMappingsTile : @RequiresApi(Build.VERSION_CODES.Q) private fun updateQsTile( - serviceState: ServiceState, + serviceState: AccessibilityServiceState, ctx: ToggleMappingsTile, isPaused: Boolean, ) { when { - serviceState == ServiceState.DISABLED -> { + serviceState == AccessibilityServiceState.DISABLED -> { qsTile.label = str(R.string.app_name) qsTile.subtitle = str(R.string.tile_service_disabled) qsTile.contentDescription = @@ -141,7 +143,7 @@ class ToggleMappingsTile : override fun onClick() { super.onClick() - if (serviceAdapter.state.value == ServiceState.DISABLED) return + if (serviceAdapter.state.value == AccessibilityServiceState.DISABLED) return if (useCase.isPaused.firstBlocking()) { useCase.resume() diff --git a/app/src/main/java/io/github/sds100/keymapper/trigger/AssistantTriggerKey.kt b/base/src/main/java/io/github/sds100/keymapper/base/trigger/AssistantTriggerKey.kt similarity index 96% rename from app/src/main/java/io/github/sds100/keymapper/trigger/AssistantTriggerKey.kt rename to base/src/main/java/io/github/sds100/keymapper/base/trigger/AssistantTriggerKey.kt index 1be79413e4..0acb6cde87 100644 --- a/app/src/main/java/io/github/sds100/keymapper/trigger/AssistantTriggerKey.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/trigger/AssistantTriggerKey.kt @@ -1,8 +1,8 @@ -package io.github.sds100.keymapper.trigger +package io.github.sds100.keymapper.base.trigger +import io.github.sds100.keymapper.base.keymaps.ClickType import io.github.sds100.keymapper.data.entities.AssistantTriggerKeyEntity import io.github.sds100.keymapper.data.entities.TriggerKeyEntity -import io.github.sds100.keymapper.keymaps.ClickType import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable import java.util.UUID diff --git a/app/src/main/java/io/github/sds100/keymapper/trigger/AssistantTriggerType.kt b/base/src/main/java/io/github/sds100/keymapper/base/trigger/AssistantTriggerType.kt similarity index 92% rename from app/src/main/java/io/github/sds100/keymapper/trigger/AssistantTriggerType.kt rename to base/src/main/java/io/github/sds100/keymapper/base/trigger/AssistantTriggerType.kt index 57a5b82736..c7ec0a2b9e 100644 --- a/app/src/main/java/io/github/sds100/keymapper/trigger/AssistantTriggerType.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/trigger/AssistantTriggerType.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.trigger +package io.github.sds100.keymapper.base.trigger /** * The type of assistant that triggers an assistant trigger key. The voice assistant diff --git a/app/src/main/java/io/github/sds100/keymapper/trigger/BaseConfigTriggerViewModel.kt b/base/src/main/java/io/github/sds100/keymapper/base/trigger/BaseConfigTriggerViewModel.kt similarity index 88% rename from app/src/main/java/io/github/sds100/keymapper/trigger/BaseConfigTriggerViewModel.kt rename to base/src/main/java/io/github/sds100/keymapper/base/trigger/BaseConfigTriggerViewModel.kt index 21a500ecdc..0244f5266b 100644 --- a/app/src/main/java/io/github/sds100/keymapper/trigger/BaseConfigTriggerViewModel.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/trigger/BaseConfigTriggerViewModel.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.trigger +package io.github.sds100.keymapper.base.trigger import android.view.KeyEvent import androidx.compose.material.icons.Icons @@ -8,41 +8,40 @@ import androidx.compose.material.icons.rounded.Fingerprint import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue -import io.github.sds100.keymapper.R -import io.github.sds100.keymapper.keymaps.ClickType -import io.github.sds100.keymapper.keymaps.ConfigKeyMapOptionsViewModel -import io.github.sds100.keymapper.keymaps.ConfigKeyMapUseCase -import io.github.sds100.keymapper.keymaps.CreateKeyMapShortcutUseCase -import io.github.sds100.keymapper.keymaps.DisplayKeyMapUseCase -import io.github.sds100.keymapper.keymaps.FingerprintGestureType -import io.github.sds100.keymapper.keymaps.FingerprintGesturesSupportedUseCase -import io.github.sds100.keymapper.keymaps.KeyMap -import io.github.sds100.keymapper.keymaps.ShortcutModel -import io.github.sds100.keymapper.onboarding.OnboardingTapTarget -import io.github.sds100.keymapper.onboarding.OnboardingUseCase -import io.github.sds100.keymapper.purchasing.ProductId -import io.github.sds100.keymapper.purchasing.PurchasingManager +import io.github.sds100.keymapper.base.R +import io.github.sds100.keymapper.base.keymaps.ClickType +import io.github.sds100.keymapper.base.keymaps.ConfigKeyMapOptionsViewModel +import io.github.sds100.keymapper.base.keymaps.ConfigKeyMapUseCase +import io.github.sds100.keymapper.base.keymaps.CreateKeyMapShortcutUseCase +import io.github.sds100.keymapper.base.keymaps.DisplayKeyMapUseCase +import io.github.sds100.keymapper.base.keymaps.FingerprintGesturesSupportedUseCase +import io.github.sds100.keymapper.base.keymaps.KeyMap +import io.github.sds100.keymapper.base.keymaps.ShortcutModel +import io.github.sds100.keymapper.base.onboarding.OnboardingTapTarget +import io.github.sds100.keymapper.base.onboarding.OnboardingUseCase +import io.github.sds100.keymapper.base.purchasing.ProductId +import io.github.sds100.keymapper.base.purchasing.PurchasingManager +import io.github.sds100.keymapper.base.system.accessibility.FingerprintGestureType +import io.github.sds100.keymapper.base.utils.InputEventStrings +import io.github.sds100.keymapper.base.utils.navigation.NavigationProvider +import io.github.sds100.keymapper.base.utils.ui.CheckBoxListItem +import io.github.sds100.keymapper.base.utils.ui.DialogModel +import io.github.sds100.keymapper.base.utils.ui.DialogProvider +import io.github.sds100.keymapper.base.utils.ui.DialogResponse +import io.github.sds100.keymapper.base.utils.ui.LinkType +import io.github.sds100.keymapper.base.utils.ui.ResourceProvider +import io.github.sds100.keymapper.base.utils.ui.ViewModelHelper +import io.github.sds100.keymapper.base.utils.ui.compose.ComposeIconInfo +import io.github.sds100.keymapper.base.utils.ui.showDialog +import io.github.sds100.keymapper.common.utils.KMError +import io.github.sds100.keymapper.common.utils.KMResult +import io.github.sds100.keymapper.common.utils.State +import io.github.sds100.keymapper.common.utils.dataOrNull +import io.github.sds100.keymapper.common.utils.ifIsData +import io.github.sds100.keymapper.common.utils.mapData +import io.github.sds100.keymapper.common.utils.onSuccess import io.github.sds100.keymapper.system.devices.InputDeviceUtils import io.github.sds100.keymapper.system.inputevents.InputEventUtils -import io.github.sds100.keymapper.util.Error -import io.github.sds100.keymapper.util.Result -import io.github.sds100.keymapper.util.State -import io.github.sds100.keymapper.util.dataOrNull -import io.github.sds100.keymapper.util.ifIsData -import io.github.sds100.keymapper.util.mapData -import io.github.sds100.keymapper.util.onSuccess -import io.github.sds100.keymapper.util.ui.CheckBoxListItem -import io.github.sds100.keymapper.util.ui.DialogResponse -import io.github.sds100.keymapper.util.ui.LinkType -import io.github.sds100.keymapper.util.ui.NavigationViewModel -import io.github.sds100.keymapper.util.ui.NavigationViewModelImpl -import io.github.sds100.keymapper.util.ui.PopupUi -import io.github.sds100.keymapper.util.ui.PopupViewModel -import io.github.sds100.keymapper.util.ui.PopupViewModelImpl -import io.github.sds100.keymapper.util.ui.ResourceProvider -import io.github.sds100.keymapper.util.ui.ViewModelHelper -import io.github.sds100.keymapper.util.ui.compose.ComposeIconInfo -import io.github.sds100.keymapper.util.ui.showPopup import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow @@ -62,10 +61,6 @@ import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch -/** - * Created by sds100 on 24/11/20. - */ - abstract class BaseConfigTriggerViewModel( private val coroutineScope: CoroutineScope, private val onboarding: OnboardingUseCase, @@ -77,9 +72,11 @@ abstract class BaseConfigTriggerViewModel( private val setupGuiKeyboard: SetupGuiKeyboardUseCase, private val fingerprintGesturesSupported: FingerprintGesturesSupportedUseCase, resourceProvider: ResourceProvider, + navigationProvider: NavigationProvider, + dialogProvider: DialogProvider, ) : ResourceProvider by resourceProvider, - PopupViewModel by PopupViewModelImpl(), - NavigationViewModel by NavigationViewModelImpl() { + DialogProvider by dialogProvider, + NavigationProvider by navigationProvider { companion object { private const val DEVICE_ID_ANY = "any" @@ -91,6 +88,7 @@ abstract class BaseConfigTriggerViewModel( config, displayKeyMap, createKeyMapShortcut, + dialogProvider, resourceProvider, ) @@ -161,7 +159,11 @@ abstract class BaseConfigTriggerViewModel( isEnabled, isChosen, ) - }.stateIn(coroutineScope, SharingStarted.Lazily, SetupGuiKeyboardState.DEFAULT) + }.stateIn( + coroutineScope, + SharingStarted.Lazily, + SetupGuiKeyboardState.DEFAULT, + ) val triggerKeyOptionsUid = MutableStateFlow(null) val triggerKeyOptionsState: StateFlow = @@ -247,7 +249,7 @@ abstract class BaseConfigTriggerViewModel( FingerprintGestureType.SWIPE_RIGHT to getString(R.string.fingerprint_gesture_right), ) - val selectedType = showPopup("pick_assistant_type", PopupUi.SingleChoice(listItems)) + val selectedType = showDialog("pick_assistant_type", DialogModel.SingleChoice(listItems)) ?: return@launch config.addFingerprintGesture(type = selectedType) @@ -440,11 +442,11 @@ abstract class BaseConfigTriggerViewModel( return } - val dialog = PopupUi.Ok( + val dialog = DialogModel.Ok( message = getString(R.string.dialog_message_parallel_trigger_order), ) - showPopup("parallel_trigger_order", dialog) ?: return + showDialog("parallel_trigger_order", dialog) ?: return onboarding.shownParallelTriggerOrderExplanation = true } @@ -454,11 +456,11 @@ abstract class BaseConfigTriggerViewModel( return } - val dialog = PopupUi.Ok( + val dialog = DialogModel.Ok( message = getString(R.string.dialog_message_sequence_trigger_explanation), ) - showPopup("sequence_trigger_explanation", dialog) + showDialog("sequence_trigger_explanation", dialog) ?: return onboarding.shownSequenceTriggerExplanation = true @@ -475,13 +477,13 @@ abstract class BaseConfigTriggerViewModel( return } - val dialog = PopupUi.Dialog( + val dialog = DialogModel.Alert( title = getString(R.string.dialog_title_keycode_to_scancode_trigger_explanation), message = getString(R.string.dialog_message_keycode_to_scancode_trigger_explanation), positiveButtonText = getString(R.string.pos_understood), ) - val response = showPopup("keycode_to_scancode_message", dialog) + val response = showDialog("keycode_to_scancode_message", dialog) if (response == DialogResponse.POSITIVE) { onboarding.shownKeyCodeToScanCodeTriggerExplanation = true @@ -489,33 +491,33 @@ abstract class BaseConfigTriggerViewModel( } if (key.keyCode == KeyEvent.KEYCODE_CAPS_LOCK) { - val dialog = PopupUi.Ok( + val dialog = DialogModel.Ok( message = getString(R.string.dialog_message_enable_physical_keyboard_caps_lock_a_keyboard_layout), ) - showPopup("caps_lock_message", dialog) + showDialog("caps_lock_message", dialog) } if (key.keyCode == KeyEvent.KEYCODE_BACK) { - val dialog = PopupUi.Ok( + val dialog = DialogModel.Ok( message = getString(R.string.dialog_message_screen_pinning_warning), ) - showPopup("screen_pinning_message", dialog) + showDialog("screen_pinning_message", dialog) } // Issue #491. Some key codes can only be detected through an input method. This will // be shown to the user by showing a keyboard icon next to the trigger key name so // explain this to the user. if (key.detectionSource == KeyEventDetectionSource.INPUT_METHOD && displayKeyMap.showTriggerKeyboardIconExplanation.first()) { - val dialog = PopupUi.Dialog( + val dialog = DialogModel.Alert( title = getString(R.string.dialog_title_keyboard_icon_means_ime_detection), message = getString(R.string.dialog_message_keyboard_icon_means_ime_detection), negativeButtonText = getString(R.string.neg_dont_show_again), positiveButtonText = getString(R.string.pos_ok), ) - val response = showPopup("keyboard_icon_explanation", dialog) + val response = showDialog("keyboard_icon_explanation", dialog) if (response == DialogResponse.NEGATIVE) { displayKeyMap.neverShowTriggerKeyboardIconExplanation() @@ -569,7 +571,10 @@ abstract class BaseConfigTriggerViewModel( .firstOrNull { it.descriptor == descriptor } ?: return - TriggerKeyDevice.External(device.descriptor, device.name) + TriggerKeyDevice.External( + device.descriptor, + device.name, + ) } } @@ -612,19 +617,19 @@ abstract class BaseConfigTriggerViewModel( } } - suspend fun handleServiceEventResult(result: Result<*>) { - if (result is Error.AccessibilityServiceDisabled) { + suspend fun handleServiceEventResult(result: KMResult<*>) { + if (result is KMError.AccessibilityServiceDisabled) { ViewModelHelper.handleAccessibilityServiceStoppedDialog( resourceProvider = this@BaseConfigTriggerViewModel, - popupViewModel = this@BaseConfigTriggerViewModel, + dialogProvider = this@BaseConfigTriggerViewModel, startService = displayKeyMap::startAccessibilityService, ) } - if (result is Error.AccessibilityServiceCrashed) { + if (result is KMError.AccessibilityServiceCrashed) { ViewModelHelper.handleAccessibilityServiceCrashedDialog( resourceProvider = this@BaseConfigTriggerViewModel, - popupViewModel = this@BaseConfigTriggerViewModel, + dialogProvider = this@BaseConfigTriggerViewModel, restartService = displayKeyMap::restartAccessibilityService, ) } @@ -636,7 +641,7 @@ abstract class BaseConfigTriggerViewModel( TriggerError.DND_ACCESS_DENIED -> ViewModelHelper.showDialogExplainingDndAccessBeingUnavailable( resourceProvider = this@BaseConfigTriggerViewModel, - popupViewModel = this@BaseConfigTriggerViewModel, + dialogProvider = this@BaseConfigTriggerViewModel, neverShowDndTriggerErrorAgain = { displayKeyMap.neverShowDndTriggerError() }, fixError = { displayKeyMap.fixTriggerError(error) }, ) @@ -740,7 +745,7 @@ abstract class BaseConfigTriggerViewModel( private fun getTriggerKeyName(key: KeyCodeTriggerKey): String { return buildString { - append(InputEventUtils.keyCodeToString(key.keyCode)) + append(InputEventStrings.keyCodeToString(key.keyCode)) if (key.detectionSource == KeyEventDetectionSource.INPUT_METHOD) { val midDot = getString(R.string.middot) @@ -796,6 +801,9 @@ abstract class BaseConfigTriggerViewModel( fun onAdvancedTriggersTapTargetCompleted() { onboarding.completedTapTarget(OnboardingTapTarget.ADVANCED_TRIGGERS) } + + abstract fun onEditFloatingButtonClick() + abstract fun onEditFloatingLayoutClick() } sealed class ConfigTriggerState { @@ -866,7 +874,8 @@ sealed class TriggerKeyListItemModel { override val linkType: LinkType, override val clickType: ClickType, ) : TriggerKeyListItemModel() { - override val error: TriggerError = TriggerError.FLOATING_BUTTON_DELETED + override val error: TriggerError = + TriggerError.FLOATING_BUTTON_DELETED } } diff --git a/base/src/main/java/io/github/sds100/keymapper/base/trigger/BaseTriggerScreen.kt b/base/src/main/java/io/github/sds100/keymapper/base/trigger/BaseTriggerScreen.kt new file mode 100644 index 0000000000..48b54e7ae8 --- /dev/null +++ b/base/src/main/java/io/github/sds100/keymapper/base/trigger/BaseTriggerScreen.kt @@ -0,0 +1,700 @@ +package io.github.sds100.keymapper.base.trigger + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.systemBarsPadding +import androidx.compose.foundation.layout.widthIn +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.itemsIndexed +import androidx.compose.foundation.lazy.rememberLazyListState +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.rounded.Fingerprint +import androidx.compose.material3.CircularProgressIndicator +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Surface +import androidx.compose.material3.Text +import androidx.compose.material3.adaptive.currentWindowAdaptiveInfo +import androidx.compose.material3.rememberModalBottomSheetState +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.tooling.preview.Devices +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import androidx.window.core.layout.WindowHeightSizeClass +import androidx.window.core.layout.WindowWidthSizeClass +import io.github.sds100.keymapper.base.R +import io.github.sds100.keymapper.base.compose.KeyMapperTheme +import io.github.sds100.keymapper.base.keymaps.ClickType +import io.github.sds100.keymapper.base.keymaps.ShortcutModel +import io.github.sds100.keymapper.base.keymaps.ShortcutRow +import io.github.sds100.keymapper.base.utils.ui.LinkType +import io.github.sds100.keymapper.base.utils.ui.compose.ComposeIconInfo +import io.github.sds100.keymapper.base.utils.ui.compose.DraggableItem +import io.github.sds100.keymapper.base.utils.ui.compose.RadioButtonText +import io.github.sds100.keymapper.base.utils.ui.compose.rememberDragDropState +import io.github.sds100.keymapper.common.utils.State + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun BaseTriggerScreen(modifier: Modifier = Modifier, viewModel: BaseConfigTriggerViewModel) { + val sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true) + val setupGuiKeyboardState by viewModel.setupGuiKeyboardState.collectAsStateWithLifecycle() + val recordTriggerState by viewModel.recordTriggerState.collectAsStateWithLifecycle() + + if (viewModel.showDpadTriggerSetupBottomSheet) { + DpadTriggerSetupBottomSheet( + modifier = Modifier.systemBarsPadding(), + onDismissRequest = { + viewModel.showDpadTriggerSetupBottomSheet = false + }, + guiKeyboardState = setupGuiKeyboardState, + onEnableKeyboardClick = viewModel::onEnableGuiKeyboardClick, + onChooseKeyboardClick = viewModel::onChooseGuiKeyboardClick, + onNeverShowAgainClick = viewModel::onNeverShowSetupDpadClick, + sheetState = sheetState, + ) + } + + if (viewModel.showNoKeysRecordedBottomSheet) { + NoKeysRecordedBottomSheet( + modifier = Modifier.systemBarsPadding(), + onDismissRequest = { + viewModel.showNoKeysRecordedBottomSheet = false + }, + viewModel = viewModel, + sheetState = sheetState, + ) + } + + val triggerKeyOptionsState by viewModel.triggerKeyOptionsState.collectAsStateWithLifecycle() + + if (triggerKeyOptionsState != null) { + TriggerKeyOptionsBottomSheet( + modifier = Modifier.systemBarsPadding(), + sheetState = sheetState, + state = triggerKeyOptionsState!!, + onDismissRequest = viewModel::onDismissTriggerKeyOptions, + onCheckDoNotRemap = viewModel::onCheckDoNotRemap, + onSelectClickType = viewModel::onSelectKeyClickType, + onSelectDevice = viewModel::onSelectTriggerKeyDevice, + onSelectAssistantType = viewModel::onSelectTriggerKeyAssistantType, + onEditFloatingButtonClick = viewModel::onEditFloatingButtonClick, + onEditFloatingLayoutClick = viewModel::onEditFloatingLayoutClick, + onSelectFingerprintGestureType = viewModel::onSelectFingerprintGestureType, + ) + } + + val configState by viewModel.state.collectAsStateWithLifecycle() + + when (val state = configState) { + is State.Loading -> Loading(modifier = modifier) + is State.Data -> { + if (isHorizontalLayout()) { + TriggerScreenHorizontal( + modifier = modifier, + configState = state.data, + recordTriggerState = recordTriggerState, + onRemoveClick = viewModel::onRemoveKeyClick, + onEditClick = viewModel::onTriggerKeyOptionsClick, + onRecordTriggerClick = viewModel::onRecordTriggerButtonClick, + onAdvancedTriggersClick = viewModel::onAdvancedTriggersClick, + onSelectClickType = viewModel::onClickTypeRadioButtonChecked, + onSelectParallelMode = viewModel::onParallelRadioButtonChecked, + onSelectSequenceMode = viewModel::onSequenceRadioButtonChecked, + onMoveTriggerKey = viewModel::onMoveTriggerKey, + onFixErrorClick = viewModel::onTriggerErrorClick, + onClickShortcut = viewModel::onClickTriggerKeyShortcut, + onRecordTriggerTapTargetCompleted = viewModel::onRecordTriggerTapTargetCompleted, + onSkipTapTarget = viewModel::onSkipTapTargetClick, + onAdvancedTriggerTapTargetCompleted = viewModel::onAdvancedTriggersTapTargetCompleted, + ) + } else { + TriggerScreenVertical( + modifier = modifier, + configState = state.data, + recordTriggerState = recordTriggerState, + onRemoveClick = viewModel::onRemoveKeyClick, + onEditClick = viewModel::onTriggerKeyOptionsClick, + onRecordTriggerClick = viewModel::onRecordTriggerButtonClick, + onAdvancedTriggersClick = viewModel::onAdvancedTriggersClick, + onSelectClickType = viewModel::onClickTypeRadioButtonChecked, + onSelectParallelMode = viewModel::onParallelRadioButtonChecked, + onSelectSequenceMode = viewModel::onSequenceRadioButtonChecked, + onMoveTriggerKey = viewModel::onMoveTriggerKey, + onFixErrorClick = viewModel::onTriggerErrorClick, + onClickShortcut = viewModel::onClickTriggerKeyShortcut, + onRecordTriggerTapTargetCompleted = viewModel::onRecordTriggerTapTargetCompleted, + onSkipTapTarget = viewModel::onSkipTapTargetClick, + onAdvancedTriggerTapTargetCompleted = viewModel::onAdvancedTriggersTapTargetCompleted, + ) + } + } + } +} + +@Composable +private fun isHorizontalLayout(): Boolean { + val windowSizeClass = currentWindowAdaptiveInfo().windowSizeClass + + return windowSizeClass.windowHeightSizeClass == WindowHeightSizeClass.COMPACT +} + +@Composable +private fun isVerticalCompactLayout(): Boolean { + val windowSizeClass = currentWindowAdaptiveInfo().windowSizeClass + + return windowSizeClass.windowHeightSizeClass == WindowHeightSizeClass.COMPACT && windowSizeClass.windowWidthSizeClass == WindowWidthSizeClass.COMPACT +} + +@Composable +private fun Loading(modifier: Modifier = Modifier) { + Box(modifier = modifier, contentAlignment = Alignment.Center) { + CircularProgressIndicator() + } +} + +@Composable +private fun TriggerScreenVertical( + modifier: Modifier = Modifier, + configState: ConfigTriggerState, + recordTriggerState: RecordTriggerState, + onRemoveClick: (String) -> Unit = {}, + onEditClick: (String) -> Unit = {}, + onSelectClickType: (ClickType) -> Unit = {}, + onSelectParallelMode: () -> Unit = {}, + onSelectSequenceMode: () -> Unit = {}, + onRecordTriggerClick: () -> Unit = {}, + onAdvancedTriggersClick: () -> Unit = {}, + onMoveTriggerKey: (fromIndex: Int, toIndex: Int) -> Unit = { _, _ -> }, + onFixErrorClick: (TriggerError) -> Unit = {}, + onClickShortcut: (TriggerKeyShortcut) -> Unit = {}, + onRecordTriggerTapTargetCompleted: () -> Unit = {}, + onSkipTapTarget: () -> Unit = {}, + onAdvancedTriggerTapTargetCompleted: () -> Unit = {}, +) { + Surface(modifier = modifier) { + Column { + when (configState) { + is ConfigTriggerState.Empty -> { + Column( + modifier = Modifier + .weight(1f) + .verticalScroll(state = rememberScrollState()), + verticalArrangement = Arrangement.Center, + ) { + Text( + modifier = Modifier.padding(32.dp), + text = stringResource(R.string.triggers_recyclerview_placeholder), + textAlign = TextAlign.Center, + ) + + if (configState.shortcuts.isNotEmpty()) { + Column(horizontalAlignment = Alignment.CenterHorizontally) { + Text( + text = stringResource(R.string.trigger_shortcuts_header), + style = MaterialTheme.typography.titleSmall, + ) + + Spacer(Modifier.height(8.dp)) + + ShortcutRow( + modifier = Modifier + .padding(horizontal = 32.dp) + .fillMaxWidth(), + shortcuts = configState.shortcuts, + onClick = onClickShortcut, + ) + } + } + } + } + + is ConfigTriggerState.Loaded -> { + val isCompact = isVerticalCompactLayout() + Spacer(Modifier.height(8.dp)) + + TriggerList( + modifier = Modifier.weight(1f), + triggerList = configState.triggerKeys, + shortcuts = configState.shortcuts, + isReorderingEnabled = configState.isReorderingEnabled, + onEditClick = onEditClick, + onRemoveClick = onRemoveClick, + onMove = onMoveTriggerKey, + onClickShortcut = onClickShortcut, + onFixErrorClick = onFixErrorClick, + ) + + if (configState.clickTypeButtons.isNotEmpty()) { + ClickTypeRadioGroup( + modifier = Modifier.padding(horizontal = 8.dp), + clickTypes = configState.clickTypeButtons, + checkedClickType = configState.checkedClickType, + onSelectClickType = onSelectClickType, + maxLines = if (isCompact) 1 else 2, + ) + } + + if (configState.triggerModeButtonsVisible) { + if (!isCompact) { + Text( + modifier = Modifier.padding(horizontal = 8.dp), + text = stringResource(R.string.press_dot_dot_dot), + style = MaterialTheme.typography.labelLarge, + ) + } + + TriggerModeRadioGroup( + modifier = Modifier.padding(horizontal = 8.dp), + mode = configState.checkedTriggerMode, + isEnabled = configState.triggerModeButtonsEnabled, + onSelectParallelMode = onSelectParallelMode, + onSelectSequenceMode = onSelectSequenceMode, + maxLines = if (isCompact) 1 else 2, + ) + } + } + } + + RecordTriggerButtonRow( + modifier = Modifier + .fillMaxWidth() + .padding(start = 8.dp, end = 8.dp, bottom = 8.dp), + onRecordTriggerClick = onRecordTriggerClick, + recordTriggerState = recordTriggerState, + onAdvancedTriggersClick = onAdvancedTriggersClick, + showRecordTriggerTapTarget = (configState as? ConfigTriggerState.Empty)?.showRecordTriggerTapTarget + ?: false, + onRecordTriggerTapTargetCompleted = onRecordTriggerTapTargetCompleted, + onSkipTapTarget = onSkipTapTarget, + showAdvancedTriggerTapTarget = configState.showAdvancedTriggersTapTarget, + onAdvancedTriggerTapTargetCompleted = onAdvancedTriggerTapTargetCompleted, + ) + } + } +} + +@Composable +private fun TriggerScreenHorizontal( + modifier: Modifier = Modifier, + configState: ConfigTriggerState, + recordTriggerState: RecordTriggerState, + onRemoveClick: (String) -> Unit = {}, + onEditClick: (String) -> Unit = {}, + onSelectClickType: (ClickType) -> Unit = {}, + onSelectParallelMode: () -> Unit = {}, + onSelectSequenceMode: () -> Unit = {}, + onRecordTriggerClick: () -> Unit = {}, + onAdvancedTriggersClick: () -> Unit = {}, + onMoveTriggerKey: (fromIndex: Int, toIndex: Int) -> Unit = { _, _ -> }, + onFixErrorClick: (TriggerError) -> Unit = {}, + onClickShortcut: (TriggerKeyShortcut) -> Unit = {}, + onRecordTriggerTapTargetCompleted: () -> Unit = {}, + onSkipTapTarget: () -> Unit = {}, + onAdvancedTriggerTapTargetCompleted: () -> Unit = {}, +) { + Surface(modifier = modifier) { + when (configState) { + is ConfigTriggerState.Empty -> Row { + Text( + modifier = Modifier + .widthIn(max = 400.dp) + .padding(32.dp) + .verticalScroll(state = rememberScrollState()), + text = stringResource(R.string.triggers_recyclerview_placeholder), + textAlign = TextAlign.Center, + ) + Column { + if (configState.shortcuts.isNotEmpty()) { + Column( + modifier = Modifier + .weight(1f) + .verticalScroll(state = rememberScrollState()), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.Center, + ) { + Text( + text = stringResource(R.string.trigger_shortcuts_header), + style = MaterialTheme.typography.titleSmall, + ) + + Spacer(Modifier.height(8.dp)) + + ShortcutRow( + modifier = Modifier + .padding(horizontal = 32.dp) + .fillMaxWidth(), + shortcuts = configState.shortcuts, + onClick = onClickShortcut, + ) + } + } + + RecordTriggerButtonRow( + modifier = Modifier.padding(start = 8.dp, end = 8.dp, bottom = 8.dp), + onRecordTriggerClick = onRecordTriggerClick, + recordTriggerState = recordTriggerState, + onAdvancedTriggersClick = onAdvancedTriggersClick, + showRecordTriggerTapTarget = (configState as? ConfigTriggerState.Empty)?.showRecordTriggerTapTarget + ?: false, + onRecordTriggerTapTargetCompleted = onRecordTriggerTapTargetCompleted, + onSkipTapTarget = onSkipTapTarget, + showAdvancedTriggerTapTarget = configState.showAdvancedTriggersTapTarget, + ) + } + } + + is ConfigTriggerState.Loaded -> Row { + TriggerList( + modifier = Modifier + .fillMaxHeight() + .widthIn(max = 400.dp), + triggerList = configState.triggerKeys, + shortcuts = configState.shortcuts, + isReorderingEnabled = configState.isReorderingEnabled, + onEditClick = onEditClick, + onRemoveClick = onRemoveClick, + onMove = onMoveTriggerKey, + onClickShortcut = onClickShortcut, + onFixErrorClick = onFixErrorClick, + ) + + Spacer(Modifier.height(8.dp)) + + Column( + modifier = Modifier.fillMaxHeight(), + verticalArrangement = Arrangement.Bottom, + ) { + Column( + modifier = Modifier + .weight(1f) + .verticalScroll(rememberScrollState()), + ) { + if (configState.clickTypeButtons.isNotEmpty()) { + ClickTypeRadioGroup( + modifier = Modifier.padding(horizontal = 8.dp), + clickTypes = configState.clickTypeButtons, + checkedClickType = configState.checkedClickType, + onSelectClickType = onSelectClickType, + ) + } + + Text( + modifier = Modifier.padding(horizontal = 8.dp), + text = stringResource(R.string.press_dot_dot_dot), + style = MaterialTheme.typography.labelLarge, + ) + + if (configState.triggerModeButtonsVisible) { + TriggerModeRadioGroup( + modifier = Modifier.padding(horizontal = 8.dp), + mode = configState.checkedTriggerMode, + isEnabled = configState.triggerModeButtonsEnabled, + onSelectParallelMode = onSelectParallelMode, + onSelectSequenceMode = onSelectSequenceMode, + ) + } + } + + RecordTriggerButtonRow( + modifier = Modifier.padding(start = 8.dp, end = 8.dp, bottom = 8.dp), + onRecordTriggerClick = onRecordTriggerClick, + recordTriggerState = recordTriggerState, + onAdvancedTriggersClick = onAdvancedTriggersClick, + showRecordTriggerTapTarget = false, + onRecordTriggerTapTargetCompleted = onRecordTriggerTapTargetCompleted, + onSkipTapTarget = onSkipTapTarget, + showAdvancedTriggerTapTarget = configState.showAdvancedTriggersTapTarget, + onAdvancedTriggerTapTargetCompleted = onAdvancedTriggerTapTargetCompleted, + ) + } + } + } + } +} + +@Composable +private fun TriggerList( + modifier: Modifier = Modifier, + triggerList: List, + shortcuts: Set>, + isReorderingEnabled: Boolean, + onRemoveClick: (String) -> Unit, + onEditClick: (String) -> Unit, + onFixErrorClick: (TriggerError) -> Unit, + onMove: (fromIndex: Int, toIndex: Int) -> Unit, + onClickShortcut: (TriggerKeyShortcut) -> Unit, +) { + val lazyListState = rememberLazyListState() + val dragDropState = rememberDragDropState( + lazyListState = lazyListState, + onMove = onMove, + // Do not drag and drop the row of shortcuts + ignoreLastItems = if (shortcuts.isEmpty()) { + 0 + } else { + 1 + }, + ) + + // Use dragContainer rather than .draggable() modifier because that causes + // dragging the first item to be always be dropped in the next position. + LazyColumn( + modifier = modifier, + state = lazyListState, + contentPadding = PaddingValues(vertical = 8.dp), + ) { + itemsIndexed( + triggerList, + key = { _, item -> item.id }, + contentType = { _, _ -> "key" }, + ) { index, model -> + DraggableItem( + dragDropState = dragDropState, + index = index, + ) { isDragging -> + TriggerKeyListItem( + modifier = Modifier.fillMaxWidth(), + model = model, + index = index, + isDraggingEnabled = triggerList.size > 1, + isDragging = isDragging, + isReorderingEnabled = isReorderingEnabled, + dragDropState = dragDropState, + onEditClick = { onEditClick(model.id) }, + onRemoveClick = { onRemoveClick(model.id) }, + onFixClick = onFixErrorClick, + ) + } + } + + if (shortcuts.isNotEmpty()) { + item(key = "shortcuts", contentType = "shortcuts") { + Column(horizontalAlignment = Alignment.CenterHorizontally) { + Text( + text = stringResource(R.string.trigger_shortcuts_header), + style = MaterialTheme.typography.titleSmall, + ) + + Spacer(Modifier.height(8.dp)) + + ShortcutRow( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 32.dp), + shortcuts = shortcuts, + onClick = { onClickShortcut(it) }, + ) + } + } + } + } +} + +@Composable +private fun ClickTypeRadioGroup( + modifier: Modifier = Modifier, + clickTypes: Set, + checkedClickType: ClickType?, + onSelectClickType: (ClickType) -> Unit, + maxLines: Int = 2, +) { + Column(modifier = modifier) { + Row(modifier = Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) { + if (clickTypes.contains(ClickType.SHORT_PRESS)) { + RadioButtonText( + modifier = Modifier.weight(1f), + isSelected = checkedClickType == ClickType.SHORT_PRESS, + text = stringResource(R.string.radio_button_short_press), + onSelected = { onSelectClickType(ClickType.SHORT_PRESS) }, + maxLines = maxLines, + ) + } + if (clickTypes.contains(ClickType.LONG_PRESS)) { + RadioButtonText( + modifier = Modifier.weight(1f), + isSelected = checkedClickType == ClickType.LONG_PRESS, + text = stringResource(R.string.radio_button_long_press), + onSelected = { onSelectClickType(ClickType.LONG_PRESS) }, + maxLines = maxLines, + ) + } + if (clickTypes.contains(ClickType.DOUBLE_PRESS)) { + RadioButtonText( + modifier = Modifier.weight(1f), + isSelected = checkedClickType == ClickType.DOUBLE_PRESS, + text = stringResource(R.string.radio_button_double_press), + onSelected = { onSelectClickType(ClickType.DOUBLE_PRESS) }, + maxLines = maxLines, + ) + } + } + } +} + +@Composable +private fun TriggerModeRadioGroup( + modifier: Modifier = Modifier, + mode: TriggerMode, + isEnabled: Boolean, + onSelectParallelMode: () -> Unit, + onSelectSequenceMode: () -> Unit, + maxLines: Int = 2, +) { + Column(modifier = modifier) { + Row(modifier = Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) { + RadioButtonText( + modifier = Modifier.weight(1f), + isSelected = mode is TriggerMode.Parallel, + isEnabled = isEnabled, + text = stringResource(R.string.radio_button_parallel), + onSelected = onSelectParallelMode, + maxLines = maxLines, + ) + RadioButtonText( + modifier = Modifier.weight(1f), + isSelected = mode == TriggerMode.Sequence, + isEnabled = isEnabled, + text = stringResource(R.string.radio_button_sequence), + onSelected = onSelectSequenceMode, + maxLines = maxLines, + ) + } + } +} + +private val sampleList = listOf( + TriggerKeyListItemModel.KeyCode( + id = "id1", + keyName = "Volume Up", + clickType = ClickType.SHORT_PRESS, + extraInfo = "External Keyboard", + linkType = LinkType.ARROW, + error = null, + ), + TriggerKeyListItemModel.FloatingButton( + id = "id2", + buttonName = "😎", + layoutName = "Gaming", + clickType = ClickType.DOUBLE_PRESS, + linkType = LinkType.ARROW, + error = null, + ), + TriggerKeyListItemModel.Assistant( + id = "id3", + assistantType = AssistantTriggerType.DEVICE, + clickType = ClickType.DOUBLE_PRESS, + linkType = LinkType.HIDDEN, + error = null, + ), +) + +private val previewState = + ConfigTriggerState.Loaded( + triggerKeys = sampleList, + isReorderingEnabled = true, + clickTypeButtons = setOf( + ClickType.SHORT_PRESS, + ClickType.LONG_PRESS, + ClickType.DOUBLE_PRESS, + ), + checkedClickType = ClickType.LONG_PRESS, + checkedTriggerMode = TriggerMode.Sequence, + triggerModeButtonsEnabled = true, + triggerModeButtonsVisible = true, + shortcuts = setOf( + ShortcutModel( + icon = ComposeIconInfo.Vector(Icons.Rounded.Fingerprint), + text = "Fingerprint gesture", + data = TriggerKeyShortcut.FINGERPRINT_GESTURE, + ), + ), + ) + +@Preview(device = Devices.PIXEL) +@Composable +private fun VerticalPreview() { + KeyMapperTheme { + TriggerScreenVertical( + configState = previewState, + recordTriggerState = RecordTriggerState.Idle, + ) + } +} + +@Preview(heightDp = 400, widthDp = 300) +@Composable +private fun VerticalPreviewTiny() { + KeyMapperTheme { + TriggerScreenVertical( + configState = previewState, + recordTriggerState = RecordTriggerState.Idle, + ) + } +} + +@Preview(device = Devices.PIXEL) +@Composable +private fun VerticalEmptyPreview() { + KeyMapperTheme { + TriggerScreenVertical( + configState = ConfigTriggerState.Empty( + shortcuts = setOf( + ShortcutModel( + icon = ComposeIconInfo.Vector(Icons.Rounded.Fingerprint), + text = "Fingerprint gesture", + data = TriggerKeyShortcut.FINGERPRINT_GESTURE, + ), + ), + ), + recordTriggerState = RecordTriggerState.Idle, + ) + } +} + +@Preview(widthDp = 800, heightDp = 300) +@Composable +private fun HorizontalPreview() { + KeyMapperTheme { + TriggerScreenHorizontal( + configState = previewState, + recordTriggerState = RecordTriggerState.Idle, + ) + } +} + +@Preview(widthDp = 800, heightDp = 300) +@Composable +private fun HorizontalEmptyPreview() { + KeyMapperTheme { + TriggerScreenHorizontal( + configState = ConfigTriggerState.Empty( + shortcuts = setOf( + ShortcutModel( + icon = ComposeIconInfo.Vector(Icons.Rounded.Fingerprint), + text = "Fingerprint gesture", + data = TriggerKeyShortcut.FINGERPRINT_GESTURE, + ), + ), + + ), + recordTriggerState = RecordTriggerState.Idle, + ) + } +} diff --git a/app/src/main/java/io/github/sds100/keymapper/trigger/ChooseTriggerKeyDeviceModel.kt b/base/src/main/java/io/github/sds100/keymapper/base/trigger/ChooseTriggerKeyDeviceModel.kt similarity index 56% rename from app/src/main/java/io/github/sds100/keymapper/trigger/ChooseTriggerKeyDeviceModel.kt rename to base/src/main/java/io/github/sds100/keymapper/base/trigger/ChooseTriggerKeyDeviceModel.kt index 4ffb1bae0a..efc216cd3f 100644 --- a/app/src/main/java/io/github/sds100/keymapper/trigger/ChooseTriggerKeyDeviceModel.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/trigger/ChooseTriggerKeyDeviceModel.kt @@ -1,8 +1,5 @@ -package io.github.sds100.keymapper.trigger +package io.github.sds100.keymapper.base.trigger -/** - * Created by sds100 on 07/03/2021. - */ data class ChooseTriggerKeyDeviceModel( val triggerKeyUid: String, val devices: List, diff --git a/app/src/main/java/io/github/sds100/keymapper/trigger/FingerprintTriggerKey.kt b/base/src/main/java/io/github/sds100/keymapper/base/trigger/FingerprintTriggerKey.kt similarity index 94% rename from app/src/main/java/io/github/sds100/keymapper/trigger/FingerprintTriggerKey.kt rename to base/src/main/java/io/github/sds100/keymapper/base/trigger/FingerprintTriggerKey.kt index a5240ff1da..820d11df43 100644 --- a/app/src/main/java/io/github/sds100/keymapper/trigger/FingerprintTriggerKey.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/trigger/FingerprintTriggerKey.kt @@ -1,9 +1,9 @@ -package io.github.sds100.keymapper.trigger +package io.github.sds100.keymapper.base.trigger +import io.github.sds100.keymapper.base.keymaps.ClickType +import io.github.sds100.keymapper.base.system.accessibility.FingerprintGestureType import io.github.sds100.keymapper.data.entities.FingerprintTriggerKeyEntity import io.github.sds100.keymapper.data.entities.TriggerKeyEntity -import io.github.sds100.keymapper.keymaps.ClickType -import io.github.sds100.keymapper.keymaps.FingerprintGestureType import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable import java.util.UUID diff --git a/app/src/main/java/io/github/sds100/keymapper/trigger/FloatingButtonKey.kt b/base/src/main/java/io/github/sds100/keymapper/base/trigger/FloatingButtonKey.kt similarity index 90% rename from app/src/main/java/io/github/sds100/keymapper/trigger/FloatingButtonKey.kt rename to base/src/main/java/io/github/sds100/keymapper/base/trigger/FloatingButtonKey.kt index a316f326fa..65b51d395e 100644 --- a/app/src/main/java/io/github/sds100/keymapper/trigger/FloatingButtonKey.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/trigger/FloatingButtonKey.kt @@ -1,11 +1,11 @@ -package io.github.sds100.keymapper.trigger +package io.github.sds100.keymapper.base.trigger +import io.github.sds100.keymapper.base.floating.FloatingButtonData +import io.github.sds100.keymapper.base.floating.FloatingButtonEntityMapper +import io.github.sds100.keymapper.base.keymaps.ClickType import io.github.sds100.keymapper.data.entities.FloatingButtonEntityWithLayout import io.github.sds100.keymapper.data.entities.FloatingButtonKeyEntity import io.github.sds100.keymapper.data.entities.TriggerKeyEntity -import io.github.sds100.keymapper.floating.FloatingButtonData -import io.github.sds100.keymapper.floating.FloatingButtonEntityMapper -import io.github.sds100.keymapper.keymaps.ClickType import kotlinx.serialization.Serializable import java.util.UUID diff --git a/app/src/main/java/io/github/sds100/keymapper/trigger/KeyCodeTriggerKey.kt b/base/src/main/java/io/github/sds100/keymapper/base/trigger/KeyCodeTriggerKey.kt similarity index 95% rename from app/src/main/java/io/github/sds100/keymapper/trigger/KeyCodeTriggerKey.kt rename to base/src/main/java/io/github/sds100/keymapper/base/trigger/KeyCodeTriggerKey.kt index 91d5096ac2..cbb4aa976c 100644 --- a/app/src/main/java/io/github/sds100/keymapper/trigger/KeyCodeTriggerKey.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/trigger/KeyCodeTriggerKey.kt @@ -1,11 +1,11 @@ -package io.github.sds100.keymapper.trigger +package io.github.sds100.keymapper.base.trigger +import io.github.sds100.keymapper.base.keymaps.ClickType +import io.github.sds100.keymapper.common.utils.hasFlag +import io.github.sds100.keymapper.common.utils.withFlag import io.github.sds100.keymapper.data.entities.KeyCodeTriggerKeyEntity import io.github.sds100.keymapper.data.entities.TriggerKeyEntity -import io.github.sds100.keymapper.keymaps.ClickType import kotlinx.serialization.Serializable -import splitties.bitflags.hasFlag -import splitties.bitflags.withFlag import java.util.UUID @Serializable diff --git a/app/src/main/java/io/github/sds100/keymapper/trigger/KeyEventDetectionSource.kt b/base/src/main/java/io/github/sds100/keymapper/base/trigger/KeyEventDetectionSource.kt similarity index 63% rename from app/src/main/java/io/github/sds100/keymapper/trigger/KeyEventDetectionSource.kt rename to base/src/main/java/io/github/sds100/keymapper/base/trigger/KeyEventDetectionSource.kt index 66f147dfc8..c231beff8a 100644 --- a/app/src/main/java/io/github/sds100/keymapper/trigger/KeyEventDetectionSource.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/trigger/KeyEventDetectionSource.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.trigger +package io.github.sds100.keymapper.base.trigger enum class KeyEventDetectionSource { ACCESSIBILITY_SERVICE, diff --git a/app/src/main/java/io/github/sds100/keymapper/trigger/KeyMapListItemModel.kt b/base/src/main/java/io/github/sds100/keymapper/base/trigger/KeyMapListItemModel.kt similarity index 75% rename from app/src/main/java/io/github/sds100/keymapper/trigger/KeyMapListItemModel.kt rename to base/src/main/java/io/github/sds100/keymapper/base/trigger/KeyMapListItemModel.kt index accb6bf73b..9e698a97bd 100644 --- a/app/src/main/java/io/github/sds100/keymapper/trigger/KeyMapListItemModel.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/trigger/KeyMapListItemModel.kt @@ -1,8 +1,8 @@ -package io.github.sds100.keymapper.trigger +package io.github.sds100.keymapper.base.trigger import androidx.compose.ui.graphics.vector.ImageVector -import io.github.sds100.keymapper.constraints.ConstraintMode -import io.github.sds100.keymapper.util.ui.compose.ComposeChipModel +import io.github.sds100.keymapper.base.constraints.ConstraintMode +import io.github.sds100.keymapper.base.utils.ui.compose.ComposeChipModel data class KeyMapListItemModel( val isSelected: Boolean, diff --git a/app/src/main/java/io/github/sds100/keymapper/trigger/RecordTriggerButtonRow.kt b/base/src/main/java/io/github/sds100/keymapper/base/trigger/RecordTriggerButtonRow.kt similarity index 92% rename from app/src/main/java/io/github/sds100/keymapper/trigger/RecordTriggerButtonRow.kt rename to base/src/main/java/io/github/sds100/keymapper/base/trigger/RecordTriggerButtonRow.kt index eead8308f3..09aabd1396 100644 --- a/app/src/main/java/io/github/sds100/keymapper/trigger/RecordTriggerButtonRow.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/trigger/RecordTriggerButtonRow.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.trigger +package io.github.sds100.keymapper.base.trigger import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer @@ -20,12 +20,12 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import com.canopas.lib.showcase.IntroShowcase -import io.github.sds100.keymapper.R -import io.github.sds100.keymapper.compose.KeyMapperTheme -import io.github.sds100.keymapper.compose.LocalCustomColorsPalette -import io.github.sds100.keymapper.onboarding.OnboardingTapTarget -import io.github.sds100.keymapper.util.ui.compose.KeyMapperTapTarget -import io.github.sds100.keymapper.util.ui.compose.keyMapperShowcaseStyle +import io.github.sds100.keymapper.base.R +import io.github.sds100.keymapper.base.compose.KeyMapperTheme +import io.github.sds100.keymapper.base.compose.LocalCustomColorsPalette +import io.github.sds100.keymapper.base.onboarding.OnboardingTapTarget +import io.github.sds100.keymapper.base.utils.ui.compose.KeyMapperTapTarget +import io.github.sds100.keymapper.base.utils.ui.compose.keyMapperShowcaseStyle @Composable fun RecordTriggerButtonRow( diff --git a/base/src/main/java/io/github/sds100/keymapper/base/trigger/RecordTriggerEvent.kt b/base/src/main/java/io/github/sds100/keymapper/base/trigger/RecordTriggerEvent.kt new file mode 100644 index 0000000000..3c52caf495 --- /dev/null +++ b/base/src/main/java/io/github/sds100/keymapper/base/trigger/RecordTriggerEvent.kt @@ -0,0 +1,30 @@ +package io.github.sds100.keymapper.base.trigger + +import android.os.Parcelable +import io.github.sds100.keymapper.system.accessibility.AccessibilityServiceEvent +import io.github.sds100.keymapper.system.devices.InputDeviceInfo +import kotlinx.parcelize.Parcelize +import kotlinx.serialization.Serializable + +sealed class RecordTriggerEvent : AccessibilityServiceEvent() { + @Parcelize + @Serializable + data class RecordedTriggerKey( + val keyCode: Int, + val device: InputDeviceInfo?, + val detectionSource: KeyEventDetectionSource, + ) : RecordTriggerEvent(), + Parcelable + + @Serializable + data object StartRecordingTrigger : RecordTriggerEvent() + + @Serializable + data object StopRecordingTrigger : RecordTriggerEvent() + + @Serializable + data class OnIncrementRecordTriggerTimer(val timeLeft: Int) : RecordTriggerEvent() + + @Serializable + data object OnStoppedRecordingTrigger : RecordTriggerEvent() +} diff --git a/app/src/main/java/io/github/sds100/keymapper/trigger/RecordTriggerState.kt b/base/src/main/java/io/github/sds100/keymapper/base/trigger/RecordTriggerState.kt similarity index 78% rename from app/src/main/java/io/github/sds100/keymapper/trigger/RecordTriggerState.kt rename to base/src/main/java/io/github/sds100/keymapper/base/trigger/RecordTriggerState.kt index afaad64fad..dcaaaddbbf 100644 --- a/app/src/main/java/io/github/sds100/keymapper/trigger/RecordTriggerState.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/trigger/RecordTriggerState.kt @@ -1,8 +1,5 @@ -package io.github.sds100.keymapper.trigger +package io.github.sds100.keymapper.base.trigger -/** - * Created by sds100 on 04/03/2021. - */ sealed class RecordTriggerState { data object Idle : RecordTriggerState() diff --git a/app/src/main/java/io/github/sds100/keymapper/trigger/RecordTriggerUseCase.kt b/base/src/main/java/io/github/sds100/keymapper/base/trigger/RecordTriggerUseCase.kt similarity index 78% rename from app/src/main/java/io/github/sds100/keymapper/trigger/RecordTriggerUseCase.kt rename to base/src/main/java/io/github/sds100/keymapper/base/trigger/RecordTriggerUseCase.kt index a9e5730ca2..0564e382c5 100644 --- a/app/src/main/java/io/github/sds100/keymapper/trigger/RecordTriggerUseCase.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/trigger/RecordTriggerUseCase.kt @@ -1,13 +1,12 @@ -package io.github.sds100.keymapper.trigger +package io.github.sds100.keymapper.base.trigger import android.view.KeyEvent -import io.github.sds100.keymapper.keymaps.detection.DpadMotionEventTracker -import io.github.sds100.keymapper.system.accessibility.ServiceAdapter +import io.github.sds100.keymapper.base.keymaps.detection.DpadMotionEventTracker +import io.github.sds100.keymapper.common.utils.KMResult +import io.github.sds100.keymapper.system.accessibility.AccessibilityServiceAdapter import io.github.sds100.keymapper.system.devices.InputDeviceInfo import io.github.sds100.keymapper.system.inputevents.InputEventUtils import io.github.sds100.keymapper.system.inputevents.MyMotionEvent -import io.github.sds100.keymapper.util.Result -import io.github.sds100.keymapper.util.ServiceEvent import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableSharedFlow @@ -17,13 +16,13 @@ import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.mapNotNull import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch +import javax.inject.Inject +import javax.inject.Singleton -/** - * Created by sds100 on 04/03/2021. - */ -class RecordTriggerController( +@Singleton +class RecordTriggerController @Inject constructor( private val coroutineScope: CoroutineScope, - private val serviceAdapter: ServiceAdapter, + private val serviceAdapter: AccessibilityServiceAdapter, ) : RecordTriggerUseCase { override val state = MutableStateFlow(RecordTriggerState.Idle) @@ -34,11 +33,11 @@ class RecordTriggerController( init { serviceAdapter.eventReceiver.onEach { event -> when (event) { - is ServiceEvent.OnStoppedRecordingTrigger -> + is RecordTriggerEvent.OnStoppedRecordingTrigger -> state.value = RecordTriggerState.Completed(recordedKeys) - is ServiceEvent.OnIncrementRecordTriggerTimer -> + is RecordTriggerEvent.OnIncrementRecordTriggerTimer -> state.value = RecordTriggerState.CountingDown(event.timeLeft) @@ -48,7 +47,7 @@ class RecordTriggerController( serviceAdapter.eventReceiver .mapNotNull { - if (it is ServiceEvent.RecordedTriggerKey) { + if (it is RecordTriggerEvent.RecordedTriggerKey) { it } else { null @@ -62,14 +61,14 @@ class RecordTriggerController( .launchIn(coroutineScope) } - override suspend fun startRecording(): Result<*> { + override suspend fun startRecording(): KMResult<*> { recordedKeys.clear() dpadMotionEventTracker.reset() - return serviceAdapter.send(ServiceEvent.StartRecordingTrigger) + return serviceAdapter.send(RecordTriggerEvent.StartRecordingTrigger) } - override suspend fun stopRecording(): Result<*> { - return serviceAdapter.send(ServiceEvent.StopRecordingTrigger) + override suspend fun stopRecording(): KMResult<*> { + return serviceAdapter.send(RecordTriggerEvent.StopRecordingTrigger) } /** @@ -128,6 +127,6 @@ interface RecordTriggerUseCase { /** * @return Success if started and an Error if failed to start. */ - suspend fun startRecording(): Result<*> - suspend fun stopRecording(): Result<*> + suspend fun startRecording(): KMResult<*> + suspend fun stopRecording(): KMResult<*> } diff --git a/app/src/main/java/io/github/sds100/keymapper/trigger/RecordedKey.kt b/base/src/main/java/io/github/sds100/keymapper/base/trigger/RecordedKey.kt similarity index 60% rename from app/src/main/java/io/github/sds100/keymapper/trigger/RecordedKey.kt rename to base/src/main/java/io/github/sds100/keymapper/base/trigger/RecordedKey.kt index 17cbc6c856..f4db2f265b 100644 --- a/app/src/main/java/io/github/sds100/keymapper/trigger/RecordedKey.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/trigger/RecordedKey.kt @@ -1,8 +1,5 @@ -package io.github.sds100.keymapper.trigger +package io.github.sds100.keymapper.base.trigger -/** - * Created by sds100 on 04/03/2021. - */ data class RecordedKey( val keyCode: Int, val device: TriggerKeyDevice, diff --git a/app/src/main/java/io/github/sds100/keymapper/trigger/SetupGuiKeyboardBottomSheet.kt b/base/src/main/java/io/github/sds100/keymapper/base/trigger/SetupGuiKeyboardBottomSheet.kt similarity index 97% rename from app/src/main/java/io/github/sds100/keymapper/trigger/SetupGuiKeyboardBottomSheet.kt rename to base/src/main/java/io/github/sds100/keymapper/base/trigger/SetupGuiKeyboardBottomSheet.kt index b6582cbee3..e08ea1e899 100644 --- a/app/src/main/java/io/github/sds100/keymapper/trigger/SetupGuiKeyboardBottomSheet.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/trigger/SetupGuiKeyboardBottomSheet.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.trigger +package io.github.sds100.keymapper.base.trigger import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column @@ -33,9 +33,9 @@ import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle -import io.github.sds100.keymapper.R -import io.github.sds100.keymapper.compose.KeyMapperTheme -import io.github.sds100.keymapper.util.ui.compose.openUriSafe +import io.github.sds100.keymapper.base.R +import io.github.sds100.keymapper.base.compose.KeyMapperTheme +import io.github.sds100.keymapper.base.utils.ui.compose.openUriSafe import kotlinx.coroutines.launch @OptIn(ExperimentalMaterial3Api::class) @@ -68,7 +68,7 @@ fun DpadTriggerSetupBottomSheet( fun NoKeysRecordedBottomSheet( modifier: Modifier = Modifier, onDismissRequest: () -> Unit, - viewModel: ConfigTriggerViewModel, + viewModel: BaseConfigTriggerViewModel, sheetState: SheetState, ) { val state by viewModel.setupGuiKeyboardState.collectAsStateWithLifecycle() diff --git a/app/src/main/java/io/github/sds100/keymapper/trigger/SetupGuiKeyboardState.kt b/base/src/main/java/io/github/sds100/keymapper/base/trigger/SetupGuiKeyboardState.kt similarity index 88% rename from app/src/main/java/io/github/sds100/keymapper/trigger/SetupGuiKeyboardState.kt rename to base/src/main/java/io/github/sds100/keymapper/base/trigger/SetupGuiKeyboardState.kt index c21861f62c..4870c06627 100644 --- a/app/src/main/java/io/github/sds100/keymapper/trigger/SetupGuiKeyboardState.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/trigger/SetupGuiKeyboardState.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.trigger +package io.github.sds100.keymapper.base.trigger data class SetupGuiKeyboardState( val isKeyboardInstalled: Boolean, diff --git a/app/src/main/java/io/github/sds100/keymapper/trigger/SetupGuiKeyboardUseCase.kt b/base/src/main/java/io/github/sds100/keymapper/base/trigger/SetupGuiKeyboardUseCase.kt similarity index 88% rename from app/src/main/java/io/github/sds100/keymapper/trigger/SetupGuiKeyboardUseCase.kt rename to base/src/main/java/io/github/sds100/keymapper/base/trigger/SetupGuiKeyboardUseCase.kt index 759e3dbff6..bbed434572 100644 --- a/app/src/main/java/io/github/sds100/keymapper/trigger/SetupGuiKeyboardUseCase.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/trigger/SetupGuiKeyboardUseCase.kt @@ -1,16 +1,17 @@ -package io.github.sds100.keymapper.trigger +package io.github.sds100.keymapper.base.trigger +import io.github.sds100.keymapper.base.system.inputmethod.KeyMapperImeHelper +import io.github.sds100.keymapper.common.utils.onSuccess import io.github.sds100.keymapper.system.apps.PackageInfo import io.github.sds100.keymapper.system.apps.PackageManagerAdapter import io.github.sds100.keymapper.system.apps.getPackageInfoFlow import io.github.sds100.keymapper.system.inputmethod.ImeInfo import io.github.sds100.keymapper.system.inputmethod.InputMethodAdapter -import io.github.sds100.keymapper.system.inputmethod.KeyMapperImeHelper -import io.github.sds100.keymapper.util.onSuccess import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.map +import javax.inject.Inject -class SetupGuiKeyboardUseCaseImpl( +class SetupGuiKeyboardUseCaseImpl @Inject constructor( private val inputMethodAdapter: InputMethodAdapter, private val packageManager: PackageManagerAdapter, ) : SetupGuiKeyboardUseCase { diff --git a/app/src/main/java/io/github/sds100/keymapper/trigger/Trigger.kt b/base/src/main/java/io/github/sds100/keymapper/base/trigger/Trigger.kt similarity index 95% rename from app/src/main/java/io/github/sds100/keymapper/trigger/Trigger.kt rename to base/src/main/java/io/github/sds100/keymapper/base/trigger/Trigger.kt index 46d94bf956..2bba80a7ae 100644 --- a/app/src/main/java/io/github/sds100/keymapper/trigger/Trigger.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/trigger/Trigger.kt @@ -1,5 +1,10 @@ -package io.github.sds100.keymapper.trigger +package io.github.sds100.keymapper.base.trigger +import io.github.sds100.keymapper.base.floating.FloatingButtonEntityMapper +import io.github.sds100.keymapper.base.keymaps.ClickType +import io.github.sds100.keymapper.common.utils.hasFlag +import io.github.sds100.keymapper.common.utils.valueOrNull +import io.github.sds100.keymapper.common.utils.withFlag import io.github.sds100.keymapper.data.entities.AssistantTriggerKeyEntity import io.github.sds100.keymapper.data.entities.EntityExtra import io.github.sds100.keymapper.data.entities.FingerprintTriggerKeyEntity @@ -8,17 +13,8 @@ import io.github.sds100.keymapper.data.entities.FloatingButtonKeyEntity import io.github.sds100.keymapper.data.entities.KeyCodeTriggerKeyEntity import io.github.sds100.keymapper.data.entities.TriggerEntity import io.github.sds100.keymapper.data.entities.getData -import io.github.sds100.keymapper.floating.FloatingButtonEntityMapper -import io.github.sds100.keymapper.keymaps.ClickType import io.github.sds100.keymapper.system.inputevents.InputEventUtils -import io.github.sds100.keymapper.util.valueOrNull import kotlinx.serialization.Serializable -import splitties.bitflags.hasFlag -import splitties.bitflags.withFlag - -/** - * Created by sds100 on 03/03/2021. - */ @Serializable data class Trigger( diff --git a/app/src/main/java/io/github/sds100/keymapper/trigger/TriggerError.kt b/base/src/main/java/io/github/sds100/keymapper/base/trigger/TriggerError.kt similarity index 88% rename from app/src/main/java/io/github/sds100/keymapper/trigger/TriggerError.kt rename to base/src/main/java/io/github/sds100/keymapper/base/trigger/TriggerError.kt index 1d00b9fa36..b50cc06efe 100644 --- a/app/src/main/java/io/github/sds100/keymapper/trigger/TriggerError.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/trigger/TriggerError.kt @@ -1,8 +1,5 @@ -package io.github.sds100.keymapper.trigger +package io.github.sds100.keymapper.base.trigger -/** - * Created by sds100 on 04/04/2021. - */ enum class TriggerError(val isFixable: Boolean) { DND_ACCESS_DENIED(isFixable = true), SCREEN_OFF_ROOT_DENIED(isFixable = true), diff --git a/app/src/main/java/io/github/sds100/keymapper/trigger/TriggerErrorSnapshot.kt b/base/src/main/java/io/github/sds100/keymapper/base/trigger/TriggerErrorSnapshot.kt similarity index 81% rename from app/src/main/java/io/github/sds100/keymapper/trigger/TriggerErrorSnapshot.kt rename to base/src/main/java/io/github/sds100/keymapper/base/trigger/TriggerErrorSnapshot.kt index 5aac124b17..70184806ee 100644 --- a/app/src/main/java/io/github/sds100/keymapper/trigger/TriggerErrorSnapshot.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/trigger/TriggerErrorSnapshot.kt @@ -1,15 +1,15 @@ -package io.github.sds100.keymapper.trigger +package io.github.sds100.keymapper.base.trigger import android.os.Build import android.view.KeyEvent -import io.github.sds100.keymapper.keymaps.KeyMap -import io.github.sds100.keymapper.keymaps.requiresImeKeyEventForwardingInPhoneCall -import io.github.sds100.keymapper.purchasing.ProductId +import io.github.sds100.keymapper.base.keymaps.KeyMap +import io.github.sds100.keymapper.base.keymaps.requiresImeKeyEventForwardingInPhoneCall +import io.github.sds100.keymapper.base.purchasing.ProductId +import io.github.sds100.keymapper.base.purchasing.PurchasingError +import io.github.sds100.keymapper.common.utils.KMResult +import io.github.sds100.keymapper.common.utils.onFailure +import io.github.sds100.keymapper.common.utils.onSuccess import io.github.sds100.keymapper.system.inputevents.InputEventUtils -import io.github.sds100.keymapper.util.Error -import io.github.sds100.keymapper.util.Result -import io.github.sds100.keymapper.util.onFailure -import io.github.sds100.keymapper.util.onSuccess /** * Store the data required for determining trigger errors to reduce the number of calls with @@ -19,7 +19,7 @@ data class TriggerErrorSnapshot( val isKeyMapperImeChosen: Boolean, val isDndAccessGranted: Boolean, val isRootGranted: Boolean, - val purchases: Result>, + val purchases: KMResult>, val showDpadImeSetupError: Boolean, ) { companion object { @@ -39,7 +39,7 @@ data class TriggerErrorSnapshot( return TriggerError.FLOATING_BUTTONS_NOT_PURCHASED } }.onFailure { error -> - if ((key is AssistantTriggerKey || key is FloatingButtonKey) && error == Error.PurchasingError.NetworkError) { + if ((key is AssistantTriggerKey || key is FloatingButtonKey) && error == PurchasingError.PurchasingProcessError.NetworkError) { return TriggerError.PURCHASE_VERIFICATION_FAILED } } diff --git a/app/src/main/java/io/github/sds100/keymapper/trigger/TriggerKey.kt b/base/src/main/java/io/github/sds100/keymapper/base/trigger/TriggerKey.kt similarity index 89% rename from app/src/main/java/io/github/sds100/keymapper/trigger/TriggerKey.kt rename to base/src/main/java/io/github/sds100/keymapper/base/trigger/TriggerKey.kt index 0f6c89a17d..1239059181 100644 --- a/app/src/main/java/io/github/sds100/keymapper/trigger/TriggerKey.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/trigger/TriggerKey.kt @@ -1,6 +1,6 @@ -package io.github.sds100.keymapper.trigger +package io.github.sds100.keymapper.base.trigger -import io.github.sds100.keymapper.keymaps.ClickType +import io.github.sds100.keymapper.base.keymaps.ClickType import kotlinx.serialization.Serializable @Serializable diff --git a/app/src/main/java/io/github/sds100/keymapper/trigger/TriggerKeyDevice.kt b/base/src/main/java/io/github/sds100/keymapper/base/trigger/TriggerKeyDevice.kt similarity index 93% rename from app/src/main/java/io/github/sds100/keymapper/trigger/TriggerKeyDevice.kt rename to base/src/main/java/io/github/sds100/keymapper/base/trigger/TriggerKeyDevice.kt index 24f6dc8672..08d7942721 100644 --- a/app/src/main/java/io/github/sds100/keymapper/trigger/TriggerKeyDevice.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/trigger/TriggerKeyDevice.kt @@ -1,12 +1,8 @@ -package io.github.sds100.keymapper.trigger +package io.github.sds100.keymapper.base.trigger import io.github.sds100.keymapper.system.devices.InputDeviceInfo import kotlinx.serialization.Serializable -/** - * Created by sds100 on 21/02/2021. - */ - @Serializable sealed class TriggerKeyDevice : Comparable { override fun compareTo(other: TriggerKeyDevice) = this.javaClass.name.compareTo(other.javaClass.name) diff --git a/app/src/main/java/io/github/sds100/keymapper/trigger/TriggerKeyListItem.kt b/base/src/main/java/io/github/sds100/keymapper/base/trigger/TriggerKeyListItem.kt similarity index 97% rename from app/src/main/java/io/github/sds100/keymapper/trigger/TriggerKeyListItem.kt rename to base/src/main/java/io/github/sds100/keymapper/base/trigger/TriggerKeyListItem.kt index 2bc355370a..4e38181428 100644 --- a/app/src/main/java/io/github/sds100/keymapper/trigger/TriggerKeyListItem.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/trigger/TriggerKeyListItem.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.trigger +package io.github.sds100.keymapper.base.trigger import androidx.compose.foundation.gestures.Orientation import androidx.compose.foundation.gestures.draggable @@ -41,11 +41,11 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp -import io.github.sds100.keymapper.R -import io.github.sds100.keymapper.keymaps.ClickType -import io.github.sds100.keymapper.keymaps.FingerprintGestureType -import io.github.sds100.keymapper.util.ui.LinkType -import io.github.sds100.keymapper.util.ui.compose.DragDropState +import io.github.sds100.keymapper.base.R +import io.github.sds100.keymapper.base.keymaps.ClickType +import io.github.sds100.keymapper.base.system.accessibility.FingerprintGestureType +import io.github.sds100.keymapper.base.utils.ui.LinkType +import io.github.sds100.keymapper.base.utils.ui.compose.DragDropState @Composable fun TriggerKeyListItem( diff --git a/app/src/main/java/io/github/sds100/keymapper/trigger/TriggerKeyOptionsBottomSheet.kt b/base/src/main/java/io/github/sds100/keymapper/base/trigger/TriggerKeyOptionsBottomSheet.kt similarity index 96% rename from app/src/main/java/io/github/sds100/keymapper/trigger/TriggerKeyOptionsBottomSheet.kt rename to base/src/main/java/io/github/sds100/keymapper/base/trigger/TriggerKeyOptionsBottomSheet.kt index 5de6ed7cbc..e104ecf8c9 100644 --- a/app/src/main/java/io/github/sds100/keymapper/trigger/TriggerKeyOptionsBottomSheet.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/trigger/TriggerKeyOptionsBottomSheet.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.trigger +package io.github.sds100.keymapper.base.trigger import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column @@ -34,14 +34,14 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp -import io.github.sds100.keymapper.R -import io.github.sds100.keymapper.compose.KeyMapperTheme -import io.github.sds100.keymapper.keymaps.ClickType -import io.github.sds100.keymapper.keymaps.FingerprintGestureType -import io.github.sds100.keymapper.util.ui.CheckBoxListItem -import io.github.sds100.keymapper.util.ui.compose.CheckBoxText -import io.github.sds100.keymapper.util.ui.compose.RadioButtonText -import io.github.sds100.keymapper.util.ui.compose.openUriSafe +import io.github.sds100.keymapper.base.R +import io.github.sds100.keymapper.base.compose.KeyMapperTheme +import io.github.sds100.keymapper.base.keymaps.ClickType +import io.github.sds100.keymapper.base.system.accessibility.FingerprintGestureType +import io.github.sds100.keymapper.base.utils.ui.CheckBoxListItem +import io.github.sds100.keymapper.base.utils.ui.compose.CheckBoxText +import io.github.sds100.keymapper.base.utils.ui.compose.RadioButtonText +import io.github.sds100.keymapper.base.utils.ui.compose.openUriSafe import kotlinx.coroutines.launch @OptIn(ExperimentalMaterial3Api::class) diff --git a/app/src/main/java/io/github/sds100/keymapper/trigger/TriggerKeyShortcut.kt b/base/src/main/java/io/github/sds100/keymapper/base/trigger/TriggerKeyShortcut.kt similarity index 66% rename from app/src/main/java/io/github/sds100/keymapper/trigger/TriggerKeyShortcut.kt rename to base/src/main/java/io/github/sds100/keymapper/base/trigger/TriggerKeyShortcut.kt index 26c90c031c..c94755cbeb 100644 --- a/app/src/main/java/io/github/sds100/keymapper/trigger/TriggerKeyShortcut.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/trigger/TriggerKeyShortcut.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.trigger +package io.github.sds100.keymapper.base.trigger enum class TriggerKeyShortcut { ASSISTANT, diff --git a/app/src/main/java/io/github/sds100/keymapper/trigger/TriggerMode.kt b/base/src/main/java/io/github/sds100/keymapper/base/trigger/TriggerMode.kt similarity index 85% rename from app/src/main/java/io/github/sds100/keymapper/trigger/TriggerMode.kt rename to base/src/main/java/io/github/sds100/keymapper/base/trigger/TriggerMode.kt index 1c04435521..0b52d9ff0a 100644 --- a/app/src/main/java/io/github/sds100/keymapper/trigger/TriggerMode.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/trigger/TriggerMode.kt @@ -1,12 +1,8 @@ -package io.github.sds100.keymapper.trigger +package io.github.sds100.keymapper.base.trigger -import io.github.sds100.keymapper.keymaps.ClickType +import io.github.sds100.keymapper.base.keymaps.ClickType import kotlinx.serialization.Serializable -/** - * Created by sds100 on 21/02/2021. - */ - @Serializable sealed class TriggerMode : Comparable { override fun compareTo(other: TriggerMode) = this.javaClass.name.compareTo(other.javaClass.name) diff --git a/app/src/main/java/io/github/sds100/keymapper/system/volume/DndModeUtils.kt b/base/src/main/java/io/github/sds100/keymapper/base/utils/DndModeStrings.kt similarity index 56% rename from app/src/main/java/io/github/sds100/keymapper/system/volume/DndModeUtils.kt rename to base/src/main/java/io/github/sds100/keymapper/base/utils/DndModeStrings.kt index 28c7267b97..50b3563cf8 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/volume/DndModeUtils.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/utils/DndModeStrings.kt @@ -1,11 +1,9 @@ -package io.github.sds100.keymapper.system.volume +package io.github.sds100.keymapper.base.utils -import io.github.sds100.keymapper.R +import io.github.sds100.keymapper.base.R +import io.github.sds100.keymapper.system.volume.DndMode -/** - * Created by sds100 on 23/03/2021. - */ -object DndModeUtils { +object DndModeStrings { fun getLabel(dndMode: DndMode) = when (dndMode) { DndMode.ALARMS -> R.string.dnd_mode_alarms DndMode.PRIORITY -> R.string.dnd_mode_priority diff --git a/base/src/main/java/io/github/sds100/keymapper/base/utils/ErrorUtils.kt b/base/src/main/java/io/github/sds100/keymapper/base/utils/ErrorUtils.kt new file mode 100644 index 0000000000..2dedb5f341 --- /dev/null +++ b/base/src/main/java/io/github/sds100/keymapper/base/utils/ErrorUtils.kt @@ -0,0 +1,196 @@ +package io.github.sds100.keymapper.base.utils + +import android.content.pm.PackageManager +import io.github.sds100.keymapper.base.R +import io.github.sds100.keymapper.base.utils.ui.ResourceProvider +import io.github.sds100.keymapper.common.utils.BuildUtils +import io.github.sds100.keymapper.common.utils.KMError +import io.github.sds100.keymapper.data.DataError +import io.github.sds100.keymapper.system.SystemError +import io.github.sds100.keymapper.system.permissions.Permission + +fun KMError.getFullMessage(resourceProvider: ResourceProvider): String { + return when (this) { + is SystemError.PermissionDenied -> { + val resId = when (permission) { + Permission.WRITE_SETTINGS -> R.string.error_action_requires_write_settings_permission + Permission.CAMERA -> R.string.error_action_requires_camera_permission + Permission.DEVICE_ADMIN -> R.string.error_need_to_enable_device_admin + Permission.READ_PHONE_STATE -> R.string.error_action_requires_read_phone_state_permission + Permission.ACCESS_NOTIFICATION_POLICY -> R.string.error_action_notification_policy_permission + Permission.WRITE_SECURE_SETTINGS -> R.string.error_need_write_secure_settings_permission + Permission.NOTIFICATION_LISTENER -> R.string.error_denied_notification_listener_service_permission + Permission.CALL_PHONE -> R.string.error_denied_call_phone_permission + Permission.ROOT -> R.string.error_requires_root + Permission.IGNORE_BATTERY_OPTIMISATION -> R.string.error_battery_optimisation_enabled + Permission.SHIZUKU -> R.string.error_shizuku_permission_denied + Permission.ACCESS_FINE_LOCATION -> R.string.error_access_fine_location_permission_denied + Permission.ANSWER_PHONE_CALL -> R.string.error_answer_end_phone_call_permission_denied + Permission.FIND_NEARBY_DEVICES -> R.string.error_find_nearby_devices_permission_denied + Permission.POST_NOTIFICATIONS -> R.string.error_notifications_permission_denied + } + + resourceProvider.getString(resId) + } + + is KMError.AppNotFound -> resourceProvider.getString( + R.string.error_app_isnt_installed, + packageName, + ) + + is KMError.AppDisabled -> resourceProvider.getString( + R.string.error_app_is_disabled_package_name, + this.packageName, + ) + + is KMError.NoCompatibleImeEnabled -> resourceProvider.getString(R.string.error_key_mapper_ime_service_disabled) + is KMError.NoCompatibleImeChosen -> resourceProvider.getString(R.string.error_ime_must_be_chosen) + is KMError.SystemFeatureNotSupported -> when (this.feature) { + PackageManager.FEATURE_NFC -> resourceProvider.getString(R.string.error_system_feature_nfc_unsupported) + PackageManager.FEATURE_CAMERA -> resourceProvider.getString(R.string.error_system_feature_camera_unsupported) + PackageManager.FEATURE_FINGERPRINT -> resourceProvider.getString(R.string.error_system_feature_fingerprint_unsupported) + PackageManager.FEATURE_WIFI -> resourceProvider.getString(R.string.error_system_feature_wifi_unsupported) + PackageManager.FEATURE_BLUETOOTH -> resourceProvider.getString(R.string.error_system_feature_bluetooth_unsupported) + PackageManager.FEATURE_DEVICE_ADMIN -> resourceProvider.getString(R.string.error_system_feature_device_admin_unsupported) + PackageManager.FEATURE_CAMERA_FLASH -> resourceProvider.getString(R.string.error_system_feature_camera_flash_unsupported) + PackageManager.FEATURE_TELEPHONY -> resourceProvider.getString(R.string.error_system_feature_telephony_unsupported) + else -> throw Exception("Don't know how to get error message for this system feature ${this.feature}") + } + + is DataError.ExtraNotFound -> resourceProvider.getString( + R.string.error_extra_not_found, + extraId, + ) + + is KMError.SdkVersionTooLow -> resourceProvider.getString( + R.string.error_sdk_version_too_low, + BuildUtils.getSdkVersionName(minSdk), + ) + + is KMError.SdkVersionTooHigh -> resourceProvider.getString( + R.string.error_sdk_version_too_high, + BuildUtils.getSdkVersionName(maxSdk), + ) + + is KMError.InputMethodNotFound -> resourceProvider.getString( + R.string.error_ime_not_found, + imeLabel, + ) + + is KMError.FrontFlashNotFound -> resourceProvider.getString(R.string.error_front_flash_not_found) + is KMError.BackFlashNotFound -> resourceProvider.getString(R.string.error_back_flash_not_found) + is KMError.DeviceNotFound -> resourceProvider.getString(R.string.error_device_not_found) + is KMError.Exception -> exception.toString() + is KMError.EmptyJson -> resourceProvider.getString(R.string.error_empty_json) + is KMError.InvalidNumber -> resourceProvider.getString(R.string.error_invalid_number) + is KMError.NumberTooSmall -> resourceProvider.getString(R.string.error_number_too_small, min) + is KMError.NumberTooBig -> resourceProvider.getString(R.string.error_number_too_big, max) + is KMError.EmptyText -> resourceProvider.getString(R.string.error_cant_be_empty) + KMError.BackupVersionTooNew -> resourceProvider.getString(R.string.error_backup_version_too_new) + KMError.NoIncompatibleKeyboardsInstalled -> resourceProvider.getString(R.string.error_no_incompatible_input_methods_installed) + KMError.NoMediaSessions -> resourceProvider.getString(R.string.error_no_media_sessions) + KMError.NoVoiceAssistant -> resourceProvider.getString(R.string.error_voice_assistant_not_found) + KMError.AccessibilityServiceDisabled -> resourceProvider.getString(R.string.error_accessibility_service_disabled) + KMError.LauncherShortcutsNotSupported -> resourceProvider.getString(R.string.error_launcher_shortcuts_not_supported) + KMError.AccessibilityServiceCrashed -> resourceProvider.getString(R.string.error_accessibility_service_crashed) + KMError.CantFindImeSettings -> resourceProvider.getString(R.string.error_cant_find_ime_settings) + KMError.CantShowImePickerInBackground -> resourceProvider.getString(R.string.error_cant_show_ime_picker_in_background) + KMError.FailedToFindAccessibilityNode -> resourceProvider.getString(R.string.error_failed_to_find_accessibility_node) + is KMError.FailedToPerformAccessibilityGlobalAction -> resourceProvider.getString( + R.string.error_failed_to_perform_accessibility_global_action, + action, + ) + + KMError.FailedToDispatchGesture -> resourceProvider.getString(R.string.error_failed_to_dispatch_gesture) + KMError.AppShortcutCantBeOpened -> resourceProvider.getString(R.string.error_opening_app_shortcut) + KMError.InsufficientPermissionsToOpenAppShortcut -> resourceProvider.getString(R.string.error_keymapper_doesnt_have_permission_app_shortcut) + KMError.NoAppToPhoneCall -> resourceProvider.getString(R.string.error_no_app_to_phone_call) + + KMError.CameraInUse -> resourceProvider.getString(R.string.error_camera_in_use) + KMError.CameraError -> resourceProvider.getString(R.string.error_camera_error) + KMError.CameraDisabled -> resourceProvider.getString(R.string.error_camera_disabled) + KMError.CameraDisconnected -> resourceProvider.getString(R.string.error_camera_disconnected) + KMError.MaxCamerasInUse -> resourceProvider.getString(R.string.error_max_cameras_in_use) + KMError.CameraVariableFlashlightStrengthUnsupported -> resourceProvider.getString(R.string.error_variable_flashlight_strength_unsupported) + + is KMError.FailedToModifySystemSetting -> resourceProvider.getString( + R.string.error_failed_to_modify_system_setting, + setting, + ) + + is SystemError.ImeDisabled -> resourceProvider.getString( + R.string.error_ime_disabled, + this.ime.label, + ) + + KMError.FailedToChangeIme -> resourceProvider.getString(R.string.error_failed_to_change_ime) + KMError.NoCameraApp -> resourceProvider.getString(R.string.error_no_camera_app) + KMError.NoDeviceAssistant -> resourceProvider.getString(R.string.error_no_device_assistant) + KMError.NoSettingsApp -> resourceProvider.getString(R.string.error_no_settings_app) + KMError.NoAppToOpenUrl -> resourceProvider.getString(R.string.error_no_app_to_open_url) + + KMError.CantFindSoundFile -> resourceProvider.getString(R.string.error_cant_find_sound_file) + is KMError.CorruptJsonFile -> reason + + is KMError.CannotCreateFileInTarget -> resourceProvider.getString( + R.string.error_file_access_denied, + uri, + ) + + KMError.FileOperationCancelled -> resourceProvider.getString(R.string.error_file_operation_cancelled) + is KMError.NoSpaceLeftOnTarget -> resourceProvider.getString( + R.string.error_no_space_left_at_target, + uri, + ) + + is KMError.NotADirectory -> resourceProvider.getString(R.string.error_not_a_directory, uri) + is KMError.NotAFile -> resourceProvider.getString(R.string.error_not_a_file, uri) + is KMError.SourceFileNotFound -> resourceProvider.getString( + R.string.error_source_file_not_found, + uri, + ) + + KMError.StoragePermissionDenied -> resourceProvider.getString(R.string.error_storage_permission_denied) + KMError.TargetDirectoryMatchesSourceDirectory -> resourceProvider.getString(R.string.error_matching_source_and_target_paths) + is KMError.TargetDirectoryNotFound -> resourceProvider.getString( + R.string.error_directory_not_found, + uri, + ) + + is KMError.TargetFileNotFound -> resourceProvider.getString( + R.string.error_target_file_not_found, + uri, + ) + + KMError.UnknownIOError -> resourceProvider.getString(R.string.error_io_error) + KMError.ShizukuNotStarted -> resourceProvider.getString(R.string.error_shizuku_not_started) + KMError.NoFileName -> resourceProvider.getString(R.string.error_no_file_name) + KMError.CantDetectKeyEventsInPhoneCall -> resourceProvider.getString(R.string.trigger_error_cant_detect_in_phone_call_explanation) + KMError.GestureStrokeCountTooHigh -> resourceProvider.getString(R.string.trigger_error_gesture_stroke_count_too_high) + KMError.GestureDurationTooHigh -> resourceProvider.getString(R.string.trigger_error_gesture_duration_too_high) + + KMError.DpadTriggerImeNotSelected -> resourceProvider.getString(R.string.trigger_error_dpad_ime_not_selected) + KMError.InvalidBackup -> resourceProvider.getString(R.string.error_invalid_backup) + KMError.MalformedUrl -> resourceProvider.getString(R.string.error_malformed_url) + KMError.UiElementNotFound -> resourceProvider.getString(R.string.error_ui_element_not_found) + else -> throw IllegalArgumentException("Unknown error $this") + } +} + +val KMError.isFixable: Boolean + get() = when (this) { + is KMError.AppNotFound, + is KMError.AppDisabled, + KMError.NoCompatibleImeEnabled, + KMError.NoCompatibleImeChosen, + is SystemError.ImeDisabled, + KMError.AccessibilityServiceDisabled, + KMError.AccessibilityServiceCrashed, + is SystemError.PermissionDenied, + is KMError.ShizukuNotStarted, + is KMError.CantDetectKeyEventsInPhoneCall, + + -> true + + else -> false + } diff --git a/app/src/main/java/io/github/sds100/keymapper/util/FilterUtils.kt b/base/src/main/java/io/github/sds100/keymapper/base/utils/FilterUtils.kt similarity index 83% rename from app/src/main/java/io/github/sds100/keymapper/util/FilterUtils.kt rename to base/src/main/java/io/github/sds100/keymapper/base/utils/FilterUtils.kt index c944f94985..5ac7a28816 100644 --- a/app/src/main/java/io/github/sds100/keymapper/util/FilterUtils.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/utils/FilterUtils.kt @@ -1,16 +1,13 @@ -package io.github.sds100.keymapper.util +package io.github.sds100.keymapper.base.utils -import io.github.sds100.keymapper.util.ui.ISearchable +import io.github.sds100.keymapper.base.utils.ui.ISearchable +import io.github.sds100.keymapper.common.utils.State import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.flow import kotlinx.coroutines.withContext import java.util.Locale -/** - * Created by sds100 on 22/03/2021. - */ - fun List.filterByQuery(query: String?): Flow>> = flow { if (query.isNullOrBlank()) { emit(State.Data(this@filterByQuery)) diff --git a/app/src/main/java/io/github/sds100/keymapper/system/inputevents/InputEventUtils.kt b/base/src/main/java/io/github/sds100/keymapper/base/utils/InputEventStrings.kt similarity index 51% rename from app/src/main/java/io/github/sds100/keymapper/system/inputevents/InputEventUtils.kt rename to base/src/main/java/io/github/sds100/keymapper/base/utils/InputEventStrings.kt index a42c1949fa..256152c0b7 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/inputevents/InputEventUtils.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/utils/InputEventStrings.kt @@ -1,16 +1,36 @@ -package io.github.sds100.keymapper.system.inputevents +package io.github.sds100.keymapper.base.utils import android.os.Build -import android.view.InputDevice -import android.view.InputEvent import android.view.KeyEvent -import io.github.sds100.keymapper.R -import splitties.bitflags.withFlag +import io.github.sds100.keymapper.base.R +import io.github.sds100.keymapper.system.inputevents.InputEventUtils.KEYCODE_TO_SCANCODE_OFFSET + +object InputEventStrings { + + val MODIFIER_LABELS = mapOf( + KeyEvent.META_CTRL_ON to R.string.meta_state_ctrl, + KeyEvent.META_CTRL_LEFT_ON to R.string.meta_state_ctrl_left, + KeyEvent.META_CTRL_RIGHT_ON to R.string.meta_state_ctrl_right, + + KeyEvent.META_ALT_ON to R.string.meta_state_alt, + KeyEvent.META_ALT_LEFT_ON to R.string.meta_state_alt_left, + KeyEvent.META_ALT_RIGHT_ON to R.string.meta_state_alt_right, + + KeyEvent.META_SHIFT_ON to R.string.meta_state_shift, + KeyEvent.META_SHIFT_LEFT_ON to R.string.meta_state_shift_left, + KeyEvent.META_SHIFT_RIGHT_ON to R.string.meta_state_shift_right, + + KeyEvent.META_META_ON to R.string.meta_state_meta, + KeyEvent.META_META_LEFT_ON to R.string.meta_state_meta_left, + KeyEvent.META_META_RIGHT_ON to R.string.meta_state_meta_right, + + KeyEvent.META_SYM_ON to R.string.meta_state_sym, + KeyEvent.META_CAPS_LOCK_ON to R.string.meta_state_caps_lock, + KeyEvent.META_NUM_LOCK_ON to R.string.meta_state_num_lock, + KeyEvent.META_SCROLL_LOCK_ON to R.string.meta_state_scroll_lock, + KeyEvent.META_FUNCTION_ON to R.string.meta_state_function, + ) -/** - * Created by sds100 on 17/07/2018. - */ -object InputEventUtils { /** * Maps keys which aren't single characters like the Control keys to a string representation */ @@ -341,356 +361,6 @@ object InputEventUtils { } }.toMap() - private val KEYCODES: Set - get() = setOf( - KeyEvent.KEYCODE_SOFT_LEFT, - KeyEvent.KEYCODE_SOFT_RIGHT, - KeyEvent.KEYCODE_HOME, - KeyEvent.KEYCODE_BACK, - KeyEvent.KEYCODE_CALL, - KeyEvent.KEYCODE_ENDCALL, - KeyEvent.KEYCODE_0, - KeyEvent.KEYCODE_1, - KeyEvent.KEYCODE_2, - KeyEvent.KEYCODE_3, - KeyEvent.KEYCODE_4, - KeyEvent.KEYCODE_5, - KeyEvent.KEYCODE_6, - KeyEvent.KEYCODE_7, - KeyEvent.KEYCODE_8, - KeyEvent.KEYCODE_9, - KeyEvent.KEYCODE_STAR, - KeyEvent.KEYCODE_POUND, - KeyEvent.KEYCODE_DPAD_UP, - KeyEvent.KEYCODE_DPAD_DOWN, - KeyEvent.KEYCODE_DPAD_LEFT, - KeyEvent.KEYCODE_DPAD_RIGHT, - KeyEvent.KEYCODE_DPAD_CENTER, - KeyEvent.KEYCODE_VOLUME_UP, - KeyEvent.KEYCODE_VOLUME_DOWN, - KeyEvent.KEYCODE_POWER, - KeyEvent.KEYCODE_CAMERA, - KeyEvent.KEYCODE_CLEAR, - KeyEvent.KEYCODE_A, - KeyEvent.KEYCODE_B, - KeyEvent.KEYCODE_C, - KeyEvent.KEYCODE_D, - KeyEvent.KEYCODE_E, - KeyEvent.KEYCODE_F, - KeyEvent.KEYCODE_G, - KeyEvent.KEYCODE_H, - KeyEvent.KEYCODE_I, - KeyEvent.KEYCODE_J, - KeyEvent.KEYCODE_K, - KeyEvent.KEYCODE_L, - KeyEvent.KEYCODE_M, - KeyEvent.KEYCODE_N, - KeyEvent.KEYCODE_O, - KeyEvent.KEYCODE_P, - KeyEvent.KEYCODE_Q, - KeyEvent.KEYCODE_R, - KeyEvent.KEYCODE_S, - KeyEvent.KEYCODE_T, - KeyEvent.KEYCODE_U, - KeyEvent.KEYCODE_V, - KeyEvent.KEYCODE_W, - KeyEvent.KEYCODE_X, - KeyEvent.KEYCODE_Y, - KeyEvent.KEYCODE_Z, - KeyEvent.KEYCODE_COMMA, - KeyEvent.KEYCODE_PERIOD, - KeyEvent.KEYCODE_ALT_LEFT, - KeyEvent.KEYCODE_ALT_RIGHT, - KeyEvent.KEYCODE_SHIFT_LEFT, - KeyEvent.KEYCODE_SHIFT_RIGHT, - KeyEvent.KEYCODE_TAB, - KeyEvent.KEYCODE_SPACE, - KeyEvent.KEYCODE_SYM, - KeyEvent.KEYCODE_EXPLORER, - KeyEvent.KEYCODE_ENVELOPE, - KeyEvent.KEYCODE_ENTER, - KeyEvent.KEYCODE_FORWARD_DEL, - KeyEvent.KEYCODE_DEL, - KeyEvent.KEYCODE_GRAVE, - KeyEvent.KEYCODE_MINUS, - KeyEvent.KEYCODE_EQUALS, - KeyEvent.KEYCODE_LEFT_BRACKET, - KeyEvent.KEYCODE_RIGHT_BRACKET, - KeyEvent.KEYCODE_BACKSLASH, - KeyEvent.KEYCODE_SEMICOLON, - KeyEvent.KEYCODE_APOSTROPHE, - KeyEvent.KEYCODE_SLASH, - KeyEvent.KEYCODE_AT, - KeyEvent.KEYCODE_ALT_LEFT, - KeyEvent.KEYCODE_HEADSETHOOK, - KeyEvent.KEYCODE_FOCUS, - KeyEvent.KEYCODE_PLUS, - KeyEvent.KEYCODE_MENU, - KeyEvent.KEYCODE_NOTIFICATION, - KeyEvent.KEYCODE_SEARCH, - KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE, - KeyEvent.KEYCODE_MEDIA_STOP, - KeyEvent.KEYCODE_MEDIA_NEXT, - KeyEvent.KEYCODE_MEDIA_PREVIOUS, - KeyEvent.KEYCODE_MEDIA_REWIND, - KeyEvent.KEYCODE_MEDIA_FAST_FORWARD, - KeyEvent.KEYCODE_PAGE_UP, - KeyEvent.KEYCODE_PAGE_DOWN, - KeyEvent.KEYCODE_PICTSYMBOLS, - KeyEvent.KEYCODE_SWITCH_CHARSET, - KeyEvent.KEYCODE_BUTTON_A, - KeyEvent.KEYCODE_BUTTON_B, - KeyEvent.KEYCODE_BUTTON_C, - KeyEvent.KEYCODE_BUTTON_X, - KeyEvent.KEYCODE_BUTTON_Y, - KeyEvent.KEYCODE_BUTTON_Z, - KeyEvent.KEYCODE_BUTTON_L1, - KeyEvent.KEYCODE_BUTTON_R1, - KeyEvent.KEYCODE_BUTTON_L2, - KeyEvent.KEYCODE_BUTTON_R2, - KeyEvent.KEYCODE_BUTTON_THUMBL, - KeyEvent.KEYCODE_BUTTON_THUMBR, - KeyEvent.KEYCODE_BUTTON_START, - KeyEvent.KEYCODE_BUTTON_SELECT, - KeyEvent.KEYCODE_BUTTON_MODE, - KeyEvent.KEYCODE_ESCAPE, - KeyEvent.KEYCODE_DEL, - KeyEvent.KEYCODE_CTRL_LEFT, - KeyEvent.KEYCODE_CTRL_RIGHT, - KeyEvent.KEYCODE_CAPS_LOCK, - KeyEvent.KEYCODE_SCROLL_LOCK, - KeyEvent.KEYCODE_META_LEFT, - KeyEvent.KEYCODE_META_RIGHT, - KeyEvent.KEYCODE_FUNCTION, - KeyEvent.KEYCODE_SYSRQ, - KeyEvent.KEYCODE_BREAK, - KeyEvent.KEYCODE_MOVE_HOME, - KeyEvent.KEYCODE_MOVE_END, - KeyEvent.KEYCODE_INSERT, - KeyEvent.KEYCODE_FORWARD, - KeyEvent.KEYCODE_MEDIA_PLAY, - KeyEvent.KEYCODE_MEDIA_PAUSE, - KeyEvent.KEYCODE_MEDIA_CLOSE, - KeyEvent.KEYCODE_MEDIA_EJECT, - KeyEvent.KEYCODE_MEDIA_RECORD, - KeyEvent.KEYCODE_F1, - KeyEvent.KEYCODE_F2, - KeyEvent.KEYCODE_F3, - KeyEvent.KEYCODE_F4, - KeyEvent.KEYCODE_F5, - KeyEvent.KEYCODE_F6, - KeyEvent.KEYCODE_F7, - KeyEvent.KEYCODE_F8, - KeyEvent.KEYCODE_F9, - KeyEvent.KEYCODE_F10, - KeyEvent.KEYCODE_F11, - KeyEvent.KEYCODE_F12, - KeyEvent.KEYCODE_NUM, - KeyEvent.KEYCODE_NUM_LOCK, - KeyEvent.KEYCODE_NUMPAD_0, - KeyEvent.KEYCODE_NUMPAD_1, - KeyEvent.KEYCODE_NUMPAD_2, - KeyEvent.KEYCODE_NUMPAD_3, - KeyEvent.KEYCODE_NUMPAD_4, - KeyEvent.KEYCODE_NUMPAD_5, - KeyEvent.KEYCODE_NUMPAD_6, - KeyEvent.KEYCODE_NUMPAD_7, - KeyEvent.KEYCODE_NUMPAD_8, - KeyEvent.KEYCODE_NUMPAD_9, - KeyEvent.KEYCODE_NUMPAD_DIVIDE, - KeyEvent.KEYCODE_NUMPAD_MULTIPLY, - KeyEvent.KEYCODE_NUMPAD_SUBTRACT, - KeyEvent.KEYCODE_NUMPAD_ADD, - KeyEvent.KEYCODE_NUMPAD_DOT, - KeyEvent.KEYCODE_NUMPAD_COMMA, - KeyEvent.KEYCODE_NUMPAD_ENTER, - KeyEvent.KEYCODE_NUMPAD_EQUALS, - KeyEvent.KEYCODE_NUMPAD_LEFT_PAREN, - KeyEvent.KEYCODE_NUMPAD_RIGHT_PAREN, - KeyEvent.KEYCODE_MUTE, - KeyEvent.KEYCODE_VOLUME_MUTE, - KeyEvent.KEYCODE_INFO, - KeyEvent.KEYCODE_CHANNEL_UP, - KeyEvent.KEYCODE_CHANNEL_DOWN, - KeyEvent.KEYCODE_ZOOM_IN, - KeyEvent.KEYCODE_ZOOM_OUT, - KeyEvent.KEYCODE_TV, - KeyEvent.KEYCODE_WINDOW, - KeyEvent.KEYCODE_GUIDE, - KeyEvent.KEYCODE_DVR, - KeyEvent.KEYCODE_BOOKMARK, - KeyEvent.KEYCODE_CAPTIONS, - KeyEvent.KEYCODE_SETTINGS, - KeyEvent.KEYCODE_TV_POWER, - KeyEvent.KEYCODE_TV_INPUT, - KeyEvent.KEYCODE_STB_POWER, - KeyEvent.KEYCODE_STB_INPUT, - KeyEvent.KEYCODE_AVR_POWER, - KeyEvent.KEYCODE_AVR_INPUT, - KeyEvent.KEYCODE_PROG_RED, - KeyEvent.KEYCODE_PROG_GREEN, - KeyEvent.KEYCODE_PROG_YELLOW, - KeyEvent.KEYCODE_PROG_BLUE, - KeyEvent.KEYCODE_APP_SWITCH, - KeyEvent.KEYCODE_BUTTON_1, - KeyEvent.KEYCODE_BUTTON_2, - KeyEvent.KEYCODE_BUTTON_3, - KeyEvent.KEYCODE_BUTTON_4, - KeyEvent.KEYCODE_BUTTON_5, - KeyEvent.KEYCODE_BUTTON_6, - KeyEvent.KEYCODE_BUTTON_7, - KeyEvent.KEYCODE_BUTTON_8, - KeyEvent.KEYCODE_BUTTON_9, - KeyEvent.KEYCODE_BUTTON_10, - KeyEvent.KEYCODE_BUTTON_11, - KeyEvent.KEYCODE_BUTTON_12, - KeyEvent.KEYCODE_BUTTON_13, - KeyEvent.KEYCODE_BUTTON_14, - KeyEvent.KEYCODE_BUTTON_15, - KeyEvent.KEYCODE_BUTTON_16, - KeyEvent.KEYCODE_LANGUAGE_SWITCH, - KeyEvent.KEYCODE_MANNER_MODE, - KeyEvent.KEYCODE_3D_MODE, - KeyEvent.KEYCODE_CONTACTS, - KeyEvent.KEYCODE_CALENDAR, - KeyEvent.KEYCODE_MUSIC, - KeyEvent.KEYCODE_CALCULATOR, - KeyEvent.KEYCODE_ZENKAKU_HANKAKU, - KeyEvent.KEYCODE_EISU, - KeyEvent.KEYCODE_MUHENKAN, - KeyEvent.KEYCODE_HENKAN, - KeyEvent.KEYCODE_KATAKANA_HIRAGANA, - KeyEvent.KEYCODE_YEN, - KeyEvent.KEYCODE_RO, - KeyEvent.KEYCODE_KANA, - KeyEvent.KEYCODE_ASSIST, - KeyEvent.KEYCODE_POWER, - KeyEvent.KEYCODE_BRIGHTNESS_DOWN, - KeyEvent.KEYCODE_BRIGHTNESS_UP, - KeyEvent.KEYCODE_MEDIA_AUDIO_TRACK, - KeyEvent.KEYCODE_PAIRING, - KeyEvent.KEYCODE_MEDIA_TOP_MENU, - KeyEvent.KEYCODE_11, - KeyEvent.KEYCODE_12, - KeyEvent.KEYCODE_LAST_CHANNEL, - KeyEvent.KEYCODE_TV_DATA_SERVICE, - KeyEvent.KEYCODE_VOICE_ASSIST, - KeyEvent.KEYCODE_TV_RADIO_SERVICE, - KeyEvent.KEYCODE_TV_TELETEXT, - KeyEvent.KEYCODE_TV_NUMBER_ENTRY, - KeyEvent.KEYCODE_TV_TERRESTRIAL_ANALOG, - KeyEvent.KEYCODE_TV_TERRESTRIAL_DIGITAL, - KeyEvent.KEYCODE_TV_SATELLITE, - KeyEvent.KEYCODE_TV_SATELLITE_BS, - KeyEvent.KEYCODE_TV_SATELLITE_CS, - KeyEvent.KEYCODE_TV_SATELLITE_SERVICE, - KeyEvent.KEYCODE_TV_NETWORK, - KeyEvent.KEYCODE_TV_ANTENNA_CABLE, - KeyEvent.KEYCODE_TV_INPUT_HDMI_1, - KeyEvent.KEYCODE_TV_INPUT_HDMI_2, - KeyEvent.KEYCODE_TV_INPUT_HDMI_3, - KeyEvent.KEYCODE_TV_INPUT_HDMI_4, - KeyEvent.KEYCODE_TV_INPUT_COMPOSITE_1, - KeyEvent.KEYCODE_TV_INPUT_COMPOSITE_2, - KeyEvent.KEYCODE_TV_INPUT_COMPONENT_1, - KeyEvent.KEYCODE_TV_INPUT_COMPONENT_2, - KeyEvent.KEYCODE_TV_INPUT_VGA_1, - KeyEvent.KEYCODE_TV_AUDIO_DESCRIPTION, - KeyEvent.KEYCODE_TV_AUDIO_DESCRIPTION_MIX_UP, - KeyEvent.KEYCODE_TV_AUDIO_DESCRIPTION_MIX_DOWN, - KeyEvent.KEYCODE_TV_ZOOM_MODE, - KeyEvent.KEYCODE_TV_CONTENTS_MENU, - KeyEvent.KEYCODE_TV_MEDIA_CONTEXT_MENU, - KeyEvent.KEYCODE_TV_TIMER_PROGRAMMING, - KeyEvent.KEYCODE_HELP, - ) - - private val KEYCODES_API_23: Set - get() = setOf( - KeyEvent.KEYCODE_NAVIGATE_PREVIOUS, - KeyEvent.KEYCODE_NAVIGATE_NEXT, - KeyEvent.KEYCODE_NAVIGATE_IN, - KeyEvent.KEYCODE_NAVIGATE_OUT, - KeyEvent.KEYCODE_MEDIA_SKIP_FORWARD, - KeyEvent.KEYCODE_MEDIA_SKIP_BACKWARD, - KeyEvent.KEYCODE_MEDIA_STEP_FORWARD, - KeyEvent.KEYCODE_MEDIA_STEP_BACKWARD, - ) - - private val KEYCODES_API_24: Set - get() = setOf( - KeyEvent.KEYCODE_STEM_PRIMARY, - KeyEvent.KEYCODE_STEM_1, - KeyEvent.KEYCODE_STEM_2, - KeyEvent.KEYCODE_STEM_3, - KeyEvent.KEYCODE_DPAD_UP_LEFT, - KeyEvent.KEYCODE_DPAD_DOWN_LEFT, - KeyEvent.KEYCODE_DPAD_UP_RIGHT, - KeyEvent.KEYCODE_DPAD_DOWN_RIGHT, - KeyEvent.KEYCODE_SOFT_SLEEP, - KeyEvent.KEYCODE_CUT, - KeyEvent.KEYCODE_COPY, - KeyEvent.KEYCODE_PASTE, - ) - - private val KEYCODES_API_25: Set - get() = setOf( - KeyEvent.KEYCODE_SYSTEM_NAVIGATION_UP, - KeyEvent.KEYCODE_SYSTEM_NAVIGATION_DOWN, - KeyEvent.KEYCODE_SYSTEM_NAVIGATION_LEFT, - KeyEvent.KEYCODE_SYSTEM_NAVIGATION_RIGHT, - ) - - private val KEYCODES_API_28: Set - get() = setOf( - KeyEvent.KEYCODE_ALL_APPS, - ) - - /** - * These are key code maps for the getevent command. These names aren't the same as the - * KeyEvent key codes in the Android SDK so these have to be manually whitelisted - * as people need. - */ - val GET_EVENT_LABEL_TO_KEYCODE: List> = listOf( - "KEY_VOLUMEDOWN" to KeyEvent.KEYCODE_VOLUME_DOWN, - "KEY_VOLUMEUP" to KeyEvent.KEYCODE_VOLUME_UP, - "KEY_MEDIA" to KeyEvent.KEYCODE_HEADSETHOOK, - "KEY_HEADSETHOOK" to KeyEvent.KEYCODE_HEADSETHOOK, - "KEY_CAMERA_FOCUS" to KeyEvent.KEYCODE_FOCUS, - "02fe" to KeyEvent.KEYCODE_CAMERA, - "00fa" to KeyEvent.KEYCODE_CAMERA, - - // This kernel key event code seems to be the Bixby button - // but different ROMs have different key maps and so - // it is reported as different Android key codes. - "02bf" to KeyEvent.KEYCODE_MENU, - "02bf" to KeyEvent.KEYCODE_ASSIST, - - "KEY_SEARCH" to KeyEvent.KEYCODE_SEARCH, - ) - - fun canDetectKeyWhenScreenOff(keyCode: Int): Boolean = GET_EVENT_LABEL_TO_KEYCODE.any { it.second == keyCode } - - val MODIFIER_KEYCODES: Set - get() = setOf( - KeyEvent.KEYCODE_SHIFT_LEFT, - KeyEvent.KEYCODE_SHIFT_RIGHT, - KeyEvent.KEYCODE_ALT_LEFT, - KeyEvent.KEYCODE_ALT_RIGHT, - KeyEvent.KEYCODE_CTRL_LEFT, - KeyEvent.KEYCODE_CTRL_RIGHT, - KeyEvent.KEYCODE_META_LEFT, - KeyEvent.KEYCODE_META_RIGHT, - KeyEvent.KEYCODE_SYM, - KeyEvent.KEYCODE_NUM, - KeyEvent.KEYCODE_FUNCTION, - ) - - /** - * Used for keyCode to scanCode fallback to go past possible keyCode values - */ - val KEYCODE_TO_SCANCODE_OFFSET: Int = 1000 - /** * Create a text representation of a key event. E.g if the control key was pressed, * "Ctrl" will be returned @@ -702,171 +372,4 @@ object InputEventUtils { it ?: "unknown keycode $keyCode" } } - - fun isModifierKey(keyCode: Int): Boolean = keyCode in MODIFIER_KEYCODES - - fun isGamepadKeyCode(keyCode: Int): Boolean { - when (keyCode) { - KeyEvent.KEYCODE_BUTTON_A, - KeyEvent.KEYCODE_BUTTON_B, - KeyEvent.KEYCODE_BUTTON_C, - KeyEvent.KEYCODE_BUTTON_X, - KeyEvent.KEYCODE_BUTTON_Y, - KeyEvent.KEYCODE_BUTTON_Z, - KeyEvent.KEYCODE_BUTTON_L1, - KeyEvent.KEYCODE_BUTTON_R1, - KeyEvent.KEYCODE_BUTTON_L2, - KeyEvent.KEYCODE_BUTTON_R2, - KeyEvent.KEYCODE_BUTTON_THUMBL, - KeyEvent.KEYCODE_BUTTON_THUMBR, - KeyEvent.KEYCODE_BUTTON_START, - KeyEvent.KEYCODE_BUTTON_SELECT, - KeyEvent.KEYCODE_BUTTON_MODE, - KeyEvent.KEYCODE_BUTTON_1, - KeyEvent.KEYCODE_BUTTON_2, - KeyEvent.KEYCODE_BUTTON_3, - KeyEvent.KEYCODE_BUTTON_4, - KeyEvent.KEYCODE_BUTTON_5, - KeyEvent.KEYCODE_BUTTON_6, - KeyEvent.KEYCODE_BUTTON_7, - KeyEvent.KEYCODE_BUTTON_8, - KeyEvent.KEYCODE_BUTTON_9, - KeyEvent.KEYCODE_BUTTON_10, - KeyEvent.KEYCODE_BUTTON_11, - KeyEvent.KEYCODE_BUTTON_12, - KeyEvent.KEYCODE_BUTTON_13, - KeyEvent.KEYCODE_BUTTON_14, - KeyEvent.KEYCODE_BUTTON_15, - KeyEvent.KEYCODE_BUTTON_16, - -> return true - - else -> return false - } - } - - /** - * Get all the valid key codes which work on the Android version for the device. - */ - fun getKeyCodes(): List { - val keyCodes = KEYCODES.toMutableList() - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - keyCodes.addAll(KEYCODES_API_23) - } - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - keyCodes.addAll(KEYCODES_API_24) - } - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) { - keyCodes.addAll(KEYCODES_API_25) - } - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { - keyCodes.addAll(KEYCODES_API_28) - } - - return keyCodes - } - - fun modifierKeycodeToMetaState(modifier: Int) = when (modifier) { - KeyEvent.KEYCODE_ALT_LEFT -> KeyEvent.META_ALT_LEFT_ON.withFlag(KeyEvent.META_ALT_ON) - KeyEvent.KEYCODE_ALT_RIGHT -> KeyEvent.META_ALT_RIGHT_ON.withFlag(KeyEvent.META_ALT_ON) - - KeyEvent.KEYCODE_SHIFT_LEFT -> KeyEvent.META_SHIFT_LEFT_ON.withFlag(KeyEvent.META_SHIFT_ON) - KeyEvent.KEYCODE_SHIFT_RIGHT -> KeyEvent.META_SHIFT_RIGHT_ON.withFlag(KeyEvent.META_SHIFT_ON) - - KeyEvent.KEYCODE_SYM -> KeyEvent.META_SYM_ON - - KeyEvent.KEYCODE_FUNCTION -> KeyEvent.META_FUNCTION_ON - - KeyEvent.KEYCODE_CTRL_LEFT -> KeyEvent.META_CTRL_LEFT_ON.withFlag(KeyEvent.META_CTRL_ON) - KeyEvent.KEYCODE_CTRL_RIGHT -> KeyEvent.META_CTRL_RIGHT_ON.withFlag(KeyEvent.META_CTRL_ON) - - KeyEvent.KEYCODE_META_LEFT -> KeyEvent.META_META_LEFT_ON.withFlag(KeyEvent.META_META_ON) - KeyEvent.KEYCODE_META_RIGHT -> KeyEvent.META_META_RIGHT_ON.withFlag(KeyEvent.META_META_ON) - - KeyEvent.KEYCODE_CAPS_LOCK -> KeyEvent.META_CAPS_LOCK_ON - KeyEvent.KEYCODE_NUM_LOCK -> KeyEvent.META_NUM_LOCK_ON - KeyEvent.KEYCODE_SCROLL_LOCK -> KeyEvent.META_SCROLL_LOCK_ON - - else -> throw Exception("can't convert modifier $modifier to meta state") - } - - val MODIFIER_LABELS = mapOf( - KeyEvent.META_CTRL_ON to R.string.meta_state_ctrl, - KeyEvent.META_CTRL_LEFT_ON to R.string.meta_state_ctrl_left, - KeyEvent.META_CTRL_RIGHT_ON to R.string.meta_state_ctrl_right, - - KeyEvent.META_ALT_ON to R.string.meta_state_alt, - KeyEvent.META_ALT_LEFT_ON to R.string.meta_state_alt_left, - KeyEvent.META_ALT_RIGHT_ON to R.string.meta_state_alt_right, - - KeyEvent.META_SHIFT_ON to R.string.meta_state_shift, - KeyEvent.META_SHIFT_LEFT_ON to R.string.meta_state_shift_left, - KeyEvent.META_SHIFT_RIGHT_ON to R.string.meta_state_shift_right, - - KeyEvent.META_META_ON to R.string.meta_state_meta, - KeyEvent.META_META_LEFT_ON to R.string.meta_state_meta_left, - KeyEvent.META_META_RIGHT_ON to R.string.meta_state_meta_right, - - KeyEvent.META_SYM_ON to R.string.meta_state_sym, - KeyEvent.META_CAPS_LOCK_ON to R.string.meta_state_caps_lock, - KeyEvent.META_NUM_LOCK_ON to R.string.meta_state_num_lock, - KeyEvent.META_SCROLL_LOCK_ON to R.string.meta_state_scroll_lock, - KeyEvent.META_FUNCTION_ON to R.string.meta_state_function, - ) - - fun isDpadKeyCode(code: Int): Boolean { - return code == KeyEvent.KEYCODE_DPAD_LEFT || - code == KeyEvent.KEYCODE_DPAD_RIGHT || - code == KeyEvent.KEYCODE_DPAD_UP || - code == KeyEvent.KEYCODE_DPAD_DOWN || - code == KeyEvent.KEYCODE_DPAD_UP_LEFT || - code == KeyEvent.KEYCODE_DPAD_UP_RIGHT || - code == KeyEvent.KEYCODE_DPAD_DOWN_LEFT || - code == KeyEvent.KEYCODE_DPAD_DOWN_RIGHT - } - - fun isDpadDevice(event: InputEvent): Boolean = // Check that input comes from a device with directional pads. - event.source and InputDevice.SOURCE_DPAD != InputDevice.SOURCE_DPAD - - fun isGamepadButton(keyCode: Int): Boolean { - return when (keyCode) { - KeyEvent.KEYCODE_BUTTON_A, - KeyEvent.KEYCODE_BUTTON_B, - KeyEvent.KEYCODE_BUTTON_C, - KeyEvent.KEYCODE_BUTTON_X, - KeyEvent.KEYCODE_BUTTON_Y, - KeyEvent.KEYCODE_BUTTON_Z, - KeyEvent.KEYCODE_BUTTON_L1, - KeyEvent.KEYCODE_BUTTON_R1, - KeyEvent.KEYCODE_BUTTON_L2, - KeyEvent.KEYCODE_BUTTON_R2, - KeyEvent.KEYCODE_BUTTON_THUMBL, - KeyEvent.KEYCODE_BUTTON_THUMBR, - KeyEvent.KEYCODE_BUTTON_START, - KeyEvent.KEYCODE_BUTTON_SELECT, - KeyEvent.KEYCODE_BUTTON_MODE, - KeyEvent.KEYCODE_BUTTON_1, - KeyEvent.KEYCODE_BUTTON_2, - KeyEvent.KEYCODE_BUTTON_3, - KeyEvent.KEYCODE_BUTTON_4, - KeyEvent.KEYCODE_BUTTON_5, - KeyEvent.KEYCODE_BUTTON_6, - KeyEvent.KEYCODE_BUTTON_7, - KeyEvent.KEYCODE_BUTTON_8, - KeyEvent.KEYCODE_BUTTON_9, - KeyEvent.KEYCODE_BUTTON_10, - KeyEvent.KEYCODE_BUTTON_11, - KeyEvent.KEYCODE_BUTTON_12, - KeyEvent.KEYCODE_BUTTON_13, - KeyEvent.KEYCODE_BUTTON_14, - KeyEvent.KEYCODE_BUTTON_15, - KeyEvent.KEYCODE_BUTTON_16, - -> true - - else -> false - } - } } diff --git a/base/src/main/java/io/github/sds100/keymapper/base/utils/IntentStrings.kt b/base/src/main/java/io/github/sds100/keymapper/base/utils/IntentStrings.kt new file mode 100644 index 0000000000..397ce57539 --- /dev/null +++ b/base/src/main/java/io/github/sds100/keymapper/base/utils/IntentStrings.kt @@ -0,0 +1,64 @@ +package io.github.sds100.keymapper.base.utils + +import io.github.sds100.keymapper.base.R +import io.github.sds100.keymapper.system.intents.BoolArrayExtraType +import io.github.sds100.keymapper.system.intents.BoolExtraType +import io.github.sds100.keymapper.system.intents.ByteArrayExtraType +import io.github.sds100.keymapper.system.intents.ByteExtraType +import io.github.sds100.keymapper.system.intents.CharArrayExtraType +import io.github.sds100.keymapper.system.intents.CharExtraType +import io.github.sds100.keymapper.system.intents.DoubleArrayExtraType +import io.github.sds100.keymapper.system.intents.DoubleExtraType +import io.github.sds100.keymapper.system.intents.FloatArrayExtraType +import io.github.sds100.keymapper.system.intents.FloatExtraType +import io.github.sds100.keymapper.system.intents.IntArrayExtraType +import io.github.sds100.keymapper.system.intents.IntExtraType +import io.github.sds100.keymapper.system.intents.IntentExtraType +import io.github.sds100.keymapper.system.intents.LongArrayExtraType +import io.github.sds100.keymapper.system.intents.LongExtraType +import io.github.sds100.keymapper.system.intents.ShortArrayExtraType +import io.github.sds100.keymapper.system.intents.ShortExtraType +import io.github.sds100.keymapper.system.intents.StringArrayExtraType +import io.github.sds100.keymapper.system.intents.StringExtraType + +fun IntentExtraType.getLabelStringRes(): Int = when (this) { + is BoolExtraType -> R.string.intent_type_bool_header + is BoolArrayExtraType -> R.string.intent_type_bool_array_header + is IntExtraType -> R.string.intent_type_int_header + is IntArrayExtraType -> R.string.intent_type_int_array_header + is StringExtraType -> R.string.intent_type_string_header + is StringArrayExtraType -> R.string.intent_type_string_array_header + is LongExtraType -> R.string.intent_type_long_header + is LongArrayExtraType -> R.string.intent_type_long_array_header + is ByteExtraType -> R.string.intent_type_byte_header + is ByteArrayExtraType -> R.string.intent_type_byte_array_header + is DoubleExtraType -> R.string.intent_type_double_header + is DoubleArrayExtraType -> R.string.intent_type_double_array_header + is CharExtraType -> R.string.intent_type_char_header + is CharArrayExtraType -> R.string.intent_type_char_array_header + is FloatExtraType -> R.string.intent_type_float_header + is FloatArrayExtraType -> R.string.intent_type_float_array_header + is ShortExtraType -> R.string.intent_type_short_header + is ShortArrayExtraType -> R.string.intent_type_short_array_header +} + +fun IntentExtraType.getExampleStringRes(): Int = when (this) { + is BoolExtraType -> R.string.intent_type_bool_example + is BoolArrayExtraType -> R.string.intent_type_bool_array_example + is IntExtraType -> R.string.intent_type_int_example + is IntArrayExtraType -> R.string.intent_type_int_array_example + is StringExtraType -> R.string.intent_type_string_example + is StringArrayExtraType -> R.string.intent_type_string_array_example + is LongExtraType -> R.string.intent_type_long_example + is LongArrayExtraType -> R.string.intent_type_long_array_example + is ByteExtraType -> R.string.intent_type_byte_example + is ByteArrayExtraType -> R.string.intent_type_byte_array_example + is DoubleExtraType -> R.string.intent_type_double_example + is DoubleArrayExtraType -> R.string.intent_type_double_array_example + is CharExtraType -> R.string.intent_type_char_example + is CharArrayExtraType -> R.string.intent_type_char_array_example + is FloatExtraType -> R.string.intent_type_float_example + is FloatArrayExtraType -> R.string.intent_type_float_array_example + is ShortExtraType -> R.string.intent_type_short_example + is ShortArrayExtraType -> R.string.intent_type_short_array_example +} diff --git a/app/src/main/java/io/github/sds100/keymapper/system/volume/RingerModeUtils.kt b/base/src/main/java/io/github/sds100/keymapper/base/utils/RingerModeStrings.kt similarity index 58% rename from app/src/main/java/io/github/sds100/keymapper/system/volume/RingerModeUtils.kt rename to base/src/main/java/io/github/sds100/keymapper/base/utils/RingerModeStrings.kt index 7605409862..a719a2822b 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/volume/RingerModeUtils.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/utils/RingerModeStrings.kt @@ -1,11 +1,9 @@ -package io.github.sds100.keymapper.system.volume +package io.github.sds100.keymapper.base.utils -import io.github.sds100.keymapper.R +import io.github.sds100.keymapper.base.R +import io.github.sds100.keymapper.system.volume.RingerMode -/** - * Created by sds100 on 23/03/2021. - */ -object RingerModeUtils { +object RingerModeStrings { fun getLabel(ringerMode: RingerMode) = when (ringerMode) { RingerMode.NORMAL -> R.string.ringer_mode_normal RingerMode.VIBRATE -> R.string.ringer_mode_vibrate diff --git a/app/src/main/java/io/github/sds100/keymapper/util/ShareUtils.kt b/base/src/main/java/io/github/sds100/keymapper/base/utils/ShareUtils.kt similarity index 89% rename from app/src/main/java/io/github/sds100/keymapper/util/ShareUtils.kt rename to base/src/main/java/io/github/sds100/keymapper/base/utils/ShareUtils.kt index 8b305ed2d0..5b999c61bb 100644 --- a/app/src/main/java/io/github/sds100/keymapper/util/ShareUtils.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/utils/ShareUtils.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.util +package io.github.sds100.keymapper.base.utils import android.app.PendingIntent import android.content.ActivityNotFoundException @@ -10,9 +10,8 @@ import android.os.Build import android.service.chooser.ChooserAction import androidx.core.app.ShareCompat import androidx.core.net.toUri -import io.github.sds100.keymapper.BaseMainActivity -import io.github.sds100.keymapper.Constants -import io.github.sds100.keymapper.R +import io.github.sds100.keymapper.base.BaseMainActivity +import io.github.sds100.keymapper.base.R object ShareUtils { fun sendMail(ctx: Context, email: String, subject: String, body: String) { @@ -28,7 +27,7 @@ object ShareUtils { } } - fun shareFile(ctx: Context, file: Uri) { + fun shareFile(ctx: Context, file: Uri, packageName: String) { try { val type = ctx.contentResolver.getType(file) @@ -39,7 +38,7 @@ object ShareUtils { .also { intent -> if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) { val broadcast = Intent(BaseMainActivity.ACTION_SAVE_FILE).apply { - setPackage(Constants.PACKAGE_NAME) + setPackage(packageName) putExtra(BaseMainActivity.EXTRA_FILE_URI, file) } diff --git a/app/src/main/java/io/github/sds100/keymapper/util/VersionHelper.kt b/base/src/main/java/io/github/sds100/keymapper/base/utils/VersionHelper.kt similarity index 65% rename from app/src/main/java/io/github/sds100/keymapper/util/VersionHelper.kt rename to base/src/main/java/io/github/sds100/keymapper/base/utils/VersionHelper.kt index eb59eb2411..173bd9f697 100644 --- a/app/src/main/java/io/github/sds100/keymapper/util/VersionHelper.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/utils/VersionHelper.kt @@ -1,8 +1,5 @@ -package io.github.sds100.keymapper.util +package io.github.sds100.keymapper.base.utils -/** - * Created by sds100 on 25/04/2021. - */ object VersionHelper { const val VERSION_2_3_0 = 43 @@ -13,7 +10,7 @@ object VersionHelper { const val FINGERPRINT_GESTURES_MIN_VERSION = 40 /** - * This is version 3.0.0-beta.1 when the assistant trigger was first introduced. + * This is version 3.0.0-beta.1 when floating buttons were first introduced. */ const val FLOATING_BUTTON_MIN_VERSION = 81 } diff --git a/app/src/main/java/io/github/sds100/keymapper/system/volume/VolumeStreamUtils.kt b/base/src/main/java/io/github/sds100/keymapper/base/utils/VolumeStreamStrings.kt similarity index 74% rename from app/src/main/java/io/github/sds100/keymapper/system/volume/VolumeStreamUtils.kt rename to base/src/main/java/io/github/sds100/keymapper/base/utils/VolumeStreamStrings.kt index 6b91b76e92..f8556402c9 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/volume/VolumeStreamUtils.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/utils/VolumeStreamStrings.kt @@ -1,11 +1,9 @@ -package io.github.sds100.keymapper.system.volume +package io.github.sds100.keymapper.base.utils -import io.github.sds100.keymapper.R +import io.github.sds100.keymapper.base.R +import io.github.sds100.keymapper.system.volume.VolumeStream -/** - * Created by sds100 on 23/03/2021. - */ -object VolumeStreamUtils { +object VolumeStreamStrings { fun getLabel(stream: VolumeStream) = when (stream) { VolumeStream.ALARM -> R.string.stream_alarm VolumeStream.DTMF -> R.string.stream_dtmf diff --git a/app/src/main/java/io/github/sds100/keymapper/util/ui/NavDestination.kt b/base/src/main/java/io/github/sds100/keymapper/base/utils/navigation/NavDestination.kt similarity index 61% rename from app/src/main/java/io/github/sds100/keymapper/util/ui/NavDestination.kt rename to base/src/main/java/io/github/sds100/keymapper/base/utils/navigation/NavDestination.kt index eababf264b..8f6c870c49 100644 --- a/app/src/main/java/io/github/sds100/keymapper/util/ui/NavDestination.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/utils/navigation/NavDestination.kt @@ -1,22 +1,22 @@ -package io.github.sds100.keymapper.util.ui - -import io.github.sds100.keymapper.actions.ActionData -import io.github.sds100.keymapper.actions.pinchscreen.PinchPickCoordinateResult -import io.github.sds100.keymapper.actions.swipescreen.SwipePickCoordinateResult -import io.github.sds100.keymapper.actions.tapscreen.PickCoordinateResult -import io.github.sds100.keymapper.constraints.Constraint +package io.github.sds100.keymapper.base.utils.navigation + +import io.github.sds100.keymapper.base.actions.ActionData +import io.github.sds100.keymapper.base.actions.pinchscreen.PinchPickCoordinateResult +import io.github.sds100.keymapper.base.actions.swipescreen.SwipePickCoordinateResult +import io.github.sds100.keymapper.base.actions.tapscreen.PickCoordinateResult +import io.github.sds100.keymapper.base.constraints.Constraint +import io.github.sds100.keymapper.base.system.apps.ChooseAppShortcutResult +import io.github.sds100.keymapper.base.system.intents.ConfigIntentResult import io.github.sds100.keymapper.system.apps.ActivityInfo -import io.github.sds100.keymapper.system.apps.ChooseAppShortcutResult import io.github.sds100.keymapper.system.bluetooth.BluetoothDeviceInfo -import io.github.sds100.keymapper.system.intents.ConfigIntentResult +import kotlinx.serialization.Serializable -/** - * Created by sds100 on 25/07/2021. - */ -sealed class NavDestination { +@Serializable +abstract class NavDestination(val isCompose: Boolean = false) { abstract val id: String companion object { + const val ID_HOME = "home" const val ID_CHOOSE_APP = "choose_app" const val ID_CHOOSE_APP_SHORTCUT = "choose_app_shortcut" const val ID_KEY_CODE = "key_code" @@ -34,10 +34,15 @@ sealed class NavDestination { const val ID_ABOUT = "about" const val ID_CONFIG_KEY_MAP = "config_key_map" const val ID_SHIZUKU_SETTINGS = "shizuku_settings" - const val ID_CONFIG_FLOATING_BUTTON = "config_floating_button" const val ID_INTERACT_UI_ELEMENT_ACTION = "interact_ui_element_action" } + @Serializable + data object Home : NavDestination() { + override val id: String = ID_HOME + } + + @Serializable data class ChooseApp( /** * Allow the list to show hidden apps that can't be launched. @@ -47,84 +52,102 @@ sealed class NavDestination { override val id: String = ID_CHOOSE_APP } + @Serializable data object ChooseAppShortcut : NavDestination() { override val id: String = ID_CHOOSE_APP_SHORTCUT } + @Serializable data object ChooseKeyCode : NavDestination() { override val id: String = ID_KEY_CODE } - data class ConfigKeyEventAction(val action: ActionData.InputKeyEvent? = null) : NavDestination() { + @Serializable + data class ConfigKeyEventAction(val action: ActionData.InputKeyEvent? = null) : + NavDestination() { override val id: String = ID_KEY_EVENT } + @Serializable data class PickCoordinate(val result: PickCoordinateResult? = null) : NavDestination() { override val id: String = ID_PICK_COORDINATE } - data class PickSwipeCoordinate(val result: SwipePickCoordinateResult? = null) : NavDestination() { + @Serializable + data class PickSwipeCoordinate(val result: SwipePickCoordinateResult? = null) : + NavDestination() { override val id: String = ID_PICK_SWIPE_COORDINATE } - data class PickPinchCoordinate(val result: PinchPickCoordinateResult? = null) : NavDestination() { + @Serializable + data class PickPinchCoordinate(val result: PinchPickCoordinateResult? = null) : + NavDestination() { override val id: String = ID_PICK_PINCH_COORDINATE } + @Serializable data class ConfigIntent(val result: ConfigIntentResult? = null) : NavDestination() { override val id: String = ID_CONFIG_INTENT } + @Serializable data object ChooseActivity : NavDestination() { override val id: String = ID_CHOOSE_ACTIVITY } + @Serializable data object ChooseSound : NavDestination() { override val id: String = ID_CHOOSE_SOUND } - data object ChooseAction : NavDestination() { + @Serializable + data object ChooseAction : NavDestination(isCompose = true) { override val id: String = ID_CHOOSE_ACTION } - data object ChooseConstraint : NavDestination() { + @Serializable + data object ChooseConstraint : NavDestination(isCompose = true) { override val id: String = ID_CHOOSE_CONSTRAINT } + @Serializable data object ChooseBluetoothDevice : NavDestination() { override val id: String = ID_CHOOSE_BLUETOOTH_DEVICE } + @Serializable data object Settings : NavDestination() { override val id: String = ID_SETTINGS } + @Serializable data object About : NavDestination() { override val id: String = ID_ABOUT } - sealed class ConfigKeyMap : NavDestination() { + @Serializable + data class OpenKeyMap(val keyMapUid: String, val showAdvancedTriggers: Boolean = false) : + NavDestination(isCompose = true) { override val id: String = ID_CONFIG_KEY_MAP - abstract val showAdvancedTriggers: Boolean - - data class Open(val keyMapUid: String, override val showAdvancedTriggers: Boolean = false) : ConfigKeyMap() - - data class New(val groupUid: String?, override val showAdvancedTriggers: Boolean = false) : ConfigKeyMap() } - data object ChooseFloatingLayout : NavDestination() { - override val id: String = "choose_floating_layout" + @Serializable + data class NewKeyMap( + val groupUid: String?, + val showAdvancedTriggers: Boolean = false, + val floatingButtonToUse: String? = null, + ) : NavDestination(isCompose = true) { + override val id: String = ID_CONFIG_KEY_MAP } + @Serializable data object ShizukuSettings : NavDestination() { override val id: String = ID_SHIZUKU_SETTINGS } - data class ConfigFloatingButton(val buttonUid: String?) : NavDestination() { - override val id: String = ID_CONFIG_FLOATING_BUTTON - } - - data class InteractUiElement(val action: ActionData.InteractUiElement?) : NavDestination() { + @Serializable + data class InteractUiElement(val actionJson: String?) : + NavDestination(isCompose = true) { override val id: String = ID_INTERACT_UI_ELEMENT_ACTION } } diff --git a/base/src/main/java/io/github/sds100/keymapper/base/utils/navigation/NavResult.kt b/base/src/main/java/io/github/sds100/keymapper/base/utils/navigation/NavResult.kt new file mode 100644 index 0000000000..1829cdbcee --- /dev/null +++ b/base/src/main/java/io/github/sds100/keymapper/base/utils/navigation/NavResult.kt @@ -0,0 +1,3 @@ +package io.github.sds100.keymapper.base.utils.navigation + +data class NavResult(val key: String, val data: String?) diff --git a/base/src/main/java/io/github/sds100/keymapper/base/utils/navigation/NavigateEvent.kt b/base/src/main/java/io/github/sds100/keymapper/base/utils/navigation/NavigateEvent.kt new file mode 100644 index 0000000000..b55f78d6f3 --- /dev/null +++ b/base/src/main/java/io/github/sds100/keymapper/base/utils/navigation/NavigateEvent.kt @@ -0,0 +1,3 @@ +package io.github.sds100.keymapper.base.utils.navigation + +data class NavigateEvent(val key: String, val destination: NavDestination<*>) diff --git a/base/src/main/java/io/github/sds100/keymapper/base/utils/navigation/NavigationProvider.kt b/base/src/main/java/io/github/sds100/keymapper/base/utils/navigation/NavigationProvider.kt new file mode 100644 index 0000000000..0cea5a666a --- /dev/null +++ b/base/src/main/java/io/github/sds100/keymapper/base/utils/navigation/NavigationProvider.kt @@ -0,0 +1,440 @@ +package io.github.sds100.keymapper.base.utils.navigation + +import android.os.Bundle +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.core.os.bundleOf +import androidx.fragment.app.Fragment +import androidx.fragment.app.clearFragmentResultListener +import androidx.fragment.app.setFragmentResultListener +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import androidx.lifecycle.lifecycleScope +import androidx.navigation.NavDirections +import androidx.navigation.NavHostController +import androidx.navigation.compose.currentBackStackEntryAsState +import androidx.navigation.fragment.findNavController +import io.github.sds100.keymapper.base.NavBaseAppDirections +import io.github.sds100.keymapper.base.actions.keyevent.ChooseKeyCodeFragment +import io.github.sds100.keymapper.base.actions.keyevent.ConfigKeyEventActionFragment +import io.github.sds100.keymapper.base.actions.pinchscreen.PinchPickDisplayCoordinateFragment +import io.github.sds100.keymapper.base.actions.sound.ChooseSoundFileFragment +import io.github.sds100.keymapper.base.actions.swipescreen.SwipePickDisplayCoordinateFragment +import io.github.sds100.keymapper.base.actions.tapscreen.PickDisplayCoordinateFragment +import io.github.sds100.keymapper.base.system.apps.ChooseActivityFragment +import io.github.sds100.keymapper.base.system.apps.ChooseAppFragment +import io.github.sds100.keymapper.base.system.apps.ChooseAppShortcutFragment +import io.github.sds100.keymapper.base.system.bluetooth.ChooseBluetoothDeviceFragment +import io.github.sds100.keymapper.base.system.intents.ConfigIntentFragment +import io.github.sds100.keymapper.system.bluetooth.BluetoothDeviceInfo +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.drop +import kotlinx.coroutines.flow.dropWhile +import kotlinx.coroutines.flow.filter +import kotlinx.coroutines.flow.filterNotNull +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.merge +import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.flow.update +import kotlinx.coroutines.runBlocking +import kotlinx.serialization.json.Json +import javax.inject.Inject +import javax.inject.Singleton + +/** + * This class handles communication of navigation requests and results between view models, + * fragments, and Compose destinations. The aim of this class is to enable a way + * for "synchronous" communication between destinations with suspending functions. + * + * The flow is generally this: + * 1. The view model calls [navigate] which then emits a value in the [onNavigate] flow. The + * [navigate] function will suspend until a result is returned. This is being observed in the + * fragment and in the Compose NavHost. The [setupFragmentNavigation] method + * sets up result passing between fragment destinations in a synchronous manner. + * 2. They check the [NavDestination.isCompose] flag to know whether to handle it. They handle + * navigating to the destination and then call [handledNavigateRequest] to clear the state flow. The + * current destination has now changed. + * 3. The result is handled differently depending on whether it is a fragment destination or + * composable. + * + * If it is a fragment then the view model has its own flow to expose results to its + * corresponding fragment. The fragment will observe it and then call setFragmentResult and then + * navigateUp on the nav controller. The [setupFragmentNavigation] registers a listener + * and will update the [onNavResult] flow with the result, which has been observed by the + * [navigate] function the entire time. The origin view model now has the result. + * + * The view model in the new destination calls [popBackStack], or + * [popBackStackWithResult] which then sends the result value into [onReturnResult]. The NavHost + * observes this, calls [handledReturnResult], then sends the result to [onNavResult], which + * the [navigate] function has been observing. The origin view model now has the result. + */ +@Singleton +class NavigationProviderImpl @Inject constructor() : NavigationProvider { + private val _onNavigate = MutableStateFlow(null) + override val onNavigate = _onNavigate.asStateFlow() + + private val _onNavResult = MutableStateFlow(null) + override val onNavResult = _onNavResult.asStateFlow() + + private val _onReturnResult = MutableStateFlow(null) + override val onReturnResult: StateFlow = _onReturnResult.asStateFlow() + + private val _popBackStack = MutableStateFlow(null) + val popBackStack: StateFlow = _popBackStack.asStateFlow() + + fun handledPop() { + _popBackStack.update { null } + } + + override fun handledReturnResult() { + _onReturnResult.update { null } + } + + override fun handledNavigateRequest() { + _onNavigate.update { null } + } + + override fun handledNavResult() { + _onNavResult.update { null } + } + + override suspend fun navigate(event: NavigateEvent) { + // wait for the view to collect so navigating can happen + _onNavigate.subscriptionCount.first { it > 0 } + + _onNavigate.emit(event) + } + + override fun onNavResult(result: NavResult) { + runBlocking { _onNavResult.emit(result) } + } + + override suspend fun popBackStack() { + _popBackStack.value = Unit + } + + /** + * @param data The data in String or JSON format to return. + */ + override suspend fun popBackStackWithResult(data: String) { + _onReturnResult.subscriptionCount.first { it > 0 } + _onReturnResult.emit(data) + } +} + +interface NavigationProvider { + val onNavigate: StateFlow + suspend fun navigate(event: NavigateEvent) + fun handledNavigateRequest() + + val onNavResult: StateFlow + fun onNavResult(result: NavResult) + fun handledNavResult() + + val onReturnResult: StateFlow + fun handledReturnResult() + + suspend fun popBackStackWithResult(data: String) + suspend fun popBackStack() +} + +suspend inline fun NavigationProvider.navigate( + key: String, + destination: NavDestination, +): R? { + navigate(NavigateEvent(key, destination)) + + /* + This ensures only one job for a dialog is active at once by cancelling previous jobs when a new + dialog is shown with the same key. + + Must drop the first value because it came from our call to navigate. + */ + return merge( + onNavigate.drop(1).filterNotNull().dropWhile { it.key != key }.map { null }, + onNavResult.filterNotNull() + .dropWhile { it.key != key } + .map { result -> result.data?.let { Json.decodeFromString(it) } }, + ).first() +} + +@Composable +fun SetupNavigation( + navigationProvider: NavigationProviderImpl, + navController: NavHostController, +) { + val navEvent: NavigateEvent? by navigationProvider.onNavigate + .collectAsStateWithLifecycle(null) + + val returnResult: String? by navigationProvider.onReturnResult + .collectAsStateWithLifecycle(null) + + val currentEntry by navController.currentBackStackEntryAsState() + + val popBackStack by navigationProvider.popBackStack.collectAsStateWithLifecycle( + null, + ) + + LaunchedEffect(key1 = popBackStack) { + popBackStack ?: return@LaunchedEffect + + navController.navigateUp() + navigationProvider.handledPop() + } + + LaunchedEffect(returnResult) { + val result = returnResult ?: return@LaunchedEffect + + // Set the result in previous screen. + navController.previousBackStackEntry + ?.savedStateHandle + ?.set("result", result) + + navController.navigateUp() + navigationProvider.handledReturnResult() + } + + LaunchedEffect(currentEntry) { + val currentEntry = currentEntry ?: return@LaunchedEffect + + val requestKey = + currentEntry.savedStateHandle.remove("request_key") + + // If the current screen has a result then handle it. + val data = currentEntry.savedStateHandle.remove("result") + + if (requestKey != null && data != null) { + navigationProvider.onNavResult(NavResult(requestKey, data)) + navigationProvider.handledNavResult() + } + } + + LaunchedEffect(navEvent) { + val navEvent = navEvent ?: return@LaunchedEffect + + if (!navEvent.destination.isCompose) { + return@LaunchedEffect + } + + // Store the request key before navigating. + navController.currentBackStackEntry + ?.savedStateHandle + ?.set("request_key", navEvent.key) + + navController.navigate(navEvent.destination) + + navigationProvider.handledNavigateRequest() + } +} + +/** + * Must call in fragment's onCreate + */ +fun NavigationProvider.setupFragmentNavigation(fragment: Fragment) { + val navigationSavedStateKey = "navigation:${this.javaClass.name}" + + val pendingResultsKeysExtra = "pending_results_keys" + val pendingResultsDestinationsExtra = "pending_results_destinations" + + /** + * Maps request keys to their destination. + */ + val pendingResults = mutableMapOf() + + fragment.savedStateRegistry.registerSavedStateProvider(navigationSavedStateKey) { + bundleOf( + pendingResultsKeysExtra to pendingResults.keys.toTypedArray(), + pendingResultsDestinationsExtra to pendingResults.values.toTypedArray(), + ) + } + + fragment.savedStateRegistry.consumeRestoredStateForKey(navigationSavedStateKey) + ?.let { bundle -> + val oldPendingResultsKeys: Array = + bundle.getStringArray(pendingResultsKeysExtra)!! + + val oldPendingResultsDestinations: Array = + bundle.getStringArray(pendingResultsDestinationsExtra)!! + + oldPendingResultsKeys.forEachIndexed { i, requestKey -> + val destination = oldPendingResultsDestinations[i] + + pendingResults[requestKey] = destination + + fragment.setFragmentResultListener(requestKey) { _, bundle -> + sendNavResultFromBundle(requestKey, destination, bundle) + } + } + } + + onNavigate + .filterNotNull() + .filter { !it.destination.isCompose } + .onEach { event -> + val (requestKey, destination) = event + + pendingResults[requestKey] = destination.id + + fragment.clearFragmentResultListener(requestKey) + + fragment.setFragmentResultListener(requestKey) { _, bundle -> + pendingResults.remove(event.key) + sendNavResultFromBundle(event.key, event.destination.id, bundle) + handledNavResult() + } + + val direction = getDirection(destination, requestKey) + + fragment.findNavController().navigate(direction) + handledNavigateRequest() + }.launchIn(fragment.lifecycleScope) +} + +private fun getDirection(destination: NavDestination<*>, requestKey: String): NavDirections { + return when (destination) { + is NavDestination.ChooseApp -> NavBaseAppDirections.chooseApp( + destination.allowHiddenApps, + requestKey, + ) + + NavDestination.ChooseAppShortcut -> NavBaseAppDirections.chooseAppShortcut(requestKey) + NavDestination.ChooseKeyCode -> NavBaseAppDirections.chooseKeyCode(requestKey) + is NavDestination.ConfigKeyEventAction -> { + val json = destination.action?.let { + Json.encodeToString(it) + } + + NavBaseAppDirections.configKeyEvent(requestKey, json) + } + + is NavDestination.PickCoordinate -> { + val json = destination.result?.let { + Json.encodeToString(it) + } + + NavBaseAppDirections.pickDisplayCoordinate(requestKey, json) + } + + is NavDestination.PickSwipeCoordinate -> { + val json = destination.result?.let { + Json.encodeToString(it) + } + + NavBaseAppDirections.swipePickDisplayCoordinate(requestKey, json) + } + + is NavDestination.PickPinchCoordinate -> { + val json = destination.result?.let { + Json.encodeToString(it) + } + + NavBaseAppDirections.pinchPickDisplayCoordinate(requestKey, json) + } + + is NavDestination.ConfigIntent -> { + val json = destination.result?.let { + Json.encodeToString(it) + } + + NavBaseAppDirections.configIntent(requestKey, json) + } + + is NavDestination.ChooseActivity -> NavBaseAppDirections.chooseActivity(requestKey) + is NavDestination.ChooseSound -> NavBaseAppDirections.chooseSoundFile(requestKey) + + is NavDestination.ChooseBluetoothDevice -> NavBaseAppDirections.chooseBluetoothDevice( + requestKey, + ) + + NavDestination.About -> NavBaseAppDirections.actionGlobalAboutFragment() + NavDestination.Settings -> NavBaseAppDirections.toSettingsFragment() + + NavDestination.ShizukuSettings -> NavBaseAppDirections.toShizukuSettingsFragment() + + else -> throw IllegalArgumentException("Can not find a direction for this destination: $destination") + } +} + +fun NavigationProvider.sendNavResultFromBundle( + requestKey: String, + destinationId: String, + bundle: Bundle, +) { + when (destinationId) { + NavDestination.ID_CHOOSE_APP -> { + val packageName = bundle.getString(ChooseAppFragment.EXTRA_PACKAGE_NAME) + + onNavResult(NavResult(requestKey, Json.encodeToString(packageName!!))) + } + + NavDestination.ID_CHOOSE_APP_SHORTCUT -> { + val json = bundle.getString(ChooseAppShortcutFragment.EXTRA_RESULT) + + onNavResult(NavResult(requestKey, json)) + } + + NavDestination.ID_KEY_CODE -> { + val keyCode = bundle.getInt(ChooseKeyCodeFragment.EXTRA_KEYCODE) + + onNavResult(NavResult(requestKey, Json.encodeToString(keyCode))) + } + + NavDestination.ID_KEY_EVENT -> { + val json = bundle.getString(ConfigKeyEventActionFragment.EXTRA_RESULT)!! + + onNavResult(NavResult(requestKey, json)) + } + + NavDestination.ID_PICK_COORDINATE -> { + val json = bundle.getString(PickDisplayCoordinateFragment.EXTRA_RESULT)!! + + onNavResult(NavResult(requestKey, json)) + } + + NavDestination.ID_PICK_SWIPE_COORDINATE -> { + val json = bundle.getString(SwipePickDisplayCoordinateFragment.EXTRA_RESULT)!! + + onNavResult(NavResult(requestKey, json)) + } + + NavDestination.ID_PICK_PINCH_COORDINATE -> { + val json = bundle.getString(PinchPickDisplayCoordinateFragment.EXTRA_RESULT)!! + + onNavResult(NavResult(requestKey, json)) + } + + NavDestination.ID_CONFIG_INTENT -> { + val json = bundle.getString(ConfigIntentFragment.EXTRA_RESULT)!! + + onNavResult(NavResult(requestKey, json)) + } + + NavDestination.ID_CHOOSE_ACTIVITY -> { + val json = bundle.getString(ChooseActivityFragment.EXTRA_RESULT)!! + + onNavResult(NavResult(requestKey, json)) + } + + NavDestination.ID_CHOOSE_SOUND -> { + val json = bundle.getString(ChooseSoundFileFragment.EXTRA_RESULT)!! + + onNavResult(NavResult(requestKey, json)) + } + + NavDestination.ID_CHOOSE_BLUETOOTH_DEVICE -> { + val address = bundle.getString(ChooseBluetoothDeviceFragment.EXTRA_ADDRESS)!! + val name = bundle.getString(ChooseBluetoothDeviceFragment.EXTRA_NAME)!! + + onNavResult( + NavResult( + requestKey, + Json.encodeToString(BluetoothDeviceInfo(address, name)), + ), + ) + } + } +} diff --git a/app/src/main/java/io/github/sds100/keymapper/util/ui/NavigationUtils.kt b/base/src/main/java/io/github/sds100/keymapper/base/utils/navigation/NavigationUtils.kt similarity index 71% rename from app/src/main/java/io/github/sds100/keymapper/util/ui/NavigationUtils.kt rename to base/src/main/java/io/github/sds100/keymapper/base/utils/navigation/NavigationUtils.kt index 205f2c9215..688e2548e4 100644 --- a/app/src/main/java/io/github/sds100/keymapper/util/ui/NavigationUtils.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/utils/navigation/NavigationUtils.kt @@ -1,12 +1,9 @@ -package io.github.sds100.keymapper.util.ui +package io.github.sds100.keymapper.base.utils.navigation import androidx.lifecycle.LifecycleOwner import androidx.navigation.NavBackStackEntry import androidx.navigation.NavController - -/** - * Created by sds100 on 25/03/2020. - */ +import androidx.navigation.toRoute fun NavBackStackEntry.observeLiveData( lifecycleOwner: LifecycleOwner, @@ -37,3 +34,17 @@ fun NavController.setCurrentDestinationLiveData(key: String, value: T) { getBackStackEntry(it).setLiveData(key, value) } } + +inline fun NavBackStackEntry.handleRouteArgs(block: (R) -> Unit) { + if ( + savedStateHandle.contains("handled_args") + ) { + return + } + + val args = toRoute() + + block(args) + + savedStateHandle["handled_args"] = true +} diff --git a/app/src/main/java/io/github/sds100/keymapper/util/ui/BindingAdapters.kt b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/BindingAdapters.kt similarity index 89% rename from app/src/main/java/io/github/sds100/keymapper/util/ui/BindingAdapters.kt rename to base/src/main/java/io/github/sds100/keymapper/base/utils/ui/BindingAdapters.kt index c8e337507c..004ef3d711 100644 --- a/app/src/main/java/io/github/sds100/keymapper/util/ui/BindingAdapters.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/BindingAdapters.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.util.ui +package io.github.sds100.keymapper.base.utils.ui import android.content.Context import android.content.res.ColorStateList @@ -13,15 +13,8 @@ import com.google.android.material.color.MaterialColors import com.google.android.material.slider.Slider import com.google.android.material.textfield.TextInputLayout import com.google.android.material.textview.MaterialTextView -import io.github.sds100.keymapper.R +import io.github.sds100.keymapper.base.R import io.github.sds100.keymapper.system.url.UrlUtils -import io.github.sds100.keymapper.util.str -import io.github.sds100.keymapper.util.styledColor -import io.github.sds100.keymapper.util.styledFloat - -/** - * Created by sds100 on 25/01/2020. - */ @BindingAdapter("app:onTextChanged") fun EditText.onTextChangedListener(textWatcher: TextWatcher) { @@ -116,7 +109,7 @@ fun View.enabled(isEnabled: Boolean) { fun TintType.toColor(ctx: Context): Int? = when (this) { TintType.None -> null - TintType.OnSurface -> ctx.styledColor(R.attr.colorOnSurface) - TintType.Error -> ctx.styledColor(R.attr.colorError) + TintType.OnSurface -> ctx.color(R.color.md_theme_onSurface) + TintType.Error -> ctx.color(R.color.md_theme_error) is TintType.Color -> this.color } diff --git a/app/src/main/java/io/github/sds100/keymapper/util/ui/CheckBoxListItem.kt b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/CheckBoxListItem.kt similarity index 71% rename from app/src/main/java/io/github/sds100/keymapper/util/ui/CheckBoxListItem.kt rename to base/src/main/java/io/github/sds100/keymapper/base/utils/ui/CheckBoxListItem.kt index 1c1f8a04ae..e14210c6e1 100644 --- a/app/src/main/java/io/github/sds100/keymapper/util/ui/CheckBoxListItem.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/CheckBoxListItem.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.util.ui +package io.github.sds100.keymapper.base.utils.ui data class CheckBoxListItem( override val id: String, diff --git a/app/src/main/java/io/github/sds100/keymapper/util/ui/ChooseAppStoreModel.kt b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/ChooseAppStoreModel.kt similarity index 63% rename from app/src/main/java/io/github/sds100/keymapper/util/ui/ChooseAppStoreModel.kt rename to base/src/main/java/io/github/sds100/keymapper/base/utils/ui/ChooseAppStoreModel.kt index 5d724df2ab..e243c84ba7 100644 --- a/app/src/main/java/io/github/sds100/keymapper/util/ui/ChooseAppStoreModel.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/ChooseAppStoreModel.kt @@ -1,8 +1,5 @@ -package io.github.sds100.keymapper.util.ui +package io.github.sds100.keymapper.base.utils.ui -/** - * Created by sds100 on 24/07/20. - */ data class ChooseAppStoreModel( val playStoreLink: String? = null, val fdroidLink: String? = null, diff --git a/app/src/main/java/io/github/sds100/keymapper/util/ui/DefaultSimpleListItem.kt b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/DefaultSimpleListItem.kt similarity index 87% rename from app/src/main/java/io/github/sds100/keymapper/util/ui/DefaultSimpleListItem.kt rename to base/src/main/java/io/github/sds100/keymapper/base/utils/ui/DefaultSimpleListItem.kt index d633ca5e3f..5a69457b35 100644 --- a/app/src/main/java/io/github/sds100/keymapper/util/ui/DefaultSimpleListItem.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/DefaultSimpleListItem.kt @@ -1,8 +1,5 @@ -package io.github.sds100.keymapper.util.ui +package io.github.sds100.keymapper.base.utils.ui -/** - * Created by sds100 on 22/07/2021. - */ data class DefaultSimpleListItem( override val id: String, override val title: String, diff --git a/app/src/main/java/io/github/sds100/keymapper/util/ui/PopupUi.kt b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/DialogModel.kt similarity index 72% rename from app/src/main/java/io/github/sds100/keymapper/util/ui/PopupUi.kt rename to base/src/main/java/io/github/sds100/keymapper/base/utils/ui/DialogModel.kt index cb42104ded..40c359c0f3 100644 --- a/app/src/main/java/io/github/sds100/keymapper/util/ui/PopupUi.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/DialogModel.kt @@ -1,26 +1,22 @@ -package io.github.sds100.keymapper.util.ui +package io.github.sds100.keymapper.base.utils.ui -/** - * Created by sds100 on 23/03/2021. - */ - -sealed class PopupUi { +sealed class DialogModel { data class SnackBar( val message: String, val long: Boolean = false, val actionText: String? = null, - ) : PopupUi() + ) : DialogModel() - data class Ok(val message: String, val title: String? = null) : PopupUi() + data class Ok(val message: String, val title: String? = null) : DialogModel() - data class Dialog( + data class Alert( val title: CharSequence? = null, val message: CharSequence, val positiveButtonText: CharSequence, val neutralButtonText: CharSequence? = null, val negativeButtonText: CharSequence? = null, - ) : PopupUi() + ) : DialogModel() data class Text( val hint: String, @@ -29,15 +25,15 @@ sealed class PopupUi { val inputType: Int? = null, val message: CharSequence? = null, val autoCompleteEntries: List = emptyList(), - ) : PopupUi() + ) : DialogModel() data class SingleChoice( val items: List>, - ) : PopupUi() + ) : DialogModel() - data class MultiChoice(val items: List>) : PopupUi>() + data class MultiChoice(val items: List>) : DialogModel>() - data class Toast(val text: String) : PopupUi() + data class Toast(val text: String) : DialogModel() data class ChooseAppStore( val title: CharSequence, @@ -45,9 +41,9 @@ sealed class PopupUi { val model: ChooseAppStoreModel, val positiveButtonText: CharSequence? = null, val negativeButtonText: CharSequence? = null, - ) : PopupUi() + ) : DialogModel() - data class OpenUrl(val url: String) : PopupUi() + data class OpenUrl(val url: String) : DialogModel() } enum class DialogResponse { diff --git a/app/src/main/java/io/github/sds100/keymapper/util/ui/PopupViewModel.kt b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/DialogProvider.kt similarity index 68% rename from app/src/main/java/io/github/sds100/keymapper/util/ui/PopupViewModel.kt rename to base/src/main/java/io/github/sds100/keymapper/base/utils/ui/DialogProvider.kt index a3c93d37cf..3e65e66f17 100644 --- a/app/src/main/java/io/github/sds100/keymapper/util/ui/PopupViewModel.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/DialogProvider.kt @@ -1,8 +1,9 @@ -package io.github.sds100.keymapper.util.ui +package io.github.sds100.keymapper.base.utils.ui import android.content.Context import android.view.LayoutInflater import android.view.View +import android.widget.Toast import androidx.databinding.ViewDataBinding import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentActivity @@ -10,10 +11,9 @@ import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleObserver import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.OnLifecycleEvent -import io.github.sds100.keymapper.R -import io.github.sds100.keymapper.databinding.DialogChooseAppStoreBinding +import io.github.sds100.keymapper.base.R +import io.github.sds100.keymapper.base.databinding.DialogChooseAppStoreBinding import io.github.sds100.keymapper.system.url.UrlUtils -import io.github.sds100.keymapper.util.launchRepeatOnLifecycle import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.SharedFlow import kotlinx.coroutines.flow.asSharedFlow @@ -24,89 +24,87 @@ import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.merge import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.runBlocking -import splitties.toast.toast +import javax.inject.Inject +import javax.inject.Singleton -/** - * Created by sds100 on 23/03/2021. - */ +@Singleton +class DialogProviderImpl @Inject constructor() : DialogProvider { -class PopupViewModelImpl : PopupViewModel { - - private val _onUserResponse by lazy { MutableSharedFlow() } + private val _onUserResponse by lazy { MutableSharedFlow() } override val onUserResponse by lazy { _onUserResponse.asSharedFlow() } - private val getUserResponse by lazy { MutableSharedFlow() } - override val showPopup by lazy { getUserResponse.asSharedFlow() } + private val getUserResponse by lazy { MutableSharedFlow() } + override val showDialog by lazy { getUserResponse.asSharedFlow() } - override suspend fun showPopup(event: ShowPopupEvent) { + override suspend fun showDialog(event: ShowDialogEvent) { // wait for the view to collect so no dialogs are missed getUserResponse.subscriptionCount.first { it > 0 } getUserResponse.emit(event) } - override fun onUserResponse(event: OnPopupResponseEvent) { + override fun onUserResponse(event: OnDialogResponseEvent) { runBlocking { _onUserResponse.emit(event) } } } -interface PopupViewModel { - val showPopup: SharedFlow - val onUserResponse: SharedFlow +interface DialogProvider { + val showDialog: SharedFlow + val onUserResponse: SharedFlow - suspend fun showPopup(event: ShowPopupEvent) - fun onUserResponse(event: OnPopupResponseEvent) + suspend fun showDialog(event: ShowDialogEvent) + fun onUserResponse(event: OnDialogResponseEvent) } -fun PopupViewModel.onUserResponse(key: String, response: Any?) { - onUserResponse(OnPopupResponseEvent(key, response)) +fun DialogProvider.onUserResponse(key: String, response: Any?) { + onUserResponse(OnDialogResponseEvent(key, response)) } -suspend inline fun PopupViewModel.showPopup( +suspend inline fun DialogProvider.showDialog( key: String, - ui: PopupUi, + ui: DialogModel, ): R? { - showPopup(ShowPopupEvent(key, ui)) + showDialog(ShowDialogEvent(key, ui)) /* This ensures only one job for a dialog is active at once by cancelling previous jobs when a new dialog is shown with the same key */ return merge( - showPopup.dropWhile { it.key != key }.map { null }, + showDialog.dropWhile { it.key != key }.map { null }, onUserResponse.dropWhile { it.response !is R? && it.key != key }.map { it.response }, ).first() as R? } -fun PopupViewModel.showPopups( +fun DialogProvider.showDialogs( fragment: Fragment, binding: ViewDataBinding, ) { - showPopups(fragment.requireContext(), fragment.viewLifecycleOwner, binding.root) + showDialogs(fragment.requireContext(), fragment.viewLifecycleOwner, binding.root) } -fun PopupViewModel.showPopups( +fun DialogProvider.showDialogs( fragment: Fragment, rootView: View, ) { - showPopups(fragment.requireContext(), fragment.viewLifecycleOwner, rootView) + showDialogs(fragment.requireContext(), fragment.viewLifecycleOwner, rootView) } -fun PopupViewModel.showPopups( +fun DialogProvider.showDialogs( activity: FragmentActivity, rootView: View, ) { - showPopups(activity, activity, rootView) + showDialogs(activity, activity, rootView) } -fun PopupViewModel.showPopups( +fun DialogProvider.showDialogs( ctx: Context, lifecycleOwner: LifecycleOwner, rootView: View, ) { // must be onCreate because dismissing in onDestroy lifecycleOwner.launchRepeatOnLifecycle(Lifecycle.State.CREATED) { - showPopup.onEach { event -> + showDialog.onEach { event -> var responded = false val observer = object : LifecycleObserver { @@ -125,16 +123,16 @@ fun PopupViewModel.showPopups( val response: Any? when (event.ui) { - is PopupUi.Ok -> + is DialogModel.Ok -> response = ctx.okDialog(lifecycleOwner, event.ui.message, event.ui.title) - is PopupUi.MultiChoice<*> -> + is DialogModel.MultiChoice<*> -> response = ctx.multiChoiceDialog(lifecycleOwner, event.ui.items) - is PopupUi.SingleChoice<*> -> + is DialogModel.SingleChoice<*> -> response = ctx.singleChoiceDialog(lifecycleOwner, event.ui.items) - is PopupUi.SnackBar -> + is DialogModel.SnackBar -> response = SnackBarUtils.show( rootView.findViewById(R.id.coordinatorLayout), event.ui.message, @@ -142,7 +140,7 @@ fun PopupViewModel.showPopups( event.ui.long, ) - is PopupUi.Text -> + is DialogModel.Text -> response = ctx.editTextStringAlertDialog( lifecycleOwner, event.ui.hint, @@ -153,15 +151,15 @@ fun PopupViewModel.showPopups( event.ui.autoCompleteEntries, ) - is PopupUi.Dialog -> + is DialogModel.Alert -> response = ctx.materialAlertDialog(lifecycleOwner, event.ui) - is PopupUi.Toast -> { - ctx.toast(event.ui.text) + is DialogModel.Toast -> { + Toast.makeText(ctx, event.ui.text, Toast.LENGTH_SHORT).show() response = Unit } - is PopupUi.ChooseAppStore -> { + is DialogModel.ChooseAppStore -> { val view = DialogChooseAppStoreBinding.inflate(LayoutInflater.from(ctx)).apply { model = event.ui.model }.root @@ -176,7 +174,7 @@ fun PopupViewModel.showPopups( ) } - is PopupUi.OpenUrl -> { + is DialogModel.OpenUrl -> { UrlUtils.openUrl(ctx, event.ui.url) response = Unit } diff --git a/app/src/main/java/io/github/sds100/keymapper/util/ui/DialogUtils.kt b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/DialogUtils.kt similarity index 73% rename from app/src/main/java/io/github/sds100/keymapper/util/ui/DialogUtils.kt rename to base/src/main/java/io/github/sds100/keymapper/base/utils/ui/DialogUtils.kt index f805bde891..c3d465875c 100644 --- a/app/src/main/java/io/github/sds100/keymapper/util/ui/DialogUtils.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/DialogUtils.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.util.ui +package io.github.sds100.keymapper.base.utils.ui import android.app.Dialog import android.content.Context @@ -12,23 +12,12 @@ import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.OnLifecycleEvent import androidx.lifecycle.lifecycleScope import com.google.android.material.textfield.TextInputLayout -import io.github.sds100.keymapper.R -import io.github.sds100.keymapper.ServiceLocator -import io.github.sds100.keymapper.databinding.DialogEdittextNumberBinding -import io.github.sds100.keymapper.databinding.DialogEdittextStringBinding -import io.github.sds100.keymapper.util.Error -import io.github.sds100.keymapper.util.Result -import io.github.sds100.keymapper.util.Success -import io.github.sds100.keymapper.util.errorOrNull -import io.github.sds100.keymapper.util.getFullMessage -import io.github.sds100.keymapper.util.isSuccess -import io.github.sds100.keymapper.util.launchRepeatOnLifecycle -import io.github.sds100.keymapper.util.onSuccess -import io.github.sds100.keymapper.util.resumeIfNotCompleted +import io.github.sds100.keymapper.base.R +import io.github.sds100.keymapper.base.databinding.DialogEdittextStringBinding +import io.github.sds100.keymapper.common.utils.resumeIfNotCompleted import kotlinx.coroutines.CancellableContinuation import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.collectLatest -import kotlinx.coroutines.flow.map import kotlinx.coroutines.suspendCancellableCoroutine import splitties.alertdialog.appcompat.message import splitties.alertdialog.appcompat.negativeButton @@ -37,13 +26,9 @@ import splitties.alertdialog.appcompat.title import splitties.alertdialog.material.materialAlertDialog import kotlin.coroutines.resume -/** - * Created by sds100 on 30/03/2020. - */ - suspend fun Context.materialAlertDialog( lifecycleOwner: LifecycleOwner, - model: PopupUi.Dialog, + model: DialogModel.Alert, ) = suspendCancellableCoroutine { continuation -> materialAlertDialog { @@ -240,76 +225,6 @@ suspend fun Context.editTextStringAlertDialog( } } -suspend fun Context.editTextNumberAlertDialog( - lifecycleOwner: LifecycleOwner, - hint: String, - min: Int? = null, - max: Int? = null, -) = suspendCancellableCoroutine { continuation -> - - fun isValid(text: String?): Result { - if (text.isNullOrBlank()) { - return Error.InvalidNumber - } - - return try { - val num = text.toInt() - - min?.let { - if (num < min) { - return Error.NumberTooSmall(min) - } - } - - max?.let { - if (num > max) { - return Error.NumberTooBig(max) - } - } - - Success(num) - } catch (e: NumberFormatException) { - Error.InvalidNumber - } - } - - val resourceProvider = ServiceLocator.resourceProvider(this) - val text = MutableStateFlow("") - - val inflater = LayoutInflater.from(this@editTextNumberAlertDialog) - val binding = DialogEdittextNumberBinding.inflate(inflater).apply { - setHint(hint) - setText(text) - } - - val alertDialog = materialAlertDialog { - okButton { - isValid(text.value).onSuccess { num -> - continuation.resume(num) - } - } - - negativeButton(R.string.neg_cancel) { it.cancel() } - - setView(binding.root) - } - - alertDialog.show() - alertDialog.resumeNullOnDismiss(continuation) - alertDialog.dismissOnDestroy(lifecycleOwner) - - lifecycleOwner.launchRepeatOnLifecycle(Lifecycle.State.RESUMED) { - text.map { isValid(it) } - .collectLatest { isValid -> - alertDialog.getButton(AlertDialog.BUTTON_POSITIVE).isEnabled = - isValid.isSuccess - - binding.textInputLayout.error = - isValid.errorOrNull()?.getFullMessage(resourceProvider) - } - } -} - suspend fun Context.okDialog( lifecycleOwner: LifecycleOwner, message: String, diff --git a/app/src/main/java/io/github/sds100/keymapper/util/ui/EpoxyRecyclerViewModelHelper.kt b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/EpoxyRecyclerViewModelHelper.kt similarity index 79% rename from app/src/main/java/io/github/sds100/keymapper/util/ui/EpoxyRecyclerViewModelHelper.kt rename to base/src/main/java/io/github/sds100/keymapper/base/utils/ui/EpoxyRecyclerViewModelHelper.kt index 557c50b15d..e41a0ec9b4 100644 --- a/app/src/main/java/io/github/sds100/keymapper/util/ui/EpoxyRecyclerViewModelHelper.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/EpoxyRecyclerViewModelHelper.kt @@ -1,12 +1,8 @@ -package io.github.sds100.keymapper.util.ui +package io.github.sds100.keymapper.base.utils.ui import com.airbnb.epoxy.EpoxyController -import io.github.sds100.keymapper.checkbox -import io.github.sds100.keymapper.databinding.ListItemCheckboxBinding - -/** - * Created by sds100 on 20/03/2021. - */ +import io.github.sds100.keymapper.base.checkbox +import io.github.sds100.keymapper.base.databinding.ListItemCheckboxBinding fun EpoxyController.configuredCheckBox( model: CheckBoxListItem, diff --git a/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/ISearchable.kt b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/ISearchable.kt new file mode 100644 index 0000000000..5d9ee34efe --- /dev/null +++ b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/ISearchable.kt @@ -0,0 +1,5 @@ +package io.github.sds100.keymapper.base.utils.ui + +interface ISearchable { + fun getSearchableString(): String +} diff --git a/app/src/main/java/io/github/sds100/keymapper/util/ui/IconInfo.kt b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/IconInfo.kt similarity index 59% rename from app/src/main/java/io/github/sds100/keymapper/util/ui/IconInfo.kt rename to base/src/main/java/io/github/sds100/keymapper/base/utils/ui/IconInfo.kt index 0e105a16ef..63790b11e8 100644 --- a/app/src/main/java/io/github/sds100/keymapper/util/ui/IconInfo.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/IconInfo.kt @@ -1,8 +1,5 @@ -package io.github.sds100.keymapper.util.ui +package io.github.sds100.keymapper.base.utils.ui import android.graphics.drawable.Drawable -/** - * Created by sds100 on 18/03/2021. - */ data class IconInfo(val drawable: Drawable, val tintType: TintType = TintType.None) diff --git a/app/src/main/java/io/github/sds100/keymapper/util/CoroutineUtils.kt b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/LifecycleUtils.kt similarity index 60% rename from app/src/main/java/io/github/sds100/keymapper/util/CoroutineUtils.kt rename to base/src/main/java/io/github/sds100/keymapper/base/utils/ui/LifecycleUtils.kt index 2177f9c972..e4ce0e7e0e 100644 --- a/app/src/main/java/io/github/sds100/keymapper/util/CoroutineUtils.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/LifecycleUtils.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.util +package io.github.sds100.keymapper.base.utils.ui import androidx.fragment.app.Fragment import androidx.lifecycle.Lifecycle @@ -7,17 +7,8 @@ import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.coroutineScope import androidx.lifecycle.lifecycleScope import androidx.lifecycle.repeatOnLifecycle -import kotlinx.coroutines.CancellableContinuation import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.first import kotlinx.coroutines.launch -import kotlinx.coroutines.runBlocking -import kotlin.coroutines.resume - -/** - * Created by sds100 on 18/11/20. - */ val Fragment.viewLifecycleScope: LifecycleCoroutineScope get() = viewLifecycleOwner.lifecycle.coroutineScope @@ -30,11 +21,3 @@ fun LifecycleOwner.launchRepeatOnLifecycle( this@launchRepeatOnLifecycle.repeatOnLifecycle(state, block) } } - -fun CancellableContinuation.resumeIfNotCompleted(value: T) { - if (!this.isCompleted) { - this.resume(value) - } -} - -fun Flow.firstBlocking(): T = runBlocking { first() } diff --git a/app/src/main/java/io/github/sds100/keymapper/util/ui/LinkType.kt b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/LinkType.kt similarity index 54% rename from app/src/main/java/io/github/sds100/keymapper/util/ui/LinkType.kt rename to base/src/main/java/io/github/sds100/keymapper/base/utils/ui/LinkType.kt index b5034e3f55..c87246d622 100644 --- a/app/src/main/java/io/github/sds100/keymapper/util/ui/LinkType.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/LinkType.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.util.ui +package io.github.sds100.keymapper.base.utils.ui enum class LinkType { HIDDEN, diff --git a/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/ListItem.kt b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/ListItem.kt new file mode 100644 index 0000000000..06f5600943 --- /dev/null +++ b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/ListItem.kt @@ -0,0 +1,5 @@ +package io.github.sds100.keymapper.base.utils.ui + +interface ListItem { + val id: String +} diff --git a/app/src/main/java/io/github/sds100/keymapper/util/ui/MultiChoiceItem.kt b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/MultiChoiceItem.kt similarity index 53% rename from app/src/main/java/io/github/sds100/keymapper/util/ui/MultiChoiceItem.kt rename to base/src/main/java/io/github/sds100/keymapper/base/utils/ui/MultiChoiceItem.kt index b8c7f6c778..1eb06e5859 100644 --- a/app/src/main/java/io/github/sds100/keymapper/util/ui/MultiChoiceItem.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/MultiChoiceItem.kt @@ -1,6 +1,3 @@ -package io.github.sds100.keymapper.util.ui +package io.github.sds100.keymapper.base.utils.ui -/** - * Created by sds100 on 26/07/2021. - */ data class MultiChoiceItem(val id: ID, val label: String, val isChecked: Boolean = false) diff --git a/app/src/main/java/io/github/sds100/keymapper/util/ui/MultiSelectProvider.kt b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/MultiSelectProvider.kt similarity index 96% rename from app/src/main/java/io/github/sds100/keymapper/util/ui/MultiSelectProvider.kt rename to base/src/main/java/io/github/sds100/keymapper/base/utils/ui/MultiSelectProvider.kt index 27050a2a91..2dcd672b1a 100644 --- a/app/src/main/java/io/github/sds100/keymapper/util/ui/MultiSelectProvider.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/MultiSelectProvider.kt @@ -1,12 +1,8 @@ -package io.github.sds100.keymapper.util.ui +package io.github.sds100.keymapper.base.utils.ui import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.update -/** - * Created by sds100 on 11/02/2020. - */ - class MultiSelectProvider { private val lock = Any() val state = MutableStateFlow(SelectionState.NotSelecting) diff --git a/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/OnDialogResponseEvent.kt b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/OnDialogResponseEvent.kt new file mode 100644 index 0000000000..db31c57486 --- /dev/null +++ b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/OnDialogResponseEvent.kt @@ -0,0 +1,3 @@ +package io.github.sds100.keymapper.base.utils.ui + +data class OnDialogResponseEvent(val key: String, val response: Any?) diff --git a/app/src/main/java/io/github/sds100/keymapper/util/ui/RadioButtonPairListItem.kt b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/RadioButtonPairListItem.kt similarity index 77% rename from app/src/main/java/io/github/sds100/keymapper/util/ui/RadioButtonPairListItem.kt rename to base/src/main/java/io/github/sds100/keymapper/base/utils/ui/RadioButtonPairListItem.kt index d7f7cd8f74..353b9dd2b4 100644 --- a/app/src/main/java/io/github/sds100/keymapper/util/ui/RadioButtonPairListItem.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/RadioButtonPairListItem.kt @@ -1,8 +1,5 @@ -package io.github.sds100.keymapper.util.ui +package io.github.sds100.keymapper.base.utils.ui -/** - * Created by sds100 on 12/04/2021. - */ data class RadioButtonPairListItem( override val id: String, val header: String, diff --git a/app/src/main/java/io/github/sds100/keymapper/util/ui/RadioButtonTripleListItem.kt b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/RadioButtonTripleListItem.kt similarity index 82% rename from app/src/main/java/io/github/sds100/keymapper/util/ui/RadioButtonTripleListItem.kt rename to base/src/main/java/io/github/sds100/keymapper/base/utils/ui/RadioButtonTripleListItem.kt index 451b14d096..810c560bda 100644 --- a/app/src/main/java/io/github/sds100/keymapper/util/ui/RadioButtonTripleListItem.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/RadioButtonTripleListItem.kt @@ -1,8 +1,5 @@ -package io.github.sds100.keymapper.util.ui +package io.github.sds100.keymapper.base.utils.ui -/** - * Created by sds100 on 12/04/2021. - */ data class RadioButtonTripleListItem( override val id: String, val header: String, diff --git a/app/src/main/java/io/github/sds100/keymapper/util/ui/RecyclerViewFragment.kt b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/RecyclerViewFragment.kt similarity index 97% rename from app/src/main/java/io/github/sds100/keymapper/util/ui/RecyclerViewFragment.kt rename to base/src/main/java/io/github/sds100/keymapper/base/utils/ui/RecyclerViewFragment.kt index a0588ac7e0..937b7b37a2 100644 --- a/app/src/main/java/io/github/sds100/keymapper/util/ui/RecyclerViewFragment.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/RecyclerViewFragment.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.util.ui +package io.github.sds100.keymapper.base.utils.ui import android.os.Bundle import android.view.LayoutInflater @@ -19,15 +19,12 @@ import androidx.navigation.fragment.findNavController import androidx.savedstate.SavedStateRegistry import com.airbnb.epoxy.EpoxyRecyclerView import com.google.android.material.bottomappbar.BottomAppBar -import io.github.sds100.keymapper.R -import io.github.sds100.keymapper.util.State -import io.github.sds100.keymapper.util.launchRepeatOnLifecycle +import io.github.sds100.keymapper.base.R +import io.github.sds100.keymapper.base.utils.navigation.observeCurrentDestinationLiveData +import io.github.sds100.keymapper.common.utils.State import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.collectLatest -/** - * Created by sds100 on 22/02/2020. - */ abstract class RecyclerViewFragment : Fragment() { companion object { diff --git a/app/src/main/java/io/github/sds100/keymapper/util/ui/RecyclerViewUtils.kt b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/RecyclerViewUtils.kt similarity index 92% rename from app/src/main/java/io/github/sds100/keymapper/util/ui/RecyclerViewUtils.kt rename to base/src/main/java/io/github/sds100/keymapper/base/utils/ui/RecyclerViewUtils.kt index 3d029f4e20..692bfe9efe 100644 --- a/app/src/main/java/io/github/sds100/keymapper/util/ui/RecyclerViewUtils.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/RecyclerViewUtils.kt @@ -1,16 +1,12 @@ -package io.github.sds100.keymapper.util.ui +package io.github.sds100.keymapper.base.utils.ui import android.graphics.Rect import android.view.View import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.RecyclerView -import io.github.sds100.keymapper.R +import io.github.sds100.keymapper.base.R import kotlin.math.floor -/** - * Created by sds100 on 26/07/2021. - */ - object RecyclerViewUtils { fun applySimpleListItemDecorations(recyclerView: RecyclerView) { val itemPadding = recyclerView.resources.getDimensionPixelSize(R.dimen.grid_padding) diff --git a/app/src/main/java/io/github/sds100/keymapper/util/ui/ResourceExt.kt b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/ResourceExt.kt similarity index 88% rename from app/src/main/java/io/github/sds100/keymapper/util/ui/ResourceExt.kt rename to base/src/main/java/io/github/sds100/keymapper/base/utils/ui/ResourceExt.kt index 724e99aaa6..59789c69af 100644 --- a/app/src/main/java/io/github/sds100/keymapper/util/ui/ResourceExt.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/ResourceExt.kt @@ -1,9 +1,10 @@ -package io.github.sds100.keymapper.util +package io.github.sds100.keymapper.base.utils.ui import android.content.Context import android.content.res.ColorStateList import android.content.res.TypedArray import android.graphics.drawable.Drawable +import android.os.Looper import android.util.AttributeSet import android.view.View import androidx.annotation.ArrayRes @@ -20,22 +21,14 @@ import androidx.core.content.ContextCompat import androidx.core.content.res.getResourceIdOrThrow import androidx.fragment.app.Fragment import com.google.android.material.color.MaterialColors -import splitties.mainthread.isMainThread - -/** - * Created by sds100 on 17/05/2020. - */ // Using varargs doesn't work since prints [LJava.lang.object@32f...etc fun Context.str(@StringRes resId: Int, formatArg: Any? = null): String = getString(resId, formatArg) -fun Context.str(@StringRes resId: Int, formatArgArray: Array): String = - getString(resId, *formatArgArray) +fun Context.str(@StringRes resId: Int, formatArgArray: Array): String = getString(resId, *formatArgArray) -fun View.str(@StringRes resId: Int, formatArgs: Any? = null): String = - context.str(resId, formatArgs) +fun View.str(@StringRes resId: Int, formatArgs: Any? = null): String = context.str(resId, formatArgs) -fun Fragment.str(@StringRes resId: Int, formatArgs: Any? = null): String = - requireContext().str(resId, formatArgs) +fun Fragment.str(@StringRes resId: Int, formatArgs: Any? = null): String = requireContext().str(resId, formatArgs) fun Context.strArray(@ArrayRes resId: Int): Array = resources.getStringArray(resId) fun Fragment.strArray(@ArrayRes resId: Int): Array = requireContext().strArray(resId) @@ -118,14 +111,12 @@ fun View.str( attributeSet: AttributeSet, @StyleableRes styleableId: IntArray, @StyleableRes attrId: Int, -) = - context.str(attributeSet, styleableId, attrId) +) = context.str(attributeSet, styleableId, attrId) /** * Get a resource drawable. Can be safely used to get vector drawables on pre-lollipop. */ -fun Context.drawable(@DrawableRes resId: Int): Drawable = - AppCompatResources.getDrawable(this, resId)!! +fun Context.drawable(@DrawableRes resId: Int): Drawable = AppCompatResources.getDrawable(this, resId)!! fun View.drawable(@DrawableRes resId: Int): Drawable = context.drawable(resId) fun Fragment.drawable(@DrawableRes resId: Int): Drawable = requireContext().drawable(resId) @@ -140,11 +131,9 @@ fun Context.color(@ColorRes resId: Int, harmonize: Boolean = false): Int { } } -fun View.color(@ColorRes resId: Int, harmonize: Boolean = false): Int = - context.color(resId, harmonize) +fun View.color(@ColorRes resId: Int, harmonize: Boolean = false): Int = context.color(resId, harmonize) -fun Fragment.color(@ColorRes resId: Int, harmonize: Boolean = false): Int = - requireContext().color(resId, harmonize) +fun Fragment.color(@ColorRes resId: Int, harmonize: Boolean = false): Int = requireContext().color(resId, harmonize) @ColorInt fun Context.styledColor(@AttrRes attr: Int) = withStyledAttributes(attr) { getColor(it, 0) } @@ -164,14 +153,12 @@ fun Fragment.int(@IntegerRes resId: Int) = requireContext().int(resId) fun Context.intArray(@ArrayRes resId: Int): IntArray = resources.getIntArray(resId) fun Fragment.intArray(@ArrayRes resId: Int): IntArray = resources.getIntArray(resId) -fun Context.styledColorSL(@AttrRes attr: Int): ColorStateList? = - withStyledAttributes(attr) { getColorStateList(it) } +fun Context.styledColorSL(@AttrRes attr: Int): ColorStateList? = withStyledAttributes(attr) { getColorStateList(it) } fun Fragment.styledColorSL(@AttrRes attr: Int) = context!!.styledColorSL(attr) fun View.styledColorSL(@AttrRes attr: Int) = context.styledColorSL(attr) -fun Context.colorSl(@ColorRes color: Int): ColorStateList? = - ContextCompat.getColorStateList(this, color) +fun Context.colorSl(@ColorRes color: Int): ColorStateList? = ContextCompat.getColorStateList(this, color) fun View.colorSl(@ColorRes color: Int) = context.colorSl(color) @@ -185,7 +172,7 @@ inline fun Context.withStyledAttributes( styledAttrs.func(styledAttrs.getIndex(0)).also { styledAttrs.recycle() } } -fun Context.obtainStyledAttr(@AttrRes attrRes: Int): TypedArray = if (isMainThread) { +fun Context.obtainStyledAttr(@AttrRes attrRes: Int): TypedArray = if (Looper.getMainLooper().isCurrentThread) { uiThreadConfinedCachedAttrArray[0] = attrRes obtainStyledAttributes(uiThreadConfinedCachedAttrArray) } else { diff --git a/app/src/main/java/io/github/sds100/keymapper/util/ui/ResourceProvider.kt b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/ResourceProvider.kt similarity index 84% rename from app/src/main/java/io/github/sds100/keymapper/util/ui/ResourceProvider.kt rename to base/src/main/java/io/github/sds100/keymapper/base/utils/ui/ResourceProvider.kt index a3c90db2cb..ca41420107 100644 --- a/app/src/main/java/io/github/sds100/keymapper/util/ui/ResourceProvider.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/ResourceProvider.kt @@ -1,24 +1,21 @@ -package io.github.sds100.keymapper.util.ui +package io.github.sds100.keymapper.base.utils.ui import android.content.Context import android.graphics.drawable.Drawable import androidx.annotation.ColorRes import androidx.annotation.DrawableRes import androidx.annotation.StringRes -import io.github.sds100.keymapper.util.color -import io.github.sds100.keymapper.util.drawable -import io.github.sds100.keymapper.util.str +import dagger.hilt.android.qualifiers.ApplicationContext import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.launch +import javax.inject.Inject +import javax.inject.Singleton -/** - * Created by sds100 on 21/02/2021. - */ - -class ResourceProviderImpl( - context: Context, +@Singleton +class ResourceProviderImpl @Inject constructor( + @ApplicationContext context: Context, private val coroutineScope: CoroutineScope, ) : ResourceProvider { private val ctx = context.applicationContext diff --git a/app/src/main/java/io/github/sds100/keymapper/util/ui/SectionHeaderListItem.kt b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/SectionHeaderListItem.kt similarity index 50% rename from app/src/main/java/io/github/sds100/keymapper/util/ui/SectionHeaderListItem.kt rename to base/src/main/java/io/github/sds100/keymapper/base/utils/ui/SectionHeaderListItem.kt index 30d3090d60..3b5eb31482 100644 --- a/app/src/main/java/io/github/sds100/keymapper/util/ui/SectionHeaderListItem.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/SectionHeaderListItem.kt @@ -1,6 +1,3 @@ -package io.github.sds100.keymapper.util.ui +package io.github.sds100.keymapper.base.utils.ui -/** - * Created by sds100 on 23/03/2021. - */ data class SectionHeaderListItem(override val id: String, val text: String) : ListItem diff --git a/app/src/main/java/io/github/sds100/keymapper/util/ui/SelectionState.kt b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/SelectionState.kt similarity index 64% rename from app/src/main/java/io/github/sds100/keymapper/util/ui/SelectionState.kt rename to base/src/main/java/io/github/sds100/keymapper/base/utils/ui/SelectionState.kt index cf29ee1db7..43d29e37ae 100644 --- a/app/src/main/java/io/github/sds100/keymapper/util/ui/SelectionState.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/SelectionState.kt @@ -1,8 +1,5 @@ -package io.github.sds100.keymapper.util.ui +package io.github.sds100.keymapper.base.utils.ui -/** - * Created by sds100 on 22/03/2021. - */ sealed class SelectionState { data class Selecting(val selectedIds: Set) : SelectionState() data object NotSelecting : SelectionState() diff --git a/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/ShowDialogEvent.kt b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/ShowDialogEvent.kt new file mode 100644 index 0000000000..67051f04ca --- /dev/null +++ b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/ShowDialogEvent.kt @@ -0,0 +1,3 @@ +package io.github.sds100.keymapper.base.utils.ui + +data class ShowDialogEvent(val key: String, val ui: DialogModel<*>) diff --git a/app/src/main/java/io/github/sds100/keymapper/util/ui/SimpleRecyclerViewFragment.kt b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/SimpleRecyclerViewFragment.kt similarity index 86% rename from app/src/main/java/io/github/sds100/keymapper/util/ui/SimpleRecyclerViewFragment.kt rename to base/src/main/java/io/github/sds100/keymapper/base/utils/ui/SimpleRecyclerViewFragment.kt index e1fcd1c8ae..263f6e8d96 100644 --- a/app/src/main/java/io/github/sds100/keymapper/util/ui/SimpleRecyclerViewFragment.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/SimpleRecyclerViewFragment.kt @@ -1,17 +1,13 @@ -package io.github.sds100.keymapper.util.ui +package io.github.sds100.keymapper.base.utils.ui import android.view.LayoutInflater import android.view.ViewGroup import androidx.annotation.MenuRes import androidx.annotation.StringRes import com.google.android.material.bottomappbar.BottomAppBar -import io.github.sds100.keymapper.R -import io.github.sds100.keymapper.databinding.FragmentSimpleRecyclerviewBinding -import io.github.sds100.keymapper.util.str +import io.github.sds100.keymapper.base.R +import io.github.sds100.keymapper.base.databinding.FragmentSimpleRecyclerviewBinding -/** - * Created by sds100 on 22/02/2020. - */ abstract class SimpleRecyclerViewFragment : RecyclerViewFragment() { @MenuRes diff --git a/app/src/main/java/io/github/sds100/keymapper/util/ui/SliderMaximums.kt b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/SliderMaximums.kt similarity index 84% rename from app/src/main/java/io/github/sds100/keymapper/util/ui/SliderMaximums.kt rename to base/src/main/java/io/github/sds100/keymapper/base/utils/ui/SliderMaximums.kt index ec142983c0..3c221c1e43 100644 --- a/app/src/main/java/io/github/sds100/keymapper/util/ui/SliderMaximums.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/SliderMaximums.kt @@ -1,8 +1,5 @@ -package io.github.sds100.keymapper.util.ui +package io.github.sds100.keymapper.base.utils.ui -/** - * Created by sds100 on 12/04/2021. - */ object SliderMaximums { const val ACTION_MULTIPLIER = 20 const val DELAY_BEFORE_NEXT_ACTION = 2000 diff --git a/app/src/main/java/io/github/sds100/keymapper/util/ui/SliderMinimums.kt b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/SliderMinimums.kt similarity index 82% rename from app/src/main/java/io/github/sds100/keymapper/util/ui/SliderMinimums.kt rename to base/src/main/java/io/github/sds100/keymapper/base/utils/ui/SliderMinimums.kt index b8e7ca53a9..5a4c852b8e 100644 --- a/app/src/main/java/io/github/sds100/keymapper/util/ui/SliderMinimums.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/SliderMinimums.kt @@ -1,8 +1,5 @@ -package io.github.sds100.keymapper.util.ui +package io.github.sds100.keymapper.base.utils.ui -/** - * Created by sds100 on 12/04/2021. - */ object SliderMinimums { const val ACTION_MULTIPLIER = 1 const val DELAY_BEFORE_NEXT_ACTION = 0 diff --git a/app/src/main/java/io/github/sds100/keymapper/util/ui/SliderStepSizes.kt b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/SliderStepSizes.kt similarity index 83% rename from app/src/main/java/io/github/sds100/keymapper/util/ui/SliderStepSizes.kt rename to base/src/main/java/io/github/sds100/keymapper/base/utils/ui/SliderStepSizes.kt index b8969158ae..6777a2bd2f 100644 --- a/app/src/main/java/io/github/sds100/keymapper/util/ui/SliderStepSizes.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/SliderStepSizes.kt @@ -1,8 +1,5 @@ -package io.github.sds100.keymapper.util.ui +package io.github.sds100.keymapper.base.utils.ui -/** - * Created by sds100 on 12/04/2021. - */ object SliderStepSizes { const val ACTION_MULTIPLIER = 1 const val DELAY_BEFORE_NEXT_ACTION = 100 diff --git a/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/SnackBarUtils.kt b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/SnackBarUtils.kt new file mode 100644 index 0000000000..f529e2b017 --- /dev/null +++ b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/SnackBarUtils.kt @@ -0,0 +1,45 @@ +package io.github.sds100.keymapper.base.utils.ui + +import androidx.coordinatorlayout.widget.CoordinatorLayout +import com.google.android.material.snackbar.Snackbar +import io.github.sds100.keymapper.base.R +import kotlinx.coroutines.suspendCancellableCoroutine +import kotlin.coroutines.resume + +object SnackBarUtils { + + suspend fun show( + view: CoordinatorLayout, + text: String, + actionText: String? = null, + long: Boolean = false, + ) = suspendCancellableCoroutine { continuation -> + + val duration = if (long) { + Snackbar.LENGTH_LONG + } else { + Snackbar.LENGTH_SHORT + } + + Snackbar.make(view, text, duration) + .setAnchorView(R.id.fab) + .setAction(actionText, { + if (!continuation.isCompleted) { + continuation.resume(Unit) + } + }) + .addCallback(object : Snackbar.Callback() { + override fun onDismissed(transientBottomBar: Snackbar?, event: Int) { + if (!continuation.isCompleted) { + continuation.resume(null) + } + } + }) + .show() + + // if there is no action then there is no point waiting for a user response + if (actionText == null) { + continuation.resume(null) + } + } +} diff --git a/app/src/main/java/io/github/sds100/keymapper/util/ui/SquareImageButton.kt b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/SquareImageButton.kt similarity index 82% rename from app/src/main/java/io/github/sds100/keymapper/util/ui/SquareImageButton.kt rename to base/src/main/java/io/github/sds100/keymapper/base/utils/ui/SquareImageButton.kt index 63e0dd53a0..6a87f6ca99 100644 --- a/app/src/main/java/io/github/sds100/keymapper/util/ui/SquareImageButton.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/SquareImageButton.kt @@ -1,12 +1,9 @@ -package io.github.sds100.keymapper.util.ui +package io.github.sds100.keymapper.base.utils.ui import android.content.Context import android.util.AttributeSet import androidx.appcompat.widget.AppCompatImageButton -/** - * Created by sds100 on 16/07/2018. - */ class SquareImageButton(context: Context, attrs: AttributeSet?) : AppCompatImageButton(context, attrs) { override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { // have equal sides. diff --git a/app/src/main/java/io/github/sds100/keymapper/util/ui/TextListItem.kt b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/TextListItem.kt similarity index 75% rename from app/src/main/java/io/github/sds100/keymapper/util/ui/TextListItem.kt rename to base/src/main/java/io/github/sds100/keymapper/base/utils/ui/TextListItem.kt index 78a13e2970..ad58334aab 100644 --- a/app/src/main/java/io/github/sds100/keymapper/util/ui/TextListItem.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/TextListItem.kt @@ -1,8 +1,4 @@ -package io.github.sds100.keymapper.util.ui - -/** - * Created by sds100 on 31/03/2021. - */ +package io.github.sds100.keymapper.base.utils.ui sealed class TextListItem : ListItem { data class Success(override val id: String, val text: String) : TextListItem() diff --git a/app/src/main/java/io/github/sds100/keymapper/util/ui/TintType.kt b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/TintType.kt similarity index 73% rename from app/src/main/java/io/github/sds100/keymapper/util/ui/TintType.kt rename to base/src/main/java/io/github/sds100/keymapper/base/utils/ui/TintType.kt index 4740f1bfb7..8a07a9a626 100644 --- a/app/src/main/java/io/github/sds100/keymapper/util/ui/TintType.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/TintType.kt @@ -1,10 +1,7 @@ -package io.github.sds100.keymapper.util.ui +package io.github.sds100.keymapper.base.utils.ui import androidx.annotation.ColorInt -/** - * Created by sds100 on 03/04/2020. - */ sealed class TintType { object None : TintType() object OnSurface : TintType() diff --git a/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/UnsavedChangesDialog.kt b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/UnsavedChangesDialog.kt new file mode 100644 index 0000000000..8342f5b818 --- /dev/null +++ b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/UnsavedChangesDialog.kt @@ -0,0 +1,36 @@ +package io.github.sds100.keymapper.base.utils.ui + +import androidx.compose.material3.AlertDialog +import androidx.compose.material3.Text +import androidx.compose.material3.TextButton +import androidx.compose.runtime.Composable +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview +import io.github.sds100.keymapper.base.R +import io.github.sds100.keymapper.base.compose.KeyMapperTheme + +@Composable +fun UnsavedChangesDialog( + onDismiss: () -> Unit, + onDiscardClick: () -> Unit, +) { + AlertDialog( + onDismissRequest = onDismiss, + title = { Text(stringResource(R.string.dialog_title_unsaved_changes)) }, + text = { Text(stringResource(R.string.dialog_message_unsaved_changes)) }, + confirmButton = { + TextButton(onClick = onDiscardClick) { Text(stringResource(R.string.pos_discard_changes)) } + }, + dismissButton = { + TextButton(onClick = onDismiss) { Text(stringResource(R.string.neg_keep_editing)) } + }, + ) +} + +@Preview +@Composable +private fun Preview() { + KeyMapperTheme { + UnsavedChangesDialog(onDismiss = {}, onDiscardClick = {}) + } +} diff --git a/app/src/main/java/io/github/sds100/keymapper/util/ui/ViewModelHelper.kt b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/ViewModelHelper.kt similarity index 72% rename from app/src/main/java/io/github/sds100/keymapper/util/ui/ViewModelHelper.kt rename to base/src/main/java/io/github/sds100/keymapper/base/utils/ui/ViewModelHelper.kt index 9ed849da43..117e4364cb 100644 --- a/app/src/main/java/io/github/sds100/keymapper/util/ui/ViewModelHelper.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/ViewModelHelper.kt @@ -1,22 +1,20 @@ -package io.github.sds100.keymapper.util.ui +package io.github.sds100.keymapper.base.utils.ui -import io.github.sds100.keymapper.R +import io.github.sds100.keymapper.base.R +import io.github.sds100.keymapper.base.utils.getFullMessage +import io.github.sds100.keymapper.base.utils.isFixable +import io.github.sds100.keymapper.common.utils.KMError +import io.github.sds100.keymapper.system.SystemError import io.github.sds100.keymapper.system.permissions.Permission -import io.github.sds100.keymapper.util.Error -import io.github.sds100.keymapper.util.getFullMessage -import io.github.sds100.keymapper.util.isFixable -/** - * Created by sds100 on 04/11/2021. - */ object ViewModelHelper { suspend fun handleKeyMapperCrashedDialog( resourceProvider: ResourceProvider, - popupViewModel: PopupViewModel, + dialogProvider: DialogProvider, restartService: () -> Boolean, ignoreCrashed: () -> Unit, ) { - val dialog = PopupUi.Dialog( + val dialog = DialogModel.Alert( title = resourceProvider.getString(R.string.dialog_title_key_mapper_crashed), message = resourceProvider.getText(R.string.dialog_message_key_mapper_crashed), positiveButtonText = resourceProvider.getString(R.string.dialog_button_read_dont_kill_my_app_yes), @@ -24,13 +22,13 @@ object ViewModelHelper { neutralButtonText = resourceProvider.getString(R.string.pos_restart), ) - val response = popupViewModel.showPopup("app_crashed_prompt", dialog) ?: return + val response = dialogProvider.showDialog("app_crashed_prompt", dialog) ?: return when (response) { DialogResponse.POSITIVE -> { val popup = - PopupUi.OpenUrl(resourceProvider.getString(R.string.url_dont_kill_my_app)) - popupViewModel.showPopup("dont_kill_my_app", popup) + DialogModel.OpenUrl(resourceProvider.getString(R.string.url_dont_kill_my_app)) + dialogProvider.showDialog("dont_kill_my_app", popup) } DialogResponse.NEGATIVE -> ignoreCrashed() @@ -41,9 +39,9 @@ object ViewModelHelper { suspend fun showAccessibilityServiceExplanationDialog( resourceProvider: ResourceProvider, - popupViewModel: PopupViewModel, + dialogProvider: DialogProvider, ): DialogResponse { - val dialog = PopupUi.Dialog( + val dialog = DialogModel.Alert( title = resourceProvider.getString(R.string.dialog_title_accessibility_service_explanation), message = resourceProvider.getString(R.string.dialog_message_accessibility_service_explanation), positiveButtonText = resourceProvider.getString(R.string.enable), @@ -51,7 +49,7 @@ object ViewModelHelper { ) val response = - popupViewModel.showPopup("accessibility_service_explanation", dialog) + dialogProvider.showDialog("accessibility_service_explanation", dialog) ?: return DialogResponse.NEGATIVE return response @@ -59,9 +57,9 @@ object ViewModelHelper { suspend fun handleCantFindAccessibilitySettings( resourceProvider: ResourceProvider, - popupViewModel: PopupViewModel, + dialogProvider: DialogProvider, ) { - val dialog = PopupUi.Dialog( + val dialog = DialogModel.Alert( title = resourceProvider.getString(R.string.dialog_title_cant_find_accessibility_settings_page), message = resourceProvider.getText(R.string.dialog_message_cant_find_accessibility_settings_page), positiveButtonText = resourceProvider.getString(R.string.pos_start_service_with_adb_guide), @@ -69,93 +67,93 @@ object ViewModelHelper { ) val response = - popupViewModel.showPopup("cant_find_accessibility_settings", dialog) ?: return + dialogProvider.showDialog("cant_find_accessibility_settings", dialog) ?: return if (response == DialogResponse.POSITIVE) { val url = resourceProvider.getString(R.string.url_cant_find_accessibility_settings_issue) - val openUrlPopup = PopupUi.OpenUrl(url) + val openUrlPopup = DialogModel.OpenUrl(url) - popupViewModel.showPopup("url_cant_find_accessibility_settings_issue", openUrlPopup) + dialogProvider.showDialog("url_cant_find_accessibility_settings_issue", openUrlPopup) } } suspend fun handleAccessibilityServiceStoppedDialog( resourceProvider: ResourceProvider, - popupViewModel: PopupViewModel, + dialogProvider: DialogProvider, startService: () -> Boolean, ) { val explanationResponse = - showAccessibilityServiceExplanationDialog(resourceProvider, popupViewModel) + showAccessibilityServiceExplanationDialog(resourceProvider, dialogProvider) if (explanationResponse != DialogResponse.POSITIVE) { return } if (!startService.invoke()) { - handleCantFindAccessibilitySettings(resourceProvider, popupViewModel) + handleCantFindAccessibilitySettings(resourceProvider, dialogProvider) } } suspend fun handleAccessibilityServiceCrashedDialog( resourceProvider: ResourceProvider, - popupViewModel: PopupViewModel, + dialogProvider: DialogProvider, restartService: () -> Boolean, ) { - val dialog = PopupUi.Dialog( + val dialog = DialogModel.Alert( title = resourceProvider.getString(R.string.dialog_title_accessibility_service_explanation), message = resourceProvider.getString(R.string.dialog_message_restart_accessibility_service), positiveButtonText = resourceProvider.getString(R.string.pos_restart), negativeButtonText = resourceProvider.getString(R.string.neg_cancel), ) - val response = popupViewModel.showPopup("accessibility_service_explanation", dialog) + val response = dialogProvider.showDialog("accessibility_service_explanation", dialog) if (response != DialogResponse.POSITIVE) { return } if (!restartService.invoke()) { - handleCantFindAccessibilitySettings(resourceProvider, popupViewModel) + handleCantFindAccessibilitySettings(resourceProvider, dialogProvider) } } suspend fun showFixErrorDialog( resourceProvider: ResourceProvider, - popupViewModel: PopupViewModel, - error: Error, + dialogProvider: DialogProvider, + error: KMError, fixError: suspend () -> Unit, ) { if (error.isFixable) { - val dialog = PopupUi.Dialog( + val dialog = DialogModel.Alert( title = resourceProvider.getString(R.string.dialog_title_home_fix_error), message = error.getFullMessage(resourceProvider), positiveButtonText = resourceProvider.getString(R.string.dialog_button_fix), negativeButtonText = resourceProvider.getText(R.string.neg_cancel), ) - val response = popupViewModel.showPopup("fix_error", dialog) + val response = dialogProvider.showDialog("fix_error", dialog) if (response == DialogResponse.POSITIVE) { fixError.invoke() } } else { - val dialog = PopupUi.Dialog( + val dialog = DialogModel.Alert( message = error.getFullMessage(resourceProvider), positiveButtonText = resourceProvider.getString(R.string.pos_ok), ) - popupViewModel.showPopup("fix_error", dialog) + dialogProvider.showDialog("fix_error", dialog) } } suspend fun showDialogExplainingDndAccessBeingUnavailable( resourceProvider: ResourceProvider, - popupViewModel: PopupViewModel, + dialogProvider: DialogProvider, neverShowDndTriggerErrorAgain: () -> Unit, fixError: suspend () -> Unit, ) { - val dialog = PopupUi.Dialog( + val dialog = DialogModel.Alert( title = resourceProvider.getString(R.string.dialog_title_fix_dnd_trigger_error), message = resourceProvider.getText(R.string.dialog_message_fix_dnd_trigger_error), positiveButtonText = resourceProvider.getString(R.string.pos_ok), @@ -163,10 +161,10 @@ object ViewModelHelper { neutralButtonText = resourceProvider.getString(R.string.neg_dont_show_again), ) - val dialogResponse = popupViewModel.showPopup("fix_dnd_trigger_error", dialog) + val dialogResponse = dialogProvider.showDialog("fix_dnd_trigger_error", dialog) if (dialogResponse == DialogResponse.POSITIVE) { - val error = Error.PermissionDenied(Permission.ACCESS_NOTIFICATION_POLICY) + SystemError.PermissionDenied(Permission.ACCESS_NOTIFICATION_POLICY) fixError.invoke() } else if (dialogResponse == DialogResponse.NEUTRAL) { neverShowDndTriggerErrorAgain.invoke() diff --git a/app/src/main/java/io/github/sds100/keymapper/util/ui/compose/CheckBoxText.kt b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/compose/CheckBoxText.kt similarity index 96% rename from app/src/main/java/io/github/sds100/keymapper/util/ui/compose/CheckBoxText.kt rename to base/src/main/java/io/github/sds100/keymapper/base/utils/ui/compose/CheckBoxText.kt index b476a04113..cbe29ef5af 100644 --- a/app/src/main/java/io/github/sds100/keymapper/util/ui/compose/CheckBoxText.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/compose/CheckBoxText.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.util.ui.compose +package io.github.sds100.keymapper.base.utils.ui.compose import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Row diff --git a/app/src/main/java/io/github/sds100/keymapper/util/ui/compose/CollapsableFloatingActionButton.kt b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/compose/CollapsableFloatingActionButton.kt similarity index 95% rename from app/src/main/java/io/github/sds100/keymapper/util/ui/compose/CollapsableFloatingActionButton.kt rename to base/src/main/java/io/github/sds100/keymapper/base/utils/ui/compose/CollapsableFloatingActionButton.kt index 0da7372e08..706c2299b8 100644 --- a/app/src/main/java/io/github/sds100/keymapper/util/ui/compose/CollapsableFloatingActionButton.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/compose/CollapsableFloatingActionButton.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.util.ui.compose +package io.github.sds100.keymapper.base.utils.ui.compose import androidx.compose.animation.AnimatedContent import androidx.compose.animation.AnimatedVisibility diff --git a/app/src/main/java/io/github/sds100/keymapper/util/ui/compose/CompactChip.kt b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/compose/CompactChip.kt similarity index 96% rename from app/src/main/java/io/github/sds100/keymapper/util/ui/compose/CompactChip.kt rename to base/src/main/java/io/github/sds100/keymapper/base/utils/ui/compose/CompactChip.kt index e669f1733d..226b93841f 100644 --- a/app/src/main/java/io/github/sds100/keymapper/util/ui/compose/CompactChip.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/compose/CompactChip.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.util.ui.compose +package io.github.sds100.keymapper.base.utils.ui.compose import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer @@ -21,7 +21,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp -import io.github.sds100.keymapper.keymaps.chipHeight +import io.github.sds100.keymapper.base.keymaps.chipHeight @Composable fun CompactChip( diff --git a/app/src/main/java/io/github/sds100/keymapper/util/ui/compose/ComposeChipModel.kt b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/compose/ComposeChipModel.kt similarity index 76% rename from app/src/main/java/io/github/sds100/keymapper/util/ui/compose/ComposeChipModel.kt rename to base/src/main/java/io/github/sds100/keymapper/base/utils/ui/compose/ComposeChipModel.kt index cbeaa7db8a..15f44addaf 100644 --- a/app/src/main/java/io/github/sds100/keymapper/util/ui/compose/ComposeChipModel.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/compose/ComposeChipModel.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.util.ui.compose +package io.github.sds100.keymapper.base.utils.ui.compose sealed class ComposeChipModel { abstract val id: String @@ -13,7 +13,7 @@ sealed class ComposeChipModel { data class Error( override val id: String, override val text: String, - val error: io.github.sds100.keymapper.util.Error, + val error: io.github.sds100.keymapper.common.utils.KMError, val isFixable: Boolean = true, ) : ComposeChipModel() } diff --git a/app/src/main/java/io/github/sds100/keymapper/util/ui/compose/ComposeDialogs.kt b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/compose/ComposeDialogs.kt similarity index 98% rename from app/src/main/java/io/github/sds100/keymapper/util/ui/compose/ComposeDialogs.kt rename to base/src/main/java/io/github/sds100/keymapper/base/utils/ui/compose/ComposeDialogs.kt index 067329b505..f05cf9f5f5 100644 --- a/app/src/main/java/io/github/sds100/keymapper/util/ui/compose/ComposeDialogs.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/compose/ComposeDialogs.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.util.ui.compose +package io.github.sds100.keymapper.base.utils.ui.compose import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box diff --git a/app/src/main/java/io/github/sds100/keymapper/util/ui/compose/ComposeIconInfo.kt b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/compose/ComposeIconInfo.kt similarity index 81% rename from app/src/main/java/io/github/sds100/keymapper/util/ui/compose/ComposeIconInfo.kt rename to base/src/main/java/io/github/sds100/keymapper/base/utils/ui/compose/ComposeIconInfo.kt index 9b5b28468e..4d2dfec387 100644 --- a/app/src/main/java/io/github/sds100/keymapper/util/ui/compose/ComposeIconInfo.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/compose/ComposeIconInfo.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.util.ui.compose +package io.github.sds100.keymapper.base.utils.ui.compose import androidx.compose.ui.graphics.vector.ImageVector diff --git a/app/src/main/java/io/github/sds100/keymapper/util/ui/compose/DragDropState.kt b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/compose/DragDropState.kt similarity index 99% rename from app/src/main/java/io/github/sds100/keymapper/util/ui/compose/DragDropState.kt rename to base/src/main/java/io/github/sds100/keymapper/base/utils/ui/compose/DragDropState.kt index 2dfb597db2..391aa53804 100644 --- a/app/src/main/java/io/github/sds100/keymapper/util/ui/compose/DragDropState.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/compose/DragDropState.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.util.ui.compose +package io.github.sds100.keymapper.base.utils.ui.compose import androidx.compose.animation.core.Animatable import androidx.compose.animation.core.Spring diff --git a/app/src/main/java/io/github/sds100/keymapper/util/ui/compose/DraggableItem.kt b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/compose/DraggableItem.kt similarity index 95% rename from app/src/main/java/io/github/sds100/keymapper/util/ui/compose/DraggableItem.kt rename to base/src/main/java/io/github/sds100/keymapper/base/utils/ui/compose/DraggableItem.kt index b0653c9fb4..d40e0cb3cd 100644 --- a/app/src/main/java/io/github/sds100/keymapper/util/ui/compose/DraggableItem.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/compose/DraggableItem.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.util.ui.compose +package io.github.sds100.keymapper.base.utils.ui.compose import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.BoxScope diff --git a/app/src/main/java/io/github/sds100/keymapper/util/ui/compose/KeyMapperDropdownMenu.kt b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/compose/KeyMapperDropdownMenu.kt similarity index 97% rename from app/src/main/java/io/github/sds100/keymapper/util/ui/compose/KeyMapperDropdownMenu.kt rename to base/src/main/java/io/github/sds100/keymapper/base/utils/ui/compose/KeyMapperDropdownMenu.kt index eafba75c5d..cd4629e72d 100644 --- a/app/src/main/java/io/github/sds100/keymapper/util/ui/compose/KeyMapperDropdownMenu.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/compose/KeyMapperDropdownMenu.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.util.ui.compose +package io.github.sds100.keymapper.base.utils.ui.compose import androidx.compose.material3.DropdownMenuItem import androidx.compose.material3.ExperimentalMaterial3Api diff --git a/app/src/main/java/io/github/sds100/keymapper/util/ui/compose/KeyMapperSliderThumb.kt b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/compose/KeyMapperSliderThumb.kt similarity index 89% rename from app/src/main/java/io/github/sds100/keymapper/util/ui/compose/KeyMapperSliderThumb.kt rename to base/src/main/java/io/github/sds100/keymapper/base/utils/ui/compose/KeyMapperSliderThumb.kt index 2ac4d27e3d..b869245f4d 100644 --- a/app/src/main/java/io/github/sds100/keymapper/util/ui/compose/KeyMapperSliderThumb.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/compose/KeyMapperSliderThumb.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.util.ui.compose +package io.github.sds100.keymapper.base.utils.ui.compose import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.material3.SliderDefaults diff --git a/app/src/main/java/io/github/sds100/keymapper/util/ui/compose/KeyMapperTapTarget.kt b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/compose/KeyMapperTapTarget.kt similarity index 91% rename from app/src/main/java/io/github/sds100/keymapper/util/ui/compose/KeyMapperTapTarget.kt rename to base/src/main/java/io/github/sds100/keymapper/base/utils/ui/compose/KeyMapperTapTarget.kt index 71313f5f0b..5169ea85ad 100644 --- a/app/src/main/java/io/github/sds100/keymapper/util/ui/compose/KeyMapperTapTarget.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/compose/KeyMapperTapTarget.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.util.ui.compose +package io.github.sds100.keymapper.base.utils.ui.compose import androidx.compose.foundation.BorderStroke import androidx.compose.foundation.layout.Column @@ -12,8 +12,8 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import com.canopas.lib.showcase.component.ShowcaseStyle -import io.github.sds100.keymapper.R -import io.github.sds100.keymapper.onboarding.OnboardingTapTarget +import io.github.sds100.keymapper.base.R +import io.github.sds100.keymapper.base.onboarding.OnboardingTapTarget @Composable fun KeyMapperTapTarget( diff --git a/app/src/main/java/io/github/sds100/keymapper/util/ui/compose/ListItemFixError.kt b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/compose/ListItemFixError.kt similarity index 90% rename from app/src/main/java/io/github/sds100/keymapper/util/ui/compose/ListItemFixError.kt rename to base/src/main/java/io/github/sds100/keymapper/base/utils/ui/compose/ListItemFixError.kt index bf4f4d48ea..727b39accd 100644 --- a/app/src/main/java/io/github/sds100/keymapper/util/ui/compose/ListItemFixError.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/compose/ListItemFixError.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.util.ui.compose +package io.github.sds100.keymapper.base.utils.ui.compose import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer @@ -18,9 +18,9 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp -import io.github.sds100.keymapper.R -import io.github.sds100.keymapper.compose.KeyMapperTheme -import io.github.sds100.keymapper.util.ui.TextListItem +import io.github.sds100.keymapper.base.R +import io.github.sds100.keymapper.base.compose.KeyMapperTheme +import io.github.sds100.keymapper.base.utils.ui.TextListItem @Composable fun ListItemFixError( diff --git a/app/src/main/java/io/github/sds100/keymapper/util/ui/compose/OptionsHeaderRow.kt b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/compose/OptionsHeaderRow.kt similarity index 94% rename from app/src/main/java/io/github/sds100/keymapper/util/ui/compose/OptionsHeaderRow.kt rename to base/src/main/java/io/github/sds100/keymapper/base/utils/ui/compose/OptionsHeaderRow.kt index af867d2133..4754c14c69 100644 --- a/app/src/main/java/io/github/sds100/keymapper/util/ui/compose/OptionsHeaderRow.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/compose/OptionsHeaderRow.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.util.ui.compose +package io.github.sds100.keymapper.base.utils.ui.compose import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer diff --git a/app/src/main/java/io/github/sds100/keymapper/util/ui/compose/RadioButtonText.kt b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/compose/RadioButtonText.kt similarity index 97% rename from app/src/main/java/io/github/sds100/keymapper/util/ui/compose/RadioButtonText.kt rename to base/src/main/java/io/github/sds100/keymapper/base/utils/ui/compose/RadioButtonText.kt index 84f4b07702..aea3b6426a 100644 --- a/app/src/main/java/io/github/sds100/keymapper/util/ui/compose/RadioButtonText.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/compose/RadioButtonText.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.util.ui.compose +package io.github.sds100.keymapper.base.utils.ui.compose import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Row diff --git a/app/src/main/java/io/github/sds100/keymapper/util/ui/compose/SearchAppBarActions.kt b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/compose/SearchAppBarActions.kt similarity index 96% rename from app/src/main/java/io/github/sds100/keymapper/util/ui/compose/SearchAppBarActions.kt rename to base/src/main/java/io/github/sds100/keymapper/base/utils/ui/compose/SearchAppBarActions.kt index 5ee078990d..02176b229e 100644 --- a/app/src/main/java/io/github/sds100/keymapper/util/ui/compose/SearchAppBarActions.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/compose/SearchAppBarActions.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.util.ui.compose +package io.github.sds100.keymapper.base.utils.ui.compose import androidx.compose.foundation.layout.RowScope import androidx.compose.material.icons.Icons @@ -18,7 +18,7 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource -import io.github.sds100.keymapper.R +import io.github.sds100.keymapper.base.R @Composable @OptIn(ExperimentalMaterial3Api::class) diff --git a/app/src/main/java/io/github/sds100/keymapper/util/ui/compose/SimpleListItem.kt b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/compose/SimpleListItem.kt similarity index 96% rename from app/src/main/java/io/github/sds100/keymapper/util/ui/compose/SimpleListItem.kt rename to base/src/main/java/io/github/sds100/keymapper/base/utils/ui/compose/SimpleListItem.kt index 0c758c99e7..91e4a622b5 100644 --- a/app/src/main/java/io/github/sds100/keymapper/util/ui/compose/SimpleListItem.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/compose/SimpleListItem.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.util.ui.compose +package io.github.sds100.keymapper.base.utils.ui.compose import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column @@ -31,9 +31,9 @@ import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import com.google.accompanist.drawablepainter.rememberDrawablePainter -import io.github.sds100.keymapper.R -import io.github.sds100.keymapper.compose.KeyMapperTheme -import io.github.sds100.keymapper.util.drawable +import io.github.sds100.keymapper.base.R +import io.github.sds100.keymapper.base.compose.KeyMapperTheme +import io.github.sds100.keymapper.base.utils.ui.drawable @Composable fun SimpleListItemHeader( diff --git a/app/src/main/java/io/github/sds100/keymapper/util/ui/compose/SimpleListItemModel.kt b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/compose/SimpleListItemModel.kt similarity index 84% rename from app/src/main/java/io/github/sds100/keymapper/util/ui/compose/SimpleListItemModel.kt rename to base/src/main/java/io/github/sds100/keymapper/base/utils/ui/compose/SimpleListItemModel.kt index a233865011..1682d7c971 100644 --- a/app/src/main/java/io/github/sds100/keymapper/util/ui/compose/SimpleListItemModel.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/compose/SimpleListItemModel.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.util.ui.compose +package io.github.sds100.keymapper.base.utils.ui.compose data class SimpleListItemGroup(val header: String, val items: List) diff --git a/app/src/main/java/io/github/sds100/keymapper/util/ui/compose/SliderOptionText.kt b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/compose/SliderOptionText.kt similarity index 97% rename from app/src/main/java/io/github/sds100/keymapper/util/ui/compose/SliderOptionText.kt rename to base/src/main/java/io/github/sds100/keymapper/base/utils/ui/compose/SliderOptionText.kt index 5cf9059ee7..303b1299f0 100644 --- a/app/src/main/java/io/github/sds100/keymapper/util/ui/compose/SliderOptionText.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/compose/SliderOptionText.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.util.ui.compose +package io.github.sds100.keymapper.base.utils.ui.compose import androidx.compose.animation.AnimatedVisibility import androidx.compose.foundation.interaction.MutableInteractionSource @@ -35,8 +35,8 @@ import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp -import io.github.sds100.keymapper.R -import io.github.sds100.keymapper.compose.KeyMapperTheme +import io.github.sds100.keymapper.base.R +import io.github.sds100.keymapper.base.compose.KeyMapperTheme import kotlin.math.roundToInt @OptIn(ExperimentalMaterial3Api::class) diff --git a/app/src/main/java/io/github/sds100/keymapper/util/ui/compose/UriHandlerUtils.kt b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/compose/UriHandlerUtils.kt similarity index 69% rename from app/src/main/java/io/github/sds100/keymapper/util/ui/compose/UriHandlerUtils.kt rename to base/src/main/java/io/github/sds100/keymapper/base/utils/ui/compose/UriHandlerUtils.kt index 59b70ff257..8ba4358c1b 100644 --- a/app/src/main/java/io/github/sds100/keymapper/util/ui/compose/UriHandlerUtils.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/compose/UriHandlerUtils.kt @@ -1,10 +1,10 @@ -package io.github.sds100.keymapper.util.ui.compose +package io.github.sds100.keymapper.base.utils.ui.compose import android.content.Context import android.widget.Toast import androidx.compose.ui.platform.UriHandler -import io.github.sds100.keymapper.R -import io.github.sds100.keymapper.util.str +import io.github.sds100.keymapper.base.R +import io.github.sds100.keymapper.base.utils.ui.str fun UriHandler.openUriSafe(ctx: Context, uri: String) { try { diff --git a/app/src/main/java/io/github/sds100/keymapper/util/ui/compose/WindowSizeClassExt.kt b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/compose/WindowSizeClassExt.kt similarity index 96% rename from app/src/main/java/io/github/sds100/keymapper/util/ui/compose/WindowSizeClassExt.kt rename to base/src/main/java/io/github/sds100/keymapper/base/utils/ui/compose/WindowSizeClassExt.kt index aa727713e5..bcdf0924a9 100644 --- a/app/src/main/java/io/github/sds100/keymapper/util/ui/compose/WindowSizeClassExt.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/compose/WindowSizeClassExt.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.util.ui.compose +package io.github.sds100.keymapper.base.utils.ui.compose import androidx.window.core.layout.WindowHeightSizeClass import androidx.window.core.layout.WindowWidthSizeClass diff --git a/app/src/main/java/io/github/sds100/keymapper/util/ui/compose/icons/AdGroup.kt b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/compose/icons/AdGroup.kt similarity index 97% rename from app/src/main/java/io/github/sds100/keymapper/util/ui/compose/icons/AdGroup.kt rename to base/src/main/java/io/github/sds100/keymapper/base/utils/ui/compose/icons/AdGroup.kt index 05f0f4db8b..431a1e884f 100644 --- a/app/src/main/java/io/github/sds100/keymapper/util/ui/compose/icons/AdGroup.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/compose/icons/AdGroup.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.util.ui.compose.icons +package io.github.sds100.keymapper.base.utils.ui.compose.icons import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.SolidColor diff --git a/app/src/main/java/io/github/sds100/keymapper/util/ui/compose/icons/HomeIotDevice.kt b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/compose/icons/HomeIotDevice.kt similarity index 98% rename from app/src/main/java/io/github/sds100/keymapper/util/ui/compose/icons/HomeIotDevice.kt rename to base/src/main/java/io/github/sds100/keymapper/base/utils/ui/compose/icons/HomeIotDevice.kt index 2767867d43..d03c326303 100644 --- a/app/src/main/java/io/github/sds100/keymapper/util/ui/compose/icons/HomeIotDevice.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/compose/icons/HomeIotDevice.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.util.ui.compose.icons +package io.github.sds100.keymapper.base.utils.ui.compose.icons import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.SolidColor diff --git a/app/src/main/java/io/github/sds100/keymapper/util/ui/compose/icons/Import.kt b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/compose/icons/Import.kt similarity index 98% rename from app/src/main/java/io/github/sds100/keymapper/util/ui/compose/icons/Import.kt rename to base/src/main/java/io/github/sds100/keymapper/base/utils/ui/compose/icons/Import.kt index 378e634e9e..8d71dc619a 100644 --- a/app/src/main/java/io/github/sds100/keymapper/util/ui/compose/icons/Import.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/compose/icons/Import.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.util.ui.compose.icons +package io.github.sds100.keymapper.base.utils.ui.compose.icons import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.SolidColor diff --git a/app/src/main/java/io/github/sds100/keymapper/util/ui/compose/icons/InstantMix.kt b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/compose/icons/InstantMix.kt similarity index 97% rename from app/src/main/java/io/github/sds100/keymapper/util/ui/compose/icons/InstantMix.kt rename to base/src/main/java/io/github/sds100/keymapper/base/utils/ui/compose/icons/InstantMix.kt index 18be2e6859..fc5bbce79f 100644 --- a/app/src/main/java/io/github/sds100/keymapper/util/ui/compose/icons/InstantMix.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/compose/icons/InstantMix.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.util.ui.compose.icons +package io.github.sds100.keymapper.base.utils.ui.compose.icons import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.SolidColor diff --git a/app/src/main/java/io/github/sds100/keymapper/util/ui/compose/icons/JumpToElement.kt b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/compose/icons/JumpToElement.kt similarity index 98% rename from app/src/main/java/io/github/sds100/keymapper/util/ui/compose/icons/JumpToElement.kt rename to base/src/main/java/io/github/sds100/keymapper/base/utils/ui/compose/icons/JumpToElement.kt index 498d3bc295..afefdb1adb 100644 --- a/app/src/main/java/io/github/sds100/keymapper/util/ui/compose/icons/JumpToElement.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/compose/icons/JumpToElement.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.util.ui.compose.icons +package io.github.sds100.keymapper.base.utils.ui.compose.icons import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.SolidColor diff --git a/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/compose/icons/KeyMapperIcons.kt b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/compose/icons/KeyMapperIcons.kt new file mode 100644 index 0000000000..1d5c1d891b --- /dev/null +++ b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/compose/icons/KeyMapperIcons.kt @@ -0,0 +1,3 @@ +package io.github.sds100.keymapper.base.utils.ui.compose.icons + +object KeyMapperIcons diff --git a/app/src/main/java/io/github/sds100/keymapper/util/ui/compose/icons/MatchWord.kt b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/compose/icons/MatchWord.kt similarity index 98% rename from app/src/main/java/io/github/sds100/keymapper/util/ui/compose/icons/MatchWord.kt rename to base/src/main/java/io/github/sds100/keymapper/base/utils/ui/compose/icons/MatchWord.kt index 41ed511db2..5ae8142c46 100644 --- a/app/src/main/java/io/github/sds100/keymapper/util/ui/compose/icons/MatchWord.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/compose/icons/MatchWord.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.util.ui.compose.icons +package io.github.sds100.keymapper.base.utils.ui.compose.icons import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.SolidColor diff --git a/app/src/main/java/io/github/sds100/keymapper/util/ui/compose/icons/NfcOff.kt b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/compose/icons/NfcOff.kt similarity index 97% rename from app/src/main/java/io/github/sds100/keymapper/util/ui/compose/icons/NfcOff.kt rename to base/src/main/java/io/github/sds100/keymapper/base/utils/ui/compose/icons/NfcOff.kt index 9080fee645..cf198ec9cf 100644 --- a/app/src/main/java/io/github/sds100/keymapper/util/ui/compose/icons/NfcOff.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/compose/icons/NfcOff.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.util.ui.compose.icons +package io.github.sds100.keymapper.base.utils.ui.compose.icons import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.SolidColor diff --git a/app/src/main/java/io/github/sds100/keymapper/util/ui/compose/icons/TextSelectEnd.kt b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/compose/icons/TextSelectEnd.kt similarity index 98% rename from app/src/main/java/io/github/sds100/keymapper/util/ui/compose/icons/TextSelectEnd.kt rename to base/src/main/java/io/github/sds100/keymapper/base/utils/ui/compose/icons/TextSelectEnd.kt index 8edb9a2642..bc6adec357 100644 --- a/app/src/main/java/io/github/sds100/keymapper/util/ui/compose/icons/TextSelectEnd.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/compose/icons/TextSelectEnd.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.util.ui.compose.icons +package io.github.sds100.keymapper.base.utils.ui.compose.icons import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.SolidColor diff --git a/app/src/main/java/io/github/sds100/keymapper/util/ui/compose/icons/TextSelectMoveForwardCharacter.kt b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/compose/icons/TextSelectMoveForwardCharacter.kt similarity index 97% rename from app/src/main/java/io/github/sds100/keymapper/util/ui/compose/icons/TextSelectMoveForwardCharacter.kt rename to base/src/main/java/io/github/sds100/keymapper/base/utils/ui/compose/icons/TextSelectMoveForwardCharacter.kt index d7967f8586..2e6be90307 100644 --- a/app/src/main/java/io/github/sds100/keymapper/util/ui/compose/icons/TextSelectMoveForwardCharacter.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/compose/icons/TextSelectMoveForwardCharacter.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.util.ui.compose.icons +package io.github.sds100.keymapper.base.utils.ui.compose.icons import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.SolidColor diff --git a/app/src/main/java/io/github/sds100/keymapper/util/ui/compose/icons/TopPanelClose.kt b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/compose/icons/TopPanelClose.kt similarity index 97% rename from app/src/main/java/io/github/sds100/keymapper/util/ui/compose/icons/TopPanelClose.kt rename to base/src/main/java/io/github/sds100/keymapper/base/utils/ui/compose/icons/TopPanelClose.kt index b1ea2034b8..7795f4ee29 100644 --- a/app/src/main/java/io/github/sds100/keymapper/util/ui/compose/icons/TopPanelClose.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/compose/icons/TopPanelClose.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.util.ui.compose.icons +package io.github.sds100.keymapper.base.utils.ui.compose.icons import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.SolidColor diff --git a/app/src/main/java/io/github/sds100/keymapper/util/ui/compose/icons/TopPanelOpen.kt b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/compose/icons/TopPanelOpen.kt similarity index 97% rename from app/src/main/java/io/github/sds100/keymapper/util/ui/compose/icons/TopPanelOpen.kt rename to base/src/main/java/io/github/sds100/keymapper/base/utils/ui/compose/icons/TopPanelOpen.kt index 821435c66f..531319676b 100644 --- a/app/src/main/java/io/github/sds100/keymapper/util/ui/compose/icons/TopPanelOpen.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/utils/ui/compose/icons/TopPanelOpen.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.util.ui.compose.icons +package io.github.sds100.keymapper.base.utils.ui.compose.icons import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.SolidColor diff --git a/app/src/main/res/anim/slide_in_bottom.xml b/base/src/main/res/anim/slide_in_bottom.xml similarity index 100% rename from app/src/main/res/anim/slide_in_bottom.xml rename to base/src/main/res/anim/slide_in_bottom.xml diff --git a/app/src/main/res/anim/slide_in_left.xml b/base/src/main/res/anim/slide_in_left.xml similarity index 100% rename from app/src/main/res/anim/slide_in_left.xml rename to base/src/main/res/anim/slide_in_left.xml diff --git a/app/src/main/res/anim/slide_in_right.xml b/base/src/main/res/anim/slide_in_right.xml similarity index 100% rename from app/src/main/res/anim/slide_in_right.xml rename to base/src/main/res/anim/slide_in_right.xml diff --git a/app/src/main/res/anim/slide_out_bottom.xml b/base/src/main/res/anim/slide_out_bottom.xml similarity index 100% rename from app/src/main/res/anim/slide_out_bottom.xml rename to base/src/main/res/anim/slide_out_bottom.xml diff --git a/app/src/main/res/anim/slide_out_left.xml b/base/src/main/res/anim/slide_out_left.xml similarity index 100% rename from app/src/main/res/anim/slide_out_left.xml rename to base/src/main/res/anim/slide_out_left.xml diff --git a/app/src/main/res/anim/slide_out_right.xml b/base/src/main/res/anim/slide_out_right.xml similarity index 100% rename from app/src/main/res/anim/slide_out_right.xml rename to base/src/main/res/anim/slide_out_right.xml diff --git a/app/src/main/res/drawable/dnd_circle_off_outline.xml b/base/src/main/res/drawable/dnd_circle_off_outline.xml similarity index 100% rename from app/src/main/res/drawable/dnd_circle_off_outline.xml rename to base/src/main/res/drawable/dnd_circle_off_outline.xml diff --git a/app/src/main/res/drawable/dnd_circle_outline.xml b/base/src/main/res/drawable/dnd_circle_outline.xml similarity index 100% rename from app/src/main/res/drawable/dnd_circle_outline.xml rename to base/src/main/res/drawable/dnd_circle_outline.xml diff --git a/app/src/main/res/drawable/ic_baseline_add_24.xml b/base/src/main/res/drawable/ic_baseline_add_24.xml similarity index 100% rename from app/src/main/res/drawable/ic_baseline_add_24.xml rename to base/src/main/res/drawable/ic_baseline_add_24.xml diff --git a/app/src/main/res/drawable/ic_baseline_announcement_24.xml b/base/src/main/res/drawable/ic_baseline_announcement_24.xml similarity index 100% rename from app/src/main/res/drawable/ic_baseline_announcement_24.xml rename to base/src/main/res/drawable/ic_baseline_announcement_24.xml diff --git a/app/src/main/res/drawable/ic_baseline_arrow_back_24.xml b/base/src/main/res/drawable/ic_baseline_arrow_back_24.xml similarity index 100% rename from app/src/main/res/drawable/ic_baseline_arrow_back_24.xml rename to base/src/main/res/drawable/ic_baseline_arrow_back_24.xml diff --git a/app/src/main/res/drawable/ic_baseline_arrow_downward_24.xml b/base/src/main/res/drawable/ic_baseline_arrow_downward_24.xml similarity index 100% rename from app/src/main/res/drawable/ic_baseline_arrow_downward_24.xml rename to base/src/main/res/drawable/ic_baseline_arrow_downward_24.xml diff --git a/app/src/main/res/drawable/ic_baseline_arrow_forward_24.xml b/base/src/main/res/drawable/ic_baseline_arrow_forward_24.xml similarity index 100% rename from app/src/main/res/drawable/ic_baseline_arrow_forward_24.xml rename to base/src/main/res/drawable/ic_baseline_arrow_forward_24.xml diff --git a/app/src/main/res/drawable/ic_baseline_battery_charging_full_24.xml b/base/src/main/res/drawable/ic_baseline_battery_charging_full_24.xml similarity index 100% rename from app/src/main/res/drawable/ic_baseline_battery_charging_full_24.xml rename to base/src/main/res/drawable/ic_baseline_battery_charging_full_24.xml diff --git a/app/src/main/res/drawable/ic_baseline_call_end_24.xml b/base/src/main/res/drawable/ic_baseline_call_end_24.xml similarity index 100% rename from app/src/main/res/drawable/ic_baseline_call_end_24.xml rename to base/src/main/res/drawable/ic_baseline_call_end_24.xml diff --git a/app/src/main/res/drawable/ic_baseline_check_64.xml b/base/src/main/res/drawable/ic_baseline_check_64.xml similarity index 100% rename from app/src/main/res/drawable/ic_baseline_check_64.xml rename to base/src/main/res/drawable/ic_baseline_check_64.xml diff --git a/app/src/main/res/drawable/ic_baseline_clear_all_24.xml b/base/src/main/res/drawable/ic_baseline_clear_all_24.xml similarity index 100% rename from app/src/main/res/drawable/ic_baseline_clear_all_24.xml rename to base/src/main/res/drawable/ic_baseline_clear_all_24.xml diff --git a/app/src/main/res/drawable/ic_baseline_content_copy_64.xml b/base/src/main/res/drawable/ic_baseline_content_copy_64.xml similarity index 100% rename from app/src/main/res/drawable/ic_baseline_content_copy_64.xml rename to base/src/main/res/drawable/ic_baseline_content_copy_64.xml diff --git a/app/src/main/res/drawable/ic_baseline_cross_64.xml b/base/src/main/res/drawable/ic_baseline_cross_64.xml similarity index 100% rename from app/src/main/res/drawable/ic_baseline_cross_64.xml rename to base/src/main/res/drawable/ic_baseline_cross_64.xml diff --git a/app/src/main/res/drawable/ic_baseline_delete_outline_24.xml b/base/src/main/res/drawable/ic_baseline_delete_outline_24.xml similarity index 100% rename from app/src/main/res/drawable/ic_baseline_delete_outline_24.xml rename to base/src/main/res/drawable/ic_baseline_delete_outline_24.xml diff --git a/app/src/main/res/drawable/ic_baseline_devices_other_24.xml b/base/src/main/res/drawable/ic_baseline_devices_other_24.xml similarity index 100% rename from app/src/main/res/drawable/ic_baseline_devices_other_24.xml rename to base/src/main/res/drawable/ic_baseline_devices_other_24.xml diff --git a/app/src/main/res/drawable/ic_baseline_devices_other_64.xml b/base/src/main/res/drawable/ic_baseline_devices_other_64.xml similarity index 100% rename from app/src/main/res/drawable/ic_baseline_devices_other_64.xml rename to base/src/main/res/drawable/ic_baseline_devices_other_64.xml diff --git a/app/src/main/res/drawable/ic_baseline_done_24.xml b/base/src/main/res/drawable/ic_baseline_done_24.xml similarity index 100% rename from app/src/main/res/drawable/ic_baseline_done_24.xml rename to base/src/main/res/drawable/ic_baseline_done_24.xml diff --git a/app/src/main/res/drawable/ic_baseline_drag_handle_24.xml b/base/src/main/res/drawable/ic_baseline_drag_handle_24.xml similarity index 100% rename from app/src/main/res/drawable/ic_baseline_drag_handle_24.xml rename to base/src/main/res/drawable/ic_baseline_drag_handle_24.xml diff --git a/app/src/main/res/drawable/ic_baseline_error_outline_24.xml b/base/src/main/res/drawable/ic_baseline_error_outline_24.xml similarity index 100% rename from app/src/main/res/drawable/ic_baseline_error_outline_24.xml rename to base/src/main/res/drawable/ic_baseline_error_outline_24.xml diff --git a/app/src/main/res/drawable/ic_baseline_expand_less_24.xml b/base/src/main/res/drawable/ic_baseline_expand_less_24.xml similarity index 100% rename from app/src/main/res/drawable/ic_baseline_expand_less_24.xml rename to base/src/main/res/drawable/ic_baseline_expand_less_24.xml diff --git a/app/src/main/res/drawable/ic_baseline_fingerprint_64.xml b/base/src/main/res/drawable/ic_baseline_fingerprint_64.xml similarity index 100% rename from app/src/main/res/drawable/ic_baseline_fingerprint_64.xml rename to base/src/main/res/drawable/ic_baseline_fingerprint_64.xml diff --git a/app/src/main/res/drawable/ic_baseline_help_outline_24.xml b/base/src/main/res/drawable/ic_baseline_help_outline_24.xml similarity index 100% rename from app/src/main/res/drawable/ic_baseline_help_outline_24.xml rename to base/src/main/res/drawable/ic_baseline_help_outline_24.xml diff --git a/app/src/main/res/drawable/ic_baseline_menu_24.xml b/base/src/main/res/drawable/ic_baseline_menu_24.xml similarity index 100% rename from app/src/main/res/drawable/ic_baseline_menu_24.xml rename to base/src/main/res/drawable/ic_baseline_menu_24.xml diff --git a/app/src/main/res/drawable/ic_baseline_mobile_off_24.xml b/base/src/main/res/drawable/ic_baseline_mobile_off_24.xml similarity index 100% rename from app/src/main/res/drawable/ic_baseline_mobile_off_24.xml rename to base/src/main/res/drawable/ic_baseline_mobile_off_24.xml diff --git a/app/src/main/res/drawable/ic_baseline_refresh_24.xml b/base/src/main/res/drawable/ic_baseline_refresh_24.xml similarity index 100% rename from app/src/main/res/drawable/ic_baseline_refresh_24.xml rename to base/src/main/res/drawable/ic_baseline_refresh_24.xml diff --git a/app/src/main/res/drawable/ic_baseline_ring_volume_24.xml b/base/src/main/res/drawable/ic_baseline_ring_volume_24.xml similarity index 100% rename from app/src/main/res/drawable/ic_baseline_ring_volume_24.xml rename to base/src/main/res/drawable/ic_baseline_ring_volume_24.xml diff --git a/app/src/main/res/drawable/ic_baseline_select_all_24.xml b/base/src/main/res/drawable/ic_baseline_select_all_24.xml similarity index 100% rename from app/src/main/res/drawable/ic_baseline_select_all_24.xml rename to base/src/main/res/drawable/ic_baseline_select_all_24.xml diff --git a/app/src/main/res/drawable/ic_baseline_warning_24.xml b/base/src/main/res/drawable/ic_baseline_warning_24.xml similarity index 100% rename from app/src/main/res/drawable/ic_baseline_warning_24.xml rename to base/src/main/res/drawable/ic_baseline_warning_24.xml diff --git a/app/src/main/res/drawable/ic_battery_70.xml b/base/src/main/res/drawable/ic_battery_70.xml similarity index 100% rename from app/src/main/res/drawable/ic_battery_70.xml rename to base/src/main/res/drawable/ic_battery_70.xml diff --git a/app/src/main/res/drawable/ic_battery_std_white_64dp.xml b/base/src/main/res/drawable/ic_battery_std_white_64dp.xml similarity index 100% rename from app/src/main/res/drawable/ic_battery_std_white_64dp.xml rename to base/src/main/res/drawable/ic_battery_std_white_64dp.xml diff --git a/app/src/main/res/drawable/ic_content_copy.xml b/base/src/main/res/drawable/ic_content_copy.xml similarity index 100% rename from app/src/main/res/drawable/ic_content_copy.xml rename to base/src/main/res/drawable/ic_content_copy.xml diff --git a/app/src/main/res/drawable/ic_content_cut.xml b/base/src/main/res/drawable/ic_content_cut.xml similarity index 100% rename from app/src/main/res/drawable/ic_content_cut.xml rename to base/src/main/res/drawable/ic_content_cut.xml diff --git a/app/src/main/res/drawable/ic_content_paste.xml b/base/src/main/res/drawable/ic_content_paste.xml similarity index 100% rename from app/src/main/res/drawable/ic_content_paste.xml rename to base/src/main/res/drawable/ic_content_paste.xml diff --git a/app/src/main/res/drawable/ic_cursor.xml b/base/src/main/res/drawable/ic_cursor.xml similarity index 100% rename from app/src/main/res/drawable/ic_cursor.xml rename to base/src/main/res/drawable/ic_cursor.xml diff --git a/app/src/main/res/drawable/ic_disable_brightness_auto_24dp.xml b/base/src/main/res/drawable/ic_disable_brightness_auto_24dp.xml similarity index 100% rename from app/src/main/res/drawable/ic_disable_brightness_auto_24dp.xml rename to base/src/main/res/drawable/ic_disable_brightness_auto_24dp.xml diff --git a/app/src/main/res/drawable/ic_discord.xml b/base/src/main/res/drawable/ic_discord.xml similarity index 100% rename from app/src/main/res/drawable/ic_discord.xml rename to base/src/main/res/drawable/ic_discord.xml diff --git a/app/src/main/res/drawable/ic_dock_white_64dp.xml b/base/src/main/res/drawable/ic_dock_white_64dp.xml similarity index 100% rename from app/src/main/res/drawable/ic_dock_white_64dp.xml rename to base/src/main/res/drawable/ic_dock_white_64dp.xml diff --git a/app/src/main/res/drawable/ic_fdroid.xml b/base/src/main/res/drawable/ic_fdroid.xml similarity index 100% rename from app/src/main/res/drawable/ic_fdroid.xml rename to base/src/main/res/drawable/ic_fdroid.xml diff --git a/app/src/main/res/drawable/ic_flashlight.xml b/base/src/main/res/drawable/ic_flashlight.xml similarity index 100% rename from app/src/main/res/drawable/ic_flashlight.xml rename to base/src/main/res/drawable/ic_flashlight.xml diff --git a/app/src/main/res/drawable/ic_flashlight_off.xml b/base/src/main/res/drawable/ic_flashlight_off.xml similarity index 100% rename from app/src/main/res/drawable/ic_flashlight_off.xml rename to base/src/main/res/drawable/ic_flashlight_off.xml diff --git a/app/src/main/res/drawable/ic_github.xml b/base/src/main/res/drawable/ic_github.xml similarity index 100% rename from app/src/main/res/drawable/ic_github.xml rename to base/src/main/res/drawable/ic_github.xml diff --git a/app/src/main/res/drawable/ic_google_play.xml b/base/src/main/res/drawable/ic_google_play.xml similarity index 100% rename from app/src/main/res/drawable/ic_google_play.xml rename to base/src/main/res/drawable/ic_google_play.xml diff --git a/app/src/main/res/drawable/ic_home_automation.xml b/base/src/main/res/drawable/ic_home_automation.xml similarity index 100% rename from app/src/main/res/drawable/ic_home_automation.xml rename to base/src/main/res/drawable/ic_home_automation.xml diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/base/src/main/res/drawable/ic_launcher_background.xml similarity index 100% rename from app/src/main/res/drawable/ic_launcher_background.xml rename to base/src/main/res/drawable/ic_launcher_background.xml diff --git a/app/src/main/res/drawable/ic_launcher_foreground.xml b/base/src/main/res/drawable/ic_launcher_foreground.xml similarity index 100% rename from app/src/main/res/drawable/ic_launcher_foreground.xml rename to base/src/main/res/drawable/ic_launcher_foreground.xml diff --git a/app/src/main/res/drawable/ic_launcher_web.png b/base/src/main/res/drawable/ic_launcher_web.png similarity index 100% rename from app/src/main/res/drawable/ic_launcher_web.png rename to base/src/main/res/drawable/ic_launcher_web.png diff --git a/app/src/main/res/drawable/ic_letter_24.xml b/base/src/main/res/drawable/ic_letter_24.xml similarity index 100% rename from app/src/main/res/drawable/ic_letter_24.xml rename to base/src/main/res/drawable/ic_letter_24.xml diff --git a/app/src/main/res/drawable/ic_nfc_off.xml b/base/src/main/res/drawable/ic_nfc_off.xml similarity index 100% rename from app/src/main/res/drawable/ic_nfc_off.xml rename to base/src/main/res/drawable/ic_nfc_off.xml diff --git a/app/src/main/res/drawable/ic_notification_error.xml b/base/src/main/res/drawable/ic_notification_error.xml similarity index 100% rename from app/src/main/res/drawable/ic_notification_error.xml rename to base/src/main/res/drawable/ic_notification_error.xml diff --git a/app/src/main/res/drawable/ic_notification_fingerprint.xml b/base/src/main/res/drawable/ic_notification_fingerprint.xml similarity index 100% rename from app/src/main/res/drawable/ic_notification_fingerprint.xml rename to base/src/main/res/drawable/ic_notification_fingerprint.xml diff --git a/app/src/main/res/drawable/ic_notification_keyboard.xml b/base/src/main/res/drawable/ic_notification_keyboard.xml similarity index 100% rename from app/src/main/res/drawable/ic_notification_keyboard.xml rename to base/src/main/res/drawable/ic_notification_keyboard.xml diff --git a/app/src/main/res/drawable/ic_notification_keyboard_hide.xml b/base/src/main/res/drawable/ic_notification_keyboard_hide.xml similarity index 100% rename from app/src/main/res/drawable/ic_notification_keyboard_hide.xml rename to base/src/main/res/drawable/ic_notification_keyboard_hide.xml diff --git a/app/src/main/res/drawable/ic_notification_pause.xml b/base/src/main/res/drawable/ic_notification_pause.xml similarity index 100% rename from app/src/main/res/drawable/ic_notification_pause.xml rename to base/src/main/res/drawable/ic_notification_pause.xml diff --git a/app/src/main/res/drawable/ic_notification_play.xml b/base/src/main/res/drawable/ic_notification_play.xml similarity index 100% rename from app/src/main/res/drawable/ic_notification_play.xml rename to base/src/main/res/drawable/ic_notification_play.xml diff --git a/app/src/main/res/drawable/ic_notification_settings.xml b/base/src/main/res/drawable/ic_notification_settings.xml similarity index 100% rename from app/src/main/res/drawable/ic_notification_settings.xml rename to base/src/main/res/drawable/ic_notification_settings.xml diff --git a/app/src/main/res/drawable/ic_outline_account.xml b/base/src/main/res/drawable/ic_outline_account.xml similarity index 100% rename from app/src/main/res/drawable/ic_outline_account.xml rename to base/src/main/res/drawable/ic_outline_account.xml diff --git a/app/src/main/res/drawable/ic_outline_airplanemode_active_24.xml b/base/src/main/res/drawable/ic_outline_airplanemode_active_24.xml similarity index 100% rename from app/src/main/res/drawable/ic_outline_airplanemode_active_24.xml rename to base/src/main/res/drawable/ic_outline_airplanemode_active_24.xml diff --git a/app/src/main/res/drawable/ic_outline_airplanemode_inactive_24.xml b/base/src/main/res/drawable/ic_outline_airplanemode_inactive_24.xml similarity index 100% rename from app/src/main/res/drawable/ic_outline_airplanemode_inactive_24.xml rename to base/src/main/res/drawable/ic_outline_airplanemode_inactive_24.xml diff --git a/app/src/main/res/drawable/ic_outline_android_24.xml b/base/src/main/res/drawable/ic_outline_android_24.xml similarity index 100% rename from app/src/main/res/drawable/ic_outline_android_24.xml rename to base/src/main/res/drawable/ic_outline_android_24.xml diff --git a/app/src/main/res/drawable/ic_outline_assistant_24.xml b/base/src/main/res/drawable/ic_outline_assistant_24.xml similarity index 100% rename from app/src/main/res/drawable/ic_outline_assistant_24.xml rename to base/src/main/res/drawable/ic_outline_assistant_24.xml diff --git a/app/src/main/res/drawable/ic_outline_bluetooth_24.xml b/base/src/main/res/drawable/ic_outline_bluetooth_24.xml similarity index 100% rename from app/src/main/res/drawable/ic_outline_bluetooth_24.xml rename to base/src/main/res/drawable/ic_outline_bluetooth_24.xml diff --git a/app/src/main/res/drawable/ic_outline_bluetooth_connected_24.xml b/base/src/main/res/drawable/ic_outline_bluetooth_connected_24.xml similarity index 100% rename from app/src/main/res/drawable/ic_outline_bluetooth_connected_24.xml rename to base/src/main/res/drawable/ic_outline_bluetooth_connected_24.xml diff --git a/app/src/main/res/drawable/ic_outline_bluetooth_disabled_24.xml b/base/src/main/res/drawable/ic_outline_bluetooth_disabled_24.xml similarity index 100% rename from app/src/main/res/drawable/ic_outline_bluetooth_disabled_24.xml rename to base/src/main/res/drawable/ic_outline_bluetooth_disabled_24.xml diff --git a/app/src/main/res/drawable/ic_outline_brightness_auto_24.xml b/base/src/main/res/drawable/ic_outline_brightness_auto_24.xml similarity index 100% rename from app/src/main/res/drawable/ic_outline_brightness_auto_24.xml rename to base/src/main/res/drawable/ic_outline_brightness_auto_24.xml diff --git a/app/src/main/res/drawable/ic_outline_brightness_high_24.xml b/base/src/main/res/drawable/ic_outline_brightness_high_24.xml similarity index 100% rename from app/src/main/res/drawable/ic_outline_brightness_high_24.xml rename to base/src/main/res/drawable/ic_outline_brightness_high_24.xml diff --git a/app/src/main/res/drawable/ic_outline_brightness_low_24.xml b/base/src/main/res/drawable/ic_outline_brightness_low_24.xml similarity index 100% rename from app/src/main/res/drawable/ic_outline_brightness_low_24.xml rename to base/src/main/res/drawable/ic_outline_brightness_low_24.xml diff --git a/app/src/main/res/drawable/ic_outline_brightness_medium_24.xml b/base/src/main/res/drawable/ic_outline_brightness_medium_24.xml similarity index 100% rename from app/src/main/res/drawable/ic_outline_brightness_medium_24.xml rename to base/src/main/res/drawable/ic_outline_brightness_medium_24.xml diff --git a/app/src/main/res/drawable/ic_outline_bug_report_24.xml b/base/src/main/res/drawable/ic_outline_bug_report_24.xml similarity index 100% rename from app/src/main/res/drawable/ic_outline_bug_report_24.xml rename to base/src/main/res/drawable/ic_outline_bug_report_24.xml diff --git a/app/src/main/res/drawable/ic_outline_bug_report_64.xml b/base/src/main/res/drawable/ic_outline_bug_report_64.xml similarity index 100% rename from app/src/main/res/drawable/ic_outline_bug_report_64.xml rename to base/src/main/res/drawable/ic_outline_bug_report_64.xml diff --git a/app/src/main/res/drawable/ic_outline_call_24.xml b/base/src/main/res/drawable/ic_outline_call_24.xml similarity index 100% rename from app/src/main/res/drawable/ic_outline_call_24.xml rename to base/src/main/res/drawable/ic_outline_call_24.xml diff --git a/app/src/main/res/drawable/ic_outline_call_end_24.xml b/base/src/main/res/drawable/ic_outline_call_end_24.xml similarity index 100% rename from app/src/main/res/drawable/ic_outline_call_end_24.xml rename to base/src/main/res/drawable/ic_outline_call_end_24.xml diff --git a/app/src/main/res/drawable/ic_outline_camera_alt_24.xml b/base/src/main/res/drawable/ic_outline_camera_alt_24.xml similarity index 100% rename from app/src/main/res/drawable/ic_outline_camera_alt_24.xml rename to base/src/main/res/drawable/ic_outline_camera_alt_24.xml diff --git a/app/src/main/res/drawable/ic_outline_check_circle_outline_24.xml b/base/src/main/res/drawable/ic_outline_check_circle_outline_24.xml similarity index 100% rename from app/src/main/res/drawable/ic_outline_check_circle_outline_24.xml rename to base/src/main/res/drawable/ic_outline_check_circle_outline_24.xml diff --git a/app/src/main/res/drawable/ic_outline_clear_24.xml b/base/src/main/res/drawable/ic_outline_clear_24.xml similarity index 100% rename from app/src/main/res/drawable/ic_outline_clear_24.xml rename to base/src/main/res/drawable/ic_outline_clear_24.xml diff --git a/app/src/main/res/drawable/ic_outline_devices_other_64.xml b/base/src/main/res/drawable/ic_outline_devices_other_64.xml similarity index 100% rename from app/src/main/res/drawable/ic_outline_devices_other_64.xml rename to base/src/main/res/drawable/ic_outline_devices_other_64.xml diff --git a/app/src/main/res/drawable/ic_outline_dnd_circle_outline_64.xml b/base/src/main/res/drawable/ic_outline_dnd_circle_outline_64.xml similarity index 100% rename from app/src/main/res/drawable/ic_outline_dnd_circle_outline_64.xml rename to base/src/main/res/drawable/ic_outline_dnd_circle_outline_64.xml diff --git a/app/src/main/res/drawable/ic_outline_edit_24.xml b/base/src/main/res/drawable/ic_outline_edit_24.xml similarity index 100% rename from app/src/main/res/drawable/ic_outline_edit_24.xml rename to base/src/main/res/drawable/ic_outline_edit_24.xml diff --git a/app/src/main/res/drawable/ic_outline_error_outline_64.xml b/base/src/main/res/drawable/ic_outline_error_outline_64.xml similarity index 100% rename from app/src/main/res/drawable/ic_outline_error_outline_64.xml rename to base/src/main/res/drawable/ic_outline_error_outline_64.xml diff --git a/app/src/main/res/drawable/ic_outline_expand_more_24.xml b/base/src/main/res/drawable/ic_outline_expand_more_24.xml similarity index 100% rename from app/src/main/res/drawable/ic_outline_expand_more_24.xml rename to base/src/main/res/drawable/ic_outline_expand_more_24.xml diff --git a/app/src/main/res/drawable/ic_outline_fast_forward_24.xml b/base/src/main/res/drawable/ic_outline_fast_forward_24.xml similarity index 100% rename from app/src/main/res/drawable/ic_outline_fast_forward_24.xml rename to base/src/main/res/drawable/ic_outline_fast_forward_24.xml diff --git a/app/src/main/res/drawable/ic_outline_fast_rewind_24.xml b/base/src/main/res/drawable/ic_outline_fast_rewind_24.xml similarity index 100% rename from app/src/main/res/drawable/ic_outline_fast_rewind_24.xml rename to base/src/main/res/drawable/ic_outline_fast_rewind_24.xml diff --git a/app/src/main/res/drawable/ic_outline_feedback_24.xml b/base/src/main/res/drawable/ic_outline_feedback_24.xml similarity index 100% rename from app/src/main/res/drawable/ic_outline_feedback_24.xml rename to base/src/main/res/drawable/ic_outline_feedback_24.xml diff --git a/app/src/main/res/drawable/ic_outline_feedback_64.xml b/base/src/main/res/drawable/ic_outline_feedback_64.xml similarity index 100% rename from app/src/main/res/drawable/ic_outline_feedback_64.xml rename to base/src/main/res/drawable/ic_outline_feedback_64.xml diff --git a/app/src/main/res/drawable/ic_outline_file_copy_24.xml b/base/src/main/res/drawable/ic_outline_file_copy_24.xml similarity index 100% rename from app/src/main/res/drawable/ic_outline_file_copy_24.xml rename to base/src/main/res/drawable/ic_outline_file_copy_24.xml diff --git a/app/src/main/res/drawable/ic_outline_fullscreen_24.xml b/base/src/main/res/drawable/ic_outline_fullscreen_24.xml similarity index 100% rename from app/src/main/res/drawable/ic_outline_fullscreen_24.xml rename to base/src/main/res/drawable/ic_outline_fullscreen_24.xml diff --git a/app/src/main/res/drawable/ic_outline_help_center_64.xml b/base/src/main/res/drawable/ic_outline_help_center_64.xml similarity index 100% rename from app/src/main/res/drawable/ic_outline_help_center_64.xml rename to base/src/main/res/drawable/ic_outline_help_center_64.xml diff --git a/app/src/main/res/drawable/ic_outline_home_24.xml b/base/src/main/res/drawable/ic_outline_home_24.xml similarity index 100% rename from app/src/main/res/drawable/ic_outline_home_24.xml rename to base/src/main/res/drawable/ic_outline_home_24.xml diff --git a/app/src/main/res/drawable/ic_outline_info_24.xml b/base/src/main/res/drawable/ic_outline_info_24.xml similarity index 100% rename from app/src/main/res/drawable/ic_outline_info_24.xml rename to base/src/main/res/drawable/ic_outline_info_24.xml diff --git a/app/src/main/res/drawable/ic_outline_keyboard_24.xml b/base/src/main/res/drawable/ic_outline_keyboard_24.xml similarity index 100% rename from app/src/main/res/drawable/ic_outline_keyboard_24.xml rename to base/src/main/res/drawable/ic_outline_keyboard_24.xml diff --git a/app/src/main/res/drawable/ic_outline_keyboard_hide_24.xml b/base/src/main/res/drawable/ic_outline_keyboard_hide_24.xml similarity index 100% rename from app/src/main/res/drawable/ic_outline_keyboard_hide_24.xml rename to base/src/main/res/drawable/ic_outline_keyboard_hide_24.xml diff --git a/app/src/main/res/drawable/ic_outline_link_24.xml b/base/src/main/res/drawable/ic_outline_link_24.xml similarity index 100% rename from app/src/main/res/drawable/ic_outline_link_24.xml rename to base/src/main/res/drawable/ic_outline_link_24.xml diff --git a/app/src/main/res/drawable/ic_outline_lock_24.xml b/base/src/main/res/drawable/ic_outline_lock_24.xml similarity index 100% rename from app/src/main/res/drawable/ic_outline_lock_24.xml rename to base/src/main/res/drawable/ic_outline_lock_24.xml diff --git a/app/src/main/res/drawable/ic_outline_lock_open_24.xml b/base/src/main/res/drawable/ic_outline_lock_open_24.xml similarity index 100% rename from app/src/main/res/drawable/ic_outline_lock_open_24.xml rename to base/src/main/res/drawable/ic_outline_lock_open_24.xml diff --git a/app/src/main/res/drawable/ic_outline_more_vert_24.xml b/base/src/main/res/drawable/ic_outline_more_vert_24.xml similarity index 100% rename from app/src/main/res/drawable/ic_outline_more_vert_24.xml rename to base/src/main/res/drawable/ic_outline_more_vert_24.xml diff --git a/app/src/main/res/drawable/ic_outline_nfc_24.xml b/base/src/main/res/drawable/ic_outline_nfc_24.xml similarity index 100% rename from app/src/main/res/drawable/ic_outline_nfc_24.xml rename to base/src/main/res/drawable/ic_outline_nfc_24.xml diff --git a/app/src/main/res/drawable/ic_outline_open_in_new_24.xml b/base/src/main/res/drawable/ic_outline_open_in_new_24.xml similarity index 100% rename from app/src/main/res/drawable/ic_outline_open_in_new_24.xml rename to base/src/main/res/drawable/ic_outline_open_in_new_24.xml diff --git a/app/src/main/res/drawable/ic_outline_pause_24.xml b/base/src/main/res/drawable/ic_outline_pause_24.xml similarity index 100% rename from app/src/main/res/drawable/ic_outline_pause_24.xml rename to base/src/main/res/drawable/ic_outline_pause_24.xml diff --git a/app/src/main/res/drawable/ic_outline_pinch_app_24.xml b/base/src/main/res/drawable/ic_outline_pinch_app_24.xml similarity index 100% rename from app/src/main/res/drawable/ic_outline_pinch_app_24.xml rename to base/src/main/res/drawable/ic_outline_pinch_app_24.xml diff --git a/app/src/main/res/drawable/ic_outline_play_arrow_24.xml b/base/src/main/res/drawable/ic_outline_play_arrow_24.xml similarity index 100% rename from app/src/main/res/drawable/ic_outline_play_arrow_24.xml rename to base/src/main/res/drawable/ic_outline_play_arrow_24.xml diff --git a/app/src/main/res/drawable/ic_outline_power_settings_new_24.xml b/base/src/main/res/drawable/ic_outline_power_settings_new_24.xml similarity index 100% rename from app/src/main/res/drawable/ic_outline_power_settings_new_24.xml rename to base/src/main/res/drawable/ic_outline_power_settings_new_24.xml diff --git a/app/src/main/res/drawable/ic_outline_privacy_tip_24.xml b/base/src/main/res/drawable/ic_outline_privacy_tip_24.xml similarity index 100% rename from app/src/main/res/drawable/ic_outline_privacy_tip_24.xml rename to base/src/main/res/drawable/ic_outline_privacy_tip_24.xml diff --git a/app/src/main/res/drawable/ic_outline_refresh_64.xml b/base/src/main/res/drawable/ic_outline_refresh_64.xml similarity index 100% rename from app/src/main/res/drawable/ic_outline_refresh_64.xml rename to base/src/main/res/drawable/ic_outline_refresh_64.xml diff --git a/app/src/main/res/drawable/ic_outline_save_24.xml b/base/src/main/res/drawable/ic_outline_save_24.xml similarity index 100% rename from app/src/main/res/drawable/ic_outline_save_24.xml rename to base/src/main/res/drawable/ic_outline_save_24.xml diff --git a/app/src/main/res/drawable/ic_outline_screen_lock_rotation_24.xml b/base/src/main/res/drawable/ic_outline_screen_lock_rotation_24.xml similarity index 100% rename from app/src/main/res/drawable/ic_outline_screen_lock_rotation_24.xml rename to base/src/main/res/drawable/ic_outline_screen_lock_rotation_24.xml diff --git a/app/src/main/res/drawable/ic_outline_screen_rotation_24.xml b/base/src/main/res/drawable/ic_outline_screen_rotation_24.xml similarity index 100% rename from app/src/main/res/drawable/ic_outline_screen_rotation_24.xml rename to base/src/main/res/drawable/ic_outline_screen_rotation_24.xml diff --git a/app/src/main/res/drawable/ic_outline_search_24.xml b/base/src/main/res/drawable/ic_outline_search_24.xml similarity index 100% rename from app/src/main/res/drawable/ic_outline_search_24.xml rename to base/src/main/res/drawable/ic_outline_search_24.xml diff --git a/app/src/main/res/drawable/ic_outline_settings_24.xml b/base/src/main/res/drawable/ic_outline_settings_24.xml similarity index 100% rename from app/src/main/res/drawable/ic_outline_settings_24.xml rename to base/src/main/res/drawable/ic_outline_settings_24.xml diff --git a/app/src/main/res/drawable/ic_outline_settings_applications_24.xml b/base/src/main/res/drawable/ic_outline_settings_applications_24.xml similarity index 100% rename from app/src/main/res/drawable/ic_outline_settings_applications_24.xml rename to base/src/main/res/drawable/ic_outline_settings_applications_24.xml diff --git a/app/src/main/res/drawable/ic_outline_share_64.xml b/base/src/main/res/drawable/ic_outline_share_64.xml similarity index 100% rename from app/src/main/res/drawable/ic_outline_share_64.xml rename to base/src/main/res/drawable/ic_outline_share_64.xml diff --git a/app/src/main/res/drawable/ic_outline_short_text_24.xml b/base/src/main/res/drawable/ic_outline_short_text_24.xml similarity index 100% rename from app/src/main/res/drawable/ic_outline_short_text_24.xml rename to base/src/main/res/drawable/ic_outline_short_text_24.xml diff --git a/app/src/main/res/drawable/ic_outline_signal_cellular_4_bar_24.xml b/base/src/main/res/drawable/ic_outline_signal_cellular_4_bar_24.xml similarity index 100% rename from app/src/main/res/drawable/ic_outline_signal_cellular_4_bar_24.xml rename to base/src/main/res/drawable/ic_outline_signal_cellular_4_bar_24.xml diff --git a/app/src/main/res/drawable/ic_outline_signal_cellular_off_24.xml b/base/src/main/res/drawable/ic_outline_signal_cellular_off_24.xml similarity index 100% rename from app/src/main/res/drawable/ic_outline_signal_cellular_off_24.xml rename to base/src/main/res/drawable/ic_outline_signal_cellular_off_24.xml diff --git a/app/src/main/res/drawable/ic_outline_signal_wifi_statusbar_null_24.xml b/base/src/main/res/drawable/ic_outline_signal_wifi_statusbar_null_24.xml similarity index 100% rename from app/src/main/res/drawable/ic_outline_signal_wifi_statusbar_null_24.xml rename to base/src/main/res/drawable/ic_outline_signal_wifi_statusbar_null_24.xml diff --git a/app/src/main/res/drawable/ic_outline_skip_next_24.xml b/base/src/main/res/drawable/ic_outline_skip_next_24.xml similarity index 100% rename from app/src/main/res/drawable/ic_outline_skip_next_24.xml rename to base/src/main/res/drawable/ic_outline_skip_next_24.xml diff --git a/app/src/main/res/drawable/ic_outline_skip_previous_24.xml b/base/src/main/res/drawable/ic_outline_skip_previous_24.xml similarity index 100% rename from app/src/main/res/drawable/ic_outline_skip_previous_24.xml rename to base/src/main/res/drawable/ic_outline_skip_previous_24.xml diff --git a/app/src/main/res/drawable/ic_outline_star_border_24.xml b/base/src/main/res/drawable/ic_outline_star_border_24.xml similarity index 100% rename from app/src/main/res/drawable/ic_outline_star_border_24.xml rename to base/src/main/res/drawable/ic_outline_star_border_24.xml diff --git a/app/src/main/res/drawable/ic_outline_star_rate_24.xml b/base/src/main/res/drawable/ic_outline_star_rate_24.xml similarity index 100% rename from app/src/main/res/drawable/ic_outline_star_rate_24.xml rename to base/src/main/res/drawable/ic_outline_star_rate_24.xml diff --git a/app/src/main/res/drawable/ic_outline_stay_current_landscape_24.xml b/base/src/main/res/drawable/ic_outline_stay_current_landscape_24.xml similarity index 100% rename from app/src/main/res/drawable/ic_outline_stay_current_landscape_24.xml rename to base/src/main/res/drawable/ic_outline_stay_current_landscape_24.xml diff --git a/app/src/main/res/drawable/ic_outline_stay_current_portrait_24.xml b/base/src/main/res/drawable/ic_outline_stay_current_portrait_24.xml similarity index 100% rename from app/src/main/res/drawable/ic_outline_stay_current_portrait_24.xml rename to base/src/main/res/drawable/ic_outline_stay_current_portrait_24.xml diff --git a/app/src/main/res/drawable/ic_outline_stop_circle_24.xml b/base/src/main/res/drawable/ic_outline_stop_circle_24.xml similarity index 100% rename from app/src/main/res/drawable/ic_outline_stop_circle_24.xml rename to base/src/main/res/drawable/ic_outline_stop_circle_24.xml diff --git a/app/src/main/res/drawable/ic_outline_swipe_app_24.xml b/base/src/main/res/drawable/ic_outline_swipe_app_24.xml similarity index 100% rename from app/src/main/res/drawable/ic_outline_swipe_app_24.xml rename to base/src/main/res/drawable/ic_outline_swipe_app_24.xml diff --git a/app/src/main/res/drawable/ic_outline_touch_app_24.xml b/base/src/main/res/drawable/ic_outline_touch_app_24.xml similarity index 100% rename from app/src/main/res/drawable/ic_outline_touch_app_24.xml rename to base/src/main/res/drawable/ic_outline_touch_app_24.xml diff --git a/app/src/main/res/drawable/ic_outline_translate_24.xml b/base/src/main/res/drawable/ic_outline_translate_24.xml similarity index 100% rename from app/src/main/res/drawable/ic_outline_translate_24.xml rename to base/src/main/res/drawable/ic_outline_translate_24.xml diff --git a/app/src/main/res/drawable/ic_outline_vibration_24.xml b/base/src/main/res/drawable/ic_outline_vibration_24.xml similarity index 100% rename from app/src/main/res/drawable/ic_outline_vibration_24.xml rename to base/src/main/res/drawable/ic_outline_vibration_24.xml diff --git a/app/src/main/res/drawable/ic_outline_volume_down_24.xml b/base/src/main/res/drawable/ic_outline_volume_down_24.xml similarity index 100% rename from app/src/main/res/drawable/ic_outline_volume_down_24.xml rename to base/src/main/res/drawable/ic_outline_volume_down_24.xml diff --git a/app/src/main/res/drawable/ic_outline_volume_mute_24.xml b/base/src/main/res/drawable/ic_outline_volume_mute_24.xml similarity index 100% rename from app/src/main/res/drawable/ic_outline_volume_mute_24.xml rename to base/src/main/res/drawable/ic_outline_volume_mute_24.xml diff --git a/app/src/main/res/drawable/ic_outline_volume_up_24.xml b/base/src/main/res/drawable/ic_outline_volume_up_24.xml similarity index 100% rename from app/src/main/res/drawable/ic_outline_volume_up_24.xml rename to base/src/main/res/drawable/ic_outline_volume_up_24.xml diff --git a/app/src/main/res/drawable/ic_outline_wifi_24.xml b/base/src/main/res/drawable/ic_outline_wifi_24.xml similarity index 100% rename from app/src/main/res/drawable/ic_outline_wifi_24.xml rename to base/src/main/res/drawable/ic_outline_wifi_24.xml diff --git a/app/src/main/res/drawable/ic_outline_wifi_off_24.xml b/base/src/main/res/drawable/ic_outline_wifi_off_24.xml similarity index 100% rename from app/src/main/res/drawable/ic_outline_wifi_off_24.xml rename to base/src/main/res/drawable/ic_outline_wifi_off_24.xml diff --git a/app/src/main/res/drawable/ic_permission_input_method.xml b/base/src/main/res/drawable/ic_permission_input_method.xml similarity index 100% rename from app/src/main/res/drawable/ic_permission_input_method.xml rename to base/src/main/res/drawable/ic_permission_input_method.xml diff --git a/app/src/main/res/drawable/ic_play_pause_24dp.xml b/base/src/main/res/drawable/ic_play_pause_24dp.xml similarity index 100% rename from app/src/main/res/drawable/ic_play_pause_24dp.xml rename to base/src/main/res/drawable/ic_play_pause_24dp.xml diff --git a/app/src/main/res/drawable/ic_q_24.xml b/base/src/main/res/drawable/ic_q_24.xml similarity index 100% rename from app/src/main/res/drawable/ic_q_24.xml rename to base/src/main/res/drawable/ic_q_24.xml diff --git a/app/src/main/res/drawable/ic_script_text_outline.xml b/base/src/main/res/drawable/ic_script_text_outline.xml similarity index 100% rename from app/src/main/res/drawable/ic_script_text_outline.xml rename to base/src/main/res/drawable/ic_script_text_outline.xml diff --git a/app/src/main/res/drawable/ic_search_black_24dp.xml b/base/src/main/res/drawable/ic_search_black_24dp.xml similarity index 100% rename from app/src/main/res/drawable/ic_search_black_24dp.xml rename to base/src/main/res/drawable/ic_search_black_24dp.xml diff --git a/app/src/main/res/drawable/ic_sort_24.xml b/base/src/main/res/drawable/ic_sort_24.xml similarity index 100% rename from app/src/main/res/drawable/ic_sort_24.xml rename to base/src/main/res/drawable/ic_sort_24.xml diff --git a/app/src/main/res/drawable/ic_tile_error.xml b/base/src/main/res/drawable/ic_tile_error.xml similarity index 100% rename from app/src/main/res/drawable/ic_tile_error.xml rename to base/src/main/res/drawable/ic_tile_error.xml diff --git a/app/src/main/res/drawable/ic_tile_keyboard.xml b/base/src/main/res/drawable/ic_tile_keyboard.xml similarity index 100% rename from app/src/main/res/drawable/ic_tile_keyboard.xml rename to base/src/main/res/drawable/ic_tile_keyboard.xml diff --git a/app/src/main/res/drawable/ic_tile_pause.xml b/base/src/main/res/drawable/ic_tile_pause.xml similarity index 100% rename from app/src/main/res/drawable/ic_tile_pause.xml rename to base/src/main/res/drawable/ic_tile_pause.xml diff --git a/app/src/main/res/drawable/ic_tile_resume.xml b/base/src/main/res/drawable/ic_tile_resume.xml similarity index 100% rename from app/src/main/res/drawable/ic_tile_resume.xml rename to base/src/main/res/drawable/ic_tile_resume.xml diff --git a/app/src/main/res/drawable/outline_bubble_chart_24.xml b/base/src/main/res/drawable/outline_bubble_chart_24.xml similarity index 100% rename from app/src/main/res/drawable/outline_bubble_chart_24.xml rename to base/src/main/res/drawable/outline_bubble_chart_24.xml diff --git a/app/src/main/res/drawable/profile_pic_bydario.png b/base/src/main/res/drawable/profile_pic_bydario.png similarity index 100% rename from app/src/main/res/drawable/profile_pic_bydario.png rename to base/src/main/res/drawable/profile_pic_bydario.png diff --git a/app/src/main/res/drawable/profile_pic_jambl3r.jpg b/base/src/main/res/drawable/profile_pic_jambl3r.jpg similarity index 100% rename from app/src/main/res/drawable/profile_pic_jambl3r.jpg rename to base/src/main/res/drawable/profile_pic_jambl3r.jpg diff --git a/app/src/main/res/drawable/profile_pic_kekero.png b/base/src/main/res/drawable/profile_pic_kekero.png similarity index 100% rename from app/src/main/res/drawable/profile_pic_kekero.png rename to base/src/main/res/drawable/profile_pic_kekero.png diff --git a/app/src/main/res/drawable/profile_pic_sds100.jpeg b/base/src/main/res/drawable/profile_pic_sds100.jpeg similarity index 100% rename from app/src/main/res/drawable/profile_pic_sds100.jpeg rename to base/src/main/res/drawable/profile_pic_sds100.jpeg diff --git a/app/src/main/res/drawable/round_folder_open_24.xml b/base/src/main/res/drawable/round_folder_open_24.xml similarity index 100% rename from app/src/main/res/drawable/round_folder_open_24.xml rename to base/src/main/res/drawable/round_folder_open_24.xml diff --git a/app/src/main/res/layout/activity_main.xml b/base/src/main/res/layout/activity_main.xml similarity index 88% rename from app/src/main/res/layout/activity_main.xml rename to base/src/main/res/layout/activity_main.xml index bab9f10586..1c30b5bf2b 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/base/src/main/res/layout/activity_main.xml @@ -13,7 +13,6 @@ android:name="androidx.navigation.fragment.NavHostFragment" android:layout_width="match_parent" android:layout_height="match_parent" - app:defaultNavHost="true" - app:navGraph="@navigation/nav_app" /> + app:defaultNavHost="true" /> \ No newline at end of file diff --git a/app/src/main/res/layout/app_bar_recyclerview_fragment.xml b/base/src/main/res/layout/app_bar_recyclerview_fragment.xml similarity index 100% rename from app/src/main/res/layout/app_bar_recyclerview_fragment.xml rename to base/src/main/res/layout/app_bar_recyclerview_fragment.xml diff --git a/app/src/main/res/layout/dialog_choose_app_store.xml b/base/src/main/res/layout/dialog_choose_app_store.xml similarity index 95% rename from app/src/main/res/layout/dialog_choose_app_store.xml rename to base/src/main/res/layout/dialog_choose_app_store.xml index e42cff3567..af7de866af 100644 --- a/app/src/main/res/layout/dialog_choose_app_store.xml +++ b/base/src/main/res/layout/dialog_choose_app_store.xml @@ -8,7 +8,7 @@ + type="io.github.sds100.keymapper.base.utils.ui.ChooseAppStoreModel" /> + type="io.github.sds100.keymapper.base.system.apps.ChooseAppViewModel" /> + type="io.github.sds100.keymapper.base.actions.sound.ChooseSoundFileViewModel" /> diff --git a/app/src/main/res/layout/fragment_compose.xml b/base/src/main/res/layout/fragment_compose.xml similarity index 100% rename from app/src/main/res/layout/fragment_compose.xml rename to base/src/main/res/layout/fragment_compose.xml diff --git a/app/src/main/res/layout/fragment_compose_view.xml b/base/src/main/res/layout/fragment_compose_view.xml similarity index 100% rename from app/src/main/res/layout/fragment_compose_view.xml rename to base/src/main/res/layout/fragment_compose_view.xml diff --git a/app/src/main/res/layout/fragment_config_intent.xml b/base/src/main/res/layout/fragment_config_intent.xml similarity index 99% rename from app/src/main/res/layout/fragment_config_intent.xml rename to base/src/main/res/layout/fragment_config_intent.xml index ab9d2d0e59..1fc72d7cf4 100644 --- a/app/src/main/res/layout/fragment_config_intent.xml +++ b/base/src/main/res/layout/fragment_config_intent.xml @@ -9,7 +9,7 @@ + type="io.github.sds100.keymapper.base.system.intents.ConfigIntentViewModel" /> + type="io.github.sds100.keymapper.base.actions.keyevent.ConfigKeyEventActionViewModel" /> + type="io.github.sds100.keymapper.base.actions.tapscreen.PickDisplayCoordinateViewModel" /> - + type="io.github.sds100.keymapper.base.actions.pinchscreen.PinchPickDisplayCoordinateViewModel" /> - + type="io.github.sds100.keymapper.base.actions.swipescreen.SwipePickDisplayCoordinateViewModel" /> - + type="io.github.sds100.keymapper.base.utils.ui.CheckBoxListItem" /> + type="io.github.sds100.keymapper.base.utils.ui.TextListItem.Error" /> - + + type="io.github.sds100.keymapper.base.logging.LogEntryListItem" /> + type="io.github.sds100.keymapper.base.utils.ui.RadioButtonPairListItem" /> + type="io.github.sds100.keymapper.base.utils.ui.RadioButtonTripleListItem" /> + type="io.github.sds100.keymapper.base.utils.ui.SimpleListItemOld" /> + - - - - - - - - - - - - + android:id="@+id/nav_base_app"> - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/navigation/nav_settings.xml b/base/src/main/res/navigation/nav_settings.xml similarity index 83% rename from app/src/main/res/navigation/nav_settings.xml rename to base/src/main/res/navigation/nav_settings.xml index b8459151be..fbca7f6d25 100644 --- a/app/src/main/res/navigation/nav_settings.xml +++ b/base/src/main/res/navigation/nav_settings.xml @@ -6,7 +6,7 @@ + android:name="io.github.sds100.keymapper.base.settings.AutomaticallyChangeImeSettings" /> \ No newline at end of file diff --git a/app/src/main/res/raw/caps_camera.kcm b/base/src/main/res/raw/caps_camera.kcm similarity index 100% rename from app/src/main/res/raw/caps_camera.kcm rename to base/src/main/res/raw/caps_camera.kcm diff --git a/app/src/main/res/values-night/colors.xml b/base/src/main/res/values-night/colors.xml similarity index 100% rename from app/src/main/res/values-night/colors.xml rename to base/src/main/res/values-night/colors.xml diff --git a/app/src/main/res/values-tr/strings.xml b/base/src/main/res/values-tr/strings.xml similarity index 100% rename from app/src/main/res/values-tr/strings.xml rename to base/src/main/res/values-tr/strings.xml diff --git a/app/src/main/res/values/anim.xml b/base/src/main/res/values/anim.xml similarity index 100% rename from app/src/main/res/values/anim.xml rename to base/src/main/res/values/anim.xml diff --git a/app/src/main/res/values/colors.xml b/base/src/main/res/values/colors.xml similarity index 100% rename from app/src/main/res/values/colors.xml rename to base/src/main/res/values/colors.xml diff --git a/app/src/main/res/values/dimens.xml b/base/src/main/res/values/dimens.xml similarity index 100% rename from app/src/main/res/values/dimens.xml rename to base/src/main/res/values/dimens.xml diff --git a/base/src/main/res/values/navigation.xml b/base/src/main/res/values/navigation.xml new file mode 100644 index 0000000000..9e63c70d1e --- /dev/null +++ b/base/src/main/res/values/navigation.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/values/prefs.xml b/base/src/main/res/values/prefs.xml similarity index 100% rename from app/src/main/res/values/prefs.xml rename to base/src/main/res/values/prefs.xml diff --git a/app/src/main/res/values/strings.xml b/base/src/main/res/values/strings.xml similarity index 100% rename from app/src/main/res/values/strings.xml rename to base/src/main/res/values/strings.xml diff --git a/app/src/main/res/values/styles.xml b/base/src/main/res/values/styles.xml similarity index 100% rename from app/src/main/res/values/styles.xml rename to base/src/main/res/values/styles.xml diff --git a/app/src/main/res/values/themes.xml b/base/src/main/res/values/themes.xml similarity index 100% rename from app/src/main/res/values/themes.xml rename to base/src/main/res/values/themes.xml diff --git a/app/src/main/res/xml/config_accessibility_service.xml b/base/src/main/res/xml/config_accessibility_service.xml similarity index 100% rename from app/src/main/res/xml/config_accessibility_service.xml rename to base/src/main/res/xml/config_accessibility_service.xml diff --git a/app/src/main/res/xml/preferences_empty.xml b/base/src/main/res/xml/preferences_empty.xml similarity index 100% rename from app/src/main/res/xml/preferences_empty.xml rename to base/src/main/res/xml/preferences_empty.xml diff --git a/app/src/main/res/xml/provider_paths.xml b/base/src/main/res/xml/provider_paths.xml similarity index 100% rename from app/src/main/res/xml/provider_paths.xml rename to base/src/main/res/xml/provider_paths.xml diff --git a/app/src/test/java/io/github/sds100/keymapper/BackupManagerTest.kt b/base/src/test/java/io/github/sds100/keymapper/base/BackupManagerTest.kt similarity index 93% rename from app/src/test/java/io/github/sds100/keymapper/BackupManagerTest.kt rename to base/src/test/java/io/github/sds100/keymapper/base/BackupManagerTest.kt index 07815d2b57..6541b1a811 100644 --- a/app/src/test/java/io/github/sds100/keymapper/BackupManagerTest.kt +++ b/base/src/test/java/io/github/sds100/keymapper/base/BackupManagerTest.kt @@ -1,13 +1,21 @@ -package io.github.sds100.keymapper +package io.github.sds100.keymapper.base import com.github.salomonbrys.kotson.get import com.google.gson.Gson import com.google.gson.JsonParser -import io.github.sds100.keymapper.actions.sound.SoundFileInfo -import io.github.sds100.keymapper.actions.sound.SoundsManager -import io.github.sds100.keymapper.backup.BackupContent -import io.github.sds100.keymapper.backup.BackupManagerImpl -import io.github.sds100.keymapper.backup.RestoreType +import io.github.sds100.keymapper.base.actions.sound.SoundFileInfo +import io.github.sds100.keymapper.base.actions.sound.SoundsManager +import io.github.sds100.keymapper.base.backup.BackupContent +import io.github.sds100.keymapper.base.backup.BackupManagerImpl +import io.github.sds100.keymapper.base.backup.RestoreType +import io.github.sds100.keymapper.base.repositories.FakePreferenceRepository +import io.github.sds100.keymapper.base.system.files.FakeFileAdapter +import io.github.sds100.keymapper.base.system.files.JavaFile +import io.github.sds100.keymapper.base.utils.TestBuildConfigProvider +import io.github.sds100.keymapper.common.utils.KMError +import io.github.sds100.keymapper.common.utils.State +import io.github.sds100.keymapper.common.utils.Success +import io.github.sds100.keymapper.common.utils.UuidGenerator import io.github.sds100.keymapper.data.db.AppDatabase import io.github.sds100.keymapper.data.entities.ActionEntity import io.github.sds100.keymapper.data.entities.EntityExtra @@ -16,18 +24,11 @@ import io.github.sds100.keymapper.data.entities.FloatingLayoutEntity import io.github.sds100.keymapper.data.entities.FloatingLayoutEntityWithButtons import io.github.sds100.keymapper.data.entities.GroupEntity import io.github.sds100.keymapper.data.entities.KeyMapEntity -import io.github.sds100.keymapper.data.repositories.FakePreferenceRepository import io.github.sds100.keymapper.data.repositories.FloatingLayoutRepository import io.github.sds100.keymapper.data.repositories.GroupRepository +import io.github.sds100.keymapper.data.repositories.KeyMapRepository import io.github.sds100.keymapper.data.repositories.PreferenceRepository -import io.github.sds100.keymapper.keymaps.KeyMapRepository -import io.github.sds100.keymapper.system.files.FakeFileAdapter import io.github.sds100.keymapper.system.files.IFile -import io.github.sds100.keymapper.system.files.JavaFile -import io.github.sds100.keymapper.util.Error -import io.github.sds100.keymapper.util.State -import io.github.sds100.keymapper.util.Success -import io.github.sds100.keymapper.util.UuidGenerator import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.MutableStateFlow @@ -61,10 +62,6 @@ import org.mockito.kotlin.whenever import timber.log.Timber import java.io.File -/** - * Created by sds100 on 19/04/2021. - */ - @Suppress("BlockingMethodInNonBlockingContext") @ExperimentalCoroutinesApi @RunWith(MockitoJUnitRunner::class) @@ -116,7 +113,6 @@ class BackupManagerTest { fileAdapter = fakeFileAdapter, keyMapRepository = mockKeyMapRepository, preferenceRepository = fakePreferenceRepository, - throwExceptions = true, dispatchers = dispatcherProvider, soundsManager = mockSoundsManager, uuidGenerator = mockUuidGenerator, @@ -125,6 +121,7 @@ class BackupManagerTest { on { layouts } doReturn MutableStateFlow(State.Data(emptyList())) }, groupRepository = mockGroupRepository, + buildConfigProvider = TestBuildConfigProvider(), ) parser = JsonParser() @@ -149,7 +146,7 @@ class BackupManagerTest { lastOpenedDate = 0L, ) - val parentGroup2 = GroupEntity( + GroupEntity( uid = "parent_group_2_uid", name = "parent_group_2_name", parentUid = null, @@ -171,7 +168,7 @@ class BackupManagerTest { ) val backupContent = BackupContent( - appVersion = Constants.VERSION_CODE, + appVersion = BuildConfig.VERSION_CODE, dbVersion = AppDatabase.DATABASE_VERSION, groups = listOf(childGroup, grandChildGroup, parentGroup1), ) @@ -226,7 +223,7 @@ class BackupManagerTest { ) val backupContent = BackupContent( - appVersion = Constants.VERSION_CODE, + appVersion = BuildConfig.VERSION_CODE, dbVersion = AppDatabase.DATABASE_VERSION, groups = listOf(parentGroup2, grandChildGroup, childGroup, parentGroup1), ) @@ -318,7 +315,7 @@ class BackupManagerTest { advanceUntilIdle() // THEN - assertThat(result, `is`(Error.BackupVersionTooNew)) + assertThat(result, `is`(KMError.BackupVersionTooNew)) } /** @@ -542,7 +539,7 @@ class BackupManagerTest { val result = backupManager.restore(copyFileToPrivateFolder(fileName), RestoreType.REPLACE) - assertThat(result, `is`(Error.BackupVersionTooNew)) + assertThat(result, `is`(KMError.BackupVersionTooNew)) verify(mockKeyMapRepository, never()).insert(anyVararg()) } @@ -553,7 +550,7 @@ class BackupManagerTest { val result = backupManager.restore(copyFileToPrivateFolder(fileName), RestoreType.REPLACE) - assertThat(result, `is`(Error.BackupVersionTooNew)) + assertThat(result, `is`(KMError.BackupVersionTooNew)) } @Test @@ -562,7 +559,7 @@ class BackupManagerTest { val result = backupManager.restore(copyFileToPrivateFolder(fileName), RestoreType.REPLACE) - assertThat(result, `is`(Error.EmptyJson)) + assertThat(result, `is`(KMError.EmptyJson)) } @Test @@ -571,7 +568,7 @@ class BackupManagerTest { val result = backupManager.restore(copyFileToPrivateFolder(fileName), RestoreType.REPLACE) - assertThat(result, IsInstanceOf(Error.CorruptJsonFile::class.java)) + assertThat(result, IsInstanceOf(KMError.CorruptJsonFile::class.java)) } @Test diff --git a/app/src/test/java/io/github/sds100/keymapper/ConfigKeyMapUseCaseTest.kt b/base/src/test/java/io/github/sds100/keymapper/base/ConfigKeyMapUseCaseTest.kt similarity index 92% rename from app/src/test/java/io/github/sds100/keymapper/ConfigKeyMapUseCaseTest.kt rename to base/src/test/java/io/github/sds100/keymapper/base/ConfigKeyMapUseCaseTest.kt index d80b0cbe1e..3d57377e3d 100644 --- a/app/src/test/java/io/github/sds100/keymapper/ConfigKeyMapUseCaseTest.kt +++ b/base/src/test/java/io/github/sds100/keymapper/base/ConfigKeyMapUseCaseTest.kt @@ -1,24 +1,24 @@ -package io.github.sds100.keymapper +package io.github.sds100.keymapper.base import android.view.KeyEvent -import io.github.sds100.keymapper.actions.Action -import io.github.sds100.keymapper.actions.ActionData -import io.github.sds100.keymapper.constraints.Constraint -import io.github.sds100.keymapper.keymaps.ClickType -import io.github.sds100.keymapper.keymaps.ConfigKeyMapUseCaseController -import io.github.sds100.keymapper.keymaps.FingerprintGestureType -import io.github.sds100.keymapper.keymaps.KeyMap +import io.github.sds100.keymapper.base.actions.Action +import io.github.sds100.keymapper.base.actions.ActionData +import io.github.sds100.keymapper.base.constraints.Constraint +import io.github.sds100.keymapper.base.keymaps.ClickType +import io.github.sds100.keymapper.base.keymaps.ConfigKeyMapUseCaseController +import io.github.sds100.keymapper.base.keymaps.KeyMap +import io.github.sds100.keymapper.base.system.accessibility.FingerprintGestureType +import io.github.sds100.keymapper.base.trigger.AssistantTriggerKey +import io.github.sds100.keymapper.base.trigger.AssistantTriggerType +import io.github.sds100.keymapper.base.trigger.KeyEventDetectionSource +import io.github.sds100.keymapper.base.trigger.Trigger +import io.github.sds100.keymapper.base.trigger.TriggerKeyDevice +import io.github.sds100.keymapper.base.trigger.TriggerMode +import io.github.sds100.keymapper.base.utils.singleKeyTrigger +import io.github.sds100.keymapper.base.utils.triggerKey +import io.github.sds100.keymapper.common.utils.State +import io.github.sds100.keymapper.common.utils.dataOrNull import io.github.sds100.keymapper.system.inputevents.InputEventUtils -import io.github.sds100.keymapper.trigger.AssistantTriggerKey -import io.github.sds100.keymapper.trigger.AssistantTriggerType -import io.github.sds100.keymapper.trigger.KeyEventDetectionSource -import io.github.sds100.keymapper.trigger.Trigger -import io.github.sds100.keymapper.trigger.TriggerKeyDevice -import io.github.sds100.keymapper.trigger.TriggerMode -import io.github.sds100.keymapper.util.State -import io.github.sds100.keymapper.util.dataOrNull -import io.github.sds100.keymapper.util.singleKeyTrigger -import io.github.sds100.keymapper.util.triggerKey import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.UnconfinedTestDispatcher @@ -32,10 +32,6 @@ import org.junit.Before import org.junit.Test import org.mockito.kotlin.mock -/** - * Created by sds100 on 19/04/2021. - */ - @ExperimentalCoroutinesApi class ConfigKeyMapUseCaseTest { @@ -237,7 +233,7 @@ class ConfigKeyMapUseCaseTest { assertThat(trigger.keys, hasSize(2)) assertThat( trigger.keys[0], - instanceOf(_root_ide_package_.io.github.sds100.keymapper.trigger.KeyCodeTriggerKey::class.java), + instanceOf(io.github.sds100.keymapper.base.trigger.KeyCodeTriggerKey::class.java), ) assertThat(trigger.keys[1], instanceOf(AssistantTriggerKey::class.java)) } @@ -259,7 +255,7 @@ class ConfigKeyMapUseCaseTest { assertThat(trigger.keys, hasSize(2)) assertThat( trigger.keys[0], - instanceOf(_root_ide_package_.io.github.sds100.keymapper.trigger.KeyCodeTriggerKey::class.java), + instanceOf(io.github.sds100.keymapper.base.trigger.KeyCodeTriggerKey::class.java), ) assertThat(trigger.keys[1], instanceOf(AssistantTriggerKey::class.java)) } diff --git a/app/src/test/java/io/github/sds100/keymapper/KeyMapJsonMigrationTest.kt b/base/src/test/java/io/github/sds100/keymapper/base/KeyMapJsonMigrationTest.kt similarity index 97% rename from app/src/test/java/io/github/sds100/keymapper/KeyMapJsonMigrationTest.kt rename to base/src/test/java/io/github/sds100/keymapper/base/KeyMapJsonMigrationTest.kt index 3c028b19b1..b995839e32 100644 --- a/app/src/test/java/io/github/sds100/keymapper/KeyMapJsonMigrationTest.kt +++ b/base/src/test/java/io/github/sds100/keymapper/base/KeyMapJsonMigrationTest.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper +package io.github.sds100.keymapper.base import androidx.arch.core.executor.testing.InstantTaskExecutorRule import com.github.salomonbrys.kotson.get @@ -6,12 +6,12 @@ import com.github.salomonbrys.kotson.toJsonArray import com.google.gson.Gson import com.google.gson.JsonArray import com.google.gson.JsonParser +import io.github.sds100.keymapper.base.utils.JsonTestUtils import io.github.sds100.keymapper.data.migration.JsonMigration import io.github.sds100.keymapper.data.migration.Migration10To11 import io.github.sds100.keymapper.data.migration.Migration11To12 import io.github.sds100.keymapper.data.migration.Migration9To10 import io.github.sds100.keymapper.data.migration.MigrationUtils -import io.github.sds100.keymapper.util.JsonTestUtils import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.UnconfinedTestDispatcher @@ -21,10 +21,6 @@ import org.junit.Rule import org.junit.Test import java.io.InputStream -/** - * Created by sds100 on 22/01/21. - */ - @ExperimentalCoroutinesApi class KeyMapJsonMigrationTest { companion object { diff --git a/app/src/test/java/io/github/sds100/keymapper/LegacyFingerprintMapMigrationTest.kt b/base/src/test/java/io/github/sds100/keymapper/base/LegacyFingerprintMapMigrationTest.kt similarity index 97% rename from app/src/test/java/io/github/sds100/keymapper/LegacyFingerprintMapMigrationTest.kt rename to base/src/test/java/io/github/sds100/keymapper/base/LegacyFingerprintMapMigrationTest.kt index 8c5f6813f6..c0b043b365 100644 --- a/app/src/test/java/io/github/sds100/keymapper/LegacyFingerprintMapMigrationTest.kt +++ b/base/src/test/java/io/github/sds100/keymapper/base/LegacyFingerprintMapMigrationTest.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper +package io.github.sds100.keymapper.base import androidx.arch.core.executor.testing.InstantTaskExecutorRule import androidx.datastore.preferences.core.stringPreferencesKey @@ -8,11 +8,11 @@ import com.google.gson.Gson import com.google.gson.JsonArray import com.google.gson.JsonObject import com.google.gson.JsonParser +import io.github.sds100.keymapper.base.utils.JsonTestUtils import io.github.sds100.keymapper.data.migration.JsonMigration import io.github.sds100.keymapper.data.migration.MigrationUtils import io.github.sds100.keymapper.data.migration.fingerprintmaps.FingerprintMapMigration0To1 import io.github.sds100.keymapper.data.migration.fingerprintmaps.FingerprintMapMigration1To2 -import io.github.sds100.keymapper.util.JsonTestUtils import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.UnconfinedTestDispatcher @@ -22,10 +22,6 @@ import org.junit.Rule import org.junit.Test import java.io.InputStream -/** - * Created by sds100 on 22/01/21. - */ - @ExperimentalCoroutinesApi class LegacyFingerprintMapMigrationTest { companion object { diff --git a/app/src/test/java/io/github/sds100/keymapper/TestDispatcherProvider.kt b/base/src/test/java/io/github/sds100/keymapper/base/TestDispatcherProvider.kt similarity index 70% rename from app/src/test/java/io/github/sds100/keymapper/TestDispatcherProvider.kt rename to base/src/test/java/io/github/sds100/keymapper/base/TestDispatcherProvider.kt index f1384aba31..3afb5bf624 100644 --- a/app/src/test/java/io/github/sds100/keymapper/TestDispatcherProvider.kt +++ b/base/src/test/java/io/github/sds100/keymapper/base/TestDispatcherProvider.kt @@ -1,12 +1,8 @@ -package io.github.sds100.keymapper +package io.github.sds100.keymapper.base -import io.github.sds100.keymapper.util.DispatcherProvider +import io.github.sds100.keymapper.common.utils.DispatcherProvider import kotlinx.coroutines.test.TestDispatcher -/** - * Created by sds100 on 01/05/2021. - */ - class TestDispatcherProvider( private val testDispatcher: TestDispatcher, ) : DispatcherProvider { diff --git a/app/src/test/java/io/github/sds100/keymapper/TestLoggingTree.kt b/base/src/test/java/io/github/sds100/keymapper/base/TestLoggingTree.kt similarity index 72% rename from app/src/test/java/io/github/sds100/keymapper/TestLoggingTree.kt rename to base/src/test/java/io/github/sds100/keymapper/base/TestLoggingTree.kt index 8e536fe8bf..9c8cafddd3 100644 --- a/app/src/test/java/io/github/sds100/keymapper/TestLoggingTree.kt +++ b/base/src/test/java/io/github/sds100/keymapper/base/TestLoggingTree.kt @@ -1,10 +1,7 @@ -package io.github.sds100.keymapper +package io.github.sds100.keymapper.base import timber.log.Timber -/** - * Created by sds100 on 25/06/2021. - */ class TestLoggingTree : Timber.Tree() { override fun log(priority: Int, tag: String?, message: String, t: Throwable?) { t?.printStackTrace() diff --git a/app/src/test/java/io/github/sds100/keymapper/actions/GetActionFailedUseCaseTest.kt b/base/src/test/java/io/github/sds100/keymapper/base/actions/GetActionFailedUseCaseTest.kt similarity index 89% rename from app/src/test/java/io/github/sds100/keymapper/actions/GetActionFailedUseCaseTest.kt rename to base/src/test/java/io/github/sds100/keymapper/base/actions/GetActionFailedUseCaseTest.kt index 608de9dcfa..3cc610d0ee 100644 --- a/app/src/test/java/io/github/sds100/keymapper/actions/GetActionFailedUseCaseTest.kt +++ b/base/src/test/java/io/github/sds100/keymapper/base/actions/GetActionFailedUseCaseTest.kt @@ -1,11 +1,12 @@ -package io.github.sds100.keymapper.actions +package io.github.sds100.keymapper.base.actions import android.view.KeyEvent -import io.github.sds100.keymapper.shizuku.ShizukuAdapter +import io.github.sds100.keymapper.base.utils.TestBuildConfigProvider +import io.github.sds100.keymapper.common.utils.KMError import io.github.sds100.keymapper.system.inputmethod.ImeInfo import io.github.sds100.keymapper.system.inputmethod.InputMethodAdapter import io.github.sds100.keymapper.system.permissions.PermissionAdapter -import io.github.sds100.keymapper.util.Error +import io.github.sds100.keymapper.system.shizuku.ShizukuAdapter import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.first @@ -22,10 +23,6 @@ import org.mockito.junit.MockitoJUnitRunner import org.mockito.kotlin.mock import org.mockito.kotlin.whenever -/** - * Created by sds100 on 01/05/2021. - */ - @ExperimentalCoroutinesApi @RunWith(MockitoJUnitRunner::class) class GetActionFailedUseCaseTest { @@ -46,7 +43,7 @@ class GetActionFailedUseCaseTest { mockPermissionAdapter = mock() useCase = GetActionErrorUseCaseImpl( - packageManager = mock(), + packageManagerAdapter = mock(), inputMethodAdapter = mockInputMethodAdapter, permissionAdapter = mockPermissionAdapter, systemFeatureAdapter = mock(), @@ -54,6 +51,7 @@ class GetActionFailedUseCaseTest { soundsManager = mock(), shizukuAdapter = mockShizukuAdapter, ringtoneAdapter = mock(), + buildConfigProvider = TestBuildConfigProvider(), ) } @@ -111,6 +109,6 @@ class GetActionFailedUseCaseTest { val error = useCase.actionErrorSnapshot.first().getError(action) // THEN - assertThat(error, `is`(Error.ShizukuNotStarted)) + assertThat(error, `is`(KMError.ShizukuNotStarted)) } } diff --git a/app/src/test/java/io/github/sds100/keymapper/actions/PerformActionsUseCaseTest.kt b/base/src/test/java/io/github/sds100/keymapper/base/actions/PerformActionsUseCaseTest.kt similarity index 89% rename from app/src/test/java/io/github/sds100/keymapper/actions/PerformActionsUseCaseTest.kt rename to base/src/test/java/io/github/sds100/keymapper/base/actions/PerformActionsUseCaseTest.kt index d2c9df0c1e..5dee3c53b7 100644 --- a/app/src/test/java/io/github/sds100/keymapper/actions/PerformActionsUseCaseTest.kt +++ b/base/src/test/java/io/github/sds100/keymapper/base/actions/PerformActionsUseCaseTest.kt @@ -1,16 +1,16 @@ -package io.github.sds100.keymapper.actions +package io.github.sds100.keymapper.base.actions import android.view.InputDevice import android.view.KeyEvent -import io.github.sds100.keymapper.system.accessibility.IAccessibilityService -import io.github.sds100.keymapper.system.devices.FakeDevicesAdapter +import io.github.sds100.keymapper.base.system.accessibility.IAccessibilityService +import io.github.sds100.keymapper.base.system.devices.FakeDevicesAdapter +import io.github.sds100.keymapper.base.system.inputmethod.ImeInputEventInjector +import io.github.sds100.keymapper.common.utils.InputEventType +import io.github.sds100.keymapper.common.utils.KMError +import io.github.sds100.keymapper.common.utils.State import io.github.sds100.keymapper.system.devices.InputDeviceInfo -import io.github.sds100.keymapper.system.inputmethod.ImeInputEventInjector import io.github.sds100.keymapper.system.inputmethod.InputKeyModel -import io.github.sds100.keymapper.system.popup.PopupMessageAdapter -import io.github.sds100.keymapper.util.Error -import io.github.sds100.keymapper.util.InputEventType -import io.github.sds100.keymapper.util.State +import io.github.sds100.keymapper.system.popup.ToastAdapter import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.test.TestScope @@ -29,10 +29,6 @@ import org.mockito.kotlin.times import org.mockito.kotlin.verify import org.mockito.kotlin.whenever -/** - * Created by sds100 on 01/05/2021. - */ - @ExperimentalCoroutinesApi @RunWith(MockitoJUnitRunner::class) class PerformActionsUseCaseTest { @@ -44,7 +40,7 @@ class PerformActionsUseCaseTest { private lateinit var mockImeInputEventInjector: ImeInputEventInjector private lateinit var fakeDevicesAdapter: FakeDevicesAdapter private lateinit var mockAccessibilityService: IAccessibilityService - private lateinit var mockToastAdapter: PopupMessageAdapter + private lateinit var mockToastAdapter: ToastAdapter @Before fun init() { @@ -55,22 +51,22 @@ class PerformActionsUseCaseTest { useCase = PerformActionsUseCaseImpl( testScope, - accessibilityService = mockAccessibilityService, + service = mockAccessibilityService, inputMethodAdapter = mock(), fileAdapter = mock(), suAdapter = mock { on { isGranted }.then { MutableStateFlow(false) } }, - shellAdapter = mock(), + shell = mock(), intentAdapter = mock(), - getActionError = mock(), - imeInputEventInjector = mockImeInputEventInjector, + getActionErrorUseCase = mock(), + keyMapperImeMessenger = mockImeInputEventInjector, packageManagerAdapter = mock(), appShortcutAdapter = mock(), - popupMessageAdapter = mockToastAdapter, - deviceAdapter = fakeDevicesAdapter, + toastAdapter = mockToastAdapter, + devicesAdapter = fakeDevicesAdapter, phoneAdapter = mock(), - volumeAdapter = mock(), + audioAdapter = mock(), cameraAdapter = mock(), displayAdapter = mock(), lockScreenAdapter = mock(), @@ -81,9 +77,8 @@ class PerformActionsUseCaseTest { nfcAdapter = mock(), openUrlAdapter = mock(), resourceProvider = mock(), - preferenceRepository = mock(), + settingsRepository = mock(), soundsManager = mock(), - shizukuInputEventInjector = mock(), permissionAdapter = mock(), notificationReceiverAdapter = mock(), ringtoneAdapter = mock(), @@ -103,13 +98,13 @@ class PerformActionsUseCaseTest { any(), any(), ), - ).doReturn(Error.FailedToFindAccessibilityNode) + ).doReturn(KMError.FailedToFindAccessibilityNode) // WHEN useCase.perform(action) // THEN - verify(mockToastAdapter, never()).showPopupMessage(anyOrNull()) + verify(mockToastAdapter, never()).show(anyOrNull()) } /** diff --git a/app/src/test/java/io/github/sds100/keymapper/actions/keyevents/ConfigKeyServiceEventActionViewModelTest.kt b/base/src/test/java/io/github/sds100/keymapper/base/actions/keyevents/ConfigKeyServiceEventActionViewModelTest.kt similarity index 92% rename from app/src/test/java/io/github/sds100/keymapper/actions/keyevents/ConfigKeyServiceEventActionViewModelTest.kt rename to base/src/test/java/io/github/sds100/keymapper/base/actions/keyevents/ConfigKeyServiceEventActionViewModelTest.kt index 298c1dc130..03b1da73f4 100644 --- a/app/src/test/java/io/github/sds100/keymapper/actions/keyevents/ConfigKeyServiceEventActionViewModelTest.kt +++ b/base/src/test/java/io/github/sds100/keymapper/base/actions/keyevents/ConfigKeyServiceEventActionViewModelTest.kt @@ -1,8 +1,8 @@ -package io.github.sds100.keymapper.actions.keyevents +package io.github.sds100.keymapper.base.actions.keyevents import androidx.arch.core.executor.testing.InstantTaskExecutorRule -import io.github.sds100.keymapper.actions.keyevent.ConfigKeyEventActionViewModel -import io.github.sds100.keymapper.actions.keyevent.ConfigKeyEventUseCase +import io.github.sds100.keymapper.base.actions.keyevent.ConfigKeyEventActionViewModel +import io.github.sds100.keymapper.base.actions.keyevent.ConfigKeyEventUseCase import io.github.sds100.keymapper.system.devices.InputDeviceInfo import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -24,10 +24,6 @@ import org.mockito.junit.MockitoJUnitRunner import org.mockito.kotlin.any import org.mockito.kotlin.mock -/** - * Created by sds100 on 28/04/2021. - */ - @ExperimentalCoroutinesApi @RunWith(MockitoJUnitRunner::class) class ConfigKeyServiceEventActionViewModelTest { diff --git a/app/src/test/java/io/github/sds100/keymapper/constraints/ConstraintSnapshotTest.kt b/base/src/test/java/io/github/sds100/keymapper/base/constraints/ConstraintSnapshotTest.kt similarity index 98% rename from app/src/test/java/io/github/sds100/keymapper/constraints/ConstraintSnapshotTest.kt rename to base/src/test/java/io/github/sds100/keymapper/base/constraints/ConstraintSnapshotTest.kt index d2cc2e3fc8..9769a7386e 100644 --- a/app/src/test/java/io/github/sds100/keymapper/constraints/ConstraintSnapshotTest.kt +++ b/base/src/test/java/io/github/sds100/keymapper/base/constraints/ConstraintSnapshotTest.kt @@ -1,6 +1,6 @@ -package io.github.sds100.keymapper.constraints +package io.github.sds100.keymapper.base.constraints -import io.github.sds100.keymapper.util.TestConstraintSnapshot +import io.github.sds100.keymapper.base.utils.TestConstraintSnapshot import org.hamcrest.MatcherAssert.assertThat import org.hamcrest.Matchers.`is` import org.junit.Test diff --git a/app/src/test/java/io/github/sds100/keymapper/keymaps/DpadMotionEventTrackerTest.kt b/base/src/test/java/io/github/sds100/keymapper/base/keymaps/DpadMotionEventTrackerTest.kt similarity index 98% rename from app/src/test/java/io/github/sds100/keymapper/keymaps/DpadMotionEventTrackerTest.kt rename to base/src/test/java/io/github/sds100/keymapper/base/keymaps/DpadMotionEventTrackerTest.kt index 732c7d92b0..23ce84f14b 100644 --- a/app/src/test/java/io/github/sds100/keymapper/keymaps/DpadMotionEventTrackerTest.kt +++ b/base/src/test/java/io/github/sds100/keymapper/base/keymaps/DpadMotionEventTrackerTest.kt @@ -1,8 +1,8 @@ -package io.github.sds100.keymapper.keymaps +package io.github.sds100.keymapper.base.keymaps import android.view.InputDevice import android.view.KeyEvent -import io.github.sds100.keymapper.keymaps.detection.DpadMotionEventTracker +import io.github.sds100.keymapper.base.keymaps.detection.DpadMotionEventTracker import io.github.sds100.keymapper.system.devices.InputDeviceInfo import io.github.sds100.keymapper.system.inputevents.MyKeyEvent import io.github.sds100.keymapper.system.inputevents.MyMotionEvent @@ -16,10 +16,6 @@ import org.junit.Before import org.junit.Test import org.junit.runner.RunWith -/** - * Created by sds100 on 15/05/2021. - */ - @ExperimentalCoroutinesApi @RunWith(JUnitParamsRunner::class) class DpadMotionEventTrackerTest { diff --git a/app/src/test/java/io/github/sds100/keymapper/keymaps/KeyMapControllerTest.kt b/base/src/test/java/io/github/sds100/keymapper/base/keymaps/KeyMapControllerTest.kt similarity index 98% rename from app/src/test/java/io/github/sds100/keymapper/keymaps/KeyMapControllerTest.kt rename to base/src/test/java/io/github/sds100/keymapper/base/keymaps/KeyMapControllerTest.kt index c068b9cb03..b626d0382e 100644 --- a/app/src/test/java/io/github/sds100/keymapper/keymaps/KeyMapControllerTest.kt +++ b/base/src/test/java/io/github/sds100/keymapper/base/keymaps/KeyMapControllerTest.kt @@ -1,38 +1,40 @@ -package io.github.sds100.keymapper.keymaps +package io.github.sds100.keymapper.base.keymaps import android.view.KeyEvent import androidx.arch.core.executor.testing.InstantTaskExecutorRule -import io.github.sds100.keymapper.actions.Action -import io.github.sds100.keymapper.actions.ActionData -import io.github.sds100.keymapper.actions.ActionErrorSnapshot -import io.github.sds100.keymapper.actions.PerformActionsUseCase -import io.github.sds100.keymapper.actions.RepeatMode -import io.github.sds100.keymapper.constraints.Constraint -import io.github.sds100.keymapper.constraints.ConstraintMode -import io.github.sds100.keymapper.constraints.ConstraintSnapshot -import io.github.sds100.keymapper.constraints.ConstraintState -import io.github.sds100.keymapper.constraints.DetectConstraintsUseCase -import io.github.sds100.keymapper.keymaps.detection.DetectKeyMapModel -import io.github.sds100.keymapper.keymaps.detection.DetectKeyMapsUseCase -import io.github.sds100.keymapper.keymaps.detection.KeyMapController +import io.github.sds100.keymapper.base.actions.Action +import io.github.sds100.keymapper.base.actions.ActionData +import io.github.sds100.keymapper.base.actions.ActionErrorSnapshot +import io.github.sds100.keymapper.base.actions.PerformActionsUseCase +import io.github.sds100.keymapper.base.actions.RepeatMode +import io.github.sds100.keymapper.base.constraints.Constraint +import io.github.sds100.keymapper.base.constraints.ConstraintMode +import io.github.sds100.keymapper.base.constraints.ConstraintSnapshot +import io.github.sds100.keymapper.base.constraints.ConstraintState +import io.github.sds100.keymapper.base.constraints.DetectConstraintsUseCase +import io.github.sds100.keymapper.base.keymaps.detection.DetectKeyMapModel +import io.github.sds100.keymapper.base.keymaps.detection.DetectKeyMapsUseCase +import io.github.sds100.keymapper.base.keymaps.detection.KeyMapController +import io.github.sds100.keymapper.base.system.accessibility.FingerprintGestureType +import io.github.sds100.keymapper.base.trigger.FingerprintTriggerKey +import io.github.sds100.keymapper.base.trigger.KeyCodeTriggerKey +import io.github.sds100.keymapper.base.trigger.KeyEventDetectionSource +import io.github.sds100.keymapper.base.trigger.Trigger +import io.github.sds100.keymapper.base.trigger.TriggerKey +import io.github.sds100.keymapper.base.trigger.TriggerKeyDevice +import io.github.sds100.keymapper.base.trigger.TriggerMode +import io.github.sds100.keymapper.base.utils.TestConstraintSnapshot +import io.github.sds100.keymapper.base.utils.parallelTrigger +import io.github.sds100.keymapper.base.utils.sequenceTrigger +import io.github.sds100.keymapper.base.utils.singleKeyTrigger +import io.github.sds100.keymapper.base.utils.triggerKey +import io.github.sds100.keymapper.common.utils.InputEventType +import io.github.sds100.keymapper.common.utils.KMError +import io.github.sds100.keymapper.common.utils.withFlag import io.github.sds100.keymapper.system.camera.CameraLens import io.github.sds100.keymapper.system.devices.InputDeviceInfo import io.github.sds100.keymapper.system.inputevents.MyKeyEvent import io.github.sds100.keymapper.system.inputevents.MyMotionEvent -import io.github.sds100.keymapper.trigger.FingerprintTriggerKey -import io.github.sds100.keymapper.trigger.KeyCodeTriggerKey -import io.github.sds100.keymapper.trigger.KeyEventDetectionSource -import io.github.sds100.keymapper.trigger.Trigger -import io.github.sds100.keymapper.trigger.TriggerKey -import io.github.sds100.keymapper.trigger.TriggerKeyDevice -import io.github.sds100.keymapper.trigger.TriggerMode -import io.github.sds100.keymapper.util.Error -import io.github.sds100.keymapper.util.InputEventType -import io.github.sds100.keymapper.util.TestConstraintSnapshot -import io.github.sds100.keymapper.util.parallelTrigger -import io.github.sds100.keymapper.util.sequenceTrigger -import io.github.sds100.keymapper.util.singleKeyTrigger -import io.github.sds100.keymapper.util.triggerKey import junitparams.JUnitParamsRunner import junitparams.Parameters import junitparams.naming.TestCaseName @@ -63,11 +65,6 @@ import org.mockito.kotlin.never import org.mockito.kotlin.times import org.mockito.kotlin.verify import org.mockito.kotlin.whenever -import splitties.bitflags.withFlag - -/** - * Created by sds100 on 17/05/2020. - */ @ExperimentalCoroutinesApi @RunWith(JUnitParamsRunner::class) @@ -183,7 +180,7 @@ class KeyMapControllerTest { } on { getErrorSnapshot() } doReturn object : ActionErrorSnapshot { - override fun getError(action: ActionData): Error? = null + override fun getError(action: ActionData): KMError? = null } } @@ -1323,8 +1320,8 @@ class KeyMapControllerTest { // WHEN whenever(performActionsUseCase.getErrorSnapshot()).thenReturn(object : ActionErrorSnapshot { - override fun getError(action: ActionData): Error { - return Error.NoCompatibleImeChosen + override fun getError(action: ActionData): KMError { + return KMError.NoCompatibleImeChosen } }) diff --git a/app/src/test/java/io/github/sds100/keymapper/keymaps/ProcessKeyMapGroupsForDetectionTest.kt b/base/src/test/java/io/github/sds100/keymapper/base/keymaps/ProcessKeyMapGroupsForDetectionTest.kt similarity index 94% rename from app/src/test/java/io/github/sds100/keymapper/keymaps/ProcessKeyMapGroupsForDetectionTest.kt rename to base/src/test/java/io/github/sds100/keymapper/base/keymaps/ProcessKeyMapGroupsForDetectionTest.kt index ac2ab51cf3..abcd815259 100644 --- a/app/src/test/java/io/github/sds100/keymapper/keymaps/ProcessKeyMapGroupsForDetectionTest.kt +++ b/base/src/test/java/io/github/sds100/keymapper/base/keymaps/ProcessKeyMapGroupsForDetectionTest.kt @@ -1,11 +1,11 @@ -package io.github.sds100.keymapper.keymaps +package io.github.sds100.keymapper.base.keymaps -import io.github.sds100.keymapper.constraints.Constraint -import io.github.sds100.keymapper.constraints.ConstraintMode -import io.github.sds100.keymapper.constraints.ConstraintState -import io.github.sds100.keymapper.groups.Group -import io.github.sds100.keymapper.keymaps.detection.DetectKeyMapModel -import io.github.sds100.keymapper.keymaps.detection.DetectKeyMapsUseCaseImpl +import io.github.sds100.keymapper.base.constraints.Constraint +import io.github.sds100.keymapper.base.constraints.ConstraintMode +import io.github.sds100.keymapper.base.constraints.ConstraintState +import io.github.sds100.keymapper.base.groups.Group +import io.github.sds100.keymapper.base.keymaps.detection.DetectKeyMapModel +import io.github.sds100.keymapper.base.keymaps.detection.DetectKeyMapsUseCaseImpl import org.hamcrest.MatcherAssert.assertThat import org.hamcrest.Matchers import org.junit.Test diff --git a/app/src/test/java/io/github/sds100/keymapper/keymaps/TriggerKeyMapFromOtherAppsControllerTest.kt b/base/src/test/java/io/github/sds100/keymapper/base/keymaps/TriggerKeyMapFromOtherAppsControllerTest.kt similarity index 80% rename from app/src/test/java/io/github/sds100/keymapper/keymaps/TriggerKeyMapFromOtherAppsControllerTest.kt rename to base/src/test/java/io/github/sds100/keymapper/base/keymaps/TriggerKeyMapFromOtherAppsControllerTest.kt index 021d19bc77..2d1aa43d22 100644 --- a/app/src/test/java/io/github/sds100/keymapper/keymaps/TriggerKeyMapFromOtherAppsControllerTest.kt +++ b/base/src/test/java/io/github/sds100/keymapper/base/keymaps/TriggerKeyMapFromOtherAppsControllerTest.kt @@ -1,16 +1,16 @@ -package io.github.sds100.keymapper.keymaps - -import io.github.sds100.keymapper.actions.Action -import io.github.sds100.keymapper.actions.ActionData -import io.github.sds100.keymapper.actions.ActionErrorSnapshot -import io.github.sds100.keymapper.actions.PerformActionsUseCase -import io.github.sds100.keymapper.actions.RepeatMode -import io.github.sds100.keymapper.constraints.DetectConstraintsUseCase -import io.github.sds100.keymapper.keymaps.detection.DetectKeyMapsUseCase -import io.github.sds100.keymapper.keymaps.detection.TriggerKeyMapFromOtherAppsController -import io.github.sds100.keymapper.trigger.Trigger -import io.github.sds100.keymapper.util.Error -import io.github.sds100.keymapper.util.TestConstraintSnapshot +package io.github.sds100.keymapper.base.keymaps + +import io.github.sds100.keymapper.base.actions.Action +import io.github.sds100.keymapper.base.actions.ActionData +import io.github.sds100.keymapper.base.actions.ActionErrorSnapshot +import io.github.sds100.keymapper.base.actions.PerformActionsUseCase +import io.github.sds100.keymapper.base.actions.RepeatMode +import io.github.sds100.keymapper.base.constraints.DetectConstraintsUseCase +import io.github.sds100.keymapper.base.keymaps.detection.DetectKeyMapsUseCase +import io.github.sds100.keymapper.base.keymaps.detection.TriggerKeyMapFromOtherAppsController +import io.github.sds100.keymapper.base.trigger.Trigger +import io.github.sds100.keymapper.base.utils.TestConstraintSnapshot +import io.github.sds100.keymapper.common.utils.KMError import junitparams.JUnitParamsRunner import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.delay @@ -27,10 +27,6 @@ import org.mockito.kotlin.mock import org.mockito.kotlin.times import org.mockito.kotlin.verify -/** - * Created by sds100 on 23/06/2021. - */ - @ExperimentalCoroutinesApi @RunWith(JUnitParamsRunner::class) class TriggerKeyMapFromOtherAppsControllerTest { @@ -81,7 +77,7 @@ class TriggerKeyMapFromOtherAppsControllerTest { } on { getErrorSnapshot() } doReturn object : ActionErrorSnapshot { - override fun getError(action: ActionData): Error? = null + override fun getError(action: ActionData): KMError? = null } } diff --git a/app/src/test/java/io/github/sds100/keymapper/data/repositories/FakePreferenceRepository.kt b/base/src/test/java/io/github/sds100/keymapper/base/repositories/FakePreferenceRepository.kt similarity index 87% rename from app/src/test/java/io/github/sds100/keymapper/data/repositories/FakePreferenceRepository.kt rename to base/src/test/java/io/github/sds100/keymapper/base/repositories/FakePreferenceRepository.kt index 3c4d491026..03cf0533a2 100644 --- a/app/src/test/java/io/github/sds100/keymapper/data/repositories/FakePreferenceRepository.kt +++ b/base/src/test/java/io/github/sds100/keymapper/base/repositories/FakePreferenceRepository.kt @@ -1,13 +1,11 @@ -package io.github.sds100.keymapper.data.repositories +package io.github.sds100.keymapper.base.repositories import androidx.datastore.preferences.core.Preferences +import io.github.sds100.keymapper.data.repositories.PreferenceRepository import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.map -/** - * Created by sds100 on 26/04/2021. - */ class FakePreferenceRepository : PreferenceRepository { private val preferences: MutableStateFlow, Any?>> = MutableStateFlow(emptyMap()) diff --git a/app/src/test/java/io/github/sds100/keymapper/data/repositories/KeyMapRepositoryTest.kt b/base/src/test/java/io/github/sds100/keymapper/base/repositories/KeyMapRepositoryTest.kt similarity index 92% rename from app/src/test/java/io/github/sds100/keymapper/data/repositories/KeyMapRepositoryTest.kt rename to base/src/test/java/io/github/sds100/keymapper/base/repositories/KeyMapRepositoryTest.kt index 97738f47ea..fb53bae60e 100644 --- a/app/src/test/java/io/github/sds100/keymapper/data/repositories/KeyMapRepositoryTest.kt +++ b/base/src/test/java/io/github/sds100/keymapper/base/repositories/KeyMapRepositoryTest.kt @@ -1,10 +1,11 @@ -package io.github.sds100.keymapper.data.repositories +package io.github.sds100.keymapper.base.repositories -import io.github.sds100.keymapper.TestDispatcherProvider +import io.github.sds100.keymapper.base.TestDispatcherProvider +import io.github.sds100.keymapper.base.system.devices.FakeDevicesAdapter import io.github.sds100.keymapper.data.db.dao.KeyMapDao import io.github.sds100.keymapper.data.entities.FingerprintMapEntity import io.github.sds100.keymapper.data.entities.KeyMapEntity -import io.github.sds100.keymapper.system.devices.FakeDevicesAdapter +import io.github.sds100.keymapper.data.repositories.RoomKeyMapRepository import io.github.sds100.keymapper.system.devices.InputDeviceInfo import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.MutableSharedFlow @@ -21,10 +22,6 @@ import org.mockito.kotlin.inOrder import org.mockito.kotlin.mock import org.mockito.kotlin.times -/** - * Created by sds100 on 01/05/2021. - */ - @ExperimentalCoroutinesApi @RunWith(MockitoJUnitRunner::class) class KeyMapRepositoryTest { diff --git a/app/src/test/java/io/github/sds100/keymapper/system/devices/FakeDevicesAdapter.kt b/base/src/test/java/io/github/sds100/keymapper/base/system/devices/FakeDevicesAdapter.kt similarity index 72% rename from app/src/test/java/io/github/sds100/keymapper/system/devices/FakeDevicesAdapter.kt rename to base/src/test/java/io/github/sds100/keymapper/base/system/devices/FakeDevicesAdapter.kt index 0f0979de36..ba2e23d056 100644 --- a/app/src/test/java/io/github/sds100/keymapper/system/devices/FakeDevicesAdapter.kt +++ b/base/src/test/java/io/github/sds100/keymapper/base/system/devices/FakeDevicesAdapter.kt @@ -1,15 +1,14 @@ -package io.github.sds100.keymapper.system.devices +package io.github.sds100.keymapper.base.system.devices +import io.github.sds100.keymapper.common.utils.KMResult +import io.github.sds100.keymapper.common.utils.State import io.github.sds100.keymapper.system.bluetooth.BluetoothDeviceInfo -import io.github.sds100.keymapper.util.Result -import io.github.sds100.keymapper.util.State +import io.github.sds100.keymapper.system.devices.DevicesAdapter +import io.github.sds100.keymapper.system.devices.InputDeviceInfo import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow -/** - * Created by sds100 on 26/04/2021. - */ class FakeDevicesAdapter : DevicesAdapter { override val onInputDeviceConnect = MutableSharedFlow() override val onInputDeviceDisconnect = MutableSharedFlow() @@ -29,7 +28,7 @@ class FakeDevicesAdapter : DevicesAdapter { return deviceHasKey.invoke(id, keyCode) } - override fun getInputDeviceName(descriptor: String): Result { + override fun getInputDeviceName(descriptor: String): KMResult { throw Exception() } } diff --git a/app/src/test/java/io/github/sds100/keymapper/system/files/FakeFileAdapter.kt b/base/src/test/java/io/github/sds100/keymapper/base/system/files/FakeFileAdapter.kt similarity index 80% rename from app/src/test/java/io/github/sds100/keymapper/system/files/FakeFileAdapter.kt rename to base/src/test/java/io/github/sds100/keymapper/base/system/files/FakeFileAdapter.kt index 5d652a63aa..6321c20df8 100644 --- a/app/src/test/java/io/github/sds100/keymapper/system/files/FakeFileAdapter.kt +++ b/base/src/test/java/io/github/sds100/keymapper/base/system/files/FakeFileAdapter.kt @@ -1,15 +1,14 @@ -package io.github.sds100.keymapper.system.files +package io.github.sds100.keymapper.base.system.files -import io.github.sds100.keymapper.util.Result -import io.github.sds100.keymapper.util.Success +import io.github.sds100.keymapper.common.utils.KMResult +import io.github.sds100.keymapper.common.utils.Success +import io.github.sds100.keymapper.system.files.FileAdapter +import io.github.sds100.keymapper.system.files.IFile import kotlinx.coroutines.runBlocking import org.junit.rules.TemporaryFolder import java.io.File import java.io.InputStream -/** - * Created by sds100 on 29/06/2021. - */ class FakeFileAdapter( private val tempFolder: TemporaryFolder, ) : FileAdapter { @@ -24,7 +23,7 @@ class FakeFileAdapter( throw Exception() } - override fun openDownloadsFile(fileName: String, mimeType: String): Result { + override fun openDownloadsFile(fileName: String, mimeType: String): KMResult { throw Exception() } @@ -46,7 +45,7 @@ class FakeFileAdapter( return "" } - override fun createZipFile(destination: IFile, files: Set): Result<*> { + override fun createZipFile(destination: IFile, files: Set): KMResult<*> { runBlocking { files.forEach { file -> file.copyTo(destination) @@ -56,7 +55,7 @@ class FakeFileAdapter( return Success(Unit) } - override suspend fun extractZipFile(zipFile: IFile, destination: IFile): Result<*> { + override suspend fun extractZipFile(zipFile: IFile, destination: IFile): KMResult<*> { zipFile.listFiles()!!.forEach { file -> file.copyTo(destination) } diff --git a/app/src/test/java/io/github/sds100/keymapper/system/files/JavaFile.kt b/base/src/test/java/io/github/sds100/keymapper/base/system/files/JavaFile.kt similarity index 88% rename from app/src/test/java/io/github/sds100/keymapper/system/files/JavaFile.kt rename to base/src/test/java/io/github/sds100/keymapper/base/system/files/JavaFile.kt index d38a7999aa..4e86d7b9ee 100644 --- a/app/src/test/java/io/github/sds100/keymapper/system/files/JavaFile.kt +++ b/base/src/test/java/io/github/sds100/keymapper/base/system/files/JavaFile.kt @@ -1,16 +1,14 @@ -package io.github.sds100.keymapper.system.files +package io.github.sds100.keymapper.base.system.files import com.anggrayudi.storage.file.recreateFile -import io.github.sds100.keymapper.util.Result -import io.github.sds100.keymapper.util.Success +import io.github.sds100.keymapper.common.utils.KMResult +import io.github.sds100.keymapper.common.utils.Success +import io.github.sds100.keymapper.system.files.IFile import timber.log.Timber import java.io.File import java.io.InputStream import java.io.OutputStream -/** - * Created by sds100 on 29/06/2021. - */ class JavaFile(val file: File) : IFile { override val uri: String @@ -74,7 +72,7 @@ class JavaFile(val file: File) : IFile { file.mkdirs() } - override suspend fun copyTo(directory: IFile, fileName: String?): Result<*> { + override suspend fun copyTo(directory: IFile, fileName: String?): KMResult<*> { val targetFile = File((directory as JavaFile).file, fileName ?: this.name) if (this.isDirectory) { diff --git a/app/src/test/java/io/github/sds100/keymapper/system/intents/ConfigIntentViewModelTest.kt b/base/src/test/java/io/github/sds100/keymapper/base/system/intents/ConfigIntentViewModelTest.kt similarity index 59% rename from app/src/test/java/io/github/sds100/keymapper/system/intents/ConfigIntentViewModelTest.kt rename to base/src/test/java/io/github/sds100/keymapper/base/system/intents/ConfigIntentViewModelTest.kt index 627ff1d7d9..4e7082753f 100644 --- a/app/src/test/java/io/github/sds100/keymapper/system/intents/ConfigIntentViewModelTest.kt +++ b/base/src/test/java/io/github/sds100/keymapper/base/system/intents/ConfigIntentViewModelTest.kt @@ -1,13 +1,14 @@ -package io.github.sds100.keymapper.system.intents +package io.github.sds100.keymapper.base.system.intents import android.content.Intent import androidx.arch.core.executor.testing.InstantTaskExecutorRule -import io.github.sds100.keymapper.util.firstBlocking -import io.github.sds100.keymapper.util.ui.FakeResourceProvider -import io.github.sds100.keymapper.util.ui.MultiChoiceItem -import io.github.sds100.keymapper.util.ui.PopupUi -import io.github.sds100.keymapper.util.ui.ShowPopupEvent -import io.github.sds100.keymapper.util.ui.onUserResponse +import io.github.sds100.keymapper.base.utils.ui.DialogModel +import io.github.sds100.keymapper.base.utils.ui.DialogProviderImpl +import io.github.sds100.keymapper.base.utils.ui.FakeResourceProvider +import io.github.sds100.keymapper.base.utils.ui.MultiChoiceItem +import io.github.sds100.keymapper.base.utils.ui.ShowDialogEvent +import io.github.sds100.keymapper.base.utils.ui.onUserResponse +import io.github.sds100.keymapper.common.utils.firstBlocking import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.UnconfinedTestDispatcher @@ -19,9 +20,6 @@ import org.junit.Before import org.junit.Rule import org.junit.Test -/** - * Created by sds100 on 29/04/2022. - */ @ExperimentalCoroutinesApi internal class ConfigIntentViewModelTest { @@ -37,14 +35,17 @@ internal class ConfigIntentViewModelTest { Dispatchers.setMain(testDispatcher) fakeResourceProvider = FakeResourceProvider() - viewModel = ConfigIntentViewModel(fakeResourceProvider) + viewModel = ConfigIntentViewModel( + fakeResourceProvider, + dialogProvider = DialogProviderImpl(), + ) } @Test fun showFlagsDialog_whenNoFlags_checkNoFlags() { viewModel.showFlagsDialog() - val popupEvent: ShowPopupEvent = viewModel.showPopup.firstBlocking() - val multipleChoiceDialog = popupEvent.ui as PopupUi.MultiChoice<*> + val popupEvent: ShowDialogEvent = viewModel.showDialog.firstBlocking() + val multipleChoiceDialog = popupEvent.ui as DialogModel.MultiChoice<*> assertThat(multipleChoiceDialog.items.none { it.isChecked }, `is`(true)) } @@ -52,12 +53,12 @@ internal class ConfigIntentViewModelTest { @Test fun showFlagsDialog_whenFlags_checkFlags() { viewModel.showFlagsDialog() - val addFlagPopupEvent: ShowPopupEvent = viewModel.showPopup.firstBlocking() + val addFlagPopupEvent: ShowDialogEvent = viewModel.showDialog.firstBlocking() viewModel.onUserResponse(addFlagPopupEvent.key, listOf(Intent.FLAG_ACTIVITY_NEW_TASK)) viewModel.showFlagsDialog() - val popupEvent: ShowPopupEvent = viewModel.showPopup.firstBlocking() - val multipleChoiceDialog = popupEvent.ui as PopupUi.MultiChoice<*> + val popupEvent: ShowDialogEvent = viewModel.showDialog.firstBlocking() + val multipleChoiceDialog = popupEvent.ui as DialogModel.MultiChoice<*> val expectedCheckedItem = MultiChoiceItem(Intent.FLAG_ACTIVITY_NEW_TASK, "FLAG_ACTIVITY_NEW_TASK", true) diff --git a/app/src/test/java/io/github/sds100/keymapper/util/FlowUtils.kt b/base/src/test/java/io/github/sds100/keymapper/base/utils/FlowUtils.kt similarity index 84% rename from app/src/test/java/io/github/sds100/keymapper/util/FlowUtils.kt rename to base/src/test/java/io/github/sds100/keymapper/base/utils/FlowUtils.kt index cde03040ea..a34dd5b549 100644 --- a/app/src/test/java/io/github/sds100/keymapper/util/FlowUtils.kt +++ b/base/src/test/java/io/github/sds100/keymapper/base/utils/FlowUtils.kt @@ -1,12 +1,9 @@ -package io.github.sds100.keymapper.util +package io.github.sds100.keymapper.base.utils import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.toList import kotlinx.coroutines.withTimeoutOrNull -/** - * Created by sds100 on 19/04/2021. - */ object FlowUtils { /** * This is useful for collecting SharedFlow in tests. diff --git a/app/src/androidTest/java/io/github/sds100/keymapper/JsonTestUtils.kt b/base/src/test/java/io/github/sds100/keymapper/base/utils/JsonTestUtils.kt similarity index 97% rename from app/src/androidTest/java/io/github/sds100/keymapper/JsonTestUtils.kt rename to base/src/test/java/io/github/sds100/keymapper/base/utils/JsonTestUtils.kt index d79454b9df..d3754fcc80 100644 --- a/app/src/androidTest/java/io/github/sds100/keymapper/JsonTestUtils.kt +++ b/base/src/test/java/io/github/sds100/keymapper/base/utils/JsonTestUtils.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper +package io.github.sds100.keymapper.base.utils import com.github.salomonbrys.kotson.contains import com.github.salomonbrys.kotson.forEach @@ -11,9 +11,6 @@ import org.hamcrest.MatcherAssert.assertThat import org.hamcrest.core.Is.`is` import org.junit.Assert -/** - * Created by sds100 on 25/01/21. - */ object JsonTestUtils { private const val NAME_SEPARATOR = '/' diff --git a/app/src/test/java/io/github/sds100/keymapper/util/KeyMapUtils.kt b/base/src/test/java/io/github/sds100/keymapper/base/utils/KeyMapUtils.kt similarity index 58% rename from app/src/test/java/io/github/sds100/keymapper/util/KeyMapUtils.kt rename to base/src/test/java/io/github/sds100/keymapper/base/utils/KeyMapUtils.kt index eb4a9c26c3..cacadd68b9 100644 --- a/app/src/test/java/io/github/sds100/keymapper/util/KeyMapUtils.kt +++ b/base/src/test/java/io/github/sds100/keymapper/base/utils/KeyMapUtils.kt @@ -1,15 +1,12 @@ -package io.github.sds100.keymapper.util +package io.github.sds100.keymapper.base.utils -import io.github.sds100.keymapper.keymaps.ClickType -import io.github.sds100.keymapper.trigger.KeyEventDetectionSource -import io.github.sds100.keymapper.trigger.Trigger -import io.github.sds100.keymapper.trigger.TriggerKey -import io.github.sds100.keymapper.trigger.TriggerKeyDevice -import io.github.sds100.keymapper.trigger.TriggerMode - -/** - * Created by sds100 on 19/04/2021. - */ +import io.github.sds100.keymapper.base.keymaps.ClickType +import io.github.sds100.keymapper.base.trigger.KeyCodeTriggerKey +import io.github.sds100.keymapper.base.trigger.KeyEventDetectionSource +import io.github.sds100.keymapper.base.trigger.Trigger +import io.github.sds100.keymapper.base.trigger.TriggerKey +import io.github.sds100.keymapper.base.trigger.TriggerKeyDevice +import io.github.sds100.keymapper.base.trigger.TriggerMode fun singleKeyTrigger(key: TriggerKey): Trigger = Trigger( keys = listOf(key), @@ -32,7 +29,7 @@ fun triggerKey( clickType: ClickType = ClickType.SHORT_PRESS, consume: Boolean = true, detectionSource: KeyEventDetectionSource = KeyEventDetectionSource.ACCESSIBILITY_SERVICE, -): _root_ide_package_.io.github.sds100.keymapper.trigger.KeyCodeTriggerKey = _root_ide_package_.io.github.sds100.keymapper.trigger.KeyCodeTriggerKey( +): KeyCodeTriggerKey = KeyCodeTriggerKey( keyCode = keyCode, device = device, clickType = clickType, diff --git a/base/src/test/java/io/github/sds100/keymapper/base/utils/TestBuildConfigProvider.kt b/base/src/test/java/io/github/sds100/keymapper/base/utils/TestBuildConfigProvider.kt new file mode 100644 index 0000000000..0bce5ac12c --- /dev/null +++ b/base/src/test/java/io/github/sds100/keymapper/base/utils/TestBuildConfigProvider.kt @@ -0,0 +1,13 @@ +package io.github.sds100.keymapper.base.utils + +import android.os.Build +import io.github.sds100.keymapper.base.BuildConfig +import io.github.sds100.keymapper.common.BuildConfigProvider + +class TestBuildConfigProvider : BuildConfigProvider { + override val minApi: Int = Build.VERSION_CODES.LOLLIPOP + override val maxApi: Int = 1000 + override val packageName: String = BuildConfig.LIBRARY_PACKAGE_NAME + override val version: String = "1.0.0" + override val versionCode: Int = 1 +} diff --git a/app/src/test/java/io/github/sds100/keymapper/util/TestConstraintSnapshot.kt b/base/src/test/java/io/github/sds100/keymapper/base/utils/TestConstraintSnapshot.kt similarity index 95% rename from app/src/test/java/io/github/sds100/keymapper/util/TestConstraintSnapshot.kt rename to base/src/test/java/io/github/sds100/keymapper/base/utils/TestConstraintSnapshot.kt index 6e2d46ec34..a01eaf2edb 100644 --- a/app/src/test/java/io/github/sds100/keymapper/util/TestConstraintSnapshot.kt +++ b/base/src/test/java/io/github/sds100/keymapper/base/utils/TestConstraintSnapshot.kt @@ -1,10 +1,10 @@ -package io.github.sds100.keymapper.util +package io.github.sds100.keymapper.base.utils -import io.github.sds100.keymapper.constraints.Constraint -import io.github.sds100.keymapper.constraints.ConstraintSnapshot +import io.github.sds100.keymapper.base.constraints.Constraint +import io.github.sds100.keymapper.base.constraints.ConstraintSnapshot +import io.github.sds100.keymapper.common.utils.Orientation import io.github.sds100.keymapper.system.bluetooth.BluetoothDeviceInfo import io.github.sds100.keymapper.system.camera.CameraLens -import io.github.sds100.keymapper.system.display.Orientation import io.github.sds100.keymapper.system.phone.CallState import timber.log.Timber import java.time.LocalTime diff --git a/app/src/test/java/io/github/sds100/keymapper/util/ui/FakeResourceProvider.kt b/base/src/test/java/io/github/sds100/keymapper/base/utils/ui/FakeResourceProvider.kt similarity index 91% rename from app/src/test/java/io/github/sds100/keymapper/util/ui/FakeResourceProvider.kt rename to base/src/test/java/io/github/sds100/keymapper/base/utils/ui/FakeResourceProvider.kt index 9574f8c285..d289db839d 100644 --- a/app/src/test/java/io/github/sds100/keymapper/util/ui/FakeResourceProvider.kt +++ b/base/src/test/java/io/github/sds100/keymapper/base/utils/ui/FakeResourceProvider.kt @@ -1,12 +1,9 @@ -package io.github.sds100.keymapper.util.ui +package io.github.sds100.keymapper.base.utils.ui import android.graphics.drawable.Drawable import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableSharedFlow -/** - * Created by sds100 on 26/04/2021. - */ class FakeResourceProvider : ResourceProvider { val stringResourceMap: MutableMap = mutableMapOf() override val onThemeChange: Flow = MutableSharedFlow() diff --git a/app/src/test/resources/backup-manager-test/corrupt.json b/base/src/test/resources/backup-manager-test/corrupt.json similarity index 100% rename from app/src/test/resources/backup-manager-test/corrupt.json rename to base/src/test/resources/backup-manager-test/corrupt.json diff --git a/base/src/test/resources/backup-manager-test/empty.json b/base/src/test/resources/backup-manager-test/empty.json new file mode 100644 index 0000000000..e69de29bb2 diff --git a/app/src/test/resources/backup-manager-test/legacy-backup-test-data.json b/base/src/test/resources/backup-manager-test/legacy-backup-test-data.json similarity index 100% rename from app/src/test/resources/backup-manager-test/legacy-backup-test-data.json rename to base/src/test/resources/backup-manager-test/legacy-backup-test-data.json diff --git a/app/src/test/resources/backup-manager-test/restore-all-legacy-fingerprint-maps-no-version.json b/base/src/test/resources/backup-manager-test/restore-all-legacy-fingerprint-maps-no-version.json similarity index 100% rename from app/src/test/resources/backup-manager-test/restore-all-legacy-fingerprint-maps-no-version.json rename to base/src/test/resources/backup-manager-test/restore-all-legacy-fingerprint-maps-no-version.json diff --git a/app/src/test/resources/backup-manager-test/restore-all-legacy-fingerprint-maps.json b/base/src/test/resources/backup-manager-test/restore-all-legacy-fingerprint-maps.json similarity index 100% rename from app/src/test/resources/backup-manager-test/restore-all-legacy-fingerprint-maps.json rename to base/src/test/resources/backup-manager-test/restore-all-legacy-fingerprint-maps.json diff --git a/app/src/test/resources/backup-manager-test/restore-all.zip/data.json b/base/src/test/resources/backup-manager-test/restore-all.zip/data.json similarity index 100% rename from app/src/test/resources/backup-manager-test/restore-all.zip/data.json rename to base/src/test/resources/backup-manager-test/restore-all.zip/data.json diff --git a/base/src/test/resources/backup-manager-test/restore-all.zip/sounds/sound.ogg b/base/src/test/resources/backup-manager-test/restore-all.zip/sounds/sound.ogg new file mode 100644 index 0000000000..e69de29bb2 diff --git a/app/src/test/resources/backup-manager-test/restore-app-version-too-big.zip/data.json b/base/src/test/resources/backup-manager-test/restore-app-version-too-big.zip/data.json similarity index 100% rename from app/src/test/resources/backup-manager-test/restore-app-version-too-big.zip/data.json rename to base/src/test/resources/backup-manager-test/restore-app-version-too-big.zip/data.json diff --git a/app/src/test/resources/backup-manager-test/restore-keymap-db-version-too-big.json b/base/src/test/resources/backup-manager-test/restore-keymap-db-version-too-big.json similarity index 100% rename from app/src/test/resources/backup-manager-test/restore-keymap-db-version-too-big.json rename to base/src/test/resources/backup-manager-test/restore-keymap-db-version-too-big.json diff --git a/app/src/test/resources/backup-manager-test/restore-keymaps-no-db-version.json b/base/src/test/resources/backup-manager-test/restore-keymaps-no-db-version.json similarity index 100% rename from app/src/test/resources/backup-manager-test/restore-keymaps-no-db-version.json rename to base/src/test/resources/backup-manager-test/restore-keymaps-no-db-version.json diff --git a/app/src/test/resources/backup-manager-test/restore-legacy-fingerprint-map-version-too-big.json b/base/src/test/resources/backup-manager-test/restore-legacy-fingerprint-map-version-too-big.json similarity index 100% rename from app/src/test/resources/backup-manager-test/restore-legacy-fingerprint-map-version-too-big.json rename to base/src/test/resources/backup-manager-test/restore-legacy-fingerprint-map-version-too-big.json diff --git a/app/src/test/resources/backup-manager-test/restore-legacy-single-fingerprint-map.json b/base/src/test/resources/backup-manager-test/restore-legacy-single-fingerprint-map.json similarity index 100% rename from app/src/test/resources/backup-manager-test/restore-legacy-single-fingerprint-map.json rename to base/src/test/resources/backup-manager-test/restore-legacy-single-fingerprint-map.json diff --git a/app/src/test/resources/backup-manager-test/restore-many-keymaps.json b/base/src/test/resources/backup-manager-test/restore-many-keymaps.json similarity index 100% rename from app/src/test/resources/backup-manager-test/restore-many-keymaps.json rename to base/src/test/resources/backup-manager-test/restore-many-keymaps.json diff --git a/app/src/test/resources/backup-manager-test/restore-no-app-version.zip/data.json b/base/src/test/resources/backup-manager-test/restore-no-app-version.zip/data.json similarity index 100% rename from app/src/test/resources/backup-manager-test/restore-no-app-version.zip/data.json rename to base/src/test/resources/backup-manager-test/restore-no-app-version.zip/data.json diff --git a/app/src/test/resources/backup-manager-test/restore-no-sounds-folder.zip/data.json b/base/src/test/resources/backup-manager-test/restore-no-sounds-folder.zip/data.json similarity index 100% rename from app/src/test/resources/backup-manager-test/restore-no-sounds-folder.zip/data.json rename to base/src/test/resources/backup-manager-test/restore-no-sounds-folder.zip/data.json diff --git a/app/src/test/resources/json-migration-test/migration-10-11-expected-data.json b/base/src/test/resources/json-migration-test/migration-10-11-expected-data.json similarity index 100% rename from app/src/test/resources/json-migration-test/migration-10-11-expected-data.json rename to base/src/test/resources/json-migration-test/migration-10-11-expected-data.json diff --git a/app/src/test/resources/json-migration-test/migration-10-11-test-data.json b/base/src/test/resources/json-migration-test/migration-10-11-test-data.json similarity index 100% rename from app/src/test/resources/json-migration-test/migration-10-11-test-data.json rename to base/src/test/resources/json-migration-test/migration-10-11-test-data.json diff --git a/app/src/test/resources/json-migration-test/migration-11-12-expected-data.json b/base/src/test/resources/json-migration-test/migration-11-12-expected-data.json similarity index 100% rename from app/src/test/resources/json-migration-test/migration-11-12-expected-data.json rename to base/src/test/resources/json-migration-test/migration-11-12-expected-data.json diff --git a/app/src/test/resources/json-migration-test/migration-11-12-test-data.json b/base/src/test/resources/json-migration-test/migration-11-12-test-data.json similarity index 100% rename from app/src/test/resources/json-migration-test/migration-11-12-test-data.json rename to base/src/test/resources/json-migration-test/migration-11-12-test-data.json diff --git a/app/src/test/resources/json-migration-test/migration-9-11-expected-data.json b/base/src/test/resources/json-migration-test/migration-9-11-expected-data.json similarity index 100% rename from app/src/test/resources/json-migration-test/migration-9-11-expected-data.json rename to base/src/test/resources/json-migration-test/migration-9-11-expected-data.json diff --git a/app/src/test/resources/json-migration-test/migration-9-11-test-data.json b/base/src/test/resources/json-migration-test/migration-9-11-test-data.json similarity index 100% rename from app/src/test/resources/json-migration-test/migration-9-11-test-data.json rename to base/src/test/resources/json-migration-test/migration-9-11-test-data.json diff --git a/build.gradle b/build.gradle deleted file mode 100644 index e17e83582b..0000000000 --- a/build.gradle +++ /dev/null @@ -1,41 +0,0 @@ -buildscript { - ext.kotlin_version = '2.1.0' - - repositories { - google() - mavenCentral() - maven { - url "https://plugins.gradle.org/m2/" - } - } - - dependencies { - def nav_version = '2.6.0' - - classpath "androidx.navigation:navigation-safe-args-gradle-plugin:$nav_version" - classpath 'com.android.tools.build:gradle:8.9.1' - classpath "org.jlleitschuh.gradle:ktlint-gradle:12.1.0" - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version" - classpath "org.jetbrains.kotlin.plugin.compose:org.jetbrains.kotlin.plugin.compose.gradle.plugin:2.1.0" - classpath "com.google.devtools.ksp:com.google.devtools.ksp.gradle.plugin:2.1.0-1.0.28" - classpath "androidx.room:androidx.room.gradle.plugin:2.6.1" - // NOTE: Do not place your application dependencies here; they belong - // in the individual module build.gradle files - } -} - -allprojects { - repositories { - google() - mavenCentral() - maven { url "https://jitpack.io" } - maven { url 'https://maven.google.com/' } - maven { url 'https://dl.bintray.com/rikkaw/Shizuku' } - } -} - -task clean(type: Delete) { - delete rootProject.buildDir -} - diff --git a/build.gradle.kts b/build.gradle.kts new file mode 100644 index 0000000000..9e070cd106 --- /dev/null +++ b/build.gradle.kts @@ -0,0 +1,15 @@ + // Top-level build file where you can add configuration options common to all sub-projects/modules. +plugins { + alias(libs.plugins.android.application) apply false + alias(libs.plugins.kotlin.android) apply false + alias(libs.plugins.kotlin.compose) apply false + alias(libs.plugins.kotlin.kapt) apply false + alias(libs.plugins.kotlin.serialization) apply false + alias(libs.plugins.kotlin.parcelize) apply false + alias(libs.plugins.androidx.navigation.safeargs.kotlin) apply false + alias(libs.plugins.androidx.room) apply false + alias(libs.plugins.google.devtools.ksp) apply false + alias(libs.plugins.jlleitschuh.gradle.ktlint) apply false + alias(libs.plugins.android.library) apply false + alias(libs.plugins.dagger.hilt.android) apply false +} diff --git a/common/.gitignore b/common/.gitignore new file mode 100644 index 0000000000..42afabfd2a --- /dev/null +++ b/common/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/common/build.gradle.kts b/common/build.gradle.kts new file mode 100644 index 0000000000..a2f2a1491f --- /dev/null +++ b/common/build.gradle.kts @@ -0,0 +1,51 @@ +plugins { + alias(libs.plugins.android.library) + alias(libs.plugins.kotlin.android) + alias(libs.plugins.jlleitschuh.gradle.ktlint) + alias(libs.plugins.kotlin.serialization) + alias(libs.plugins.google.devtools.ksp) + alias(libs.plugins.dagger.hilt.android) +} + +android { + namespace = "io.github.sds100.keymapper.common" + compileSdk = libs.versions.compile.sdk.get().toInt() + + defaultConfig { + minSdk = libs.versions.min.sdk.get().toInt() + + consumerProguardFiles("consumer-rules.pro") + } + + buildTypes { + release { + isMinifyEnabled = true + proguardFiles( + getDefaultProguardFile("proguard-android-optimize.txt"), + "proguard-rules.pro", + ) + } + } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 + } + + kotlinOptions { + jvmTarget = "11" + } + + composeOptions { + kotlinCompilerExtensionVersion = libs.versions.compose.compiler.get() + } +} + +dependencies { + // kotlin stuff + implementation(libs.kotlinx.coroutines.android) + implementation(libs.kotlinx.serialization.json) + + implementation(libs.androidx.core.ktx) + implementation(libs.dagger.hilt.android) + ksp(libs.dagger.hilt.android.compiler) +} diff --git a/common/consumer-rules.pro b/common/consumer-rules.pro new file mode 100644 index 0000000000..e69de29bb2 diff --git a/common/proguard-rules.pro b/common/proguard-rules.pro new file mode 100644 index 0000000000..481bb43481 --- /dev/null +++ b/common/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/common/src/main/AndroidManifest.xml b/common/src/main/AndroidManifest.xml new file mode 100644 index 0000000000..44008a4332 --- /dev/null +++ b/common/src/main/AndroidManifest.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/common/src/main/java/io/github/sds100/keymapper/common/BuildConfigProvider.kt b/common/src/main/java/io/github/sds100/keymapper/common/BuildConfigProvider.kt new file mode 100644 index 0000000000..c52f9e2116 --- /dev/null +++ b/common/src/main/java/io/github/sds100/keymapper/common/BuildConfigProvider.kt @@ -0,0 +1,9 @@ +package io.github.sds100.keymapper.common + +interface BuildConfigProvider { + val minApi: Int + val maxApi: Int + val packageName: String + val version: String + val versionCode: Int +} diff --git a/common/src/main/java/io/github/sds100/keymapper/common/KeyMapperClassProvider.kt b/common/src/main/java/io/github/sds100/keymapper/common/KeyMapperClassProvider.kt new file mode 100644 index 0000000000..b973f33365 --- /dev/null +++ b/common/src/main/java/io/github/sds100/keymapper/common/KeyMapperClassProvider.kt @@ -0,0 +1,6 @@ +package io.github.sds100.keymapper.common + +interface KeyMapperClassProvider { + fun getMainActivity(): Class<*> + fun getAccessibilityService(): Class<*> +} diff --git a/common/src/main/java/io/github/sds100/keymapper/common/utils/BuildUtils.kt b/common/src/main/java/io/github/sds100/keymapper/common/utils/BuildUtils.kt new file mode 100644 index 0000000000..6a44d3785f --- /dev/null +++ b/common/src/main/java/io/github/sds100/keymapper/common/utils/BuildUtils.kt @@ -0,0 +1,33 @@ +package io.github.sds100.keymapper.common.utils + +import android.os.Build + +object BuildUtils { + /** + * @return the name of the android version for each [Build.VERSION_CODES] after the minimum api for this app. + * + * E.g 28 = "Pie 9.0" + */ + fun getSdkVersionName(version: Int): String = when (version) { + Build.VERSION_CODES.JELLY_BEAN -> "Jelly Bean 4.1" + Build.VERSION_CODES.JELLY_BEAN_MR1 -> "Jelly Bean 4.2" + Build.VERSION_CODES.JELLY_BEAN_MR2 -> "Jelly Bean 4.3" + Build.VERSION_CODES.KITKAT -> "KitKat 4.4" + Build.VERSION_CODES.LOLLIPOP -> "Lollipop 5.0" + Build.VERSION_CODES.LOLLIPOP_MR1 -> "Lollipop 5.1" + Build.VERSION_CODES.M -> "Marshmallow 6.0" + Build.VERSION_CODES.N -> "Nougat 7.0" + Build.VERSION_CODES.N_MR1 -> "Nougat 7.1" + Build.VERSION_CODES.O -> "Oreo 8.0" + Build.VERSION_CODES.O_MR1 -> "Oreo 8.1" + Build.VERSION_CODES.P -> "Pie 9.0" + Build.VERSION_CODES.Q -> "10" + Build.VERSION_CODES.R -> "11" + Build.VERSION_CODES.S -> "12" + Build.VERSION_CODES.S_V2 -> "12L" + Build.VERSION_CODES.TIRAMISU -> "13" + Build.VERSION_CODES.UPSIDE_DOWN_CAKE -> "14" + Build.VERSION_CODES.VANILLA_ICE_CREAM -> "15" + else -> "API $version" + } +} diff --git a/app/src/main/java/io/github/sds100/keymapper/util/BundleUtils.kt b/common/src/main/java/io/github/sds100/keymapper/common/utils/BundleUtils.kt similarity index 63% rename from app/src/main/java/io/github/sds100/keymapper/util/BundleUtils.kt rename to common/src/main/java/io/github/sds100/keymapper/common/utils/BundleUtils.kt index b0be6c5e29..da327c98d2 100644 --- a/app/src/main/java/io/github/sds100/keymapper/util/BundleUtils.kt +++ b/common/src/main/java/io/github/sds100/keymapper/common/utils/BundleUtils.kt @@ -1,14 +1,8 @@ -package io.github.sds100.keymapper.ui.utils +package io.github.sds100.keymapper.common.utils import android.os.Bundle -import kotlinx.serialization.decodeFromString -import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json -/** - * Created by sds100 on 15/03/2021. - */ - inline fun Bundle.getJsonSerializable(key: String): T? = getString(key)?.let { Json.decodeFromString(it) } diff --git a/common/src/main/java/io/github/sds100/keymapper/common/utils/CoroutineUtils.kt b/common/src/main/java/io/github/sds100/keymapper/common/utils/CoroutineUtils.kt new file mode 100644 index 0000000000..de93311481 --- /dev/null +++ b/common/src/main/java/io/github/sds100/keymapper/common/utils/CoroutineUtils.kt @@ -0,0 +1,15 @@ +package io.github.sds100.keymapper.common.utils + +import kotlinx.coroutines.CancellableContinuation +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.runBlocking +import kotlin.coroutines.resume + +fun CancellableContinuation.resumeIfNotCompleted(value: T) { + if (!this.isCompleted) { + this.resume(value) + } +} + +fun Flow.firstBlocking(): T = runBlocking { first() } diff --git a/app/src/main/java/io/github/sds100/keymapper/util/DispatcherProvider.kt b/common/src/main/java/io/github/sds100/keymapper/common/utils/DispatcherProvider.kt similarity index 83% rename from app/src/main/java/io/github/sds100/keymapper/util/DispatcherProvider.kt rename to common/src/main/java/io/github/sds100/keymapper/common/utils/DispatcherProvider.kt index 0a9949f6d3..0d980b3ccd 100644 --- a/app/src/main/java/io/github/sds100/keymapper/util/DispatcherProvider.kt +++ b/common/src/main/java/io/github/sds100/keymapper/common/utils/DispatcherProvider.kt @@ -1,12 +1,8 @@ -package io.github.sds100.keymapper.util +package io.github.sds100.keymapper.common.utils import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.Dispatchers -/** - * Created by sds100 on 30/01/21. - */ - interface DispatcherProvider { fun main(): CoroutineDispatcher = Dispatchers.Main fun default(): CoroutineDispatcher = Dispatchers.Default diff --git a/app/src/main/java/io/github/sds100/keymapper/util/DisplayUtils.kt b/common/src/main/java/io/github/sds100/keymapper/common/utils/DisplayUtils.kt similarity index 94% rename from app/src/main/java/io/github/sds100/keymapper/util/DisplayUtils.kt rename to common/src/main/java/io/github/sds100/keymapper/common/utils/DisplayUtils.kt index b5e625cd98..6f0f332b70 100644 --- a/app/src/main/java/io/github/sds100/keymapper/util/DisplayUtils.kt +++ b/common/src/main/java/io/github/sds100/keymapper/common/utils/DisplayUtils.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.util +package io.github.sds100.keymapper.common.utils import android.content.Context import android.graphics.Point diff --git a/common/src/main/java/io/github/sds100/keymapper/common/utils/FlagUtils.kt b/common/src/main/java/io/github/sds100/keymapper/common/utils/FlagUtils.kt new file mode 100644 index 0000000000..e152dcd305 --- /dev/null +++ b/common/src/main/java/io/github/sds100/keymapper/common/utils/FlagUtils.kt @@ -0,0 +1,43 @@ +/* + * Copyright 2019-2021 Louis Cognault Ayeva Derman. Use of this source code is governed by the Apache 2.0 license. + */ + +@file:Suppress("NOTHING_TO_INLINE") + +package io.github.sds100.keymapper.common.utils + +import kotlin.experimental.and +import kotlin.experimental.inv +import kotlin.experimental.or + +inline fun Long.hasFlag(flag: Long): Boolean = flag and this == flag +inline fun Long.withFlag(flag: Long): Long = this or flag +inline fun Long.minusFlag(flag: Long): Long = this and flag.inv() + +inline fun Int.hasFlag(flag: Int): Boolean = flag and this == flag +inline fun Int.withFlag(flag: Int): Int = this or flag +inline fun Int.minusFlag(flag: Int): Int = this and flag.inv() + +inline fun Short.hasFlag(flag: Short): Boolean = flag and this == flag +inline fun Short.withFlag(flag: Short): Short = this or flag +inline fun Short.minusFlag(flag: Short): Short = this and flag.inv() + +inline fun Byte.hasFlag(flag: Byte): Boolean = flag and this == flag +inline fun Byte.withFlag(flag: Byte): Byte = this or flag +inline fun Byte.minusFlag(flag: Byte): Byte = this and flag.inv() + +inline fun ULong.hasFlag(flag: ULong): Boolean = flag and this == flag +inline fun ULong.withFlag(flag: ULong): ULong = this or flag +inline fun ULong.minusFlag(flag: ULong): ULong = this and flag.inv() + +inline fun UInt.hasFlag(flag: UInt): Boolean = flag and this == flag +inline fun UInt.withFlag(flag: UInt): UInt = this or flag +inline fun UInt.minusFlag(flag: UInt): UInt = this and flag.inv() + +inline fun UShort.hasFlag(flag: UShort): Boolean = flag and this == flag +inline fun UShort.withFlag(flag: UShort): UShort = this or flag +inline fun UShort.minusFlag(flag: UShort): UShort = this and flag.inv() + +inline fun UByte.hasFlag(flag: UByte): Boolean = flag and this == flag +inline fun UByte.withFlag(flag: UByte): UByte = this or flag +inline fun UByte.minusFlag(flag: UByte): UByte = this and flag.inv() diff --git a/common/src/main/java/io/github/sds100/keymapper/common/utils/InputEventType.kt b/common/src/main/java/io/github/sds100/keymapper/common/utils/InputEventType.kt new file mode 100644 index 0000000000..e3805172d5 --- /dev/null +++ b/common/src/main/java/io/github/sds100/keymapper/common/utils/InputEventType.kt @@ -0,0 +1,7 @@ +package io.github.sds100.keymapper.common.utils + +enum class InputEventType { + DOWN_UP, + DOWN, + UP, +} diff --git a/common/src/main/java/io/github/sds100/keymapper/common/utils/KMResult.kt b/common/src/main/java/io/github/sds100/keymapper/common/utils/KMResult.kt new file mode 100644 index 0000000000..ac7493b303 --- /dev/null +++ b/common/src/main/java/io/github/sds100/keymapper/common/utils/KMResult.kt @@ -0,0 +1,167 @@ +package io.github.sds100.keymapper.common.utils + +/** + * Inspired from @antonyharfield great example! + */ + +sealed class KMResult + +data class Success(val value: T) : KMResult() + +abstract class KMError : KMResult() { + data class Exception(val exception: java.lang.Exception) : KMError() + data class SystemFeatureNotSupported(val feature: String) : KMError() + data class SdkVersionTooLow(val minSdk: Int) : KMError() + data class SdkVersionTooHigh(val maxSdk: Int) : KMError() + data class InputMethodNotFound(val imeLabel: String) : KMError() + data object NoVoiceAssistant : KMError() + data object NoDeviceAssistant : KMError() + data object NoCameraApp : KMError() + data object NoSettingsApp : KMError() + data object FrontFlashNotFound : KMError() + data object BackFlashNotFound : KMError() + data class DeviceNotFound(val descriptor: String) : KMError() + data object InvalidNumber : KMError() + data class NumberTooBig(val max: Int) : KMError() + data class NumberTooSmall(val min: Int) : KMError() + data object EmptyText : KMError() + data object NoIncompatibleKeyboardsInstalled : KMError() + data object NoMediaSessions : KMError() + data object BackupVersionTooNew : KMError() + data object LauncherShortcutsNotSupported : KMError() + + data class AppNotFound(val packageName: String) : KMError() + data class AppDisabled(val packageName: String) : KMError() + data object AppShortcutCantBeOpened : KMError() + data object InsufficientPermissionsToOpenAppShortcut : KMError() + data object NoCompatibleImeEnabled : KMError() + data object NoCompatibleImeChosen : KMError() + + data object AccessibilityServiceDisabled : KMError() + data object AccessibilityServiceCrashed : KMError() + + data object CantShowImePickerInBackground : KMError() + data object CantFindImeSettings : KMError() + data object GestureStrokeCountTooHigh : KMError() + data object GestureDurationTooHigh : KMError() + + data object FailedToFindAccessibilityNode : KMError() + data class FailedToPerformAccessibilityGlobalAction(val action: Int) : KMError() + data object FailedToDispatchGesture : KMError() + + data object CameraInUse : KMError() + data object CameraDisconnected : KMError() + data object CameraDisabled : KMError() + data object MaxCamerasInUse : KMError() + data object CameraError : KMError() + data object CameraVariableFlashlightStrengthUnsupported : KMError() + + data class FailedToModifySystemSetting(val setting: String) : KMError() + data object FailedToChangeIme : KMError() + data object NoAppToOpenUrl : KMError() + data object NoAppToPhoneCall : KMError() + + data class NotAFile(val uri: String) : KMError() + data class NotADirectory(val uri: String) : KMError() + data object StoragePermissionDenied : KMError() + data class CannotCreateFileInTarget(val uri: String) : KMError() + data class SourceFileNotFound(val uri: String) : KMError() + data class TargetFileNotFound(val uri: String) : KMError() + data class TargetDirectoryNotFound(val uri: String) : KMError() + data object UnknownIOError : KMError() + data object FileOperationCancelled : KMError() + data object TargetDirectoryMatchesSourceDirectory : KMError() + data class NoSpaceLeftOnTarget(val uri: String) : KMError() + data object NoFileName : KMError() + data object InvalidBackup : KMError() + + data object EmptyJson : KMError() + data object CantFindSoundFile : KMError() + data class CorruptJsonFile(val reason: String) : KMError() + + data object ShizukuNotStarted : KMError() + data object CantDetectKeyEventsInPhoneCall : KMError() + + /** + * DPAD triggers require a Key Mapper keyboard to be selected. + */ + data object DpadTriggerImeNotSelected : KMError() + data object MalformedUrl : KMError() + + data object UiElementNotFound : KMError() +} + +inline fun KMResult.onSuccess(f: (T) -> Unit): KMResult { + if (this is Success) { + f(this.value) + } + + return this +} + +inline fun KMResult.onFailure(f: (error: KMError) -> U): KMResult { + if (this is KMError) { + f(this) + } + + return this +} + +inline infix fun KMResult.then(f: (T) -> KMResult) = when (this) { + is Success -> f(this.value) + is KMError -> this +} + +suspend infix fun KMResult.suspendThen(f: suspend (T) -> KMResult) = when (this) { + is Success -> f(this.value) + is KMError -> this +} + +inline infix fun KMResult.otherwise(f: (error: KMError) -> KMResult) = when (this) { + is Success -> this + is KMError -> f(this) +} + +inline fun KMResult.resolve( + onSuccess: (value: T) -> U, + onFailure: (error: KMError) -> U, +) = when (this) { + is Success -> onSuccess(this.value) + is KMError -> onFailure(this) +} + +inline infix fun KMResult.valueIfFailure(f: (error: KMError) -> T): T = when (this) { + is Success -> this.value + is KMError -> f(this) +} + +fun KMResult.errorOrNull(): KMError? { + when (this) { + is KMError -> return this + else -> Unit + } + + return null +} + +fun KMResult.valueOrNull(): T? { + when (this) { + is Success -> return this.value + else -> Unit + } + + return null +} + +val KMResult.isError: Boolean + get() = this is KMError + +val KMResult.isSuccess: Boolean + get() = this is Success + +fun KMResult.handle(onSuccess: (value: T) -> U, onError: (error: KMError) -> U): U = when (this) { + is Success -> onSuccess(value) + is KMError -> onError(this) +} + +fun T.success() = Success(this) diff --git a/app/src/main/java/io/github/sds100/keymapper/util/ListUtils.kt b/common/src/main/java/io/github/sds100/keymapper/common/utils/ListUtils.kt similarity index 91% rename from app/src/main/java/io/github/sds100/keymapper/util/ListUtils.kt rename to common/src/main/java/io/github/sds100/keymapper/common/utils/ListUtils.kt index 429f0b7a48..0b07f85202 100644 --- a/app/src/main/java/io/github/sds100/keymapper/util/ListUtils.kt +++ b/common/src/main/java/io/github/sds100/keymapper/common/utils/ListUtils.kt @@ -1,11 +1,7 @@ -package io.github.sds100.keymapper.util +package io.github.sds100.keymapper.common.utils import java.util.Collections -/** - * Created by sds100 on 11/03/2021. - */ - fun MutableList<*>.moveElement(fromIndex: Int, toIndex: Int) { if (toIndex >= size || fromIndex >= size) { return diff --git a/app/src/main/java/io/github/sds100/keymapper/util/MapUtils.kt b/common/src/main/java/io/github/sds100/keymapper/common/utils/MapUtils.kt similarity index 60% rename from app/src/main/java/io/github/sds100/keymapper/util/MapUtils.kt rename to common/src/main/java/io/github/sds100/keymapper/common/utils/MapUtils.kt index 90ae18d739..a3874745a9 100644 --- a/app/src/main/java/io/github/sds100/keymapper/util/MapUtils.kt +++ b/common/src/main/java/io/github/sds100/keymapper/common/utils/MapUtils.kt @@ -1,8 +1,4 @@ -package io.github.sds100.keymapper.util - -/** - * Created by sds100 on 19/03/2021. - */ +package io.github.sds100.keymapper.common.utils /** * Not for high speed stuff. diff --git a/app/src/main/java/io/github/sds100/keymapper/util/MathUtils.kt b/common/src/main/java/io/github/sds100/keymapper/common/utils/MathUtils.kt similarity index 97% rename from app/src/main/java/io/github/sds100/keymapper/util/MathUtils.kt rename to common/src/main/java/io/github/sds100/keymapper/common/utils/MathUtils.kt index 8b2037c7d6..ad24560739 100644 --- a/app/src/main/java/io/github/sds100/keymapper/util/MathUtils.kt +++ b/common/src/main/java/io/github/sds100/keymapper/common/utils/MathUtils.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.util +package io.github.sds100.keymapper.common.utils import android.graphics.Point import kotlin.math.atan2 diff --git a/app/src/main/java/io/github/sds100/keymapper/actions/uielement/NodeInteractionType.kt b/common/src/main/java/io/github/sds100/keymapper/common/utils/NodeInteractionType.kt similarity index 90% rename from app/src/main/java/io/github/sds100/keymapper/actions/uielement/NodeInteractionType.kt rename to common/src/main/java/io/github/sds100/keymapper/common/utils/NodeInteractionType.kt index 8d02874b45..5ea59249aa 100644 --- a/app/src/main/java/io/github/sds100/keymapper/actions/uielement/NodeInteractionType.kt +++ b/common/src/main/java/io/github/sds100/keymapper/common/utils/NodeInteractionType.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.actions.uielement +package io.github.sds100.keymapper.common.utils import android.view.accessibility.AccessibilityNodeInfo diff --git a/app/src/main/java/io/github/sds100/keymapper/system/display/Orientation.kt b/common/src/main/java/io/github/sds100/keymapper/common/utils/Orientation.kt similarity index 53% rename from app/src/main/java/io/github/sds100/keymapper/system/display/Orientation.kt rename to common/src/main/java/io/github/sds100/keymapper/common/utils/Orientation.kt index f29629ac9e..dc0d7413b7 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/display/Orientation.kt +++ b/common/src/main/java/io/github/sds100/keymapper/common/utils/Orientation.kt @@ -1,8 +1,5 @@ -package io.github.sds100.keymapper.system.display +package io.github.sds100.keymapper.common.utils -/** - * Created by sds100 on 22/02/2021. - */ enum class Orientation { ORIENTATION_0, ORIENTATION_90, diff --git a/common/src/main/java/io/github/sds100/keymapper/common/utils/PinchScreenType.kt b/common/src/main/java/io/github/sds100/keymapper/common/utils/PinchScreenType.kt new file mode 100644 index 0000000000..ec069521f1 --- /dev/null +++ b/common/src/main/java/io/github/sds100/keymapper/common/utils/PinchScreenType.kt @@ -0,0 +1,6 @@ +package io.github.sds100.keymapper.common.utils + +enum class PinchScreenType { + PINCH_IN, + PINCH_OUT, +} diff --git a/app/src/main/java/io/github/sds100/keymapper/util/SizeKM.kt b/common/src/main/java/io/github/sds100/keymapper/common/utils/SizeKM.kt similarity index 77% rename from app/src/main/java/io/github/sds100/keymapper/util/SizeKM.kt rename to common/src/main/java/io/github/sds100/keymapper/common/utils/SizeKM.kt index db92edb679..04e65dc7f7 100644 --- a/app/src/main/java/io/github/sds100/keymapper/util/SizeKM.kt +++ b/common/src/main/java/io/github/sds100/keymapper/common/utils/SizeKM.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.util +package io.github.sds100.keymapper.common.utils import kotlinx.serialization.Serializable diff --git a/app/src/main/java/io/github/sds100/keymapper/util/State.kt b/common/src/main/java/io/github/sds100/keymapper/common/utils/State.kt similarity index 86% rename from app/src/main/java/io/github/sds100/keymapper/util/State.kt rename to common/src/main/java/io/github/sds100/keymapper/common/utils/State.kt index 57cd353eb2..81aaa68288 100644 --- a/app/src/main/java/io/github/sds100/keymapper/util/State.kt +++ b/common/src/main/java/io/github/sds100/keymapper/common/utils/State.kt @@ -1,8 +1,5 @@ -package io.github.sds100.keymapper.util +package io.github.sds100.keymapper.common.utils -/** - * Created by sds100 on 17/03/2021. - */ sealed class State { data class Data(val data: T) : State() data object Loading : State() diff --git a/app/src/main/java/io/github/sds100/keymapper/util/StringUtils.kt b/common/src/main/java/io/github/sds100/keymapper/common/utils/StringUtils.kt similarity index 84% rename from app/src/main/java/io/github/sds100/keymapper/util/StringUtils.kt rename to common/src/main/java/io/github/sds100/keymapper/common/utils/StringUtils.kt index 0e68e5e666..e593631591 100644 --- a/app/src/main/java/io/github/sds100/keymapper/util/StringUtils.kt +++ b/common/src/main/java/io/github/sds100/keymapper/common/utils/StringUtils.kt @@ -1,13 +1,8 @@ -package io.github.sds100.keymapper.util +package io.github.sds100.keymapper.common.utils -import androidx.annotation.IntRange import kotlin.math.roundToInt -/** - * Created by sds100 on 24/04/2021. - */ - -fun String.getWordBoundaries(@IntRange(from = 0L) cursorPosition: Int): Pair? { +fun String.getWordBoundaries(cursorPosition: Int): Pair? { if (this.isBlank()) return null // return null if there is just whitespace around the position diff --git a/app/src/main/java/io/github/sds100/keymapper/util/TimeUtils.kt b/common/src/main/java/io/github/sds100/keymapper/common/utils/TimeUtils.kt similarity index 85% rename from app/src/main/java/io/github/sds100/keymapper/util/TimeUtils.kt rename to common/src/main/java/io/github/sds100/keymapper/common/utils/TimeUtils.kt index 633e084da4..450e438d9b 100644 --- a/app/src/main/java/io/github/sds100/keymapper/util/TimeUtils.kt +++ b/common/src/main/java/io/github/sds100/keymapper/common/utils/TimeUtils.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.util +package io.github.sds100.keymapper.common.utils import java.time.format.DateTimeFormatter import java.time.format.FormatStyle diff --git a/app/src/main/java/io/github/sds100/keymapper/util/TreeNode.kt b/common/src/main/java/io/github/sds100/keymapper/common/utils/TreeNode.kt similarity index 89% rename from app/src/main/java/io/github/sds100/keymapper/util/TreeNode.kt rename to common/src/main/java/io/github/sds100/keymapper/common/utils/TreeNode.kt index 52e63d0e30..1165dfb6fc 100644 --- a/app/src/main/java/io/github/sds100/keymapper/util/TreeNode.kt +++ b/common/src/main/java/io/github/sds100/keymapper/common/utils/TreeNode.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.util +package io.github.sds100.keymapper.common.utils data class TreeNode(val value: T, val children: MutableList> = mutableListOf()) diff --git a/app/src/main/java/io/github/sds100/keymapper/util/UserHandleUtils.kt b/common/src/main/java/io/github/sds100/keymapper/common/utils/UserHandleUtils.kt similarity index 70% rename from app/src/main/java/io/github/sds100/keymapper/util/UserHandleUtils.kt rename to common/src/main/java/io/github/sds100/keymapper/common/utils/UserHandleUtils.kt index 09018ca073..43880737a5 100644 --- a/app/src/main/java/io/github/sds100/keymapper/util/UserHandleUtils.kt +++ b/common/src/main/java/io/github/sds100/keymapper/common/utils/UserHandleUtils.kt @@ -1,11 +1,7 @@ -package io.github.sds100.keymapper.util +package io.github.sds100.keymapper.common.utils import android.os.UserHandle -/** - * Created by sds100 on 20/07/2021. - */ - fun UserHandle.getIdentifier(): Int { val getIdentifierMethod = UserHandle::class.java.getMethod("getIdentifier") diff --git a/app/src/main/java/io/github/sds100/keymapper/util/UuidGenerator.kt b/common/src/main/java/io/github/sds100/keymapper/common/utils/UuidGenerator.kt similarity index 50% rename from app/src/main/java/io/github/sds100/keymapper/util/UuidGenerator.kt rename to common/src/main/java/io/github/sds100/keymapper/common/utils/UuidGenerator.kt index 8b44af483c..9c0ebf6ae4 100644 --- a/app/src/main/java/io/github/sds100/keymapper/util/UuidGenerator.kt +++ b/common/src/main/java/io/github/sds100/keymapper/common/utils/UuidGenerator.kt @@ -1,12 +1,9 @@ -package io.github.sds100.keymapper.util +package io.github.sds100.keymapper.common.utils import java.util.UUID +import javax.inject.Inject -/** - * Created by sds100 on 29/06/2021. - */ - -class DefaultUuidGenerator : UuidGenerator { +class DefaultUuidGenerator @Inject constructor() : UuidGenerator { override fun random(): String = UUID.randomUUID().toString() } diff --git a/crowdin.yaml b/crowdin.yaml index 4aac34d394..3551026c2e 100644 --- a/crowdin.yaml +++ b/crowdin.yaml @@ -5,8 +5,8 @@ api_token_env: "CROWDIN_PERSONAL_TOKEN" preserve_hierarchy: true files: - - source: /app/src/main/res/values/strings.xml - translation: /app/src/main/res/values-%two_letters_code%/strings.xml + - source: /base/src/main/res/values/strings.xml + translation: /base/src/main/res/values-%two_letters_code%/strings.xml - source: /fastlane/metadata/android/en-US/full_description.txt translation: /fastlane/metadata/android/%locale_with_underscore%/full_description.txt - source: /fastlane/metadata/android/en-US/short_description.txt diff --git a/data/.gitignore b/data/.gitignore new file mode 100644 index 0000000000..42afabfd2a --- /dev/null +++ b/data/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/data/build.gradle.kts b/data/build.gradle.kts new file mode 100644 index 0000000000..f8c352922b --- /dev/null +++ b/data/build.gradle.kts @@ -0,0 +1,66 @@ +plugins { + alias(libs.plugins.android.library) + alias(libs.plugins.kotlin.android) + alias(libs.plugins.kotlin.serialization) + alias(libs.plugins.kotlin.parcelize) + alias(libs.plugins.androidx.room) + alias(libs.plugins.google.devtools.ksp) + alias(libs.plugins.jlleitschuh.gradle.ktlint) +} + +android { + namespace = "io.github.sds100.keymapper.data" + compileSdk = libs.versions.compile.sdk.get().toInt() + + defaultConfig { + minSdk = libs.versions.min.sdk.get().toInt() + + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + consumerProguardFiles("consumer-rules.pro") + } + + buildTypes { + release { + isMinifyEnabled = true + proguardFiles( + getDefaultProguardFile("proguard-android-optimize.txt"), + "proguard-rules.pro", + ) + } + } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 + } + kotlinOptions { + jvmTarget = "11" + } + + room { + + schemaDirectory("$projectDir/schemas") + } +} + +dependencies { + implementation(project(":common")) + + // kotlin stuff + implementation(libs.kotlinx.coroutines.android) + implementation(libs.kotlinx.serialization.json) + implementation(libs.androidx.core.ktx) + + implementation(libs.androidx.room.ktx) + ksp(libs.androidx.room.compiler) + + implementation(libs.androidx.datastore.preferences) + implementation(libs.androidx.preference.ktx) + implementation(libs.kotson) + implementation(libs.jakewharton.timber) + + implementation(libs.dagger.hilt.android) + ksp(libs.dagger.hilt.android.compiler) + + testImplementation(libs.junit) + androidTestImplementation(libs.androidx.test.ext.junit) +} diff --git a/data/consumer-rules.pro b/data/consumer-rules.pro new file mode 100644 index 0000000000..e69de29bb2 diff --git a/data/proguard-rules.pro b/data/proguard-rules.pro new file mode 100644 index 0000000000..481bb43481 --- /dev/null +++ b/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/app/schemas/io.github.sds100.keymapper.data.db.AppDatabase/1.json b/data/schemas/io.github.sds100.keymapper.data.db.AppDatabase/1.json similarity index 100% rename from app/schemas/io.github.sds100.keymapper.data.db.AppDatabase/1.json rename to data/schemas/io.github.sds100.keymapper.data.db.AppDatabase/1.json diff --git a/app/schemas/io.github.sds100.keymapper.data.db.AppDatabase/10.json b/data/schemas/io.github.sds100.keymapper.data.db.AppDatabase/10.json similarity index 100% rename from app/schemas/io.github.sds100.keymapper.data.db.AppDatabase/10.json rename to data/schemas/io.github.sds100.keymapper.data.db.AppDatabase/10.json diff --git a/app/schemas/io.github.sds100.keymapper.data.db.AppDatabase/11.json b/data/schemas/io.github.sds100.keymapper.data.db.AppDatabase/11.json similarity index 100% rename from app/schemas/io.github.sds100.keymapper.data.db.AppDatabase/11.json rename to data/schemas/io.github.sds100.keymapper.data.db.AppDatabase/11.json diff --git a/app/schemas/io.github.sds100.keymapper.data.db.AppDatabase/12.json b/data/schemas/io.github.sds100.keymapper.data.db.AppDatabase/12.json similarity index 100% rename from app/schemas/io.github.sds100.keymapper.data.db.AppDatabase/12.json rename to data/schemas/io.github.sds100.keymapper.data.db.AppDatabase/12.json diff --git a/app/schemas/io.github.sds100.keymapper.data.db.AppDatabase/13.json b/data/schemas/io.github.sds100.keymapper.data.db.AppDatabase/13.json similarity index 100% rename from app/schemas/io.github.sds100.keymapper.data.db.AppDatabase/13.json rename to data/schemas/io.github.sds100.keymapper.data.db.AppDatabase/13.json diff --git a/app/schemas/io.github.sds100.keymapper.data.db.AppDatabase/14.json b/data/schemas/io.github.sds100.keymapper.data.db.AppDatabase/14.json similarity index 100% rename from app/schemas/io.github.sds100.keymapper.data.db.AppDatabase/14.json rename to data/schemas/io.github.sds100.keymapper.data.db.AppDatabase/14.json diff --git a/app/schemas/io.github.sds100.keymapper.data.db.AppDatabase/15.json b/data/schemas/io.github.sds100.keymapper.data.db.AppDatabase/15.json similarity index 100% rename from app/schemas/io.github.sds100.keymapper.data.db.AppDatabase/15.json rename to data/schemas/io.github.sds100.keymapper.data.db.AppDatabase/15.json diff --git a/app/schemas/io.github.sds100.keymapper.data.db.AppDatabase/16.json b/data/schemas/io.github.sds100.keymapper.data.db.AppDatabase/16.json similarity index 100% rename from app/schemas/io.github.sds100.keymapper.data.db.AppDatabase/16.json rename to data/schemas/io.github.sds100.keymapper.data.db.AppDatabase/16.json diff --git a/app/schemas/io.github.sds100.keymapper.data.db.AppDatabase/17.json b/data/schemas/io.github.sds100.keymapper.data.db.AppDatabase/17.json similarity index 100% rename from app/schemas/io.github.sds100.keymapper.data.db.AppDatabase/17.json rename to data/schemas/io.github.sds100.keymapper.data.db.AppDatabase/17.json diff --git a/app/schemas/io.github.sds100.keymapper.data.db.AppDatabase/18.json b/data/schemas/io.github.sds100.keymapper.data.db.AppDatabase/18.json similarity index 100% rename from app/schemas/io.github.sds100.keymapper.data.db.AppDatabase/18.json rename to data/schemas/io.github.sds100.keymapper.data.db.AppDatabase/18.json diff --git a/app/schemas/io.github.sds100.keymapper.data.db.AppDatabase/19.json b/data/schemas/io.github.sds100.keymapper.data.db.AppDatabase/19.json similarity index 100% rename from app/schemas/io.github.sds100.keymapper.data.db.AppDatabase/19.json rename to data/schemas/io.github.sds100.keymapper.data.db.AppDatabase/19.json diff --git a/app/schemas/io.github.sds100.keymapper.data.db.AppDatabase/2.json b/data/schemas/io.github.sds100.keymapper.data.db.AppDatabase/2.json similarity index 100% rename from app/schemas/io.github.sds100.keymapper.data.db.AppDatabase/2.json rename to data/schemas/io.github.sds100.keymapper.data.db.AppDatabase/2.json diff --git a/app/schemas/io.github.sds100.keymapper.data.db.AppDatabase/20.json b/data/schemas/io.github.sds100.keymapper.data.db.AppDatabase/20.json similarity index 100% rename from app/schemas/io.github.sds100.keymapper.data.db.AppDatabase/20.json rename to data/schemas/io.github.sds100.keymapper.data.db.AppDatabase/20.json diff --git a/app/schemas/io.github.sds100.keymapper.data.db.AppDatabase/3.json b/data/schemas/io.github.sds100.keymapper.data.db.AppDatabase/3.json similarity index 100% rename from app/schemas/io.github.sds100.keymapper.data.db.AppDatabase/3.json rename to data/schemas/io.github.sds100.keymapper.data.db.AppDatabase/3.json diff --git a/app/schemas/io.github.sds100.keymapper.data.db.AppDatabase/4.json b/data/schemas/io.github.sds100.keymapper.data.db.AppDatabase/4.json similarity index 100% rename from app/schemas/io.github.sds100.keymapper.data.db.AppDatabase/4.json rename to data/schemas/io.github.sds100.keymapper.data.db.AppDatabase/4.json diff --git a/app/schemas/io.github.sds100.keymapper.data.db.AppDatabase/5.json b/data/schemas/io.github.sds100.keymapper.data.db.AppDatabase/5.json similarity index 100% rename from app/schemas/io.github.sds100.keymapper.data.db.AppDatabase/5.json rename to data/schemas/io.github.sds100.keymapper.data.db.AppDatabase/5.json diff --git a/app/schemas/io.github.sds100.keymapper.data.db.AppDatabase/6.json b/data/schemas/io.github.sds100.keymapper.data.db.AppDatabase/6.json similarity index 100% rename from app/schemas/io.github.sds100.keymapper.data.db.AppDatabase/6.json rename to data/schemas/io.github.sds100.keymapper.data.db.AppDatabase/6.json diff --git a/app/schemas/io.github.sds100.keymapper.data.db.AppDatabase/7.json b/data/schemas/io.github.sds100.keymapper.data.db.AppDatabase/7.json similarity index 100% rename from app/schemas/io.github.sds100.keymapper.data.db.AppDatabase/7.json rename to data/schemas/io.github.sds100.keymapper.data.db.AppDatabase/7.json diff --git a/app/schemas/io.github.sds100.keymapper.data.db.AppDatabase/8.json b/data/schemas/io.github.sds100.keymapper.data.db.AppDatabase/8.json similarity index 100% rename from app/schemas/io.github.sds100.keymapper.data.db.AppDatabase/8.json rename to data/schemas/io.github.sds100.keymapper.data.db.AppDatabase/8.json diff --git a/app/schemas/io.github.sds100.keymapper.data.db.AppDatabase/9.json b/data/schemas/io.github.sds100.keymapper.data.db.AppDatabase/9.json similarity index 100% rename from app/schemas/io.github.sds100.keymapper.data.db.AppDatabase/9.json rename to data/schemas/io.github.sds100.keymapper.data.db.AppDatabase/9.json diff --git a/data/src/main/AndroidManifest.xml b/data/src/main/AndroidManifest.xml new file mode 100644 index 0000000000..a5918e68ab --- /dev/null +++ b/data/src/main/AndroidManifest.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/data/src/main/java/io/github/sds100/keymapper/data/DataError.kt b/data/src/main/java/io/github/sds100/keymapper/data/DataError.kt new file mode 100644 index 0000000000..06beb1dfd2 --- /dev/null +++ b/data/src/main/java/io/github/sds100/keymapper/data/DataError.kt @@ -0,0 +1,5 @@ +package io.github.sds100.keymapper.data +import io.github.sds100.keymapper.common.utils.KMError +object DataError { + data class ExtraNotFound(val extraId: String) : KMError() +} diff --git a/data/src/main/java/io/github/sds100/keymapper/data/DataHiltModule.kt b/data/src/main/java/io/github/sds100/keymapper/data/DataHiltModule.kt new file mode 100644 index 0000000000..0dd446dbfe --- /dev/null +++ b/data/src/main/java/io/github/sds100/keymapper/data/DataHiltModule.kt @@ -0,0 +1,53 @@ +package io.github.sds100.keymapper.data + +import dagger.Binds +import dagger.Module +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent +import io.github.sds100.keymapper.data.repositories.AccessibilityNodeRepository +import io.github.sds100.keymapper.data.repositories.FloatingButtonRepository +import io.github.sds100.keymapper.data.repositories.FloatingLayoutRepository +import io.github.sds100.keymapper.data.repositories.GroupRepository +import io.github.sds100.keymapper.data.repositories.KeyMapRepository +import io.github.sds100.keymapper.data.repositories.LogRepository +import io.github.sds100.keymapper.data.repositories.PreferenceRepository +import io.github.sds100.keymapper.data.repositories.RoomAccessibilityNodeRepository +import io.github.sds100.keymapper.data.repositories.RoomFloatingButtonRepository +import io.github.sds100.keymapper.data.repositories.RoomFloatingLayoutRepository +import io.github.sds100.keymapper.data.repositories.RoomGroupRepository +import io.github.sds100.keymapper.data.repositories.RoomKeyMapRepository +import io.github.sds100.keymapper.data.repositories.RoomLogRepository +import io.github.sds100.keymapper.data.repositories.SettingsPreferenceRepository +import javax.inject.Singleton + +@Module +@InstallIn(SingletonComponent::class) +abstract class DataHiltModule { + @Singleton + @Binds + abstract fun providePreferenceRepository(impl: SettingsPreferenceRepository): PreferenceRepository + + @Singleton + @Binds + abstract fun provideGroupRepository(impl: RoomGroupRepository): GroupRepository + + @Singleton + @Binds + abstract fun provideKeyMapRepository(impl: RoomKeyMapRepository): KeyMapRepository + + @Singleton + @Binds + abstract fun provideAccessibilityNodeRepository(impl: RoomAccessibilityNodeRepository): AccessibilityNodeRepository + + @Singleton + @Binds + abstract fun provideLogRepository(impl: RoomLogRepository): LogRepository + + @Singleton + @Binds + abstract fun provideFloatingButtonRepository(impl: RoomFloatingButtonRepository): FloatingButtonRepository + + @Singleton + @Binds + abstract fun provideFloatingLayoutRepository(impl: RoomFloatingLayoutRepository): FloatingLayoutRepository +} diff --git a/app/src/main/java/io/github/sds100/keymapper/data/Keys.kt b/data/src/main/java/io/github/sds100/keymapper/data/Keys.kt similarity index 99% rename from app/src/main/java/io/github/sds100/keymapper/data/Keys.kt rename to data/src/main/java/io/github/sds100/keymapper/data/Keys.kt index dfd38baa43..681c7eaba9 100644 --- a/app/src/main/java/io/github/sds100/keymapper/data/Keys.kt +++ b/data/src/main/java/io/github/sds100/keymapper/data/Keys.kt @@ -5,9 +5,6 @@ import androidx.datastore.preferences.core.intPreferencesKey import androidx.datastore.preferences.core.stringPreferencesKey import androidx.datastore.preferences.core.stringSetPreferencesKey -/** - * Created by sds100 on 19/01/21. - */ object Keys { val darkTheme = stringPreferencesKey("pref_dark_theme_mode") val hasRootPermission = booleanPreferencesKey("pref_allow_root_features") diff --git a/app/src/main/java/io/github/sds100/keymapper/data/PreferenceDefaults.kt b/data/src/main/java/io/github/sds100/keymapper/data/PreferenceDefaults.kt similarity index 92% rename from app/src/main/java/io/github/sds100/keymapper/data/PreferenceDefaults.kt rename to data/src/main/java/io/github/sds100/keymapper/data/PreferenceDefaults.kt index 03e164e359..187f4ef34e 100644 --- a/app/src/main/java/io/github/sds100/keymapper/data/PreferenceDefaults.kt +++ b/data/src/main/java/io/github/sds100/keymapper/data/PreferenceDefaults.kt @@ -1,9 +1,5 @@ package io.github.sds100.keymapper.data -/** - * Created by sds100 on 30/01/21. - */ - object PreferenceDefaults { const val DARK_THEME = "2" diff --git a/app/src/main/java/io/github/sds100/keymapper/data/db/AppDatabase.kt b/data/src/main/java/io/github/sds100/keymapper/data/db/AppDatabase.kt similarity index 99% rename from app/src/main/java/io/github/sds100/keymapper/data/db/AppDatabase.kt rename to data/src/main/java/io/github/sds100/keymapper/data/db/AppDatabase.kt index bba74e2b66..cd64a24ece 100644 --- a/app/src/main/java/io/github/sds100/keymapper/data/db/AppDatabase.kt +++ b/data/src/main/java/io/github/sds100/keymapper/data/db/AppDatabase.kt @@ -45,9 +45,6 @@ import io.github.sds100.keymapper.data.migration.Migration6To7 import io.github.sds100.keymapper.data.migration.Migration8To9 import io.github.sds100.keymapper.data.migration.Migration9To10 -/** - * Created by sds100 on 24/01/2020. - */ @Database( entities = [KeyMapEntity::class, FingerprintMapEntity::class, LogEntryEntity::class, FloatingLayoutEntity::class, FloatingButtonEntity::class, GroupEntity::class, AccessibilityNodeEntity::class], version = DATABASE_VERSION, diff --git a/data/src/main/java/io/github/sds100/keymapper/data/db/AppDatabaseModule.kt b/data/src/main/java/io/github/sds100/keymapper/data/db/AppDatabaseModule.kt new file mode 100644 index 0000000000..3b1ae3b73f --- /dev/null +++ b/data/src/main/java/io/github/sds100/keymapper/data/db/AppDatabaseModule.kt @@ -0,0 +1,88 @@ +package io.github.sds100.keymapper.data.db + +import android.content.Context +import androidx.datastore.preferences.preferencesDataStore +import androidx.room.Room +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.android.qualifiers.ApplicationContext +import dagger.hilt.components.SingletonComponent +import io.github.sds100.keymapper.data.db.dao.AccessibilityNodeDao +import io.github.sds100.keymapper.data.db.dao.FingerprintMapDao +import io.github.sds100.keymapper.data.db.dao.FloatingButtonDao +import io.github.sds100.keymapper.data.db.dao.FloatingLayoutDao +import io.github.sds100.keymapper.data.db.dao.GroupDao +import io.github.sds100.keymapper.data.db.dao.KeyMapDao +import io.github.sds100.keymapper.data.db.dao.LogEntryDao +import javax.inject.Singleton + +@Module +@InstallIn(SingletonComponent::class) +internal class AppDatabaseModule { + @Singleton + @Provides + fun provideAppDatabase( + @ApplicationContext ctx: Context, + ): AppDatabase { + return createDatabase(ctx) + } + + @Provides + fun provideKeyMapDao(database: AppDatabase): KeyMapDao { + return database.keyMapDao() + } + + @Provides + fun provideFingerprintMapDao(database: AppDatabase): FingerprintMapDao { + return database.fingerprintMapDao() + } + + @Provides + fun provideLogEntryDao(database: AppDatabase): LogEntryDao { + return database.logEntryDao() + } + + @Provides + fun provideFloatingLayoutDao(database: AppDatabase): FloatingLayoutDao { + return database.floatingLayoutDao() + } + + @Provides + fun provideFloatingButtonDao(database: AppDatabase): FloatingButtonDao { + return database.floatingButtonDao() + } + + @Provides + fun provideGroupDao(database: AppDatabase): GroupDao { + return database.groupDao() + } + + @Provides + fun provideAccessibilityNodeDao(database: AppDatabase): AccessibilityNodeDao { + return database.accessibilityNodeDao() + } + + private fun createDatabase(context: Context): AppDatabase = Room.databaseBuilder( + context.applicationContext, + AppDatabase::class.java, + AppDatabase.DATABASE_NAME, + ).addMigrations( + AppDatabase.MIGRATION_1_2, + AppDatabase.MIGRATION_2_3, + AppDatabase.MIGRATION_3_4, + AppDatabase.MIGRATION_4_5, + AppDatabase.MIGRATION_5_6, + AppDatabase.MIGRATION_6_7, + AppDatabase.MIGRATION_7_8, + AppDatabase.MIGRATION_8_9, + AppDatabase.MIGRATION_9_10, + AppDatabase.MIGRATION_10_11, + AppDatabase.RoomMigration11To12(context.applicationContext.legacyFingerprintMapDataStore), + AppDatabase.MIGRATION_12_13, + AppDatabase.MIGRATION_13_14, + AppDatabase.MIGRATION_17_18, + ).build() + + private val Context.legacyFingerprintMapDataStore by preferencesDataStore("fingerprint_gestures") +} diff --git a/app/src/main/java/io/github/sds100/keymapper/data/db/dao/AccessibilityNodeDao.kt b/data/src/main/java/io/github/sds100/keymapper/data/db/dao/AccessibilityNodeDao.kt similarity index 100% rename from app/src/main/java/io/github/sds100/keymapper/data/db/dao/AccessibilityNodeDao.kt rename to data/src/main/java/io/github/sds100/keymapper/data/db/dao/AccessibilityNodeDao.kt diff --git a/app/src/main/java/io/github/sds100/keymapper/data/db/dao/FingerprintMapDao.kt b/data/src/main/java/io/github/sds100/keymapper/data/db/dao/FingerprintMapDao.kt similarity index 96% rename from app/src/main/java/io/github/sds100/keymapper/data/db/dao/FingerprintMapDao.kt rename to data/src/main/java/io/github/sds100/keymapper/data/db/dao/FingerprintMapDao.kt index 74122137ac..3f14042f03 100644 --- a/app/src/main/java/io/github/sds100/keymapper/data/db/dao/FingerprintMapDao.kt +++ b/data/src/main/java/io/github/sds100/keymapper/data/db/dao/FingerprintMapDao.kt @@ -8,10 +8,6 @@ import androidx.room.Update import io.github.sds100.keymapper.data.entities.FingerprintMapEntity import kotlinx.coroutines.flow.Flow -/** - * Created by sds100 on 28/04/2021. - */ - @Dao interface FingerprintMapDao { companion object { diff --git a/app/src/main/java/io/github/sds100/keymapper/data/db/dao/FloatingButtonDao.kt b/data/src/main/java/io/github/sds100/keymapper/data/db/dao/FloatingButtonDao.kt similarity index 100% rename from app/src/main/java/io/github/sds100/keymapper/data/db/dao/FloatingButtonDao.kt rename to data/src/main/java/io/github/sds100/keymapper/data/db/dao/FloatingButtonDao.kt diff --git a/app/src/main/java/io/github/sds100/keymapper/data/db/dao/FloatingLayoutDao.kt b/data/src/main/java/io/github/sds100/keymapper/data/db/dao/FloatingLayoutDao.kt similarity index 100% rename from app/src/main/java/io/github/sds100/keymapper/data/db/dao/FloatingLayoutDao.kt rename to data/src/main/java/io/github/sds100/keymapper/data/db/dao/FloatingLayoutDao.kt diff --git a/app/src/main/java/io/github/sds100/keymapper/data/db/dao/GroupDao.kt b/data/src/main/java/io/github/sds100/keymapper/data/db/dao/GroupDao.kt similarity index 100% rename from app/src/main/java/io/github/sds100/keymapper/data/db/dao/GroupDao.kt rename to data/src/main/java/io/github/sds100/keymapper/data/db/dao/GroupDao.kt diff --git a/app/src/main/java/io/github/sds100/keymapper/data/db/dao/KeyMapDao.kt b/data/src/main/java/io/github/sds100/keymapper/data/db/dao/KeyMapDao.kt similarity index 98% rename from app/src/main/java/io/github/sds100/keymapper/data/db/dao/KeyMapDao.kt rename to data/src/main/java/io/github/sds100/keymapper/data/db/dao/KeyMapDao.kt index c72b0a0f78..12db4e7752 100644 --- a/app/src/main/java/io/github/sds100/keymapper/data/db/dao/KeyMapDao.kt +++ b/data/src/main/java/io/github/sds100/keymapper/data/db/dao/KeyMapDao.kt @@ -9,10 +9,6 @@ import androidx.room.Update import io.github.sds100.keymapper.data.entities.KeyMapEntity import kotlinx.coroutines.flow.Flow -/** - * Created by sds100 on 18/02/20. - */ - @Dao interface KeyMapDao { companion object { diff --git a/app/src/main/java/io/github/sds100/keymapper/data/db/dao/LogEntryDao.kt b/data/src/main/java/io/github/sds100/keymapper/data/db/dao/LogEntryDao.kt similarity index 95% rename from app/src/main/java/io/github/sds100/keymapper/data/db/dao/LogEntryDao.kt rename to data/src/main/java/io/github/sds100/keymapper/data/db/dao/LogEntryDao.kt index 163b63f4fd..21f6717031 100644 --- a/app/src/main/java/io/github/sds100/keymapper/data/db/dao/LogEntryDao.kt +++ b/data/src/main/java/io/github/sds100/keymapper/data/db/dao/LogEntryDao.kt @@ -6,10 +6,6 @@ import androidx.room.Query import io.github.sds100.keymapper.data.entities.LogEntryEntity import kotlinx.coroutines.flow.Flow -/** - * Created by sds100 on 18/02/20. - */ - @Dao interface LogEntryDao { companion object { diff --git a/app/src/main/java/io/github/sds100/keymapper/data/db/typeconverter/ActionListTypeConverter.kt b/data/src/main/java/io/github/sds100/keymapper/data/db/typeconverter/ActionListTypeConverter.kt similarity index 94% rename from app/src/main/java/io/github/sds100/keymapper/data/db/typeconverter/ActionListTypeConverter.kt rename to data/src/main/java/io/github/sds100/keymapper/data/db/typeconverter/ActionListTypeConverter.kt index ccce6fc97c..993a25a63a 100644 --- a/app/src/main/java/io/github/sds100/keymapper/data/db/typeconverter/ActionListTypeConverter.kt +++ b/data/src/main/java/io/github/sds100/keymapper/data/db/typeconverter/ActionListTypeConverter.kt @@ -7,10 +7,6 @@ import com.google.gson.GsonBuilder import io.github.sds100.keymapper.data.entities.ActionEntity import io.github.sds100.keymapper.data.entities.ConstraintEntity -/** - * Created by sds100 on 05/09/2018. - */ - class ActionListTypeConverter { private val gson = GsonBuilder().registerTypeAdapter(ConstraintEntity.DESERIALIZER).create() diff --git a/app/src/main/java/io/github/sds100/keymapper/data/db/typeconverter/ConstantTypeConverters.kt b/data/src/main/java/io/github/sds100/keymapper/data/db/typeconverter/ConstantTypeConverters.kt similarity index 85% rename from app/src/main/java/io/github/sds100/keymapper/data/db/typeconverter/ConstantTypeConverters.kt rename to data/src/main/java/io/github/sds100/keymapper/data/db/typeconverter/ConstantTypeConverters.kt index d4aa216be7..efb8c03a62 100644 --- a/app/src/main/java/io/github/sds100/keymapper/data/db/typeconverter/ConstantTypeConverters.kt +++ b/data/src/main/java/io/github/sds100/keymapper/data/db/typeconverter/ConstantTypeConverters.kt @@ -1,6 +1,6 @@ package io.github.sds100.keymapper.data.db.typeconverter -import io.github.sds100.keymapper.system.display.Orientation +import io.github.sds100.keymapper.common.utils.Orientation object ConstantTypeConverters { val ORIENTATION_MAP = mapOf( diff --git a/app/src/main/java/io/github/sds100/keymapper/data/db/typeconverter/ConstraintListTypeConverter.kt b/data/src/main/java/io/github/sds100/keymapper/data/db/typeconverter/ConstraintListTypeConverter.kt similarity index 93% rename from app/src/main/java/io/github/sds100/keymapper/data/db/typeconverter/ConstraintListTypeConverter.kt rename to data/src/main/java/io/github/sds100/keymapper/data/db/typeconverter/ConstraintListTypeConverter.kt index 7e7b43c0d1..da676515d9 100644 --- a/app/src/main/java/io/github/sds100/keymapper/data/db/typeconverter/ConstraintListTypeConverter.kt +++ b/data/src/main/java/io/github/sds100/keymapper/data/db/typeconverter/ConstraintListTypeConverter.kt @@ -6,10 +6,6 @@ import com.github.salomonbrys.kotson.registerTypeAdapter import com.google.gson.GsonBuilder import io.github.sds100.keymapper.data.entities.ConstraintEntity -/** - * Created by sds100 on 05/09/2018. - */ - class ConstraintListTypeConverter { private val gson = GsonBuilder().registerTypeAdapter(ConstraintEntity.DESERIALIZER).create() diff --git a/app/src/main/java/io/github/sds100/keymapper/data/db/typeconverter/ExtraListTypeConverter.kt b/data/src/main/java/io/github/sds100/keymapper/data/db/typeconverter/ExtraListTypeConverter.kt similarity index 91% rename from app/src/main/java/io/github/sds100/keymapper/data/db/typeconverter/ExtraListTypeConverter.kt rename to data/src/main/java/io/github/sds100/keymapper/data/db/typeconverter/ExtraListTypeConverter.kt index c7e5c038dc..4bccde0fab 100644 --- a/app/src/main/java/io/github/sds100/keymapper/data/db/typeconverter/ExtraListTypeConverter.kt +++ b/data/src/main/java/io/github/sds100/keymapper/data/db/typeconverter/ExtraListTypeConverter.kt @@ -5,10 +5,6 @@ import com.github.salomonbrys.kotson.fromJson import com.google.gson.GsonBuilder import io.github.sds100.keymapper.data.entities.EntityExtra -/** - * Created by sds100 on 05/09/2018. - */ - class ExtraListTypeConverter { private val gson = GsonBuilder().create() diff --git a/app/src/main/java/io/github/sds100/keymapper/data/db/typeconverter/NodeInteractionTypeSetTypeConverter.kt b/data/src/main/java/io/github/sds100/keymapper/data/db/typeconverter/NodeInteractionTypeSetTypeConverter.kt similarity index 87% rename from app/src/main/java/io/github/sds100/keymapper/data/db/typeconverter/NodeInteractionTypeSetTypeConverter.kt rename to data/src/main/java/io/github/sds100/keymapper/data/db/typeconverter/NodeInteractionTypeSetTypeConverter.kt index d4093d82d8..b44cda1ddb 100644 --- a/app/src/main/java/io/github/sds100/keymapper/data/db/typeconverter/NodeInteractionTypeSetTypeConverter.kt +++ b/data/src/main/java/io/github/sds100/keymapper/data/db/typeconverter/NodeInteractionTypeSetTypeConverter.kt @@ -1,11 +1,7 @@ package io.github.sds100.keymapper.data.db.typeconverter import androidx.room.TypeConverter -import io.github.sds100.keymapper.actions.uielement.NodeInteractionType - -/** - * Created by sds100 on 05/09/2018. - */ +import io.github.sds100.keymapper.common.utils.NodeInteractionType class NodeInteractionTypeSetTypeConverter { @TypeConverter diff --git a/app/src/main/java/io/github/sds100/keymapper/data/db/typeconverter/TriggerTypeConverter.kt b/data/src/main/java/io/github/sds100/keymapper/data/db/typeconverter/TriggerTypeConverter.kt similarity index 95% rename from app/src/main/java/io/github/sds100/keymapper/data/db/typeconverter/TriggerTypeConverter.kt rename to data/src/main/java/io/github/sds100/keymapper/data/db/typeconverter/TriggerTypeConverter.kt index 58d967d6a6..146405f4ac 100644 --- a/app/src/main/java/io/github/sds100/keymapper/data/db/typeconverter/TriggerTypeConverter.kt +++ b/data/src/main/java/io/github/sds100/keymapper/data/db/typeconverter/TriggerTypeConverter.kt @@ -8,10 +8,6 @@ import io.github.sds100.keymapper.data.entities.EntityExtra import io.github.sds100.keymapper.data.entities.TriggerEntity import io.github.sds100.keymapper.data.entities.TriggerKeyEntity -/** - * Created by sds100 on 05/09/2018. - */ - class TriggerTypeConverter { private val gson = GsonBuilder() .registerTypeAdapter(TriggerEntity.DESERIALIZER) diff --git a/app/src/main/java/io/github/sds100/keymapper/data/entities/AccessibilityNodeEntity.kt b/data/src/main/java/io/github/sds100/keymapper/data/entities/AccessibilityNodeEntity.kt similarity index 97% rename from app/src/main/java/io/github/sds100/keymapper/data/entities/AccessibilityNodeEntity.kt rename to data/src/main/java/io/github/sds100/keymapper/data/entities/AccessibilityNodeEntity.kt index f84769395c..c285376e6c 100644 --- a/app/src/main/java/io/github/sds100/keymapper/data/entities/AccessibilityNodeEntity.kt +++ b/data/src/main/java/io/github/sds100/keymapper/data/entities/AccessibilityNodeEntity.kt @@ -4,7 +4,7 @@ import android.os.Parcelable import androidx.room.ColumnInfo import androidx.room.Entity import androidx.room.PrimaryKey -import io.github.sds100.keymapper.actions.uielement.NodeInteractionType +import io.github.sds100.keymapper.common.utils.NodeInteractionType import io.github.sds100.keymapper.data.db.dao.AccessibilityNodeDao.Companion.KEY_ACTIONS import io.github.sds100.keymapper.data.db.dao.AccessibilityNodeDao.Companion.KEY_CLASS_NAME import io.github.sds100.keymapper.data.db.dao.AccessibilityNodeDao.Companion.KEY_CONTENT_DESCRIPTION diff --git a/app/src/main/java/io/github/sds100/keymapper/data/entities/ActionEntity.kt b/data/src/main/java/io/github/sds100/keymapper/data/entities/ActionEntity.kt similarity index 99% rename from app/src/main/java/io/github/sds100/keymapper/data/entities/ActionEntity.kt rename to data/src/main/java/io/github/sds100/keymapper/data/entities/ActionEntity.kt index be62380df3..ad42ed3012 100644 --- a/app/src/main/java/io/github/sds100/keymapper/data/entities/ActionEntity.kt +++ b/data/src/main/java/io/github/sds100/keymapper/data/entities/ActionEntity.kt @@ -11,10 +11,6 @@ import io.github.sds100.keymapper.data.entities.ActionEntity.Type import kotlinx.parcelize.Parcelize import java.util.UUID -/** - * Created by sds100 on 16/07/2018. - */ - /** * @property [data] The information required to perform the action. E.g if the type is [Type.APP], * the data will be the package name of the application diff --git a/app/src/main/java/io/github/sds100/keymapper/data/entities/AssistantTriggerKeyEntity.kt b/data/src/main/java/io/github/sds100/keymapper/data/entities/AssistantTriggerKeyEntity.kt similarity index 100% rename from app/src/main/java/io/github/sds100/keymapper/data/entities/AssistantTriggerKeyEntity.kt rename to data/src/main/java/io/github/sds100/keymapper/data/entities/AssistantTriggerKeyEntity.kt diff --git a/app/src/main/java/io/github/sds100/keymapper/data/entities/ConstraintEntity.kt b/data/src/main/java/io/github/sds100/keymapper/data/entities/ConstraintEntity.kt similarity index 98% rename from app/src/main/java/io/github/sds100/keymapper/data/entities/ConstraintEntity.kt rename to data/src/main/java/io/github/sds100/keymapper/data/entities/ConstraintEntity.kt index c79ea9cb66..6690875809 100644 --- a/app/src/main/java/io/github/sds100/keymapper/data/entities/ConstraintEntity.kt +++ b/data/src/main/java/io/github/sds100/keymapper/data/entities/ConstraintEntity.kt @@ -9,10 +9,6 @@ import com.google.gson.annotations.SerializedName import kotlinx.parcelize.Parcelize import java.util.UUID -/** - * Created by sds100 on 17/03/2020. - */ - @Parcelize data class ConstraintEntity( @SerializedName(NAME_TYPE) diff --git a/app/src/main/java/io/github/sds100/keymapper/data/entities/EntityExtra.kt b/data/src/main/java/io/github/sds100/keymapper/data/entities/EntityExtra.kt similarity index 74% rename from app/src/main/java/io/github/sds100/keymapper/data/entities/EntityExtra.kt rename to data/src/main/java/io/github/sds100/keymapper/data/entities/EntityExtra.kt index 1a1c7139ad..7427a6e02e 100644 --- a/app/src/main/java/io/github/sds100/keymapper/data/entities/EntityExtra.kt +++ b/data/src/main/java/io/github/sds100/keymapper/data/entities/EntityExtra.kt @@ -4,15 +4,11 @@ import android.os.Parcelable import com.github.salomonbrys.kotson.byString import com.github.salomonbrys.kotson.jsonDeserializer import com.google.gson.annotations.SerializedName -import io.github.sds100.keymapper.util.Error -import io.github.sds100.keymapper.util.Result -import io.github.sds100.keymapper.util.Success +import io.github.sds100.keymapper.common.utils.KMResult +import io.github.sds100.keymapper.common.utils.Success +import io.github.sds100.keymapper.data.DataError import kotlinx.parcelize.Parcelize -/** - * Created by sds100 on 26/01/2019. - */ - @Parcelize data class EntityExtra( @SerializedName(NAME_ID) @@ -36,9 +32,9 @@ data class EntityExtra( } } -fun List.getData(extraId: String): Result { +fun List.getData(extraId: String): KMResult { return find { it.id == extraId }.let { - it ?: return@let Error.ExtraNotFound(extraId) + it ?: return@let DataError.ExtraNotFound(extraId) Success(it.data) } diff --git a/app/src/main/java/io/github/sds100/keymapper/data/entities/FingerprintMapEntity.kt b/data/src/main/java/io/github/sds100/keymapper/data/entities/FingerprintMapEntity.kt similarity index 98% rename from app/src/main/java/io/github/sds100/keymapper/data/entities/FingerprintMapEntity.kt rename to data/src/main/java/io/github/sds100/keymapper/data/entities/FingerprintMapEntity.kt index 613cbc740c..b5c824f97b 100755 --- a/app/src/main/java/io/github/sds100/keymapper/data/entities/FingerprintMapEntity.kt +++ b/data/src/main/java/io/github/sds100/keymapper/data/entities/FingerprintMapEntity.kt @@ -11,10 +11,6 @@ import com.github.salomonbrys.kotson.jsonDeserializer import com.google.gson.annotations.SerializedName import io.github.sds100.keymapper.data.db.dao.FingerprintMapDao -/** - * Created by sds100 on 08/11/20. - */ - @Entity(tableName = FingerprintMapDao.TABLE_NAME) data class FingerprintMapEntity( @SerializedName(NAME_ID) diff --git a/app/src/main/java/io/github/sds100/keymapper/data/entities/FingerprintTriggerKeyEntity.kt b/data/src/main/java/io/github/sds100/keymapper/data/entities/FingerprintTriggerKeyEntity.kt similarity index 100% rename from app/src/main/java/io/github/sds100/keymapper/data/entities/FingerprintTriggerKeyEntity.kt rename to data/src/main/java/io/github/sds100/keymapper/data/entities/FingerprintTriggerKeyEntity.kt diff --git a/app/src/main/java/io/github/sds100/keymapper/data/entities/FloatingButtonEntity.kt b/data/src/main/java/io/github/sds100/keymapper/data/entities/FloatingButtonEntity.kt similarity index 100% rename from app/src/main/java/io/github/sds100/keymapper/data/entities/FloatingButtonEntity.kt rename to data/src/main/java/io/github/sds100/keymapper/data/entities/FloatingButtonEntity.kt diff --git a/app/src/main/java/io/github/sds100/keymapper/data/entities/FloatingButtonEntityWithLayout.kt b/data/src/main/java/io/github/sds100/keymapper/data/entities/FloatingButtonEntityWithLayout.kt similarity index 100% rename from app/src/main/java/io/github/sds100/keymapper/data/entities/FloatingButtonEntityWithLayout.kt rename to data/src/main/java/io/github/sds100/keymapper/data/entities/FloatingButtonEntityWithLayout.kt diff --git a/app/src/main/java/io/github/sds100/keymapper/data/entities/FloatingButtonKeyEntity.kt b/data/src/main/java/io/github/sds100/keymapper/data/entities/FloatingButtonKeyEntity.kt similarity index 100% rename from app/src/main/java/io/github/sds100/keymapper/data/entities/FloatingButtonKeyEntity.kt rename to data/src/main/java/io/github/sds100/keymapper/data/entities/FloatingButtonKeyEntity.kt diff --git a/app/src/main/java/io/github/sds100/keymapper/data/entities/FloatingLayoutEntity.kt b/data/src/main/java/io/github/sds100/keymapper/data/entities/FloatingLayoutEntity.kt similarity index 100% rename from app/src/main/java/io/github/sds100/keymapper/data/entities/FloatingLayoutEntity.kt rename to data/src/main/java/io/github/sds100/keymapper/data/entities/FloatingLayoutEntity.kt diff --git a/app/src/main/java/io/github/sds100/keymapper/data/entities/FloatingLayoutEntityWithButtons.kt b/data/src/main/java/io/github/sds100/keymapper/data/entities/FloatingLayoutEntityWithButtons.kt similarity index 100% rename from app/src/main/java/io/github/sds100/keymapper/data/entities/FloatingLayoutEntityWithButtons.kt rename to data/src/main/java/io/github/sds100/keymapper/data/entities/FloatingLayoutEntityWithButtons.kt diff --git a/app/src/main/java/io/github/sds100/keymapper/data/entities/GroupEntity.kt b/data/src/main/java/io/github/sds100/keymapper/data/entities/GroupEntity.kt similarity index 100% rename from app/src/main/java/io/github/sds100/keymapper/data/entities/GroupEntity.kt rename to data/src/main/java/io/github/sds100/keymapper/data/entities/GroupEntity.kt diff --git a/app/src/main/java/io/github/sds100/keymapper/data/entities/GroupEntityWithChildren.kt b/data/src/main/java/io/github/sds100/keymapper/data/entities/GroupEntityWithChildren.kt similarity index 100% rename from app/src/main/java/io/github/sds100/keymapper/data/entities/GroupEntityWithChildren.kt rename to data/src/main/java/io/github/sds100/keymapper/data/entities/GroupEntityWithChildren.kt diff --git a/app/src/main/java/io/github/sds100/keymapper/data/entities/KeyCodeTriggerKeyEntity.kt b/data/src/main/java/io/github/sds100/keymapper/data/entities/KeyCodeTriggerKeyEntity.kt similarity index 100% rename from app/src/main/java/io/github/sds100/keymapper/data/entities/KeyCodeTriggerKeyEntity.kt rename to data/src/main/java/io/github/sds100/keymapper/data/entities/KeyCodeTriggerKeyEntity.kt diff --git a/app/src/main/java/io/github/sds100/keymapper/data/entities/KeyMapEntitiesWithGroup.kt b/data/src/main/java/io/github/sds100/keymapper/data/entities/KeyMapEntitiesWithGroup.kt similarity index 100% rename from app/src/main/java/io/github/sds100/keymapper/data/entities/KeyMapEntitiesWithGroup.kt rename to data/src/main/java/io/github/sds100/keymapper/data/entities/KeyMapEntitiesWithGroup.kt diff --git a/app/src/main/java/io/github/sds100/keymapper/data/entities/KeyMapEntity.kt b/data/src/main/java/io/github/sds100/keymapper/data/entities/KeyMapEntity.kt similarity index 98% rename from app/src/main/java/io/github/sds100/keymapper/data/entities/KeyMapEntity.kt rename to data/src/main/java/io/github/sds100/keymapper/data/entities/KeyMapEntity.kt index bb9dda5088..5b5e94ba04 100644 --- a/app/src/main/java/io/github/sds100/keymapper/data/entities/KeyMapEntity.kt +++ b/data/src/main/java/io/github/sds100/keymapper/data/entities/KeyMapEntity.kt @@ -19,10 +19,6 @@ import io.github.sds100.keymapper.data.db.dao.KeyMapDao import kotlinx.parcelize.Parcelize import java.util.UUID -/** - * Created by sds100 on 12/07/2018. - */ - @Entity( tableName = KeyMapDao.TABLE_NAME, indices = [Index(value = [KeyMapDao.KEY_UID], unique = true)], diff --git a/app/src/main/java/io/github/sds100/keymapper/data/entities/LogEntryEntity.kt b/data/src/main/java/io/github/sds100/keymapper/data/entities/LogEntryEntity.kt similarity index 93% rename from app/src/main/java/io/github/sds100/keymapper/data/entities/LogEntryEntity.kt rename to data/src/main/java/io/github/sds100/keymapper/data/entities/LogEntryEntity.kt index c901c29ed7..bd42e17c29 100644 --- a/app/src/main/java/io/github/sds100/keymapper/data/entities/LogEntryEntity.kt +++ b/data/src/main/java/io/github/sds100/keymapper/data/entities/LogEntryEntity.kt @@ -5,9 +5,6 @@ import androidx.room.Entity import androidx.room.PrimaryKey import io.github.sds100.keymapper.data.db.dao.LogEntryDao -/** - * Created by sds100 on 13/05/2021. - */ @Entity(tableName = LogEntryDao.TABLE_NAME) data class LogEntryEntity( @PrimaryKey(autoGenerate = true) diff --git a/app/src/main/java/io/github/sds100/keymapper/data/entities/TriggerEntity.kt b/data/src/main/java/io/github/sds100/keymapper/data/entities/TriggerEntity.kt similarity index 98% rename from app/src/main/java/io/github/sds100/keymapper/data/entities/TriggerEntity.kt rename to data/src/main/java/io/github/sds100/keymapper/data/entities/TriggerEntity.kt index c6b81db172..1a2d114c70 100644 --- a/app/src/main/java/io/github/sds100/keymapper/data/entities/TriggerEntity.kt +++ b/data/src/main/java/io/github/sds100/keymapper/data/entities/TriggerEntity.kt @@ -9,10 +9,6 @@ import com.github.salomonbrys.kotson.jsonDeserializer import com.google.gson.annotations.SerializedName import kotlinx.parcelize.Parcelize -/** - * Created by sds100 on 16/07/2018. - */ - @Parcelize data class TriggerEntity( @SerializedName(NAME_KEYS) diff --git a/app/src/main/java/io/github/sds100/keymapper/data/entities/TriggerKeyEntity.kt b/data/src/main/java/io/github/sds100/keymapper/data/entities/TriggerKeyEntity.kt similarity index 100% rename from app/src/main/java/io/github/sds100/keymapper/data/entities/TriggerKeyEntity.kt rename to data/src/main/java/io/github/sds100/keymapper/data/entities/TriggerKeyEntity.kt diff --git a/app/src/main/java/io/github/sds100/keymapper/data/migration/AutoMigration14To15.kt b/data/src/main/java/io/github/sds100/keymapper/data/migration/AutoMigration14To15.kt similarity index 100% rename from app/src/main/java/io/github/sds100/keymapper/data/migration/AutoMigration14To15.kt rename to data/src/main/java/io/github/sds100/keymapper/data/migration/AutoMigration14To15.kt diff --git a/app/src/main/java/io/github/sds100/keymapper/data/migration/AutoMigration15To16.kt b/data/src/main/java/io/github/sds100/keymapper/data/migration/AutoMigration15To16.kt similarity index 100% rename from app/src/main/java/io/github/sds100/keymapper/data/migration/AutoMigration15To16.kt rename to data/src/main/java/io/github/sds100/keymapper/data/migration/AutoMigration15To16.kt diff --git a/app/src/main/java/io/github/sds100/keymapper/data/migration/AutoMigration16To17.kt b/data/src/main/java/io/github/sds100/keymapper/data/migration/AutoMigration16To17.kt similarity index 100% rename from app/src/main/java/io/github/sds100/keymapper/data/migration/AutoMigration16To17.kt rename to data/src/main/java/io/github/sds100/keymapper/data/migration/AutoMigration16To17.kt diff --git a/app/src/main/java/io/github/sds100/keymapper/data/migration/AutoMigration18To19.kt b/data/src/main/java/io/github/sds100/keymapper/data/migration/AutoMigration18To19.kt similarity index 100% rename from app/src/main/java/io/github/sds100/keymapper/data/migration/AutoMigration18To19.kt rename to data/src/main/java/io/github/sds100/keymapper/data/migration/AutoMigration18To19.kt diff --git a/app/src/main/java/io/github/sds100/keymapper/data/migration/AutoMigration19To20.kt b/data/src/main/java/io/github/sds100/keymapper/data/migration/AutoMigration19To20.kt similarity index 100% rename from app/src/main/java/io/github/sds100/keymapper/data/migration/AutoMigration19To20.kt rename to data/src/main/java/io/github/sds100/keymapper/data/migration/AutoMigration19To20.kt diff --git a/app/src/main/java/io/github/sds100/keymapper/data/migration/JsonMigration.kt b/data/src/main/java/io/github/sds100/keymapper/data/migration/JsonMigration.kt similarity index 83% rename from app/src/main/java/io/github/sds100/keymapper/data/migration/JsonMigration.kt rename to data/src/main/java/io/github/sds100/keymapper/data/migration/JsonMigration.kt index dcc7cb0a38..146de584db 100644 --- a/app/src/main/java/io/github/sds100/keymapper/data/migration/JsonMigration.kt +++ b/data/src/main/java/io/github/sds100/keymapper/data/migration/JsonMigration.kt @@ -2,9 +2,6 @@ package io.github.sds100.keymapper.data.migration import com.google.gson.JsonObject -/** - * Created by sds100 on 22/01/21. - */ class JsonMigration( val versionBefore: Int, val versionAfter: Int, diff --git a/app/src/main/java/io/github/sds100/keymapper/data/migration/Migration10To11.kt b/data/src/main/java/io/github/sds100/keymapper/data/migration/Migration10To11.kt similarity index 100% rename from app/src/main/java/io/github/sds100/keymapper/data/migration/Migration10To11.kt rename to data/src/main/java/io/github/sds100/keymapper/data/migration/Migration10To11.kt diff --git a/app/src/main/java/io/github/sds100/keymapper/data/migration/Migration11To12.kt b/data/src/main/java/io/github/sds100/keymapper/data/migration/Migration11To12.kt similarity index 99% rename from app/src/main/java/io/github/sds100/keymapper/data/migration/Migration11To12.kt rename to data/src/main/java/io/github/sds100/keymapper/data/migration/Migration11To12.kt index eca08ec637..edc4a961c9 100644 --- a/app/src/main/java/io/github/sds100/keymapper/data/migration/Migration11To12.kt +++ b/data/src/main/java/io/github/sds100/keymapper/data/migration/Migration11To12.kt @@ -15,7 +15,7 @@ import com.google.gson.JsonArray import com.google.gson.JsonElement import com.google.gson.JsonObject import com.google.gson.JsonParser -import io.github.sds100.keymapper.util.firstBlocking +import io.github.sds100.keymapper.common.utils.firstBlocking /** * Move fingerprint maps from data store into sqlite database and move device info list information diff --git a/app/src/main/java/io/github/sds100/keymapper/data/migration/Migration13To14.kt b/data/src/main/java/io/github/sds100/keymapper/data/migration/Migration13To14.kt similarity index 100% rename from app/src/main/java/io/github/sds100/keymapper/data/migration/Migration13To14.kt rename to data/src/main/java/io/github/sds100/keymapper/data/migration/Migration13To14.kt diff --git a/app/src/main/java/io/github/sds100/keymapper/data/migration/Migration1To2.kt b/data/src/main/java/io/github/sds100/keymapper/data/migration/Migration1To2.kt similarity index 98% rename from app/src/main/java/io/github/sds100/keymapper/data/migration/Migration1To2.kt rename to data/src/main/java/io/github/sds100/keymapper/data/migration/Migration1To2.kt index c631cf3df7..41037750a4 100644 --- a/app/src/main/java/io/github/sds100/keymapper/data/migration/Migration1To2.kt +++ b/data/src/main/java/io/github/sds100/keymapper/data/migration/Migration1To2.kt @@ -12,15 +12,11 @@ import com.google.gson.Gson import com.google.gson.JsonArray import com.google.gson.JsonObject import com.google.gson.JsonParser +import io.github.sds100.keymapper.common.utils.hasFlag import io.github.sds100.keymapper.data.entities.ActionEntity import io.github.sds100.keymapper.data.entities.KeyCodeTriggerKeyEntity -import splitties.bitflags.hasFlag import timber.log.Timber -/** - * Created by sds100 on 06/06/20. - */ - /** * Mahoosive update/overhaul from 1.0 to 2.0 */ diff --git a/app/src/main/java/io/github/sds100/keymapper/data/migration/Migration2To3.kt b/data/src/main/java/io/github/sds100/keymapper/data/migration/Migration2To3.kt similarity index 96% rename from app/src/main/java/io/github/sds100/keymapper/data/migration/Migration2To3.kt rename to data/src/main/java/io/github/sds100/keymapper/data/migration/Migration2To3.kt index b3297b3b77..b2aac0e8ad 100644 --- a/app/src/main/java/io/github/sds100/keymapper/data/migration/Migration2To3.kt +++ b/data/src/main/java/io/github/sds100/keymapper/data/migration/Migration2To3.kt @@ -8,11 +8,7 @@ import com.github.salomonbrys.kotson.get import com.google.gson.JsonArray import com.google.gson.JsonObject import com.google.gson.JsonParser -import splitties.bitflags.withFlag - -/** - * Created by sds100 on 25/06/20. - */ +import io.github.sds100.keymapper.common.utils.withFlag /** * #379 feat: add option to repeat for all types of actions diff --git a/app/src/main/java/io/github/sds100/keymapper/data/migration/Migration3To4.kt b/data/src/main/java/io/github/sds100/keymapper/data/migration/Migration3To4.kt similarity index 95% rename from app/src/main/java/io/github/sds100/keymapper/data/migration/Migration3To4.kt rename to data/src/main/java/io/github/sds100/keymapper/data/migration/Migration3To4.kt index f659a70706..f39fffe8b0 100644 --- a/app/src/main/java/io/github/sds100/keymapper/data/migration/Migration3To4.kt +++ b/data/src/main/java/io/github/sds100/keymapper/data/migration/Migration3To4.kt @@ -7,11 +7,6 @@ import androidx.sqlite.db.SupportSQLiteQueryBuilder import com.github.salomonbrys.kotson.set import com.google.gson.Gson import com.google.gson.JsonParser -import kotlin.collections.set - -/** - * Created by sds100 on 25/06/20. - */ /** * #376 make trigger mode settings always visible. diff --git a/app/src/main/java/io/github/sds100/keymapper/data/migration/Migration4To5.kt b/data/src/main/java/io/github/sds100/keymapper/data/migration/Migration4To5.kt similarity index 97% rename from app/src/main/java/io/github/sds100/keymapper/data/migration/Migration4To5.kt rename to data/src/main/java/io/github/sds100/keymapper/data/migration/Migration4To5.kt index 4207c0dc94..6f4e4aeb4d 100644 --- a/app/src/main/java/io/github/sds100/keymapper/data/migration/Migration4To5.kt +++ b/data/src/main/java/io/github/sds100/keymapper/data/migration/Migration4To5.kt @@ -11,13 +11,9 @@ import com.google.gson.Gson import com.google.gson.JsonArray import com.google.gson.JsonObject import com.google.gson.JsonParser +import io.github.sds100.keymapper.common.utils.hasFlag +import io.github.sds100.keymapper.common.utils.withFlag import io.github.sds100.keymapper.data.entities.ActionEntity -import splitties.bitflags.hasFlag -import splitties.bitflags.withFlag - -/** - * Created by sds100 on 25/06/20. - */ /** * #382 feat: unique repeat behaviour for each action diff --git a/app/src/main/java/io/github/sds100/keymapper/data/migration/Migration5To6.kt b/data/src/main/java/io/github/sds100/keymapper/data/migration/Migration5To6.kt similarity index 96% rename from app/src/main/java/io/github/sds100/keymapper/data/migration/Migration5To6.kt rename to data/src/main/java/io/github/sds100/keymapper/data/migration/Migration5To6.kt index 0ab7846d7c..4a2de3f013 100644 --- a/app/src/main/java/io/github/sds100/keymapper/data/migration/Migration5To6.kt +++ b/data/src/main/java/io/github/sds100/keymapper/data/migration/Migration5To6.kt @@ -8,10 +8,6 @@ import com.github.salomonbrys.kotson.set import com.google.gson.Gson import com.google.gson.JsonParser -/** - * Created by sds100 on 25/06/20. - */ - /** * move keymap flags to trigger flags */ diff --git a/app/src/main/java/io/github/sds100/keymapper/data/migration/Migration6To7.kt b/data/src/main/java/io/github/sds100/keymapper/data/migration/Migration6To7.kt similarity index 93% rename from app/src/main/java/io/github/sds100/keymapper/data/migration/Migration6To7.kt rename to data/src/main/java/io/github/sds100/keymapper/data/migration/Migration6To7.kt index bf2378431a..a137888a53 100644 --- a/app/src/main/java/io/github/sds100/keymapper/data/migration/Migration6To7.kt +++ b/data/src/main/java/io/github/sds100/keymapper/data/migration/Migration6To7.kt @@ -8,16 +8,12 @@ import com.github.salomonbrys.kotson.fromJson import com.github.salomonbrys.kotson.registerTypeAdapter import com.google.gson.Gson import com.google.gson.GsonBuilder +import io.github.sds100.keymapper.common.utils.hasFlag +import io.github.sds100.keymapper.common.utils.minusFlag +import io.github.sds100.keymapper.common.utils.withFlag import io.github.sds100.keymapper.data.entities.KeyCodeTriggerKeyEntity import io.github.sds100.keymapper.data.entities.TriggerEntity import io.github.sds100.keymapper.data.entities.TriggerKeyEntity -import splitties.bitflags.hasFlag -import splitties.bitflags.minusFlag -import splitties.bitflags.withFlag - -/** - * Created by sds100 on 25/06/20. - */ object Migration6To7 { diff --git a/app/src/main/java/io/github/sds100/keymapper/data/migration/Migration8To9.kt b/data/src/main/java/io/github/sds100/keymapper/data/migration/Migration8To9.kt similarity index 100% rename from app/src/main/java/io/github/sds100/keymapper/data/migration/Migration8To9.kt rename to data/src/main/java/io/github/sds100/keymapper/data/migration/Migration8To9.kt diff --git a/app/src/main/java/io/github/sds100/keymapper/data/migration/Migration9To10.kt b/data/src/main/java/io/github/sds100/keymapper/data/migration/Migration9To10.kt similarity index 95% rename from app/src/main/java/io/github/sds100/keymapper/data/migration/Migration9To10.kt rename to data/src/main/java/io/github/sds100/keymapper/data/migration/Migration9To10.kt index 1d5b846cce..f0c53e47c0 100644 --- a/app/src/main/java/io/github/sds100/keymapper/data/migration/Migration9To10.kt +++ b/data/src/main/java/io/github/sds100/keymapper/data/migration/Migration9To10.kt @@ -13,9 +13,9 @@ import com.google.gson.JsonArray import com.google.gson.JsonElement import com.google.gson.JsonObject import com.google.gson.JsonParser -import splitties.bitflags.hasFlag -import splitties.bitflags.minusFlag -import splitties.bitflags.withFlag +import io.github.sds100.keymapper.common.utils.hasFlag +import io.github.sds100.keymapper.common.utils.minusFlag +import io.github.sds100.keymapper.common.utils.withFlag /** * Move the action option "show performing toast when performing" to a trigger option. diff --git a/app/src/main/java/io/github/sds100/keymapper/data/migration/MigrationUtils.kt b/data/src/main/java/io/github/sds100/keymapper/data/migration/MigrationUtils.kt similarity index 94% rename from app/src/main/java/io/github/sds100/keymapper/data/migration/MigrationUtils.kt rename to data/src/main/java/io/github/sds100/keymapper/data/migration/MigrationUtils.kt index 3e8772074f..2cdf8ba802 100644 --- a/app/src/main/java/io/github/sds100/keymapper/data/migration/MigrationUtils.kt +++ b/data/src/main/java/io/github/sds100/keymapper/data/migration/MigrationUtils.kt @@ -2,9 +2,6 @@ package io.github.sds100.keymapper.data.migration import com.google.gson.JsonObject -/** - * Created by sds100 on 24/01/21. - */ object MigrationUtils { fun migrate( migrations: List, diff --git a/app/src/main/java/io/github/sds100/keymapper/data/migration/fingerprintmaps/FingerprintMapMigration0To1.kt b/data/src/main/java/io/github/sds100/keymapper/data/migration/fingerprintmaps/FingerprintMapMigration0To1.kt similarity index 89% rename from app/src/main/java/io/github/sds100/keymapper/data/migration/fingerprintmaps/FingerprintMapMigration0To1.kt rename to data/src/main/java/io/github/sds100/keymapper/data/migration/fingerprintmaps/FingerprintMapMigration0To1.kt index dd9e03d48e..b87e667f1b 100644 --- a/app/src/main/java/io/github/sds100/keymapper/data/migration/fingerprintmaps/FingerprintMapMigration0To1.kt +++ b/data/src/main/java/io/github/sds100/keymapper/data/migration/fingerprintmaps/FingerprintMapMigration0To1.kt @@ -4,13 +4,9 @@ import com.github.salomonbrys.kotson.byArray import com.github.salomonbrys.kotson.byInt import com.github.salomonbrys.kotson.set import com.google.gson.JsonObject -import splitties.bitflags.hasFlag -import splitties.bitflags.minusFlag -import splitties.bitflags.withFlag - -/** - * Created by sds100 on 22/01/21. - */ +import io.github.sds100.keymapper.common.utils.hasFlag +import io.github.sds100.keymapper.common.utils.minusFlag +import io.github.sds100.keymapper.common.utils.withFlag /** * Move the action option "show performing toast when performing" to a trigger option. diff --git a/app/src/main/java/io/github/sds100/keymapper/data/migration/fingerprintmaps/FingerprintMapMigration1To2.kt b/data/src/main/java/io/github/sds100/keymapper/data/migration/fingerprintmaps/FingerprintMapMigration1To2.kt similarity index 100% rename from app/src/main/java/io/github/sds100/keymapper/data/migration/fingerprintmaps/FingerprintMapMigration1To2.kt rename to data/src/main/java/io/github/sds100/keymapper/data/migration/fingerprintmaps/FingerprintMapMigration1To2.kt diff --git a/app/src/main/java/io/github/sds100/keymapper/data/migration/fingerprintmaps/FingerprintToKeyMapMigration.kt b/data/src/main/java/io/github/sds100/keymapper/data/migration/fingerprintmaps/FingerprintToKeyMapMigration.kt similarity index 97% rename from app/src/main/java/io/github/sds100/keymapper/data/migration/fingerprintmaps/FingerprintToKeyMapMigration.kt rename to data/src/main/java/io/github/sds100/keymapper/data/migration/fingerprintmaps/FingerprintToKeyMapMigration.kt index 735dbab356..5563acb5b7 100644 --- a/app/src/main/java/io/github/sds100/keymapper/data/migration/fingerprintmaps/FingerprintToKeyMapMigration.kt +++ b/data/src/main/java/io/github/sds100/keymapper/data/migration/fingerprintmaps/FingerprintToKeyMapMigration.kt @@ -1,12 +1,12 @@ package io.github.sds100.keymapper.data.migration.fingerprintmaps +import io.github.sds100.keymapper.common.utils.hasFlag import io.github.sds100.keymapper.data.entities.EntityExtra import io.github.sds100.keymapper.data.entities.FingerprintMapEntity import io.github.sds100.keymapper.data.entities.FingerprintTriggerKeyEntity import io.github.sds100.keymapper.data.entities.KeyMapEntity import io.github.sds100.keymapper.data.entities.TriggerEntity import io.github.sds100.keymapper.data.entities.TriggerKeyEntity -import splitties.bitflags.hasFlag object FingerprintToKeyMapMigration { fun migrate(entity: FingerprintMapEntity): KeyMapEntity? { diff --git a/data/src/main/java/io/github/sds100/keymapper/data/repositories/AccessibilityNodeRepository.kt b/data/src/main/java/io/github/sds100/keymapper/data/repositories/AccessibilityNodeRepository.kt new file mode 100644 index 0000000000..d378175640 --- /dev/null +++ b/data/src/main/java/io/github/sds100/keymapper/data/repositories/AccessibilityNodeRepository.kt @@ -0,0 +1,12 @@ +package io.github.sds100.keymapper.data.repositories + +import io.github.sds100.keymapper.common.utils.State +import io.github.sds100.keymapper.data.entities.AccessibilityNodeEntity +import kotlinx.coroutines.flow.Flow + +interface AccessibilityNodeRepository { + val nodes: Flow>> + suspend fun get(id: Long): AccessibilityNodeEntity? + fun insert(vararg node: AccessibilityNodeEntity) + suspend fun deleteAll() +} diff --git a/data/src/main/java/io/github/sds100/keymapper/data/repositories/FloatingButtonRepository.kt b/data/src/main/java/io/github/sds100/keymapper/data/repositories/FloatingButtonRepository.kt new file mode 100644 index 0000000000..2470680b0b --- /dev/null +++ b/data/src/main/java/io/github/sds100/keymapper/data/repositories/FloatingButtonRepository.kt @@ -0,0 +1,15 @@ +package io.github.sds100.keymapper.data.repositories + +import io.github.sds100.keymapper.common.utils.State +import io.github.sds100.keymapper.data.entities.FloatingButtonEntity +import io.github.sds100.keymapper.data.entities.FloatingButtonEntityWithLayout +import kotlinx.coroutines.flow.Flow + +interface FloatingButtonRepository { + val buttonsList: Flow>> + + fun insert(vararg button: FloatingButtonEntity) + fun update(button: FloatingButtonEntity) + suspend fun get(uid: String): FloatingButtonEntityWithLayout? + fun delete(vararg uid: String) +} diff --git a/data/src/main/java/io/github/sds100/keymapper/data/repositories/FloatingLayoutRepository.kt b/data/src/main/java/io/github/sds100/keymapper/data/repositories/FloatingLayoutRepository.kt new file mode 100644 index 0000000000..4b8fda0967 --- /dev/null +++ b/data/src/main/java/io/github/sds100/keymapper/data/repositories/FloatingLayoutRepository.kt @@ -0,0 +1,20 @@ +package io.github.sds100.keymapper.data.repositories + +import io.github.sds100.keymapper.common.utils.State +import io.github.sds100.keymapper.data.entities.FloatingLayoutEntity +import io.github.sds100.keymapper.data.entities.FloatingLayoutEntityWithButtons +import kotlinx.coroutines.flow.Flow + +interface FloatingLayoutRepository { + val layouts: Flow>> + suspend fun insert(vararg layout: FloatingLayoutEntity) + + /** + * @return whether the update happened successfully. It can be false if some constraints + * failed. + */ + suspend fun update(vararg layout: FloatingLayoutEntity): Boolean + fun get(uid: String): Flow + fun delete(vararg uid: String) + suspend fun count(): Int +} diff --git a/data/src/main/java/io/github/sds100/keymapper/data/repositories/GroupRepository.kt b/data/src/main/java/io/github/sds100/keymapper/data/repositories/GroupRepository.kt new file mode 100644 index 0000000000..ec00f476d7 --- /dev/null +++ b/data/src/main/java/io/github/sds100/keymapper/data/repositories/GroupRepository.kt @@ -0,0 +1,21 @@ +package io.github.sds100.keymapper.data.repositories + +import io.github.sds100.keymapper.data.entities.GroupEntity +import io.github.sds100.keymapper.data.entities.GroupEntityWithChildren +import io.github.sds100.keymapper.data.entities.KeyMapEntitiesWithGroup +import kotlinx.coroutines.flow.Flow + +interface GroupRepository { + val groups: Flow> + + fun getKeyMapsByGroup(groupUid: String): Flow + suspend fun getGroup(uid: String): GroupEntity? + fun getAllGroups(): Flow> + fun getGroups(vararg uid: String): Flow> + fun getGroupsByParent(uid: String?): Flow> + fun getGroupWithChildren(uid: String): Flow + suspend fun insert(groupEntity: GroupEntity) + suspend fun update(groupEntity: GroupEntity) + fun delete(uid: String) + suspend fun setLastOpenedDate(groupUid: String, timestamp: Long) +} diff --git a/app/src/main/java/io/github/sds100/keymapper/keymaps/KeyMapRepository.kt b/data/src/main/java/io/github/sds100/keymapper/data/repositories/KeyMapRepository.kt similarity index 84% rename from app/src/main/java/io/github/sds100/keymapper/keymaps/KeyMapRepository.kt rename to data/src/main/java/io/github/sds100/keymapper/data/repositories/KeyMapRepository.kt index 2c16070364..c83d5c79f4 100644 --- a/app/src/main/java/io/github/sds100/keymapper/keymaps/KeyMapRepository.kt +++ b/data/src/main/java/io/github/sds100/keymapper/data/repositories/KeyMapRepository.kt @@ -1,12 +1,9 @@ -package io.github.sds100.keymapper.keymaps +package io.github.sds100.keymapper.data.repositories +import io.github.sds100.keymapper.common.utils.State import io.github.sds100.keymapper.data.entities.KeyMapEntity -import io.github.sds100.keymapper.util.State import kotlinx.coroutines.flow.Flow -/** - * Created by sds100 on 18/03/2021. - */ interface KeyMapRepository { val keyMapList: Flow>> diff --git a/app/src/main/java/io/github/sds100/keymapper/logging/LogRepository.kt b/data/src/main/java/io/github/sds100/keymapper/data/repositories/LogRepository.kt similarity index 68% rename from app/src/main/java/io/github/sds100/keymapper/logging/LogRepository.kt rename to data/src/main/java/io/github/sds100/keymapper/data/repositories/LogRepository.kt index 55b30bf939..1df1d3479a 100644 --- a/app/src/main/java/io/github/sds100/keymapper/logging/LogRepository.kt +++ b/data/src/main/java/io/github/sds100/keymapper/data/repositories/LogRepository.kt @@ -1,12 +1,9 @@ -package io.github.sds100.keymapper.logging +package io.github.sds100.keymapper.data.repositories +import io.github.sds100.keymapper.common.utils.State import io.github.sds100.keymapper.data.entities.LogEntryEntity -import io.github.sds100.keymapper.util.State import kotlinx.coroutines.flow.Flow -/** - * Created by sds100 on 13/05/2021. - */ interface LogRepository { val log: Flow>> fun insert(entry: LogEntryEntity) diff --git a/app/src/main/java/io/github/sds100/keymapper/data/repositories/PreferenceRepository.kt b/data/src/main/java/io/github/sds100/keymapper/data/repositories/PreferenceRepository.kt similarity index 89% rename from app/src/main/java/io/github/sds100/keymapper/data/repositories/PreferenceRepository.kt rename to data/src/main/java/io/github/sds100/keymapper/data/repositories/PreferenceRepository.kt index 94136926de..7635037203 100644 --- a/app/src/main/java/io/github/sds100/keymapper/data/repositories/PreferenceRepository.kt +++ b/data/src/main/java/io/github/sds100/keymapper/data/repositories/PreferenceRepository.kt @@ -3,9 +3,6 @@ package io.github.sds100.keymapper.data.repositories import androidx.datastore.preferences.core.Preferences import kotlinx.coroutines.flow.Flow -/** - * Created by sds100 on 13/02/21. - */ interface PreferenceRepository { fun get(key: Preferences.Key): Flow fun set(key: Preferences.Key, value: T?) diff --git a/app/src/main/java/io/github/sds100/keymapper/data/repositories/RepositoryUtils.kt b/data/src/main/java/io/github/sds100/keymapper/data/repositories/RepositoryUtils.kt similarity index 100% rename from app/src/main/java/io/github/sds100/keymapper/data/repositories/RepositoryUtils.kt rename to data/src/main/java/io/github/sds100/keymapper/data/repositories/RepositoryUtils.kt diff --git a/app/src/main/java/io/github/sds100/keymapper/data/repositories/AccessibilityNodeRepository.kt b/data/src/main/java/io/github/sds100/keymapper/data/repositories/RoomAccessibilityNodeRepository.kt similarity index 82% rename from app/src/main/java/io/github/sds100/keymapper/data/repositories/AccessibilityNodeRepository.kt rename to data/src/main/java/io/github/sds100/keymapper/data/repositories/RoomAccessibilityNodeRepository.kt index 8783d66dd5..5bb8eb668e 100644 --- a/app/src/main/java/io/github/sds100/keymapper/data/repositories/AccessibilityNodeRepository.kt +++ b/data/src/main/java/io/github/sds100/keymapper/data/repositories/RoomAccessibilityNodeRepository.kt @@ -1,12 +1,11 @@ package io.github.sds100.keymapper.data.repositories import android.database.sqlite.SQLiteConstraintException +import io.github.sds100.keymapper.common.utils.State import io.github.sds100.keymapper.data.db.dao.AccessibilityNodeDao import io.github.sds100.keymapper.data.entities.AccessibilityNodeEntity -import io.github.sds100.keymapper.util.State import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.flowOn @@ -14,15 +13,11 @@ import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch import kotlinx.coroutines.withContext +import javax.inject.Inject +import javax.inject.Singleton -interface AccessibilityNodeRepository { - val nodes: Flow>> - suspend fun get(id: Long): AccessibilityNodeEntity? - fun insert(vararg node: AccessibilityNodeEntity) - suspend fun deleteAll() -} - -class AccessibilityNodeRepositoryImpl( +@Singleton +class RoomAccessibilityNodeRepository @Inject constructor( private val coroutineScope: CoroutineScope, private val dao: AccessibilityNodeDao, ) : AccessibilityNodeRepository { diff --git a/app/src/main/java/io/github/sds100/keymapper/data/repositories/FloatingButtonRepository.kt b/data/src/main/java/io/github/sds100/keymapper/data/repositories/RoomFloatingButtonRepository.kt similarity index 79% rename from app/src/main/java/io/github/sds100/keymapper/data/repositories/FloatingButtonRepository.kt rename to data/src/main/java/io/github/sds100/keymapper/data/repositories/RoomFloatingButtonRepository.kt index 50080c1290..b22e8938ae 100644 --- a/app/src/main/java/io/github/sds100/keymapper/data/repositories/FloatingButtonRepository.kt +++ b/data/src/main/java/io/github/sds100/keymapper/data/repositories/RoomFloatingButtonRepository.kt @@ -1,29 +1,22 @@ package io.github.sds100.keymapper.data.repositories +import io.github.sds100.keymapper.common.utils.DefaultDispatcherProvider +import io.github.sds100.keymapper.common.utils.DispatcherProvider +import io.github.sds100.keymapper.common.utils.State import io.github.sds100.keymapper.data.db.dao.FloatingButtonDao import io.github.sds100.keymapper.data.entities.FloatingButtonEntity import io.github.sds100.keymapper.data.entities.FloatingButtonEntityWithLayout -import io.github.sds100.keymapper.util.DefaultDispatcherProvider -import io.github.sds100.keymapper.util.DispatcherProvider -import io.github.sds100.keymapper.util.State import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch +import javax.inject.Inject +import javax.inject.Singleton -interface FloatingButtonRepository { - val buttonsList: Flow>> - - fun insert(vararg button: FloatingButtonEntity) - fun update(button: FloatingButtonEntity) - suspend fun get(uid: String): FloatingButtonEntityWithLayout? - fun delete(vararg uid: String) -} - -class RoomFloatingButtonRepository( +@Singleton +class RoomFloatingButtonRepository @Inject constructor( private val dao: FloatingButtonDao, private val coroutineScope: CoroutineScope, private val dispatchers: DispatcherProvider = DefaultDispatcherProvider(), diff --git a/app/src/main/java/io/github/sds100/keymapper/data/repositories/FloatingLayoutRepository.kt b/data/src/main/java/io/github/sds100/keymapper/data/repositories/RoomFloatingLayoutRepository.kt similarity index 72% rename from app/src/main/java/io/github/sds100/keymapper/data/repositories/FloatingLayoutRepository.kt rename to data/src/main/java/io/github/sds100/keymapper/data/repositories/RoomFloatingLayoutRepository.kt index 88fcc5a0b4..bea863f9b8 100644 --- a/app/src/main/java/io/github/sds100/keymapper/data/repositories/FloatingLayoutRepository.kt +++ b/data/src/main/java/io/github/sds100/keymapper/data/repositories/RoomFloatingLayoutRepository.kt @@ -1,12 +1,12 @@ package io.github.sds100.keymapper.data.repositories import android.database.sqlite.SQLiteConstraintException +import io.github.sds100.keymapper.common.utils.DefaultDispatcherProvider +import io.github.sds100.keymapper.common.utils.DispatcherProvider +import io.github.sds100.keymapper.common.utils.State import io.github.sds100.keymapper.data.db.dao.FloatingLayoutDao import io.github.sds100.keymapper.data.entities.FloatingLayoutEntity import io.github.sds100.keymapper.data.entities.FloatingLayoutEntityWithButtons -import io.github.sds100.keymapper.util.DefaultDispatcherProvider -import io.github.sds100.keymapper.util.DispatcherProvider -import io.github.sds100.keymapper.util.State import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.SharingStarted @@ -15,22 +15,11 @@ import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch import kotlinx.coroutines.withContext +import javax.inject.Inject +import javax.inject.Singleton -interface FloatingLayoutRepository { - val layouts: Flow>> - suspend fun insert(vararg layout: FloatingLayoutEntity) - - /** - * @return whether the update happened successfully. It can be false if some constraints - * failed. - */ - suspend fun update(vararg layout: FloatingLayoutEntity): Boolean - fun get(uid: String): Flow - fun delete(vararg uid: String) - suspend fun count(): Int -} - -class RoomFloatingLayoutRepository( +@Singleton +class RoomFloatingLayoutRepository @Inject constructor( private val dao: FloatingLayoutDao, private val coroutineScope: CoroutineScope, private val dispatchers: DispatcherProvider = DefaultDispatcherProvider(), diff --git a/app/src/main/java/io/github/sds100/keymapper/data/repositories/GroupRepository.kt b/data/src/main/java/io/github/sds100/keymapper/data/repositories/RoomGroupRepository.kt similarity index 76% rename from app/src/main/java/io/github/sds100/keymapper/data/repositories/GroupRepository.kt rename to data/src/main/java/io/github/sds100/keymapper/data/repositories/RoomGroupRepository.kt index 23423e11b8..8bef8186d4 100644 --- a/app/src/main/java/io/github/sds100/keymapper/data/repositories/GroupRepository.kt +++ b/data/src/main/java/io/github/sds100/keymapper/data/repositories/RoomGroupRepository.kt @@ -1,11 +1,11 @@ package io.github.sds100.keymapper.data.repositories +import io.github.sds100.keymapper.common.utils.DefaultDispatcherProvider +import io.github.sds100.keymapper.common.utils.DispatcherProvider import io.github.sds100.keymapper.data.db.dao.GroupDao import io.github.sds100.keymapper.data.entities.GroupEntity import io.github.sds100.keymapper.data.entities.GroupEntityWithChildren import io.github.sds100.keymapper.data.entities.KeyMapEntitiesWithGroup -import io.github.sds100.keymapper.util.DefaultDispatcherProvider -import io.github.sds100.keymapper.util.DispatcherProvider import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.SharingStarted @@ -14,23 +14,11 @@ import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch import kotlinx.coroutines.withContext +import javax.inject.Inject +import javax.inject.Singleton -interface GroupRepository { - val groups: Flow> - - fun getKeyMapsByGroup(groupUid: String): Flow - suspend fun getGroup(uid: String): GroupEntity? - fun getAllGroups(): Flow> - fun getGroups(vararg uid: String): Flow> - fun getGroupsByParent(uid: String?): Flow> - fun getGroupWithChildren(uid: String): Flow - suspend fun insert(groupEntity: GroupEntity) - suspend fun update(groupEntity: GroupEntity) - fun delete(uid: String) - suspend fun setLastOpenedDate(groupUid: String, timestamp: Long) -} - -class RoomGroupRepository( +@Singleton +class RoomGroupRepository @Inject constructor( private val dao: GroupDao, private val coroutineScope: CoroutineScope, private val dispatchers: DispatcherProvider = DefaultDispatcherProvider(), diff --git a/app/src/main/java/io/github/sds100/keymapper/data/repositories/RoomKeyMapRepository.kt b/data/src/main/java/io/github/sds100/keymapper/data/repositories/RoomKeyMapRepository.kt similarity index 92% rename from app/src/main/java/io/github/sds100/keymapper/data/repositories/RoomKeyMapRepository.kt rename to data/src/main/java/io/github/sds100/keymapper/data/repositories/RoomKeyMapRepository.kt index 7ad76800a7..dd05f6d82d 100644 --- a/app/src/main/java/io/github/sds100/keymapper/data/repositories/RoomKeyMapRepository.kt +++ b/data/src/main/java/io/github/sds100/keymapper/data/repositories/RoomKeyMapRepository.kt @@ -1,15 +1,14 @@ package io.github.sds100.keymapper.data.repositories +import io.github.sds100.keymapper.common.utils.DefaultDispatcherProvider +import io.github.sds100.keymapper.common.utils.DispatcherProvider +import io.github.sds100.keymapper.common.utils.State +import io.github.sds100.keymapper.common.utils.splitIntoBatches import io.github.sds100.keymapper.data.db.dao.FingerprintMapDao import io.github.sds100.keymapper.data.db.dao.KeyMapDao import io.github.sds100.keymapper.data.entities.FingerprintMapEntity import io.github.sds100.keymapper.data.entities.KeyMapEntity import io.github.sds100.keymapper.data.migration.fingerprintmaps.FingerprintToKeyMapMigration -import io.github.sds100.keymapper.keymaps.KeyMapRepository -import io.github.sds100.keymapper.util.DefaultDispatcherProvider -import io.github.sds100.keymapper.util.DispatcherProvider -import io.github.sds100.keymapper.util.State -import io.github.sds100.keymapper.util.splitIntoBatches import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.SharingStarted @@ -20,8 +19,11 @@ import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import java.util.UUID +import javax.inject.Inject +import javax.inject.Singleton -class RoomKeyMapRepository( +@Singleton +class RoomKeyMapRepository @Inject constructor( private val keyMapDao: KeyMapDao, private val fingerprintMapDao: FingerprintMapDao, private val coroutineScope: CoroutineScope, diff --git a/app/src/main/java/io/github/sds100/keymapper/data/repositories/RoomLogRepository.kt b/data/src/main/java/io/github/sds100/keymapper/data/repositories/RoomLogRepository.kt similarity index 91% rename from app/src/main/java/io/github/sds100/keymapper/data/repositories/RoomLogRepository.kt rename to data/src/main/java/io/github/sds100/keymapper/data/repositories/RoomLogRepository.kt index 6ce032aa55..083a8034b9 100644 --- a/app/src/main/java/io/github/sds100/keymapper/data/repositories/RoomLogRepository.kt +++ b/data/src/main/java/io/github/sds100/keymapper/data/repositories/RoomLogRepository.kt @@ -1,9 +1,8 @@ package io.github.sds100.keymapper.data.repositories +import io.github.sds100.keymapper.common.utils.State import io.github.sds100.keymapper.data.db.dao.LogEntryDao import io.github.sds100.keymapper.data.entities.LogEntryEntity -import io.github.sds100.keymapper.logging.LogRepository -import io.github.sds100.keymapper.util.State import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.Flow @@ -15,11 +14,11 @@ import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch +import javax.inject.Inject +import javax.inject.Singleton -/** - * Created by sds100 on 13/05/2021. - */ -class RoomLogRepository( +@Singleton +class RoomLogRepository @Inject constructor( private val coroutineScope: CoroutineScope, private val dao: LogEntryDao, ) : LogRepository { diff --git a/app/src/main/java/io/github/sds100/keymapper/data/repositories/SettingsPreferenceRepository.kt b/data/src/main/java/io/github/sds100/keymapper/data/repositories/SettingsPreferenceRepository.kt similarity index 88% rename from app/src/main/java/io/github/sds100/keymapper/data/repositories/SettingsPreferenceRepository.kt rename to data/src/main/java/io/github/sds100/keymapper/data/repositories/SettingsPreferenceRepository.kt index b4fba3ba06..8d7f330d20 100644 --- a/app/src/main/java/io/github/sds100/keymapper/data/repositories/SettingsPreferenceRepository.kt +++ b/data/src/main/java/io/github/sds100/keymapper/data/repositories/SettingsPreferenceRepository.kt @@ -4,14 +4,18 @@ import android.content.Context import androidx.datastore.preferences.core.Preferences import androidx.datastore.preferences.core.edit import androidx.datastore.preferences.preferencesDataStore +import dagger.hilt.android.qualifiers.ApplicationContext import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.map import kotlinx.coroutines.launch +import javax.inject.Inject +import javax.inject.Singleton -class SettingsPreferenceRepository( - context: Context, +@Singleton +class SettingsPreferenceRepository @Inject constructor( + @ApplicationContext context: Context, private val coroutineScope: CoroutineScope, ) : PreferenceRepository { diff --git a/app/src/main/java/io/github/sds100/keymapper/util/PreferenceDelegate.kt b/data/src/main/java/io/github/sds100/keymapper/data/utils/PreferenceDelegate.kt similarity index 89% rename from app/src/main/java/io/github/sds100/keymapper/util/PreferenceDelegate.kt rename to data/src/main/java/io/github/sds100/keymapper/data/utils/PreferenceDelegate.kt index 3664a76b8a..f8fe4539c1 100644 --- a/app/src/main/java/io/github/sds100/keymapper/util/PreferenceDelegate.kt +++ b/data/src/main/java/io/github/sds100/keymapper/data/utils/PreferenceDelegate.kt @@ -1,15 +1,12 @@ -package io.github.sds100.keymapper.util +package io.github.sds100.keymapper.data.utils import androidx.datastore.preferences.core.Preferences +import io.github.sds100.keymapper.common.utils.firstBlocking import io.github.sds100.keymapper.data.repositories.PreferenceRepository import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.map import kotlin.reflect.KProperty -/** - * Created by sds100 on 14/02/21. - */ - class FlowPrefDelegate( private val key: Preferences.Key, private val defaultValue: T, diff --git a/app/src/main/java/io/github/sds100/keymapper/util/SharedPrefsDataStoreWrapper.kt b/data/src/main/java/io/github/sds100/keymapper/data/utils/SharedPrefsDataStoreWrapper.kt similarity index 57% rename from app/src/main/java/io/github/sds100/keymapper/util/SharedPrefsDataStoreWrapper.kt rename to data/src/main/java/io/github/sds100/keymapper/data/utils/SharedPrefsDataStoreWrapper.kt index 332c9938ab..44b5eb8eee 100644 --- a/app/src/main/java/io/github/sds100/keymapper/util/SharedPrefsDataStoreWrapper.kt +++ b/data/src/main/java/io/github/sds100/keymapper/data/utils/SharedPrefsDataStoreWrapper.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.util +package io.github.sds100.keymapper.data.utils import androidx.datastore.preferences.core.booleanPreferencesKey import androidx.datastore.preferences.core.doublePreferencesKey @@ -8,15 +8,13 @@ import androidx.datastore.preferences.core.longPreferencesKey import androidx.datastore.preferences.core.stringPreferencesKey import androidx.datastore.preferences.core.stringSetPreferencesKey import androidx.preference.PreferenceDataStore -import io.github.sds100.keymapper.settings.ConfigSettingsUseCase +import io.github.sds100.keymapper.data.repositories.PreferenceRepository import kotlinx.coroutines.flow.first import kotlinx.coroutines.runBlocking +import javax.inject.Inject -/** - * Created by sds100 on 19/01/21. - */ -class SharedPrefsDataStoreWrapper( - private val configSettingsUseCase: ConfigSettingsUseCase, +class SharedPrefsDataStoreWrapper @Inject constructor( + private val preferenceRepository: PreferenceRepository, ) : PreferenceDataStore() { override fun getBoolean(key: String, defValue: Boolean) = getFromSharedPrefs(key, defValue) @@ -28,30 +26,28 @@ class SharedPrefsDataStoreWrapper( override fun getInt(key: String, defValue: Int) = getFromSharedPrefs(key, defValue) override fun putInt(key: String, value: Int) = setFromSharedPrefs(key, value) - override fun getStringSet(key: String, defValues: MutableSet?) = - getStringSetFromSharedPrefs(key, defValues ?: emptySet()) + override fun getStringSet(key: String, defValues: MutableSet?) = getStringSetFromSharedPrefs(key, defValues ?: emptySet()) - override fun putStringSet(key: String, defValues: MutableSet?) = - setStringSetFromSharedPrefs(key, defValues) + override fun putStringSet(key: String, defValues: MutableSet?) = setStringSetFromSharedPrefs(key, defValues) private inline fun getFromSharedPrefs(key: String, default: T): T = runBlocking { when (default) { - is String? -> configSettingsUseCase.getPreference(stringPreferencesKey(key)).first() + is String? -> preferenceRepository.get(stringPreferencesKey(key)).first() ?: default - is Boolean? -> configSettingsUseCase.getPreference(booleanPreferencesKey(key)) + is Boolean? -> preferenceRepository.get(booleanPreferencesKey(key)) .first() ?: default - is Int? -> configSettingsUseCase.getPreference(intPreferencesKey(key)).first() + is Int? -> preferenceRepository.get(intPreferencesKey(key)).first() ?: default - is Long? -> configSettingsUseCase.getPreference(longPreferencesKey(key)).first() + is Long? -> preferenceRepository.get(longPreferencesKey(key)).first() ?: default - is Float? -> configSettingsUseCase.getPreference(floatPreferencesKey(key)).first() + is Float? -> preferenceRepository.get(floatPreferencesKey(key)).first() ?: default - is Double? -> configSettingsUseCase.getPreference(doublePreferencesKey(key)).first() + is Double? -> preferenceRepository.get(doublePreferencesKey(key)).first() ?: default else -> { @@ -65,12 +61,12 @@ class SharedPrefsDataStoreWrapper( key ?: return when (value) { - is String -> configSettingsUseCase.setPreference(stringPreferencesKey(key), value) - is Boolean -> configSettingsUseCase.setPreference(booleanPreferencesKey(key), value) - is Int -> configSettingsUseCase.setPreference(intPreferencesKey(key), value) - is Long -> configSettingsUseCase.setPreference(longPreferencesKey(key), value) - is Float -> configSettingsUseCase.setPreference(floatPreferencesKey(key), value) - is Double -> configSettingsUseCase.setPreference(doublePreferencesKey(key), value) + is String -> preferenceRepository.set(stringPreferencesKey(key), value) + is Boolean -> preferenceRepository.set(booleanPreferencesKey(key), value) + is Int -> preferenceRepository.set(intPreferencesKey(key), value) + is Long -> preferenceRepository.set(longPreferencesKey(key), value) + is Float -> preferenceRepository.set(floatPreferencesKey(key), value) + is Double -> preferenceRepository.set(doublePreferencesKey(key), value) else -> { val type = value?.let { it::class.java.name } throw IllegalArgumentException("Don't know how to set a value in shared preferences for this type $type") @@ -78,14 +74,13 @@ class SharedPrefsDataStoreWrapper( } } - private fun getStringSetFromSharedPrefs(key: String, default: Set?): Set = - runBlocking { - configSettingsUseCase.getPreference(stringSetPreferencesKey(key)).first() ?: emptySet() - } + private fun getStringSetFromSharedPrefs(key: String, default: Set?): Set = runBlocking { + preferenceRepository.get(stringSetPreferencesKey(key)).first() ?: emptySet() + } private fun setStringSetFromSharedPrefs(key: String?, value: Set?) { key ?: return - configSettingsUseCase.setPreference(stringSetPreferencesKey(key), value) + preferenceRepository.set(stringSetPreferencesKey(key), value) } } diff --git a/fastlane/Fastfile b/fastlane/Fastfile index 9e3fc27b77..790e634b97 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -19,11 +19,11 @@ default_platform(:android) desc "Create testing release" lane :testing do - gradle(task: "clean assembleFreeCi") + gradle(task: "clean assembleCi") end desc "Create and deploy production release" -lane :prod do +lane :production do prompt(text: "Did you write whats new?") version_code = get_properties_value(key: "VERSION_CODE", path: "./app/version.properties") @@ -32,7 +32,9 @@ lane :prod do # Don't create changelog for f-droid because not committing it # File.write("metadata/android/en-US/changelogs/" + version_code + ".txt", whats_new) - gradle(task: "testProDebugUnitTest") + Dir.chdir("..") do + gradle(task: "testDebugUnitTest") + end github_token = prompt( text: "Github token: ", @@ -53,32 +55,35 @@ lane :prod do # gradle(task: "assembleDebug") # Release the free build to GitHub because billing only works if signed by Google Play - gradle(task: "assembleFreeRelease") - gradle(task: "bundleProRelease") + gradle(task: "assembleRelease") - apk_path_release="app/build/outputs/apk/free/release/keymapper-" + version_name + ".apk" + Dir.chdir("..") do + gradle(task: "bundleRelease") + end + + apk_path_release="app/build/outputs/apk/release/keymapper-foss-" + version_name + ".apk" # First release to google play so any errors with the descriptions are resolved before # creating the git tag. - supply( - aab: "app/build/outputs/bundle/proRelease/app-pro-release.aab", - track: "internal", - skip_upload_apk: true - ) - - whats_new = File.read("../app/src/main/assets/whats-new.txt") - - github_release = set_github_release( - repository_name: "keymapperorg/KeyMapper", - api_bearer: github_token, - name: version_name, - tag_name: "v" + version_name, - description: whats_new, - commitish: "master", - upload_assets: [apk_path_release], - is_draft: false, - is_prerelease: false - ) +# supply( +# aab: "../app/build/outputs/bundle/release/app-pro-release.aab", +# track: "internal", +# skip_upload_apk: true +# ) +# +# whats_new = File.read("../app/src/main/assets/whats-new.txt") +# +# github_release = set_github_release( +# repository_name: "keymapperorg/KeyMapper", +# api_bearer: github_token, +# name: version_name, +# tag_name: "v" + version_name, +# description: whats_new, +# commitish: "master", +# upload_assets: [apk_path_release], +# is_draft: false, +# is_prerelease: false +# ) end desc "Create and deploy internal testing release" @@ -102,19 +107,22 @@ lane :internal do # Do not release a debug build for pro version. # gradle(task: "assembleDebug") -# Release the free build to GitHub because billing only works if signed by Google Play - gradle(task: "bundleProRelease") - # First release to google play so any errors with the descriptions are resolved before - # creating the git tag. - supply( - aab: "app/build/outputs/bundle/proRelease/app-pro-release.aab", - track: "internal", - skip_upload_apk: true, - skip_upload_metadata: true, - skip_upload_changelogs: true, - skip_upload_images: true, - skip_upload_screenshots: true - ) + Dir.chdir("..") do + # Release the free build to GitHub because billing only works if signed by Google Play + gradle(task: "bundleProRelease") + + # First release to google play so any errors with the descriptions are resolved before + # creating the git tag. + supply( + aab: "app/build/outputs/bundle/release/app-pro-release.aab", + track: "internal", + skip_upload_apk: true, + skip_upload_metadata: true, + skip_upload_changelogs: true, + skip_upload_images: true, + skip_upload_screenshots: true + ) + end end diff --git a/fastlane/README.md b/fastlane/README.md index 07067c6e22..e1c1a3b723 100644 --- a/fastlane/README.md +++ b/fastlane/README.md @@ -21,10 +21,10 @@ For _fastlane_ installation instructions, see [Installing _fastlane_](https://do Create testing release -### prod +### production ```sh -[bundle exec] fastlane prod +[bundle exec] fastlane production ``` Create and deploy production release diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml new file mode 100644 index 0000000000..ee4cd11df2 --- /dev/null +++ b/gradle/libs.versions.toml @@ -0,0 +1,216 @@ +[versions] +compile-sdk = "35" +hilt-navigation-compose = "1.2.0" +min-sdk = "21" +build-tools = "35.0.0" +target-sdk = "35" + +android-gradle-plugin = "8.9.1" +androidx-activity = "1.10.1" +androidx-appcompat = "1.7.0" +androidx-arch-core-testing = "2.2.0" +androidx-constraintlayout = "2.2.1" +androidx-core-ktx = "1.16.0" +androidx-core-splashscreen = "1.0.1" +androidx-datastore-preferences = "1.2.0-alpha02" +androidx-fragment = "1.8.6" +androidx-junit = "1.2.1" # formerly androidXTestExtKotlinRunnerVersion +androidx-legacy-support-core-ui = "1.0.0" +androidx-lifecycle = "2.9.0" +androidx-lifecycle-extensions = "2.2.0" # Note: lifecycle-extensions is deprecated +androidx-multidex = "2.0.1" +androidx-navigation = "2.9.0" # App level nav_version +androidx-navigation-safeargs-gradle-plugin = "2.6.0" # Project level nav_version +androidx-preference-ktx = "1.2.1" +androidx-recyclerview = "1.4.0" +androidx-room = "2.7.1" # room_version for dependencies +androidx-room-gradle-plugin = "2.6.1" # For plugin +androidx-test-core = "1.6.1" +androidx-viewpager2 = "1.1.0" + +dagger-hilt-android = "2.56.2" + +compose-bom = "2025.05.01" +compose-compiler = "1.5.10" # kotlinCompilerExtensionVersion + +desugar-jdk-libs = "2.1.5" +epoxy = "4.6.2" +flexbox = "3.0.0" +google-accompanist-drawablepainter = "0.35.0-alpha" +hiddenapibypass = "4.3" +introshowcaseview = "2.0.2" +junit = "4.13.2" +junit-params = "1.1.1" + +kotlin = "2.1.0" +kotlin-serialization-json = "1.8.0" +coroutines = "1.9.0" + +kotson = "2.5.0" +ksp-gradle-plugin = "2.1.0-1.0.28" +ktlint-gradle = "12.1.0" +#leakcanary = "2.6" # Commented out in original file +lingala-zip4j = "2.8.0" +material = "1.13.0-alpha13" + +mflisar-dragselectrecyclerview = "0.3" +mockito-android = "4.6.1" +mockito-core = "5.15.2" +mockito-inline = "5.2.0" +mockito-kotlin = "4.0.0" + +okhttp = "4.12.0" +robolectric = "4.14.1" +shizuku = "13.1.5" +splitties = "3.0.0" +storage-anggrayudi = "0.8.1" +timber = "5.0.1" +room-testing-legacy = "1.1.1" +espresso-core = "3.6.1" +ui-tooling = "1.8.1" # android.arch.persistence.room:testing + +[libraries] +# Kotlin +androidx-hilt-navigation-compose = { module = "androidx.hilt:hilt-navigation-compose", version.ref = "hilt-navigation-compose" } +dagger-hilt-android = { module = "com.google.dagger:hilt-android", version.ref = "dagger-hilt-android" } +dagger-hilt-android-compiler = { module = "com.google.dagger:hilt-android-compiler", version.ref = "dagger-hilt-android" } +kotlin-stdlib-jdk8 = { group = "org.jetbrains.kotlin", name = "kotlin-stdlib-jdk8", version.ref = "kotlin" } +kotlinx-coroutines-android = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-android", version.ref = "coroutines" } +kotlinx-coroutines-test = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-test", version.ref = "coroutines" } +kotlinx-serialization-json = { group = "org.jetbrains.kotlinx", name = "kotlinx-serialization-json", version.ref = "kotlin-serialization-json" } + +# AndroidX +androidx-activity-compose = { group = "androidx.activity", name = "activity-compose", version.ref = "androidx-activity" } +androidx-activity-ktx = { group = "androidx.activity", name = "activity-ktx", version.ref = "androidx-activity" } +androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "androidx-appcompat" } +androidx-arch-core-testing = { group = "androidx.arch.core", name = "core-testing", version.ref = "androidx-arch-core-testing" } +androidx-constraintlayout = { group = "androidx.constraintlayout", name = "constraintlayout", version.ref = "androidx-constraintlayout" } +androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "androidx-core-ktx" } +androidx-core-splashscreen = { group = "androidx.core", name = "core-splashscreen", version.ref = "androidx-core-splashscreen" } +androidx-datastore-preferences = { group = "androidx.datastore", name = "datastore-preferences", version.ref = "androidx-datastore-preferences" } +androidx-fragment-ktx = { group = "androidx.fragment", name = "fragment-ktx", version.ref = "androidx-fragment" } +androidx-fragment-testing = { group = "androidx.fragment", name = "fragment-testing", version.ref = "androidx-fragment" } +androidx-junit-ktx = { group = "androidx.test.ext", name = "junit-ktx", version.ref = "androidx-junit" } # Combines ext:junit and -ktx +androidx-legacy-support-core-ui = { group = "androidx.legacy", name = "legacy-support-core-ui", version.ref = "androidx-legacy-support-core-ui" } +androidx-lifecycle-extensions = { group = "androidx.lifecycle", name = "lifecycle-extensions", version.ref = "androidx-lifecycle-extensions" } +androidx-lifecycle-livedata-ktx = { group = "androidx.lifecycle", name = "lifecycle-livedata-ktx", version.ref = "androidx-lifecycle" } +androidx-lifecycle-runtime-ktx = { group = "androidx.lifecycle", name = "lifecycle-runtime-ktx", version.ref = "androidx-lifecycle" } +androidx-lifecycle-viewmodel-ktx = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-ktx", version.ref = "androidx-lifecycle" } +androidx-multidex = { group = "androidx.multidex", name = "multidex", version.ref = "androidx-multidex" } +androidx-navigation-compose = { group = "androidx.navigation", name = "navigation-compose", version.ref = "androidx-navigation" } +androidx-navigation-fragment-compose = { module = "androidx.navigation:navigation-fragment-compose", version.ref = "androidx-navigation" } # Custom example if needed +androidx-navigation-fragment-ktx = { group = "androidx.navigation", name = "navigation-fragment-ktx", version.ref = "androidx-navigation" } +androidx-navigation-testing = { group = "androidx.navigation", name = "navigation-testing", version.ref = "androidx-navigation" } +androidx-navigation-ui-ktx = { group = "androidx.navigation", name = "navigation-ui-ktx", version.ref = "androidx-navigation" } +androidx-preference-ktx = { group = "androidx.preference", name = "preference-ktx", version.ref = "androidx-preference-ktx" } +androidx-recyclerview = { group = "androidx.recyclerview", name = "recyclerview", version.ref = "androidx-recyclerview" } +androidx-room-compiler = { group = "androidx.room", name = "room-compiler", version.ref = "androidx-room" } +androidx-room-ktx = { group = "androidx.room", name = "room-ktx", version.ref = "androidx-room" } +androidx-room-runtime = { group = "androidx.room", name = "room-runtime", version.ref = "androidx-room" } +androidx-room-testing-legacy = { group = "android.arch.persistence.room", name = "testing", version.ref = "room-testing-legacy" } +androidx-test-core = { group = "androidx.test", name = "core", version.ref = "androidx-test-core" } +androidx-test-core-ktx = { group = "androidx.test", name = "core-ktx", version.ref = "androidx-test-core" } +androidx-test-ext-junit = { group = "androidx.test.ext", name = "junit", version.ref = "androidx-junit" } +androidx-viewpager2 = { group = "androidx.viewpager2", name = "viewpager2", version.ref = "androidx-viewpager2" } + +# Compose +androidx-compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "compose-bom" } +androidx-compose-foundation = { group = "androidx.compose.foundation", name = "foundation" } +androidx-compose-material-icons-extended = { group = "androidx.compose.material", name = "material-icons-extended-android" } +androidx-compose-material3 = { group = "androidx.compose.material3", name = "material3-android" } +androidx-compose-material3-adaptive = { group = "androidx.compose.material3.adaptive", name = "adaptive-android" } +androidx-compose-material3-adaptive-navigation = { group = "androidx.compose.material3.adaptive", name = "adaptive-navigation" } +androidx-compose-ui-android = { group = "androidx.compose.ui", name = "ui-android" } +androidx-compose-ui-tooling = { group = "androidx.compose.ui", name = "ui-tooling" } +androidx-compose-ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-tooling-preview-android" } + +# Google +google-accompanist-drawablepainter = { group = "com.google.accompanist", name = "accompanist-drawablepainter", version.ref = "google-accompanist-drawablepainter" } +google-android-material = { group = "com.google.android.material", name = "material", version.ref = "material" } +google-flexbox = { group = "com.google.android.flexbox", name = "flexbox", version.ref = "flexbox" } + +# Square +squareup-okhttp = { group = "com.squareup.okhttp3", name = "okhttp", version.ref = "okhttp" } +#squareup-leakcanary-android = { group = "com.squareup.leakcanary", name = "leakcanary-android", version.ref = "leakcanary" } # Commented out + +# Airbnb +airbnb-epoxy = { group = "com.airbnb.android", name = "epoxy", version.ref = "epoxy" } +airbnb-epoxy-databinding = { group = "com.airbnb.android", name = "epoxy-databinding", version.ref = "epoxy" } +airbnb-epoxy-processor = { group = "com.airbnb.android", name = "epoxy-processor", version.ref = "epoxy" } + +# Splitties +splitties-alertdialog-appcompat-coroutines = { group = "com.louiscad.splitties", name = "splitties-alertdialog-appcompat-coroutines", version.ref = "splitties" } +splitties-alertdialog-material = { group = "com.louiscad.splitties", name = "splitties-alertdialog-material", version.ref = "splitties" } +splitties-bitflags = { group = "com.louiscad.splitties", name = "splitties-bitflags", version.ref = "splitties" } +splitties-mainthread = { group = "com.louiscad.splitties", name = "splitties-mainthread", version.ref = "splitties" } +splitties-snackbar = { group = "com.louiscad.splitties", name = "splitties-snackbar", version.ref = "splitties" } +splitties-toast = { group = "com.louiscad.splitties", name = "splitties-toast", version.ref = "splitties" } + +# Rikka Shizuku +rikka-shizuku-api = { group = "dev.rikka.shizuku", name = "api", version.ref = "shizuku" } +rikka-shizuku-provider = { group = "dev.rikka.shizuku", name = "provider", version.ref = "shizuku" } + +# Testing +junit = { group = "junit", name = "junit", version.ref = "junit" } +junit-params = { group = "pl.pragmatists", name = "JUnitParams", version.ref = "junit-params" } +mockito-android = { group = "org.mockito", name = "mockito-android", version.ref = "mockito-android" } +mockito-core = { group = "org.mockito", name = "mockito-core", version.ref = "mockito-core" } +mockito-inline = { group = "org.mockito", name = "mockito-inline", version.ref = "mockito-inline" } +mockito-kotlin = { group = "org.mockito.kotlin", name = "mockito-kotlin", version.ref = "mockito-kotlin" } +robolectric = { group = "org.robolectric", name = "robolectric", version.ref = "robolectric" } +hamcrest-all = { group = "org.hamcrest", name = "hamcrest-all", version = "1.3" } # No version variable + +# Other +anggrayudi-storage = { group = "com.anggrayudi", name = "storage", version.ref = "storage-anggrayudi" } +canopas-introshowcaseview = { group = "com.canopas.intro-showcase-view", name = "introshowcaseview", version.ref = "introshowcaseview" } +desugar-jdk-libs = { group = "com.android.tools", name = "desugar_jdk_libs", version.ref = "desugar-jdk-libs" } +github-mflisar-dragselectrecyclerview = { group = "com.github.MFlisar", name = "DragSelectRecyclerView", version.ref = "mflisar-dragselectrecyclerview" } +jakewharton-timber = { group = "com.jakewharton.timber", name = "timber", version.ref = "timber" } +kotson = { group = "com.github.salomonbrys.kotson", name = "kotson", version.ref = "kotson" } +lsposed-hiddenapibypass = { group = "org.lsposed.hiddenapibypass", name = "hiddenapibypass", version.ref = "hiddenapibypass" } +net-lingala-zip4j = { group = "net.lingala.zip4j", name = "zip4j", version.ref = "lingala-zip4j" } + +# Gradle Plugins - Aliases for buildscript dependencies / plugins block +# These are referenced in build.gradle.kts files' plugins blocks by their ID. +# Versions defined here can be used by plugins {} block in settings.gradle.kts if needed. +android-gradleplugin = { group = "com.android.tools.build", name = "gradle", version.ref = "android-gradle-plugin" } +kotlin-gradleplugin = { group = "org.jetbrains.kotlin", name = "kotlin-gradle-plugin", version.ref = "kotlin" } +kotlin-serialization-gradleplugin = { group = "org.jetbrains.kotlin", name = "kotlin-serialization", version.ref = "kotlin" } +ksp-gradleplugin = { group = "com.google.devtools.ksp", name = "com.google.devtools.ksp.gradle.plugin", version.ref = "ksp-gradle-plugin" } +navigation-safeargs-gradleplugin = { group = "androidx.navigation", name = "navigation-safe-args-gradle-plugin", version.ref = "androidx-navigation-safeargs-gradle-plugin" } +ktlint-gradleplugin = { group = "org.jlleitschuh.gradle", name = "ktlint-gradle", version.ref = "ktlint-gradle" } +kotlin-compose-compiler-gradleplugin = { group = "org.jetbrains.kotlin.plugin.compose", name = "org.jetbrains.kotlin.plugin.compose.gradle.plugin", version.ref = "kotlin" } # Using kotlin version for compose plugin as per original setup +room-gradleplugin = { group = "androidx.room", name = "androidx.room.gradle.plugin", version.ref = "androidx-room-gradle-plugin" } +androidx-espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espresso-core" } +androidx-ui-tooling = { group = "androidx.compose.ui", name = "ui-tooling", version.ref = "ui-tooling" } + +[plugins] +android-application = { id = "com.android.application", version.ref = "android-gradle-plugin" } +androidx-navigation-safeargs-kotlin = { id = "androidx.navigation.safeargs.kotlin", version.ref = "androidx-navigation-safeargs-gradle-plugin" } +androidx-room = { id = "androidx.room", version.ref = "androidx-room-gradle-plugin" } +google-devtools-ksp = { id = "com.google.devtools.ksp", version.ref = "ksp-gradle-plugin" } +jlleitschuh-gradle-ktlint = { id = "org.jlleitschuh.gradle.ktlint", version.ref = "ktlint-gradle" } +kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } +kotlin-compose = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" } +kotlin-kapt = { id = "org.jetbrains.kotlin.kapt", version.ref = "kotlin" } +kotlin-parcelize = { id = "org.jetbrains.kotlin.plugin.parcelize", version.ref = "kotlin" } +kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" } +android-library = { id = "com.android.library", version.ref = "android-gradle-plugin" } +dagger-hilt-android = { id = "com.google.dagger.hilt.android", version.ref = "dagger-hilt-android" } + +[bundles] +splitties = [ + "splitties-alertdialog-appcompat-coroutines", + "splitties-alertdialog-material", +] +androidx-lifecycle = [ + "androidx-lifecycle-viewmodel-ktx", + "androidx-lifecycle-runtime-ktx", + "androidx-lifecycle-livedata-ktx", +] +androidx-navigation = [ + "androidx-navigation-fragment-ktx", + "androidx-navigation-ui-ktx", + "androidx-navigation-compose", + "androidx-navigation-fragment-compose", +] \ No newline at end of file diff --git a/settings.gradle b/settings.gradle deleted file mode 100644 index a2a582b50a..0000000000 --- a/settings.gradle +++ /dev/null @@ -1,2 +0,0 @@ -include ':app' -include ':systemstubs' diff --git a/settings.gradle.kts b/settings.gradle.kts new file mode 100644 index 0000000000..266e977f2e --- /dev/null +++ b/settings.gradle.kts @@ -0,0 +1,33 @@ +pluginManagement { + repositories { + google { + content { + includeGroupByRegex("com\\.android.*") + includeGroupByRegex("com\\.google.*") + includeGroupByRegex("androidx.*") + } + } + mavenCentral() + gradlePluginPortal() + } +} +dependencyResolutionManagement { + repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) + repositories { + google() + mavenCentral() + maven { url = uri("https://jitpack.io") } + maven { url = uri("https://maven.google.com/") } + maven { url = uri("https://dl.bintray.com/rikkaw/Shizuku") } + } +} + +rootProject.name = "KeyMapperFoss" +include(":app") +include(":systemstubs") +include(":base") +include(":api") +include(":system") +include(":common") +include(":data") +include(":shizuku") diff --git a/shizuku/.gitignore b/shizuku/.gitignore new file mode 100644 index 0000000000..42afabfd2a --- /dev/null +++ b/shizuku/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/shizuku/build.gradle.kts b/shizuku/build.gradle.kts new file mode 100644 index 0000000000..a959a4e481 --- /dev/null +++ b/shizuku/build.gradle.kts @@ -0,0 +1,43 @@ +plugins { + alias(libs.plugins.android.library) + alias(libs.plugins.kotlin.android) +} + +android { + namespace = "io.github.sds100.keymapper.shizuku" + compileSdk = 35 + + 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_11 + targetCompatibility = JavaVersion.VERSION_11 + } + kotlinOptions { + jvmTarget = "11" + } +} + +dependencies { + + implementation(libs.androidx.core.ktx) + implementation(libs.androidx.appcompat) + implementation(libs.google.android.material) + testImplementation(libs.junit) + androidTestImplementation(libs.androidx.test.ext.junit) + androidTestImplementation(libs.androidx.espresso.core) +} \ No newline at end of file diff --git a/shizuku/consumer-rules.pro b/shizuku/consumer-rules.pro new file mode 100644 index 0000000000..e69de29bb2 diff --git a/shizuku/proguard-rules.pro b/shizuku/proguard-rules.pro new file mode 100644 index 0000000000..481bb43481 --- /dev/null +++ b/shizuku/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/shizuku/src/androidTest/java/io/github/sds100/keymapper/shizuku/ExampleInstrumentedTest.kt b/shizuku/src/androidTest/java/io/github/sds100/keymapper/shizuku/ExampleInstrumentedTest.kt new file mode 100644 index 0000000000..44e338cfc3 --- /dev/null +++ b/shizuku/src/androidTest/java/io/github/sds100/keymapper/shizuku/ExampleInstrumentedTest.kt @@ -0,0 +1,24 @@ +package io.github.sds100.keymapper.shizuku + +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("io.github.sds100.keymapper.shizuku.test", appContext.packageName) + } +} \ No newline at end of file diff --git a/shizuku/src/main/AndroidManifest.xml b/shizuku/src/main/AndroidManifest.xml new file mode 100644 index 0000000000..a5918e68ab --- /dev/null +++ b/shizuku/src/main/AndroidManifest.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/shizuku/src/test/java/io/github/sds100/keymapper/shizuku/ExampleUnitTest.kt b/shizuku/src/test/java/io/github/sds100/keymapper/shizuku/ExampleUnitTest.kt new file mode 100644 index 0000000000..c372bb7be5 --- /dev/null +++ b/shizuku/src/test/java/io/github/sds100/keymapper/shizuku/ExampleUnitTest.kt @@ -0,0 +1,17 @@ +package io.github.sds100.keymapper.shizuku + +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/system/.gitignore b/system/.gitignore new file mode 100644 index 0000000000..42afabfd2a --- /dev/null +++ b/system/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/system/build.gradle.kts b/system/build.gradle.kts new file mode 100644 index 0000000000..89a9f148bb --- /dev/null +++ b/system/build.gradle.kts @@ -0,0 +1,62 @@ +plugins { + alias(libs.plugins.android.library) + alias(libs.plugins.kotlin.android) + alias(libs.plugins.google.devtools.ksp) + alias(libs.plugins.dagger.hilt.android) + alias(libs.plugins.kotlin.serialization) + alias(libs.plugins.kotlin.parcelize) +} + +android { + namespace = "io.github.sds100.keymapper.system" + compileSdk = libs.versions.compile.sdk.get().toInt() + + defaultConfig { + minSdk = libs.versions.min.sdk.get().toInt() + } + + buildTypes { + release { + isMinifyEnabled = true + proguardFiles( + getDefaultProguardFile("proguard-android-optimize.txt"), + "proguard-rules.pro", + ) + } + } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 + } + kotlinOptions { + jvmTarget = "11" + } + + buildFeatures { + aidl = true + } +} + +dependencies { + implementation(project(":common")) + implementation(project(":data")) + implementation(project(":systemstubs")) + + // kotlin stuff + implementation(libs.kotlinx.coroutines.android) + implementation(libs.kotlinx.serialization.json) + + implementation(libs.androidx.core.ktx) + implementation(libs.jakewharton.timber) + implementation(libs.dagger.hilt.android) + ksp(libs.dagger.hilt.android.compiler) + implementation(libs.net.lingala.zip4j) + implementation(libs.lsposed.hiddenapibypass) + implementation(libs.anggrayudi.storage) + implementation(libs.androidx.core.ktx) + implementation(libs.squareup.okhttp) + implementation(libs.rikka.shizuku.api) + implementation(libs.rikka.shizuku.provider) + implementation(libs.androidx.datastore.preferences) + implementation(libs.androidx.preference.ktx) +} diff --git a/system/consumer-rules.pro b/system/consumer-rules.pro new file mode 100644 index 0000000000..e69de29bb2 diff --git a/system/proguard-rules.pro b/system/proguard-rules.pro new file mode 100644 index 0000000000..481bb43481 --- /dev/null +++ b/system/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/system/src/ci/res/values/strings.xml b/system/src/ci/res/values/strings.xml new file mode 100644 index 0000000000..2364c4723b --- /dev/null +++ b/system/src/ci/res/values/strings.xml @@ -0,0 +1,4 @@ + + + Key Mapper CI Basic Input Method + \ No newline at end of file diff --git a/system/src/debug/res/values/strings.xml b/system/src/debug/res/values/strings.xml new file mode 100644 index 0000000000..634c8afe28 --- /dev/null +++ b/system/src/debug/res/values/strings.xml @@ -0,0 +1,4 @@ + + + Key Mapper Debug Basic Input Method + \ No newline at end of file diff --git a/system/src/main/AndroidManifest.xml b/system/src/main/AndroidManifest.xml new file mode 100644 index 0000000000..cf384912b2 --- /dev/null +++ b/system/src/main/AndroidManifest.xml @@ -0,0 +1,101 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/aidl/io/github/sds100/keymapper/api/IKeyEventRelayService.aidl b/system/src/main/aidl/io/github/sds100/keymapper/api/IKeyEventRelayService.aidl similarity index 100% rename from app/src/main/aidl/io/github/sds100/keymapper/api/IKeyEventRelayService.aidl rename to system/src/main/aidl/io/github/sds100/keymapper/api/IKeyEventRelayService.aidl diff --git a/app/src/main/aidl/io/github/sds100/keymapper/api/IKeyEventRelayServiceCallback.aidl b/system/src/main/aidl/io/github/sds100/keymapper/api/IKeyEventRelayServiceCallback.aidl similarity index 100% rename from app/src/main/aidl/io/github/sds100/keymapper/api/IKeyEventRelayServiceCallback.aidl rename to system/src/main/aidl/io/github/sds100/keymapper/api/IKeyEventRelayServiceCallback.aidl diff --git a/app/src/main/java/io/github/sds100/keymapper/system/AndroidSystemFeatureAdapter.kt b/system/src/main/java/io/github/sds100/keymapper/system/AndroidSystemFeatureAdapter.kt similarity index 62% rename from app/src/main/java/io/github/sds100/keymapper/system/AndroidSystemFeatureAdapter.kt rename to system/src/main/java/io/github/sds100/keymapper/system/AndroidSystemFeatureAdapter.kt index d813b1a128..0e92208654 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/AndroidSystemFeatureAdapter.kt +++ b/system/src/main/java/io/github/sds100/keymapper/system/AndroidSystemFeatureAdapter.kt @@ -1,12 +1,15 @@ package io.github.sds100.keymapper.system import android.content.Context +import dagger.hilt.android.qualifiers.ApplicationContext +import javax.inject.Inject +import javax.inject.Singleton import io.github.sds100.keymapper.system.permissions.SystemFeatureAdapter -/** - * Created by sds100 on 17/03/2021. - */ -class AndroidSystemFeatureAdapter(context: Context) : SystemFeatureAdapter { +@Singleton +class AndroidSystemFeatureAdapter @Inject constructor( + @ApplicationContext private val context: Context +) : SystemFeatureAdapter { private val ctx = context.applicationContext override fun hasSystemFeature(feature: String): Boolean = ctx.packageManager.hasSystemFeature(feature) diff --git a/app/src/main/java/io/github/sds100/keymapper/system/DeviceAdmin.kt b/system/src/main/java/io/github/sds100/keymapper/system/DeviceAdmin.kt similarity index 74% rename from app/src/main/java/io/github/sds100/keymapper/system/DeviceAdmin.kt rename to system/src/main/java/io/github/sds100/keymapper/system/DeviceAdmin.kt index 7d29233def..86d1416574 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/DeviceAdmin.kt +++ b/system/src/main/java/io/github/sds100/keymapper/system/DeviceAdmin.kt @@ -2,8 +2,4 @@ package io.github.sds100.keymapper.system import android.app.admin.DeviceAdminReceiver -/** - * Created by sds100 on 31/03/2019. - */ - class DeviceAdmin : DeviceAdminReceiver() diff --git a/app/src/main/java/io/github/sds100/keymapper/system/JobSchedulerHelper.kt b/system/src/main/java/io/github/sds100/keymapper/system/JobSchedulerHelper.kt similarity index 98% rename from app/src/main/java/io/github/sds100/keymapper/system/JobSchedulerHelper.kt rename to system/src/main/java/io/github/sds100/keymapper/system/JobSchedulerHelper.kt index 5f49445425..bbbe2a4d75 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/JobSchedulerHelper.kt +++ b/system/src/main/java/io/github/sds100/keymapper/system/JobSchedulerHelper.kt @@ -13,9 +13,6 @@ import io.github.sds100.keymapper.system.inputmethod.AndroidInputMethodAdapter import io.github.sds100.keymapper.system.inputmethod.ObserveInputMethodsJob import io.github.sds100.keymapper.system.notifications.ObserveNotificationListenersJob -/** - * Created by sds100 on 02/04/2021. - */ object JobSchedulerHelper { private const val ID_OBSERVE_ACCESSIBILITY_SERVICES = 1 diff --git a/app/src/main/java/io/github/sds100/keymapper/system/SettingsUtils.kt b/system/src/main/java/io/github/sds100/keymapper/system/SettingsUtils.kt similarity index 99% rename from app/src/main/java/io/github/sds100/keymapper/system/SettingsUtils.kt rename to system/src/main/java/io/github/sds100/keymapper/system/SettingsUtils.kt index 57d5da1996..6fbe786ccd 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/SettingsUtils.kt +++ b/system/src/main/java/io/github/sds100/keymapper/system/SettingsUtils.kt @@ -5,9 +5,7 @@ import android.content.Context import android.provider.Settings import androidx.annotation.RequiresPermission -/** - * Created by sds100 on 31/01/21. - */ + object SettingsUtils { /** diff --git a/app/src/main/java/io/github/sds100/keymapper/system/Shell.kt b/system/src/main/java/io/github/sds100/keymapper/system/Shell.kt similarity index 56% rename from app/src/main/java/io/github/sds100/keymapper/system/Shell.kt rename to system/src/main/java/io/github/sds100/keymapper/system/Shell.kt index 10b043e54d..1b9d0b7535 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/Shell.kt +++ b/system/src/main/java/io/github/sds100/keymapper/system/Shell.kt @@ -1,20 +1,20 @@ package io.github.sds100.keymapper.system +import io.github.sds100.keymapper.common.utils.KMError +import io.github.sds100.keymapper.common.utils.KMResult +import io.github.sds100.keymapper.common.utils.Success import io.github.sds100.keymapper.system.shell.ShellAdapter -import io.github.sds100.keymapper.util.Error -import io.github.sds100.keymapper.util.Result -import io.github.sds100.keymapper.util.Success import java.io.IOException import java.io.InputStream +import javax.inject.Inject +import javax.inject.Singleton -/** - * Created by sds100 on 05/11/2018. - */ -object Shell : ShellAdapter { +@Singleton +class Shell @Inject constructor() : ShellAdapter { /** * @return whether the command was executed successfully */ - fun run(vararg command: String, waitFor: Boolean = false): Boolean = try { + override fun run(vararg command: String, waitFor: Boolean): Boolean = try { val process = Runtime.getRuntime().exec(command) if (waitFor) { @@ -30,23 +30,21 @@ object Shell : ShellAdapter { * Remember to close it after using it. */ @Throws(IOException::class) - fun getShellCommandStdOut(vararg command: String): InputStream = - Runtime.getRuntime().exec(command).inputStream + override fun getShellCommandStdOut(vararg command: String): InputStream = Runtime.getRuntime().exec(command).inputStream /** * Remember to close it after using it. */ @Throws(IOException::class) - fun getShellCommandStdErr(vararg command: String): InputStream = - Runtime.getRuntime().exec(command).errorStream + fun getShellCommandStdErr(vararg command: String): InputStream = Runtime.getRuntime().exec(command).errorStream - override fun execute(command: String): Result<*> { + override fun execute(command: String): KMResult<*> { try { Runtime.getRuntime().exec(command) return Success(Unit) } catch (e: IOException) { - return Error.Exception(e) + return KMError.Exception(e) } } } diff --git a/system/src/main/java/io/github/sds100/keymapper/system/SystemError.kt b/system/src/main/java/io/github/sds100/keymapper/system/SystemError.kt new file mode 100644 index 0000000000..09a56f818e --- /dev/null +++ b/system/src/main/java/io/github/sds100/keymapper/system/SystemError.kt @@ -0,0 +1,10 @@ +package io.github.sds100.keymapper.system + +import io.github.sds100.keymapper.common.utils.KMError +import io.github.sds100.keymapper.system.inputmethod.ImeInfo +import io.github.sds100.keymapper.system.permissions.Permission + +sealed class SystemError : KMError() { + data class PermissionDenied(val permission: Permission) : KMError() + data class ImeDisabled(val ime: ImeInfo) : KMError() +} diff --git a/system/src/main/java/io/github/sds100/keymapper/system/SystemHiltModule.kt b/system/src/main/java/io/github/sds100/keymapper/system/SystemHiltModule.kt new file mode 100644 index 0000000000..08d09239a9 --- /dev/null +++ b/system/src/main/java/io/github/sds100/keymapper/system/SystemHiltModule.kt @@ -0,0 +1,183 @@ +package io.github.sds100.keymapper.system + +import dagger.Binds +import dagger.Module +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent +import io.github.sds100.keymapper.system.airplanemode.AirplaneModeAdapter +import io.github.sds100.keymapper.system.airplanemode.AndroidAirplaneModeAdapter +import io.github.sds100.keymapper.system.apps.AndroidAppShortcutAdapter +import io.github.sds100.keymapper.system.apps.AndroidPackageManagerAdapter +import io.github.sds100.keymapper.system.apps.AppShortcutAdapter +import io.github.sds100.keymapper.system.apps.PackageManagerAdapter +import io.github.sds100.keymapper.system.bluetooth.AndroidBluetoothAdapter +import io.github.sds100.keymapper.system.bluetooth.BluetoothAdapter +import io.github.sds100.keymapper.system.camera.AndroidCameraAdapter +import io.github.sds100.keymapper.system.camera.CameraAdapter +import io.github.sds100.keymapper.system.clipboard.AndroidClipboardAdapter +import io.github.sds100.keymapper.system.clipboard.ClipboardAdapter +import io.github.sds100.keymapper.system.devices.AndroidDevicesAdapter +import io.github.sds100.keymapper.system.devices.DevicesAdapter +import io.github.sds100.keymapper.system.display.AndroidDisplayAdapter +import io.github.sds100.keymapper.system.display.DisplayAdapter +import io.github.sds100.keymapper.system.files.AndroidFileAdapter +import io.github.sds100.keymapper.system.files.FileAdapter +import io.github.sds100.keymapper.system.inputmethod.AndroidInputMethodAdapter +import io.github.sds100.keymapper.system.inputmethod.InputMethodAdapter +import io.github.sds100.keymapper.system.intents.IntentAdapter +import io.github.sds100.keymapper.system.intents.IntentAdapterImpl +import io.github.sds100.keymapper.system.leanback.LeanbackAdapter +import io.github.sds100.keymapper.system.leanback.LeanbackAdapterImpl +import io.github.sds100.keymapper.system.lock.AndroidLockScreenAdapter +import io.github.sds100.keymapper.system.lock.LockScreenAdapter +import io.github.sds100.keymapper.system.media.AndroidMediaAdapter +import io.github.sds100.keymapper.system.media.MediaAdapter +import io.github.sds100.keymapper.system.network.AndroidNetworkAdapter +import io.github.sds100.keymapper.system.network.NetworkAdapter +import io.github.sds100.keymapper.system.nfc.AndroidNfcAdapter +import io.github.sds100.keymapper.system.nfc.NfcAdapter +import io.github.sds100.keymapper.system.notifications.NotificationReceiverAdapter +import io.github.sds100.keymapper.system.notifications.NotificationReceiverAdapterImpl +import io.github.sds100.keymapper.system.permissions.AndroidPermissionAdapter +import io.github.sds100.keymapper.system.permissions.PermissionAdapter +import io.github.sds100.keymapper.system.permissions.SystemFeatureAdapter +import io.github.sds100.keymapper.system.phone.AndroidPhoneAdapter +import io.github.sds100.keymapper.system.phone.PhoneAdapter +import io.github.sds100.keymapper.system.popup.AndroidToastAdapter +import io.github.sds100.keymapper.system.popup.ToastAdapter +import io.github.sds100.keymapper.system.power.AndroidPowerAdapter +import io.github.sds100.keymapper.system.power.PowerAdapter +import io.github.sds100.keymapper.system.ringtones.AndroidRingtoneAdapter +import io.github.sds100.keymapper.system.ringtones.RingtoneAdapter +import io.github.sds100.keymapper.system.root.SuAdapter +import io.github.sds100.keymapper.system.root.SuAdapterImpl +import io.github.sds100.keymapper.system.shell.ShellAdapter +import io.github.sds100.keymapper.system.shizuku.ShizukuAdapter +import io.github.sds100.keymapper.system.shizuku.ShizukuAdapterImpl +import io.github.sds100.keymapper.system.url.AndroidOpenUrlAdapter +import io.github.sds100.keymapper.system.url.OpenUrlAdapter +import io.github.sds100.keymapper.system.vibrator.AndroidVibratorAdapter +import io.github.sds100.keymapper.system.vibrator.VibratorAdapter +import io.github.sds100.keymapper.system.volume.AndroidVolumeAdapter +import io.github.sds100.keymapper.system.volume.VolumeAdapter +import javax.inject.Singleton + +@Module +@InstallIn(SingletonComponent::class) +abstract class SystemHiltModule { + @Singleton + @Binds + abstract fun provideLockscreenAdapter(impl: AndroidLockScreenAdapter): LockScreenAdapter + + @Singleton + @Binds + abstract fun provideAirplaneModeAdapter(impl: AndroidAirplaneModeAdapter): AirplaneModeAdapter + + @Singleton + @Binds + abstract fun provideAppShortcutAdapter(impl: AndroidAppShortcutAdapter): AppShortcutAdapter + + @Singleton + @Binds + abstract fun providePackageManagerAdapter(impl: AndroidPackageManagerAdapter): PackageManagerAdapter + + @Singleton + @Binds + abstract fun provideBluetoothAdapter(impl: AndroidBluetoothAdapter): BluetoothAdapter + + @Singleton + @Binds + abstract fun provideCameraAdapter(impl: AndroidCameraAdapter): CameraAdapter + + @Singleton + @Binds + abstract fun provideClipboardAdapter(impl: AndroidClipboardAdapter): ClipboardAdapter + + @Singleton + @Binds + abstract fun provideDevicesAdapter(impl: AndroidDevicesAdapter): DevicesAdapter + + @Singleton + @Binds + abstract fun provideDisplayAdapter(impl: AndroidDisplayAdapter): DisplayAdapter + + @Singleton + @Binds + abstract fun provideFileAdapter(impl: AndroidFileAdapter): FileAdapter + + @Singleton + @Binds + abstract fun provideInputMethodAdapter(impl: AndroidInputMethodAdapter): InputMethodAdapter + + @Singleton + @Binds + abstract fun provideIntentAdapter(impl: IntentAdapterImpl): IntentAdapter + + @Singleton + @Binds + abstract fun provideLeanbackAdapter(impl: LeanbackAdapterImpl): LeanbackAdapter + + @Singleton + @Binds + abstract fun provideMediaAdapter(impl: AndroidMediaAdapter): MediaAdapter + + @Singleton + @Binds + abstract fun provideNetworkAdapter(impl: AndroidNetworkAdapter): NetworkAdapter + + @Singleton + @Binds + abstract fun provideNfcAdapter(impl: AndroidNfcAdapter): NfcAdapter + + @Singleton + @Binds + abstract fun providePermissionAdapter(impl: AndroidPermissionAdapter): PermissionAdapter + + @Singleton + @Binds + abstract fun providePhoneAdapter(impl: AndroidPhoneAdapter): PhoneAdapter + + @Singleton + @Binds + abstract fun providePopupMessageAdapter(impl: AndroidToastAdapter): ToastAdapter + + @Singleton + @Binds + abstract fun providePowerAdapter(impl: AndroidPowerAdapter): PowerAdapter + + @Singleton + @Binds + abstract fun provideRingtoneAdapter(impl: AndroidRingtoneAdapter): RingtoneAdapter + + @Singleton + @Binds + abstract fun provideSuAdapter(impl: SuAdapterImpl): SuAdapter + + @Singleton + @Binds + abstract fun provideOpenUrlAdapter(impl: AndroidOpenUrlAdapter): OpenUrlAdapter + + @Singleton + @Binds + abstract fun provideVibratorAdapter(impl: AndroidVibratorAdapter): VibratorAdapter + + @Singleton + @Binds + abstract fun provideVolumeAdapter(impl: AndroidVolumeAdapter): VolumeAdapter + + @Singleton + @Binds + abstract fun provideShellAdapter(impl: Shell): ShellAdapter + + @Singleton + @Binds + abstract fun provideShizukuAdapter(impl: ShizukuAdapterImpl): ShizukuAdapter + + @Singleton + @Binds + abstract fun provideNotificationReceiverAdapter(impl: NotificationReceiverAdapterImpl): NotificationReceiverAdapter + + @Singleton + @Binds + abstract fun provideSystemFeatureAdapter(impl: AndroidSystemFeatureAdapter): SystemFeatureAdapter +} diff --git a/app/src/main/java/io/github/sds100/keymapper/system/accessibility/ServiceAdapter.kt b/system/src/main/java/io/github/sds100/keymapper/system/accessibility/AccessibilityServiceAdapter.kt similarity index 69% rename from app/src/main/java/io/github/sds100/keymapper/system/accessibility/ServiceAdapter.kt rename to system/src/main/java/io/github/sds100/keymapper/system/accessibility/AccessibilityServiceAdapter.kt index 8eea14db6c..b3c4c68464 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/accessibility/ServiceAdapter.kt +++ b/system/src/main/java/io/github/sds100/keymapper/system/accessibility/AccessibilityServiceAdapter.kt @@ -1,15 +1,12 @@ package io.github.sds100.keymapper.system.accessibility -import io.github.sds100.keymapper.util.Result -import io.github.sds100.keymapper.util.ServiceEvent +import io.github.sds100.keymapper.common.utils.KMResult import kotlinx.coroutines.flow.SharedFlow import kotlinx.coroutines.flow.StateFlow -/** - * Created by sds100 on 17/03/2021. - */ -interface ServiceAdapter { - val state: StateFlow +interface AccessibilityServiceAdapter { + val state: StateFlow + fun invalidateState() /** * @return Whether the service could be started successfully. @@ -32,16 +29,16 @@ interface ServiceAdapter { /** * Send an event to the service. */ - suspend fun send(event: ServiceEvent): Result<*> + suspend fun send(event: AccessibilityServiceEvent): KMResult<*> /** * Send an event to the service asynchronously. This method * will return immediately and you won't be notified of whether it is sent. */ - fun sendAsync(event: ServiceEvent) + fun sendAsync(event: AccessibilityServiceEvent) /** * A flow of events coming from the service. */ - val eventReceiver: SharedFlow + val eventReceiver: SharedFlow } diff --git a/system/src/main/java/io/github/sds100/keymapper/system/accessibility/AccessibilityServiceEvent.kt b/system/src/main/java/io/github/sds100/keymapper/system/accessibility/AccessibilityServiceEvent.kt new file mode 100644 index 0000000000..0c6fa47668 --- /dev/null +++ b/system/src/main/java/io/github/sds100/keymapper/system/accessibility/AccessibilityServiceEvent.kt @@ -0,0 +1,38 @@ +package io.github.sds100.keymapper.system.accessibility + +import kotlinx.serialization.Serializable + +@Serializable +abstract class AccessibilityServiceEvent { + + @Serializable + data class Ping(val key: String) : AccessibilityServiceEvent() + + @Serializable + data class Pong(val key: String) : AccessibilityServiceEvent() + + @Serializable + data object OnHideKeyboardEvent : AccessibilityServiceEvent() + + @Serializable + data object OnShowKeyboardEvent : AccessibilityServiceEvent() + + @Serializable + data object HideKeyboard : AccessibilityServiceEvent() + + @Serializable + data object ShowKeyboard : AccessibilityServiceEvent() + + @Serializable + data class ChangeIme(val imeId: String) : AccessibilityServiceEvent() + + @Serializable + data object DisableService : AccessibilityServiceEvent() + + @Serializable + data class OnInputFocusChange(val isFocussed: Boolean) : AccessibilityServiceEvent() + + @Serializable + data class EnableInputMethod(val imeId: String) : AccessibilityServiceEvent() + +} diff --git a/app/src/main/java/io/github/sds100/keymapper/system/accessibility/ServiceState.kt b/system/src/main/java/io/github/sds100/keymapper/system/accessibility/AccessibilityServiceState.kt similarity index 58% rename from app/src/main/java/io/github/sds100/keymapper/system/accessibility/ServiceState.kt rename to system/src/main/java/io/github/sds100/keymapper/system/accessibility/AccessibilityServiceState.kt index 0e417ef809..f762a294b5 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/accessibility/ServiceState.kt +++ b/system/src/main/java/io/github/sds100/keymapper/system/accessibility/AccessibilityServiceState.kt @@ -1,9 +1,7 @@ package io.github.sds100.keymapper.system.accessibility -/** - * Created by sds100 on 09/05/2021. - */ -enum class ServiceState { + +enum class AccessibilityServiceState { ENABLED, CRASHED, DISABLED, diff --git a/app/src/main/java/io/github/sds100/keymapper/system/accessibility/ObserveEnabledAccessibilityServicesJob.kt b/system/src/main/java/io/github/sds100/keymapper/system/accessibility/ObserveEnabledAccessibilityServicesJob.kt similarity index 71% rename from app/src/main/java/io/github/sds100/keymapper/system/accessibility/ObserveEnabledAccessibilityServicesJob.kt rename to system/src/main/java/io/github/sds100/keymapper/system/accessibility/ObserveEnabledAccessibilityServicesJob.kt index a51bceac3f..7ea2ade895 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/accessibility/ObserveEnabledAccessibilityServicesJob.kt +++ b/system/src/main/java/io/github/sds100/keymapper/system/accessibility/ObserveEnabledAccessibilityServicesJob.kt @@ -3,15 +3,19 @@ package io.github.sds100.keymapper.system.accessibility import android.app.job.JobParameters import android.app.job.JobService import android.os.Build -import io.github.sds100.keymapper.KeyMapperApp +import dagger.hilt.android.AndroidEntryPoint import io.github.sds100.keymapper.system.JobSchedulerHelper +import javax.inject.Inject -/** - * Created by sds100 on 02/04/2021. - */ +@AndroidEntryPoint class ObserveEnabledAccessibilityServicesJob : JobService() { + + @Inject + lateinit var accessibilityServiceAdapter: AccessibilityServiceAdapter + override fun onStartJob(params: JobParameters?): Boolean { - (application!! as KeyMapperApp).accessibilityServiceAdapter.updateWhetherServiceIsEnabled() + accessibilityServiceAdapter.invalidateState() + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { JobSchedulerHelper.observeEnabledAccessibilityServices(application!!) } diff --git a/system/src/main/java/io/github/sds100/keymapper/system/airplanemode/AirplaneModeAdapter.kt b/system/src/main/java/io/github/sds100/keymapper/system/airplanemode/AirplaneModeAdapter.kt new file mode 100644 index 0000000000..6c38f9f3a4 --- /dev/null +++ b/system/src/main/java/io/github/sds100/keymapper/system/airplanemode/AirplaneModeAdapter.kt @@ -0,0 +1,9 @@ +package io.github.sds100.keymapper.system.airplanemode + +import io.github.sds100.keymapper.common.utils.KMResult + +interface AirplaneModeAdapter { + fun isEnabled(): Boolean + fun enable(): KMResult<*> + fun disable(): KMResult<*> +} diff --git a/app/src/main/java/io/github/sds100/keymapper/system/airplanemode/AndroidAirplaneModeAdapter.kt b/system/src/main/java/io/github/sds100/keymapper/system/airplanemode/AndroidAirplaneModeAdapter.kt similarity index 68% rename from app/src/main/java/io/github/sds100/keymapper/system/airplanemode/AndroidAirplaneModeAdapter.kt rename to system/src/main/java/io/github/sds100/keymapper/system/airplanemode/AndroidAirplaneModeAdapter.kt index 8eaa251118..df7c4a7c5c 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/airplanemode/AndroidAirplaneModeAdapter.kt +++ b/system/src/main/java/io/github/sds100/keymapper/system/airplanemode/AndroidAirplaneModeAdapter.kt @@ -2,26 +2,27 @@ package io.github.sds100.keymapper.system.airplanemode import android.content.Context import android.provider.Settings +import io.github.sds100.keymapper.common.utils.KMResult +import io.github.sds100.keymapper.common.utils.onSuccess import io.github.sds100.keymapper.system.SettingsUtils import io.github.sds100.keymapper.system.root.SuAdapter -import io.github.sds100.keymapper.util.Result -import io.github.sds100.keymapper.util.onSuccess +import dagger.hilt.android.qualifiers.ApplicationContext +import javax.inject.Inject +import javax.inject.Singleton -/** - * Created by sds100 on 24/04/2021. - */ -class AndroidAirplaneModeAdapter( - context: Context, +@Singleton +class AndroidAirplaneModeAdapter @Inject constructor( + @ApplicationContext private val context: Context, val suAdapter: SuAdapter, ) : AirplaneModeAdapter { private val ctx = context.applicationContext - override fun enable(): Result<*> = + override fun enable(): KMResult<*> = suAdapter.execute("settings put global airplane_mode_on 1").onSuccess { broadcastAirplaneModeChanged(false) } - override fun disable(): Result<*> = + override fun disable(): KMResult<*> = suAdapter.execute("settings put global airplane_mode_on 0").onSuccess { broadcastAirplaneModeChanged(false) } diff --git a/app/src/main/java/io/github/sds100/keymapper/system/apps/ActivityInfo.kt b/system/src/main/java/io/github/sds100/keymapper/system/apps/ActivityInfo.kt similarity index 80% rename from app/src/main/java/io/github/sds100/keymapper/system/apps/ActivityInfo.kt rename to system/src/main/java/io/github/sds100/keymapper/system/apps/ActivityInfo.kt index 3b4e73e3b8..3504e71246 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/apps/ActivityInfo.kt +++ b/system/src/main/java/io/github/sds100/keymapper/system/apps/ActivityInfo.kt @@ -2,10 +2,6 @@ package io.github.sds100.keymapper.system.apps import kotlinx.serialization.Serializable -/** - * Created by sds100 on 15/03/2021. - */ - @Serializable data class ActivityInfo( val activityName: String, diff --git a/app/src/main/java/io/github/sds100/keymapper/system/apps/AndroidAppShortcutAdapter.kt b/system/src/main/java/io/github/sds100/keymapper/system/apps/AndroidAppShortcutAdapter.kt similarity index 77% rename from app/src/main/java/io/github/sds100/keymapper/system/apps/AndroidAppShortcutAdapter.kt rename to system/src/main/java/io/github/sds100/keymapper/system/apps/AndroidAppShortcutAdapter.kt index 15e070668d..69072392a7 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/apps/AndroidAppShortcutAdapter.kt +++ b/system/src/main/java/io/github/sds100/keymapper/system/apps/AndroidAppShortcutAdapter.kt @@ -13,20 +13,23 @@ import androidx.core.content.pm.ShortcutInfoCompat import androidx.core.content.pm.ShortcutManagerCompat import androidx.core.graphics.drawable.IconCompat import androidx.core.graphics.drawable.toBitmap -import io.github.sds100.keymapper.api.LaunchKeyMapShortcutActivity -import io.github.sds100.keymapper.util.Error -import io.github.sds100.keymapper.util.Result -import io.github.sds100.keymapper.util.State -import io.github.sds100.keymapper.util.Success -import io.github.sds100.keymapper.util.success +import dagger.hilt.android.qualifiers.ApplicationContext +import io.github.sds100.keymapper.common.utils.KMError +import io.github.sds100.keymapper.common.utils.KMResult +import io.github.sds100.keymapper.common.utils.State +import io.github.sds100.keymapper.common.utils.Success +import io.github.sds100.keymapper.common.utils.success import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.flow import java.util.UUID - -/** - * Created by sds100 on 20/03/2021. - */ -class AndroidAppShortcutAdapter(context: Context) : AppShortcutAdapter { +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class AndroidAppShortcutAdapter @Inject constructor( + @ApplicationContext private val context: Context, + private val keyMapShortcutActivityIntentBuilder: KeyMapShortcutActivityIntentBuilder, +) : AppShortcutAdapter { private val ctx = context.applicationContext override val installedAppShortcuts: Flow>> = flow { @@ -86,24 +89,18 @@ class AndroidAppShortcutAdapter(context: Context) : AppShortcutAdapter { val builder = ShortcutInfoCompat.Builder(ctx, UUID.randomUUID().toString()).apply { setIcon(icon) setShortLabel(label) - - Intent(ctx, LaunchKeyMapShortcutActivity::class.java).apply { - action = intentAction - - putExtras(intentExtras) - - setIntent(this) - } + val intent = keyMapShortcutActivityIntentBuilder.build(intentAction, intentExtras) + setIntent(intent) } return builder.build() } - override fun pinShortcut(shortcut: ShortcutInfoCompat): Result<*> { + override fun pinShortcut(shortcut: ShortcutInfoCompat): KMResult<*> { val supported = ShortcutManagerCompat.requestPinShortcut(ctx, shortcut, null) if (!supported) { - return Error.LauncherShortcutsNotSupported + return KMError.LauncherShortcutsNotSupported } else { return Success(Unit) } @@ -111,7 +108,7 @@ class AndroidAppShortcutAdapter(context: Context) : AppShortcutAdapter { override fun createShortcutResultIntent(shortcut: ShortcutInfoCompat): Intent = ShortcutManagerCompat.createShortcutResultIntent(ctx, shortcut) - override fun getShortcutName(info: AppShortcutInfo): Result { + override fun getShortcutName(info: AppShortcutInfo): KMResult { try { return ctx.packageManager .getActivityInfo(ComponentName(info.packageName, info.activityName), 0) @@ -119,22 +116,22 @@ class AndroidAppShortcutAdapter(context: Context) : AppShortcutAdapter { .toString() .success() } catch (e: PackageManager.NameNotFoundException) { - return Error.AppNotFound(info.packageName) + return KMError.AppNotFound(info.packageName) } } - override fun getShortcutIcon(info: AppShortcutInfo): Result { + override fun getShortcutIcon(info: AppShortcutInfo): KMResult { try { return ctx.packageManager .getActivityInfo(ComponentName(info.packageName, info.activityName), 0) .loadIcon(ctx.packageManager) .success() } catch (e: PackageManager.NameNotFoundException) { - return Error.AppNotFound(info.packageName) + return KMError.AppNotFound(info.packageName) } } - override fun launchShortcut(uri: String): Result<*> { + override fun launchShortcut(uri: String): KMResult<*> { val intent = Intent.parseUri(uri, 0) intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) @@ -160,9 +157,9 @@ class AndroidAppShortcutAdapter(context: Context) : AppShortcutAdapter { return Success(Unit) } catch (e: SecurityException) { - return Error.InsufficientPermissionsToOpenAppShortcut + return KMError.InsufficientPermissionsToOpenAppShortcut } catch (e: Exception) { - return Error.AppShortcutCantBeOpened + return KMError.AppShortcutCantBeOpened } } } diff --git a/app/src/main/java/io/github/sds100/keymapper/system/apps/AndroidPackageManagerAdapter.kt b/system/src/main/java/io/github/sds100/keymapper/system/apps/AndroidPackageManagerAdapter.kt similarity index 86% rename from app/src/main/java/io/github/sds100/keymapper/system/apps/AndroidPackageManagerAdapter.kt rename to system/src/main/java/io/github/sds100/keymapper/system/apps/AndroidPackageManagerAdapter.kt index de6061a27c..f28b595ea0 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/apps/AndroidPackageManagerAdapter.kt +++ b/system/src/main/java/io/github/sds100/keymapper/system/apps/AndroidPackageManagerAdapter.kt @@ -15,17 +15,18 @@ import android.graphics.drawable.Drawable import android.net.Uri import android.os.BadParcelableException import android.os.Build -import android.os.DeadSystemException +import android.os.RemoteException import android.os.TransactionTooLargeException import android.provider.MediaStore import android.provider.Settings import androidx.core.content.ContextCompat import androidx.core.content.pm.PackageInfoCompat -import io.github.sds100.keymapper.util.Error -import io.github.sds100.keymapper.util.Result -import io.github.sds100.keymapper.util.State -import io.github.sds100.keymapper.util.Success -import io.github.sds100.keymapper.util.success +import dagger.hilt.android.qualifiers.ApplicationContext +import io.github.sds100.keymapper.common.utils.KMError +import io.github.sds100.keymapper.common.utils.KMResult +import io.github.sds100.keymapper.common.utils.State +import io.github.sds100.keymapper.common.utils.Success +import io.github.sds100.keymapper.common.utils.success import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.MutableSharedFlow @@ -35,14 +36,13 @@ import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.map import kotlinx.coroutines.launch import kotlinx.coroutines.withContext -import splitties.bitflags.withFlag import java.io.IOException +import javax.inject.Inject +import javax.inject.Singleton -/** - * Created by sds100 on 16/03/2021. - */ -class AndroidPackageManagerAdapter( - context: Context, +@Singleton +class AndroidPackageManagerAdapter @Inject constructor( + @ApplicationContext context: Context, coroutineScope: CoroutineScope, ) : PackageManagerAdapter { private val ctx: Context = context.applicationContext @@ -101,7 +101,7 @@ class AndroidPackageManagerAdapter( .mapNotNull { createPackageInfoModel(it) } } catch (_: BadParcelableException) { emptyList() - } catch (_: DeadSystemException) { + } catch (_: RemoteException) { emptyList() } } @@ -141,7 +141,7 @@ class AndroidPackageManagerAdapter( } } - override fun launchVoiceAssistant(): Result<*> { + override fun launchVoiceAssistant(): KMResult<*> { try { Intent(Intent.ACTION_VOICE_COMMAND).apply { flags = Intent.FLAG_ACTIVITY_NEW_TASK @@ -150,11 +150,11 @@ class AndroidPackageManagerAdapter( return Success(Unit) } catch (e: ActivityNotFoundException) { - return Error.NoVoiceAssistant + return KMError.NoVoiceAssistant } } - override fun launchDeviceAssistant(): Result<*> { + override fun launchDeviceAssistant(): KMResult<*> { try { Intent(Intent.ACTION_ASSIST).apply { flags = Intent.FLAG_ACTIVITY_NEW_TASK @@ -163,15 +163,15 @@ class AndroidPackageManagerAdapter( return Success(Unit) } catch (e: ActivityNotFoundException) { - return Error.NoDeviceAssistant + return KMError.NoDeviceAssistant } } - override fun getDeviceAssistantPackage(): Result { + override fun getDeviceAssistantPackage(): KMResult { val settingValue = Settings.Secure.getString(ctx.contentResolver, "assistant") if (settingValue.isNullOrEmpty()) { - return Error.NoDeviceAssistant + return KMError.NoDeviceAssistant } val packageName = settingValue.split("/").first() @@ -181,13 +181,13 @@ class AndroidPackageManagerAdapter( override fun enableApp(packageName: String) { Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply { data = Uri.parse("package:$packageName") - flags = Intent.FLAG_ACTIVITY_NO_HISTORY.withFlag(Intent.FLAG_ACTIVITY_NEW_TASK) + flags = Intent.FLAG_ACTIVITY_NO_HISTORY or Intent.FLAG_ACTIVITY_NEW_TASK ctx.startActivity(this) } } - override fun isAppEnabled(packageName: String): Result { + override fun isAppEnabled(packageName: String): KMResult { when (val packagesState = installedPackages.value) { is State.Data -> { val packages = packagesState.data @@ -195,7 +195,7 @@ class AndroidPackageManagerAdapter( val appPackage = packages.find { it.packageName == packageName } if (appPackage == null) { - return Error.AppNotFound(packageName) + return KMError.AppNotFound(packageName) } else { return Success(appPackage.isEnabled) } @@ -204,7 +204,7 @@ class AndroidPackageManagerAdapter( State.Loading -> return try { Success(packageManager.getApplicationInfo(packageName, 0).enabled) } catch (e: PackageManager.NameNotFoundException) { - Error.AppNotFound(packageName) + KMError.AppNotFound(packageName) } } } @@ -229,7 +229,7 @@ class AndroidPackageManagerAdapter( } @SuppressLint("UnspecifiedImmutableFlag") // only specify the flag on SDK 23+. SDK 31 is first to enforce it. - override fun openApp(packageName: String): Result<*> { + override fun openApp(packageName: String): KMResult<*> { val leanbackIntent = packageManager.getLeanbackLaunchIntentForPackage(packageName) val normalIntent = packageManager.getLaunchIntentForPackage(packageName) @@ -242,12 +242,12 @@ class AndroidPackageManagerAdapter( // if the app is disabled, show an error message because it won't open if (!appInfo.enabled) { - return Error.AppDisabled(packageName) + return KMError.AppDisabled(packageName) } return Success(Unit) } catch (e: Exception) { - return Error.AppNotFound(packageName) + return KMError.AppNotFound(packageName) } } else { val pendingIntent = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { @@ -279,7 +279,7 @@ class AndroidPackageManagerAdapter( return activityExists } - override fun launchCameraApp(): Result<*> { + override fun launchCameraApp(): KMResult<*> { try { /** * See this guide on how the camera is launched with double press power button in @@ -304,12 +304,12 @@ class AndroidPackageManagerAdapter( return Success(Unit) } catch (e: ActivityNotFoundException) { - return Error.NoCameraApp + return KMError.NoCameraApp } } } - override fun launchSettingsApp(): Result<*> { + override fun launchSettingsApp(): KMResult<*> { try { Intent(Settings.ACTION_SETTINGS).apply { flags = Intent.FLAG_ACTIVITY_NEW_TASK @@ -318,7 +318,7 @@ class AndroidPackageManagerAdapter( return Success(Unit) } catch (e: ActivityNotFoundException) { - return Error.NoSettingsApp + return KMError.NoSettingsApp } } @@ -333,7 +333,7 @@ class AndroidPackageManagerAdapter( } } - override fun getAppName(packageName: String): Result { + override fun getAppName(packageName: String): KMResult { try { return packageManager .getApplicationInfo(packageName, 0) @@ -341,26 +341,26 @@ class AndroidPackageManagerAdapter( .toString() .success() } catch (e: PackageManager.NameNotFoundException) { - return Error.AppNotFound(packageName) + return KMError.AppNotFound(packageName) } catch (e: IOException) { - return Error.AppNotFound(packageName) + return KMError.AppNotFound(packageName) } } - override fun getAppIcon(packageName: String): Result { + override fun getAppIcon(packageName: String): KMResult { try { return packageManager .getApplicationInfo(packageName, 0) .loadIcon(packageManager) .success() } catch (e: PackageManager.NameNotFoundException) { - return Error.AppNotFound(packageName) + return KMError.AppNotFound(packageName) } catch (e: IOException) { - return Error.AppNotFound(packageName) + return KMError.AppNotFound(packageName) } } - override fun getActivityLabel(packageName: String, activityClass: String): Result { + override fun getActivityLabel(packageName: String, activityClass: String): KMResult { try { val component = ComponentName(packageName, activityClass) @@ -370,11 +370,11 @@ class AndroidPackageManagerAdapter( .toString() .success() } catch (e: PackageManager.NameNotFoundException) { - return Error.AppNotFound(packageName) + return KMError.AppNotFound(packageName) } } - override fun getActivityIcon(packageName: String, activityClass: String): Result { + override fun getActivityIcon(packageName: String, activityClass: String): KMResult { try { val component = ComponentName(packageName, activityClass) @@ -383,7 +383,7 @@ class AndroidPackageManagerAdapter( .loadIcon(packageManager) .success() } catch (e: PackageManager.NameNotFoundException) { - return Error.AppNotFound(packageName) + return KMError.AppNotFound(packageName) } } diff --git a/app/src/main/java/io/github/sds100/keymapper/system/apps/AppShortcutAdapter.kt b/system/src/main/java/io/github/sds100/keymapper/system/apps/AppShortcutAdapter.kt similarity index 67% rename from app/src/main/java/io/github/sds100/keymapper/system/apps/AppShortcutAdapter.kt rename to system/src/main/java/io/github/sds100/keymapper/system/apps/AppShortcutAdapter.kt index 1e418d5b27..724cc4a17d 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/apps/AppShortcutAdapter.kt +++ b/system/src/main/java/io/github/sds100/keymapper/system/apps/AppShortcutAdapter.kt @@ -4,14 +4,10 @@ import android.content.Intent import android.graphics.drawable.Drawable import android.os.Bundle import androidx.core.content.pm.ShortcutInfoCompat -import io.github.sds100.keymapper.util.Result -import io.github.sds100.keymapper.util.State +import io.github.sds100.keymapper.common.utils.KMResult +import io.github.sds100.keymapper.common.utils.State import kotlinx.coroutines.flow.Flow -/** - * Created by sds100 on 20/03/2021. - */ - interface AppShortcutAdapter { val installedAppShortcuts: Flow>> val areLauncherShortcutsSupported: Boolean @@ -30,10 +26,10 @@ interface AppShortcutAdapter { intentExtras: Bundle, ): ShortcutInfoCompat - fun pinShortcut(shortcut: ShortcutInfoCompat): Result<*> + fun pinShortcut(shortcut: ShortcutInfoCompat): KMResult<*> fun createShortcutResultIntent(shortcut: ShortcutInfoCompat): Intent - fun getShortcutName(info: AppShortcutInfo): Result - fun getShortcutIcon(info: AppShortcutInfo): Result - fun launchShortcut(uri: String): Result<*> + fun getShortcutName(info: AppShortcutInfo): KMResult + fun getShortcutIcon(info: AppShortcutInfo): KMResult + fun launchShortcut(uri: String): KMResult<*> } diff --git a/app/src/main/java/io/github/sds100/keymapper/system/apps/AppShortcutInfo.kt b/system/src/main/java/io/github/sds100/keymapper/system/apps/AppShortcutInfo.kt similarity index 75% rename from app/src/main/java/io/github/sds100/keymapper/system/apps/AppShortcutInfo.kt rename to system/src/main/java/io/github/sds100/keymapper/system/apps/AppShortcutInfo.kt index fa8b87f1ac..2b2bbc45e7 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/apps/AppShortcutInfo.kt +++ b/system/src/main/java/io/github/sds100/keymapper/system/apps/AppShortcutInfo.kt @@ -1,8 +1,5 @@ package io.github.sds100.keymapper.system.apps -/** - * Created by sds100 on 23/03/2021. - */ data class AppShortcutInfo( val packageName: String, val activityName: String, diff --git a/system/src/main/java/io/github/sds100/keymapper/system/apps/KeyMapShortcutActivityIntentBuilder.kt b/system/src/main/java/io/github/sds100/keymapper/system/apps/KeyMapShortcutActivityIntentBuilder.kt new file mode 100644 index 0000000000..b25a2cac13 --- /dev/null +++ b/system/src/main/java/io/github/sds100/keymapper/system/apps/KeyMapShortcutActivityIntentBuilder.kt @@ -0,0 +1,11 @@ +package io.github.sds100.keymapper.system.apps + +import android.content.Intent +import android.os.Bundle + +interface KeyMapShortcutActivityIntentBuilder { + fun build( + intentAction: String, + intentExtras: Bundle, + ): Intent +} diff --git a/app/src/main/java/io/github/sds100/keymapper/system/apps/PackageInfo.kt b/system/src/main/java/io/github/sds100/keymapper/system/apps/PackageInfo.kt similarity index 86% rename from app/src/main/java/io/github/sds100/keymapper/system/apps/PackageInfo.kt rename to system/src/main/java/io/github/sds100/keymapper/system/apps/PackageInfo.kt index 42686f9f7a..d5fedd7bdb 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/apps/PackageInfo.kt +++ b/system/src/main/java/io/github/sds100/keymapper/system/apps/PackageInfo.kt @@ -1,8 +1,6 @@ package io.github.sds100.keymapper.system.apps -/** - * Created by sds100 on 16/03/2021. - */ + data class PackageInfo( val packageName: String, diff --git a/app/src/main/java/io/github/sds100/keymapper/system/apps/PackageManagerAdapter.kt b/system/src/main/java/io/github/sds100/keymapper/system/apps/PackageManagerAdapter.kt similarity index 65% rename from app/src/main/java/io/github/sds100/keymapper/system/apps/PackageManagerAdapter.kt rename to system/src/main/java/io/github/sds100/keymapper/system/apps/PackageManagerAdapter.kt index bc93c32399..6e61c822cf 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/apps/PackageManagerAdapter.kt +++ b/system/src/main/java/io/github/sds100/keymapper/system/apps/PackageManagerAdapter.kt @@ -1,38 +1,36 @@ package io.github.sds100.keymapper.system.apps import android.graphics.drawable.Drawable -import io.github.sds100.keymapper.util.Result -import io.github.sds100.keymapper.util.State +import io.github.sds100.keymapper.common.utils.KMResult +import io.github.sds100.keymapper.common.utils.State import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.callbackFlow -/** - * Created by sds100 on 26/02/2021. - */ + interface PackageManagerAdapter { val onPackagesChanged: Flow val installedPackages: StateFlow>> - fun getAppName(packageName: String): Result - fun getAppIcon(packageName: String): Result + fun getAppName(packageName: String): KMResult + fun getAppIcon(packageName: String): KMResult fun getPackageInfo(packageName: String): PackageInfo? - fun getActivityLabel(packageName: String, activityClass: String): Result - fun getActivityIcon(packageName: String, activityClass: String): Result - fun isAppEnabled(packageName: String): Result + fun getActivityLabel(packageName: String, activityClass: String): KMResult + fun getActivityIcon(packageName: String, activityClass: String): KMResult + fun isAppEnabled(packageName: String): KMResult fun isAppInstalled(packageName: String): Boolean - fun openApp(packageName: String): Result<*> + fun openApp(packageName: String): KMResult<*> fun enableApp(packageName: String) fun downloadApp(packageName: String) - fun launchVoiceAssistant(): Result<*> - fun launchDeviceAssistant(): Result<*> + fun launchVoiceAssistant(): KMResult<*> + fun launchDeviceAssistant(): KMResult<*> fun isVoiceAssistantInstalled(): Boolean - fun getDeviceAssistantPackage(): Result + fun getDeviceAssistantPackage(): KMResult - fun launchCameraApp(): Result<*> - fun launchSettingsApp(): Result<*> + fun launchCameraApp(): KMResult<*> + fun launchSettingsApp(): KMResult<*> } fun PackageManagerAdapter.isAppInstalledFlow(packageName: String): Flow = callbackFlow { diff --git a/app/src/main/java/io/github/sds100/keymapper/system/bluetooth/AndroidBluetoothAdapter.kt b/system/src/main/java/io/github/sds100/keymapper/system/bluetooth/AndroidBluetoothAdapter.kt similarity index 87% rename from app/src/main/java/io/github/sds100/keymapper/system/bluetooth/AndroidBluetoothAdapter.kt rename to system/src/main/java/io/github/sds100/keymapper/system/bluetooth/AndroidBluetoothAdapter.kt index 9c0bd14f65..942f313e6d 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/bluetooth/AndroidBluetoothAdapter.kt +++ b/system/src/main/java/io/github/sds100/keymapper/system/bluetooth/AndroidBluetoothAdapter.kt @@ -10,20 +10,20 @@ import android.content.IntentFilter import android.content.pm.PackageManager import androidx.core.content.ContextCompat import androidx.core.content.getSystemService -import io.github.sds100.keymapper.util.Error -import io.github.sds100.keymapper.util.Result -import io.github.sds100.keymapper.util.Success +import io.github.sds100.keymapper.common.utils.KMError +import io.github.sds100.keymapper.common.utils.KMResult +import io.github.sds100.keymapper.common.utils.Success import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.launch +import dagger.hilt.android.qualifiers.ApplicationContext +import javax.inject.Inject +import javax.inject.Singleton -/** - * Created by sds100 on 14/02/2021. - */ - -class AndroidBluetoothAdapter( - context: Context, +@Singleton +class AndroidBluetoothAdapter @Inject constructor( + @ApplicationContext private val context: Context, private val coroutineScope: CoroutineScope, ) : io.github.sds100.keymapper.system.bluetooth.BluetoothAdapter { @@ -129,9 +129,9 @@ class AndroidBluetoothAdapter( } } - override fun enable(): Result<*> { + override fun enable(): KMResult<*> { if (adapter == null) { - return Error.SystemFeatureNotSupported(PackageManager.FEATURE_BLUETOOTH) + return KMError.SystemFeatureNotSupported(PackageManager.FEATURE_BLUETOOTH) } adapter.enable() @@ -139,9 +139,9 @@ class AndroidBluetoothAdapter( return Success(Unit) } - override fun disable(): Result<*> { + override fun disable(): KMResult<*> { if (adapter == null) { - return Error.SystemFeatureNotSupported(PackageManager.FEATURE_BLUETOOTH) + return KMError.SystemFeatureNotSupported(PackageManager.FEATURE_BLUETOOTH) } adapter.disable() diff --git a/app/src/main/java/io/github/sds100/keymapper/system/bluetooth/BluetoothAdapter.kt b/system/src/main/java/io/github/sds100/keymapper/system/bluetooth/BluetoothAdapter.kt similarity index 68% rename from app/src/main/java/io/github/sds100/keymapper/system/bluetooth/BluetoothAdapter.kt rename to system/src/main/java/io/github/sds100/keymapper/system/bluetooth/BluetoothAdapter.kt index 569e0080fc..15e7448164 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/bluetooth/BluetoothAdapter.kt +++ b/system/src/main/java/io/github/sds100/keymapper/system/bluetooth/BluetoothAdapter.kt @@ -1,11 +1,8 @@ package io.github.sds100.keymapper.system.bluetooth -import io.github.sds100.keymapper.util.Result +import io.github.sds100.keymapper.common.utils.KMResult import kotlinx.coroutines.flow.Flow -/** - * Created by sds100 on 14/02/2021. - */ interface BluetoothAdapter { val onDeviceConnect: Flow val onDeviceDisconnect: Flow @@ -13,6 +10,6 @@ interface BluetoothAdapter { val isBluetoothEnabled: Flow - fun enable(): Result<*> - fun disable(): Result<*> + fun enable(): KMResult<*> + fun disable(): KMResult<*> } diff --git a/app/src/main/java/io/github/sds100/keymapper/system/bluetooth/BluetoothBroadcastReceiver.kt b/system/src/main/java/io/github/sds100/keymapper/system/bluetooth/BluetoothBroadcastReceiver.kt similarity index 71% rename from app/src/main/java/io/github/sds100/keymapper/system/bluetooth/BluetoothBroadcastReceiver.kt rename to system/src/main/java/io/github/sds100/keymapper/system/bluetooth/BluetoothBroadcastReceiver.kt index 9314780f80..bbb3dcf094 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/bluetooth/BluetoothBroadcastReceiver.kt +++ b/system/src/main/java/io/github/sds100/keymapper/system/bluetooth/BluetoothBroadcastReceiver.kt @@ -4,14 +4,15 @@ import android.bluetooth.BluetoothDevice import android.content.BroadcastReceiver import android.content.Context import android.content.Intent -import io.github.sds100.keymapper.KeyMapperApp - -/** - * Created by sds100 on 28/12/2018. - */ +import dagger.hilt.android.AndroidEntryPoint +import javax.inject.Inject +@AndroidEntryPoint class BluetoothBroadcastReceiver : BroadcastReceiver() { + @Inject + lateinit var bluetoothAdapter: AndroidBluetoothAdapter + override fun onReceive(context: Context?, intent: Intent?) { context ?: return intent ?: return @@ -19,7 +20,7 @@ class BluetoothBroadcastReceiver : BroadcastReceiver() { if (intent.action == BluetoothDevice.ACTION_ACL_CONNECTED || intent.action == BluetoothDevice.ACTION_ACL_DISCONNECTED ) { - (context.applicationContext as KeyMapperApp).bluetoothMonitor.onReceiveIntent(intent) + bluetoothAdapter.onReceiveIntent(intent) } } } diff --git a/app/src/main/java/io/github/sds100/keymapper/system/bluetooth/BluetoothDeviceInfo.kt b/system/src/main/java/io/github/sds100/keymapper/system/bluetooth/BluetoothDeviceInfo.kt similarity index 73% rename from app/src/main/java/io/github/sds100/keymapper/system/bluetooth/BluetoothDeviceInfo.kt rename to system/src/main/java/io/github/sds100/keymapper/system/bluetooth/BluetoothDeviceInfo.kt index 2d7de81279..e42dc1a4bb 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/bluetooth/BluetoothDeviceInfo.kt +++ b/system/src/main/java/io/github/sds100/keymapper/system/bluetooth/BluetoothDeviceInfo.kt @@ -1,6 +1,3 @@ package io.github.sds100.keymapper.system.bluetooth -/** - * Created by sds100 on 07/04/2021. - */ data class BluetoothDeviceInfo(val address: String, val name: String) diff --git a/app/src/main/java/io/github/sds100/keymapper/system/camera/AndroidCameraAdapter.kt b/system/src/main/java/io/github/sds100/keymapper/system/camera/AndroidCameraAdapter.kt similarity index 83% rename from app/src/main/java/io/github/sds100/keymapper/system/camera/AndroidCameraAdapter.kt rename to system/src/main/java/io/github/sds100/keymapper/system/camera/AndroidCameraAdapter.kt index ca96844989..18de04aadd 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/camera/AndroidCameraAdapter.kt +++ b/system/src/main/java/io/github/sds100/keymapper/system/camera/AndroidCameraAdapter.kt @@ -7,20 +7,23 @@ import android.hardware.camera2.CameraManager import android.os.Build import androidx.annotation.RequiresApi import androidx.core.content.getSystemService -import io.github.sds100.keymapper.util.Error -import io.github.sds100.keymapper.util.Result -import io.github.sds100.keymapper.util.Success +import io.github.sds100.keymapper.common.utils.KMError +import io.github.sds100.keymapper.common.utils.KMResult +import io.github.sds100.keymapper.common.utils.Success import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.update import timber.log.Timber import kotlin.collections.set - -/** - * Created by sds100 on 17/03/2021. - */ -class AndroidCameraAdapter(context: Context) : CameraAdapter { +import dagger.hilt.android.qualifiers.ApplicationContext +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class AndroidCameraAdapter @Inject constructor( + @ApplicationContext private val context: Context +) : CameraAdapter { private val ctx = context.applicationContext private val cameraManager: CameraManager by lazy { ctx.getSystemService()!! } @@ -135,11 +138,11 @@ class AndroidCameraAdapter(context: Context) : CameraAdapter { return null } - override fun enableFlashlight(lens: CameraLens, strengthPercent: Float?): Result<*> = setFlashlightMode(true, lens, strengthPercent) + override fun enableFlashlight(lens: CameraLens, strengthPercent: Float?): KMResult<*> = setFlashlightMode(true, lens, strengthPercent) - override fun disableFlashlight(lens: CameraLens): Result<*> = setFlashlightMode(false, lens) + override fun disableFlashlight(lens: CameraLens): KMResult<*> = setFlashlightMode(false, lens) - override fun toggleFlashlight(lens: CameraLens, strengthPercent: Float?): Result<*> = setFlashlightMode(!isFlashEnabledMap.value[lens]!!, lens, strengthPercent) + override fun toggleFlashlight(lens: CameraLens, strengthPercent: Float?): KMResult<*> = setFlashlightMode(!isFlashEnabledMap.value[lens]!!, lens, strengthPercent) override fun isFlashlightOn(lens: CameraLens): Boolean = isFlashEnabledMap.value[lens] ?: false @@ -147,9 +150,9 @@ class AndroidCameraAdapter(context: Context) : CameraAdapter { return isFlashEnabledMap.map { it[lens] ?: false } } - override fun changeFlashlightStrength(lens: CameraLens, percent: Float): Result<*> { + override fun changeFlashlightStrength(lens: CameraLens, percent: Float): KMResult<*> { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) { - return Error.SdkVersionTooLow(minSdk = Build.VERSION_CODES.TIRAMISU) + return KMError.SdkVersionTooLow(minSdk = Build.VERSION_CODES.TIRAMISU) } // If the flash is disabled and it should be decreased then do nothing. @@ -162,8 +165,8 @@ class AndroidCameraAdapter(context: Context) : CameraAdapter { if (cameraId == null) { return when (lens) { - CameraLens.FRONT -> Error.FrontFlashNotFound - CameraLens.BACK -> Error.BackFlashNotFound + CameraLens.FRONT -> KMError.FrontFlashNotFound + CameraLens.BACK -> KMError.BackFlashNotFound } } @@ -202,9 +205,9 @@ class AndroidCameraAdapter(context: Context) : CameraAdapter { enabled: Boolean, lens: CameraLens, strengthPercent: Float? = null, - ): Result<*> { + ): KMResult<*> { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { - return Error.SdkVersionTooLow(minSdk = Build.VERSION_CODES.M) + return KMError.SdkVersionTooLow(minSdk = Build.VERSION_CODES.M) } try { @@ -213,8 +216,8 @@ class AndroidCameraAdapter(context: Context) : CameraAdapter { if (cameraId == null || flashInfo == null) { return when (lens) { - CameraLens.FRONT -> Error.FrontFlashNotFound - CameraLens.BACK -> Error.BackFlashNotFound + CameraLens.FRONT -> KMError.FrontFlashNotFound + CameraLens.BACK -> KMError.BackFlashNotFound } } @@ -234,17 +237,17 @@ class AndroidCameraAdapter(context: Context) : CameraAdapter { } catch (e: CameraAccessException) { return convertCameraException(e) } catch (e: Exception) { - return Error.Exception(e) + return KMError.Exception(e) } } private fun convertCameraException(e: CameraAccessException) = when (e.reason) { - CameraAccessException.CAMERA_IN_USE -> Error.CameraInUse - CameraAccessException.CAMERA_DISCONNECTED -> Error.CameraDisconnected - CameraAccessException.CAMERA_DISABLED -> Error.CameraDisabled - CameraAccessException.CAMERA_ERROR -> Error.CameraError - CameraAccessException.MAX_CAMERAS_IN_USE -> Error.MaxCamerasInUse - else -> Error.Exception(e) + CameraAccessException.CAMERA_IN_USE -> KMError.CameraInUse + CameraAccessException.CAMERA_DISCONNECTED -> KMError.CameraDisconnected + CameraAccessException.CAMERA_DISABLED -> KMError.CameraDisabled + CameraAccessException.CAMERA_ERROR -> KMError.CameraError + CameraAccessException.MAX_CAMERAS_IN_USE -> KMError.MaxCamerasInUse + else -> KMError.Exception(e) } private fun updateState(lens: CameraLens, enabled: Boolean) { diff --git a/app/src/main/java/io/github/sds100/keymapper/system/camera/CameraAdapter.kt b/system/src/main/java/io/github/sds100/keymapper/system/camera/CameraAdapter.kt similarity index 84% rename from app/src/main/java/io/github/sds100/keymapper/system/camera/CameraAdapter.kt rename to system/src/main/java/io/github/sds100/keymapper/system/camera/CameraAdapter.kt index 32f6811f56..c9f34b0843 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/camera/CameraAdapter.kt +++ b/system/src/main/java/io/github/sds100/keymapper/system/camera/CameraAdapter.kt @@ -1,11 +1,8 @@ package io.github.sds100.keymapper.system.camera -import io.github.sds100.keymapper.util.Result +import io.github.sds100.keymapper.common.utils.KMResult import kotlinx.coroutines.flow.Flow -/** - * Created by sds100 on 17/03/2021. - */ interface CameraAdapter { /** * @return null if this lens does not have a flash. @@ -16,14 +13,14 @@ interface CameraAdapter { * @param strengthPercent is a percentage of the brightness from 0 to 1.0. Null if the default * brightness should be used. */ - fun enableFlashlight(lens: CameraLens, strengthPercent: Float?): Result<*> + fun enableFlashlight(lens: CameraLens, strengthPercent: Float?): KMResult<*> /** * @param strengthPercent is a percentage of the brightness from 0 to 1.0. Null if the default * brightness should be used. */ - fun toggleFlashlight(lens: CameraLens, strengthPercent: Float?): Result<*> - fun disableFlashlight(lens: CameraLens): Result<*> + fun toggleFlashlight(lens: CameraLens, strengthPercent: Float?): KMResult<*> + fun disableFlashlight(lens: CameraLens): KMResult<*> fun isFlashlightOn(lens: CameraLens): Boolean fun isFlashlightOnFlow(lens: CameraLens): Flow @@ -31,5 +28,5 @@ interface CameraAdapter { * @param percent This is the percentage of the max strength to increase/decrease by. Set it * negative to decrease the strength. */ - fun changeFlashlightStrength(lens: CameraLens, percent: Float): Result<*> + fun changeFlashlightStrength(lens: CameraLens, percent: Float): KMResult<*> } diff --git a/app/src/main/java/io/github/sds100/keymapper/system/camera/CameraFlashInfo.kt b/system/src/main/java/io/github/sds100/keymapper/system/camera/CameraFlashInfo.kt similarity index 100% rename from app/src/main/java/io/github/sds100/keymapper/system/camera/CameraFlashInfo.kt rename to system/src/main/java/io/github/sds100/keymapper/system/camera/CameraFlashInfo.kt diff --git a/app/src/main/java/io/github/sds100/keymapper/system/camera/CameraLens.kt b/system/src/main/java/io/github/sds100/keymapper/system/camera/CameraLens.kt similarity index 68% rename from app/src/main/java/io/github/sds100/keymapper/system/camera/CameraLens.kt rename to system/src/main/java/io/github/sds100/keymapper/system/camera/CameraLens.kt index 6e2546f694..7ddef7ae0b 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/camera/CameraLens.kt +++ b/system/src/main/java/io/github/sds100/keymapper/system/camera/CameraLens.kt @@ -1,8 +1,5 @@ package io.github.sds100.keymapper.system.camera -/** - * Created by sds100 on 22/02/2021. - */ enum class CameraLens { FRONT, BACK, diff --git a/app/src/main/java/io/github/sds100/keymapper/system/clipboard/AndroidClipboardAdapter.kt b/system/src/main/java/io/github/sds100/keymapper/system/clipboard/AndroidClipboardAdapter.kt similarity index 66% rename from app/src/main/java/io/github/sds100/keymapper/system/clipboard/AndroidClipboardAdapter.kt rename to system/src/main/java/io/github/sds100/keymapper/system/clipboard/AndroidClipboardAdapter.kt index 1df06cc582..ed4051ef21 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/clipboard/AndroidClipboardAdapter.kt +++ b/system/src/main/java/io/github/sds100/keymapper/system/clipboard/AndroidClipboardAdapter.kt @@ -4,11 +4,14 @@ import android.content.ClipData import android.content.ClipboardManager import android.content.Context import androidx.core.content.getSystemService +import dagger.hilt.android.qualifiers.ApplicationContext +import javax.inject.Inject +import javax.inject.Singleton -/** - * Created by sds100 on 14/05/2021. - */ -class AndroidClipboardAdapter(context: Context) : ClipboardAdapter { +@Singleton +class AndroidClipboardAdapter @Inject constructor( + @ApplicationContext private val context: Context +) : ClipboardAdapter { private val ctx = context.applicationContext private val clipboardManager: ClipboardManager? = ctx.getSystemService() diff --git a/app/src/main/java/io/github/sds100/keymapper/system/clipboard/ClipboardAdapter.kt b/system/src/main/java/io/github/sds100/keymapper/system/clipboard/ClipboardAdapter.kt similarity index 74% rename from app/src/main/java/io/github/sds100/keymapper/system/clipboard/ClipboardAdapter.kt rename to system/src/main/java/io/github/sds100/keymapper/system/clipboard/ClipboardAdapter.kt index 241f0fe636..4db37bfa14 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/clipboard/ClipboardAdapter.kt +++ b/system/src/main/java/io/github/sds100/keymapper/system/clipboard/ClipboardAdapter.kt @@ -1,8 +1,5 @@ package io.github.sds100.keymapper.system.clipboard -/** - * Created by sds100 on 14/05/2021. - */ interface ClipboardAdapter { fun copy(label: String, text: String) } diff --git a/app/src/main/java/io/github/sds100/keymapper/system/devices/AndroidDevicesAdapter.kt b/system/src/main/java/io/github/sds100/keymapper/system/devices/AndroidDevicesAdapter.kt similarity index 89% rename from app/src/main/java/io/github/sds100/keymapper/system/devices/AndroidDevicesAdapter.kt rename to system/src/main/java/io/github/sds100/keymapper/system/devices/AndroidDevicesAdapter.kt index f593683c97..4de8e4696a 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/devices/AndroidDevicesAdapter.kt +++ b/system/src/main/java/io/github/sds100/keymapper/system/devices/AndroidDevicesAdapter.kt @@ -5,16 +5,17 @@ import android.bluetooth.BluetoothManager import android.content.Context import android.hardware.input.InputManager import android.os.Handler +import android.os.Looper import android.view.InputDevice import androidx.core.content.getSystemService +import io.github.sds100.keymapper.common.utils.KMError +import io.github.sds100.keymapper.common.utils.KMResult +import io.github.sds100.keymapper.common.utils.Success import io.github.sds100.keymapper.system.bluetooth.BluetoothDeviceInfo import io.github.sds100.keymapper.system.permissions.Permission import io.github.sds100.keymapper.system.permissions.PermissionAdapter -import io.github.sds100.keymapper.util.Error -import io.github.sds100.keymapper.util.Result -import io.github.sds100.keymapper.util.State -import io.github.sds100.keymapper.util.Success -import io.github.sds100.keymapper.util.ifIsData +import io.github.sds100.keymapper.common.utils.State +import io.github.sds100.keymapper.common.utils.ifIsData import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow @@ -24,13 +25,13 @@ import kotlinx.coroutines.flow.merge import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch -import splitties.mainthread.mainLooper +import dagger.hilt.android.qualifiers.ApplicationContext +import javax.inject.Inject +import javax.inject.Singleton -/** - * Created by sds100 on 13/03/2021. - */ -class AndroidDevicesAdapter( - context: Context, +@Singleton +class AndroidDevicesAdapter @Inject constructor( + @ApplicationContext private val context: Context, private val bluetoothAdapter: io.github.sds100.keymapper.system.bluetooth.BluetoothAdapter, private val permissionAdapter: PermissionAdapter, private val coroutineScope: CoroutineScope, @@ -94,7 +95,7 @@ class AndroidDevicesAdapter( updateInputDevices() } }, - Handler(mainLooper), + Handler(Looper.getMainLooper()), ) } @@ -124,7 +125,7 @@ class AndroidDevicesAdapter( return device.hasKeys(keyCode)[0] } - override fun getInputDeviceName(descriptor: String): Result { + override fun getInputDeviceName(descriptor: String): KMResult { for (id in InputDevice.getDeviceIds()) { val device = InputDevice.getDevice(id) ?: continue @@ -133,7 +134,7 @@ class AndroidDevicesAdapter( } } - return Error.DeviceNotFound(descriptor) + return KMError.DeviceNotFound(descriptor) } private fun updateInputDevices() { diff --git a/app/src/main/java/io/github/sds100/keymapper/system/devices/DevicesAdapter.kt b/system/src/main/java/io/github/sds100/keymapper/system/devices/DevicesAdapter.kt similarity index 75% rename from app/src/main/java/io/github/sds100/keymapper/system/devices/DevicesAdapter.kt rename to system/src/main/java/io/github/sds100/keymapper/system/devices/DevicesAdapter.kt index fcf399bc75..b244531a06 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/devices/DevicesAdapter.kt +++ b/system/src/main/java/io/github/sds100/keymapper/system/devices/DevicesAdapter.kt @@ -1,14 +1,11 @@ package io.github.sds100.keymapper.system.devices +import io.github.sds100.keymapper.common.utils.KMResult import io.github.sds100.keymapper.system.bluetooth.BluetoothDeviceInfo -import io.github.sds100.keymapper.util.Result -import io.github.sds100.keymapper.util.State +import io.github.sds100.keymapper.common.utils.State import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.StateFlow -/** - * Created by sds100 on 07/03/2021. - */ interface DevicesAdapter { val onInputDeviceConnect: Flow val onInputDeviceDisconnect: Flow @@ -18,5 +15,5 @@ interface DevicesAdapter { val connectedBluetoothDevices: StateFlow> fun deviceHasKey(id: Int, keyCode: Int): Boolean - fun getInputDeviceName(descriptor: String): Result + fun getInputDeviceName(descriptor: String): KMResult } diff --git a/app/src/main/java/io/github/sds100/keymapper/system/devices/InputDeviceInfo.kt b/system/src/main/java/io/github/sds100/keymapper/system/devices/InputDeviceInfo.kt similarity index 88% rename from app/src/main/java/io/github/sds100/keymapper/system/devices/InputDeviceInfo.kt rename to system/src/main/java/io/github/sds100/keymapper/system/devices/InputDeviceInfo.kt index 465c3b5adf..c66b126bcc 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/devices/InputDeviceInfo.kt +++ b/system/src/main/java/io/github/sds100/keymapper/system/devices/InputDeviceInfo.kt @@ -4,10 +4,6 @@ import android.os.Parcelable import kotlinx.parcelize.Parcelize import kotlinx.serialization.Serializable -/** - * Created by sds100 on 07/03/2021. - */ - @Parcelize @Serializable data class InputDeviceInfo( diff --git a/app/src/main/java/io/github/sds100/keymapper/system/devices/InputDeviceUtils.kt b/system/src/main/java/io/github/sds100/keymapper/system/devices/InputDeviceUtils.kt similarity index 96% rename from app/src/main/java/io/github/sds100/keymapper/system/devices/InputDeviceUtils.kt rename to system/src/main/java/io/github/sds100/keymapper/system/devices/InputDeviceUtils.kt index 86bfa6d789..b81d75f2ea 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/devices/InputDeviceUtils.kt +++ b/system/src/main/java/io/github/sds100/keymapper/system/devices/InputDeviceUtils.kt @@ -5,10 +5,6 @@ import android.view.InputDevice import java.lang.reflect.InvocationTargetException import java.lang.reflect.Method -/** - * Created by sds100 on 24/04/2020. - */ - object InputDeviceUtils { fun appendDeviceDescriptorToName(descriptor: String, name: String): String = "$name ${descriptor.substring(0..4)}" diff --git a/app/src/main/java/io/github/sds100/keymapper/system/display/AndroidDisplayAdapter.kt b/system/src/main/java/io/github/sds100/keymapper/system/display/AndroidDisplayAdapter.kt similarity index 80% rename from app/src/main/java/io/github/sds100/keymapper/system/display/AndroidDisplayAdapter.kt rename to system/src/main/java/io/github/sds100/keymapper/system/display/AndroidDisplayAdapter.kt index 1a9c2bfa98..3c4eaf1c08 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/display/AndroidDisplayAdapter.kt +++ b/system/src/main/java/io/github/sds100/keymapper/system/display/AndroidDisplayAdapter.kt @@ -9,12 +9,14 @@ import android.provider.Settings import android.view.Surface import androidx.core.content.ContextCompat import androidx.core.content.getSystemService +import dagger.hilt.android.qualifiers.ApplicationContext +import io.github.sds100.keymapper.common.utils.KMError +import io.github.sds100.keymapper.common.utils.Orientation +import io.github.sds100.keymapper.common.utils.KMResult +import io.github.sds100.keymapper.common.utils.SizeKM +import io.github.sds100.keymapper.common.utils.Success +import io.github.sds100.keymapper.common.utils.getRealDisplaySize import io.github.sds100.keymapper.system.SettingsUtils -import io.github.sds100.keymapper.util.Error -import io.github.sds100.keymapper.util.Result -import io.github.sds100.keymapper.util.SizeKM -import io.github.sds100.keymapper.util.Success -import io.github.sds100.keymapper.util.getRealDisplaySize import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.delay import kotlinx.coroutines.flow.Flow @@ -22,12 +24,12 @@ import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.update import kotlinx.coroutines.flow.updateAndGet import kotlinx.coroutines.launch +import javax.inject.Inject +import javax.inject.Singleton -/** - * Created by sds100 on 17/04/2021. - */ -class AndroidDisplayAdapter( - context: Context, +@Singleton +class AndroidDisplayAdapter @Inject constructor( + @ApplicationContext private val context: Context, private val coroutineScope: CoroutineScope, ) : DisplayAdapter { companion object { @@ -112,27 +114,27 @@ class AndroidDisplayAdapter( override fun isAutoRotateEnabled(): Boolean = SettingsUtils.getSystemSetting(ctx, Settings.System.ACCELEROMETER_ROTATION) == 1 - override fun enableAutoRotate(): Result<*> { + override fun enableAutoRotate(): KMResult<*> { val success = SettingsUtils.putSystemSetting(ctx, Settings.System.ACCELEROMETER_ROTATION, 1) if (success) { return Success(Unit) } else { - return Error.FailedToModifySystemSetting(Settings.System.ACCELEROMETER_ROTATION) + return KMError.FailedToModifySystemSetting(Settings.System.ACCELEROMETER_ROTATION) } } - override fun disableAutoRotate(): Result<*> { + override fun disableAutoRotate(): KMResult<*> { val success = SettingsUtils.putSystemSetting(ctx, Settings.System.ACCELEROMETER_ROTATION, 0) if (success) { return Success(Unit) } else { - return Error.FailedToModifySystemSetting(Settings.System.ACCELEROMETER_ROTATION) + return KMError.FailedToModifySystemSetting(Settings.System.ACCELEROMETER_ROTATION) } } - override fun setOrientation(orientation: Orientation): Result<*> { + override fun setOrientation(orientation: Orientation): KMResult<*> { val sdkRotationValue = when (orientation) { Orientation.ORIENTATION_0 -> Surface.ROTATION_0 Orientation.ORIENTATION_90 -> Surface.ROTATION_90 @@ -146,7 +148,7 @@ class AndroidDisplayAdapter( if (success) { return Success(Unit) } else { - return Error.FailedToModifySystemSetting(Settings.System.USER_ROTATION) + return KMError.FailedToModifySystemSetting(Settings.System.USER_ROTATION) } } @@ -155,7 +157,7 @@ class AndroidDisplayAdapter( Settings.System.SCREEN_BRIGHTNESS_MODE, ) == Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC - override fun increaseBrightness(): Result<*> { + override fun increaseBrightness(): KMResult<*> { // auto-brightness must be disabled disableAutoBrightness() @@ -179,11 +181,11 @@ class AndroidDisplayAdapter( return if (success) { Success(Unit) } else { - Error.FailedToModifySystemSetting(Settings.System.SCREEN_BRIGHTNESS) + KMError.FailedToModifySystemSetting(Settings.System.SCREEN_BRIGHTNESS) } } - override fun decreaseBrightness(): Result<*> { + override fun decreaseBrightness(): KMResult<*> { // auto-brightness must be disabled disableAutoBrightness() @@ -207,22 +209,22 @@ class AndroidDisplayAdapter( return if (success) { Success(Unit) } else { - Error.FailedToModifySystemSetting(Settings.System.SCREEN_BRIGHTNESS) + KMError.FailedToModifySystemSetting(Settings.System.SCREEN_BRIGHTNESS) } } - override fun enableAutoBrightness(): Result<*> = setBrightnessMode(Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC) + override fun enableAutoBrightness(): KMResult<*> = setBrightnessMode(Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC) - override fun disableAutoBrightness(): Result<*> = setBrightnessMode(Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL) + override fun disableAutoBrightness(): KMResult<*> = setBrightnessMode(Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL) - private fun setBrightnessMode(mode: Int): Result<*> { + private fun setBrightnessMode(mode: Int): KMResult<*> { val success = SettingsUtils.putSystemSetting(ctx, Settings.System.SCREEN_BRIGHTNESS_MODE, mode) return if (success) { Success(Unit) } else { - Error.FailedToModifySystemSetting(Settings.System.SCREEN_BRIGHTNESS_MODE) + KMError.FailedToModifySystemSetting(Settings.System.SCREEN_BRIGHTNESS_MODE) } } diff --git a/app/src/main/java/io/github/sds100/keymapper/system/display/DisplayAdapter.kt b/system/src/main/java/io/github/sds100/keymapper/system/display/DisplayAdapter.kt similarity index 52% rename from app/src/main/java/io/github/sds100/keymapper/system/display/DisplayAdapter.kt rename to system/src/main/java/io/github/sds100/keymapper/system/display/DisplayAdapter.kt index 765797348f..a38fe5a177 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/display/DisplayAdapter.kt +++ b/system/src/main/java/io/github/sds100/keymapper/system/display/DisplayAdapter.kt @@ -1,7 +1,8 @@ package io.github.sds100.keymapper.system.display -import io.github.sds100.keymapper.util.Result -import io.github.sds100.keymapper.util.SizeKM +import io.github.sds100.keymapper.common.utils.KMResult +import io.github.sds100.keymapper.common.utils.SizeKM +import io.github.sds100.keymapper.common.utils.Orientation import kotlinx.coroutines.flow.Flow interface DisplayAdapter { @@ -12,9 +13,9 @@ interface DisplayAdapter { val isAmbientDisplayEnabled: Flow fun isAutoRotateEnabled(): Boolean - fun enableAutoRotate(): Result<*> - fun disableAutoRotate(): Result<*> - fun setOrientation(orientation: Orientation): Result<*> + fun enableAutoRotate(): KMResult<*> + fun disableAutoRotate(): KMResult<*> + fun setOrientation(orientation: Orientation): KMResult<*> /** * Fetch the orientation and bypass the cached value that updates when the listener changes. @@ -22,8 +23,8 @@ interface DisplayAdapter { fun fetchOrientation(): Orientation fun isAutoBrightnessEnabled(): Boolean - fun increaseBrightness(): Result<*> - fun decreaseBrightness(): Result<*> - fun enableAutoBrightness(): Result<*> - fun disableAutoBrightness(): Result<*> + fun increaseBrightness(): KMResult<*> + fun decreaseBrightness(): KMResult<*> + fun enableAutoBrightness(): KMResult<*> + fun disableAutoBrightness(): KMResult<*> } diff --git a/app/src/main/java/io/github/sds100/keymapper/system/files/AndroidFileAdapter.kt b/system/src/main/java/io/github/sds100/keymapper/system/files/AndroidFileAdapter.kt similarity index 84% rename from app/src/main/java/io/github/sds100/keymapper/system/files/AndroidFileAdapter.kt rename to system/src/main/java/io/github/sds100/keymapper/system/files/AndroidFileAdapter.kt index 0b95792f0d..448ce230da 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/files/AndroidFileAdapter.kt +++ b/system/src/main/java/io/github/sds100/keymapper/system/files/AndroidFileAdapter.kt @@ -10,21 +10,25 @@ import androidx.core.content.FileProvider import androidx.core.net.toUri import androidx.documentfile.provider.DocumentFile import com.anggrayudi.storage.file.toDocumentFile -import io.github.sds100.keymapper.Constants -import io.github.sds100.keymapper.util.Error -import io.github.sds100.keymapper.util.Result -import io.github.sds100.keymapper.util.Success +import io.github.sds100.keymapper.common.utils.KMError +import io.github.sds100.keymapper.common.utils.KMResult +import io.github.sds100.keymapper.common.utils.Success import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import net.lingala.zip4j.ZipFile import java.io.File import java.io.InputStream import java.util.UUID - -/** - * Created by sds100 on 13/04/2021. - */ -class AndroidFileAdapter(context: Context) : FileAdapter { +import dagger.hilt.android.qualifiers.ApplicationContext +import io.github.sds100.keymapper.common.BuildConfigProvider +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class AndroidFileAdapter @Inject constructor( + @ApplicationContext private val context: Context, + private val buildConfigProvider: BuildConfigProvider +) : FileAdapter { private val ctx = context.applicationContext private val contentResolver: ContentResolver = ctx.contentResolver @@ -50,7 +54,7 @@ class AndroidFileAdapter(context: Context) : FileAdapter { override fun openAsset(fileName: String): InputStream = ctx.assets.open(fileName) - override fun openDownloadsFile(fileName: String, mimeType: String): Result { + override fun openDownloadsFile(fileName: String, mimeType: String): KMResult { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { val contentValues = ContentValues().apply { put(MediaStore.MediaColumns.DISPLAY_NAME, fileName) @@ -61,15 +65,15 @@ class AndroidFileAdapter(context: Context) : FileAdapter { val uri = contentResolver.insert(MediaStore.Downloads.EXTERNAL_CONTENT_URI, contentValues) - ?: return Error.UnknownIOError + ?: return KMError.UnknownIOError - val file = DocumentFile.fromSingleUri(ctx, uri) ?: return Error.UnknownIOError + val file = DocumentFile.fromSingleUri(ctx, uri) ?: return KMError.UnknownIOError return Success(DocumentFileWrapper(file, ctx)) } else { val downloadsFile = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) - val documentFile = downloadsFile.toDocumentFile(ctx) ?: return Error.UnknownIOError + val documentFile = downloadsFile.toDocumentFile(ctx) ?: return KMError.UnknownIOError val file = DocumentFileWrapper(documentFile, ctx) return Success(file) @@ -78,7 +82,7 @@ class AndroidFileAdapter(context: Context) : FileAdapter { override fun getPicturesFolder(): String = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES).path - override fun createZipFile(destination: IFile, files: Set): Result<*> { + override fun createZipFile(destination: IFile, files: Set): KMResult<*> { val zipUid = UUID.randomUUID().toString() val tempZipFile = File(ctx.filesDir, "$zipUid.zip") @@ -107,7 +111,7 @@ class AndroidFileAdapter(context: Context) : FileAdapter { return Success(Unit) } - override suspend fun extractZipFile(zipFile: IFile, destination: IFile): Result<*> { + override suspend fun extractZipFile(zipFile: IFile, destination: IFile): KMResult<*> { withContext(Dispatchers.IO) { val zipUid = UUID.randomUUID().toString() val tempZipFileCopy = File(ctx.filesDir, "$zipUid.zip") @@ -131,7 +135,7 @@ class AndroidFileAdapter(context: Context) : FileAdapter { override fun getPublicUriForPrivateFile(privateFile: IFile): String { return FileProvider.getUriForFile( ctx, - "${Constants.PACKAGE_NAME}.provider", + "${buildConfigProvider.packageName}.provider", privateFile.toJavaFile(), ).toString() } diff --git a/app/src/main/java/io/github/sds100/keymapper/system/files/DocumentFileWrapper.kt b/system/src/main/java/io/github/sds100/keymapper/system/files/DocumentFileWrapper.kt similarity index 81% rename from app/src/main/java/io/github/sds100/keymapper/system/files/DocumentFileWrapper.kt rename to system/src/main/java/io/github/sds100/keymapper/system/files/DocumentFileWrapper.kt index 5d7c9da6d4..1bf21fb57e 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/files/DocumentFileWrapper.kt +++ b/system/src/main/java/io/github/sds100/keymapper/system/files/DocumentFileWrapper.kt @@ -12,9 +12,9 @@ import com.anggrayudi.storage.file.openInputStream import com.anggrayudi.storage.file.openOutputStream import com.anggrayudi.storage.file.recreateFile import com.anggrayudi.storage.media.FileDescription -import io.github.sds100.keymapper.util.Error -import io.github.sds100.keymapper.util.Result -import io.github.sds100.keymapper.util.Success +import io.github.sds100.keymapper.common.utils.KMError +import io.github.sds100.keymapper.common.utils.KMResult +import io.github.sds100.keymapper.common.utils.Success import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import java.io.File @@ -23,9 +23,6 @@ import java.io.OutputStream import kotlin.coroutines.resume import kotlin.coroutines.suspendCoroutine -/** - * Created by sds100 on 28/06/2021. - */ class DocumentFileWrapper(val file: DocumentFile, context: Context) : IFile { private val ctx = context.applicationContext @@ -93,7 +90,7 @@ class DocumentFileWrapper(val file: DocumentFile, context: Context) : IFile { } } - override suspend fun copyTo(directory: IFile, fileName: String?): Result<*> = withContext(Dispatchers.Default) { + override suspend fun copyTo(directory: IFile, fileName: String?): KMResult<*> = withContext(Dispatchers.Default) { suspendCoroutine { continuation -> val callback = object : FileCallback() { override fun onCompleted(result: Any) { @@ -106,21 +103,21 @@ class DocumentFileWrapper(val file: DocumentFile, context: Context) : IFile { super.onFailed(errorCode) val error = when (errorCode) { - ErrorCode.STORAGE_PERMISSION_DENIED -> Error.StoragePermissionDenied - ErrorCode.CANNOT_CREATE_FILE_IN_TARGET -> Error.CannotCreateFileInTarget( + ErrorCode.STORAGE_PERMISSION_DENIED -> KMError.StoragePermissionDenied + ErrorCode.CANNOT_CREATE_FILE_IN_TARGET -> KMError.CannotCreateFileInTarget( directory.uri, ) - ErrorCode.SOURCE_FILE_NOT_FOUND -> Error.SourceFileNotFound(this@DocumentFileWrapper.uri) - ErrorCode.TARGET_FILE_NOT_FOUND -> Error.TargetFileNotFound(directory.uri) - ErrorCode.TARGET_FOLDER_NOT_FOUND -> Error.TargetDirectoryNotFound( + ErrorCode.SOURCE_FILE_NOT_FOUND -> KMError.SourceFileNotFound(this@DocumentFileWrapper.uri) + ErrorCode.TARGET_FILE_NOT_FOUND -> KMError.TargetFileNotFound(directory.uri) + ErrorCode.TARGET_FOLDER_NOT_FOUND -> KMError.TargetDirectoryNotFound( directory.uri, ) - ErrorCode.UNKNOWN_IO_ERROR -> Error.UnknownIOError - ErrorCode.CANCELED -> Error.FileOperationCancelled - ErrorCode.TARGET_FOLDER_CANNOT_HAVE_SAME_PATH_WITH_SOURCE_FOLDER -> Error.TargetDirectoryMatchesSourceDirectory - ErrorCode.NO_SPACE_LEFT_ON_TARGET_PATH -> Error.NoSpaceLeftOnTarget( + ErrorCode.UNKNOWN_IO_ERROR -> KMError.UnknownIOError + ErrorCode.CANCELED -> KMError.FileOperationCancelled + ErrorCode.TARGET_FOLDER_CANNOT_HAVE_SAME_PATH_WITH_SOURCE_FOLDER -> KMError.TargetDirectoryMatchesSourceDirectory + ErrorCode.NO_SPACE_LEFT_ON_TARGET_PATH -> KMError.NoSpaceLeftOnTarget( directory.uri, ) } diff --git a/app/src/main/java/io/github/sds100/keymapper/system/files/FileAdapter.kt b/system/src/main/java/io/github/sds100/keymapper/system/files/FileAdapter.kt similarity index 64% rename from app/src/main/java/io/github/sds100/keymapper/system/files/FileAdapter.kt rename to system/src/main/java/io/github/sds100/keymapper/system/files/FileAdapter.kt index 9ad168c2fb..fa7d4aa035 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/files/FileAdapter.kt +++ b/system/src/main/java/io/github/sds100/keymapper/system/files/FileAdapter.kt @@ -1,22 +1,19 @@ package io.github.sds100.keymapper.system.files -import io.github.sds100.keymapper.util.Result +import io.github.sds100.keymapper.common.utils.KMResult import java.io.InputStream -/** - * Created by sds100 on 13/04/2021. - */ interface FileAdapter { fun openAsset(fileName: String): InputStream fun getPicturesFolder(): String - fun openDownloadsFile(fileName: String, mimeType: String): Result + fun openDownloadsFile(fileName: String, mimeType: String): KMResult fun getPrivateFile(path: String): IFile fun getFile(parent: IFile, path: String): IFile fun getFileFromUri(uri: String): IFile fun getPublicUriForPrivateFile(privateFile: IFile): String - fun createZipFile(destination: IFile, files: Set): Result<*> - suspend fun extractZipFile(zipFile: IFile, destination: IFile): Result<*> + fun createZipFile(destination: IFile, files: Set): KMResult<*> + suspend fun extractZipFile(zipFile: IFile, destination: IFile): KMResult<*> } diff --git a/app/src/main/java/io/github/sds100/keymapper/system/files/FileUtils.kt b/system/src/main/java/io/github/sds100/keymapper/system/files/FileUtils.kt similarity index 97% rename from app/src/main/java/io/github/sds100/keymapper/system/files/FileUtils.kt rename to system/src/main/java/io/github/sds100/keymapper/system/files/FileUtils.kt index d870339f02..ed6bc8aa82 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/files/FileUtils.kt +++ b/system/src/main/java/io/github/sds100/keymapper/system/files/FileUtils.kt @@ -14,10 +14,6 @@ import java.io.IOException import java.text.SimpleDateFormat import java.util.Calendar -/** - * Created by sds100 on 15/12/2018. - */ - object FileUtils { const val MIME_TYPE_IMAGES = "image/*" diff --git a/app/src/main/java/io/github/sds100/keymapper/system/files/IFile.kt b/system/src/main/java/io/github/sds100/keymapper/system/files/IFile.kt similarity index 85% rename from app/src/main/java/io/github/sds100/keymapper/system/files/IFile.kt rename to system/src/main/java/io/github/sds100/keymapper/system/files/IFile.kt index 55547b9deb..9ceb791937 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/files/IFile.kt +++ b/system/src/main/java/io/github/sds100/keymapper/system/files/IFile.kt @@ -1,13 +1,10 @@ package io.github.sds100.keymapper.system.files -import io.github.sds100.keymapper.util.Result +import io.github.sds100.keymapper.common.utils.KMResult import java.io.File import java.io.InputStream import java.io.OutputStream -/** - * Created by sds100 on 28/06/2021. - */ interface IFile { val uri: String val path: String @@ -26,7 +23,7 @@ interface IFile { fun createFile() fun createDirectory() - suspend fun copyTo(directory: IFile, fileName: String? = null): Result<*> + suspend fun copyTo(directory: IFile, fileName: String? = null): KMResult<*> } fun IFile.toJavaFile(): File = File(path) diff --git a/app/src/main/java/io/github/sds100/keymapper/system/inputevents/InputEventInjector.kt b/system/src/main/java/io/github/sds100/keymapper/system/inputevents/InputEventInjector.kt similarity index 100% rename from app/src/main/java/io/github/sds100/keymapper/system/inputevents/InputEventInjector.kt rename to system/src/main/java/io/github/sds100/keymapper/system/inputevents/InputEventInjector.kt diff --git a/system/src/main/java/io/github/sds100/keymapper/system/inputevents/InputEventUtils.kt b/system/src/main/java/io/github/sds100/keymapper/system/inputevents/InputEventUtils.kt new file mode 100644 index 0000000000..ace7de6e71 --- /dev/null +++ b/system/src/main/java/io/github/sds100/keymapper/system/inputevents/InputEventUtils.kt @@ -0,0 +1,503 @@ +package io.github.sds100.keymapper.system.inputevents + +import android.os.Build +import android.view.InputDevice +import android.view.InputEvent +import android.view.KeyEvent +import io.github.sds100.keymapper.common.utils.withFlag + +object InputEventUtils { + + private val KEYCODES: Set + get() = setOf( + KeyEvent.KEYCODE_SOFT_LEFT, + KeyEvent.KEYCODE_SOFT_RIGHT, + KeyEvent.KEYCODE_HOME, + KeyEvent.KEYCODE_BACK, + KeyEvent.KEYCODE_CALL, + KeyEvent.KEYCODE_ENDCALL, + KeyEvent.KEYCODE_0, + KeyEvent.KEYCODE_1, + KeyEvent.KEYCODE_2, + KeyEvent.KEYCODE_3, + KeyEvent.KEYCODE_4, + KeyEvent.KEYCODE_5, + KeyEvent.KEYCODE_6, + KeyEvent.KEYCODE_7, + KeyEvent.KEYCODE_8, + KeyEvent.KEYCODE_9, + KeyEvent.KEYCODE_STAR, + KeyEvent.KEYCODE_POUND, + KeyEvent.KEYCODE_DPAD_UP, + KeyEvent.KEYCODE_DPAD_DOWN, + KeyEvent.KEYCODE_DPAD_LEFT, + KeyEvent.KEYCODE_DPAD_RIGHT, + KeyEvent.KEYCODE_DPAD_CENTER, + KeyEvent.KEYCODE_VOLUME_UP, + KeyEvent.KEYCODE_VOLUME_DOWN, + KeyEvent.KEYCODE_POWER, + KeyEvent.KEYCODE_CAMERA, + KeyEvent.KEYCODE_CLEAR, + KeyEvent.KEYCODE_A, + KeyEvent.KEYCODE_B, + KeyEvent.KEYCODE_C, + KeyEvent.KEYCODE_D, + KeyEvent.KEYCODE_E, + KeyEvent.KEYCODE_F, + KeyEvent.KEYCODE_G, + KeyEvent.KEYCODE_H, + KeyEvent.KEYCODE_I, + KeyEvent.KEYCODE_J, + KeyEvent.KEYCODE_K, + KeyEvent.KEYCODE_L, + KeyEvent.KEYCODE_M, + KeyEvent.KEYCODE_N, + KeyEvent.KEYCODE_O, + KeyEvent.KEYCODE_P, + KeyEvent.KEYCODE_Q, + KeyEvent.KEYCODE_R, + KeyEvent.KEYCODE_S, + KeyEvent.KEYCODE_T, + KeyEvent.KEYCODE_U, + KeyEvent.KEYCODE_V, + KeyEvent.KEYCODE_W, + KeyEvent.KEYCODE_X, + KeyEvent.KEYCODE_Y, + KeyEvent.KEYCODE_Z, + KeyEvent.KEYCODE_COMMA, + KeyEvent.KEYCODE_PERIOD, + KeyEvent.KEYCODE_ALT_LEFT, + KeyEvent.KEYCODE_ALT_RIGHT, + KeyEvent.KEYCODE_SHIFT_LEFT, + KeyEvent.KEYCODE_SHIFT_RIGHT, + KeyEvent.KEYCODE_TAB, + KeyEvent.KEYCODE_SPACE, + KeyEvent.KEYCODE_SYM, + KeyEvent.KEYCODE_EXPLORER, + KeyEvent.KEYCODE_ENVELOPE, + KeyEvent.KEYCODE_ENTER, + KeyEvent.KEYCODE_FORWARD_DEL, + KeyEvent.KEYCODE_DEL, + KeyEvent.KEYCODE_GRAVE, + KeyEvent.KEYCODE_MINUS, + KeyEvent.KEYCODE_EQUALS, + KeyEvent.KEYCODE_LEFT_BRACKET, + KeyEvent.KEYCODE_RIGHT_BRACKET, + KeyEvent.KEYCODE_BACKSLASH, + KeyEvent.KEYCODE_SEMICOLON, + KeyEvent.KEYCODE_APOSTROPHE, + KeyEvent.KEYCODE_SLASH, + KeyEvent.KEYCODE_AT, + KeyEvent.KEYCODE_ALT_LEFT, + KeyEvent.KEYCODE_HEADSETHOOK, + KeyEvent.KEYCODE_FOCUS, + KeyEvent.KEYCODE_PLUS, + KeyEvent.KEYCODE_MENU, + KeyEvent.KEYCODE_NOTIFICATION, + KeyEvent.KEYCODE_SEARCH, + KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE, + KeyEvent.KEYCODE_MEDIA_STOP, + KeyEvent.KEYCODE_MEDIA_NEXT, + KeyEvent.KEYCODE_MEDIA_PREVIOUS, + KeyEvent.KEYCODE_MEDIA_REWIND, + KeyEvent.KEYCODE_MEDIA_FAST_FORWARD, + KeyEvent.KEYCODE_PAGE_UP, + KeyEvent.KEYCODE_PAGE_DOWN, + KeyEvent.KEYCODE_PICTSYMBOLS, + KeyEvent.KEYCODE_SWITCH_CHARSET, + KeyEvent.KEYCODE_BUTTON_A, + KeyEvent.KEYCODE_BUTTON_B, + KeyEvent.KEYCODE_BUTTON_C, + KeyEvent.KEYCODE_BUTTON_X, + KeyEvent.KEYCODE_BUTTON_Y, + KeyEvent.KEYCODE_BUTTON_Z, + KeyEvent.KEYCODE_BUTTON_L1, + KeyEvent.KEYCODE_BUTTON_R1, + KeyEvent.KEYCODE_BUTTON_L2, + KeyEvent.KEYCODE_BUTTON_R2, + KeyEvent.KEYCODE_BUTTON_THUMBL, + KeyEvent.KEYCODE_BUTTON_THUMBR, + KeyEvent.KEYCODE_BUTTON_START, + KeyEvent.KEYCODE_BUTTON_SELECT, + KeyEvent.KEYCODE_BUTTON_MODE, + KeyEvent.KEYCODE_ESCAPE, + KeyEvent.KEYCODE_DEL, + KeyEvent.KEYCODE_CTRL_LEFT, + KeyEvent.KEYCODE_CTRL_RIGHT, + KeyEvent.KEYCODE_CAPS_LOCK, + KeyEvent.KEYCODE_SCROLL_LOCK, + KeyEvent.KEYCODE_META_LEFT, + KeyEvent.KEYCODE_META_RIGHT, + KeyEvent.KEYCODE_FUNCTION, + KeyEvent.KEYCODE_SYSRQ, + KeyEvent.KEYCODE_BREAK, + KeyEvent.KEYCODE_MOVE_HOME, + KeyEvent.KEYCODE_MOVE_END, + KeyEvent.KEYCODE_INSERT, + KeyEvent.KEYCODE_FORWARD, + KeyEvent.KEYCODE_MEDIA_PLAY, + KeyEvent.KEYCODE_MEDIA_PAUSE, + KeyEvent.KEYCODE_MEDIA_CLOSE, + KeyEvent.KEYCODE_MEDIA_EJECT, + KeyEvent.KEYCODE_MEDIA_RECORD, + KeyEvent.KEYCODE_F1, + KeyEvent.KEYCODE_F2, + KeyEvent.KEYCODE_F3, + KeyEvent.KEYCODE_F4, + KeyEvent.KEYCODE_F5, + KeyEvent.KEYCODE_F6, + KeyEvent.KEYCODE_F7, + KeyEvent.KEYCODE_F8, + KeyEvent.KEYCODE_F9, + KeyEvent.KEYCODE_F10, + KeyEvent.KEYCODE_F11, + KeyEvent.KEYCODE_F12, + KeyEvent.KEYCODE_NUM, + KeyEvent.KEYCODE_NUM_LOCK, + KeyEvent.KEYCODE_NUMPAD_0, + KeyEvent.KEYCODE_NUMPAD_1, + KeyEvent.KEYCODE_NUMPAD_2, + KeyEvent.KEYCODE_NUMPAD_3, + KeyEvent.KEYCODE_NUMPAD_4, + KeyEvent.KEYCODE_NUMPAD_5, + KeyEvent.KEYCODE_NUMPAD_6, + KeyEvent.KEYCODE_NUMPAD_7, + KeyEvent.KEYCODE_NUMPAD_8, + KeyEvent.KEYCODE_NUMPAD_9, + KeyEvent.KEYCODE_NUMPAD_DIVIDE, + KeyEvent.KEYCODE_NUMPAD_MULTIPLY, + KeyEvent.KEYCODE_NUMPAD_SUBTRACT, + KeyEvent.KEYCODE_NUMPAD_ADD, + KeyEvent.KEYCODE_NUMPAD_DOT, + KeyEvent.KEYCODE_NUMPAD_COMMA, + KeyEvent.KEYCODE_NUMPAD_ENTER, + KeyEvent.KEYCODE_NUMPAD_EQUALS, + KeyEvent.KEYCODE_NUMPAD_LEFT_PAREN, + KeyEvent.KEYCODE_NUMPAD_RIGHT_PAREN, + KeyEvent.KEYCODE_MUTE, + KeyEvent.KEYCODE_VOLUME_MUTE, + KeyEvent.KEYCODE_INFO, + KeyEvent.KEYCODE_CHANNEL_UP, + KeyEvent.KEYCODE_CHANNEL_DOWN, + KeyEvent.KEYCODE_ZOOM_IN, + KeyEvent.KEYCODE_ZOOM_OUT, + KeyEvent.KEYCODE_TV, + KeyEvent.KEYCODE_WINDOW, + KeyEvent.KEYCODE_GUIDE, + KeyEvent.KEYCODE_DVR, + KeyEvent.KEYCODE_BOOKMARK, + KeyEvent.KEYCODE_CAPTIONS, + KeyEvent.KEYCODE_SETTINGS, + KeyEvent.KEYCODE_TV_POWER, + KeyEvent.KEYCODE_TV_INPUT, + KeyEvent.KEYCODE_STB_POWER, + KeyEvent.KEYCODE_STB_INPUT, + KeyEvent.KEYCODE_AVR_POWER, + KeyEvent.KEYCODE_AVR_INPUT, + KeyEvent.KEYCODE_PROG_RED, + KeyEvent.KEYCODE_PROG_GREEN, + KeyEvent.KEYCODE_PROG_YELLOW, + KeyEvent.KEYCODE_PROG_BLUE, + KeyEvent.KEYCODE_APP_SWITCH, + KeyEvent.KEYCODE_BUTTON_1, + KeyEvent.KEYCODE_BUTTON_2, + KeyEvent.KEYCODE_BUTTON_3, + KeyEvent.KEYCODE_BUTTON_4, + KeyEvent.KEYCODE_BUTTON_5, + KeyEvent.KEYCODE_BUTTON_6, + KeyEvent.KEYCODE_BUTTON_7, + KeyEvent.KEYCODE_BUTTON_8, + KeyEvent.KEYCODE_BUTTON_9, + KeyEvent.KEYCODE_BUTTON_10, + KeyEvent.KEYCODE_BUTTON_11, + KeyEvent.KEYCODE_BUTTON_12, + KeyEvent.KEYCODE_BUTTON_13, + KeyEvent.KEYCODE_BUTTON_14, + KeyEvent.KEYCODE_BUTTON_15, + KeyEvent.KEYCODE_BUTTON_16, + KeyEvent.KEYCODE_LANGUAGE_SWITCH, + KeyEvent.KEYCODE_MANNER_MODE, + KeyEvent.KEYCODE_3D_MODE, + KeyEvent.KEYCODE_CONTACTS, + KeyEvent.KEYCODE_CALENDAR, + KeyEvent.KEYCODE_MUSIC, + KeyEvent.KEYCODE_CALCULATOR, + KeyEvent.KEYCODE_ZENKAKU_HANKAKU, + KeyEvent.KEYCODE_EISU, + KeyEvent.KEYCODE_MUHENKAN, + KeyEvent.KEYCODE_HENKAN, + KeyEvent.KEYCODE_KATAKANA_HIRAGANA, + KeyEvent.KEYCODE_YEN, + KeyEvent.KEYCODE_RO, + KeyEvent.KEYCODE_KANA, + KeyEvent.KEYCODE_ASSIST, + KeyEvent.KEYCODE_POWER, + KeyEvent.KEYCODE_BRIGHTNESS_DOWN, + KeyEvent.KEYCODE_BRIGHTNESS_UP, + KeyEvent.KEYCODE_MEDIA_AUDIO_TRACK, + KeyEvent.KEYCODE_PAIRING, + KeyEvent.KEYCODE_MEDIA_TOP_MENU, + KeyEvent.KEYCODE_11, + KeyEvent.KEYCODE_12, + KeyEvent.KEYCODE_LAST_CHANNEL, + KeyEvent.KEYCODE_TV_DATA_SERVICE, + KeyEvent.KEYCODE_VOICE_ASSIST, + KeyEvent.KEYCODE_TV_RADIO_SERVICE, + KeyEvent.KEYCODE_TV_TELETEXT, + KeyEvent.KEYCODE_TV_NUMBER_ENTRY, + KeyEvent.KEYCODE_TV_TERRESTRIAL_ANALOG, + KeyEvent.KEYCODE_TV_TERRESTRIAL_DIGITAL, + KeyEvent.KEYCODE_TV_SATELLITE, + KeyEvent.KEYCODE_TV_SATELLITE_BS, + KeyEvent.KEYCODE_TV_SATELLITE_CS, + KeyEvent.KEYCODE_TV_SATELLITE_SERVICE, + KeyEvent.KEYCODE_TV_NETWORK, + KeyEvent.KEYCODE_TV_ANTENNA_CABLE, + KeyEvent.KEYCODE_TV_INPUT_HDMI_1, + KeyEvent.KEYCODE_TV_INPUT_HDMI_2, + KeyEvent.KEYCODE_TV_INPUT_HDMI_3, + KeyEvent.KEYCODE_TV_INPUT_HDMI_4, + KeyEvent.KEYCODE_TV_INPUT_COMPOSITE_1, + KeyEvent.KEYCODE_TV_INPUT_COMPOSITE_2, + KeyEvent.KEYCODE_TV_INPUT_COMPONENT_1, + KeyEvent.KEYCODE_TV_INPUT_COMPONENT_2, + KeyEvent.KEYCODE_TV_INPUT_VGA_1, + KeyEvent.KEYCODE_TV_AUDIO_DESCRIPTION, + KeyEvent.KEYCODE_TV_AUDIO_DESCRIPTION_MIX_UP, + KeyEvent.KEYCODE_TV_AUDIO_DESCRIPTION_MIX_DOWN, + KeyEvent.KEYCODE_TV_ZOOM_MODE, + KeyEvent.KEYCODE_TV_CONTENTS_MENU, + KeyEvent.KEYCODE_TV_MEDIA_CONTEXT_MENU, + KeyEvent.KEYCODE_TV_TIMER_PROGRAMMING, + KeyEvent.KEYCODE_HELP, + ) + + private val KEYCODES_API_23: Set + get() = setOf( + KeyEvent.KEYCODE_NAVIGATE_PREVIOUS, + KeyEvent.KEYCODE_NAVIGATE_NEXT, + KeyEvent.KEYCODE_NAVIGATE_IN, + KeyEvent.KEYCODE_NAVIGATE_OUT, + KeyEvent.KEYCODE_MEDIA_SKIP_FORWARD, + KeyEvent.KEYCODE_MEDIA_SKIP_BACKWARD, + KeyEvent.KEYCODE_MEDIA_STEP_FORWARD, + KeyEvent.KEYCODE_MEDIA_STEP_BACKWARD, + ) + + private val KEYCODES_API_24: Set + get() = setOf( + KeyEvent.KEYCODE_STEM_PRIMARY, + KeyEvent.KEYCODE_STEM_1, + KeyEvent.KEYCODE_STEM_2, + KeyEvent.KEYCODE_STEM_3, + KeyEvent.KEYCODE_DPAD_UP_LEFT, + KeyEvent.KEYCODE_DPAD_DOWN_LEFT, + KeyEvent.KEYCODE_DPAD_UP_RIGHT, + KeyEvent.KEYCODE_DPAD_DOWN_RIGHT, + KeyEvent.KEYCODE_SOFT_SLEEP, + KeyEvent.KEYCODE_CUT, + KeyEvent.KEYCODE_COPY, + KeyEvent.KEYCODE_PASTE, + ) + + private val KEYCODES_API_25: Set + get() = setOf( + KeyEvent.KEYCODE_SYSTEM_NAVIGATION_UP, + KeyEvent.KEYCODE_SYSTEM_NAVIGATION_DOWN, + KeyEvent.KEYCODE_SYSTEM_NAVIGATION_LEFT, + KeyEvent.KEYCODE_SYSTEM_NAVIGATION_RIGHT, + ) + + private val KEYCODES_API_28: Set + get() = setOf( + KeyEvent.KEYCODE_ALL_APPS, + ) + + /** + * These are key code maps for the getevent command. These names aren't the same as the + * KeyEvent key codes in the Android SDK so these have to be manually whitelisted + * as people need. + */ + val GET_EVENT_LABEL_TO_KEYCODE: List> = listOf( + "KEY_VOLUMEDOWN" to KeyEvent.KEYCODE_VOLUME_DOWN, + "KEY_VOLUMEUP" to KeyEvent.KEYCODE_VOLUME_UP, + "KEY_MEDIA" to KeyEvent.KEYCODE_HEADSETHOOK, + "KEY_HEADSETHOOK" to KeyEvent.KEYCODE_HEADSETHOOK, + "KEY_CAMERA_FOCUS" to KeyEvent.KEYCODE_FOCUS, + "02fe" to KeyEvent.KEYCODE_CAMERA, + "00fa" to KeyEvent.KEYCODE_CAMERA, + + // This kernel key event code seems to be the Bixby button + // but different ROMs have different key maps and so + // it is reported as different Android key codes. + "02bf" to KeyEvent.KEYCODE_MENU, + "02bf" to KeyEvent.KEYCODE_ASSIST, + + "KEY_SEARCH" to KeyEvent.KEYCODE_SEARCH, + ) + + fun canDetectKeyWhenScreenOff(keyCode: Int): Boolean = GET_EVENT_LABEL_TO_KEYCODE.any { it.second == keyCode } + + val MODIFIER_KEYCODES: Set + get() = setOf( + KeyEvent.KEYCODE_SHIFT_LEFT, + KeyEvent.KEYCODE_SHIFT_RIGHT, + KeyEvent.KEYCODE_ALT_LEFT, + KeyEvent.KEYCODE_ALT_RIGHT, + KeyEvent.KEYCODE_CTRL_LEFT, + KeyEvent.KEYCODE_CTRL_RIGHT, + KeyEvent.KEYCODE_META_LEFT, + KeyEvent.KEYCODE_META_RIGHT, + KeyEvent.KEYCODE_SYM, + KeyEvent.KEYCODE_NUM, + KeyEvent.KEYCODE_FUNCTION, + ) + + /** + * Used for keyCode to scanCode fallback to go past possible keyCode values + */ + val KEYCODE_TO_SCANCODE_OFFSET: Int = 1000 + + fun isModifierKey(keyCode: Int): Boolean = keyCode in MODIFIER_KEYCODES + + fun isGamepadKeyCode(keyCode: Int): Boolean { + when (keyCode) { + KeyEvent.KEYCODE_BUTTON_A, + KeyEvent.KEYCODE_BUTTON_B, + KeyEvent.KEYCODE_BUTTON_C, + KeyEvent.KEYCODE_BUTTON_X, + KeyEvent.KEYCODE_BUTTON_Y, + KeyEvent.KEYCODE_BUTTON_Z, + KeyEvent.KEYCODE_BUTTON_L1, + KeyEvent.KEYCODE_BUTTON_R1, + KeyEvent.KEYCODE_BUTTON_L2, + KeyEvent.KEYCODE_BUTTON_R2, + KeyEvent.KEYCODE_BUTTON_THUMBL, + KeyEvent.KEYCODE_BUTTON_THUMBR, + KeyEvent.KEYCODE_BUTTON_START, + KeyEvent.KEYCODE_BUTTON_SELECT, + KeyEvent.KEYCODE_BUTTON_MODE, + KeyEvent.KEYCODE_BUTTON_1, + KeyEvent.KEYCODE_BUTTON_2, + KeyEvent.KEYCODE_BUTTON_3, + KeyEvent.KEYCODE_BUTTON_4, + KeyEvent.KEYCODE_BUTTON_5, + KeyEvent.KEYCODE_BUTTON_6, + KeyEvent.KEYCODE_BUTTON_7, + KeyEvent.KEYCODE_BUTTON_8, + KeyEvent.KEYCODE_BUTTON_9, + KeyEvent.KEYCODE_BUTTON_10, + KeyEvent.KEYCODE_BUTTON_11, + KeyEvent.KEYCODE_BUTTON_12, + KeyEvent.KEYCODE_BUTTON_13, + KeyEvent.KEYCODE_BUTTON_14, + KeyEvent.KEYCODE_BUTTON_15, + KeyEvent.KEYCODE_BUTTON_16, + -> return true + + else -> return false + } + } + + /** + * Get all the valid key codes which work on the Android version for the device. + */ + fun getKeyCodes(): List { + val keyCodes = KEYCODES.toMutableList() + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + keyCodes.addAll(KEYCODES_API_23) + } + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + keyCodes.addAll(KEYCODES_API_24) + } + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) { + keyCodes.addAll(KEYCODES_API_25) + } + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { + keyCodes.addAll(KEYCODES_API_28) + } + + return keyCodes + } + + fun modifierKeycodeToMetaState(modifier: Int) = when (modifier) { + KeyEvent.KEYCODE_ALT_LEFT -> KeyEvent.META_ALT_LEFT_ON.withFlag(KeyEvent.META_ALT_ON) + KeyEvent.KEYCODE_ALT_RIGHT -> KeyEvent.META_ALT_RIGHT_ON.withFlag(KeyEvent.META_ALT_ON) + + KeyEvent.KEYCODE_SHIFT_LEFT -> KeyEvent.META_SHIFT_LEFT_ON.withFlag(KeyEvent.META_SHIFT_ON) + KeyEvent.KEYCODE_SHIFT_RIGHT -> KeyEvent.META_SHIFT_RIGHT_ON.withFlag(KeyEvent.META_SHIFT_ON) + + KeyEvent.KEYCODE_SYM -> KeyEvent.META_SYM_ON + + KeyEvent.KEYCODE_FUNCTION -> KeyEvent.META_FUNCTION_ON + + KeyEvent.KEYCODE_CTRL_LEFT -> KeyEvent.META_CTRL_LEFT_ON.withFlag(KeyEvent.META_CTRL_ON) + KeyEvent.KEYCODE_CTRL_RIGHT -> KeyEvent.META_CTRL_RIGHT_ON.withFlag(KeyEvent.META_CTRL_ON) + + KeyEvent.KEYCODE_META_LEFT -> KeyEvent.META_META_LEFT_ON.withFlag(KeyEvent.META_META_ON) + KeyEvent.KEYCODE_META_RIGHT -> KeyEvent.META_META_RIGHT_ON.withFlag(KeyEvent.META_META_ON) + + KeyEvent.KEYCODE_CAPS_LOCK -> KeyEvent.META_CAPS_LOCK_ON + KeyEvent.KEYCODE_NUM_LOCK -> KeyEvent.META_NUM_LOCK_ON + KeyEvent.KEYCODE_SCROLL_LOCK -> KeyEvent.META_SCROLL_LOCK_ON + + else -> throw Exception("can't convert modifier $modifier to meta state") + } + + fun isDpadKeyCode(code: Int): Boolean { + return code == KeyEvent.KEYCODE_DPAD_LEFT || + code == KeyEvent.KEYCODE_DPAD_RIGHT || + code == KeyEvent.KEYCODE_DPAD_UP || + code == KeyEvent.KEYCODE_DPAD_DOWN || + code == KeyEvent.KEYCODE_DPAD_UP_LEFT || + code == KeyEvent.KEYCODE_DPAD_UP_RIGHT || + code == KeyEvent.KEYCODE_DPAD_DOWN_LEFT || + code == KeyEvent.KEYCODE_DPAD_DOWN_RIGHT + } + + fun isDpadDevice(event: InputEvent): Boolean = // Check that input comes from a device with directional pads. + event.source and InputDevice.SOURCE_DPAD != InputDevice.SOURCE_DPAD + + fun isGamepadButton(keyCode: Int): Boolean { + return when (keyCode) { + KeyEvent.KEYCODE_BUTTON_A, + KeyEvent.KEYCODE_BUTTON_B, + KeyEvent.KEYCODE_BUTTON_C, + KeyEvent.KEYCODE_BUTTON_X, + KeyEvent.KEYCODE_BUTTON_Y, + KeyEvent.KEYCODE_BUTTON_Z, + KeyEvent.KEYCODE_BUTTON_L1, + KeyEvent.KEYCODE_BUTTON_R1, + KeyEvent.KEYCODE_BUTTON_L2, + KeyEvent.KEYCODE_BUTTON_R2, + KeyEvent.KEYCODE_BUTTON_THUMBL, + KeyEvent.KEYCODE_BUTTON_THUMBR, + KeyEvent.KEYCODE_BUTTON_START, + KeyEvent.KEYCODE_BUTTON_SELECT, + KeyEvent.KEYCODE_BUTTON_MODE, + KeyEvent.KEYCODE_BUTTON_1, + KeyEvent.KEYCODE_BUTTON_2, + KeyEvent.KEYCODE_BUTTON_3, + KeyEvent.KEYCODE_BUTTON_4, + KeyEvent.KEYCODE_BUTTON_5, + KeyEvent.KEYCODE_BUTTON_6, + KeyEvent.KEYCODE_BUTTON_7, + KeyEvent.KEYCODE_BUTTON_8, + KeyEvent.KEYCODE_BUTTON_9, + KeyEvent.KEYCODE_BUTTON_10, + KeyEvent.KEYCODE_BUTTON_11, + KeyEvent.KEYCODE_BUTTON_12, + KeyEvent.KEYCODE_BUTTON_13, + KeyEvent.KEYCODE_BUTTON_14, + KeyEvent.KEYCODE_BUTTON_15, + KeyEvent.KEYCODE_BUTTON_16, + -> true + + else -> false + } + } +} diff --git a/app/src/main/java/io/github/sds100/keymapper/system/inputevents/MyKeyEvent.kt b/system/src/main/java/io/github/sds100/keymapper/system/inputevents/MyKeyEvent.kt similarity index 100% rename from app/src/main/java/io/github/sds100/keymapper/system/inputevents/MyKeyEvent.kt rename to system/src/main/java/io/github/sds100/keymapper/system/inputevents/MyKeyEvent.kt diff --git a/app/src/main/java/io/github/sds100/keymapper/system/inputevents/MyMotionEvent.kt b/system/src/main/java/io/github/sds100/keymapper/system/inputevents/MyMotionEvent.kt similarity index 100% rename from app/src/main/java/io/github/sds100/keymapper/system/inputevents/MyMotionEvent.kt rename to system/src/main/java/io/github/sds100/keymapper/system/inputevents/MyMotionEvent.kt diff --git a/app/src/main/java/io/github/sds100/keymapper/system/inputmethod/AndroidInputMethodAdapter.kt b/system/src/main/java/io/github/sds100/keymapper/system/inputmethod/AndroidInputMethodAdapter.kt similarity index 78% rename from app/src/main/java/io/github/sds100/keymapper/system/inputmethod/AndroidInputMethodAdapter.kt rename to system/src/main/java/io/github/sds100/keymapper/system/inputmethod/AndroidInputMethodAdapter.kt index 65b99149e4..71da8a1a1d 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/inputmethod/AndroidInputMethodAdapter.kt +++ b/system/src/main/java/io/github/sds100/keymapper/system/inputmethod/AndroidInputMethodAdapter.kt @@ -13,23 +13,25 @@ import android.provider.Settings import android.view.inputmethod.InputMethodManager import androidx.core.content.ContextCompat import androidx.core.content.getSystemService -import io.github.sds100.keymapper.Constants +import dagger.hilt.android.qualifiers.ApplicationContext +import io.github.sds100.keymapper.common.BuildConfigProvider +import io.github.sds100.keymapper.common.utils.KMError +import io.github.sds100.keymapper.common.utils.KMResult +import io.github.sds100.keymapper.common.utils.Success +import io.github.sds100.keymapper.common.utils.onFailure +import io.github.sds100.keymapper.common.utils.onSuccess +import io.github.sds100.keymapper.common.utils.otherwise +import io.github.sds100.keymapper.common.utils.then +import io.github.sds100.keymapper.common.utils.valueOrNull import io.github.sds100.keymapper.system.JobSchedulerHelper import io.github.sds100.keymapper.system.SettingsUtils -import io.github.sds100.keymapper.system.accessibility.ServiceAdapter -import io.github.sds100.keymapper.system.accessibility.ServiceState +import io.github.sds100.keymapper.system.SystemError +import io.github.sds100.keymapper.system.accessibility.AccessibilityServiceAdapter +import io.github.sds100.keymapper.system.accessibility.AccessibilityServiceEvent +import io.github.sds100.keymapper.system.accessibility.AccessibilityServiceState import io.github.sds100.keymapper.system.permissions.Permission import io.github.sds100.keymapper.system.permissions.PermissionAdapter import io.github.sds100.keymapper.system.root.SuAdapter -import io.github.sds100.keymapper.util.Error -import io.github.sds100.keymapper.util.Result -import io.github.sds100.keymapper.util.ServiceEvent -import io.github.sds100.keymapper.util.Success -import io.github.sds100.keymapper.util.onFailure -import io.github.sds100.keymapper.util.onSuccess -import io.github.sds100.keymapper.util.otherwise -import io.github.sds100.keymapper.util.then -import io.github.sds100.keymapper.util.valueOrNull import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow @@ -44,17 +46,17 @@ import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch import kotlinx.coroutines.withTimeoutOrNull import timber.log.Timber +import javax.inject.Inject +import javax.inject.Singleton -/** - * Created by sds100 on 14/02/2021. - */ - -class AndroidInputMethodAdapter( - context: Context, +@Singleton +class AndroidInputMethodAdapter @Inject constructor( + @ApplicationContext private val context: Context, private val coroutineScope: CoroutineScope, - private val serviceAdapter: ServiceAdapter, + private val serviceAdapter: AccessibilityServiceAdapter, private val permissionAdapter: PermissionAdapter, private val suAdapter: SuAdapter, + private val buildConfigProvider: BuildConfigProvider, ) : InputMethodAdapter { companion object { @@ -99,7 +101,9 @@ class AndroidInputMethodAdapter( suspend fun invalidate() { when { Build.VERSION.SDK_INT >= Build.VERSION_CODES.R && - serviceAdapter.state.first() == ServiceState.ENABLED -> send(true) + serviceAdapter.state.first() == AccessibilityServiceState.ENABLED -> send( + true, + ) permissionAdapter.isGranted(Permission.WRITE_SECURE_SETTINGS) -> send(true) @@ -161,7 +165,7 @@ class AndroidInputMethodAdapter( ) } - override fun showImePicker(fromForeground: Boolean): Result<*> { + override fun showImePicker(fromForeground: Boolean): KMResult<*> { when { fromForeground || Build.VERSION.SDK_INT < Build.VERSION_CODES.O_MR1 -> { inputMethodManager.showInputMethodPicker() @@ -174,11 +178,11 @@ class AndroidInputMethodAdapter( return suAdapter.execute(command) } - else -> return Error.CantShowImePickerInBackground + else -> return KMError.CantShowImePickerInBackground } } - override suspend fun enableIme(imeId: String): Result<*> = enableImeWithoutUserInput(imeId).otherwise { + override suspend fun enableIme(imeId: String): KMResult<*> = enableImeWithoutUserInput(imeId).otherwise { try { val intent = Intent(Settings.ACTION_INPUT_METHOD_SETTINGS) intent.flags = Intent.FLAG_ACTIVITY_NO_HISTORY or Intent.FLAG_ACTIVITY_NEW_TASK @@ -186,24 +190,24 @@ class AndroidInputMethodAdapter( ctx.startActivity(intent) Success(Unit) } catch (e: Exception) { - Error.CantFindImeSettings + KMError.CantFindImeSettings } } - private suspend fun enableImeWithoutUserInput(imeId: String): Result<*> { - return getInfoByPackageName(Constants.PACKAGE_NAME).then { keyMapperImeInfo -> + private suspend fun enableImeWithoutUserInput(imeId: String): KMResult<*> { + return getInfoByPackageName(buildConfigProvider.packageName).then { keyMapperImeInfo -> if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU && imeId == keyMapperImeInfo.id) { - serviceAdapter.send(ServiceEvent.EnableInputMethod(keyMapperImeInfo.id)) + serviceAdapter.send(AccessibilityServiceEvent.EnableInputMethod(keyMapperImeInfo.id)) } else { suAdapter.execute("ime enable $imeId") } } } - override suspend fun chooseImeWithoutUserInput(imeId: String): Result { + override suspend fun chooseImeWithoutUserInput(imeId: String): KMResult { getInfoById(imeId).onSuccess { if (!it.isEnabled) { - return Error.ImeDisabled(it) + return SystemError.ImeDisabled(it) } }.onFailure { return it @@ -211,8 +215,8 @@ class AndroidInputMethodAdapter( var failed = true - if (failed && Build.VERSION.SDK_INT >= Build.VERSION_CODES.R && serviceAdapter.state.value == ServiceState.ENABLED) { - serviceAdapter.send(ServiceEvent.ChangeIme(imeId)).onSuccess { + if (failed && Build.VERSION.SDK_INT >= Build.VERSION_CODES.R && serviceAdapter.state.value == AccessibilityServiceState.ENABLED) { + serviceAdapter.send(AccessibilityServiceEvent.ChangeIme(imeId)).onSuccess { failed = false } } @@ -228,7 +232,7 @@ class AndroidInputMethodAdapter( } if (failed) { - return Error.FailedToChangeIme + return KMError.FailedToChangeIme } // wait for the ime to change and then return the info of the ime @@ -239,18 +243,18 @@ class AndroidInputMethodAdapter( if (didImeChange != null) { return Success(didImeChange) } else { - return Error.FailedToChangeIme + return KMError.FailedToChangeIme } } - override fun getInfoById(imeId: String): Result { + override fun getInfoById(imeId: String): KMResult { val info = - getInputMethods().find { it.id == imeId } ?: return Error.InputMethodNotFound(imeId) + getInputMethods().find { it.id == imeId } ?: return KMError.InputMethodNotFound(imeId) return Success(info) } - override fun getInfoByPackageName(packageName: String): Result = getImeId(packageName).then { getInfoById(it) } + override fun getInfoByPackageName(packageName: String): KMResult = getImeId(packageName).then { getInfoById(it) } /** * Example: @@ -300,12 +304,12 @@ class AndroidInputMethodAdapter( private fun getChosenImeId(): String = Settings.Secure.getString(ctx.contentResolver, Settings.Secure.DEFAULT_INPUT_METHOD) - private fun getImeId(packageName: String): Result { + private fun getImeId(packageName: String): KMResult { val imeId = inputMethodManager.inputMethodList.find { it.packageName == packageName }?.id return if (imeId == null) { - Error.InputMethodNotFound(packageName) + KMError.InputMethodNotFound(packageName) } else { Success(imeId) } diff --git a/app/src/main/java/io/github/sds100/keymapper/system/inputmethod/ImeInfo.kt b/system/src/main/java/io/github/sds100/keymapper/system/inputmethod/ImeInfo.kt similarity index 82% rename from app/src/main/java/io/github/sds100/keymapper/system/inputmethod/ImeInfo.kt rename to system/src/main/java/io/github/sds100/keymapper/system/inputmethod/ImeInfo.kt index c02f2b4511..bd9f86d066 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/inputmethod/ImeInfo.kt +++ b/system/src/main/java/io/github/sds100/keymapper/system/inputmethod/ImeInfo.kt @@ -1,8 +1,5 @@ package io.github.sds100.keymapper.system.inputmethod -/** - * Created by sds100 on 23/03/2021. - */ data class ImeInfo( val id: String, val packageName: String, diff --git a/app/src/main/java/io/github/sds100/keymapper/system/inputmethod/InputKeyModel.kt b/system/src/main/java/io/github/sds100/keymapper/system/inputmethod/InputKeyModel.kt similarity index 78% rename from app/src/main/java/io/github/sds100/keymapper/system/inputmethod/InputKeyModel.kt rename to system/src/main/java/io/github/sds100/keymapper/system/inputmethod/InputKeyModel.kt index 17e4a53871..1142fef197 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/inputmethod/InputKeyModel.kt +++ b/system/src/main/java/io/github/sds100/keymapper/system/inputmethod/InputKeyModel.kt @@ -1,11 +1,8 @@ package io.github.sds100.keymapper.system.inputmethod import android.view.InputDevice -import io.github.sds100.keymapper.util.InputEventType +import io.github.sds100.keymapper.common.utils.InputEventType -/** - * Created by sds100 on 21/04/2021. - */ data class InputKeyModel( val keyCode: Int, val inputType: InputEventType = InputEventType.DOWN_UP, diff --git a/app/src/main/java/io/github/sds100/keymapper/system/inputmethod/InputMethodAdapter.kt b/system/src/main/java/io/github/sds100/keymapper/system/inputmethod/InputMethodAdapter.kt similarity index 51% rename from app/src/main/java/io/github/sds100/keymapper/system/inputmethod/InputMethodAdapter.kt rename to system/src/main/java/io/github/sds100/keymapper/system/inputmethod/InputMethodAdapter.kt index 1b0257b4b3..07ef2b30a2 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/inputmethod/InputMethodAdapter.kt +++ b/system/src/main/java/io/github/sds100/keymapper/system/inputmethod/InputMethodAdapter.kt @@ -1,22 +1,19 @@ package io.github.sds100.keymapper.system.inputmethod -import io.github.sds100.keymapper.util.Result +import io.github.sds100.keymapper.common.utils.KMResult import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.StateFlow -/** - * Created by sds100 on 14/02/2021. - */ interface InputMethodAdapter { val isUserInputRequiredToChangeIme: Flow - fun showImePicker(fromForeground: Boolean): Result<*> - suspend fun enableIme(imeId: String): Result<*> + fun showImePicker(fromForeground: Boolean): KMResult<*> + suspend fun enableIme(imeId: String): KMResult<*> - suspend fun chooseImeWithoutUserInput(imeId: String): Result + suspend fun chooseImeWithoutUserInput(imeId: String): KMResult - fun getInfoById(imeId: String): Result - fun getInfoByPackageName(packageName: String): Result + fun getInfoById(imeId: String): KMResult + fun getInfoByPackageName(packageName: String): KMResult /** * The last used input method is first. diff --git a/app/src/main/java/io/github/sds100/keymapper/api/KeyEventRelayServiceWrapper.kt b/system/src/main/java/io/github/sds100/keymapper/system/inputmethod/KeyEventRelayServiceWrapper.kt similarity index 88% rename from app/src/main/java/io/github/sds100/keymapper/api/KeyEventRelayServiceWrapper.kt rename to system/src/main/java/io/github/sds100/keymapper/system/inputmethod/KeyEventRelayServiceWrapper.kt index c65f15673b..24dccae1b1 100644 --- a/app/src/main/java/io/github/sds100/keymapper/api/KeyEventRelayServiceWrapper.kt +++ b/system/src/main/java/io/github/sds100/keymapper/system/inputmethod/KeyEventRelayServiceWrapper.kt @@ -1,4 +1,4 @@ -package io.github.sds100.keymapper.api +package io.github.sds100.keymapper.system.inputmethod import android.content.ComponentName import android.content.Context @@ -9,6 +9,9 @@ import android.os.IBinder import android.os.RemoteException import android.view.KeyEvent import android.view.MotionEvent +import io.github.sds100.keymapper.api.IKeyEventRelayService +import io.github.sds100.keymapper.api.IKeyEventRelayServiceCallback +import io.github.sds100.keymapper.system.inputmethod.KeyEventRelayServiceWrapper /** * This handles connecting to the relay service and exposes an interface @@ -18,6 +21,7 @@ import android.view.MotionEvent class KeyEventRelayServiceWrapperImpl( private val ctx: Context, private val id: String, + private val servicePackageName: String, private val callback: IKeyEventRelayServiceCallback, ) : KeyEventRelayServiceWrapper { @@ -91,7 +95,10 @@ class KeyEventRelayServiceWrapperImpl( private fun bind() { try { - val relayServiceIntent = Intent(ctx, KeyEventRelayService::class.java) + val relayServiceIntent = Intent() + val component = + ComponentName(servicePackageName, "io.github.sds100.keymapper.api.KeyEventRelayService") + relayServiceIntent.setComponent(component) val isSuccess = ctx.bindService(relayServiceIntent, serviceConnection, Context.BIND_AUTO_CREATE) @@ -124,4 +131,4 @@ class KeyEventRelayServiceWrapperImpl( interface KeyEventRelayServiceWrapper { fun sendKeyEvent(event: KeyEvent, targetPackageName: String, callbackId: String): Boolean fun sendMotionEvent(event: MotionEvent, targetPackageName: String, callbackId: String): Boolean -} +} \ No newline at end of file diff --git a/app/src/main/java/io/github/sds100/keymapper/system/inputmethod/KeyMapperImeService.kt b/system/src/main/java/io/github/sds100/keymapper/system/inputmethod/KeyMapperImeService.kt similarity index 88% rename from app/src/main/java/io/github/sds100/keymapper/system/inputmethod/KeyMapperImeService.kt rename to system/src/main/java/io/github/sds100/keymapper/system/inputmethod/KeyMapperImeService.kt index 20f63ce5a7..470d1707c5 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/inputmethod/KeyMapperImeService.kt +++ b/system/src/main/java/io/github/sds100/keymapper/system/inputmethod/KeyMapperImeService.kt @@ -16,15 +16,16 @@ import android.view.inputmethod.EditorInfo import android.view.inputmethod.InputMethodManager import androidx.core.content.ContextCompat import androidx.core.content.getSystemService -import io.github.sds100.keymapper.Constants +import dagger.hilt.android.AndroidEntryPoint import io.github.sds100.keymapper.api.IKeyEventRelayServiceCallback -import io.github.sds100.keymapper.api.KeyEventRelayService -import io.github.sds100.keymapper.api.KeyEventRelayServiceWrapperImpl +import io.github.sds100.keymapper.common.BuildConfigProvider +import javax.inject.Inject /** - * Created by sds100 on 31/03/2020. + * DO NOT MOVE. Must stay in this package so the user's input method settings are not reset + * when the component name changes. */ - +@AndroidEntryPoint class KeyMapperImeService : InputMethodService() { companion object { @@ -42,8 +43,13 @@ class KeyMapperImeService : InputMethodService() { "io.github.sds100.keymapper.inputmethod.EXTRA_TEXT" const val KEY_MAPPER_INPUT_METHOD_EXTRA_KEY_EVENT = "io.github.sds100.keymapper.inputmethod.EXTRA_KEY_EVENT" + + private const val CALLBACK_ID_ACCESSIBILITY_SERVICE = "accessibility_service" + private const val CALLBACK_ID_INPUT_METHOD = "input_method" } + @Inject + lateinit var buildConfigProvider: BuildConfigProvider private val userManager: UserManager? by lazy { getSystemService() } private val inputMethodManager: InputMethodManager? by lazy { getSystemService() @@ -113,7 +119,8 @@ class KeyMapperImeService : InputMethodService() { private val keyEventRelayServiceWrapper: KeyEventRelayServiceWrapperImpl by lazy { KeyEventRelayServiceWrapperImpl( ctx = this, - id = KeyEventRelayService.CALLBACK_ID_INPUT_METHOD, + id = CALLBACK_ID_INPUT_METHOD, + servicePackageName = buildConfigProvider.packageName, callback = keyEventReceiverCallback, ) } @@ -159,8 +166,8 @@ class KeyMapperImeService : InputMethodService() { val consume = keyEventRelayServiceWrapper.sendMotionEvent( event = event, - targetPackageName = Constants.PACKAGE_NAME, - callbackId = KeyEventRelayService.CALLBACK_ID_ACCESSIBILITY_SERVICE, + targetPackageName = buildConfigProvider.packageName, + callbackId = CALLBACK_ID_ACCESSIBILITY_SERVICE, ) return if (consume) { @@ -175,8 +182,8 @@ class KeyMapperImeService : InputMethodService() { val consume = keyEventRelayServiceWrapper.sendKeyEvent( event = event, - targetPackageName = Constants.PACKAGE_NAME, - callbackId = KeyEventRelayService.CALLBACK_ID_ACCESSIBILITY_SERVICE, + targetPackageName = buildConfigProvider.packageName, + callbackId = CALLBACK_ID_ACCESSIBILITY_SERVICE, ) return if (consume) { @@ -191,8 +198,8 @@ class KeyMapperImeService : InputMethodService() { val consume = keyEventRelayServiceWrapper.sendKeyEvent( event = event, - targetPackageName = Constants.PACKAGE_NAME, - callbackId = KeyEventRelayService.CALLBACK_ID_ACCESSIBILITY_SERVICE, + targetPackageName = buildConfigProvider.packageName, + callbackId = CALLBACK_ID_ACCESSIBILITY_SERVICE, ) return if (consume) { diff --git a/app/src/main/java/io/github/sds100/keymapper/system/inputmethod/ObserveInputMethodsJob.kt b/system/src/main/java/io/github/sds100/keymapper/system/inputmethod/ObserveInputMethodsJob.kt similarity index 71% rename from app/src/main/java/io/github/sds100/keymapper/system/inputmethod/ObserveInputMethodsJob.kt rename to system/src/main/java/io/github/sds100/keymapper/system/inputmethod/ObserveInputMethodsJob.kt index 48ccaad53d..d571e37950 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/inputmethod/ObserveInputMethodsJob.kt +++ b/system/src/main/java/io/github/sds100/keymapper/system/inputmethod/ObserveInputMethodsJob.kt @@ -3,15 +3,19 @@ package io.github.sds100.keymapper.system.inputmethod import android.app.job.JobParameters import android.app.job.JobService import android.os.Build -import io.github.sds100.keymapper.KeyMapperApp +import dagger.hilt.android.AndroidEntryPoint import io.github.sds100.keymapper.system.JobSchedulerHelper +import javax.inject.Inject -/** - * Created by sds100 on 02/04/2021. - */ +@AndroidEntryPoint class ObserveInputMethodsJob : JobService() { + + @Inject + lateinit var inputMethodAdapter: AndroidInputMethodAdapter + override fun onStartJob(params: JobParameters?): Boolean { - (applicationContext as KeyMapperApp).inputMethodAdapter.onInputMethodsUpdate() + inputMethodAdapter.onInputMethodsUpdate() + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { JobSchedulerHelper.observeInputMethods(applicationContext) } diff --git a/app/src/main/java/io/github/sds100/keymapper/system/intents/IntentAdapter.kt b/system/src/main/java/io/github/sds100/keymapper/system/intents/IntentAdapter.kt similarity index 67% rename from app/src/main/java/io/github/sds100/keymapper/system/intents/IntentAdapter.kt rename to system/src/main/java/io/github/sds100/keymapper/system/intents/IntentAdapter.kt index c57191588f..ebb6d120d1 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/intents/IntentAdapter.kt +++ b/system/src/main/java/io/github/sds100/keymapper/system/intents/IntentAdapter.kt @@ -2,22 +2,22 @@ package io.github.sds100.keymapper.system.intents import android.content.Context import android.content.Intent -import io.github.sds100.keymapper.util.Error -import io.github.sds100.keymapper.util.Result -import io.github.sds100.keymapper.util.Success - -/** - * Created by sds100 on 21/04/2021. - */ - -class IntentAdapterImpl(context: Context) : IntentAdapter { +import dagger.hilt.android.qualifiers.ApplicationContext +import io.github.sds100.keymapper.common.utils.KMError +import io.github.sds100.keymapper.common.utils.KMResult +import io.github.sds100.keymapper.common.utils.Success +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class IntentAdapterImpl @Inject constructor(@ApplicationContext private val context: Context) : IntentAdapter { private val ctx = context.applicationContext override fun send( target: IntentTarget, uri: String, extras: List, - ): Result<*> { + ): KMResult<*> { val intent = Intent.parseUri(uri, 0) extras.forEach { e -> @@ -39,11 +39,11 @@ class IntentAdapterImpl(context: Context) : IntentAdapter { } return Success(Unit) } catch (e: Exception) { - return Error.Exception(e) + return KMError.Exception(e) } } } interface IntentAdapter { - fun send(target: IntentTarget, uri: String, extras: List): Result<*> + fun send(target: IntentTarget, uri: String, extras: List): KMResult<*> } diff --git a/app/src/main/java/io/github/sds100/keymapper/system/intents/IntentExtraListItem.kt b/system/src/main/java/io/github/sds100/keymapper/system/intents/IntentExtraListItem.kt similarity index 93% rename from app/src/main/java/io/github/sds100/keymapper/system/intents/IntentExtraListItem.kt rename to system/src/main/java/io/github/sds100/keymapper/system/intents/IntentExtraListItem.kt index 10c7a03905..83d70ae599 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/intents/IntentExtraListItem.kt +++ b/system/src/main/java/io/github/sds100/keymapper/system/intents/IntentExtraListItem.kt @@ -1,9 +1,5 @@ package io.github.sds100.keymapper.system.intents -/** - * Created by sds100 on 01/01/21. - */ - // don't factor out properties because otherwise the Epoxyrecyclerview doesn't update when the // model changes sealed class IntentExtraListItem { diff --git a/app/src/main/java/io/github/sds100/keymapper/system/intents/IntentExtraModel.kt b/system/src/main/java/io/github/sds100/keymapper/system/intents/IntentExtraModel.kt similarity index 91% rename from app/src/main/java/io/github/sds100/keymapper/system/intents/IntentExtraModel.kt rename to system/src/main/java/io/github/sds100/keymapper/system/intents/IntentExtraModel.kt index 3b23af3582..46f4ec46d8 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/intents/IntentExtraModel.kt +++ b/system/src/main/java/io/github/sds100/keymapper/system/intents/IntentExtraModel.kt @@ -3,9 +3,6 @@ package io.github.sds100.keymapper.system.intents import kotlinx.serialization.Serializable import java.util.UUID -/** - * Created by sds100 on 01/01/21. - */ @Serializable data class IntentExtraModel( val type: IntentExtraType, diff --git a/app/src/main/java/io/github/sds100/keymapper/system/intents/IntentExtraType.kt b/system/src/main/java/io/github/sds100/keymapper/system/intents/IntentExtraType.kt similarity index 63% rename from app/src/main/java/io/github/sds100/keymapper/system/intents/IntentExtraType.kt rename to system/src/main/java/io/github/sds100/keymapper/system/intents/IntentExtraType.kt index 832c2effd6..5d127d1f9d 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/intents/IntentExtraType.kt +++ b/system/src/main/java/io/github/sds100/keymapper/system/intents/IntentExtraType.kt @@ -1,19 +1,10 @@ package io.github.sds100.keymapper.system.intents import android.content.Intent -import io.github.sds100.keymapper.R import kotlinx.serialization.Serializable -import kotlinx.serialization.Transient - -/** - * Created by sds100 on 01/01/21. - */ @Serializable sealed class IntentExtraType { - abstract val labelStringRes: Int - abstract val exampleStringRes: Int - abstract fun putInIntent(intent: Intent, name: String, value: String) /** @@ -25,13 +16,7 @@ sealed class IntentExtraType { } @Serializable -class BoolExtraType : IntentExtraType() { - @Transient - override val labelStringRes = R.string.intent_type_bool_header - - @Transient - override val exampleStringRes = R.string.intent_type_bool_example - +data object BoolExtraType : IntentExtraType() { override fun putInIntent(intent: Intent, name: String, value: String) { intent.putExtra(name, parse(value)) } @@ -44,13 +29,7 @@ class BoolExtraType : IntentExtraType() { } @Serializable -class BoolArrayExtraType : IntentExtraType() { - @Transient - override val labelStringRes = R.string.intent_type_bool_array_header - - @Transient - override val exampleStringRes = R.string.intent_type_bool_array_example - +data object BoolArrayExtraType : IntentExtraType() { override fun putInIntent(intent: Intent, name: String, value: String) { intent.putExtra(name, parse(value)) } @@ -71,13 +50,7 @@ class BoolArrayExtraType : IntentExtraType() { } @Serializable -class IntExtraType : IntentExtraType() { - @Transient - override val labelStringRes = R.string.intent_type_int_header - - @Transient - override val exampleStringRes = R.string.intent_type_int_example - +data object IntExtraType : IntentExtraType() { override fun putInIntent(intent: Intent, name: String, value: String) { intent.putExtra(name, parse(value)) } @@ -90,13 +63,7 @@ class IntExtraType : IntentExtraType() { } @Serializable -class IntArrayExtraType : IntentExtraType() { - @Transient - override val labelStringRes = R.string.intent_type_int_array_header - - @Transient - override val exampleStringRes = R.string.intent_type_int_array_example - +data object IntArrayExtraType : IntentExtraType() { override fun putInIntent(intent: Intent, name: String, value: String) { intent.putExtra(name, parse(value)) } @@ -117,13 +84,7 @@ class IntArrayExtraType : IntentExtraType() { } @Serializable -class StringExtraType : IntentExtraType() { - @Transient - override val labelStringRes = R.string.intent_type_string_header - - @Transient - override val exampleStringRes = R.string.intent_type_string_example - +data object StringExtraType : IntentExtraType() { override fun putInIntent(intent: Intent, name: String, value: String) { intent.putExtra(name, parse(value)) } @@ -132,13 +93,7 @@ class StringExtraType : IntentExtraType() { } @Serializable -class StringArrayExtraType : IntentExtraType() { - @Transient - override val labelStringRes = R.string.intent_type_string_array_header - - @Transient - override val exampleStringRes = R.string.intent_type_string_array_example - +data object StringArrayExtraType : IntentExtraType() { override fun putInIntent(intent: Intent, name: String, value: String) { intent.putExtra(name, parse(value)) } @@ -153,13 +108,7 @@ class StringArrayExtraType : IntentExtraType() { } @Serializable -class LongExtraType : IntentExtraType() { - @Transient - override val labelStringRes = R.string.intent_type_long_header - - @Transient - override val exampleStringRes = R.string.intent_type_long_example - +data object LongExtraType : IntentExtraType() { override fun putInIntent(intent: Intent, name: String, value: String) { intent.putExtra(name, parse(value)) } @@ -172,13 +121,7 @@ class LongExtraType : IntentExtraType() { } @Serializable -class LongArrayExtraType : IntentExtraType() { - @Transient - override val labelStringRes = R.string.intent_type_long_array_header - - @Transient - override val exampleStringRes = R.string.intent_type_long_array_example - +data object LongArrayExtraType : IntentExtraType() { override fun putInIntent(intent: Intent, name: String, value: String) { intent.putExtra(name, parse(value)) } @@ -199,13 +142,7 @@ class LongArrayExtraType : IntentExtraType() { } @Serializable -class ByteExtraType : IntentExtraType() { - @Transient - override val labelStringRes = R.string.intent_type_byte_header - - @Transient - override val exampleStringRes = R.string.intent_type_byte_example - +data object ByteExtraType : IntentExtraType() { override fun putInIntent(intent: Intent, name: String, value: String) { intent.putExtra(name, parse(value)) } @@ -218,13 +155,7 @@ class ByteExtraType : IntentExtraType() { } @Serializable -class ByteArrayExtraType : IntentExtraType() { - @Transient - override val labelStringRes = R.string.intent_type_byte_array_header - - @Transient - override val exampleStringRes = R.string.intent_type_byte_array_example - +data object ByteArrayExtraType : IntentExtraType() { override fun putInIntent(intent: Intent, name: String, value: String) { intent.putExtra(name, parse(value)) } @@ -245,13 +176,7 @@ class ByteArrayExtraType : IntentExtraType() { } @Serializable -class DoubleExtraType : IntentExtraType() { - @Transient - override val labelStringRes = R.string.intent_type_double_header - - @Transient - override val exampleStringRes = R.string.intent_type_double_example - +data object DoubleExtraType : IntentExtraType() { override fun putInIntent(intent: Intent, name: String, value: String) { intent.putExtra(name, parse(value)) } @@ -264,13 +189,7 @@ class DoubleExtraType : IntentExtraType() { } @Serializable -class DoubleArrayExtraType : IntentExtraType() { - @Transient - override val labelStringRes = R.string.intent_type_double_array_header - - @Transient - override val exampleStringRes = R.string.intent_type_double_array_example - +data object DoubleArrayExtraType : IntentExtraType() { override fun putInIntent(intent: Intent, name: String, value: String) { intent.putExtra(name, parse(value)) } @@ -291,13 +210,7 @@ class DoubleArrayExtraType : IntentExtraType() { } @Serializable -class CharExtraType : IntentExtraType() { - @Transient - override val labelStringRes = R.string.intent_type_char_header - - @Transient - override val exampleStringRes = R.string.intent_type_char_example - +data object CharExtraType : IntentExtraType() { override fun putInIntent(intent: Intent, name: String, value: String) { intent.putExtra(name, parse(value)) } @@ -310,13 +223,7 @@ class CharExtraType : IntentExtraType() { } @Serializable -class CharArrayExtraType : IntentExtraType() { - @Transient - override val labelStringRes = R.string.intent_type_char_array_header - - @Transient - override val exampleStringRes = R.string.intent_type_char_array_example - +data object CharArrayExtraType : IntentExtraType() { override fun putInIntent(intent: Intent, name: String, value: String) { intent.putExtra(name, parse(value)) } @@ -337,13 +244,7 @@ class CharArrayExtraType : IntentExtraType() { } @Serializable -class FloatExtraType : IntentExtraType() { - @Transient - override val labelStringRes = R.string.intent_type_float_header - - @Transient - override val exampleStringRes = R.string.intent_type_float_example - +data object FloatExtraType : IntentExtraType() { override fun putInIntent(intent: Intent, name: String, value: String) { intent.putExtra(name, parse(value)) } @@ -356,13 +257,7 @@ class FloatExtraType : IntentExtraType() { } @Serializable -class FloatArrayExtraType : IntentExtraType() { - @Transient - override val labelStringRes = R.string.intent_type_float_array_header - - @Transient - override val exampleStringRes = R.string.intent_type_float_array_example - +data object FloatArrayExtraType : IntentExtraType() { override fun putInIntent(intent: Intent, name: String, value: String) { intent.putExtra(name, parse(value)) } @@ -383,13 +278,7 @@ class FloatArrayExtraType : IntentExtraType() { } @Serializable -class ShortExtraType : IntentExtraType() { - @Transient - override val labelStringRes = R.string.intent_type_short_header - - @Transient - override val exampleStringRes = R.string.intent_type_short_example - +data object ShortExtraType : IntentExtraType() { override fun putInIntent(intent: Intent, name: String, value: String) { intent.putExtra(name, parse(value)) } @@ -402,13 +291,7 @@ class ShortExtraType : IntentExtraType() { } @Serializable -class ShortArrayExtraType : IntentExtraType() { - @Transient - override val labelStringRes = R.string.intent_type_short_array_header - - @Transient - override val exampleStringRes = R.string.intent_type_short_array_example - +data object ShortArrayExtraType : IntentExtraType() { override fun putInIntent(intent: Intent, name: String, value: String) { intent.putExtra(name, parse(value)) } diff --git a/app/src/main/java/io/github/sds100/keymapper/system/intents/IntentTarget.kt b/system/src/main/java/io/github/sds100/keymapper/system/intents/IntentTarget.kt similarity index 75% rename from app/src/main/java/io/github/sds100/keymapper/system/intents/IntentTarget.kt rename to system/src/main/java/io/github/sds100/keymapper/system/intents/IntentTarget.kt index 9a79d3ed43..4592167cd6 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/intents/IntentTarget.kt +++ b/system/src/main/java/io/github/sds100/keymapper/system/intents/IntentTarget.kt @@ -1,8 +1,5 @@ package io.github.sds100.keymapper.system.intents -/** - * Created by sds100 on 05/01/21. - */ enum class IntentTarget { ACTIVITY, BROADCAST_RECEIVER, diff --git a/app/src/main/java/io/github/sds100/keymapper/system/leanback/LeanbackAdapter.kt b/system/src/main/java/io/github/sds100/keymapper/system/leanback/LeanbackAdapter.kt similarity index 69% rename from app/src/main/java/io/github/sds100/keymapper/system/leanback/LeanbackAdapter.kt rename to system/src/main/java/io/github/sds100/keymapper/system/leanback/LeanbackAdapter.kt index fda2f7d576..059208e275 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/leanback/LeanbackAdapter.kt +++ b/system/src/main/java/io/github/sds100/keymapper/system/leanback/LeanbackAdapter.kt @@ -4,12 +4,14 @@ import android.app.UiModeManager import android.content.Context import android.content.res.Configuration import androidx.core.content.getSystemService +import dagger.hilt.android.qualifiers.ApplicationContext +import javax.inject.Inject +import javax.inject.Singleton -/** - * Created by sds100 on 21/07/2021. - */ - -class LeanbackAdapterImpl(context: Context) : LeanbackAdapter { +@Singleton +class LeanbackAdapterImpl @Inject constructor( + @ApplicationContext context: Context, +) : LeanbackAdapter { private val ctx = context.applicationContext override fun isTvDevice(): Boolean { diff --git a/app/src/main/java/io/github/sds100/keymapper/system/leanback/LeanbackUtils.kt b/system/src/main/java/io/github/sds100/keymapper/system/leanback/LeanbackUtils.kt similarity index 91% rename from app/src/main/java/io/github/sds100/keymapper/system/leanback/LeanbackUtils.kt rename to system/src/main/java/io/github/sds100/keymapper/system/leanback/LeanbackUtils.kt index 7102875c9d..b146648113 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/leanback/LeanbackUtils.kt +++ b/system/src/main/java/io/github/sds100/keymapper/system/leanback/LeanbackUtils.kt @@ -5,9 +5,6 @@ import android.content.Context import android.content.res.Configuration import androidx.core.content.getSystemService -/** - * Created by sds100 on 17/06/2021. - */ object LeanbackUtils { fun isTvDevice(ctx: Context): Boolean { val uiModeManager = ctx.getSystemService() ?: return false diff --git a/app/src/main/java/io/github/sds100/keymapper/system/lock/AndroidLockScreenAdapter.kt b/system/src/main/java/io/github/sds100/keymapper/system/lock/AndroidLockScreenAdapter.kt similarity index 88% rename from app/src/main/java/io/github/sds100/keymapper/system/lock/AndroidLockScreenAdapter.kt rename to system/src/main/java/io/github/sds100/keymapper/system/lock/AndroidLockScreenAdapter.kt index 6b4fb1ec7b..2674c3081f 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/lock/AndroidLockScreenAdapter.kt +++ b/system/src/main/java/io/github/sds100/keymapper/system/lock/AndroidLockScreenAdapter.kt @@ -10,17 +10,15 @@ import android.os.Build import androidx.annotation.RequiresApi import androidx.core.content.ContextCompat import androidx.core.content.getSystemService -import io.github.sds100.keymapper.util.Result -import io.github.sds100.keymapper.util.Success +import dagger.hilt.android.qualifiers.ApplicationContext +import io.github.sds100.keymapper.common.utils.KMResult +import io.github.sds100.keymapper.common.utils.Success import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.update +import javax.inject.Inject -/** - * Created by sds100 on 22/04/2021. - */ -class AndroidLockScreenAdapter(context: Context) : LockScreenAdapter { - private val ctx = context.applicationContext +class AndroidLockScreenAdapter @Inject constructor(@ApplicationContext private val ctx: Context) : LockScreenAdapter { private val devicePolicyManager: DevicePolicyManager by lazy { ctx.getSystemService()!! } private val keyguardManager: KeyguardManager by lazy { ctx.getSystemService()!! } @@ -77,7 +75,7 @@ class AndroidLockScreenAdapter(context: Context) : LockScreenAdapter { override fun isLockedFlow(): Flow = isLockedFlow - override fun secureLockDevice(): Result<*> { + override fun secureLockDevice(): KMResult<*> { devicePolicyManager.lockNow() return Success(Unit) } diff --git a/app/src/main/java/io/github/sds100/keymapper/system/lock/LockScreenAdapter.kt b/system/src/main/java/io/github/sds100/keymapper/system/lock/LockScreenAdapter.kt similarity index 77% rename from app/src/main/java/io/github/sds100/keymapper/system/lock/LockScreenAdapter.kt rename to system/src/main/java/io/github/sds100/keymapper/system/lock/LockScreenAdapter.kt index ef1ca69e0f..2823fbe325 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/lock/LockScreenAdapter.kt +++ b/system/src/main/java/io/github/sds100/keymapper/system/lock/LockScreenAdapter.kt @@ -2,14 +2,12 @@ package io.github.sds100.keymapper.system.lock import android.os.Build import androidx.annotation.RequiresApi -import io.github.sds100.keymapper.util.Result +import io.github.sds100.keymapper.common.utils.KMResult import kotlinx.coroutines.flow.Flow -/** - * Created by sds100 on 20/04/2021. - */ + interface LockScreenAdapter { - fun secureLockDevice(): Result<*> + fun secureLockDevice(): KMResult<*> @RequiresApi(Build.VERSION_CODES.LOLLIPOP_MR1) fun isLocked(): Boolean diff --git a/app/src/main/java/io/github/sds100/keymapper/system/media/AndroidMediaAdapter.kt b/system/src/main/java/io/github/sds100/keymapper/system/media/AndroidMediaAdapter.kt similarity index 74% rename from app/src/main/java/io/github/sds100/keymapper/system/media/AndroidMediaAdapter.kt rename to system/src/main/java/io/github/sds100/keymapper/system/media/AndroidMediaAdapter.kt index 3886863a38..d764a2945e 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/media/AndroidMediaAdapter.kt +++ b/system/src/main/java/io/github/sds100/keymapper/system/media/AndroidMediaAdapter.kt @@ -12,10 +12,10 @@ import android.os.Build import android.view.KeyEvent import androidx.annotation.RequiresApi import androidx.core.content.getSystemService +import io.github.sds100.keymapper.common.utils.KMError +import io.github.sds100.keymapper.common.utils.KMResult +import io.github.sds100.keymapper.common.utils.Success import io.github.sds100.keymapper.system.volume.VolumeStream -import io.github.sds100.keymapper.util.Error -import io.github.sds100.keymapper.util.Result -import io.github.sds100.keymapper.util.Success import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow @@ -23,11 +23,15 @@ import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch import java.io.FileNotFoundException - -/** - * Created by sds100 on 21/04/2021. - */ -class AndroidMediaAdapter(context: Context, coroutineScope: CoroutineScope) : MediaAdapter { +import dagger.hilt.android.qualifiers.ApplicationContext +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class AndroidMediaAdapter @Inject constructor( + @ApplicationContext private val context: Context, + private val coroutineScope: CoroutineScope +) : MediaAdapter { private val ctx = context.applicationContext private val audioManager: AudioManager by lazy { ctx.getSystemService()!! } @@ -68,23 +72,23 @@ class AndroidMediaAdapter(context: Context, coroutineScope: CoroutineScope) : Me } } - override fun fastForward(packageName: String?): Result<*> = sendMediaKeyEvent(KeyEvent.KEYCODE_MEDIA_FAST_FORWARD, packageName) + override fun fastForward(packageName: String?): KMResult<*> = sendMediaKeyEvent(KeyEvent.KEYCODE_MEDIA_FAST_FORWARD, packageName) - override fun rewind(packageName: String?): Result<*> = sendMediaKeyEvent(KeyEvent.KEYCODE_MEDIA_REWIND, packageName) + override fun rewind(packageName: String?): KMResult<*> = sendMediaKeyEvent(KeyEvent.KEYCODE_MEDIA_REWIND, packageName) - override fun play(packageName: String?): Result<*> = sendMediaKeyEvent(KeyEvent.KEYCODE_MEDIA_PLAY, packageName) + override fun play(packageName: String?): KMResult<*> = sendMediaKeyEvent(KeyEvent.KEYCODE_MEDIA_PLAY, packageName) - override fun pause(packageName: String?): Result<*> = sendMediaKeyEvent(KeyEvent.KEYCODE_MEDIA_PAUSE, packageName) + override fun pause(packageName: String?): KMResult<*> = sendMediaKeyEvent(KeyEvent.KEYCODE_MEDIA_PAUSE, packageName) - override fun playPause(packageName: String?): Result<*> = sendMediaKeyEvent(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE, packageName) + override fun playPause(packageName: String?): KMResult<*> = sendMediaKeyEvent(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE, packageName) - override fun previousTrack(packageName: String?): Result<*> = sendMediaKeyEvent(KeyEvent.KEYCODE_MEDIA_PREVIOUS, packageName) + override fun previousTrack(packageName: String?): KMResult<*> = sendMediaKeyEvent(KeyEvent.KEYCODE_MEDIA_PREVIOUS, packageName) - override fun nextTrack(packageName: String?): Result<*> = sendMediaKeyEvent(KeyEvent.KEYCODE_MEDIA_NEXT, packageName) + override fun nextTrack(packageName: String?): KMResult<*> = sendMediaKeyEvent(KeyEvent.KEYCODE_MEDIA_NEXT, packageName) - override fun stop(packageName: String?): Result<*> = sendMediaKeyEvent(KeyEvent.KEYCODE_MEDIA_STOP, packageName) + override fun stop(packageName: String?): KMResult<*> = sendMediaKeyEvent(KeyEvent.KEYCODE_MEDIA_STOP, packageName) - override fun stopFileMedia(): Result<*> { + override fun stopFileMedia(): KMResult<*> { synchronized(mediaPlayerLock) { mediaPlayer?.stop() mediaPlayer?.release() @@ -94,19 +98,19 @@ class AndroidMediaAdapter(context: Context, coroutineScope: CoroutineScope) : Me return Success(Unit) } - override fun stepForward(packageName: String?): Result<*> { + override fun stepForward(packageName: String?): KMResult<*> { return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { sendMediaKeyEvent(KeyEvent.KEYCODE_MEDIA_STEP_FORWARD, packageName) } else { - return Error.SdkVersionTooLow(Build.VERSION_CODES.M) + return KMError.SdkVersionTooLow(Build.VERSION_CODES.M) } } - override fun stepBackward(packageName: String?): Result<*> { + override fun stepBackward(packageName: String?): KMResult<*> { return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { sendMediaKeyEvent(KeyEvent.KEYCODE_MEDIA_STEP_BACKWARD, packageName) } else { - return Error.SdkVersionTooLow(Build.VERSION_CODES.M) + return KMError.SdkVersionTooLow(Build.VERSION_CODES.M) } } @@ -133,7 +137,7 @@ class AndroidMediaAdapter(context: Context, coroutineScope: CoroutineScope) : Me return audioVolumeControlStreams } - override fun playFile(uri: String, stream: VolumeStream): Result<*> { + override fun playFile(uri: String, stream: VolumeStream): KMResult<*> { try { synchronized(mediaPlayerLock) { mediaPlayer?.stop() @@ -169,9 +173,9 @@ class AndroidMediaAdapter(context: Context, coroutineScope: CoroutineScope) : Me return Success(Unit) } catch (e: FileNotFoundException) { - return Error.SourceFileNotFound(uri) + return KMError.SourceFileNotFound(uri) } catch (e: Exception) { - return Error.Exception(e) + return KMError.Exception(e) } } @@ -179,7 +183,7 @@ class AndroidMediaAdapter(context: Context, coroutineScope: CoroutineScope) : Me activeMediaSessions.update { mediaSessions } } - private fun sendMediaKeyEvent(keyCode: Int, packageName: String?): Result<*> { + private fun sendMediaKeyEvent(keyCode: Int, packageName: String?): KMResult<*> { if (packageName == null) { audioManager.dispatchMediaKeyEvent(KeyEvent(KeyEvent.ACTION_DOWN, keyCode)) audioManager.dispatchMediaKeyEvent(KeyEvent(KeyEvent.ACTION_UP, keyCode)) diff --git a/app/src/main/java/io/github/sds100/keymapper/system/media/MediaAdapter.kt b/system/src/main/java/io/github/sds100/keymapper/system/media/MediaAdapter.kt similarity index 56% rename from app/src/main/java/io/github/sds100/keymapper/system/media/MediaAdapter.kt rename to system/src/main/java/io/github/sds100/keymapper/system/media/MediaAdapter.kt index c0a4858e81..79e16d53dc 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/media/MediaAdapter.kt +++ b/system/src/main/java/io/github/sds100/keymapper/system/media/MediaAdapter.kt @@ -2,13 +2,11 @@ package io.github.sds100.keymapper.system.media import android.os.Build import androidx.annotation.RequiresApi +import io.github.sds100.keymapper.common.utils.KMResult import io.github.sds100.keymapper.system.volume.VolumeStream -import io.github.sds100.keymapper.util.Result import kotlinx.coroutines.flow.Flow -/** - * Created by sds100 on 21/04/2021. - */ + interface MediaAdapter { /** @@ -28,17 +26,17 @@ interface MediaAdapter { fun getActiveAudioVolumeStreams(): Set fun getActiveAudioVolumeStreamsFlow(): Flow> - fun fastForward(packageName: String? = null): Result<*> - fun rewind(packageName: String? = null): Result<*> - fun play(packageName: String? = null): Result<*> - fun pause(packageName: String? = null): Result<*> - fun playPause(packageName: String? = null): Result<*> - fun previousTrack(packageName: String? = null): Result<*> - fun nextTrack(packageName: String? = null): Result<*> - fun stop(packageName: String? = null): Result<*> - fun stepForward(packageName: String? = null): Result<*> - fun stepBackward(packageName: String? = null): Result<*> + fun fastForward(packageName: String? = null): KMResult<*> + fun rewind(packageName: String? = null): KMResult<*> + fun play(packageName: String? = null): KMResult<*> + fun pause(packageName: String? = null): KMResult<*> + fun playPause(packageName: String? = null): KMResult<*> + fun previousTrack(packageName: String? = null): KMResult<*> + fun nextTrack(packageName: String? = null): KMResult<*> + fun stop(packageName: String? = null): KMResult<*> + fun stepForward(packageName: String? = null): KMResult<*> + fun stepBackward(packageName: String? = null): KMResult<*> - fun playFile(uri: String, stream: VolumeStream): Result<*> - fun stopFileMedia(): Result<*> + fun playFile(uri: String, stream: VolumeStream): KMResult<*> + fun stopFileMedia(): KMResult<*> } diff --git a/app/src/main/java/io/github/sds100/keymapper/system/network/AndroidNetworkAdapter.kt b/system/src/main/java/io/github/sds100/keymapper/system/network/AndroidNetworkAdapter.kt similarity index 86% rename from app/src/main/java/io/github/sds100/keymapper/system/network/AndroidNetworkAdapter.kt rename to system/src/main/java/io/github/sds100/keymapper/system/network/AndroidNetworkAdapter.kt index ba05d76cfb..8c05233836 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/network/AndroidNetworkAdapter.kt +++ b/system/src/main/java/io/github/sds100/keymapper/system/network/AndroidNetworkAdapter.kt @@ -9,10 +9,10 @@ import android.os.Build import android.telephony.TelephonyManager import androidx.core.content.ContextCompat import androidx.core.content.getSystemService +import io.github.sds100.keymapper.common.utils.KMError +import io.github.sds100.keymapper.common.utils.KMResult +import io.github.sds100.keymapper.common.utils.Success import io.github.sds100.keymapper.system.root.SuAdapter -import io.github.sds100.keymapper.util.Error -import io.github.sds100.keymapper.util.Result -import io.github.sds100.keymapper.util.Success import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow @@ -25,12 +25,13 @@ import okhttp3.RequestBody.Companion.toRequestBody import okio.IOException import okio.use import timber.log.Timber +import dagger.hilt.android.qualifiers.ApplicationContext +import javax.inject.Inject +import javax.inject.Singleton -/** - * Created by sds100 on 24/04/2021. - */ -class AndroidNetworkAdapter( - context: Context, +@Singleton +class AndroidNetworkAdapter @Inject constructor( + @ApplicationContext private val context: Context, private val suAdapter: SuAdapter, ) : NetworkAdapter { private val ctx = context.applicationContext @@ -86,7 +87,7 @@ class AndroidNetworkAdapter( override fun isWifiEnabledFlow(): Flow = isWifiEnabled - override fun enableWifi(): Result<*> { + override fun enableWifi(): KMResult<*> { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { return suAdapter.execute("svc wifi enable") } else { @@ -95,7 +96,7 @@ class AndroidNetworkAdapter( } } - override fun disableWifi(): Result<*> { + override fun disableWifi(): KMResult<*> { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { return suAdapter.execute("svc wifi disable") } else { @@ -112,9 +113,9 @@ class AndroidNetworkAdapter( } } - override fun enableMobileData(): Result<*> = suAdapter.execute("svc data enable") + override fun enableMobileData(): KMResult<*> = suAdapter.execute("svc data enable") - override fun disableMobileData(): Result<*> = suAdapter.execute("svc data disable") + override fun disableMobileData(): KMResult<*> = suAdapter.execute("svc data disable") /** * @return Null on Android 10+ because there is no API to do this anymore. @@ -134,7 +135,7 @@ class AndroidNetworkAdapter( url: String, body: String, authorizationHeader: String, - ): Result<*> { + ): KMResult<*> { try { val requestBody = when (method) { HttpMethod.HEAD -> Request.Builder().head() @@ -162,16 +163,16 @@ class AndroidNetworkAdapter( Timber.d(response.toString()) if (!response.isSuccessful) { - return Error.UnknownIOError + return KMError.UnknownIOError } return Success(Unit) } } catch (e: IOException) { Timber.e(e) - return Error.UnknownIOError + return KMError.UnknownIOError } catch (e: IllegalArgumentException) { - return Error.MalformedUrl + return KMError.MalformedUrl } } } diff --git a/app/src/main/java/io/github/sds100/keymapper/system/network/HttpMethod.kt b/system/src/main/java/io/github/sds100/keymapper/system/network/HttpMethod.kt similarity index 100% rename from app/src/main/java/io/github/sds100/keymapper/system/network/HttpMethod.kt rename to system/src/main/java/io/github/sds100/keymapper/system/network/HttpMethod.kt diff --git a/app/src/main/java/io/github/sds100/keymapper/system/network/NetworkAdapter.kt b/system/src/main/java/io/github/sds100/keymapper/system/network/NetworkAdapter.kt similarity index 66% rename from app/src/main/java/io/github/sds100/keymapper/system/network/NetworkAdapter.kt rename to system/src/main/java/io/github/sds100/keymapper/system/network/NetworkAdapter.kt index e0e6e23210..d7a1f04a7c 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/network/NetworkAdapter.kt +++ b/system/src/main/java/io/github/sds100/keymapper/system/network/NetworkAdapter.kt @@ -1,11 +1,9 @@ package io.github.sds100.keymapper.system.network -import io.github.sds100.keymapper.util.Result +import io.github.sds100.keymapper.common.utils.KMResult import kotlinx.coroutines.flow.Flow -/** - * Created by sds100 on 24/04/2021. - */ + interface NetworkAdapter { val connectedWifiSSID: String? val connectedWifiSSIDFlow: Flow @@ -13,13 +11,13 @@ interface NetworkAdapter { fun isWifiEnabled(): Boolean fun isWifiEnabledFlow(): Flow - fun enableWifi(): Result<*> - fun disableWifi(): Result<*> + fun enableWifi(): KMResult<*> + fun disableWifi(): KMResult<*> fun isMobileDataEnabled(): Boolean - fun enableMobileData(): Result<*> - fun disableMobileData(): Result<*> + fun enableMobileData(): KMResult<*> + fun disableMobileData(): KMResult<*> fun getKnownWifiSSIDs(): List? @@ -28,5 +26,5 @@ interface NetworkAdapter { url: String, body: String, authorizationHeader: String, - ): Result<*> + ): KMResult<*> } diff --git a/app/src/main/java/io/github/sds100/keymapper/system/nfc/AndroidNfcAdapter.kt b/system/src/main/java/io/github/sds100/keymapper/system/nfc/AndroidNfcAdapter.kt similarity index 52% rename from app/src/main/java/io/github/sds100/keymapper/system/nfc/AndroidNfcAdapter.kt rename to system/src/main/java/io/github/sds100/keymapper/system/nfc/AndroidNfcAdapter.kt index 2c4be4c8e8..0f11120f17 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/nfc/AndroidNfcAdapter.kt +++ b/system/src/main/java/io/github/sds100/keymapper/system/nfc/AndroidNfcAdapter.kt @@ -3,14 +3,15 @@ package io.github.sds100.keymapper.system.nfc import android.content.Context import android.nfc.NfcManager import androidx.core.content.getSystemService +import io.github.sds100.keymapper.common.utils.KMResult import io.github.sds100.keymapper.system.root.SuAdapter -import io.github.sds100.keymapper.util.Result +import dagger.hilt.android.qualifiers.ApplicationContext +import javax.inject.Inject +import javax.inject.Singleton -/** - * Created by sds100 on 24/04/2021. - */ -class AndroidNfcAdapter( - context: Context, +@Singleton +class AndroidNfcAdapter @Inject constructor( + @ApplicationContext private val context: Context, private val suAdapter: SuAdapter, ) : NfcAdapter { private val ctx = context.applicationContext @@ -19,7 +20,7 @@ class AndroidNfcAdapter( override fun isEnabled(): Boolean = nfcManager.defaultAdapter.isEnabled - override fun enable(): Result<*> = suAdapter.execute("svc nfc enable") + override fun enable(): KMResult<*> = suAdapter.execute("svc nfc enable") - override fun disable(): Result<*> = suAdapter.execute("svc nfc disable") + override fun disable(): KMResult<*> = suAdapter.execute("svc nfc disable") } diff --git a/system/src/main/java/io/github/sds100/keymapper/system/nfc/NfcAdapter.kt b/system/src/main/java/io/github/sds100/keymapper/system/nfc/NfcAdapter.kt new file mode 100644 index 0000000000..e155ffd1e4 --- /dev/null +++ b/system/src/main/java/io/github/sds100/keymapper/system/nfc/NfcAdapter.kt @@ -0,0 +1,10 @@ +package io.github.sds100.keymapper.system.nfc + +import io.github.sds100.keymapper.common.utils.KMResult + + +interface NfcAdapter { + fun isEnabled(): Boolean + fun enable(): KMResult<*> + fun disable(): KMResult<*> +} diff --git a/app/src/main/java/io/github/sds100/keymapper/system/notifications/NotificationAdapter.kt b/system/src/main/java/io/github/sds100/keymapper/system/notifications/NotificationAdapter.kt similarity index 90% rename from app/src/main/java/io/github/sds100/keymapper/system/notifications/NotificationAdapter.kt rename to system/src/main/java/io/github/sds100/keymapper/system/notifications/NotificationAdapter.kt index 211489d140..0b61b3a015 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/notifications/NotificationAdapter.kt +++ b/system/src/main/java/io/github/sds100/keymapper/system/notifications/NotificationAdapter.kt @@ -2,9 +2,7 @@ package io.github.sds100.keymapper.system.notifications import kotlinx.coroutines.flow.Flow -/** - * Created by sds100 on 16/04/2021. - */ + interface NotificationAdapter { /** * The string is the ID of the action. diff --git a/app/src/main/java/io/github/sds100/keymapper/system/notifications/NotificationChannelModel.kt b/system/src/main/java/io/github/sds100/keymapper/system/notifications/NotificationChannelModel.kt similarity index 78% rename from app/src/main/java/io/github/sds100/keymapper/system/notifications/NotificationChannelModel.kt rename to system/src/main/java/io/github/sds100/keymapper/system/notifications/NotificationChannelModel.kt index 33e6018f09..f716f1882b 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/notifications/NotificationChannelModel.kt +++ b/system/src/main/java/io/github/sds100/keymapper/system/notifications/NotificationChannelModel.kt @@ -1,8 +1,6 @@ package io.github.sds100.keymapper.system.notifications -/** - * Created by sds100 on 17/04/2021. - */ + data class NotificationChannelModel( val id: String, val name: String, diff --git a/app/src/main/java/io/github/sds100/keymapper/system/notifications/NotificationModel.kt b/system/src/main/java/io/github/sds100/keymapper/system/notifications/NotificationModel.kt similarity index 96% rename from app/src/main/java/io/github/sds100/keymapper/system/notifications/NotificationModel.kt rename to system/src/main/java/io/github/sds100/keymapper/system/notifications/NotificationModel.kt index f7e72a1406..30bd5c1cb3 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/notifications/NotificationModel.kt +++ b/system/src/main/java/io/github/sds100/keymapper/system/notifications/NotificationModel.kt @@ -2,9 +2,7 @@ package io.github.sds100.keymapper.system.notifications import androidx.annotation.DrawableRes -/** - * Created by sds100 on 16/04/2021. - */ + data class NotificationModel( val id: Int, val channel: String, diff --git a/app/src/main/java/io/github/sds100/keymapper/system/notifications/NotificationReceiver.kt b/system/src/main/java/io/github/sds100/keymapper/system/notifications/NotificationReceiver.kt similarity index 79% rename from app/src/main/java/io/github/sds100/keymapper/system/notifications/NotificationReceiver.kt rename to system/src/main/java/io/github/sds100/keymapper/system/notifications/NotificationReceiver.kt index a64b1df640..6d8e80bc5c 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/notifications/NotificationReceiver.kt +++ b/system/src/main/java/io/github/sds100/keymapper/system/notifications/NotificationReceiver.kt @@ -1,7 +1,6 @@ package io.github.sds100.keymapper.system.notifications import android.content.ComponentName -import android.content.Intent import android.media.session.MediaSessionManager import android.service.notification.NotificationListenerService import android.service.notification.StatusBarNotification @@ -10,18 +9,15 @@ import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.LifecycleRegistry import androidx.lifecycle.lifecycleScope -import io.github.sds100.keymapper.ServiceLocator -import io.github.sds100.keymapper.util.ServiceEvent +import dagger.hilt.android.AndroidEntryPoint +import io.github.sds100.keymapper.system.media.AndroidMediaAdapter import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import timber.log.Timber +import javax.inject.Inject -/** - * Created by sds100 on 14/11/20. - */ -class NotificationReceiver : - NotificationListenerService(), - LifecycleOwner { +@AndroidEntryPoint +class NotificationReceiver : NotificationListenerService(), LifecycleOwner { private val mediaSessionManager: MediaSessionManager by lazy { getSystemService()!! } private val notificationListenerComponent by lazy { @@ -31,7 +27,8 @@ class NotificationReceiver : ) } - private val mediaAdapter by lazy { ServiceLocator.mediaAdapter(this) } + @Inject + lateinit var mediaAdapter: AndroidMediaAdapter private val activeSessionsChangeListener = MediaSessionManager.OnActiveSessionsChangedListener { controllers -> @@ -40,9 +37,9 @@ class NotificationReceiver : private var lastNotificationKey: String? = null - private val serviceAdapter: NotificationReceiverAdapter by lazy { - ServiceLocator.notificationReceiverAdapter(this) - } + + @Inject + lateinit var serviceAdapter: NotificationReceiverAdapterImpl private lateinit var lifecycleRegistry: LifecycleRegistry @@ -55,8 +52,8 @@ class NotificationReceiver : serviceAdapter.eventsToService .onEach { event -> when (event) { - ServiceEvent.DismissLastNotification -> cancelNotification(lastNotificationKey) - ServiceEvent.DismissAllNotifications -> cancelAllNotifications() + NotificationServiceEvent.DismissLastNotification -> cancelNotification(lastNotificationKey) + NotificationServiceEvent.DismissAllNotifications -> cancelAllNotifications() else -> Unit } }.launchIn(lifecycleScope) @@ -81,9 +78,6 @@ class NotificationReceiver : } } - override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int = - super.onStartCommand(intent, flags, startId) - override fun onListenerConnected() { super.onListenerConnected() diff --git a/system/src/main/java/io/github/sds100/keymapper/system/notifications/NotificationReceiverAdapter.kt b/system/src/main/java/io/github/sds100/keymapper/system/notifications/NotificationReceiverAdapter.kt new file mode 100644 index 0000000000..92027920b2 --- /dev/null +++ b/system/src/main/java/io/github/sds100/keymapper/system/notifications/NotificationReceiverAdapter.kt @@ -0,0 +1,40 @@ +package io.github.sds100.keymapper.system.notifications + +import io.github.sds100.keymapper.common.utils.KMResult +import kotlinx.coroutines.flow.SharedFlow +import kotlinx.coroutines.flow.StateFlow + +interface NotificationReceiverAdapter { + val isEnabled: StateFlow + + /** + * @return Whether the service could be started successfully. + */ + fun start(): Boolean + + /** + * @return Whether the service could be restarted successfully. + */ + fun restart(): Boolean + + /** + * @return Whether the service could be restarted successfully. + */ + fun stop(): Boolean + + /** + * Send an event to the service. + */ + suspend fun send(event: NotificationServiceEvent): KMResult<*> + + /** + * Send an event to the service asynchronously. This method + * will return immediately and you won't be notified of whether it is sent. + */ + fun sendAsync(event: NotificationServiceEvent) + + /** + * A flow of events coming from the service. + */ + val eventReceiver: SharedFlow +} diff --git a/app/src/main/java/io/github/sds100/keymapper/system/notifications/NotificationReceiverAdapter.kt b/system/src/main/java/io/github/sds100/keymapper/system/notifications/NotificationReceiverAdapterImpl.kt similarity index 62% rename from app/src/main/java/io/github/sds100/keymapper/system/notifications/NotificationReceiverAdapter.kt rename to system/src/main/java/io/github/sds100/keymapper/system/notifications/NotificationReceiverAdapterImpl.kt index 7bde0f7822..401479513e 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/notifications/NotificationReceiverAdapter.kt +++ b/system/src/main/java/io/github/sds100/keymapper/system/notifications/NotificationReceiverAdapterImpl.kt @@ -10,39 +10,38 @@ import android.os.Handler import android.os.Looper import android.provider.Settings import androidx.core.app.NotificationManagerCompat -import io.github.sds100.keymapper.Constants +import dagger.hilt.android.qualifiers.ApplicationContext +import io.github.sds100.keymapper.common.BuildConfigProvider +import io.github.sds100.keymapper.common.utils.KMResult +import io.github.sds100.keymapper.common.utils.Success +import io.github.sds100.keymapper.common.utils.withFlag import io.github.sds100.keymapper.system.JobSchedulerHelper -import io.github.sds100.keymapper.system.accessibility.ServiceAdapter -import io.github.sds100.keymapper.system.accessibility.ServiceState +import io.github.sds100.keymapper.system.SystemError import io.github.sds100.keymapper.system.permissions.Permission -import io.github.sds100.keymapper.util.Error -import io.github.sds100.keymapper.util.Result -import io.github.sds100.keymapper.util.ServiceEvent -import io.github.sds100.keymapper.util.Success import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch -import splitties.bitflags.withFlag +import javax.inject.Inject +import javax.inject.Singleton -/** - * Created by sds100 on 27/07/2021. - */ - -class NotificationReceiverAdapter( - context: Context, +@Singleton +class NotificationReceiverAdapterImpl @Inject constructor( + @ApplicationContext context: Context, private val coroutineScope: CoroutineScope, -) : ServiceAdapter { + private val buildConfigProvider: BuildConfigProvider, +) : NotificationReceiverAdapter { private val ctx: Context = context.applicationContext - override val state: MutableStateFlow = MutableStateFlow(ServiceState.DISABLED) + override val isEnabled: MutableStateFlow = MutableStateFlow(false) - override val eventReceiver: MutableSharedFlow = MutableSharedFlow() - val eventsToService = MutableSharedFlow() + override val eventReceiver: MutableSharedFlow = MutableSharedFlow() + val eventsToService = MutableSharedFlow() init { // use job scheduler because there is there is a much shorter delay when the app is in the background if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - JobSchedulerHelper.observeEnabledNotificationListeners(ctx) + JobSchedulerHelper.observeEnabledNotificationListeners(ctx) } else { val uri = Settings.Secure.getUriFor("enabled_notification_listeners") val observer = object : ContentObserver(Handler(Looper.getMainLooper())) { @@ -50,7 +49,7 @@ class NotificationReceiverAdapter( super.onChange(selfChange, uri) coroutineScope.launch { - state.value = getState() + isEnabled.update { getIsEnabled() } } } } @@ -59,13 +58,13 @@ class NotificationReceiverAdapter( } coroutineScope.launch { - state.value = getState() + isEnabled.update { getIsEnabled() } } } - override suspend fun send(event: ServiceEvent): Result<*> { - if (state.value != ServiceState.ENABLED) { - return Error.PermissionDenied(Permission.NOTIFICATION_LISTENER) + override suspend fun send(event: NotificationServiceEvent): KMResult<*> { + if (isEnabled.value) { + return SystemError.PermissionDenied(Permission.NOTIFICATION_LISTENER) } coroutineScope.launch { @@ -75,7 +74,7 @@ class NotificationReceiverAdapter( return Success(Unit) } - override fun sendAsync(event: ServiceEvent) { + override fun sendAsync(event: NotificationServiceEvent) { coroutineScope.launch { eventsToService.emit(event) } @@ -87,9 +86,6 @@ class NotificationReceiverAdapter( override fun stop(): Boolean = openSettingsPage() - override suspend fun isCrashed(): Boolean = false - override fun acknowledgeCrashed() {} - private fun openSettingsPage(): Boolean { Intent(Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS).apply { flags = Intent.FLAG_ACTIVITY_NEW_TASK @@ -105,14 +101,10 @@ class NotificationReceiverAdapter( } } - private fun getState(): ServiceState { + private fun getIsEnabled(): Boolean { val isEnabled = NotificationManagerCompat.getEnabledListenerPackages(ctx) - .contains(Constants.PACKAGE_NAME) + .contains(buildConfigProvider.packageName) - return if (isEnabled) { - ServiceState.ENABLED - } else { - ServiceState.DISABLED - } + return isEnabled } } diff --git a/system/src/main/java/io/github/sds100/keymapper/system/notifications/NotificationServiceEvent.kt b/system/src/main/java/io/github/sds100/keymapper/system/notifications/NotificationServiceEvent.kt new file mode 100644 index 0000000000..42843285eb --- /dev/null +++ b/system/src/main/java/io/github/sds100/keymapper/system/notifications/NotificationServiceEvent.kt @@ -0,0 +1,13 @@ +package io.github.sds100.keymapper.system.notifications + +import kotlinx.serialization.Serializable + +sealed class NotificationServiceEvent { + + @Serializable + data object DismissLastNotification : NotificationServiceEvent() + + @Serializable + data object DismissAllNotifications : NotificationServiceEvent() + +} \ No newline at end of file diff --git a/app/src/main/java/io/github/sds100/keymapper/system/notifications/NotificationUtils.kt b/system/src/main/java/io/github/sds100/keymapper/system/notifications/NotificationUtils.kt similarity index 78% rename from app/src/main/java/io/github/sds100/keymapper/system/notifications/NotificationUtils.kt rename to system/src/main/java/io/github/sds100/keymapper/system/notifications/NotificationUtils.kt index fa7c0b59be..b8453a5496 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/notifications/NotificationUtils.kt +++ b/system/src/main/java/io/github/sds100/keymapper/system/notifications/NotificationUtils.kt @@ -5,18 +5,13 @@ import android.content.Intent import android.os.Build import android.provider.Settings import androidx.annotation.RequiresApi -import io.github.sds100.keymapper.Constants - -/** - * Created by sds100 on 30/09/2018. - */ object NotificationUtils { @RequiresApi(Build.VERSION_CODES.O) fun openChannelSettings(ctx: Context, channelId: String) { Intent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS).apply { - putExtra(Settings.EXTRA_APP_PACKAGE, Constants.PACKAGE_NAME) + putExtra(Settings.EXTRA_APP_PACKAGE, ctx.packageName) putExtra(Settings.EXTRA_CHANNEL_ID, channelId) addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) diff --git a/app/src/main/java/io/github/sds100/keymapper/system/notifications/ObserveNotificationListenersJob.kt b/system/src/main/java/io/github/sds100/keymapper/system/notifications/ObserveNotificationListenersJob.kt similarity index 66% rename from app/src/main/java/io/github/sds100/keymapper/system/notifications/ObserveNotificationListenersJob.kt rename to system/src/main/java/io/github/sds100/keymapper/system/notifications/ObserveNotificationListenersJob.kt index 59753abaf8..d01039e34d 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/notifications/ObserveNotificationListenersJob.kt +++ b/system/src/main/java/io/github/sds100/keymapper/system/notifications/ObserveNotificationListenersJob.kt @@ -3,15 +3,19 @@ package io.github.sds100.keymapper.system.notifications import android.app.job.JobParameters import android.app.job.JobService import android.os.Build -import io.github.sds100.keymapper.KeyMapperApp +import dagger.hilt.android.AndroidEntryPoint import io.github.sds100.keymapper.system.JobSchedulerHelper +import io.github.sds100.keymapper.system.permissions.AndroidPermissionAdapter +import javax.inject.Inject -/** - * Created by sds100 on 02/04/2021. - */ +@AndroidEntryPoint class ObserveNotificationListenersJob : JobService() { + + @Inject + lateinit var permissionAdapter: AndroidPermissionAdapter + override fun onStartJob(params: JobParameters?): Boolean { - (applicationContext as KeyMapperApp).permissionAdapter.onPermissionsChanged() + permissionAdapter.onPermissionsChanged() if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { JobSchedulerHelper.observeEnabledNotificationListeners(applicationContext) diff --git a/app/src/main/java/io/github/sds100/keymapper/system/permissions/AndroidPermissionAdapter.kt b/system/src/main/java/io/github/sds100/keymapper/system/permissions/AndroidPermissionAdapter.kt similarity index 85% rename from app/src/main/java/io/github/sds100/keymapper/system/permissions/AndroidPermissionAdapter.kt rename to system/src/main/java/io/github/sds100/keymapper/system/permissions/AndroidPermissionAdapter.kt index 4b7e63735f..61a23cea99 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/permissions/AndroidPermissionAdapter.kt +++ b/system/src/main/java/io/github/sds100/keymapper/system/permissions/AndroidPermissionAdapter.kt @@ -15,20 +15,22 @@ import android.provider.Settings import androidx.core.app.NotificationManagerCompat import androidx.core.content.ContextCompat import androidx.core.content.getSystemService -import io.github.sds100.keymapper.Constants +import dagger.hilt.android.qualifiers.ApplicationContext +import io.github.sds100.keymapper.common.BuildConfigProvider +import io.github.sds100.keymapper.common.utils.KMError +import io.github.sds100.keymapper.common.utils.KMResult +import io.github.sds100.keymapper.common.utils.getIdentifier +import io.github.sds100.keymapper.common.utils.onFailure +import io.github.sds100.keymapper.common.utils.onSuccess +import io.github.sds100.keymapper.common.utils.success import io.github.sds100.keymapper.data.Keys import io.github.sds100.keymapper.data.repositories.PreferenceRepository -import io.github.sds100.keymapper.shizuku.ShizukuUtils import io.github.sds100.keymapper.system.DeviceAdmin -import io.github.sds100.keymapper.system.accessibility.ServiceAdapter +import io.github.sds100.keymapper.system.SystemError import io.github.sds100.keymapper.system.apps.PackageManagerAdapter +import io.github.sds100.keymapper.system.notifications.NotificationReceiverAdapter import io.github.sds100.keymapper.system.root.SuAdapter -import io.github.sds100.keymapper.util.Error -import io.github.sds100.keymapper.util.Result -import io.github.sds100.keymapper.util.getIdentifier -import io.github.sds100.keymapper.util.onFailure -import io.github.sds100.keymapper.util.onSuccess -import io.github.sds100.keymapper.util.success +import io.github.sds100.keymapper.system.shizuku.ShizukuUtils import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableSharedFlow @@ -47,17 +49,18 @@ import rikka.shizuku.Shizuku import rikka.shizuku.ShizukuBinderWrapper import rikka.shizuku.SystemServiceHelper import timber.log.Timber +import javax.inject.Inject +import javax.inject.Singleton -/** - * Created by sds100 on 17/03/2021. - */ -class AndroidPermissionAdapter( - context: Context, +@Singleton +class AndroidPermissionAdapter @Inject constructor( + @ApplicationContext private val context: Context, private val coroutineScope: CoroutineScope, private val suAdapter: SuAdapter, - private val notificationReceiverAdapter: ServiceAdapter, + private val notificationReceiverAdapter: NotificationReceiverAdapter, private val preferenceRepository: PreferenceRepository, private val packageManagerAdapter: PackageManagerAdapter, + private val buildConfigProvider: BuildConfigProvider, ) : PermissionAdapter { companion object { const val REQUEST_CODE_SHIZUKU_PERMISSION = 1 @@ -113,7 +116,7 @@ class AndroidPermissionAdapter( } } - notificationReceiverAdapter.state + notificationReceiverAdapter.isEnabled .drop(1) .onEach { onPermissionsChanged() } .launchIn(coroutineScope) @@ -130,8 +133,8 @@ class AndroidPermissionAdapter( coroutineScope.launch { _request.emit(permission) } } - override fun grant(permissionName: String): Result<*> { - val result: Result<*> + override fun grant(permissionName: String): KMResult<*> { + val result: KMResult<*> if (ContextCompat.checkSelfPermission( ctx, @@ -149,24 +152,24 @@ class AndroidPermissionAdapter( if (ContextCompat.checkSelfPermission(ctx, permissionName) == PERMISSION_GRANTED) { success() } else { - Error.Exception(Exception("Failed to grant permission with Shizuku.")) + KMError.Exception(Exception("Failed to grant permission with Shizuku.")) } } catch (e: Exception) { - Error.Exception(e) + KMError.Exception(e) } } else if (isGranted(Permission.ROOT)) { suAdapter.execute( - "pm grant ${Constants.PACKAGE_NAME} $permissionName", + "pm grant ${buildConfigProvider.packageName} $permissionName", block = true, ) if (ContextCompat.checkSelfPermission(ctx, permissionName) == PERMISSION_GRANTED) { result = success() } else { result = - Error.Exception(Exception("Failed to grant permission with root. Key Mapper may not actually have root permission.")) + KMError.Exception(Exception("Failed to grant permission with root. Key Mapper may not actually have root permission.")) } } else { - result = Error.PermissionDenied(Permission.SHIZUKU) + result = SystemError.PermissionDenied(Permission.SHIZUKU) } result.onSuccess { @@ -187,7 +190,7 @@ class AndroidPermissionAdapter( if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) { try { shizukuPermissionManager.grantRuntimePermission( - Constants.PACKAGE_NAME, + buildConfigProvider.packageName, permissionName, ctx.deviceId, userId, @@ -195,14 +198,14 @@ class AndroidPermissionAdapter( } catch (_: NoSuchMethodError) { try { shizukuPermissionManager.grantRuntimePermission( - Constants.PACKAGE_NAME, + buildConfigProvider.packageName, permissionName, "0", userId, ) } catch (_: NoSuchMethodError) { shizukuPermissionManager.grantRuntimePermission( - Constants.PACKAGE_NAME, + buildConfigProvider.packageName, permissionName, userId, ) @@ -211,13 +214,13 @@ class AndroidPermissionAdapter( // In Android 11 this method was moved from IPackageManager to IPermissionManager. } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { shizukuPermissionManager.grantRuntimePermission( - Constants.PACKAGE_NAME, + buildConfigProvider.packageName, permissionName, userId, ) } else { shizukuPackageManager.grantRuntimePermission( - Constants.PACKAGE_NAME, + buildConfigProvider.packageName, permissionName, userId, ) @@ -270,7 +273,7 @@ class AndroidPermissionAdapter( Permission.NOTIFICATION_LISTENER -> NotificationManagerCompat.getEnabledListenerPackages(ctx) - .contains(Constants.PACKAGE_NAME) + .contains(buildConfigProvider.packageName) Permission.CALL_PHONE -> ContextCompat.checkSelfPermission( @@ -283,7 +286,7 @@ class AndroidPermissionAdapter( Permission.IGNORE_BATTERY_OPTIMISATION -> if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { val ignoringOptimisations = - powerManager?.isIgnoringBatteryOptimizations(Constants.PACKAGE_NAME) + powerManager?.isIgnoringBatteryOptimizations(buildConfigProvider.packageName) when { powerManager == null -> Timber.i("Power manager is null") diff --git a/app/src/main/java/io/github/sds100/keymapper/system/permissions/Permission.kt b/system/src/main/java/io/github/sds100/keymapper/system/permissions/Permission.kt similarity index 90% rename from app/src/main/java/io/github/sds100/keymapper/system/permissions/Permission.kt rename to system/src/main/java/io/github/sds100/keymapper/system/permissions/Permission.kt index 43319c74eb..f552ff3c8d 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/permissions/Permission.kt +++ b/system/src/main/java/io/github/sds100/keymapper/system/permissions/Permission.kt @@ -1,8 +1,6 @@ package io.github.sds100.keymapper.system.permissions -/** - * Created by sds100 on 08/04/2021. - */ + enum class Permission { WRITE_SETTINGS, CAMERA, diff --git a/app/src/main/java/io/github/sds100/keymapper/system/permissions/PermissionAdapter.kt b/system/src/main/java/io/github/sds100/keymapper/system/permissions/PermissionAdapter.kt similarity index 79% rename from app/src/main/java/io/github/sds100/keymapper/system/permissions/PermissionAdapter.kt rename to system/src/main/java/io/github/sds100/keymapper/system/permissions/PermissionAdapter.kt index 6e6b41ddba..62427cf3ce 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/permissions/PermissionAdapter.kt +++ b/system/src/main/java/io/github/sds100/keymapper/system/permissions/PermissionAdapter.kt @@ -1,11 +1,9 @@ package io.github.sds100.keymapper.system.permissions -import io.github.sds100.keymapper.util.Result +import io.github.sds100.keymapper.common.utils.KMResult import kotlinx.coroutines.flow.Flow -/** - * Created by sds100 on 16/03/2021. - */ + interface PermissionAdapter { val onPermissionsUpdate: Flow fun isGranted(permission: Permission): Boolean @@ -20,5 +18,5 @@ interface PermissionAdapter { * Grant a permission automatically without requiring the user. * Requires root access or Shizuku. */ - fun grant(permissionName: String): Result<*> + fun grant(permissionName: String): KMResult<*> } diff --git a/app/src/main/java/io/github/sds100/keymapper/system/permissions/SystemFeatureAdapter.kt b/system/src/main/java/io/github/sds100/keymapper/system/permissions/SystemFeatureAdapter.kt similarity index 80% rename from app/src/main/java/io/github/sds100/keymapper/system/permissions/SystemFeatureAdapter.kt rename to system/src/main/java/io/github/sds100/keymapper/system/permissions/SystemFeatureAdapter.kt index 2d5a586c65..dd7474a841 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/permissions/SystemFeatureAdapter.kt +++ b/system/src/main/java/io/github/sds100/keymapper/system/permissions/SystemFeatureAdapter.kt @@ -1,8 +1,6 @@ package io.github.sds100.keymapper.system.permissions -/** - * Created by sds100 on 16/03/2021. - */ + interface SystemFeatureAdapter { fun hasSystemFeature(feature: String): Boolean fun getSystemFeatures(): List diff --git a/app/src/main/java/io/github/sds100/keymapper/system/phone/AndroidPhoneAdapter.kt b/system/src/main/java/io/github/sds100/keymapper/system/phone/AndroidPhoneAdapter.kt similarity index 85% rename from app/src/main/java/io/github/sds100/keymapper/system/phone/AndroidPhoneAdapter.kt rename to system/src/main/java/io/github/sds100/keymapper/system/phone/AndroidPhoneAdapter.kt index 81bb1387e8..fd23ff5917 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/phone/AndroidPhoneAdapter.kt +++ b/system/src/main/java/io/github/sds100/keymapper/system/phone/AndroidPhoneAdapter.kt @@ -9,18 +9,19 @@ import android.telecom.TelecomManager import android.telephony.PhoneStateListener import android.telephony.TelephonyManager import androidx.core.content.getSystemService -import io.github.sds100.keymapper.util.Error -import io.github.sds100.keymapper.util.Result -import io.github.sds100.keymapper.util.Success +import io.github.sds100.keymapper.common.utils.KMError +import io.github.sds100.keymapper.common.utils.KMResult +import io.github.sds100.keymapper.common.utils.Success import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.launch +import dagger.hilt.android.qualifiers.ApplicationContext +import javax.inject.Inject +import javax.inject.Singleton -/** - * Created by sds100 on 21/04/2021. - */ -class AndroidPhoneAdapter( - context: Context, +@Singleton +class AndroidPhoneAdapter @Inject constructor( + @ApplicationContext private val context: Context, private val coroutineScope: CoroutineScope, ) : PhoneAdapter { private val ctx: Context = context.applicationContext @@ -56,7 +57,7 @@ class AndroidPhoneAdapter( override fun getCallState(): CallState = callStateConverter(telephonyManager.callState) - override fun startCall(number: String): Result<*> { + override fun startCall(number: String): KMResult<*> { try { Intent(Intent.ACTION_CALL).apply { data = Uri.parse("tel:$number") @@ -66,7 +67,7 @@ class AndroidPhoneAdapter( return Success(Unit) } catch (e: ActivityNotFoundException) { - return Error.NoAppToPhoneCall + return KMError.NoAppToPhoneCall } } diff --git a/app/src/main/java/io/github/sds100/keymapper/system/phone/CallState.kt b/system/src/main/java/io/github/sds100/keymapper/system/phone/CallState.kt similarity index 72% rename from app/src/main/java/io/github/sds100/keymapper/system/phone/CallState.kt rename to system/src/main/java/io/github/sds100/keymapper/system/phone/CallState.kt index bfb1168ef9..4a5dd6f303 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/phone/CallState.kt +++ b/system/src/main/java/io/github/sds100/keymapper/system/phone/CallState.kt @@ -1,8 +1,5 @@ package io.github.sds100.keymapper.system.phone -/** - * Created by sds100 on 17/01/2022. - */ enum class CallState { RINGING, IN_PHONE_CALL, diff --git a/app/src/main/java/io/github/sds100/keymapper/system/phone/PhoneAdapter.kt b/system/src/main/java/io/github/sds100/keymapper/system/phone/PhoneAdapter.kt similarity index 73% rename from app/src/main/java/io/github/sds100/keymapper/system/phone/PhoneAdapter.kt rename to system/src/main/java/io/github/sds100/keymapper/system/phone/PhoneAdapter.kt index dc1f273823..83fe2973be 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/phone/PhoneAdapter.kt +++ b/system/src/main/java/io/github/sds100/keymapper/system/phone/PhoneAdapter.kt @@ -1,11 +1,9 @@ package io.github.sds100.keymapper.system.phone -import io.github.sds100.keymapper.util.Result +import io.github.sds100.keymapper.common.utils.KMResult import kotlinx.coroutines.flow.Flow -/** - * Created by sds100 on 21/04/2021. - */ + interface PhoneAdapter { val callStateFlow: Flow @@ -14,7 +12,7 @@ interface PhoneAdapter { * a security exception will be thrown. */ fun getCallState(): CallState - fun startCall(number: String): Result<*> + fun startCall(number: String): KMResult<*> fun answerCall() fun endCall() } diff --git a/system/src/main/java/io/github/sds100/keymapper/system/popup/AndroidToastAdapter.kt b/system/src/main/java/io/github/sds100/keymapper/system/popup/AndroidToastAdapter.kt new file mode 100644 index 0000000000..b4e7e7cf0a --- /dev/null +++ b/system/src/main/java/io/github/sds100/keymapper/system/popup/AndroidToastAdapter.kt @@ -0,0 +1,16 @@ +package io.github.sds100.keymapper.system.popup + +import android.content.Context +import android.widget.Toast +import dagger.hilt.android.qualifiers.ApplicationContext +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class AndroidToastAdapter @Inject constructor( + @ApplicationContext private val ctx: Context, +) : ToastAdapter { + override fun show(message: String) { + Toast.makeText(ctx, message, Toast.LENGTH_SHORT).show() + } +} diff --git a/system/src/main/java/io/github/sds100/keymapper/system/popup/ToastAdapter.kt b/system/src/main/java/io/github/sds100/keymapper/system/popup/ToastAdapter.kt new file mode 100644 index 0000000000..4cce00be35 --- /dev/null +++ b/system/src/main/java/io/github/sds100/keymapper/system/popup/ToastAdapter.kt @@ -0,0 +1,6 @@ +package io.github.sds100.keymapper.system.popup + + +interface ToastAdapter { + fun show(message: String) +} diff --git a/app/src/main/java/io/github/sds100/keymapper/system/power/AndroidPowerAdapter.kt b/system/src/main/java/io/github/sds100/keymapper/system/power/AndroidPowerAdapter.kt similarity index 88% rename from app/src/main/java/io/github/sds100/keymapper/system/power/AndroidPowerAdapter.kt rename to system/src/main/java/io/github/sds100/keymapper/system/power/AndroidPowerAdapter.kt index 66e971115e..10b6d5f619 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/power/AndroidPowerAdapter.kt +++ b/system/src/main/java/io/github/sds100/keymapper/system/power/AndroidPowerAdapter.kt @@ -11,8 +11,14 @@ import androidx.core.content.getSystemService import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow - -class AndroidPowerAdapter(context: Context) : PowerAdapter { +import dagger.hilt.android.qualifiers.ApplicationContext +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class AndroidPowerAdapter @Inject constructor( + @ApplicationContext private val context: Context +) : PowerAdapter { private val ctx: Context = context.applicationContext private val batteryManager: BatteryManager by lazy { ctx.getSystemService()!! } diff --git a/app/src/main/java/io/github/sds100/keymapper/system/power/PowerAdapter.kt b/system/src/main/java/io/github/sds100/keymapper/system/power/PowerAdapter.kt similarity index 78% rename from app/src/main/java/io/github/sds100/keymapper/system/power/PowerAdapter.kt rename to system/src/main/java/io/github/sds100/keymapper/system/power/PowerAdapter.kt index 257771c0bc..ddaf4bb5f5 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/power/PowerAdapter.kt +++ b/system/src/main/java/io/github/sds100/keymapper/system/power/PowerAdapter.kt @@ -2,9 +2,7 @@ package io.github.sds100.keymapper.system.power import kotlinx.coroutines.flow.StateFlow -/** - * Created by sds100 on 21/05/2022. - */ + interface PowerAdapter { val isCharging: StateFlow } diff --git a/app/src/main/java/io/github/sds100/keymapper/system/ringtones/RingtoneAdapter.kt b/system/src/main/java/io/github/sds100/keymapper/system/ringtones/RingtoneAdapter.kt similarity index 69% rename from app/src/main/java/io/github/sds100/keymapper/system/ringtones/RingtoneAdapter.kt rename to system/src/main/java/io/github/sds100/keymapper/system/ringtones/RingtoneAdapter.kt index ae036aaa7e..136fae35bc 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/ringtones/RingtoneAdapter.kt +++ b/system/src/main/java/io/github/sds100/keymapper/system/ringtones/RingtoneAdapter.kt @@ -5,12 +5,16 @@ import android.media.Ringtone import android.media.RingtoneManager import android.os.Build import androidx.core.net.toUri -import io.github.sds100.keymapper.util.Error -import io.github.sds100.keymapper.util.Result -import io.github.sds100.keymapper.util.Success +import dagger.hilt.android.qualifiers.ApplicationContext +import io.github.sds100.keymapper.common.utils.KMError +import io.github.sds100.keymapper.common.utils.KMResult +import io.github.sds100.keymapper.common.utils.Success +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class AndroidRingtoneAdapter @Inject constructor(@ApplicationContext private val ctx: Context) : RingtoneAdapter { -class AndroidRingtoneAdapter(context: Context) : RingtoneAdapter { - private val ctx: Context = context.applicationContext private val ringtoneManager: RingtoneManager by lazy { RingtoneManager(ctx).apply { setType(RingtoneManager.TYPE_ALL) @@ -21,11 +25,11 @@ class AndroidRingtoneAdapter(context: Context) : RingtoneAdapter { private val lock = Any() private var playingRingtone: Ringtone? = null - override fun getLabel(uri: String): Result { + override fun getLabel(uri: String): KMResult { val ringtone = getRingtone(uri) if (ringtone == null) { - return Error.CantFindSoundFile + return KMError.CantFindSoundFile } return Success(ringtone.getTitle(ctx)) @@ -35,11 +39,11 @@ class AndroidRingtoneAdapter(context: Context) : RingtoneAdapter { return getRingtone(uri) != null } - override fun play(uri: String): Result { + override fun play(uri: String): KMResult { val ringtone = getRingtone(uri) if (ringtone == null) { - return Error.CantFindSoundFile + return KMError.CantFindSoundFile } else { ringtoneManager.stopPreviousRingtone() @@ -72,8 +76,8 @@ class AndroidRingtoneAdapter(context: Context) : RingtoneAdapter { } interface RingtoneAdapter { - fun getLabel(uri: String): Result + fun getLabel(uri: String): KMResult fun exists(uri: String): Boolean - fun play(uri: String): Result + fun play(uri: String): KMResult fun stopPlaying() } diff --git a/app/src/main/java/io/github/sds100/keymapper/system/root/SuAdapter.kt b/system/src/main/java/io/github/sds100/keymapper/system/root/SuAdapter.kt similarity index 63% rename from app/src/main/java/io/github/sds100/keymapper/system/root/SuAdapter.kt rename to system/src/main/java/io/github/sds100/keymapper/system/root/SuAdapter.kt index 7b9db9f99e..081f1deafb 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/root/SuAdapter.kt +++ b/system/src/main/java/io/github/sds100/keymapper/system/root/SuAdapter.kt @@ -1,13 +1,14 @@ package io.github.sds100.keymapper.system.root +import io.github.sds100.keymapper.common.utils.KMError +import io.github.sds100.keymapper.common.utils.KMResult +import io.github.sds100.keymapper.common.utils.Success +import io.github.sds100.keymapper.common.utils.firstBlocking import io.github.sds100.keymapper.data.Keys import io.github.sds100.keymapper.data.repositories.PreferenceRepository -import io.github.sds100.keymapper.system.Shell +import io.github.sds100.keymapper.system.SystemError import io.github.sds100.keymapper.system.permissions.Permission -import io.github.sds100.keymapper.util.Error -import io.github.sds100.keymapper.util.Result -import io.github.sds100.keymapper.util.Success -import io.github.sds100.keymapper.util.firstBlocking +import io.github.sds100.keymapper.system.shell.ShellAdapter import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow @@ -15,13 +16,13 @@ import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn import java.io.IOException import java.io.InputStream +import javax.inject.Inject +import javax.inject.Singleton -/** - * Created by sds100 on 21/04/2021. - */ - -class SuAdapterImpl( +@Singleton +class SuAdapterImpl @Inject constructor( coroutineScope: CoroutineScope, + private val shell: ShellAdapter, private val preferenceRepository: PreferenceRepository, ) : SuAdapter { private var process: Process? = null @@ -34,20 +35,20 @@ class SuAdapterImpl( preferenceRepository.set(Keys.hasRootPermission, true) // show the su prompt - Shell.run("su") + shell.run("su") return true } - override fun execute(command: String, block: Boolean): Result<*> { + override fun execute(command: String, block: Boolean): KMResult<*> { if (!isGranted.firstBlocking()) { - return Error.PermissionDenied(Permission.ROOT) + return SystemError.PermissionDenied(Permission.ROOT) } try { if (block) { // Don't use the long running su process because that will block the thread indefinitely - Shell.run("su", "-c", command, waitFor = true) + shell.run("su", "-c", command, waitFor = true) } else { if (process == null) { process = ProcessBuilder("su").start() @@ -61,20 +62,20 @@ class SuAdapterImpl( return Success(Unit) } catch (e: Exception) { - return Error.Exception(e) + return KMError.Exception(e) } } - override fun getCommandOutput(command: String): Result { + override fun getCommandOutput(command: String): KMResult { if (!isGranted.firstBlocking()) { - return Error.PermissionDenied(Permission.ROOT) + return SystemError.PermissionDenied(Permission.ROOT) } try { - val inputStream = Shell.getShellCommandStdOut("su", "-c", command) + val inputStream = shell.getShellCommandStdOut("su", "-c", command) return Success(inputStream) } catch (e: IOException) { - return Error.UnknownIOError + return KMError.UnknownIOError } } } @@ -86,6 +87,6 @@ interface SuAdapter { * @return whether root permission was granted successfully */ fun requestPermission(): Boolean - fun execute(command: String, block: Boolean = false): Result<*> - fun getCommandOutput(command: String): Result + fun execute(command: String, block: Boolean = false): KMResult<*> + fun getCommandOutput(command: String): KMResult } diff --git a/system/src/main/java/io/github/sds100/keymapper/system/shell/ShellAdapter.kt b/system/src/main/java/io/github/sds100/keymapper/system/shell/ShellAdapter.kt new file mode 100644 index 0000000000..f22b677ec6 --- /dev/null +++ b/system/src/main/java/io/github/sds100/keymapper/system/shell/ShellAdapter.kt @@ -0,0 +1,10 @@ +package io.github.sds100.keymapper.system.shell + +import io.github.sds100.keymapper.common.utils.KMResult +import java.io.InputStream + +interface ShellAdapter { + fun run(vararg command: String, waitFor: Boolean = false): Boolean + fun execute(command: String): KMResult<*> + fun getShellCommandStdOut(vararg command: String): InputStream +} diff --git a/app/src/main/java/io/github/sds100/keymapper/shizuku/ShizukuAdapter.kt b/system/src/main/java/io/github/sds100/keymapper/system/shizuku/ShizukuAdapter.kt similarity index 66% rename from app/src/main/java/io/github/sds100/keymapper/shizuku/ShizukuAdapter.kt rename to system/src/main/java/io/github/sds100/keymapper/system/shizuku/ShizukuAdapter.kt index db431328f5..d3c1aabf02 100644 --- a/app/src/main/java/io/github/sds100/keymapper/shizuku/ShizukuAdapter.kt +++ b/system/src/main/java/io/github/sds100/keymapper/system/shizuku/ShizukuAdapter.kt @@ -1,12 +1,11 @@ -package io.github.sds100.keymapper.shizuku +package io.github.sds100.keymapper.system.shizuku import kotlinx.coroutines.flow.StateFlow -/** - * Created by sds100 on 20/07/2021. - */ + interface ShizukuAdapter { val isInstalled: StateFlow val isStarted: StateFlow fun openShizukuApp() + fun requestPermission() } diff --git a/app/src/main/java/io/github/sds100/keymapper/shizuku/ShizukuAdapterImpl.kt b/system/src/main/java/io/github/sds100/keymapper/system/shizuku/ShizukuAdapterImpl.kt similarity index 79% rename from app/src/main/java/io/github/sds100/keymapper/shizuku/ShizukuAdapterImpl.kt rename to system/src/main/java/io/github/sds100/keymapper/system/shizuku/ShizukuAdapterImpl.kt index 7d96ea34a3..b9db5d2541 100644 --- a/app/src/main/java/io/github/sds100/keymapper/shizuku/ShizukuAdapterImpl.kt +++ b/system/src/main/java/io/github/sds100/keymapper/system/shizuku/ShizukuAdapterImpl.kt @@ -1,7 +1,8 @@ -package io.github.sds100.keymapper.shizuku +package io.github.sds100.keymapper.system.shizuku import io.github.sds100.keymapper.system.apps.PackageManagerAdapter import io.github.sds100.keymapper.system.apps.isAppInstalledFlow +import io.github.sds100.keymapper.system.permissions.AndroidPermissionAdapter import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted @@ -9,11 +10,11 @@ import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.stateIn import rikka.shizuku.Shizuku +import javax.inject.Inject +import javax.inject.Singleton -/** - * Created by sds100 on 20/07/2021. - */ -class ShizukuAdapterImpl( +@Singleton +class ShizukuAdapterImpl @Inject constructor( private val coroutineScope: CoroutineScope, private val packageManagerAdapter: PackageManagerAdapter, ) : ShizukuAdapter { @@ -51,4 +52,10 @@ class ShizukuAdapterImpl( override fun openShizukuApp() { packageManagerAdapter.openApp(ShizukuUtils.SHIZUKU_PACKAGE) } + + override fun requestPermission() { + if (Shizuku.getBinder() != null) { + Shizuku.requestPermission(AndroidPermissionAdapter.REQUEST_CODE_SHIZUKU_PERMISSION) + } + } } diff --git a/app/src/main/java/io/github/sds100/keymapper/shizuku/ShizukuInputEventInjector.kt b/system/src/main/java/io/github/sds100/keymapper/system/shizuku/ShizukuInputEventInjector.kt similarity index 94% rename from app/src/main/java/io/github/sds100/keymapper/shizuku/ShizukuInputEventInjector.kt rename to system/src/main/java/io/github/sds100/keymapper/system/shizuku/ShizukuInputEventInjector.kt index 2b812d21c0..e63b4e4590 100644 --- a/app/src/main/java/io/github/sds100/keymapper/shizuku/ShizukuInputEventInjector.kt +++ b/system/src/main/java/io/github/sds100/keymapper/system/shizuku/ShizukuInputEventInjector.kt @@ -1,13 +1,13 @@ -package io.github.sds100.keymapper.shizuku +package io.github.sds100.keymapper.system.shizuku import android.annotation.SuppressLint import android.content.Context import android.hardware.input.IInputManager import android.os.SystemClock import android.view.KeyEvent +import io.github.sds100.keymapper.common.utils.InputEventType import io.github.sds100.keymapper.system.inputevents.InputEventInjector import io.github.sds100.keymapper.system.inputmethod.InputKeyModel -import io.github.sds100.keymapper.util.InputEventType import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import rikka.shizuku.ShizukuBinderWrapper diff --git a/app/src/main/java/io/github/sds100/keymapper/shizuku/ShizukuUtils.kt b/system/src/main/java/io/github/sds100/keymapper/system/shizuku/ShizukuUtils.kt similarity index 85% rename from app/src/main/java/io/github/sds100/keymapper/shizuku/ShizukuUtils.kt rename to system/src/main/java/io/github/sds100/keymapper/system/shizuku/ShizukuUtils.kt index 7f7c07d78c..df8a057936 100644 --- a/app/src/main/java/io/github/sds100/keymapper/shizuku/ShizukuUtils.kt +++ b/system/src/main/java/io/github/sds100/keymapper/system/shizuku/ShizukuUtils.kt @@ -1,10 +1,8 @@ -package io.github.sds100.keymapper.shizuku +package io.github.sds100.keymapper.system.shizuku import android.os.Build -/** - * Created by sds100 on 20/07/2021. - */ + object ShizukuUtils { const val SHIZUKU_PACKAGE = "moe.shizuku.privileged.api" diff --git a/system/src/main/java/io/github/sds100/keymapper/system/url/AndroidOpenUrlAdapter.kt b/system/src/main/java/io/github/sds100/keymapper/system/url/AndroidOpenUrlAdapter.kt new file mode 100644 index 0000000000..6c29a4cb36 --- /dev/null +++ b/system/src/main/java/io/github/sds100/keymapper/system/url/AndroidOpenUrlAdapter.kt @@ -0,0 +1,17 @@ +package io.github.sds100.keymapper.system.url + +import android.content.Context +import dagger.hilt.android.qualifiers.ApplicationContext +import javax.inject.Inject +import javax.inject.Singleton +import io.github.sds100.keymapper.common.utils.KMResult + +@Singleton +class AndroidOpenUrlAdapter @Inject constructor( + @ApplicationContext private val context: Context +) : OpenUrlAdapter { + + private val ctx = context.applicationContext + + override fun openUrl(url: String): KMResult<*> = UrlUtils.openUrl(ctx, url) +} diff --git a/system/src/main/java/io/github/sds100/keymapper/system/url/OpenUrlAdapter.kt b/system/src/main/java/io/github/sds100/keymapper/system/url/OpenUrlAdapter.kt new file mode 100644 index 0000000000..3fa4ec3c2e --- /dev/null +++ b/system/src/main/java/io/github/sds100/keymapper/system/url/OpenUrlAdapter.kt @@ -0,0 +1,8 @@ +package io.github.sds100.keymapper.system.url + +import io.github.sds100.keymapper.common.utils.KMResult + + +interface OpenUrlAdapter { + fun openUrl(url: String): KMResult<*> +} diff --git a/app/src/main/java/io/github/sds100/keymapper/system/url/UrlUtils.kt b/system/src/main/java/io/github/sds100/keymapper/system/url/UrlUtils.kt similarity index 63% rename from app/src/main/java/io/github/sds100/keymapper/system/url/UrlUtils.kt rename to system/src/main/java/io/github/sds100/keymapper/system/url/UrlUtils.kt index 472dea054c..68a5e58afe 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/url/UrlUtils.kt +++ b/system/src/main/java/io/github/sds100/keymapper/system/url/UrlUtils.kt @@ -4,16 +4,14 @@ import android.content.ActivityNotFoundException import android.content.Context import android.content.Intent import androidx.core.net.toUri -import io.github.sds100.keymapper.util.Error -import io.github.sds100.keymapper.util.Result -import io.github.sds100.keymapper.util.success +import io.github.sds100.keymapper.common.utils.KMError +import io.github.sds100.keymapper.common.utils.KMResult +import io.github.sds100.keymapper.common.utils.success + -/** - * Created by sds100 on 11/01/21. - */ object UrlUtils { - fun openUrl(ctx: Context, url: String): Result<*> { + fun openUrl(ctx: Context, url: String): KMResult<*> { Intent(Intent.ACTION_VIEW, url.toUri()).apply { flags = Intent.FLAG_ACTIVITY_NEW_TASK @@ -21,7 +19,7 @@ object UrlUtils { ctx.startActivity(this) return success() } catch (e: ActivityNotFoundException) { - return Error.NoAppToOpenUrl + return KMError.NoAppToOpenUrl } } } diff --git a/app/src/main/java/io/github/sds100/keymapper/system/vibrator/AndroidVibratorAdapter.kt b/system/src/main/java/io/github/sds100/keymapper/system/vibrator/AndroidVibratorAdapter.kt similarity index 80% rename from app/src/main/java/io/github/sds100/keymapper/system/vibrator/AndroidVibratorAdapter.kt rename to system/src/main/java/io/github/sds100/keymapper/system/vibrator/AndroidVibratorAdapter.kt index 5b7deb0288..51159df53f 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/vibrator/AndroidVibratorAdapter.kt +++ b/system/src/main/java/io/github/sds100/keymapper/system/vibrator/AndroidVibratorAdapter.kt @@ -6,11 +6,14 @@ import android.os.VibrationAttributes import android.os.VibrationEffect import android.os.Vibrator import androidx.core.content.getSystemService +import dagger.hilt.android.qualifiers.ApplicationContext +import javax.inject.Inject +import javax.inject.Singleton -/** - * Created by sds100 on 17/04/2021. - */ -class AndroidVibratorAdapter(context: Context) : VibratorAdapter { +@Singleton +class AndroidVibratorAdapter @Inject constructor( + @ApplicationContext private val context: Context +) : VibratorAdapter { private val vibrator: Vibrator? = context.getSystemService() override fun vibrate(duration: Long) { diff --git a/app/src/main/java/io/github/sds100/keymapper/system/vibrator/VibratorAdapter.kt b/system/src/main/java/io/github/sds100/keymapper/system/vibrator/VibratorAdapter.kt similarity index 72% rename from app/src/main/java/io/github/sds100/keymapper/system/vibrator/VibratorAdapter.kt rename to system/src/main/java/io/github/sds100/keymapper/system/vibrator/VibratorAdapter.kt index 72f90a0ae6..57f55f1559 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/vibrator/VibratorAdapter.kt +++ b/system/src/main/java/io/github/sds100/keymapper/system/vibrator/VibratorAdapter.kt @@ -1,8 +1,6 @@ package io.github.sds100.keymapper.system.vibrator -/** - * Created by sds100 on 17/04/2021. - */ + interface VibratorAdapter { fun vibrate(duration: Long) } diff --git a/app/src/main/java/io/github/sds100/keymapper/system/volume/AndroidVolumeAdapter.kt b/system/src/main/java/io/github/sds100/keymapper/system/volume/AndroidVolumeAdapter.kt similarity index 76% rename from app/src/main/java/io/github/sds100/keymapper/system/volume/AndroidVolumeAdapter.kt rename to system/src/main/java/io/github/sds100/keymapper/system/volume/AndroidVolumeAdapter.kt index c1d6105851..e0b3c50c73 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/volume/AndroidVolumeAdapter.kt +++ b/system/src/main/java/io/github/sds100/keymapper/system/volume/AndroidVolumeAdapter.kt @@ -6,16 +6,20 @@ import android.media.AudioManager import android.os.Build import androidx.annotation.RequiresApi import androidx.core.content.getSystemService +import io.github.sds100.keymapper.common.utils.KMError +import io.github.sds100.keymapper.common.utils.KMResult +import io.github.sds100.keymapper.common.utils.Success +import io.github.sds100.keymapper.common.utils.then +import io.github.sds100.keymapper.system.SystemError import io.github.sds100.keymapper.system.permissions.Permission -import io.github.sds100.keymapper.util.Error -import io.github.sds100.keymapper.util.Result -import io.github.sds100.keymapper.util.Success -import io.github.sds100.keymapper.util.then - -/** - * Created by sds100 on 20/04/2021. - */ -class AndroidVolumeAdapter(context: Context) : VolumeAdapter { +import dagger.hilt.android.qualifiers.ApplicationContext +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class AndroidVolumeAdapter @Inject constructor( + @ApplicationContext private val context: Context +) : VolumeAdapter { private val ctx = context.applicationContext private val audioManager: AudioManager by lazy { ctx.getSystemService()!! } @@ -29,50 +33,50 @@ class AndroidVolumeAdapter(context: Context) : VolumeAdapter { else -> throw Exception("Don't know how to convert this ringer moder ${audioManager.ringerMode}") } - override fun raiseVolume(stream: VolumeStream?, showVolumeUi: Boolean): Result<*> = + override fun raiseVolume(stream: VolumeStream?, showVolumeUi: Boolean): KMResult<*> = stream.convert().then { streamType -> adjustVolume(AudioManager.ADJUST_RAISE, showVolumeUi, streamType) } - override fun lowerVolume(stream: VolumeStream?, showVolumeUi: Boolean): Result<*> = + override fun lowerVolume(stream: VolumeStream?, showVolumeUi: Boolean): KMResult<*> = stream.convert().then { streamType -> adjustVolume(AudioManager.ADJUST_LOWER, showVolumeUi, streamType) } - override fun muteVolume(stream: VolumeStream?, showVolumeUi: Boolean): Result<*> { + override fun muteVolume(stream: VolumeStream?, showVolumeUi: Boolean): KMResult<*> { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { return stream.convert().then { streamType -> adjustVolume(AudioManager.ADJUST_MUTE, showVolumeUi, streamType) } } else { - return Error.SdkVersionTooLow(minSdk = Build.VERSION_CODES.M) + return KMError.SdkVersionTooLow(minSdk = Build.VERSION_CODES.M) } } - override fun unmuteVolume(stream: VolumeStream?, showVolumeUi: Boolean): Result<*> { + override fun unmuteVolume(stream: VolumeStream?, showVolumeUi: Boolean): KMResult<*> { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { return stream.convert().then { streamType -> adjustVolume(AudioManager.ADJUST_UNMUTE, showVolumeUi, streamType) } } else { - return Error.SdkVersionTooLow(minSdk = Build.VERSION_CODES.M) + return KMError.SdkVersionTooLow(minSdk = Build.VERSION_CODES.M) } } - override fun toggleMuteVolume(stream: VolumeStream?, showVolumeUi: Boolean): Result<*> { + override fun toggleMuteVolume(stream: VolumeStream?, showVolumeUi: Boolean): KMResult<*> { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { return stream.convert().then { streamType -> adjustVolume(AudioManager.ADJUST_TOGGLE_MUTE, showVolumeUi, streamType) } } else { - return Error.SdkVersionTooLow(minSdk = Build.VERSION_CODES.M) + return KMError.SdkVersionTooLow(minSdk = Build.VERSION_CODES.M) } } - override fun showVolumeUi(): Result<*> = + override fun showVolumeUi(): KMResult<*> = adjustVolume(AudioManager.ADJUST_SAME, showVolumeUi = true) - override fun setRingerMode(mode: RingerMode): Result<*> { + override fun setRingerMode(mode: RingerMode): KMResult<*> { try { val sdkMode = when (mode) { RingerMode.NORMAL -> AudioManager.RINGER_MODE_NORMAL @@ -84,26 +88,26 @@ class AndroidVolumeAdapter(context: Context) : VolumeAdapter { return Success(Unit) } catch (e: SecurityException) { - return Error.PermissionDenied(Permission.ACCESS_NOTIFICATION_POLICY) + return SystemError.PermissionDenied(Permission.ACCESS_NOTIFICATION_POLICY) } } - override fun enableDndMode(dndMode: DndMode): Result<*> { + override fun enableDndMode(dndMode: DndMode): KMResult<*> { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { notificationManager.setInterruptionFilter(dndMode.convert()) return Success(Unit) } - return Error.SdkVersionTooLow(Build.VERSION_CODES.M) + return KMError.SdkVersionTooLow(Build.VERSION_CODES.M) } - override fun disableDndMode(): Result<*> { + override fun disableDndMode(): KMResult<*> { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { notificationManager.setInterruptionFilter(NotificationManager.INTERRUPTION_FILTER_ALL) return Success(Unit) } - return Error.SdkVersionTooLow(Build.VERSION_CODES.M) + return KMError.SdkVersionTooLow(Build.VERSION_CODES.M) } override fun isDndEnabled(): Boolean = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { @@ -119,7 +123,7 @@ class AndroidVolumeAdapter(context: Context) : VolumeAdapter { DndMode.NONE -> NotificationManager.INTERRUPTION_FILTER_NONE } - private fun VolumeStream?.convert(): Result = when (this) { + private fun VolumeStream?.convert(): KMResult = when (this) { VolumeStream.ALARM -> Success(AudioManager.STREAM_ALARM) VolumeStream.DTMF -> Success(AudioManager.STREAM_DTMF) VolumeStream.MUSIC -> Success(AudioManager.STREAM_MUSIC) @@ -131,7 +135,7 @@ class AndroidVolumeAdapter(context: Context) : VolumeAdapter { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { Success(AudioManager.STREAM_ACCESSIBILITY) } else { - Error.SdkVersionTooLow(minSdk = Build.VERSION_CODES.O) + KMError.SdkVersionTooLow(minSdk = Build.VERSION_CODES.O) } null -> Success(null) @@ -141,7 +145,7 @@ class AndroidVolumeAdapter(context: Context) : VolumeAdapter { adjustMode: Int, showVolumeUi: Boolean = false, streamType: Int? = null, - ): Result<*> { + ): KMResult<*> { try { val flag = if (showVolumeUi) { AudioManager.FLAG_SHOW_UI @@ -157,7 +161,7 @@ class AndroidVolumeAdapter(context: Context) : VolumeAdapter { return Success(Unit) } catch (e: SecurityException) { - return Error.PermissionDenied(Permission.ACCESS_NOTIFICATION_POLICY) + return SystemError.PermissionDenied(Permission.ACCESS_NOTIFICATION_POLICY) } } } diff --git a/app/src/main/java/io/github/sds100/keymapper/system/volume/DndMode.kt b/system/src/main/java/io/github/sds100/keymapper/system/volume/DndMode.kt similarity index 75% rename from app/src/main/java/io/github/sds100/keymapper/system/volume/DndMode.kt rename to system/src/main/java/io/github/sds100/keymapper/system/volume/DndMode.kt index e5ccf7280f..92deb0ec84 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/volume/DndMode.kt +++ b/system/src/main/java/io/github/sds100/keymapper/system/volume/DndMode.kt @@ -1,9 +1,5 @@ package io.github.sds100.keymapper.system.volume -/** - * Created by sds100 on 22/02/2021. - */ - /** * Do Not Disturb mode */ diff --git a/app/src/main/java/io/github/sds100/keymapper/system/volume/RingerMode.kt b/system/src/main/java/io/github/sds100/keymapper/system/volume/RingerMode.kt similarity index 71% rename from app/src/main/java/io/github/sds100/keymapper/system/volume/RingerMode.kt rename to system/src/main/java/io/github/sds100/keymapper/system/volume/RingerMode.kt index 744090d3cc..5460db38ec 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/volume/RingerMode.kt +++ b/system/src/main/java/io/github/sds100/keymapper/system/volume/RingerMode.kt @@ -1,8 +1,6 @@ package io.github.sds100.keymapper.system.volume -/** - * Created by sds100 on 22/02/2021. - */ + enum class RingerMode { NORMAL, VIBRATE, diff --git a/app/src/main/java/io/github/sds100/keymapper/system/volume/VolumeAdapter.kt b/system/src/main/java/io/github/sds100/keymapper/system/volume/VolumeAdapter.kt similarity index 55% rename from app/src/main/java/io/github/sds100/keymapper/system/volume/VolumeAdapter.kt rename to system/src/main/java/io/github/sds100/keymapper/system/volume/VolumeAdapter.kt index bad515409c..2c71fd9020 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/volume/VolumeAdapter.kt +++ b/system/src/main/java/io/github/sds100/keymapper/system/volume/VolumeAdapter.kt @@ -1,22 +1,20 @@ package io.github.sds100.keymapper.system.volume -import io.github.sds100.keymapper.util.Result +import io.github.sds100.keymapper.common.utils.KMResult + -/** - * Created by sds100 on 20/04/2021. - */ interface VolumeAdapter { val ringerMode: RingerMode - fun raiseVolume(stream: VolumeStream? = null, showVolumeUi: Boolean): Result<*> - fun lowerVolume(stream: VolumeStream? = null, showVolumeUi: Boolean): Result<*> - fun muteVolume(stream: VolumeStream? = null, showVolumeUi: Boolean): Result<*> - fun unmuteVolume(stream: VolumeStream? = null, showVolumeUi: Boolean): Result<*> - fun toggleMuteVolume(stream: VolumeStream? = null, showVolumeUi: Boolean): Result<*> - fun showVolumeUi(): Result<*> - fun setRingerMode(mode: RingerMode): Result<*> + fun raiseVolume(stream: VolumeStream? = null, showVolumeUi: Boolean): KMResult<*> + fun lowerVolume(stream: VolumeStream? = null, showVolumeUi: Boolean): KMResult<*> + fun muteVolume(stream: VolumeStream? = null, showVolumeUi: Boolean): KMResult<*> + fun unmuteVolume(stream: VolumeStream? = null, showVolumeUi: Boolean): KMResult<*> + fun toggleMuteVolume(stream: VolumeStream? = null, showVolumeUi: Boolean): KMResult<*> + fun showVolumeUi(): KMResult<*> + fun setRingerMode(mode: RingerMode): KMResult<*> fun isDndEnabled(): Boolean - fun enableDndMode(dndMode: DndMode): Result<*> - fun disableDndMode(): Result<*> + fun enableDndMode(dndMode: DndMode): KMResult<*> + fun disableDndMode(): KMResult<*> } diff --git a/app/src/main/java/io/github/sds100/keymapper/system/volume/VolumeStream.kt b/system/src/main/java/io/github/sds100/keymapper/system/volume/VolumeStream.kt similarity index 80% rename from app/src/main/java/io/github/sds100/keymapper/system/volume/VolumeStream.kt rename to system/src/main/java/io/github/sds100/keymapper/system/volume/VolumeStream.kt index 1e37f81005..fc243f7130 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/volume/VolumeStream.kt +++ b/system/src/main/java/io/github/sds100/keymapper/system/volume/VolumeStream.kt @@ -1,8 +1,6 @@ package io.github.sds100.keymapper.system.volume -/** - * Created by sds100 on 22/02/2021. - */ + enum class VolumeStream { ALARM, DTMF, diff --git a/system/src/main/res/values/strings.xml b/system/src/main/res/values/strings.xml new file mode 100644 index 0000000000..b644907005 --- /dev/null +++ b/system/src/main/res/values/strings.xml @@ -0,0 +1,4 @@ + + + Key Mapper Basic Input Method + \ No newline at end of file diff --git a/app/src/main/res/xml/device_admin.xml b/system/src/main/res/xml/device_admin.xml similarity index 100% rename from app/src/main/res/xml/device_admin.xml rename to system/src/main/res/xml/device_admin.xml diff --git a/app/src/main/res/xml/input_method.xml b/system/src/main/res/xml/input_method.xml similarity index 100% rename from app/src/main/res/xml/input_method.xml rename to system/src/main/res/xml/input_method.xml diff --git a/app/src/main/res/xml/keyboard_layouts.xml b/system/src/main/res/xml/keyboard_layouts.xml similarity index 100% rename from app/src/main/res/xml/keyboard_layouts.xml rename to system/src/main/res/xml/keyboard_layouts.xml diff --git a/systemstubs/build.gradle.kts b/systemstubs/build.gradle.kts index 3e715ee3ff..ddcd69ea12 100644 --- a/systemstubs/build.gradle.kts +++ b/systemstubs/build.gradle.kts @@ -5,13 +5,10 @@ plugins { android { namespace = "io.github.sds100.keymapper.systemstubs" - compileSdk = 35 + compileSdk = libs.versions.compile.sdk.get().toInt() defaultConfig { - minSdk = 21 - - testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" - consumerProguardFiles("consumer-rules.pro") + minSdk = libs.versions.min.sdk.get().toInt() } buildTypes { @@ -27,11 +24,15 @@ android { } } compileOptions { - sourceCompatibility = JavaVersion.VERSION_17 - targetCompatibility = JavaVersion.VERSION_17 + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 } kotlinOptions { - jvmTarget = "17" + jvmTarget = "11" + } + + buildFeatures { + aidl = true } } diff --git a/app/src/main/aidl/android/content/pm/IPackageManager.aidl b/systemstubs/src/main/aidl/android/content/pm/IPackageManager.aidl similarity index 100% rename from app/src/main/aidl/android/content/pm/IPackageManager.aidl rename to systemstubs/src/main/aidl/android/content/pm/IPackageManager.aidl diff --git a/app/src/main/aidl/android/hardware/input/IInputManager.aidl b/systemstubs/src/main/aidl/android/hardware/input/IInputManager.aidl similarity index 73% rename from app/src/main/aidl/android/hardware/input/IInputManager.aidl rename to systemstubs/src/main/aidl/android/hardware/input/IInputManager.aidl index d724bd19d0..0cbe5f383d 100644 --- a/app/src/main/aidl/android/hardware/input/IInputManager.aidl +++ b/systemstubs/src/main/aidl/android/hardware/input/IInputManager.aidl @@ -1,8 +1,6 @@ package android.hardware.input; -/** - * Created by sds100 on 15/07/2021. - */ + interface IInputManager { boolean injectInputEvent(in InputEvent event, int mode); } \ No newline at end of file