Optimize extensions and components and packages

This commit is contained in:
Ash 2022-04-03 00:30:25 +08:00
parent 257a6332ac
commit 622d0e2cfd
78 changed files with 292 additions and 942 deletions

View File

@ -14,6 +14,9 @@ import me.ash.reader.data.repository.*
import me.ash.reader.data.source.OpmlLocalDataSource import me.ash.reader.data.source.OpmlLocalDataSource
import me.ash.reader.data.source.ReaderDatabase import me.ash.reader.data.source.ReaderDatabase
import me.ash.reader.data.source.RssNetworkDataSource import me.ash.reader.data.source.RssNetworkDataSource
import me.ash.reader.ui.ext.DataStoreKeys
import me.ash.reader.ui.ext.dataStore
import me.ash.reader.ui.ext.put
import javax.inject.Inject import javax.inject.Inject
@HiltAndroidApp @HiltAndroidApp

View File

@ -1,3 +0,0 @@
package me.ash.reader
fun Int.spacerDollar(str: Any): String = "$this$$str"

View File

@ -1,17 +0,0 @@
package me.ash.reader.data
import androidx.room.TypeConverter
import java.util.*
class Converters {
@TypeConverter
fun toDate(dateLong: Long?): Date? {
return dateLong?.let { Date(it) }
}
@TypeConverter
fun fromDate(date: Date?): Long? {
return date?.time
}
}

View File

