Repository should be DB ok.
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
aminecmi 2022-08-23 16:19:24 +02:00
parent 59eb399cfa
commit 2547ce824a
41 changed files with 175 additions and 102 deletions

View File

@ -11,6 +11,7 @@ import bou.amine.apps.readerforselfossv2.android.themes.AppColors
import bou.amine.apps.readerforselfossv2.android.themes.Toppings import bou.amine.apps.readerforselfossv2.android.themes.Toppings
import bou.amine.apps.readerforselfossv2.android.utils.Config import bou.amine.apps.readerforselfossv2.android.utils.Config
import bou.amine.apps.readerforselfossv2.android.utils.isBaseUrlValid import bou.amine.apps.readerforselfossv2.android.utils.isBaseUrlValid
import bou.amine.apps.readerforselfossv2.model.NetworkUnavailableException
import bou.amine.apps.readerforselfossv2.repository.Repository import bou.amine.apps.readerforselfossv2.repository.Repository
import com.ftinc.scoop.Scoop import com.ftinc.scoop.Scoop
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
@ -109,33 +110,40 @@ class AddSourceActivity : AppCompatActivity(), DIAware {
} }
fun handleSpoutFailure(networkIssue: Boolean = false) {
Toast.makeText(
this@AddSourceActivity,
if (networkIssue) R.string.cant_get_spouts_no_network else R.string.cant_get_spouts,
Toast.LENGTH_SHORT
).show()
mProgress.visibility = View.GONE
}
CoroutineScope(Dispatchers.Main).launch { CoroutineScope(Dispatchers.Main).launch {
val items = repository.getSpouts() try {
if (items != null) { val items = repository.getSpouts()
if (items != null) {
val itemsStrings = items.map { it.value.name }
for ((key, value) in items) {
spoutsKV[value.name] = key
}
val itemsStrings = items.map { it.value.name } mProgress.visibility = View.GONE
for ((key, value) in items) { formContainer.visibility = View.VISIBLE
spoutsKV[value.name] = key
val spinnerArrayAdapter =
ArrayAdapter(
this@AddSourceActivity,
android.R.layout.simple_spinner_item,
itemsStrings
)
spinnerArrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
spoutsSpinner.adapter = spinnerArrayAdapter
} else {
handleSpoutFailure()
} }
} catch (e: NetworkUnavailableException) {
mProgress.visibility = View.GONE handleSpoutFailure(networkIssue = true)
formContainer.visibility = View.VISIBLE
val spinnerArrayAdapter =
ArrayAdapter(
this@AddSourceActivity,
android.R.layout.simple_spinner_item,
itemsStrings
)
spinnerArrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
spoutsSpinner.adapter = spinnerArrayAdapter
} else {
Toast.makeText(
this@AddSourceActivity,
R.string.cant_get_spouts,
Toast.LENGTH_SHORT
).show()
mProgress.visibility = View.GONE
} }
} }
} }

View File

