WIP: Share feature
This commit is contained in:
parent
9ca5ebe6d2
commit
3b30e39eb5
9 changed files with 236 additions and 2 deletions
|
@ -58,6 +58,20 @@
|
|||
android:parentActivityName=".ui.DetailActivity">
|
||||
</activity>
|
||||
|
||||
<!-- Share file activity, incoming files/shares -->
|
||||
<activity android:name=".ui.ShareActivity" android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.SEND" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<data android:mimeType="image/*" />
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.SEND" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<data android:mimeType="text/plain" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<!-- Subscriber foreground service for hosts other than ntfy.sh -->
|
||||
<service android:name=".service.SubscriberService"/>
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
134
app/src/main/java/io/heckel/ntfy/ui/ShareActivity.kt
Normal file
134
app/src/main/java/io/heckel/ntfy/ui/ShareActivity.kt
Normal file
|
@ -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<Parcelable>(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"
|
||||
}
|
||||
}
|
9
app/src/main/res/drawable/ic_send_white_24dp.xml
Normal file
9
app/src/main/res/drawable/ic_send_white_24dp.xml
Normal file
|
@ -0,0 +1,9 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="M4.01,6.03l7.51,3.22 -7.52,-1 0.01,-2.22m7.5,8.72L4,17.97v-2.22l7.51,-1M2.01,3L2,10l15,2 -15,2 0.01,7L23,12 2.01,3z"
|
||||
android:fillColor="#FFFFFF"/>
|
||||
</vector>
|
62
app/src/main/res/layout/activity_share.xml
Normal file
62
app/src/main/res/layout/activity_share.xml
Normal file
|
@ -0,0 +1,62 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="horizontal" android:padding="10dp">
|
||||
|
||||
<ProgressBar
|
||||
style="?android:attr/progressBarStyle"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:id="@+id/share_progress"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
android:indeterminate="true" android:visibility="visible" app:layout_constraintTop_toTopOf="parent" android:layout_marginTop="5dp"/>
|
||||
<TextView
|
||||
android:id="@+id/share_content_title"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="5dp"
|
||||
android:paddingBottom="2dp"
|
||||
android:text="@string/share_content_title"
|
||||
android:textAlignment="viewStart"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Medium" android:paddingStart="4dp"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"/>
|
||||
<com.google.android.material.imageview.ShapeableImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" app:srcCompat="@drawable/ic_cancel_gray_24dp"
|
||||
android:id="@+id/share_content_image" app:layout_constraintStart_toStartOf="parent"
|
||||
android:scaleType="fitStart"
|
||||
android:adjustViewBounds="true" android:maxHeight="150dp"
|
||||
app:shapeAppearanceOverlay="@style/roundedCornersImageView" android:visibility="visible"
|
||||
app:layout_constraintTop_toBottomOf="@id/share_content_title" android:layout_marginTop="5dp" android:layout_marginStart="5dp"/>
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/share_content_text"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" android:hint="@string/share_content_text_hint"
|
||||
android:importantForAutofill="no"
|
||||
app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent"
|
||||
android:lines="10" android:gravity="start|top" app:layout_constraintTop_toBottomOf="@id/share_content_image" android:minLines="1" android:layout_marginTop="5dp"/>
|
||||
<TextView
|
||||
android:id="@+id/share_topic_title"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="5dp"
|
||||
android:paddingBottom="3dp"
|
||||
android:text="Share to topic"
|
||||
android:textAlignment="viewStart"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Medium" android:paddingStart="4dp"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/share_content_text" android:layout_marginTop="10dp"/>
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/share_topic_text"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" android:hint="@string/add_dialog_topic_name_hint"
|
||||
android:importantForAutofill="no"
|
||||
android:maxLines="1" android:inputType="text" android:maxLength="64"
|
||||
app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/share_topic_title"/>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -15,7 +15,7 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
<TextView
|
||||
android:id="@+id/add_dialog_subscribe_title_text"
|
||||
android:id="@+id/add_dialog_subscribe_title"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="16dp"
|
||||
|
@ -41,7 +41,7 @@
|
|||
android:layout_height="wrap_content" android:id="@+id/add_dialog_subscribe_description"
|
||||
android:paddingStart="4dp" android:paddingTop="3dp" app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/add_dialog_subscribe_title_text"/>
|
||||
app:layout_constraintTop_toBottomOf="@id/add_dialog_subscribe_title"/>
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/add_dialog_subscribe_topic_text"
|
||||
android:layout_width="match_parent"
|
||||
|
|
4
app/src/main/res/menu/menu_share_action_bar.xml
Normal file
4
app/src/main/res/menu/menu_share_action_bar.xml
Normal file
|
@ -0,0 +1,4 @@
|
|||
<menu xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
<item android:id="@+id/share_menu_send" android:title="@string/share_menu_send"
|
||||
app:showAsAction="always" android:icon="@drawable/ic_send_white_24dp"/>
|
||||
</menu>
|
|
@ -185,6 +185,14 @@
|
|||
<string name="detail_settings_title">Subscription settings</string>
|
||||
<!-- ... -->
|
||||
|
||||
<!-- Share activity -->
|
||||
<string name="share_title">Share</string>
|
||||
<string name="share_menu_send">Share</string>
|
||||
<string name="share_content_title">Message preview</string>
|
||||
<string name="share_content_text_hint">Add the content you\'d like to share here</string>
|
||||
<string name="share_content_image_text">An image was shared with you.</string>
|
||||
<string name="share_content_image_error">Cannot read image</string>
|
||||
|
||||
<!-- Notification dialog -->
|
||||
<string name="notification_dialog_title">Pause notifications</string>
|
||||
<string name="notification_dialog_cancel">Cancel</string>
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in a new issue