Commit ce9b6234 authored by Christophe Henry's avatar Christophe Henry

Fix #52: implement favorites support

parent 3b9da71c
Pipeline #3802 passed with stage
in 0 seconds
......@@ -6,6 +6,7 @@
* Better handle images embedded in a link by showing the link seperatly ([!63](https://git.feneas.org/christophehenry/freshrss-android/merge_requests/63))
* Add a notification to report crashes ([!67](https://git.feneas.org/christophehenry/freshrss-android/merge_requests/67))
* Implement [#52](https://git.feneas.org/christophehenry/freshrss-android/issues/52): support favorites ([!88](https://git.feneas.org/christophehenry/freshrss-android/merge_requests/88))
## Bug fixes
......
......@@ -4,7 +4,8 @@ pipeline {
image "bitriseio/docker-android"
args "-v /etc/passwd:/etc/passwd:ro " +
"-v /home/android/android-sdk-linux/:/opt/android-sdk-linux/:rw " +
"-v /home/android/.gradle/:/root/.gradle/:rw " +
// Disable for now, see https://stackoverflow.com/a/55590096
// "-v /home/android/.gradle/:/root/.gradle/:rw " +
"-v /home/android/freshrss_signkey.jks:/home/android/freshrss_signkey.jks:ro " +
"-u root --privileged"
}
......
......@@ -16,7 +16,7 @@ android {
versionCode 12
versionName "1.2.2"
testInstrumentationRunner "fr.chenry.android.freshrss.utils.FreshRSSTestRunner"
testInstrumentationRunnerArguments clearPackageData: 'true'
testInstrumentationRunnerArguments clearPackageData: "true"
javaCompileOptions {
annotationProcessorOptions {
arguments = ["room.schemaLocation": schema_location]
......@@ -106,20 +106,20 @@ spotless {
dependencies {
def appcompat_version = "1.1.0"
def activity_version = "1.1.0"
def fragment_version = '1.2.2'
def fragment_version = "1.2.2"
def lifecycle_version = "2.2.0"
def room_version = '2.2.4'
def room_version = "2.2.4"
def roomigrant_version = "0.1.7"
def jackson_version = '2.10.2'
def jackson_version = "2.10.3"
def espresso_version = "3.2.0"
def android_navigation = "1.0.0"
def jsoup_version = '1.12.2'
def acraVersion = '5.5.0'
def jsoup_version = "1.13.1"
def acraVersion = "5.5.0"
def autoservice_version = "1.0-rc6"
def android_test = "1.2.0"
def retrofit_version = "2.7.2"
def okhttp_version = "4.4.0"
def work_version = "2.3.2"
def okhttp_version = "4.4.1"
def work_version = "2.3.3"
// Linter
ktlint "com.github.shyiko:ktlint:0.31.0"
......@@ -137,11 +137,11 @@ dependencies {
implementation "androidx.activity:activity-ktx:$activity_version"
implementation "androidx.fragment:fragment-ktx:$fragment_version"
implementation 'androidx.core:core-ktx:1.2.0'
implementation "androidx.core:core-ktx:1.2.0"
implementation "androidx.constraintlayout:constraintlayout:1.1.3"
implementation "androidx.recyclerview:recyclerview:1.1.0"
implementation "androidx.preference:preference-ktx:1.1.0"
implementation 'com.google.android.material:material:1.2.0-alpha05'
implementation "com.google.android.material:material:1.2.0-alpha05"
// AndroidX testing
debugImplementation "androidx.fragment:fragment-testing:$fragment_version"
......@@ -177,7 +177,7 @@ dependencies {
// WorkManager
implementation "androidx.work:work-runtime-ktx:$work_version"
implementation "com.google.guava:guava:28.2-android"
implementation 'com.google.guava:guava:28.2-jre'
// Utils
......@@ -226,6 +226,7 @@ dependencies {
androidTestImplementation "androidx.test.espresso:espresso-contrib:$espresso_version"
androidTestImplementation "androidx.work:work-testing:$work_version"
// Debug
debugImplementation "com.facebook.stetho:stetho:1.5.1"
}
......@@ -10,6 +10,7 @@ import androidx.annotation.StringRes
import androidx.core.app.NotificationCompat
import androidx.work.*
import fr.chenry.android.freshrss.store.Store
import fr.chenry.android.freshrss.store.api.ALL_ITEMS_ID
import fr.chenry.android.freshrss.store.database.models.Subscription
import fr.chenry.android.freshrss.utils.*
import kotlinx.coroutines.*
......@@ -62,8 +63,9 @@ class RefreshWorker(appContext: Context, workerParams: WorkerParameters): Corout
Store.getSubscriptions()
Store.getUnreadCount()
Store.getStreamContents(Subscription.ALL_ITEMS_ID)
Store.getStreamContents(ALL_ITEMS_ID)
Store.getUnreadItemIds()
Store.getFavoriteItemIds()
}
cancelRefreshNotification()
......
package fr.chenry.android.freshrss.components.subscriptionarticles
package fr.chenry.android.freshrss.components.articles
import android.content.Intent
import android.os.Bundle
......@@ -12,23 +12,21 @@ import androidx.lifecycle.*
import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
import fr.chenry.android.freshrss.F
import fr.chenry.android.freshrss.R
import fr.chenry.android.freshrss.components.subscriptionarticles.webviewutils.FRSSWebView
import fr.chenry.android.freshrss.components.subscriptionarticles.webviewutils.ShareIntent
import fr.chenry.android.freshrss.components.articles.webviewutils.FRSSWebView
import fr.chenry.android.freshrss.components.articles.webviewutils.ShareIntent
import fr.chenry.android.freshrss.store.Store
import fr.chenry.android.freshrss.store.database.models.*
import fr.chenry.android.freshrss.store.viewmodels.SubscriptionArticleVM
import fr.chenry.android.freshrss.store.viewmodels.SubscriptionArticleVMF
import fr.chenry.android.freshrss.utils.e
import fr.chenry.android.freshrss.utils.isConnectedToNetwork
import fr.chenry.android.freshrss.store.viewmodels.ArticleVM
import fr.chenry.android.freshrss.store.viewmodels.ArticleVMF
import fr.chenry.android.freshrss.utils.*
import kotlinx.coroutines.*
class ArticleDetailFragment: Fragment() {
private lateinit var articleId: String
private val model: SubscriptionArticleVM by lazy {
ViewModelProvider(requireActivity().viewModelStore, SubscriptionArticleVMF(articleId))
.get("articleId=$articleId", SubscriptionArticleVM::class.java)
private val model: ArticleVM by lazy {
ViewModelProvider(requireActivity().viewModelStore, ArticleVMF(articleId))
.get("articleId=$articleId", ArticleVM::class.java)
}
private var isFetching = MutableLiveData<Boolean>().apply {value = false}
private val article: Article get() = model.liveData.value!!
private val subscription: Subscription get() = model.subscription
......@@ -72,7 +70,7 @@ class ArticleDetailFragment: Fragment() {
private fun setupShareAction(view: View) {
view.findViewById<ExtendedFloatingActionButton>(R.id.fab_share)
.setOnClickListener {
val chooserTitle = F.getString(R.string.share_article, subscription.title)
val chooserTitle = requireF().getString(R.string.share_article, subscription.title)
startActivity(Intent.createChooser(ShareIntent.create(getTemplateAttributes()), chooserTitle))
}
}
......@@ -110,18 +108,18 @@ class ArticleDetailFragment: Fragment() {
}
private fun setReadStatus(readStatus: ReadStatus) {
if(!F.context.isConnectedToNetwork()) {
if(!requireF().isConnectedToNetwork()) {
Toast.makeText(context, R.string.no_internet_connection_avaible, Toast.LENGTH_LONG).show()
return
}
if(article.requestOnGoing) {
if(article.readStatusRequestOnGoing) {
Toast.makeText(context, R.string.request_already_ongoing, LENGTH_SHORT).show()
return
}
GlobalScope.launch {
val result = Store.postReadStatusAsync(article, readStatus)
val result = Store.postReadStatus(article, readStatus)
result.onFailure {
withContext(Dispatchers.Main) {
......
package fr.chenry.android.freshrss.components.subscriptionarticles
package fr.chenry.android.freshrss.components.articles
import android.view.View
import android.widget.Toast
import android.widget.Toast.LENGTH_SHORT
import androidx.databinding.DataBindingUtil
import androidx.recyclerview.widget.RecyclerView
import eu.davidea.flexibleadapter.FlexibleAdapter
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
import eu.davidea.flexibleadapter.items.IFlexible
import eu.davidea.viewholders.FlexibleViewHolder
import fr.chenry.android.freshrss.BR
import fr.chenry.android.freshrss.R
import fr.chenry.android.freshrss.components.subscriptionarticles.SubscriptionArticleViewItem.ArticleViewHolder
import fr.chenry.android.freshrss.*
import fr.chenry.android.freshrss.components.articles.ArticleViewItem.ArticleViewHolder
import fr.chenry.android.freshrss.databinding.FragmentSubscriptionArticleBinding
import fr.chenry.android.freshrss.store.database.models.Article
import fr.chenry.android.freshrss.store.database.models.Subscription
import fr.chenry.android.freshrss.store.Store
import fr.chenry.android.freshrss.store.database.models.*
import fr.chenry.android.freshrss.utils.e
import fr.chenry.android.freshrss.utils.isConnectedToNetwork
import kotlinx.coroutines.*
class SubscriptionArticleViewItem(
class ArticleViewItem(
private val application: FreshRSSApplication,
private val subscription: Subscription,
val article: Article
): AbstractFlexibleItem<ArticleViewHolder>() {
......@@ -34,7 +39,7 @@ class SubscriptionArticleViewItem(
) = holder.bind(article)
override fun equals(other: Any?): Boolean {
if(other !is SubscriptionArticleViewItem) return false
if(other !is ArticleViewItem) return false
return article == other.article
}
......@@ -44,7 +49,6 @@ class SubscriptionArticleViewItem(
): ArticleViewHolder = ArticleViewHolder(DataBindingUtil.bind(view)!!, adapter)
override fun getLayoutRes(): Int = R.layout.fragment_subscription_article
override fun hashCode(): Int = article.hashCode()
inner class ArticleViewHolder(
......@@ -53,13 +57,14 @@ class SubscriptionArticleViewItem(
): FlexibleViewHolder(binding.root, flexibleAdapter) {
private val frontView = binding.root.findViewById<View>(R.id.fragment_subscription_article_front_view)
private val rearLeftView =
binding.root.findViewById<View>(R.id.fragment_subscription_article_rear_left_view)
private val frontView = binding.root.findViewById<View>(R.id.fragment_subscription_base_layout)
private val rearLeftView = binding.root.findViewById<View>(R.id.fragment_subscription_article_rear_left_view)
fun bind(article: Article) {
val listener = FavoriteClickListener(this@ArticleViewItem.application, article)
binding.setVariable(BR.article, article)
binding.setVariable(BR.subscription, subscription)
binding.setVariable(BR.onFavoriteClickListener, listener)
binding.executePendingBindings()
}
......@@ -67,4 +72,46 @@ class SubscriptionArticleViewItem(
override fun getRearLeftView(): View = rearLeftView
override fun getActivationElevation(): Float = 1f
}
class FavoriteClickListener(
private val application: FreshRSSApplication,
private val article: Article
): View.OnClickListener {
override fun onClick(v: View) {
if(!application.isConnectedToNetwork()) {
Toast.makeText(application, R.string.no_internet_connection_avaible, Toast.LENGTH_LONG).show()
return
}
if(article.favoriteRequestOnGoing) {
Toast.makeText(application, R.string.request_already_ongoing, LENGTH_SHORT).show()
return
}
GlobalScope.launch {
article.favoriteRequestOnGoing = true
val expected = article.favorite.toggle()
Store.postFavoriteStatus(article, expected).onFailure {err ->
this.e(err)
val message = when(expected) {
FavoriteStatus.FAVORITE -> application.getString(R.string.add_favorite_status, article.title)
FavoriteStatus.NOT_FAVORITE -> application.getString(
R.string.remove_favorit_status,
article.title
)
}
val toastText = application.getString(R.string.unable_to, message)
withContext(Dispatchers.Main) {
Toast.makeText(application, toastText, LENGTH_SHORT).show()
}
}
article.favoriteRequestOnGoing = false
}
}
}
}
package fr.chenry.android.freshrss.components.subscriptionarticles
package fr.chenry.android.freshrss.components.articles
import android.os.Bundle
import android.view.*
......@@ -13,32 +13,39 @@ import androidx.navigation.fragment.navArgs
import androidx.recyclerview.widget.*
import androidx.recyclerview.widget.RecyclerView.ViewHolder
import eu.davidea.flexibleadapter.FlexibleAdapter
import eu.davidea.flexibleadapter.common.FlexibleItemDecoration
import fr.chenry.android.freshrss.R
import fr.chenry.android.freshrss.components.subscriptions.SubscriptionSection
import fr.chenry.android.freshrss.store.Store
import fr.chenry.android.freshrss.store.database.models.ReadStatus
import fr.chenry.android.freshrss.store.database.models.ReadStatus.READ
import fr.chenry.android.freshrss.store.database.models.ReadStatus.UNREAD
import fr.chenry.android.freshrss.store.database.models.Subscription
import fr.chenry.android.freshrss.store.viewmodels.*
import fr.chenry.android.freshrss.utils.e
import fr.chenry.android.freshrss.utils.*
import kotlinx.android.synthetic.main.fragment_subscription_articles.*
import kotlinx.coroutines.*
class SubscriptionArticlesFragment: Fragment() {
private val args: SubscriptionArticlesFragmentArgs by navArgs()
class ArticlesFragment: Fragment() {
private val args: ArticlesFragmentArgs by navArgs()
private val subscription: Subscription by lazy {args.subscription}
private val readStatus: ReadStatus by lazy {args.readStatus}
private val section: SubscriptionSection by lazy {args.section}
private val workInfos by viewModels<RefreshWorkInfosVM>()
private val model: SubscriptionArticlesVM by lazy {
ViewModelProvider(requireActivity().viewModelStore, SubscriptionArticlesVMF(subscription, readStatus))
.get("stream=${subscription.id}:readStatus=$readStatus", SubscriptionArticlesVM::class.java)
private val model: ArticlesVM by lazy {
ViewModelProvider(requireActivity().viewModelStore, ArticlesVMF(requireF(), subscription, section))
.get("stream=${subscription.id}:section=$section", ArticlesVM::class.java)
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
val view = inflater.inflate(R.layout.fragment_subscription_articles, container, false)
view.findViewById<RecyclerView>(R.id.fragment_subscription_article_recycler).apply {
val itemDecoration = FlexibleItemDecoration(requireContext())
.withDefaultDivider()
.withDrawOver(true)
.withDrawDividerOnLastItem(true)
addItemDecoration(itemDecoration)
layoutManager = LinearLayoutManager(context)
adapter = ArticleAdapter(model.liveData.value ?: listOf())
}
......@@ -47,14 +54,19 @@ class SubscriptionArticlesFragment: Fragment() {
}
private fun toggleProgressCircle(articles: List<*>) {
fragment_subscription_article_empty_list.text = when(readStatus) {
READ -> getString(R.string.empty_subscription_list, model.subscription.title)
UNREAD -> getString(R.string.empty_subscription_unread_list, model.subscription.title)
fragment_subscription_article_empty_list.text = when(section) {
SubscriptionSection.ALL -> getString(R.string.empty_subscription_list, model.subscription.title)
SubscriptionSection.UNREAD -> getString(R.string.empty_subscription_unread_list, model.subscription.title)
SubscriptionSection.FAVORITES -> getString(
R.string.empty_subscription_favorite_list,
model.subscription.title
)
}
when(readStatus) {
READ -> R.drawable.ic_undraw_blogging
UNREAD -> R.drawable.ic_undraw_all_read
when(section) {
SubscriptionSection.ALL -> R.drawable.ic_undraw_blogging
SubscriptionSection.UNREAD -> R.drawable.ic_undraw_all_read
SubscriptionSection.FAVORITES -> R.drawable.ic_undraw_favorite
}.let {fragment_subscription_article_empty_list.setImageResource(it)}
if(articles.isNotEmpty()) {
......@@ -75,9 +87,9 @@ class SubscriptionArticlesFragment: Fragment() {
}
}
private inner class ArticleAdapter(items: List<SubscriptionArticleViewItem>):
FlexibleAdapter<SubscriptionArticleViewItem>(items, null, true),
Observer<List<SubscriptionArticleViewItem>>,
private inner class ArticleAdapter(items: List<ArticleViewItem>):
FlexibleAdapter<ArticleViewItem>(items, null, true),
Observer<List<ArticleViewItem>>,
FlexibleAdapter.OnItemClickListener,
FlexibleAdapter.OnItemSwipeListener {
......@@ -100,15 +112,15 @@ class SubscriptionArticlesFragment: Fragment() {
override fun isEmpty(): Boolean = (model.liveData.value ?: listOf()).isEmpty()
override fun onChanged(articlesViewItemSubscriptions: List<SubscriptionArticleViewItem>?) {
override fun onChanged(articlesViewItemSubscriptions: List<ArticleViewItem>?) {
(articlesViewItemSubscriptions ?: listOf()).let {
toggleProgressCircle(it)
updateDataSet(it, true)
}
}
override fun onItemClick(view: View?, position: Int): Boolean = getArticleId(position)?.let {
val direction = SubscriptionArticlesFragmentDirections.articlesToArticleDetail(it)
override fun onItemClick(view: View, position: Int): Boolean = getArticleId(position)?.let {
val direction = ArticlesFragmentDirections.articlesToArticleDetail(it)
findNavController().navigate(direction)
true
} ?: false
......@@ -121,12 +133,25 @@ class SubscriptionArticlesFragment: Fragment() {
private fun getArticleId(position: Int) = getItem(position)?.article?.id
private fun toggleArticleReadStatus(position: Int) = getItem(position)?.let {
private fun toggleArticleReadStatus(position: Int): Unit = getItem(position)?.let {
if(!requireF().isConnectedToNetwork()) {
Toast.makeText(context, R.string.no_internet_connection_avaible, Toast.LENGTH_LONG).show()
return
}
if(it.article.readStatusRequestOnGoing) {
Toast.makeText(context, R.string.request_already_ongoing, LENGTH_SHORT).show()
return
}
it.article.readStatusRequestOnGoing = true
GlobalScope.launch {
Store.postReadStatusAsync(it.article, it.article.readStatus.toggle()).onFailure {
this@ArticleAdapter.e(it)
val fragment = this@SubscriptionArticlesFragment
val message = when(readStatus) {
val expected = it.article.readStatus.toggle()
Store.postReadStatus(it.article, expected).onFailure {err ->
this@ArticleAdapter.e(err)
val fragment = this@ArticlesFragment
val message = when(expected) {
READ -> fragment.getString(R.string.read)
UNREAD -> fragment.getString(R.string.unread)
}.let {msg -> fragment.getString(R.string.mark_read_status_authorization, msg)}
......@@ -138,10 +163,12 @@ class SubscriptionArticlesFragment: Fragment() {
}
}
withContext(Dispatchers.Main) {
if(readStatus == READ) this@ArticleAdapter.notifyItemChanged(position)
if(section == SubscriptionSection.ALL) withContext(Dispatchers.Main) {
this@ArticleAdapter.notifyItemChanged(position)
}
it.article.readStatusRequestOnGoing = false
}
}
}.unit()
}
}
package fr.chenry.android.freshrss.components.subscriptionarticles.webviewutils
package fr.chenry.android.freshrss.components.articles.webviewutils
import android.content.Context
import android.util.AttributeSet
......
package fr.chenry.android.freshrss.components.subscriptionarticles.webviewutils
package fr.chenry.android.freshrss.components.articles.webviewutils
import android.content.Intent
import android.net.MailTo
......
package fr.chenry.android.freshrss.components.subscriptionarticles.webviewutils
package fr.chenry.android.freshrss.components.articles.webviewutils
import android.content.Intent
......
package fr.chenry.android.freshrss.components.subscriptionarticles.webviewutils
package fr.chenry.android.freshrss.components.articles.webviewutils
import android.content.Intent
import android.content.Intent.ACTION_SEND
import android.content.Intent.EXTRA_TEXT
import com.x5.template.Theme
import fr.chenry.android.freshrss.components.subscriptionarticles.webviewutils.chunkfilters.SentenceCapFilter
import fr.chenry.android.freshrss.components.subscriptionarticles.webviewutils.chunkfilters.RemoveFeedTitleFilter
import fr.chenry.android.freshrss.components.articles.webviewutils.chunkfilters.SentenceCapFilter
import fr.chenry.android.freshrss.components.articles.webviewutils.chunkfilters.RemoveFeedTitleFilter
object ShareIntent {
private val defaultTemplate = """
......
package fr.chenry.android.freshrss.components.subscriptionarticles.webviewutils.chunkfilters
package fr.chenry.android.freshrss.components.articles.webviewutils.chunkfilters
import com.x5.template.Chunk
import com.x5.template.filters.FilterArgs
import com.x5.template.filters.ObjectFilter
import java.util.Locale
import java.util.regex.Pattern
import kotlin.text.RegexOption.IGNORE_CASE
object ChunkFilters {
......
......@@ -10,15 +10,14 @@ import androidx.navigation.fragment.navArgs
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
import fr.chenry.android.freshrss.F
import fr.chenry.android.freshrss.R
import fr.chenry.android.freshrss.components.subscriptions.SubscriptionSection.*
import fr.chenry.android.freshrss.components.subscriptions.adapters.SubscriptionViewItems
import fr.chenry.android.freshrss.components.subscriptions.adapters.SubscriptionsFlexibleAdapter
import fr.chenry.android.freshrss.store.database.models.*
import fr.chenry.android.freshrss.store.database.models.ReadStatus.READ
import fr.chenry.android.freshrss.store.viewmodels.*
import fr.chenry.android.freshrss.utils.EmotionnalImageSubtext
import fr.chenry.android.freshrss.utils.requireF
import kotlinx.android.synthetic.main.fragment_subscriptions.*
class SubscriptionsFragment: Fragment(), Observer<SubscriptionViewItems> {
......@@ -34,7 +33,6 @@ class SubscriptionsFragment: Fragment(), Observer<SubscriptionViewItems> {
.get(key, SubscriptionsVM::class.java)
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val view = inflater.inflate(R.layout.fragment_subscriptions, container, false)
......@@ -57,7 +55,7 @@ class SubscriptionsFragment: Fragment(), Observer<SubscriptionViewItems> {
UNREAD -> R.string.empty_subscriptions_section_unread
FAVORITES -> R.string.empty_subscriptions_section_favorites
}
}.let {F.getString(it, category.label)}
}.let {requireF().getString(it, category.label)}
view.findViewById<EmotionnalImageSubtext>(R.id.fragment_subscriptions_empty_list).text = contentDescription
......@@ -72,29 +70,23 @@ class SubscriptionsFragment: Fragment(), Observer<SubscriptionViewItems> {
view.findViewById<SwipeRefreshLayout>(R.id.subcription_pull_to_refresh)?.let {
workInfos.isWorkerRunningLiveData.observe(viewLifecycleOwner) {b -> it.isRefreshing = b}
it.setOnRefreshListener(F::refresh)
it.setOnRefreshListener(requireF()::refresh)
}
return view
}
override fun onChanged(subscriptions: SubscriptionViewItems?)
= toggleProgressCircle((subscriptions.isNullOrEmpty()))
fun onClick(subscription: Subscription) = when(section) {
FAVORITES -> subscription to READ
ALL -> subscription to READ
UNREAD -> subscription to ReadStatus.UNREAD
}.let {
val direction = if(category == VoidCategory)
MainSubscriptionFragmentDirections.mainSubscriptionsToArticles(it.first, it.second) else
SubscriptionsFragmentDirections.articlesCategoryToArticles(it.first, it.second)
findNavController().navigate(direction)
}
override fun onChanged(subscriptions: SubscriptionViewItems?) =
toggleProgressCircle((subscriptions.isNullOrEmpty()))
fun onClick(subscription: Subscription) = when(category) {
VoidCategory -> MainSubscriptionFragmentDirections.mainSubscriptionsToArticles(subscription, section)
else -> SubscriptionsFragmentDirections.articlesCategoryToArticles(subscription, section)
}.let(findNavController()::navigate)
fun onClick(subscriptionCategory: SubscriptionCategory) =
MainSubscriptionFragmentDirections.mainSubscriptionsToArticlesCategory(subscriptionCategory, section)
.let {findNavController().navigate(it)}
.let(findNavController()::navigate)
private fun initRecyclerView(view: View) {
val adapter = SubscriptionsFlexibleAdapter(this)
......
......@@ -2,13 +2,9 @@ package fr.chenry.android.freshrss.store
import androidx.lifecycle.*
import fr.chenry.android.freshrss.F
import fr.chenry.android.freshrss.store.api.API
import fr.chenry.android.freshrss.store.api.LOGIN_ENPOINT
import fr.chenry.android.freshrss.store.api.*
import fr.chenry.android.freshrss.store.api.utils.*
import fr.chenry.android.freshrss.store.database.models.*
import fr.chenry.android.freshrss.store.database.models.Article.Companion.fromContentItem
import fr.chenry.android.freshrss.store.database.models.ReadStatus.READ
import fr.chenry.android.freshrss.store.database.models.ReadStatus.UNREAD
import fr.chenry.android.freshrss.utils.*
import kotlinx.coroutines.*