Loading app/src/main/java/io/heckel/ntfy/data/Repository.kt +28 −1 Original line number Original line Diff line number Diff line Loading @@ -143,9 +143,34 @@ class Repository(private val sharedPrefs: SharedPreferences, private val subscri .apply() .apply() } } fun setMinPriority(minPriority: Int) { if (minPriority <= 1) { sharedPrefs.edit() .remove(SHARED_PREFS_MIN_PRIORITY) .apply() } else { sharedPrefs.edit() .putInt(SHARED_PREFS_MIN_PRIORITY, minPriority) .apply() } } fun getMinPriority(): Int { return sharedPrefs.getInt(SHARED_PREFS_MIN_PRIORITY, 1) // 1/low means all priorities } fun getBroadcastEnabled(): Boolean { return sharedPrefs.getBoolean(SHARED_PREFS_BROADCAST_ENABLED, true) // Enabled by default } fun setBroadcastEnabled(enabled: Boolean) { sharedPrefs.edit() .putBoolean(SHARED_PREFS_BROADCAST_ENABLED, enabled) .apply() } fun getUnifiedPushEnabled(): Boolean { fun getUnifiedPushEnabled(): Boolean { return sharedPrefs.getBoolean(SHARED_PREFS_UNIFIED_PUSH_ENABLED, true) // Enabled by default! return sharedPrefs.getBoolean(SHARED_PREFS_UNIFIED_PUSH_ENABLED, true) // Enabled by default } } fun setUnifiedPushEnabled(enabled: Boolean) { fun setUnifiedPushEnabled(enabled: Boolean) { Loading Loading @@ -263,6 +288,8 @@ class Repository(private val sharedPrefs: SharedPreferences, private val subscri const val SHARED_PREFS_POLL_WORKER_VERSION = "PollWorkerVersion" const val SHARED_PREFS_POLL_WORKER_VERSION = "PollWorkerVersion" const val SHARED_PREFS_AUTO_RESTART_WORKER_VERSION = "AutoRestartWorkerVersion" const val SHARED_PREFS_AUTO_RESTART_WORKER_VERSION = "AutoRestartWorkerVersion" const val SHARED_PREFS_MUTED_UNTIL_TIMESTAMP = "MutedUntil" const val SHARED_PREFS_MUTED_UNTIL_TIMESTAMP = "MutedUntil" const val SHARED_PREFS_MIN_PRIORITY = "MinPriority" const val SHARED_PREFS_BROADCAST_ENABLED = "BroadcastEnabled" const val SHARED_PREFS_UNIFIED_PUSH_ENABLED = "UnifiedPushEnabled" const val SHARED_PREFS_UNIFIED_PUSH_ENABLED = "UnifiedPushEnabled" const val SHARED_PREFS_UNIFIED_PUSH_BASE_URL = "UnifiedPushBaseURL" const val SHARED_PREFS_UNIFIED_PUSH_BASE_URL = "UnifiedPushBaseURL" Loading app/src/main/java/io/heckel/ntfy/msg/BroadcastService.kt +34 −19 Original line number Original line Diff line number Diff line Loading @@ -13,8 +13,8 @@ import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.launch import kotlinx.coroutines.launch /** /** * The broadcast service is responsible for sending and receiving broadcasted intents * The broadcast service is responsible for sending and receiving broadcast intents * in order to facilitate taks app integrations. * in order to facilitate tasks app integrations. */ */ class BroadcastService(private val ctx: Context) { class BroadcastService(private val ctx: Context) { fun send(subscription: Subscription, notification: Notification, muted: Boolean) { fun send(subscription: Subscription, notification: Notification, muted: Boolean) { Loading @@ -36,6 +36,10 @@ class BroadcastService(private val ctx: Context) { ctx.sendBroadcast(intent) ctx.sendBroadcast(intent) } } /** * This receiver is triggered when the SEND_MESSAGE intent is received. * See AndroidManifest.xml for details. */ class BroadcastReceiver : android.content.BroadcastReceiver() { class BroadcastReceiver : android.content.BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { override fun onReceive(context: Context, intent: Intent) { Log.d(TAG, "Broadcast received: $intent") Log.d(TAG, "Broadcast received: $intent") Loading @@ -46,13 +50,12 @@ class BroadcastService(private val ctx: Context) { private fun send(ctx: Context, intent: Intent) { private fun send(ctx: Context, intent: Intent) { val api = ApiService() val api = ApiService() val baseUrl = intent.getStringExtra("base_url") ?: ctx.getString(R.string.app_base_url) val baseUrl = getStringExtra(intent, "base_url") ?: ctx.getString(R.string.app_base_url) val topic = intent.getStringExtra("topic") ?: return val topic = getStringExtra(intent, "topic") ?: return val message = intent.getStringExtra("message") ?: return val message = getStringExtra(intent, "message") ?: return val title = intent.getStringExtra("title") ?: "" val title = getStringExtra(intent, "title") ?: "" val tags = intent.getStringExtra("tags") ?: "" val tags = getStringExtra(intent,"tags") ?: "" val priority = if (intent.getStringExtra("priority") != null) { val priority = when (getStringExtra(intent, "priority")) { when (intent.getStringExtra("priority")) { "min", "1" -> 1 "min", "1" -> 1 "low", "2" -> 2 "low", "2" -> 2 "default", "3" -> 3 "default", "3" -> 3 Loading @@ -60,10 +63,7 @@ class BroadcastService(private val ctx: Context) { "urgent", "max", "5" -> 5 "urgent", "max", "5" -> 5 else -> 0 else -> 0 } } } else { val delay = getStringExtra(intent,"delay") ?: "" intent.getIntExtra("priority", 0) } val delay = intent.getStringExtra("delay") ?: "" GlobalScope.launch(Dispatchers.IO) { GlobalScope.launch(Dispatchers.IO) { api.publish( api.publish( baseUrl = baseUrl, baseUrl = baseUrl, Loading @@ -76,11 +76,26 @@ class BroadcastService(private val ctx: Context) { ) ) } } } } /** * Gets an extra as a String value, even if the extra may be an int or a long. */ private fun getStringExtra(intent: Intent, name: String): String? { if (intent.getStringExtra(name) != null) { return intent.getStringExtra(name) } else if (intent.getIntExtra(name, DOES_NOT_EXIST) != DOES_NOT_EXIST) { return intent.getIntExtra(name, DOES_NOT_EXIST).toString() } else if (intent.getLongExtra(name, DOES_NOT_EXIST.toLong()) != DOES_NOT_EXIST.toLong()) { return intent.getLongExtra(name, DOES_NOT_EXIST.toLong()).toString() } return null } } } companion object { companion object { private const val TAG = "NtfyBroadcastService" private const val TAG = "NtfyBroadcastService" private const val MESSAGE_RECEIVED_ACTION = "io.heckel.ntfy.MESSAGE_RECEIVED" private const val MESSAGE_RECEIVED_ACTION = "io.heckel.ntfy.MESSAGE_RECEIVED" private const val MESSAGE_SEND_ACTION = "io.heckel.ntfy.SEND_MESSAGE" // If changed, change in manifest too! private const val MESSAGE_SEND_ACTION = "io.heckel.ntfy.SEND_MESSAGE" // If changed, change in manifest too! private const val DOES_NOT_EXIST = -2586000 } } } } app/src/main/java/io/heckel/ntfy/msg/NotificationDispatcher.kt +21 −6 Original line number Original line Diff line number Diff line Loading @@ -21,10 +21,10 @@ class NotificationDispatcher(val context: Context, val repository: Repository) { } } fun dispatch(subscription: Subscription, notification: Notification) { fun dispatch(subscription: Subscription, notification: Notification) { val muted = checkMuted(subscription) val muted = getMuted(subscription) val notify = checkNotify(subscription, notification, muted) val notify = shouldNotify(subscription, notification, muted) val broadcast = subscription.upAppId == null // Never broadcast for UnifiedPush val broadcast = shouldBroadcast(subscription) val distribute = subscription.upAppId != null // Only distribute for UnifiedPush subscriptions val distribute = shouldDistribute(subscription) if (notify) { if (notify) { notifier.send(subscription, notification) notifier.send(subscription, notification) } } Loading @@ -38,15 +38,30 @@ class NotificationDispatcher(val context: Context, val repository: Repository) { } } } } private fun checkNotify(subscription: Subscription, notification: Notification, muted: Boolean): Boolean { private fun shouldNotify(subscription: Subscription, notification: Notification, muted: Boolean): Boolean { if (subscription.upAppId != null) { if (subscription.upAppId != null) { return false return false } } val priority = if (notification.priority > 0) notification.priority else 3 if (priority < repository.getMinPriority()) { return false } val detailsVisible = repository.detailViewSubscriptionId.get() == notification.subscriptionId val detailsVisible = repository.detailViewSubscriptionId.get() == notification.subscriptionId return !detailsVisible && !muted return !detailsVisible && !muted } } private fun checkMuted(subscription: Subscription): Boolean { private fun shouldBroadcast(subscription: Subscription): Boolean { if (subscription.upAppId != null) { // Never broadcast for UnifiedPush subscriptions return false } return repository.getBroadcastEnabled() } private fun shouldDistribute(subscription: Subscription): Boolean { return subscription.upAppId != null // Only distribute for UnifiedPush subscriptions } private fun getMuted(subscription: Subscription): Boolean { if (repository.isGlobalMuted()) { if (repository.isGlobalMuted()) { return true return true } } Loading app/src/main/java/io/heckel/ntfy/ui/MainActivity.kt +2 −1 Original line number Original line Diff line number Diff line Loading @@ -87,7 +87,7 @@ class MainActivity : AppCompatActivity(), ActionMode.Callback, AddFragment.Subsc val onSubscriptionLongClick = { s: Subscription -> onSubscriptionItemLongClick(s) } val onSubscriptionLongClick = { s: Subscription -> onSubscriptionItemLongClick(s) } mainList = findViewById(R.id.main_subscriptions_list) mainList = findViewById(R.id.main_subscriptions_list) adapter = MainAdapter(onSubscriptionClick, onSubscriptionLongClick) adapter = MainAdapter(repository, onSubscriptionClick, onSubscriptionLongClick) mainList.adapter = adapter mainList.adapter = adapter viewModel.list().observe(this) { viewModel.list().observe(this) { Loading Loading @@ -261,6 +261,7 @@ class MainActivity : AppCompatActivity(), ActionMode.Callback, AddFragment.Subsc repository.setGlobalMutedUntil(mutedUntilTimestamp) repository.setGlobalMutedUntil(mutedUntilTimestamp) showHideNotificationMenuItems() showHideNotificationMenuItems() runOnUiThread { runOnUiThread { redrawList() // Update the "muted until" icons when (mutedUntilTimestamp) { when (mutedUntilTimestamp) { 0L -> Toast.makeText(this@MainActivity, getString(R.string.notification_dialog_enabled_toast_message), Toast.LENGTH_LONG).show() 0L -> Toast.makeText(this@MainActivity, getString(R.string.notification_dialog_enabled_toast_message), Toast.LENGTH_LONG).show() 1L -> Toast.makeText(this@MainActivity, getString(R.string.notification_dialog_muted_forever_toast_message), Toast.LENGTH_LONG).show() 1L -> Toast.makeText(this@MainActivity, getString(R.string.notification_dialog_muted_forever_toast_message), Toast.LENGTH_LONG).show() Loading app/src/main/java/io/heckel/ntfy/ui/MainAdapter.kt +9 −5 Original line number Original line Diff line number Diff line Loading @@ -10,12 +10,13 @@ import androidx.recyclerview.widget.ListAdapter import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView import io.heckel.ntfy.R import io.heckel.ntfy.R import io.heckel.ntfy.data.ConnectionState import io.heckel.ntfy.data.ConnectionState import io.heckel.ntfy.data.Repository import io.heckel.ntfy.data.Subscription import io.heckel.ntfy.data.Subscription import io.heckel.ntfy.util.topicShortUrl import io.heckel.ntfy.util.topicShortUrl import java.text.DateFormat import java.text.DateFormat import java.util.* import java.util.* class MainAdapter(private val onClick: (Subscription) -> Unit, private val onLongClick: (Subscription) -> Unit) : class MainAdapter(private val repository: Repository, private val onClick: (Subscription) -> Unit, private val onLongClick: (Subscription) -> Unit) : ListAdapter<Subscription, MainAdapter.SubscriptionViewHolder>(TopicDiffCallback) { ListAdapter<Subscription, MainAdapter.SubscriptionViewHolder>(TopicDiffCallback) { val selected = mutableSetOf<Long>() // Subscription IDs val selected = mutableSetOf<Long>() // Subscription IDs Loading @@ -23,7 +24,7 @@ class MainAdapter(private val onClick: (Subscription) -> Unit, private val onLon override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SubscriptionViewHolder { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SubscriptionViewHolder { val view = LayoutInflater.from(parent.context) val view = LayoutInflater.from(parent.context) .inflate(R.layout.fragment_main_item, parent, false) .inflate(R.layout.fragment_main_item, parent, false) return SubscriptionViewHolder(view, selected, onClick, onLongClick) return SubscriptionViewHolder(view, repository, selected, onClick, onLongClick) } } /* Gets current topic and uses it to bind view. */ /* Gets current topic and uses it to bind view. */ Loading @@ -41,7 +42,7 @@ class MainAdapter(private val onClick: (Subscription) -> Unit, private val onLon } } /* ViewHolder for Topic, takes in the inflated view and the onClick behavior. */ /* ViewHolder for Topic, takes in the inflated view and the onClick behavior. */ class SubscriptionViewHolder(itemView: View, private val selected: Set<Long>, val onClick: (Subscription) -> Unit, val onLongClick: (Subscription) -> Unit) : class SubscriptionViewHolder(itemView: View, private val repository: Repository, private val selected: Set<Long>, val onClick: (Subscription) -> Unit, val onLongClick: (Subscription) -> Unit) : RecyclerView.ViewHolder(itemView) { RecyclerView.ViewHolder(itemView) { private var subscription: Subscription? = null private var subscription: Subscription? = null private val context: Context = itemView.context private val context: Context = itemView.context Loading Loading @@ -78,11 +79,14 @@ class MainAdapter(private val onClick: (Subscription) -> Unit, private val onLon } else { } else { dateStr dateStr } } val globalMutedUntil = repository.getGlobalMutedUntil() val showMutedForeverIcon = (subscription.mutedUntil == 1L || globalMutedUntil == 1L) && subscription.upAppId == null val showMutedUntilIcon = !showMutedForeverIcon && (subscription.mutedUntil > 1L || globalMutedUntil > 1L) && subscription.upAppId == null nameView.text = topicShortUrl(subscription.baseUrl, subscription.topic) nameView.text = topicShortUrl(subscription.baseUrl, subscription.topic) statusView.text = statusMessage statusView.text = statusMessage dateView.text = dateText dateView.text = dateText notificationDisabledUntilImageView.visibility = if (subscription.mutedUntil > 1L) View.VISIBLE else View.GONE notificationDisabledUntilImageView.visibility = if (showMutedUntilIcon) View.VISIBLE else View.GONE notificationDisabledForeverImageView.visibility = if (subscription.mutedUntil == 1L) View.VISIBLE else View.GONE notificationDisabledForeverImageView.visibility = if (showMutedForeverIcon) View.VISIBLE else View.GONE instantImageView.visibility = if (subscription.instant) View.VISIBLE else View.GONE instantImageView.visibility = if (subscription.instant) View.VISIBLE else View.GONE if (subscription.upAppId != null || subscription.newCount == 0) { if (subscription.upAppId != null || subscription.newCount == 0) { newItemsView.visibility = View.GONE newItemsView.visibility = View.GONE Loading Loading
app/src/main/java/io/heckel/ntfy/data/Repository.kt +28 −1 Original line number Original line Diff line number Diff line Loading @@ -143,9 +143,34 @@ class Repository(private val sharedPrefs: SharedPreferences, private val subscri .apply() .apply() } } fun setMinPriority(minPriority: Int) { if (minPriority <= 1) { sharedPrefs.edit() .remove(SHARED_PREFS_MIN_PRIORITY) .apply() } else { sharedPrefs.edit() .putInt(SHARED_PREFS_MIN_PRIORITY, minPriority) .apply() } } fun getMinPriority(): Int { return sharedPrefs.getInt(SHARED_PREFS_MIN_PRIORITY, 1) // 1/low means all priorities } fun getBroadcastEnabled(): Boolean { return sharedPrefs.getBoolean(SHARED_PREFS_BROADCAST_ENABLED, true) // Enabled by default } fun setBroadcastEnabled(enabled: Boolean) { sharedPrefs.edit() .putBoolean(SHARED_PREFS_BROADCAST_ENABLED, enabled) .apply() } fun getUnifiedPushEnabled(): Boolean { fun getUnifiedPushEnabled(): Boolean { return sharedPrefs.getBoolean(SHARED_PREFS_UNIFIED_PUSH_ENABLED, true) // Enabled by default! return sharedPrefs.getBoolean(SHARED_PREFS_UNIFIED_PUSH_ENABLED, true) // Enabled by default } } fun setUnifiedPushEnabled(enabled: Boolean) { fun setUnifiedPushEnabled(enabled: Boolean) { Loading Loading @@ -263,6 +288,8 @@ class Repository(private val sharedPrefs: SharedPreferences, private val subscri const val SHARED_PREFS_POLL_WORKER_VERSION = "PollWorkerVersion" const val SHARED_PREFS_POLL_WORKER_VERSION = "PollWorkerVersion" const val SHARED_PREFS_AUTO_RESTART_WORKER_VERSION = "AutoRestartWorkerVersion" const val SHARED_PREFS_AUTO_RESTART_WORKER_VERSION = "AutoRestartWorkerVersion" const val SHARED_PREFS_MUTED_UNTIL_TIMESTAMP = "MutedUntil" const val SHARED_PREFS_MUTED_UNTIL_TIMESTAMP = "MutedUntil" const val SHARED_PREFS_MIN_PRIORITY = "MinPriority" const val SHARED_PREFS_BROADCAST_ENABLED = "BroadcastEnabled" const val SHARED_PREFS_UNIFIED_PUSH_ENABLED = "UnifiedPushEnabled" const val SHARED_PREFS_UNIFIED_PUSH_ENABLED = "UnifiedPushEnabled" const val SHARED_PREFS_UNIFIED_PUSH_BASE_URL = "UnifiedPushBaseURL" const val SHARED_PREFS_UNIFIED_PUSH_BASE_URL = "UnifiedPushBaseURL" Loading
app/src/main/java/io/heckel/ntfy/msg/BroadcastService.kt +34 −19 Original line number Original line Diff line number Diff line Loading @@ -13,8 +13,8 @@ import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.launch import kotlinx.coroutines.launch /** /** * The broadcast service is responsible for sending and receiving broadcasted intents * The broadcast service is responsible for sending and receiving broadcast intents * in order to facilitate taks app integrations. * in order to facilitate tasks app integrations. */ */ class BroadcastService(private val ctx: Context) { class BroadcastService(private val ctx: Context) { fun send(subscription: Subscription, notification: Notification, muted: Boolean) { fun send(subscription: Subscription, notification: Notification, muted: Boolean) { Loading @@ -36,6 +36,10 @@ class BroadcastService(private val ctx: Context) { ctx.sendBroadcast(intent) ctx.sendBroadcast(intent) } } /** * This receiver is triggered when the SEND_MESSAGE intent is received. * See AndroidManifest.xml for details. */ class BroadcastReceiver : android.content.BroadcastReceiver() { class BroadcastReceiver : android.content.BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { override fun onReceive(context: Context, intent: Intent) { Log.d(TAG, "Broadcast received: $intent") Log.d(TAG, "Broadcast received: $intent") Loading @@ -46,13 +50,12 @@ class BroadcastService(private val ctx: Context) { private fun send(ctx: Context, intent: Intent) { private fun send(ctx: Context, intent: Intent) { val api = ApiService() val api = ApiService() val baseUrl = intent.getStringExtra("base_url") ?: ctx.getString(R.string.app_base_url) val baseUrl = getStringExtra(intent, "base_url") ?: ctx.getString(R.string.app_base_url) val topic = intent.getStringExtra("topic") ?: return val topic = getStringExtra(intent, "topic") ?: return val message = intent.getStringExtra("message") ?: return val message = getStringExtra(intent, "message") ?: return val title = intent.getStringExtra("title") ?: "" val title = getStringExtra(intent, "title") ?: "" val tags = intent.getStringExtra("tags") ?: "" val tags = getStringExtra(intent,"tags") ?: "" val priority = if (intent.getStringExtra("priority") != null) { val priority = when (getStringExtra(intent, "priority")) { when (intent.getStringExtra("priority")) { "min", "1" -> 1 "min", "1" -> 1 "low", "2" -> 2 "low", "2" -> 2 "default", "3" -> 3 "default", "3" -> 3 Loading @@ -60,10 +63,7 @@ class BroadcastService(private val ctx: Context) { "urgent", "max", "5" -> 5 "urgent", "max", "5" -> 5 else -> 0 else -> 0 } } } else { val delay = getStringExtra(intent,"delay") ?: "" intent.getIntExtra("priority", 0) } val delay = intent.getStringExtra("delay") ?: "" GlobalScope.launch(Dispatchers.IO) { GlobalScope.launch(Dispatchers.IO) { api.publish( api.publish( baseUrl = baseUrl, baseUrl = baseUrl, Loading @@ -76,11 +76,26 @@ class BroadcastService(private val ctx: Context) { ) ) } } } } /** * Gets an extra as a String value, even if the extra may be an int or a long. */ private fun getStringExtra(intent: Intent, name: String): String? { if (intent.getStringExtra(name) != null) { return intent.getStringExtra(name) } else if (intent.getIntExtra(name, DOES_NOT_EXIST) != DOES_NOT_EXIST) { return intent.getIntExtra(name, DOES_NOT_EXIST).toString() } else if (intent.getLongExtra(name, DOES_NOT_EXIST.toLong()) != DOES_NOT_EXIST.toLong()) { return intent.getLongExtra(name, DOES_NOT_EXIST.toLong()).toString() } return null } } } companion object { companion object { private const val TAG = "NtfyBroadcastService" private const val TAG = "NtfyBroadcastService" private const val MESSAGE_RECEIVED_ACTION = "io.heckel.ntfy.MESSAGE_RECEIVED" private const val MESSAGE_RECEIVED_ACTION = "io.heckel.ntfy.MESSAGE_RECEIVED" private const val MESSAGE_SEND_ACTION = "io.heckel.ntfy.SEND_MESSAGE" // If changed, change in manifest too! private const val MESSAGE_SEND_ACTION = "io.heckel.ntfy.SEND_MESSAGE" // If changed, change in manifest too! private const val DOES_NOT_EXIST = -2586000 } } } }
app/src/main/java/io/heckel/ntfy/msg/NotificationDispatcher.kt +21 −6 Original line number Original line Diff line number Diff line Loading @@ -21,10 +21,10 @@ class NotificationDispatcher(val context: Context, val repository: Repository) { } } fun dispatch(subscription: Subscription, notification: Notification) { fun dispatch(subscription: Subscription, notification: Notification) { val muted = checkMuted(subscription) val muted = getMuted(subscription) val notify = checkNotify(subscription, notification, muted) val notify = shouldNotify(subscription, notification, muted) val broadcast = subscription.upAppId == null // Never broadcast for UnifiedPush val broadcast = shouldBroadcast(subscription) val distribute = subscription.upAppId != null // Only distribute for UnifiedPush subscriptions val distribute = shouldDistribute(subscription) if (notify) { if (notify) { notifier.send(subscription, notification) notifier.send(subscription, notification) } } Loading @@ -38,15 +38,30 @@ class NotificationDispatcher(val context: Context, val repository: Repository) { } } } } private fun checkNotify(subscription: Subscription, notification: Notification, muted: Boolean): Boolean { private fun shouldNotify(subscription: Subscription, notification: Notification, muted: Boolean): Boolean { if (subscription.upAppId != null) { if (subscription.upAppId != null) { return false return false } } val priority = if (notification.priority > 0) notification.priority else 3 if (priority < repository.getMinPriority()) { return false } val detailsVisible = repository.detailViewSubscriptionId.get() == notification.subscriptionId val detailsVisible = repository.detailViewSubscriptionId.get() == notification.subscriptionId return !detailsVisible && !muted return !detailsVisible && !muted } } private fun checkMuted(subscription: Subscription): Boolean { private fun shouldBroadcast(subscription: Subscription): Boolean { if (subscription.upAppId != null) { // Never broadcast for UnifiedPush subscriptions return false } return repository.getBroadcastEnabled() } private fun shouldDistribute(subscription: Subscription): Boolean { return subscription.upAppId != null // Only distribute for UnifiedPush subscriptions } private fun getMuted(subscription: Subscription): Boolean { if (repository.isGlobalMuted()) { if (repository.isGlobalMuted()) { return true return true } } Loading
app/src/main/java/io/heckel/ntfy/ui/MainActivity.kt +2 −1 Original line number Original line Diff line number Diff line Loading @@ -87,7 +87,7 @@ class MainActivity : AppCompatActivity(), ActionMode.Callback, AddFragment.Subsc val onSubscriptionLongClick = { s: Subscription -> onSubscriptionItemLongClick(s) } val onSubscriptionLongClick = { s: Subscription -> onSubscriptionItemLongClick(s) } mainList = findViewById(R.id.main_subscriptions_list) mainList = findViewById(R.id.main_subscriptions_list) adapter = MainAdapter(onSubscriptionClick, onSubscriptionLongClick) adapter = MainAdapter(repository, onSubscriptionClick, onSubscriptionLongClick) mainList.adapter = adapter mainList.adapter = adapter viewModel.list().observe(this) { viewModel.list().observe(this) { Loading Loading @@ -261,6 +261,7 @@ class MainActivity : AppCompatActivity(), ActionMode.Callback, AddFragment.Subsc repository.setGlobalMutedUntil(mutedUntilTimestamp) repository.setGlobalMutedUntil(mutedUntilTimestamp) showHideNotificationMenuItems() showHideNotificationMenuItems() runOnUiThread { runOnUiThread { redrawList() // Update the "muted until" icons when (mutedUntilTimestamp) { when (mutedUntilTimestamp) { 0L -> Toast.makeText(this@MainActivity, getString(R.string.notification_dialog_enabled_toast_message), Toast.LENGTH_LONG).show() 0L -> Toast.makeText(this@MainActivity, getString(R.string.notification_dialog_enabled_toast_message), Toast.LENGTH_LONG).show() 1L -> Toast.makeText(this@MainActivity, getString(R.string.notification_dialog_muted_forever_toast_message), Toast.LENGTH_LONG).show() 1L -> Toast.makeText(this@MainActivity, getString(R.string.notification_dialog_muted_forever_toast_message), Toast.LENGTH_LONG).show() Loading
app/src/main/java/io/heckel/ntfy/ui/MainAdapter.kt +9 −5 Original line number Original line Diff line number Diff line Loading @@ -10,12 +10,13 @@ import androidx.recyclerview.widget.ListAdapter import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView import io.heckel.ntfy.R import io.heckel.ntfy.R import io.heckel.ntfy.data.ConnectionState import io.heckel.ntfy.data.ConnectionState import io.heckel.ntfy.data.Repository import io.heckel.ntfy.data.Subscription import io.heckel.ntfy.data.Subscription import io.heckel.ntfy.util.topicShortUrl import io.heckel.ntfy.util.topicShortUrl import java.text.DateFormat import java.text.DateFormat import java.util.* import java.util.* class MainAdapter(private val onClick: (Subscription) -> Unit, private val onLongClick: (Subscription) -> Unit) : class MainAdapter(private val repository: Repository, private val onClick: (Subscription) -> Unit, private val onLongClick: (Subscription) -> Unit) : ListAdapter<Subscription, MainAdapter.SubscriptionViewHolder>(TopicDiffCallback) { ListAdapter<Subscription, MainAdapter.SubscriptionViewHolder>(TopicDiffCallback) { val selected = mutableSetOf<Long>() // Subscription IDs val selected = mutableSetOf<Long>() // Subscription IDs Loading @@ -23,7 +24,7 @@ class MainAdapter(private val onClick: (Subscription) -> Unit, private val onLon override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SubscriptionViewHolder { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SubscriptionViewHolder { val view = LayoutInflater.from(parent.context) val view = LayoutInflater.from(parent.context) .inflate(R.layout.fragment_main_item, parent, false) .inflate(R.layout.fragment_main_item, parent, false) return SubscriptionViewHolder(view, selected, onClick, onLongClick) return SubscriptionViewHolder(view, repository, selected, onClick, onLongClick) } } /* Gets current topic and uses it to bind view. */ /* Gets current topic and uses it to bind view. */ Loading @@ -41,7 +42,7 @@ class MainAdapter(private val onClick: (Subscription) -> Unit, private val onLon } } /* ViewHolder for Topic, takes in the inflated view and the onClick behavior. */ /* ViewHolder for Topic, takes in the inflated view and the onClick behavior. */ class SubscriptionViewHolder(itemView: View, private val selected: Set<Long>, val onClick: (Subscription) -> Unit, val onLongClick: (Subscription) -> Unit) : class SubscriptionViewHolder(itemView: View, private val repository: Repository, private val selected: Set<Long>, val onClick: (Subscription) -> Unit, val onLongClick: (Subscription) -> Unit) : RecyclerView.ViewHolder(itemView) { RecyclerView.ViewHolder(itemView) { private var subscription: Subscription? = null private var subscription: Subscription? = null private val context: Context = itemView.context private val context: Context = itemView.context Loading Loading @@ -78,11 +79,14 @@ class MainAdapter(private val onClick: (Subscription) -> Unit, private val onLon } else { } else { dateStr dateStr } } val globalMutedUntil = repository.getGlobalMutedUntil() val showMutedForeverIcon = (subscription.mutedUntil == 1L || globalMutedUntil == 1L) && subscription.upAppId == null val showMutedUntilIcon = !showMutedForeverIcon && (subscription.mutedUntil > 1L || globalMutedUntil > 1L) && subscription.upAppId == null nameView.text = topicShortUrl(subscription.baseUrl, subscription.topic) nameView.text = topicShortUrl(subscription.baseUrl, subscription.topic) statusView.text = statusMessage statusView.text = statusMessage dateView.text = dateText dateView.text = dateText notificationDisabledUntilImageView.visibility = if (subscription.mutedUntil > 1L) View.VISIBLE else View.GONE notificationDisabledUntilImageView.visibility = if (showMutedUntilIcon) View.VISIBLE else View.GONE notificationDisabledForeverImageView.visibility = if (subscription.mutedUntil == 1L) View.VISIBLE else View.GONE notificationDisabledForeverImageView.visibility = if (showMutedForeverIcon) View.VISIBLE else View.GONE instantImageView.visibility = if (subscription.instant) View.VISIBLE else View.GONE instantImageView.visibility = if (subscription.instant) View.VISIBLE else View.GONE if (subscription.upAppId != null || subscription.newCount == 0) { if (subscription.upAppId != null || subscription.newCount == 0) { newItemsView.visibility = View.GONE newItemsView.visibility = View.GONE Loading