forked from Louvorg/ReaderForSelfoss-multiplatform
Compare commits
17
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a76b3dd2a9 | ||
|
|
91aed5a777 | ||
|
|
8823cc6c6c | ||
|
|
74ef4da15b | ||
|
|
bd96c67788 | ||
|
|
da71de6806 | ||
|
|
0264da8ccc | ||
|
|
270d959ee0 | ||
|
|
6d11dfb80c | ||
|
|
4184bbb900 | ||
|
|
4c12c9d570 | ||
|
|
f4db02521d | ||
|
|
01763556b1 | ||
|
|
e2411c00d8 | ||
|
|
0473a5f7bc | ||
|
|
d0d6a4378c | ||
|
|
1dfa3c9f07 |
+98
-7
@@ -1,26 +1,117 @@
|
||||
kind: pipeline
|
||||
type: docker
|
||||
name: android
|
||||
name: test
|
||||
|
||||
steps:
|
||||
- name: code-analysis
|
||||
- name: AnylyseBuildTest
|
||||
image: mingc/android-build-box:latest
|
||||
failure: ignore
|
||||
commands:
|
||||
- ls -la
|
||||
- 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 "---------------------------------------------------------"
|
||||
- echo "Building..."
|
||||
- ./gradlew :androidApp:build -PignoreGitVersion=true -P appLoginUrl="\"URL\"" -P appLoginUsername="\"LOGIN\"" -P appLoginPassword="\"PASS\"" -P pushCache=false
|
||||
- echo "---------------------------------------------------------"
|
||||
- echo "Testing..."
|
||||
- echo "---------------------------------------------------------"
|
||||
environment:
|
||||
SONAR_HOST_URL:
|
||||
from_secret: sonarScannerHostUrl
|
||||
SONAR_LOGIN:
|
||||
from_secret: sonarScannerLogin
|
||||
trigger:
|
||||
event:
|
||||
- push
|
||||
- pull_request
|
||||
|
||||
- name: test
|
||||
image: mingc/android-build-box:latest
|
||||
---
|
||||
kind: pipeline
|
||||
type: docker
|
||||
name: Publish
|
||||
|
||||
steps:
|
||||
- name: createTag
|
||||
image: ubuntu:latest
|
||||
commands:
|
||||
- ./gradlew test -PignoreGitVersion=true -P appLoginUrl="\"URL\"" -P appLoginUsername="\"LOGIN\"" -P appLoginPassword="\"PASS\"" -P pushCache=false
|
||||
- apt-get update && apt-get install -y git
|
||||
- ./build.sh --publish --from-ci
|
||||
- git remote add pushing https://$GITEA_USR:$GITEA_PASS@gitea.amine-louveau.fr/Louvorg/ReaderForSelfoss-multiplatform.git
|
||||
- git push pushing --tags
|
||||
environment:
|
||||
GITEA_USR:
|
||||
from_secret: giteaUsr
|
||||
GITEA_PASS:
|
||||
from_secret: giteaPass
|
||||
|
||||
- name: scpFiles
|
||||
image: appleboy/drone-scp
|
||||
settings:
|
||||
host: amine-louveau.fr
|
||||
username: ubuntu
|
||||
key:
|
||||
from_secret: privateKey
|
||||
port: 22
|
||||
target: /home/ubuntu/
|
||||
source: version.txt
|
||||
|
||||
- name: deploy
|
||||
image: appleboy/drone-ssh
|
||||
settings:
|
||||
host: amine-louveau.fr
|
||||
user: ubuntu
|
||||
key:
|
||||
from_secret: privateKey
|
||||
command_timeout: 2m
|
||||
script:
|
||||
- cd /home/ubuntu
|
||||
- sudo rm -rf /var/www/amine/version.txt
|
||||
- sudo chown www-data:www-data ./version.txt
|
||||
- sudo mv version.txt /var/www/amine/
|
||||
|
||||
trigger:
|
||||
event:
|
||||
- promote
|
||||
target:
|
||||
- production
|
||||
|
||||
---
|
||||
kind: pipeline
|
||||
type: docker
|
||||
name: Release
|
||||
|
||||
steps:
|
||||
- name: build
|
||||
image: mingc/android-build-box:latest
|
||||
commands:
|
||||
- ./gradlew :androidApp:build -PignoreGitVersion=true -P appLoginUrl="\"URL\"" -P appLoginUsername="\"LOGIN\"" -P appLoginPassword="\"PASS\"" -P pushCache=false
|
||||
- echo "Generate APK"
|
||||
- ./gradlew :androidApp:assembleGithubConfigRelease -PignoreGitVersion=true -P appLoginUrl="\"URL\"" -P appLoginUsername="\"LOGIN\"" -P appLoginPassword="\"PASS\"" -P pushCache=false
|
||||
- echo "---------------------------------------------------------"
|
||||
- echo "Get Key"
|
||||
- wget https://amine-louveau.fr/key
|
||||
- echo "---------------------------------------------------------"
|
||||
- echo "Zipalign"
|
||||
- $ANDROID_HOME/build-tools/31.0.0/zipalign -f -v 4 androidApp/build/outputs/apk/githubConfig/release/androidApp-githubConfig-release-unsigned.apk androidApp/build/outputs/apk/githubConfig/release/android-prod-released-ziped.apk
|
||||
- echo "---------------------------------------------------------"
|
||||
- echo "Sign"
|
||||
- $ANDROID_HOME/build-tools/31.0.0/apksigner sign -v --out signed.apk --ks ./key --ks-key-alias $YOUR_KEY_ALIAS --ks-pass pass:$YOUR_KEYSTORE_PASSWORD --v1-signing-enabled true --v2-signing-enabled true androidApp/build/outputs/apk/githubConfig/release/android-prod-released-ziped.apk
|
||||
- echo "---------------------------------------------------------"
|
||||
- echo "Verify"
|
||||
- $ANDROID_HOME/build-tools/31.0.0/apksigner verify signed.apk
|
||||
environment:
|
||||
YOUR_KEYSTORE_PASSWORD:
|
||||
from_secret: keyPass
|
||||
YOUR_KEY_ALIAS:
|
||||
from_secret: keyAlias
|
||||
|
||||
- name: gitea_release
|
||||
image: plugins/gitea-release
|
||||
settings:
|
||||
api_key:
|
||||
from_secret: giteaAPI
|
||||
base_url: https://gitea.amine-louveau.fr
|
||||
files: signed.apk
|
||||
trigger:
|
||||
event:
|
||||
- tag
|
||||
@@ -1,3 +1,14 @@
|
||||
# V2/Multiplatform rewrite
|
||||
|
||||
**v1**
|
||||
|
||||
- The app has the same functionalities as before.
|
||||
|
||||
|
||||
--------------------------------------------------------------------
|
||||
|
||||
# Old version changes
|
||||
|
||||
**1.7.x**
|
||||
|
||||
- Hiding tags with 0 articles
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# ReaderForSelfoss-multiplatform
|
||||
# ReaderForSelfoss-multiplatform [](https://build.amine-louveau.fr/Louvorg/ReaderForSelfoss-multiplatform)
|
||||
|
||||
[](https://crowdin.com/project/readerforselfoss)
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ fun gitVersion(): String {
|
||||
println("Tag found on current commit")
|
||||
execWithOutput("git -C ../ describe --contains HEAD")
|
||||
}
|
||||
return process.replace("'", "").substring(1).replace("\\.", "").trim()
|
||||
return process.replace("^0", "").replace("'", "").substring(1).replace("\\.", "").trim()
|
||||
}
|
||||
|
||||
fun versionCodeFromGit(): Int {
|
||||
@@ -93,7 +93,7 @@ android {
|
||||
}
|
||||
flavorDimensions.add("build")
|
||||
productFlavors {
|
||||
create("github") {
|
||||
create("githubConfig") {
|
||||
versionNameSuffix = "-github"
|
||||
dimension = "build"
|
||||
}
|
||||
@@ -101,6 +101,7 @@ android {
|
||||
kotlinOptions {
|
||||
jvmTarget = "1.8"
|
||||
}
|
||||
namespace = "bou.amine.apps.readerforselfossv2.android"
|
||||
|
||||
}
|
||||
|
||||
|
||||
Vendored
+29
-2
@@ -55,11 +55,38 @@
|
||||
public *;
|
||||
}
|
||||
|
||||
-dontwarn com.anupcowkur.reservoir.**
|
||||
|
||||
-dontwarn javax.annotation.**
|
||||
|
||||
-keep class android.support.v7.widget.SearchView { *; }
|
||||
|
||||
# maybe remove later ?
|
||||
-keep class * extends androidx.fragment.app.Fragment
|
||||
|
||||
|
||||
# Keep `Companion` object fields of serializable classes.
|
||||
# This avoids serializer lookup through `getDeclaredClasses` as done for named companion objects.
|
||||
-if @kotlinx.serialization.Serializable class **
|
||||
-keepclassmembers class <1> {
|
||||
static <1>$Companion Companion;
|
||||
}
|
||||
|
||||
# Keep `serializer()` on companion objects (both default and named) of serializable classes.
|
||||
-if @kotlinx.serialization.Serializable class ** {
|
||||
static **$* *;
|
||||
}
|
||||
-keepclassmembers class <2>$<3> {
|
||||
kotlinx.serialization.KSerializer serializer(...);
|
||||
}
|
||||
|
||||
# Keep `INSTANCE.serializer()` of serializable objects.
|
||||
-if @kotlinx.serialization.Serializable class ** {
|
||||
public static ** INSTANCE;
|
||||
}
|
||||
-keepclassmembers class <1> {
|
||||
public static <1> INSTANCE;
|
||||
kotlinx.serialization.KSerializer serializer(...);
|
||||
}
|
||||
|
||||
# @Serializable and @Polymorphic are used at runtime for polymorphic serialization.
|
||||
-keepattributes RuntimeVisibleAnnotations,AnnotationDefault
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# NOTE: This is copy/pasted in jenkins
|
||||
|
||||
rm -f version.txt
|
||||
printf "versionName=$1-github\nversionCode=$1" >> version.txt
|
||||
|
||||
# You'll need to change server as your server and define a VERSION_PATH.
|
||||
scp version.txt server:$VERSION_PATH
|
||||
|
||||
rm version.txt
|
||||
@@ -1,7 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
package="bou.amine.apps.readerforselfossv2.android">
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
|
||||
+2
-2
@@ -9,7 +9,7 @@ import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import bou.amine.apps.readerforselfossv2.android.databinding.ActivityAddSourceBinding
|
||||
import bou.amine.apps.readerforselfossv2.android.themes.AppColors
|
||||
import bou.amine.apps.readerforselfossv2.android.themes.Toppings
|
||||
import bou.amine.apps.readerforselfossv2.android.utils.isBaseUrlValid
|
||||
import bou.amine.apps.readerforselfossv2.android.utils.isBaseUrlInvalid
|
||||
import bou.amine.apps.readerforselfossv2.model.NetworkUnavailableException
|
||||
import bou.amine.apps.readerforselfossv2.repository.Repository
|
||||
import bou.amine.apps.readerforselfossv2.service.AppSettingsService
|
||||
@@ -84,7 +84,7 @@ class AddSourceActivity : AppCompatActivity(), DIAware {
|
||||
super.onResume()
|
||||
|
||||
val baseUrl = appSettingsService.getBaseUrl()
|
||||
if (baseUrl.isEmpty() || !baseUrl.isBaseUrlValid(this@AddSourceActivity)) {
|
||||
if (baseUrl.isEmpty() || baseUrl.isBaseUrlInvalid()) {
|
||||
mustLoginToAddSource()
|
||||
} else {
|
||||
handleSpoutsSpinner(binding.spoutsSpinner, binding.progress, binding.formContainer)
|
||||
|
||||
@@ -95,6 +95,7 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
||||
|
||||
private val settingsLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
|
||||
appSettingsService.refreshUserSettings()
|
||||
recreate()
|
||||
}
|
||||
|
||||
override val di by closestDI()
|
||||
|
||||
@@ -14,7 +14,7 @@ import androidx.appcompat.app.AlertDialog
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import bou.amine.apps.readerforselfossv2.android.databinding.ActivityLoginBinding
|
||||
import bou.amine.apps.readerforselfossv2.android.themes.AppColors
|
||||
import bou.amine.apps.readerforselfossv2.android.utils.isBaseUrlValid
|
||||
import bou.amine.apps.readerforselfossv2.android.utils.isBaseUrlInvalid
|
||||
import bou.amine.apps.readerforselfossv2.repository.Repository
|
||||
import bou.amine.apps.readerforselfossv2.service.AppSettingsService
|
||||
import com.mikepenz.aboutlibraries.LibsBuilder
|
||||
@@ -115,14 +115,14 @@ class LoginActivity : AppCompatActivity(), DIAware {
|
||||
binding.passwordView.error = null
|
||||
|
||||
// Store values at the time of the login attempt.
|
||||
val url = binding.urlView.text.toString()
|
||||
val login = binding.loginView.text.toString()
|
||||
val password = binding.passwordView.text.toString()
|
||||
val url = binding.urlView.text.toString().trim()
|
||||
val login = binding.loginView.text.toString().trim()
|
||||
val password = binding.passwordView.text.toString().trim()
|
||||
|
||||
var cancel = false
|
||||
var focusView: View? = null
|
||||
|
||||
if (!url.isBaseUrlValid(this@LoginActivity)) {
|
||||
if (url.isBaseUrlInvalid()) {
|
||||
binding.urlView.error = getString(R.string.login_url_problem)
|
||||
focusView = binding.urlView
|
||||
cancel = true
|
||||
|
||||
+2
-2
@@ -30,7 +30,7 @@ abstract class ItemsAdapter<VH : RecyclerView.ViewHolder?> : RecyclerView.Adapte
|
||||
updateItems(this.items)
|
||||
}
|
||||
|
||||
private fun unmarkSnackbar(i: SelfossModel.Item, position: Int) {
|
||||
private fun unmarkSnackbar(position: Int) {
|
||||
val s = Snackbar
|
||||
.make(
|
||||
app.findViewById(R.id.coordLayout),
|
||||
@@ -87,7 +87,7 @@ abstract class ItemsAdapter<VH : RecyclerView.ViewHolder?> : RecyclerView.Adapte
|
||||
notifyItemChanged(position)
|
||||
}
|
||||
if (showSnackbar) {
|
||||
unmarkSnackbar(i, position)
|
||||
unmarkSnackbar(position)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -268,8 +268,8 @@ class ArticleFragment : Fragment(), DIAware {
|
||||
|
||||
private fun getContentFromMercury(customTabsIntent: CustomTabsIntent) {
|
||||
if (repository.isNetworkAvailable()) {
|
||||
binding.progressBar.visibility = View.VISIBLE
|
||||
val parser = MercuryApi()
|
||||
binding.progressBar.visibility = View.VISIBLE
|
||||
val parser = MercuryApi()
|
||||
|
||||
parser.parseUrl(url).enqueue(
|
||||
object : Callback<ParsedContent> {
|
||||
|
||||
+2
-2
@@ -163,7 +163,7 @@ private fun openInBrowser(linkDecoded: String, app: Activity) {
|
||||
fun String.isUrlValid(): Boolean =
|
||||
this.toHttpUrlOrNull() != null && Patterns.WEB_URL.matcher(this).matches()
|
||||
|
||||
fun String.isBaseUrlValid(ctx: Context): Boolean {
|
||||
fun String.isBaseUrlInvalid(): Boolean {
|
||||
val baseUrl = this.toHttpUrlOrNull()
|
||||
var existsAndEndsWithSlash = false
|
||||
if (baseUrl != null) {
|
||||
@@ -171,7 +171,7 @@ fun String.isBaseUrlValid(ctx: Context): Boolean {
|
||||
existsAndEndsWithSlash = "" == pathSegments[pathSegments.size - 1]
|
||||
}
|
||||
|
||||
return Patterns.WEB_URL.matcher(this).matches() && existsAndEndsWithSlash
|
||||
return !(Patterns.WEB_URL.matcher(this).matches() && existsAndEndsWithSlash)
|
||||
}
|
||||
|
||||
fun Context.openInBrowserAsNewTask(i: SelfossModel.Item) {
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
#!/bin/bash
|
||||
# You can pass --force as first parameter to force push and tag creation.
|
||||
|
||||
echo "Creating tag $@"
|
||||
|
||||
TAG="v$@"
|
||||
git tag ${TAG}
|
||||
|
||||
echo "Pushing tag"
|
||||
|
||||
git push origin ${TAG}
|
||||
+1
-1
@@ -6,7 +6,7 @@ buildscript {
|
||||
}
|
||||
dependencies {
|
||||
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.10")
|
||||
classpath("com.android.tools.build:gradle:7.2.2")
|
||||
classpath("com.android.tools.build:gradle:7.3.0")
|
||||
|
||||
// sonarquve
|
||||
classpath("org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:3.4.0.2513")
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
git fetch --tags -p
|
||||
|
||||
BASE_VERSION="1.7"
|
||||
BASE_VERSION="1"
|
||||
LAST_TAG=$(git tag -l | sort -V | tail -1)
|
||||
|
||||
INITIAL_VERSION="${BASE_VERSION//./}$(date '+%y%m%j')"
|
||||
@@ -21,11 +21,11 @@ VERSION="${INITIAL_VERSION}${TODAYS_VERSION}"
|
||||
|
||||
PARAMS_EXCEPT_PUBLISH=$(echo $1 | sed 's/\-\-publish//')
|
||||
|
||||
./version.sh ${VERSION} ${PARAMS_EXCEPT_PUBLISH}
|
||||
./version.sh ${VERSION} ${PARAMS_EXCEPT_PUBLISH} $@
|
||||
|
||||
if [[ "$@" == *'--publish'* ]]
|
||||
then
|
||||
./publish-version.sh ${VERSION}
|
||||
./publish-version.sh ${VERSION} $@
|
||||
else
|
||||
echo "Did not publish. If you wanted to do so, call the script with \"--publish\" or \"--publish-local\"."
|
||||
fi
|
||||
@@ -1,3 +1 @@
|
||||
A new RSS reader for <a href="http://selfoss.aditu.de/">selfoss</a>.
|
||||
|
||||
It connects to your selfoss instance (works only with selfoss, and can't work without it), and you'll be able to read and manage all your RSS feeds.
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
#Wed Feb 09 17:05:19 CET 2022
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip
|
||||
distributionPath=wrapper/dists
|
||||
zipStorePath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
Executable
+15
@@ -0,0 +1,15 @@
|
||||
#!/bin/bash
|
||||
|
||||
# NOTE: This is copy/pasted in jenkins
|
||||
|
||||
rm -f version.txt
|
||||
printf "versionName=$1-github\nversionCode=$1" >> version.txt
|
||||
|
||||
if [[ "$@" == *'--from-ci'* ]]
|
||||
then
|
||||
echo "File created. HANDLE IN CI"
|
||||
else
|
||||
# You'll need to change server as your server and define a VERSION_PATH.
|
||||
scp version.txt server:$VERSION_PATH
|
||||
rm version.txt
|
||||
fi
|
||||
@@ -56,8 +56,6 @@ kotlin {
|
||||
dependencies {
|
||||
implementation(kotlin("test-common"))
|
||||
implementation(kotlin("test-annotations-common"))
|
||||
implementation("io.mockk:mockk:1.12.0")
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.0")
|
||||
}
|
||||
}
|
||||
val androidMain by getting {
|
||||
@@ -114,6 +112,7 @@ android {
|
||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||
targetCompatibility = JavaVersion.VERSION_1_8
|
||||
}
|
||||
namespace = "bou.amine.apps.readerforselfossv2"
|
||||
}
|
||||
|
||||
sqldelight {
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest package="bou.amine.apps.readerforselfossv2" />
|
||||
<manifest />
|
||||
+56
-1
@@ -2,7 +2,14 @@ package bou.amine.apps.readerforselfossv2.model
|
||||
|
||||
import bou.amine.apps.readerforselfossv2.utils.DateUtils
|
||||
import bou.amine.apps.readerforselfossv2.utils.getHtmlDecoded
|
||||
import kotlinx.serialization.KSerializer
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.descriptors.PrimitiveKind
|
||||
import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
|
||||
import kotlinx.serialization.descriptors.SerialDescriptor
|
||||
import kotlinx.serialization.encoding.Decoder
|
||||
import kotlinx.serialization.encoding.Encoder
|
||||
import kotlinx.serialization.json.*
|
||||
|
||||
class SelfossModel {
|
||||
|
||||
@@ -50,6 +57,7 @@ class SelfossModel {
|
||||
data class Source(
|
||||
val id: Int,
|
||||
val title: String,
|
||||
@Serializable(with = TagsListSerializer::class)
|
||||
val tags: List<String>,
|
||||
val spout: String,
|
||||
val error: String,
|
||||
@@ -62,12 +70,15 @@ class SelfossModel {
|
||||
val datetime: String,
|
||||
val title: String,
|
||||
val content: String,
|
||||
@Serializable(with = BooleanSerializer::class)
|
||||
var unread: Boolean,
|
||||
@Serializable(with = BooleanSerializer::class)
|
||||
var starred: Boolean,
|
||||
val thumbnail: String?,
|
||||
val icon: String?,
|
||||
val link: String,
|
||||
val sourcetitle: String,
|
||||
@Serializable(with = TagsListSerializer::class)
|
||||
val tags: List<String>
|
||||
) {
|
||||
// TODO: maybe find a better way to handle these kind of urls
|
||||
@@ -105,4 +116,48 @@ class SelfossModel {
|
||||
return this
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: this seems to be super slow.
|
||||
object TagsListSerializer : KSerializer<List<String>> {
|
||||
override fun deserialize(decoder: Decoder): List<String> {
|
||||
return when(val json = ((decoder as JsonDecoder).decodeJsonElement())) {
|
||||
is JsonArray -> json.toList().map { it.toString() }
|
||||
else -> json.toString().split(",")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override val descriptor: SerialDescriptor
|
||||
get() = PrimitiveSerialDescriptor("tags", PrimitiveKind.STRING)
|
||||
|
||||
override fun serialize(encoder: Encoder, value: List<String>) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
}
|
||||
|
||||
object BooleanSerializer : KSerializer<Boolean> {
|
||||
override fun deserialize(decoder: Decoder): Boolean {
|
||||
val json = ((decoder as JsonDecoder).decodeJsonElement()).jsonPrimitive
|
||||
return json.booleanOrNull ?: json.int == 1
|
||||
}
|
||||
|
||||
override val descriptor: SerialDescriptor
|
||||
get() = PrimitiveSerialDescriptor("b", PrimitiveKind.BOOLEAN)
|
||||
|
||||
override fun serialize(encoder: Encoder, value: Boolean) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
}
|
||||
|
||||
class StatusAndData<T>(val success: Boolean, val data: T? = null) {
|
||||
companion object {
|
||||
fun <T> succes(d: T): StatusAndData<T> {
|
||||
return StatusAndData(true, d)
|
||||
}
|
||||
|
||||
fun <T> error(): StatusAndData<T> {
|
||||
return StatusAndData(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+46
-38
@@ -11,7 +11,6 @@ import io.github.aakira.napier.Napier
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runBlocking
|
||||
|
||||
class Repository(private val api: SelfossApi, private val appSettingsService: AppSettingsService, connectivityStatus: ConnectivityStatus, private val db: ReaderForSelfossDB) {
|
||||
|
||||
@@ -39,7 +38,7 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap
|
||||
|
||||
init {
|
||||
// TODO: Dispatchers.IO not available in KMM, an alternative solution should be found
|
||||
runBlocking {
|
||||
CoroutineScope(Dispatchers.Main).launch {
|
||||
updateApiVersion()
|
||||
dateUtils = DateUtils(appSettingsService)
|
||||
reloadBadges()
|
||||
@@ -48,7 +47,7 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap
|
||||
|
||||
suspend fun getNewerItems(): ArrayList<SelfossModel.Item> {
|
||||
// TODO: Use the updatedSince parameter
|
||||
var fetchedItems: List<SelfossModel.Item>? = null
|
||||
var fetchedItems: SelfossModel.StatusAndData<List<SelfossModel.Item>> = SelfossModel.StatusAndData.error()
|
||||
if (isNetworkAvailable()) {
|
||||
fetchedItems = api.getItems(
|
||||
displayedItems.type,
|
||||
@@ -60,23 +59,25 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap
|
||||
)
|
||||
} else {
|
||||
if (appSettingsService.isItemCachingEnabled()) {
|
||||
fetchedItems = getDBItems().filter {
|
||||
displayedItems == ItemType.ALL ||
|
||||
(it.unread && displayedItems == ItemType.UNREAD) ||
|
||||
(it.starred && displayedItems == ItemType.STARRED)
|
||||
}.map { it.toView() }
|
||||
fetchedItems = SelfossModel.StatusAndData.succes(
|
||||
getDBItems().filter {
|
||||
displayedItems == ItemType.ALL ||
|
||||
(it.unread && displayedItems == ItemType.UNREAD) ||
|
||||
(it.starred && displayedItems == ItemType.STARRED)
|
||||
}.map { it.toView() }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (fetchedItems != null) {
|
||||
items = ArrayList(fetchedItems)
|
||||
if (fetchedItems.success && fetchedItems.data != null) {
|
||||
items = ArrayList(fetchedItems.data!!)
|
||||
sortItems()
|
||||
}
|
||||
return items
|
||||
}
|
||||
|
||||
suspend fun getOlderItems(): ArrayList<SelfossModel.Item> {
|
||||
var fetchedItems: List<SelfossModel.Item>? = null
|
||||
var fetchedItems: SelfossModel.StatusAndData<List<SelfossModel.Item>> = SelfossModel.StatusAndData.error()
|
||||
if (isNetworkAvailable()) {
|
||||
val offset = items.size
|
||||
fetchedItems = api.getItems(
|
||||
@@ -89,16 +90,16 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap
|
||||
)
|
||||
} // When using the db cache, we load everything the first time, so there should be nothing more to load.
|
||||
|
||||
if (fetchedItems != null) {
|
||||
items.addAll(fetchedItems)
|
||||
if (fetchedItems.success && fetchedItems.data != null) {
|
||||
items.addAll(fetchedItems.data!!)
|
||||
sortItems()
|
||||
}
|
||||
return items
|
||||
}
|
||||
|
||||
private suspend fun getMaxItemsForBackground(itemType: ItemType): List<SelfossModel.Item>? {
|
||||
private suspend fun getMaxItemsForBackground(itemType: ItemType): List<SelfossModel.Item> {
|
||||
return if (isNetworkAvailable()) {
|
||||
api.getItems(
|
||||
val items = api.getItems(
|
||||
itemType.type,
|
||||
0,
|
||||
tagFilter?.tag,
|
||||
@@ -107,6 +108,11 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap
|
||||
null,
|
||||
200
|
||||
)
|
||||
return if (items.success && items.data != null) {
|
||||
items.data
|
||||
} else {
|
||||
emptyList()
|
||||
}
|
||||
} else {
|
||||
emptyList()
|
||||
}
|
||||
@@ -120,10 +126,10 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap
|
||||
var success = false
|
||||
if (isNetworkAvailable()) {
|
||||
val response = api.stats()
|
||||
if (response != null) {
|
||||
badgeUnread = response.unread
|
||||
badgeAll = response.total
|
||||
badgeStarred = response.starred
|
||||
if (response.success && response.data != null) {
|
||||
badgeUnread = response.data.unread
|
||||
badgeAll = response.data.total
|
||||
badgeStarred = response.data.starred
|
||||
success = true
|
||||
}
|
||||
} else {
|
||||
@@ -139,19 +145,23 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap
|
||||
suspend fun getTags(): List<SelfossModel.Tag>? {
|
||||
return if (isNetworkAvailable()) {
|
||||
val apiTags = api.tags()
|
||||
if (apiTags != null && (appSettingsService.isItemCachingEnabled() || !appSettingsService.isUpdateSourcesEnabled())) {
|
||||
resetDBTagsWithData(apiTags)
|
||||
if (apiTags.success && apiTags.data != null && (appSettingsService.isItemCachingEnabled() || !appSettingsService.isUpdateSourcesEnabled())) {
|
||||
resetDBTagsWithData(apiTags.data)
|
||||
}
|
||||
apiTags
|
||||
apiTags.data
|
||||
} else {
|
||||
getDBTags().map { it.toView() }
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Add tests
|
||||
suspend fun getSpouts(): Map<String, SelfossModel.Spout>? {
|
||||
return if (isNetworkAvailable()) {
|
||||
api.spouts()
|
||||
val spouts = api.spouts()
|
||||
return if (spouts.success && spouts.data != null) {
|
||||
spouts.data
|
||||
} else {
|
||||
emptyMap() // TODO: do something here
|
||||
}
|
||||
} else {
|
||||
throw NetworkUnavailableException()
|
||||
}
|
||||
@@ -160,10 +170,10 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap
|
||||
suspend fun getSources(): ArrayList<SelfossModel.Source>? {
|
||||
return if (isNetworkAvailable()) {
|
||||
val apiSources = api.sources()
|
||||
if (apiSources != null && (appSettingsService.isItemCachingEnabled() || !appSettingsService.isUpdateSourcesEnabled())) {
|
||||
resetDBSourcesWithData(apiSources)
|
||||
if (apiSources.success && apiSources.data != null && (appSettingsService.isItemCachingEnabled() || !appSettingsService.isUpdateSourcesEnabled())) {
|
||||
resetDBSourcesWithData(apiSources.data)
|
||||
}
|
||||
apiSources
|
||||
apiSources.data
|
||||
} else {
|
||||
ArrayList(getDBSources().map { it.toView() })
|
||||
}
|
||||
@@ -180,7 +190,7 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap
|
||||
|
||||
private suspend fun markAsReadById(id: Int): Boolean {
|
||||
return if (isNetworkAvailable()) {
|
||||
api.markAsRead(id.toString())?.isSuccess == true
|
||||
api.markAsRead(id.toString())?.isSuccess
|
||||
} else {
|
||||
insertDBAction(id.toString(), read = true)
|
||||
true
|
||||
@@ -199,7 +209,7 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap
|
||||
|
||||
private suspend fun unmarkAsReadById(id: Int): Boolean {
|
||||
return if (isNetworkAvailable()) {
|
||||
api.unmarkAsRead(id.toString())?.isSuccess == true
|
||||
api.unmarkAsRead(id.toString())?.isSuccess
|
||||
} else {
|
||||
insertDBAction(id.toString(), unread = true)
|
||||
true
|
||||
@@ -217,7 +227,7 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap
|
||||
|
||||
private suspend fun starrById(id: Int): Boolean {
|
||||
return if (isNetworkAvailable()) {
|
||||
api.starr(id.toString())?.isSuccess == true
|
||||
api.starr(id.toString())?.isSuccess
|
||||
} else {
|
||||
insertDBAction(id.toString(), starred = true)
|
||||
true
|
||||
@@ -235,7 +245,7 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap
|
||||
|
||||
private suspend fun unstarrById(id: Int): Boolean {
|
||||
return if (isNetworkAvailable()) {
|
||||
api.unstarr(id.toString())?.isSuccess == true
|
||||
api.unstarr(id.toString())?.isSuccess
|
||||
} else {
|
||||
insertDBAction(id.toString(), starred = true)
|
||||
true
|
||||
@@ -245,7 +255,7 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap
|
||||
suspend fun markAllAsRead(items: ArrayList<SelfossModel.Item>): Boolean {
|
||||
var success = false
|
||||
|
||||
if (isNetworkAvailable() && api.markAllAsRead(items.map { it.id.toString() })?.isSuccess == true) {
|
||||
if (isNetworkAvailable() && api.markAllAsRead(items.map { it.id.toString() })?.isSuccess) {
|
||||
success = true
|
||||
for (item in items) {
|
||||
markAsReadLocally(item)
|
||||
@@ -334,7 +344,7 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap
|
||||
|
||||
suspend fun updateRemote(): Boolean {
|
||||
return if (isNetworkAvailable()) {
|
||||
api.update()?.equals("finished") ?: false
|
||||
api.update()?.equals("finished")
|
||||
} else {
|
||||
false
|
||||
}
|
||||
@@ -367,8 +377,8 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap
|
||||
|
||||
if (isNetworkAvailable()) {
|
||||
val fetchedVersion = api.version()
|
||||
if (fetchedVersion != null && fetchedVersion.getApiMajorVersion() != apiMajorVersion) {
|
||||
appSettingsService.updateApiVersion(fetchedVersion.getApiMajorVersion())
|
||||
if (fetchedVersion.success && fetchedVersion.data != null && fetchedVersion.data.getApiMajorVersion() != apiMajorVersion) {
|
||||
appSettingsService.updateApiVersion(fetchedVersion.data.getApiMajorVersion())
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -381,10 +391,8 @@ 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()
|
||||
|
||||
// TODO: This function should be private
|
||||
fun getDBSources(): List<SOURCE> = db.sourcesQueries.sources().executeAsList()
|
||||
|
||||
private fun resetDBTagsWithData(tagEntities: List<SelfossModel.Tag>) {
|
||||
@@ -429,7 +437,7 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap
|
||||
val newItems = getMaxItemsForBackground(ItemType.UNREAD)
|
||||
val allItems = getMaxItemsForBackground(ItemType.ALL)
|
||||
val starredItems = getMaxItemsForBackground(ItemType.STARRED)
|
||||
insertDBItems(newItems.orEmpty() + allItems.orEmpty() + starredItems.orEmpty())
|
||||
insertDBItems(newItems + allItems + starredItems)
|
||||
return newItems
|
||||
} catch (e: Throwable) {
|
||||
// We do nothing
|
||||
|
||||
@@ -10,6 +10,7 @@ import io.ktor.client.plugins.contentnegotiation.*
|
||||
import io.ktor.client.plugins.logging.*
|
||||
import io.ktor.client.request.*
|
||||
import io.ktor.client.request.forms.*
|
||||
import io.ktor.client.statement.*
|
||||
import io.ktor.http.*
|
||||
import io.ktor.serialization.kotlinx.json.*
|
||||
import kotlinx.serialization.json.Json
|
||||
@@ -34,7 +35,7 @@ class SelfossApi(private val appSettingsService: AppSettingsService) {
|
||||
appSettingsService.logApiCalls(message)
|
||||
}
|
||||
}
|
||||
level = LogLevel.ALL
|
||||
level = LogLevel.INFO
|
||||
}
|
||||
install(HttpTimeout) {
|
||||
requestTimeoutMillis = appSettingsService.getApiTimeout()
|
||||
@@ -65,11 +66,11 @@ class SelfossApi(private val appSettingsService: AppSettingsService) {
|
||||
client = createHttpClient()
|
||||
}
|
||||
|
||||
suspend fun login(): SelfossModel.SuccessResponse? =
|
||||
client.get(url("/login")) {
|
||||
suspend fun login(): SelfossModel.SuccessResponse =
|
||||
maybeResponse(client.get(url("/login")) {
|
||||
parameter("username", appSettingsService.getUserName())
|
||||
parameter("password", appSettingsService.getPassword())
|
||||
}.body()
|
||||
})
|
||||
|
||||
suspend fun getItems(
|
||||
type: String,
|
||||
@@ -79,8 +80,8 @@ class SelfossApi(private val appSettingsService: AppSettingsService) {
|
||||
search: String?,
|
||||
updatedSince: String?,
|
||||
items: Int? = null
|
||||
): List<SelfossModel.Item>? =
|
||||
client.get(url("/items")) {
|
||||
): SelfossModel.StatusAndData<List<SelfossModel.Item>> =
|
||||
bodyOrFailure(client.get(url("/items")) {
|
||||
parameter("username", appSettingsService.getUserName())
|
||||
parameter("password", appSettingsService.getPassword())
|
||||
parameter("type", type)
|
||||
@@ -90,74 +91,74 @@ class SelfossApi(private val appSettingsService: AppSettingsService) {
|
||||
parameter("updatedsince", updatedSince)
|
||||
parameter("items", items ?: appSettingsService.getItemsNumber())
|
||||
parameter("offset", offset)
|
||||
}.body()
|
||||
})
|
||||
|
||||
suspend fun stats(): SelfossModel.Stats? =
|
||||
client.get(url("/stats")) {
|
||||
suspend fun stats(): SelfossModel.StatusAndData<SelfossModel.Stats> =
|
||||
bodyOrFailure(client.get(url("/stats")) {
|
||||
parameter("username", appSettingsService.getUserName())
|
||||
parameter("password", appSettingsService.getPassword())
|
||||
}.body()
|
||||
})
|
||||
|
||||
suspend fun tags(): List<SelfossModel.Tag>? =
|
||||
client.get(url("/tags")) {
|
||||
suspend fun tags(): SelfossModel.StatusAndData<List<SelfossModel.Tag>> =
|
||||
bodyOrFailure(client.get(url("/tags")) {
|
||||
parameter("username", appSettingsService.getUserName())
|
||||
parameter("password", appSettingsService.getPassword())
|
||||
}.body()
|
||||
})
|
||||
|
||||
suspend fun update(): String? =
|
||||
client.get(url("/update")) {
|
||||
suspend fun update(): SelfossModel.StatusAndData<String> =
|
||||
bodyOrFailure(client.get(url("/update")) {
|
||||
parameter("username", appSettingsService.getUserName())
|
||||
parameter("password", appSettingsService.getPassword())
|
||||
}.body()
|
||||
})
|
||||
|
||||
suspend fun spouts(): Map<String, SelfossModel.Spout>? =
|
||||
client.get(url("/sources/spouts")) {
|
||||
suspend fun spouts(): SelfossModel.StatusAndData<Map<String, SelfossModel.Spout>> =
|
||||
bodyOrFailure(client.get(url("/sources/spouts")) {
|
||||
parameter("username", appSettingsService.getUserName())
|
||||
parameter("password", appSettingsService.getPassword())
|
||||
}.body()
|
||||
})
|
||||
|
||||
suspend fun sources(): ArrayList<SelfossModel.Source>? =
|
||||
client.get(url("/sources/list")) {
|
||||
suspend fun sources(): SelfossModel.StatusAndData<ArrayList<SelfossModel.Source>> =
|
||||
bodyOrFailure(client.get(url("/sources/list")) {
|
||||
parameter("username", appSettingsService.getUserName())
|
||||
parameter("password", appSettingsService.getPassword())
|
||||
}.body()
|
||||
})
|
||||
|
||||
suspend fun version(): SelfossModel.ApiVersion? =
|
||||
client.get(url("/api/about")).body()
|
||||
suspend fun version(): SelfossModel.StatusAndData<SelfossModel.ApiVersion> =
|
||||
bodyOrFailure(client.get(url("/api/about")))
|
||||
|
||||
suspend fun markAsRead(id: String): SelfossModel.SuccessResponse? =
|
||||
client.post(url("/mark/$id")) {
|
||||
suspend fun markAsRead(id: String): SelfossModel.SuccessResponse =
|
||||
maybeResponse(client.post(url("/mark/$id")) {
|
||||
parameter("username", appSettingsService.getUserName())
|
||||
parameter("password", appSettingsService.getPassword())
|
||||
}.body()
|
||||
})
|
||||
|
||||
suspend fun unmarkAsRead(id: String): SelfossModel.SuccessResponse? =
|
||||
client.post(url("/unmark/$id")) {
|
||||
suspend fun unmarkAsRead(id: String): SelfossModel.SuccessResponse =
|
||||
maybeResponse(client.post(url("/unmark/$id")) {
|
||||
parameter("username", appSettingsService.getUserName())
|
||||
parameter("password", appSettingsService.getPassword())
|
||||
}.body()
|
||||
})
|
||||
|
||||
suspend fun starr(id: String): SelfossModel.SuccessResponse? =
|
||||
client.post(url("/starr/$id")) {
|
||||
suspend fun starr(id: String): SelfossModel.SuccessResponse =
|
||||
maybeResponse(client.post(url("/starr/$id")) {
|
||||
parameter("username", appSettingsService.getUserName())
|
||||
parameter("password", appSettingsService.getPassword())
|
||||
}.body()
|
||||
})
|
||||
|
||||
suspend fun unstarr(id: String): SelfossModel.SuccessResponse? =
|
||||
client.post(url("/unstarr/$id")) {
|
||||
suspend fun unstarr(id: String): SelfossModel.SuccessResponse =
|
||||
maybeResponse(client.post(url("/unstarr/$id")) {
|
||||
parameter("username", appSettingsService.getUserName())
|
||||
parameter("password", appSettingsService.getPassword())
|
||||
}.body()
|
||||
})
|
||||
|
||||
suspend fun markAllAsRead(ids: List<String>): SelfossModel.SuccessResponse? =
|
||||
client.submitForm(
|
||||
suspend fun markAllAsRead(ids: List<String>): SelfossModel.SuccessResponse =
|
||||
maybeResponse(client.submitForm(
|
||||
url = url("/mark"),
|
||||
formParameters = Parameters.build {
|
||||
append("username", appSettingsService.getUserName())
|
||||
append("password", appSettingsService.getPassword())
|
||||
ids.map { append("ids[]", it) }
|
||||
}
|
||||
).body()
|
||||
))
|
||||
|
||||
suspend fun createSourceForVersion(
|
||||
title: String,
|
||||
@@ -166,12 +167,14 @@ class SelfossApi(private val appSettingsService: AppSettingsService) {
|
||||
tags: String,
|
||||
filter: String,
|
||||
version: Int
|
||||
): SelfossModel.SuccessResponse? =
|
||||
if (version > 1) {
|
||||
createSource2(title, url, spout, tags, filter)
|
||||
} else {
|
||||
createSource(title, url, spout, tags, filter)
|
||||
}
|
||||
): SelfossModel.SuccessResponse =
|
||||
maybeResponse(
|
||||
if (version > 1) {
|
||||
createSource2(title, url, spout, tags, filter)
|
||||
} else {
|
||||
createSource(title, url, spout, tags, filter)
|
||||
}
|
||||
)
|
||||
|
||||
suspend fun createSource(
|
||||
title: String,
|
||||
@@ -179,7 +182,7 @@ class SelfossApi(private val appSettingsService: AppSettingsService) {
|
||||
spout: String,
|
||||
tags: String,
|
||||
filter: String
|
||||
): SelfossModel.SuccessResponse? =
|
||||
): HttpResponse =
|
||||
client.submitForm(
|
||||
url = url("/source?username=${appSettingsService.getUserName()}&password=${appSettingsService.getPassword()}"),
|
||||
formParameters = Parameters.build {
|
||||
@@ -189,7 +192,7 @@ class SelfossApi(private val appSettingsService: AppSettingsService) {
|
||||
append("tags", tags)
|
||||
append("filter", filter)
|
||||
}
|
||||
).body()
|
||||
)
|
||||
|
||||
suspend fun createSource2(
|
||||
title: String,
|
||||
@@ -197,7 +200,7 @@ class SelfossApi(private val appSettingsService: AppSettingsService) {
|
||||
spout: String,
|
||||
tags: String,
|
||||
filter: String
|
||||
): SelfossModel.SuccessResponse? =
|
||||
): HttpResponse =
|
||||
client.submitForm(
|
||||
url = url("/source?username=${appSettingsService.getUserName()}&password=${appSettingsService.getPassword()}"),
|
||||
formParameters = Parameters.build {
|
||||
@@ -207,11 +210,27 @@ class SelfossApi(private val appSettingsService: AppSettingsService) {
|
||||
append("tags[]", tags)
|
||||
append("filter", filter)
|
||||
}
|
||||
).body()
|
||||
)
|
||||
|
||||
suspend fun deleteSource(id: Int): SelfossModel.SuccessResponse? =
|
||||
client.delete(url("/source/$id")) {
|
||||
suspend fun deleteSource(id: Int): SelfossModel.SuccessResponse =
|
||||
maybeResponse(client.delete(url("/source/$id")) {
|
||||
parameter("username", appSettingsService.getUserName())
|
||||
parameter("password", appSettingsService.getPassword())
|
||||
}.body()
|
||||
})
|
||||
|
||||
suspend fun maybeResponse(r: HttpResponse): SelfossModel.SuccessResponse {
|
||||
return if (r.status.isSuccess()) {
|
||||
r.body()
|
||||
} else {
|
||||
SelfossModel.SuccessResponse(false)
|
||||
}
|
||||
}
|
||||
|
||||
suspend inline fun <reified T> bodyOrFailure(r: HttpResponse): SelfossModel.StatusAndData<T> {
|
||||
return if (r.status.isSuccess()) {
|
||||
SelfossModel.StatusAndData.succes(r.body())
|
||||
} else {
|
||||
SelfossModel.StatusAndData.error()
|
||||
}
|
||||
}
|
||||
}
|
||||
-549
@@ -1,549 +0,0 @@
|
||||
package bou.amine.apps.readerforselfossv2.repository
|
||||
|
||||
import bou.amine.apps.readerforselfossv2.dao.ITEM
|
||||
import bou.amine.apps.readerforselfossv2.dao.ReaderForSelfossDB
|
||||
import bou.amine.apps.readerforselfossv2.dao.SOURCE
|
||||
import bou.amine.apps.readerforselfossv2.dao.TAG
|
||||
import bou.amine.apps.readerforselfossv2.model.SelfossModel
|
||||
import bou.amine.apps.readerforselfossv2.rest.SelfossApi
|
||||
import bou.amine.apps.readerforselfossv2.service.AppSettingsService
|
||||
import bou.amine.apps.readerforselfossv2.utils.ItemType
|
||||
import bou.amine.apps.readerforselfossv2.utils.toEntity
|
||||
import bou.amine.apps.readerforselfossv2.utils.toView
|
||||
import com.github.ln_12.library.ConnectivityStatus
|
||||
import io.mockk.*
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlin.test.*
|
||||
|
||||
class RepositoryTest() {
|
||||
private val connectivityStatus = mockk<ConnectivityStatus>()
|
||||
private val db = mockk<ReaderForSelfossDB>()
|
||||
private val appSettingsService = mockk<AppSettingsService>()
|
||||
private val api = mockk<SelfossApi>()
|
||||
|
||||
private val NUMBER_ARTICLES = 100
|
||||
private val NUMBER_UNREAD = 50
|
||||
private val NUMBER_STARRED = 20
|
||||
|
||||
@BeforeTest
|
||||
fun setup() {
|
||||
clearAllMocks()
|
||||
every { appSettingsService.getApiVersion() } returns 4
|
||||
every { appSettingsService.getBaseUrl() } returns "https://test.com/selfoss/"
|
||||
every { appSettingsService.isItemCachingEnabled() } returns false
|
||||
every { appSettingsService.isUpdateSourcesEnabled() } returns true
|
||||
|
||||
every { connectivityStatus.isNetworkConnected } returns MutableStateFlow(true)
|
||||
|
||||
coEvery { api.version() } returns SelfossModel.ApiVersion("2.19-ba1e8e3", "4.0.0")
|
||||
coEvery { api.stats() } returns SelfossModel.Stats(NUMBER_ARTICLES, NUMBER_UNREAD, NUMBER_STARRED)
|
||||
|
||||
every { db.itemsQueries.items().executeAsList() } returns generateTestDBItems()
|
||||
every { db.tagsQueries.deleteAllTags() } returns Unit
|
||||
every { db.tagsQueries.transaction(any(), any()) } returns Unit
|
||||
every { db.tagsQueries.insertTag(any()) } returns Unit
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Instantiate repository`() {
|
||||
val repository = Repository(api, appSettingsService, connectivityStatus, db)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Instantiate repository without api version`() {
|
||||
every { appSettingsService.getApiVersion() } returns -1
|
||||
every { connectivityStatus.isNetworkConnected } returns MutableStateFlow(false)
|
||||
|
||||
val repository = Repository(api, appSettingsService, connectivityStatus, db)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Instantiate repository with negative stats`() {
|
||||
coEvery { api.stats() } returns SelfossModel.Stats(-100, -50, -20)
|
||||
|
||||
val repository = Repository(api, appSettingsService, connectivityStatus, db)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Get api 4 date with api 1 version stored`() {
|
||||
every { appSettingsService.getApiVersion() } returns 1
|
||||
coEvery { api.getItems(any(), any(), any(), any(), any(), any(), any()) } returns generateTestApiItem()
|
||||
every { appSettingsService.updateApiVersion(any()) } returns Unit
|
||||
|
||||
val repository = Repository(api, appSettingsService, connectivityStatus, db)
|
||||
runBlocking {
|
||||
repository.getNewerItems()
|
||||
}
|
||||
|
||||
assertSame(repository.items.size, 1)
|
||||
verify(exactly = 1) { appSettingsService.updateApiVersion(4) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Get api 1 date with api 4 version stored`() {
|
||||
every { appSettingsService.getApiVersion() } returns 4
|
||||
coEvery { api.version() } returns null
|
||||
val itemParameters = FakeItemParameters()
|
||||
itemParameters.datetime = "2021-04-23 11:45:32"
|
||||
coEvery { api.getItems(any(), any(), any(), any(), any(), any(), any()) } returns generateTestApiItem(itemParameters)
|
||||
|
||||
val repository = Repository(api, appSettingsService, connectivityStatus, db)
|
||||
runBlocking {
|
||||
repository.getNewerItems()
|
||||
}
|
||||
|
||||
assertSame(1, repository.items.size)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Get newer items`() {
|
||||
coEvery { api.getItems(any(), any(), any(), any(), any(), any(), any()) } returns generateTestApiItem()
|
||||
|
||||
val repository = Repository(api, appSettingsService, connectivityStatus, db)
|
||||
runBlocking {
|
||||
repository.getNewerItems()
|
||||
}
|
||||
|
||||
assertSame(repository.items.size, 1)
|
||||
coVerify(exactly = 1) { api.getItems("unread", 0, null, null, null, null, any()) }
|
||||
verify(exactly = 0) { db.itemsQueries.items().executeAsList()}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Get all newer items`() {
|
||||
coEvery { api.getItems(any(), any(), any(), any(), any(), any(), any()) } returns generateTestApiItem()
|
||||
|
||||
val repository = Repository(api, appSettingsService, connectivityStatus, db)
|
||||
repository.displayedItems = ItemType.ALL
|
||||
runBlocking {
|
||||
repository.getNewerItems()
|
||||
}
|
||||
|
||||
assertSame(repository.items.size, 1)
|
||||
coVerify(exactly = 1) { api.getItems("all", 0, null, null, null, null, any()) }
|
||||
verify(exactly = 0) { db.itemsQueries.items().executeAsList()}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Get newer starred items`() {
|
||||
coEvery { api.getItems(any(), any(), any(), any(), any(), any(), any()) } returns generateTestApiItem()
|
||||
|
||||
val repository = Repository(api, appSettingsService, connectivityStatus, db)
|
||||
repository.displayedItems = ItemType.STARRED
|
||||
runBlocking {
|
||||
repository.getNewerItems()
|
||||
}
|
||||
|
||||
assertSame(repository.items.size, 1)
|
||||
coVerify(exactly = 1) { api.getItems("starred", 0, null, null, null, null, any()) }
|
||||
verify(exactly = 0) { db.itemsQueries.items().executeAsList()}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Get newer items without connectivity`() {
|
||||
every { connectivityStatus.isNetworkConnected } returns MutableStateFlow(false)
|
||||
every { appSettingsService.isItemCachingEnabled() } returns true
|
||||
|
||||
val repository = Repository(api, appSettingsService, connectivityStatus, db)
|
||||
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 generateTestApiItem()
|
||||
|
||||
val repository = Repository(api, appSettingsService, connectivityStatus, db)
|
||||
repository.items = ArrayList(generateTestApiItem())
|
||||
runBlocking {
|
||||
repository.getOlderItems()
|
||||
}
|
||||
|
||||
assertSame(repository.items.size, 2)
|
||||
coVerify(exactly = 1) { api.getItems("unread", 1, null, null, null, null, any()) }
|
||||
verify(exactly = 0) { db.itemsQueries.items().executeAsList()}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Get all older items`() {
|
||||
coEvery { api.getItems(any(), any(), any(), any(), any(), any(), any()) } returns generateTestApiItem()
|
||||
|
||||
val repository = Repository(api, appSettingsService, connectivityStatus, db)
|
||||
repository.items = ArrayList(generateTestApiItem())
|
||||
repository.displayedItems = ItemType.ALL
|
||||
runBlocking {
|
||||
repository.getOlderItems()
|
||||
}
|
||||
|
||||
assertSame(repository.items.size, 2)
|
||||
coVerify(exactly = 1) { api.getItems("all", 1, null, null, null, null, any()) }
|
||||
verify(exactly = 0) { db.itemsQueries.items().executeAsList()}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Get older starred items`() {
|
||||
coEvery { api.getItems(any(), any(), any(), any(), any(), any(), any()) } returns generateTestApiItem()
|
||||
|
||||
val repository = Repository(api, appSettingsService, connectivityStatus, db)
|
||||
repository.displayedItems = ItemType.STARRED
|
||||
repository.items = ArrayList(generateTestApiItem())
|
||||
runBlocking {
|
||||
repository.getOlderItems()
|
||||
}
|
||||
|
||||
assertSame(repository.items.size, 2)
|
||||
coVerify(exactly = 1) { api.getItems("starred", 1, null, null, null, null, any()) }
|
||||
verify(exactly = 0) { db.itemsQueries.items().executeAsList()}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Reload badges`() {
|
||||
var success = false
|
||||
|
||||
val repository = Repository(api, appSettingsService, connectivityStatus, db)
|
||||
runBlocking {
|
||||
success = repository.reloadBadges()
|
||||
}
|
||||
|
||||
assertSame(true, success)
|
||||
assertSame(NUMBER_ARTICLES, repository.badgeAll)
|
||||
assertSame(NUMBER_UNREAD, repository.badgeUnread)
|
||||
assertSame(NUMBER_STARRED, repository.badgeStarred)
|
||||
coVerify(atLeast = 1) { api.stats() }
|
||||
verify(exactly = 0) { db.itemsQueries.items().executeAsList()}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Reload badges without response`() {
|
||||
coEvery { api.stats() } returns null
|
||||
|
||||
var success = false
|
||||
|
||||
val repository = Repository(api, appSettingsService, connectivityStatus, db)
|
||||
runBlocking {
|
||||
success = repository.reloadBadges()
|
||||
}
|
||||
|
||||
assertSame(false, success)
|
||||
assertSame(0, repository.badgeAll)
|
||||
assertSame(0, repository.badgeUnread)
|
||||
assertSame(0, repository.badgeStarred)
|
||||
coVerify(atLeast = 1) { api.stats() }
|
||||
verify(exactly = 0) { db.itemsQueries.items().executeAsList()}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Reload badges with items caching`() {
|
||||
every { connectivityStatus.isNetworkConnected } returns MutableStateFlow(false)
|
||||
every { appSettingsService.isItemCachingEnabled() } returns true
|
||||
|
||||
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)
|
||||
assertSame(1, repository.badgeAll)
|
||||
assertSame(0, repository.badgeUnread)
|
||||
assertSame(1, repository.badgeStarred)
|
||||
coVerify(exactly = 0) { api.stats() }
|
||||
verify(atLeast = 1) { db.itemsQueries.items().executeAsList()}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Reload badges without items caching`() {
|
||||
every { connectivityStatus.isNetworkConnected } returns MutableStateFlow(false)
|
||||
every { appSettingsService.isItemCachingEnabled() } returns false
|
||||
|
||||
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(false, success)
|
||||
assertSame(0, repository.badgeAll)
|
||||
assertSame(0, repository.badgeUnread)
|
||||
assertSame(0, repository.badgeStarred)
|
||||
coVerify(exactly = 0) { api.stats() }
|
||||
verify(exactly = 0) { db.itemsQueries.items().executeAsList()}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Get tags`() {
|
||||
val tags = listOf(SelfossModel.Tag("test", "red", 6),
|
||||
SelfossModel.Tag("second", "yellow", 0))
|
||||
|
||||
coEvery { api.tags() } returns tags
|
||||
|
||||
val repository = Repository(api, appSettingsService, connectivityStatus, db)
|
||||
var testTags: List<SelfossModel.Tag>? = null
|
||||
runBlocking {
|
||||
testTags = repository.getTags()
|
||||
}
|
||||
|
||||
assertSame(tags, testTags)
|
||||
verify(exactly = 0) { db.tagsQueries.tags().executeAsList() }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Get tags with sources update 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 tags
|
||||
coEvery { db.tagsQueries.tags().executeAsList() } returns tagsDB
|
||||
every { appSettingsService.isUpdateSourcesEnabled() } returns false
|
||||
|
||||
val repository = Repository(api, appSettingsService, connectivityStatus, db)
|
||||
var testTags: List<SelfossModel.Tag>? = null
|
||||
runBlocking {
|
||||
testTags = repository.getTags()
|
||||
}
|
||||
|
||||
assertNotSame(tags, testTags)
|
||||
assertSame(tagsDB.first().name, testTags?.first()?.tag)
|
||||
coVerify(exactly = 0) { api.tags() }
|
||||
verify(atLeast = 1) { db.tagsQueries.tags().executeAsList() }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Get tags with sources update and db 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 tags
|
||||
coEvery { db.tagsQueries.tags().executeAsList() } returns tagsDB
|
||||
every { appSettingsService.isUpdateSourcesEnabled() } returns false
|
||||
every { appSettingsService.isItemCachingEnabled() } returns false
|
||||
|
||||
val repository = Repository(api, appSettingsService, connectivityStatus, db)
|
||||
var testTags: List<SelfossModel.Tag>? = null
|
||||
runBlocking {
|
||||
testTags = repository.getTags()
|
||||
}
|
||||
|
||||
assertSame(null, testTags)
|
||||
coVerify(exactly = 0) { api.tags() }
|
||||
verify(exactly = 0) { db.tagsQueries.tags().executeAsList() }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Get tags without connection`() {
|
||||
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 tags
|
||||
coEvery { db.tagsQueries.tags().executeAsList() } returns tagsDB
|
||||
every { connectivityStatus.isNetworkConnected } returns MutableStateFlow(false)
|
||||
|
||||
val repository = Repository(api, appSettingsService, connectivityStatus, db)
|
||||
var testTags: List<SelfossModel.Tag>? = null
|
||||
runBlocking {
|
||||
testTags = repository.getTags()
|
||||
}
|
||||
|
||||
assertNotSame(tags, testTags)
|
||||
assertSame(tagsDB.first().name, testTags?.first()?.tag)
|
||||
coVerify(exactly = 0) { api.tags() }
|
||||
verify(atLeast = 1) { db.tagsQueries.tags().executeAsList() }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Get tags without connection 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 tags
|
||||
coEvery { db.tagsQueries.tags().executeAsList() } returns tagsDB
|
||||
every { connectivityStatus.isNetworkConnected } returns MutableStateFlow(false)
|
||||
every { appSettingsService.isItemCachingEnabled() } returns false
|
||||
|
||||
val repository = Repository(api, appSettingsService, connectivityStatus, db)
|
||||
var testTags: List<SelfossModel.Tag>? = null
|
||||
runBlocking {
|
||||
testTags = repository.getTags()
|
||||
}
|
||||
|
||||
assertSame(null, testTags)
|
||||
coVerify(exactly = 0) { api.tags() }
|
||||
verify(exactly = 0) { db.tagsQueries.tags().executeAsList() }
|
||||
}
|
||||
|
||||
@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"))
|
||||
|
||||
coEvery { api.sources() } returns sources
|
||||
val repository = Repository(api, appSettingsService, connectivityStatus, db)
|
||||
var testSources: List<SelfossModel.Source>? = null
|
||||
runBlocking {
|
||||
testSources = repository.getSources()
|
||||
}
|
||||
|
||||
assertSame(sources, testSources)
|
||||
coVerify(exactly = 1) { api.sources() }
|
||||
verify(exactly = 0) { db.sourcesQueries.sources().executeAsList() }
|
||||
}
|
||||
|
||||
@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 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 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() }
|
||||
}
|
||||
|
||||
@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 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
|
||||
coEvery { api.sources() } returns 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()
|
||||
}
|
||||
|
||||
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 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() }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `get sources with sources update 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 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 false
|
||||
coEvery { api.sources() } returns 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()
|
||||
}
|
||||
|
||||
assertSame(null, testSources)
|
||||
coVerify(exactly = 0) { api.sources() }
|
||||
verify(exactly = 0) { db.sourcesQueries.sources().executeAsList() }
|
||||
}
|
||||
}
|
||||
|
||||
fun generateTestDBItems(item : FakeItemParameters = FakeItemParameters()) : List<ITEM> {
|
||||
return listOf(ITEM(
|
||||
id = item.id,
|
||||
datetime = item.datetime,
|
||||
title = item.title,
|
||||
content = item.content,
|
||||
unread = item.unread,
|
||||
starred = item.starred,
|
||||
thumbnail = item.thumbnail,
|
||||
icon = item.icon,
|
||||
link = item.link,
|
||||
sourcetitle = item.sourcetitle,
|
||||
tags = item.tags
|
||||
))}
|
||||
|
||||
fun generateTestApiItem(item : FakeItemParameters = FakeItemParameters()) : List<SelfossModel.Item> {
|
||||
return listOf(
|
||||
SelfossModel.Item(
|
||||
id = item.id.toInt(),
|
||||
datetime = item.datetime,
|
||||
title = item.title,
|
||||
content = item.content,
|
||||
unread = item.unread,
|
||||
starred = item.starred,
|
||||
thumbnail = item.thumbnail,
|
||||
icon = item.icon,
|
||||
link = item.link,
|
||||
sourcetitle = item.sourcetitle,
|
||||
tags = item.tags.split(',')
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
class FakeItemParameters() {
|
||||
val 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>"
|
||||
var unread = true
|
||||
var starred = true
|
||||
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"
|
||||
}
|
||||
Executable
+14
@@ -0,0 +1,14 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo "Creating tag $1"
|
||||
|
||||
TAG="v$1"
|
||||
git tag -a ${TAG} -m ${TAG}
|
||||
|
||||
if [[ "$@" == *'--from-ci'* ]]
|
||||
then
|
||||
echo "Tag created. HANDLE IN CI"
|
||||
else
|
||||
echo "Pushing tag"
|
||||
git push origin ${TAG}
|
||||
fi
|
||||
Reference in New Issue
Block a user