summaryrefslogtreecommitdiff
path: root/app/src/main/java/org/terst/feedreader/ui/LinkReaderScreen.kt
blob: ff764c46ad4c7ec86725cc57c5cad00113e454a8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
package org.terst.feedreader.ui

import android.content.Intent
import android.net.Uri
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.material.icons.filled.OpenInBrowser
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
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.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.compose.ui.viewinterop.AndroidView
import org.terst.feedreader.readability.ReaderExtractor

/**
 * A lightweight, non-persisted reader view for links tapped inside an article's
 * WebView -- extracts the linked page with the same Readability pipeline as the
 * main reader, but doesn't touch the DB (it's not a subscribed article), and
 * recursively re-opens itself for any further links tapped inside, so link-hopping
 * stays inside the app's reader instead of dropping into a raw WebView or the
 * system browser.
 */
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun LinkReaderScreen(url: String, onBack: () -> Unit, onOpenLink: (String) -> Unit) {
    val context = LocalContext.current
    var title by remember(url) { mutableStateOf<String?>(null) }
    var content by remember(url) { mutableStateOf<String?>(null) }
    var failed by remember(url) { mutableStateOf(false) }

    LaunchedEffect(url) {
        val extracted = ReaderExtractor.extract(context, url)
        val extractedContent = extracted?.content
        if (extractedContent != null) {
            title = extracted.title
            content = extractedContent
        } else {
            failed = true
        }
    }

    Scaffold(
        topBar = {
            TopAppBar(
                title = {
                    Text(title ?: Uri.parse(url).host ?: "Article", maxLines = 1, overflow = TextOverflow.Ellipsis)
                },
                navigationIcon = {
                    IconButton(onClick = onBack) {
                        Icon(Icons.Default.ArrowBack, contentDescription = "Back")
                    }
                },
                actions = {
                    IconButton(onClick = {
                        context.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(url)))
                    }) {
                        Icon(Icons.Default.OpenInBrowser, contentDescription = "Open in browser")
                    }
                }
            )
        }
    ) { padding ->
        Box(modifier = Modifier.fillMaxSize().padding(padding)) {
            val currentContent = content
            when {
                currentContent != null -> {
                    val loadedContent = remember(url) { mutableStateOf<String?>(null) }
                    AndroidView(
                        modifier = Modifier.fillMaxSize(),
                        factory = { ctx ->
                            newReaderWebView(ctx, onOpenLink).apply {
                                loadDataWithBaseURL(url, wrapReaderHtml(currentContent), "text/html", "UTF-8", null)
                                loadedContent.value = currentContent
                            }
                        },
                        update = { webView ->
                            if (loadedContent.value != currentContent) {
                                webView.loadDataWithBaseURL(url, wrapReaderHtml(currentContent), "text/html", "UTF-8", null)
                                loadedContent.value = currentContent
                            }
                        },
                        onRelease = { webView -> webView.destroy() }
                    )
                }
                failed -> Text(
                    "Couldn't extract a reader view for this page -- try \"Open in browser\" instead.",
                    modifier = Modifier.align(Alignment.Center).padding(24.dp),
                    color = MaterialTheme.colorScheme.onSurfaceVariant
                )
                else -> CircularProgressIndicator(modifier = Modifier.align(Alignment.Center))
            }
        }
    }
}