From ee9e0a455383b0c4f64213ffdfaadf5a8c52f098 Mon Sep 17 00:00:00 2001 From: Ash Date: Fri, 4 Mar 2022 00:14:36 +0800 Subject: [PATCH] Add click notification feature --- app/src/main/java/me/ash/reader/App.kt | 8 ++ .../me/ash/reader/data/article/ArticleDao.kt | 9 ++ .../{ui/data => data/constant}/Filter.kt | 2 +- .../constant}/NavigationBarItem.kt | 6 +- .../me/ash/reader/data/constant/Symbol.kt | 7 + .../data/repository/ArticleRepository.kt | 4 + .../reader/data/repository/RssRepository.kt | 53 ++++++-- .../me/ash/reader/ui/page/common/HomeEntry.kt | 21 ++- .../me/ash/reader/ui/page/common/RouteName.kt | 2 + .../me/ash/reader/ui/page/home/HomePage.kt | 47 ++++++- .../ash/reader/ui/page/home/HomeViewModel.kt | 8 +- .../ui/page/home/article/ArticlePage.kt | 120 +++++++++--------- .../ash/reader/ui/page/home/feed/FeedPage.kt | 12 +- .../ash/reader/ui/page/home/read/ReadPage.kt | 7 +- .../reader/ui/page/home/read/ReadViewModel.kt | 2 +- .../reader/ui/page/settings/SettingsPage.kt | 49 +++++++ .../java/me/ash/reader/ui/util/Extension.kt | 11 +- .../main/java/me/ash/reader/ui/util/Symbol.kt | 5 - .../ash/reader/ui/widget/AppNavigationBar.kt | 4 +- 19 files changed, 274 insertions(+), 103 deletions(-) rename app/src/main/java/me/ash/reader/{ui/data => data/constant}/Filter.kt (94%) rename app/src/main/java/me/ash/reader/{ui/data => data/constant}/NavigationBarItem.kt (67%) create mode 100644 app/src/main/java/me/ash/reader/data/constant/Symbol.kt create mode 100644 app/src/main/java/me/ash/reader/ui/page/settings/SettingsPage.kt delete mode 100644 app/src/main/java/me/ash/reader/ui/util/Symbol.kt diff --git a/app/src/main/java/me/ash/reader/App.kt b/app/src/main/java/me/ash/reader/App.kt index 69e4fcc..f8b32f3 100644 --- a/app/src/main/java/me/ash/reader/App.kt +++ b/app/src/main/java/me/ash/reader/App.kt @@ -1,6 +1,10 @@ package me.ash.reader import android.app.Application +import androidx.compose.animation.ExperimentalAnimationApi +import androidx.compose.foundation.ExperimentalFoundationApi +import androidx.compose.material3.ExperimentalMaterial3Api +import com.google.accompanist.pager.ExperimentalPagerApi import dagger.hilt.android.HiltAndroidApp import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.GlobalScope @@ -14,6 +18,10 @@ import me.ash.reader.data.source.ReaderDatabase import me.ash.reader.data.source.RssNetworkDataSource import javax.inject.Inject +@ExperimentalAnimationApi +@ExperimentalMaterial3Api +@ExperimentalPagerApi +@ExperimentalFoundationApi @DelicateCoroutinesApi @HiltAndroidApp class App : Application() { diff --git a/app/src/main/java/me/ash/reader/data/article/ArticleDao.kt b/app/src/main/java/me/ash/reader/data/article/ArticleDao.kt index fa6b19f..5f697aa 100644 --- a/app/src/main/java/me/ash/reader/data/article/ArticleDao.kt +++ b/app/src/main/java/me/ash/reader/data/article/ArticleDao.kt @@ -271,6 +271,15 @@ interface ArticleDao { ) suspend fun queryLatestByFeedId(accountId: Int, feedId: Int): Article? + @Transaction + @Query( + """ + SELECT * FROM article + WHERE id = :id + """ + ) + suspend fun queryById(id: Int): ArticleWithFeed? + @Insert suspend fun insert(article: Article): Long diff --git a/app/src/main/java/me/ash/reader/ui/data/Filter.kt b/app/src/main/java/me/ash/reader/data/constant/Filter.kt similarity index 94% rename from app/src/main/java/me/ash/reader/ui/data/Filter.kt rename to app/src/main/java/me/ash/reader/data/constant/Filter.kt index ba44bf9..647fc82 100644 --- a/app/src/main/java/me/ash/reader/ui/data/Filter.kt +++ b/app/src/main/java/me/ash/reader/data/constant/Filter.kt @@ -1,4 +1,4 @@ -package me.ash.reader.ui.data +package me.ash.reader.data.constant class Filter( var index: Int, diff --git a/app/src/main/java/me/ash/reader/ui/data/NavigationBarItem.kt b/app/src/main/java/me/ash/reader/data/constant/NavigationBarItem.kt similarity index 67% rename from app/src/main/java/me/ash/reader/ui/data/NavigationBarItem.kt rename to app/src/main/java/me/ash/reader/data/constant/NavigationBarItem.kt index ee04cb5..7b9c978 100644 --- a/app/src/main/java/me/ash/reader/ui/data/NavigationBarItem.kt +++ b/app/src/main/java/me/ash/reader/data/constant/NavigationBarItem.kt @@ -1,7 +1,9 @@ -package me.ash.reader.ui.data +package me.ash.reader.data.constant import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.rounded.* +import androidx.compose.material.icons.rounded.FiberManualRecord +import androidx.compose.material.icons.rounded.Star +import androidx.compose.material.icons.rounded.Subject import androidx.compose.ui.graphics.vector.ImageVector class NavigationBarItem( diff --git a/app/src/main/java/me/ash/reader/data/constant/Symbol.kt b/app/src/main/java/me/ash/reader/data/constant/Symbol.kt new file mode 100644 index 0000000..692f834 --- /dev/null +++ b/app/src/main/java/me/ash/reader/data/constant/Symbol.kt @@ -0,0 +1,7 @@ +package me.ash.reader.data.constant + +object Symbol { + const val NOTHING: String = "null" + const val NOTIFICATION_CHANNEL_GROUP_ARTICLE_UPDATE: String = "article.update" + const val EXTRA_ARTICLE_ID: String = "article.id" +} \ No newline at end of file diff --git a/app/src/main/java/me/ash/reader/data/repository/ArticleRepository.kt b/app/src/main/java/me/ash/reader/data/repository/ArticleRepository.kt index dd40c31..1a004d2 100644 --- a/app/src/main/java/me/ash/reader/data/repository/ArticleRepository.kt +++ b/app/src/main/java/me/ash/reader/data/repository/ArticleRepository.kt @@ -86,4 +86,8 @@ class ArticleRepository @Inject constructor( suspend fun updateArticleInfo(article: Article) { articleDao.update(article) } + + suspend fun findArticleById(id: Int): ArticleWithFeed? { + return articleDao.queryById(id) + } } \ No newline at end of file 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 e3651f3..d16229c 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 @@ -3,29 +3,34 @@ package me.ash.reader.data.repository import android.app.Notification import android.app.NotificationChannel import android.app.NotificationManager +import android.app.PendingIntent import android.content.Context +import android.content.Intent import android.os.Build import android.util.Log +import androidx.compose.animation.ExperimentalAnimationApi +import androidx.compose.foundation.ExperimentalFoundationApi +import androidx.compose.material3.ExperimentalMaterial3Api import androidx.core.app.NotificationCompat import androidx.core.content.ContextCompat.getSystemService import androidx.work.* import com.github.muhrifqii.parserss.ParseRSS +import com.google.accompanist.pager.ExperimentalPagerApi import dagger.hilt.android.qualifiers.ApplicationContext import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.flow.* import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.withLock -import me.ash.reader.DataStoreKeys +import me.ash.reader.* import me.ash.reader.R import me.ash.reader.data.account.AccountDao import me.ash.reader.data.article.Article import me.ash.reader.data.article.ArticleDao +import me.ash.reader.data.constant.Symbol import me.ash.reader.data.feed.Feed import me.ash.reader.data.feed.FeedDao import me.ash.reader.data.source.ReaderDatabase import me.ash.reader.data.source.RssNetworkDataSource -import me.ash.reader.dataStore -import me.ash.reader.get import net.dankito.readability4j.Readability4J import net.dankito.readability4j.extended.Readability4JExtended import okhttp3.* @@ -34,7 +39,6 @@ import java.io.IOException import java.util.* import java.util.concurrent.TimeUnit import javax.inject.Inject -import kotlin.random.Random class RssRepository @Inject constructor( @@ -83,6 +87,10 @@ class RssRepository @Inject constructor( return workManager.getWorkInfosByTag("sync").get().size.toString() } + @ExperimentalAnimationApi + @ExperimentalMaterial3Api + @ExperimentalPagerApi + @ExperimentalFoundationApi suspend fun sync(isWork: Boolean? = false) { if (isWork == true) { workManager.cancelAllWork() @@ -92,7 +100,6 @@ class RssRepository @Inject constructor( ).setConstraints( Constraints.Builder() .setRequiredNetworkType(NetworkType.CONNECTED) - .setRequiresCharging(true) .build() ).addTag("sync").build() workManager.enqueue(syncWorkerRequest) @@ -101,6 +108,10 @@ class RssRepository @Inject constructor( } } + @ExperimentalAnimationApi + @ExperimentalMaterial3Api + @ExperimentalPagerApi + @ExperimentalFoundationApi @DelicateCoroutinesApi companion object { data class SyncState( @@ -194,26 +205,38 @@ class RssRepository @Inject constructor( if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { notificationManager.createNotificationChannel( NotificationChannel( - "ARTICLE_UPDATE", + Symbol.NOTIFICATION_CHANNEL_GROUP_ARTICLE_UPDATE, "文章更新", NotificationManager.IMPORTANCE_DEFAULT ) ) } - it.reversed().forEachIndexed { index, articleList -> - articleList.forEach { article -> - Log.i("RlOG", "combine $index ${article.feedId}: ${article.title}") - val builder = NotificationCompat.Builder(context, "ARTICLE_UPDATE") + it.reversed().forEach { articleList -> + val ids = articleDao.insertList(articleList) + articleList.forEachIndexed { index, article -> + Log.i("RlOG", "combine ${article.feedId}: ${article.title}") + val builder = NotificationCompat.Builder(context, Symbol.NOTIFICATION_CHANNEL_GROUP_ARTICLE_UPDATE) .setSmallIcon(R.drawable.ic_launcher_foreground) - .setGroup("ARTICLE_UPDATE") + .setGroup(Symbol.NOTIFICATION_CHANNEL_GROUP_ARTICLE_UPDATE) .setContentTitle(article.title) .setContentText(article.shortDescription) .setPriority(NotificationCompat.PRIORITY_DEFAULT) - notificationManager.notify(Random.nextInt(), builder.build().apply { + .setContentIntent( + PendingIntent.getActivity( + context, + ids[index].toInt(), + Intent(context, MainActivity::class.java).apply { + flags = Intent.FLAG_ACTIVITY_NEW_TASK or + Intent.FLAG_ACTIVITY_CLEAR_TASK + putExtra(Symbol.EXTRA_ARTICLE_ID, ids[index].toInt()) + }, + PendingIntent.FLAG_UPDATE_CURRENT + ) + ) + notificationManager.notify(ids[index].toInt(), builder.build().apply { flags = Notification.FLAG_AUTO_CANCEL }) } - articleDao.insertList(articleList) } }.buffer().onCompletion { val afterTime = System.currentTimeMillis() @@ -323,6 +346,10 @@ class RssRepository @Inject constructor( } } +@ExperimentalAnimationApi +@ExperimentalMaterial3Api +@ExperimentalPagerApi +@ExperimentalFoundationApi @DelicateCoroutinesApi class SyncWorker( context: Context, diff --git a/app/src/main/java/me/ash/reader/ui/page/common/HomeEntry.kt b/app/src/main/java/me/ash/reader/ui/page/common/HomeEntry.kt index 9b408d7..f971bff 100644 --- a/app/src/main/java/me/ash/reader/ui/page/common/HomeEntry.kt +++ b/app/src/main/java/me/ash/reader/ui/page/common/HomeEntry.kt @@ -12,12 +12,16 @@ import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier +import androidx.navigation.compose.NavHost +import androidx.navigation.compose.composable +import androidx.navigation.compose.rememberNavController import com.google.accompanist.insets.ProvideWindowInsets import com.google.accompanist.insets.navigationBarsHeight import com.google.accompanist.insets.statusBarsPadding import com.google.accompanist.pager.ExperimentalPagerApi import com.google.accompanist.systemuicontroller.rememberSystemUiController import me.ash.reader.ui.page.home.HomePage +import me.ash.reader.ui.page.settings.SettingsPage import me.ash.reader.ui.theme.AppTheme @ExperimentalAnimationApi @@ -26,6 +30,8 @@ import me.ash.reader.ui.theme.AppTheme @ExperimentalFoundationApi @Composable fun HomeEntry() { + val navController = rememberNavController() + AppTheme { ProvideWindowInsets { rememberSystemUiController().run { @@ -33,13 +39,24 @@ fun HomeEntry() { setSystemBarsColor(MaterialTheme.colorScheme.surface, !isSystemInDarkTheme()) setNavigationBarColor(MaterialTheme.colorScheme.surface, !isSystemInDarkTheme()) } - Column (modifier = Modifier.background(MaterialTheme.colorScheme.surface)){ + Column(modifier = Modifier.background(MaterialTheme.colorScheme.surface)) { Row( modifier = Modifier .weight(1f) .statusBarsPadding() ) { - HomePage() + NavHost( + modifier = Modifier.background(MaterialTheme.colorScheme.surface), + navController = navController, + startDestination = RouteName.HOME, + ) { + composable(route = RouteName.HOME) { + HomePage(navController) + } + composable(route = RouteName.SETTINGS) { + SettingsPage(navController) + } + } } Spacer( modifier = Modifier diff --git a/app/src/main/java/me/ash/reader/ui/page/common/RouteName.kt b/app/src/main/java/me/ash/reader/ui/page/common/RouteName.kt index 4b55562..05a0d2c 100644 --- a/app/src/main/java/me/ash/reader/ui/page/common/RouteName.kt +++ b/app/src/main/java/me/ash/reader/ui/page/common/RouteName.kt @@ -1,7 +1,9 @@ package me.ash.reader.ui.page.common object RouteName { + const val HOME = "home" const val FEED = "feed" const val ARTICLE = "article" const val READ = "read" + const val SETTINGS = "settings" } \ No newline at end of file diff --git a/app/src/main/java/me/ash/reader/ui/page/home/HomePage.kt b/app/src/main/java/me/ash/reader/ui/page/home/HomePage.kt index 72642ad..9b096f3 100644 --- a/app/src/main/java/me/ash/reader/ui/page/home/HomePage.kt +++ b/app/src/main/java/me/ash/reader/ui/page/home/HomePage.kt @@ -4,28 +4,31 @@ import android.util.Log import androidx.activity.compose.BackHandler import androidx.compose.animation.ExperimentalAnimationApi import androidx.compose.foundation.ExperimentalFoundationApi -import androidx.compose.foundation.background import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable +import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel -import androidx.navigation.compose.rememberNavController +import androidx.navigation.NavHostController import com.google.accompanist.pager.ExperimentalPagerApi import com.google.accompanist.pager.HorizontalPager import kotlinx.coroutines.flow.collect +import kotlinx.coroutines.launch +import me.ash.reader.data.constant.Symbol import me.ash.reader.ui.page.home.article.ArticlePage import me.ash.reader.ui.page.home.feed.FeedPage 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.ReadViewModel import me.ash.reader.ui.util.collectAsStateValue +import me.ash.reader.ui.util.findActivity import me.ash.reader.ui.util.pagerAnimate import me.ash.reader.ui.widget.AppNavigationBar @@ -35,15 +38,44 @@ import me.ash.reader.ui.widget.AppNavigationBar @ExperimentalFoundationApi @Composable fun HomePage( + navController: NavHostController, viewModel: HomeViewModel = hiltViewModel(), readViewModel: ReadViewModel = hiltViewModel(), ) { + val context = LocalContext.current val viewState = viewModel.viewState.collectAsStateValue() val filterState = viewModel.filterState.collectAsStateValue() val readState = readViewModel.viewState.collectAsStateValue() - val navController = rememberNavController() val scope = rememberCoroutineScope() + DisposableEffect(Unit) { + context.findActivity()?.let { activity -> + activity.intent?.let { intent -> + intent.extras?.get(Symbol.EXTRA_ARTICLE_ID)?.let { + readViewModel.dispatch(ReadViewAction.ScrollToItem(2)) + scope.launch { + val article = + readViewModel.articleRepository.findArticleById(it.toString().toInt()) + ?: return@launch + readViewModel.dispatch(ReadViewAction.InitData(article)) + if (article.feed.isFullContent) readViewModel.dispatch(ReadViewAction.RenderFullContent) + else readViewModel.dispatch(ReadViewAction.RenderDescriptionContent) + readViewModel.dispatch(ReadViewAction.RenderDescriptionContent) + viewModel.dispatch( + HomeViewAction.ScrollToPage( + scope = scope, + targetPage = 2, + ) + ) + } + } + intent.extras?.clear() + } + } + + onDispose { } + } + BackHandler(true) { val currentPage = viewState.pagerState.currentPage viewModel.dispatch( @@ -115,12 +147,11 @@ fun HomePage( HorizontalPager( count = 3, state = viewState.pagerState, - modifier = Modifier - .weight(1f) - .background(MaterialTheme.colorScheme.surface), + modifier = Modifier.weight(1f) ) { page -> when (page) { 0 -> FeedPage( + navController = navController, modifier = Modifier.pagerAnimate(this, page), filter = filterState.filter, groupAndFeedOnClick = { currentGroup, currentFeed -> @@ -141,6 +172,7 @@ fun HomePage( }, ) 1 -> ArticlePage( + navController = navController, modifier = Modifier.pagerAnimate(this, page), BackOnClick = { viewModel.dispatch( @@ -165,6 +197,7 @@ fun HomePage( }, ) 2 -> ReadPage( + navController = navController, modifier = Modifier.pagerAnimate(this, page), btnBackOnClickListener = { viewModel.dispatch( diff --git a/app/src/main/java/me/ash/reader/ui/page/home/HomeViewModel.kt b/app/src/main/java/me/ash/reader/ui/page/home/HomeViewModel.kt index 4722807..edcad5d 100644 --- a/app/src/main/java/me/ash/reader/ui/page/home/HomeViewModel.kt +++ b/app/src/main/java/me/ash/reader/ui/page/home/HomeViewModel.kt @@ -1,5 +1,8 @@ package me.ash.reader.ui.page.home +import androidx.compose.animation.ExperimentalAnimationApi +import androidx.compose.foundation.ExperimentalFoundationApi +import androidx.compose.material3.ExperimentalMaterial3Api import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.google.accompanist.pager.ExperimentalPagerApi @@ -15,10 +18,13 @@ import kotlinx.coroutines.launch import me.ash.reader.data.feed.Feed import me.ash.reader.data.group.Group import me.ash.reader.data.repository.RssRepository -import me.ash.reader.ui.data.Filter +import me.ash.reader.data.constant.Filter import javax.inject.Inject +@ExperimentalAnimationApi +@ExperimentalMaterial3Api @ExperimentalPagerApi +@ExperimentalFoundationApi @HiltViewModel class HomeViewModel @Inject constructor( private val rssRepository: RssRepository, diff --git a/app/src/main/java/me/ash/reader/ui/page/home/article/ArticlePage.kt b/app/src/main/java/me/ash/reader/ui/page/home/article/ArticlePage.kt index 2983878..ec46682 100644 --- a/app/src/main/java/me/ash/reader/ui/page/home/article/ArticlePage.kt +++ b/app/src/main/java/me/ash/reader/ui/page/home/article/ArticlePage.kt @@ -30,6 +30,7 @@ import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.hilt.navigation.compose.hiltViewModel +import androidx.navigation.NavHostController import androidx.paging.compose.collectAsLazyPagingItems import com.google.accompanist.pager.ExperimentalPagerApi import com.google.accompanist.swiperefresh.SwipeRefresh @@ -40,8 +41,8 @@ import me.ash.reader.DateTimeExt import me.ash.reader.DateTimeExt.toString import me.ash.reader.R import me.ash.reader.data.article.ArticleWithFeed +import me.ash.reader.data.constant.Filter import me.ash.reader.data.repository.RssRepository -import me.ash.reader.ui.data.Filter import me.ash.reader.ui.page.home.HomeViewAction import me.ash.reader.ui.page.home.HomeViewModel import me.ash.reader.ui.util.collectAsStateValue @@ -57,6 +58,7 @@ import me.ash.reader.ui.widget.TopTitleBox @ExperimentalFoundationApi @Composable fun ArticlePage( + navController: NavHostController, modifier: Modifier, homeViewModel: HomeViewModel = hiltViewModel(), viewModel: ArticleViewModel = hiltViewModel(), @@ -92,7 +94,7 @@ fun ArticlePage( homeViewModel.dispatch(HomeViewAction.Sync()) } ) { - Box(modifier.background(MaterialTheme.colorScheme.surface)) { + Box { TopTitleBox( title = when { filterState.group != null -> filterState.group.name @@ -241,65 +243,67 @@ private fun ArticleItem( ) } Spacer(modifier = modifier.height(1.dp)) - if (true) { - Box( - modifier = Modifier - .padding(top = 3.dp) - .size(24.dp) - .border( - 2.dp, - MaterialTheme.colorScheme.inverseOnSurface, - RoundedCornerShape(4.dp) - ), - ) { - if (articleWithFeed.feed.icon == null) { - Icon( - painter = painterResource(id = R.drawable.default_folder), - contentDescription = "icon", - modifier = modifier - .fillMaxSize() - .padding(2.dp), - tint = MaterialTheme.colorScheme.onPrimaryContainer, - ) - } else { - Image( - painter = BitmapPainter( - BitmapFactory.decodeByteArray( - articleWithFeed.feed.icon, - 0, - articleWithFeed.feed.icon!!.size - ).asImageBitmap() + Row { + if (true) { + Box( + modifier = Modifier + .padding(top = 3.dp) + .size(24.dp) + .border( + 2.dp, + MaterialTheme.colorScheme.inverseOnSurface, + RoundedCornerShape(4.dp) ), - contentDescription = "icon", - modifier = modifier - .fillMaxSize() - .padding(2.dp), - ) + ) { + if (articleWithFeed.feed.icon == null) { + Icon( + painter = painterResource(id = R.drawable.default_folder), + contentDescription = "icon", + modifier = modifier + .fillMaxSize() + .padding(2.dp), + tint = MaterialTheme.colorScheme.onPrimaryContainer, + ) + } else { + Image( + painter = BitmapPainter( + BitmapFactory.decodeByteArray( + articleWithFeed.feed.icon, + 0, + articleWithFeed.feed.icon!!.size + ).asImageBitmap() + ), + contentDescription = "icon", + modifier = modifier + .fillMaxSize() + .padding(2.dp), + ) + } } + Spacer(modifier = Modifier.width(8.dp)) + } + Column { + Text( + text = articleWithFeed.article.title, + fontSize = 18.sp, + fontWeight = FontWeight.Bold, + color = if (isStarredFilter || articleWithFeed.article.isUnread) { + MaterialTheme.colorScheme.onPrimaryContainer + } else { + MaterialTheme.colorScheme.outline + }, + maxLines = 2, + overflow = TextOverflow.Ellipsis + ) + Spacer(modifier = modifier.height(1.dp)) + Text( + text = articleWithFeed.article.shortDescription, + fontSize = 18.sp, + color = MaterialTheme.colorScheme.outline, + maxLines = 2, + overflow = TextOverflow.Ellipsis + ) } - Spacer(modifier = Modifier.width(8.dp)) - } - Column { - Text( - text = articleWithFeed.article.title, - fontSize = 18.sp, - fontWeight = FontWeight.Bold, - color = if (isStarredFilter || articleWithFeed.article.isUnread) { - MaterialTheme.colorScheme.onPrimaryContainer - } else { - MaterialTheme.colorScheme.outline - }, - maxLines = 2, - overflow = TextOverflow.Ellipsis - ) - Spacer(modifier = modifier.height(1.dp)) - Text( - text = articleWithFeed.article.shortDescription, - fontSize = 18.sp, - color = MaterialTheme.colorScheme.outline, - maxLines = 2, - overflow = TextOverflow.Ellipsis - ) } } } diff --git a/app/src/main/java/me/ash/reader/ui/page/home/feed/FeedPage.kt b/app/src/main/java/me/ash/reader/ui/page/home/feed/FeedPage.kt index a2f0a1f..91ea7e4 100644 --- a/app/src/main/java/me/ash/reader/ui/page/home/feed/FeedPage.kt +++ b/app/src/main/java/me/ash/reader/ui/page/home/feed/FeedPage.kt @@ -6,7 +6,6 @@ import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.result.contract.ActivityResultContracts import androidx.compose.animation.* import androidx.compose.foundation.ExperimentalFoundationApi -import androidx.compose.foundation.background import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.itemsIndexed @@ -26,15 +25,17 @@ import androidx.compose.ui.graphics.painter.BitmapPainter import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel +import androidx.navigation.NavHostController import com.google.accompanist.pager.ExperimentalPagerApi import kotlinx.coroutines.flow.collect import me.ash.reader.DateTimeExt import me.ash.reader.DateTimeExt.toString +import me.ash.reader.data.constant.Filter import me.ash.reader.data.feed.Feed import me.ash.reader.data.group.Group import me.ash.reader.data.group.GroupWithFeed import me.ash.reader.data.repository.RssRepository -import me.ash.reader.ui.data.Filter +import me.ash.reader.ui.page.common.RouteName import me.ash.reader.ui.page.home.HomeViewAction import me.ash.reader.ui.page.home.HomeViewModel import me.ash.reader.ui.util.collectAsStateValue @@ -47,6 +48,7 @@ import me.ash.reader.ui.widget.* @ExperimentalFoundationApi @Composable fun FeedPage( + navController: NavHostController, modifier: Modifier, viewModel: FeedViewModel = hiltViewModel(), homeViewModel: HomeViewModel = hiltViewModel(), @@ -84,9 +86,7 @@ fun FeedPage( } Box( - modifier - .fillMaxSize() - .background(MaterialTheme.colorScheme.surface) + modifier.fillMaxSize() ) { TopTitleBox( title = viewState.account?.name ?: "未知账户", @@ -109,7 +109,7 @@ fun FeedPage( title = {}, navigationIcon = { IconButton(onClick = { - + navController.navigate(route = RouteName.SETTINGS) }) { Icon( modifier = Modifier.size(22.dp), 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 b20765e..136cacf 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 @@ -5,7 +5,6 @@ import android.content.Intent import android.net.Uri import androidx.compose.animation.* import androidx.compose.foundation.ExperimentalFoundationApi -import androidx.compose.foundation.background import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.text.selection.SelectionContainer @@ -24,6 +23,7 @@ import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.hilt.navigation.compose.hiltViewModel +import androidx.navigation.NavHostController import com.airbnb.lottie.compose.LottieAnimation import com.airbnb.lottie.compose.LottieCompositionSpec import com.airbnb.lottie.compose.rememberLottieComposition @@ -44,6 +44,7 @@ import me.ash.reader.ui.widget.WebView @ExperimentalFoundationApi @Composable fun ReadPage( + navController: NavHostController, modifier: Modifier = Modifier, viewModel: ReadViewModel = hiltViewModel(), btnBackOnClickListener: () -> Unit, @@ -66,9 +67,7 @@ fun ReadPage( Box { Column( - modifier - .fillMaxSize() - .background(MaterialTheme.colorScheme.surface) + modifier.fillMaxSize() ) { SmallTopAppBar( diff --git a/app/src/main/java/me/ash/reader/ui/page/home/read/ReadViewModel.kt b/app/src/main/java/me/ash/reader/ui/page/home/read/ReadViewModel.kt index 6ec7a2f..a0a9ccf 100644 --- a/app/src/main/java/me/ash/reader/ui/page/home/read/ReadViewModel.kt +++ b/app/src/main/java/me/ash/reader/ui/page/home/read/ReadViewModel.kt @@ -16,7 +16,7 @@ import javax.inject.Inject @HiltViewModel class ReadViewModel @Inject constructor( - private val articleRepository: ArticleRepository, + val articleRepository: ArticleRepository, private val rssRepository: RssRepository, ) : ViewModel() { private val _viewState = MutableStateFlow(ReadViewState()) diff --git a/app/src/main/java/me/ash/reader/ui/page/settings/SettingsPage.kt b/app/src/main/java/me/ash/reader/ui/page/settings/SettingsPage.kt new file mode 100644 index 0000000..f2143be --- /dev/null +++ b/app/src/main/java/me/ash/reader/ui/page/settings/SettingsPage.kt @@ -0,0 +1,49 @@ +package me.ash.reader.ui.page.settings + +import androidx.compose.animation.ExperimentalAnimationApi +import androidx.compose.foundation.ExperimentalFoundationApi +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.ArrowBack +import androidx.compose.material3.* +import androidx.compose.runtime.Composable +import androidx.navigation.NavHostController +import com.google.accompanist.pager.ExperimentalPagerApi + +@ExperimentalAnimationApi +@ExperimentalMaterial3Api +@ExperimentalPagerApi +@ExperimentalFoundationApi +@Composable +fun SettingsPage( + navController: NavHostController, +) { + Scaffold( + topBar = { + LargeTopAppBar( + title = { + Text( + text = "Settings", + color = MaterialTheme.colorScheme.primary, + ) + }, + navigationIcon = { + IconButton(onClick = { + navController.popBackStack() + }) { + IconButton(onClick = { /*TODO*/ }) { + Icon( + imageVector = Icons.Filled.ArrowBack, + contentDescription = "Back", + tint = MaterialTheme.colorScheme.primary + ) + } + } + }, + ) + + }, + content = { + Text(text = "af") + }, + ) +} \ No newline at end of file diff --git a/app/src/main/java/me/ash/reader/ui/util/Extension.kt b/app/src/main/java/me/ash/reader/ui/util/Extension.kt index 11f281a..3a6916a 100644 --- a/app/src/main/java/me/ash/reader/ui/util/Extension.kt +++ b/app/src/main/java/me/ash/reader/ui/util/Extension.kt @@ -1,5 +1,8 @@ package me.ash.reader.ui.util +import android.app.Activity +import android.content.Context +import android.content.ContextWrapper import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyListState @@ -69,4 +72,10 @@ fun Modifier.roundClick(onClick: () -> Unit = {}) = this fun Modifier.paddingFixedHorizontal(top: Dp = 0.dp, bottom: Dp = 0.dp) = this .padding(horizontal = 10.dp) - .padding(top = top, bottom = bottom) \ No newline at end of file + .padding(top = top, bottom = bottom) + +fun Context.findActivity(): Activity? = when (this) { + is Activity -> this + is ContextWrapper -> baseContext.findActivity() + else -> null +} \ No newline at end of file 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 deleted file mode 100644 index 9417ef9..0000000 --- a/app/src/main/java/me/ash/reader/ui/util/Symbol.kt +++ /dev/null @@ -1,5 +0,0 @@ -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 0eeda20..cfa1562 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 @@ -34,8 +34,8 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import com.google.accompanist.pager.ExperimentalPagerApi import com.google.accompanist.pager.PagerState -import me.ash.reader.ui.data.Filter -import me.ash.reader.ui.data.NavigationBarItem +import me.ash.reader.data.constant.Filter +import me.ash.reader.data.constant.NavigationBarItem import kotlin.math.absoluteValue @ExperimentalPagerApi