@@ -23,22 +23,29 @@ import android.view.KeyEvent
2323
2424import  com.buzbuz.smartautoclicker.core.base.AndroidExecutor 
2525import  com.buzbuz.smartautoclicker.core.bitmaps.IBitmapManager 
26+ import  com.buzbuz.smartautoclicker.core.common.overlays.manager.OverlayManager 
2627import  com.buzbuz.smartautoclicker.core.display.DisplayMetrics 
2728import  com.buzbuz.smartautoclicker.core.domain.model.scenario.Scenario 
2829import  com.buzbuz.smartautoclicker.core.dumb.domain.model.DumbScenario 
2930import  com.buzbuz.smartautoclicker.core.dumb.engine.DumbEngine 
3031import  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  
3233import  com.buzbuz.smartautoclicker.feature.smart.config.ui.MainMenu 
3334import  com.buzbuz.smartautoclicker.feature.dumb.config.ui.DumbMainMenu 
3435import  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
3640import  kotlinx.coroutines.CoroutineScope 
3741import  kotlinx.coroutines.Dispatchers 
3842import  kotlinx.coroutines.Job 
3943import  kotlinx.coroutines.SupervisorJob 
4044import  kotlinx.coroutines.cancel 
4145import  kotlinx.coroutines.delay 
46+ import  kotlinx.coroutines.flow.combine 
47+ import  kotlinx.coroutines.flow.launchIn 
48+ import  kotlinx.coroutines.flow.onEach 
4249import  kotlinx.coroutines.launch 
4350
4451class  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