diff --git a/app/src/main/kotlin/org/fossify/smsmessenger/activities/ConversationDetailsActivity.kt b/app/src/main/kotlin/org/fossify/smsmessenger/activities/ConversationDetailsActivity.kt index 2d56e165..e4bba951 100644 --- a/app/src/main/kotlin/org/fossify/smsmessenger/activities/ConversationDetailsActivity.kt +++ b/app/src/main/kotlin/org/fossify/smsmessenger/activities/ConversationDetailsActivity.kt @@ -1,10 +1,21 @@ package org.fossify.smsmessenger.activities +import android.app.NotificationChannel +import android.app.NotificationManager +import android.content.Context +import android.content.Intent +import android.media.AudioAttributes +import android.media.AudioManager +import android.media.RingtoneManager +import android.os.Build import android.os.Bundle +import android.provider.Settings +import androidx.annotation.RequiresApi import androidx.core.content.res.ResourcesCompat import org.fossify.commons.extensions.* import org.fossify.commons.helpers.NavigationIcon import org.fossify.commons.helpers.ensureBackgroundThread +import org.fossify.commons.helpers.isOreoPlus import org.fossify.commons.models.SimpleContact import org.fossify.smsmessenger.adapters.ContactsAdapter import org.fossify.smsmessenger.databinding.ActivityConversationDetailsBinding @@ -46,6 +57,9 @@ class ConversationDetailsActivity : SimpleActivity() { runOnUiThread { setupTextViews() setupParticipants() + if (isOreoPlus()) { + setupCustomNotifications() + } } } } @@ -60,6 +74,62 @@ class ConversationDetailsActivity : SimpleActivity() { binding.membersHeading.setTextColor(primaryColor) } + @RequiresApi(Build.VERSION_CODES.O) + private fun setupCustomNotifications() { + binding.apply { + notificationsHeading.beVisible() + customNotificationsHolder.beVisible() + customNotifications.isChecked = config.customNotifications.contains(threadId.toString()) + customNotificationsButton.beVisibleIf(customNotifications.isChecked) + + customNotificationsHolder.setOnClickListener { + customNotifications.toggle() + if (customNotifications.isChecked) { + customNotificationsButton.beVisible() + config.addCustomNotificationsByThreadId(threadId) + createNotificationChannel() + } else { + customNotificationsButton.beGone() + config.removeCustomNotificationsByThreadId(threadId) + removeNotificationChannel() + } + } + + customNotificationsButton.setOnClickListener { + Intent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS).apply { + putExtra(Settings.EXTRA_APP_PACKAGE, packageName) + putExtra(Settings.EXTRA_CHANNEL_ID, threadId.hashCode().toString()) + startActivity(this) + } + } + } + } + + private fun getNotificationManager() = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager + + @RequiresApi(Build.VERSION_CODES.O) + private fun createNotificationChannel() { + val name = conversation?.title + val audioAttributes = AudioAttributes.Builder() + .setUsage(AudioAttributes.USAGE_NOTIFICATION) + .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION) + .setLegacyStreamType(AudioManager.STREAM_NOTIFICATION) + .build() + + NotificationChannel(threadId.hashCode().toString(), name, NotificationManager.IMPORTANCE_HIGH).apply { + setBypassDnd(false) + enableLights(true) + setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION), audioAttributes) + enableVibration(true) + getNotificationManager().createNotificationChannel(this) + } + } + + @RequiresApi(Build.VERSION_CODES.O) + private fun removeNotificationChannel() { + getNotificationManager().deleteNotificationChannel(threadId.hashCode().toString()) + } + private fun setupTextViews() { binding.conversationName.apply { ResourcesCompat.getDrawable(resources, org.fossify.commons.R.drawable.ic_edit_vector, theme)?.apply { diff --git a/app/src/main/kotlin/org/fossify/smsmessenger/extensions/Context.kt b/app/src/main/kotlin/org/fossify/smsmessenger/extensions/Context.kt index 8dadb53c..af7c0da1 100644 --- a/app/src/main/kotlin/org/fossify/smsmessenger/extensions/Context.kt +++ b/app/src/main/kotlin/org/fossify/smsmessenger/extensions/Context.kt @@ -2,6 +2,7 @@ package org.fossify.smsmessenger.extensions import android.annotation.SuppressLint import android.app.Application +import android.app.NotificationManager import android.content.ContentResolver import android.content.ContentValues import android.content.Context @@ -690,6 +691,12 @@ fun Context.deleteConversation(threadId: Long) { conversationsDB.deleteThreadId(threadId) messagesDB.deleteThreadMessages(threadId) + + if (config.customNotifications.contains(threadId.toString()) && isOreoPlus()) { + config.removeCustomNotificationsByThreadId(threadId) + val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager + notificationManager.deleteNotificationChannel(threadId.hashCode().toString()) + } } fun Context.checkAndDeleteOldRecycleBinMessages(callback: (() -> Unit)? = null) { diff --git a/app/src/main/kotlin/org/fossify/smsmessenger/helpers/Config.kt b/app/src/main/kotlin/org/fossify/smsmessenger/helpers/Config.kt index 3550ab60..3f95471a 100644 --- a/app/src/main/kotlin/org/fossify/smsmessenger/helpers/Config.kt +++ b/app/src/main/kotlin/org/fossify/smsmessenger/helpers/Config.kt @@ -115,4 +115,16 @@ class Config(context: Context) : BaseConfig(context) { var isArchiveAvailable: Boolean get() = prefs.getBoolean(IS_ARCHIVE_AVAILABLE, true) set(isArchiveAvailable) = prefs.edit().putBoolean(IS_ARCHIVE_AVAILABLE, isArchiveAvailable).apply() + + var customNotifications: Set + get() = prefs.getStringSet(CUSTOM_NOTIFICATIONS, HashSet())!! + set(customNotifications) = prefs.edit().putStringSet(CUSTOM_NOTIFICATIONS, customNotifications).apply() + + fun addCustomNotificationsByThreadId(threadId: Long) { + customNotifications = customNotifications.plus(threadId.toString()) + } + + fun removeCustomNotificationsByThreadId(threadId: Long) { + customNotifications = customNotifications.minus(threadId.toString()) + } } diff --git a/app/src/main/kotlin/org/fossify/smsmessenger/helpers/Constants.kt b/app/src/main/kotlin/org/fossify/smsmessenger/helpers/Constants.kt index f080960d..fe7e1cdd 100644 --- a/app/src/main/kotlin/org/fossify/smsmessenger/helpers/Constants.kt +++ b/app/src/main/kotlin/org/fossify/smsmessenger/helpers/Constants.kt @@ -44,6 +44,7 @@ const val USE_RECYCLE_BIN = "use_recycle_bin" const val LAST_RECYCLE_BIN_CHECK = "last_recycle_bin_check" const val IS_RECYCLE_BIN = "is_recycle_bin" const val IS_ARCHIVE_AVAILABLE = "is_archive_available" +const val CUSTOM_NOTIFICATIONS = "custom_notifications" private const val PATH = "org.fossify.smsmessenger.action." const val MARK_AS_READ = PATH + "mark_as_read" diff --git a/app/src/main/kotlin/org/fossify/smsmessenger/helpers/NotificationHelper.kt b/app/src/main/kotlin/org/fossify/smsmessenger/helpers/NotificationHelper.kt index 85eb9c8e..f36b85a0 100644 --- a/app/src/main/kotlin/org/fossify/smsmessenger/helpers/NotificationHelper.kt +++ b/app/src/main/kotlin/org/fossify/smsmessenger/helpers/NotificationHelper.kt @@ -45,9 +45,14 @@ class NotificationHelper(private val context: Context) { sender: String?, alertOnlyOnce: Boolean = false ) { - maybeCreateChannel(name = context.getString(R.string.channel_received_sms)) - val notificationId = threadId.hashCode() + + val hasCustomNotifications = context.config.customNotifications.contains(threadId.toString()) + val notificationChannel = if (hasCustomNotifications) notificationId.toString() else NOTIFICATION_CHANNEL + if (!hasCustomNotifications) { + maybeCreateChannel(notificationChannel, context.getString(R.string.channel_received_sms)) + } + val contentIntent = Intent(context, ThreadActivity::class.java).apply { putExtra(THREAD_ID, threadId) } @@ -98,7 +103,7 @@ class NotificationHelper(private val context: Context) { } else { null } - val builder = NotificationCompat.Builder(context, NOTIFICATION_CHANNEL).apply { + val builder = NotificationCompat.Builder(context, notificationChannel).apply { when (context.config.lockScreenVisibilitySetting) { LOCK_SCREEN_SENDER_MESSAGE -> { setLargeIcon(largeIcon) @@ -129,20 +134,24 @@ class NotificationHelper(private val context: Context) { } builder.addAction(org.fossify.commons.R.drawable.ic_check_vector, context.getString(R.string.mark_as_read), markAsReadPendingIntent) - .setChannelId(NOTIFICATION_CHANNEL) + .setChannelId(notificationChannel) if (isNoReplySms) { builder.addAction( org.fossify.commons.R.drawable.ic_delete_vector, context.getString(org.fossify.commons.R.string.delete), deleteSmsPendingIntent - ).setChannelId(NOTIFICATION_CHANNEL) + ).setChannelId(notificationChannel) } notificationManager.notify(notificationId, builder.build()) } @SuppressLint("NewApi") fun showSendingFailedNotification(recipientName: String, threadId: Long) { - maybeCreateChannel(name = context.getString(R.string.message_not_sent_short)) + val hasCustomNotifications = context.config.customNotifications.contains(threadId.toString()) + val notificationChannel = if (hasCustomNotifications) threadId.hashCode().toString() else NOTIFICATION_CHANNEL + if (!hasCustomNotifications) { + maybeCreateChannel(notificationChannel, context.getString(R.string.message_not_sent_short)) + } val notificationId = generateRandomId().hashCode() val intent = Intent(context, ThreadActivity::class.java).apply { @@ -152,7 +161,7 @@ class NotificationHelper(private val context: Context) { val summaryText = String.format(context.getString(R.string.message_sending_error), recipientName) val largeIcon = SimpleContactsHelper(context).getContactLetterIcon(recipientName) - val builder = NotificationCompat.Builder(context, NOTIFICATION_CHANNEL) + val builder = NotificationCompat.Builder(context, notificationChannel) .setContentTitle(context.getString(R.string.message_not_sent_short)) .setContentText(summaryText) .setColor(context.getProperPrimaryColor()) @@ -164,12 +173,12 @@ class NotificationHelper(private val context: Context) { .setDefaults(Notification.DEFAULT_LIGHTS) .setCategory(Notification.CATEGORY_MESSAGE) .setAutoCancel(true) - .setChannelId(NOTIFICATION_CHANNEL) + .setChannelId(notificationChannel) notificationManager.notify(notificationId, builder.build()) } - private fun maybeCreateChannel(name: String) { + private fun maybeCreateChannel(id: String, name: String) { if (isOreoPlus()) { val audioAttributes = AudioAttributes.Builder() .setUsage(AudioAttributes.USAGE_NOTIFICATION) @@ -177,7 +186,6 @@ class NotificationHelper(private val context: Context) { .setLegacyStreamType(AudioManager.STREAM_NOTIFICATION) .build() - val id = NOTIFICATION_CHANNEL val importance = IMPORTANCE_HIGH NotificationChannel(id, name, importance).apply { setBypassDnd(false) diff --git a/app/src/main/res/layout/activity_conversation_details.xml b/app/src/main/res/layout/activity_conversation_details.xml index 85739b65..e4fac71e 100644 --- a/app/src/main/res/layout/activity_conversation_details.xml +++ b/app/src/main/res/layout/activity_conversation_details.xml @@ -21,6 +21,50 @@ android:layout_marginTop="?attr/actionBarSize" android:orientation="vertical"> + + + + + + + + + + + + Oznacz jako przeczytane Oznacz jako nieprzeczytane Ja + Używaj niestandardowych powiadomień Cofnij archiwizację Usuń wszystkie zarchiwizowane rozmowy diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index f40131f9..14abed85 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -58,6 +58,7 @@ Mark as Read Mark as Unread Me + Use custom notifications Unarchive Delete all archived conversations