Loading app/src/main/AndroidManifest.xml +10 −1 Original line number Diff line number Diff line Loading @@ -37,10 +37,19 @@ <!-- Detail activity --> <activity android:name=".ui.DetailActivity" android:parentActivityName=".ui.MainActivity"> android:parentActivityName=".ui.MainActivity" android:exported="true"> <meta-data android:name="android.support.PARENT_ACTIVITY" android:value=".ui.MainActivity"/> <!-- Open ntfy:// links with the app --> <intent-filter android:label="@string/app_name"> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.BROWSABLE" /> <data android:scheme="ntfy" /> </intent-filter> </activity> <!-- Settings activity --> Loading app/src/main/java/io/heckel/ntfy/ui/DetailActivity.kt +73 −3 Original line number Diff line number Diff line Loading @@ -5,6 +5,7 @@ import android.content.ClipData import android.content.ClipboardManager import android.content.Context import android.content.Intent import android.content.Intent.ACTION_VIEW import android.net.Uri import android.os.Bundle import android.text.Html Loading @@ -28,6 +29,7 @@ import io.heckel.ntfy.R import io.heckel.ntfy.app.Application import io.heckel.ntfy.db.Notification import io.heckel.ntfy.db.Repository import io.heckel.ntfy.db.Subscription import io.heckel.ntfy.firebase.FirebaseMessenger import io.heckel.ntfy.util.Log import io.heckel.ntfy.msg.ApiService Loading Loading @@ -70,7 +72,7 @@ class DetailActivity : AppCompatActivity(), ActionMode.Callback, NotificationFra super.onCreate(savedInstanceState) setContentView(R.layout.activity_detail) Log.d(MainActivity.TAG, "Create $this") Log.d(TAG, "Create $this") // Dependencies that depend on Context notifier = NotificationService(this) Loading @@ -79,8 +81,76 @@ class DetailActivity : AppCompatActivity(), ActionMode.Callback, NotificationFra // Show 'Back' button supportActionBar?.setDisplayHomeAsUpEnabled(true) // Handle direct deep links to topic "ntfy://..." val url = intent?.data if (intent?.action == ACTION_VIEW && url != null) { maybeSubscribeAndLoadView(url) } else { loadView() } } private fun maybeSubscribeAndLoadView(url: Uri) { if (url.pathSegments.size != 1) { Log.w(TAG, "Invalid link $url. Aborting.") finish() return } val secure = url.getBooleanQueryParameter("secure", true) val baseUrl = if (secure) "https://${url.host}" else "http://${url.host}" val topic = url.pathSegments.first() title = topicShortUrl(baseUrl, topic) lifecycleScope.launch(Dispatchers.IO) { var subscription = repository.getSubscription(baseUrl, topic) if (subscription == null) { val instant = baseUrl != appBaseUrl subscription = Subscription( id = Random.nextLong(), baseUrl = baseUrl, topic = topic, instant = instant, mutedUntil = 0, upAppId = null, upConnectorToken = null, totalCount = 0, newCount = 0, lastActive = Date().time/1000 ) repository.addSubscription(subscription) // Subscribe to Firebase topic if ntfy.sh (even if instant, just to be sure!) if (baseUrl == appBaseUrl) { Log.d(TAG, "Subscribing to Firebase topic $topic") messenger.subscribe(topic) } // Fetch cached messages try { val user = repository.getUser(subscription.baseUrl) // May be null val notifications = api.poll(subscription.id, subscription.baseUrl, subscription.topic, user) notifications.forEach { notification -> repository.addNotification(notification) } } catch (e: Exception) { Log.e(TAG, "Unable to fetch notifications: ${e.message}", e) } runOnUiThread { val message = getString(R.string.detail_deep_link_subscribed_toast_message, topicShortUrl(baseUrl, topic)) Toast.makeText(this@DetailActivity, message, Toast.LENGTH_LONG).show() } } intent.putExtra(MainActivity.EXTRA_SUBSCRIPTION_ID, subscription.id) intent.putExtra(MainActivity.EXTRA_SUBSCRIPTION_BASE_URL, subscription.baseUrl) intent.putExtra(MainActivity.EXTRA_SUBSCRIPTION_TOPIC, subscription.topic) intent.putExtra(MainActivity.EXTRA_SUBSCRIPTION_INSTANT, subscription.instant) intent.putExtra(MainActivity.EXTRA_SUBSCRIPTION_MUTED_UNTIL, subscription.mutedUntil) runOnUiThread { loadView() } } } private fun loadView() { // Get extras required for the return to the main activity Loading Loading @@ -487,7 +557,7 @@ class DetailActivity : AppCompatActivity(), ActionMode.Callback, NotificationFra val dialog = builder .setMessage(R.string.detail_delete_dialog_message) .setPositiveButton(R.string.detail_delete_dialog_permanently_delete) { _, _ -> Log.d(MainActivity.TAG, "Deleting subscription with subscription ID $subscriptionId (topic: $subscriptionTopic)") Log.d(TAG, "Deleting subscription with subscription ID $subscriptionId (topic: $subscriptionTopic)") GlobalScope.launch(Dispatchers.IO) { repository.removeAllNotifications(subscriptionId) repository.removeSubscription(subscriptionId) Loading app/src/main/res/values-de/strings.xml +2 −1 Original line number Diff line number Diff line Loading @@ -300,4 +300,5 @@ \n%1$s \n \nKennwörter werden immer ersetzt, aber nicht hier aufgelistet.</string> <string name="detail_deep_link_subscribed_toast_message">Thema %1$s abonniert</string> </resources> app/src/main/res/values/strings.xml +1 −0 Original line number Diff line number Diff line Loading @@ -126,6 +126,7 @@ <string name="detail_copied_to_clipboard_message">Copied to clipboard</string> <string name="detail_instant_delivery_enabled">Instant delivery on</string> <string name="detail_instant_delivery_disabled">Instant delivery off</string> <string name="detail_deep_link_subscribed_toast_message">Subscribed to topic %1$s</string> <string name="detail_item_tags">Tags: %1$s</string> <string name="detail_item_snack_deleted">Notification deleted</string> <string name="detail_item_snack_undo">Undo</string> Loading Loading
app/src/main/AndroidManifest.xml +10 −1 Original line number Diff line number Diff line Loading @@ -37,10 +37,19 @@ <!-- Detail activity --> <activity android:name=".ui.DetailActivity" android:parentActivityName=".ui.MainActivity"> android:parentActivityName=".ui.MainActivity" android:exported="true"> <meta-data android:name="android.support.PARENT_ACTIVITY" android:value=".ui.MainActivity"/> <!-- Open ntfy:// links with the app --> <intent-filter android:label="@string/app_name"> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.BROWSABLE" /> <data android:scheme="ntfy" /> </intent-filter> </activity> <!-- Settings activity --> Loading
app/src/main/java/io/heckel/ntfy/ui/DetailActivity.kt +73 −3 Original line number Diff line number Diff line Loading @@ -5,6 +5,7 @@ import android.content.ClipData import android.content.ClipboardManager import android.content.Context import android.content.Intent import android.content.Intent.ACTION_VIEW import android.net.Uri import android.os.Bundle import android.text.Html Loading @@ -28,6 +29,7 @@ import io.heckel.ntfy.R import io.heckel.ntfy.app.Application import io.heckel.ntfy.db.Notification import io.heckel.ntfy.db.Repository import io.heckel.ntfy.db.Subscription import io.heckel.ntfy.firebase.FirebaseMessenger import io.heckel.ntfy.util.Log import io.heckel.ntfy.msg.ApiService Loading Loading @@ -70,7 +72,7 @@ class DetailActivity : AppCompatActivity(), ActionMode.Callback, NotificationFra super.onCreate(savedInstanceState) setContentView(R.layout.activity_detail) Log.d(MainActivity.TAG, "Create $this") Log.d(TAG, "Create $this") // Dependencies that depend on Context notifier = NotificationService(this) Loading @@ -79,8 +81,76 @@ class DetailActivity : AppCompatActivity(), ActionMode.Callback, NotificationFra // Show 'Back' button supportActionBar?.setDisplayHomeAsUpEnabled(true) // Handle direct deep links to topic "ntfy://..." val url = intent?.data if (intent?.action == ACTION_VIEW && url != null) { maybeSubscribeAndLoadView(url) } else { loadView() } } private fun maybeSubscribeAndLoadView(url: Uri) { if (url.pathSegments.size != 1) { Log.w(TAG, "Invalid link $url. Aborting.") finish() return } val secure = url.getBooleanQueryParameter("secure", true) val baseUrl = if (secure) "https://${url.host}" else "http://${url.host}" val topic = url.pathSegments.first() title = topicShortUrl(baseUrl, topic) lifecycleScope.launch(Dispatchers.IO) { var subscription = repository.getSubscription(baseUrl, topic) if (subscription == null) { val instant = baseUrl != appBaseUrl subscription = Subscription( id = Random.nextLong(), baseUrl = baseUrl, topic = topic, instant = instant, mutedUntil = 0, upAppId = null, upConnectorToken = null, totalCount = 0, newCount = 0, lastActive = Date().time/1000 ) repository.addSubscription(subscription) // Subscribe to Firebase topic if ntfy.sh (even if instant, just to be sure!) if (baseUrl == appBaseUrl) { Log.d(TAG, "Subscribing to Firebase topic $topic") messenger.subscribe(topic) } // Fetch cached messages try { val user = repository.getUser(subscription.baseUrl) // May be null val notifications = api.poll(subscription.id, subscription.baseUrl, subscription.topic, user) notifications.forEach { notification -> repository.addNotification(notification) } } catch (e: Exception) { Log.e(TAG, "Unable to fetch notifications: ${e.message}", e) } runOnUiThread { val message = getString(R.string.detail_deep_link_subscribed_toast_message, topicShortUrl(baseUrl, topic)) Toast.makeText(this@DetailActivity, message, Toast.LENGTH_LONG).show() } } intent.putExtra(MainActivity.EXTRA_SUBSCRIPTION_ID, subscription.id) intent.putExtra(MainActivity.EXTRA_SUBSCRIPTION_BASE_URL, subscription.baseUrl) intent.putExtra(MainActivity.EXTRA_SUBSCRIPTION_TOPIC, subscription.topic) intent.putExtra(MainActivity.EXTRA_SUBSCRIPTION_INSTANT, subscription.instant) intent.putExtra(MainActivity.EXTRA_SUBSCRIPTION_MUTED_UNTIL, subscription.mutedUntil) runOnUiThread { loadView() } } } private fun loadView() { // Get extras required for the return to the main activity Loading Loading @@ -487,7 +557,7 @@ class DetailActivity : AppCompatActivity(), ActionMode.Callback, NotificationFra val dialog = builder .setMessage(R.string.detail_delete_dialog_message) .setPositiveButton(R.string.detail_delete_dialog_permanently_delete) { _, _ -> Log.d(MainActivity.TAG, "Deleting subscription with subscription ID $subscriptionId (topic: $subscriptionTopic)") Log.d(TAG, "Deleting subscription with subscription ID $subscriptionId (topic: $subscriptionTopic)") GlobalScope.launch(Dispatchers.IO) { repository.removeAllNotifications(subscriptionId) repository.removeSubscription(subscriptionId) Loading
app/src/main/res/values-de/strings.xml +2 −1 Original line number Diff line number Diff line Loading @@ -300,4 +300,5 @@ \n%1$s \n \nKennwörter werden immer ersetzt, aber nicht hier aufgelistet.</string> <string name="detail_deep_link_subscribed_toast_message">Thema %1$s abonniert</string> </resources>
app/src/main/res/values/strings.xml +1 −0 Original line number Diff line number Diff line Loading @@ -126,6 +126,7 @@ <string name="detail_copied_to_clipboard_message">Copied to clipboard</string> <string name="detail_instant_delivery_enabled">Instant delivery on</string> <string name="detail_instant_delivery_disabled">Instant delivery off</string> <string name="detail_deep_link_subscribed_toast_message">Subscribed to topic %1$s</string> <string name="detail_item_tags">Tags: %1$s</string> <string name="detail_item_snack_deleted">Notification deleted</string> <string name="detail_item_snack_undo">Undo</string> Loading