@ -38,10 +38,9 @@ import bou.amine.apps.readerforselfossv2.android.utils.bottombar.removeBadge
import bou.amine.apps.readerforselfossv2.android.utils.customtabs.CustomTabActivityHelper import bou.amine.apps.readerforselfossv2.android.utils.customtabs.CustomTabActivityHelper
import bou.amine.apps.readerforselfossv2.dao.ACTION import bou.amine.apps.readerforselfossv2.dao.ACTION
import bou.amine.apps.readerforselfossv2.repository.Repository import bou.amine.apps.readerforselfossv2.repository.Repository
import bou.amine.apps.readerforselfossv2.rest.SelfossModel import bou.amine.apps.readerforselfossv2.model.SelfossModel
import bou.amine.apps.readerforselfossv2.utils.ItemType import bou.amine.apps.readerforselfossv2.utils.ItemType
import bou.amine.apps.readerforselfossv2.utils.longHash import bou.amine.apps.readerforselfossv2.utils.longHash
import bou.amine.apps.readerforselfossv2.utils.toEntity
import bou.amine.apps.readerforselfossv2.utils.toView import bou.amine.apps.readerforselfossv2.utils.toView
import com.ashokvarma.bottomnavigation.BottomNavigationBar import com.ashokvarma.bottomnavigation.BottomNavigationBar
import com.ashokvarma.bottomnavigation.BottomNavigationItem import com.ashokvarma.bottomnavigation.BottomNavigationItem
@ -167,6 +166,16 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
handleSettings() handleSettings()
getElementsAccordingToTab() getElementsAccordingToTab()
// TODO: items caching should be done in the background when starting the app, like background.kt does
// fetchedItems?.let {
// CoroutineScope(Dispatchers.Main).launch {
// insertDBItems(it)
// }
// }
} }
private fun handleSwipeRefreshLayout() { private fun handleSwipeRefreshLayout() {

View File

@ -16,7 +16,7 @@ import bou.amine.apps.readerforselfossv2.android.themes.AppColors
import bou.amine.apps.readerforselfossv2.android.themes.Toppings import bou.amine.apps.readerforselfossv2.android.themes.Toppings
import bou.amine.apps.readerforselfossv2.android.utils.toggleStar import bou.amine.apps.readerforselfossv2.android.utils.toggleStar
import bou.amine.apps.readerforselfossv2.repository.Repository import bou.amine.apps.readerforselfossv2.repository.Repository
import bou.amine.apps.readerforselfossv2.rest.SelfossModel import bou.amine.apps.readerforselfossv2.model.SelfossModel
import com.ftinc.scoop.Scoop import com.ftinc.scoop.Scoop
import com.russhwolf.settings.Settings import com.russhwolf.settings.Settings
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope

View File

@ -11,7 +11,7 @@ import bou.amine.apps.readerforselfossv2.android.databinding.ActivitySourcesBind
import bou.amine.apps.readerforselfossv2.android.themes.AppColors import bou.amine.apps.readerforselfossv2.android.themes.AppColors
import bou.amine.apps.readerforselfossv2.android.themes.Toppings import bou.amine.apps.readerforselfossv2.android.themes.Toppings
import bou.amine.apps.readerforselfossv2.repository.Repository import bou.amine.apps.readerforselfossv2.repository.Repository
import bou.amine.apps.readerforselfossv2.rest.SelfossModel import bou.amine.apps.readerforselfossv2.model.SelfossModel
import com.ftinc.scoop.Scoop import com.ftinc.scoop.Scoop
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers

View File

@ -16,7 +16,7 @@ import bou.amine.apps.readerforselfossv2.android.utils.customtabs.CustomTabActiv
import bou.amine.apps.readerforselfossv2.android.utils.glide.bitmapCenterCrop import bou.amine.apps.readerforselfossv2.android.utils.glide.bitmapCenterCrop
import bou.amine.apps.readerforselfossv2.android.utils.glide.circularBitmapDrawable import bou.amine.apps.readerforselfossv2.android.utils.glide.circularBitmapDrawable
import bou.amine.apps.readerforselfossv2.repository.Repository import bou.amine.apps.readerforselfossv2.repository.Repository
import bou.amine.apps.readerforselfossv2.rest.SelfossModel import bou.amine.apps.readerforselfossv2.model.SelfossModel
import com.amulyakhare.textdrawable.TextDrawable import com.amulyakhare.textdrawable.TextDrawable
import com.amulyakhare.textdrawable.util.ColorGenerator import com.amulyakhare.textdrawable.util.ColorGenerator
import com.bumptech.glide.Glide import com.bumptech.glide.Glide

View File

@ -13,7 +13,7 @@ import bou.amine.apps.readerforselfossv2.android.utils.customtabs.CustomTabActiv
import bou.amine.apps.readerforselfossv2.android.utils.glide.bitmapCenterCrop import bou.amine.apps.readerforselfossv2.android.utils.glide.bitmapCenterCrop
import bou.amine.apps.readerforselfossv2.android.utils.glide.circularBitmapDrawable import bou.amine.apps.readerforselfossv2.android.utils.glide.circularBitmapDrawable
import bou.amine.apps.readerforselfossv2.repository.Repository import bou.amine.apps.readerforselfossv2.repository.Repository
import bou.amine.apps.readerforselfossv2.rest.SelfossModel import bou.amine.apps.readerforselfossv2.model.SelfossModel
import com.amulyakhare.textdrawable.TextDrawable import com.amulyakhare.textdrawable.TextDrawable
import com.amulyakhare.textdrawable.util.ColorGenerator import com.amulyakhare.textdrawable.util.ColorGenerator
import org.kodein.di.DI import org.kodein.di.DI

View File

@ -8,7 +8,7 @@ import bou.amine.apps.readerforselfossv2.android.R
import bou.amine.apps.readerforselfossv2.android.themes.AppColors import bou.amine.apps.readerforselfossv2.android.themes.AppColors
import bou.amine.apps.readerforselfossv2.android.utils.Config import bou.amine.apps.readerforselfossv2.android.utils.Config
import bou.amine.apps.readerforselfossv2.repository.Repository import bou.amine.apps.readerforselfossv2.repository.Repository
import bou.amine.apps.readerforselfossv2.rest.SelfossModel import bou.amine.apps.readerforselfossv2.model.SelfossModel
import bou.amine.apps.readerforselfossv2.utils.ItemType import bou.amine.apps.readerforselfossv2.utils.ItemType
import com.google.android.material.snackbar.Snackbar import com.google.android.material.snackbar.Snackbar
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope

View File

@ -16,7 +16,7 @@ import bou.amine.apps.readerforselfossv2.android.utils.Config
import bou.amine.apps.readerforselfossv2.android.utils.glide.circularBitmapDrawable import bou.amine.apps.readerforselfossv2.android.utils.glide.circularBitmapDrawable
import bou.amine.apps.readerforselfossv2.android.utils.toTextDrawableString import bou.amine.apps.readerforselfossv2.android.utils.toTextDrawableString
import bou.amine.apps.readerforselfossv2.repository.Repository import bou.amine.apps.readerforselfossv2.repository.Repository
import bou.amine.apps.readerforselfossv2.rest.SelfossModel import bou.amine.apps.readerforselfossv2.model.SelfossModel
import com.amulyakhare.textdrawable.TextDrawable import com.amulyakhare.textdrawable.TextDrawable
import com.amulyakhare.textdrawable.util.ColorGenerator import com.amulyakhare.textdrawable.util.ColorGenerator
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope

View File

@ -18,7 +18,7 @@ import bou.amine.apps.readerforselfossv2.android.utils.Config
import bou.amine.apps.readerforselfossv2.android.utils.network.isNetworkAccessible import bou.amine.apps.readerforselfossv2.android.utils.network.isNetworkAccessible
import bou.amine.apps.readerforselfossv2.dao.ACTION import bou.amine.apps.readerforselfossv2.dao.ACTION
import bou.amine.apps.readerforselfossv2.repository.Repository import bou.amine.apps.readerforselfossv2.repository.Repository
import bou.amine.apps.readerforselfossv2.rest.SelfossModel import bou.amine.apps.readerforselfossv2.model.SelfossModel
import bou.amine.apps.readerforselfossv2.utils.ItemType import bou.amine.apps.readerforselfossv2.utils.ItemType
import com.russhwolf.settings.Settings import com.russhwolf.settings.Settings
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
@ -82,10 +82,10 @@ override fun doWork(): Result {
launch { launch {
try { try {
val newItems = repository.allItems(ItemType.UNREAD) val newItems = repository.getMaxItemsForBackground(ItemType.UNREAD)
handleNewItemsNotification(newItems, notifyNewItems, notificationManager) handleNewItemsNotification(newItems, notifyNewItems, notificationManager)
repository.allItems(ItemType.ALL) repository.getMaxItemsForBackground(ItemType.ALL)
repository.allItems(ItemType.STARRED) repository.getMaxItemsForBackground(ItemType.STARRED)
} catch (e: Throwable) {} } catch (e: Throwable) {}
} }
} }

View File

@ -31,7 +31,7 @@ import bou.amine.apps.readerforselfossv2.android.utils.customtabs.CustomTabActiv
import bou.amine.apps.readerforselfossv2.android.utils.glide.getBitmapInputStream import bou.amine.apps.readerforselfossv2.android.utils.glide.getBitmapInputStream
import bou.amine.apps.readerforselfossv2.android.utils.glide.loadMaybeBasicAuth import bou.amine.apps.readerforselfossv2.android.utils.glide.loadMaybeBasicAuth
import bou.amine.apps.readerforselfossv2.repository.Repository import bou.amine.apps.readerforselfossv2.repository.Repository
import bou.amine.apps.readerforselfossv2.rest.SelfossModel import bou.amine.apps.readerforselfossv2.model.SelfossModel
import bou.amine.apps.readerforselfossv2.utils.isEmptyOrNullOrNullString import bou.amine.apps.readerforselfossv2.utils.isEmptyOrNullOrNullString
import com.bumptech.glide.Glide import com.bumptech.glide.Glide
import com.bumptech.glide.load.engine.DiskCacheStrategy import com.bumptech.glide.load.engine.DiskCacheStrategy

View File

@ -4,7 +4,7 @@ import android.content.Context
import android.net.Uri import android.net.Uri
import android.text.Html import android.text.Html
import android.webkit.URLUtil import android.webkit.URLUtil
import bou.amine.apps.readerforselfossv2.rest.SelfossModel import bou.amine.apps.readerforselfossv2.model.SelfossModel
import com.bumptech.glide.Glide import com.bumptech.glide.Glide
import com.bumptech.glide.load.engine.DiskCacheStrategy import com.bumptech.glide.load.engine.DiskCacheStrategy
import com.bumptech.glide.request.RequestOptions import com.bumptech.glide.request.RequestOptions

View File

@ -1,10 +1,8 @@
package bou.amine.apps.readerforselfossv2.android.model package bou.amine.apps.readerforselfossv2.android.model
import android.os.Build
import android.os.Parcel import android.os.Parcel
import android.os.Parcelable import android.os.Parcelable
import androidx.annotation.RequiresApi import bou.amine.apps.readerforselfossv2.model.SelfossModel
import bou.amine.apps.readerforselfossv2.rest.SelfossModel
import com.google.gson.annotations.SerializedName import com.google.gson.annotations.SerializedName
fun SelfossModel.Item.toParcelable() : ParecelableItem = fun SelfossModel.Item.toParcelable() : ParecelableItem =

View File

@ -2,7 +2,7 @@ package bou.amine.apps.readerforselfossv2.android.utils
import android.content.Context import android.content.Context
import bou.amine.apps.readerforselfossv2.android.model.getSourceTitle import bou.amine.apps.readerforselfossv2.android.model.getSourceTitle
import bou.amine.apps.readerforselfossv2.rest.SelfossModel import bou.amine.apps.readerforselfossv2.model.SelfossModel
import bou.amine.apps.readerforselfossv2.utils.DateUtils import bou.amine.apps.readerforselfossv2.utils.DateUtils
import bou.amine.apps.readerforselfossv2.utils.parseRelativeDate import bou.amine.apps.readerforselfossv2.utils.parseRelativeDate

View File

@ -20,7 +20,7 @@ import bou.amine.apps.readerforselfossv2.android.R
import bou.amine.apps.readerforselfossv2.android.ReaderActivity import bou.amine.apps.readerforselfossv2.android.ReaderActivity
import bou.amine.apps.readerforselfossv2.android.model.getLinkDecoded import bou.amine.apps.readerforselfossv2.android.model.getLinkDecoded
import bou.amine.apps.readerforselfossv2.android.utils.customtabs.CustomTabActivityHelper import bou.amine.apps.readerforselfossv2.android.utils.customtabs.CustomTabActivityHelper
import bou.amine.apps.readerforselfossv2.rest.SelfossModel import bou.amine.apps.readerforselfossv2.model.SelfossModel
import bou.amine.apps.readerforselfossv2.utils.toStringUriWithHttp import bou.amine.apps.readerforselfossv2.utils.toStringUriWithHttp
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull import okhttp3.HttpUrl.Companion.toHttpUrlOrNull

View File

@ -168,4 +168,5 @@
<string name="reader_static_bar_on">The bottom bar will always be displayed</string> <string name="reader_static_bar_on">The bottom bar will always be displayed</string>
<string name="reader_static_bar_off">The bottom bar can be shown through the floating button</string> <string name="reader_static_bar_off">The bottom bar can be shown through the floating button</string>
<string name="remove_source">Remove source</string> <string name="remove_source">Remove source</string>
<string name="cant_get_spouts_no_network">Can\'t get spouts list because of a network issue.</string>
</resources> </resources>

View File

@ -168,4 +168,5 @@
<string name="reader_static_bar_on">The bottom bar will always be displayed</string> <string name="reader_static_bar_on">The bottom bar will always be displayed</string>
<string name="reader_static_bar_off">The bottom bar can be shown through the floating button</string> <string name="reader_static_bar_off">The bottom bar can be shown through the floating button</string>
<string name="remove_source">Remove source</string> <string name="remove_source">Remove source</string>
<string name="cant_get_spouts_no_network">Can\'t get spouts list because of a network issue.</string>
</resources> </resources>

View File

@ -168,4 +168,5 @@
<string name="reader_static_bar_on">The bottom bar will always be displayed</string> <string name="reader_static_bar_on">The bottom bar will always be displayed</string>
<string name="reader_static_bar_off">The bottom bar can be shown through the floating button</string> <string name="reader_static_bar_off">The bottom bar can be shown through the floating button</string>
<string name="remove_source">Remove source</string> <string name="remove_source">Remove source</string>
<string name="cant_get_spouts_no_network">Can\'t get spouts list because of a network issue.</string>
</resources> </resources>

View File

@ -168,4 +168,5 @@
<string name="reader_static_bar_on">The bottom bar will always be displayed</string> <string name="reader_static_bar_on">The bottom bar will always be displayed</string>
<string name="reader_static_bar_off">The bottom bar can be shown through the floating button</string> <string name="reader_static_bar_off">The bottom bar can be shown through the floating button</string>
<string name="remove_source">Remove source</string> <string name="remove_source">Remove source</string>
<string name="cant_get_spouts_no_network">Can\'t get spouts list because of a network issue.</string>
</resources> </resources>

View File

@ -168,4 +168,5 @@
<string name="reader_static_bar_on">La barre sera affichée</string> <string name="reader_static_bar_on">La barre sera affichée</string>
<string name="reader_static_bar_off">La barre sera affichée grâce au bouton</string> <string name="reader_static_bar_off">La barre sera affichée grâce au bouton</string>
<string name="remove_source">Supprimer la source</string> <string name="remove_source">Supprimer la source</string>
<string name="cant_get_spouts_no_network">Can\'t get spouts list because of a network issue.</string>
</resources> </resources>

View File

@ -168,4 +168,5 @@
<string name="reader_static_bar_on">A barra inferior mostrarase sempre</string> <string name="reader_static_bar_on">A barra inferior mostrarase sempre</string>
<string name="reader_static_bar_off">A barra inferior pode mostrarse a través do botón flotante</string> <string name="reader_static_bar_off">A barra inferior pode mostrarse a través do botón flotante</string>
<string name="remove_source">Eliminar fonte</string> <string name="remove_source">Eliminar fonte</string>
<string name="cant_get_spouts_no_network">Can\'t get spouts list because of a network issue.</string>
</resources> </resources>

View File

@ -168,4 +168,5 @@
<string name="reader_static_bar_on">The bottom bar will always be displayed</string> <string name="reader_static_bar_on">The bottom bar will always be displayed</string>
<string name="reader_static_bar_off">The bottom bar can be shown through the floating button</string> <string name="reader_static_bar_off">The bottom bar can be shown through the floating button</string>
<string name="remove_source">Remove source</string> <string name="remove_source">Remove source</string>
<string name="cant_get_spouts_no_network">Can\'t get spouts list because of a network issue.</string>
</resources> </resources>

View File

@ -168,4 +168,5 @@
<string name="reader_static_bar_on">The bottom bar will always be displayed</string> <string name="reader_static_bar_on">The bottom bar will always be displayed</string>
<string name="reader_static_bar_off">The bottom bar can be shown through the floating button</string> <string name="reader_static_bar_off">The bottom bar can be shown through the floating button</string>
<string name="remove_source">Remove source</string> <string name="remove_source">Remove source</string>
<string name="cant_get_spouts_no_network">Can\'t get spouts list because of a network issue.</string>
</resources> </resources>

View File

@ -168,4 +168,5 @@
<string name="reader_static_bar_on">The bottom bar will always be displayed</string> <string name="reader_static_bar_on">The bottom bar will always be displayed</string>
<string name="reader_static_bar_off">The bottom bar can be shown through the floating button</string> <string name="reader_static_bar_off">The bottom bar can be shown through the floating button</string>
<string name="remove_source">Remove source</string> <string name="remove_source">Remove source</string>
<string name="cant_get_spouts_no_network">Can\'t get spouts list because of a network issue.</string>
</resources> </resources>

View File

@ -168,4 +168,5 @@
<string name="reader_static_bar_on">The bottom bar will always be displayed</string> <string name="reader_static_bar_on">The bottom bar will always be displayed</string>
<string name="reader_static_bar_off">The bottom bar can be shown through the floating button</string> <string name="reader_static_bar_off">The bottom bar can be shown through the floating button</string>
<string name="remove_source">Remove source</string> <string name="remove_source">Remove source</string>
<string name="cant_get_spouts_no_network">Can\'t get spouts list because of a network issue.</string>
</resources> </resources>

View File

@ -168,4 +168,5 @@
<string name="reader_static_bar_on">The bottom bar will always be displayed</string> <string name="reader_static_bar_on">The bottom bar will always be displayed</string>
<string name="reader_static_bar_off">The bottom bar can be shown through the floating button</string> <string name="reader_static_bar_off">The bottom bar can be shown through the floating button</string>
<string name="remove_source">Remove source</string> <string name="remove_source">Remove source</string>
<string name="cant_get_spouts_no_network">Can\'t get spouts list because of a network issue.</string>
</resources> </resources>

View File

@ -168,4 +168,5 @@
<string name="reader_static_bar_on">The bottom bar will always be displayed</string> <string name="reader_static_bar_on">The bottom bar will always be displayed</string>
<string name="reader_static_bar_off">The bottom bar can be shown through the floating button</string> <string name="reader_static_bar_off">The bottom bar can be shown through the floating button</string>
<string name="remove_source">Remove source</string> <string name="remove_source">Remove source</string>
<string name="cant_get_spouts_no_network">Can\'t get spouts list because of a network issue.</string>
</resources> </resources>

View File

@ -168,4 +168,5 @@
<string name="reader_static_bar_on">The bottom bar will always be displayed</string> <string name="reader_static_bar_on">The bottom bar will always be displayed</string>
<string name="reader_static_bar_off">The bottom bar can be shown through the floating button</string> <string name="reader_static_bar_off">The bottom bar can be shown through the floating button</string>
<string name="remove_source">Remove source</string> <string name="remove_source">Remove source</string>
<string name="cant_get_spouts_no_network">Can\'t get spouts list because of a network issue.</string>
</resources> </resources>

View File

@ -168,4 +168,5 @@
<string name="reader_static_bar_on">The bottom bar will always be displayed</string> <string name="reader_static_bar_on">The bottom bar will always be displayed</string>
<string name="reader_static_bar_off">The bottom bar can be shown through the floating button</string> <string name="reader_static_bar_off">The bottom bar can be shown through the floating button</string>
<string name="remove_source">Remove source</string> <string name="remove_source">Remove source</string>
<string name="cant_get_spouts_no_network">Can\'t get spouts list because of a network issue.</string>
</resources> </resources>

View File

@ -168,4 +168,5 @@
<string name="reader_static_bar_on">底部栏将始终显示</string> <string name="reader_static_bar_on">底部栏将始终显示</string>
<string name="reader_static_bar_off">底部栏可以通过浮动按钮显示</string> <string name="reader_static_bar_off">底部栏可以通过浮动按钮显示</string>
<string name="remove_source">删除源</string> <string name="remove_source">删除源</string>
<string name="cant_get_spouts_no_network">Can\'t get spouts list because of a network issue.</string>
</resources> </resources>

View File

@ -168,4 +168,5 @@
<string name="reader_static_bar_on">The bottom bar will always be displayed</string> <string name="reader_static_bar_on">The bottom bar will always be displayed</string>
<string name="reader_static_bar_off">The bottom bar can be shown through the floating button</string> <string name="reader_static_bar_off">The bottom bar can be shown through the floating button</string>
<string name="remove_source">Remove source</string> <string name="remove_source">Remove source</string>
<string name="cant_get_spouts_no_network">Can\'t get spouts list because of a network issue.</string>
</resources> </resources>

View File

@ -39,7 +39,8 @@
<string name="addStringNoUrl">"Log in to add sources."</string> <string name="addStringNoUrl">"Log in to add sources."</string>
<string name="cant_get_sources">"Can't get sources list."</string> <string name="cant_get_sources">"Can't get sources list."</string>
<string name="cant_create_source">"Can't create source."</string> <string name="cant_create_source">"Can't create source."</string>
<string name="cant_get_spouts">"Can't get spouts list."</string> <string name="cant_get_spouts_no_network">"Can't get spouts list because of a network issue."</string>
<string name="cant_get_spouts">"Can't get spouts list. There may ben an api issue."</string>
<string name="form_not_complete">"The form is not complete"</string> <string name="form_not_complete">"The form is not complete"</string>
<string name="pref_header_links">"Links"</string> <string name="pref_header_links">"Links"</string>
<string name="issue_tracker_link">"Issue Tracker"</string> <string name="issue_tracker_link">"Issue Tracker"</string>

View File

@ -1,7 +1,7 @@
package bou.amine.apps.readerforselfossv2.utils package bou.amine.apps.readerforselfossv2.utils
import android.text.Html import android.text.Html
import bou.amine.apps.readerforselfossv2.rest.SelfossModel import bou.amine.apps.readerforselfossv2.model.SelfossModel
actual fun SelfossModel.Item.getTitleDecoded(): String { actual fun SelfossModel.Item.getTitleDecoded(): String {
return Html.fromHtml(title).toString() return Html.fromHtml(title).toString()

View File

@ -0,0 +1,3 @@
package bou.amine.apps.readerforselfossv2.model
class NetworkUnavailableException : Exception()

View File

@ -1,4 +1,4 @@
package bou.amine.apps.readerforselfossv2.rest package bou.amine.apps.readerforselfossv2.model
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable

View File

@ -1,15 +1,11 @@
package bou.amine.apps.readerforselfossv2.repository package bou.amine.apps.readerforselfossv2.repository
import bou.amine.apps.readerforselfossv2.dao.ACTION import bou.amine.apps.readerforselfossv2.dao.*
import bou.amine.apps.readerforselfossv2.dao.ReaderForSelfossDB import bou.amine.apps.readerforselfossv2.model.NetworkUnavailableException
import bou.amine.apps.readerforselfossv2.dao.SOURCE
import bou.amine.apps.readerforselfossv2.dao.TAG
import bou.amine.apps.readerforselfossv2.rest.SelfossApi import bou.amine.apps.readerforselfossv2.rest.SelfossApi
import bou.amine.apps.readerforselfossv2.rest.SelfossModel import bou.amine.apps.readerforselfossv2.model.SelfossModel
import bou.amine.apps.readerforselfossv2.service.ApiDetailsService import bou.amine.apps.readerforselfossv2.service.ApiDetailsService
import bou.amine.apps.readerforselfossv2.utils.DateUtils import bou.amine.apps.readerforselfossv2.utils.*
import bou.amine.apps.readerforselfossv2.utils.ItemType
import bou.amine.apps.readerforselfossv2.utils.toEntity
import com.github.ln_12.library.ConnectivityStatus import com.github.ln_12.library.ConnectivityStatus
import com.russhwolf.settings.Settings import com.russhwolf.settings.Settings
import io.github.aakira.napier.Napier import io.github.aakira.napier.Napier
@ -17,7 +13,7 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
class Repository(private val api: SelfossApi, private val apiDetails: ApiDetailsService, val connectivityStatus: ConnectivityStatus, private val db: ReaderForSelfossDB) { class Repository(private val api: SelfossApi, private val apiDetails: ApiDetailsService, private val connectivityStatus: ConnectivityStatus, private val db: ReaderForSelfossDB) {
val settings = Settings() val settings = Settings()
var items = ArrayList<SelfossModel.Item>() var items = ArrayList<SelfossModel.Item>()
@ -67,11 +63,14 @@ class Repository(private val api: SelfossApi, private val apiDetails: ApiDetails
null null
) )
} else { } else {
// TODO: Get items from the database if (itemsCaching) {
fetchedItems = getDBItems().map { it.toView() }
}
} }
if (fetchedItems != null) { if (fetchedItems != null) {
items = ArrayList(fetchedItems) items = ArrayList(fetchedItems)
sortItems()
} }
return items return items
} }
@ -89,17 +88,16 @@ class Repository(private val api: SelfossApi, private val apiDetails: ApiDetails
searchFilter, searchFilter,
null null
) )
} else { } // When using the db cache, we load everything the first time, so there should be nothing more to load.
// TODO: Get items from the database
}
if (fetchedItems != null) { if (fetchedItems != null) {
appendItems(fetchedItems) items.addAll(fetchedItems)
sortItems()
} }
return items return items
} }
suspend fun allItems(itemType: ItemType): List<SelfossModel.Item>? { suspend fun getMaxItemsForBackground(itemType: ItemType): List<SelfossModel.Item>? {
return if (isNetworkAvailable()) { return if (isNetworkAvailable()) {
api.getItems( api.getItems(
itemType.type, itemType.type,
@ -111,21 +109,11 @@ class Repository(private val api: SelfossApi, private val apiDetails: ApiDetails
null null
) )
} else { } else {
// TODO: Provide an error message emptyList()
null
} }
} }
private fun appendItems(fetchedItems: List<SelfossModel.Item>) { private fun sortItems() {
// TODO: Store in DB if enabled by user
val fetchedIDS = fetchedItems.map { it.id }
val tmpItems = ArrayList(items.filterNot { it.id in fetchedIDS })
tmpItems.addAll(fetchedItems)
sortItems(tmpItems)
items = tmpItems
}
private fun sortItems(items: ArrayList<SelfossModel.Item>) {
items.sortByDescending { dateUtils.parseDate(it.datetime) } items.sortByDescending { dateUtils.parseDate(it.datetime) }
} }
@ -140,38 +128,37 @@ class Repository(private val api: SelfossApi, private val apiDetails: ApiDetails
success = true success = true
} }
} else { } else {
// TODO: Compute badges from database // TODO: do this differently, because it's not efficient
val dbItems = getDBItems()
badgeUnread = dbItems.filter { item -> item.unread }.size
badgeStarred = dbItems.filter { item -> item.starred }.size
badgeAll = items.size
} }
return success return success
} }
suspend fun getTags(): List<SelfossModel.Tag>? { suspend fun getTags(): List<SelfossModel.Tag>? {
// TODO: Store in DB
return if (isNetworkAvailable()) { return if (isNetworkAvailable()) {
api.tags() api.tags()
} else { } else {
// TODO: Compute from database getDBTags().map { it.toView() }
null
} }
} }
suspend fun getSpouts(): Map<String, SelfossModel.Spout>? { suspend fun getSpouts(): Map<String, SelfossModel.Spout>? {
// TODO: Store in DB
return if (isNetworkAvailable()) { return if (isNetworkAvailable()) {
api.spouts() api.spouts()
} else { } else {
// TODO: Compute from database throw NetworkUnavailableException()
null
} }
} }
suspend fun getSources(): ArrayList<SelfossModel.Source>? { suspend fun getSources(): ArrayList<SelfossModel.Source>? {
// TODO: Store in DB
return if (isNetworkAvailable()) { return if (isNetworkAvailable()) {
api.sources() api.sources()
} else { } else {
// TODO: Compute from database ArrayList(getDBSources().map { it.toView() })
null
} }
} }
@ -184,8 +171,14 @@ class Repository(private val api: SelfossApi, private val apiDetails: ApiDetails
return success return success
} }
suspend fun markAsReadById(id: Int): Boolean = suspend fun markAsReadById(id: Int): Boolean {
isNetworkAvailable() && api.markAsRead(id.toString())?.isSuccess == true return if (isNetworkAvailable()) {
api.markAsRead(id.toString())?.isSuccess == true
} else {
insertDBAction(id.toString(), read = true)
true
}
}
suspend fun unmarkAsRead(item: SelfossModel.Item): Boolean { suspend fun unmarkAsRead(item: SelfossModel.Item): Boolean {
@ -197,8 +190,14 @@ class Repository(private val api: SelfossApi, private val apiDetails: ApiDetails
return success return success
} }
suspend fun unmarkAsReadById(id: Int): Boolean = suspend fun unmarkAsReadById(id: Int): Boolean {
isNetworkAvailable() && api.unmarkAsRead(id.toString())?.isSuccess == true return if (isNetworkAvailable()) {
api.unmarkAsRead(id.toString())?.isSuccess == true
} else {
insertDBAction(id.toString(), unread = true)
true
}
}
suspend fun starr(item: SelfossModel.Item): Boolean { suspend fun starr(item: SelfossModel.Item): Boolean {
val success = starrById(item.id) val success = starrById(item.id)
@ -209,8 +208,14 @@ class Repository(private val api: SelfossApi, private val apiDetails: ApiDetails
return success return success
} }
suspend fun starrById(id: Int): Boolean = suspend fun starrById(id: Int): Boolean {
isNetworkAvailable() && api.starr(id.toString())?.isSuccess == true return if (isNetworkAvailable()) {
api.starr(id.toString())?.isSuccess == true
} else {
insertDBAction(id.toString(), starred = true)
true
}
}
suspend fun unstarr(item: SelfossModel.Item): Boolean { suspend fun unstarr(item: SelfossModel.Item): Boolean {
val success = unstarrById(item.id) val success = unstarrById(item.id)
@ -221,9 +226,14 @@ class Repository(private val api: SelfossApi, private val apiDetails: ApiDetails
return success return success
} }
suspend fun unstarrById(id: Int): Boolean = suspend fun unstarrById(id: Int): Boolean {
isNetworkAvailable() && api.unstarr(id.toString())?.isSuccess == true return if (isNetworkAvailable()) {
api.unstarr(id.toString())?.isSuccess == true
} else {
insertDBAction(id.toString(), starred = true)
true
}
}
suspend fun markAllAsRead(items: ArrayList<SelfossModel.Item>): Boolean { suspend fun markAllAsRead(items: ArrayList<SelfossModel.Item>): Boolean {
var success = false var success = false
@ -238,35 +248,47 @@ class Repository(private val api: SelfossApi, private val apiDetails: ApiDetails
} }
private fun markAsReadLocally(item: SelfossModel.Item) { private fun markAsReadLocally(item: SelfossModel.Item) {
// TODO: Mark also in the database
if (item.unread) { if (item.unread) {
item.unread = false item.unread = false
badgeUnread -= 1 badgeUnread -= 1
} }
CoroutineScope(Dispatchers.Main).launch {
updateDBItem(item)
}
} }
private fun unmarkAsReadLocally(item: SelfossModel.Item) { private fun unmarkAsReadLocally(item: SelfossModel.Item) {
// TODO: Mark also in the database
if (!item.unread) { if (!item.unread) {
item.unread = true item.unread = true
badgeUnread += 1 badgeUnread += 1
} }
CoroutineScope(Dispatchers.Main).launch {
updateDBItem(item)
}
} }
private fun starrLocally(item: SelfossModel.Item) { private fun starrLocally(item: SelfossModel.Item) {
// TODO: Mark also in the database
if (!item.starred) { if (!item.starred) {
item.starred = true item.starred = true
badgeStarred += 1 badgeStarred += 1
} }
CoroutineScope(Dispatchers.Main).launch {
updateDBItem(item)
}
} }
private fun unstarrLocally(item: SelfossModel.Item) { private fun unstarrLocally(item: SelfossModel.Item) {
// TODO: Mark also in the database
if (item.starred) { if (item.starred) {
item.starred = false item.starred = false
badgeStarred -= 1 badgeStarred -= 1
} }
CoroutineScope(Dispatchers.Main).launch {
updateDBItem(item)
}
} }
suspend fun createSource( suspend fun createSource(
@ -292,7 +314,6 @@ class Repository(private val api: SelfossApi, private val apiDetails: ApiDetails
} }
suspend fun deleteSource(id: Int): Boolean { suspend fun deleteSource(id: Int): Boolean {
// TODO: Store in DB
var success = false var success = false
if (isNetworkAvailable()) { if (isNetworkAvailable()) {
val response = api.deleteSource(id) val response = api.deleteSource(id)
@ -376,4 +397,20 @@ class Repository(private val api: SelfossApi, private val apiDetails: ApiDetails
} }
} }
} }
private fun insertDBItems(items: List<SelfossModel.Item>) {
db.itemsQueries.transaction {
items.forEach { item ->
db.itemsQueries.insertItem(item.toEntity())
}
}
}
private fun getDBItems(): List<ITEM> = db.itemsQueries.items().executeAsList()
private fun insertDBAction(articleid: String, read: Boolean = false, unread: Boolean = false, starred: Boolean = false, unstarred: Boolean = false) =
db.actionsQueries.insertAction(articleid, read, unread, starred, unstarred)
private fun updateDBItem(item: SelfossModel.Item) =
db.itemsQueries.updateItem(item.datetime, item.getTitleDecoded(), item.content, item.unread, item.starred, item.thumbnail, item.icon, item.link, item.sourcetitle, item.tags.joinToString(","), item.id.toString())
} }

View File

@ -1,5 +1,6 @@
package bou.amine.apps.readerforselfossv2.rest package bou.amine.apps.readerforselfossv2.rest
import bou.amine.apps.readerforselfossv2.model.SelfossModel
import bou.amine.apps.readerforselfossv2.service.ApiDetailsService import bou.amine.apps.readerforselfossv2.service.ApiDetailsService
import io.ktor.client.* import io.ktor.client.*
import io.ktor.client.call.* import io.ktor.client.call.*

View File

@ -1,6 +1,6 @@
package bou.amine.apps.readerforselfossv2.utils package bou.amine.apps.readerforselfossv2.utils
import bou.amine.apps.readerforselfossv2.rest.SelfossModel import bou.amine.apps.readerforselfossv2.model.SelfossModel
fun SelfossModel.Item.parseDate(dateUtils: DateUtils): Long = fun SelfossModel.Item.parseDate(dateUtils: DateUtils): Long =

View File

@ -3,7 +3,7 @@ package bou.amine.apps.readerforselfossv2.utils
import bou.amine.apps.readerforselfossv2.dao.ITEM import bou.amine.apps.readerforselfossv2.dao.ITEM
import bou.amine.apps.readerforselfossv2.dao.SOURCE import bou.amine.apps.readerforselfossv2.dao.SOURCE
import bou.amine.apps.readerforselfossv2.dao.TAG import bou.amine.apps.readerforselfossv2.dao.TAG
import bou.amine.apps.readerforselfossv2.rest.SelfossModel import bou.amine.apps.readerforselfossv2.model.SelfossModel
fun TAG.toView(): SelfossModel.Tag = fun TAG.toView(): SelfossModel.Tag =
SelfossModel.Tag( SelfossModel.Tag(

View File

@ -1,6 +1,6 @@
package bou.amine.apps.readerforselfossv2.utils package bou.amine.apps.readerforselfossv2.utils
import bou.amine.apps.readerforselfossv2.rest.SelfossModel import bou.amine.apps.readerforselfossv2.model.SelfossModel
expect fun SelfossModel.Source.getTitleDecoded(): String expect fun SelfossModel.Source.getTitleDecoded(): String
expect fun SelfossModel.Item.getTitleDecoded(): String expect fun SelfossModel.Item.getTitleDecoded(): String

View File

@ -1,6 +1,6 @@
package bou.amine.apps.readerforselfossv2.utils package bou.amine.apps.readerforselfossv2.utils
import bou.amine.apps.readerforselfossv2.rest.SelfossModel import bou.amine.apps.readerforselfossv2.model.SelfossModel
actual fun SelfossModel.Item.getTitleDecoded(): String { actual fun SelfossModel.Item.getTitleDecoded(): String {
TODO("Not yet implemented") TODO("Not yet implemented")

View File

@ -1,6 +1,6 @@
package bou.amine.apps.readerforselfossv2.utils package bou.amine.apps.readerforselfossv2.utils
import bou.amine.apps.readerforselfossv2.rest.SelfossModel import bou.amine.apps.readerforselfossv2.model.SelfossModel
actual fun SelfossModel.Item.getTitleDecoded(): String { actual fun SelfossModel.Item.getTitleDecoded(): String {
TODO("Not yet implemented") TODO("Not yet implemented")