diff --git a/.idea/compiler.xml b/.idea/compiler.xml index b589d56e..b86273d9 100644 --- a/.idea/compiler.xml +++ b/.idea/compiler.xml @@ -1,6 +1,6 @@ - + \ No newline at end of file diff --git a/.idea/deploymentTargetSelector.xml b/.idea/deploymentTargetSelector.xml new file mode 100644 index 00000000..b268ef36 --- /dev/null +++ b/.idea/deploymentTargetSelector.xml @@ -0,0 +1,10 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 00000000..c8f004d7 --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml index e1eea1d6..c224ad56 100644 --- a/.idea/kotlinc.xml +++ b/.idea/kotlinc.xml @@ -1,6 +1,6 @@ - \ 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 00000000..1ac507e0 --- /dev/null +++ b/.idea/material_theme_project_new.xml @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file diff --git a/.idea/migrations.xml b/.idea/migrations.xml new file mode 100644 index 00000000..f8051a6f --- /dev/null +++ b/.idea/migrations.xml @@ -0,0 +1,10 @@ + + + + + + \ No newline at end of file diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml new file mode 100644 index 00000000..16660f1d --- /dev/null +++ b/.idea/runConfigurations.xml @@ -0,0 +1,17 @@ + + + + + + \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 483b1b39..d6507908 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -6,24 +6,22 @@ plugins { id 'androidx.navigation.safeargs' id 'dev.rikka.tools.refine' id 'com.google.android.gms.oss-licenses-plugin' + id 'com.google.devtools.ksp' } //Permission for Columbus to use rootProject.ext.set("columbusPermission", "com.google.android.columbus.taptap.permission.CONFIGURE_COLUMBUS_GESTURE") -def tagName = '1.6.1' -def tagVersion = 1610 +def tagName = '1.6.2' +def tagVersion = 1620 android { - compileSdk 34 - - //aidl is broken on 33... - buildToolsVersion "32.0.0" + compileSdk 35 defaultConfig { applicationId "com.kieronquinn.app.taptap" minSdk 24 - targetSdk 33 + targetSdk 35 versionCode tagVersion versionName tagName @@ -55,6 +53,7 @@ android { jvmTarget = '17' } buildFeatures { + buildConfig true viewBinding true aidl true } @@ -67,38 +66,38 @@ android { dependencies { //AndroidX - implementation 'androidx.core:core-ktx:1.10.1' - implementation 'androidx.appcompat:appcompat:1.6.1' + implementation 'androidx.core:core-ktx:1.13.1' + implementation 'androidx.appcompat:appcompat:1.7.0' implementation 'androidx.constraintlayout:constraintlayout:2.1.4' implementation "androidx.navigation:navigation-fragment-ktx:$nav_version" implementation "androidx.navigation:navigation-ui-ktx:$nav_version" - implementation "androidx.work:work-runtime-ktx:2.8.1" - implementation "androidx.core:core-ktx:1.10.1" - implementation "androidx.vectordrawable:vectordrawable-seekable:1.0.0-beta01" + implementation "androidx.work:work-runtime-ktx:2.9.1" + implementation "androidx.core:core-ktx:1.13.1" + implementation "androidx.vectordrawable:vectordrawable-seekable:1.0.0" implementation "androidx.core:core-splashscreen:1.0.1" - implementation "androidx.fragment:fragment-ktx:1.5.7" - implementation "androidx.activity:activity-ktx:1.7.2" + implementation "androidx.fragment:fragment-ktx:1.8.4" + implementation "androidx.activity:activity-ktx:1.9.3" //Lifecycle - def lifecycleVersion = '2.6.1' + def lifecycleVersion = '2.8.6' implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycleVersion" implementation "androidx.lifecycle:lifecycle-runtime-ktx:$lifecycleVersion" implementation "androidx.lifecycle:lifecycle-service:$lifecycleVersion" //Desugaring to allow Java Date on older Android versions - coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.0.3' + coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.1.2' //OSS licences screen - implementation 'com.google.android.gms:play-services-oss-licenses:17.0.1' + implementation 'com.google.android.gms:play-services-oss-licenses:17.1.0' //Room - def room_version = "2.5.1" + def room_version = "2.6.1" implementation "androidx.room:room-runtime:$room_version" implementation "androidx.room:room-ktx:$room_version" - kapt "androidx.room:room-compiler:$room_version" + ksp "androidx.room:room-compiler:$room_version" //MD3 - implementation 'com.google.android.material:material:1.9.0' + implementation 'com.google.android.material:material:1.12.0' //MonetCompat for Monet backwards compatibility implementation 'com.github.KieronQuinn:MonetCompat:0.4.1' @@ -107,17 +106,17 @@ dependencies { implementation "androidx.palette:palette-ktx:1.0.0" //Coroutines - implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1' + implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1' //Koin - implementation "io.insert-koin:koin-android:3.4.0" + implementation "io.insert-koin:koin-android:3.5.6" //Retrofit for updates + device spec query (opt-in) - implementation "com.squareup.retrofit2:retrofit:2.9.0" - implementation "com.squareup.retrofit2:converter-gson:2.9.0" + implementation "com.squareup.retrofit2:retrofit:2.11.0" + implementation "com.squareup.retrofit2:converter-gson:2.11.0" //Gson for serialization - implementation 'com.google.code.gson:gson:2.9.1' + implementation 'com.google.code.gson:gson:2.11.0' //Columbus module is separate to make it easier to work with implementation project(path: ':columbus') @@ -138,12 +137,12 @@ dependencies { implementation 'com.joaomgcd:taskerpluginlibrary:0.4.2' //Shizuku + libsu for shell/root services - def shizuku_version = '12.1.0' + def shizuku_version = '13.1.5' implementation "dev.rikka.shizuku:api:$shizuku_version" implementation "dev.rikka.shizuku:provider:$shizuku_version" implementation "dev.rikka.tools.refine:runtime:$refine_version" - def libsuVersion = '5.0.3' + def libsuVersion = '5.2.2' implementation "com.github.topjohnwu.libsu:core:${libsuVersion}" implementation "com.github.topjohnwu.libsu:service:${libsuVersion}" @@ -160,14 +159,14 @@ dependencies { implementation "io.noties.markwon:core:4.6.2" //Lottie for animations - implementation 'com.airbnb.android:lottie:5.2.0' + implementation 'com.airbnb.android:lottie:6.4.1' //Process Phoenix to fully restart the app when needed - implementation 'com.jakewharton:process-phoenix:2.1.2' + implementation 'com.jakewharton:process-phoenix:3.0.0' //Test - testImplementation 'junit:junit:4.+' - androidTestImplementation 'androidx.test.ext:junit:1.1.5' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' + testImplementation 'junit:junit:4.13.2' + androidTestImplementation 'androidx.test.ext:junit:1.2.1' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.6.1' } \ No newline at end of file diff --git a/app/release/baselineProfiles/0/app-release.dm b/app/release/baselineProfiles/0/app-release.dm new file mode 100644 index 00000000..3e51158b Binary files /dev/null and b/app/release/baselineProfiles/0/app-release.dm differ diff --git a/app/release/baselineProfiles/1/app-release.dm b/app/release/baselineProfiles/1/app-release.dm new file mode 100644 index 00000000..f0d0ba90 Binary files /dev/null and b/app/release/baselineProfiles/1/app-release.dm differ diff --git a/app/release/output-metadata.json b/app/release/output-metadata.json index 055a61aa..f0a2d8fc 100644 --- a/app/release/output-metadata.json +++ b/app/release/output-metadata.json @@ -11,10 +11,27 @@ "type": "SINGLE", "filters": [], "attributes": [], - "versionCode": 1600, - "versionName": "1.6", + "versionCode": 1620, + "versionName": "1.6.2", "outputFile": "app-release.apk" } ], - "elementType": "File" + "elementType": "File", + "baselineProfiles": [ + { + "minApi": 28, + "maxApi": 30, + "baselineProfiles": [ + "baselineProfiles/1/app-release.dm" + ] + }, + { + "minApi": 31, + "maxApi": 2147483647, + "baselineProfiles": [ + "baselineProfiles/0/app-release.dm" + ] + } + ], + "minSdkVersionForDexing": 24 } \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 454e11fa..f127a188 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -25,11 +25,14 @@ tools:ignore="ProtectedPermissions" /> + + android:theme="@style/Theme.TapTap.Splash" + tools:targetApi="tiramisu"> @@ -73,7 +76,8 @@ android:process=":crashreporting" android:excludeFromRecents="true"/> - + diff --git a/app/src/main/java/com/kieronquinn/app/taptap/components/accessibility/TapTapAccessibilityRouter.kt b/app/src/main/java/com/kieronquinn/app/taptap/components/accessibility/TapTapAccessibilityRouter.kt index a78ffc87..f30f59f1 100644 --- a/app/src/main/java/com/kieronquinn/app/taptap/components/accessibility/TapTapAccessibilityRouter.kt +++ b/app/src/main/java/com/kieronquinn/app/taptap/components/accessibility/TapTapAccessibilityRouter.kt @@ -2,11 +2,10 @@ package com.kieronquinn.app.taptap.components.accessibility import android.content.Intent import androidx.fragment.app.Fragment -import androidx.lifecycle.lifecycleScope import com.kieronquinn.app.taptap.ui.activities.MainActivity +import com.kieronquinn.app.taptap.utils.extensions.whenCreated import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableSharedFlow -import kotlinx.coroutines.flow.collect interface TapTapAccessibilityRouter { @@ -40,7 +39,7 @@ interface TapTapAccessibilityRouter { suspend fun onGestureAccessibilityStarted() fun bringToFrontOnAccessibilityStart(fragment: Fragment) { - fragment.viewLifecycleOwner.lifecycleScope.launchWhenCreated { + fragment.viewLifecycleOwner.whenCreated { this@TapTapAccessibilityRouter.accessibilityStartBus.collect { fragment.bringToFront() } @@ -48,7 +47,7 @@ interface TapTapAccessibilityRouter { } fun bringToFrontOnGestureAccessibilityStart(fragment: Fragment) { - fragment.viewLifecycleOwner.lifecycleScope.launchWhenCreated { + fragment.viewLifecycleOwner.whenCreated { this@TapTapAccessibilityRouter.gestureAccessibilityStartBus.collect { fragment.bringToFront() } diff --git a/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/actions/TapTapAction.kt b/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/actions/TapTapAction.kt index b37e630d..f6d0d1a2 100644 --- a/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/actions/TapTapAction.kt +++ b/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/actions/TapTapAction.kt @@ -12,7 +12,6 @@ import androidx.annotation.StringRes import androidx.core.app.NotificationCompat import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleOwner -import androidx.lifecycle.lifecycleScope import com.google.android.columbus.actions.Action import com.google.android.columbus.feedback.FeedbackEffect import com.google.android.columbus.gates.Gate @@ -26,6 +25,7 @@ import com.kieronquinn.app.taptap.service.accessibility.TapTapGestureAccessibili import com.kieronquinn.app.taptap.utils.extensions.getAccessibilityIntent import com.kieronquinn.app.taptap.utils.extensions.isServiceRunning import com.kieronquinn.app.taptap.utils.extensions.runOnDestroy +import com.kieronquinn.app.taptap.utils.extensions.whenCreated import com.kieronquinn.app.taptap.utils.notifications.TapTapNotificationChannel import com.kieronquinn.app.taptap.utils.notifications.TapTapNotificationId import com.kieronquinn.app.taptap.utils.notifications.TapTapNotificationIntentId @@ -86,7 +86,7 @@ abstract class TapTapAction( } private fun handleTrigger(detectionProperties: GestureSensor.DetectionProperties, isTripleTap: Boolean) { - lifecycleScope.launchWhenCreated { + lifecycle.whenCreated { onTriggered(detectionProperties, isTripleTap) } } diff --git a/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/actions/custom/AcceptCallAction.kt b/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/actions/custom/AcceptCallAction.kt index 0dcd9f17..dfdcd078 100644 --- a/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/actions/custom/AcceptCallAction.kt +++ b/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/actions/custom/AcceptCallAction.kt @@ -5,19 +5,15 @@ import android.annotation.SuppressLint import android.content.Context import android.os.Build import android.telecom.TelecomManager -import android.telephony.PhoneStateListener import android.telephony.TelephonyManager import androidx.lifecycle.Lifecycle -import androidx.lifecycle.lifecycleScope import com.google.android.columbus.feedback.FeedbackEffect import com.google.android.columbus.sensors.GestureSensor import com.kieronquinn.app.taptap.components.columbus.actions.TapTapAction -import com.kieronquinn.app.taptap.components.columbus.gates.TapTapGate import com.kieronquinn.app.taptap.components.columbus.gates.TapTapWhenGate import com.kieronquinn.app.taptap.utils.extensions.doesHavePermissions import com.kieronquinn.app.taptap.utils.extensions.onCallStateChanged -import kotlinx.coroutines.flow.callbackFlow -import kotlinx.coroutines.flow.collect +import com.kieronquinn.app.taptap.utils.extensions.whenResumed class AcceptCallAction( serviceLifecycle: Lifecycle, @@ -43,7 +39,7 @@ class AcceptCallAction( } init { - lifecycleScope.launchWhenResumed { + lifecycle.whenResumed { phoneStateListener.collect { notifyListeners() } diff --git a/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/actions/custom/LaunchAppAction.kt b/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/actions/custom/LaunchAppAction.kt index a19f2446..74e03209 100644 --- a/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/actions/custom/LaunchAppAction.kt +++ b/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/actions/custom/LaunchAppAction.kt @@ -9,7 +9,11 @@ import com.kieronquinn.app.taptap.components.accessibility.TapTapAccessibilityRo import com.kieronquinn.app.taptap.components.columbus.actions.TapTapAction import com.kieronquinn.app.taptap.components.columbus.gates.TapTapWhenGate import com.kieronquinn.app.taptap.utils.extensions.isAppLaunchable -import kotlinx.coroutines.flow.* +import com.kieronquinn.app.taptap.utils.extensions.whenCreated +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.filter +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.stateIn import org.koin.core.component.inject class LaunchAppAction( @@ -29,7 +33,7 @@ class LaunchAppAction( .stateIn(lifecycleScope, SharingStarted.Eagerly, false) init { - lifecycleScope.launchWhenCreated { + lifecycle.whenCreated { isOpen.collect { notifyListeners() } diff --git a/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/actions/custom/LaunchAppShortcutAction.kt b/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/actions/custom/LaunchAppShortcutAction.kt index 9e120a6a..8a97145d 100644 --- a/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/actions/custom/LaunchAppShortcutAction.kt +++ b/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/actions/custom/LaunchAppShortcutAction.kt @@ -1,20 +1,21 @@ package com.kieronquinn.app.taptap.components.columbus.actions.custom import android.content.Context -import android.os.Parcelable import androidx.lifecycle.Lifecycle import androidx.lifecycle.lifecycleScope import com.google.android.columbus.feedback.FeedbackEffect import com.google.android.columbus.sensors.GestureSensor import com.google.gson.Gson -import com.google.gson.annotations.SerializedName import com.kieronquinn.app.taptap.components.accessibility.TapTapAccessibilityRouter import com.kieronquinn.app.taptap.components.columbus.actions.TapTapAction import com.kieronquinn.app.taptap.components.columbus.gates.TapTapWhenGate import com.kieronquinn.app.taptap.models.columbus.AppShortcutData import com.kieronquinn.app.taptap.repositories.service.TapTapShizukuServiceRepository -import kotlinx.coroutines.flow.* -import kotlinx.parcelize.Parcelize +import com.kieronquinn.app.taptap.utils.extensions.whenCreated +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.filter +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.stateIn import org.koin.core.component.inject class LaunchAppShortcutAction( @@ -40,7 +41,7 @@ class LaunchAppShortcutAction( .stateIn(lifecycleScope, SharingStarted.Eagerly, false) init { - lifecycleScope.launchWhenCreated { + whenCreated { isOpen.collect { notifyListeners() } diff --git a/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/actions/custom/LaunchAssistantAction.kt b/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/actions/custom/LaunchAssistantAction.kt index 3335b2b7..df3bac9b 100644 --- a/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/actions/custom/LaunchAssistantAction.kt +++ b/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/actions/custom/LaunchAssistantAction.kt @@ -10,7 +10,11 @@ import com.kieronquinn.app.taptap.components.accessibility.TapTapAccessibilityRo import com.kieronquinn.app.taptap.components.columbus.actions.TapTapAction import com.kieronquinn.app.taptap.components.columbus.gates.TapTapWhenGate import com.kieronquinn.app.taptap.utils.extensions.isPackageAssistant -import kotlinx.coroutines.flow.* +import com.kieronquinn.app.taptap.utils.extensions.whenCreated +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.filter +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.stateIn import org.koin.core.component.inject class LaunchAssistantAction( @@ -29,7 +33,7 @@ class LaunchAssistantAction( .stateIn(lifecycleScope, SharingStarted.Eagerly, false) init { - lifecycleScope.launchWhenCreated { + lifecycle.whenCreated { isOpen.collect { notifyListeners() } diff --git a/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/actions/custom/LaunchCameraAction.kt b/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/actions/custom/LaunchCameraAction.kt index 3f95c489..e3f5eb54 100644 --- a/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/actions/custom/LaunchCameraAction.kt +++ b/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/actions/custom/LaunchCameraAction.kt @@ -11,7 +11,11 @@ import com.kieronquinn.app.taptap.components.columbus.actions.TapTapAction import com.kieronquinn.app.taptap.components.columbus.gates.TapTapWhenGate import com.kieronquinn.app.taptap.utils.extensions.getCameraLaunchIntent import com.kieronquinn.app.taptap.utils.extensions.isPackageCamera -import kotlinx.coroutines.flow.* +import com.kieronquinn.app.taptap.utils.extensions.whenCreated +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.filter +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.stateIn import org.koin.core.component.inject class LaunchCameraAction( @@ -35,7 +39,7 @@ class LaunchCameraAction( .stateIn(lifecycleScope, SharingStarted.Eagerly, false) init { - lifecycleScope.launchWhenCreated { + lifecycle.whenCreated { isOpen.collect { notifyListeners() } diff --git a/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/actions/custom/LaunchReachabilityAction.kt b/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/actions/custom/LaunchReachabilityAction.kt index fecd45bf..88728931 100644 --- a/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/actions/custom/LaunchReachabilityAction.kt +++ b/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/actions/custom/LaunchReachabilityAction.kt @@ -12,7 +12,12 @@ import com.kieronquinn.app.taptap.components.columbus.actions.TapTapAction import com.kieronquinn.app.taptap.components.columbus.gates.TapTapWhenGate import com.kieronquinn.app.taptap.ui.activities.ReachabilityActivity import com.kieronquinn.app.taptap.utils.extensions.isActivityRunning -import kotlinx.coroutines.flow.* +import com.kieronquinn.app.taptap.utils.extensions.whenCreated +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.collect +import kotlinx.coroutines.flow.filter +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.stateIn import org.koin.core.component.inject class LaunchReachabilityAction( @@ -32,7 +37,7 @@ class LaunchReachabilityAction( .stateIn(lifecycleScope, SharingStarted.Eagerly, "") init { - lifecycleScope.launchWhenCreated { + lifecycle.whenCreated { currentApp.collect() } } diff --git a/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/actions/custom/LaunchSearchAction.kt b/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/actions/custom/LaunchSearchAction.kt index 30673e84..02dccfcb 100644 --- a/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/actions/custom/LaunchSearchAction.kt +++ b/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/actions/custom/LaunchSearchAction.kt @@ -13,7 +13,11 @@ import com.kieronquinn.app.taptap.components.accessibility.TapTapAccessibilityRo import com.kieronquinn.app.taptap.components.columbus.actions.TapTapAction import com.kieronquinn.app.taptap.components.columbus.gates.TapTapWhenGate import com.kieronquinn.app.taptap.utils.extensions.isPackageAssistant -import kotlinx.coroutines.flow.* +import com.kieronquinn.app.taptap.utils.extensions.whenCreated +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.filter +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.stateIn import org.koin.core.component.inject class LaunchSearchAction( @@ -33,7 +37,7 @@ class LaunchSearchAction( .stateIn(lifecycleScope, SharingStarted.Eagerly, false) init { - lifecycleScope.launchWhenCreated { + lifecycle.whenCreated { isOpen.collect { notifyListeners() } diff --git a/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/actions/custom/LaunchShortcutAction.kt b/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/actions/custom/LaunchShortcutAction.kt index 655ccc4a..64e08af9 100644 --- a/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/actions/custom/LaunchShortcutAction.kt +++ b/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/actions/custom/LaunchShortcutAction.kt @@ -12,7 +12,11 @@ import com.kieronquinn.app.taptap.components.accessibility.TapTapAccessibilityRo import com.kieronquinn.app.taptap.components.columbus.actions.TapTapAction import com.kieronquinn.app.taptap.components.columbus.gates.TapTapWhenGate import com.kieronquinn.app.taptap.utils.extensions.deserialize -import kotlinx.coroutines.flow.* +import com.kieronquinn.app.taptap.utils.extensions.whenCreated +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.filter +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.stateIn import org.koin.core.component.inject class LaunchShortcutAction( @@ -44,7 +48,7 @@ class LaunchShortcutAction( .stateIn(lifecycleScope, SharingStarted.Eagerly, false) init { - lifecycleScope.launchWhenCreated { + lifecycle.whenCreated { isOpen.collect { notifyListeners() } diff --git a/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/actions/custom/NotificationsExpandAction.kt b/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/actions/custom/NotificationsExpandAction.kt index 00d12c7a..546e6a0e 100644 --- a/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/actions/custom/NotificationsExpandAction.kt +++ b/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/actions/custom/NotificationsExpandAction.kt @@ -4,12 +4,12 @@ import android.accessibilityservice.AccessibilityService import android.content.Context import android.os.Build import androidx.lifecycle.Lifecycle -import androidx.lifecycle.coroutineScope import com.google.android.columbus.feedback.FeedbackEffect import com.google.android.columbus.sensors.GestureSensor import com.kieronquinn.app.taptap.components.accessibility.TapTapAccessibilityRouter import com.kieronquinn.app.taptap.components.columbus.actions.TapTapAction import com.kieronquinn.app.taptap.components.columbus.gates.TapTapWhenGate +import com.kieronquinn.app.taptap.utils.extensions.whenCreated import org.koin.core.component.inject class NotificationsExpandAction( @@ -33,7 +33,7 @@ class NotificationsExpandAction( override val tag = "NotificationExpandAction" init { - serviceLifecycle.coroutineScope.launchWhenCreated { + serviceLifecycle.whenCreated { accessibilityRouter.accessibilityOutputBus.collect { if(it is TapTapAccessibilityRouter.AccessibilityOutput.NotificationShadeState){ isNotificationShadeOpen = it.open diff --git a/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/actions/custom/QuickSettingsExpandAction.kt b/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/actions/custom/QuickSettingsExpandAction.kt index b0f5d682..cb383450 100644 --- a/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/actions/custom/QuickSettingsExpandAction.kt +++ b/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/actions/custom/QuickSettingsExpandAction.kt @@ -4,14 +4,13 @@ import android.accessibilityservice.AccessibilityService import android.content.Context import android.os.Build import androidx.lifecycle.Lifecycle -import androidx.lifecycle.coroutineScope import com.google.android.columbus.feedback.FeedbackEffect import com.google.android.columbus.sensors.GestureSensor import com.kieronquinn.app.taptap.components.accessibility.TapTapAccessibilityRouter import com.kieronquinn.app.taptap.components.columbus.actions.TapTapAction import com.kieronquinn.app.taptap.components.columbus.gates.TapTapWhenGate +import com.kieronquinn.app.taptap.utils.extensions.whenCreated import kotlinx.coroutines.delay -import kotlinx.coroutines.flow.collect import org.koin.core.component.inject class QuickSettingsExpandAction( @@ -35,7 +34,7 @@ class QuickSettingsExpandAction( override val tag = "NotificationExpandAction" init { - serviceLifecycle.coroutineScope.launchWhenCreated { + serviceLifecycle.whenCreated { accessibilityRouter.accessibilityOutputBus.collect { if(it is TapTapAccessibilityRouter.AccessibilityOutput.QuickSettingsShadeState){ isQuickSettingsOpen = it.open diff --git a/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/actions/custom/RejectCallAction.kt b/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/actions/custom/RejectCallAction.kt index 0a6459ab..d81a73cf 100644 --- a/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/actions/custom/RejectCallAction.kt +++ b/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/actions/custom/RejectCallAction.kt @@ -7,15 +7,13 @@ import android.os.Build import android.telecom.TelecomManager import android.telephony.TelephonyManager import androidx.lifecycle.Lifecycle -import androidx.lifecycle.lifecycleScope import com.google.android.columbus.feedback.FeedbackEffect import com.google.android.columbus.sensors.GestureSensor import com.kieronquinn.app.taptap.components.columbus.actions.TapTapAction -import com.kieronquinn.app.taptap.components.columbus.gates.TapTapGate import com.kieronquinn.app.taptap.components.columbus.gates.TapTapWhenGate import com.kieronquinn.app.taptap.utils.extensions.doesHavePermissions import com.kieronquinn.app.taptap.utils.extensions.onCallStateChanged -import kotlinx.coroutines.flow.collect +import com.kieronquinn.app.taptap.utils.extensions.whenResumed class RejectCallAction( serviceLifecycle: Lifecycle, @@ -41,7 +39,7 @@ class RejectCallAction( } init { - lifecycleScope.launchWhenResumed { + lifecycle.whenResumed { phoneStateListener.collect { notifyListeners() } diff --git a/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/actions/custom/SnapchatAction.kt b/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/actions/custom/SnapchatAction.kt index 0a303d4b..4929c085 100644 --- a/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/actions/custom/SnapchatAction.kt +++ b/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/actions/custom/SnapchatAction.kt @@ -2,7 +2,6 @@ package com.kieronquinn.app.taptap.components.columbus.actions.custom import android.app.KeyguardManager import android.content.ActivityNotFoundException -import android.content.ComponentName import android.content.Context import android.content.Intent import android.provider.MediaStore @@ -15,7 +14,11 @@ import com.kieronquinn.app.taptap.components.columbus.actions.TapTapAction import com.kieronquinn.app.taptap.components.columbus.gates.TapTapWhenGate import com.kieronquinn.app.taptap.utils.extensions.EXTRA_KEY_IS_FROM_COLUMBUS import com.kieronquinn.app.taptap.utils.extensions.isAppLaunchable -import kotlinx.coroutines.flow.* +import com.kieronquinn.app.taptap.utils.extensions.whenCreated +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.filter +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.stateIn import org.koin.core.component.inject class SnapchatAction( @@ -44,7 +47,7 @@ class SnapchatAction( .stateIn(lifecycleScope, SharingStarted.Eagerly, false) init { - lifecycleScope.launchWhenCreated { + lifecycle.whenCreated { isOpen.collect { notifyListeners() } diff --git a/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/actions/custom/WakeDeviceAction.kt b/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/actions/custom/WakeDeviceAction.kt index b7836abc..07330177 100644 --- a/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/actions/custom/WakeDeviceAction.kt +++ b/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/actions/custom/WakeDeviceAction.kt @@ -13,9 +13,9 @@ import com.kieronquinn.app.taptap.components.settings.TapTapSettings import com.kieronquinn.app.taptap.ui.activities.UnlockDeviceActivity import com.kieronquinn.app.taptap.ui.activities.WakeUpActivity import com.kieronquinn.app.taptap.utils.extensions.broadcastReceiverAsFlow +import com.kieronquinn.app.taptap.utils.extensions.whenCreated import kotlinx.coroutines.delay import kotlinx.coroutines.flow.SharingStarted -import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch @@ -48,7 +48,7 @@ class WakeDeviceAction( }.stateIn(lifecycleScope, SharingStarted.Eagerly, !powerManager.isInteractive) init { - lifecycleScope.launchWhenCreated { + lifecycle.whenCreated { screenState.collect { notifyListeners() } diff --git a/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/feedback/TapTapFeedbackEffect.kt b/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/feedback/TapTapFeedbackEffect.kt index 5185ca47..e58b1456 100644 --- a/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/feedback/TapTapFeedbackEffect.kt +++ b/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/feedback/TapTapFeedbackEffect.kt @@ -2,10 +2,10 @@ package com.kieronquinn.app.taptap.components.columbus.feedback import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleOwner -import androidx.lifecycle.lifecycleScope import com.google.android.columbus.feedback.FeedbackEffect import com.google.android.columbus.sensors.GestureSensor import com.kieronquinn.app.taptap.utils.extensions.runOnDestroy +import com.kieronquinn.app.taptap.utils.extensions.whenCreated import org.koin.core.component.KoinComponent /** @@ -29,7 +29,7 @@ abstract class TapTapFeedbackEffect(private val serviceLifecycle: Lifecycle): Fe detectionProperties: GestureSensor.DetectionProperties? ) { if(detectionProperties == null) return - lifecycleScope.launchWhenCreated { + lifecycle.whenCreated { when(flags){ //Progress 2 -> onProgress(detectionProperties) diff --git a/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/gates/custom/AppVisibilityGate.kt b/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/gates/custom/AppVisibilityGate.kt index 91c41e62..61f7bb3a 100644 --- a/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/gates/custom/AppVisibilityGate.kt +++ b/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/gates/custom/AppVisibilityGate.kt @@ -5,7 +5,11 @@ import androidx.lifecycle.Lifecycle import androidx.lifecycle.lifecycleScope import com.kieronquinn.app.taptap.components.accessibility.TapTapAccessibilityRouter import com.kieronquinn.app.taptap.components.columbus.gates.TapTapGate -import kotlinx.coroutines.flow.* +import com.kieronquinn.app.taptap.utils.extensions.whenCreated +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.filter +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.stateIn import org.koin.core.component.inject class AppVisibilityGate( @@ -20,7 +24,7 @@ class AppVisibilityGate( .stateIn(lifecycleScope, SharingStarted.Eagerly, false) init { - lifecycleScope.launchWhenCreated { + lifecycle.whenCreated { appOpen.collect { notifyListeners() } diff --git a/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/gates/custom/BatterySaverGate.kt b/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/gates/custom/BatterySaverGate.kt index 64666527..6fb463b7 100644 --- a/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/gates/custom/BatterySaverGate.kt +++ b/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/gates/custom/BatterySaverGate.kt @@ -7,6 +7,7 @@ import androidx.lifecycle.Lifecycle import androidx.lifecycle.lifecycleScope import com.kieronquinn.app.taptap.components.columbus.gates.TapTapGate import com.kieronquinn.app.taptap.utils.extensions.broadcastReceiverAsFlow +import com.kieronquinn.app.taptap.utils.extensions.whenCreated import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn @@ -28,7 +29,7 @@ class BatterySaverGate( } init { - lifecycleScope.launchWhenCreated { + whenCreated { batterySaverEnabled.collect { notifyListeners() } diff --git a/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/gates/custom/CameraVisibilityGate.kt b/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/gates/custom/CameraVisibilityGate.kt index eb29bd1f..d448b004 100644 --- a/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/gates/custom/CameraVisibilityGate.kt +++ b/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/gates/custom/CameraVisibilityGate.kt @@ -6,7 +6,11 @@ import androidx.lifecycle.lifecycleScope import com.kieronquinn.app.taptap.components.accessibility.TapTapAccessibilityRouter import com.kieronquinn.app.taptap.components.columbus.gates.TapTapGate import com.kieronquinn.app.taptap.utils.extensions.isPackageCamera -import kotlinx.coroutines.flow.* +import com.kieronquinn.app.taptap.utils.extensions.whenCreated +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.filter +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.stateIn import org.koin.core.component.inject class CameraVisibilityGate( @@ -21,7 +25,7 @@ class CameraVisibilityGate( .stateIn(lifecycleScope, SharingStarted.Eagerly, false) init { - lifecycleScope.launchWhenCreated { + whenCreated { cameraOpen.collect { notifyListeners() } diff --git a/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/gates/custom/ChargingStateGate.kt b/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/gates/custom/ChargingStateGate.kt index 2269dfde..75e6d336 100644 --- a/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/gates/custom/ChargingStateGate.kt +++ b/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/gates/custom/ChargingStateGate.kt @@ -7,8 +7,8 @@ import androidx.lifecycle.lifecycleScope import com.kieronquinn.app.taptap.components.columbus.gates.TapTapGate import com.kieronquinn.app.taptap.utils.extensions.broadcastReceiverAsFlow import com.kieronquinn.app.taptap.utils.extensions.isPowerConnected +import com.kieronquinn.app.taptap.utils.extensions.whenCreated import kotlinx.coroutines.flow.SharingStarted -import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn @@ -23,7 +23,7 @@ class ChargingStateGate( }.stateIn(lifecycleScope, SharingStarted.Eagerly, context.isPowerConnected()) init { - lifecycleScope.launchWhenCreated { + lifecycle.whenCreated { batteryState.collect { notifyListeners() } diff --git a/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/gates/custom/KeyboardVisibilityGate.kt b/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/gates/custom/KeyboardVisibilityGate.kt index 27ab0c51..0aaec0d3 100644 --- a/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/gates/custom/KeyboardVisibilityGate.kt +++ b/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/gates/custom/KeyboardVisibilityGate.kt @@ -10,7 +10,12 @@ import com.kieronquinn.app.taptap.components.columbus.gates.TapTapGate import com.kieronquinn.app.taptap.utils.extensions.getSettingAsFlow import com.kieronquinn.app.taptap.utils.extensions.isKeyboardOpen import com.kieronquinn.app.taptap.utils.extensions.secureStringConverter -import kotlinx.coroutines.flow.* +import com.kieronquinn.app.taptap.utils.extensions.whenCreated +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.filter +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.stateIn import org.koin.core.component.inject class KeyboardVisibilityGate( @@ -34,7 +39,7 @@ class KeyboardVisibilityGate( }.stateIn(lifecycleScope, SharingStarted.Eagerly, false) init { - lifecycleScope.launchWhenCreated { + lifecycle.whenCreated { keyboardOpen.collect { notifyListeners() } diff --git a/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/gates/custom/LockScreenStateGate.kt b/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/gates/custom/LockScreenStateGate.kt index d9755dee..977563b4 100644 --- a/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/gates/custom/LockScreenStateGate.kt +++ b/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/gates/custom/LockScreenStateGate.kt @@ -8,8 +8,8 @@ import androidx.lifecycle.Lifecycle import androidx.lifecycle.lifecycleScope import com.kieronquinn.app.taptap.components.columbus.gates.TapTapGate import com.kieronquinn.app.taptap.utils.extensions.broadcastReceiverAsFlow +import com.kieronquinn.app.taptap.utils.extensions.whenCreated import kotlinx.coroutines.flow.SharingStarted -import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn @@ -32,7 +32,7 @@ class LockScreenStateGate( }.stateIn(lifecycleScope, SharingStarted.Eagerly, powerManager.isInteractive && keyguardManager.isKeyguardLocked) init { - lifecycleScope.launchWhenCreated { + lifecycle.whenCreated { screenState.collect { notifyListeners() } diff --git a/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/gates/custom/LockScreenStateInverseGate.kt b/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/gates/custom/LockScreenStateInverseGate.kt index e4f281eb..d0061c8f 100644 --- a/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/gates/custom/LockScreenStateInverseGate.kt +++ b/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/gates/custom/LockScreenStateInverseGate.kt @@ -9,8 +9,8 @@ import androidx.lifecycle.lifecycleScope import com.kieronquinn.app.taptap.components.columbus.gates.PassiveGate import com.kieronquinn.app.taptap.components.columbus.gates.TapTapGate import com.kieronquinn.app.taptap.utils.extensions.broadcastReceiverAsFlow +import com.kieronquinn.app.taptap.utils.extensions.whenCreated import kotlinx.coroutines.flow.SharingStarted -import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn @@ -35,7 +35,7 @@ class LockScreenStateInverseGate( }.stateIn(lifecycleScope, SharingStarted.Eagerly, powerManager.isInteractive && keyguardManager.isKeyguardLocked) init { - lifecycleScope.launchWhenCreated { + lifecycle.whenCreated { screenState.collect { notifyListeners() } diff --git a/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/gates/custom/LowBatteryGate.kt b/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/gates/custom/LowBatteryGate.kt index 947345ea..2dd26412 100644 --- a/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/gates/custom/LowBatteryGate.kt +++ b/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/gates/custom/LowBatteryGate.kt @@ -8,8 +8,9 @@ import androidx.lifecycle.Lifecycle import androidx.lifecycle.lifecycleScope import com.kieronquinn.app.taptap.components.columbus.gates.TapTapGate import com.kieronquinn.app.taptap.utils.extensions.broadcastReceiverAsFlow +import com.kieronquinn.app.taptap.utils.extensions.registerReceiverCompat +import com.kieronquinn.app.taptap.utils.extensions.whenCreated import kotlinx.coroutines.flow.SharingStarted -import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn @@ -28,7 +29,7 @@ class LowBatteryGate( } init { - lifecycleScope.launchWhenCreated { + lifecycle.whenCreated { batteryLevel.collect { notifyListeners() } @@ -36,7 +37,7 @@ class LowBatteryGate( } private fun getBatteryLevel(): Float { - val batteryStatus = context.registerReceiver(null, IntentFilter(Intent.ACTION_BATTERY_CHANGED)) + val batteryStatus = context.registerReceiverCompat(null, IntentFilter(Intent.ACTION_BATTERY_CHANGED)) val level = batteryStatus?.getIntExtra(BatteryManager.EXTRA_LEVEL, -1) ?: return 1f val scale = batteryStatus.getIntExtra(BatteryManager.EXTRA_SCALE, -1) if(level == -1 || scale == -1) return 1f diff --git a/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/gates/custom/PowerStateGate.kt b/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/gates/custom/PowerStateGate.kt index 61699e3a..52828f1e 100644 --- a/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/gates/custom/PowerStateGate.kt +++ b/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/gates/custom/PowerStateGate.kt @@ -8,8 +8,8 @@ import androidx.lifecycle.lifecycleScope import com.kieronquinn.app.taptap.components.columbus.gates.PassiveGate import com.kieronquinn.app.taptap.components.columbus.gates.TapTapGate import com.kieronquinn.app.taptap.utils.extensions.broadcastReceiverAsFlow +import com.kieronquinn.app.taptap.utils.extensions.whenResumed import kotlinx.coroutines.flow.SharingStarted -import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn @@ -31,7 +31,7 @@ class PowerStateGate( init { - lifecycleScope.launchWhenResumed { + lifecycle.whenResumed { screenState.collect { notifyListeners() } diff --git a/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/gates/custom/PowerStateInverseGate.kt b/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/gates/custom/PowerStateInverseGate.kt index bdadea43..bfc750dc 100644 --- a/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/gates/custom/PowerStateInverseGate.kt +++ b/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/gates/custom/PowerStateInverseGate.kt @@ -7,8 +7,8 @@ import androidx.lifecycle.Lifecycle import androidx.lifecycle.lifecycleScope import com.kieronquinn.app.taptap.components.columbus.gates.TapTapGate import com.kieronquinn.app.taptap.utils.extensions.broadcastReceiverAsFlow +import com.kieronquinn.app.taptap.utils.extensions.whenResumed import kotlinx.coroutines.flow.SharingStarted -import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn @@ -27,7 +27,7 @@ class PowerStateInverseGate( }.stateIn(lifecycleScope, SharingStarted.Eagerly, powerManager.isInteractive) init { - lifecycleScope.launchWhenResumed { + lifecycle.whenResumed { screenState.collect { notifyListeners() } diff --git a/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/gates/custom/TelephonyActivityGate.kt b/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/gates/custom/TelephonyActivityGate.kt index c7042390..26872a8b 100644 --- a/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/gates/custom/TelephonyActivityGate.kt +++ b/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/gates/custom/TelephonyActivityGate.kt @@ -6,8 +6,8 @@ import androidx.lifecycle.Lifecycle import androidx.lifecycle.lifecycleScope import com.kieronquinn.app.taptap.components.columbus.gates.TapTapGate import com.kieronquinn.app.taptap.utils.extensions.onCallStateChanged +import com.kieronquinn.app.taptap.utils.extensions.whenCreated import kotlinx.coroutines.flow.SharingStarted -import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn @@ -25,7 +25,7 @@ class TelephonyActivityGate( } init { - lifecycleScope.launchWhenCreated { + lifecycle.whenCreated { isCallBlocked.collect { notifyListeners() } diff --git a/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/gates/custom/UsbStateGate.kt b/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/gates/custom/UsbStateGate.kt index 375a127d..4cdafcb4 100644 --- a/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/gates/custom/UsbStateGate.kt +++ b/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/gates/custom/UsbStateGate.kt @@ -5,8 +5,8 @@ import androidx.lifecycle.Lifecycle import androidx.lifecycle.lifecycleScope import com.kieronquinn.app.taptap.components.columbus.gates.TapTapGate import com.kieronquinn.app.taptap.utils.extensions.broadcastReceiverAsFlow +import com.kieronquinn.app.taptap.utils.extensions.whenCreated import kotlinx.coroutines.flow.SharingStarted -import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn @@ -25,7 +25,7 @@ class UsbStateGate( }.stateIn(lifecycleScope, SharingStarted.Eagerly, false) init { - lifecycleScope.launchWhenCreated { + lifecycle.whenCreated { usbState.collect { notifyListeners() } diff --git a/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/sensors/TapTapCHREGestureSensor.kt b/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/sensors/TapTapCHREGestureSensor.kt index e32f87b0..b303ab25 100644 --- a/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/sensors/TapTapCHREGestureSensor.kt +++ b/app/src/main/java/com/kieronquinn/app/taptap/components/columbus/sensors/TapTapCHREGestureSensor.kt @@ -13,7 +13,6 @@ import android.os.RemoteException import android.os.SystemClock import android.util.Log import androidx.lifecycle.LifecycleOwner -import androidx.lifecycle.lifecycleScope import com.google.android.columbus.proto.nano.ColumbusGesture import com.google.android.columbus.sensors.CHREGestureSensor import com.google.android.columbus.sensors.configuration.GestureConfiguration @@ -21,8 +20,10 @@ import com.kieronquinn.app.taptap.contexthub.IRemoteContextHubClient import com.kieronquinn.app.taptap.repositories.service.TapTapShizukuServiceRepository import com.kieronquinn.app.taptap.repositories.service.TapTapShizukuServiceRepository.ShizukuServiceResponse import com.kieronquinn.app.taptap.utils.contexthub.ContextHubClientCallbackLocalToRemoteWrapper +import com.kieronquinn.app.taptap.utils.extensions.registerReceiverCompat import com.kieronquinn.app.taptap.utils.extensions.runOnDestroy import com.kieronquinn.app.taptap.utils.extensions.unregisterReceiverIfRegistered +import com.kieronquinn.app.taptap.utils.extensions.whenCreated import com.kieronquinn.app.taptap.utils.flow.FlowQueue import com.kieronquinn.app.taptap.utils.logging.UiEventLogger import com.kieronquinn.app.taptap.utils.statusbar.StatusBarStateController @@ -127,7 +128,7 @@ class TapTapCHREGestureSensor( onFail: (() -> Unit)?, onSuccess: (() -> Unit)? ) { - lifecycleOwner.lifecycleScope.launchWhenCreated { + lifecycleOwner.lifecycle.whenCreated { messageBuffer.add(NanoMessage(messageType, bytes, onFail, onSuccess)) } } @@ -232,8 +233,8 @@ class TapTapCHREGestureSensor( } override fun startListening(heuristicMode: Boolean) { - context.registerReceiver(screenStateReceiver, IntentFilter(Intent.ACTION_SCREEN_ON)) - context.registerReceiver(screenStateReceiver, IntentFilter(Intent.ACTION_SCREEN_OFF)) + context.registerReceiverCompat(screenStateReceiver, IntentFilter(Intent.ACTION_SCREEN_ON)) + context.registerReceiverCompat(screenStateReceiver, IntentFilter(Intent.ACTION_SCREEN_OFF)) super.startListening(heuristicMode) } @@ -256,7 +257,7 @@ class TapTapCHREGestureSensor( lifecycleOwner.lifecycle.runOnDestroy { stopListening() } - lifecycleOwner.lifecycleScope.launchWhenCreated { + lifecycleOwner.lifecycle.whenCreated { messageBuffer.asFlow().debounce(250L).collect { processNanoMessages(messageBuffer.asQueue()) } diff --git a/app/src/main/java/com/kieronquinn/app/taptap/service/accessibility/TapTapAccessibilityService.kt b/app/src/main/java/com/kieronquinn/app/taptap/service/accessibility/TapTapAccessibilityService.kt index 63c19fd4..75016014 100644 --- a/app/src/main/java/com/kieronquinn/app/taptap/service/accessibility/TapTapAccessibilityService.kt +++ b/app/src/main/java/com/kieronquinn/app/taptap/service/accessibility/TapTapAccessibilityService.kt @@ -1,8 +1,8 @@ package com.kieronquinn.app.taptap.service.accessibility import android.view.accessibility.AccessibilityEvent -import androidx.lifecycle.lifecycleScope import com.kieronquinn.app.taptap.components.accessibility.TapTapAccessibilityRouter +import com.kieronquinn.app.taptap.utils.extensions.whenCreated import com.kieronquinn.app.taptap.utils.lifecycle.LifecycleAccessibilityService import kotlinx.coroutines.flow.filterNot import org.koin.android.ext.android.inject @@ -49,10 +49,10 @@ class TapTapAccessibilityService: LifecycleAccessibilityService() { override fun onCreate() { super.onCreate() - lifecycleScope.launchWhenCreated { + lifecycle.whenCreated { setupInputListener() } - lifecycleScope.launchWhenCreated { + lifecycle.whenCreated { router.onAccessibilityStarted() } } @@ -85,7 +85,7 @@ class TapTapAccessibilityService: LifecycleAccessibilityService() { currentPackageName = event.packageName?.toString() ?: "android" } } - lifecycleScope.launchWhenCreated { + lifecycle.whenCreated { if(this@TapTapAccessibilityService.currentPackageName != currentPackageName){ this@TapTapAccessibilityService.currentPackageName = currentPackageName router.postOutput(TapTapAccessibilityRouter.AccessibilityOutput.AppOpen(currentPackageName)) diff --git a/app/src/main/java/com/kieronquinn/app/taptap/service/accessibility/TapTapGestureAccessibilityService.kt b/app/src/main/java/com/kieronquinn/app/taptap/service/accessibility/TapTapGestureAccessibilityService.kt index 38eab46a..9ce3b9e8 100644 --- a/app/src/main/java/com/kieronquinn/app/taptap/service/accessibility/TapTapGestureAccessibilityService.kt +++ b/app/src/main/java/com/kieronquinn/app/taptap/service/accessibility/TapTapGestureAccessibilityService.kt @@ -2,14 +2,12 @@ package com.kieronquinn.app.taptap.service.accessibility import android.accessibilityservice.GestureDescription import android.graphics.Path -import android.util.Log import android.view.accessibility.AccessibilityEvent -import androidx.lifecycle.lifecycleScope import com.kieronquinn.app.taptap.components.accessibility.TapTapAccessibilityRouter import com.kieronquinn.app.taptap.utils.extensions.getStaticStatusBarHeight import com.kieronquinn.app.taptap.utils.extensions.px +import com.kieronquinn.app.taptap.utils.extensions.whenCreated import com.kieronquinn.app.taptap.utils.lifecycle.LifecycleAccessibilityService -import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.filter import org.koin.android.ext.android.inject @@ -83,7 +81,7 @@ class TapTapGestureAccessibilityService : LifecycleAccessibilityService() { override fun onCreate() { super.onCreate() - lifecycleScope.launchWhenCreated { + lifecycle.whenCreated { setupInputListener() } } diff --git a/app/src/main/java/com/kieronquinn/app/taptap/service/foreground/TapTapForegroundService.kt b/app/src/main/java/com/kieronquinn/app/taptap/service/foreground/TapTapForegroundService.kt index faf2196d..f55322d9 100644 --- a/app/src/main/java/com/kieronquinn/app/taptap/service/foreground/TapTapForegroundService.kt +++ b/app/src/main/java/com/kieronquinn/app/taptap/service/foreground/TapTapForegroundService.kt @@ -9,7 +9,6 @@ import android.os.Build import android.provider.Settings import androidx.core.app.NotificationCompat import androidx.lifecycle.LifecycleService -import androidx.lifecycle.lifecycleScope import com.google.android.columbus.ColumbusServiceWrapper import com.kieronquinn.app.taptap.BuildConfig import com.kieronquinn.app.taptap.R @@ -27,6 +26,8 @@ import com.kieronquinn.app.taptap.repositories.service.TapTapShizukuServiceRepos import com.kieronquinn.app.taptap.utils.extensions.canUseContextHub import com.kieronquinn.app.taptap.utils.extensions.isNativeColumbusEnabled import com.kieronquinn.app.taptap.utils.extensions.isServiceRunning +import com.kieronquinn.app.taptap.utils.extensions.startForegroundCompat +import com.kieronquinn.app.taptap.utils.extensions.whenCreated import com.kieronquinn.app.taptap.utils.notifications.TapTapNotificationChannel import com.kieronquinn.app.taptap.utils.notifications.TapTapNotificationId import com.kieronquinn.app.taptap.utils.notifications.TapTapNotificationIntentId @@ -59,11 +60,7 @@ class TapTapForegroundService : LifecycleService(), KoinScopeComponent { fun start(context: Context, isRestart: Boolean = false) { val intent = getIntent(context, isRestart) context.stopService(intent) - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - context.startForegroundService(intent) - } else { - context.startService(intent) - } + context.startService(intent) } fun stop(context: Context) { @@ -93,11 +90,11 @@ class TapTapForegroundService : LifecycleService(), KoinScopeComponent { override fun onCreate() { super.onCreate() - startForeground(TapTapNotificationId.BACKGROUND.ordinal, createForegroundNotification()) + startForegroundCompat(TapTapNotificationId.BACKGROUND.ordinal, createForegroundNotification()) } override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { - lifecycleScope.launchWhenCreated { + lifecycle.whenCreated { listenForStartOrFail(intent?.getBooleanExtra(KEY_IS_RESTART, false) ?: false) startService() } @@ -162,7 +159,7 @@ class TapTapForegroundService : LifecycleService(), KoinScopeComponent { serviceRouter.onServiceStarted() } - private fun listenForStartOrFail(isRestart: Boolean) = lifecycleScope.launchWhenCreated { + private fun listenForStartOrFail(isRestart: Boolean) = lifecycle.whenCreated { showStartingNotification(isRestart) serviceEventEmitter.serviceEvent.take(1).collect { sendUpdateBroadcast() diff --git a/app/src/main/java/com/kieronquinn/app/taptap/service/quicksetting/TapTapQuickSettingTile.kt b/app/src/main/java/com/kieronquinn/app/taptap/service/quicksetting/TapTapQuickSettingTile.kt index 982b5311..570754bd 100644 --- a/app/src/main/java/com/kieronquinn/app/taptap/service/quicksetting/TapTapQuickSettingTile.kt +++ b/app/src/main/java/com/kieronquinn/app/taptap/service/quicksetting/TapTapQuickSettingTile.kt @@ -10,8 +10,12 @@ import com.kieronquinn.app.taptap.components.service.TapTapServiceRouter import com.kieronquinn.app.taptap.components.settings.TapTapSettings import com.kieronquinn.app.taptap.components.settings.invert import com.kieronquinn.app.taptap.service.foreground.TapTapForegroundService +import com.kieronquinn.app.taptap.utils.extensions.whenCreated import com.kieronquinn.app.taptap.utils.lifecycle.LifecycleTileService -import kotlinx.coroutines.flow.* +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.stateIn import org.koin.android.ext.android.inject class TapTapQuickSettingTile: LifecycleTileService() { @@ -51,7 +55,7 @@ class TapTapQuickSettingTile: LifecycleTileService() { } private fun setupState(){ - lifecycleScope.launchWhenCreated { + lifecycle.whenCreated { state.collect { handleState(it ?: return@collect) } @@ -73,13 +77,13 @@ class TapTapQuickSettingTile: LifecycleTileService() { triggerUpdate() } - private fun triggerUpdate() = lifecycleScope.launchWhenCreated { + private fun triggerUpdate() = lifecycle.whenCreated { reload.emit(Unit) } override fun onClick() { super.onClick() - lifecycleScope.launchWhenCreated { + lifecycle.whenCreated { settings.serviceEnabled.invert() TapTapForegroundService.stop(applicationContext) if(settings.serviceEnabled.get()){ diff --git a/app/src/main/java/com/kieronquinn/app/taptap/ui/activities/FlashlightToggleActivity.kt b/app/src/main/java/com/kieronquinn/app/taptap/ui/activities/FlashlightToggleActivity.kt index 748be46e..554d11fe 100644 --- a/app/src/main/java/com/kieronquinn/app/taptap/ui/activities/FlashlightToggleActivity.kt +++ b/app/src/main/java/com/kieronquinn/app/taptap/ui/activities/FlashlightToggleActivity.kt @@ -18,14 +18,13 @@ import android.view.WindowManager import androidx.appcompat.app.AppCompatActivity import androidx.core.app.NotificationCompat import androidx.core.content.ContextCompat -import androidx.lifecycle.lifecycleScope import com.kieronquinn.app.taptap.R +import com.kieronquinn.app.taptap.utils.extensions.whenCreated import com.kieronquinn.app.taptap.utils.notifications.TapTapNotificationChannel import com.kieronquinn.app.taptap.utils.notifications.TapTapNotificationId import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.delay import kotlinx.coroutines.flow.callbackFlow -import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.take /** @@ -70,7 +69,7 @@ class FlashlightToggleActivity: AppCompatActivity() { } private fun toggleFlashlight(){ - lifecycleScope.launchWhenCreated { + lifecycle.whenCreated { torchCallback.take(1).collect { try { val cameraId = cameraManager.cameraIdList[0] diff --git a/app/src/main/java/com/kieronquinn/app/taptap/ui/activities/MainActivity.kt b/app/src/main/java/com/kieronquinn/app/taptap/ui/activities/MainActivity.kt index 155c22b7..e361b1b7 100644 --- a/app/src/main/java/com/kieronquinn/app/taptap/ui/activities/MainActivity.kt +++ b/app/src/main/java/com/kieronquinn/app/taptap/ui/activities/MainActivity.kt @@ -6,11 +6,11 @@ import android.os.Bundle import android.view.View import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen import androidx.core.view.WindowCompat -import androidx.lifecycle.lifecycleScope import com.kieronquinn.app.taptap.R import com.kieronquinn.app.taptap.ui.screens.root.RootSharedViewModel import com.kieronquinn.app.taptap.utils.extensions.EXTRA_KEY_IS_FROM_COLUMBUS import com.kieronquinn.app.taptap.utils.extensions.delayPreDrawUntilFlow +import com.kieronquinn.app.taptap.utils.extensions.whenCreated import com.kieronquinn.app.taptap.work.TapTapUpdateCheckWorker import com.kieronquinn.monetcompat.app.MonetCompatActivity import org.koin.androidx.viewmodel.ext.android.viewModel @@ -33,7 +33,7 @@ class MainActivity: MonetCompatActivity() { //TODO move when android.core:splashscreen supports animations findViewById(android.R.id.content).delayPreDrawUntilFlow(rootViewModel.appReady, lifecycle) } - lifecycleScope.launchWhenCreated { + lifecycle.whenCreated { monet.awaitMonetReady() setContentView(R.layout.activity_main) } diff --git a/app/src/main/java/com/kieronquinn/app/taptap/ui/base/BaseBottomSheetFragment.kt b/app/src/main/java/com/kieronquinn/app/taptap/ui/base/BaseBottomSheetFragment.kt index 077285fe..c398f793 100644 --- a/app/src/main/java/com/kieronquinn/app/taptap/ui/base/BaseBottomSheetFragment.kt +++ b/app/src/main/java/com/kieronquinn/app/taptap/ui/base/BaseBottomSheetFragment.kt @@ -5,13 +5,17 @@ import android.app.Dialog import android.content.res.ColorStateList import android.graphics.Color import android.os.Bundle -import android.util.Log import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.core.animation.addListener -import androidx.core.view.* -import androidx.lifecycle.lifecycleScope +import androidx.core.view.ViewCompat +import androidx.core.view.WindowCompat +import androidx.core.view.WindowInsetsCompat +import androidx.core.view.marginTop +import androidx.core.view.updateLayoutParams +import androidx.core.view.updateMargins +import androidx.core.view.updatePadding import androidx.viewbinding.ViewBinding import com.google.android.material.bottomsheet.BottomSheetBehavior import com.google.android.material.bottomsheet.BottomSheetDialog @@ -20,6 +24,7 @@ import com.kieronquinn.app.taptap.R import com.kieronquinn.app.taptap.components.blur.BlurProvider import com.kieronquinn.app.taptap.utils.extensions.awaitPost import com.kieronquinn.app.taptap.utils.extensions.isDarkMode +import com.kieronquinn.app.taptap.utils.extensions.whenResumed import com.kieronquinn.monetcompat.core.MonetCompat import org.koin.android.ext.android.inject @@ -137,7 +142,7 @@ abstract class BaseBottomSheetFragment(private val inflate: (Lay private fun applyBlur(ratio: Float){ val dialogWindow = dialog?.window ?: return val appWindow = activity?.window ?: return - lifecycleScope.launchWhenResumed { + whenResumed { dialogWindow.decorView.awaitPost() blurProvider.applyDialogBlur(dialogWindow, appWindow, ratio) } @@ -146,7 +151,7 @@ abstract class BaseBottomSheetFragment(private val inflate: (Lay override fun onResume() { super.onResume() if(isBlurShowing){ - lifecycleScope.launchWhenResumed { + whenResumed { view?.awaitPost() applyBlur(1f) } diff --git a/app/src/main/java/com/kieronquinn/app/taptap/ui/base/BoundActivity.kt b/app/src/main/java/com/kieronquinn/app/taptap/ui/base/BoundActivity.kt index 5c4fd6a0..55b22348 100644 --- a/app/src/main/java/com/kieronquinn/app/taptap/ui/base/BoundActivity.kt +++ b/app/src/main/java/com/kieronquinn/app/taptap/ui/base/BoundActivity.kt @@ -3,8 +3,8 @@ package com.kieronquinn.app.taptap.ui.base import android.os.Bundle import android.view.LayoutInflater import android.view.ViewGroup -import androidx.lifecycle.lifecycleScope import androidx.viewbinding.ViewBinding +import com.kieronquinn.app.taptap.utils.extensions.whenCreated import com.kieronquinn.monetcompat.app.MonetCompatActivity abstract class BoundActivity(private val inflate: (LayoutInflater, ViewGroup?, Boolean) -> T): MonetCompatActivity() { @@ -15,7 +15,7 @@ abstract class BoundActivity(private val inflate: (LayoutInflate override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - lifecycleScope.launchWhenCreated { + lifecycle.whenCreated { monet.awaitMonetReady() _binding = inflate(layoutInflater, null, false).apply { setContentView(root) diff --git a/app/src/main/java/com/kieronquinn/app/taptap/ui/base/BoundFragment.kt b/app/src/main/java/com/kieronquinn/app/taptap/ui/base/BoundFragment.kt index 85fda719..e49738be 100644 --- a/app/src/main/java/com/kieronquinn/app/taptap/ui/base/BoundFragment.kt +++ b/app/src/main/java/com/kieronquinn/app/taptap/ui/base/BoundFragment.kt @@ -4,6 +4,7 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import androidx.core.view.WindowInsetsCompat import androidx.viewbinding.ViewBinding import com.kieronquinn.app.taptap.utils.TransitionUtils import com.kieronquinn.monetcompat.app.MonetFragment diff --git a/app/src/main/java/com/kieronquinn/app/taptap/ui/screens/container/ContainerFragment.kt b/app/src/main/java/com/kieronquinn/app/taptap/ui/screens/container/ContainerFragment.kt index d2655bd0..d9209a44 100644 --- a/app/src/main/java/com/kieronquinn/app/taptap/ui/screens/container/ContainerFragment.kt +++ b/app/src/main/java/com/kieronquinn/app/taptap/ui/screens/container/ContainerFragment.kt @@ -1,12 +1,13 @@ package com.kieronquinn.app.taptap.ui.screens.container +import android.annotation.SuppressLint import android.content.res.ColorStateList import android.graphics.Color import android.graphics.drawable.GradientDrawable import android.os.Bundle import android.view.MenuInflater import android.view.View -import androidx.activity.addCallback +import androidx.activity.OnBackPressedCallback import androidx.core.content.ContextCompat import androidx.core.content.res.ResourcesCompat import androidx.core.graphics.ColorUtils @@ -20,10 +21,31 @@ import com.kieronquinn.app.taptap.R import com.kieronquinn.app.taptap.components.navigation.ContainerNavigation import com.kieronquinn.app.taptap.components.navigation.setupWithNavigation import com.kieronquinn.app.taptap.databinding.FragmentContainerBinding -import com.kieronquinn.app.taptap.ui.base.* +import com.kieronquinn.app.taptap.ui.base.BackAvailable +import com.kieronquinn.app.taptap.ui.base.BoundFragment +import com.kieronquinn.app.taptap.ui.base.CanShowSnackbar +import com.kieronquinn.app.taptap.ui.base.LockCollapsed +import com.kieronquinn.app.taptap.ui.base.ProvidesBack +import com.kieronquinn.app.taptap.ui.base.ProvidesOverflow +import com.kieronquinn.app.taptap.ui.base.ProvidesTitle import com.kieronquinn.app.taptap.ui.screens.container.ContainerSharedViewModel.FabState.Hidden import com.kieronquinn.app.taptap.ui.screens.container.ContainerSharedViewModel.FabState.Shown -import com.kieronquinn.app.taptap.utils.extensions.* +import com.kieronquinn.app.taptap.utils.extensions.awaitPost +import com.kieronquinn.app.taptap.utils.extensions.collapsedState +import com.kieronquinn.app.taptap.utils.extensions.getRememberedAppBarCollapsed +import com.kieronquinn.app.taptap.utils.extensions.getTopFragment +import com.kieronquinn.app.taptap.utils.extensions.isDarkMode +import com.kieronquinn.app.taptap.utils.extensions.isLandscape +import com.kieronquinn.app.taptap.utils.extensions.isRtl +import com.kieronquinn.app.taptap.utils.extensions.onApplyInsets +import com.kieronquinn.app.taptap.utils.extensions.onDestinationChanged +import com.kieronquinn.app.taptap.utils.extensions.onItemClicked +import com.kieronquinn.app.taptap.utils.extensions.onNavigationIconClicked +import com.kieronquinn.app.taptap.utils.extensions.onSwipeDismissed +import com.kieronquinn.app.taptap.utils.extensions.rememberAppBarCollapsed +import com.kieronquinn.app.taptap.utils.extensions.setOnBackPressedCallback +import com.kieronquinn.app.taptap.utils.extensions.setTypeface +import com.kieronquinn.app.taptap.utils.extensions.whenResumed import com.kieronquinn.monetcompat.extensions.applyMonet import com.kieronquinn.monetcompat.extensions.toArgb import com.kieronquinn.monetcompat.extensions.views.setTint @@ -37,6 +59,23 @@ import org.koin.androidx.viewmodel.ext.android.viewModel class ContainerFragment: BoundFragment(FragmentContainerBinding::inflate) { + companion object { + private val SYSTEM_INSETS = setOf( + WindowInsetsCompat.Type.systemBars(), + WindowInsetsCompat.Type.ime(), + WindowInsetsCompat.Type.statusBars(), + WindowInsetsCompat.Type.displayCutout() + ).or() + + private fun Collection.or(): Int { + var current = 0 + forEach { + current = current.or(it) + } + return current + } + } + private val googleSansMedium by lazy { ResourcesCompat.getFont(requireContext(), R.font.google_sans_text_medium) } @@ -87,14 +126,33 @@ class ContainerFragment: BoundFragment(FragmentContain setupSnackbar() setupUpdateSnackbar() setupColumbusSettingPhoenix() + setupInsets() viewModel.writeSettingsVersion() } + private fun setupInsets() = with(binding.root) { + val padding = resources.getDimensionPixelSize(R.dimen.margin_16) + onApplyInsets { _, insets -> + val inset = insets.getInsets(SYSTEM_INSETS) + binding.fragmentContainerContainer.updatePadding( + left = inset.left, right = inset.right + ) + binding.toolbar.updatePadding( + left = inset.left, right = inset.right + ) + if(isRtl()) { + binding.collapsingToolbar.expandedTitleMarginEnd = inset.right + padding + }else { + binding.collapsingToolbar.expandedTitleMarginStart = inset.left + padding + } + } + } + private fun setupMonet() { binding.root.setBackgroundColor(monet.getBackgroundColor(requireContext())) } - private fun setupColumbusSettingPhoenix() = viewLifecycleOwner.lifecycleScope.launchWhenResumed { + private fun setupColumbusSettingPhoenix() = whenResumed { sharedViewModel.columbusSettingPhoenixBus.collect { viewModel.phoenix() } @@ -120,7 +178,7 @@ class ContainerFragment: BoundFragment(FragmentContain arrayOf(intArrayOf(android.R.attr.state_selected), intArrayOf()), intArrayOf(indicatorColor ?: Color.TRANSPARENT, Color.TRANSPARENT) ) - viewLifecycleOwner.lifecycleScope.launchWhenResumed { + whenResumed { //The onItemClicked flow can only be attached once due to its callbacks, so we share it to split the logic val flows = onItemClicked().shareIn(lifecycleScope, SharingStarted.Eagerly) launch { @@ -144,7 +202,7 @@ class ContainerFragment: BoundFragment(FragmentContain } private fun setupToolbar() = with(binding.toolbar) { - viewLifecycleOwner.lifecycleScope.launchWhenResumed { + whenResumed { onNavigationIconClicked().collect { (navHostFragment.getTopFragment() as? ProvidesBack)?.let { if(it.onBackPressed()) return@collect @@ -154,30 +212,33 @@ class ContainerFragment: BoundFragment(FragmentContain } } + @SuppressLint("RestrictedApi") private fun setupBack() { - val callback = requireActivity().onBackPressedDispatcher.addCallback( - this, - shouldBackDispatcherBeEnabled() - ) { - (navHostFragment.getTopFragment() as? ProvidesBack)?.let { - if(it.onBackPressed()) return@addCallback - } - if(!navController.popBackStack()) { - requireActivity().finish() + val callback = object: OnBackPressedCallback(true) { + override fun handleOnBackPressed() { + (navHostFragment.getTopFragment() as? ProvidesBack)?.let { + if(it.onBackPressed()) return + } + if(!navController.popBackStack()) { + requireActivity().finish() + } } } - viewLifecycleOwner.lifecycleScope.launchWhenResumed { + navController.setOnBackPressedCallback(callback) + navController.enableOnBackPressed(shouldBackDispatcherBeEnabled()) + navController.setOnBackPressedDispatcher(requireActivity().onBackPressedDispatcher) + whenResumed { navController.onDestinationChanged().collect { - callback.isEnabled = shouldBackDispatcherBeEnabled() + navController.enableOnBackPressed(shouldBackDispatcherBeEnabled()) } } } private fun shouldBackDispatcherBeEnabled(): Boolean { - return navHostFragment.getTopFragment() is ProvidesBack || navController.hasBackAvailable() + return navHostFragment.getTopFragment() is ProvidesBack } - private fun setupNavigation() = viewLifecycleOwner.lifecycleScope.launchWhenResumed { + private fun setupNavigation() = whenResumed { launch { navHostFragment.setupWithNavigation(navigation) } @@ -191,14 +252,14 @@ class ContainerFragment: BoundFragment(FragmentContain } } - private fun setupStack() = viewLifecycleOwner.lifecycleScope.launchWhenResumed { + private fun setupStack() = whenResumed { navController.onDestinationChanged().collect { binding.root.awaitPost() onTopFragmentChanged(navHostFragment.getTopFragment() ?: return@collect) } } - private fun setupCollapsedState() = viewLifecycleOwner.lifecycleScope.launchWhenResumed { + private fun setupCollapsedState() = whenResumed { binding.appBar.collapsedState().collect { navHostFragment.getTopFragment()?.rememberAppBarCollapsed(it) } @@ -213,7 +274,7 @@ class ContainerFragment: BoundFragment(FragmentContain }else{ setupMenu(null) } - if(topFragment is LockCollapsed) { + if(topFragment is LockCollapsed || requireContext().isLandscape()) { binding.appBar.setExpanded(false) }else { binding.appBar.setExpanded(!topFragment.getRememberedAppBarCollapsed()) @@ -244,7 +305,7 @@ class ContainerFragment: BoundFragment(FragmentContain view.updatePadding(bottom = insets.getInsets(WindowInsetsCompat.Type.systemBars()).bottom) } handleFabState(sharedViewModel.fabState.value) - viewLifecycleOwner.lifecycleScope.launchWhenResumed { + whenResumed { sharedViewModel.fabState.collect { handleFabState(it) } @@ -270,7 +331,7 @@ class ContainerFragment: BoundFragment(FragmentContain } } - private fun setupSnackbar() = viewLifecycleOwner.lifecycleScope.launchWhenResumed { + private fun setupSnackbar() = whenResumed { sharedViewModel.snackbarBus.collect { Snackbar.make(binding.root, it, Snackbar.LENGTH_LONG).apply { applyMonet() @@ -284,7 +345,7 @@ class ContainerFragment: BoundFragment(FragmentContain private fun setupUpdateSnackbar() { handleUpdateSnackbar(viewModel.showUpdateSnackbar.value) - viewLifecycleOwner.lifecycleScope.launchWhenResumed { + whenResumed { viewModel.showUpdateSnackbar.collect { handleUpdateSnackbar(it) } diff --git a/app/src/main/java/com/kieronquinn/app/taptap/ui/screens/decision/DecisionFragment.kt b/app/src/main/java/com/kieronquinn/app/taptap/ui/screens/decision/DecisionFragment.kt index ea37f657..ead2b48b 100644 --- a/app/src/main/java/com/kieronquinn/app/taptap/ui/screens/decision/DecisionFragment.kt +++ b/app/src/main/java/com/kieronquinn/app/taptap/ui/screens/decision/DecisionFragment.kt @@ -5,8 +5,8 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.fragment.app.Fragment -import androidx.lifecycle.lifecycleScope import com.kieronquinn.app.taptap.ui.screens.root.RootSharedViewModel +import com.kieronquinn.app.taptap.utils.extensions.whenResumed import org.koin.androidx.viewmodel.ext.android.sharedViewModel import org.koin.androidx.viewmodel.ext.android.viewModel @@ -24,7 +24,7 @@ class DecisionFragment: Fragment() { return View(context) } - private fun setupDecision() = viewLifecycleOwner.lifecycleScope.launchWhenResumed { + private fun setupDecision() = whenResumed { decisionViewModel.decisionMade.collect { rootSharedViewModel.postDecisionMade() } diff --git a/app/src/main/java/com/kieronquinn/app/taptap/ui/screens/disablecolumbus/DisableColumbusFragment.kt b/app/src/main/java/com/kieronquinn/app/taptap/ui/screens/disablecolumbus/DisableColumbusFragment.kt index 7309564d..cc0cd349 100644 --- a/app/src/main/java/com/kieronquinn/app/taptap/ui/screens/disablecolumbus/DisableColumbusFragment.kt +++ b/app/src/main/java/com/kieronquinn/app/taptap/ui/screens/disablecolumbus/DisableColumbusFragment.kt @@ -4,12 +4,12 @@ import android.os.Bundle import android.text.Html import android.text.util.Linkify import android.view.View -import androidx.lifecycle.lifecycleScope import com.kieronquinn.app.taptap.R import com.kieronquinn.app.taptap.databinding.FragmentDisableColumbusBinding import com.kieronquinn.app.taptap.ui.base.BoundFragment import com.kieronquinn.app.taptap.utils.extensions.applyBackgroundTint import com.kieronquinn.app.taptap.utils.extensions.onClicked +import com.kieronquinn.app.taptap.utils.extensions.whenResumed import me.saket.bettermovementmethod.BetterLinkMovementMethod import org.koin.androidx.viewmodel.ext.android.viewModel @@ -31,13 +31,13 @@ class DisableColumbusFragment: BoundFragment(Fra binding.disableColumbusCard.applyBackgroundTint(monet) } - private fun setupOpenSettings() = viewLifecycleOwner.lifecycleScope.launchWhenResumed { + private fun setupOpenSettings() = whenResumed { binding.disableColumbusOpenSettings.onClicked().collect { viewModel.onOpenSettingsClicked() } } - private fun setupPhoenix() = viewLifecycleOwner.lifecycleScope.launchWhenResumed { + private fun setupPhoenix() = whenResumed { viewModel.phoenixBus.collect { viewModel.phoenix() } diff --git a/app/src/main/java/com/kieronquinn/app/taptap/ui/screens/reachability/ReachabilityFragment.kt b/app/src/main/java/com/kieronquinn/app/taptap/ui/screens/reachability/ReachabilityFragment.kt index 1a0c3404..b77e407e 100644 --- a/app/src/main/java/com/kieronquinn/app/taptap/ui/screens/reachability/ReachabilityFragment.kt +++ b/app/src/main/java/com/kieronquinn/app/taptap/ui/screens/reachability/ReachabilityFragment.kt @@ -6,13 +6,12 @@ import android.os.Bundle import android.view.Gravity import android.view.View import android.widget.Toast -import androidx.lifecycle.lifecycleScope import com.kieronquinn.app.taptap.R import com.kieronquinn.app.taptap.databinding.FragmentReachabilityBinding import com.kieronquinn.app.taptap.ui.base.BoundFragment import com.kieronquinn.app.taptap.utils.extensions.onClicked import com.kieronquinn.app.taptap.utils.extensions.onLongClicked -import kotlinx.coroutines.flow.collect +import com.kieronquinn.app.taptap.utils.extensions.whenResumed import org.koin.androidx.viewmodel.ext.android.viewModel class ReachabilityFragment: BoundFragment(FragmentReachabilityBinding::inflate) { @@ -39,7 +38,7 @@ class ReachabilityFragment: BoundFragment(FragmentR setupNotificationsClick() setupQuickSettingsClick() setupNotificationsLongClick() - viewLifecycleOwner.lifecycleScope.launchWhenResumed { + whenResumed { if(!viewModel.getHasLeftHandedSet()){ Toast.makeText(requireContext(), R.string.reachability_left_handed_info, Toast.LENGTH_LONG).show() } @@ -52,7 +51,7 @@ class ReachabilityFragment: BoundFragment(FragmentR binding.reachabilityQuickSettings.iconTint = accent } - private fun setupHandedness() = viewLifecycleOwner.lifecycleScope.launchWhenResumed { + private fun setupHandedness() = whenResumed { viewModel.isLeftHanded.collect { if(it) { binding.reachabilityContainer.gravity = Gravity.BOTTOM or Gravity.START @@ -62,26 +61,26 @@ class ReachabilityFragment: BoundFragment(FragmentR } } - private fun setupNotificationsClick() = viewLifecycleOwner.lifecycleScope.launchWhenResumed { + private fun setupNotificationsClick() = whenResumed { binding.reachabilityNotifications.onClicked().collect { viewModel.onNotificationsClicked() } } - private fun setupQuickSettingsClick() = viewLifecycleOwner.lifecycleScope.launchWhenResumed { + private fun setupQuickSettingsClick() = whenResumed { binding.reachabilityQuickSettings.onClicked().collect { viewModel.onQuickSettingsClicked() } } - private fun setupNotificationsLongClick() = viewLifecycleOwner.lifecycleScope.launchWhenResumed { + private fun setupNotificationsLongClick() = whenResumed { binding.reachabilityNotifications.onLongClicked().collect { viewModel.onNotificationsLongClicked() } } fun onWindowAttributesChanged(height: Int) { - lifecycleScope.launchWhenResumed { + whenResumed { if(height < minButtonHeight){ binding.reachabilityNotifications.visibility = View.GONE binding.reachabilityQuickSettings.visibility = View.GONE @@ -93,7 +92,7 @@ class ReachabilityFragment: BoundFragment(FragmentR } fun onExitMultiWindow(providedApp: String?) { - lifecycleScope.launchWhenResumed { + whenResumed { viewModel.getCurrentApp() ?: providedApp?.let { requireContext().packageManager.getLaunchIntentForPackage(it)?.run { startActivity(this) diff --git a/app/src/main/java/com/kieronquinn/app/taptap/ui/screens/root/RootFragment.kt b/app/src/main/java/com/kieronquinn/app/taptap/ui/screens/root/RootFragment.kt index d1269201..05509445 100644 --- a/app/src/main/java/com/kieronquinn/app/taptap/ui/screens/root/RootFragment.kt +++ b/app/src/main/java/com/kieronquinn/app/taptap/ui/screens/root/RootFragment.kt @@ -2,13 +2,13 @@ package com.kieronquinn.app.taptap.ui.screens.root import android.os.Bundle import android.view.View -import androidx.lifecycle.lifecycleScope import androidx.navigation.fragment.NavHostFragment import com.kieronquinn.app.taptap.R import com.kieronquinn.app.taptap.components.navigation.RootNavigation import com.kieronquinn.app.taptap.components.navigation.setupWithNavigation import com.kieronquinn.app.taptap.databinding.FragmentRootBinding import com.kieronquinn.app.taptap.ui.base.BoundFragment +import com.kieronquinn.app.taptap.utils.extensions.whenResumed import kotlinx.coroutines.launch import org.koin.android.ext.android.inject @@ -25,7 +25,7 @@ class RootFragment: BoundFragment(FragmentRootBinding::infl setupNavigation() } - private fun setupNavigation() = viewLifecycleOwner.lifecycleScope.launchWhenResumed { + private fun setupNavigation() = whenResumed { launch { navHostFragment.setupWithNavigation(navigation) } diff --git a/app/src/main/java/com/kieronquinn/app/taptap/ui/screens/settings/actions/SettingsActionsGenericAdapter.kt b/app/src/main/java/com/kieronquinn/app/taptap/ui/screens/settings/actions/SettingsActionsGenericAdapter.kt index 2d02883b..d3c428f8 100644 --- a/app/src/main/java/com/kieronquinn/app/taptap/ui/screens/settings/actions/SettingsActionsGenericAdapter.kt +++ b/app/src/main/java/com/kieronquinn/app/taptap/ui/screens/settings/actions/SettingsActionsGenericAdapter.kt @@ -8,7 +8,6 @@ import androidx.core.content.ContextCompat import androidx.core.content.res.ResourcesCompat import androidx.core.view.isVisible import androidx.lifecycle.Lifecycle -import androidx.lifecycle.coroutineScope import androidx.recyclerview.widget.RecyclerView import androidx.viewbinding.ViewBinding import com.kieronquinn.app.taptap.R @@ -19,9 +18,14 @@ import com.kieronquinn.app.taptap.models.action.TapTapUIAction import com.kieronquinn.app.taptap.ui.screens.settings.actions.SettingsActionsGenericViewModel.SettingsActionsItem import com.kieronquinn.app.taptap.ui.screens.settings.actions.SettingsActionsGenericViewModel.SettingsActionsItem.SettingsActionsItemType import com.kieronquinn.app.taptap.ui.views.LifecycleAwareRecyclerView -import com.kieronquinn.app.taptap.utils.extensions.* +import com.kieronquinn.app.taptap.utils.extensions.addRippleForeground +import com.kieronquinn.app.taptap.utils.extensions.applyBackgroundTint +import com.kieronquinn.app.taptap.utils.extensions.isDarkMode +import com.kieronquinn.app.taptap.utils.extensions.onClicked +import com.kieronquinn.app.taptap.utils.extensions.onLongClicked +import com.kieronquinn.app.taptap.utils.extensions.whenResumed import com.kieronquinn.monetcompat.core.MonetCompat -import java.util.* +import java.util.Collections class SettingsActionsGenericAdapter( recyclerView: RecyclerView, @@ -151,12 +155,12 @@ class SettingsActionsGenericAdapter( ContextCompat.getDrawable(context, R.drawable.ic_action_chip_when_empty) itemActionChipWhen.text = context.getString(R.string.item_action_when_empty) } - holder.lifecycle.coroutineScope.launchWhenResumed { + holder.lifecycle.whenResumed { itemSettingsActionsActionHandle.onLongClicked().collect { onHandleLongPressed(holder) } } - holder.lifecycle.coroutineScope.launchWhenResumed { + holder.lifecycle.whenResumed { root.onLongClicked().collect { val isSelected = item.isSelected clearSelection() @@ -165,7 +169,7 @@ class SettingsActionsGenericAdapter( notifyItemChanged(holder.adapterPosition) } } - holder.lifecycle.coroutineScope.launchWhenResumed { + holder.lifecycle.whenResumed { itemActionChipWhen.onClicked().collect { onWhenGateChipClicked(item.action) } @@ -178,13 +182,13 @@ class SettingsActionsGenericAdapter( itemSettingsActionsInfoContent.text = context.getText(item.contentRes) if(item.onClick != null){ root.addRippleForeground() - lifecycle.coroutineScope.launchWhenResumed { + lifecycle.whenResumed { root.onClicked().collect { item.onClick.invoke() } } } - lifecycle.coroutineScope.launchWhenResumed { + lifecycle.whenResumed { itemSettingsActionsInfoDismiss.onClicked().collect { item.onCloseClick.invoke() } diff --git a/app/src/main/java/com/kieronquinn/app/taptap/ui/screens/settings/actions/SettingsActionsGenericFragment.kt b/app/src/main/java/com/kieronquinn/app/taptap/ui/screens/settings/actions/SettingsActionsGenericFragment.kt index ec3cf210..0662035a 100644 --- a/app/src/main/java/com/kieronquinn/app/taptap/ui/screens/settings/actions/SettingsActionsGenericFragment.kt +++ b/app/src/main/java/com/kieronquinn/app/taptap/ui/screens/settings/actions/SettingsActionsGenericFragment.kt @@ -7,7 +7,6 @@ import android.view.ViewGroup import androidx.constraintlayout.widget.Group import androidx.core.view.isVisible import androidx.fragment.app.setFragmentResultListener -import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.ItemTouchHelper import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView @@ -26,8 +25,8 @@ import com.kieronquinn.app.taptap.ui.screens.settings.actions.whengates.Settings import com.kieronquinn.app.taptap.utils.extensions.applyBottomInsets import com.kieronquinn.app.taptap.utils.extensions.awaitState import com.kieronquinn.app.taptap.utils.extensions.scrollToBottom +import com.kieronquinn.app.taptap.utils.extensions.whenResumed import com.kieronquinn.monetcompat.extensions.views.applyMonet -import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.debounce import org.koin.androidx.viewmodel.ext.android.sharedViewModel @@ -77,7 +76,7 @@ abstract class SettingsActionsGenericFragment(inflate private fun setupState() { handleState(viewModel.state.value) - viewLifecycleOwner.lifecycleScope.launchWhenResumed { + whenResumed { viewModel.state.collect { handleState(it) } @@ -101,7 +100,7 @@ abstract class SettingsActionsGenericFragment(inflate } } - private fun setupFab() = viewLifecycleOwner.lifecycleScope.launchWhenResumed { + private fun setupFab() = whenResumed { sharedViewModel.fabClicked.collect { when (it) { ContainerSharedViewModel.FabState.FabAction.ADD_ACTION -> { @@ -123,7 +122,7 @@ abstract class SettingsActionsGenericFragment(inflate private fun setupFabState() { handleFabState(viewModel.fabState.value) - viewLifecycleOwner.lifecycleScope.launchWhenResumed { + whenResumed { viewModel.fabState.collect { handleFabState(it) } @@ -143,20 +142,20 @@ abstract class SettingsActionsGenericFragment(inflate } } - private fun setupScrollToBottom() = viewLifecycleOwner.lifecycleScope.launchWhenResumed { + private fun setupScrollToBottom() = whenResumed { viewModel.scrollToBottomBus.collect { viewModel.state.awaitState(SettingsActionsGenericViewModel.State.Loaded::class.java) getRecyclerView().scrollToBottom() } } - private fun setupReloadService() = viewLifecycleOwner.lifecycleScope.launchWhenResumed { + private fun setupReloadService() = whenResumed { viewModel.reloadServiceBus.debounce(1000L).collect { sharedViewModel.restartService(requireContext()) } } - private fun setupSwitchReloadService() = viewLifecycleOwner.lifecycleScope.launchWhenResumed { + private fun setupSwitchReloadService() = whenResumed { viewModel.switchChanged?.debounce(1000L)?.collect { sharedViewModel.restartService(requireContext()) } diff --git a/app/src/main/java/com/kieronquinn/app/taptap/ui/screens/settings/actions/help/SettingsActionsHelpBottomSheetFragment.kt b/app/src/main/java/com/kieronquinn/app/taptap/ui/screens/settings/actions/help/SettingsActionsHelpBottomSheetFragment.kt index 08504d3b..4601fb2d 100644 --- a/app/src/main/java/com/kieronquinn/app/taptap/ui/screens/settings/actions/help/SettingsActionsHelpBottomSheetFragment.kt +++ b/app/src/main/java/com/kieronquinn/app/taptap/ui/screens/settings/actions/help/SettingsActionsHelpBottomSheetFragment.kt @@ -4,13 +4,12 @@ import android.os.Bundle import android.view.View import androidx.core.view.WindowInsetsCompat import androidx.core.view.updatePadding -import androidx.lifecycle.lifecycleScope import com.kieronquinn.app.taptap.R import com.kieronquinn.app.taptap.databinding.FragmentSettingsActionsHelpBinding import com.kieronquinn.app.taptap.ui.base.BaseBottomSheetFragment import com.kieronquinn.app.taptap.utils.extensions.onApplyInsets import com.kieronquinn.app.taptap.utils.extensions.onClicked -import kotlinx.coroutines.flow.collect +import com.kieronquinn.app.taptap.utils.extensions.whenResumed class SettingsActionsHelpBottomSheetFragment: BaseBottomSheetFragment(FragmentSettingsActionsHelpBinding::inflate) { @@ -34,7 +33,7 @@ class SettingsActionsHelpBottomSheetFragment: BaseBottomSheetFragment(inflate: (Layo private val onResume = MutableSharedFlow() private val permissionResponse = MutableSharedFlow>() private val permissionResponseContract = registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { - viewLifecycleOwner.lifecycleScope.launchWhenResumed { + whenResumed { permissionResponse.emit(it) } } private val taskerResponseContract = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { - viewLifecycleOwner.lifecycleScope.launchWhenResumed { - val taskName = it.data?.dataString ?: return@launchWhenResumed //Drop if task not picked + whenResumed { + val taskName = it.data?.dataString ?: return@whenResumed //Drop if task not picked handleAction(TapTapActionDirectory.TASKER_TASK, taskName, isReturningData = true) } } @@ -79,7 +86,7 @@ abstract class SettingsActionsAddGenericFragment(inflate: (Layo accessibilityRouter.bringToFrontOnGestureAccessibilityStart(this) } - protected fun onActionClicked(action: TapTapActionDirectory) = viewLifecycleOwner.lifecycleScope.launchWhenResumed { + protected fun onActionClicked(action: TapTapActionDirectory) = whenResumed { handleAction(action) } @@ -283,7 +290,7 @@ abstract class SettingsActionsAddGenericFragment(inflate: (Layo return requireContext().doesHaveTaskerPermission() } - protected fun showSnackbarForChip(requirement: ActionRequirement.UserDisplayedActionRequirement) = viewLifecycleOwner.lifecycleScope.launchWhenResumed { + protected fun showSnackbarForChip(requirement: ActionRequirement.UserDisplayedActionRequirement) = whenResumed { sharedViewModel.showSnackbar(getText(requirement.desc)) } @@ -291,33 +298,33 @@ abstract class SettingsActionsAddGenericFragment(inflate: (Layo setFragmentResultListener(SettingsSharedAppShortcutsSelectorFragment.FRAGMENT_RESULT_KEY_APP_SHORTCUT) { key, bundle -> val selectedAppShortcut = bundle.getParcelable( SettingsSharedAppShortcutsSelectorFragment.FRAGMENT_RESULT_KEY_APP_SHORTCUT) ?: return@setFragmentResultListener - viewLifecycleOwner.lifecycleScope.launchWhenResumed { + whenResumed { handleAction(TapTapActionDirectory.LAUNCH_APP_SHORTCUT, gson.toJson(selectedAppShortcut), isReturningRequirement = true) } } setFragmentResultListener(SettingsSharedShortcutsSelectorFragment.FRAGMENT_RESULT_KEY_SHORTCUT) { key, bundle -> val serializedShortcut = bundle.getString(SettingsSharedShortcutsSelectorFragment.FRAGMENT_RESULT_KEY_SHORTCUT) ?: return@setFragmentResultListener - viewLifecycleOwner.lifecycleScope.launchWhenResumed { + whenResumed { handleAction(TapTapActionDirectory.LAUNCH_SHORTCUT, serializedShortcut, isReturningRequirement = true) } } setFragmentResultListener(SettingsSharedQuickSettingSelectorFragment.FRAGMENT_RESULT_KEY_QUICK_SETTING) { key, bundle -> val serializedTile = bundle.getParcelable(SettingsSharedQuickSettingSelectorFragment.FRAGMENT_RESULT_KEY_QUICK_SETTING) ?: return@setFragmentResultListener - viewLifecycleOwner.lifecycleScope.launchWhenResumed { + whenResumed { handleAction(TapTapActionDirectory.QUICK_SETTING, serializedTile.component.flattenToString(), isReturningRequirement = true) } } setFragmentResultListener(SettingsSharedPackageSelectorFragment.FRAGMENT_RESULT_KEY_PACKAGE) { key, bundle -> val action = bundle.getParcelable(ARG_NAME_SHARED_ARGUMENT)?.action ?: return@setFragmentResultListener val packageName = bundle.getString(SettingsSharedPackageSelectorFragment.FRAGMENT_RESULT_KEY_PACKAGE) ?: return@setFragmentResultListener - viewLifecycleOwner.lifecycleScope.launchWhenResumed { + whenResumed { handleAction(action, packageName, isReturningRequirement = true) } } setFragmentResultListener(SettingsSharedShizukuPermissionFlowFragment.FRAGMENT_RESULT_KEY_SHIZUKU_PERMISSION) { key, bundle -> val permissionGranted = bundle.getBoolean(SettingsSharedShizukuPermissionFlowFragment.FRAGMENT_RESULT_KEY_SHIZUKU_PERMISSION, false) val action = bundle.getParcelable(ARG_NAME_SHARED_ARGUMENT)?.action ?: return@setFragmentResultListener - viewLifecycleOwner.lifecycleScope.launchWhenResumed { + whenResumed { if(permissionGranted) { handleAction(action, isReturningRequirement = true) } //Drop if permission is denied @@ -326,7 +333,7 @@ abstract class SettingsActionsAddGenericFragment(inflate: (Layo setFragmentResultListener(SettingsSharedSnapchatFragment.FRAGMENT_RESULT_KEY_SNAPCHAT) { key, bundle -> val available = bundle.getBoolean(SettingsSharedSnapchatFragment.FRAGMENT_RESULT_KEY_SNAPCHAT, false) val action = bundle.getParcelable(ARG_NAME_SHARED_ARGUMENT)?.action ?: return@setFragmentResultListener - viewLifecycleOwner.lifecycleScope.launchWhenResumed { + whenResumed { if(available) { handleAction(action, isReturningRequirement = true) } //Drop if not available @@ -336,7 +343,7 @@ abstract class SettingsActionsAddGenericFragment(inflate: (Layo override fun onResume() { super.onResume() - viewLifecycleOwner.lifecycleScope.launchWhenResumed { + whenResumed { onResume.emit(Unit) } } diff --git a/app/src/main/java/com/kieronquinn/app/taptap/ui/screens/settings/actions/selector/actions/SettingsActionsActionSelectorAdapter.kt b/app/src/main/java/com/kieronquinn/app/taptap/ui/screens/settings/actions/selector/actions/SettingsActionsActionSelectorAdapter.kt index ae185453..5eb16ae0 100644 --- a/app/src/main/java/com/kieronquinn/app/taptap/ui/screens/settings/actions/selector/actions/SettingsActionsActionSelectorAdapter.kt +++ b/app/src/main/java/com/kieronquinn/app/taptap/ui/screens/settings/actions/selector/actions/SettingsActionsActionSelectorAdapter.kt @@ -8,7 +8,6 @@ import androidx.core.content.ContextCompat import androidx.core.content.res.ResourcesCompat import androidx.core.view.isVisible import androidx.lifecycle.Lifecycle -import androidx.lifecycle.coroutineScope import androidx.recyclerview.widget.RecyclerView import com.kieronquinn.app.taptap.R import com.kieronquinn.app.taptap.databinding.ItemSettingsActionsActionSelectorItemBinding @@ -20,6 +19,7 @@ import com.kieronquinn.app.taptap.utils.extensions.addRippleForeground import com.kieronquinn.app.taptap.utils.extensions.applyBackgroundTint import com.kieronquinn.app.taptap.utils.extensions.onClicked import com.kieronquinn.app.taptap.utils.extensions.removeRippleForeground +import com.kieronquinn.app.taptap.utils.extensions.whenResumed import com.kieronquinn.monetcompat.core.MonetCompat class SettingsActionsActionSelectorAdapter( @@ -109,7 +109,7 @@ class SettingsActionsActionSelectorAdapter( chipIcon = ContextCompat.getDrawable(context, requirement.icon) } } - lifecycle.coroutineScope.launchWhenResumed { + lifecycle.whenResumed { itemSettingsActionSelectorChip.onClicked().collect { action.actionRequirement?.firstOrNull { it is ActionRequirement.UserDisplayedActionRequirement }?.let { requirement -> requirement as ActionRequirement.UserDisplayedActionRequirement diff --git a/app/src/main/java/com/kieronquinn/app/taptap/ui/screens/settings/actions/selector/actions/SettingsActionsActionSelectorFragment.kt b/app/src/main/java/com/kieronquinn/app/taptap/ui/screens/settings/actions/selector/actions/SettingsActionsActionSelectorFragment.kt index df36e178..57ebe936 100644 --- a/app/src/main/java/com/kieronquinn/app/taptap/ui/screens/settings/actions/selector/actions/SettingsActionsActionSelectorFragment.kt +++ b/app/src/main/java/com/kieronquinn/app/taptap/ui/screens/settings/actions/selector/actions/SettingsActionsActionSelectorFragment.kt @@ -4,7 +4,6 @@ import android.content.res.ColorStateList import android.os.Bundle import android.view.View import androidx.core.view.isVisible -import androidx.lifecycle.lifecycleScope import androidx.navigation.fragment.navArgs import androidx.recyclerview.widget.LinearLayoutManager import com.kieronquinn.app.taptap.R @@ -12,10 +11,11 @@ import com.kieronquinn.app.taptap.databinding.FragmentSettingsActionsAddActionSe import com.kieronquinn.app.taptap.ui.base.BackAvailable import com.kieronquinn.app.taptap.ui.base.ProvidesTitle import com.kieronquinn.app.taptap.ui.screens.settings.actions.selector.SettingsActionsAddGenericFragment -import com.kieronquinn.app.taptap.ui.screens.settings.actions.selector.actions.SettingsActionsActionSelectorViewModel.* +import com.kieronquinn.app.taptap.ui.screens.settings.actions.selector.actions.SettingsActionsActionSelectorViewModel.State import com.kieronquinn.app.taptap.utils.extensions.applyBottomInsets import com.kieronquinn.app.taptap.utils.extensions.onChanged import com.kieronquinn.app.taptap.utils.extensions.onClicked +import com.kieronquinn.app.taptap.utils.extensions.whenResumed import com.kieronquinn.monetcompat.extensions.views.applyMonet import kotlinx.coroutines.flow.debounce import kotlinx.coroutines.launch @@ -59,7 +59,7 @@ class SettingsActionsActionSelectorFragment : private fun setupState(){ handleState(viewModel.state.value) - viewLifecycleOwner.lifecycleScope.launchWhenResumed { + whenResumed { viewModel.state.collect { handleState(it) } @@ -85,7 +85,7 @@ class SettingsActionsActionSelectorFragment : private fun setupSearch() { setSearchText(viewModel.searchText.value) - viewLifecycleOwner.lifecycleScope.launchWhenResumed { + whenResumed { launch { binding.includeSearch.searchBox.onChanged().debounce(250L).collect { viewModel.setSearchText(it ?: "") @@ -94,7 +94,7 @@ class SettingsActionsActionSelectorFragment : } } - private fun setupSearchClear() = viewLifecycleOwner.lifecycleScope.launchWhenResumed { + private fun setupSearchClear() = whenResumed { launch { viewModel.searchShowClear.collect { binding.includeSearch.searchClear.isVisible = it diff --git a/app/src/main/java/com/kieronquinn/app/taptap/ui/screens/settings/actions/tripletap/SettingsActionsTripleFragment.kt b/app/src/main/java/com/kieronquinn/app/taptap/ui/screens/settings/actions/tripletap/SettingsActionsTripleFragment.kt index 090d3629..45efcea9 100644 --- a/app/src/main/java/com/kieronquinn/app/taptap/ui/screens/settings/actions/tripletap/SettingsActionsTripleFragment.kt +++ b/app/src/main/java/com/kieronquinn/app/taptap/ui/screens/settings/actions/tripletap/SettingsActionsTripleFragment.kt @@ -2,14 +2,13 @@ package com.kieronquinn.app.taptap.ui.screens.settings.actions.tripletap import android.os.Bundle import android.view.View -import androidx.lifecycle.lifecycleScope import com.kieronquinn.app.taptap.databinding.FragmentSettingsActionsTripleBinding import com.kieronquinn.app.taptap.repositories.room.actions.TripleTapAction import com.kieronquinn.app.taptap.ui.base.BackAvailable import com.kieronquinn.app.taptap.ui.base.LockCollapsed import com.kieronquinn.app.taptap.ui.screens.settings.actions.SettingsActionsGenericFragment import com.kieronquinn.app.taptap.utils.extensions.onClicked -import kotlinx.coroutines.flow.collect +import com.kieronquinn.app.taptap.utils.extensions.whenResumed import org.koin.androidx.viewmodel.ext.android.viewModel class SettingsActionsTripleFragment: SettingsActionsGenericFragment(FragmentSettingsActionsTripleBinding::inflate), LockCollapsed, BackAvailable { @@ -29,14 +28,14 @@ class SettingsActionsTripleFragment: SettingsActionsGenericFragment { @@ -195,13 +195,13 @@ class SettingsActionsWhenGatesFragment : sharedViewModel.setFabState(ContainerSharedViewModel.FabState.Hidden) } - private fun setupReloadService() = viewLifecycleOwner.lifecycleScope.launchWhenResumed { + private fun setupReloadService() = whenResumed { viewModel.reloadServiceBus.debounce(1000L).collect { sharedViewModel.restartService(requireContext()) } } - private fun setupScrollToBottom() = viewLifecycleOwner.lifecycleScope.launchWhenResumed { + private fun setupScrollToBottom() = whenResumed { viewModel.scrollToBottomBus.collect { binding.settingsActionsWhenGatesRecyclerview.scrollToBottom() } diff --git a/app/src/main/java/com/kieronquinn/app/taptap/ui/screens/settings/advanced/customsensitivity/SettingsAdvancedCustomSensitivityFragment.kt b/app/src/main/java/com/kieronquinn/app/taptap/ui/screens/settings/advanced/customsensitivity/SettingsAdvancedCustomSensitivityFragment.kt index eb820204..26b0e240 100644 --- a/app/src/main/java/com/kieronquinn/app/taptap/ui/screens/settings/advanced/customsensitivity/SettingsAdvancedCustomSensitivityFragment.kt +++ b/app/src/main/java/com/kieronquinn/app/taptap/ui/screens/settings/advanced/customsensitivity/SettingsAdvancedCustomSensitivityFragment.kt @@ -4,7 +4,6 @@ import android.os.Bundle import android.view.View import androidx.core.view.WindowInsetsCompat import androidx.core.view.updatePadding -import androidx.lifecycle.lifecycleScope import com.kieronquinn.app.taptap.R import com.kieronquinn.app.taptap.databinding.FragmentSettingsAdvancedCustomSensitivityBinding import com.kieronquinn.app.taptap.ui.base.BaseBottomSheetFragment @@ -12,8 +11,8 @@ import com.kieronquinn.app.taptap.ui.screens.container.ContainerSharedViewModel import com.kieronquinn.app.taptap.utils.extensions.onApplyInsets import com.kieronquinn.app.taptap.utils.extensions.onChanged import com.kieronquinn.app.taptap.utils.extensions.onClicked +import com.kieronquinn.app.taptap.utils.extensions.whenResumed import com.kieronquinn.monetcompat.extensions.views.applyMonet -import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.take import org.koin.androidx.viewmodel.ext.android.sharedViewModel import org.koin.androidx.viewmodel.ext.android.viewModel @@ -46,7 +45,7 @@ class SettingsAdvancedCustomSensitivityFragment: BaseBottomSheetFragment(FragmentSettingsWallpaperColorPickerBinding::inflate) { @@ -28,14 +28,14 @@ class SettingsWallpaperColorPickerBottomSheetFragment: BaseBottomSheetFragment(FragmentSettingsBackupRestoreBinding::inflate), BackAvailable { @@ -35,7 +35,7 @@ class SettingsBackupRestoreFragment: BoundFragment() private val permissionResponse = MutableSharedFlow>() private val permissionResponseContract = registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { - viewLifecycleOwner.lifecycleScope.launchWhenResumed { + whenResumed { permissionResponse.emit(it) } } @@ -95,7 +104,7 @@ class SettingsBackupRestoreRestoreFragment : private fun setupState() { handleState(viewModel.state.value) - viewLifecycleOwner.lifecycleScope.launchWhenResumed { + whenResumed { viewModel.state.collect { handleState(it) } @@ -108,14 +117,14 @@ class SettingsBackupRestoreRestoreFragment : applyBottomInsets(binding.root, resources.getDimension(R.dimen.container_fab_margin).toInt()) } - private fun setupFab() = viewLifecycleOwner.lifecycleScope.launchWhenResumed { + private fun setupFab() = whenResumed { sharedViewModel.fabClicked.collect { if (it != FabState.FabAction.RESTORE_BACKUP) return@collect viewModel.onFabClicked() } } - private fun setupClose() = viewLifecycleOwner.lifecycleScope.launchWhenResumed { + private fun setupClose() = whenResumed { binding.settingsBackupRestoreRestoreClose.onClicked().collect { viewModel.onCloseClicked() } @@ -186,9 +195,9 @@ class SettingsBackupRestoreRestoreFragment : sharedViewModel.setFabState(if (showFab) FabState.Shown(FabState.FabAction.RESTORE_BACKUP) else FabState.Hidden) } - private fun onSetupClicked(item: SettingsBackupRestoreRestoreViewModel.Item.Requirement) = viewLifecycleOwner.lifecycleScope.launchWhenResumed { + private fun onSetupClicked(item: SettingsBackupRestoreRestoreViewModel.Item.Requirement) = whenResumed { //Take the first requirement as the list is dynamic - val requirement = item.requirements.firstOrNull() ?: return@launchWhenResumed + val requirement = item.requirements.firstOrNull() ?: return@whenResumed when (requirement) { is ResolvedRequirement.Action -> handleSetupActionRequirement( requirement.requirement @@ -353,7 +362,7 @@ class SettingsBackupRestoreRestoreFragment : private fun setupResultListeners() { setFragmentResultListener(SettingsSharedShizukuPermissionFlowFragment.FRAGMENT_RESULT_KEY_SHIZUKU_PERMISSION) { key, bundle -> val permissionGranted = bundle.getBoolean(SettingsSharedShizukuPermissionFlowFragment.FRAGMENT_RESULT_KEY_SHIZUKU_PERMISSION, false) - viewLifecycleOwner.lifecycleScope.launchWhenResumed { + whenResumed { if(permissionGranted) { viewModel.onRequirementResolved(ResolvedRequirement.Action(ActionRequirement.Shizuku)) } //Drop if permission is denied @@ -361,7 +370,7 @@ class SettingsBackupRestoreRestoreFragment : } setFragmentResultListener(SettingsSharedSnapchatFragment.FRAGMENT_RESULT_KEY_SNAPCHAT) { key, bundle -> val available = bundle.getBoolean(SettingsSharedSnapchatFragment.FRAGMENT_RESULT_KEY_SNAPCHAT, false) - viewLifecycleOwner.lifecycleScope.launchWhenResumed { + whenResumed { if(available) { viewModel.onRequirementResolved(ResolvedRequirement.Action(ActionRequirement.Snapchat)) } //Drop if not available @@ -371,7 +380,7 @@ class SettingsBackupRestoreRestoreFragment : override fun onResume() { super.onResume() - viewLifecycleOwner.lifecycleScope.launchWhenResumed { + whenResumed { onResume.emit(Unit) } } diff --git a/app/src/main/java/com/kieronquinn/app/taptap/ui/screens/settings/battery/SettingsBatteryFragment.kt b/app/src/main/java/com/kieronquinn/app/taptap/ui/screens/settings/battery/SettingsBatteryFragment.kt index 53bd316c..59373422 100644 --- a/app/src/main/java/com/kieronquinn/app/taptap/ui/screens/settings/battery/SettingsBatteryFragment.kt +++ b/app/src/main/java/com/kieronquinn/app/taptap/ui/screens/settings/battery/SettingsBatteryFragment.kt @@ -2,13 +2,12 @@ package com.kieronquinn.app.taptap.ui.screens.settings.battery import android.os.Bundle import android.view.View -import androidx.lifecycle.lifecycleScope import com.kieronquinn.app.taptap.R import com.kieronquinn.app.taptap.ui.base.BackAvailable import com.kieronquinn.app.taptap.ui.screens.settings.generic.GenericSettingsAdapter import com.kieronquinn.app.taptap.ui.screens.settings.generic.GenericSettingsFragment import com.kieronquinn.app.taptap.ui.screens.settings.generic.GenericSettingsViewModel.SettingsItem -import kotlinx.coroutines.flow.collect +import com.kieronquinn.app.taptap.utils.extensions.whenResumed import org.koin.androidx.viewmodel.ext.android.viewModel class SettingsBatteryFragment : GenericSettingsFragment(), BackAvailable { @@ -67,7 +66,7 @@ class SettingsBatteryFragment : GenericSettingsFragment(), BackAvailable { setupHeaderDismiss() } - private fun setupHeaderDismiss() = viewLifecycleOwner.lifecycleScope.launchWhenResumed { + private fun setupHeaderDismiss() = whenResumed { viewModel.showHeader.collect { adapter.refreshVisibleItems() } diff --git a/app/src/main/java/com/kieronquinn/app/taptap/ui/screens/settings/gates/SettingsGatesAdapter.kt b/app/src/main/java/com/kieronquinn/app/taptap/ui/screens/settings/gates/SettingsGatesAdapter.kt index 9abc0b30..0d241b56 100644 --- a/app/src/main/java/com/kieronquinn/app/taptap/ui/screens/settings/gates/SettingsGatesAdapter.kt +++ b/app/src/main/java/com/kieronquinn/app/taptap/ui/screens/settings/gates/SettingsGatesAdapter.kt @@ -7,7 +7,6 @@ import android.view.ViewGroup import androidx.core.content.ContextCompat import androidx.core.view.isVisible import androidx.lifecycle.Lifecycle -import androidx.lifecycle.coroutineScope import androidx.viewbinding.ViewBinding import com.kieronquinn.app.taptap.R import com.kieronquinn.app.taptap.databinding.ItemSettingsGatesGateBinding @@ -15,10 +14,15 @@ import com.kieronquinn.app.taptap.databinding.ItemSettingsGatesInfoBinding import com.kieronquinn.app.taptap.ui.screens.settings.gates.SettingsGatesViewModel.SettingsGatesItem import com.kieronquinn.app.taptap.ui.screens.settings.gates.SettingsGatesViewModel.SettingsGatesItem.SettingsGatesItemType import com.kieronquinn.app.taptap.ui.views.LifecycleAwareRecyclerView -import com.kieronquinn.app.taptap.utils.extensions.* +import com.kieronquinn.app.taptap.utils.extensions.addRippleForeground +import com.kieronquinn.app.taptap.utils.extensions.applyBackgroundTint +import com.kieronquinn.app.taptap.utils.extensions.isDarkMode +import com.kieronquinn.app.taptap.utils.extensions.onClicked +import com.kieronquinn.app.taptap.utils.extensions.onLongClicked +import com.kieronquinn.app.taptap.utils.extensions.whenResumed import com.kieronquinn.monetcompat.core.MonetCompat import com.kieronquinn.monetcompat.extensions.views.applyMonetLight -import java.util.* +import java.util.Collections class SettingsGatesAdapter( recyclerView: LifecycleAwareRecyclerView, @@ -100,19 +104,19 @@ class SettingsGatesAdapter( itemSettingsGatesGateContent.text = item.gate.description itemSettingsGatesGateSwitch.isChecked = item.gate.enabled itemSettingsGatesGateSwitch.applyMonetLight() - holder.lifecycle.coroutineScope.launchWhenResumed { + holder.lifecycle.whenResumed { itemSettingsGatesGateSwitch.onClicked().collect { item.gate.enabled = !item.gate.enabled onItemStateChanged(item.gate.id, item.gate.enabled) notifyItemChanged(holder.adapterPosition) } } - holder.lifecycle.coroutineScope.launchWhenResumed { + holder.lifecycle.whenResumed { itemSettingsGatesGateHandle.onLongClicked().collect { onHandleLongPressed(holder) } } - holder.lifecycle.coroutineScope.launchWhenResumed { + holder.lifecycle.whenResumed { root.onLongClicked().collect { val isSelected = item.isSelected clearSelection() @@ -129,14 +133,14 @@ class SettingsGatesAdapter( itemSettingsGatesInfoContent.text = context.getText(item.contentRes) if(item.onClick != null){ root.addRippleForeground() - lifecycle.coroutineScope.launchWhenResumed { + lifecycle.whenResumed { root.onClicked().collect { item.onClick.invoke() } } } itemSettingsGatesInfoDismiss.isVisible = item.onCloseClick != null - lifecycle.coroutineScope.launchWhenResumed { + lifecycle.whenResumed { itemSettingsGatesInfoDismiss.onClicked().collect { item.onCloseClick?.invoke() } diff --git a/app/src/main/java/com/kieronquinn/app/taptap/ui/screens/settings/gates/SettingsGatesFragment.kt b/app/src/main/java/com/kieronquinn/app/taptap/ui/screens/settings/gates/SettingsGatesFragment.kt index b3a56dd2..fe0cffc8 100644 --- a/app/src/main/java/com/kieronquinn/app/taptap/ui/screens/settings/gates/SettingsGatesFragment.kt +++ b/app/src/main/java/com/kieronquinn/app/taptap/ui/screens/settings/gates/SettingsGatesFragment.kt @@ -4,7 +4,6 @@ import android.os.Bundle import android.view.View import androidx.core.view.isVisible import androidx.fragment.app.setFragmentResultListener -import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.ItemTouchHelper import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView @@ -15,14 +14,15 @@ import com.kieronquinn.app.taptap.ui.base.BackAvailable import com.kieronquinn.app.taptap.ui.base.BoundFragment import com.kieronquinn.app.taptap.ui.base.LockCollapsed import com.kieronquinn.app.taptap.ui.screens.container.ContainerSharedViewModel -import com.kieronquinn.app.taptap.ui.screens.settings.gates.SettingsGatesViewModel.SettingsGatesItem.* +import com.kieronquinn.app.taptap.ui.screens.settings.gates.SettingsGatesViewModel.SettingsGatesItem.Gate +import com.kieronquinn.app.taptap.ui.screens.settings.gates.SettingsGatesViewModel.SettingsGatesItem.Header import com.kieronquinn.app.taptap.ui.screens.settings.gates.SettingsGatesViewModel.State import com.kieronquinn.app.taptap.ui.screens.settings.gates.selector.SettingsGatesAddGenericFragment import com.kieronquinn.app.taptap.utils.extensions.applyBottomInsets import com.kieronquinn.app.taptap.utils.extensions.awaitState import com.kieronquinn.app.taptap.utils.extensions.scrollToBottom +import com.kieronquinn.app.taptap.utils.extensions.whenResumed import com.kieronquinn.monetcompat.extensions.views.applyMonet -import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.debounce import org.koin.android.ext.android.inject import org.koin.androidx.viewmodel.ext.android.sharedViewModel @@ -74,7 +74,7 @@ class SettingsGatesFragment : private fun setupState() { handleState(viewModel.state.value) - viewLifecycleOwner.lifecycleScope.launchWhenResumed { + whenResumed { viewModel.state.collect { handleState(it) } @@ -98,7 +98,7 @@ class SettingsGatesFragment : } } - private fun setupFab() = viewLifecycleOwner.lifecycleScope.launchWhenResumed { + private fun setupFab() = whenResumed { sharedViewModel.fabClicked.collect { when (it) { ContainerSharedViewModel.FabState.FabAction.ADD_GATE -> { @@ -120,7 +120,7 @@ class SettingsGatesFragment : private fun setupFabState() { handleFabState(viewModel.fabState.value) - viewLifecycleOwner.lifecycleScope.launchWhenResumed { + whenResumed { viewModel.fabState.collect { handleFabState(it) } @@ -138,14 +138,14 @@ class SettingsGatesFragment : } } - private fun setupScrollToBottom() = viewLifecycleOwner.lifecycleScope.launchWhenResumed { + private fun setupScrollToBottom() = whenResumed { viewModel.scrollToBottomBus.collect { viewModel.state.awaitState(State.Loaded::class.java) binding.settingsGatesRecyclerview.scrollToBottom() } } - private fun setupReloadService() = viewLifecycleOwner.lifecycleScope.launchWhenResumed { + private fun setupReloadService() = whenResumed { viewModel.reloadServiceBus.debounce(1000L).collect { sharedViewModel.restartService(requireContext()) } diff --git a/app/src/main/java/com/kieronquinn/app/taptap/ui/screens/settings/gates/help/SettingsGatesHelpBottomSheetFragment.kt b/app/src/main/java/com/kieronquinn/app/taptap/ui/screens/settings/gates/help/SettingsGatesHelpBottomSheetFragment.kt index 9cd2c83d..95f651ae 100644 --- a/app/src/main/java/com/kieronquinn/app/taptap/ui/screens/settings/gates/help/SettingsGatesHelpBottomSheetFragment.kt +++ b/app/src/main/java/com/kieronquinn/app/taptap/ui/screens/settings/gates/help/SettingsGatesHelpBottomSheetFragment.kt @@ -4,13 +4,12 @@ import android.os.Bundle import android.view.View import androidx.core.view.WindowInsetsCompat import androidx.core.view.updatePadding -import androidx.lifecycle.lifecycleScope import com.kieronquinn.app.taptap.R import com.kieronquinn.app.taptap.databinding.FragmentSettingsGatesHelpBinding import com.kieronquinn.app.taptap.ui.base.BaseBottomSheetFragment import com.kieronquinn.app.taptap.utils.extensions.onApplyInsets import com.kieronquinn.app.taptap.utils.extensions.onClicked -import kotlinx.coroutines.flow.collect +import com.kieronquinn.app.taptap.utils.extensions.whenResumed class SettingsGatesHelpBottomSheetFragment: BaseBottomSheetFragment(FragmentSettingsGatesHelpBinding::inflate) { @@ -34,7 +33,7 @@ class SettingsGatesHelpBottomSheetFragment: BaseBottomSheetFragment(inflate: (Layout private val onShizukuPermissionResponse = MutableSharedFlow(replay = 1, onBufferOverflow = BufferOverflow.DROP_OLDEST) private val permissionResponse = MutableSharedFlow>() private val permissionResponseContract = registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { - viewLifecycleOwner.lifecycleScope.launchWhenResumed { + whenResumed { permissionResponse.emit(it) } } @@ -61,7 +66,7 @@ abstract class SettingsGatesAddGenericFragment(inflate: (Layout accessibilityRouter.bringToFrontOnAccessibilityStart(this) } - protected fun onGateClicked(gate: TapTapGateDirectory) = viewLifecycleOwner.lifecycleScope.launchWhenResumed { + protected fun onGateClicked(gate: TapTapGateDirectory) = whenResumed { handleGate(gate) } @@ -153,7 +158,7 @@ abstract class SettingsGatesAddGenericFragment(inflate: (Layout return requireContext().isServiceRunning(TapTapAccessibilityService::class.java) } - protected fun showSnackbarForChip(requirement: GateRequirement.UserDisplayedGateRequirement) = viewLifecycleOwner.lifecycleScope.launchWhenResumed { + protected fun showSnackbarForChip(requirement: GateRequirement.UserDisplayedGateRequirement) = whenResumed { sharedViewModel.showSnackbar(getText(requirement.desc)) } @@ -161,14 +166,14 @@ abstract class SettingsGatesAddGenericFragment(inflate: (Layout setFragmentResultListener(SettingsSharedPackageSelectorFragment.FRAGMENT_RESULT_KEY_PACKAGE) { key, bundle -> val action = bundle.getParcelable(ARG_NAME_SHARED_ARGUMENT)?.gate ?: return@setFragmentResultListener val packageName = bundle.getString(SettingsSharedPackageSelectorFragment.FRAGMENT_RESULT_KEY_PACKAGE) ?: return@setFragmentResultListener - viewLifecycleOwner.lifecycleScope.launchWhenResumed { + whenResumed { handleGate(action, packageName, isReturningRequirement = true) } } setFragmentResultListener(SettingsSharedShizukuPermissionFlowFragment.FRAGMENT_RESULT_KEY_SHIZUKU_PERMISSION) { key, bundle -> val permissionGranted = bundle.getBoolean(SettingsSharedShizukuPermissionFlowFragment.FRAGMENT_RESULT_KEY_SHIZUKU_PERMISSION, false) val gate = bundle.getParcelable(ARG_NAME_SHARED_ARGUMENT)?.gate ?: return@setFragmentResultListener - viewLifecycleOwner.lifecycleScope.launchWhenResumed { + whenResumed { if(permissionGranted) { handleGate(gate, isReturningRequirement = true) } //Drop if permission is denied @@ -178,7 +183,7 @@ abstract class SettingsGatesAddGenericFragment(inflate: (Layout override fun onResume() { super.onResume() - viewLifecycleOwner.lifecycleScope.launchWhenResumed { + whenResumed { onResume.emit(Unit) } } diff --git a/app/src/main/java/com/kieronquinn/app/taptap/ui/screens/settings/gates/selector/gates/SettingsGatesGateSelectorAdapter.kt b/app/src/main/java/com/kieronquinn/app/taptap/ui/screens/settings/gates/selector/gates/SettingsGatesGateSelectorAdapter.kt index 60539c4c..3fde8b7d 100644 --- a/app/src/main/java/com/kieronquinn/app/taptap/ui/screens/settings/gates/selector/gates/SettingsGatesGateSelectorAdapter.kt +++ b/app/src/main/java/com/kieronquinn/app/taptap/ui/screens/settings/gates/selector/gates/SettingsGatesGateSelectorAdapter.kt @@ -8,7 +8,6 @@ import androidx.core.content.ContextCompat import androidx.core.content.res.ResourcesCompat import androidx.core.view.isVisible import androidx.lifecycle.Lifecycle -import androidx.lifecycle.coroutineScope import androidx.recyclerview.widget.RecyclerView import com.kieronquinn.app.taptap.R import com.kieronquinn.app.taptap.databinding.ItemSettingsGatesGateSelectorItemBinding @@ -20,6 +19,7 @@ import com.kieronquinn.app.taptap.utils.extensions.addRippleForeground import com.kieronquinn.app.taptap.utils.extensions.applyBackgroundTint import com.kieronquinn.app.taptap.utils.extensions.onClicked import com.kieronquinn.app.taptap.utils.extensions.removeRippleForeground +import com.kieronquinn.app.taptap.utils.extensions.whenResumed import com.kieronquinn.monetcompat.core.MonetCompat class SettingsGatesGateSelectorAdapter( @@ -111,7 +111,7 @@ class SettingsGatesGateSelectorAdapter( chipIcon = ContextCompat.getDrawable(context, requirement.icon) } } - lifecycle.coroutineScope.launchWhenResumed { + lifecycle.whenResumed { itemSettingsGateSelectorChip.onClicked().collect { gate.gateRequirement?.firstOrNull { it is GateRequirement.UserDisplayedGateRequirement }?.let { requirement -> requirement as GateRequirement.UserDisplayedGateRequirement diff --git a/app/src/main/java/com/kieronquinn/app/taptap/ui/screens/settings/gates/selector/gates/SettingsGatesGateSelectorFragment.kt b/app/src/main/java/com/kieronquinn/app/taptap/ui/screens/settings/gates/selector/gates/SettingsGatesGateSelectorFragment.kt index 5fbb8f97..30b3e95e 100644 --- a/app/src/main/java/com/kieronquinn/app/taptap/ui/screens/settings/gates/selector/gates/SettingsGatesGateSelectorFragment.kt +++ b/app/src/main/java/com/kieronquinn/app/taptap/ui/screens/settings/gates/selector/gates/SettingsGatesGateSelectorFragment.kt @@ -4,7 +4,6 @@ import android.content.res.ColorStateList import android.os.Bundle import android.view.View import androidx.core.view.isVisible -import androidx.lifecycle.lifecycleScope import androidx.navigation.fragment.navArgs import androidx.recyclerview.widget.LinearLayoutManager import com.kieronquinn.app.taptap.R @@ -16,6 +15,7 @@ import com.kieronquinn.app.taptap.ui.screens.settings.gates.selector.gates.Setti import com.kieronquinn.app.taptap.utils.extensions.applyBottomInsets import com.kieronquinn.app.taptap.utils.extensions.onChanged import com.kieronquinn.app.taptap.utils.extensions.onClicked +import com.kieronquinn.app.taptap.utils.extensions.whenResumed import com.kieronquinn.monetcompat.extensions.views.applyMonet import kotlinx.coroutines.flow.debounce import kotlinx.coroutines.launch @@ -59,7 +59,7 @@ class SettingsGatesGateSelectorFragment : private fun setupState(){ handleState(viewModel.state.value) - viewLifecycleOwner.lifecycleScope.launchWhenResumed { + whenResumed { viewModel.state.collect { handleState(it) } @@ -85,7 +85,7 @@ class SettingsGatesGateSelectorFragment : private fun setupSearch() { setSearchText(viewModel.searchText.value) - viewLifecycleOwner.lifecycleScope.launchWhenResumed { + whenResumed { launch { binding.includeSearch.searchBox.onChanged().debounce(250L).collect { viewModel.setSearchText(it ?: "") @@ -94,7 +94,7 @@ class SettingsGatesGateSelectorFragment : } } - private fun setupSearchClear() = viewLifecycleOwner.lifecycleScope.launchWhenResumed { + private fun setupSearchClear() = whenResumed { launch { viewModel.searchShowClear.collect { binding.includeSearch.searchClear.isVisible = it diff --git a/app/src/main/java/com/kieronquinn/app/taptap/ui/screens/settings/generic/GenericSettingsAdapter.kt b/app/src/main/java/com/kieronquinn/app/taptap/ui/screens/settings/generic/GenericSettingsAdapter.kt index 35894823..b3198837 100644 --- a/app/src/main/java/com/kieronquinn/app/taptap/ui/screens/settings/generic/GenericSettingsAdapter.kt +++ b/app/src/main/java/com/kieronquinn/app/taptap/ui/screens/settings/generic/GenericSettingsAdapter.kt @@ -10,19 +10,31 @@ import android.view.ViewGroup import android.widget.CompoundButton import androidx.core.content.res.ResourcesCompat import androidx.core.view.isVisible -import androidx.lifecycle.LifecycleCoroutineScope -import androidx.lifecycle.lifecycleScope +import androidx.lifecycle.Lifecycle import androidx.recyclerview.widget.RecyclerView import androidx.viewbinding.ViewBinding import com.kieronquinn.app.taptap.BuildConfig import com.kieronquinn.app.taptap.R import com.kieronquinn.app.taptap.components.settings.TapTapSettings import com.kieronquinn.app.taptap.components.settings.invert -import com.kieronquinn.app.taptap.databinding.* +import com.kieronquinn.app.taptap.databinding.ItemSettingsHeaderBinding +import com.kieronquinn.app.taptap.databinding.ItemSettingsInfoItemBinding +import com.kieronquinn.app.taptap.databinding.ItemSettingsMoreAboutBinding +import com.kieronquinn.app.taptap.databinding.ItemSettingsSliderItemBinding +import com.kieronquinn.app.taptap.databinding.ItemSettingsSwitchItemBinding +import com.kieronquinn.app.taptap.databinding.ItemSettingsTextItemBinding import com.kieronquinn.app.taptap.ui.screens.settings.generic.GenericSettingsViewModel.SettingsItem import com.kieronquinn.app.taptap.ui.screens.settings.generic.GenericSettingsViewModel.SettingsItem.SettingsItemType import com.kieronquinn.app.taptap.ui.views.LifecycleAwareRecyclerView -import com.kieronquinn.app.taptap.utils.extensions.* +import com.kieronquinn.app.taptap.utils.extensions.addRipple +import com.kieronquinn.app.taptap.utils.extensions.addRippleForeground +import com.kieronquinn.app.taptap.utils.extensions.applyBackgroundTint +import com.kieronquinn.app.taptap.utils.extensions.onChanged +import com.kieronquinn.app.taptap.utils.extensions.onClicked +import com.kieronquinn.app.taptap.utils.extensions.removeRipple +import com.kieronquinn.app.taptap.utils.extensions.removeRippleForeground +import com.kieronquinn.app.taptap.utils.extensions.setTooltipColor +import com.kieronquinn.app.taptap.utils.extensions.whenResumed import com.kieronquinn.monetcompat.core.MonetCompat import com.kieronquinn.monetcompat.extensions.views.applyMonet import me.saket.bettermovementmethod.BetterLinkMovementMethod @@ -122,23 +134,23 @@ abstract class GenericSettingsAdapter( when (holder) { is ViewHolder.Text -> holder.binding.setupTextItem( item as SettingsItem.Text, - holder.lifecycleScope + holder.lifecycle ) is ViewHolder.Switch -> holder.binding.setupSwitchItem( item as SettingsItem.Switch, - holder.lifecycleScope + holder.lifecycle ) is ViewHolder.Slider -> holder.binding.setupSliderItem( item as SettingsItem.Slider, - holder.lifecycleScope + holder.lifecycle ) is ViewHolder.Info -> holder.binding.setupInfoItem( item as SettingsItem.Info, - holder.lifecycleScope + holder.lifecycle ) is ViewHolder.About -> holder.binding.setupAboutItem( item as SettingsItem.About, - holder.lifecycleScope + holder.lifecycle ) is ViewHolder.Header -> holder.binding.setupHeaderItem( item as SettingsItem.Header @@ -152,7 +164,7 @@ abstract class GenericSettingsAdapter( private fun ItemSettingsTextItemBinding.setupTextItem( item: SettingsItem.Text, - scope: LifecycleCoroutineScope + lifecycle: Lifecycle ) { val context = root.context itemSettingsTextTitle.text = when { @@ -195,7 +207,7 @@ abstract class GenericSettingsAdapter( root.removeRipple() } itemSettingsTextIcon.setImageResource(item.icon) - scope.launchWhenResumed { + lifecycle.whenResumed { item.onClick?.let { root.onClicked().collect { if (!isEnabled) return@collect @@ -207,7 +219,7 @@ abstract class GenericSettingsAdapter( private fun ItemSettingsSwitchItemBinding.setupSwitchItem( item: SettingsItem.Switch, - scope: LifecycleCoroutineScope + lifecycle: Lifecycle ) { val context = root.context itemSettingsSwitchTitle.text = when { @@ -232,18 +244,18 @@ abstract class GenericSettingsAdapter( itemSettingsSwitchTitle.alpha = if (isEnabled) 1f else 0.5f itemSettingsSwitchContent.alpha = if (isEnabled) 1f else 0.5f itemSettingsSwitchIcon.alpha = if (isEnabled) 1f else 0.5f - scope.launchWhenResumed { + lifecycle.whenResumed { item.setting.asFlow().collect { itemSettingsSwitchSwitch.isChecked = it } } - scope.launchWhenResumed { + lifecycle.whenResumed { root.onClicked().collect { if (!isEnabled) return@collect item.setting.invert() } } - scope.launchWhenResumed { + lifecycle.whenResumed { itemSettingsSwitchSwitch.onClicked().collect { if (!isEnabled) return@collect if (item.setting is TapTapSettings.FakeTapTapSetting) { @@ -257,7 +269,7 @@ abstract class GenericSettingsAdapter( private fun ItemSettingsSliderItemBinding.setupSliderItem( item: SettingsItem.Slider, - scope: LifecycleCoroutineScope + lifecycle: Lifecycle ) { val context = root.context itemSettingsSliderTitle.text = when { @@ -285,12 +297,12 @@ abstract class GenericSettingsAdapter( setLabelFormatter(item.labelFormatter) setTooltipColor(monet.getAccentColor(context, false)) } - scope.launchWhenResumed { + lifecycle.whenResumed { item.setting.asFlow().collect { itemSettingsSliderSlider.value = it.toFloat() } } - scope.launchWhenResumed { + lifecycle.whenResumed { itemSettingsSliderSlider.onChanged().collect { item.setting.set(it) } @@ -299,7 +311,7 @@ abstract class GenericSettingsAdapter( private fun ItemSettingsInfoItemBinding.setupInfoItem( item: SettingsItem.Info, - scope: LifecycleCoroutineScope + lifecycle: Lifecycle ) { val context = root.context Linkify.addLinks(itemSettingsInfoContent, Linkify.ALL) @@ -334,7 +346,7 @@ abstract class GenericSettingsAdapter( }else{ itemSettingsInfoIcon.setImageResource(R.drawable.ic_about) } - scope.launchWhenResumed { + lifecycle.whenResumed { itemSettingsInfoDismiss.onClicked().collect { item.onDismissClicked?.invoke() } @@ -344,7 +356,7 @@ abstract class GenericSettingsAdapter( }else{ root.removeRippleForeground() } - scope.launchWhenResumed { + lifecycle.whenResumed { item.onClick?.let { root.onClicked().collect { item.onClick.invoke() @@ -355,7 +367,7 @@ abstract class GenericSettingsAdapter( private fun ItemSettingsMoreAboutBinding.setupAboutItem( item: SettingsItem.About, - scope: LifecycleCoroutineScope + lifecycle: Lifecycle ) { val context = root.context val content = context.getString(R.string.about_version, BuildConfig.VERSION_NAME) @@ -372,7 +384,7 @@ abstract class GenericSettingsAdapter( with(chip.key){ chipBackgroundColor = chipBackground typeface = googleSansTextMedium - scope.launchWhenResumed { + lifecycle.whenResumed { onClicked().collect { chip.value() } diff --git a/app/src/main/java/com/kieronquinn/app/taptap/ui/screens/settings/generic/GenericSettingsFragment.kt b/app/src/main/java/com/kieronquinn/app/taptap/ui/screens/settings/generic/GenericSettingsFragment.kt index a2b1587f..7e1a4ef3 100644 --- a/app/src/main/java/com/kieronquinn/app/taptap/ui/screens/settings/generic/GenericSettingsFragment.kt +++ b/app/src/main/java/com/kieronquinn/app/taptap/ui/screens/settings/generic/GenericSettingsFragment.kt @@ -2,18 +2,13 @@ package com.kieronquinn.app.taptap.ui.screens.settings.generic import android.os.Bundle import android.view.View -import androidx.core.view.WindowInsetsCompat -import androidx.core.view.updatePadding -import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.LinearLayoutManager -import com.kieronquinn.app.taptap.R import com.kieronquinn.app.taptap.databinding.FragmentSettingsGenericBinding import com.kieronquinn.app.taptap.ui.base.BoundFragment import com.kieronquinn.app.taptap.ui.screens.container.ContainerSharedViewModel import com.kieronquinn.app.taptap.ui.screens.settings.generic.GenericSettingsViewModel.SettingsItem import com.kieronquinn.app.taptap.utils.extensions.applyBottomInsets -import com.kieronquinn.app.taptap.utils.extensions.onApplyInsets -import kotlinx.coroutines.flow.collect +import com.kieronquinn.app.taptap.utils.extensions.whenResumed import org.koin.androidx.viewmodel.ext.android.sharedViewModel abstract class GenericSettingsFragment: BoundFragment(FragmentSettingsGenericBinding::inflate) { @@ -31,7 +26,7 @@ abstract class GenericSettingsFragment: BoundFragment(FragmentSettingsLowPowerModeShizukuInfoBinding::inflate), BackAvailable { @@ -28,7 +28,7 @@ class SettingsLowPowerModeShizukuInfoFragment: BoundFragment(Fra private fun setupSwitch(){ binding.settingsOptionsEnableTapTap.isChecked = sharedViewModel.isServiceRunning.value - viewLifecycleOwner.lifecycleScope.launchWhenResumed { + whenResumed { with(binding.settingsOptionsEnableTapTap) { launch { sharedViewModel.isServiceRunning.collect { @@ -143,7 +142,7 @@ class SettingsOptionsFragment: BoundFragment(Fra } private fun setupRestart() { - viewLifecycleOwner.lifecycleScope.launchWhenResumed { + whenResumed { viewModel.restartService?.collect { containerViewModel.restartService(requireContext()) } diff --git a/app/src/main/java/com/kieronquinn/app/taptap/ui/screens/settings/shared/internet/SettingsSharedInternetPermissionDialogFragment.kt b/app/src/main/java/com/kieronquinn/app/taptap/ui/screens/settings/shared/internet/SettingsSharedInternetPermissionDialogFragment.kt index ec835c58..7d00f1b0 100644 --- a/app/src/main/java/com/kieronquinn/app/taptap/ui/screens/settings/shared/internet/SettingsSharedInternetPermissionDialogFragment.kt +++ b/app/src/main/java/com/kieronquinn/app/taptap/ui/screens/settings/shared/internet/SettingsSharedInternetPermissionDialogFragment.kt @@ -7,13 +7,12 @@ import android.view.View import android.view.WindowManager import androidx.core.content.ContextCompat import androidx.core.view.WindowCompat -import androidx.lifecycle.lifecycleScope import com.kieronquinn.app.taptap.R import com.kieronquinn.app.taptap.databinding.FragmentDialogInternetPermissionBinding import com.kieronquinn.app.taptap.ui.base.BaseDialogFragment import com.kieronquinn.app.taptap.utils.extensions.onClicked +import com.kieronquinn.app.taptap.utils.extensions.whenResumed import com.kieronquinn.monetcompat.extensions.views.overrideRippleColor -import kotlinx.coroutines.flow.collect import org.koin.androidx.viewmodel.ext.android.viewModel class SettingsSharedInternetPermissionDialogFragment: BaseDialogFragment(FragmentDialogInternetPermissionBinding::inflate) { @@ -46,24 +45,24 @@ class SettingsSharedInternetPermissionDialogFragment: BaseDialogFragment(FragmentSettingsSharedNoRootBinding::inflate) { @@ -34,7 +33,7 @@ class SettingsSharedNoRootBottomSheetFragment: BaseBottomSheetFragment(FragmentSettingsSharedQuickSettingsSelectorBinding::inflate), BackAvailable { @@ -47,7 +46,7 @@ class SettingsSharedQuickSettingSelectorFragment: BoundFragment(Fragm binding.settingsUpdateDownloadBrowser.setTextColor(accent) } - private fun setupStartInstall() = viewLifecycleOwner.lifecycleScope.launchWhenResumed { + private fun setupStartInstall() = whenResumed { binding.settingsUpdateStartInstall.onClicked().collect { viewModel.startInstall() } } - private fun setupGitHubButton() = viewLifecycleOwner.lifecycleScope.launchWhenResumed { + private fun setupGitHubButton() = whenResumed { binding.settingsUpdateDownloadBrowser.onClicked().collect { viewModel.onDownloadBrowserClicked(args.release.gitHubUrl) } @@ -70,7 +69,7 @@ class SettingsUpdateFragment: BoundFragment(Fragm private fun setupState() { handleState(viewModel.state.value) - viewLifecycleOwner.lifecycleScope.launchWhenResumed { + whenResumed { viewModel.state.collect { handleState(it) } @@ -110,7 +109,7 @@ class SettingsUpdateFragment: BoundFragment(Fragm binding.settingsUpdateSubheading.text = getString(R.string.settings_update_subheading, BuildConfig.VERSION_NAME) binding.settingsUpdateBody.text = markwon.toMarkdown(release.body) binding.settingsUpdateInfo.applyBottomInsets(binding.root, resources.getDimension(R.dimen.container_fab_margin).toInt()) - viewLifecycleOwner.lifecycleScope.launchWhenResumed { + whenResumed { binding.settingsUpdateDownloadBrowser.onClicked().collect { viewModel.onDownloadBrowserClicked(release.gitHubUrl) } @@ -162,7 +161,7 @@ class SettingsUpdateFragment: BoundFragment(Fragm private fun setupFabState() { handleFabState(viewModel.showFab.value) - viewLifecycleOwner.lifecycleScope.launchWhenResumed { + whenResumed { viewModel.showFab.collect { handleFabState(it) } @@ -177,7 +176,7 @@ class SettingsUpdateFragment: BoundFragment(Fragm } } - private fun setupFabClick() = viewLifecycleOwner.lifecycleScope.launchWhenResumed { + private fun setupFabClick() = whenResumed { sharedViewModel.fabClicked.collect { if(it != FabState.FabAction.DOWNLOAD) return@collect viewModel.startDownload() diff --git a/app/src/main/java/com/kieronquinn/app/taptap/ui/screens/setup/base/BaseSetupFragment.kt b/app/src/main/java/com/kieronquinn/app/taptap/ui/screens/setup/base/BaseSetupFragment.kt index a7088d3b..23e3a4c8 100644 --- a/app/src/main/java/com/kieronquinn/app/taptap/ui/screens/setup/base/BaseSetupFragment.kt +++ b/app/src/main/java/com/kieronquinn/app/taptap/ui/screens/setup/base/BaseSetupFragment.kt @@ -6,12 +6,11 @@ import android.view.View import android.view.ViewGroup import androidx.activity.addCallback import androidx.appcompat.widget.Toolbar -import androidx.lifecycle.lifecycleScope import androidx.viewbinding.ViewBinding import com.kieronquinn.app.taptap.ui.base.BoundFragment import com.kieronquinn.app.taptap.ui.base.ProvidesBack import com.kieronquinn.app.taptap.utils.extensions.onNavigationIconClicked -import kotlinx.coroutines.flow.collect +import com.kieronquinn.app.taptap.utils.extensions.whenResumed abstract class BaseSetupFragment(inflate: (LayoutInflater, ViewGroup?, Boolean) -> T): BoundFragment(inflate) { @@ -37,7 +36,7 @@ abstract class BaseSetupFragment(inflate: (LayoutInflater, ViewG requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner) { onBackPressed() } - viewLifecycleOwner.lifecycleScope.launchWhenResumed { + whenResumed { toolbar?.onNavigationIconClicked()?.collect { onBackPressed() } diff --git a/app/src/main/java/com/kieronquinn/app/taptap/ui/screens/setup/complete/SetupCompleteFragment.kt b/app/src/main/java/com/kieronquinn/app/taptap/ui/screens/setup/complete/SetupCompleteFragment.kt index 61686da5..a1debd85 100644 --- a/app/src/main/java/com/kieronquinn/app/taptap/ui/screens/setup/complete/SetupCompleteFragment.kt +++ b/app/src/main/java/com/kieronquinn/app/taptap/ui/screens/setup/complete/SetupCompleteFragment.kt @@ -4,7 +4,6 @@ import android.os.Bundle import android.view.View import androidx.core.view.WindowInsetsCompat import androidx.core.view.updatePadding -import androidx.lifecycle.lifecycleScope import com.kieronquinn.app.taptap.databinding.FragmentSetupCompleteBinding import com.kieronquinn.app.taptap.ui.base.ProvidesBack import com.kieronquinn.app.taptap.ui.screens.setup.base.BaseSetupFragment @@ -12,6 +11,7 @@ import com.kieronquinn.app.taptap.utils.extensions.applyBackgroundTint import com.kieronquinn.app.taptap.utils.extensions.onApplyInsets import com.kieronquinn.app.taptap.utils.extensions.onClicked import com.kieronquinn.app.taptap.utils.extensions.replaceColour +import com.kieronquinn.app.taptap.utils.extensions.whenResumed import com.kieronquinn.monetcompat.extensions.views.overrideRippleColor import org.koin.androidx.viewmodel.ext.android.viewModel @@ -50,7 +50,7 @@ class SetupCompleteFragment: BaseSetupFragment(Fra playAnimation() } - private fun setupClose() = viewLifecycleOwner.lifecycleScope.launchWhenResumed { + private fun setupClose() = whenResumed { binding.setupCompleteClose.onClicked().collect { viewModel.onCloseClicked() } diff --git a/app/src/main/java/com/kieronquinn/app/taptap/ui/screens/setup/gesture/SetupGestureFragment.kt b/app/src/main/java/com/kieronquinn/app/taptap/ui/screens/setup/gesture/SetupGestureFragment.kt index 1572923c..1c81651f 100644 --- a/app/src/main/java/com/kieronquinn/app/taptap/ui/screens/setup/gesture/SetupGestureFragment.kt +++ b/app/src/main/java/com/kieronquinn/app/taptap/ui/screens/setup/gesture/SetupGestureFragment.kt @@ -13,7 +13,6 @@ import androidx.core.view.isVisible import androidx.core.view.updateLayoutParams import androidx.core.view.updatePadding import androidx.fragment.app.Fragment -import androidx.lifecycle.lifecycleScope import androidx.navigation.fragment.NavHostFragment import androidx.vectordrawable.graphics.drawable.SeekableAnimatedVectorDrawable import com.google.android.material.bottomsheet.BottomSheetBehavior @@ -30,7 +29,19 @@ import com.kieronquinn.app.taptap.ui.screens.setup.base.BaseSetupFragment import com.kieronquinn.app.taptap.ui.screens.setup.gesture.SetupGestureViewModel.InfoCard import com.kieronquinn.app.taptap.ui.screens.setup.gesture.SetupGestureViewModel.State import com.kieronquinn.app.taptap.ui.views.RippleView -import com.kieronquinn.app.taptap.utils.extensions.* +import com.kieronquinn.app.taptap.utils.extensions.actionBarSize +import com.kieronquinn.app.taptap.utils.extensions.addRippleForeground +import com.kieronquinn.app.taptap.utils.extensions.childBackStackTopFragment +import com.kieronquinn.app.taptap.utils.extensions.enableChangingAnimations +import com.kieronquinn.app.taptap.utils.extensions.isDarkMode +import com.kieronquinn.app.taptap.utils.extensions.onApplyInsets +import com.kieronquinn.app.taptap.utils.extensions.onClicked +import com.kieronquinn.app.taptap.utils.extensions.onDestinationChanged +import com.kieronquinn.app.taptap.utils.extensions.onNavigationIconClicked +import com.kieronquinn.app.taptap.utils.extensions.removeRippleForeground +import com.kieronquinn.app.taptap.utils.extensions.replaceColour +import com.kieronquinn.app.taptap.utils.extensions.slideOffset +import com.kieronquinn.app.taptap.utils.extensions.whenResumed import com.kieronquinn.monetcompat.extensions.views.applyMonet import kotlinx.coroutines.delay import org.koin.android.ext.android.inject @@ -111,7 +122,7 @@ class SetupGestureFragment: BaseSetupFragment(Fragm private fun setupState() { handleState(viewModel.state.value) - viewLifecycleOwner.lifecycleScope.launchWhenResumed { + whenResumed { viewModel.state.collect { handleState(it) } @@ -135,7 +146,7 @@ class SetupGestureFragment: BaseSetupFragment(Fragm } } - private fun startDemoMode() = viewLifecycleOwner.lifecycleScope.launchWhenResumed { + private fun startDemoMode() = whenResumed { delay(100L) viewModel.startDemoMode(requireContext()) } @@ -164,19 +175,19 @@ class SetupGestureFragment: BaseSetupFragment(Fragm playAnimation() } - private fun setupTaps() = viewLifecycleOwner.lifecycleScope.launchWhenResumed { + private fun setupTaps() = whenResumed { viewModel.tapEvents.collect { binding.setupGestureRipple.addRipple(RippleView.RippleType.SINGLE_TAP) } } - private fun setupDoubleTaps() = viewLifecycleOwner.lifecycleScope.launchWhenResumed { + private fun setupDoubleTaps() = whenResumed { viewModel.doubleTapEvents.collect { binding.setupGestureRipple.addRipple(RippleView.RippleType.DOUBLE_TAP) } } - private fun setupTripleTaps() = viewLifecycleOwner.lifecycleScope.launchWhenResumed { + private fun setupTripleTaps() = whenResumed { viewModel.tripleTapEvents.collect { binding.setupGestureRipple.addRipple(RippleView.RippleType.TRIPLE_TAP) } @@ -192,7 +203,7 @@ class SetupGestureFragment: BaseSetupFragment(Fragm bottomSheetBehavior.peekHeight = resources.getDimension(R.dimen.setup_gesture_bottom_sheet_peek_size).toInt() + insets.getInsets(WindowInsetsCompat.Type.systemBars()).bottom } - viewLifecycleOwner.lifecycleScope.launchWhenResumed { + whenResumed { bottomSheetBehavior.slideOffset().collect { viewModel.onBottomSheetSlideOffsetChange(it) } @@ -206,7 +217,7 @@ class SetupGestureFragment: BaseSetupFragment(Fragm .getInsets(WindowInsetsCompat.Type.systemBars()).bottom ) } - viewLifecycleOwner.lifecycleScope.launchWhenResumed { + whenResumed { viewModel.bottomSheetNavBarBlockHeight.collect { setBottomSheetNavBlockHeight(it) } @@ -226,7 +237,7 @@ class SetupGestureFragment: BaseSetupFragment(Fragm .getInsets(WindowInsetsCompat.Type.statusBars()).top ) } - viewLifecycleOwner.lifecycleScope.launchWhenResumed { + whenResumed { viewModel.bottomSheetStatusBarBlockHeight.collect { setBottomSheetStatusBlockHeight(it) } @@ -241,7 +252,7 @@ class SetupGestureFragment: BaseSetupFragment(Fragm private fun setupBottomSheetRoundedCorners() { setBottomSheetRoundedCorner(viewModel.bottomSheetRoundedCornerMultiplier.value) - viewLifecycleOwner.lifecycleScope.launchWhenResumed { + whenResumed { viewModel.bottomSheetRoundedCornerMultiplier.collect { setBottomSheetRoundedCorner(it) } @@ -266,12 +277,12 @@ class SetupGestureFragment: BaseSetupFragment(Fragm setToolbarNavigationIcon(viewModel.toolbarIcon.value) closeAvd?.currentPlayTime = viewModel.toolbarIconPlaytime.value setToolbarHeightMultiplier(viewModel.toolbarHeightMultiplier.value) - viewLifecycleOwner.lifecycleScope.launchWhenResumed { + whenResumed { viewModel.toolbarIconPlaytime.collect { closeAvd?.currentPlayTime = it } } - viewLifecycleOwner.lifecycleScope.launchWhenResumed { + whenResumed { binding.setupGestureBottomSheetToolbar.onNavigationIconClicked().collect { if(viewModel.bottomSheetExpanded.value) { onBackPressed() @@ -280,18 +291,18 @@ class SetupGestureFragment: BaseSetupFragment(Fragm } } } - viewLifecycleOwner.lifecycleScope.launchWhenResumed { + whenResumed { binding.setupGestureBottomSheetToolbar.onClicked().collect { if(!viewModel.bottomSheetDraggable.value) return@collect toggleBottomSheet() } } - viewLifecycleOwner.lifecycleScope.launchWhenResumed { + whenResumed { viewModel.toolbarHeightMultiplier.collect { setToolbarHeightMultiplier(it) } } - viewLifecycleOwner.lifecycleScope.launchWhenResumed { + whenResumed { viewModel.toolbarIcon.collect { setToolbarNavigationIcon(it) } @@ -318,13 +329,13 @@ class SetupGestureFragment: BaseSetupFragment(Fragm } } - private fun setupCloseBottomSheet() = viewLifecycleOwner.lifecycleScope.launchWhenResumed { + private fun setupCloseBottomSheet() = whenResumed { viewModel.bottomSheetCloseBus.collect { closeBottomSheet() } } - private fun setupOpenBottomSheet() = viewLifecycleOwner.lifecycleScope.launchWhenResumed { + private fun setupOpenBottomSheet() = whenResumed { viewModel.bottomSheetOpenBus.collect { openBottomSheet() } @@ -348,11 +359,11 @@ class SetupGestureFragment: BaseSetupFragment(Fragm bottomSheetBehavior.state = BottomSheetBehavior.STATE_EXPANDED } - private fun setupConfigurationNavigation() = viewLifecycleOwner.lifecycleScope.launchWhenResumed { + private fun setupConfigurationNavigation() = whenResumed { navHostFragment.setupWithNavigation(configurationNavigation) } - private fun setupNavigationTitle() = viewLifecycleOwner.lifecycleScope.launchWhenResumed { + private fun setupNavigationTitle() = whenResumed { navController.onDestinationChanged().collect { val label = it.label if(label == null || label.isBlank()) return@collect @@ -360,7 +371,7 @@ class SetupGestureFragment: BaseSetupFragment(Fragm } } - private fun setupStack() = viewLifecycleOwner.lifecycleScope.launchWhenResumed { + private fun setupStack() = whenResumed { navHostFragment.childBackStackTopFragment().collect { onTopFragmentChanged(it ?: return@collect) } @@ -368,7 +379,7 @@ class SetupGestureFragment: BaseSetupFragment(Fragm private fun setupBottomSheetDraggable() { bottomSheetBehavior.isDraggable = viewModel.bottomSheetDraggable.value - viewLifecycleOwner.lifecycleScope.launchWhenResumed { + whenResumed { viewModel.bottomSheetDraggable.collect { bottomSheetBehavior.isDraggable = it } @@ -377,7 +388,7 @@ class SetupGestureFragment: BaseSetupFragment(Fragm private fun setupInfoCard() { handleInfoCard(viewModel.infoCard.value) - viewLifecycleOwner.lifecycleScope.launchWhenResumed { + whenResumed { viewModel.infoCard.collect { handleInfoCard(it) } @@ -403,7 +414,7 @@ class SetupGestureFragment: BaseSetupFragment(Fragm } InfoCard.SUCCESS -> { binding.setupGestureInfoCard.addRippleForeground() - viewLifecycleOwner.lifecycleScope.launchWhenResumed { + whenResumed { binding.setupGestureInfoCard.onClicked().collect { viewModel.onNextClicked() } diff --git a/app/src/main/java/com/kieronquinn/app/taptap/ui/screens/setup/info/SetupInfoFragment.kt b/app/src/main/java/com/kieronquinn/app/taptap/ui/screens/setup/info/SetupInfoFragment.kt index 0abfc514..46a7664a 100644 --- a/app/src/main/java/com/kieronquinn/app/taptap/ui/screens/setup/info/SetupInfoFragment.kt +++ b/app/src/main/java/com/kieronquinn/app/taptap/ui/screens/setup/info/SetupInfoFragment.kt @@ -7,7 +7,6 @@ import android.text.util.Linkify import android.view.View import androidx.core.view.WindowInsetsCompat import androidx.core.view.updatePadding -import androidx.lifecycle.lifecycleScope import com.kieronquinn.app.taptap.R import com.kieronquinn.app.taptap.databinding.FragmentSetupInfoBinding import com.kieronquinn.app.taptap.ui.base.ProvidesBack @@ -16,6 +15,7 @@ import com.kieronquinn.app.taptap.utils.extensions.applyBackgroundTint import com.kieronquinn.app.taptap.utils.extensions.isDarkMode import com.kieronquinn.app.taptap.utils.extensions.onApplyInsets import com.kieronquinn.app.taptap.utils.extensions.onClicked +import com.kieronquinn.app.taptap.utils.extensions.whenResumed import me.saket.bettermovementmethod.BetterLinkMovementMethod import org.koin.androidx.viewmodel.ext.android.viewModel @@ -65,13 +65,13 @@ class SetupInfoFragment: BaseSetupFragment(FragmentSet binding.toolbar.setupWithScrollableView(binding.setupInfoScrollable) } - private fun setupNext() = viewLifecycleOwner.lifecycleScope.launchWhenResumed { + private fun setupNext() = whenResumed { binding.setupInfoNext.onClicked().collect { viewModel.onNextClicked(requireContext()) } } - private fun setupSource() = viewLifecycleOwner.lifecycleScope.launchWhenResumed { + private fun setupSource() = whenResumed { binding.setupInfoCardSource.onClicked().collect { viewModel.onSourceClicked() } diff --git a/app/src/main/java/com/kieronquinn/app/taptap/ui/screens/setup/info/warning/SetupInfoWarningBottomSheetFragment.kt b/app/src/main/java/com/kieronquinn/app/taptap/ui/screens/setup/info/warning/SetupInfoWarningBottomSheetFragment.kt index bc70f6e3..07fdc401 100644 --- a/app/src/main/java/com/kieronquinn/app/taptap/ui/screens/setup/info/warning/SetupInfoWarningBottomSheetFragment.kt +++ b/app/src/main/java/com/kieronquinn/app/taptap/ui/screens/setup/info/warning/SetupInfoWarningBottomSheetFragment.kt @@ -4,14 +4,12 @@ import android.os.Bundle import android.view.View import androidx.core.view.WindowInsetsCompat import androidx.core.view.updatePadding -import androidx.lifecycle.lifecycleScope import com.kieronquinn.app.taptap.R -import com.kieronquinn.app.taptap.databinding.FragmentSettingsSharedNoRootBinding import com.kieronquinn.app.taptap.databinding.FragmentSetupInfoWarningBinding import com.kieronquinn.app.taptap.ui.base.BaseBottomSheetFragment import com.kieronquinn.app.taptap.utils.extensions.onApplyInsets import com.kieronquinn.app.taptap.utils.extensions.onClicked -import kotlinx.coroutines.flow.collect +import com.kieronquinn.app.taptap.utils.extensions.whenResumed class SetupInfoWarningBottomSheetFragment: BaseBottomSheetFragment(FragmentSetupInfoWarningBinding::inflate) { @@ -35,7 +33,7 @@ class SetupInfoWarningBottomSheetFragment: BaseBottomSheetFragment(FragmentSetupLandingBinding::inflate) { @@ -26,13 +25,13 @@ class SetupLandingFragment: BaseSetupFragment(Fragm binding.setupLandingSkipSetup.setTextColor(accent) } - private fun setupSkip() = viewLifecycleOwner.lifecycleScope.launchWhenResumed { + private fun setupSkip() = whenResumed { binding.setupLandingSkipSetup.onClicked().collect { viewModel.onSkipClicked() } } - private fun setupGetStarted() = viewLifecycleOwner.lifecycleScope.launchWhenResumed { + private fun setupGetStarted() = whenResumed { binding.setupLandingGetStarted.onClicked().collect { viewModel.onStartClicked() } diff --git a/app/src/main/java/com/kieronquinn/app/taptap/ui/screens/setup/notifications/SetupNotificationsFragment.kt b/app/src/main/java/com/kieronquinn/app/taptap/ui/screens/setup/notifications/SetupNotificationsFragment.kt index 89d60bfc..80fc721c 100644 --- a/app/src/main/java/com/kieronquinn/app/taptap/ui/screens/setup/notifications/SetupNotificationsFragment.kt +++ b/app/src/main/java/com/kieronquinn/app/taptap/ui/screens/setup/notifications/SetupNotificationsFragment.kt @@ -4,12 +4,12 @@ import android.content.res.ColorStateList import android.os.Bundle import android.view.View import androidx.activity.result.contract.ActivityResultContracts -import androidx.lifecycle.lifecycleScope import com.kieronquinn.app.taptap.databinding.FragmentSetupNotificationsBinding import com.kieronquinn.app.taptap.ui.base.ProvidesBack import com.kieronquinn.app.taptap.ui.screens.setup.base.BaseSetupFragment import com.kieronquinn.app.taptap.utils.extensions.onClicked import com.kieronquinn.app.taptap.utils.extensions.replaceColour +import com.kieronquinn.app.taptap.utils.extensions.whenResumed import org.koin.androidx.viewmodel.ext.android.viewModel class SetupNotificationsFragment: BaseSetupFragment(FragmentSetupNotificationsBinding::inflate), ProvidesBack { @@ -54,7 +54,7 @@ class SetupNotificationsFragment: BaseSetupFragment(this).iApplicationThread } + +@SuppressLint("UnspecifiedRegisterReceiverFlag") +fun Context.registerReceiverCompat( + receiver: BroadcastReceiver?, + intentFilter: IntentFilter +): Intent? { + return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + registerReceiver(receiver, intentFilter, RECEIVER_EXPORTED) + }else{ + registerReceiver(receiver, intentFilter) + } +} diff --git a/app/src/main/java/com/kieronquinn/app/taptap/utils/extensions/Extensions+ContextHub.kt b/app/src/main/java/com/kieronquinn/app/taptap/utils/extensions/Extensions+ContextHub.kt index 46393a82..dad77daf 100644 --- a/app/src/main/java/com/kieronquinn/app/taptap/utils/extensions/Extensions+ContextHub.kt +++ b/app/src/main/java/com/kieronquinn/app/taptap/utils/extensions/Extensions+ContextHub.kt @@ -17,7 +17,10 @@ val Context.canEnableContextHubLogging: Boolean fun ContextHub_hasColumbusNanoApp(): Boolean { val preloadedNanoAppsFile = File("/system/vendor/etc/chre", "preloaded_nanoapps.json") - if(!preloadedNanoAppsFile.exists()) return false + if(!preloadedNanoAppsFile.exists()) { + //Fallback for if the file does not exist + return File("/system/vendor/etc/chre/columbus.so").exists() + } return try { val root = JSONObject(preloadedNanoAppsFile.readText()) val nanoApps = root.getJSONArray("nanoapps") ?: return false diff --git a/app/src/main/java/com/kieronquinn/app/taptap/utils/extensions/Extensions+Lifecycle.kt b/app/src/main/java/com/kieronquinn/app/taptap/utils/extensions/Extensions+Lifecycle.kt index d8c71e5b..5701be7c 100644 --- a/app/src/main/java/com/kieronquinn/app/taptap/utils/extensions/Extensions+Lifecycle.kt +++ b/app/src/main/java/com/kieronquinn/app/taptap/utils/extensions/Extensions+Lifecycle.kt @@ -2,7 +2,14 @@ package com.kieronquinn.app.taptap.utils.extensions import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleObserver +import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.OnLifecycleEvent +import androidx.lifecycle.coroutineScope +import androidx.lifecycle.lifecycleScope +import androidx.lifecycle.repeatOnLifecycle +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Job +import kotlinx.coroutines.launch fun Lifecycle.runOnDestroy(block: () -> Unit) { addObserver(object: LifecycleObserver { @@ -11,4 +18,36 @@ fun Lifecycle.runOnDestroy(block: () -> Unit) { block() } }) +} + +fun LifecycleOwner.whenResumed(block: suspend CoroutineScope.() -> Unit): Job { + return lifecycleScope.launch { + lifecycle.repeatOnLifecycle(Lifecycle.State.RESUMED) { + block() + } + } +} + +fun LifecycleOwner.whenCreated(block: suspend CoroutineScope.() -> Unit): Job { + return lifecycleScope.launch { + lifecycle.repeatOnLifecycle(Lifecycle.State.CREATED) { + block() + } + } +} + +fun Lifecycle.whenResumed(block: suspend CoroutineScope.() -> Unit): Job { + return coroutineScope.launch { + repeatOnLifecycle(Lifecycle.State.RESUMED) { + block() + } + } +} + +fun Lifecycle.whenCreated(block: suspend CoroutineScope.() -> Unit): Job { + return coroutineScope.launch { + repeatOnLifecycle(Lifecycle.State.CREATED) { + block() + } + } } \ No newline at end of file diff --git a/app/src/main/java/com/kieronquinn/app/taptap/utils/extensions/Extensions+Locale.kt b/app/src/main/java/com/kieronquinn/app/taptap/utils/extensions/Extensions+Locale.kt new file mode 100644 index 00000000..73a61fea --- /dev/null +++ b/app/src/main/java/com/kieronquinn/app/taptap/utils/extensions/Extensions+Locale.kt @@ -0,0 +1,7 @@ +package com.kieronquinn.app.taptap.utils.extensions + +import android.util.LayoutDirection +import androidx.core.text.layoutDirection +import java.util.Locale + +fun isRtl() = Locale.getDefault().layoutDirection == LayoutDirection.RTL \ No newline at end of file diff --git a/app/src/main/java/com/kieronquinn/app/taptap/utils/extensions/Extensions+Navigation.kt b/app/src/main/java/com/kieronquinn/app/taptap/utils/extensions/Extensions+Navigation.kt index a0ff279b..a24a98cf 100644 --- a/app/src/main/java/com/kieronquinn/app/taptap/utils/extensions/Extensions+Navigation.kt +++ b/app/src/main/java/com/kieronquinn/app/taptap/utils/extensions/Extensions+Navigation.kt @@ -1,5 +1,7 @@ package com.kieronquinn.app.taptap.utils.extensions +import android.annotation.SuppressLint +import androidx.activity.OnBackPressedCallback import androidx.navigation.NavController import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.flow.callbackFlow @@ -17,7 +19,14 @@ fun NavController.onDestinationChanged() = callbackFlow { } } +@SuppressLint("RestrictedApi") fun NavController.hasBackAvailable(): Boolean { //Seems to include the root - return backQueue.size > 2 + return currentBackStack.value.size > 2 +} + +fun NavController.setOnBackPressedCallback(callback: OnBackPressedCallback) { + NavController::class.java.getDeclaredField("onBackPressedCallback").apply { + isAccessible = true + }.set(this, callback) } \ No newline at end of file diff --git a/app/src/main/java/com/kieronquinn/app/taptap/utils/extensions/Extensions+Service.kt b/app/src/main/java/com/kieronquinn/app/taptap/utils/extensions/Extensions+Service.kt new file mode 100644 index 00000000..cb5ad8e7 --- /dev/null +++ b/app/src/main/java/com/kieronquinn/app/taptap/utils/extensions/Extensions+Service.kt @@ -0,0 +1,24 @@ +package com.kieronquinn.app.taptap.utils.extensions + +import android.app.Notification +import android.app.Service +import android.content.pm.ServiceInfo +import android.os.Build + +fun Service.startForegroundCompat(notificationId: Int, notification: Notification): Boolean { + return try { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) { + startForeground( + notificationId, + notification, + ServiceInfo.FOREGROUND_SERVICE_TYPE_CONNECTED_DEVICE + ) + }else{ + startForeground(notificationId, notification) + } + true + }catch (e: Exception) { + //Caches ForegroundServiceStartNotAllowedException on S+ when unable to startForeground + false + } +} \ No newline at end of file diff --git a/app/src/main/java/com/kieronquinn/app/taptap/utils/extensions/Extensions+View.kt b/app/src/main/java/com/kieronquinn/app/taptap/utils/extensions/Extensions+View.kt index 44ded891..a651d7ac 100644 --- a/app/src/main/java/com/kieronquinn/app/taptap/utils/extensions/Extensions+View.kt +++ b/app/src/main/java/com/kieronquinn/app/taptap/utils/extensions/Extensions+View.kt @@ -98,7 +98,7 @@ fun View.delayPreDrawUntilFlow(flow: Flow, lifecycle: Lifecycle) { removeListener() } viewTreeObserver.addOnPreDrawListener(listener) - lifecycle.coroutineScope.launchWhenResumed { + lifecycle.whenResumed { flow.collect { if(!it) return@collect removeListener() diff --git a/app/src/main/res/drawable/ic_action_tasker.xml b/app/src/main/res/drawable/ic_action_tasker.xml index 4cee0ae7..b013fcbe 100644 --- a/app/src/main/res/drawable/ic_action_tasker.xml +++ b/app/src/main/res/drawable/ic_action_tasker.xml @@ -1,21 +1,24 @@ - + android:name="path" + android:pathData="M 12 21.992 C 11.129 21.992 10.259 21.878 9.411 21.651 C 9.322 21.627 9.241 21.578 9.177 21.511 C 9.114 21.443 9.07 21.359 9.052 21.268 L 8.791 20.008 C 8.772 19.911 8.782 19.811 8.819 19.72 C 8.857 19.628 8.92 19.55 9.002 19.495 L 12.721 16.985 C 12.778 16.946 12.843 16.919 12.911 16.906 C 15.281 16.467 16.996 14.41 17 12 C 16.994 11.144 16.771 10.304 16.349 9.56 C 16.309 9.491 16.287 9.413 16.284 9.333 C 16.281 9.253 16.297 9.174 16.33 9.102 L 18.203 5.094 C 18.232 5.031 18.273 4.976 18.325 4.93 C 18.376 4.884 18.437 4.85 18.502 4.828 L 18.557 4.81 C 18.645 4.782 18.739 4.778 18.828 4.8 C 18.918 4.821 19 4.867 19.065 4.932 C 20.306 6.174 21.199 7.719 21.653 9.414 C 21.678 9.504 21.676 9.599 21.65 9.688 C 21.623 9.778 21.572 9.858 21.502 9.919 L 19.935 11.313 C 19.974 11.769 19.974 12.226 19.935 12.682 L 21.502 14.081 C 21.572 14.142 21.622 14.222 21.649 14.311 C 21.676 14.399 21.677 14.494 21.653 14.583 C 21.199 16.279 20.306 17.824 19.065 19.065 C 18.999 19.131 18.917 19.177 18.827 19.199 C 18.737 19.22 18.642 19.217 18.554 19.188 L 16.565 18.529 C 16.188 18.792 15.79 19.022 15.375 19.216 L 14.948 21.268 C 14.929 21.359 14.886 21.443 14.822 21.511 C 14.759 21.578 14.678 21.627 14.588 21.651 C 13.741 21.878 12.87 21.992 12 21.992 Z M 12 20.992 C 12.685 20.992 13.367 20.881 14.039 20.724 L 14.44 18.797 C 14.456 18.718 14.491 18.644 14.543 18.581 C 14.594 18.519 14.66 18.469 14.734 18.438 C 15.26 18.215 15.758 17.929 16.213 17.586 C 16.278 17.537 16.353 17.505 16.433 17.492 C 16.513 17.479 16.595 17.485 16.672 17.511 L 18.497 18.115 C 19.445 17.104 20.146 15.897 20.547 14.571 L 19.107 13.284 C 19.046 13.231 19 13.163 18.971 13.088 C 18.943 13.013 18.933 12.932 18.942 12.852 C 19.012 12.285 19.012 11.713 18.942 11.146 C 18.933 11.066 18.942 10.984 18.971 10.908 C 18.999 10.833 19.046 10.765 19.107 10.711 L 20.547 9.432 C 20.193 8.264 19.525 7.24 18.742 6.307 L 17.302 9.383 C 17.708 10.202 17.995 11.081 18 11.998 C 18 11.998 18 11.999 18 12 C 17.994 14.826 16.002 17.238 13.255 17.831 L 9.838 20.136 L 9.961 20.724 C 10.632 20.881 11.315 20.992 12 20.992 Z" + android:fillColor="#000" + android:strokeWidth="1"/> + android:name="path_1" + android:pathData="M 17.643 3.928 L 7.094 11.049 L 9.846 12.602 L 6.357 20.072 L 16.908 12.955 L 14.154 11.4 L 16.881 5.562 Z" + android:fillColor="#000" + android:strokeWidth="1" + android:fillType="evenOdd"/> - - + android:name="path_2" + android:pathData="M 5.443 19.19 C 5.355 19.219 5.261 19.222 5.171 19.201 C 5.082 19.179 5 19.133 4.935 19.068 C 3.694 17.827 2.801 16.282 2.346 14.586 C 2.322 14.496 2.323 14.401 2.35 14.312 C 2.376 14.223 2.428 14.143 2.497 14.081 L 4.065 12.688 C 4.026 12.231 4.026 11.774 4.065 11.318 L 2.497 9.919 C 2.428 9.858 2.377 9.778 2.351 9.689 C 2.324 9.601 2.322 9.506 2.346 9.417 C 2.801 7.721 3.694 6.176 4.935 4.935 C 5 4.869 5.083 4.823 5.173 4.801 C 5.263 4.78 5.357 4.784 5.445 4.813 L 7.435 5.471 C 7.811 5.209 8.209 4.978 8.625 4.784 L 9.052 2.732 C 9.071 2.641 9.114 2.557 9.177 2.489 C 9.241 2.422 9.322 2.373 9.411 2.349 C 10.259 2.122 11.13 2.008 12 2.008 C 12.87 2.008 13.741 2.122 14.588 2.349 C 14.678 2.373 14.759 2.422 14.822 2.489 C 14.886 2.557 14.929 2.641 14.948 2.732 L 15.208 3.992 C 15.228 4.089 15.219 4.19 15.181 4.282 C 15.144 4.374 15.08 4.453 14.997 4.508 L 11.279 7.016 C 11.221 7.055 11.157 7.081 11.088 7.094 C 8.72 7.533 7.005 9.588 7 11.997 L 7 12 C 7.005 12.856 7.228 13.696 7.651 14.44 C 7.69 14.51 7.713 14.587 7.716 14.667 C 7.719 14.747 7.703 14.826 7.669 14.899 L 5.797 18.906 C 5.768 18.969 5.726 19.025 5.675 19.07 C 5.623 19.116 5.563 19.151 5.497 19.172 Z M 5.26 17.695 L 6.698 14.617 C 6.292 13.799 6.005 12.919 6 12.003 C 6 12.002 6 12.001 6 12 C 6.005 9.174 7.998 6.762 10.745 6.169 L 14.161 3.865 L 14.039 3.276 C 13.367 3.119 12.685 3.008 12 3.008 C 11.315 3.008 10.633 3.119 9.961 3.276 L 9.56 5.203 C 9.543 5.282 9.508 5.356 9.457 5.419 C 9.406 5.482 9.34 5.531 9.266 5.562 C 8.74 5.786 8.242 6.071 7.786 6.414 C 7.722 6.463 7.646 6.495 7.566 6.508 C 7.487 6.521 7.405 6.515 7.328 6.49 L 5.503 5.885 C 4.554 6.896 3.854 8.103 3.453 9.43 L 4.893 10.716 C 4.953 10.77 5 10.837 5.028 10.912 C 5.057 10.987 5.067 11.068 5.057 11.148 C 4.988 11.715 4.988 12.287 5.057 12.854 C 5.067 12.934 5.057 13.016 5.029 13.092 C 5 13.168 4.954 13.235 4.893 13.289 L 3.453 14.568 C 3.807 15.738 4.476 16.762 5.26 17.695 Z" + android:fillColor="#000" + android:strokeWidth="1"/> diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 33b49319..ef5fa7c5 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -3,13 +3,16 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" + xmlns:app="http://schemas.android.com/apk/res-auto" android:orientation="vertical" tools:context=".MainActivity"> + android:name="androidx.navigation.fragment.NavHostFragment" + app:defaultNavHost="true" + app:navGraph="@navigation/nav_graph_activity" /> \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_container.xml b/app/src/main/res/layout/fragment_container.xml index 202bd6b5..13bd1493 100644 --- a/app/src/main/res/layout/fragment_container.xml +++ b/app/src/main/res/layout/fragment_container.xml @@ -18,7 +18,7 @@ @@ -46,6 +46,7 @@ android:name="androidx.navigation.fragment.NavHostFragment" android:layout_width="match_parent" android:layout_height="wrap_content" + app:defaultNavHost="true" app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior" app:navGraph="@navigation/nav_graph_container" /> diff --git a/app/src/main/res/layout/fragment_setup_gesture.xml b/app/src/main/res/layout/fragment_setup_gesture.xml index cc12eac7..25fc5a61 100644 --- a/app/src/main/res/layout/fragment_setup_gesture.xml +++ b/app/src/main/res/layout/fragment_setup_gesture.xml @@ -167,6 +167,7 @@ android:name="androidx.navigation.fragment.NavHostFragment" android:layout_width="match_parent" android:layout_height="match_parent" + app:defaultNavHost="true" app:navGraph="@navigation/nav_graph_setup_gesture" /> diff --git a/app/src/main/res/navigation/nav_graph_activity.xml b/app/src/main/res/navigation/nav_graph_activity.xml new file mode 100644 index 00000000..e94cad3e --- /dev/null +++ b/app/src/main/res/navigation/nav_graph_activity.xml @@ -0,0 +1,11 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/navigation/nav_graph_root.xml b/app/src/main/res/navigation/nav_graph_root.xml index 5a20f343..78b63685 100644 --- a/app/src/main/res/navigation/nav_graph_root.xml +++ b/app/src/main/res/navigation/nav_graph_root.xml @@ -11,19 +11,24 @@ android:label="DecisionFragment" > + app:destination="@id/nav_graph_setup" + app:popUpTo="@id/nav_graph_root"/> + app:destination="@id/nav_graph_settings" + app:popUpTo="@id/nav_graph_root" /> + app:destination="@id/setupUpgradeFragment" + app:popUpTo="@id/nav_graph_root" /> + app:destination="@id/noGyroscopeFragment" + app:popUpTo="@id/nav_graph_root" /> + app:destination="@id/disableColumbusFragment" + app:popUpTo="@id/nav_graph_root" /> diff --git a/app/src/main/res/values-land/dimens.xml b/app/src/main/res/values-land/dimens.xml index 7d9a0768..170fc747 100644 --- a/app/src/main/res/values-land/dimens.xml +++ b/app/src/main/res/values-land/dimens.xml @@ -1,4 +1,5 @@ 0dp + 88dp \ No newline at end of file diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml index 36ba01e8..32d68f4a 100644 --- a/app/src/main/res/values/dimens.xml +++ b/app/src/main/res/values/dimens.xml @@ -2,6 +2,7 @@ 8dp 16dp + 179dp 36dp 16dp 80dp diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml index 84dacfa1..f3917294 100644 --- a/app/src/main/res/values/themes.xml +++ b/app/src/main/res/values/themes.xml @@ -62,7 +62,7 @@