Skip to content

Commit 1fa008c

Browse files
committed
Revamp notification actions
1 parent 2730cd7 commit 1fa008c

File tree

12 files changed

+370
-117
lines changed

12 files changed

+370
-117
lines changed

core/common/overlays/src/main/java/com/buzbuz/smartautoclicker/core/common/overlays/manager/LifecycleStatesRegistry.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,5 +43,9 @@ internal class LifecycleStatesRegistry {
4343
return states
4444
}
4545

46+
fun clearStates() {
47+
overlaysLifecycleState.clear()
48+
}
49+
4650
fun haveStates(): Boolean = overlaysLifecycleState.isNotEmpty()
4751
}

core/common/overlays/src/main/java/com/buzbuz/smartautoclicker/core/common/overlays/manager/OverlayManager.kt

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,11 @@ import android.content.Context
2020
import android.graphics.Point
2121
import android.util.Log
2222
import android.view.KeyEvent
23-
2423
import androidx.lifecycle.Lifecycle
24+
2525
import com.buzbuz.smartautoclicker.core.base.Dumpable
2626
import com.buzbuz.smartautoclicker.core.base.addDumpTabulationLvl
2727
import com.buzbuz.smartautoclicker.core.common.overlays.base.BaseOverlay
28-
2928
import com.buzbuz.smartautoclicker.core.display.DisplayMetrics
3029
import com.buzbuz.smartautoclicker.core.common.overlays.base.Overlay
3130
import com.buzbuz.smartautoclicker.core.common.overlays.manager.navigation.OverlayNavigationRequest
@@ -72,6 +71,8 @@ class OverlayManager @Inject internal constructor(
7271
/** Notifies the caller of [navigateUpToRoot] once the all overlays above the root are destroyed. */
7372
private var navigateUpToRootCompletionListener: (() -> Unit)? = null
7473

74+
var onVisibilityChangedListener: (() -> Unit)? = null
75+
7576
/** Flow on the top of the overlay stack. Null if the stack is empty. */
7677
val backStackTop: Flow<Overlay?> = isNavigating
7778
.filter { navigating -> !navigating }
@@ -129,6 +130,7 @@ class OverlayManager @Inject internal constructor(
129130
Log.d(TAG, "Close all overlays (${overlayBackStack.size}, currently navigating: ${isNavigating.value}")
130131

131132
overlayNavigationRequestStack.clear()
133+
lifecyclesRegistry.clearStates()
132134
topOverlay?.destroy()
133135
repeat(overlayBackStack.size) {
134136
overlayNavigationRequestStack.push(OverlayNavigationRequest.NavigateUp)
@@ -158,6 +160,8 @@ class OverlayManager @Inject internal constructor(
158160
lifecyclesRegistry.saveStates(overlayBackStack.toList())
159161
// Hide from top to bottom of the stack
160162
overlayBackStack.forEachReversed { it.hide() }
163+
164+
onVisibilityChangedListener?.invoke()
161165
}
162166

163167
/**
@@ -185,6 +189,8 @@ class OverlayManager @Inject internal constructor(
185189

186190
} ?: Log.w(TAG, "State for overlay ${overlay.hashCode()} not found, can't restore state")
187191
}
192+
193+
onVisibilityChangedListener?.invoke()
188194
}
189195

190196
/** @return true if the overlay stack has been hidden via [hideAll], false if not. */

core/common/quality/src/main/java/com/buzbuz/smartautoclicker/core/common/quality/domain/Quality.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ package com.buzbuz.smartautoclicker.core.common.quality.domain
1919
import kotlin.time.Duration
2020
import kotlin.time.Duration.Companion.hours
2121
import kotlin.time.Duration.Companion.minutes
22-
import kotlin.time.Duration.Companion.seconds
2322

2423
/** Describe the different quality levels felt by the user. */
2524
sealed class Quality(internal val backToHighDelay: Duration? = null) {

core/smart/processing/src/main/java/com/buzbuz/smartautoclicker/core/processing/domain/DetectionRepository.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import com.buzbuz.smartautoclicker.core.domain.model.condition.ImageCondition
3232
import com.buzbuz.smartautoclicker.core.domain.model.event.ImageEvent
3333
import com.buzbuz.smartautoclicker.core.domain.model.scenario.Scenario
3434
import com.buzbuz.smartautoclicker.core.processing.data.DetectorEngine
35+
import com.buzbuz.smartautoclicker.core.processing.data.DetectorState
3536
import com.buzbuz.smartautoclicker.core.processing.domain.trying.ImageConditionProcessingTryListener
3637
import com.buzbuz.smartautoclicker.core.processing.domain.trying.ImageConditionTry
3738
import com.buzbuz.smartautoclicker.core.processing.domain.trying.ImageEventProcessingTryListener
@@ -103,6 +104,9 @@ class DetectionRepository @Inject constructor(
103104

104105
fun getScenarioId(): Identifier? = _scenarioId.value
105106

107+
fun isRunning(): Boolean =
108+
detectorEngine.state.value == DetectorState.DETECTING
109+
106110
fun startScreenRecord(
107111
context: Context,
108112
resultCode: Int,

smartautoclicker/src/main/java/com/buzbuz/smartautoclicker/LocalService.kt

Lines changed: 95 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -23,22 +23,29 @@ import android.view.KeyEvent
2323

2424
import com.buzbuz.smartautoclicker.core.base.AndroidExecutor
2525
import com.buzbuz.smartautoclicker.core.bitmaps.IBitmapManager
26+
import com.buzbuz.smartautoclicker.core.common.overlays.manager.OverlayManager
2627
import com.buzbuz.smartautoclicker.core.display.DisplayMetrics
2728
import com.buzbuz.smartautoclicker.core.domain.model.scenario.Scenario
2829
import com.buzbuz.smartautoclicker.core.dumb.domain.model.DumbScenario
2930
import com.buzbuz.smartautoclicker.core.dumb.engine.DumbEngine
3031
import com.buzbuz.smartautoclicker.core.processing.domain.DetectionRepository
31-
import com.buzbuz.smartautoclicker.core.common.overlays.manager.OverlayManager
32+
import com.buzbuz.smartautoclicker.core.processing.domain.DetectionState
3233
import com.buzbuz.smartautoclicker.feature.smart.config.ui.MainMenu
3334
import com.buzbuz.smartautoclicker.feature.dumb.config.ui.DumbMainMenu
3435
import com.buzbuz.smartautoclicker.feature.qstile.domain.QSTileRepository
36+
import com.buzbuz.smartautoclicker.feature.revenue.IRevenueRepository
37+
import com.buzbuz.smartautoclicker.feature.revenue.UserBillingState
38+
import com.buzbuz.smartautoclicker.feature.smart.debugging.domain.DebuggingRepository
3539

3640
import kotlinx.coroutines.CoroutineScope
3741
import kotlinx.coroutines.Dispatchers
3842
import kotlinx.coroutines.Job
3943
import kotlinx.coroutines.SupervisorJob
4044
import kotlinx.coroutines.cancel
4145
import kotlinx.coroutines.delay
46+
import kotlinx.coroutines.flow.combine
47+
import kotlinx.coroutines.flow.launchIn
48+
import kotlinx.coroutines.flow.onEach
4249
import kotlinx.coroutines.launch
4350

4451
class LocalService(
@@ -48,22 +55,44 @@ class LocalService(
4855
private val detectionRepository: DetectionRepository,
4956
private val bitmapManager: IBitmapManager,
5057
private val dumbEngine: DumbEngine,
51-
val tileRepository: QSTileRepository,
58+
private val tileRepository: QSTileRepository,
59+
private val revenueRepository: IRevenueRepository,
60+
private val debugRepository: DebuggingRepository,
5261
private val androidExecutor: AndroidExecutor,
5362
private val onStart: (isSmart: Boolean, name: String) -> Unit,
5463
private val onStop: () -> Unit,
64+
onStateChanged: (isRunning: Boolean, isMenuHidden: Boolean) -> Unit,
5565
) : SmartAutoClickerService.ILocalService {
5666

5767
/** Scope for this LocalService. */
5868
private val serviceScope: CoroutineScope = CoroutineScope(Dispatchers.Main + SupervisorJob())
5969
/** Coroutine job for the delayed start of engine & ui. */
6070
private var startJob: Job? = null
71+
/** Coroutine job for the paywall result upon start from notification. */
72+
private var paywallResultJob: Job? = null
73+
74+
/** State of this LocalService. */
75+
private var state: LocalServiceState = LocalServiceState(isStarted = false, isSmartLoaded = false)
6176
/** True if the overlay is started, false if not. */
62-
internal var isStarted: Boolean = false
77+
internal val isStarted: Boolean
78+
get() = state.isStarted
79+
80+
init {
81+
combine(dumbEngine.isRunning, detectionRepository.detectionState) { dumbIsRunning, smartState ->
82+
dumbIsRunning || smartState == DetectionState.DETECTING
83+
}.onEach { onStateChanged(it, overlayManager.isStackHidden()) }.launchIn(serviceScope)
84+
85+
overlayManager.onVisibilityChangedListener = {
86+
onStateChanged(
87+
dumbEngine.isRunning.value || detectionRepository.isRunning(),
88+
overlayManager.isStackHidden()
89+
)
90+
}
91+
}
6392

6493
override fun startDumbScenario(dumbScenario: DumbScenario) {
65-
if (isStarted) return
66-
isStarted = true
94+
if (state.isStarted) return
95+
state = LocalServiceState(isStarted = true, isSmartLoaded = false)
6796
onStart(false, dumbScenario.name)
6897

6998
displayMetrics.startMonitoring(context)
@@ -96,7 +125,7 @@ class LocalService(
96125
*/
97126
override fun startSmartScenario(resultCode: Int, data: Intent, scenario: Scenario) {
98127
if (isStarted) return
99-
isStarted = true
128+
state = LocalServiceState(isStarted = true, isSmartLoaded = true)
100129
onStart(true, scenario.name)
101130

102131
displayMetrics.startMonitoring(context)
@@ -123,9 +152,63 @@ class LocalService(
123152
}
124153
}
125154

155+
override fun playAndHide() {
156+
serviceScope.launch {
157+
overlayManager.hideAll()
158+
159+
if (state.isSmartLoaded && !detectionRepository.isRunning()) {
160+
if (revenueRepository.userBillingState.value == UserBillingState.AD_REQUESTED) startPaywall()
161+
else startSmartScenario()
162+
} else if (!state.isSmartLoaded && !dumbEngine.isRunning.value) {
163+
dumbEngine.startDumbScenario()
164+
}
165+
}
166+
}
167+
168+
private fun startPaywall() {
169+
revenueRepository.startPaywallUiFlow(context)
170+
171+
paywallResultJob = combine(revenueRepository.isBillingFlowInProgress, revenueRepository.userBillingState) { inProgress, state ->
172+
if (inProgress) return@combine
173+
174+
if (state != UserBillingState.AD_REQUESTED) startSmartScenario()
175+
paywallResultJob?.cancel()
176+
paywallResultJob = null
177+
}.launchIn(serviceScope)
178+
}
179+
180+
private fun startSmartScenario() {
181+
serviceScope.launch {
182+
detectionRepository.startDetection(
183+
context,
184+
debugRepository.getDebugDetectionListenerIfNeeded(context),
185+
revenueRepository.consumeTrial(),
186+
)
187+
}
188+
}
189+
190+
override fun pauseAndShow() {
191+
serviceScope.launch {
192+
when {
193+
dumbEngine.isRunning.value -> dumbEngine.stopDumbScenario()
194+
detectionRepository.isRunning() -> detectionRepository.stopDetection()
195+
}
196+
197+
overlayManager.restoreVisibility()
198+
}
199+
}
200+
201+
override fun hide() {
202+
overlayManager.hideAll()
203+
}
204+
205+
override fun show() {
206+
overlayManager.restoreVisibility()
207+
}
208+
126209
override fun stop() {
127210
if (!isStarted) return
128-
isStarted = false
211+
state = LocalServiceState(isStarted = false, isSmartLoaded = false)
129212

130213
serviceScope.launch {
131214
startJob?.join()
@@ -149,14 +232,9 @@ class LocalService(
149232
event ?: return false
150233
return overlayManager.propagateKeyEvent(event)
151234
}
235+
}
152236

153-
fun toggleOverlaysVisibility() {
154-
overlayManager.apply {
155-
if (isStackHidden()) {
156-
restoreVisibility()
157-
} else {
158-
hideAll()
159-
}
160-
}
161-
}
162-
}
237+
private data class LocalServiceState(
238+
val isStarted: Boolean,
239+
val isSmartLoaded: Boolean
240+
)

0 commit comments

Comments
 (0)