forked from Louvorg/ReaderForSelfoss-multiplatform
Compare commits
37
Commits
15ec0f2d26
...
v122102881
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8b0bbe71c9 | ||
|
|
8bfe14c019 | ||
|
|
208babbce3 | ||
|
|
02098a7aa9 | ||
|
|
d0a982f385 | ||
|
|
1d1c121aab | ||
|
|
fe12819163 | ||
|
|
023a30c008 | ||
|
|
a2862a2587 | ||
|
|
054e936657 | ||
|
|
1d2e5069b8 | ||
|
|
a147646743 | ||
|
|
32e7fc0038 | ||
|
|
c15bf44032 | ||
|
|
0bcd55bd4e | ||
|
|
ebef0b3511 | ||
|
|
713ceb05bf | ||
|
|
dc8381b661 | ||
|
|
b5b820c64b | ||
|
|
f7055626d9 | ||
|
|
6ec3e96909 | ||
|
|
22da30eaa8 | ||
|
|
79fd115f5e | ||
|
|
8dc3d319cd | ||
|
|
27bb056397 | ||
|
|
f9ba13dc32 | ||
|
|
6f60ef4346 | ||
|
|
28b950f467 | ||
|
|
a9c7ec3dc1 | ||
|
|
920d4ac1ef | ||
|
|
0e96d313ec | ||
|
|
7211fdb1a3 | ||
|
|
381d6acc82 | ||
|
|
d311c2cdeb | ||
|
|
219cae5d74 | ||
|
|
2968aee309 | ||
|
|
6cb4b35c93 |
No files matched your search
+1
-11
@@ -3,23 +3,13 @@ type: docker
|
||||
name: test
|
||||
|
||||
steps:
|
||||
- name: Anylyse
|
||||
- name: AnylyseBuildTest
|
||||
image: mingc/android-build-box:latest
|
||||
failure: ignore
|
||||
detach: true
|
||||
commands:
|
||||
- echo "---------------------------------------------------------"
|
||||
- echo "Analysing..."
|
||||
- ./gradlew sonarqube -Dsonar.projectKey=RFS2 -Dsonar.host.url=$SONAR_HOST_URL -Dsonar.login=$SONAR_LOGIN -PignoreGitVersion=true -P appLoginUrl="\"URL\"" -P appLoginUsername="\"LOGIN\"" -P appLoginPassword="\"PASS\""
|
||||
- echo "---------------------------------------------------------"
|
||||
environment:
|
||||
SONAR_HOST_URL:
|
||||
from_secret: sonarScannerHostUrl
|
||||
SONAR_LOGIN:
|
||||
from_secret: sonarScannerLogin
|
||||
- name: BuildAndTest
|
||||
image: mingc/android-build-box:latest
|
||||
commands:
|
||||
- echo "Building..."
|
||||
- ./gradlew :androidApp:build -PignoreGitVersion=true -P appLoginUrl="\"URL\"" -P appLoginUsername="\"LOGIN\"" -P appLoginPassword="\"PASS\"" -P pushCache=false
|
||||
- echo "---------------------------------------------------------"
|
||||
|
||||
+11
-28
@@ -15,9 +15,6 @@ import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.appcompat.app.ActionBarDrawerToggle
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.appcompat.app.AppCompatDelegate
|
||||
import androidx.appcompat.app.AppCompatDelegate.MODE_NIGHT_NO
|
||||
import androidx.appcompat.app.AppCompatDelegate.MODE_NIGHT_YES
|
||||
import androidx.appcompat.widget.SearchView
|
||||
import androidx.core.view.doOnNextLayout
|
||||
import androidx.drawerlayout.widget.DrawerLayout
|
||||
@@ -98,8 +95,6 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
||||
private val repository : Repository by instance()
|
||||
private val appSettingsService : AppSettingsService by instance()
|
||||
|
||||
data class DrawerData(val tags: List<SelfossModel.Tag>?, val sources: List<SelfossModel.Source>?)
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
binding = ActivityHomeBinding.inflate(layoutInflater)
|
||||
@@ -352,27 +347,15 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
||||
)
|
||||
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
val drawerData = DrawerData(repository.getDBTags().map { it.toView() },
|
||||
repository.getDBSources().map { it.toView() })
|
||||
val tags = repository.getTags()
|
||||
val sources = repository.getSources()
|
||||
runOnUiThread {
|
||||
// Only refresh if there is no data in the DB, or if the `UpdateSources` setting is enabled
|
||||
if (drawerData.sources?.isEmpty() == true || appSettingsService.isUpdateSourcesEnabled()) {
|
||||
drawerApiCalls(drawerData)
|
||||
} else {
|
||||
handleDrawerData(drawerData, loadedFromCache = true)
|
||||
}
|
||||
handleDrawerData(tags, sources)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun drawerApiCalls(drawerData: DrawerData) {
|
||||
CoroutineScope(Dispatchers.Main).launch {
|
||||
val apiDrawerData = DrawerData(repository.getTags(), repository.getSources())
|
||||
handleDrawerData(if (drawerData != apiDrawerData) apiDrawerData else drawerData)
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleDrawerData(drawerData: DrawerData, loadedFromCache: Boolean = false) {
|
||||
private fun handleDrawerData(tags: List<SelfossModel.Tag>, sources: List<SelfossModel.Source>) {
|
||||
binding.mainDrawer.itemAdapter.clear()
|
||||
|
||||
// Filters title with clear action
|
||||
@@ -386,24 +369,24 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
||||
}
|
||||
|
||||
// Hidden tags
|
||||
if (drawerData.tags != null && drawerData.tags.isNotEmpty() && appSettingsService.getHiddenTags().isNotEmpty()) {
|
||||
if (tags.isNotEmpty() && appSettingsService.getHiddenTags().isNotEmpty()) {
|
||||
secondaryItem(
|
||||
withDivider = true,
|
||||
R.string.drawer_item_hidden_tags,
|
||||
DRAWER_ID_HIDDEN_TAGS
|
||||
)
|
||||
handleHiddenTags(drawerData.tags)
|
||||
handleHiddenTags(tags)
|
||||
}
|
||||
|
||||
// Tags
|
||||
secondaryItem(withDivider = true, R.string.drawer_item_tags, DRAWER_ID_TAGS)
|
||||
if (drawerData.tags == null && !loadedFromCache) {
|
||||
if (tags.isEmpty()) {
|
||||
binding.mainDrawer.itemAdapter.add(
|
||||
SecondaryDrawerItem()
|
||||
.apply { nameRes = R.string.drawer_error_loading_tags; isSelectable = false }
|
||||
)
|
||||
} else {
|
||||
handleTags(drawerData.tags!!)
|
||||
handleTags(tags)
|
||||
}
|
||||
|
||||
// Sources
|
||||
@@ -411,15 +394,15 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
||||
startActivity(Intent(v!!.context, SourcesActivity::class.java))
|
||||
false
|
||||
}
|
||||
if (drawerData.sources == null && !loadedFromCache) {
|
||||
if (sources.isEmpty()) {
|
||||
binding.mainDrawer.itemAdapter.add(
|
||||
SecondaryDrawerItem().apply {
|
||||
nameRes = R.string.drawer_error_loading_tags
|
||||
nameRes = R.string.drawer_error_loading_sources
|
||||
isSelectable = false
|
||||
}
|
||||
)
|
||||
} else {
|
||||
handleSources(drawerData.sources!!)
|
||||
handleSources(sources)
|
||||
}
|
||||
|
||||
// About action
|
||||
|
||||
@@ -163,7 +163,6 @@ class LoginActivity : AppCompatActivity(), DIAware {
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
val result = repository.login()
|
||||
if (result) {
|
||||
repository.updateApiVersion()
|
||||
goToMain()
|
||||
} else {
|
||||
CoroutineScope(Dispatchers.Main).launch {
|
||||
|
||||
@@ -75,7 +75,6 @@ class MyApp : MultiDexApplication(), DIAware {
|
||||
).show()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun handleNotificationChannels() {
|
||||
|
||||
+13
-14
@@ -28,7 +28,7 @@ abstract class ItemsAdapter<VH : RecyclerView.ViewHolder?> : RecyclerView.Adapte
|
||||
updateItems(this.items)
|
||||
}
|
||||
|
||||
private fun unmarkSnackbar(position: Int) {
|
||||
private fun unmarkSnackbar(item: SelfossModel.Item, position: Int) {
|
||||
val s = Snackbar
|
||||
.make(
|
||||
app.findViewById(R.id.coordLayout),
|
||||
@@ -37,7 +37,7 @@ abstract class ItemsAdapter<VH : RecyclerView.ViewHolder?> : RecyclerView.Adapte
|
||||
)
|
||||
.setAction(R.string.undo_string) {
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
unreadItemAtIndex(position, false)
|
||||
unreadItemAtIndex(item, position, false)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ abstract class ItemsAdapter<VH : RecyclerView.ViewHolder?> : RecyclerView.Adapte
|
||||
s.show()
|
||||
}
|
||||
|
||||
private fun markSnackbar(position: Int) {
|
||||
private fun markSnackbar(item: SelfossModel.Item, position: Int) {
|
||||
val s = Snackbar
|
||||
.make(
|
||||
app.findViewById(R.id.coordLayout),
|
||||
@@ -55,7 +55,7 @@ abstract class ItemsAdapter<VH : RecyclerView.ViewHolder?> : RecyclerView.Adapte
|
||||
Snackbar.LENGTH_LONG
|
||||
)
|
||||
.setAction(R.string.undo_string) {
|
||||
readItemAtIndex(position)
|
||||
readItemAtIndex(item, position, false)
|
||||
}
|
||||
|
||||
val view = s.view
|
||||
@@ -66,37 +66,36 @@ abstract class ItemsAdapter<VH : RecyclerView.ViewHolder?> : RecyclerView.Adapte
|
||||
|
||||
fun handleItemAtIndex(position: Int) {
|
||||
if (items[position].unread) {
|
||||
readItemAtIndex(position)
|
||||
readItemAtIndex(items[position], position)
|
||||
} else {
|
||||
unreadItemAtIndex(position)
|
||||
unreadItemAtIndex(items[position], position)
|
||||
}
|
||||
}
|
||||
|
||||
private fun readItemAtIndex(position: Int, showSnackbar: Boolean = true) {
|
||||
val i = items[position]
|
||||
private fun readItemAtIndex(item: SelfossModel.Item, position: Int, showSnackbar: Boolean = true) {
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
repository.markAsRead(i)
|
||||
repository.markAsRead(item)
|
||||
}
|
||||
if (repository.displayedItems == ItemType.UNREAD) {
|
||||
items.remove(i)
|
||||
items.remove(item)
|
||||
notifyItemRemoved(position)
|
||||
updateItems(items)
|
||||
} else {
|
||||
notifyItemChanged(position)
|
||||
}
|
||||
if (showSnackbar) {
|
||||
unmarkSnackbar(position)
|
||||
unmarkSnackbar(item, position)
|
||||
}
|
||||
}
|
||||
|
||||
private fun unreadItemAtIndex(position: Int, showSnackbar: Boolean = true) {
|
||||
private fun unreadItemAtIndex(item: SelfossModel.Item, position: Int, showSnackbar: Boolean = true) {
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
repository.unmarkAsRead(items[position])
|
||||
repository.unmarkAsRead(item)
|
||||
|
||||
}
|
||||
notifyItemChanged(position)
|
||||
if (showSnackbar) {
|
||||
markSnackbar(position)
|
||||
markSnackbar(item, position)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+4
-2
@@ -52,11 +52,13 @@ override fun doWork(): Result {
|
||||
|
||||
repository.handleDBActions()
|
||||
|
||||
val apiItems = repository.tryToCacheItemsAndGetNewOnes()
|
||||
if (appSettingsService.isNotifyNewItemsEnabled()) {
|
||||
launch {
|
||||
handleNewItemsNotification(repository.tryToCacheItemsAndGetNewOnes(), notificationManager)
|
||||
handleNewItemsNotification(apiItems, notificationManager)
|
||||
}
|
||||
}
|
||||
apiItems.map { it.preloadImages(context) }
|
||||
}
|
||||
}
|
||||
return Result.success()
|
||||
@@ -66,6 +68,7 @@ override fun doWork(): Result {
|
||||
newItems: List<SelfossModel.Item>?,
|
||||
notificationManager: NotificationManager
|
||||
) {
|
||||
// TODO: Check if this coroutine is actually required
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
val apiItems = newItems.orEmpty()
|
||||
|
||||
@@ -102,7 +105,6 @@ override fun doWork(): Result {
|
||||
notificationManager.notify(2, newItemsNotification.build())
|
||||
}
|
||||
}
|
||||
apiItems.map { it.preloadImages(context) }
|
||||
Timer("", false).schedule(4000) {
|
||||
notificationManager.cancel(1)
|
||||
}
|
||||
|
||||
-1
@@ -249,7 +249,6 @@ class ArticleFragment : Fragment(), DIAware {
|
||||
private fun getContentFromMercury() {
|
||||
if (repository.isNetworkAvailable()) {
|
||||
binding.progressBar.visibility = View.VISIBLE
|
||||
// TODO: The api should be accessed through the repository
|
||||
val parser = MercuryApi()
|
||||
|
||||
parser.parseUrl(url).enqueue(
|
||||
|
||||
@@ -132,4 +132,5 @@
|
||||
<string name="mode_dark">Dark mode</string>
|
||||
<string name="mode_system">Follow the system setting</string>
|
||||
<string name="mode_light">Light mode</string>
|
||||
<string name="drawer_error_loading_sources">Error loading sources…</string>
|
||||
</resources>
|
||||
@@ -132,4 +132,5 @@
|
||||
<string name="mode_dark">Dark mode</string>
|
||||
<string name="mode_system">Follow the system setting</string>
|
||||
<string name="mode_light">Light mode</string>
|
||||
<string name="drawer_error_loading_sources">Error loading sources…</string>
|
||||
</resources>
|
||||
@@ -132,4 +132,5 @@
|
||||
<string name="mode_dark">Dark mode</string>
|
||||
<string name="mode_system">Follow the system setting</string>
|
||||
<string name="mode_light">Light mode</string>
|
||||
<string name="drawer_error_loading_sources">Error loading sources…</string>
|
||||
</resources>
|
||||
@@ -132,4 +132,5 @@
|
||||
<string name="mode_dark">Dark mode</string>
|
||||
<string name="mode_system">Follow the system setting</string>
|
||||
<string name="mode_light">Light mode</string>
|
||||
<string name="drawer_error_loading_sources">Error loading sources…</string>
|
||||
</resources>
|
||||
@@ -132,4 +132,5 @@
|
||||
<string name="mode_dark">Thème sombre</string>
|
||||
<string name="mode_system">Utiliser les paramètres système</string>
|
||||
<string name="mode_light">Thème clair</string>
|
||||
<string name="drawer_error_loading_sources">Error loading sources…</string>
|
||||
</resources>
|
||||
@@ -132,4 +132,5 @@
|
||||
<string name="mode_dark">Dark mode</string>
|
||||
<string name="mode_system">Follow the system setting</string>
|
||||
<string name="mode_light">Light mode</string>
|
||||
<string name="drawer_error_loading_sources">Error loading sources…</string>
|
||||
</resources>
|
||||
@@ -132,4 +132,5 @@
|
||||
<string name="mode_dark">Dark mode</string>
|
||||
<string name="mode_system">Follow the system setting</string>
|
||||
<string name="mode_light">Light mode</string>
|
||||
<string name="drawer_error_loading_sources">Error loading sources…</string>
|
||||
</resources>
|
||||
@@ -132,4 +132,5 @@
|
||||
<string name="mode_dark">Dark mode</string>
|
||||
<string name="mode_system">Follow the system setting</string>
|
||||
<string name="mode_light">Light mode</string>
|
||||
<string name="drawer_error_loading_sources">Error loading sources…</string>
|
||||
</resources>
|
||||
@@ -132,4 +132,5 @@
|
||||
<string name="mode_dark">Dark mode</string>
|
||||
<string name="mode_system">Follow the system setting</string>
|
||||
<string name="mode_light">Light mode</string>
|
||||
<string name="drawer_error_loading_sources">Error loading sources…</string>
|
||||
</resources>
|
||||
@@ -132,4 +132,5 @@
|
||||
<string name="mode_dark">Dark mode</string>
|
||||
<string name="mode_system">Follow the system setting</string>
|
||||
<string name="mode_light">Light mode</string>
|
||||
<string name="drawer_error_loading_sources">Error loading sources…</string>
|
||||
</resources>
|
||||
@@ -132,4 +132,5 @@
|
||||
<string name="mode_dark">Dark mode</string>
|
||||
<string name="mode_system">Follow the system setting</string>
|
||||
<string name="mode_light">Light mode</string>
|
||||
<string name="drawer_error_loading_sources">Error loading sources…</string>
|
||||
</resources>
|
||||
@@ -132,4 +132,5 @@
|
||||
<string name="mode_dark">Dark mode</string>
|
||||
<string name="mode_system">Follow the system setting</string>
|
||||
<string name="mode_light">Light mode</string>
|
||||
<string name="drawer_error_loading_sources">Error loading sources…</string>
|
||||
</resources>
|
||||
@@ -132,4 +132,5 @@
|
||||
<string name="mode_dark">Dark mode</string>
|
||||
<string name="mode_system">Follow the system setting</string>
|
||||
<string name="mode_light">Light mode</string>
|
||||
<string name="drawer_error_loading_sources">Error loading sources…</string>
|
||||
</resources>
|
||||
@@ -132,4 +132,5 @@
|
||||
<string name="mode_dark">Dark mode</string>
|
||||
<string name="mode_system">Follow the system setting</string>
|
||||
<string name="mode_light">Light mode</string>
|
||||
<string name="drawer_error_loading_sources">Error loading sources…</string>
|
||||
</resources>
|
||||
@@ -132,4 +132,5 @@
|
||||
<string name="mode_dark">深色模式</string>
|
||||
<string name="mode_system">遵循系统设置</string>
|
||||
<string name="mode_light">浅色模式</string>
|
||||
<string name="drawer_error_loading_sources">Error loading sources…</string>
|
||||
</resources>
|
||||
@@ -132,4 +132,5 @@
|
||||
<string name="mode_dark">Dark mode</string>
|
||||
<string name="mode_system">Follow the system setting</string>
|
||||
<string name="mode_light">Light mode</string>
|
||||
<string name="drawer_error_loading_sources">Error loading sources…</string>
|
||||
</resources>
|
||||
@@ -63,6 +63,7 @@
|
||||
<string name="card_height_off">Card height will be fixed</string>
|
||||
<string name="source_code">Source code</string>
|
||||
<string name="drawer_error_loading_tags">Error loading tags…</string>
|
||||
<string name="drawer_error_loading_sources">Error loading sources…</string>
|
||||
<string name="drawer_item_filters">Filters</string>
|
||||
<string name="drawer_action_clear">clear</string>
|
||||
<string name="drawer_item_tags">Tags</string>
|
||||
@@ -109,7 +110,7 @@
|
||||
<string name="pref_switch_periodic_refresh_on">Articles will periodically be synced</string>
|
||||
<string name="pref_periodic_refresh_minutes_title"><![CDATA[Sync interval ( >= 15 minutes)]]></string>
|
||||
<string name="pref_switch_refresh_when_charging">Only refresh when phone is charging</string>
|
||||
<string name="loading_notification_title">Loading ...</string>
|
||||
<string name="loading_notification_title">Loading …</string>
|
||||
<string name="loading_notification_text">Selfoss is syncing your articles</string>
|
||||
<string name="notification_channel_sync">Sync notification</string>
|
||||
<string name="new_items_channel_sync">New items notification</string>
|
||||
|
||||
+5
-1
@@ -138,7 +138,11 @@ class SelfossModel {
|
||||
object BooleanSerializer : KSerializer<Boolean> {
|
||||
override fun deserialize(decoder: Decoder): Boolean {
|
||||
val json = ((decoder as JsonDecoder).decodeJsonElement()).jsonPrimitive
|
||||
return json.booleanOrNull ?: json.int == 1
|
||||
return if (json.booleanOrNull != null) {
|
||||
json.boolean
|
||||
} else {
|
||||
json.int == 1
|
||||
}
|
||||
}
|
||||
|
||||
override val descriptor: SerialDescriptor
|
||||
|
||||
+46
-28
@@ -37,8 +37,12 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap
|
||||
var badgeStarred = 0
|
||||
set(value) {field = if (value < 0) { 0 } else { value } }
|
||||
|
||||
private var fetchedSources = false
|
||||
private var fetchedTags = false
|
||||
|
||||
init {
|
||||
// TODO: Dispatchers.IO not available in KMM, an alternative solution should be found
|
||||
connectivityStatus.start()
|
||||
runBlocking {
|
||||
updateApiVersion()
|
||||
dateUtils = DateUtils(appSettingsService)
|
||||
@@ -62,12 +66,19 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap
|
||||
} else {
|
||||
if (appSettingsService.isItemCachingEnabled()) {
|
||||
fromDB = true
|
||||
var dbItems = getDBItems().filter {
|
||||
displayedItems == ItemType.ALL ||
|
||||
(it.unread && displayedItems == ItemType.UNREAD) ||
|
||||
(it.starred && displayedItems == ItemType.STARRED)
|
||||
}
|
||||
if (tagFilter != null) {
|
||||
dbItems = dbItems.filter { it.tags.split(',').contains(tagFilter!!.tag) }
|
||||
}
|
||||
if (sourceFilter != null) {
|
||||
dbItems = dbItems.filter { it.sourcetitle == sourceFilter!!.title }
|
||||
}
|
||||
fetchedItems = SelfossModel.StatusAndData.succes(
|
||||
getDBItems().filter {
|
||||
displayedItems == ItemType.ALL ||
|
||||
(it.unread && displayedItems == ItemType.UNREAD) ||
|
||||
(it.starred && displayedItems == ItemType.STARRED)
|
||||
}.map { it.toView() }
|
||||
dbItems.map { it.toView() }
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -106,9 +117,9 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap
|
||||
val items = api.getItems(
|
||||
itemType.type,
|
||||
0,
|
||||
tagFilter?.tag,
|
||||
sourceFilter?.id?.toLong(),
|
||||
searchFilter,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
200
|
||||
)
|
||||
@@ -132,25 +143,32 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap
|
||||
badgeStarred = response.data.starred
|
||||
success = true
|
||||
}
|
||||
} else {
|
||||
} else if (appSettingsService.isItemCachingEnabled()) {
|
||||
// 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
|
||||
badgeAll = dbItems.size
|
||||
success = true
|
||||
}
|
||||
return success
|
||||
}
|
||||
|
||||
suspend fun getTags(): List<SelfossModel.Tag> {
|
||||
return if (isNetworkAvailable()) {
|
||||
val isDatabaseEnabled = appSettingsService.isItemCachingEnabled() || !appSettingsService.isUpdateSourcesEnabled()
|
||||
return if (isNetworkAvailable() && !fetchedTags) {
|
||||
val apiTags = api.tags()
|
||||
if (apiTags.success && apiTags.data != null && (appSettingsService.isItemCachingEnabled() || !appSettingsService.isUpdateSourcesEnabled())) {
|
||||
if (apiTags.success && apiTags.data != null && isDatabaseEnabled) {
|
||||
resetDBTagsWithData(apiTags.data)
|
||||
if (!appSettingsService.isUpdateSourcesEnabled()) {
|
||||
fetchedTags = true
|
||||
}
|
||||
}
|
||||
apiTags.data ?: emptyList()
|
||||
} else {
|
||||
} else if (isDatabaseEnabled) {
|
||||
getDBTags().map { it.toView() }
|
||||
} else {
|
||||
emptyList()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -168,15 +186,21 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun getSources(): ArrayList<SelfossModel.Source>? {
|
||||
return if (isNetworkAvailable()) {
|
||||
suspend fun getSources(): ArrayList<SelfossModel.Source> {
|
||||
val isDatabaseEnabled = appSettingsService.isItemCachingEnabled() || !appSettingsService.isUpdateSourcesEnabled()
|
||||
return if (isNetworkAvailable() && !fetchedSources) {
|
||||
val apiSources = api.sources()
|
||||
if (apiSources.success && apiSources.data != null && (appSettingsService.isItemCachingEnabled() || !appSettingsService.isUpdateSourcesEnabled())) {
|
||||
if (apiSources.success && apiSources.data != null && isDatabaseEnabled) {
|
||||
resetDBSourcesWithData(apiSources.data)
|
||||
if (!appSettingsService.isUpdateSourcesEnabled()) {
|
||||
fetchedSources = true
|
||||
}
|
||||
}
|
||||
apiSources.data
|
||||
} else {
|
||||
apiSources.data ?: ArrayList()
|
||||
} else if (isDatabaseEnabled) {
|
||||
ArrayList(getDBSources().map { it.toView() })
|
||||
} else {
|
||||
ArrayList()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -347,7 +371,7 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap
|
||||
|
||||
suspend fun updateRemote(): Boolean {
|
||||
return if (isNetworkAvailable()) {
|
||||
api.update().equals("finished")
|
||||
api.update().data.equals("finished")
|
||||
} else {
|
||||
false
|
||||
}
|
||||
@@ -375,8 +399,7 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap
|
||||
api.refreshLoginInformation()
|
||||
}
|
||||
|
||||
// TODO: This should be private
|
||||
suspend fun updateApiVersion() {
|
||||
private suspend fun updateApiVersion() {
|
||||
val apiMajorVersion = appSettingsService.getApiVersion()
|
||||
|
||||
if (isNetworkAvailable()) {
|
||||
@@ -387,8 +410,6 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: This should be private (since all api calls are made through the repository
|
||||
// no other entity needs to know about the connectivity status)
|
||||
fun isNetworkAvailable() = isConnectionAvailable.value && !offlineOverride
|
||||
|
||||
private fun getDBActions(): List<ACTION> =
|
||||
@@ -397,11 +418,9 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap
|
||||
private fun deleteDBAction(action: ACTION) =
|
||||
db.actionsQueries.deleteAction(action.id)
|
||||
|
||||
// TODO: This function should be private
|
||||
fun getDBTags(): List<TAG> = db.tagsQueries.tags().executeAsList()
|
||||
private fun getDBTags(): List<TAG> = db.tagsQueries.tags().executeAsList()
|
||||
|
||||
// TODO: This function should be private
|
||||
fun getDBSources(): List<SOURCE> = db.sourcesQueries.sources().executeAsList()
|
||||
private fun getDBSources(): List<SOURCE> = db.sourcesQueries.sources().executeAsList()
|
||||
|
||||
private fun resetDBTagsWithData(tagEntities: List<SelfossModel.Tag>) {
|
||||
db.tagsQueries.deleteAllTags()
|
||||
@@ -439,7 +458,6 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap
|
||||
private fun updateDBItem(item: SelfossModel.Item) =
|
||||
db.itemsQueries.updateItem(item.datetime, item.title.getHtmlDecoded(), item.content, item.unread, item.starred, item.thumbnail, item.icon, item.link, item.sourcetitle, item.tags.joinToString(","), item.id.toString())
|
||||
|
||||
|
||||
suspend fun tryToCacheItemsAndGetNewOnes(): List<SelfossModel.Item> {
|
||||
try {
|
||||
val newItems = getMaxItemsForBackground(ItemType.UNREAD)
|
||||
|
||||
@@ -65,6 +65,6 @@ fun SelfossModel.Item.toEntity(): ITEM =
|
||||
this.thumbnail,
|
||||
this.icon,
|
||||
this.link,
|
||||
this.title.getHtmlDecoded(),
|
||||
this.sourcetitle.getHtmlDecoded(),
|
||||
this.tags.joinToString(",")
|
||||
)
|
||||
+293
-102
@@ -17,7 +17,7 @@ import kotlin.test.*
|
||||
|
||||
class RepositoryTest() {
|
||||
private val connectivityStatus = mockk<ConnectivityStatus>()
|
||||
private val db = mockk<ReaderForSelfossDB>()
|
||||
private val db = mockk<ReaderForSelfossDB>(relaxed = true)
|
||||
private val appSettingsService = mockk<AppSettingsService>()
|
||||
private val api = mockk<SelfossApi>()
|
||||
|
||||
@@ -31,7 +31,7 @@ class RepositoryTest() {
|
||||
every { appSettingsService.getApiVersion() } returns 4
|
||||
every { appSettingsService.getBaseUrl() } returns "https://test.com/selfoss/"
|
||||
every { appSettingsService.isItemCachingEnabled() } returns false
|
||||
every { appSettingsService.isUpdateSourcesEnabled() } returns true
|
||||
every { appSettingsService.isUpdateSourcesEnabled() } returns false
|
||||
|
||||
every { connectivityStatus.isNetworkConnected } returns MutableStateFlow(true)
|
||||
|
||||
@@ -42,18 +42,16 @@ class RepositoryTest() {
|
||||
every { db.tagsQueries.deleteAllTags() } returns Unit
|
||||
every { db.tagsQueries.transaction(any(), any()) } returns Unit
|
||||
every { db.tagsQueries.insertTag(any()) } returns Unit
|
||||
|
||||
every { connectivityStatus.start() } returns Unit
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Instantiate repository`() {
|
||||
val success = try {
|
||||
Repository(api, appSettingsService, connectivityStatus, db)
|
||||
true
|
||||
} catch (e: Exception) {
|
||||
false
|
||||
}
|
||||
Repository(api, appSettingsService, connectivityStatus, db)
|
||||
|
||||
assertEquals(true, success)
|
||||
coVerify(exactly = 1) { api.version() }
|
||||
coVerify(exactly = 1) { api.stats() }
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -61,28 +59,23 @@ class RepositoryTest() {
|
||||
every { appSettingsService.getApiVersion() } returns -1
|
||||
every { connectivityStatus.isNetworkConnected } returns MutableStateFlow(false)
|
||||
|
||||
val success = try {
|
||||
Repository(api, appSettingsService, connectivityStatus, db)
|
||||
true
|
||||
} catch (e: Exception) {
|
||||
false
|
||||
}
|
||||
Repository(api, appSettingsService, connectivityStatus, db)
|
||||
|
||||
assertEquals(true, success)
|
||||
coVerify(exactly = 0) { api.version() }
|
||||
coVerify(exactly = 0) { api.stats() }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Instantiate repository with negative stats`() {
|
||||
coEvery { api.stats() } returns SelfossModel.StatusAndData(success = true, data = SelfossModel.Stats(-100, -50, -20))
|
||||
|
||||
val success = try {
|
||||
Repository(api, appSettingsService, connectivityStatus, db)
|
||||
true
|
||||
} catch (e: Exception) {
|
||||
false
|
||||
}
|
||||
val repository = Repository(api, appSettingsService, connectivityStatus, db)
|
||||
|
||||
assertEquals(true, success)
|
||||
assertEquals(0, repository.badgeAll)
|
||||
assertEquals(0, repository.badgeStarred)
|
||||
assertEquals(0, repository.badgeUnread)
|
||||
coVerify(exactly = 1) { api.version() }
|
||||
coVerify(exactly = 1) { api.stats() }
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -180,6 +173,60 @@ class RepositoryTest() {
|
||||
verify(atLeast = 1) { db.itemsQueries.items().executeAsList()}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Get newer items without connectivity and tag filter`() {
|
||||
val itemParameter1 = FakeItemParameters()
|
||||
val itemParameter2 = FakeItemParameters()
|
||||
val itemParameter3 = FakeItemParameters()
|
||||
itemParameter2.tags = "Test, Stuff"
|
||||
itemParameter2.id = "2"
|
||||
itemParameter3.tags = "Other, Tag"
|
||||
itemParameter3.id = "3"
|
||||
coEvery { db.itemsQueries.items().executeAsList() } returns generateTestDBItems(itemParameter1) +
|
||||
generateTestDBItems(itemParameter2) +
|
||||
generateTestDBItems(itemParameter3)
|
||||
|
||||
every { connectivityStatus.isNetworkConnected } returns MutableStateFlow(false)
|
||||
every { appSettingsService.isItemCachingEnabled() } returns true
|
||||
|
||||
val repository = Repository(api, appSettingsService, connectivityStatus, db)
|
||||
repository.tagFilter = SelfossModel.Tag("Test", "red", 3)
|
||||
runBlocking {
|
||||
repository.getNewerItems()
|
||||
}
|
||||
|
||||
assertSame(repository.items.size, 1)
|
||||
coVerify(exactly = 0) { api.getItems("unread", 0, null, null, null, null, any()) }
|
||||
verify(atLeast = 1) { db.itemsQueries.items().executeAsList()}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Get newer items without connectivity and source filter`() {
|
||||
val itemParameter1 = FakeItemParameters()
|
||||
val itemParameter2 = FakeItemParameters()
|
||||
val itemParameter3 = FakeItemParameters()
|
||||
itemParameter2.sourcetitle = "Test"
|
||||
itemParameter2.id = "2"
|
||||
itemParameter3.sourcetitle = "Other"
|
||||
itemParameter3.id = "3"
|
||||
coEvery { db.itemsQueries.items().executeAsList() } returns generateTestDBItems(itemParameter1) +
|
||||
generateTestDBItems(itemParameter2) +
|
||||
generateTestDBItems(itemParameter3)
|
||||
|
||||
every { connectivityStatus.isNetworkConnected } returns MutableStateFlow(false)
|
||||
every { appSettingsService.isItemCachingEnabled() } returns true
|
||||
|
||||
val repository = Repository(api, appSettingsService, connectivityStatus, db)
|
||||
repository.sourceFilter = SelfossModel.Source(1, "Test", listOf("tags"),"spouts\\rss\\fulltextrss", "", "b3aa8a664d08eb15d6ff1db2fa83e0d9.png")
|
||||
runBlocking {
|
||||
repository.getNewerItems()
|
||||
}
|
||||
|
||||
assertSame(repository.items.size, 1)
|
||||
coVerify(exactly = 0) { api.getItems("unread", 0, null, null, null, null, any()) }
|
||||
verify(atLeast = 1) { db.itemsQueries.items().executeAsList()}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Get older items`() {
|
||||
coEvery { api.getItems(any(), any(), any(), any(), any(), any(), any()) } returns
|
||||
@@ -267,24 +314,19 @@ class RepositoryTest() {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Reload badges with items caching`() {
|
||||
fun `Reload badges without connection`() {
|
||||
every { connectivityStatus.isNetworkConnected } returns MutableStateFlow(false)
|
||||
every { appSettingsService.isItemCachingEnabled() } returns true
|
||||
every { db.itemsQueries.items().executeAsList() } returns generateTestDBItems()
|
||||
|
||||
val itemParameter = FakeItemParameters()
|
||||
itemParameter.starred = true
|
||||
itemParameter.unread = false
|
||||
|
||||
var success = false
|
||||
|
||||
val repository = Repository(api, appSettingsService, connectivityStatus, db)
|
||||
repository.items = ArrayList(generateTestApiItem(itemParameter))
|
||||
runBlocking {
|
||||
success = repository.reloadBadges()
|
||||
}
|
||||
|
||||
assertSame(true, success)
|
||||
assertTrue(success)
|
||||
assertSame(1, repository.badgeAll)
|
||||
assertSame(1, repository.badgeUnread)
|
||||
assertSame(1, repository.badgeStarred)
|
||||
@@ -293,23 +335,19 @@ class RepositoryTest() {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Reload badges without items caching`() {
|
||||
fun `Reload badges without connection and items caching disabled`() {
|
||||
every { connectivityStatus.isNetworkConnected } returns MutableStateFlow(false)
|
||||
every { appSettingsService.isItemCachingEnabled() } returns false
|
||||
|
||||
val itemParameter = FakeItemParameters()
|
||||
itemParameter.starred = true
|
||||
itemParameter.unread = false
|
||||
every { appSettingsService.isUpdateSourcesEnabled() } returns true
|
||||
|
||||
var success = false
|
||||
|
||||
val repository = Repository(api, appSettingsService, connectivityStatus, db)
|
||||
repository.items = ArrayList(generateTestApiItem(itemParameter))
|
||||
runBlocking {
|
||||
success = repository.reloadBadges()
|
||||
}
|
||||
|
||||
assertSame(false, success)
|
||||
assertFalse(success)
|
||||
assertSame(0, repository.badgeAll)
|
||||
assertSame(0, repository.badgeUnread)
|
||||
assertSame(0, repository.badgeStarred)
|
||||
@@ -321,8 +359,13 @@ class RepositoryTest() {
|
||||
fun `Get tags`() {
|
||||
val tags = listOf(SelfossModel.Tag("test", "red", 6),
|
||||
SelfossModel.Tag("second", "yellow", 0))
|
||||
val tagsDB = listOf(TAG("test_DB", "red", 6),
|
||||
TAG("second_DB", "yellow", 0))
|
||||
|
||||
coEvery { api.tags() } returns SelfossModel.StatusAndData(success = true, data = tags)
|
||||
coEvery { db.tagsQueries.tags().executeAsList() } returns tagsDB
|
||||
every { appSettingsService.isUpdateSourcesEnabled() } returns true
|
||||
every { appSettingsService.isItemCachingEnabled() } returns true
|
||||
|
||||
val repository = Repository(api, appSettingsService, connectivityStatus, db)
|
||||
var testTags: List<SelfossModel.Tag>? = null
|
||||
@@ -331,7 +374,8 @@ class RepositoryTest() {
|
||||
}
|
||||
|
||||
assertSame(tags, testTags)
|
||||
verify(exactly = 0) { db.tagsQueries.tags().executeAsList() }
|
||||
assertNotSame(tagsDB.map { it.toView() }, testTags)
|
||||
coVerify(exactly = 1) { api.tags() }
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -344,20 +388,45 @@ class RepositoryTest() {
|
||||
coEvery { api.tags() } returns SelfossModel.StatusAndData(success = true, data = tags)
|
||||
coEvery { db.tagsQueries.tags().executeAsList() } returns tagsDB
|
||||
every { appSettingsService.isUpdateSourcesEnabled() } returns false
|
||||
every { appSettingsService.isItemCachingEnabled() } returns true
|
||||
|
||||
val repository = Repository(api, appSettingsService, connectivityStatus, db)
|
||||
var testTags: List<SelfossModel.Tag> = emptyList()
|
||||
runBlocking {
|
||||
testTags = repository.getTags()
|
||||
// Tags will be fetched from the database on the second call, thus testTags != tags
|
||||
testTags = repository.getTags()
|
||||
}
|
||||
|
||||
coVerify(exactly = 1) { api.tags() }
|
||||
assertNotSame(tags, testTags)
|
||||
assertContentEquals(tagsDB.map { it.toView() }, testTags)
|
||||
coVerify(exactly = 1) { api.tags() }
|
||||
verify(atLeast = 1) { db.tagsQueries.tags().executeAsList() }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Get tags with items caching disabled`() {
|
||||
val tags = listOf(SelfossModel.Tag("test", "red", 6),
|
||||
SelfossModel.Tag("second", "yellow", 0))
|
||||
val tagsDB = listOf(TAG("test_DB", "red", 6),
|
||||
TAG("second_DB", "yellow", 0))
|
||||
|
||||
coEvery { api.tags() } returns SelfossModel.StatusAndData(success = true, data = tags)
|
||||
coEvery { db.tagsQueries.tags().executeAsList() } returns tagsDB
|
||||
every { appSettingsService.isUpdateSourcesEnabled() } returns true
|
||||
every { appSettingsService.isItemCachingEnabled() } returns false
|
||||
|
||||
val repository = Repository(api, appSettingsService, connectivityStatus, db)
|
||||
var testTags: List<SelfossModel.Tag> = emptyList()
|
||||
runBlocking {
|
||||
testTags = repository.getTags()
|
||||
}
|
||||
|
||||
assertSame(tags, testTags)
|
||||
coVerify(exactly = 1) { api.tags() }
|
||||
verify(exactly = 0) { db.tagsQueries.tags().executeAsList() }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Get tags with sources update and items caching disabled`() {
|
||||
val tags = listOf(SelfossModel.Tag("test", "red", 6),
|
||||
@@ -374,11 +443,13 @@ class RepositoryTest() {
|
||||
var testTags: List<SelfossModel.Tag> = emptyList()
|
||||
runBlocking {
|
||||
testTags = repository.getTags()
|
||||
testTags = repository.getTags()
|
||||
}
|
||||
|
||||
assertSame(emptyList(), testTags)
|
||||
coVerify(exactly = 0) { api.tags() }
|
||||
verify(exactly = 0) { db.tagsQueries.tags().executeAsList() }
|
||||
coVerify(exactly = 1) { api.tags() }
|
||||
assertNotSame(tags, testTags)
|
||||
assertContentEquals(tagsDB.map { it.toView() }, testTags)
|
||||
verify(atLeast = 1) { db.tagsQueries.tags().executeAsList() }
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -391,6 +462,8 @@ class RepositoryTest() {
|
||||
coEvery { api.tags() } returns SelfossModel.StatusAndData(success = true, data = tags)
|
||||
coEvery { db.tagsQueries.tags().executeAsList() } returns tagsDB
|
||||
every { connectivityStatus.isNetworkConnected } returns MutableStateFlow(false)
|
||||
every { appSettingsService.isUpdateSourcesEnabled() } returns true
|
||||
every { appSettingsService.isItemCachingEnabled() } returns true
|
||||
|
||||
val repository = Repository(api, appSettingsService, connectivityStatus, db)
|
||||
var testTags: List<SelfossModel.Tag> = emptyList()
|
||||
@@ -399,7 +472,7 @@ class RepositoryTest() {
|
||||
}
|
||||
|
||||
assertNotSame(tags, testTags)
|
||||
assertSame(tagsDB.first().name, testTags.first().tag)
|
||||
assertContentEquals(tagsDB.map { it.toView() }, testTags)
|
||||
coVerify(exactly = 0) { api.tags() }
|
||||
verify(atLeast = 1) { db.tagsQueries.tags().executeAsList() }
|
||||
}
|
||||
@@ -415,6 +488,7 @@ class RepositoryTest() {
|
||||
coEvery { db.tagsQueries.tags().executeAsList() } returns tagsDB
|
||||
every { connectivityStatus.isNetworkConnected } returns MutableStateFlow(false)
|
||||
every { appSettingsService.isItemCachingEnabled() } returns false
|
||||
every { appSettingsService.isUpdateSourcesEnabled() } returns true
|
||||
|
||||
val repository = Repository(api, appSettingsService, connectivityStatus, db)
|
||||
var testTags: List<SelfossModel.Tag> = emptyList()
|
||||
@@ -422,9 +496,9 @@ class RepositoryTest() {
|
||||
testTags = repository.getTags()
|
||||
}
|
||||
|
||||
assertContentEquals(tagsDB.map { it.toView() }, testTags)
|
||||
assertSame(emptyList(), testTags)
|
||||
coVerify(exactly = 0) { api.tags() }
|
||||
verify(atLeast = 1) { db.tagsQueries.tags().executeAsList() }
|
||||
verify(exactly = 0) { db.tagsQueries.tags().executeAsList() }
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -438,6 +512,7 @@ class RepositoryTest() {
|
||||
coEvery { db.tagsQueries.tags().executeAsList() } returns tagsDB
|
||||
every { connectivityStatus.isNetworkConnected } returns MutableStateFlow(false)
|
||||
every { appSettingsService.isUpdateSourcesEnabled() } returns false
|
||||
every { appSettingsService.isItemCachingEnabled() } returns true
|
||||
|
||||
val repository = Repository(api, appSettingsService, connectivityStatus, db)
|
||||
var testTags: List<SelfossModel.Tag> = emptyList()
|
||||
@@ -452,30 +527,36 @@ class RepositoryTest() {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `get sources`() {
|
||||
val sources = arrayListOf(SelfossModel.Source(1, "First source", listOf("Test", "second"),"spouts\\rss\\fulltextrss", "", "d8c92cdb1ef119ea85c4b9205c879ca7.png"),
|
||||
SelfossModel.Source(2, "Second source", listOf("second"),"spouts\\rss\\fulltextrss", "", "b3aa8a664d08eb15d6ff1db2fa83e0d9.png"))
|
||||
fun `Get tags without connection and sources update and items caching disabled`() {
|
||||
val tags = listOf(SelfossModel.Tag("test", "red", 6),
|
||||
SelfossModel.Tag("second", "yellow", 0))
|
||||
val tagsDB = listOf(TAG("test_DB", "red", 6),
|
||||
TAG("second_DB", "yellow", 0))
|
||||
|
||||
coEvery { api.tags() } returns SelfossModel.StatusAndData(success = true, data = tags)
|
||||
coEvery { db.tagsQueries.tags().executeAsList() } returns tagsDB
|
||||
every { connectivityStatus.isNetworkConnected } returns MutableStateFlow(false)
|
||||
every { appSettingsService.isUpdateSourcesEnabled() } returns false
|
||||
every { appSettingsService.isItemCachingEnabled() } returns false
|
||||
|
||||
coEvery { api.sources() } returns SelfossModel.StatusAndData(success = true, data = sources)
|
||||
val repository = Repository(api, appSettingsService, connectivityStatus, db)
|
||||
var testSources: List<SelfossModel.Source>? = null
|
||||
var testTags: List<SelfossModel.Tag> = emptyList()
|
||||
runBlocking {
|
||||
testSources = repository.getSources()
|
||||
testTags = repository.getTags()
|
||||
}
|
||||
|
||||
assertSame(sources, testSources)
|
||||
coVerify(exactly = 1) { api.sources() }
|
||||
verify(exactly = 0) { db.sourcesQueries.sources().executeAsList() }
|
||||
assertContentEquals(tagsDB.map { it.toView() }, testTags)
|
||||
coVerify(exactly = 0) { api.tags() }
|
||||
verify(atLeast = 1) { db.tagsQueries.tags().executeAsList() }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `get sources without connection`() {
|
||||
fun `get sources`() {
|
||||
val sources = arrayListOf(SelfossModel.Source(1, "First source", listOf("Test", "second"),"spouts\\rss\\fulltextrss", "", "d8c92cdb1ef119ea85c4b9205c879ca7.png"),
|
||||
SelfossModel.Source(2, "Second source", listOf("second"),"spouts\\rss\\fulltextrss", "", "b3aa8a664d08eb15d6ff1db2fa83e0d9.png"))
|
||||
val sourcesDB = listOf<SOURCE>(SOURCE("1", "First source", "Test,second","spouts\\rss\\fulltextrss", "", "d8c92cdb1ef119ea85c4b9205c879ca7.png"),
|
||||
val sourcesDB = listOf<SOURCE>(SOURCE("1", "First DB source", "Test,second","spouts\\rss\\fulltextrss", "", "d8c92cdb1ef119ea85c4b9205c879ca7.png"),
|
||||
SOURCE("2", "Second source", "second","spouts\\rss\\fulltextrss", "", "b3aa8a664d08eb15d6ff1db2fa83e0d9.png"))
|
||||
|
||||
every { connectivityStatus.isNetworkConnected } returns MutableStateFlow(false)
|
||||
coEvery { api.sources() } returns SelfossModel.StatusAndData(success = true, data = sources)
|
||||
every { db.sourcesQueries.sources().executeAsList() } returns sourcesDB
|
||||
val repository = Repository(api, appSettingsService, connectivityStatus, db)
|
||||
@@ -484,19 +565,44 @@ class RepositoryTest() {
|
||||
testSources = repository.getSources()
|
||||
}
|
||||
|
||||
assertContentEquals(sources, testSources)
|
||||
coVerify(exactly = 0) { api.sources() }
|
||||
assertSame(sources, testSources)
|
||||
assertNotEquals(sourcesDB.map { it.toView() }, testSources)
|
||||
coVerify(exactly = 1) { api.sources() }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `get sources with sources update disabled`() {
|
||||
val sources = arrayListOf(SelfossModel.Source(1, "First source", listOf("Test", "second"),"spouts\\rss\\fulltextrss", "", "d8c92cdb1ef119ea85c4b9205c879ca7.png"),
|
||||
SelfossModel.Source(2, "Second DB source", listOf("second"),"spouts\\rss\\fulltextrss", "", "b3aa8a664d08eb15d6ff1db2fa83e0d9.png"))
|
||||
val sourcesDB = listOf<SOURCE>(SOURCE("1", "First source", "Test,second","spouts\\rss\\fulltextrss", "", "d8c92cdb1ef119ea85c4b9205c879ca7.png"),
|
||||
SOURCE("2", "Second source", "second","spouts\\rss\\fulltextrss", "", "b3aa8a664d08eb15d6ff1db2fa83e0d9.png"))
|
||||
|
||||
every { appSettingsService.isUpdateSourcesEnabled() } returns false
|
||||
every { appSettingsService.isItemCachingEnabled() } returns true
|
||||
coEvery { api.sources() } returns SelfossModel.StatusAndData(success = true, data = sources)
|
||||
every { db.sourcesQueries.sources().executeAsList() } returns sourcesDB
|
||||
val repository = Repository(api, appSettingsService, connectivityStatus, db)
|
||||
var testSources: List<SelfossModel.Source>? = null
|
||||
runBlocking {
|
||||
testSources = repository.getSources()
|
||||
// Sources will be fetched from the database on the second call, thus testSources != sources
|
||||
testSources = repository.getSources()
|
||||
}
|
||||
|
||||
coVerify(exactly = 1) { api.sources() }
|
||||
assertNotSame(sources, testSources)
|
||||
assertContentEquals(sourcesDB.map { it.toView() }, testSources)
|
||||
verify(atLeast = 1) { db.sourcesQueries.sources().executeAsList() }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `get sources without connection and items caching disabled`() {
|
||||
fun `get sources with items caching disabled`() {
|
||||
val sources = arrayListOf(SelfossModel.Source(1, "First source", listOf("Test", "second"),"spouts\\rss\\fulltextrss", "", "d8c92cdb1ef119ea85c4b9205c879ca7.png"),
|
||||
SelfossModel.Source(2, "Second source", listOf("second"),"spouts\\rss\\fulltextrss", "", "b3aa8a664d08eb15d6ff1db2fa83e0d9.png"))
|
||||
val sourcesDB = listOf<SOURCE>(SOURCE("1", "First source", "Test,second","spouts\\rss\\fulltextrss", "", "d8c92cdb1ef119ea85c4b9205c879ca7.png"),
|
||||
SOURCE("2", "Second source", "second","spouts\\rss\\fulltextrss", "", "b3aa8a664d08eb15d6ff1db2fa83e0d9.png"))
|
||||
|
||||
every { connectivityStatus.isNetworkConnected } returns MutableStateFlow(false)
|
||||
every { appSettingsService.isUpdateSourcesEnabled() } returns true
|
||||
every { appSettingsService.isItemCachingEnabled() } returns false
|
||||
coEvery { api.sources() } returns SelfossModel.StatusAndData(success = true, data = sources)
|
||||
every { db.sourcesQueries.sources().executeAsList() } returns sourcesDB
|
||||
@@ -506,30 +612,9 @@ class RepositoryTest() {
|
||||
testSources = repository.getSources()
|
||||
}
|
||||
|
||||
assertSame(null, testSources)
|
||||
coVerify(exactly = 0) { api.sources() }
|
||||
verify(exactly = 0) { db.sourcesQueries.sources().executeAsList() }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `get sources with sources update disabled`() {
|
||||
val sources = arrayListOf(SelfossModel.Source(1, "First source", listOf("Test", "second"),"spouts\\rss\\fulltextrss", "", "d8c92cdb1ef119ea85c4b9205c879ca7.png"),
|
||||
SelfossModel.Source(2, "Second source", listOf("second"),"spouts\\rss\\fulltextrss", "", "b3aa8a664d08eb15d6ff1db2fa83e0d9.png"))
|
||||
val sourcesDB = listOf<SOURCE>(SOURCE("1", "First source", "Test,second","spouts\\rss\\fulltextrss", "", "d8c92cdb1ef119ea85c4b9205c879ca7.png"),
|
||||
SOURCE("2", "Second source", "second","spouts\\rss\\fulltextrss", "", "b3aa8a664d08eb15d6ff1db2fa83e0d9.png"))
|
||||
|
||||
every { appSettingsService.isUpdateSourcesEnabled() } returns false
|
||||
coEvery { api.sources() } returns SelfossModel.StatusAndData(success = true, data = sources)
|
||||
every { db.sourcesQueries.sources().executeAsList() } returns sourcesDB
|
||||
val repository = Repository(api, appSettingsService, connectivityStatus, db)
|
||||
var testSources: List<SelfossModel.Source>? = null
|
||||
runBlocking {
|
||||
testSources = repository.getSources()
|
||||
}
|
||||
|
||||
assertContentEquals(sources, testSources)
|
||||
coVerify(exactly = 0) { api.sources() }
|
||||
verify(atLeast = 1) { db.sourcesQueries.sources().executeAsList() }
|
||||
assertSame(sources, testSources)
|
||||
coVerify(exactly = 1) { api.sources() }
|
||||
verify(exactly = 0) { db.sourcesQueries }
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -549,11 +634,101 @@ class RepositoryTest() {
|
||||
testSources = repository.getSources()
|
||||
}
|
||||
|
||||
assertSame(null, testSources)
|
||||
assertSame(sources, testSources)
|
||||
coVerify(exactly = 1) { api.sources() }
|
||||
verify(atLeast = 1) { db.sourcesQueries }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `get sources without connection`() {
|
||||
val sources = arrayListOf(SelfossModel.Source(1, "First source", listOf("Test", "second"),"spouts\\rss\\fulltextrss", "", "d8c92cdb1ef119ea85c4b9205c879ca7.png"),
|
||||
SelfossModel.Source(2, "Second source", listOf("second"),"spouts\\rss\\fulltextrss", "", "b3aa8a664d08eb15d6ff1db2fa83e0d9.png"))
|
||||
val sourcesDB = listOf<SOURCE>(SOURCE("1", "First DB source", "Test,second","spouts\\rss\\fulltextrss", "", "d8c92cdb1ef119ea85c4b9205c879ca7.png"),
|
||||
SOURCE("2", "Second source", "second","spouts\\rss\\fulltextrss", "", "b3aa8a664d08eb15d6ff1db2fa83e0d9.png"))
|
||||
|
||||
every { connectivityStatus.isNetworkConnected } returns MutableStateFlow(false)
|
||||
coEvery { api.sources() } returns SelfossModel.StatusAndData(success = true, data = sources)
|
||||
every { db.sourcesQueries.sources().executeAsList() } returns sourcesDB
|
||||
val repository = Repository(api, appSettingsService, connectivityStatus, db)
|
||||
var testSources: List<SelfossModel.Source>? = null
|
||||
runBlocking {
|
||||
testSources = repository.getSources()
|
||||
}
|
||||
|
||||
assertContentEquals(sourcesDB.map { it.toView() }, testSources)
|
||||
coVerify(exactly = 0) { api.sources() }
|
||||
verify(atLeast = 1) { db.sourcesQueries.sources().executeAsList() }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `get sources without connection and items caching disabled`() {
|
||||
val sources = arrayListOf(SelfossModel.Source(1, "First source", listOf("Test", "second"),"spouts\\rss\\fulltextrss", "", "d8c92cdb1ef119ea85c4b9205c879ca7.png"),
|
||||
SelfossModel.Source(2, "Second source", listOf("second"),"spouts\\rss\\fulltextrss", "", "b3aa8a664d08eb15d6ff1db2fa83e0d9.png"))
|
||||
val sourcesDB = listOf<SOURCE>(SOURCE("1", "First DB source", "Test,second","spouts\\rss\\fulltextrss", "", "d8c92cdb1ef119ea85c4b9205c879ca7.png"),
|
||||
SOURCE("2", "Second source", "second","spouts\\rss\\fulltextrss", "", "b3aa8a664d08eb15d6ff1db2fa83e0d9.png"))
|
||||
|
||||
every { connectivityStatus.isNetworkConnected } returns MutableStateFlow(false)
|
||||
every { appSettingsService.isItemCachingEnabled() } returns false
|
||||
every { appSettingsService.isUpdateSourcesEnabled() } returns true
|
||||
coEvery { api.sources() } returns SelfossModel.StatusAndData(success = true, data = sources)
|
||||
every { db.sourcesQueries.sources().executeAsList() } returns sourcesDB
|
||||
val repository = Repository(api, appSettingsService, connectivityStatus, db)
|
||||
var testSources: List<SelfossModel.Source>? = null
|
||||
runBlocking {
|
||||
testSources = repository.getSources()
|
||||
}
|
||||
|
||||
assertContentEquals(ArrayList(), testSources)
|
||||
coVerify(exactly = 0) { api.sources() }
|
||||
verify(exactly = 0) { db.sourcesQueries.sources().executeAsList() }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `get sources without connection and sources update disabled`() {
|
||||
val sources = arrayListOf(SelfossModel.Source(1, "First source", listOf("Test", "second"),"spouts\\rss\\fulltextrss", "", "d8c92cdb1ef119ea85c4b9205c879ca7.png"),
|
||||
SelfossModel.Source(2, "Second source", listOf("second"),"spouts\\rss\\fulltextrss", "", "b3aa8a664d08eb15d6ff1db2fa83e0d9.png"))
|
||||
val sourcesDB = listOf<SOURCE>(SOURCE("1", "First DB source", "Test,second","spouts\\rss\\fulltextrss", "", "d8c92cdb1ef119ea85c4b9205c879ca7.png"),
|
||||
SOURCE("2", "Second source", "second","spouts\\rss\\fulltextrss", "", "b3aa8a664d08eb15d6ff1db2fa83e0d9.png"))
|
||||
|
||||
every { connectivityStatus.isNetworkConnected } returns MutableStateFlow(false)
|
||||
every { appSettingsService.isItemCachingEnabled() } returns true
|
||||
every { appSettingsService.isUpdateSourcesEnabled() } returns false
|
||||
coEvery { api.sources() } returns SelfossModel.StatusAndData(success = true, data = sources)
|
||||
every { db.sourcesQueries.sources().executeAsList() } returns sourcesDB
|
||||
val repository = Repository(api, appSettingsService, connectivityStatus, db)
|
||||
var testSources: List<SelfossModel.Source>? = null
|
||||
runBlocking {
|
||||
testSources = repository.getSources()
|
||||
}
|
||||
|
||||
assertContentEquals(sourcesDB.map { it.toView() }, testSources)
|
||||
coVerify(exactly = 0) { api.sources() }
|
||||
verify(atLeast = 1) { db.sourcesQueries.sources().executeAsList() }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `get sources without connection and items caching and sources update disabled`() {
|
||||
val sources = arrayListOf(SelfossModel.Source(1, "First source", listOf("Test", "second"),"spouts\\rss\\fulltextrss", "", "d8c92cdb1ef119ea85c4b9205c879ca7.png"),
|
||||
SelfossModel.Source(2, "Second source", listOf("second"),"spouts\\rss\\fulltextrss", "", "b3aa8a664d08eb15d6ff1db2fa83e0d9.png"))
|
||||
val sourcesDB = listOf<SOURCE>(SOURCE("1", "First DB source", "Test,second","spouts\\rss\\fulltextrss", "", "d8c92cdb1ef119ea85c4b9205c879ca7.png"),
|
||||
SOURCE("2", "Second source", "second","spouts\\rss\\fulltextrss", "", "b3aa8a664d08eb15d6ff1db2fa83e0d9.png"))
|
||||
|
||||
every { connectivityStatus.isNetworkConnected } returns MutableStateFlow(false)
|
||||
every { appSettingsService.isItemCachingEnabled() } returns false
|
||||
every { appSettingsService.isUpdateSourcesEnabled() } returns false
|
||||
coEvery { api.sources() } returns SelfossModel.StatusAndData(success = true, data = sources)
|
||||
every { db.sourcesQueries.sources().executeAsList() } returns sourcesDB
|
||||
val repository = Repository(api, appSettingsService, connectivityStatus, db)
|
||||
var testSources: List<SelfossModel.Source>? = null
|
||||
runBlocking {
|
||||
testSources = repository.getSources()
|
||||
}
|
||||
|
||||
assertContentEquals(sourcesDB.map { it.toView() }, testSources)
|
||||
coVerify(exactly = 0) { api.sources() }
|
||||
verify(atLeast = 1) { db.sourcesQueries.sources().executeAsList() }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `create source`() {
|
||||
coEvery { api.createSourceForVersion(any(), any(), any(), any(), any(), any()) } returns
|
||||
@@ -654,12 +829,26 @@ class RepositoryTest() {
|
||||
}
|
||||
|
||||
coVerify(exactly = 1) { api.update() }
|
||||
assertSame(true, response)
|
||||
assertTrue(response)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `update remote but response fails`() {
|
||||
coEvery { api.update()} returns SelfossModel.StatusAndData(success = false, data = "undocumented...")
|
||||
coEvery { api.update()} returns SelfossModel.StatusAndData(success = false, data = "unallowed access")
|
||||
|
||||
val repository = Repository(api, appSettingsService, connectivityStatus, db)
|
||||
var response = false
|
||||
runBlocking {
|
||||
response = repository.updateRemote()
|
||||
}
|
||||
|
||||
coVerify(exactly = 1) { api.update() }
|
||||
assertSame(false, response)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `update remote with unallowed access`() {
|
||||
coEvery { api.update()} returns SelfossModel.StatusAndData(success = true, data = "unallowed access")
|
||||
|
||||
val repository = Repository(api, appSettingsService, connectivityStatus, db)
|
||||
var response = false
|
||||
@@ -743,8 +932,16 @@ class RepositoryTest() {
|
||||
|
||||
@Test
|
||||
fun `cache items`() {
|
||||
coEvery { api.getItems(any(), any(), any(), any(), any(), any(), any()) } returns
|
||||
SelfossModel.StatusAndData(success = true, data = generateTestApiItem())
|
||||
val itemParameter1 = FakeItemParameters()
|
||||
val itemParameter2 = FakeItemParameters()
|
||||
val itemParameter3 = FakeItemParameters()
|
||||
itemParameter2.id = "2"
|
||||
itemParameter3.id = "3"
|
||||
coEvery { api.getItems(any(), any(), any(), any(), any(), any(), any()) } returnsMany listOf(
|
||||
SelfossModel.StatusAndData(success = true, data = generateTestApiItem(itemParameter1)),
|
||||
SelfossModel.StatusAndData(success = true, data = generateTestApiItem(itemParameter2)),
|
||||
SelfossModel.StatusAndData(success = true, data = generateTestApiItem(itemParameter1)),
|
||||
)
|
||||
|
||||
val repository = Repository(api, appSettingsService, connectivityStatus, db)
|
||||
repository.tagFilter = SelfossModel.Tag("Tag", "read", 0)
|
||||
@@ -757,13 +954,11 @@ class RepositoryTest() {
|
||||
"d8c92cdb1ef119ea85c4b9205c879ca7.png"
|
||||
)
|
||||
repository.searchFilter = "search"
|
||||
var items = emptyList<SelfossModel.Item>()
|
||||
runBlocking {
|
||||
items = repository.tryToCacheItemsAndGetNewOnes()
|
||||
repository.tryToCacheItemsAndGetNewOnes()
|
||||
}
|
||||
|
||||
coVerify(exactly = 3) { api.getItems(any(), 0, null, null, null, null, 200) }
|
||||
assertSame(3, items.size)
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -782,13 +977,11 @@ class RepositoryTest() {
|
||||
"d8c92cdb1ef119ea85c4b9205c879ca7.png"
|
||||
)
|
||||
repository.searchFilter = "search"
|
||||
var items = emptyList<SelfossModel.Item>()
|
||||
runBlocking {
|
||||
items = repository.tryToCacheItemsAndGetNewOnes()
|
||||
repository.tryToCacheItemsAndGetNewOnes()
|
||||
}
|
||||
|
||||
coVerify(exactly = 3) { api.getItems(any(), 0, null, null, null, null, 200) }
|
||||
assertSame(0, items.size)
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -808,13 +1001,11 @@ class RepositoryTest() {
|
||||
"d8c92cdb1ef119ea85c4b9205c879ca7.png"
|
||||
)
|
||||
repository.searchFilter = "search"
|
||||
var items = emptyList<SelfossModel.Item>()
|
||||
runBlocking {
|
||||
items = repository.tryToCacheItemsAndGetNewOnes()
|
||||
repository.tryToCacheItemsAndGetNewOnes()
|
||||
}
|
||||
|
||||
coVerify(exactly = 0) { api.getItems(any(), 0, null, null, null, null, 200) }
|
||||
assertSame(emptyList<SelfossModel.Item>(), items)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -852,7 +1043,7 @@ fun generateTestApiItem(item : FakeItemParameters = FakeItemParameters()) : List
|
||||
}
|
||||
|
||||
class FakeItemParameters() {
|
||||
val id = "20"
|
||||
var id = "20"
|
||||
var datetime = "2022-09-09T03:32:01-04:00"
|
||||
val title = "Etica della ricerca sotto i riflettori."
|
||||
val content = "<p><strong>Luigi Campanella, già Presidente SCI</strong></p>\n<p>L’etica della scienza è di certo ambito di cui continuiamo a scoprire nuovi aspetti e risvolti.</p>\n<p>L’ultimo è quello delle intelligenze artificiali capaci di creare opere complesse basate su immagini e parole memorizzate con il rischio di fake news e di contenuti disturbanti.</p>\n<p>Per evitare che ciò accada si sta procedendo filtrando secondo criteri di autocensura i dati da cui l’intelligenza artificiale parte.</p>\n<p>Comincia ad intravedersi un futuro prossimo di competizione fra autori umani ed artificiali nel quale sarà importante, quando i loro prodotti saranno indistinguibili, dichiararne l’origine.</p>\n<p>Come si comprende, si conferma che gli aspetti etici dell’innovazione e della ricerca si diversificato sempre di più.</p>\n<p>La biologia molecolare e la genetica già in passato hanno posto all’attenzione comune aspetti di etica della scienza che hanno indotto a nuove riflessioni circa i limiti delle ricerche.</p>\n<p>L’argomento, sempre attuale, torna sulle prime pagine a seguito della pubblicazione di una ricerca della Università di Cambridge che ha sviluppato una struttura cellulare di un topo con un cuore che batte regolarmente.</p>\n<img src=\"https://ilblogdellasci.files.wordpress.com/2022/09/image002-1.png?w=481\" alt=\"\" width=\"697\" height=\"430\" /><img src=\"https://ilblogdellasci.files.wordpress.com/2022/09/image003-1.png?w=906\" alt=\"\" /><p>Magdalena Zernicka-Goetz</p>\n<img src=\"https://ilblogdellasci.files.wordpress.com/2022/09/image004.jpg?w=474\" alt=\"\" width=\"622\" height=\"465\" /><p>Gianluca Amadei</p>\n<p>Del gruppo fa parte anche uno scienziato italiano Gianluca Amadei,che dinnanzi alle obiezioni di natura etica sulla realizzazione della vita artificiale si è affrettato a sostenere che non è creare nuove vite il fine primario della ricerca, ma quello di salvare quelle esistenti, di dare contributi essenziali alla medicina citando il caso del fallimento tuttora non interpretato di alcune gravidanze e di superare la sperimentazione animale, così contribuendo positivamente alla soluzione di un altro dilemma etico.</p>\n<p>L’embrione sintetico ha ovviamente come primo traguardo il contributo ai trapianti oggi drammaticamente carenti nell’offerta rispetto alla domanda, con attese fino a 4 anni per i trapianti di cuore ed a 2 anni per quelli di fegato. Il lavoro dovrebbe adesso continuare presso l’Ateneo di Padova per creare nuovi organi e nuovi farmaci.</p>"
|
||||
@@ -861,6 +1052,6 @@ class FakeItemParameters() {
|
||||
val thumbnail = null
|
||||
val icon = "ba79e238383ce83c23a169929c8906ef.png"
|
||||
val link = "https://ilblogdellasci.wordpress.com/2022/09/09/etica-della-ricerca-sotto-i-riflettori/"
|
||||
val sourcetitle = "La Chimica e la Società"
|
||||
val tags = "Chimica, Testing"
|
||||
var sourcetitle = "La Chimica e la Società"
|
||||
var tags = "Chimica, Testing"
|
||||
}
|
||||
Reference in New Issue
Block a user