diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 64c4bdf..877c1f9 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -58,6 +58,20 @@
android:parentActivityName=".ui.DetailActivity">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/java/io/heckel/ntfy/ui/AddFragment.kt b/app/src/main/java/io/heckel/ntfy/ui/AddFragment.kt
index d0b64ec..06675c9 100644
--- a/app/src/main/java/io/heckel/ntfy/ui/AddFragment.kt
+++ b/app/src/main/java/io/heckel/ntfy/ui/AddFragment.kt
@@ -374,6 +374,7 @@ class AddFragment : DialogFragment() {
}
private fun validateInputSubscribeView() {
+ if (!this::positiveButton.isInitialized) return // As per crash seen in Google Play
lifecycleScope.launch(Dispatchers.IO) {
val baseUrl = getBaseUrl()
val topic = subscribeTopicText.text.toString()
@@ -398,6 +399,7 @@ class AddFragment : DialogFragment() {
}
private fun validateInputLoginView() {
+ if (!this::positiveButton.isInitialized) return // As per crash seen in Google Play
if (loginUsernameText.visibility == View.GONE) {
positiveButton.isEnabled = true
} else {
diff --git a/app/src/main/java/io/heckel/ntfy/ui/ShareActivity.kt b/app/src/main/java/io/heckel/ntfy/ui/ShareActivity.kt
new file mode 100644
index 0000000..9a4fcb1
--- /dev/null
+++ b/app/src/main/java/io/heckel/ntfy/ui/ShareActivity.kt
@@ -0,0 +1,134 @@
+package io.heckel.ntfy.ui
+
+import android.content.Intent
+import android.graphics.BitmapFactory
+import android.net.Uri
+import android.os.Bundle
+import android.os.Parcelable
+import android.text.Editable
+import android.text.TextWatcher
+import android.view.Menu
+import android.view.MenuItem
+import android.view.View
+import android.widget.ImageView
+import android.widget.ProgressBar
+import android.widget.TextView
+import androidx.appcompat.app.AppCompatActivity
+import io.heckel.ntfy.R
+import io.heckel.ntfy.app.Application
+import io.heckel.ntfy.msg.ApiService
+import io.heckel.ntfy.util.Log
+
+class ShareActivity : AppCompatActivity() {
+ private val repository by lazy { (application as Application).repository }
+ private val api = ApiService()
+
+ // UI elements
+ private lateinit var menu: Menu
+ private lateinit var sendItem: MenuItem
+ private lateinit var contentImage: ImageView
+ private lateinit var contentText: TextView
+ private lateinit var topicText: TextView
+ private lateinit var progress: ProgressBar
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_share)
+
+ Log.init(this) // Init logs in all entry points
+ Log.d(TAG, "Create $this")
+
+ // Action bar
+ title = getString(R.string.share_title)
+
+ // Show 'Back' button
+ supportActionBar?.setDisplayHomeAsUpEnabled(true)
+
+ // UI elements
+ contentText = findViewById(R.id.share_content_text)
+ contentImage = findViewById(R.id.share_content_image)
+ topicText = findViewById(R.id.share_topic_text)
+ progress = findViewById(R.id.share_progress)
+ progress.visibility = View.GONE
+
+ val textWatcher = object : TextWatcher {
+ override fun afterTextChanged(s: Editable?) {
+ validateInput()
+ }
+ override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
+ // Nothing
+ }
+ override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
+ // Nothing
+ }
+ }
+ topicText.addTextChangedListener(textWatcher)
+
+ // Incoming intent
+ val intent = intent ?: return
+ if (intent.action != Intent.ACTION_SEND) return
+ if ("text/plain" == intent.type) {
+ handleSendText(intent)
+ } else if (intent.type?.startsWith("image/") == true) {
+ handleSendImage(intent)
+ }
+ }
+
+ private fun handleSendText(intent: Intent) {
+ intent.getStringExtra(Intent.EXTRA_TEXT)?.let { text ->
+ contentImage.visibility = View.GONE
+ contentText.text = text
+ }
+ }
+
+ private fun handleSendImage(intent: Intent) {
+ val uri = intent.getParcelableExtra(Intent.EXTRA_STREAM) as? Uri ?: return
+ try {
+ val resolver = applicationContext.contentResolver
+ val bitmapStream = resolver.openInputStream(uri)
+ val bitmap = BitmapFactory.decodeStream(bitmapStream)
+ contentImage.setImageBitmap(bitmap)
+ contentImage.visibility = View.VISIBLE
+ contentText.text = getString(R.string.share_content_image_text)
+ } catch (_: Exception) {
+ contentText.text = getString(R.string.share_content_image_error)
+ }
+ }
+
+ override fun onSupportNavigateUp(): Boolean {
+ finish()
+ return true
+ }
+
+ override fun onCreateOptionsMenu(menu: Menu): Boolean {
+ menuInflater.inflate(R.menu.menu_share_action_bar, menu)
+ this.menu = menu
+ sendItem = menu.findItem(R.id.share_menu_send)
+ validateInput() // Disable icon
+ return true
+ }
+
+ override fun onOptionsItemSelected(item: MenuItem): Boolean {
+ return when (item.itemId) {
+ R.id.share_menu_send -> {
+ onShareClick()
+ true
+ }
+ else -> super.onOptionsItemSelected(item)
+ }
+ }
+
+ private fun onShareClick() {
+
+ }
+
+ private fun validateInput() {
+ if (!this::sendItem.isInitialized) return // Initialized late in onCreateOptionsMenu
+ sendItem.isEnabled = contentText.text.isNotEmpty() && topicText.text.isNotEmpty()
+ sendItem.icon.alpha = if (sendItem.isEnabled) 255 else 130
+ }
+
+ companion object {
+ const val TAG = "NtfyShareActivity"
+ }
+}
diff --git a/app/src/main/res/drawable/ic_send_white_24dp.xml b/app/src/main/res/drawable/ic_send_white_24dp.xml
new file mode 100644
index 0000000..508229c
--- /dev/null
+++ b/app/src/main/res/drawable/ic_send_white_24dp.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/layout/activity_share.xml b/app/src/main/res/layout/activity_share.xml
new file mode 100644
index 0000000..be596ce
--- /dev/null
+++ b/app/src/main/res/layout/activity_share.xml
@@ -0,0 +1,62 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/fragment_add_dialog.xml b/app/src/main/res/layout/fragment_add_dialog.xml
index 7ee8a8c..9de08b0 100644
--- a/app/src/main/res/layout/fragment_add_dialog.xml
+++ b/app/src/main/res/layout/fragment_add_dialog.xml
@@ -15,7 +15,7 @@
android:layout_height="wrap_content"
android:orientation="horizontal">
+ app:layout_constraintTop_toBottomOf="@id/add_dialog_subscribe_title"/>
+
+
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index e2cd1a4..28fa3d7 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -185,6 +185,14 @@
Subscription settings
+
+ Share
+ Share
+ Message preview
+ Add the content you\'d like to share here
+ An image was shared with you.
+ Cannot read image
+
Pause notifications
Cancel
diff --git a/fastlane/metadata/android/en-US/changelog/22.txt b/fastlane/metadata/android/en-US/changelog/22.txt
index b48eecd..39095aa 100644
--- a/fastlane/metadata/android/en-US/changelog/22.txt
+++ b/fastlane/metadata/android/en-US/changelog/22.txt
@@ -4,3 +4,4 @@ Features:
Bug fixes:
* Do not attempt to download attachments if they are already expired (#135)
+* Fixed crash in AddFragment as seen per stack trace in Play Console (no ticket)