From 3b30e39eb560b5ef52e929e8b35daaeb3844ad12 Mon Sep 17 00:00:00 2001 From: Philipp Heckel Date: Fri, 11 Feb 2022 10:46:55 -0500 Subject: [PATCH] WIP: Share feature --- app/src/main/AndroidManifest.xml | 14 ++ .../java/io/heckel/ntfy/ui/AddFragment.kt | 2 + .../java/io/heckel/ntfy/ui/ShareActivity.kt | 134 ++++++++++++++++++ .../main/res/drawable/ic_send_white_24dp.xml | 9 ++ app/src/main/res/layout/activity_share.xml | 62 ++++++++ .../main/res/layout/fragment_add_dialog.xml | 4 +- .../main/res/menu/menu_share_action_bar.xml | 4 + app/src/main/res/values/strings.xml | 8 ++ .../metadata/android/en-US/changelog/22.txt | 1 + 9 files changed, 236 insertions(+), 2 deletions(-) create mode 100644 app/src/main/java/io/heckel/ntfy/ui/ShareActivity.kt create mode 100644 app/src/main/res/drawable/ic_send_white_24dp.xml create mode 100644 app/src/main/res/layout/activity_share.xml create mode 100644 app/src/main/res/menu/menu_share_action_bar.xml 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)