Skip to content

Commit 2aabf9b

Browse files
committed
Improve managers to use instances and improve context handling
1 parent 5957eae commit 2aabf9b

26 files changed

+319
-277
lines changed

app/src/main/java/com/wstxda/toolkit/base/BaseTileService.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import android.app.PendingIntent
55
import android.content.Intent
66
import android.os.Build
77
import android.service.quicksettings.TileService
8+
import androidx.annotation.CallSuper
89
import kotlinx.coroutines.CoroutineScope
910
import kotlinx.coroutines.Dispatchers
1011
import kotlinx.coroutines.SupervisorJob
@@ -14,11 +15,13 @@ abstract class BaseTileService : TileService() {
1415

1516
protected val serviceScope = CoroutineScope(SupervisorJob() + Dispatchers.Main)
1617

18+
@CallSuper
1719
override fun onStartListening() {
1820
super.onStartListening()
1921
updateTile()
2022
}
2123

24+
@CallSuper
2225
override fun onDestroy() {
2326
super.onDestroy()
2427
serviceScope.cancel()

app/src/main/java/com/wstxda/toolkit/manager/audio/SoundModeManager.kt

Lines changed: 27 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -7,71 +7,64 @@ import android.content.Intent
77
import android.content.IntentFilter
88
import android.media.AudioManager
99
import android.os.Build
10-
import kotlinx.coroutines.flow.MutableStateFlow
11-
import kotlinx.coroutines.flow.asStateFlow
10+
import kotlinx.coroutines.channels.awaitClose
11+
import kotlinx.coroutines.flow.Flow
12+
import kotlinx.coroutines.flow.callbackFlow
13+
import kotlinx.coroutines.flow.distinctUntilChanged
1214

13-
object SoundModeManager {
15+
class SoundModeManager(private val context: Context) {
1416

15-
private lateinit var audioManager: AudioManager
16-
private lateinit var notificationManager: NotificationManager
17+
private val audioManager = context.getSystemService(Context.AUDIO_SERVICE) as AudioManager
18+
private val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
1719

18-
private val _currentMode = MutableStateFlow(SoundMode.NORMAL)
19-
val currentMode = _currentMode.asStateFlow()
20+
val currentModeFlow: Flow<SoundMode> = callbackFlow {
21+
trySend(getCurrentModeInternal())
2022

21-
private val ringerModeReceiver = object : BroadcastReceiver() {
22-
override fun onReceive(context: Context, intent: Intent) {
23-
if (intent.action == AudioManager.RINGER_MODE_CHANGED_ACTION) {
24-
_currentMode.value = getCurrentModeInternal()
23+
val receiver = object : BroadcastReceiver() {
24+
override fun onReceive(context: Context, intent: Intent) {
25+
if (intent.action == AudioManager.RINGER_MODE_CHANGED_ACTION) {
26+
trySend(getCurrentModeInternal())
27+
}
2528
}
2629
}
27-
}
28-
29-
fun init(context: Context) {
30-
audioManager = context.getSystemService(Context.AUDIO_SERVICE) as AudioManager
31-
notificationManager =
32-
context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
33-
34-
_currentMode.value = getCurrentModeInternal()
3530

3631
context.registerReceiver(
37-
ringerModeReceiver,
32+
receiver,
3833
IntentFilter(AudioManager.RINGER_MODE_CHANGED_ACTION),
3934
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
4035
Context.RECEIVER_NOT_EXPORTED
4136
} else 0
4237
)
43-
}
38+
39+
awaitClose {
40+
try {
41+
context.unregisterReceiver(receiver)
42+
} catch (_: IllegalArgumentException) {
43+
}
44+
}
45+
}.distinctUntilChanged()
4446

4547
fun hasPermission(): Boolean {
46-
return if (::notificationManager.isInitialized) {
47-
notificationManager.isNotificationPolicyAccessGranted
48-
} else false
48+
return notificationManager.isNotificationPolicyAccessGranted
4949
}
5050

5151
fun cycleMode() {
5252
if (!hasPermission()) return
5353

54-
val newMode = when (_currentMode.value) {
54+
val current = getCurrentModeInternal()
55+
val newMode = when (current) {
5556
SoundMode.NORMAL -> SoundMode.VIBRATE
5657
SoundMode.VIBRATE -> SoundMode.SILENT
5758
SoundMode.SILENT -> SoundMode.NORMAL
5859
}
5960
audioManager.ringerMode = newMode.ringerMode
6061
}
6162

62-
private fun getCurrentModeInternal(): SoundMode {
63-
if (!::audioManager.isInitialized) return SoundMode.NORMAL
63+
fun getCurrentModeInternal(): SoundMode {
6464
return when (audioManager.ringerMode) {
6565
AudioManager.RINGER_MODE_VIBRATE -> SoundMode.VIBRATE
6666
AudioManager.RINGER_MODE_SILENT -> SoundMode.SILENT
6767
else -> SoundMode.NORMAL
6868
}
6969
}
70-
71-
fun unregisterReceiver(context: Context) {
72-
try {
73-
context.unregisterReceiver(ringerModeReceiver)
74-
} catch (_: IllegalArgumentException) {
75-
}
76-
}
7770
}

app/src/main/java/com/wstxda/toolkit/manager/games/CoinFlipManager.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ package com.wstxda.toolkit.manager.games
22

33
import kotlin.random.Random
44

5-
object CoinFlipManager {
5+
class CoinFlipManager() {
66

77
var headsCount = 0
88
private set

app/src/main/java/com/wstxda/toolkit/manager/games/DiceRollManager.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ package com.wstxda.toolkit.manager.games
22

33
import kotlin.random.Random
44

5-
object DiceRollManager {
5+
class DiceRollManager() {
66

77
fun roll(): Int {
88
return Random.nextInt(1, 7)

app/src/main/java/com/wstxda/toolkit/manager/power/CaffeineManager.kt

Lines changed: 65 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,19 @@ import com.wstxda.toolkit.tiles.power.CaffeineTileService
1212
import kotlinx.coroutines.flow.MutableStateFlow
1313
import kotlinx.coroutines.flow.asStateFlow
1414

15-
object CaffeineManager {
15+
class CaffeineManager(context: Context) {
1616

17-
private const val PREF_NAME = "caffeine_prefs"
18-
private const val PREF_KEY_ORIGINAL = "original_timeout"
19-
private const val PREF_KEY_EXPECTED = "expected_timeout"
20-
private const val DEFAULT_TIMEOUT = 60000
17+
companion object {
18+
private const val PREF_NAME = "caffeine_prefs"
19+
private const val PREF_KEY_ORIGINAL = "original_timeout"
20+
private const val PREF_KEY_EXPECTED = "expected_timeout"
21+
private const val DEFAULT_TIMEOUT = 60000
22+
}
23+
24+
private val appContext = context.applicationContext
25+
private val _currentState = MutableStateFlow<CaffeineState>(CaffeineState.Off)
26+
val currentState = _currentState.asStateFlow()
27+
private var isReceiverRegistered = false
2128

2229
private val stateCycle = listOf(
2330
CaffeineState.Off,
@@ -28,134 +35,139 @@ object CaffeineManager {
2835
CaffeineState.Infinite
2936
)
3037

31-
private val _currentState = MutableStateFlow<CaffeineState>(CaffeineState.Off)
32-
val currentState = _currentState.asStateFlow()
33-
34-
private var isReceiverRegistered = false
3538
private val screenOffReceiver = object : BroadcastReceiver() {
3639
override fun onReceive(context: Context, intent: Intent) {
3740
if (intent.action == Intent.ACTION_SCREEN_OFF) {
38-
forceReset(context)
41+
restoreOriginalTimeout()
3942
}
4043
}
4144
}
4245

43-
fun synchronizeState(context: Context) {
44-
val prefs = getPrefs(context)
46+
fun synchronizeState() {
47+
val prefs = getPrefs()
4548
val expectedTimeout = prefs.getInt(PREF_KEY_EXPECTED, -1)
4649

4750
if (expectedTimeout != -1) {
48-
val systemTimeout = getSystemTimeout(context)
51+
val systemTimeout = getSystemTimeout()
52+
4953
if (systemTimeout != expectedTimeout) {
50-
forceReset(context)
54+
forceReset()
5155
} else {
5256
val restoredState =
5357
stateCycle.find { it.timeout == expectedTimeout } ?: CaffeineState.Off
5458
_currentState.value = restoredState
55-
toggleReceiver(context, true)
59+
toggleReceiver(true)
5660
}
5761
} else {
5862
_currentState.value = CaffeineState.Off
59-
toggleReceiver(context, false)
63+
toggleReceiver(false)
6064
}
6165
}
6266

63-
fun isPermissionGranted(context: Context): Boolean {
64-
return Settings.System.canWrite(context)
67+
fun isPermissionGranted(): Boolean {
68+
return Settings.System.canWrite(appContext)
6569
}
6670

67-
fun cycleState(context: Context) {
68-
if (!isPermissionGranted(context)) return
71+
fun cycleState() {
72+
if (!isPermissionGranted()) return
6973

7074
val currentIndex = stateCycle.indexOf(_currentState.value)
7175
val nextIndex = (currentIndex + 1) % stateCycle.size
7276
val nextState = stateCycle[nextIndex]
7377

74-
applyState(context, nextState)
78+
applyState(nextState)
7579
}
7680

77-
private fun applyState(context: Context, newState: CaffeineState) {
81+
fun cleanup() {
82+
try {
83+
if (isReceiverRegistered) {
84+
appContext.unregisterReceiver(screenOffReceiver)
85+
isReceiverRegistered = false
86+
}
87+
} catch (_: IllegalArgumentException) {
88+
}
89+
}
90+
91+
private fun applyState(newState: CaffeineState) {
7892
if (newState == CaffeineState.Off) {
79-
restoreOriginalTimeout(context)
93+
restoreOriginalTimeout()
8094
} else {
8195
if (_currentState.value == CaffeineState.Off) {
82-
saveOriginalTimeout(context)
96+
saveOriginalTimeout()
8397
}
84-
85-
if (setSystemTimeout(context, newState.timeout)) {
98+
if (setSystemTimeout(newState.timeout)) {
8699
_currentState.value = newState
87-
getPrefs(context).edit { putInt(PREF_KEY_EXPECTED, newState.timeout) }
88-
toggleReceiver(context, true)
100+
getPrefs().edit { putInt(PREF_KEY_EXPECTED, newState.timeout) }
101+
toggleReceiver(true)
89102
} else {
90-
forceReset(context)
103+
forceReset()
91104
}
92105
}
93-
requestTileUpdate(context)
106+
requestTileUpdate()
94107
}
95108

96-
private fun saveOriginalTimeout(context: Context) {
97-
val current = getSystemTimeout(context)
109+
private fun saveOriginalTimeout() {
110+
val current = getSystemTimeout()
98111
if (stateCycle.any { it.timeout == current && it != CaffeineState.Off }) {
99112
return
100113
}
101-
getPrefs(context).edit { putInt(PREF_KEY_ORIGINAL, current) }
114+
getPrefs().edit { putInt(PREF_KEY_ORIGINAL, current) }
102115
}
103116

104-
private fun restoreOriginalTimeout(context: Context) {
105-
val original = getPrefs(context).getInt(PREF_KEY_ORIGINAL, DEFAULT_TIMEOUT)
106-
setSystemTimeout(context, original)
107-
forceReset(context)
117+
private fun restoreOriginalTimeout() {
118+
val original = getPrefs().getInt(PREF_KEY_ORIGINAL, DEFAULT_TIMEOUT)
119+
setSystemTimeout(original)
120+
forceReset()
108121
}
109122

110-
private fun forceReset(context: Context) {
123+
private fun forceReset() {
111124
_currentState.value = CaffeineState.Off
112-
getPrefs(context).edit {
125+
getPrefs().edit {
113126
remove(PREF_KEY_EXPECTED)
114127
}
115-
toggleReceiver(context, false)
116-
requestTileUpdate(context)
128+
toggleReceiver(false)
129+
requestTileUpdate()
117130
}
118131

119-
private fun toggleReceiver(context: Context, enable: Boolean) {
132+
private fun toggleReceiver(enable: Boolean) {
120133
if (enable && !isReceiverRegistered) {
121-
context.applicationContext.registerReceiver(
134+
appContext.registerReceiver(
122135
screenOffReceiver, IntentFilter(Intent.ACTION_SCREEN_OFF)
123136
)
124137
isReceiverRegistered = true
125138
} else if (!enable && isReceiverRegistered) {
126139
try {
127-
context.applicationContext.unregisterReceiver(screenOffReceiver)
128-
} catch (_: Exception) {
140+
appContext.unregisterReceiver(screenOffReceiver)
141+
} catch (_: IllegalArgumentException) {
129142
}
130143
isReceiverRegistered = false
131144
}
132145
}
133146

134-
private fun getSystemTimeout(context: Context): Int {
147+
private fun getSystemTimeout(): Int {
135148
return try {
136-
Settings.System.getInt(context.contentResolver, Settings.System.SCREEN_OFF_TIMEOUT)
149+
Settings.System.getInt(appContext.contentResolver, Settings.System.SCREEN_OFF_TIMEOUT)
137150
} catch (_: Exception) {
138151
DEFAULT_TIMEOUT
139152
}
140153
}
141154

142-
private fun setSystemTimeout(context: Context, timeout: Int): Boolean {
155+
private fun setSystemTimeout(timeout: Int): Boolean {
143156
return try {
144157
Settings.System.putInt(
145-
context.contentResolver, Settings.System.SCREEN_OFF_TIMEOUT, timeout
158+
appContext.contentResolver, Settings.System.SCREEN_OFF_TIMEOUT, timeout
146159
)
147160
true
148161
} catch (_: Exception) {
149162
false
150163
}
151164
}
152165

153-
private fun requestTileUpdate(context: Context) {
166+
private fun requestTileUpdate() {
154167
TileService.requestListeningState(
155-
context, ComponentName(context, CaffeineTileService::class.java)
168+
appContext, ComponentName(appContext, CaffeineTileService::class.java)
156169
)
157170
}
158171

159-
private fun getPrefs(context: Context) =
160-
context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE)
172+
private fun getPrefs() = appContext.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE)
161173
}

app/src/main/java/com/wstxda/toolkit/manager/sensors/CompassManager.kt

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,17 +16,16 @@ import kotlin.math.abs
1616

1717
object CompassManager : SensorEventListener {
1818

19+
private var appContext: Context? = null
20+
private var lastHapticDegrees: Float? = null
21+
private var isSensorRegistered = false
22+
1923
private val _isActive = MutableStateFlow(false)
2024
val isActive = _isActive.asStateFlow()
2125

2226
private val _currentDegrees = MutableStateFlow(0f)
2327
val currentDegrees = _currentDegrees.asStateFlow()
2428

25-
private var appContext: Context? = null
26-
27-
private var lastHapticDegrees: Float? = null
28-
private var isSensorRegistered = false
29-
3029
private val sensorManager: SensorManager?
3130
get() = appContext?.getSystemService()
3231

0 commit comments

Comments
 (0)