Skip to content

Commit

Permalink
minor improvement
Browse files Browse the repository at this point in the history
  • Loading branch information
robinsrk committed Dec 9, 2024
1 parent 3207530 commit 0d5b2eb
Show file tree
Hide file tree
Showing 11 changed files with 160 additions and 29 deletions.
4 changes: 2 additions & 2 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ android {
applicationId = "dev.robin.flip_2_dnd"
minSdk = 23
targetSdk = 34
versionCode = 6
versionName = "1.0.6"
versionCode = 7
versionName = "1.0.7"
vectorDrawables {
useSupportLibrary = true
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,42 @@ import android.app.NotificationManager
import android.content.Context
import android.util.Log
import dev.robin.flip_2_dnd.domain.repository.DndRepository
import dev.robin.flip_2_dnd.domain.repository.SettingsRepository
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.runBlocking
import javax.inject.Inject
import javax.inject.Singleton

@Singleton
class DndRepositoryImpl @Inject constructor(
@ApplicationContext private val context: Context
@ApplicationContext private val context: Context,
private val settingsRepository: SettingsRepository
) : DndRepository {
private val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
private val _isDndEnabled = MutableStateFlow(false)
private val _dndMode = MutableStateFlow("All Notifications")

private val dndStateUpdateJob: Job

init {
updateDndState()
// Start continuous monitoring of DND state
dndStateUpdateJob = startDndStateMonitoring()
}

private fun startDndStateMonitoring(): Job = CoroutineScope(Dispatchers.Default).launch {
while (isActive) {
updateDndState()
delay(1000) // Check every second
}
}

override fun isDndEnabled(): Flow<Boolean> = _isDndEnabled
override fun getDndMode(): Flow<String> = _dndMode

override suspend fun setDndEnabled(enabled: Boolean) {
if (!notificationManager.isNotificationPolicyAccessGranted) {
Expand All @@ -31,12 +49,19 @@ class DndRepositoryImpl @Inject constructor(

try {
val newFilter = if (enabled) {
NotificationManager.INTERRUPTION_FILTER_NONE
val isPriorityDndEnabled = runBlocking {
settingsRepository.getPriorityDndEnabled().first()
}
if (isPriorityDndEnabled) {
NotificationManager.INTERRUPTION_FILTER_PRIORITY
} else {
NotificationManager.INTERRUPTION_FILTER_NONE
}
} else {
NotificationManager.INTERRUPTION_FILTER_ALL
}
notificationManager.setInterruptionFilter(newFilter)
updateDndState()
updateDndState() // Ensure state is updated immediately after changing
Log.d("DndRepository", "DND state changed to: $enabled")
} catch (e: Exception) {
Log.e("DndRepository", "Error setting DND state", e)
Expand All @@ -49,9 +74,38 @@ class DndRepositoryImpl @Inject constructor(
}

private fun updateDndState() {
// Use Android's native method to check if DND is active
val currentFilter = notificationManager.currentInterruptionFilter
val isDndEnabled = currentFilter == NotificationManager.INTERRUPTION_FILTER_NONE
_isDndEnabled.value = isDndEnabled
Log.d("DndRepository", "Current DND state: $isDndEnabled (Filter: $currentFilter)")

val isDndActive = currentFilter != NotificationManager.INTERRUPTION_FILTER_ALL

val dndMode = when (currentFilter) {
NotificationManager.INTERRUPTION_FILTER_NONE -> "Total Silence"
NotificationManager.INTERRUPTION_FILTER_PRIORITY -> "Priority Mode"
NotificationManager.INTERRUPTION_FILTER_ALARMS -> "Alarms Only"
NotificationManager.INTERRUPTION_FILTER_ALL -> "All Notifications"
else -> "Unknown Mode"
}

// Only update if the state has changed to avoid unnecessary updates
if (_isDndEnabled.value != isDndActive) {
_isDndEnabled.value = isDndActive
}

if (_dndMode.value != dndMode) {
_dndMode.value = dndMode
}

Log.d("DndRepository", """
Current DND Details:
- Active: $isDndActive
- Mode: $dndMode
- Raw Filter: $currentFilter
""".trimIndent())
}

// Ensure the monitoring job is cancelled when the repository is no longer used
override fun onCleared() {
dndStateUpdateJob.cancel()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import kotlinx.coroutines.flow.Flow

interface DndRepository {
fun isDndEnabled(): Flow<Boolean>
fun getDndMode(): Flow<String>
suspend fun setDndEnabled(enabled: Boolean)
suspend fun toggleDnd()
fun onCleared()
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,10 @@ fun MainScreen(
verticalArrangement = Arrangement.Center
) {
Image(
painter = painterResource(id = R.drawable.app_icon),
contentDescription = "Do Not Enter Icon",
painter = painterResource(
id = if (state.isDndEnabled) R.drawable.ic_dnd_on else R.drawable.ic_dnd_off
),
contentDescription = "Do Not Disturb Icon",
modifier = Modifier
.fillMaxWidth(0.7f)
.aspectRatio(1f),
Expand All @@ -52,7 +54,7 @@ fun MainScreen(
Spacer(modifier = Modifier.height(32.dp))

Text(
text = if (state.isDndEnabled) "DND is ON" else "DND is OFF",
text = if (state.isDndEnabled) "DND: ${state.dndMode}" else "DND is OFF",
style = MaterialTheme.typography.headlineMedium,
color = MaterialTheme.colorScheme.primary
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import dev.robin.flip_2_dnd.domain.model.PhoneOrientation
data class MainState(
val orientation: PhoneOrientation = PhoneOrientation.UNKNOWN,
val isDndEnabled: Boolean = false,
val dndMode: String = "All Notifications",
val isScreenOffOnly: Boolean = false,
val isVibrationEnabled: Boolean = true,
val isSoundEnabled: Boolean = false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,10 +73,19 @@ class MainViewModel @Inject constructor(

private fun observeDndState() {
viewModelScope.launch {
dndRepository.isDndEnabled().collect { enabled ->
Log.d("MainViewModel", "DND state changed: $enabled")
_state.update { it.copy(isDndEnabled = enabled) }
}
// Combine DND enabled state and mode
combine(
dndRepository.isDndEnabled(),
dndRepository.getDndMode()
) { enabled, mode ->
Log.d("MainViewModel", "DND state changed: $enabled, Mode: $mode")
_state.update {
it.copy(
isDndEnabled = enabled,
dndMode = mode
)
}
}.collect()
}
}

Expand Down
47 changes: 35 additions & 12 deletions app/src/main/java/dev/robin/flip_2_dnd/services/DndService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import android.util.Log
import dev.robin.flip_2_dnd.R
import dev.robin.flip_2_dnd.domain.repository.SettingsRepository
import dev.robin.flip_2_dnd.data.repository.SettingsRepositoryImpl
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.first
Expand Down Expand Up @@ -42,16 +43,27 @@ class DndService(private val context: Context) {
private fun vibrate(pattern: LongArray) {
runBlocking {
val isVibrationEnabled = settingsRepository.getVibrationEnabled().first()
Log.d(TAG, "Vibration check: enabled=$isVibrationEnabled")
if (isVibrationEnabled) {
Log.d(TAG, "Vibration check: enabled=$isVibrationEnabled, pattern=${pattern.contentToString()}")

// Log the entire vibration process for debugging
if (!isVibrationEnabled) {
Log.w(TAG, "Vibration is disabled. Skipping vibration.")
return@runBlocking
}

try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val timings = pattern
val amplitudes = IntArray(pattern.size) { VibrationEffect.DEFAULT_AMPLITUDE }
Log.d(TAG, "Creating waveform vibration for Android O+")
vibrator.vibrate(VibrationEffect.createWaveform(timings, amplitudes, -1))
} else {
Log.d(TAG, "Using deprecated vibration method for older Android versions")
@Suppress("DEPRECATION")
vibrator.vibrate(pattern, -1)
}
} catch (e: Exception) {
Log.e(TAG, "Error during vibration: ${e.message}", e)
}
}
}
Expand Down Expand Up @@ -102,6 +114,7 @@ class DndService(private val context: Context) {
// Any other value means DND is ON with different levels
val isDndCurrentlyOn = currentFilter != NotificationManager.INTERRUPTION_FILTER_ALL

// Determine the new filter first
val newFilter = if (!isDndCurrentlyOn) {
// If DND is currently OFF, turn it ON with appropriate mode
runBlocking {
Expand All @@ -118,6 +131,26 @@ class DndService(private val context: Context) {
NotificationManager.INTERRUPTION_FILTER_ALL
}

// Play feedback BEFORE setting the filter
val willBeDndEnabled = newFilter != NotificationManager.INTERRUPTION_FILTER_ALL
playSound(willBeDndEnabled)
if (willBeDndEnabled) {
// Two vibrations for DND ON
vibrate(longArrayOf(0, 200, 200, 200))
} else {
// One vibration for DND OFF
vibrate(longArrayOf(0, 200))
}

// Add 2-second delay only when turning on Total Silence DND
if (willBeDndEnabled && newFilter == NotificationManager.INTERRUPTION_FILTER_NONE) {
runBlocking {
Log.d(TAG, "Waiting 2 seconds before setting Total Silence DND")
delay(2000)
}
}

// Now set the interruption filter
Log.d(TAG, "Setting DND filter from $currentFilter to $newFilter")
notificationManager.setInterruptionFilter(newFilter)

Expand All @@ -133,16 +166,6 @@ class DndService(private val context: Context) {
}
Log.d(TAG, "DND ${if (_isDndEnabled.value) "enabled" else "disabled"} by ${if (_isAppEnabledDnd.value) "app" else "user"}")

// Play feedback
playSound(_isDndEnabled.value)
if (_isDndEnabled.value) {
// Two vibrations for DND ON
vibrate(longArrayOf(0, 200, 200, 200))
} else {
// One vibration for DND OFF
vibrate(longArrayOf(0, 200))
}

} catch (e: SecurityException) {
Log.e(TAG, "SecurityException toggling DND: ${e.message}", e)
openDndSettings()
Expand Down
15 changes: 15 additions & 0 deletions app/src/main/res/drawable/ic_dnd_off.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#808080"
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8zM7,11h10v2L7,13z"/>
<path
android:strokeColor="#FF0000"
android:strokeWidth="3"
android:strokeLineCap="round"
android:pathData="M19,5 L5,19"/>
</vector>
10 changes: 10 additions & 0 deletions app/src/main/res/drawable/ic_dnd_on.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FF0000"
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8zM7,11h10v2L7,13z"/>
</vector>
16 changes: 14 additions & 2 deletions metadata/dev.robin.flip_2_dnd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,20 @@ Builds:
subdir: app
gradle:
- yes
- versionName: '1.0.6'
versionCode: 6
commit: v1.0.6
subdir: app
gradle:
- yes
- versionName: '1.0.7'
versionCode: 7
commit: v1.0.7
subdir: app
gradle:
- yes

AutoUpdateMode: Version
UpdateCheckMode: Tags
CurrentVersion: '1.0.6'
CurrentVersionCode: 6
CurrentVersion: '1.0.7'
CurrentVersionCode: 7
3 changes: 3 additions & 0 deletions metadata/en-US/changelogs/7.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
- Improved DND mode detection and toggle behavior
- Enhanced Total Silence mode activation
- Minor performance and stability improvements

0 comments on commit 0d5b2eb

Please sign in to comment.