Skip to content

Commit

Permalink
add alarm in progress task
Browse files Browse the repository at this point in the history
  • Loading branch information
derysudrajat committed Apr 11, 2022
1 parent 126b99c commit 6a10111
Show file tree
Hide file tree
Showing 18 changed files with 161 additions and 63 deletions.
1 change: 1 addition & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM"/>

<application
android:name=".di.AlifApp"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,21 @@
package id.derysudrajat.alif.data.model

import android.os.Parcelable
import com.google.firebase.Timestamp
import id.derysudrajat.alif.repo.local.entity.CheckedTaskEntity
import id.derysudrajat.alif.repo.local.entity.ProgressTaskEntity
import id.derysudrajat.alif.utils.TimeUtils.formatDate
import kotlinx.parcelize.Parcelize
import java.util.*

@Parcelize
data class ProgressTask(
val id: Long,
val title: String,
val date: Long,
var repeating: String,
var isCheck: Boolean
)
) : Parcelable

fun ProgressTask.toProgressEntity() = ProgressTaskEntity(
this.id, this.title, this.date, Timestamp(Date(date)).formatDate, this.repeating
Expand Down
19 changes: 12 additions & 7 deletions app/src/main/java/id/derysudrajat/alif/repo/PrayerRepository.kt
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
package id.derysudrajat.alif.repo

import android.util.Log
import com.google.firebase.Timestamp
import id.derysudrajat.alif.data.model.*
import id.derysudrajat.alif.data.repository.DataRepositoryImpl
import id.derysudrajat.alif.repo.local.LocalDataSource
import id.derysudrajat.alif.repo.local.entity.ProgressTaskEntity
import id.derysudrajat.alif.repo.local.entity.toPayerReminders
import id.derysudrajat.alif.repo.local.entity.toProgressTask
import id.derysudrajat.alif.repo.remote.RemoteDataSource
import id.derysudrajat.alif.utils.TimeUtils.formatDate
import id.derysudrajat.alif.utils.TimeUtils.indexOfDay
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow
Expand Down Expand Up @@ -36,14 +35,20 @@ class PrayerRepository @Inject constructor(

override suspend fun getProgressTask(date: String): Flow<List<ProgressTask>> = flow {
localDataSource.getCheckedTask(date).collect { checkedTask ->
localDataSource.getAllProgressTask().map { entities ->
entities.filter { it.repeating.contains(Regex("([$indexOfDay,7,-1])")) }
.filter { if (!it.repeating.contains("7")) it.date == Timestamp.now().formatDate else it.title.isNotBlank() }
.sortedBy { it.date }.toProgressTask(checkedTask)
}.collect { emit(it) }
localDataSource.getAllProgressTask().collect {entity ->
emit(entity.filter { it.filterDay() }.sortedBy { it.dateLong }.toProgressTask(checkedTask))
}
}
}

private fun ProgressTaskEntity.filterDay(): Boolean {
var isContain = false
this.repeating.split(" ").forEach {
if (it.isNotBlank()) isContain = listOf(indexOfDay,7,-1).contains(it.toInt())
}
return isContain
}

override suspend fun addProgressTask(task: ProgressTask) {
localDataSource.addProgressTask(task.toProgressEntity())
localDataSource.addCheckedTask(task.toCheckedEntity())
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
package id.derysudrajat.alif.repo.remote.network

import id.derysudrajat.alif.repo.remote.response.PrayerScheduleResponse
import kotlinx.coroutines.flow.Flow
import retrofit2.http.GET
import retrofit2.http.Query

interface PrayerService {
//latitude=-6.650216&longitude=108.538614&method=2&month=3&year=2022
@GET("calendar")
suspend fun getSchedule(
@Query("latitude") lat: Double,
Expand Down
143 changes: 116 additions & 27 deletions app/src/main/java/id/derysudrajat/alif/service/PrayerAlarm.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,28 +5,30 @@ import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.app.PendingIntent.FLAG_IMMUTABLE
import android.app.PendingIntent.FLAG_MUTABLE
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.media.AudioAttributes
import android.media.MediaPlayer
import android.net.Uri
import android.os.Build
import android.util.Log
import android.widget.Toast
import androidx.core.app.NotificationCompat
import androidx.core.content.ContextCompat
import com.google.firebase.Timestamp
import dagger.hilt.android.AndroidEntryPoint
import id.derysudrajat.alif.R
import id.derysudrajat.alif.data.model.PrayerReminder
import id.derysudrajat.alif.data.model.ProgressTask
import id.derysudrajat.alif.data.model.hour
import id.derysudrajat.alif.data.model.minutes
import id.derysudrajat.alif.repo.PrayerRepository
import id.derysudrajat.alif.ui.main.MainActivity
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import id.derysudrajat.alif.utils.TimeUtils
import id.derysudrajat.alif.utils.TimeUtils.day
import id.derysudrajat.alif.utils.TimeUtils.hour
import id.derysudrajat.alif.utils.TimeUtils.hourMinutes
import id.derysudrajat.alif.utils.TimeUtils.minutes
import java.util.*
import javax.inject.Inject

Expand All @@ -36,8 +38,10 @@ class PrayerAlarm : BroadcastReceiver() {

companion object {
const val EXTRA_ALARM = "extra_alarm"
const val EXTRA_ALARM_ACTIVITY = "extra_alarm"

const val NOTIFICATION_TITLE = "Prayer Reminder"
const val NOTIFICATION_TITLE_ACTIVITY = "Task Reminder"
private const val NOTIFICATION_ID = 101
const val NOTIFICATION_REQUEST_CODE = 102
const val CHANNEL_ID = "Reminder"
Expand All @@ -58,8 +62,18 @@ class PrayerAlarm : BroadcastReceiver() {
lateinit var repository: PrayerRepository

override fun onReceive(context: Context, intent: Intent) {
intent.extras?.getParcelable<ProgressTask>(EXTRA_ALARM_ACTIVITY)?.let {
showAlarmNotification(
context, NOTIFICATION_TITLE_ACTIVITY, "Now it's time to do ${it.title}"
)
}
intent.extras?.getParcelable<PrayerReminder>(EXTRA_ALARM)?.let {
showAlarmNotification(context, it)
showAlarmNotification(context, NOTIFICATION_TITLE, buildString {
append("Now it's time for ")
append(getScheduleName(it.index))
append(" pray at ")
append(it.time)
})
if (it.index != 0 || it.index != 2) {
val mediaPlayer = MediaPlayer.create(
context, if (it.index == 1) R.raw.adzan_fajr else R.raw.adzan_makkah
Expand All @@ -72,7 +86,11 @@ class PrayerAlarm : BroadcastReceiver() {
}
}

fun setPrayerAlarm(context: Context, prayerReminder: PrayerReminder, showToast: Boolean? = true) {
fun setPrayerAlarm(
context: Context,
prayerReminder: PrayerReminder,
showToast: Boolean? = true
) {
val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
val intent = Intent(context, PrayerAlarm::class.java)
intent.putExtra(EXTRA_ALARM, prayerReminder)
Expand All @@ -83,8 +101,10 @@ class PrayerAlarm : BroadcastReceiver() {
set(Calendar.SECOND, 0)
}

val pendingIntent =
PendingIntent.getBroadcast(context, prayerReminder.index, intent, PendingIntent.FLAG_UPDATE_CURRENT or FLAG_IMMUTABLE)
val pendingIntent = PendingIntent.getBroadcast(
context, prayerReminder.index,
intent, PendingIntent.FLAG_UPDATE_CURRENT or FLAG_IMMUTABLE
)
alarmManager.setInexactRepeating(
AlarmManager.RTC_WAKEUP,
calendar.timeInMillis,
Expand All @@ -98,26 +118,102 @@ class PrayerAlarm : BroadcastReceiver() {
).show()
}

fun cancelAlarm(context: Context, prayerReminder: PrayerReminder) {
fun setActivityAlarm(context: Context, progressTask: ProgressTask, showToast: Boolean?) {
val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
val intent = Intent(context, PrayerAlarm::class.java)
intent.putExtra(EXTRA_ALARM_ACTIVITY, progressTask)
val calendar = Calendar.getInstance()
val currentDate = Timestamp(Date(progressTask.date))

val repeating = progressTask.repeating.split(" ")
if (repeating.size != 1) repeating.forEach {
if (it.isNotBlank()) {
// set multiple time and interval 7 and [id + interval]
var interval = it.toInt() - TimeUtils.indexOfDay
if (interval == -1) interval = 7

calendar.apply {
set(Calendar.DAY_OF_MONTH, currentDate.day + interval)
set(Calendar.HOUR_OF_DAY, currentDate.hour)
set(Calendar.MINUTE, currentDate.minutes)
set(Calendar.SECOND, 0)
}
val pendingIntent = PendingIntent.getBroadcast(
context, (progressTask.id + interval).toInt(),
intent, PendingIntent.FLAG_UPDATE_CURRENT or FLAG_IMMUTABLE
)
alarmManager.setInexactRepeating(
AlarmManager.RTC_WAKEUP,
calendar.timeInMillis,
AlarmManager.INTERVAL_DAY * 7,
pendingIntent
)
}
} else {
calendar.apply {
set(Calendar.HOUR_OF_DAY, currentDate.hour)
set(Calendar.MINUTE, currentDate.minutes)
set(Calendar.SECOND, 0)
}
val pendingIntent = PendingIntent.getBroadcast(
context, progressTask.id.toInt(),
intent, PendingIntent.FLAG_UPDATE_CURRENT or FLAG_IMMUTABLE
)
when (repeating.first().toInt()) {
7 -> alarmManager.setInexactRepeating(
AlarmManager.RTC_WAKEUP,
calendar.timeInMillis,
AlarmManager.INTERVAL_DAY,
pendingIntent
)
else -> alarmManager.set(
AlarmManager.RTC_WAKEUP,
calendar.timeInMillis,
pendingIntent
)
}
}
if (showToast == true) Toast.makeText(
context,
"Reminder for ${progressTask.title} at ${currentDate.hourMinutes} is set",
Toast.LENGTH_SHORT
).show()
}

fun cancelActivityAlarm(context: Context, progressTask: ProgressTask) {
val repeating = progressTask.repeating.split(" ")
if (repeating.size != 1) {
repeating.forEach {
if (it.isNotBlank()) {
var interval = it.toInt() - TimeUtils.indexOfDay
if (interval == -1) interval = 7
cancelAlarm(context, (progressTask.id + interval).toInt())
}
}
} else cancelAlarm(context, progressTask.id.toInt())
Toast.makeText(context, "Reminder for ${progressTask.title} is unset", Toast.LENGTH_SHORT)
.show()
}

fun cancelAlarm(context: Context, id: Int, message: String? = "") {
val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
val intent = Intent(context, PrayerAlarm::class.java)
val requestCode = prayerReminder.index
val pendingIntent = PendingIntent.getBroadcast(
context, requestCode, intent,
context, id, intent,
PendingIntent.FLAG_UPDATE_CURRENT or FLAG_IMMUTABLE

)
pendingIntent.cancel()
alarmManager.cancel(pendingIntent)
Toast.makeText(
context, "Reminder for ${getScheduleName(prayerReminder.index)} pray is unset",
Toast.LENGTH_SHORT
).show()
message?.let {
val text = it.ifBlank { "Reminder for ${getScheduleName(id)} pray is unset" }
Toast.makeText(context, text, Toast.LENGTH_SHORT).show()
}
}

private fun showAlarmNotification(
context: Context,
prayerReminder: PrayerReminder
title: String,
content: String
) {

val notificationManagerCompat =
Expand All @@ -143,15 +239,8 @@ class PrayerAlarm : BroadcastReceiver() {

val builder = NotificationCompat.Builder(context, CHANNEL_ID)
.setSmallIcon(R.drawable.ic_alif)
.setContentTitle(NOTIFICATION_TITLE)
.setContentText(
buildString {
append("Now it's time for ")
append(getScheduleName(prayerReminder.index))
append(" pray at ")
append(prayerReminder.time)
}
)
.setContentTitle(title)
.setContentText(content)
.setColor(ContextCompat.getColor(context, R.color.primary))
.setContentIntent(pendingIntent)
.setPriority(NotificationCompat.PRIORITY_MAX)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ class ActivityAdapter(
if (data.isCheck) R.color.primary else R.color.black_60
)
}
ivCheck.setOnClickListener { onChecked(data.id, !data.isCheck) }
btnCheck.setOnClickListener { onChecked(data.id, !data.isCheck) }
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,17 @@ package id.derysudrajat.alif.ui.activity

import android.app.Activity
import android.content.Intent
import android.graphics.*
import android.os.Bundle
import androidx.activity.result.contract.ActivityResultContracts
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.core.widget.NestedScrollView
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.DefaultItemAnimator
import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.RecyclerView
import com.google.firebase.Timestamp
import dagger.hilt.android.AndroidEntryPoint
import id.derysudrajat.alif.R
import id.derysudrajat.alif.data.model.ProgressTask
import id.derysudrajat.alif.databinding.ActivityProgressBinding
import id.derysudrajat.alif.ui.addactivity.AddProgressActivity
Expand Down Expand Up @@ -77,7 +74,7 @@ class ProgressActivity : AppCompatActivity() {
}

private fun setupAppBar() = binding.appBar.apply {
tvTitle.text = "Activity"
tvTitle.text = buildString { append("Activity") }
btnBack.setOnClickListener {
setResult(RESULT_OK)
finish()
Expand All @@ -98,7 +95,7 @@ class ProgressActivity : AppCompatActivity() {
ItemTouchHelper(object : ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.RIGHT) {
override fun onMove(v: RecyclerView, h: RecyclerView.ViewHolder, t: RecyclerView.ViewHolder) = false
override fun onSwiped(h: RecyclerView.ViewHolder, dir: Int) {
viewModel.deleteTask(h.absoluteAdapterPosition)
viewModel.deleteTask(this@ProgressActivity, h.absoluteAdapterPosition)
}
}).attachToRecyclerView(binding.rvActivity)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,22 @@
package id.derysudrajat.alif.ui.activity

import android.content.Context
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.google.firebase.Timestamp
import dagger.hilt.android.lifecycle.HiltViewModel
import id.derysudrajat.alif.data.model.ProgressTask
import id.derysudrajat.alif.repo.PrayerRepository
import id.derysudrajat.alif.service.PrayerAlarm
import id.derysudrajat.alif.utils.TimeUtils.formatDate
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.launch
import javax.inject.Inject

@HiltViewModel
class ProgressActivityViewModel @Inject constructor(
val repository: PrayerRepository
val repository: PrayerRepository,
private val alarm: PrayerAlarm
) : ViewModel() {

private val scope = viewModelScope
Expand All @@ -37,7 +40,8 @@ class ProgressActivityViewModel @Inject constructor(
}
}

fun deleteTask(position: Int) {
fun deleteTask(context: Context, position: Int) {
alarm.cancelActivityAlarm(context, currentActivity[position])
scope.launch { repository.deleteProgressTask(currentActivity[position]) }
.also { getTodayActivity() }
}
Expand Down
Loading

0 comments on commit 6a10111

Please sign in to comment.