通知
This commit is contained in:
@@ -0,0 +1,67 @@
|
||||
package com.taskttl.core.alarm
|
||||
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import com.taskttl.core.notification.NotificationManager
|
||||
import com.taskttl.core.notification.NotificationPayload
|
||||
import com.taskttl.core.notification.NotificationRepeatType
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class AlarmReceiver : BroadcastReceiver() {
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
if (intent.action != "com.taskttl.ALARM_TRIGGER") return
|
||||
|
||||
val id = intent.getStringExtra("id") ?: return
|
||||
val title = intent.getStringExtra("title") ?: "TaskTTL"
|
||||
val message = intent.getStringExtra("message") ?: ""
|
||||
|
||||
// 使用协程调用统一通知方法
|
||||
CoroutineScope(Dispatchers.Main).launch {
|
||||
NotificationManager.scheduleNotification(
|
||||
NotificationPayload(
|
||||
id = id,
|
||||
title = title,
|
||||
message = message,
|
||||
triggerTimeMillis = System.currentTimeMillis(),
|
||||
repeatType = NotificationRepeatType.NONE
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
|
||||
// val id = intent.getStringExtra("id") ?: return
|
||||
// val title = intent.getStringExtra("title") ?: "TaskTTL"
|
||||
// val message = intent.getStringExtra("message") ?: ""
|
||||
//
|
||||
// val channelId = "taskttl_channel"
|
||||
//
|
||||
// // 确保通道存在
|
||||
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
// val nm = context.getSystemService(Context.NOTIFICATION_SERVICE) as android.app.NotificationManager
|
||||
// if (nm.getNotificationChannel(channelId) == null) {
|
||||
// val channel = android.app.NotificationChannel(
|
||||
// channelId,
|
||||
// "TaskTTL Notifications",
|
||||
// android.app.NotificationManager.IMPORTANCE_HIGH
|
||||
// )
|
||||
// channel.description = "TaskTTL 提醒通知"
|
||||
// nm.createNotificationChannel(channel)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // 构建通知
|
||||
// val builder = NotificationCompat.Builder(context, channelId)
|
||||
// .setContentTitle(title)
|
||||
// .setContentText(message)
|
||||
// .setSmallIcon(R.mipmap.ic_launcher)
|
||||
// .setAutoCancel(true)
|
||||
// .setPriority(NotificationCompat.PRIORITY_HIGH)
|
||||
//
|
||||
// val nm = context.getSystemService(Context.NOTIFICATION_SERVICE) as android.app.NotificationManager
|
||||
// nm.notify(id.hashCode(), builder.build())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.taskttl.core.alarm
|
||||
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import com.taskttl.core.notification.NotificationPayload
|
||||
|
||||
class BootReceiver : BroadcastReceiver() {
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
if (intent.action == Intent.ACTION_BOOT_COMPLETED) {
|
||||
// 重新注册所有闹钟(可从数据库恢复)
|
||||
|
||||
// 这里假设你有一个持久化存储保存了待触发通知列表
|
||||
// 例如 Room / SharedPreferences / 数据库
|
||||
// val pendingNotifications = loadPendingNotifications(context)
|
||||
//
|
||||
// // 使用协程重新注册通知
|
||||
// CoroutineScope(Dispatchers.Main).launch {
|
||||
// pendingNotifications.forEach { payload ->
|
||||
// NotificationManager.scheduleNotification(payload)
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 从存储中获取设备重启后需要重新注册的通知
|
||||
*/
|
||||
private fun loadPendingNotifications(context: Context): List<NotificationPayload> {
|
||||
// TODO: 这里你需要实现真实数据恢复逻辑
|
||||
// 示例:返回一个空列表
|
||||
return emptyList()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,197 @@
|
||||
package com.taskttl.core.notification
|
||||
|
||||
import android.Manifest
|
||||
import android.app.Activity
|
||||
import android.app.AlarmManager
|
||||
import android.app.PendingIntent
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.media.RingtoneManager
|
||||
import android.os.Build
|
||||
import androidx.core.app.ActivityCompat
|
||||
import androidx.core.app.NotificationCompat
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.work.*
|
||||
import com.taskttl.MainApplication
|
||||
import com.taskttl.R
|
||||
import com.taskttl.core.alarm.AlarmReceiver
|
||||
import com.taskttl.core.utils.LogUtils
|
||||
import java.util.concurrent.TimeUnit
|
||||
import kotlin.math.max
|
||||
|
||||
actual object NotificationManager {
|
||||
|
||||
private val channelId = "taskttl_channel"
|
||||
|
||||
init {
|
||||
setupNotificationChannel()
|
||||
}
|
||||
|
||||
private fun getActivity(): Activity = MainApplication.currentActivity()
|
||||
?: throw IllegalStateException("No activity available")
|
||||
|
||||
/** 创建通知通道(Android 8+) */
|
||||
private fun setupNotificationChannel() {
|
||||
val activity = MainApplication.currentActivity() ?: return
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
val nm = activity.getSystemService(Context.NOTIFICATION_SERVICE) as android.app.NotificationManager
|
||||
if (nm.getNotificationChannel(channelId) == null) {
|
||||
val channel = android.app.NotificationChannel(
|
||||
channelId,
|
||||
"TaskTTL Notifications",
|
||||
android.app.NotificationManager.IMPORTANCE_HIGH
|
||||
).apply { description = "TaskTTL 提醒通知" }
|
||||
nm.createNotificationChannel(channel)
|
||||
LogUtils.d("DevTTL_NotificationTest", "Notification channel created")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** 调度通知 */
|
||||
actual suspend fun scheduleNotification(payload: NotificationPayload) {
|
||||
val activity = getActivity()
|
||||
|
||||
// Android 13+ 权限检查
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU &&
|
||||
ContextCompat.checkSelfPermission(activity, Manifest.permission.POST_NOTIFICATIONS)
|
||||
!= PackageManager.PERMISSION_GRANTED
|
||||
) {
|
||||
ActivityCompat.requestPermissions(
|
||||
activity,
|
||||
arrayOf(Manifest.permission.POST_NOTIFICATIONS),
|
||||
1001
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
val delay = max(0, payload.triggerTimeMillis - System.currentTimeMillis())
|
||||
if (delay == 0L) {
|
||||
showImmediateNotification(payload)
|
||||
return
|
||||
}
|
||||
|
||||
if (delay <= 24 * 60 * 60 * 1000L && payload.repeatType == NotificationRepeatType.NONE) {
|
||||
scheduleExactAlarm(payload)
|
||||
} else {
|
||||
scheduleWorkManager(payload)
|
||||
}
|
||||
}
|
||||
|
||||
/** AlarmManager 精确闹钟 */
|
||||
private fun scheduleExactAlarm(payload: NotificationPayload) {
|
||||
val activity = getActivity()
|
||||
val alarmManager = activity.getSystemService(Context.ALARM_SERVICE) as AlarmManager
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S && !alarmManager.canScheduleExactAlarms()) {
|
||||
scheduleWorkManager(payload) // 回退 WorkManager
|
||||
return
|
||||
}
|
||||
|
||||
val intent = Intent(activity, AlarmReceiver::class.java).apply {
|
||||
action = "com.taskttl.ALARM_TRIGGER"
|
||||
putExtra("id", payload.id)
|
||||
putExtra("title", payload.title)
|
||||
putExtra("message", payload.message)
|
||||
}
|
||||
|
||||
val pendingIntent = PendingIntent.getBroadcast(
|
||||
activity,
|
||||
payload.id.hashCode(),
|
||||
intent,
|
||||
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
|
||||
)
|
||||
|
||||
alarmManager.setExactAndAllowWhileIdle(
|
||||
AlarmManager.RTC_WAKEUP,
|
||||
payload.triggerTimeMillis,
|
||||
pendingIntent
|
||||
)
|
||||
}
|
||||
|
||||
/** WorkManager 长期/周期通知 */
|
||||
private fun scheduleWorkManager(payload: NotificationPayload) {
|
||||
val activity = getActivity()
|
||||
val data = workDataOf(
|
||||
"id" to payload.id,
|
||||
"title" to payload.title,
|
||||
"message" to payload.message,
|
||||
"repeatType" to payload.repeatType.name
|
||||
)
|
||||
|
||||
val workManager = WorkManager.getInstance(activity)
|
||||
|
||||
if (payload.repeatType == NotificationRepeatType.NONE) {
|
||||
val delay = max(0, payload.triggerTimeMillis - System.currentTimeMillis())
|
||||
val request = OneTimeWorkRequestBuilder<NotificationWorker>()
|
||||
.setInitialDelay(delay, TimeUnit.MILLISECONDS)
|
||||
.setInputData(data)
|
||||
.addTag(payload.id)
|
||||
.build()
|
||||
workManager.enqueue(request)
|
||||
} else {
|
||||
val interval = when (payload.repeatType) {
|
||||
NotificationRepeatType.DAILY -> 24 * 60 * 60 * 1000L
|
||||
NotificationRepeatType.WEEKLY -> 7 * 24 * 60 * 60 * 1000L
|
||||
NotificationRepeatType.MONTHLY -> 30 * 24 * 60 * 60 * 1000L
|
||||
else -> 24 * 60 * 60 * 1000L
|
||||
}
|
||||
|
||||
val request = PeriodicWorkRequestBuilder<NotificationWorker>(interval, TimeUnit.MILLISECONDS)
|
||||
.setInputData(data)
|
||||
.addTag(payload.id)
|
||||
.build()
|
||||
|
||||
workManager.enqueueUniquePeriodicWork(
|
||||
payload.id,
|
||||
ExistingPeriodicWorkPolicy.UPDATE,
|
||||
request
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** 立即显示通知 */
|
||||
private fun showImmediateNotification(payload: NotificationPayload) {
|
||||
val activity = getActivity()
|
||||
val nm = activity.getSystemService(Context.NOTIFICATION_SERVICE) as android.app.NotificationManager
|
||||
|
||||
val notification = NotificationCompat.Builder(activity, channelId)
|
||||
.setContentTitle(payload.title)
|
||||
.setContentText(payload.message)
|
||||
.setSmallIcon(R.mipmap.ic_launcher)
|
||||
.setPriority(NotificationCompat.PRIORITY_HIGH)
|
||||
.setAutoCancel(true)
|
||||
// .setDefaults(NotificationCompat.DEFAULT_SOUND)
|
||||
.setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION))
|
||||
.build()
|
||||
|
||||
nm.notify(payload.id.hashCode(), notification)
|
||||
}
|
||||
|
||||
|
||||
/** 取消通知 */
|
||||
actual suspend fun cancelNotification(id: String) {
|
||||
val activity = getActivity()
|
||||
WorkManager.getInstance(activity).cancelAllWorkByTag(id)
|
||||
|
||||
val alarmManager = activity.getSystemService(Context.ALARM_SERVICE) as AlarmManager
|
||||
val intent = Intent(activity, AlarmReceiver::class.java)
|
||||
val pendingIntent = PendingIntent.getBroadcast(
|
||||
activity,
|
||||
id.hashCode(),
|
||||
intent,
|
||||
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
|
||||
)
|
||||
alarmManager.cancel(pendingIntent)
|
||||
|
||||
val nm = activity.getSystemService(Context.NOTIFICATION_SERVICE) as android.app.NotificationManager
|
||||
nm.cancel(id.hashCode())
|
||||
}
|
||||
|
||||
actual suspend fun cancelAll() {
|
||||
val activity = getActivity()
|
||||
WorkManager.getInstance(activity).cancelAllWork()
|
||||
val nm = activity.getSystemService(Context.NOTIFICATION_SERVICE) as android.app.NotificationManager
|
||||
nm.cancelAll()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
package com.taskttl.core.notification
|
||||
|
||||
import android.Manifest
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.os.Build
|
||||
import android.util.Log
|
||||
import androidx.core.app.ActivityCompat
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.net.toUri
|
||||
import com.taskttl.MainApplication
|
||||
import androidx.core.content.edit
|
||||
|
||||
actual object NotificationPermissionManager {
|
||||
private const val REQUEST_CODE = 2025
|
||||
private var callback: NotificationPermissionCallback? = null
|
||||
|
||||
/**
|
||||
* 在 Activity 的 onRequestPermissionsResult 中调用
|
||||
*/
|
||||
fun handlePermissionResult(requestCode: Int, grantResults: IntArray) {
|
||||
if (requestCode == REQUEST_CODE) {
|
||||
if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
||||
callback?.onGranted()
|
||||
} else {
|
||||
callback?.onDenied()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// expect/actual 适配:Android 需要 Activity 参数
|
||||
actual fun requestPermission(callback: NotificationPermissionCallback) {
|
||||
// Android 13 以下无需权限
|
||||
if (Build.VERSION.SDK_INT < 33) {
|
||||
callback.onGranted()
|
||||
return
|
||||
}
|
||||
|
||||
val activity = MainApplication.currentActivity()
|
||||
if (activity == null) {
|
||||
Log.w("NotificationPermission", "No current activity found")
|
||||
callback.onDenied()
|
||||
return
|
||||
}
|
||||
this.callback = callback
|
||||
|
||||
val prefs = activity.getSharedPreferences("app_prefs", Context.MODE_PRIVATE)
|
||||
|
||||
val permission = Manifest.permission.POST_NOTIFICATIONS
|
||||
val granted = ContextCompat.checkSelfPermission(
|
||||
activity, permission
|
||||
) == PackageManager.PERMISSION_GRANTED
|
||||
if (granted) {
|
||||
callback.onGranted()
|
||||
} else {
|
||||
val isFirstRequest = prefs.getBoolean("notification_first_request", true)
|
||||
val shouldShowRationale =
|
||||
ActivityCompat.shouldShowRequestPermissionRationale(activity, permission)
|
||||
|
||||
if (!shouldShowRationale && !isFirstRequest) {
|
||||
openNotificationSettings()
|
||||
callback.onDenied()
|
||||
} else {
|
||||
ActivityCompat.requestPermissions(activity, arrayOf(permission), REQUEST_CODE)
|
||||
}
|
||||
}
|
||||
|
||||
prefs.edit { putBoolean("notification_first_request", false) }
|
||||
}
|
||||
|
||||
|
||||
actual fun verifyPermission(): Boolean {
|
||||
// Android 13 以下无需权限
|
||||
if (Build.VERSION.SDK_INT < 33) {
|
||||
return true
|
||||
}
|
||||
val activity = MainApplication.currentActivity()
|
||||
if (activity == null) {
|
||||
Log.w("NotificationPermission", "No current activity found")
|
||||
return false
|
||||
}
|
||||
val permission = Manifest.permission.POST_NOTIFICATIONS
|
||||
val granted = ContextCompat.checkSelfPermission(
|
||||
activity, permission
|
||||
) == PackageManager.PERMISSION_GRANTED
|
||||
return granted
|
||||
}
|
||||
|
||||
/**
|
||||
* 引导用户到系统设置页关闭通知权限
|
||||
*/
|
||||
actual fun disablePermission() {
|
||||
openNotificationSettings()
|
||||
}
|
||||
|
||||
|
||||
private fun openNotificationSettings() {
|
||||
val context = MainApplication.currentActivity() ?: MainApplication.instance
|
||||
val intent = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
// API 26 及以上,打开通知设置页
|
||||
Intent().apply {
|
||||
action = android.provider.Settings.ACTION_APP_NOTIFICATION_SETTINGS
|
||||
putExtra(android.provider.Settings.EXTRA_APP_PACKAGE, context.packageName)
|
||||
}
|
||||
} else {
|
||||
// API 26 以下,打开应用详情页
|
||||
Intent().apply {
|
||||
action = android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS
|
||||
data = "package:${context.packageName}".toUri()
|
||||
}
|
||||
}
|
||||
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
|
||||
try {
|
||||
context.startActivity(intent)
|
||||
Log.d("NotificationPermission", "打开通知设置页")
|
||||
} catch (e: Exception) {
|
||||
Log.e("NotificationPermission", "无法打开通知设置页: ${e.message}")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package com.taskttl.core.notification
|
||||
|
||||
import android.app.PendingIntent
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.media.RingtoneManager
|
||||
import androidx.core.app.NotificationCompat
|
||||
import androidx.work.CoroutineWorker
|
||||
import androidx.work.WorkerParameters
|
||||
import com.taskttl.MainActivity
|
||||
import com.taskttl.R
|
||||
|
||||
class NotificationWorker(
|
||||
context: Context,
|
||||
params: WorkerParameters
|
||||
) : CoroutineWorker(context, params) {
|
||||
|
||||
override suspend fun doWork(): Result {
|
||||
val id = inputData.getString("id") ?: return Result.failure()
|
||||
val title = inputData.getString("title") ?: "TaskTTL"
|
||||
val message = inputData.getString("message") ?: ""
|
||||
|
||||
sendNotification(id, title, message)
|
||||
return Result.success()
|
||||
}
|
||||
|
||||
private fun sendNotification(id: String, title: String, message: String) {
|
||||
val context = applicationContext
|
||||
val channelId = "taskttl_channel"
|
||||
|
||||
val intent = Intent(context, MainActivity::class.java).apply {
|
||||
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
|
||||
}
|
||||
|
||||
val pendingIntent = PendingIntent.getActivity(
|
||||
context,
|
||||
id.hashCode(),
|
||||
intent,
|
||||
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
|
||||
)
|
||||
|
||||
val builder = NotificationCompat.Builder(context, channelId)
|
||||
.setContentTitle(title)
|
||||
.setContentText(message)
|
||||
.setSmallIcon(R.mipmap.ic_launcher)
|
||||
.setContentIntent(pendingIntent)
|
||||
.setAutoCancel(true)
|
||||
.setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION))
|
||||
.setPriority(NotificationCompat.PRIORITY_HIGH)
|
||||
|
||||
val nm = context.getSystemService(Context.NOTIFICATION_SERVICE) as android.app.NotificationManager
|
||||
nm.notify(id.hashCode(), builder.build())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.taskttl.core.notification
|
||||
|
||||
/**
|
||||
* 通知管理器
|
||||
* @author admin
|
||||
* @date 2025/10/16
|
||||
* @constructor 创建[NotificationManager]
|
||||
*/
|
||||
expect object NotificationManager {
|
||||
/**
|
||||
* 日程通知
|
||||
* @param [payload] 有效载荷
|
||||
*/
|
||||
suspend fun scheduleNotification(payload: NotificationPayload)
|
||||
|
||||
/**
|
||||
* 取消通知
|
||||
* @param [id] ID
|
||||
*/
|
||||
suspend fun cancelNotification(id: String)
|
||||
|
||||
/**
|
||||
* 全部取消
|
||||
*/
|
||||
suspend fun cancelAll()
|
||||
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.taskttl.core.notification
|
||||
|
||||
/**
|
||||
* 通知有效载荷
|
||||
* @author admin
|
||||
* @date 2025/10/16
|
||||
* @constructor 创建[NotificationPayload]
|
||||
* @param [id] ID
|
||||
* @param [title] 标题
|
||||
* @param [message] 消息
|
||||
* @param [triggerTimeMillis] 触发时间毫秒
|
||||
* @param [repeatType] 重复类型
|
||||
*/
|
||||
data class NotificationPayload(
|
||||
val id: String,
|
||||
val title: String,
|
||||
val message: String,
|
||||
val triggerTimeMillis: Long,
|
||||
val repeatType: NotificationRepeatType = NotificationRepeatType.NONE,
|
||||
)
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.taskttl.core.notification
|
||||
|
||||
/**
|
||||
* 通知权限回调接口
|
||||
*/
|
||||
interface NotificationPermissionCallback {
|
||||
/**
|
||||
* 授予
|
||||
*/
|
||||
fun onGranted()
|
||||
|
||||
/**
|
||||
* 被否认
|
||||
*/
|
||||
fun onDenied()
|
||||
}
|
||||
|
||||
/**
|
||||
* 跨平台通知权限处理器
|
||||
*/
|
||||
expect object NotificationPermissionManager {
|
||||
/**
|
||||
* 请求通知权限
|
||||
* @return 是否允许
|
||||
*/
|
||||
fun requestPermission(callback: NotificationPermissionCallback)
|
||||
|
||||
fun verifyPermission(): Boolean
|
||||
|
||||
fun disablePermission()
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.taskttl.core.notification
|
||||
|
||||
/**
|
||||
* 通知重复类型
|
||||
* @author admin
|
||||
* @date 2025/10/16
|
||||
* @constructor 创建[NotificationRepeatType]
|
||||
*/
|
||||
enum class NotificationRepeatType {
|
||||
NONE,
|
||||
DAILY,
|
||||
WEEKLY,
|
||||
MONTHLY
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package com.taskttl.core.notification
|
||||
|
||||
import platform.UserNotifications.*
|
||||
|
||||
actual class NotificationManager {
|
||||
actual suspend fun scheduleNotification(payload: NotificationPayload) {
|
||||
val content = UNMutableNotificationContent().apply {
|
||||
title = payload.title
|
||||
body = payload.message
|
||||
sound = UNNotificationSound.defaultSound()
|
||||
}
|
||||
|
||||
val interval = (payload.triggerTimeMillis - getCurrentTimeMillis()) / 1000.0
|
||||
val trigger = UNTimeIntervalNotificationTrigger.triggerWithTimeInterval(
|
||||
interval,
|
||||
repeats = payload.repeatType != NotificationRepeatType.NONE
|
||||
)
|
||||
|
||||
val request = UNNotificationRequest.requestWithIdentifier(
|
||||
payload.id,
|
||||
content,
|
||||
trigger
|
||||
)
|
||||
|
||||
UNUserNotificationCenter.currentNotificationCenter()
|
||||
.addNotificationRequest(request) { error ->
|
||||
error?.let { println("❌ Notification Error: ${it.localizedDescription}") }
|
||||
}
|
||||
}
|
||||
|
||||
actual suspend fun cancelNotification(id: String) {
|
||||
UNUserNotificationCenter.currentNotificationCenter()
|
||||
.removePendingNotificationRequestsWithIdentifiers(listOf(id))
|
||||
}
|
||||
|
||||
actual suspend fun cancelAll() {
|
||||
UNUserNotificationCenter.currentNotificationCenter()
|
||||
.removeAllPendingNotificationRequests()
|
||||
}
|
||||
|
||||
private fun getCurrentTimeMillis(): Long =
|
||||
(platform.Foundation.NSDate().timeIntervalSince1970 * 1000).toLong()
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.taskttl.core.notification
|
||||
|
||||
import platform.UserNotifications.*
|
||||
|
||||
actual object NotificationPermissionManager {
|
||||
actual fun requestPermission(callback: NotificationPermissionCallback) {
|
||||
val center = UNUserNotificationCenter.currentNotificationCenter()
|
||||
center.requestAuthorizationWithOptions(
|
||||
UNAuthorizationOptionAlert or UNAuthorizationOptionSound or UNAuthorizationOptionBadge
|
||||
) { granted, _ ->
|
||||
if (granted) callback.onGranted() else callback.onDenied()
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user