diff --git a/app/src/main/java/eu/toldi/balazs/anotherfeedreader/MainActivity.kt b/app/src/main/java/eu/toldi/balazs/anotherfeedreader/MainActivity.kt index 4630091..36d9690 100644 --- a/app/src/main/java/eu/toldi/balazs/anotherfeedreader/MainActivity.kt +++ b/app/src/main/java/eu/toldi/balazs/anotherfeedreader/MainActivity.kt @@ -64,7 +64,8 @@ class MainActivity : ComponentActivity() { val scope = rememberCoroutineScope() val drawerState = rememberDrawerState(DrawerValue.Closed) - val articleList = viewModel.articles.observeAsState(emptyList()) + val articleList = viewModel.articles + val feedList = viewModel.feeds.observeAsState() Scaffold( floatingActionButton = { FloatingActionButton( @@ -96,12 +97,17 @@ class MainActivity : ComponentActivity() { .fillMaxWidth() ) { - items(articleList.value.size) { index -> - val articleAndFeed = articleList.value[index] - articleAndFeed.articles.sortedByDescending { it.pubDate } - .forEach { - showArticle(articleAndFeed.feed, article = it) - } + items( + count = articleList.value.size, + key = { index -> + articleList.value[index].articleId as Long + } + ) { index -> + Log.e(null, articleList.value.size.toString()) + val article = articleList.value[index] + val feed = + feedList.value?.first() { it.feedId == article.feedId } + feed?.let { it1 -> showArticle(it1, article = article) } } } } @@ -146,7 +152,7 @@ class MainActivity : ComponentActivity() { ) { Text( - text = if (selectedIndex == 0) "None" else viewModel.feedsState.value!!.filterIsInstance()[selectedIndex - 1].name.toString(), + text = if (selectedIndex == 0) "None" else viewModel.feeds.value!!.filterIsInstance()[selectedIndex - 1].name.toString(), modifier = Modifier .fillMaxWidth() .clickable(onClick = { expanded = true }) @@ -163,13 +169,13 @@ class MainActivity : ComponentActivity() { Text(text = "None") } - viewModel.feedsState.value!!.filterIsInstance() + viewModel.feeds.value!!.filterIsInstance() .forEachIndexed { index, s -> DropdownMenuItem(onClick = { selectedIndex = index + 1 expanded = false }) { - viewModel.feedsState.value!![index].name?.let { + viewModel.feeds.value!![index].name?.let { Text(text = it) } } @@ -197,7 +203,7 @@ class MainActivity : ComponentActivity() { viewModel.addFeed(feed) else { var counter = 0 - viewModel.feedsState.value!!.forEachIndexed { index, feedGroup -> + viewModel.feeds.value!!.forEachIndexed { index, feedGroup -> if (feedGroup is FeedGroup) { counter++ if (counter == selectedIndex) { @@ -262,17 +268,8 @@ class MainActivity : ComponentActivity() { Modifier .pointerInput(Unit) { detectTapGestures( - onTap = { - WebView.webURL = article.url.toString() - WebView.barTitle = - feed.name ?: "" - startActivity( - Intent( - baseContext, - WebView::class.java - ) - ) - }, + + onTap = { openArticle(article.url.toString(), feed.name.toString()) }, onLongPress = { val share = Intent.createChooser(Intent().apply { @@ -397,10 +394,7 @@ class MainActivity : ComponentActivity() { .fillMaxWidth() .padding(vertical = 5.dp, horizontal = 4.dp) .clickable { - /*feeds.limit = if (feeds.limit == feed) { - null - } else feed*/ - viewModel.changeFeed() + viewModel.setLimit(feed) }, elevation = 10.dp, backgroundColor = MaterialTheme.colors.surface, @@ -470,7 +464,8 @@ class MainActivity : ComponentActivity() { drawerState: DrawerState, content: @Composable () -> Unit ) { - val feedList = viewModel.feedsState?.value ?: emptyList() + val feedLiveData = viewModel.feeds.observeAsState(emptyList()) + val feedList = feedLiveData.value ModalDrawer(drawerState = drawerState, drawerContent = { LazyColumn(modifier = Modifier.fillMaxHeight()) { item { @@ -479,8 +474,7 @@ class MainActivity : ComponentActivity() { .fillMaxWidth() .padding(vertical = 5.dp, horizontal = 4.dp) .clickable { - //feeds.limit = null - viewModel.changeFeed() + viewModel.setLimit(null) }, elevation = 10.dp, backgroundColor = MaterialTheme.colors.surface, @@ -534,6 +528,16 @@ class MainActivity : ComponentActivity() { } } }*/ +fun openArticle(articleURL: String, feedName: String) { + WebView.webURL = articleURL + WebView.barTitle = feedName + startActivity( + Intent( + baseContext, + WebView::class.java + ) + ) +} } \ No newline at end of file diff --git a/app/src/main/java/eu/toldi/balazs/anotherfeedreader/entities/Article.kt b/app/src/main/java/eu/toldi/balazs/anotherfeedreader/entities/Article.kt index 3fedd71..6fc9cad 100644 --- a/app/src/main/java/eu/toldi/balazs/anotherfeedreader/entities/Article.kt +++ b/app/src/main/java/eu/toldi/balazs/anotherfeedreader/entities/Article.kt @@ -1,5 +1,6 @@ package eu.toldi.balazs.anotherfeedreader.entities +import android.util.Log import androidx.room.ColumnInfo import androidx.room.Entity import androidx.room.Ignore @@ -10,8 +11,10 @@ import org.jsoup.Jsoup import org.w3c.dom.Element import org.w3c.dom.Node import org.w3c.dom.NodeList -import java.time.LocalDateTime +import java.time.Instant +import java.time.ZoneId import java.time.ZoneOffset +import java.time.ZonedDateTime import java.time.format.DateTimeFormatter @Entity(tableName = "article") @@ -52,12 +55,17 @@ data class Article( val feed: Feed? ) { + var pubDate: ZonedDateTime? + get() = pubDate_stamp?.let { + ZonedDateTime.ofInstant( + Instant.ofEpochSecond(pubDate_stamp!!), + ZoneId.systemDefault() + ) + } + set(value) { + pubDate_stamp = value?.toLocalDateTime()?.toEpochSecond(ZoneOffset.UTC) + } - @Ignore - val pubDate : LocalDateTime? - init { - pubDate = pubDate_stamp?.let { LocalDateTime.ofEpochSecond(it,0, ZoneOffset.UTC) } - } override fun toString(): String { return "Article{" + "title='" + title + '\'' + @@ -68,12 +76,21 @@ data class Article( ", pubDate=" + pubDate + '}' } - constructor() : this(null,"","","","","",null,null){ + + constructor() : this(null, "", "", "", "", "", null, null) { } + override fun equals(other: Any?): Boolean { + return if (other is Article) { + return title == other.title && url == other.url + } else return false + } + + @ColumnInfo(name = "containingFeedId") var feedId: Long = 0 + companion object { /** * Cikk beolvasása egy megadott Node objektumból. Egy hírcsatorna beolvasásakor könnyedén alkalmazható egy "item" Node-ra @@ -86,7 +103,7 @@ data class Article( var description: String? = null var imageURL: String? = null var author: String? = null - var pubDate: LocalDateTime? = null + var pubDate: ZonedDateTime? = null for (j in 0 until properties.getLength()) { val node: Node = properties.item(j) val tagName: String = node.getNodeName() @@ -94,7 +111,7 @@ data class Article( when (tagName) { "title" -> title = node.getTextContent() "author", "dc:creator" -> author = node.getTextContent() - "pubDate" -> pubDate = LocalDateTime.parse( + "pubDate" -> pubDate = ZonedDateTime.parse( node.textContent, DateTimeFormatter.RFC_1123_DATE_TIME ) @@ -112,6 +129,7 @@ data class Article( } } } + Log.e(null, "$title ${pubDate.toString()}") if (imageURL == null && url != null) { runBlocking(IO) { val con = Jsoup.connect(url) @@ -128,8 +146,16 @@ data class Article( } } } - return Article(null,title, url, description, imageURL, author, pubDate?.toEpochSecond( - ZoneOffset.UTC), feed) + return Article( + null, + title, + url, + description, + imageURL, + author, + pubDate?.toEpochSecond(), + feed + ) } } diff --git a/app/src/main/java/eu/toldi/balazs/anotherfeedreader/repository/FeedRepository.kt b/app/src/main/java/eu/toldi/balazs/anotherfeedreader/repository/FeedRepository.kt index e10fbd2..6f5a073 100644 --- a/app/src/main/java/eu/toldi/balazs/anotherfeedreader/repository/FeedRepository.kt +++ b/app/src/main/java/eu/toldi/balazs/anotherfeedreader/repository/FeedRepository.kt @@ -7,7 +7,6 @@ import androidx.compose.runtime.mutableStateOf import androidx.lifecycle.LiveData import eu.toldi.balazs.anotherfeedreader.entities.Article import eu.toldi.balazs.anotherfeedreader.entities.Feed -import eu.toldi.balazs.anotherfeedreader.sqlite.FeedsAndArticles import eu.toldi.balazs.anotherfeedreader.sqlite.FeedsAndArticlesDAO import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers.IO @@ -24,11 +23,29 @@ class FeedRepository(private val feedsAndArticleDAO: FeedsAndArticlesDAO) { private val _isRefereshing: MutableState = mutableStateOf(false) - public val isRefeshing: State + val isRefeshing: State get() = _isRefereshing - fun getAllArticles(): LiveData> { - return feedsAndArticleDAO.getAll() + private var limit: Feed? = null + + private val _articleState: MutableState> = mutableStateOf(emptyList()) + + val articleState: State> = _articleState + + suspend fun initArticles() = withContext(IO) { + _articleState.value = getAllArticles() + } + + suspend fun getAllArticles(): List
{ + + return if (limit != null) { + _isRefereshing.value = true + withContext(IO) { + feedsAndArticleDAO.getArticlesByFeed(limit!!.feedId!!).also { + _isRefereshing.value = false + } + } + } else withContext(IO) { feedsAndArticleDAO.getAllList() } } suspend fun instert(feed: Feed, article: Article) { @@ -42,9 +59,14 @@ class FeedRepository(private val feedsAndArticleDAO: FeedsAndArticlesDAO) { withContext(IO) { try { _isRefereshing.value = true - val feeds = feedsAndArticleDAO.getFeedsList() - feeds?.forEach { feed -> - updateFeed(feed) + if (limit != null) { + updateFeed(limit!!) + + } else { + val feeds = feedsAndArticleDAO.getFeedsList() + feeds?.forEach { feed -> + updateFeed(feed) + } } _isRefereshing.value = false } catch (e: Exception) { @@ -71,7 +93,9 @@ class FeedRepository(private val feedsAndArticleDAO: FeedsAndArticlesDAO) { for (i in 0 until items.length) { val article: Node = items.item(i) val a = withContext(Dispatchers.IO) { Article.createFromNode(article, feed = feed) } - feedsAndArticleDAO.insertArticle(feed, a) + val a1 = withContext(IO) { a.url?.let { feedsAndArticleDAO.getArticleByURL(it) } } + if (a != a1) + feedsAndArticleDAO.insertArticle(feed, a) } feed.faviconURL = withContext(Dispatchers.IO) { @@ -89,4 +113,9 @@ class FeedRepository(private val feedsAndArticleDAO: FeedsAndArticlesDAO) { feedsAndArticleDAO.insertFeed(feed) updateFeeds() } + + suspend fun setLimit(feed: Feed?) { + limit = feed + _articleState.value = getAllArticles() + } } \ No newline at end of file diff --git a/app/src/main/java/eu/toldi/balazs/anotherfeedreader/sqlite/FeedsAndArticlesDAO.kt b/app/src/main/java/eu/toldi/balazs/anotherfeedreader/sqlite/FeedsAndArticlesDAO.kt index d798668..41b9561 100644 --- a/app/src/main/java/eu/toldi/balazs/anotherfeedreader/sqlite/FeedsAndArticlesDAO.kt +++ b/app/src/main/java/eu/toldi/balazs/anotherfeedreader/sqlite/FeedsAndArticlesDAO.kt @@ -9,15 +9,24 @@ import eu.toldi.balazs.anotherfeedreader.entities.Feed interface FeedsAndArticlesDAO { @Transaction - @Query("SELECT * FROM feed INNER JOIN article ON feed.feedId = article.containingFeedId ORDER BY article.pubDate") + @Query("SELECT * FROM feed INNER JOIN article ON feed.feedId = article.containingFeedId ORDER BY article.pubDate DESC") fun getAll(): LiveData> + @Transaction + @Query("SELECT * FROM feed INNER JOIN article ON feed.feedId = article.containingFeedId ORDER BY article.pubDate DESC") + fun getAllList(): List
+ @Query("SELECT * FROM feed") fun getFeeds(): LiveData> @Query("SELECT * FROM feed") fun getFeedsList(): List + @Query("SELECT * FROM article WHERE url = :url") + fun getArticleByURL(url: String): Article + + @Query("SELECT * FROM feed INNER JOIN article ON feed.feedId = article.containingFeedId WHERE feed.feedId = :feedId ORDER BY article.pubDate DESC") + fun getArticlesByFeed(feedId: Long): List
fun insertArticle(feed: Feed, article: Article) { feed.feedId?.let { article.feedId = it } diff --git a/app/src/main/java/eu/toldi/balazs/anotherfeedreader/viewmodel/FeedViewModel.kt b/app/src/main/java/eu/toldi/balazs/anotherfeedreader/viewmodel/FeedViewModel.kt index 38ba8d5..a0f6342 100644 --- a/app/src/main/java/eu/toldi/balazs/anotherfeedreader/viewmodel/FeedViewModel.kt +++ b/app/src/main/java/eu/toldi/balazs/anotherfeedreader/viewmodel/FeedViewModel.kt @@ -5,10 +5,10 @@ import androidx.compose.runtime.State import androidx.lifecycle.AndroidViewModel import androidx.lifecycle.LiveData import androidx.lifecycle.viewModelScope +import eu.toldi.balazs.anotherfeedreader.entities.Article import eu.toldi.balazs.anotherfeedreader.entities.Feed import eu.toldi.balazs.anotherfeedreader.repository.FeedRepository import eu.toldi.balazs.anotherfeedreader.sqlite.AppDatabase -import eu.toldi.balazs.anotherfeedreader.sqlite.FeedsAndArticles import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.Job import kotlinx.coroutines.launch @@ -16,15 +16,19 @@ import kotlinx.coroutines.launch class FeedViewModel(application: Application) : AndroidViewModel(application) { private val feedRepo: FeedRepository - val articles: LiveData> - val feedsState: LiveData> + val articles: State> + val feeds: LiveData> val isRefereshing: State init { val feedsAndArticlesDao = AppDatabase.getInstance(application).feedsAndArticlesDao() feedRepo = FeedRepository(feedsAndArticleDAO = feedsAndArticlesDao) - articles = feedRepo.getAllArticles() - feedsState = feedRepo.getFeedList() + articles = feedRepo.articleState + viewModelScope.launch(IO) { + //feedRepo.initArticles() + feedRepo.updateFeeds() + } + feeds = feedRepo.getFeedList() isRefereshing = feedRepo.isRefeshing } @@ -36,12 +40,19 @@ class FeedViewModel(application: Application) : AndroidViewModel(application) { fun changeFeed() { viewModelScope.launch { + } } fun changeFeedList() { viewModelScope.launch { - //feedsState.value = feedRepo.getFeedList().value + + } + } + + fun setLimit(feed: Feed?) { + viewModelScope.launch { + feedRepo.setLimit(feed) } } diff --git a/build.gradle b/build.gradle index 58652cd..df033c6 100644 --- a/build.gradle +++ b/build.gradle @@ -8,7 +8,7 @@ buildscript { mavenCentral() } dependencies { - classpath "com.android.tools.build:gradle:7.0.2" + classpath 'com.android.tools.build:gradle:7.0.3' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.5.21" // NOTE: Do not place your application dependencies here; they belong