mirror of https://github.com/readrops/Readrops.git
Compare commits
4 Commits
bf7ac41d6e
...
d486bd92f9
Author | SHA1 | Date |
---|---|---|
Shinokuni | d486bd92f9 | |
Shinokuni | 7b644cbc97 | |
Shinokuni | 02a3f82b72 | |
Shinokuni | 91378f0a54 |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -1,41 +1,52 @@
|
|||
package com.readrops.app.compose.item
|
||||
|
||||
import android.util.Base64
|
||||
import android.webkit.WebView
|
||||
import android.webkit.WebViewClient
|
||||
import androidx.compose.foundation.background
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.widget.RelativeLayout
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.IntrinsicSize
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.offset
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableFloatStateOf
|
||||
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.draw.clip
|
||||
import androidx.compose.ui.geometry.Offset
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.toArgb
|
||||
import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
|
||||
import androidx.compose.ui.input.nestedscroll.NestedScrollSource
|
||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.IntOffset
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.viewinterop.AndroidView
|
||||
import androidx.core.view.children
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import cafe.adriel.voyager.koin.getScreenModel
|
||||
import coil.compose.AsyncImage
|
||||
import com.readrops.api.utils.DateUtils
|
||||
import com.readrops.app.compose.R
|
||||
import com.readrops.app.compose.util.Utils
|
||||
import com.readrops.app.compose.item.view.ItemNestedScrollView
|
||||
import com.readrops.app.compose.item.view.ItemWebView
|
||||
import com.readrops.app.compose.util.components.AndroidScreen
|
||||
import com.readrops.app.compose.util.components.CenteredProgressIndicator
|
||||
import com.readrops.app.compose.util.components.IconText
|
||||
|
@ -47,90 +58,136 @@ import org.koin.core.parameter.parametersOf
|
|||
import kotlin.math.roundToInt
|
||||
|
||||
class ItemScreen(
|
||||
private val itemId: Int,
|
||||
private val itemId: Int
|
||||
) : AndroidScreen() {
|
||||
|
||||
@Composable
|
||||
override fun Content() {
|
||||
val context = LocalContext.current
|
||||
val density = LocalDensity.current
|
||||
|
||||
val screenModel =
|
||||
getScreenModel<ItemScreenModel>(parameters = { parametersOf(itemId) })
|
||||
val scrollState = rememberScrollState()
|
||||
|
||||
val state by screenModel.state.collectAsStateWithLifecycle()
|
||||
|
||||
val primaryColor = MaterialTheme.colorScheme.primary
|
||||
val backgroundColor = MaterialTheme.colorScheme.background
|
||||
val onBackgroundColor = MaterialTheme.colorScheme.onBackground
|
||||
|
||||
Column(
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.background(color = MaterialTheme.colorScheme.background)
|
||||
.verticalScroll(scrollState)
|
||||
) {
|
||||
if (state.itemWithFeed != null) {
|
||||
val itemWithFeed = state.itemWithFeed!!
|
||||
var isScrollable by remember { mutableStateOf(true) }
|
||||
|
||||
if (itemWithFeed.item.imageLink != null) {
|
||||
BackgroundTitle(
|
||||
itemWithFeed = itemWithFeed
|
||||
)
|
||||
} else {
|
||||
val tintColor = if (itemWithFeed.bgColor != 0) {
|
||||
Color(itemWithFeed.bgColor)
|
||||
} else {
|
||||
MaterialTheme.colorScheme.onBackground
|
||||
}
|
||||
// https://developer.android.com/develop/ui/compose/touch-input/pointer-input/scroll#parent-compose-child-view
|
||||
val bottomBarHeight = 64.dp
|
||||
val bottomBarHeightPx = with(density) { bottomBarHeight.roundToPx().toFloat() }
|
||||
val bottomBarOffsetHeightPx = remember { mutableFloatStateOf(0f) }
|
||||
|
||||
SimpleTitle(
|
||||
itemWithFeed = itemWithFeed,
|
||||
titleColor = tintColor,
|
||||
accentColor = tintColor,
|
||||
baseColor = MaterialTheme.colorScheme.onBackground,
|
||||
bottomPadding = true
|
||||
val nestedScrollConnection = remember {
|
||||
object : NestedScrollConnection {
|
||||
override fun onPreScroll(available: Offset, source: NestedScrollSource): Offset {
|
||||
val delta = available.y
|
||||
val newOffset = bottomBarOffsetHeightPx.floatValue + delta
|
||||
bottomBarOffsetHeightPx.floatValue = newOffset.coerceIn(-bottomBarHeightPx, 0f)
|
||||
|
||||
return Offset.Zero
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (state.itemWithFeed != null) {
|
||||
val itemWithFeed = state.itemWithFeed!!
|
||||
val item = itemWithFeed.item
|
||||
|
||||
val accentColor = if (itemWithFeed.bgColor != 0) {
|
||||
Color(itemWithFeed.bgColor)
|
||||
} else {
|
||||
primaryColor
|
||||
}
|
||||
|
||||
fun openUrl(url: String) {
|
||||
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(url))
|
||||
context.startActivity(intent)
|
||||
}
|
||||
|
||||
Scaffold(
|
||||
modifier = Modifier
|
||||
.nestedScroll(nestedScrollConnection),
|
||||
bottomBar = {
|
||||
ItemScreenBottomBar(
|
||||
item = item,
|
||||
accentColor = accentColor,
|
||||
modifier = Modifier
|
||||
.height(bottomBarHeight)
|
||||
.offset {
|
||||
if (isScrollable) {
|
||||
IntOffset(
|
||||
x = 0,
|
||||
y = -bottomBarOffsetHeightPx.floatValue.roundToInt()
|
||||
)
|
||||
} else {
|
||||
IntOffset(0, 0)
|
||||
}
|
||||
},
|
||||
onShare = { screenModel.shareItem(item, context) },
|
||||
onOpenUrl = { openUrl(item.link!!) },
|
||||
onChangeReadState = {
|
||||
screenModel.setItemReadState(item.apply { isRead = it })
|
||||
},
|
||||
onChangeStarState = {
|
||||
screenModel.setItemStarState(item.apply { isStarred = it })
|
||||
}
|
||||
)
|
||||
}
|
||||
) { paddingValues ->
|
||||
Box(
|
||||
modifier = Modifier.padding(paddingValues)
|
||||
) {
|
||||
AndroidView(
|
||||
factory = { context ->
|
||||
ItemNestedScrollView(
|
||||
context = context,
|
||||
onGlobalLayoutListener = { viewHeight, contentHeight ->
|
||||
isScrollable = viewHeight - contentHeight < 0
|
||||
},
|
||||
onUrlClick = { url -> openUrl(url) }
|
||||
) {
|
||||
if (item.imageLink != null) {
|
||||
BackgroundTitle(
|
||||
itemWithFeed = itemWithFeed
|
||||
)
|
||||
} else {
|
||||
val tintColor = if (itemWithFeed.bgColor != 0) {
|
||||
Color(itemWithFeed.bgColor)
|
||||
} else {
|
||||
MaterialTheme.colorScheme.onBackground
|
||||
}
|
||||
|
||||
AndroidView(
|
||||
factory = { context ->
|
||||
WebView(context).apply {
|
||||
settings.javaScriptEnabled = true
|
||||
webViewClient = WebViewClient()
|
||||
SimpleTitle(
|
||||
itemWithFeed = itemWithFeed,
|
||||
titleColor = tintColor,
|
||||
accentColor = tintColor,
|
||||
baseColor = MaterialTheme.colorScheme.onBackground,
|
||||
bottomPadding = true
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
update = { nestedScrollView ->
|
||||
val relativeLayout =
|
||||
(nestedScrollView.children.toList()[0] as RelativeLayout)
|
||||
val webView = relativeLayout.children.toList()[1] as ItemWebView
|
||||
|
||||
settings.builtInZoomControls = true
|
||||
settings.displayZoomControls = false
|
||||
settings.setSupportZoom(false)
|
||||
|
||||
isVerticalScrollBarEnabled = false
|
||||
setBackgroundColor(backgroundColor.toArgb())
|
||||
webView.loadText(
|
||||
itemWithFeed = itemWithFeed,
|
||||
accentColor = accentColor,
|
||||
backgroundColor = backgroundColor,
|
||||
onBackgroundColor = onBackgroundColor
|
||||
)
|
||||
}
|
||||
},
|
||||
update = { webView ->
|
||||
val tintColor = if (itemWithFeed.bgColor != 0) {
|
||||
Color(itemWithFeed.bgColor)
|
||||
} else {
|
||||
primaryColor
|
||||
}
|
||||
|
||||
val string = context.getString(
|
||||
R.string.webview_html_template,
|
||||
Utils.getCssColor(tintColor.toArgb()),
|
||||
Utils.getCssColor(onBackgroundColor.toArgb()),
|
||||
Utils.getCssColor(backgroundColor.toArgb()),
|
||||
screenModel.formatText()
|
||||
)
|
||||
val data =
|
||||
Base64.encodeToString(string.encodeToByteArray(), Base64.NO_PADDING)
|
||||
|
||||
webView.loadData(data, "text/html; charset=utf-8", "base64")
|
||||
}
|
||||
)
|
||||
|
||||
} else {
|
||||
CenteredProgressIndicator()
|
||||
)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
CenteredProgressIndicator()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -215,7 +272,8 @@ fun SimpleTitle(
|
|||
Text(
|
||||
text = itemWithFeed.feedName,
|
||||
style = MaterialTheme.typography.labelLarge,
|
||||
color = baseColor
|
||||
color = baseColor,
|
||||
textAlign = TextAlign.Center
|
||||
)
|
||||
|
||||
ShortSpacer()
|
||||
|
|
|
@ -0,0 +1,84 @@
|
|||
package com.readrops.app.compose.item
|
||||
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Share
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import com.readrops.app.compose.R
|
||||
import com.readrops.app.compose.util.theme.spacing
|
||||
import com.readrops.db.entities.Item
|
||||
|
||||
@Composable
|
||||
fun ItemScreenBottomBar(
|
||||
item: Item,
|
||||
accentColor: Color,
|
||||
onShare: () -> Unit,
|
||||
onOpenUrl: () -> Unit,
|
||||
onChangeReadState: (Boolean) -> Unit,
|
||||
onChangeStarState: (Boolean) -> Unit,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
Surface(
|
||||
color = accentColor,
|
||||
modifier = modifier.fillMaxWidth()
|
||||
) {
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.SpaceAround,
|
||||
modifier = Modifier.padding(MaterialTheme.spacing.shortSpacing)
|
||||
) {
|
||||
IconButton(
|
||||
onClick = { onChangeReadState(!item.isRead) }
|
||||
) {
|
||||
Icon(
|
||||
painter = painterResource(
|
||||
id = if (item.isRead)
|
||||
R.drawable.ic_remove_done
|
||||
else R.drawable.ic_done_all
|
||||
),
|
||||
contentDescription = null
|
||||
)
|
||||
}
|
||||
|
||||
IconButton(
|
||||
onClick = { onChangeStarState(!item.isStarred) }
|
||||
) {
|
||||
Icon(
|
||||
painter = painterResource(
|
||||
id = if (item.isStarred)
|
||||
R.drawable.ic_star
|
||||
else R.drawable.ic_star_outline
|
||||
),
|
||||
contentDescription = null
|
||||
)
|
||||
}
|
||||
|
||||
IconButton(
|
||||
onClick = onShare
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.Default.Share,
|
||||
contentDescription = null
|
||||
)
|
||||
}
|
||||
|
||||
IconButton(
|
||||
onClick = onOpenUrl
|
||||
) {
|
||||
Icon(
|
||||
painter = painterResource(id = R.drawable.ic_open_in_browser),
|
||||
contentDescription = null
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,31 +1,55 @@
|
|||
package com.readrops.app.compose.item
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import androidx.compose.runtime.Stable
|
||||
import cafe.adriel.voyager.core.model.StateScreenModel
|
||||
import cafe.adriel.voyager.core.model.screenModelScope
|
||||
import com.readrops.app.compose.repositories.BaseRepository
|
||||
import com.readrops.db.Database
|
||||
import com.readrops.db.entities.Item
|
||||
import com.readrops.db.entities.account.Account
|
||||
import com.readrops.db.pojo.ItemWithFeed
|
||||
import com.readrops.db.queries.ItemSelectionQueryBuilder
|
||||
import kotlinx.coroutines.CoroutineDispatcher
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.launch
|
||||
import org.jsoup.Jsoup
|
||||
import org.jsoup.parser.Parser
|
||||
import org.koin.core.component.KoinComponent
|
||||
import org.koin.core.component.get
|
||||
import org.koin.core.parameter.parametersOf
|
||||
|
||||
class ItemScreenModel(
|
||||
private val database: Database,
|
||||
private val itemId: Int
|
||||
) : StateScreenModel<ItemState>(ItemState()) {
|
||||
private val itemId: Int,
|
||||
private val dispatcher: CoroutineDispatcher = Dispatchers.IO
|
||||
) : StateScreenModel<ItemState>(ItemState()), KoinComponent {
|
||||
|
||||
//TODO Is this really the best solution?
|
||||
lateinit var account: Account
|
||||
lateinit var repository: BaseRepository
|
||||
|
||||
init {
|
||||
screenModelScope.launch(Dispatchers.IO) {
|
||||
mutableState.update {
|
||||
val query = ItemSelectionQueryBuilder.buildQuery(itemId, false)
|
||||
screenModelScope.launch(dispatcher) {
|
||||
database.newAccountDao().selectCurrentAccount()
|
||||
.collect { account ->
|
||||
this@ItemScreenModel.account = account!!
|
||||
repository = get { parametersOf(account) }
|
||||
|
||||
it.copy(
|
||||
itemWithFeed = database.newItemDao().selectItemById(query)
|
||||
)
|
||||
}
|
||||
val query = ItemSelectionQueryBuilder.buildQuery(
|
||||
itemId = itemId,
|
||||
separateState = account.config.useSeparateState
|
||||
)
|
||||
|
||||
database.newItemDao().selectItemById(query)
|
||||
.collect { itemWithFeed ->
|
||||
mutableState.update {
|
||||
it.copy(itemWithFeed = itemWithFeed)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -41,6 +65,30 @@ class ItemScreenModel(
|
|||
document.select("div,span").forEach { it.clearAttributes() }
|
||||
return document.body().html()
|
||||
}
|
||||
|
||||
fun shareItem(item: Item, context: Context) {
|
||||
Intent().apply {
|
||||
action = Intent.ACTION_SEND
|
||||
type = "text/plain"
|
||||
putExtra(Intent.EXTRA_TEXT, item.link)
|
||||
}.also {
|
||||
context.startActivity(Intent.createChooser(it, null))
|
||||
}
|
||||
}
|
||||
|
||||
fun setItemReadState(item: Item) {
|
||||
//TODO support separateState
|
||||
screenModelScope.launch(dispatcher) {
|
||||
repository.setItemReadState(item)
|
||||
}
|
||||
}
|
||||
|
||||
fun setItemStarState(item: Item) {
|
||||
//TODO support separateState
|
||||
screenModelScope.launch(dispatcher) {
|
||||
repository.setItemStarState(item)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Stable
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
package com.readrops.app.compose.item.view
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.widget.RelativeLayout
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.platform.ComposeView
|
||||
import androidx.core.view.ViewCompat
|
||||
import androidx.core.widget.NestedScrollView
|
||||
|
||||
@SuppressLint("ResourceType", "ViewConstructor")
|
||||
class ItemNestedScrollView(
|
||||
context: Context,
|
||||
onGlobalLayoutListener: (viewHeight: Int, contentHeight: Int) -> Unit,
|
||||
onUrlClick: (String) -> Unit,
|
||||
composeViewContent: @Composable () -> Unit
|
||||
) : NestedScrollView(context) {
|
||||
|
||||
init {
|
||||
addView(
|
||||
RelativeLayout(context).apply {
|
||||
ViewCompat.setNestedScrollingEnabled(this, true)
|
||||
|
||||
val composeView = ComposeView(context).apply {
|
||||
id = 1
|
||||
|
||||
setContent {
|
||||
composeViewContent()
|
||||
}
|
||||
}
|
||||
|
||||
val composeViewParams = RelativeLayout.LayoutParams(
|
||||
LayoutParams.MATCH_PARENT,
|
||||
LayoutParams.WRAP_CONTENT
|
||||
)
|
||||
composeViewParams.addRule(RelativeLayout.CENTER_HORIZONTAL)
|
||||
composeView.layoutParams = composeViewParams
|
||||
|
||||
val webView = ItemWebView(
|
||||
context = context,
|
||||
onUrlClick = onUrlClick
|
||||
).apply {
|
||||
id = 2
|
||||
ViewCompat.setNestedScrollingEnabled(this, true)
|
||||
}
|
||||
|
||||
val webViewParams = RelativeLayout.LayoutParams(
|
||||
LayoutParams.MATCH_PARENT,
|
||||
LayoutParams.WRAP_CONTENT
|
||||
)
|
||||
|
||||
webViewParams.addRule(RelativeLayout.BELOW, composeView.id)
|
||||
webView.layoutParams = webViewParams
|
||||
|
||||
addView(composeView)
|
||||
addView(webView)
|
||||
}
|
||||
)
|
||||
|
||||
viewTreeObserver.addOnGlobalLayoutListener {
|
||||
val viewHeight = this.measuredHeight
|
||||
val contentHeight = getChildAt(0).height
|
||||
|
||||
onGlobalLayoutListener(viewHeight, contentHeight)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
package com.readrops.app.compose.item.view
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import android.webkit.WebView
|
||||
import android.webkit.WebViewClient
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.toArgb
|
||||
import com.readrops.app.compose.R
|
||||
import com.readrops.app.compose.util.Utils
|
||||
import com.readrops.db.pojo.ItemWithFeed
|
||||
import org.jsoup.Jsoup
|
||||
import org.jsoup.parser.Parser
|
||||
|
||||
@SuppressLint("SetJavaScriptEnabled", "ViewConstructor")
|
||||
class ItemWebView(
|
||||
context: Context,
|
||||
onUrlClick: (String) -> Unit,
|
||||
attrs: AttributeSet? = null,
|
||||
) : WebView(context, attrs) {
|
||||
|
||||
init {
|
||||
settings.javaScriptEnabled = true
|
||||
settings.builtInZoomControls = true
|
||||
settings.displayZoomControls = false
|
||||
settings.setSupportZoom(false)
|
||||
isVerticalScrollBarEnabled = false
|
||||
|
||||
webViewClient = object : WebViewClient() {
|
||||
override fun shouldOverrideUrlLoading(view: WebView?, url: String?): Boolean {
|
||||
url?.let { onUrlClick(it) }
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun loadText(
|
||||
itemWithFeed: ItemWithFeed,
|
||||
accentColor: Color,
|
||||
backgroundColor: Color,
|
||||
onBackgroundColor: Color
|
||||
) {
|
||||
val string = context.getString(
|
||||
R.string.webview_html_template,
|
||||
Utils.getCssColor(accentColor.toArgb()),
|
||||
Utils.getCssColor(onBackgroundColor.toArgb()),
|
||||
Utils.getCssColor(backgroundColor.toArgb()),
|
||||
formatText(itemWithFeed)
|
||||
)
|
||||
|
||||
loadDataWithBaseURL(
|
||||
"file:///android_asset/",
|
||||
string,
|
||||
"text/html; charset=utf-8",
|
||||
"UTF-8",
|
||||
null
|
||||
)
|
||||
}
|
||||
|
||||
private fun formatText(itemWithFeed: ItemWithFeed): String {
|
||||
return if (itemWithFeed.item.content != null) {
|
||||
val document = if (itemWithFeed.websiteUrl != null) Jsoup.parse(
|
||||
Parser.unescapeEntities(itemWithFeed.item.text, false), itemWithFeed.websiteUrl
|
||||
) else Jsoup.parse(
|
||||
Parser.unescapeEntities(itemWithFeed.item.text, false)
|
||||
)
|
||||
|
||||
document.select("div,span").forEach { it.clearAttributes() }
|
||||
return document.body().html()
|
||||
} else {
|
||||
""
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#000000" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
|
||||
|
||||
<path android:fillColor="@android:color/white" android:pathData="M1.79,12l5.58,5.59L5.96,19 0.37,13.41 1.79,12zM2.24,4.22L12.9,14.89l-1.28,1.28L7.44,12l-1.41,1.41L11.62,19l2.69,-2.69 4.89,4.89 1.41,-1.41L3.65,2.81 2.24,4.22zM17.14,13.49L23.62,7 22.2,5.59l-6.48,6.48 1.42,1.42zM17.96,7l-1.41,-1.41 -3.65,3.66 1.41,1.41L17.96,7z"/>
|
||||
|
||||
</vector>
|
|
@ -0,0 +1,5 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#000000" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
|
||||
|
||||
<path android:fillColor="@android:color/white" android:pathData="M12,17.27L18.18,21l-1.64,-7.03L22,9.24l-7.19,-0.61L12,2 9.19,8.63 2,9.24l5.46,4.73L5.82,21z"/>
|
||||
|
||||
</vector>
|
|
@ -0,0 +1,5 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#000000" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
|
||||
|
||||
<path android:fillColor="@android:color/white" android:pathData="M22,9.24l-7.19,-0.62L12,2 9.19,8.63 2,9.24l5.46,4.73L5.82,21 12,17.27 18.18,21l-1.63,-7.03L22,9.24zM12,15.4l-3.76,2.27 1,-4.28 -3.32,-2.88 4.38,-0.38L12,6.1l1.71,4.04 4.38,0.38 -3.32,2.88 1,4.28L12,15.4z"/>
|
||||
|
||||
</vector>
|
|
@ -15,6 +15,14 @@
|
|||
%3$s: background color
|
||||
*/
|
||||
|
||||
@font-face {
|
||||
font-family: Inter;
|
||||
font-style: normal;
|
||||
font-weight: normal;
|
||||
font-display: swap;
|
||||
src: url("fonts/Inter-Regular.woff2") format("woff2");
|
||||
}
|
||||
|
||||
a:link, a:active, a:hover { color: %1$s }
|
||||
|
||||
* {
|
||||
|
@ -31,6 +39,7 @@
|
|||
margin-right: 3%%;
|
||||
color: %2$s;
|
||||
background-color: %3$s;
|
||||
font-family: Inter !important;
|
||||
}
|
||||
|
||||
figure, img, iframe, video {
|
||||
|
|
|
@ -10,6 +10,7 @@ import com.readrops.db.entities.Folder
|
|||
import com.readrops.db.entities.Item
|
||||
import com.readrops.db.entities.ItemState
|
||||
import com.readrops.db.pojo.ItemWithFeed
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
@Dao
|
||||
abstract class NewItemDao : NewBaseDao<Item> {
|
||||
|
@ -18,7 +19,7 @@ abstract class NewItemDao : NewBaseDao<Item> {
|
|||
abstract fun selectAll(query: SupportSQLiteQuery): PagingSource<Int, ItemWithFeed>
|
||||
|
||||
@RawQuery(observedEntities = [Item::class, ItemState::class])
|
||||
abstract suspend fun selectItemById(query: SupportSQLiteQuery): ItemWithFeed
|
||||
abstract fun selectItemById(query: SupportSQLiteQuery): Flow<ItemWithFeed>
|
||||
|
||||
@Query("Update Item Set read = :read Where id = :itemId")
|
||||
abstract suspend fun updateReadState(itemId: Int, read: Boolean)
|
||||
|
|
Loading…
Reference in New Issue