summaryrefslogtreecommitdiff
path: root/app/src/main/java/org/terst/feedreader/ui/ShareReceiverActivity.kt
diff options
context:
space:
mode:
Diffstat (limited to 'app/src/main/java/org/terst/feedreader/ui/ShareReceiverActivity.kt')
-rw-r--r--app/src/main/java/org/terst/feedreader/ui/ShareReceiverActivity.kt113
1 files changed, 113 insertions, 0 deletions
diff --git a/app/src/main/java/org/terst/feedreader/ui/ShareReceiverActivity.kt b/app/src/main/java/org/terst/feedreader/ui/ShareReceiverActivity.kt
new file mode 100644
index 0000000..656bebc
--- /dev/null
+++ b/app/src/main/java/org/terst/feedreader/ui/ShareReceiverActivity.kt
@@ -0,0 +1,113 @@
+package org.terst.feedreader.ui
+
+import android.os.Bundle
+import androidx.activity.ComponentActivity
+import androidx.activity.compose.setContent
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.padding
+import androidx.compose.material3.Button
+import androidx.compose.material3.Card
+import androidx.compose.material3.CircularProgressIndicator
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.unit.dp
+import org.terst.feedreader.data.AppDatabase
+import org.terst.feedreader.data.ArticleEntity
+import org.terst.feedreader.data.Net
+import org.terst.feedreader.data.Settings
+import org.terst.feedreader.readability.ReaderExtractor
+import org.terst.feedreader.stash.StashClient
+import org.terst.feedreader.stash.StashSaveResult
+import java.security.MessageDigest
+
+private val URL_REGEX = Regex("""https?://\S+""")
+
+/**
+ * Share-sheet target: a URL shared from any other app lands here. Extracts
+ * the article on-device (so it's readable offline immediately, independent
+ * of Stash), stores it locally as a standalone saved article (feedId=null,
+ * not tied to any subscription), and best-effort archives it to Stash.
+ */
+class ShareReceiverActivity : ComponentActivity() {
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ val sharedText = intent?.getStringExtra(android.content.Intent.EXTRA_TEXT).orEmpty()
+ val url = URL_REGEX.find(sharedText)?.value
+
+ setContent {
+ MaterialTheme {
+ ShareReceiverContent(url = url, onDone = { finish() })
+ }
+ }
+ }
+}
+
+@Composable
+private fun ShareReceiverContent(url: String?, onDone: () -> Unit) {
+ val context = LocalContext.current
+ var status by remember { mutableStateOf(if (url == null) "No link found in shared content" else "Saving…") }
+ var done by remember { mutableStateOf(url == null) }
+
+ LaunchedEffect(url) {
+ if (url == null) return@LaunchedEffect
+ val db = AppDatabase.get(context)
+
+ val extracted = ReaderExtractor.extract(context, url)
+ val id = MessageDigest.getInstance("SHA-256").digest(url.toByteArray()).joinToString("") { "%02x".format(it) }
+ db.articleDao().upsert(
+ ArticleEntity(
+ id = id,
+ feedId = null,
+ title = extracted?.title ?: url,
+ link = url,
+ extractedContent = extracted?.content,
+ isSaved = true,
+ createdAt = System.currentTimeMillis()
+ )
+ )
+
+ val settings = Settings(context)
+ val client = StashClient(Net.client, settings.stashBaseUrlNow(), settings.stashApiKeyNow())
+ status = when (val result = client.saveArticle(url, extracted?.title)) {
+ is StashSaveResult.Saved -> {
+ db.articleDao().setStashArtifactId(id, result.artifact.id)
+ "Saved for offline reading and archived to Stash"
+ }
+ is StashSaveResult.AlreadySaved -> {
+ db.articleDao().setStashArtifactId(id, result.existingId)
+ "Saved for offline reading (already in Stash)"
+ }
+ is StashSaveResult.Failed ->
+ "Saved for offline reading. Stash archive failed: ${result.message}"
+ }
+ done = true
+ }
+
+ Column(modifier = Modifier.padding(24.dp)) {
+ Card(modifier = Modifier.padding(8.dp)) {
+ Column(modifier = Modifier.padding(20.dp)) {
+ Text("Feeds", style = MaterialTheme.typography.titleMedium)
+ Spacer(modifier = Modifier.height(8.dp))
+ Text(status)
+ if (!done) {
+ Spacer(modifier = Modifier.height(8.dp))
+ CircularProgressIndicator()
+ } else {
+ Spacer(modifier = Modifier.height(8.dp))
+ Button(onClick = onDone) { Text("Done") }
+ }
+ }
+ }
+ }
+}