diff --git a/app/src/main/java/me/ash/reader/data/feed/Feed.kt b/app/src/main/java/me/ash/reader/data/feed/Feed.kt index 27b3b35..a004e07 100644 --- a/app/src/main/java/me/ash/reader/data/feed/Feed.kt +++ b/app/src/main/java/me/ash/reader/data/feed/Feed.kt @@ -19,7 +19,7 @@ data class Feed( @ColumnInfo val name: String, @ColumnInfo - var icon: String? = null, + var icon: ByteArray? = null, @ColumnInfo val url: String, @ColumnInfo(index = true) @@ -31,4 +31,37 @@ data class Feed( ) { @Ignore var important: Int? = 0 + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as Feed + + if (id != other.id) return false + if (name != other.name) return false + if (icon != null) { + if (other.icon == null) return false + if (!icon.contentEquals(other.icon)) return false + } else if (other.icon != null) return false + if (url != other.url) return false + if (groupId != other.groupId) return false + if (accountId != other.accountId) return false + if (isFullContent != other.isFullContent) return false + if (important != other.important) return false + + return true + } + + override fun hashCode(): Int { + var result = id ?: 0 + result = 31 * result + name.hashCode() + result = 31 * result + (icon?.contentHashCode() ?: 0) + result = 31 * result + url.hashCode() + result = 31 * result + groupId + result = 31 * result + accountId + result = 31 * result + isFullContent.hashCode() + result = 31 * result + (important ?: 0) + return result + } } diff --git a/app/src/main/java/me/ash/reader/data/repository/RssRepository.kt b/app/src/main/java/me/ash/reader/data/repository/RssRepository.kt index 70683cc..e3651f3 100644 --- a/app/src/main/java/me/ash/reader/data/repository/RssRepository.kt +++ b/app/src/main/java/me/ash/reader/data/repository/RssRepository.kt @@ -93,7 +93,6 @@ class RssRepository @Inject constructor( Constraints.Builder() .setRequiredNetworkType(NetworkType.CONNECTED) .setRequiresCharging(true) - .setRequiresDeviceIdle(true) .build() ).addTag("sync").build() workManager.enqueue(syncWorkerRequest) @@ -161,18 +160,18 @@ class RssRepository @Inject constructor( val articles = mutableListOf
() chunked[it].forEach { feed -> val latest = articleDao.queryLatestByFeedId(accountId, feed.id ?: 0) -// if (feed.icon == null) { -// queryRssIcon(feedDao, feed, latest?.link) -// } articles.addAll( queryRssXml( rssNetworkDataSource, accountId, feed, latest?.title, - ) + ).also { + if (feed.icon == null && it.isNotEmpty()) { + queryRssIcon(feedDao, feed, it.first().link) + } + } ) - syncState.update { it.copy( feedCount = feeds.size, @@ -280,34 +279,44 @@ class RssRepository @Inject constructor( articleLink: String?, ) { if (articleLink == null) return - val exe = OkHttpClient() - .newCall(Request.Builder().url(articleLink).build()).execute() - val content = exe.body?.string() - Log.i("rlog", "queryRssIcon: $content") + val execute = OkHttpClient() + .newCall(Request.Builder().url(articleLink).build()) + .execute() + val content = execute.body?.string() val regex = - Regex(""" + Log.i("RLog", "FeedList: ${feed.icon}") BarButton( barButtonType = ItemType( // icon = feed.icon ?: "", - icon = painterResource(id = R.drawable.default_folder), + icon = if (feed.icon == null) { + null + } else { + BitmapPainter( + BitmapFactory.decodeByteArray( + feed.icon, + 0, + feed.icon!!.size + ).asImageBitmap() + ) + }, content = feed.name, important = feed.important ?: 0 ) diff --git a/app/src/main/java/me/ash/reader/ui/page/home/read/ReadPage.kt b/app/src/main/java/me/ash/reader/ui/page/home/read/ReadPage.kt index 7a13f8e..b20765e 100644 --- a/app/src/main/java/me/ash/reader/ui/page/home/read/ReadPage.kt +++ b/app/src/main/java/me/ash/reader/ui/page/home/read/ReadPage.kt @@ -168,6 +168,7 @@ private fun Header( ) { Column( modifier = Modifier + .fillMaxWidth() .roundClick { context.startActivity( Intent(Intent.ACTION_VIEW, Uri.parse(article.link)) diff --git a/app/src/main/java/me/ash/reader/ui/util/Symbol.kt b/app/src/main/java/me/ash/reader/ui/util/Symbol.kt new file mode 100644 index 0000000..9417ef9 --- /dev/null +++ b/app/src/main/java/me/ash/reader/ui/util/Symbol.kt @@ -0,0 +1,5 @@ +package me.ash.reader.ui.util + +object Symbol { + const val nothing: String = "null" +} \ No newline at end of file diff --git a/app/src/main/java/me/ash/reader/ui/widget/AppNavigationBar.kt b/app/src/main/java/me/ash/reader/ui/widget/AppNavigationBar.kt index d1337df..0eeda20 100644 --- a/app/src/main/java/me/ash/reader/ui/widget/AppNavigationBar.kt +++ b/app/src/main/java/me/ash/reader/ui/widget/AppNavigationBar.kt @@ -1,5 +1,6 @@ package me.ash.reader.ui.widget +import android.view.HapticFeedbackConstants import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.animateContentSize import androidx.compose.animation.core.FastOutLinearInEasing @@ -27,6 +28,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.draw.alpha import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalView import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp @@ -83,7 +85,9 @@ fun AppNavigationBar( } } - Divider(modifier = Modifier.alpha(0.3f)) + Divider( + modifier = Modifier.alpha(0.3f), + ) Box( modifier = modifier .background(MaterialTheme.colorScheme.surface) @@ -141,6 +145,7 @@ private fun FilterBar( filter: Filter, onSelected: (Filter) -> Unit = {}, ) { + val view = LocalView.current Row( modifier = modifier, horizontalArrangement = Arrangement.Center, @@ -168,6 +173,7 @@ private fun FilterBar( ) .clip(CircleShape) .clickable(onClick = { + view.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP) onSelected( when (index) { 0 -> Filter.Starred @@ -237,6 +243,7 @@ private fun ReaderBar( starredOnClick: (afterIsStarred: Boolean) -> Unit = {}, fullContentOnClick: (afterIsFullContent: Boolean) -> Unit = {}, ) { + val view = LocalView.current var fullContent by remember { mutableStateOf(isFullContent) } Row( horizontalArrangement = Arrangement.SpaceBetween, @@ -246,6 +253,7 @@ private fun ReaderBar( .padding(horizontal = 8.dp) ) { CanBeDisabledIconButton( + modifier = Modifier.size(18.dp), disabled = disabled, imageVector = if (isUnread) { Icons.Rounded.Circle @@ -255,6 +263,7 @@ private fun ReaderBar( contentDescription = "Mark Unread", tint = MaterialTheme.colorScheme.primary, ) { + view.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP) unreadOnClick(!isUnread) } CanBeDisabledIconButton( @@ -268,6 +277,7 @@ private fun ReaderBar( contentDescription = "Starred", tint = MaterialTheme.colorScheme.primary, ) { + view.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP) starredOnClick(!isStarred) } CanBeDisabledIconButton( @@ -277,7 +287,7 @@ private fun ReaderBar( contentDescription = "Next Article", tint = MaterialTheme.colorScheme.primary, ) { - + view.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP) } CanBeDisabledIconButton( disabled = disabled, @@ -285,7 +295,7 @@ private fun ReaderBar( contentDescription = "Add Tag", tint = MaterialTheme.colorScheme.primary, ) { - + view.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP) } CanBeDisabledIconButton( disabled = disabled, @@ -298,6 +308,7 @@ private fun ReaderBar( contentDescription = "Full Content Parsing", tint = MaterialTheme.colorScheme.primary, ) { + view.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP) val afterIsFullContent = !fullContent fullContent = afterIsFullContent fullContentOnClick(afterIsFullContent) diff --git a/app/src/main/java/me/ash/reader/ui/widget/BarButton.kt b/app/src/main/java/me/ash/reader/ui/widget/BarButton.kt index a9f1891..712de3f 100644 --- a/app/src/main/java/me/ash/reader/ui/widget/BarButton.kt +++ b/app/src/main/java/me/ash/reader/ui/widget/BarButton.kt @@ -1,6 +1,8 @@ package me.ash.reader.ui.widget +import android.graphics.BitmapFactory import androidx.compose.animation.ExperimentalAnimationApi +import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.* @@ -12,11 +14,17 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.asImageBitmap +import androidx.compose.ui.graphics.painter.BitmapPainter import androidx.compose.ui.graphics.painter.Painter import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.res.painterResource import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp +import me.ash.reader.R import me.ash.reader.ui.util.paddingFixedHorizontal import me.ash.reader.ui.util.roundClick @@ -43,60 +51,73 @@ fun BarButton( end = if (barButtonType is FirstExpandType) 2.dp else 10.dp ) ) { - Row(verticalAlignment = Alignment.CenterVertically) { - when (barButtonType) { - is SecondExpandType -> { - Icon( - imageVector = barButtonType.img as ImageVector, - contentDescription = "icon", - modifier = Modifier - .padding(end = 4.dp) - .clip(CircleShape) - .clickable(onClick = iconOnClickListener), - tint = MaterialTheme.colorScheme.onPrimaryContainer, - ) - } - is ItemType -> { - val modifier = Modifier - Row( - modifier = modifier - .padding(start = 28.dp, end = 4.dp) - .size(24.dp) -// .background(if (barButtonType.img.isBlank()) MaterialTheme.colorScheme.inversePrimary else Color.Unspecified), - .background(MaterialTheme.colorScheme.inversePrimary), - horizontalArrangement = Arrangement.Center, - verticalAlignment = Alignment.CenterVertically, - ) { + when (barButtonType) { + is SecondExpandType -> { + Icon( + imageVector = barButtonType.img, + contentDescription = "icon", + modifier = Modifier + .padding(end = 4.dp) + .clip(CircleShape) + .clickable(onClick = iconOnClickListener), + tint = MaterialTheme.colorScheme.onPrimaryContainer, + ) + } + is ItemType -> { + val modifier = Modifier + Row( + modifier = modifier + .padding(start = 28.dp, end = 4.dp) + .size(24.dp) + .background( + if (barButtonType.icon != null) Color.Unspecified + else MaterialTheme.colorScheme.inversePrimary + ), +// .background(MaterialTheme.colorScheme.inversePrimary), + horizontalArrangement = Arrangement.Center, + verticalAlignment = Alignment.CenterVertically, + ) { + if (barButtonType.icon == null) { Icon( -// painter = rememberImagePainter(barButtonType.img), - painter = barButtonType.img, + painter = painterResource(id = R.drawable.default_folder), contentDescription = "icon", modifier = modifier.fillMaxSize(), tint = MaterialTheme.colorScheme.onPrimaryContainer, ) + } else { + Image( + painter = barButtonType.icon, + contentDescription = "icon", + modifier = modifier.fillMaxSize(), + ) } } } - when (barButtonType) { - is ButtonType -> { - AnimatedText( - text = barButtonType.text, - fontSize = 22.sp, - fontWeight = FontWeight.Bold, - color = MaterialTheme.colorScheme.primary, - ) - } - else -> { - Text( - text = barButtonType.text, - fontSize = if (barButtonType is FirstExpandType) 22.sp else 18.sp, - fontWeight = if (barButtonType is FirstExpandType) FontWeight.Bold else FontWeight.SemiBold, - color = if (barButtonType is FirstExpandType) - MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.onPrimaryContainer, - ) - } + } + when (barButtonType) { + is ButtonType -> { + AnimatedText( + modifier = Modifier.weight(1f), + text = barButtonType.text, + fontSize = 22.sp, + fontWeight = FontWeight.Bold, + color = MaterialTheme.colorScheme.primary, + ) + } + else -> { + Text( + modifier = Modifier + .weight(1f) + .padding(end = 20.dp), + maxLines = 1, + overflow = TextOverflow.Ellipsis, + text = barButtonType.text, + fontSize = if (barButtonType is FirstExpandType) 22.sp else 18.sp, + fontWeight = if (barButtonType is FirstExpandType) FontWeight.Bold else FontWeight.SemiBold, + color = if (barButtonType is FirstExpandType) + MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.onPrimaryContainer, + ) } - } when (barButtonType) { is ButtonType, is ItemType, is SecondExpandType -> { @@ -163,13 +184,15 @@ class SecondExpandType( class ItemType( // private val icon: String, - private val icon: Painter, + val icon: BitmapPainter?, private val content: String, private val important: Int, ) : BarButtonType { // override val img: String override val img: Painter - get() = icon + get() = icon ?: BitmapPainter( + BitmapFactory.decodeByteArray(byteArrayOf(), 0, 0).asImageBitmap() + ) override val text: String get() = content override val additional: Any diff --git a/app/src/main/java/me/ash/reader/ui/widget/TopTitleBox.kt b/app/src/main/java/me/ash/reader/ui/widget/TopTitleBox.kt index c19df7d..75db6b0 100644 --- a/app/src/main/java/me/ash/reader/ui/widget/TopTitleBox.kt +++ b/app/src/main/java/me/ash/reader/ui/widget/TopTitleBox.kt @@ -73,7 +73,7 @@ fun BoxScope.TopTitleBox( interactionSource = MutableInteractionSource(), indication = null, onClickLabel = "回到顶部", - onClick = clickable ?: {} + onClick = clickable ), contentAlignment = Alignment.Center ) { @@ -86,6 +86,7 @@ fun BoxScope.TopTitleBox( ) Spacer(modifier = Modifier.height(SpacerHeight.dp)) AnimatedText( + modifier = Modifier.width(200.dp), text = description, fontWeight = FontWeight.SemiBold, fontSize = descriptionFontSize.sp, diff --git a/app/src/main/res/drawable/ic_default_feed_icon.xml b/app/src/main/res/drawable/ic_default_feed_icon.xml deleted file mode 100644 index e36c78d..0000000 --- a/app/src/main/res/drawable/ic_default_feed_icon.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - diff --git a/app/src/main/res/drawable/ic_default_folder.xml b/app/src/main/res/drawable/ic_default_folder.xml deleted file mode 100644 index dc56202..0000000 --- a/app/src/main/res/drawable/ic_default_folder.xml +++ /dev/null @@ -1,5 +0,0 @@ - diff --git a/app/src/main/res/drawable/ic_undraw_no_data.xml b/app/src/main/res/drawable/ic_undraw_no_data.xml deleted file mode 100644 index 258dfe3..0000000 --- a/app/src/main/res/drawable/ic_undraw_no_data.xml +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - - - - - - -