diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/activities/SetReminderActivity.kt b/app/src/main/java/ml/docilealligator/infinityforreddit/activities/SetReminderActivity.kt index 56d93be6..9d0b27ce 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/activities/SetReminderActivity.kt +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/activities/SetReminderActivity.kt @@ -5,13 +5,13 @@ import android.content.Intent import android.content.SharedPreferences import android.os.Build import android.os.Bundle +import android.widget.Toast import androidx.activity.compose.setContent import androidx.activity.enableEdgeToEdge import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.WindowInsetsSides import androidx.compose.foundation.layout.fillMaxSize @@ -29,12 +29,14 @@ import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.Scaffold -import androidx.compose.material3.Text +import androidx.compose.material3.SnackbarHost +import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.TimePicker import androidx.compose.material3.TopAppBarDefaults.enterAlwaysScrollBehavior import androidx.compose.material3.rememberDatePickerState import androidx.compose.material3.rememberTimePickerState import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableLongStateOf import androidx.compose.runtime.mutableStateOf @@ -45,12 +47,14 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.vectorResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp -import androidx.compose.ui.window.DialogProperties import androidx.core.view.WindowInsetsControllerCompat import androidx.lifecycle.ViewModelProvider +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import ml.docilealligator.infinityforreddit.AppResult import ml.docilealligator.infinityforreddit.Infinity import ml.docilealligator.infinityforreddit.R import ml.docilealligator.infinityforreddit.RedditDataRoomDatabase @@ -138,6 +142,7 @@ class SetReminderActivity: BaseActivity() { mViewModel = ViewModelProvider.create( this, provideFactory( + accountName, intent.getParcelableExtra(EXTRA_POST), intent.getStringExtra(EXTRA_POST_ID), intent.getParcelableExtra(EXTRA_COMMENT), @@ -161,8 +166,8 @@ class SetReminderActivity: BaseActivity() { val context = LocalContext.current val scrollBehavior = enterAlwaysScrollBehavior() - val commentContent = remember { - mViewModel.comment?.commentRawText?.substring(200) + val content = remember { + mViewModel.content } var showDatePicker by remember { mutableStateOf(false) } @@ -180,6 +185,11 @@ class SetReminderActivity: BaseActivity() { mutableStateOf("") } + val setReminderResult by mViewModel.setReminderResult.collectAsStateWithLifecycle() + + val snackbarHostState = remember { SnackbarHostState() } + var snackbarMessage: String? by remember { mutableStateOf(null) } + LaunchedEffect(timePickerState.hour, timePickerState.minute, datePickerState.selectedDateMillis) { datePickerState.selectedDateMillis?.let { reminderTimeMillis = getDateAndTimeMillis(it, timePickerState.hour, timePickerState.minute) @@ -191,6 +201,26 @@ class SetReminderActivity: BaseActivity() { } } + LaunchedEffect(snackbarMessage) { + snackbarMessage?.let { + snackbarHostState.showSnackbar(it) + } + } + + LaunchedEffect(setReminderResult) { + setReminderResult?.let { + when (it) { + is AppResult.Success<*> -> { + Toast.makeText(context, R.string.reminder_set, Toast.LENGTH_SHORT).show() + finish() + } + is AppResult.Error<*> -> { + snackbarMessage = getString(it.error as Int) + } + } + } + } + Scaffold( topBar = { ThemedTopAppBar( @@ -199,7 +229,15 @@ class SetReminderActivity: BaseActivity() { windowInsetsController = windowInsetsController, actions = { IconButton(onClick = { - + if (reminderTimeMillis == 0L || reminderTimeString.isEmpty()) { + snackbarMessage = getString(R.string.please_set_reminder_time) + return@IconButton + } + if (reminderTimeMillis < System.currentTimeMillis()) { + snackbarMessage = getString(R.string.reminder_time_must_be_in_future) + return@IconButton + } + mViewModel.setReminder(reminderTimeMillis) }) { Icon( imageVector = ImageVector.vectorResource(R.drawable.ic_check_circle_toolbar_24dp), @@ -216,6 +254,9 @@ class SetReminderActivity: BaseActivity() { .fillMaxSize() .nestedScroll(scrollBehavior.nestedScrollConnection) .imePadding(), + snackbarHost = { + SnackbarHost(hostState = snackbarHostState) + }, contentWindowInsets = if (isImmersiveInterfaceEnabled) WindowInsets.safeDrawing else WindowInsets.navigationBars.only(WindowInsetsSides.Bottom) ) { innerPadding -> Column( @@ -224,14 +265,9 @@ class SetReminderActivity: BaseActivity() { .background(Color(LocalAppTheme.current.backgroundColor)) .padding(innerPadding), ) { - if (commentContent != null) { + if (content.isNotEmpty()) { PrimaryText( - commentContent, - modifier = Modifier.padding(16.dp) - ) - } else if (mViewModel.post != null) { - PrimaryText( - mViewModel.post!!.title, + content, modifier = Modifier.padding(16.dp) ) } diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/reminder/ReminderDao.kt b/app/src/main/java/ml/docilealligator/infinityforreddit/reminder/ReminderDao.kt index 7b31cf2d..6c3e18f8 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/reminder/ReminderDao.kt +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/reminder/ReminderDao.kt @@ -2,12 +2,13 @@ package ml.docilealligator.infinityforreddit.reminder import androidx.room.Dao import androidx.room.Insert +import androidx.room.OnConflictStrategy import androidx.room.Query import kotlinx.coroutines.flow.Flow @Dao interface ReminderDao { - @Insert + @Insert(onConflict = OnConflictStrategy.REPLACE) suspend fun insert(reminder: Reminder) @Query("SELECT * FROM reminders") diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/reminder/ReminderManager.kt b/app/src/main/java/ml/docilealligator/infinityforreddit/reminder/ReminderManager.kt index 45aa7294..20639c07 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/reminder/ReminderManager.kt +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/reminder/ReminderManager.kt @@ -6,17 +6,19 @@ import android.app.PendingIntent import android.content.Intent import kotlinx.coroutines.flow.Flow import ml.docilealligator.infinityforreddit.RedditDataRoomDatabase -import kotlin.jvm.java class ReminderManager( private val applicationContext: Application, private val redditRoomDatabase: RedditDataRoomDatabase, private val alarmManager: AlarmManager ) { - fun setReminder(reminder: Reminder) { + suspend fun setReminder(reminder: Reminder) { + redditRoomDatabase.reminderDao().insert(reminder) + val alarmIntent = Intent(applicationContext, ReminderAlarmReceiver::class.java).let { intent -> - PendingIntent.getBroadcast(applicationContext, 0, intent, 0) + PendingIntent.getBroadcast(applicationContext, 0, intent, + PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE) } alarmManager.set( diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/viewmodels/SetReminderViewModel.kt b/app/src/main/java/ml/docilealligator/infinityforreddit/viewmodels/SetReminderViewModel.kt index c857c578..00a7309c 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/viewmodels/SetReminderViewModel.kt +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/viewmodels/SetReminderViewModel.kt @@ -1,27 +1,55 @@ package ml.docilealligator.infinityforreddit.viewmodels -import android.content.SharedPreferences +import androidx.compose.runtime.MutableState +import androidx.compose.runtime.mutableStateOf import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider +import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewmodel.CreationExtras -import ml.docilealligator.infinityforreddit.RedditDataRoomDatabase +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.launch +import ml.docilealligator.infinityforreddit.AppResult +import ml.docilealligator.infinityforreddit.R import ml.docilealligator.infinityforreddit.comment.Comment import ml.docilealligator.infinityforreddit.post.Post +import ml.docilealligator.infinityforreddit.reminder.Reminder import ml.docilealligator.infinityforreddit.reminder.ReminderManager -import retrofit2.Retrofit class SetReminderViewModel( + val accountName: String, val post: Post?, val postId: String?, val comment: Comment?, private val reminderManager: ReminderManager ): ViewModel() { - fun setReminder() { + private val _setReminderResult: MutableStateFlow?> = MutableStateFlow(null) + val setReminderResult = _setReminderResult.asStateFlow() + val content: String + get() = comment?.commentRawText?.substring(200) ?: post?.title ?: "" + + fun setReminder( + reminderTime: Long + ) { + (post?.id ?: postId)?.let { + viewModelScope.launch { + reminderManager.setReminder( + Reminder( + accountName, it, comment?.id ?: "", content, System.currentTimeMillis(), reminderTime + ) + ) + _setReminderResult.value = AppResult.Success(Unit) + } + } ?: run { + _setReminderResult.value = AppResult.Error(R.string.invalid_reminder_post_id) + } } companion object { fun provideFactory( + accountName: String, post: Post?, postId: String?, comment: Comment?, @@ -34,7 +62,7 @@ class SetReminderViewModel( extras: CreationExtras ): T { return SetReminderViewModel( - post, postId, comment, reminderManager + accountName, post, postId, comment, reminderManager ) as T } } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 20f4ba3d..f3cf3657 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1655,4 +1655,8 @@ Set Date Set Time You\'ll receive a reminder notification on the date and time you set: + Please set a reminder time + The reminder time must be in the future. + Invalid post id + Reminder set