Skip to content

Commit 5e405a5

Browse files
authored
Merge pull request #35 from avidraghav/improved_error_handling
Improve error handling in the set Reminder flow
2 parents 0d3dc49 + abe5aab commit 5e405a5

File tree

7 files changed

+168
-129
lines changed

7 files changed

+168
-129
lines changed

app/src/main/java/com/raghav/spacedawnv2/launchesscreen/LaunchesScreenVM.kt

Lines changed: 29 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@ import com.raghav.spacedawnv2.domain.model.LaunchDetail
66
import com.raghav.spacedawnv2.domain.model.toReminder
77
import com.raghav.spacedawnv2.domain.repository.LaunchesRepository
88
import com.raghav.spacedawnv2.domain.usecase.AddReminderUseCase
9-
import com.raghav.spacedawnv2.domain.util.Constants
9+
import com.raghav.spacedawnv2.domain.util.NotificationPermissionException
10+
import com.raghav.spacedawnv2.domain.util.ReminderAndNotificationPermissionException
11+
import com.raghav.spacedawnv2.domain.util.ReminderPermissionException
1012
import com.raghav.spacedawnv2.domain.util.Resource
1113
import dagger.hilt.android.lifecycle.HiltViewModel
1214
import javax.inject.Inject
@@ -76,30 +78,36 @@ class LaunchesScreenVM @Inject constructor(
7678
addReminderUseCase(reminder).let { result ->
7779
when (result) {
7880
is Resource.Error -> {
79-
when (result.errorMessage) {
80-
Constants.REMINDER_PERMISSION_NOT_AVAILABLE -> {
81-
_eventFlow.emit(
82-
LaunchesScreenEvent.PermissionToSetReminderNotGranted
83-
)
84-
}
81+
if (result.exception != null) {
82+
when (result.exception) {
83+
is ReminderPermissionException -> {
84+
_eventFlow.emit(
85+
LaunchesScreenEvent.PermissionToSetReminderNotGranted
86+
)
87+
}
8588

86-
Constants.NOTIFICATION_PERMISSION_NOT_AVAILABLE -> {
87-
_eventFlow.emit(
88-
LaunchesScreenEvent.PermissionToSendNotificationsNotGranted
89-
)
90-
}
89+
is NotificationPermissionException -> {
90+
_eventFlow.emit(
91+
LaunchesScreenEvent.PermissionToSendNotificationsNotGranted
92+
)
93+
}
9194

92-
Constants.NOTIFICATION_REMINDER_PERMISSION_NOT_AVAILABLE -> {
93-
_eventFlow.emit(
94-
LaunchesScreenEvent.PermissionsToSendNotificationsAndSetReminderNotGranted
95-
)
96-
}
95+
is ReminderAndNotificationPermissionException -> {
96+
_eventFlow.emit(
97+
LaunchesScreenEvent.PermissionsToSendNotificationsAndSetReminderNotGranted
98+
)
99+
}
97100

98-
else -> {
99-
_eventFlow.emit(
100-
LaunchesScreenEvent.ReminderNotSet(result.errorMessage)
101-
)
101+
else -> {
102+
_eventFlow.emit(
103+
LaunchesScreenEvent.ReminderNotSet(result.errorMessage)
104+
)
105+
}
102106
}
107+
} else {
108+
_eventFlow.emit(
109+
LaunchesScreenEvent.ReminderNotSet(result.errorMessage)
110+
)
103111
}
104112
}
105113

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
package com.raghav.spacedawnv2.navigation
2+
3+
import android.app.Activity
4+
import androidx.compose.animation.AnimatedContentTransitionScope
5+
import androidx.compose.material3.SnackbarDuration
6+
import androidx.compose.material3.SnackbarHostState
7+
import androidx.compose.material3.SnackbarResult
8+
import androidx.compose.runtime.Composable
9+
import androidx.compose.runtime.getValue
10+
import androidx.compose.runtime.rememberUpdatedState
11+
import androidx.compose.ui.Modifier
12+
import androidx.compose.ui.platform.LocalContext
13+
import androidx.compose.ui.res.stringResource
14+
import androidx.navigation.NavHostController
15+
import androidx.navigation.compose.NavHost
16+
import androidx.navigation.compose.composable
17+
import com.raghav.spacedawnv2.R
18+
import com.raghav.spacedawnv2.launchesscreen.LaunchesScreen
19+
import com.raghav.spacedawnv2.remindersscreen.RemindersScreen
20+
import com.raghav.spacedawnv2.util.Helpers.Companion.navigateSingleTopTo
21+
import kotlinx.coroutines.CoroutineScope
22+
import kotlinx.coroutines.launch
23+
24+
@Composable
25+
fun SpaceDawnNavHost(
26+
navController: NavHostController,
27+
modifier: Modifier = Modifier,
28+
snackbarHostState: SnackbarHostState,
29+
coroutineScope: CoroutineScope
30+
) {
31+
NavHost(
32+
navController = navController,
33+
startDestination = LaunchesScreen.route,
34+
modifier = modifier
35+
) {
36+
// Launches Screen
37+
composable(
38+
LaunchesScreen.route,
39+
enterTransition = {
40+
slideIntoContainer(AnimatedContentTransitionScope.SlideDirection.Right)
41+
},
42+
exitTransition = {
43+
slideOutOfContainer(AnimatedContentTransitionScope.SlideDirection.Left)
44+
}
45+
) {
46+
val activity = (LocalContext.current as? Activity)
47+
val actionLabel by rememberUpdatedState(
48+
newValue = stringResource(id = R.string.reminders)
49+
)
50+
LaunchesScreen(
51+
systemBackButtonClicked = { activity?.finish() },
52+
reminderSetSuccessfully = {
53+
coroutineScope.launch {
54+
val actionTaken = snackbarHostState.showSnackbar(
55+
it,
56+
actionLabel = actionLabel,
57+
withDismissAction = true,
58+
duration = SnackbarDuration.Short
59+
)
60+
when (actionTaken) {
61+
SnackbarResult.ActionPerformed -> {
62+
navController.navigateSingleTopTo(RemindersScreen.route)
63+
}
64+
65+
else -> {}
66+
}
67+
}
68+
},
69+
reminderNotSet = {
70+
coroutineScope.launch {
71+
snackbarHostState.showSnackbar(
72+
it,
73+
withDismissAction = true
74+
)
75+
}
76+
}
77+
)
78+
}
79+
// Reminders Screen
80+
composable(
81+
RemindersScreen.route,
82+
enterTransition = {
83+
slideIntoContainer(AnimatedContentTransitionScope.SlideDirection.Left)
84+
},
85+
exitTransition = {
86+
slideOutOfContainer(AnimatedContentTransitionScope.SlideDirection.Right)
87+
}
88+
) {
89+
val snackBarMessage by rememberUpdatedState(
90+
newValue = stringResource(R.string.reminder_cancelled_successfully)
91+
)
92+
RemindersScreen(
93+
onBackPressed = { navController.navigateSingleTopTo(LaunchesScreen.route) },
94+
reminderNotCancelled = { message ->
95+
coroutineScope.launch {
96+
snackbarHostState.showSnackbar(
97+
message.toString(),
98+
withDismissAction = true
99+
)
100+
}
101+
},
102+
reminderCancelled = {
103+
coroutineScope.launch {
104+
snackbarHostState.showSnackbar(
105+
// need to extract to string res
106+
snackBarMessage,
107+
withDismissAction = true
108+
)
109+
}
110+
}
111+
)
112+
}
113+
}
114+
}

app/src/main/java/com/raghav/spacedawnv2/ui/MainActivity.kt

Lines changed: 6 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
package com.raghav.spacedawnv2.ui
22

3-
import android.app.Activity
43
import android.os.Bundle
54
import androidx.activity.ComponentActivity
65
import androidx.activity.compose.setContent
7-
import androidx.compose.animation.AnimatedContentTransitionScope
86
import androidx.compose.foundation.layout.RowScope
97
import androidx.compose.foundation.layout.fillMaxSize
108
import androidx.compose.foundation.layout.padding
@@ -13,40 +11,30 @@ import androidx.compose.material3.MaterialTheme
1311
import androidx.compose.material3.NavigationBar
1412
import androidx.compose.material3.NavigationBarItem
1513
import androidx.compose.material3.Scaffold
16-
import androidx.compose.material3.SnackbarDuration
1714
import androidx.compose.material3.SnackbarHost
1815
import androidx.compose.material3.SnackbarHostState
19-
import androidx.compose.material3.SnackbarResult
2016
import androidx.compose.material3.Surface
2117
import androidx.compose.material3.Text
2218
import androidx.compose.runtime.Composable
2319
import androidx.compose.runtime.getValue
2420
import androidx.compose.runtime.remember
2521
import androidx.compose.runtime.rememberCoroutineScope
26-
import androidx.compose.runtime.rememberUpdatedState
2722
import androidx.compose.ui.Modifier
28-
import androidx.compose.ui.platform.LocalContext
29-
import androidx.compose.ui.res.stringResource
3023
import androidx.compose.ui.tooling.preview.Preview
3124
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
3225
import androidx.navigation.NavDestination
3326
import androidx.navigation.NavDestination.Companion.hierarchy
3427
import androidx.navigation.NavHostController
35-
import androidx.navigation.compose.NavHost
36-
import androidx.navigation.compose.composable
3728
import androidx.navigation.compose.currentBackStackEntryAsState
3829
import androidx.navigation.compose.rememberNavController
39-
import com.raghav.spacedawnv2.R
40-
import com.raghav.spacedawnv2.launchesscreen.LaunchesScreen
4130
import com.raghav.spacedawnv2.navigation.Destination
4231
import com.raghav.spacedawnv2.navigation.LaunchesScreen
4332
import com.raghav.spacedawnv2.navigation.RemindersScreen
44-
import com.raghav.spacedawnv2.remindersscreen.RemindersScreen
33+
import com.raghav.spacedawnv2.navigation.SpaceDawnNavHost
4534
import com.raghav.spacedawnv2.ui.theme.SpaceDawnTheme
4635
import com.raghav.spacedawnv2.ui.theme.spacing
4736
import com.raghav.spacedawnv2.util.Helpers.Companion.navigateSingleTopTo
4837
import dagger.hilt.android.AndroidEntryPoint
49-
import kotlinx.coroutines.launch
5038

5139
@AndroidEntryPoint
5240
class MainActivity : ComponentActivity() {
@@ -81,89 +69,12 @@ fun SpaceDawnApp(modifier: Modifier = Modifier) {
8169
SnackbarHost(snackbarHostState)
8270
}
8371
) { innerPadding ->
84-
NavHost(
72+
SpaceDawnNavHost(
8573
navController = navController,
86-
startDestination = LaunchesScreen.route,
87-
modifier = Modifier.padding(innerPadding)
88-
) {
89-
// Launches Screen
90-
composable(
91-
LaunchesScreen.route,
92-
enterTransition = {
93-
slideIntoContainer(AnimatedContentTransitionScope.SlideDirection.Right)
94-
},
95-
exitTransition = {
96-
slideOutOfContainer(AnimatedContentTransitionScope.SlideDirection.Left)
97-
}
98-
) {
99-
val activity = (LocalContext.current as? Activity)
100-
val actionLabel by rememberUpdatedState(
101-
newValue = stringResource(id = R.string.reminders)
102-
)
103-
LaunchesScreen(
104-
systemBackButtonClicked = { activity?.finish() },
105-
reminderSetSuccessfully = {
106-
scope.launch {
107-
val actionTaken = snackbarHostState.showSnackbar(
108-
it,
109-
actionLabel = actionLabel,
110-
withDismissAction = true,
111-
duration = SnackbarDuration.Short
112-
)
113-
when (actionTaken) {
114-
SnackbarResult.ActionPerformed -> {
115-
navController.navigateSingleTopTo(RemindersScreen.route)
116-
}
117-
118-
else -> {}
119-
}
120-
}
121-
},
122-
reminderNotSet = {
123-
scope.launch {
124-
snackbarHostState.showSnackbar(
125-
it,
126-
withDismissAction = true
127-
)
128-
}
129-
}
130-
)
131-
}
132-
// Reminders Screen
133-
composable(
134-
RemindersScreen.route,
135-
enterTransition = {
136-
slideIntoContainer(AnimatedContentTransitionScope.SlideDirection.Left)
137-
},
138-
exitTransition = {
139-
slideOutOfContainer(AnimatedContentTransitionScope.SlideDirection.Right)
140-
}
141-
) {
142-
val snackBarMessage by rememberUpdatedState(
143-
newValue = stringResource(R.string.reminder_cancelled_successfully)
144-
)
145-
RemindersScreen(
146-
onBackPressed = { navController.navigateSingleTopTo(LaunchesScreen.route) },
147-
reminderNotCancelled = { message ->
148-
scope.launch {
149-
snackbarHostState.showSnackbar(
150-
message.toString(),
151-
withDismissAction = true
152-
)
153-
}
154-
},
155-
reminderCancelled = {
156-
scope.launch {
157-
snackbarHostState.showSnackbar(
158-
// need to extract to string res
159-
snackBarMessage,
160-
withDismissAction = true
161-
)
162-
}
163-
}
164-
)
165-
}
166-
}
74+
modifier = Modifier.padding(innerPadding),
75+
snackbarHostState = snackbarHostState,
76+
coroutineScope = scope
77+
)
16778
}
16879
}
16980

domain/src/main/java/com/raghav/spacedawnv2/domain/usecase/AddReminderUseCase.kt

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@ package com.raghav.spacedawnv2.domain.usecase
22

33
import com.raghav.spacedawnv2.domain.model.Reminder
44
import com.raghav.spacedawnv2.domain.repository.LaunchesRepository
5-
import com.raghav.spacedawnv2.domain.util.Constants
5+
import com.raghav.spacedawnv2.domain.util.NotificationPermissionException
6+
import com.raghav.spacedawnv2.domain.util.ReminderAndNotificationPermissionException
7+
import com.raghav.spacedawnv2.domain.util.ReminderPermissionException
68
import com.raghav.spacedawnv2.domain.util.ReminderScheduler
79
import com.raghav.spacedawnv2.domain.util.ReminderState
810
import com.raghav.spacedawnv2.domain.util.Resource
@@ -49,23 +51,25 @@ class AddReminderUseCase @Inject constructor(
4951
when {
5052
reminderState.reminderPermission && !reminderState.notificationPermission -> {
5153
Resource.Error(
52-
message = Constants.NOTIFICATION_PERMISSION_NOT_AVAILABLE
54+
exception = NotificationPermissionException()
5355
)
5456
}
5557

5658
!reminderState.reminderPermission && reminderState.notificationPermission -> {
57-
Resource.Error(message = Constants.REMINDER_PERMISSION_NOT_AVAILABLE)
59+
Resource.Error(
60+
exception = ReminderPermissionException()
61+
)
5862
}
5963

6064
!reminderState.reminderPermission && !reminderState.notificationPermission -> {
6165
Resource.Error(
62-
message = Constants.NOTIFICATION_REMINDER_PERMISSION_NOT_AVAILABLE
66+
exception = ReminderAndNotificationPermissionException()
6367
)
6468
}
6569

6670
else -> {
6771
Resource.Error(
68-
message = Constants.NOTIFICATION_REMINDER_PERMISSION_NOT_AVAILABLE
72+
exception = ReminderAndNotificationPermissionException()
6973
)
7074
}
7175
}

domain/src/main/java/com/raghav/spacedawnv2/domain/util/Constants.kt

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,10 @@ object Constants {
88
const val REMINDER_SET = "Reminder Set Successfully"
99
const val REMINDER_NOTIFICATION_CHANNEL = "Launch Reminders"
1010
const val REMINDER_CHANNEL_ID = "launch_reminders"
11-
const val REMINDER_PERMISSION_NOT_AVAILABLE = "reminder_permission_not_available"
12-
const val NOTIFICATION_PERMISSION_NOT_AVAILABLE = "notification_permission_not_available"
13-
const val NOTIFICATION_REMINDER_PERMISSION_NOT_AVAILABLE =
14-
"notification_reminder_permission_not_available"
1511
const val KEY_LAUNCH_NAME = "key_launch_name"
1612
const val KEY_LAUNCH_ID = "key_reminder_name"
1713
const val TEN_MINUTES_IN_MILLIS = 600_000L
1814
const val REMINDER_SOUND_DURATION = 10_000L
1915
const val REMINDER_NOTIFICATION_AND_CLEANUP = "reminder_notification_and_cleanup"
2016
const val SET_REMINDER_AFTER_DEVICE_BOOT = "set_reminder_after_device_boot"
21-
const val API_THROTTLED_MESSAGE = "Requests Limit Reached, please try after 1 hour"
22-
const val UNKNOWN_ERROR_MESSAGE = "Some Unknown Error Occurred"
2317
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package com.raghav.spacedawnv2.domain.util
2+
3+
class ReminderPermissionException : Exception()
4+
class NotificationPermissionException : Exception()
5+
class ReminderAndNotificationPermissionException : Exception()

0 commit comments

Comments
 (0)