Add "clear notifications" menu item

This commit is contained in:
Philipp Heckel 2021-11-07 13:29:19 -05:00
parent e730b1657e
commit 94d45eee3b
4 changed files with 60 additions and 12 deletions

View file

@ -115,6 +115,10 @@ class DetailActivity : AppCompatActivity(), ActionMode.Callback {
onRefreshClick() onRefreshClick()
true true
} }
R.id.detail_menu_clear -> {
onClearClick()
true
}
R.id.detail_menu_unsubscribe -> { R.id.detail_menu_unsubscribe -> {
onDeleteClick() onDeleteClick()
true true
@ -123,7 +127,22 @@ class DetailActivity : AppCompatActivity(), ActionMode.Callback {
} }
} }
private fun onTestClick() {
Log.d(TAG, "Sending test notification to ${topicShortUrl(subscriptionBaseUrl, subscriptionTopic)}")
val message = getString(R.string.detail_test_message, Date().toString())
val successFn = { _: String -> }
val failureFn = { error: VolleyError ->
Toast
.makeText(this, getString(R.string.detail_test_message_error, error.message), Toast.LENGTH_LONG)
.show()
}
api.publish(subscriptionBaseUrl, subscriptionTopic, message, successFn, failureFn)
}
private fun onRefreshClick() { private fun onRefreshClick() {
Log.d(TAG, "Fetching cached notifications for ${topicShortUrl(subscriptionBaseUrl, subscriptionTopic)}")
val activity = this val activity = this
val successFn = { notifications: List<Notification> -> val successFn = { notifications: List<Notification> ->
lifecycleScope.launch(Dispatchers.IO) { lifecycleScope.launch(Dispatchers.IO) {
@ -147,15 +166,16 @@ class DetailActivity : AppCompatActivity(), ActionMode.Callback {
api.poll(subscriptionId, subscriptionBaseUrl, subscriptionTopic, successFn, failureFn) api.poll(subscriptionId, subscriptionBaseUrl, subscriptionTopic, successFn, failureFn)
} }
private fun onTestClick() { private fun onClearClick() {
val message = getString(R.string.detail_test_message, Date().toString()) val builder = AlertDialog.Builder(this)
val successFn = { _: String -> } builder
val failureFn = { error: VolleyError -> .setMessage(R.string.detail_clear_dialog_message)
Toast .setPositiveButton(R.string.detail_clear_dialog_permanently_delete) { _, _ ->
.makeText(this, getString(R.string.detail_test_message_error, error.message), Toast.LENGTH_LONG) viewModel.removeAll(subscriptionId)
.show() }
} .setNegativeButton(R.string.detail_clear_dialog_cancel) { _, _ -> /* Do nothing */ }
api.publish(subscriptionBaseUrl, subscriptionTopic, message, successFn, failureFn) .create()
.show()
} }
private fun onDeleteClick() { private fun onDeleteClick() {

View file

@ -8,15 +8,21 @@ import android.net.Uri
import android.os.Bundle import android.os.Bundle
import android.util.Log import android.util.Log
import android.view.* import android.view.*
import android.widget.Toast
import androidx.activity.viewModels import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import com.google.firebase.messaging.FirebaseMessaging import com.google.firebase.messaging.FirebaseMessaging
import io.heckel.ntfy.R import io.heckel.ntfy.R
import io.heckel.ntfy.app.Application import io.heckel.ntfy.app.Application
import io.heckel.ntfy.data.Notification
import io.heckel.ntfy.data.Subscription import io.heckel.ntfy.data.Subscription
import io.heckel.ntfy.data.topicShortUrl import io.heckel.ntfy.data.topicShortUrl
import io.heckel.ntfy.msg.ApiService
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import java.util.* import java.util.*
import kotlin.random.Random import kotlin.random.Random
@ -24,15 +30,20 @@ class MainActivity : AppCompatActivity(), ActionMode.Callback {
private val viewModel by viewModels<SubscriptionsViewModel> { private val viewModel by viewModels<SubscriptionsViewModel> {
SubscriptionsViewModelFactory((application as Application).repository) SubscriptionsViewModelFactory((application as Application).repository)
} }
private val repository by lazy { (application as Application).repository }
private lateinit var mainList: RecyclerView private lateinit var mainList: RecyclerView
private lateinit var adapter: MainAdapter private lateinit var adapter: MainAdapter
private lateinit var fab: View private lateinit var fab: View
private var actionMode: ActionMode? = null private var actionMode: ActionMode? = null
private lateinit var api: ApiService // Context-dependent
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContentView(R.layout.main_activity) setContentView(R.layout.main_activity)
// Dependencies that depend on Context
api = ApiService(this)
// Action bar // Action bar
title = getString(R.string.main_action_bar_title) title = getString(R.string.main_action_bar_title)
@ -90,8 +101,10 @@ class MainActivity : AppCompatActivity(), ActionMode.Callback {
} }
private fun onSubscribe(topic: String, baseUrl: String) { private fun onSubscribe(topic: String, baseUrl: String) {
// FIXME ignores baseUrl
Log.d(TAG, "Adding subscription ${topicShortUrl(baseUrl, topic)}") Log.d(TAG, "Adding subscription ${topicShortUrl(baseUrl, topic)}")
// Add subscription to database
val subscription = Subscription( val subscription = Subscription(
id = Random.nextLong(), id = Random.nextLong(),
baseUrl = baseUrl, baseUrl = baseUrl,
@ -100,6 +113,8 @@ class MainActivity : AppCompatActivity(), ActionMode.Callback {
lastActive = Date().time/1000 lastActive = Date().time/1000
) )
viewModel.add(subscription) viewModel.add(subscription)
// Subscribe to Firebase topic
FirebaseMessaging FirebaseMessaging
.getInstance() .getInstance()
.subscribeToTopic(topic) .subscribeToTopic(topic)
@ -110,9 +125,17 @@ class MainActivity : AppCompatActivity(), ActionMode.Callback {
Log.e(TAG, "Subscribing to topic failed: $it") Log.e(TAG, "Subscribing to topic failed: $it")
} }
// FIXME ignores baseUrl // Fetch cached messages
val successFn = { notifications: List<Notification> ->
lifecycleScope.launch(Dispatchers.IO) {
notifications.forEach { repository.addNotification(it) }
}
Unit
}
api.poll(subscription.id, subscription.baseUrl, subscription.topic, successFn, { _ -> })
onSubscriptionItemClick(subscription) // Add to detail view after adding it // Switch to detail view after adding it
onSubscriptionItemClick(subscription)
} }
private fun onSubscriptionItemClick(subscription: Subscription) { private fun onSubscriptionItemClick(subscription: Subscription) {

View file

@ -1,5 +1,6 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android" > <menu xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:id="@+id/detail_menu_test" android:title="@string/detail_menu_test"/> <item android:id="@+id/detail_menu_test" android:title="@string/detail_menu_test"/>
<item android:id="@+id/detail_menu_refresh" android:title="@string/detail_menu_refresh"/> <item android:id="@+id/detail_menu_refresh" android:title="@string/detail_menu_refresh"/>
<item android:id="@+id/detail_menu_clear" android:title="@string/detail_menu_clear"/>
<item android:id="@+id/detail_menu_unsubscribe" android:title="@string/detail_menu_unsubscribe"/> <item android:id="@+id/detail_menu_unsubscribe" android:title="@string/detail_menu_unsubscribe"/>
</menu> </menu>

View file

@ -42,6 +42,9 @@
<string name="detail_how_to_intro">To send notifications to this topic, simply PUT or POST to the topic URL.</string> <string name="detail_how_to_intro">To send notifications to this topic, simply PUT or POST to the topic URL.</string>
<string name="detail_how_to_example"><![CDATA[ Example (using curl):<br/><tt>$ curl -d \"Hi\" %1$s</tt> ]]></string> <string name="detail_how_to_example"><![CDATA[ Example (using curl):<br/><tt>$ curl -d \"Hi\" %1$s</tt> ]]></string>
<string name="detail_how_to_link">For more detailed instructions, check out the ntfy.sh website and documentation.</string> <string name="detail_how_to_link">For more detailed instructions, check out the ntfy.sh website and documentation.</string>
<string name="detail_clear_dialog_message">Do you really want to delete all of the messages you received?</string>
<string name="detail_clear_dialog_permanently_delete">Permanently delete</string>
<string name="detail_clear_dialog_cancel">Cancel</string>
<string name="detail_delete_dialog_message">Do you really want to unsubscribe from this topic and delete all of the messages you received?</string> <string name="detail_delete_dialog_message">Do you really want to unsubscribe from this topic and delete all of the messages you received?</string>
<string name="detail_delete_dialog_permanently_delete">Permanently delete</string> <string name="detail_delete_dialog_permanently_delete">Permanently delete</string>
<string name="detail_delete_dialog_cancel">Cancel</string> <string name="detail_delete_dialog_cancel">Cancel</string>
@ -52,8 +55,9 @@
<string name="detail_refresh_message_error">Could not refresh topic: %1$s</string> <string name="detail_refresh_message_error">Could not refresh topic: %1$s</string>
<!-- Detail activity: Action bar --> <!-- Detail activity: Action bar -->
<string name="detail_menu_refresh">Force refresh</string>
<string name="detail_menu_test">Send test notification</string> <string name="detail_menu_test">Send test notification</string>
<string name="detail_menu_refresh">Fetch cached notifications</string>
<string name="detail_menu_clear">Clear notifications</string>
<string name="detail_menu_unsubscribe">Unsubscribe</string> <string name="detail_menu_unsubscribe">Unsubscribe</string>
<!-- Detail activity: Action mode --> <!-- Detail activity: Action mode -->