@ -1,6 +1,7 @@
package me.ash.reader.data.account package me.ash.reader.data.dao
import androidx.room.* import androidx.room.*
import me.ash.reader.data.entity.Account
@Dao @Dao
interface AccountDao { interface AccountDao {

View File

@ -1,8 +1,11 @@
package me.ash.reader.data.article package me.ash.reader.data.dao
import androidx.paging.PagingSource import androidx.paging.PagingSource
import androidx.room.* import androidx.room.*
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import me.ash.reader.data.entity.Article
import me.ash.reader.data.entity.ArticleWithFeed
import me.ash.reader.data.entity.ImportantCount
@Dao @Dao
interface ArticleDao { interface ArticleDao {

View File

@ -1,6 +1,7 @@
package me.ash.reader.data.feed package me.ash.reader.data.dao
import androidx.room.* import androidx.room.*
import me.ash.reader.data.entity.Feed
@Dao @Dao
interface FeedDao { interface FeedDao {

View File

@ -1,7 +1,9 @@
package me.ash.reader.data.group package me.ash.reader.data.dao
import androidx.room.* import androidx.room.*
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import me.ash.reader.data.entity.Group
import me.ash.reader.data.entity.GroupWithFeed
@Dao @Dao
interface GroupDao { interface GroupDao {

View File

@ -1,4 +1,4 @@
package me.ash.reader.data.account package me.ash.reader.data.entity
import androidx.room.ColumnInfo import androidx.room.ColumnInfo
import androidx.room.Entity import androidx.room.Entity

View File

@ -1,10 +1,9 @@
package me.ash.reader.data.article package me.ash.reader.data.entity
import androidx.room.ColumnInfo import androidx.room.ColumnInfo
import androidx.room.Entity import androidx.room.Entity
import androidx.room.ForeignKey import androidx.room.ForeignKey
import androidx.room.PrimaryKey import androidx.room.PrimaryKey
import me.ash.reader.data.feed.Feed
import java.util.* import java.util.*
@Entity( @Entity(

View File

@ -1,8 +1,7 @@
package me.ash.reader.data.article package me.ash.reader.data.entity
import androidx.room.Embedded import androidx.room.Embedded
import androidx.room.Relation import androidx.room.Relation
import me.ash.reader.data.feed.Feed
data class ArticleWithFeed( data class ArticleWithFeed(
@Embedded @Embedded

View File

@ -1,7 +1,6 @@
package me.ash.reader.data.feed package me.ash.reader.data.entity
import androidx.room.* import androidx.room.*
import me.ash.reader.data.group.Group
@Entity( @Entity(
tableName = "feed", tableName = "feed",

View File

@ -1,8 +1,7 @@
package me.ash.reader.data.feed package me.ash.reader.data.entity
import androidx.room.Embedded import androidx.room.Embedded
import androidx.room.Relation import androidx.room.Relation
import me.ash.reader.data.article.Article
data class FeedWithArticle( data class FeedWithArticle(
@Embedded @Embedded

View File

@ -1,8 +1,7 @@
package me.ash.reader.data.feed package me.ash.reader.data.entity
import androidx.room.Embedded import androidx.room.Embedded
import androidx.room.Relation import androidx.room.Relation
import me.ash.reader.data.group.Group
data class FeedWithGroup( data class FeedWithGroup(
@Embedded @Embedded

View File

@ -1,4 +1,4 @@
package me.ash.reader.data.constant package me.ash.reader.data.entity
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.FiberManualRecord import androidx.compose.material.icons.filled.FiberManualRecord

View File

@ -1,4 +1,4 @@
package me.ash.reader.data.group package me.ash.reader.data.entity
import androidx.room.ColumnInfo import androidx.room.ColumnInfo
import androidx.room.Entity import androidx.room.Entity

View File

@ -1,8 +1,7 @@
package me.ash.reader.data.group package me.ash.reader.data.entity
import androidx.room.Embedded import androidx.room.Embedded
import androidx.room.Relation import androidx.room.Relation
import me.ash.reader.data.feed.Feed
data class GroupWithFeed( data class GroupWithFeed(
@Embedded @Embedded

View File

@ -1,4 +1,4 @@
package me.ash.reader.data.article package me.ash.reader.data.entity
data class ImportantCount( data class ImportantCount(
val important: Int, val important: Int,

View File

@ -6,10 +6,10 @@ import dagger.Provides
import dagger.hilt.InstallIn import dagger.hilt.InstallIn
import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent import dagger.hilt.components.SingletonComponent
import me.ash.reader.data.account.AccountDao import me.ash.reader.data.dao.AccountDao
import me.ash.reader.data.article.ArticleDao import me.ash.reader.data.dao.ArticleDao
import me.ash.reader.data.feed.FeedDao import me.ash.reader.data.dao.FeedDao
import me.ash.reader.data.group.GroupDao import me.ash.reader.data.dao.GroupDao
import me.ash.reader.data.source.ReaderDatabase import me.ash.reader.data.source.ReaderDatabase
import javax.inject.Singleton import javax.inject.Singleton

View File

@ -10,18 +10,13 @@ import dagger.assisted.AssistedInject
import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.flow.* import kotlinx.coroutines.flow.*
import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.Mutex
import me.ash.reader.currentAccountId import me.ash.reader.data.dao.AccountDao
import me.ash.reader.data.account.AccountDao import me.ash.reader.data.dao.ArticleDao
import me.ash.reader.data.article.Article import me.ash.reader.data.dao.FeedDao
import me.ash.reader.data.article.ArticleDao import me.ash.reader.data.dao.GroupDao
import me.ash.reader.data.article.ArticleWithFeed import me.ash.reader.data.entity.*
import me.ash.reader.data.article.ImportantCount
import me.ash.reader.data.feed.Feed
import me.ash.reader.data.feed.FeedDao
import me.ash.reader.data.group.Group
import me.ash.reader.data.group.GroupDao
import me.ash.reader.data.group.GroupWithFeed
import me.ash.reader.data.source.RssNetworkDataSource import me.ash.reader.data.source.RssNetworkDataSource
import me.ash.reader.ui.ext.currentAccountId
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
abstract class AbstractRssRepository constructor( abstract class AbstractRssRepository constructor(

View File

@ -3,12 +3,12 @@ package me.ash.reader.data.repository
import android.content.Context import android.content.Context
import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.android.qualifiers.ApplicationContext
import me.ash.reader.R import me.ash.reader.R
import me.ash.reader.currentAccountId import me.ash.reader.data.dao.AccountDao
import me.ash.reader.data.account.Account import me.ash.reader.data.dao.GroupDao
import me.ash.reader.data.account.AccountDao import me.ash.reader.data.entity.Account
import me.ash.reader.data.group.Group import me.ash.reader.data.entity.Group
import me.ash.reader.data.group.GroupDao import me.ash.reader.ui.ext.currentAccountId
import me.ash.reader.spacerDollar import me.ash.reader.ui.ext.spacerDollar
import javax.inject.Inject import javax.inject.Inject
class AccountRepository @Inject constructor( class AccountRepository @Inject constructor(

View File

@ -8,20 +8,20 @@ import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.sync.withLock import kotlinx.coroutines.sync.withLock
import me.ash.reader.currentAccountId import me.ash.reader.data.dao.AccountDao
import me.ash.reader.data.account.AccountDao import me.ash.reader.data.dao.ArticleDao
import me.ash.reader.data.article.Article import me.ash.reader.data.dao.FeedDao
import me.ash.reader.data.article.ArticleDao import me.ash.reader.data.dao.GroupDao
import me.ash.reader.data.feed.Feed import me.ash.reader.data.entity.Article
import me.ash.reader.data.feed.FeedDao import me.ash.reader.data.entity.Feed
import me.ash.reader.data.group.Group import me.ash.reader.data.entity.Group
import me.ash.reader.data.group.GroupDao
import me.ash.reader.data.module.ApplicationScope import me.ash.reader.data.module.ApplicationScope
import me.ash.reader.data.module.DispatcherDefault import me.ash.reader.data.module.DispatcherDefault
import me.ash.reader.data.module.DispatcherIO import me.ash.reader.data.module.DispatcherIO
import me.ash.reader.data.source.FeverApiDataSource import me.ash.reader.data.source.FeverApiDataSource
import me.ash.reader.data.source.RssNetworkDataSource import me.ash.reader.data.source.RssNetworkDataSource
import me.ash.reader.spacerDollar import me.ash.reader.ui.ext.currentAccountId
import me.ash.reader.ui.ext.spacerDollar
import net.dankito.readability4j.extended.Readability4JExtended import net.dankito.readability4j.extended.Readability4JExtended
import java.util.* import java.util.*
import javax.inject.Inject import javax.inject.Inject

View File

@ -14,18 +14,18 @@ import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.* import kotlinx.coroutines.*
import me.ash.reader.MainActivity import me.ash.reader.MainActivity
import me.ash.reader.R import me.ash.reader.R
import me.ash.reader.currentAccountId import me.ash.reader.data.dao.AccountDao
import me.ash.reader.data.account.AccountDao import me.ash.reader.data.dao.ArticleDao
import me.ash.reader.data.article.Article import me.ash.reader.data.dao.FeedDao
import me.ash.reader.data.article.ArticleDao import me.ash.reader.data.dao.GroupDao
import me.ash.reader.data.feed.Feed import me.ash.reader.data.entity.Article
import me.ash.reader.data.feed.FeedDao import me.ash.reader.data.entity.Feed
import me.ash.reader.data.group.Group import me.ash.reader.data.entity.Group
import me.ash.reader.data.group.GroupDao
import me.ash.reader.data.module.ApplicationScope import me.ash.reader.data.module.ApplicationScope
import me.ash.reader.data.module.DispatcherDefault import me.ash.reader.data.module.DispatcherDefault
import me.ash.reader.data.module.DispatcherIO import me.ash.reader.data.module.DispatcherIO
import me.ash.reader.data.source.RssNetworkDataSource import me.ash.reader.data.source.RssNetworkDataSource
import me.ash.reader.ui.ext.currentAccountId
import me.ash.reader.ui.page.common.ExtraName import me.ash.reader.ui.page.common.ExtraName
import me.ash.reader.ui.page.common.NotificationGroupName import me.ash.reader.ui.page.common.NotificationGroupName
import java.util.* import java.util.*

View File

@ -8,13 +8,13 @@ import be.ceau.opml.entity.Opml
import be.ceau.opml.entity.Outline import be.ceau.opml.entity.Outline
import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.android.qualifiers.ApplicationContext
import me.ash.reader.R import me.ash.reader.R
import me.ash.reader.currentAccountId import me.ash.reader.data.dao.AccountDao
import me.ash.reader.data.account.AccountDao import me.ash.reader.data.dao.FeedDao
import me.ash.reader.data.feed.Feed import me.ash.reader.data.dao.GroupDao
import me.ash.reader.data.feed.FeedDao import me.ash.reader.data.entity.Feed
import me.ash.reader.data.group.GroupDao
import me.ash.reader.data.source.OpmlLocalDataSource import me.ash.reader.data.source.OpmlLocalDataSource
import me.ash.reader.spacerDollar import me.ash.reader.ui.ext.currentAccountId
import me.ash.reader.ui.ext.spacerDollar
import java.io.InputStream import java.io.InputStream
import java.util.* import java.util.*
import javax.inject.Inject import javax.inject.Inject

View File

@ -6,14 +6,14 @@ import android.util.Log
import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import me.ash.reader.currentAccountId import me.ash.reader.data.dao.FeedDao
import me.ash.reader.data.article.Article import me.ash.reader.data.entity.Article
import me.ash.reader.data.feed.Feed import me.ash.reader.data.entity.Feed
import me.ash.reader.data.feed.FeedDao import me.ash.reader.data.entity.FeedWithArticle
import me.ash.reader.data.feed.FeedWithArticle
import me.ash.reader.data.module.DispatcherIO import me.ash.reader.data.module.DispatcherIO
import me.ash.reader.data.source.RssNetworkDataSource import me.ash.reader.data.source.RssNetworkDataSource
import me.ash.reader.spacerDollar import me.ash.reader.ui.ext.currentAccountId
import me.ash.reader.ui.ext.spacerDollar
import net.dankito.readability4j.Readability4J import net.dankito.readability4j.Readability4J
import net.dankito.readability4j.extended.Readability4JExtended import net.dankito.readability4j.extended.Readability4JExtended
import okhttp3.OkHttpClient import okhttp3.OkHttpClient

View File

@ -2,8 +2,8 @@ package me.ash.reader.data.repository
import android.content.Context import android.content.Context
import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.android.qualifiers.ApplicationContext
import me.ash.reader.currentAccountType import me.ash.reader.data.entity.Account
import me.ash.reader.data.account.Account import me.ash.reader.ui.ext.currentAccountType
import javax.inject.Inject import javax.inject.Inject
class RssRepository @Inject constructor( class RssRepository @Inject constructor(

View File

@ -5,11 +5,11 @@ import be.ceau.opml.OpmlParser
import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import me.ash.reader.currentAccountId import me.ash.reader.data.entity.Feed
import me.ash.reader.data.feed.Feed import me.ash.reader.data.entity.Group
import me.ash.reader.data.group.Group import me.ash.reader.data.entity.GroupWithFeed
import me.ash.reader.data.group.GroupWithFeed
import me.ash.reader.data.module.DispatcherIO import me.ash.reader.data.module.DispatcherIO
import me.ash.reader.ui.ext.currentAccountId
import java.io.InputStream import java.io.InputStream
import java.util.* import java.util.*
import javax.inject.Inject import javax.inject.Inject

View File

@ -1,26 +1,23 @@
package me.ash.reader.data.source package me.ash.reader.data.source
import android.content.Context import android.content.Context
import androidx.room.Database import androidx.room.*
import androidx.room.Room import me.ash.reader.data.dao.AccountDao
import androidx.room.RoomDatabase import me.ash.reader.data.dao.ArticleDao
import androidx.room.TypeConverters import me.ash.reader.data.dao.FeedDao
import me.ash.reader.data.Converters import me.ash.reader.data.dao.GroupDao
import me.ash.reader.data.account.Account import me.ash.reader.data.entity.Account
import me.ash.reader.data.account.AccountDao import me.ash.reader.data.entity.Article
import me.ash.reader.data.article.Article import me.ash.reader.data.entity.Feed
import me.ash.reader.data.article.ArticleDao import me.ash.reader.data.entity.Group
import me.ash.reader.data.feed.Feed import java.util.*
import me.ash.reader.data.feed.FeedDao
import me.ash.reader.data.group.Group
import me.ash.reader.data.group.GroupDao
@Database( @Database(
entities = [Account::class, Feed::class, Article::class, Group::class], entities = [Account::class, Feed::class, Article::class, Group::class],
version = 1, version = 1,
exportSchema = false, exportSchema = false,
) )
@TypeConverters(Converters::class) @TypeConverters(ReaderDatabase.Converters::class)
abstract class ReaderDatabase : RoomDatabase() { abstract class ReaderDatabase : RoomDatabase() {
abstract fun accountDao(): AccountDao abstract fun accountDao(): AccountDao
abstract fun feedDao(): FeedDao abstract fun feedDao(): FeedDao
@ -42,4 +39,17 @@ abstract class ReaderDatabase : RoomDatabase() {
} }
} }
} }
class Converters {
@TypeConverter
fun toDate(dateLong: Long?): Date? {
return dateLong?.let { Date(it) }
}
@TypeConverter
fun fromDate(date: Date?): Long? {
return date?.time
}
}
} }

View File

@ -1,4 +1,4 @@
package me.ash.reader.ui.widget package me.ash.reader.ui.component
import androidx.compose.animation.* import androidx.compose.animation.*
import androidx.compose.animation.core.FastOutSlowInEasing import androidx.compose.animation.core.FastOutSlowInEasing

View File

@ -1,4 +1,4 @@
package me.ash.reader.ui.widget package me.ash.reader.ui.component
import androidx.compose.animation.Crossfade import androidx.compose.animation.Crossfade
import androidx.compose.foundation.background import androidx.compose.foundation.background

View File

@ -1,4 +1,4 @@
package me.ash.reader.ui.widget package me.ash.reader.ui.component
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.*

View File

@ -1,4 +1,4 @@
package me.ash.reader.ui.widget package me.ash.reader.ui.component
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.material3.Icon import androidx.compose.material3.Icon

View File

@ -1,4 +1,4 @@
package me.ash.reader.ui.widget package me.ash.reader.ui.component
import androidx.compose.material3.AlertDialog import androidx.compose.material3.AlertDialog
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable

View File

@ -1,4 +1,4 @@
package me.ash.reader.ui.widget package me.ash.reader.ui.component
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue

View File

@ -1,4 +1,4 @@
package me.ash.reader.ui.widget package me.ash.reader.ui.component
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.material3.DropdownMenu import androidx.compose.material3.DropdownMenu

View File

@ -1,4 +1,4 @@
package me.ash.reader.ui.widget package me.ash.reader.ui.component
import androidx.compose.foundation.BorderStroke import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.interaction.MutableInteractionSource
@ -153,7 +153,7 @@ fun SelectionEditorChip(
onValueChange = { onValueChange(it) }, onValueChange = { onValueChange(it) },
cursorBrush = SolidColor(MaterialTheme.colorScheme.onSurfaceVariant), cursorBrush = SolidColor(MaterialTheme.colorScheme.onSurfaceVariant),
textStyle = MaterialTheme.typography.titleSmall.copy( textStyle = MaterialTheme.typography.titleSmall.copy(
color = MaterialTheme.colorScheme.onSurfaceVariant, color = MaterialTheme.colorScheme.onSurfaceVariant,
), ),
decorationBox = { innerTextField -> decorationBox = { innerTextField ->
Row( Row(

View File

@ -1,4 +1,4 @@
package me.ash.reader.ui.widget package me.ash.reader.ui.component
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding

View File

@ -1,4 +1,4 @@
package me.ash.reader.ui.widget package me.ash.reader.ui.component
import androidx.compose.animation.animateContentSize import androidx.compose.animation.animateContentSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth

View File

@ -1,4 +1,4 @@
package me.ash.reader.ui.widget package me.ash.reader.ui.component
import android.content.Intent import android.content.Intent
import android.graphics.Bitmap import android.graphics.Bitmap
@ -8,6 +8,9 @@ import android.util.Log
import android.webkit.* import android.webkit.*
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.toArgb import androidx.compose.ui.graphics.toArgb
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
@ -29,80 +32,94 @@ fun WebView(
val context = LocalContext.current val context = LocalContext.current
val color = MaterialTheme.colorScheme.onSurfaceVariant.toArgb() val color = MaterialTheme.colorScheme.onSurfaceVariant.toArgb()
val backgroundColor = MaterialTheme.colorScheme.surface.toArgb() val backgroundColor = MaterialTheme.colorScheme.surface.toArgb()
val webViewClient = object : WebViewClient() { val webViewClient by remember {
mutableStateOf(object : WebViewClient() {
override fun shouldInterceptRequest(view: WebView?, url: String?): WebResourceResponse? { override fun shouldInterceptRequest(
if (url != null && url.contains(INJECTION_TOKEN)) { view: WebView?,
try { url: String?
val assetPath = url.substring( ): WebResourceResponse? {
url.indexOf(INJECTION_TOKEN) + INJECTION_TOKEN.length, if (url != null && url.contains(INJECTION_TOKEN)) {
url.length try {
) val assetPath = url.substring(
return WebResourceResponse( url.indexOf(INJECTION_TOKEN) + INJECTION_TOKEN.length,
"text/HTML", url.length
"UTF-8", )
context.assets.open(assetPath) return WebResourceResponse(
) "text/HTML",
} catch (e: Exception) { "UTF-8",
Log.e("RLog", "WebView shouldInterceptRequest: $e") context.assets.open(assetPath)
)
} catch (e: Exception) {
Log.e("RLog", "WebView shouldInterceptRequest: $e")
}
} }
return super.shouldInterceptRequest(view, url);
} }
return super.shouldInterceptRequest(view, url);
}
override fun onPageStarted( override fun onPageStarted(
view: WebView?, view: WebView?,
url: String?, url: String?,
favicon: Bitmap? favicon: Bitmap?
) { ) {
super.onPageStarted(view, url, favicon) super.onPageStarted(view, url, favicon)
// _isLoading = true // _isLoading = true
onProgressChange(-1) onProgressChange(-1)
} }
override fun onPageFinished(view: WebView?, url: String?) { override fun onPageFinished(view: WebView?, url: String?) {
super.onPageFinished(view, url) super.onPageFinished(view, url)
val jsCode = "javascript:(function(){" + val jsCode = "javascript:(function(){" +
"var imgs=document.getElementsByTagName(\"img\");" + "var imgs=document.getElementsByTagName(\"img\");" +
"for(var i=0;i<imgs.length;i++){" + "for(var i=0;i<imgs.length;i++){" +
"imgs[i].pos = i;" + "imgs[i].pos = i;" +
"imgs[i].onclick=function(){" + "imgs[i].onclick=function(){" +
// "window.jsCallJavaObj.openImage(this.src,this.pos);" + // "window.jsCallJavaObj.openImage(this.src,this.pos);" +
"alert('asf');" + "alert('asf');" +
"}}})()" "}}})()"
view!!.loadUrl(jsCode) view!!.loadUrl(jsCode)
viewModel.dispatch(ReadViewAction.ChangeLoading(false)) viewModel.dispatch(ReadViewAction.ChangeLoading(false))
onProgressChange(100) onProgressChange(100)
} }
override fun shouldOverrideUrlLoading( override fun shouldOverrideUrlLoading(
view: WebView?, view: WebView?,
request: WebResourceRequest? request: WebResourceRequest?
): Boolean { ): Boolean {
if (null == request?.url) return false if (null == request?.url) return false
val url = request.url.toString() val url = request.url.toString()
context.startActivity( context.startActivity(
Intent(Intent.ACTION_VIEW, Uri.parse(url)) Intent(Intent.ACTION_VIEW, Uri.parse(url))
) )
return true return true
} }
override fun onReceivedError( override fun onReceivedError(
view: WebView?, view: WebView?,
request: WebResourceRequest?, request: WebResourceRequest?,
error: WebResourceError? error: WebResourceError?
) { ) {
super.onReceivedError(view, request, error) super.onReceivedError(view, request, error)
onReceivedError(error) onReceivedError(error)
} }
override fun onReceivedSslError( override fun onReceivedSslError(
view: WebView?, view: WebView?,
handler: SslErrorHandler?, handler: SslErrorHandler?,
error: SslError? error: SslError?
) { ) {
handler?.cancel() handler?.cancel()
} }
})
}
val webView by remember {
mutableStateOf(WebView(context).apply {
this.webViewClient = webViewClient
setBackgroundColor(backgroundColor)
isHorizontalScrollBarEnabled = false
isVerticalScrollBarEnabled = false
})
} }
// Column( // Column(
@ -121,14 +138,7 @@ fun WebView(
AndroidView( AndroidView(
modifier = modifier, modifier = modifier,
factory = { factory = { webView },
WebView(it).apply {
this.webViewClient = webViewClient
setBackgroundColor(backgroundColor)
isHorizontalScrollBarEnabled = false
isVerticalScrollBarEnabled = false
}
},
update = { update = {
it.apply { it.apply {
Log.i("RLog", "CustomWebView: ${content}") Log.i("RLog", "CustomWebView: ${content}")

View File

@ -1,4 +1,4 @@
package me.ash.reader.ui.extension package me.ash.reader.ui.ext
import androidx.compose.material3.ColorScheme import androidx.compose.material3.ColorScheme
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color

View File

@ -1,4 +1,4 @@
package me.ash.reader.ui.extension package me.ash.reader.ui.ext
import android.app.Activity import android.app.Activity
import android.content.Context import android.content.Context

View File

@ -1,4 +1,4 @@
package me.ash.reader package me.ash.reader.ui.ext
import android.content.Context import android.content.Context
import android.util.Log import android.util.Log

View File

@ -1,12 +1,13 @@
package me.ash.reader package me.ash.reader.ui.ext
import android.content.Context import android.content.Context
import androidx.core.os.ConfigurationCompat import androidx.core.os.ConfigurationCompat
import me.ash.reader.R
import java.text.DateFormat import java.text.DateFormat
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.* import java.util.*
fun Date.formatToString( fun Date.formatAsString(
context: Context, context: Context,
onlyHourMinute: Boolean? = false, onlyHourMinute: Boolean? = false,
atHourMinute: Boolean? = false, atHourMinute: Boolean? = false,

View File

@ -1,9 +1,9 @@
package me.ash.reader.ui.extension package me.ash.reader.ui.ext
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import me.ash.reader.R import me.ash.reader.R
import me.ash.reader.data.constant.Filter import me.ash.reader.data.entity.Filter
@Composable @Composable
fun Filter.getName(): String = when (this) { fun Filter.getName(): String = when (this) {

View File

@ -1,4 +1,4 @@
package me.ash.reader.ui.extension package me.ash.reader.ui.ext
import androidx.compose.foundation.lazy.LazyListState import androidx.compose.foundation.lazy.LazyListState
import kotlin.math.abs import kotlin.math.abs

View File

@ -1,4 +1,4 @@
package me.ash.reader.ui.extension package me.ash.reader.ui.ext
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding

View File

@ -0,0 +1,3 @@
package me.ash.reader.ui.ext
fun Int.spacerDollar(str: Any): String = "$this$$str"

View File

@ -1,4 +1,4 @@
package me.ash.reader.ui.extension package me.ash.reader.ui.ext
import com.google.accompanist.pager.ExperimentalPagerApi import com.google.accompanist.pager.ExperimentalPagerApi
import com.google.accompanist.pager.PagerState import com.google.accompanist.pager.PagerState

View File

@ -0,0 +1,12 @@
package me.ash.reader.ui.ext
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.StateFlow
import kotlin.coroutines.CoroutineContext
@Composable
fun <T> StateFlow<T>.collectAsStateValue(
context: CoroutineContext = Dispatchers.Default
): T = collectAsState(context).value

View File

@ -1,4 +1,4 @@
package me.ash.reader package me.ash.reader.ui.ext
fun String.formatUrl(): String { fun String.formatUrl(): String {
if (this.startsWith("//")) { if (this.startsWith("//")) {

View File

@ -1,23 +0,0 @@
package me.ash.reader.ui.extension
import androidx.compose.runtime.Composable
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.State
import androidx.compose.runtime.collectAsState
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.StateFlow
import kotlin.coroutines.CoroutineContext
import kotlin.reflect.KProperty
@Composable
fun <T> StateFlow<T>.collectAsStateValue(
context: CoroutineContext = Dispatchers.Default
): T = collectAsState(context).value
@Suppress("NOTHING_TO_INLINE")
inline operator fun <T> State<T>.getValue(thisObj: Any?, property: KProperty<*>): T = value
@Suppress("NOTHING_TO_INLINE")
inline operator fun <T> MutableState<T>.setValue(thisObj: Any?, property: KProperty<*>, value: T) {
this.value = value
}

View File

@ -7,8 +7,8 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.zIndex import androidx.compose.ui.zIndex
import com.google.accompanist.pager.ExperimentalPagerApi import com.google.accompanist.pager.ExperimentalPagerApi
import me.ash.reader.data.constant.Filter import me.ash.reader.data.entity.Filter
import me.ash.reader.ui.extension.getName import me.ash.reader.ui.ext.getName
@OptIn(ExperimentalPagerApi::class) @OptIn(ExperimentalPagerApi::class)
@Composable @Composable
@ -21,7 +21,10 @@ fun FilterBar(
modifier = Modifier.height(60.dp) modifier = Modifier.height(60.dp)
) { ) {
Divider( Divider(
modifier = Modifier.fillMaxWidth().height(1.dp).zIndex(1f), modifier = Modifier
.fillMaxWidth()
.height(1.dp)
.zIndex(1f),
color = MaterialTheme.colorScheme.secondaryContainer.copy(alpha = 0.24f) color = MaterialTheme.colorScheme.secondaryContainer.copy(alpha = 0.24f)
) )
NavigationBar( NavigationBar(

View File

@ -10,8 +10,9 @@ import androidx.hilt.navigation.compose.hiltViewModel
import androidx.navigation.NavHostController import androidx.navigation.NavHostController
import com.google.accompanist.pager.ExperimentalPagerApi import com.google.accompanist.pager.ExperimentalPagerApi
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import me.ash.reader.ui.extension.collectAsStateValue import me.ash.reader.ui.component.ViewPager
import me.ash.reader.ui.extension.findActivity import me.ash.reader.ui.ext.collectAsStateValue
import me.ash.reader.ui.ext.findActivity
import me.ash.reader.ui.page.common.ExtraName import me.ash.reader.ui.page.common.ExtraName
import me.ash.reader.ui.page.home.drawer.feed.FeedOptionDrawer import me.ash.reader.ui.page.home.drawer.feed.FeedOptionDrawer
import me.ash.reader.ui.page.home.drawer.feed.FeedOptionViewAction import me.ash.reader.ui.page.home.drawer.feed.FeedOptionViewAction
@ -21,7 +22,6 @@ import me.ash.reader.ui.page.home.flow.FlowPage
import me.ash.reader.ui.page.home.read.ReadPage import me.ash.reader.ui.page.home.read.ReadPage
import me.ash.reader.ui.page.home.read.ReadViewAction import me.ash.reader.ui.page.home.read.ReadViewAction
import me.ash.reader.ui.page.home.read.ReadViewModel import me.ash.reader.ui.page.home.read.ReadViewModel
import me.ash.reader.ui.widget.ViewPager
@OptIn(ExperimentalPagerApi::class, androidx.compose.material.ExperimentalMaterialApi::class) @OptIn(ExperimentalPagerApi::class, androidx.compose.material.ExperimentalMaterialApi::class)
@Composable @Composable

View File

@ -9,12 +9,12 @@ import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.update import kotlinx.coroutines.flow.update
import me.ash.reader.data.constant.Filter import me.ash.reader.data.entity.Feed
import me.ash.reader.data.feed.Feed import me.ash.reader.data.entity.Filter
import me.ash.reader.data.group.Group import me.ash.reader.data.entity.Group
import me.ash.reader.data.repository.AbstractRssRepository import me.ash.reader.data.repository.AbstractRssRepository
import me.ash.reader.data.repository.RssRepository import me.ash.reader.data.repository.RssRepository
import me.ash.reader.ui.extension.animateScrollToPage import me.ash.reader.ui.ext.animateScrollToPage
import javax.inject.Inject import javax.inject.Inject
@OptIn(ExperimentalPagerApi::class) @OptIn(ExperimentalPagerApi::class)

View File

@ -14,8 +14,8 @@ import androidx.compose.ui.res.stringResource
import androidx.hilt.navigation.compose.hiltViewModel import androidx.hilt.navigation.compose.hiltViewModel
import com.google.accompanist.pager.ExperimentalPagerApi import com.google.accompanist.pager.ExperimentalPagerApi
import me.ash.reader.R import me.ash.reader.R
import me.ash.reader.ui.extension.collectAsStateValue import me.ash.reader.ui.component.Dialog
import me.ash.reader.ui.widget.Dialog import me.ash.reader.ui.ext.collectAsStateValue
@OptIn(ExperimentalPagerApi::class) @OptIn(ExperimentalPagerApi::class)
@Composable @Composable

View File

@ -17,11 +17,11 @@ import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel import androidx.hilt.navigation.compose.hiltViewModel
import me.ash.reader.R import me.ash.reader.R
import me.ash.reader.ui.extension.collectAsStateValue import me.ash.reader.ui.component.BottomDrawer
import me.ash.reader.ui.extension.roundClick import me.ash.reader.ui.component.Subtitle
import me.ash.reader.ui.ext.collectAsStateValue
import me.ash.reader.ui.ext.roundClick
import me.ash.reader.ui.page.home.feeds.subscribe.ResultViewPage import me.ash.reader.ui.page.home.feeds.subscribe.ResultViewPage
import me.ash.reader.ui.widget.BottomDrawer
import me.ash.reader.ui.widget.Subtitle
@OptIn(ExperimentalMaterialApi::class) @OptIn(ExperimentalMaterialApi::class)
@Composable @Composable

View File

@ -15,8 +15,8 @@ import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.update import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import me.ash.reader.data.feed.Feed import me.ash.reader.data.entity.Feed
import me.ash.reader.data.group.Group import me.ash.reader.data.entity.Group
import me.ash.reader.data.repository.RssRepository import me.ash.reader.data.repository.RssRepository
import javax.inject.Inject import javax.inject.Inject

View File

@ -18,7 +18,7 @@ import androidx.compose.ui.platform.LocalView
import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel import androidx.hilt.navigation.compose.hiltViewModel
import me.ash.reader.data.feed.Feed import me.ash.reader.data.entity.Feed
import me.ash.reader.ui.page.home.drawer.feed.FeedOptionViewAction import me.ash.reader.ui.page.home.drawer.feed.FeedOptionViewAction
import me.ash.reader.ui.page.home.drawer.feed.FeedOptionViewModel import me.ash.reader.ui.page.home.drawer.feed.FeedOptionViewModel

View File

@ -28,16 +28,16 @@ import androidx.hilt.navigation.compose.hiltViewModel
import androidx.navigation.NavHostController import androidx.navigation.NavHostController
import me.ash.reader.R import me.ash.reader.R
import me.ash.reader.data.repository.AbstractRssRepository import me.ash.reader.data.repository.AbstractRssRepository
import me.ash.reader.ui.extension.collectAsStateValue import me.ash.reader.ui.component.Banner
import me.ash.reader.ui.extension.getDesc import me.ash.reader.ui.component.Subtitle
import me.ash.reader.ui.extension.getName import me.ash.reader.ui.ext.collectAsStateValue
import me.ash.reader.ui.ext.getDesc
import me.ash.reader.ui.ext.getName
import me.ash.reader.ui.page.home.FilterBar import me.ash.reader.ui.page.home.FilterBar
import me.ash.reader.ui.page.home.FilterState import me.ash.reader.ui.page.home.FilterState
import me.ash.reader.ui.page.home.feeds.subscribe.SubscribeDialog import me.ash.reader.ui.page.home.feeds.subscribe.SubscribeDialog
import me.ash.reader.ui.page.home.feeds.subscribe.SubscribeViewAction import me.ash.reader.ui.page.home.feeds.subscribe.SubscribeViewAction
import me.ash.reader.ui.page.home.feeds.subscribe.SubscribeViewModel import me.ash.reader.ui.page.home.feeds.subscribe.SubscribeViewModel
import me.ash.reader.ui.widget.Banner
import me.ash.reader.ui.widget.Subtitle
@OptIn( @OptIn(
ExperimentalMaterial3Api::class, com.google.accompanist.pager.ExperimentalPagerApi::class, ExperimentalMaterial3Api::class, com.google.accompanist.pager.ExperimentalPagerApi::class,

View File

@ -8,9 +8,9 @@ import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.* import kotlinx.coroutines.flow.*
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import me.ash.reader.data.account.Account import me.ash.reader.data.entity.Account
import me.ash.reader.data.constant.Filter import me.ash.reader.data.entity.Filter
import me.ash.reader.data.group.GroupWithFeed import me.ash.reader.data.entity.GroupWithFeed
import me.ash.reader.data.repository.AccountRepository import me.ash.reader.data.repository.AccountRepository
import me.ash.reader.data.repository.OpmlRepository import me.ash.reader.data.repository.OpmlRepository
import me.ash.reader.data.repository.RssRepository import me.ash.reader.data.repository.RssRepository

View File

@ -22,7 +22,7 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import me.ash.reader.R import me.ash.reader.R
import me.ash.reader.data.feed.Feed import me.ash.reader.data.entity.Feed
@OptIn(ExperimentalMaterialApi::class, androidx.compose.foundation.ExperimentalFoundationApi::class) @OptIn(ExperimentalMaterialApi::class, androidx.compose.foundation.ExperimentalFoundationApi::class)
@Composable @Composable
@ -57,7 +57,9 @@ fun GroupItem(
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
) { ) {
Text( Text(
modifier = Modifier.weight(1f).padding(start = 28.dp), modifier = Modifier
.weight(1f)
.padding(start = 28.dp),
text = text, text = text,
style = MaterialTheme.typography.titleMedium, style = MaterialTheme.typography.titleMedium,
color = MaterialTheme.colorScheme.onSecondaryContainer, color = MaterialTheme.colorScheme.onSecondaryContainer,

View File

@ -22,11 +22,11 @@ import androidx.compose.ui.unit.dp
import com.google.accompanist.flowlayout.FlowRow import com.google.accompanist.flowlayout.FlowRow
import com.google.accompanist.flowlayout.MainAxisAlignment import com.google.accompanist.flowlayout.MainAxisAlignment
import me.ash.reader.R import me.ash.reader.R
import me.ash.reader.data.group.Group import me.ash.reader.data.entity.Group
import me.ash.reader.ui.extension.roundClick import me.ash.reader.ui.component.SelectionChip
import me.ash.reader.ui.widget.SelectionChip import me.ash.reader.ui.component.SelectionEditorChip
import me.ash.reader.ui.widget.SelectionEditorChip import me.ash.reader.ui.component.Subtitle
import me.ash.reader.ui.widget.Subtitle import me.ash.reader.ui.ext.roundClick
@Composable @Composable
fun ResultViewPage( fun ResultViewPage(

View File

@ -21,10 +21,9 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.DialogProperties import androidx.compose.ui.window.DialogProperties
import androidx.hilt.navigation.compose.hiltViewModel import androidx.hilt.navigation.compose.hiltViewModel
import com.google.accompanist.pager.ExperimentalPagerApi import com.google.accompanist.pager.ExperimentalPagerApi
import me.ash.reader.*
import me.ash.reader.R import me.ash.reader.R
import me.ash.reader.ui.extension.collectAsStateValue import me.ash.reader.ui.component.Dialog
import me.ash.reader.ui.widget.Dialog import me.ash.reader.ui.ext.*
@OptIn(ExperimentalPagerApi::class, androidx.compose.ui.ExperimentalComposeUiApi::class) @OptIn(ExperimentalPagerApi::class, androidx.compose.ui.ExperimentalComposeUiApi::class)
@Composable @Composable

View File

@ -9,15 +9,15 @@ import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.* import kotlinx.coroutines.*
import kotlinx.coroutines.flow.* import kotlinx.coroutines.flow.*
import me.ash.reader.R import me.ash.reader.R
import me.ash.reader.data.article.Article import me.ash.reader.data.entity.Article
import me.ash.reader.data.feed.Feed import me.ash.reader.data.entity.Feed
import me.ash.reader.data.group.Group import me.ash.reader.data.entity.Group
import me.ash.reader.data.repository.OpmlRepository import me.ash.reader.data.repository.OpmlRepository
import me.ash.reader.data.repository.RssHelper import me.ash.reader.data.repository.RssHelper
import me.ash.reader.data.repository.RssRepository import me.ash.reader.data.repository.RssRepository
import me.ash.reader.data.repository.StringsRepository import me.ash.reader.data.repository.StringsRepository
import me.ash.reader.formatUrl import me.ash.reader.ui.ext.animateScrollToPage
import me.ash.reader.ui.extension.animateScrollToPage import me.ash.reader.ui.ext.formatUrl
import java.io.InputStream import java.io.InputStream
import javax.inject.Inject import javax.inject.Inject

View File

@ -6,8 +6,8 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.input.pointer.pointerInput import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.platform.LocalFocusManager import androidx.compose.ui.platform.LocalFocusManager
import com.google.accompanist.pager.ExperimentalPagerApi import com.google.accompanist.pager.ExperimentalPagerApi
import me.ash.reader.data.group.Group import me.ash.reader.data.entity.Group
import me.ash.reader.ui.widget.ViewPager import me.ash.reader.ui.component.ViewPager
@OptIn(ExperimentalPagerApi::class) @OptIn(ExperimentalPagerApi::class)
@Composable @Composable

View File

@ -15,8 +15,8 @@ import androidx.compose.ui.draw.clip
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import me.ash.reader.data.article.ArticleWithFeed import me.ash.reader.data.entity.ArticleWithFeed
import me.ash.reader.formatToString import me.ash.reader.ui.ext.formatAsString
@Composable @Composable
fun ArticleItem( fun ArticleItem(
@ -40,7 +40,9 @@ fun ArticleItem(
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
) { ) {
Text( Text(
modifier = Modifier.weight(1f).padding(start = 30.dp), modifier = Modifier
.weight(1f)
.padding(start = 30.dp),
text = articleWithFeed.feed.name, text = articleWithFeed.feed.name,
color = MaterialTheme.colorScheme.tertiary, color = MaterialTheme.colorScheme.tertiary,
style = MaterialTheme.typography.labelMedium, style = MaterialTheme.typography.labelMedium,
@ -49,7 +51,7 @@ fun ArticleItem(
) )
Text( Text(
modifier = Modifier.padding(start = 6.dp), modifier = Modifier.padding(start = 6.dp),
text = articleWithFeed.article.date.formatToString(context, onlyHourMinute = true), text = articleWithFeed.article.date.formatAsString(context, onlyHourMinute = true),
color = MaterialTheme.colorScheme.outline.copy(alpha = 0.7f), color = MaterialTheme.colorScheme.outline.copy(alpha = 0.7f),
style = MaterialTheme.typography.labelMedium, style = MaterialTheme.typography.labelMedium,
) )

View File

@ -8,8 +8,8 @@ import androidx.compose.foundation.lazy.LazyListScope
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.paging.compose.LazyPagingItems import androidx.paging.compose.LazyPagingItems
import me.ash.reader.data.article.ArticleWithFeed import me.ash.reader.data.entity.ArticleWithFeed
import me.ash.reader.formatToString import me.ash.reader.ui.ext.formatAsString
@OptIn(ExperimentalFoundationApi::class) @OptIn(ExperimentalFoundationApi::class)
fun LazyListScope.generateArticleList( fun LazyListScope.generateArticleList(
@ -20,7 +20,7 @@ fun LazyListScope.generateArticleList(
var lastItemDay: String? = null var lastItemDay: String? = null
for (itemIndex in 0 until pagingItems.itemCount) { for (itemIndex in 0 until pagingItems.itemCount) {
val currentItem = pagingItems.peek(itemIndex) ?: continue val currentItem = pagingItems.peek(itemIndex) ?: continue
val currentItemDay = currentItem.article.date.formatToString(context) val currentItemDay = currentItem.article.date.formatAsString(context)
if (lastItemDay != currentItemDay) { if (lastItemDay != currentItemDay) {
if (itemIndex != 0) { if (itemIndex != 0) {
item { Spacer(modifier = Modifier.height(40.dp)) } item { Spacer(modifier = Modifier.height(40.dp)) }

View File

@ -24,9 +24,9 @@ import androidx.paging.LoadState
import androidx.paging.compose.collectAsLazyPagingItems import androidx.paging.compose.collectAsLazyPagingItems
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import me.ash.reader.R import me.ash.reader.R
import me.ash.reader.data.article.ArticleWithFeed import me.ash.reader.data.entity.ArticleWithFeed
import me.ash.reader.ui.extension.collectAsStateValue import me.ash.reader.ui.ext.collectAsStateValue
import me.ash.reader.ui.extension.getName import me.ash.reader.ui.ext.getName
import me.ash.reader.ui.page.home.FilterBar import me.ash.reader.ui.page.home.FilterBar
import me.ash.reader.ui.page.home.FilterState import me.ash.reader.ui.page.home.FilterState

View File

@ -11,7 +11,7 @@ import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.* import kotlinx.coroutines.flow.*
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import me.ash.reader.data.article.ArticleWithFeed import me.ash.reader.data.entity.ArticleWithFeed
import me.ash.reader.data.repository.RssRepository import me.ash.reader.data.repository.RssRepository
import me.ash.reader.ui.page.home.FilterState import me.ash.reader.ui.page.home.FilterState
import javax.inject.Inject import javax.inject.Inject

View File

@ -9,9 +9,9 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import me.ash.reader.data.article.ArticleWithFeed import me.ash.reader.data.entity.ArticleWithFeed
import me.ash.reader.formatToString import me.ash.reader.ui.ext.formatAsString
import me.ash.reader.ui.extension.roundClick import me.ash.reader.ui.ext.roundClick
@Composable @Composable
fun Header( fun Header(
@ -30,7 +30,7 @@ fun Header(
.padding(12.dp) .padding(12.dp)
) { ) {
Text( Text(
text = articleWithFeed.article.date.formatToString(context, atHourMinute = true), text = articleWithFeed.article.date.formatAsString(context, atHourMinute = true),
color = MaterialTheme.colorScheme.outline.copy(alpha = 0.7f), color = MaterialTheme.colorScheme.outline.copy(alpha = 0.7f),
style = MaterialTheme.typography.labelMedium, style = MaterialTheme.typography.labelMedium,
) )

View File

@ -22,7 +22,7 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.zIndex import androidx.compose.ui.zIndex
import me.ash.reader.R import me.ash.reader.R
import me.ash.reader.ui.widget.CanBeDisabledIconButton import me.ash.reader.ui.component.CanBeDisabledIconButton
@Composable @Composable
fun ReadBar( fun ReadBar(

View File

@ -21,9 +21,9 @@ import androidx.compose.ui.zIndex
import androidx.hilt.navigation.compose.hiltViewModel import androidx.hilt.navigation.compose.hiltViewModel
import androidx.navigation.NavHostController import androidx.navigation.NavHostController
import me.ash.reader.R import me.ash.reader.R
import me.ash.reader.data.article.ArticleWithFeed import me.ash.reader.data.entity.ArticleWithFeed
import me.ash.reader.ui.extension.collectAsStateValue import me.ash.reader.ui.component.WebView
import me.ash.reader.ui.widget.WebView import me.ash.reader.ui.ext.collectAsStateValue
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable

View File

@ -11,7 +11,7 @@ import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.update import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import me.ash.reader.data.article.ArticleWithFeed import me.ash.reader.data.entity.ArticleWithFeed
import me.ash.reader.data.repository.RssHelper import me.ash.reader.data.repository.RssHelper
import me.ash.reader.data.repository.RssRepository import me.ash.reader.data.repository.RssRepository
import javax.inject.Inject import javax.inject.Inject

View File

@ -11,7 +11,6 @@ import androidx.compose.material3.*
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
@ -20,9 +19,8 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import androidx.navigation.NavHostController import androidx.navigation.NavHostController
import me.ash.reader.R import me.ash.reader.R
import me.ash.reader.ui.extension.paddingFixedHorizontal import me.ash.reader.ui.ext.paddingFixedHorizontal
import me.ash.reader.ui.extension.roundClick import me.ash.reader.ui.ext.roundClick
import me.ash.reader.ui.widget.TopTitleBox
@Composable @Composable
fun SettingsPage( fun SettingsPage(
@ -33,17 +31,6 @@ fun SettingsPage(
// LargeTopAppBar( // LargeTopAppBar(
// title = { Text(text = "Settings") } // title = { Text(text = "Settings") }
// ) // )
TopTitleBox(
title = "Settings",
description = "",
listState = listState,
startOffset = Offset(20f, 78f),
startHeight = 72f,
startTitleFontSize = 36f,
startDescriptionFontSize = 0f,
) {
}
Column { Column {
SmallTopAppBar( SmallTopAppBar(
title = {}, title = {},

View File

@ -1,41 +0,0 @@
package me.ash.reader.ui.widget
import android.util.Log
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.expandVertically
import androidx.compose.animation.fadeIn
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.LazyListScope
import androidx.compose.foundation.lazy.LazyListState
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
@Composable
fun AnimateLazyColumn(
modifier: Modifier = Modifier,
state: LazyListState = rememberLazyListState(),
reference: Any?,
content: LazyListScope.() -> Unit,
) {
var visible by remember { mutableStateOf(true) }
LaunchedEffect(reference) {
Log.i("RLog", "reference change")
visible = false
// delay(50)
visible = true
}
AnimatedVisibility(
modifier = modifier.fillMaxSize(),
visible = visible,
enter = fadeIn() + expandVertically(),
) {
LazyColumn(
modifier = modifier,
state = state,
content = content,
)
}
}

View File

@ -1,134 +0,0 @@
import android.annotation.SuppressLint
import androidx.compose.animation.*
import androidx.compose.animation.core.Animatable
import androidx.compose.animation.core.MutableTransitionState
import androidx.compose.foundation.lazy.LazyItemScope
import androidx.compose.foundation.lazy.LazyListScope
import androidx.compose.runtime.*
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListUpdateCallback
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
@Suppress("UpdateTransitionLabel", "TransitionPropertiesLabel")
@SuppressLint("ComposableNaming", "UnusedTransitionTargetStateParameter")
/**
* @param state Use [updateAnimatedItemsState].
*/
inline fun <T> LazyListScope.animatedItemsIndexed(
state: List<AnimatedItem<T>>,
enterTransition: EnterTransition = expandVertically(),
exitTransition: ExitTransition = shrinkVertically(),
noinline key: ((item: T) -> Any)? = null,
crossinline itemContent: @Composable LazyItemScope.(index: Int, item: T) -> Unit
) {
items(
state.size,
if (key != null) { keyIndex: Int -> key(state[keyIndex].item) } else null
) { index ->
val item = state[index]
val visibility = item.visibility
key(key?.invoke(item.item)) {
AnimatedVisibility(
visibleState = visibility,
enter = enterTransition,
exit = exitTransition
) {
itemContent(index, item.item)
}
}
}
}
@Composable
fun <T> updateAnimatedItemsState(
newList: List<T>
): State<List<AnimatedItem<T>>> {
val state = remember { mutableStateOf(emptyList<AnimatedItem<T>>()) }
LaunchedEffect(newList) {
if (state.value == newList) {
return@LaunchedEffect
}
val oldList = state.value.toList()
val diffCb = object : DiffUtil.Callback() {
override fun getOldListSize(): Int = oldList.size
override fun getNewListSize(): Int = newList.size
override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean =
oldList[oldItemPosition].item == newList[newItemPosition]
override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean =
oldList[oldItemPosition].item == newList[newItemPosition]
}
val diffResult = calculateDiff(false, diffCb)
val compositeList = oldList.toMutableList()
diffResult.dispatchUpdatesTo(object : ListUpdateCallback {
override fun onInserted(position: Int, count: Int) {
for (i in 0 until count) {
val newItem = AnimatedItem(
visibility = MutableTransitionState(false),
newList[position + i]
)
newItem.visibility.targetState = true
compositeList.add(position + i, newItem)
}
}
override fun onRemoved(position: Int, count: Int) {
for (i in 0 until count) {
compositeList[position + i].visibility.targetState = false
}
}
override fun onMoved(fromPosition: Int, toPosition: Int) {
// not detecting moves.
}
override fun onChanged(position: Int, count: Int, payload: Any?) {
// irrelevant with compose.
}
})
if (state.value != compositeList) {
state.value = compositeList
}
val initialAnimation = Animatable(1.0f)
initialAnimation.animateTo(0f)
state.value = state.value.filter { it.visibility.targetState }
}
return state
}
data class AnimatedItem<T>(
val visibility: MutableTransitionState<Boolean>,
val item: T,
) {
override fun hashCode(): Int {
return item?.hashCode() ?: 0
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as AnimatedItem<*>
if (item != other.item) return false
return true
}
}
suspend fun calculateDiff(
detectMoves: Boolean = true,
diffCb: DiffUtil.Callback
): DiffUtil.DiffResult {
return withContext(Dispatchers.Unconfined) {
DiffUtil.calculateDiff(diffCb, detectMoves)
}
}

View File

@ -1,305 +0,0 @@
package me.ash.reader.ui.widget
import androidx.compose.animation.core.Animatable
import androidx.compose.animation.core.Spring
import androidx.compose.animation.core.SpringSpec
import androidx.compose.animation.core.calculateTargetValue
import androidx.compose.animation.splineBasedDecay
import androidx.compose.foundation.gestures.*
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clipToBounds
import androidx.compose.ui.input.pointer.PointerInputChange
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.input.pointer.positionChange
import androidx.compose.ui.input.pointer.util.VelocityTracker
import androidx.compose.ui.layout.Layout
import androidx.compose.ui.layout.Placeable
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.unit.Constraints
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.IntSize
import androidx.compose.ui.unit.dp
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
import kotlin.math.absoluteValue
import kotlin.math.ceil
import kotlin.math.roundToInt
import kotlin.math.sign
//val items = listOf(
// Color.Red,
// Color.Blue,
// Color.Green,
// Color.Yellow,
// Color.Cyan,
// Color.Magenta,
//)
@Composable
fun <T : Any> CustomPager(
items: List<T>,
modifier: Modifier = Modifier,
orientation: Orientation = Orientation.Horizontal,
initialIndex: Int = 0,
/*@FloatRange(from = 0.0, to = 1.0)*/
itemFraction: Float = 1f,
itemSpacing: Dp = 0.dp,
/*@FloatRange(from = 0.0, to = 1.0)*/
overshootFraction: Float = .5f,
onItemSelect: (T) -> Unit = {},
contentFactory: @Composable (T) -> Unit,
) {
Pager(
items,
modifier,
orientation,
initialIndex,
itemFraction,
itemSpacing,
overshootFraction,
onItemSelect = { index -> onItemSelect(items[index]) },
) {
items.forEach { item ->
Box(
modifier = when (orientation) {
Orientation.Horizontal -> Modifier.fillMaxWidth()
Orientation.Vertical -> Modifier.fillMaxHeight()
},
contentAlignment = Alignment.Center,
) {
contentFactory(item)
}
}
}
}
@Composable
fun <T : Any> Pager(
items: List<T>,
modifier: Modifier = Modifier,
orientation: Orientation = Orientation.Horizontal,
initialIndex: Int = 0,
/*@FloatRange(from = 0.0, to = 1.0)*/
itemFraction: Float = 1f,
itemSpacing: Dp = 0.dp,
/*@FloatRange(from = 0.0, to = 1.0)*/
overshootFraction: Float = .5f,
onItemSelect: (Int) -> Unit = {},
content: @Composable () -> Unit,
) {
require(initialIndex in 0..items.lastIndex) { "Initial index out of bounds" }
require(itemFraction > 0f && itemFraction <= 1f) { "Item fraction must be in the (0f, 1f] range" }
require(overshootFraction > 0f && itemFraction <= 1f) { "Overshoot fraction must be in the (0f, 1f] range" }
val scope = rememberCoroutineScope()
val state = rememberPagerState()
state.currentIndex = initialIndex
state.numberOfItems = items.size
state.itemFraction = itemFraction
state.overshootFraction = overshootFraction
state.itemSpacing = with(LocalDensity.current) { itemSpacing.toPx() }
state.orientation = orientation
state.listener = onItemSelect
state.scope = scope
Layout(
content = content,
modifier = modifier
.clipToBounds()
.then(state.inputModifier),
) { measurables, constraints ->
val dimension = constraints.dimension(orientation)
val looseConstraints = constraints.toLooseConstraints(orientation, state.itemFraction)
val placeables = measurables.map { measurable -> measurable.measure(looseConstraints) }
val size = placeables.getSize(orientation, dimension)
val itemDimension = (dimension * state.itemFraction).roundToInt()
state.itemDimension = itemDimension
val halfItemDimension = itemDimension / 2
layout(size.width, size.height) {
val centerOffset = dimension / 2 - halfItemDimension
val dragOffset = state.dragOffset.value
val roundedDragOffset = dragOffset.roundToInt()
val spacing = state.itemSpacing.roundToInt()
val itemDimensionWithSpace = itemDimension + state.itemSpacing
val first = ceil(
(dragOffset - itemDimension - centerOffset) / itemDimensionWithSpace
).toInt().coerceAtLeast(0)
val last = ((dimension + dragOffset - centerOffset) / itemDimensionWithSpace).toInt()
.coerceAtMost(items.lastIndex)
for (i in first..last) {
val offset = i * (itemDimension + spacing) - roundedDragOffset + centerOffset
placeables[i].place(
x = when (orientation) {
Orientation.Horizontal -> offset
Orientation.Vertical -> 0
},
y = when (orientation) {
Orientation.Horizontal -> 0
Orientation.Vertical -> offset
}
)
}
}
}
LaunchedEffect(key1 = items, key2 = initialIndex) {
state.snapTo(initialIndex)
}
}
@Composable
private fun rememberPagerState(): PagerState = remember { PagerState() }
private fun Constraints.dimension(orientation: Orientation) = when (orientation) {
Orientation.Horizontal -> maxWidth
Orientation.Vertical -> maxHeight
}
private fun Constraints.toLooseConstraints(
orientation: Orientation,
itemFraction: Float,
): Constraints {
val dimension = dimension(orientation)
return when (orientation) {
Orientation.Horizontal -> copy(
minWidth = (dimension * itemFraction).roundToInt(),
maxWidth = (dimension * itemFraction).roundToInt(),
minHeight = 0,
)
Orientation.Vertical -> copy(
minWidth = 0,
minHeight = (dimension * itemFraction).roundToInt(),
maxHeight = (dimension * itemFraction).roundToInt(),
)
}
}
private fun List<Placeable>.getSize(
orientation: Orientation,
dimension: Int,
): IntSize {
return when (orientation) {
Orientation.Horizontal -> IntSize(
dimension,
maxByOrNull { it.height }?.height ?: 0
)
Orientation.Vertical -> IntSize(
maxByOrNull { it.width }?.width ?: 0,
dimension
)
}
}
private class PagerState {
var currentIndex by mutableStateOf(0)
var numberOfItems by mutableStateOf(0)
var itemFraction by mutableStateOf(0f)
var overshootFraction by mutableStateOf(0f)
var itemSpacing by mutableStateOf(0f)
var itemDimension by mutableStateOf(0)
var orientation by mutableStateOf(Orientation.Horizontal)
var scope: CoroutineScope? by mutableStateOf(null)
var listener: (Int) -> Unit by mutableStateOf({})
val dragOffset = Animatable(0f)
private val animationSpec = SpringSpec<Float>(
dampingRatio = Spring.DampingRatioLowBouncy,
stiffness = Spring.StiffnessLow,
)
suspend fun snapTo(index: Int) {
dragOffset.snapTo(index.toFloat() * (itemDimension + itemSpacing))
}
val inputModifier = Modifier.pointerInput(numberOfItems) {
fun itemIndex(offset: Int): Int = (offset / (itemDimension + itemSpacing)).roundToInt()
.coerceIn(0, numberOfItems - 1)
fun updateIndex(offset: Float) {
val index = itemIndex(offset.roundToInt())
if (index != currentIndex) {
currentIndex = index
listener(index)
}
}
fun calculateOffsetLimit(): OffsetLimit {
val dimension = when (orientation) {
Orientation.Horizontal -> size.width
Orientation.Vertical -> size.height
}
val itemSideMargin = (dimension - itemDimension) / 2f
return OffsetLimit(
min = -dimension * overshootFraction + itemSideMargin,
max = numberOfItems * (itemDimension + itemSpacing) - (1f - overshootFraction) * dimension + itemSideMargin,
)
}
forEachGesture {
awaitPointerEventScope {
val tracker = VelocityTracker()
val decay = splineBasedDecay<Float>(this)
val down = awaitFirstDown()
val offsetLimit = calculateOffsetLimit()
val dragHandler = { change: PointerInputChange ->
scope?.launch {
val dragChange = change.calculateDragChange(orientation)
dragOffset.snapTo(
(dragOffset.value - dragChange).coerceIn(
offsetLimit.min,
offsetLimit.max
)
)
updateIndex(dragOffset.value)
}
tracker.addPosition(change.uptimeMillis, change.position)
}
when (orientation) {
Orientation.Horizontal -> horizontalDrag(down.id, dragHandler)
Orientation.Vertical -> verticalDrag(down.id, dragHandler)
}
val velocity = tracker.calculateVelocity(orientation)
scope?.launch {
var targetOffset = decay.calculateTargetValue(dragOffset.value, -velocity)
val remainder = targetOffset.toInt().absoluteValue % itemDimension
val extra = if (remainder > itemDimension / 2f) 1 else 0
val lastVisibleIndex =
(targetOffset.absoluteValue / itemDimension.toFloat()).toInt() + extra
targetOffset =
(lastVisibleIndex * (itemDimension + itemSpacing) * targetOffset.sign)
.coerceIn(
0f,
(numberOfItems - 1).toFloat() * (itemDimension + itemSpacing)
)
dragOffset.animateTo(
animationSpec = animationSpec,
targetValue = targetOffset,
initialVelocity = -velocity
) {
updateIndex(value)
}
}
}
}
}
data class OffsetLimit(
val min: Float,
val max: Float,
)
}
private fun VelocityTracker.calculateVelocity(orientation: Orientation) = when (orientation) {
Orientation.Horizontal -> calculateVelocity().x
Orientation.Vertical -> calculateVelocity().y
}
private fun PointerInputChange.calculateDragChange(orientation: Orientation) =
when (orientation) {
Orientation.Horizontal -> positionChange().x
Orientation.Vertical -> positionChange().y
}

View File

@ -1,58 +0,0 @@
package me.ash.reader.ui.widget
import androidx.compose.animation.core.animateFloat
import androidx.compose.animation.core.spring
import androidx.compose.animation.core.updateTransition
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.BoxScope
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import com.google.accompanist.pager.ExperimentalPagerApi
import com.google.accompanist.pager.PagerState
import kotlin.math.absoluteValue
@OptIn(ExperimentalPagerApi::class)
@Composable
fun BoxScope.MaskBox(
modifier: Modifier = Modifier,
pagerState: PagerState,
currentPage: Int = 0,
) {
val transition = updateTransition(targetState = pagerState, label = "")
val maskAlpha by transition.animateFloat(
label = "",
transitionSpec = {
spring()
}
) {
when {
it.targetPage == currentPage -> {
if (it.currentPage > currentPage) {
1f - it.currentPageOffset.absoluteValue
} else {
0f
}
}
it.targetPage > currentPage -> {
it.currentPageOffset.absoluteValue
}
else -> 0f
}
}
Box(
modifier
.alpha(maskAlpha)
) {
Box(
modifier = modifier
.fillMaxSize()
.background(MaterialTheme.colorScheme.surfaceVariant)
)
}
}

View File

@ -1,97 +0,0 @@
package me.ash.reader.ui.widget
import androidx.compose.animation.core.*
import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyListState
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
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 androidx.compose.ui.zIndex
import me.ash.reader.ui.extension.calculateTopBarAnimateValue
@Composable
fun BoxScope.TopTitleBox(
title: String,
description: String,
listState: LazyListState,
SpacerHeight: Float = Float.NaN,
startOffset: Offset,
startHeight: Float,
startTitleFontSize: Float,
startDescriptionFontSize: Float,
clickable: () -> Unit = {},
) {
val transition = updateTransition(targetState = listState, label = "")
val offset by transition.animateOffset(
label = "",
transitionSpec = { spring() }
) {
Offset(
x = it.calculateTopBarAnimateValue(startOffset.x, 56f),
y = it.calculateTopBarAnimateValue(startOffset.y, 0f)
)
}
val height by transition.animateFloat(
label = "",
transitionSpec = { spring() }
) {
it.calculateTopBarAnimateValue(startHeight, 64f)
}
val titleFontSize by transition.animateFloat(
label = "",
transitionSpec = { spring(stiffness = Spring.StiffnessHigh) }
) {
it.calculateTopBarAnimateValue(startTitleFontSize, 16f)
}
val descriptionFontSize by transition.animateFloat(
label = "",
transitionSpec = { spring(stiffness = Spring.StiffnessHigh) }
) {
it.calculateTopBarAnimateValue(startDescriptionFontSize, 12f)
}
Box(
modifier = Modifier
.zIndex(1f)
.height(height.dp)
.offset(offset.x.dp, offset.y.dp)
.clickable(
interactionSource = MutableInteractionSource(),
indication = null,
onClickLabel = "回到顶部",
onClick = clickable
),
contentAlignment = Alignment.Center
) {
Column {
AnimatedText(
text = title,
fontWeight = FontWeight.Bold,
fontSize = titleFontSize.sp,
color = MaterialTheme.colorScheme.primary
)
Spacer(modifier = Modifier.height(SpacerHeight.dp))
AnimatedText(
modifier = Modifier.width(200.dp),
text = description,
fontWeight = FontWeight.SemiBold,
fontSize = descriptionFontSize.sp,
color = MaterialTheme.colorScheme.secondary,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
)
}
}
}