Compare commits
No commits in common. "a4527940b85de608cab74ee682bc63bdb062813e" and "16b10dc1b77e638e87d3d7b663fa4c2d150b6bb7" have entirely different histories.
a4527940b8
...
16b10dc1b7
@ -8,7 +8,7 @@ steps:
|
|||||||
commands:
|
commands:
|
||||||
- echo "---------------------------------------------------------"
|
- echo "---------------------------------------------------------"
|
||||||
- echo "Configure gradle..."
|
- echo "Configure gradle..."
|
||||||
- mkdir -p ~/.gradle && echo "org.gradle.daemon=false\nignoreGitVersion=true\nappLoginUrl=\"URL\"\nappLoginUsername=\"LOGIN\"\nappLoginPassword=\"PASS\"\npushCache=false\nsystemProp.org.gradle.internal.http.connectionTimeout=180000\nsystemProp.org.gradle.internal.http.socketTimeout=180000" >> ~/.gradle/gradle.properties
|
- mkdir -p ~/.gradle && echo "org.gradle.daemon=false\nignoreGitVersion=true\nappLoginUrl=\"URL\"\nappLoginUsername=\"LOGIN\"\nappLoginPassword=\"PASS\"\npushCache=false" >> ~/.gradle/gradle.properties
|
||||||
- echo "---------------------------------------------------------"
|
- echo "---------------------------------------------------------"
|
||||||
- echo "Analysing..."
|
- echo "Analysing..."
|
||||||
- ./gradlew sonarqube -Dsonar.projectKey=RFS2 -Dsonar.host.url=$SONAR_HOST_URL -Dsonar.login=$SONAR_LOGIN
|
- ./gradlew sonarqube -Dsonar.projectKey=RFS2 -Dsonar.host.url=$SONAR_HOST_URL -Dsonar.login=$SONAR_LOGIN
|
||||||
@ -90,7 +90,7 @@ steps:
|
|||||||
commands:
|
commands:
|
||||||
- echo "---------------------------------------------------------"
|
- echo "---------------------------------------------------------"
|
||||||
- echo "Configure gradle..."
|
- echo "Configure gradle..."
|
||||||
- mkdir -p ~/.gradle && echo "org.gradle.daemon=false\nignoreGitVersion=true\nappLoginUrl=\"URL\"\nappLoginUsername=\"LOGIN\"\nappLoginPassword=\"PASS\"\npushCache=false\nsystemProp.org.gradle.internal.http.connectionTimeout=180000\nsystemProp.org.gradle.internal.http.socketTimeout=180000" >> ~/.gradle/gradle.properties
|
- mkdir -p ~/.gradle && echo "org.gradle.daemon=false\nignoreGitVersion=true\nappLoginUrl=\"URL\"\nappLoginUsername=\"LOGIN\"\nappLoginPassword=\"PASS\"\npushCache=false" >> ~/.gradle/gradle.properties
|
||||||
- echo "---------------------------------------------------------"
|
- echo "---------------------------------------------------------"
|
||||||
- echo "Generate APK"
|
- echo "Generate APK"
|
||||||
- ./gradlew :androidApp:assembleGithubConfigRelease -P pushCache=false
|
- ./gradlew :androidApp:assembleGithubConfigRelease -P pushCache=false
|
||||||
|
@ -6,7 +6,6 @@ plugins {
|
|||||||
id("com.android.application")
|
id("com.android.application")
|
||||||
kotlin("android")
|
kotlin("android")
|
||||||
kotlin("kapt")
|
kotlin("kapt")
|
||||||
id("com.mikepenz.aboutlibraries.plugin")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Project.execWithOutput(cmd: String, ignore: Boolean = false): String {
|
fun Project.execWithOutput(cmd: String, ignore: Boolean = false): String {
|
||||||
@ -63,7 +62,7 @@ android {
|
|||||||
kotlinOptions {
|
kotlinOptions {
|
||||||
jvmTarget = "11"
|
jvmTarget = "11"
|
||||||
}
|
}
|
||||||
compileSdk = 33
|
compileSdk = 32
|
||||||
buildToolsVersion = "31.0.0"
|
buildToolsVersion = "31.0.0"
|
||||||
buildFeatures {
|
buildFeatures {
|
||||||
viewBinding = true
|
viewBinding = true
|
||||||
@ -71,7 +70,7 @@ android {
|
|||||||
defaultConfig {
|
defaultConfig {
|
||||||
applicationId = "bou.amine.apps.readerforselfossv2.android"
|
applicationId = "bou.amine.apps.readerforselfossv2.android"
|
||||||
minSdk = 21
|
minSdk = 21
|
||||||
targetSdk = 33
|
targetSdk = 32
|
||||||
versionCode = versionCodeFromGit()
|
versionCode = versionCodeFromGit()
|
||||||
versionName = versionNameFromGit()
|
versionName = versionNameFromGit()
|
||||||
|
|
||||||
@ -139,8 +138,15 @@ dependencies {
|
|||||||
implementation("androidx.multidex:multidex:2.0.1")
|
implementation("androidx.multidex:multidex:2.0.1")
|
||||||
|
|
||||||
// About
|
// About
|
||||||
implementation("com.mikepenz:aboutlibraries-core:10.5.1")
|
implementation("com.mikepenz:aboutlibraries-core:8.9.4")
|
||||||
implementation("com.mikepenz:aboutlibraries:10.5.1")
|
implementation("com.mikepenz:aboutlibraries:8.9.4")
|
||||||
|
implementation("com.mikepenz:aboutlibraries-definitions:8.9.4")
|
||||||
|
|
||||||
|
// Retrofit + http logging + okhttp
|
||||||
|
implementation("com.squareup.retrofit2:retrofit:2.9.0")
|
||||||
|
implementation("com.squareup.okhttp3:logging-interceptor:5.0.0-alpha.3")
|
||||||
|
implementation("com.squareup.retrofit2:converter-gson:2.9.0")
|
||||||
|
implementation("com.burgstaller:okhttp-digest:2.5")
|
||||||
|
|
||||||
// Material-ish things
|
// Material-ish things
|
||||||
implementation("com.ashokvarma.android:bottom-navigation-bar:2.2.0")
|
implementation("com.ashokvarma.android:bottom-navigation-bar:2.2.0")
|
||||||
@ -204,13 +210,3 @@ tasks.withType<Test> {
|
|||||||
showStandardStreams = true
|
showStandardStreams = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
aboutLibraries {
|
|
||||||
offlineMode = true
|
|
||||||
fetchRemoteLicense = false
|
|
||||||
fetchRemoteFunding = false
|
|
||||||
includePlatform = false
|
|
||||||
strictMode = com.mikepenz.aboutlibraries.plugin.StrictMode.FAIL
|
|
||||||
duplicationMode = com.mikepenz.aboutlibraries.plugin.DuplicateMode.MERGE
|
|
||||||
duplicationRule = com.mikepenz.aboutlibraries.plugin.DuplicateRule.GROUP
|
|
||||||
}
|
|
7
androidApp/proguard-rules.pro
vendored
7
androidApp/proguard-rules.pro
vendored
@ -30,8 +30,15 @@
|
|||||||
<fields>;
|
<fields>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
-dontwarn okio.**
|
||||||
|
-dontwarn retrofit2.Platform$Java8
|
||||||
|
-keep class retrofit.** { *; }
|
||||||
|
-keepclasseswithmembers class * {
|
||||||
|
@retrofit.http.* <methods>;
|
||||||
|
}
|
||||||
-keepattributes *Annotation*,Signature
|
-keepattributes *Annotation*,Signature
|
||||||
-keepattributes Exceptions
|
-keepattributes Exceptions
|
||||||
|
-dontwarn okio.**
|
||||||
-dontwarn javax.annotation.Nullable
|
-dontwarn javax.annotation.Nullable
|
||||||
-dontwarn javax.annotation.ParametersAreNonnullByDefault
|
-dontwarn javax.annotation.ParametersAreNonnullByDefault
|
||||||
|
|
||||||
|
@ -15,8 +15,7 @@
|
|||||||
android:supportsRtl="true"
|
android:supportsRtl="true"
|
||||||
android:networkSecurityConfig="@xml/network_security_config"
|
android:networkSecurityConfig="@xml/network_security_config"
|
||||||
android:theme="@style/NoBar"
|
android:theme="@style/NoBar"
|
||||||
android:dataExtractionRules="@xml/data_extraction_rules"
|
android:dataExtractionRules="@xml/data_extraction_rules">
|
||||||
android:configChanges="uiMode">
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".MainActivity"
|
android:name=".MainActivity"
|
||||||
android:theme="@style/SplashTheme"
|
android:theme="@style/SplashTheme"
|
||||||
|
@ -18,7 +18,6 @@ import androidx.appcompat.app.AppCompatActivity
|
|||||||
import androidx.appcompat.widget.SearchView
|
import androidx.appcompat.widget.SearchView
|
||||||
import androidx.core.view.doOnNextLayout
|
import androidx.core.view.doOnNextLayout
|
||||||
import androidx.drawerlayout.widget.DrawerLayout
|
import androidx.drawerlayout.widget.DrawerLayout
|
||||||
import androidx.lifecycle.lifecycleScope
|
|
||||||
import androidx.recyclerview.widget.*
|
import androidx.recyclerview.widget.*
|
||||||
import androidx.work.Constraints
|
import androidx.work.Constraints
|
||||||
import androidx.work.ExistingPeriodicWorkPolicy
|
import androidx.work.ExistingPeriodicWorkPolicy
|
||||||
@ -179,6 +178,8 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
|||||||
|
|
||||||
adapter.handleItemAtIndex(position)
|
adapter.handleItemAtIndex(position)
|
||||||
|
|
||||||
|
reloadBadgeContent()
|
||||||
|
|
||||||
val tagHashes = i.tags.map { it.longHash() }
|
val tagHashes = i.tags.map { it.longHash() }
|
||||||
tagsBadge = tagsBadge.map {
|
tagsBadge = tagsBadge.map {
|
||||||
if (tagHashes.contains(it.key)) {
|
if (tagHashes.contains(it.key)) {
|
||||||
@ -206,16 +207,6 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
|||||||
ItemTouchHelper(simpleItemTouchCallback).attachToRecyclerView(binding.recyclerView)
|
ItemTouchHelper(simpleItemTouchCallback).attachToRecyclerView(binding.recyclerView)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateBottomBarBadgeCount(badge: TextBadgeItem, count: Int) {
|
|
||||||
if (count > 0) {
|
|
||||||
badge
|
|
||||||
.setText(count.toString())
|
|
||||||
.maybeShow()
|
|
||||||
} else {
|
|
||||||
badge.removeBadge()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun handleBottomBar() {
|
private fun handleBottomBar() {
|
||||||
|
|
||||||
tabNewBadge = TextBadgeItem()
|
tabNewBadge = TextBadgeItem()
|
||||||
@ -228,28 +219,6 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
|||||||
.setText("")
|
.setText("")
|
||||||
.setHideOnSelect(false).hide(false)
|
.setHideOnSelect(false).hide(false)
|
||||||
|
|
||||||
if (appSettingsService.isDisplayUnreadCountEnabled()) {
|
|
||||||
lifecycleScope.launch {
|
|
||||||
repository.badgeUnread.collect {
|
|
||||||
updateBottomBarBadgeCount(tabNewBadge, it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (appSettingsService.isDisplayAllCountEnabled()) {
|
|
||||||
lifecycleScope.launch {
|
|
||||||
repository.badgeAll.collect {
|
|
||||||
updateBottomBarBadgeCount(tabArchiveBadge, it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
lifecycleScope.launch {
|
|
||||||
repository.badgeStarred.collect {
|
|
||||||
updateBottomBarBadgeCount(tabStarredBadge, it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val tabNew =
|
val tabNew =
|
||||||
BottomNavigationItem(
|
BottomNavigationItem(
|
||||||
R.drawable.ic_tab_fiber_new_black_24dp,
|
R.drawable.ic_tab_fiber_new_black_24dp,
|
||||||
@ -745,12 +714,29 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
|||||||
|
|
||||||
private fun reloadBadges() {
|
private fun reloadBadges() {
|
||||||
if (appSettingsService.isDisplayUnreadCountEnabled() || appSettingsService.isDisplayAllCountEnabled()) {
|
if (appSettingsService.isDisplayUnreadCountEnabled() || appSettingsService.isDisplayAllCountEnabled()) {
|
||||||
CoroutineScope(Dispatchers.IO).launch {
|
CoroutineScope(Dispatchers.Main).launch {
|
||||||
repository.reloadBadges()
|
repository.reloadBadges()
|
||||||
|
reloadBadgeContent()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun reloadBadgeContent() {
|
||||||
|
if (appSettingsService.isDisplayUnreadCountEnabled()) {
|
||||||
|
tabNewBadge
|
||||||
|
.setText(repository.badgeUnread.toString())
|
||||||
|
.maybeShow()
|
||||||
|
}
|
||||||
|
if (appSettingsService.isDisplayAllCountEnabled()) {
|
||||||
|
tabArchiveBadge
|
||||||
|
.setText(repository.badgeAll.toString())
|
||||||
|
.maybeShow()
|
||||||
|
tabStarredBadge
|
||||||
|
.setText(repository.badgeStarred.toString())
|
||||||
|
.maybeShow()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun reloadTagsBadges() {
|
private fun reloadTagsBadges() {
|
||||||
tagsBadge.forEach {
|
tagsBadge.forEach {
|
||||||
binding.mainDrawer.updateBadge(it.key, StringHolder(it.value.toString()))
|
binding.mainDrawer.updateBadge(it.key, StringHolder(it.value.toString()))
|
||||||
@ -872,10 +858,10 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
|||||||
|
|
||||||
private fun maxItemNumber(): Int =
|
private fun maxItemNumber(): Int =
|
||||||
when (elementsShown) {
|
when (elementsShown) {
|
||||||
ItemType.UNREAD -> repository.badgeUnread.value
|
ItemType.UNREAD -> repository.badgeUnread
|
||||||
ItemType.ALL -> repository.badgeAll.value
|
ItemType.ALL -> repository.badgeAll
|
||||||
ItemType.STARRED -> repository.badgeStarred.value
|
ItemType.STARRED -> repository.badgeStarred
|
||||||
else -> repository.badgeUnread.value // if !elementsShown then unread are fetched.
|
else -> repository.badgeUnread // if !elementsShown then unread are fetched.
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateItems(adapterItems: ArrayList<SelfossModel.Item>) {
|
private fun updateItems(adapterItems: ArrayList<SelfossModel.Item>) {
|
||||||
|
@ -3,14 +3,11 @@ package bou.amine.apps.readerforselfossv2.android
|
|||||||
import android.app.NotificationChannel
|
import android.app.NotificationChannel
|
||||||
import android.app.NotificationManager
|
import android.app.NotificationManager
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.res.Configuration
|
|
||||||
import android.graphics.drawable.Drawable
|
import android.graphics.drawable.Drawable
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.widget.ImageView
|
import android.widget.ImageView
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.appcompat.app.AppCompatDelegate
|
|
||||||
import androidx.appcompat.app.AppCompatDelegate.*
|
|
||||||
import androidx.lifecycle.DefaultLifecycleObserver
|
import androidx.lifecycle.DefaultLifecycleObserver
|
||||||
import androidx.lifecycle.LifecycleOwner
|
import androidx.lifecycle.LifecycleOwner
|
||||||
import androidx.lifecycle.ProcessLifecycleOwner
|
import androidx.lifecycle.ProcessLifecycleOwner
|
||||||
@ -51,7 +48,6 @@ class MyApp : MultiDexApplication(), DIAware {
|
|||||||
private val viewModel: AppViewModel by instance()
|
private val viewModel: AppViewModel by instance()
|
||||||
private val connectivityStatus: ConnectivityStatus by instance()
|
private val connectivityStatus: ConnectivityStatus by instance()
|
||||||
private val driverFactory: DriverFactory by instance()
|
private val driverFactory: DriverFactory by instance()
|
||||||
private val appSettingsService : AppSettingsService by instance()
|
|
||||||
|
|
||||||
// TODO: handle with the "previous" way
|
// TODO: handle with the "previous" way
|
||||||
private val isConnectionAvailable: MutableStateFlow<Boolean> = MutableStateFlow(true)
|
private val isConnectionAvailable: MutableStateFlow<Boolean> = MutableStateFlow(true)
|
||||||
@ -136,19 +132,6 @@ class MyApp : MultiDexApplication(), DIAware {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onConfigurationChanged(newConfig: Configuration) {
|
|
||||||
super.onConfigurationChanged(newConfig)
|
|
||||||
if (appSettingsService.getCurrentTheme() == MODE_NIGHT_FOLLOW_SYSTEM) {
|
|
||||||
var mode = when (newConfig.uiMode and Configuration.UI_MODE_NIGHT_MASK) {
|
|
||||||
Configuration.UI_MODE_NIGHT_YES -> MODE_NIGHT_YES
|
|
||||||
else -> MODE_NIGHT_NO
|
|
||||||
}
|
|
||||||
setDefaultNightMode(mode)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
class AppLifeCycleObserver(val connectivityStatus: ConnectivityStatus, val repository: Repository) : DefaultLifecycleObserver {
|
class AppLifeCycleObserver(val connectivityStatus: ConnectivityStatus, val repository: Repository) : DefaultLifecycleObserver {
|
||||||
|
|
||||||
override fun onResume(owner: LifecycleOwner) {
|
override fun onResume(owner: LifecycleOwner) {
|
||||||
|
@ -36,9 +36,9 @@ class ReaderActivity : AppCompatActivity(), DIAware {
|
|||||||
|
|
||||||
private fun showMenuItem(willAddToFavorite: Boolean) {
|
private fun showMenuItem(willAddToFavorite: Boolean) {
|
||||||
if (willAddToFavorite) {
|
if (willAddToFavorite) {
|
||||||
toolbarMenu.findItem(R.id.star).icon?.setTint(Color.WHITE)
|
toolbarMenu.findItem(R.id.star).icon.setTint(Color.WHITE)
|
||||||
} else {
|
} else {
|
||||||
toolbarMenu.findItem(R.id.star).icon?.setTint(Color.RED)
|
toolbarMenu.findItem(R.id.star).icon.setTint(Color.RED)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,11 +111,13 @@ class ItemCardAdapter(
|
|||||||
CoroutineScope(Dispatchers.IO).launch {
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
repository.unstarr(item)
|
repository.unstarr(item)
|
||||||
}
|
}
|
||||||
|
item.starred = false
|
||||||
binding.favButton.isSelected = false
|
binding.favButton.isSelected = false
|
||||||
} else {
|
} else {
|
||||||
CoroutineScope(Dispatchers.IO).launch {
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
repository.starr(item)
|
repository.starr(item)
|
||||||
}
|
}
|
||||||
|
item.starred = true
|
||||||
binding.favButton.isSelected = true
|
binding.favButton.isSelected = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,35 @@
|
|||||||
|
package bou.amine.apps.readerforselfossv2.android.api.mercury
|
||||||
|
|
||||||
|
import com.google.gson.GsonBuilder
|
||||||
|
import okhttp3.OkHttpClient
|
||||||
|
import okhttp3.logging.HttpLoggingInterceptor
|
||||||
|
import retrofit2.Call
|
||||||
|
import retrofit2.Retrofit
|
||||||
|
import retrofit2.converter.gson.GsonConverterFactory
|
||||||
|
|
||||||
|
class MercuryApi() {
|
||||||
|
private val service: MercuryService
|
||||||
|
|
||||||
|
init {
|
||||||
|
|
||||||
|
val interceptor = HttpLoggingInterceptor()
|
||||||
|
interceptor.level = HttpLoggingInterceptor.Level.NONE
|
||||||
|
val client = OkHttpClient.Builder().addInterceptor(interceptor).build()
|
||||||
|
|
||||||
|
val gson = GsonBuilder()
|
||||||
|
.setLenient()
|
||||||
|
.create()
|
||||||
|
val retrofit =
|
||||||
|
Retrofit
|
||||||
|
.Builder()
|
||||||
|
.baseUrl("https://www.amine-louveau.fr")
|
||||||
|
.client(client)
|
||||||
|
.addConverterFactory(GsonConverterFactory.create(gson))
|
||||||
|
.build()
|
||||||
|
service = retrofit.create(MercuryService::class.java)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun parseUrl(url: String): Call<ParsedContent> {
|
||||||
|
return service.parseUrl(url)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,59 @@
|
|||||||
|
package bou.amine.apps.readerforselfossv2.android.api.mercury
|
||||||
|
|
||||||
|
import android.os.Parcel
|
||||||
|
import android.os.Parcelable
|
||||||
|
import com.google.gson.annotations.SerializedName
|
||||||
|
|
||||||
|
class ParsedContent(
|
||||||
|
@SerializedName("title") val title: String,
|
||||||
|
@SerializedName("content") val content: String?,
|
||||||
|
@SerializedName("date_published") val date_published: String,
|
||||||
|
@SerializedName("lead_image_url") val lead_image_url: String?,
|
||||||
|
@SerializedName("dek") val dek: String,
|
||||||
|
@SerializedName("url") val url: String,
|
||||||
|
@SerializedName("domain") val domain: String,
|
||||||
|
@SerializedName("excerpt") val excerpt: String,
|
||||||
|
@SerializedName("total_pages") val total_pages: Int,
|
||||||
|
@SerializedName("rendered_pages") val rendered_pages: Int,
|
||||||
|
@SerializedName("next_page_url") val next_page_url: String
|
||||||
|
) : Parcelable {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
@JvmField
|
||||||
|
val CREATOR: Parcelable.Creator<ParsedContent> =
|
||||||
|
object : Parcelable.Creator<ParsedContent> {
|
||||||
|
override fun createFromParcel(source: Parcel): ParsedContent = ParsedContent(source)
|
||||||
|
override fun newArray(size: Int): Array<ParsedContent?> = arrayOfNulls(size)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(source: Parcel) : this(
|
||||||
|
title = source.readString().orEmpty(),
|
||||||
|
content = source.readString(),
|
||||||
|
date_published = source.readString().orEmpty(),
|
||||||
|
lead_image_url = source.readString(),
|
||||||
|
dek = source.readString().orEmpty(),
|
||||||
|
url = source.readString().orEmpty(),
|
||||||
|
domain = source.readString().orEmpty(),
|
||||||
|
excerpt = source.readString().orEmpty(),
|
||||||
|
total_pages = source.readInt(),
|
||||||
|
rendered_pages = source.readInt(),
|
||||||
|
next_page_url = source.readString().orEmpty()
|
||||||
|
)
|
||||||
|
|
||||||
|
override fun describeContents() = 0
|
||||||
|
|
||||||
|
override fun writeToParcel(dest: Parcel, flags: Int) {
|
||||||
|
dest.writeString(title)
|
||||||
|
dest.writeString(content)
|
||||||
|
dest.writeString(date_published)
|
||||||
|
dest.writeString(lead_image_url)
|
||||||
|
dest.writeString(dek)
|
||||||
|
dest.writeString(url)
|
||||||
|
dest.writeString(domain)
|
||||||
|
dest.writeString(excerpt)
|
||||||
|
dest.writeInt(total_pages)
|
||||||
|
dest.writeInt(rendered_pages)
|
||||||
|
dest.writeString(next_page_url)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,10 @@
|
|||||||
|
package bou.amine.apps.readerforselfossv2.android.api.mercury
|
||||||
|
|
||||||
|
import retrofit2.Call
|
||||||
|
import retrofit2.http.GET
|
||||||
|
import retrofit2.http.Query
|
||||||
|
|
||||||
|
interface MercuryService {
|
||||||
|
@GET("parser.php")
|
||||||
|
fun parseUrl(@Query("link") link: String): Call<ParsedContent>
|
||||||
|
}
|
@ -21,6 +21,8 @@ import androidx.core.widget.NestedScrollView
|
|||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import bou.amine.apps.readerforselfossv2.android.ImageActivity
|
import bou.amine.apps.readerforselfossv2.android.ImageActivity
|
||||||
import bou.amine.apps.readerforselfossv2.android.R
|
import bou.amine.apps.readerforselfossv2.android.R
|
||||||
|
import bou.amine.apps.readerforselfossv2.android.api.mercury.MercuryApi
|
||||||
|
import bou.amine.apps.readerforselfossv2.android.api.mercury.ParsedContent
|
||||||
import bou.amine.apps.readerforselfossv2.android.databinding.FragmentArticleBinding
|
import bou.amine.apps.readerforselfossv2.android.databinding.FragmentArticleBinding
|
||||||
import bou.amine.apps.readerforselfossv2.android.model.ParecelableItem
|
import bou.amine.apps.readerforselfossv2.android.model.ParecelableItem
|
||||||
import bou.amine.apps.readerforselfossv2.android.model.toModel
|
import bou.amine.apps.readerforselfossv2.android.model.toModel
|
||||||
@ -30,7 +32,6 @@ import bou.amine.apps.readerforselfossv2.android.utils.openInBrowserAsNewTask
|
|||||||
import bou.amine.apps.readerforselfossv2.android.utils.shareLink
|
import bou.amine.apps.readerforselfossv2.android.utils.shareLink
|
||||||
import bou.amine.apps.readerforselfossv2.model.SelfossModel
|
import bou.amine.apps.readerforselfossv2.model.SelfossModel
|
||||||
import bou.amine.apps.readerforselfossv2.repository.Repository
|
import bou.amine.apps.readerforselfossv2.repository.Repository
|
||||||
import bou.amine.apps.readerforselfossv2.rest.MercuryApi
|
|
||||||
import bou.amine.apps.readerforselfossv2.service.AppSettingsService
|
import bou.amine.apps.readerforselfossv2.service.AppSettingsService
|
||||||
import bou.amine.apps.readerforselfossv2.utils.getHtmlDecoded
|
import bou.amine.apps.readerforselfossv2.utils.getHtmlDecoded
|
||||||
import bou.amine.apps.readerforselfossv2.utils.getImages
|
import bou.amine.apps.readerforselfossv2.utils.getImages
|
||||||
@ -48,6 +49,9 @@ import org.kodein.di.DI
|
|||||||
import org.kodein.di.DIAware
|
import org.kodein.di.DIAware
|
||||||
import org.kodein.di.android.x.closestDI
|
import org.kodein.di.android.x.closestDI
|
||||||
import org.kodein.di.instance
|
import org.kodein.di.instance
|
||||||
|
import retrofit2.Call
|
||||||
|
import retrofit2.Callback
|
||||||
|
import retrofit2.Response
|
||||||
import java.net.MalformedURLException
|
import java.net.MalformedURLException
|
||||||
import java.net.URL
|
import java.net.URL
|
||||||
import java.util.*
|
import java.util.*
|
||||||
@ -77,9 +81,6 @@ class ArticleFragment : Fragment(), DIAware {
|
|||||||
private var font = ""
|
private var font = ""
|
||||||
private var staticBar = false
|
private var staticBar = false
|
||||||
|
|
||||||
private val mercuryApi : MercuryApi by instance()
|
|
||||||
|
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
@ -248,21 +249,26 @@ class ArticleFragment : Fragment(), DIAware {
|
|||||||
private fun getContentFromMercury() {
|
private fun getContentFromMercury() {
|
||||||
if (repository.isNetworkAvailable()) {
|
if (repository.isNetworkAvailable()) {
|
||||||
binding.progressBar.visibility = View.VISIBLE
|
binding.progressBar.visibility = View.VISIBLE
|
||||||
|
val parser = MercuryApi()
|
||||||
|
|
||||||
CoroutineScope(Dispatchers.Main).launch {
|
parser.parseUrl(url).enqueue(
|
||||||
val response = mercuryApi.query(url)
|
object : Callback<ParsedContent> {
|
||||||
if (response.success) {
|
override fun onResponse(
|
||||||
|
call: Call<ParsedContent>,
|
||||||
|
response: Response<ParsedContent>
|
||||||
|
) {
|
||||||
|
// TODO: clean all the following after finding the mercury content issue
|
||||||
try {
|
try {
|
||||||
if (response.data != null && response.data!!.content != null && !response.data!!.content.isNullOrEmpty()) {
|
if (response.body() != null && response.body()!!.content != null && !response.body()!!.content.isNullOrEmpty()) {
|
||||||
try {
|
try {
|
||||||
binding.titleView.text = response.data!!.title
|
binding.titleView.text = response.body()!!.title
|
||||||
if (typeface != null) {
|
if (typeface != null) {
|
||||||
binding.titleView.typeface = typeface
|
binding.titleView.typeface = typeface
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
// Note: Mercury may return relative urls... If it does the url val will not be changed.
|
// Note: Mercury may return relative urls... If it does the url val will not be changed.
|
||||||
URL(response.data!!.url)
|
URL(response.body()!!.url)
|
||||||
url = response.data!!.url
|
url = response.body()!!.url
|
||||||
} catch (e: MalformedURLException) {
|
} catch (e: MalformedURLException) {
|
||||||
// Mercury returned a relative url. We do nothing.
|
// Mercury returned a relative url. We do nothing.
|
||||||
}
|
}
|
||||||
@ -270,20 +276,20 @@ class ArticleFragment : Fragment(), DIAware {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
contentText = response.data!!.content.orEmpty()
|
contentText = response.body()!!.content.orEmpty()
|
||||||
htmlToWebview()
|
htmlToWebview()
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (response.data!!.lead_image_url != null && !response.data!!.lead_image_url.isNullOrEmpty() && context != null) {
|
if (response.body()!!.lead_image_url != null && !response.body()!!.lead_image_url.isNullOrEmpty() && context != null) {
|
||||||
binding.imageView.visibility = View.VISIBLE
|
binding.imageView.visibility = View.VISIBLE
|
||||||
try {
|
try {
|
||||||
Glide
|
Glide
|
||||||
.with(requireContext())
|
.with(requireContext())
|
||||||
.asBitmap()
|
.asBitmap()
|
||||||
.load(
|
.load(
|
||||||
response.data!!.lead_image_url.orEmpty()
|
response.body()!!.lead_image_url.orEmpty()
|
||||||
)
|
)
|
||||||
.apply(RequestOptions.fitCenterTransform())
|
.apply(RequestOptions.fitCenterTransform())
|
||||||
.into(binding.imageView)
|
.into(binding.imageView)
|
||||||
@ -317,10 +323,14 @@ class ArticleFragment : Fragment(), DIAware {
|
|||||||
if (context != null) {
|
if (context != null) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
openInBrowserAfterFailing()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onFailure(
|
||||||
|
call: Call<ParsedContent>,
|
||||||
|
t: Throwable
|
||||||
|
) = openInBrowserAfterFailing()
|
||||||
}
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -379,7 +389,7 @@ class ArticleFragment : Fragment(), DIAware {
|
|||||||
}
|
}
|
||||||
|
|
||||||
val gestureDetector = GestureDetector(activity, object : GestureDetector.SimpleOnGestureListener() {
|
val gestureDetector = GestureDetector(activity, object : GestureDetector.SimpleOnGestureListener() {
|
||||||
override fun onSingleTapUp(e: MotionEvent): Boolean {
|
override fun onSingleTapUp(e: MotionEvent?): Boolean {
|
||||||
return performClick()
|
return performClick()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -400,7 +410,6 @@ class ArticleFragment : Fragment(), DIAware {
|
|||||||
val fontName = when (font) {
|
val fontName = when (font) {
|
||||||
getString(R.string.open_sans_font_id) -> "Open Sans"
|
getString(R.string.open_sans_font_id) -> "Open Sans"
|
||||||
getString(R.string.roboto_font_id) -> "Roboto"
|
getString(R.string.roboto_font_id) -> "Roboto"
|
||||||
getString(R.string.source_code_pro_font_id) -> "Source Code Pro"
|
|
||||||
else -> ""
|
else -> ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@ package bou.amine.apps.readerforselfossv2.android.model
|
|||||||
import android.os.Parcel
|
import android.os.Parcel
|
||||||
import android.os.Parcelable
|
import android.os.Parcelable
|
||||||
import bou.amine.apps.readerforselfossv2.model.SelfossModel
|
import bou.amine.apps.readerforselfossv2.model.SelfossModel
|
||||||
|
import com.google.gson.annotations.SerializedName
|
||||||
|
|
||||||
fun SelfossModel.Item.toParcelable() : ParecelableItem =
|
fun SelfossModel.Item.toParcelable() : ParecelableItem =
|
||||||
ParecelableItem(
|
ParecelableItem(
|
||||||
@ -33,17 +34,17 @@ fun ParecelableItem.toModel() : SelfossModel.Item =
|
|||||||
this.tags.split(",")
|
this.tags.split(",")
|
||||||
)
|
)
|
||||||
data class ParecelableItem(
|
data class ParecelableItem(
|
||||||
val id: Int,
|
@SerializedName("id") val id: Int,
|
||||||
val datetime: String,
|
@SerializedName("datetime") val datetime: String,
|
||||||
val title: String,
|
@SerializedName("title") val title: String,
|
||||||
val content: String,
|
@SerializedName("content") val content: String,
|
||||||
var unread: Boolean,
|
@SerializedName("unread") var unread: Boolean,
|
||||||
var starred: Boolean,
|
@SerializedName("starred") var starred: Boolean,
|
||||||
val thumbnail: String?,
|
@SerializedName("thumbnail") val thumbnail: String?,
|
||||||
val icon: String?,
|
@SerializedName("icon") val icon: String?,
|
||||||
val link: String,
|
@SerializedName("link") val link: String,
|
||||||
val sourcetitle: String,
|
@SerializedName("sourcetitle") val sourcetitle: String,
|
||||||
val tags: String
|
@SerializedName("tags") val tags: String
|
||||||
) : Parcelable {
|
) : Parcelable {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
@ -1,7 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<font-family xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
||||||
app:fontProviderAuthority="com.google.android.gms.fonts"
|
|
||||||
app:fontProviderPackage="com.google.android.gms"
|
|
||||||
app:fontProviderQuery="name=Source Code Pro&weight=500"
|
|
||||||
app:fontProviderCerts="@array/com_google_android_gms_fonts_certs">
|
|
||||||
</font-family>
|
|
@ -9,7 +9,7 @@
|
|||||||
<string-array name="ModeValues">
|
<string-array name="ModeValues">
|
||||||
<item>1</item> <!--MODE_NIGHT_NO-->
|
<item>1</item> <!--MODE_NIGHT_NO-->
|
||||||
<item>2</item> <!--MODE_NIGHT_YES-->
|
<item>2</item> <!--MODE_NIGHT_YES-->
|
||||||
<item>-1</item> <!--MODE_NIGHT_FOLLOW_SYSTEM-->
|
<item>0</item> <!--MODE_NIGHT_AUTO_TIME-->
|
||||||
</string-array>
|
</string-array>
|
||||||
|
|
||||||
<string-array name="Voice">
|
<string-array name="Voice">
|
||||||
|
@ -3,6 +3,5 @@
|
|||||||
<array name="preloaded_fonts" translatable="false">
|
<array name="preloaded_fonts" translatable="false">
|
||||||
<item>@font/open_sans</item>
|
<item>@font/open_sans</item>
|
||||||
<item>@font/roboto</item>
|
<item>@font/roboto</item>
|
||||||
<item>@font/source_code_pro_medium</item>
|
|
||||||
</array>
|
</array>
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -4,6 +4,5 @@
|
|||||||
<item></item>
|
<item></item>
|
||||||
<item>@string/open_sans_font_id</item>
|
<item>@string/open_sans_font_id</item>
|
||||||
<item>@string/roboto_font_id</item>
|
<item>@string/roboto_font_id</item>
|
||||||
<item>@string/source_code_pro_font_id</item>
|
|
||||||
</array>
|
</array>
|
||||||
</resources>
|
</resources>
|
@ -4,6 +4,5 @@
|
|||||||
<item>Systems</item>
|
<item>Systems</item>
|
||||||
<item>Open Sans</item>
|
<item>Open Sans</item>
|
||||||
<item>Roboto</item>
|
<item>Roboto</item>
|
||||||
<item>Source Code Pro</item>
|
|
||||||
</array>
|
</array>
|
||||||
</resources>
|
</resources>
|
@ -125,7 +125,6 @@
|
|||||||
<string name="reader_text_align_left">Align left</string>
|
<string name="reader_text_align_left">Align left</string>
|
||||||
<string name="reader_text_align_justify">Justify</string>
|
<string name="reader_text_align_justify">Justify</string>
|
||||||
<string name="settings_reader_font">Reader font</string>
|
<string name="settings_reader_font">Reader font</string>
|
||||||
<string name="source_code_pro_font_id" translatable="false">source_code_pro_medium</string>
|
|
||||||
<string name="open_sans_font_id" translatable="false">open_sans</string>
|
<string name="open_sans_font_id" translatable="false">open_sans</string>
|
||||||
<string name="roboto_font_id" translatable="false">roboto</string>
|
<string name="roboto_font_id" translatable="false">roboto</string>
|
||||||
<string name="reader_static_bar_title">Static bottom bar in the article viewer</string>
|
<string name="reader_static_bar_title">Static bottom bar in the article viewer</string>
|
||||||
|
@ -4,8 +4,6 @@ import bou.amine.apps.readerforselfossv2.dao.ReaderForSelfossDB
|
|||||||
import bou.amine.apps.readerforselfossv2.dao.SOURCE
|
import bou.amine.apps.readerforselfossv2.dao.SOURCE
|
||||||
import bou.amine.apps.readerforselfossv2.dao.TAG
|
import bou.amine.apps.readerforselfossv2.dao.TAG
|
||||||
import bou.amine.apps.readerforselfossv2.model.SelfossModel
|
import bou.amine.apps.readerforselfossv2.model.SelfossModel
|
||||||
import bou.amine.apps.readerforselfossv2.model.StatusAndData
|
|
||||||
import bou.amine.apps.readerforselfossv2.model.SuccessResponse
|
|
||||||
import bou.amine.apps.readerforselfossv2.rest.SelfossApi
|
import bou.amine.apps.readerforselfossv2.rest.SelfossApi
|
||||||
import bou.amine.apps.readerforselfossv2.service.AppSettingsService
|
import bou.amine.apps.readerforselfossv2.service.AppSettingsService
|
||||||
import bou.amine.apps.readerforselfossv2.utils.ItemType
|
import bou.amine.apps.readerforselfossv2.utils.ItemType
|
||||||
@ -49,11 +47,11 @@ class RepositoryTest {
|
|||||||
every { appSettingsService.isItemCachingEnabled() } returns false
|
every { appSettingsService.isItemCachingEnabled() } returns false
|
||||||
every { appSettingsService.isUpdateSourcesEnabled() } returns false
|
every { appSettingsService.isUpdateSourcesEnabled() } returns false
|
||||||
|
|
||||||
coEvery { api.version() } returns StatusAndData(
|
coEvery { api.version() } returns SelfossModel.StatusAndData(
|
||||||
success = true,
|
success = true,
|
||||||
data = SelfossModel.ApiVersion("2.19-ba1e8e3", "4.0.0")
|
data = SelfossModel.ApiVersion("2.19-ba1e8e3", "4.0.0")
|
||||||
)
|
)
|
||||||
coEvery { api.stats() } returns StatusAndData(
|
coEvery { api.stats() } returns SelfossModel.StatusAndData(
|
||||||
success = true,
|
success = true,
|
||||||
data = SelfossModel.Stats(NUMBER_ARTICLES, NUMBER_UNREAD, NUMBER_STARRED)
|
data = SelfossModel.Stats(NUMBER_ARTICLES, NUMBER_UNREAD, NUMBER_STARRED)
|
||||||
)
|
)
|
||||||
@ -85,7 +83,7 @@ class RepositoryTest {
|
|||||||
fun get_api_4_date_with_api_1_version_stored() {
|
fun get_api_4_date_with_api_1_version_stored() {
|
||||||
every { appSettingsService.getApiVersion() } returns 1
|
every { appSettingsService.getApiVersion() } returns 1
|
||||||
coEvery { api.getItems(any(), any(), any(), any(), any(), any(), any()) } returns
|
coEvery { api.getItems(any(), any(), any(), any(), any(), any(), any()) } returns
|
||||||
StatusAndData(success = true, data = generateTestApiItem())
|
SelfossModel.StatusAndData(success = true, data = generateTestApiItem())
|
||||||
every { appSettingsService.updateApiVersion(any()) } returns Unit
|
every { appSettingsService.updateApiVersion(any()) } returns Unit
|
||||||
|
|
||||||
initializeRepository()
|
initializeRepository()
|
||||||
@ -100,11 +98,11 @@ class RepositoryTest {
|
|||||||
@Test
|
@Test
|
||||||
fun get_api_1_date_with_api_4_version_stored() {
|
fun get_api_1_date_with_api_4_version_stored() {
|
||||||
every { appSettingsService.getApiVersion() } returns 4
|
every { appSettingsService.getApiVersion() } returns 4
|
||||||
coEvery { api.version() } returns StatusAndData(success = false, null)
|
coEvery { api.version() } returns SelfossModel.StatusAndData(success = false, null)
|
||||||
val itemParameters = FakeItemParameters()
|
val itemParameters = FakeItemParameters()
|
||||||
itemParameters.datetime = "2021-04-23 11:45:32"
|
itemParameters.datetime = "2021-04-23 11:45:32"
|
||||||
coEvery { api.getItems(any(), any(), any(), any(), any(), any(), any()) } returns
|
coEvery { api.getItems(any(), any(), any(), any(), any(), any(), any()) } returns
|
||||||
StatusAndData(
|
SelfossModel.StatusAndData(
|
||||||
success = true,
|
success = true,
|
||||||
data = generateTestApiItem(itemParameters)
|
data = generateTestApiItem(itemParameters)
|
||||||
)
|
)
|
||||||
@ -120,7 +118,7 @@ class RepositoryTest {
|
|||||||
@Test
|
@Test
|
||||||
fun get_newer_items() {
|
fun get_newer_items() {
|
||||||
coEvery { api.getItems(any(), any(), any(), any(), any(), any(), any()) } returns
|
coEvery { api.getItems(any(), any(), any(), any(), any(), any(), any()) } returns
|
||||||
StatusAndData(success = true, data = generateTestApiItem())
|
SelfossModel.StatusAndData(success = true, data = generateTestApiItem())
|
||||||
|
|
||||||
initializeRepository()
|
initializeRepository()
|
||||||
runBlocking {
|
runBlocking {
|
||||||
@ -135,7 +133,7 @@ class RepositoryTest {
|
|||||||
@Test
|
@Test
|
||||||
fun get_all_newer_items() {
|
fun get_all_newer_items() {
|
||||||
coEvery { api.getItems(any(), any(), any(), any(), any(), any(), any()) } returns
|
coEvery { api.getItems(any(), any(), any(), any(), any(), any(), any()) } returns
|
||||||
StatusAndData(success = true, data = generateTestApiItem())
|
SelfossModel.StatusAndData(success = true, data = generateTestApiItem())
|
||||||
|
|
||||||
initializeRepository()
|
initializeRepository()
|
||||||
repository.displayedItems = ItemType.ALL
|
repository.displayedItems = ItemType.ALL
|
||||||
@ -151,7 +149,7 @@ class RepositoryTest {
|
|||||||
@Test
|
@Test
|
||||||
fun get_newer_starred_items() {
|
fun get_newer_starred_items() {
|
||||||
coEvery { api.getItems(any(), any(), any(), any(), any(), any(), any()) } returns
|
coEvery { api.getItems(any(), any(), any(), any(), any(), any(), any()) } returns
|
||||||
StatusAndData(success = true, data = generateTestApiItem())
|
SelfossModel.StatusAndData(success = true, data = generateTestApiItem())
|
||||||
|
|
||||||
initializeRepository()
|
initializeRepository()
|
||||||
repository.displayedItems = ItemType.STARRED
|
repository.displayedItems = ItemType.STARRED
|
||||||
@ -244,7 +242,7 @@ class RepositoryTest {
|
|||||||
@Test
|
@Test
|
||||||
fun get_older_items() {
|
fun get_older_items() {
|
||||||
coEvery { api.getItems(any(), any(), any(), any(), any(), any(), any()) } returns
|
coEvery { api.getItems(any(), any(), any(), any(), any(), any(), any()) } returns
|
||||||
StatusAndData(success = true, data = generateTestApiItem())
|
SelfossModel.StatusAndData(success = true, data = generateTestApiItem())
|
||||||
|
|
||||||
initializeRepository()
|
initializeRepository()
|
||||||
repository.items = ArrayList(generateTestApiItem())
|
repository.items = ArrayList(generateTestApiItem())
|
||||||
@ -260,7 +258,7 @@ class RepositoryTest {
|
|||||||
@Test
|
@Test
|
||||||
fun get_all_older_items() {
|
fun get_all_older_items() {
|
||||||
coEvery { api.getItems(any(), any(), any(), any(), any(), any(), any()) } returns
|
coEvery { api.getItems(any(), any(), any(), any(), any(), any(), any()) } returns
|
||||||
StatusAndData(success = true, data = generateTestApiItem())
|
SelfossModel.StatusAndData(success = true, data = generateTestApiItem())
|
||||||
|
|
||||||
initializeRepository()
|
initializeRepository()
|
||||||
repository.items = ArrayList(generateTestApiItem())
|
repository.items = ArrayList(generateTestApiItem())
|
||||||
@ -277,7 +275,7 @@ class RepositoryTest {
|
|||||||
@Test
|
@Test
|
||||||
fun get_older_starred_items() {
|
fun get_older_starred_items() {
|
||||||
coEvery { api.getItems(any(), any(), any(), any(), any(), any(), any()) } returns
|
coEvery { api.getItems(any(), any(), any(), any(), any(), any(), any()) } returns
|
||||||
StatusAndData(success = true, data = generateTestApiItem())
|
SelfossModel.StatusAndData(success = true, data = generateTestApiItem())
|
||||||
|
|
||||||
initializeRepository()
|
initializeRepository()
|
||||||
repository.displayedItems = ItemType.STARRED
|
repository.displayedItems = ItemType.STARRED
|
||||||
@ -301,16 +299,16 @@ class RepositoryTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
assertSame(true, success)
|
assertSame(true, success)
|
||||||
assertEquals(NUMBER_ARTICLES, repository.badgeAll.value)
|
assertSame(NUMBER_ARTICLES, repository.badgeAll)
|
||||||
assertEquals(NUMBER_UNREAD, repository.badgeUnread.value)
|
assertSame(NUMBER_UNREAD, repository.badgeUnread)
|
||||||
assertEquals(NUMBER_STARRED, repository.badgeStarred.value)
|
assertSame(NUMBER_STARRED, repository.badgeStarred)
|
||||||
coVerify(atLeast = 1) { api.stats() }
|
coVerify(atLeast = 1) { api.stats() }
|
||||||
verify(exactly = 0) { db.itemsQueries.items().executeAsList() }
|
verify(exactly = 0) { db.itemsQueries.items().executeAsList() }
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun reload_badges_without_response() {
|
fun reload_badges_without_response() {
|
||||||
coEvery { api.stats() } returns StatusAndData(success = false, data = null)
|
coEvery { api.stats() } returns SelfossModel.StatusAndData(success = false, data = null)
|
||||||
|
|
||||||
var success: Boolean
|
var success: Boolean
|
||||||
|
|
||||||
@ -320,9 +318,9 @@ class RepositoryTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
assertSame(false, success)
|
assertSame(false, success)
|
||||||
assertSame(0, repository.badgeAll.value)
|
assertSame(0, repository.badgeAll)
|
||||||
assertSame(0, repository.badgeUnread.value)
|
assertSame(0, repository.badgeUnread)
|
||||||
assertSame(0, repository.badgeStarred.value)
|
assertSame(0, repository.badgeStarred)
|
||||||
coVerify(atLeast = 1) { api.stats() }
|
coVerify(atLeast = 1) { api.stats() }
|
||||||
verify(exactly = 0) { db.itemsQueries.items().executeAsList() }
|
verify(exactly = 0) { db.itemsQueries.items().executeAsList() }
|
||||||
}
|
}
|
||||||
@ -340,9 +338,9 @@ class RepositoryTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
assertTrue(success)
|
assertTrue(success)
|
||||||
assertEquals(1, repository.badgeAll.value)
|
assertSame(1, repository.badgeAll)
|
||||||
assertEquals(1, repository.badgeUnread.value)
|
assertSame(1, repository.badgeUnread)
|
||||||
assertEquals(1, repository.badgeStarred.value)
|
assertSame(1, repository.badgeStarred)
|
||||||
coVerify(exactly = 0) { api.stats() }
|
coVerify(exactly = 0) { api.stats() }
|
||||||
verify(atLeast = 1) { db.itemsQueries.items().executeAsList() }
|
verify(atLeast = 1) { db.itemsQueries.items().executeAsList() }
|
||||||
}
|
}
|
||||||
@ -360,9 +358,9 @@ class RepositoryTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
assertFalse(success)
|
assertFalse(success)
|
||||||
assertSame(0, repository.badgeAll.value)
|
assertSame(0, repository.badgeAll)
|
||||||
assertSame(0, repository.badgeUnread.value)
|
assertSame(0, repository.badgeUnread)
|
||||||
assertSame(0, repository.badgeStarred.value)
|
assertSame(0, repository.badgeStarred)
|
||||||
coVerify(exactly = 0) { api.stats() }
|
coVerify(exactly = 0) { api.stats() }
|
||||||
verify(exactly = 0) { db.itemsQueries.items().executeAsList() }
|
verify(exactly = 0) { db.itemsQueries.items().executeAsList() }
|
||||||
}
|
}
|
||||||
@ -378,7 +376,7 @@ class RepositoryTest {
|
|||||||
TAG("second_DB", "yellow", 0)
|
TAG("second_DB", "yellow", 0)
|
||||||
)
|
)
|
||||||
|
|
||||||
coEvery { api.tags() } returns StatusAndData(success = true, data = tags)
|
coEvery { api.tags() } returns SelfossModel.StatusAndData(success = true, data = tags)
|
||||||
coEvery { db.tagsQueries.tags().executeAsList() } returns tagsDB
|
coEvery { db.tagsQueries.tags().executeAsList() } returns tagsDB
|
||||||
every { appSettingsService.isUpdateSourcesEnabled() } returns true
|
every { appSettingsService.isUpdateSourcesEnabled() } returns true
|
||||||
every { appSettingsService.isItemCachingEnabled() } returns true
|
every { appSettingsService.isItemCachingEnabled() } returns true
|
||||||
@ -405,7 +403,7 @@ class RepositoryTest {
|
|||||||
TAG("second_DB", "yellow", 0)
|
TAG("second_DB", "yellow", 0)
|
||||||
)
|
)
|
||||||
|
|
||||||
coEvery { api.tags() } returns StatusAndData(success = true, data = tags)
|
coEvery { api.tags() } returns SelfossModel.StatusAndData(success = true, data = tags)
|
||||||
coEvery { db.tagsQueries.tags().executeAsList() } returns tagsDB
|
coEvery { db.tagsQueries.tags().executeAsList() } returns tagsDB
|
||||||
every { appSettingsService.isUpdateSourcesEnabled() } returns false
|
every { appSettingsService.isUpdateSourcesEnabled() } returns false
|
||||||
every { appSettingsService.isItemCachingEnabled() } returns true
|
every { appSettingsService.isItemCachingEnabled() } returns true
|
||||||
@ -435,7 +433,7 @@ class RepositoryTest {
|
|||||||
TAG("second_DB", "yellow", 0)
|
TAG("second_DB", "yellow", 0)
|
||||||
)
|
)
|
||||||
|
|
||||||
coEvery { api.tags() } returns StatusAndData(success = true, data = tags)
|
coEvery { api.tags() } returns SelfossModel.StatusAndData(success = true, data = tags)
|
||||||
coEvery { db.tagsQueries.tags().executeAsList() } returns tagsDB
|
coEvery { db.tagsQueries.tags().executeAsList() } returns tagsDB
|
||||||
every { appSettingsService.isUpdateSourcesEnabled() } returns true
|
every { appSettingsService.isUpdateSourcesEnabled() } returns true
|
||||||
every { appSettingsService.isItemCachingEnabled() } returns false
|
every { appSettingsService.isItemCachingEnabled() } returns false
|
||||||
@ -462,7 +460,7 @@ class RepositoryTest {
|
|||||||
TAG("second_DB", "yellow", 0)
|
TAG("second_DB", "yellow", 0)
|
||||||
)
|
)
|
||||||
|
|
||||||
coEvery { api.tags() } returns StatusAndData(success = true, data = tags)
|
coEvery { api.tags() } returns SelfossModel.StatusAndData(success = true, data = tags)
|
||||||
coEvery { db.tagsQueries.tags().executeAsList() } returns tagsDB
|
coEvery { db.tagsQueries.tags().executeAsList() } returns tagsDB
|
||||||
every { appSettingsService.isUpdateSourcesEnabled() } returns false
|
every { appSettingsService.isUpdateSourcesEnabled() } returns false
|
||||||
every { appSettingsService.isItemCachingEnabled() } returns false
|
every { appSettingsService.isItemCachingEnabled() } returns false
|
||||||
@ -491,7 +489,7 @@ class RepositoryTest {
|
|||||||
TAG("second_DB", "yellow", 0)
|
TAG("second_DB", "yellow", 0)
|
||||||
)
|
)
|
||||||
|
|
||||||
coEvery { api.tags() } returns StatusAndData(success = true, data = tags)
|
coEvery { api.tags() } returns SelfossModel.StatusAndData(success = true, data = tags)
|
||||||
coEvery { db.tagsQueries.tags().executeAsList() } returns tagsDB
|
coEvery { db.tagsQueries.tags().executeAsList() } returns tagsDB
|
||||||
every { appSettingsService.isUpdateSourcesEnabled() } returns true
|
every { appSettingsService.isUpdateSourcesEnabled() } returns true
|
||||||
every { appSettingsService.isItemCachingEnabled() } returns true
|
every { appSettingsService.isItemCachingEnabled() } returns true
|
||||||
@ -519,7 +517,7 @@ class RepositoryTest {
|
|||||||
TAG("second_DB", "yellow", 0)
|
TAG("second_DB", "yellow", 0)
|
||||||
)
|
)
|
||||||
|
|
||||||
coEvery { api.tags() } returns StatusAndData(success = true, data = tags)
|
coEvery { api.tags() } returns SelfossModel.StatusAndData(success = true, data = tags)
|
||||||
coEvery { db.tagsQueries.tags().executeAsList() } returns tagsDB
|
coEvery { db.tagsQueries.tags().executeAsList() } returns tagsDB
|
||||||
every { appSettingsService.isItemCachingEnabled() } returns false
|
every { appSettingsService.isItemCachingEnabled() } returns false
|
||||||
every { appSettingsService.isUpdateSourcesEnabled() } returns true
|
every { appSettingsService.isUpdateSourcesEnabled() } returns true
|
||||||
@ -546,7 +544,7 @@ class RepositoryTest {
|
|||||||
TAG("second_DB", "yellow", 0)
|
TAG("second_DB", "yellow", 0)
|
||||||
)
|
)
|
||||||
|
|
||||||
coEvery { api.tags() } returns StatusAndData(success = true, data = tags)
|
coEvery { api.tags() } returns SelfossModel.StatusAndData(success = true, data = tags)
|
||||||
coEvery { db.tagsQueries.tags().executeAsList() } returns tagsDB
|
coEvery { db.tagsQueries.tags().executeAsList() } returns tagsDB
|
||||||
every { appSettingsService.isUpdateSourcesEnabled() } returns false
|
every { appSettingsService.isUpdateSourcesEnabled() } returns false
|
||||||
every { appSettingsService.isItemCachingEnabled() } returns true
|
every { appSettingsService.isItemCachingEnabled() } returns true
|
||||||
@ -574,7 +572,7 @@ class RepositoryTest {
|
|||||||
TAG("second_DB", "yellow", 0)
|
TAG("second_DB", "yellow", 0)
|
||||||
)
|
)
|
||||||
|
|
||||||
coEvery { api.tags() } returns StatusAndData(success = true, data = tags)
|
coEvery { api.tags() } returns SelfossModel.StatusAndData(success = true, data = tags)
|
||||||
coEvery { db.tagsQueries.tags().executeAsList() } returns tagsDB
|
coEvery { db.tagsQueries.tags().executeAsList() } returns tagsDB
|
||||||
every { appSettingsService.isUpdateSourcesEnabled() } returns false
|
every { appSettingsService.isUpdateSourcesEnabled() } returns false
|
||||||
every { appSettingsService.isItemCachingEnabled() } returns false
|
every { appSettingsService.isItemCachingEnabled() } returns false
|
||||||
@ -629,7 +627,7 @@ class RepositoryTest {
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
coEvery { api.sources() } returns StatusAndData(success = true, data = sources)
|
coEvery { api.sources() } returns SelfossModel.StatusAndData(success = true, data = sources)
|
||||||
every { db.sourcesQueries.sources().executeAsList() } returns sourcesDB
|
every { db.sourcesQueries.sources().executeAsList() } returns sourcesDB
|
||||||
initializeRepository()
|
initializeRepository()
|
||||||
var testSources: List<SelfossModel.Source>?
|
var testSources: List<SelfossModel.Source>?
|
||||||
@ -683,7 +681,7 @@ class RepositoryTest {
|
|||||||
|
|
||||||
every { appSettingsService.isUpdateSourcesEnabled() } returns false
|
every { appSettingsService.isUpdateSourcesEnabled() } returns false
|
||||||
every { appSettingsService.isItemCachingEnabled() } returns true
|
every { appSettingsService.isItemCachingEnabled() } returns true
|
||||||
coEvery { api.sources() } returns StatusAndData(success = true, data = sources)
|
coEvery { api.sources() } returns SelfossModel.StatusAndData(success = true, data = sources)
|
||||||
every { db.sourcesQueries.sources().executeAsList() } returns sourcesDB
|
every { db.sourcesQueries.sources().executeAsList() } returns sourcesDB
|
||||||
initializeRepository()
|
initializeRepository()
|
||||||
var testSources: List<SelfossModel.Source>?
|
var testSources: List<SelfossModel.Source>?
|
||||||
@ -740,7 +738,7 @@ class RepositoryTest {
|
|||||||
|
|
||||||
every { appSettingsService.isUpdateSourcesEnabled() } returns true
|
every { appSettingsService.isUpdateSourcesEnabled() } returns true
|
||||||
every { appSettingsService.isItemCachingEnabled() } returns false
|
every { appSettingsService.isItemCachingEnabled() } returns false
|
||||||
coEvery { api.sources() } returns StatusAndData(success = true, data = sources)
|
coEvery { api.sources() } returns SelfossModel.StatusAndData(success = true, data = sources)
|
||||||
every { db.sourcesQueries.sources().executeAsList() } returns sourcesDB
|
every { db.sourcesQueries.sources().executeAsList() } returns sourcesDB
|
||||||
initializeRepository()
|
initializeRepository()
|
||||||
var testSources: List<SelfossModel.Source>?
|
var testSources: List<SelfossModel.Source>?
|
||||||
@ -794,7 +792,7 @@ class RepositoryTest {
|
|||||||
|
|
||||||
every { appSettingsService.isUpdateSourcesEnabled() } returns false
|
every { appSettingsService.isUpdateSourcesEnabled() } returns false
|
||||||
every { appSettingsService.isItemCachingEnabled() } returns false
|
every { appSettingsService.isItemCachingEnabled() } returns false
|
||||||
coEvery { api.sources() } returns StatusAndData(success = true, data = sources)
|
coEvery { api.sources() } returns SelfossModel.StatusAndData(success = true, data = sources)
|
||||||
every { db.sourcesQueries.sources().executeAsList() } returns sourcesDB
|
every { db.sourcesQueries.sources().executeAsList() } returns sourcesDB
|
||||||
initializeRepository()
|
initializeRepository()
|
||||||
var testSources: List<SelfossModel.Source>?
|
var testSources: List<SelfossModel.Source>?
|
||||||
@ -846,7 +844,7 @@ class RepositoryTest {
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
coEvery { api.sources() } returns StatusAndData(success = true, data = sources)
|
coEvery { api.sources() } returns SelfossModel.StatusAndData(success = true, data = sources)
|
||||||
every { db.sourcesQueries.sources().executeAsList() } returns sourcesDB
|
every { db.sourcesQueries.sources().executeAsList() } returns sourcesDB
|
||||||
initializeRepository(MutableStateFlow(false))
|
initializeRepository(MutableStateFlow(false))
|
||||||
var testSources: List<SelfossModel.Source>?
|
var testSources: List<SelfossModel.Source>?
|
||||||
@ -900,7 +898,7 @@ class RepositoryTest {
|
|||||||
|
|
||||||
every { appSettingsService.isItemCachingEnabled() } returns false
|
every { appSettingsService.isItemCachingEnabled() } returns false
|
||||||
every { appSettingsService.isUpdateSourcesEnabled() } returns true
|
every { appSettingsService.isUpdateSourcesEnabled() } returns true
|
||||||
coEvery { api.sources() } returns StatusAndData(success = true, data = sources)
|
coEvery { api.sources() } returns SelfossModel.StatusAndData(success = true, data = sources)
|
||||||
every { db.sourcesQueries.sources().executeAsList() } returns sourcesDB
|
every { db.sourcesQueries.sources().executeAsList() } returns sourcesDB
|
||||||
initializeRepository(MutableStateFlow(false))
|
initializeRepository(MutableStateFlow(false))
|
||||||
var testSources: List<SelfossModel.Source>?
|
var testSources: List<SelfossModel.Source>?
|
||||||
@ -954,7 +952,7 @@ class RepositoryTest {
|
|||||||
|
|
||||||
every { appSettingsService.isItemCachingEnabled() } returns true
|
every { appSettingsService.isItemCachingEnabled() } returns true
|
||||||
every { appSettingsService.isUpdateSourcesEnabled() } returns false
|
every { appSettingsService.isUpdateSourcesEnabled() } returns false
|
||||||
coEvery { api.sources() } returns StatusAndData(success = true, data = sources)
|
coEvery { api.sources() } returns SelfossModel.StatusAndData(success = true, data = sources)
|
||||||
every { db.sourcesQueries.sources().executeAsList() } returns sourcesDB
|
every { db.sourcesQueries.sources().executeAsList() } returns sourcesDB
|
||||||
initializeRepository(MutableStateFlow(false))
|
initializeRepository(MutableStateFlow(false))
|
||||||
var testSources: List<SelfossModel.Source>?
|
var testSources: List<SelfossModel.Source>?
|
||||||
@ -1008,7 +1006,7 @@ class RepositoryTest {
|
|||||||
|
|
||||||
every { appSettingsService.isItemCachingEnabled() } returns false
|
every { appSettingsService.isItemCachingEnabled() } returns false
|
||||||
every { appSettingsService.isUpdateSourcesEnabled() } returns false
|
every { appSettingsService.isUpdateSourcesEnabled() } returns false
|
||||||
coEvery { api.sources() } returns StatusAndData(success = true, data = sources)
|
coEvery { api.sources() } returns SelfossModel.StatusAndData(success = true, data = sources)
|
||||||
every { db.sourcesQueries.sources().executeAsList() } returns sourcesDB
|
every { db.sourcesQueries.sources().executeAsList() } returns sourcesDB
|
||||||
initializeRepository(MutableStateFlow(false))
|
initializeRepository(MutableStateFlow(false))
|
||||||
var testSources: List<SelfossModel.Source>?
|
var testSources: List<SelfossModel.Source>?
|
||||||
@ -1024,7 +1022,7 @@ class RepositoryTest {
|
|||||||
@Test
|
@Test
|
||||||
fun create_source() {
|
fun create_source() {
|
||||||
coEvery { api.createSourceForVersion(any(), any(), any(), any(), any(), any()) } returns
|
coEvery { api.createSourceForVersion(any(), any(), any(), any(), any(), any()) } returns
|
||||||
SuccessResponse(true)
|
SelfossModel.SuccessResponse(true)
|
||||||
|
|
||||||
initializeRepository()
|
initializeRepository()
|
||||||
var response: Boolean
|
var response: Boolean
|
||||||
@ -1054,7 +1052,7 @@ class RepositoryTest {
|
|||||||
@Test
|
@Test
|
||||||
fun create_source_but_response_fails() {
|
fun create_source_but_response_fails() {
|
||||||
coEvery { api.createSourceForVersion(any(), any(), any(), any(), any(), any()) } returns
|
coEvery { api.createSourceForVersion(any(), any(), any(), any(), any(), any()) } returns
|
||||||
SuccessResponse(false)
|
SelfossModel.SuccessResponse(false)
|
||||||
|
|
||||||
initializeRepository()
|
initializeRepository()
|
||||||
var response: Boolean
|
var response: Boolean
|
||||||
@ -1084,7 +1082,7 @@ class RepositoryTest {
|
|||||||
@Test
|
@Test
|
||||||
fun create_source_without_connection() {
|
fun create_source_without_connection() {
|
||||||
coEvery { api.createSourceForVersion(any(), any(), any(), any(), any(), any()) } returns
|
coEvery { api.createSourceForVersion(any(), any(), any(), any(), any(), any()) } returns
|
||||||
SuccessResponse(true)
|
SelfossModel.SuccessResponse(true)
|
||||||
|
|
||||||
initializeRepository(MutableStateFlow(false))
|
initializeRepository(MutableStateFlow(false))
|
||||||
var response: Boolean
|
var response: Boolean
|
||||||
@ -1113,7 +1111,7 @@ class RepositoryTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun delete_source() {
|
fun delete_source() {
|
||||||
coEvery { api.deleteSource(any()) } returns SuccessResponse(true)
|
coEvery { api.deleteSource(any()) } returns SelfossModel.SuccessResponse(true)
|
||||||
|
|
||||||
initializeRepository()
|
initializeRepository()
|
||||||
var response: Boolean
|
var response: Boolean
|
||||||
@ -1127,7 +1125,7 @@ class RepositoryTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun delete_source_but_response_fails() {
|
fun delete_source_but_response_fails() {
|
||||||
coEvery { api.deleteSource(any()) } returns SuccessResponse(false)
|
coEvery { api.deleteSource(any()) } returns SelfossModel.SuccessResponse(false)
|
||||||
|
|
||||||
initializeRepository()
|
initializeRepository()
|
||||||
var response: Boolean
|
var response: Boolean
|
||||||
@ -1141,7 +1139,7 @@ class RepositoryTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun delete_source_without_connection() {
|
fun delete_source_without_connection() {
|
||||||
coEvery { api.deleteSource(any()) } returns SuccessResponse(false)
|
coEvery { api.deleteSource(any()) } returns SelfossModel.SuccessResponse(false)
|
||||||
|
|
||||||
initializeRepository(MutableStateFlow(false))
|
initializeRepository(MutableStateFlow(false))
|
||||||
var response: Boolean
|
var response: Boolean
|
||||||
@ -1155,7 +1153,7 @@ class RepositoryTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun update_remote() {
|
fun update_remote() {
|
||||||
coEvery { api.update() } returns StatusAndData(
|
coEvery { api.update() } returns SelfossModel.StatusAndData(
|
||||||
success = true,
|
success = true,
|
||||||
data = "finished"
|
data = "finished"
|
||||||
)
|
)
|
||||||
@ -1172,7 +1170,7 @@ class RepositoryTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun update_remote_but_response_fails() {
|
fun update_remote_but_response_fails() {
|
||||||
coEvery { api.update() } returns StatusAndData(
|
coEvery { api.update() } returns SelfossModel.StatusAndData(
|
||||||
success = false,
|
success = false,
|
||||||
data = "unallowed access"
|
data = "unallowed access"
|
||||||
)
|
)
|
||||||
@ -1189,7 +1187,7 @@ class RepositoryTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun update_remote_with_unallowed_access() {
|
fun update_remote_with_unallowed_access() {
|
||||||
coEvery { api.update() } returns StatusAndData(
|
coEvery { api.update() } returns SelfossModel.StatusAndData(
|
||||||
success = true,
|
success = true,
|
||||||
data = "unallowed access"
|
data = "unallowed access"
|
||||||
)
|
)
|
||||||
@ -1206,7 +1204,7 @@ class RepositoryTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun update_remote_without_connection() {
|
fun update_remote_without_connection() {
|
||||||
coEvery { api.update() } returns StatusAndData(
|
coEvery { api.update() } returns SelfossModel.StatusAndData(
|
||||||
success = true,
|
success = true,
|
||||||
data = "undocumented..."
|
data = "undocumented..."
|
||||||
)
|
)
|
||||||
@ -1223,7 +1221,7 @@ class RepositoryTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun login() {
|
fun login() {
|
||||||
coEvery { api.login() } returns SuccessResponse(success = true)
|
coEvery { api.login() } returns SelfossModel.SuccessResponse(success = true)
|
||||||
|
|
||||||
initializeRepository()
|
initializeRepository()
|
||||||
var response: Boolean
|
var response: Boolean
|
||||||
@ -1237,7 +1235,7 @@ class RepositoryTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun login_but_response_fails() {
|
fun login_but_response_fails() {
|
||||||
coEvery { api.login() } returns SuccessResponse(success = false)
|
coEvery { api.login() } returns SelfossModel.SuccessResponse(success = false)
|
||||||
|
|
||||||
initializeRepository()
|
initializeRepository()
|
||||||
var response: Boolean
|
var response: Boolean
|
||||||
@ -1251,7 +1249,7 @@ class RepositoryTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun login_but_without_connection() {
|
fun login_but_without_connection() {
|
||||||
coEvery { api.login() } returns SuccessResponse(success = true)
|
coEvery { api.login() } returns SelfossModel.SuccessResponse(success = true)
|
||||||
|
|
||||||
initializeRepository(MutableStateFlow(false))
|
initializeRepository(MutableStateFlow(false))
|
||||||
var response: Boolean
|
var response: Boolean
|
||||||
@ -1299,9 +1297,9 @@ class RepositoryTest {
|
|||||||
any()
|
any()
|
||||||
)
|
)
|
||||||
} returnsMany listOf(
|
} returnsMany listOf(
|
||||||
StatusAndData(success = true, data = generateTestApiItem(itemParameter1)),
|
SelfossModel.StatusAndData(success = true, data = generateTestApiItem(itemParameter1)),
|
||||||
StatusAndData(success = true, data = generateTestApiItem(itemParameter2)),
|
SelfossModel.StatusAndData(success = true, data = generateTestApiItem(itemParameter2)),
|
||||||
StatusAndData(success = true, data = generateTestApiItem(itemParameter1)),
|
SelfossModel.StatusAndData(success = true, data = generateTestApiItem(itemParameter1)),
|
||||||
)
|
)
|
||||||
|
|
||||||
initializeRepository()
|
initializeRepository()
|
||||||
@ -1325,7 +1323,7 @@ class RepositoryTest {
|
|||||||
@Test
|
@Test
|
||||||
fun cache_items_but_response_fails() {
|
fun cache_items_but_response_fails() {
|
||||||
coEvery { api.getItems(any(), any(), any(), any(), any(), any(), any()) } returns
|
coEvery { api.getItems(any(), any(), any(), any(), any(), any(), any()) } returns
|
||||||
StatusAndData(success = false, data = generateTestApiItem())
|
SelfossModel.StatusAndData(success = false, data = generateTestApiItem())
|
||||||
|
|
||||||
initializeRepository()
|
initializeRepository()
|
||||||
repository.tagFilter = SelfossModel.Tag("Tag", "read", 0)
|
repository.tagFilter = SelfossModel.Tag("Tag", "read", 0)
|
||||||
@ -1348,7 +1346,7 @@ class RepositoryTest {
|
|||||||
@Test
|
@Test
|
||||||
fun cache_items_without_connection() {
|
fun cache_items_without_connection() {
|
||||||
coEvery { api.getItems(any(), any(), any(), any(), any(), any(), any()) } returns
|
coEvery { api.getItems(any(), any(), any(), any(), any(), any(), any()) } returns
|
||||||
StatusAndData(success = false, data = generateTestApiItem())
|
SelfossModel.StatusAndData(success = false, data = generateTestApiItem())
|
||||||
|
|
||||||
initializeRepository(MutableStateFlow(false))
|
initializeRepository(MutableStateFlow(false))
|
||||||
repository.tagFilter = SelfossModel.Tag("Tag", "read", 0)
|
repository.tagFilter = SelfossModel.Tag("Tag", "read", 0)
|
||||||
|
@ -12,7 +12,6 @@ plugins {
|
|||||||
kotlin("android").version("1.7.20").apply(false)
|
kotlin("android").version("1.7.20").apply(false)
|
||||||
kotlin("multiplatform").version("1.7.20").apply(false)
|
kotlin("multiplatform").version("1.7.20").apply(false)
|
||||||
id("org.sonarqube").version("3.4.0.2513").apply(false)
|
id("org.sonarqube").version("3.4.0.2513").apply(false)
|
||||||
id("com.mikepenz.aboutlibraries.plugin").version("10.5.1").apply(false)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
apply(plugin = "org.sonarqube")
|
apply(plugin = "org.sonarqube")
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package bou.amine.apps.readerforselfossv2.DI
|
package bou.amine.apps.readerforselfossv2.DI
|
||||||
|
|
||||||
import bou.amine.apps.readerforselfossv2.rest.MercuryApi
|
|
||||||
import bou.amine.apps.readerforselfossv2.rest.SelfossApi
|
import bou.amine.apps.readerforselfossv2.rest.SelfossApi
|
||||||
import bou.amine.apps.readerforselfossv2.service.AppSettingsService
|
import bou.amine.apps.readerforselfossv2.service.AppSettingsService
|
||||||
import org.kodein.di.DI
|
import org.kodein.di.DI
|
||||||
@ -11,5 +10,4 @@ import org.kodein.di.singleton
|
|||||||
val networkModule by DI.Module {
|
val networkModule by DI.Module {
|
||||||
bind<AppSettingsService>() with singleton { AppSettingsService() }
|
bind<AppSettingsService>() with singleton { AppSettingsService() }
|
||||||
bind<SelfossApi>() with singleton { SelfossApi(instance()) }
|
bind<SelfossApi>() with singleton { SelfossApi(instance()) }
|
||||||
bind<MercuryApi>() with singleton { MercuryApi() }
|
|
||||||
}
|
}
|
@ -1,157 +0,0 @@
|
|||||||
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 MercuryModel {
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
class ParsedContent(
|
|
||||||
val title: String,
|
|
||||||
val content: String?,
|
|
||||||
val lead_image_url: String?,
|
|
||||||
val url: String
|
|
||||||
)
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
data class Tag(
|
|
||||||
val tag: String,
|
|
||||||
val color: String,
|
|
||||||
val unread: Int
|
|
||||||
)
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
class Stats(
|
|
||||||
val total: Int,
|
|
||||||
val unread: Int,
|
|
||||||
val starred: Int
|
|
||||||
)
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
data class Spout(
|
|
||||||
val name: String,
|
|
||||||
val description: String
|
|
||||||
)
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
data class ApiVersion(
|
|
||||||
val version: String?,
|
|
||||||
val apiversion: String?
|
|
||||||
) {
|
|
||||||
fun getApiMajorVersion() : Int {
|
|
||||||
var versionNumber = 0
|
|
||||||
if (apiversion != null) {
|
|
||||||
versionNumber = apiversion.substringBefore(".").toInt()
|
|
||||||
}
|
|
||||||
return versionNumber
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
data class Source(
|
|
||||||
val id: Int,
|
|
||||||
val title: String,
|
|
||||||
@Serializable(with = TagsListSerializer::class)
|
|
||||||
val tags: List<String>,
|
|
||||||
val spout: String,
|
|
||||||
val error: String,
|
|
||||||
val icon: String?
|
|
||||||
)
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
data class Item(
|
|
||||||
val id: Int,
|
|
||||||
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
|
|
||||||
fun getLinkDecoded(): String {
|
|
||||||
var stringUrl: String
|
|
||||||
stringUrl =
|
|
||||||
if (link.startsWith("http://news.google.com/news/") || link.startsWith("https://news.google.com/news/")) {
|
|
||||||
if (link.contains("&url=")) {
|
|
||||||
link.substringAfter("&url=")
|
|
||||||
} else {
|
|
||||||
this.link.replace("&", "&")
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.link.replace("&", "&")
|
|
||||||
}
|
|
||||||
|
|
||||||
// handle :443 => https
|
|
||||||
if (stringUrl.contains(":443")) {
|
|
||||||
stringUrl = stringUrl.replace(":443", "").replace("http://", "https://")
|
|
||||||
}
|
|
||||||
|
|
||||||
// handle url not starting with http
|
|
||||||
if (stringUrl.startsWith("//")) {
|
|
||||||
stringUrl = "http:$stringUrl"
|
|
||||||
}
|
|
||||||
|
|
||||||
return stringUrl
|
|
||||||
}
|
|
||||||
|
|
||||||
fun sourceAndDateText(): String =
|
|
||||||
this.sourcetitle.getHtmlDecoded() + DateUtils.parseRelativeDate(this.datetime)
|
|
||||||
|
|
||||||
fun toggleStar(): Item {
|
|
||||||
this.starred = !this.starred
|
|
||||||
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 if (json.booleanOrNull != null) {
|
|
||||||
json.boolean
|
|
||||||
} else {
|
|
||||||
json.int == 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override val descriptor: SerialDescriptor
|
|
||||||
get() = PrimitiveSerialDescriptor("b", PrimitiveKind.BOOLEAN)
|
|
||||||
|
|
||||||
override fun serialize(encoder: Encoder, value: Boolean) {
|
|
||||||
TODO("Not yet implemented")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,40 +0,0 @@
|
|||||||
package bou.amine.apps.readerforselfossv2.model
|
|
||||||
|
|
||||||
import io.ktor.client.call.*
|
|
||||||
import io.ktor.client.statement.*
|
|
||||||
import io.ktor.http.*
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
class SuccessResponse(val success: Boolean) {
|
|
||||||
val isSuccess: Boolean
|
|
||||||
get() = success
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun maybeResponse(r: HttpResponse): SuccessResponse {
|
|
||||||
return if (r.status.isSuccess()) {
|
|
||||||
r.body()
|
|
||||||
} else {
|
|
||||||
SuccessResponse(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend inline fun <reified T> bodyOrFailure(r: HttpResponse): StatusAndData<T> {
|
|
||||||
return if (r.status.isSuccess()) {
|
|
||||||
StatusAndData.succes(r.body())
|
|
||||||
} else {
|
|
||||||
StatusAndData.error()
|
|
||||||
}
|
|
||||||
}
|
|
@ -20,6 +20,12 @@ class SelfossModel {
|
|||||||
val unread: Int
|
val unread: Int
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
class SuccessResponse(val success: Boolean) {
|
||||||
|
val isSuccess: Boolean
|
||||||
|
get() = success
|
||||||
|
}
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
class Stats(
|
class Stats(
|
||||||
val total: Int,
|
val total: Int,
|
||||||
@ -146,4 +152,16 @@ class SelfossModel {
|
|||||||
TODO("Not yet implemented")
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,6 @@ package bou.amine.apps.readerforselfossv2.repository
|
|||||||
import bou.amine.apps.readerforselfossv2.dao.*
|
import bou.amine.apps.readerforselfossv2.dao.*
|
||||||
import bou.amine.apps.readerforselfossv2.model.NetworkUnavailableException
|
import bou.amine.apps.readerforselfossv2.model.NetworkUnavailableException
|
||||||
import bou.amine.apps.readerforselfossv2.model.SelfossModel
|
import bou.amine.apps.readerforselfossv2.model.SelfossModel
|
||||||
import bou.amine.apps.readerforselfossv2.model.StatusAndData
|
|
||||||
import bou.amine.apps.readerforselfossv2.rest.SelfossApi
|
import bou.amine.apps.readerforselfossv2.rest.SelfossApi
|
||||||
import bou.amine.apps.readerforselfossv2.service.AppSettingsService
|
import bou.amine.apps.readerforselfossv2.service.AppSettingsService
|
||||||
import bou.amine.apps.readerforselfossv2.utils.*
|
import bou.amine.apps.readerforselfossv2.utils.*
|
||||||
@ -11,7 +10,6 @@ import io.github.aakira.napier.Napier
|
|||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.asStateFlow
|
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
class Repository(private val api: SelfossApi, private val appSettingsService: AppSettingsService, val isConnectionAvailable: MutableStateFlow<Boolean>, private val db: ReaderForSelfossDB) {
|
class Repository(private val api: SelfossApi, private val appSettingsService: AppSettingsService, val isConnectionAvailable: MutableStateFlow<Boolean>, private val db: ReaderForSelfossDB) {
|
||||||
@ -29,19 +27,19 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap
|
|||||||
|
|
||||||
var offlineOverride = false
|
var offlineOverride = false
|
||||||
|
|
||||||
private val _badgeUnread = MutableStateFlow(0)
|
var badgeUnread = 0
|
||||||
val badgeUnread = _badgeUnread.asStateFlow()
|
set(value) {field = if (value < 0) { 0 } else { value } }
|
||||||
private val _badgeAll = MutableStateFlow(0)
|
var badgeAll = 0
|
||||||
val badgeAll = _badgeAll.asStateFlow()
|
set(value) {field = if (value < 0) { 0 } else { value } }
|
||||||
private val _badgeStarred = MutableStateFlow(0)
|
var badgeStarred = 0
|
||||||
val badgeStarred = _badgeStarred.asStateFlow()
|
set(value) {field = if (value < 0) { 0 } else { value } }
|
||||||
|
|
||||||
private var fetchedSources = false
|
private var fetchedSources = false
|
||||||
private var fetchedTags = false
|
private var fetchedTags = false
|
||||||
|
|
||||||
suspend fun getNewerItems(): ArrayList<SelfossModel.Item> {
|
suspend fun getNewerItems(): ArrayList<SelfossModel.Item> {
|
||||||
// TODO: Use the updatedSince parameter
|
// TODO: Use the updatedSince parameter
|
||||||
var fetchedItems: StatusAndData<List<SelfossModel.Item>> = StatusAndData.error()
|
var fetchedItems: SelfossModel.StatusAndData<List<SelfossModel.Item>> = SelfossModel.StatusAndData.error()
|
||||||
var fromDB = false
|
var fromDB = false
|
||||||
if (isNetworkAvailable()) {
|
if (isNetworkAvailable()) {
|
||||||
fetchedItems = api.getItems(
|
fetchedItems = api.getItems(
|
||||||
@ -66,7 +64,7 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap
|
|||||||
if (sourceFilter != null) {
|
if (sourceFilter != null) {
|
||||||
dbItems = dbItems.filter { it.sourcetitle == sourceFilter!!.title }
|
dbItems = dbItems.filter { it.sourcetitle == sourceFilter!!.title }
|
||||||
}
|
}
|
||||||
fetchedItems = StatusAndData.succes(
|
fetchedItems = SelfossModel.StatusAndData.succes(
|
||||||
dbItems.map { it.toView() }
|
dbItems.map { it.toView() }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -82,7 +80,7 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap
|
|||||||
}
|
}
|
||||||
|
|
||||||
suspend fun getOlderItems(): ArrayList<SelfossModel.Item> {
|
suspend fun getOlderItems(): ArrayList<SelfossModel.Item> {
|
||||||
var fetchedItems: StatusAndData<List<SelfossModel.Item>> = StatusAndData.error()
|
var fetchedItems: SelfossModel.StatusAndData<List<SelfossModel.Item>> = SelfossModel.StatusAndData.error()
|
||||||
if (isNetworkAvailable()) {
|
if (isNetworkAvailable()) {
|
||||||
val offset = items.size
|
val offset = items.size
|
||||||
fetchedItems = api.getItems(
|
fetchedItems = api.getItems(
|
||||||
@ -127,17 +125,17 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap
|
|||||||
if (isNetworkAvailable()) {
|
if (isNetworkAvailable()) {
|
||||||
val response = api.stats()
|
val response = api.stats()
|
||||||
if (response.success && response.data != null) {
|
if (response.success && response.data != null) {
|
||||||
_badgeUnread.value = response.data.unread
|
badgeUnread = response.data.unread
|
||||||
_badgeAll.value = response.data.total
|
badgeAll = response.data.total
|
||||||
_badgeStarred.value = response.data.starred
|
badgeStarred = response.data.starred
|
||||||
success = true
|
success = true
|
||||||
}
|
}
|
||||||
} else if (appSettingsService.isItemCachingEnabled()) {
|
} else if (appSettingsService.isItemCachingEnabled()) {
|
||||||
// TODO: do this differently, because it's not efficient
|
// TODO: do this differently, because it's not efficient
|
||||||
val dbItems = getDBItems()
|
val dbItems = getDBItems()
|
||||||
_badgeUnread.value = dbItems.filter { item -> item.unread }.size
|
badgeUnread = dbItems.filter { item -> item.unread }.size
|
||||||
_badgeStarred.value = dbItems.filter { item -> item.starred }.size
|
badgeStarred = dbItems.filter { item -> item.starred }.size
|
||||||
_badgeAll.value = dbItems.size
|
badgeAll = dbItems.size
|
||||||
success = true
|
success = true
|
||||||
}
|
}
|
||||||
return success
|
return success
|
||||||
@ -285,7 +283,7 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap
|
|||||||
private fun markAsReadLocally(item: SelfossModel.Item) {
|
private fun markAsReadLocally(item: SelfossModel.Item) {
|
||||||
if (item.unread) {
|
if (item.unread) {
|
||||||
item.unread = false
|
item.unread = false
|
||||||
_badgeUnread.value -= 1
|
badgeUnread -= 1
|
||||||
}
|
}
|
||||||
|
|
||||||
CoroutineScope(Dispatchers.Main).launch {
|
CoroutineScope(Dispatchers.Main).launch {
|
||||||
@ -296,7 +294,7 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap
|
|||||||
private fun unmarkAsReadLocally(item: SelfossModel.Item) {
|
private fun unmarkAsReadLocally(item: SelfossModel.Item) {
|
||||||
if (!item.unread) {
|
if (!item.unread) {
|
||||||
item.unread = true
|
item.unread = true
|
||||||
_badgeUnread.value += 1
|
badgeUnread += 1
|
||||||
}
|
}
|
||||||
|
|
||||||
CoroutineScope(Dispatchers.Main).launch {
|
CoroutineScope(Dispatchers.Main).launch {
|
||||||
@ -307,7 +305,7 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap
|
|||||||
private fun starrLocally(item: SelfossModel.Item) {
|
private fun starrLocally(item: SelfossModel.Item) {
|
||||||
if (!item.starred) {
|
if (!item.starred) {
|
||||||
item.starred = true
|
item.starred = true
|
||||||
_badgeStarred.value += 1
|
badgeStarred += 1
|
||||||
}
|
}
|
||||||
|
|
||||||
CoroutineScope(Dispatchers.Main).launch {
|
CoroutineScope(Dispatchers.Main).launch {
|
||||||
@ -318,7 +316,7 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap
|
|||||||
private fun unstarrLocally(item: SelfossModel.Item) {
|
private fun unstarrLocally(item: SelfossModel.Item) {
|
||||||
if (item.starred) {
|
if (item.starred) {
|
||||||
item.starred = false
|
item.starred = false
|
||||||
_badgeStarred.value -= 1
|
badgeStarred -= 1
|
||||||
}
|
}
|
||||||
|
|
||||||
CoroutineScope(Dispatchers.Main).launch {
|
CoroutineScope(Dispatchers.Main).launch {
|
||||||
|
@ -1,43 +0,0 @@
|
|||||||
package bou.amine.apps.readerforselfossv2.rest
|
|
||||||
|
|
||||||
import bou.amine.apps.readerforselfossv2.model.*
|
|
||||||
import io.github.aakira.napier.Napier
|
|
||||||
import io.ktor.client.*
|
|
||||||
import io.ktor.client.plugins.cache.*
|
|
||||||
import io.ktor.client.plugins.contentnegotiation.*
|
|
||||||
import io.ktor.client.plugins.logging.*
|
|
||||||
import io.ktor.client.request.*
|
|
||||||
import io.ktor.serialization.kotlinx.json.*
|
|
||||||
import kotlinx.serialization.json.Json
|
|
||||||
|
|
||||||
class MercuryApi() {
|
|
||||||
|
|
||||||
var client = createHttpClient()
|
|
||||||
|
|
||||||
private fun createHttpClient(): HttpClient {
|
|
||||||
return HttpClient {
|
|
||||||
install(ContentNegotiation) {
|
|
||||||
install(HttpCache)
|
|
||||||
json(Json {
|
|
||||||
prettyPrint = true
|
|
||||||
isLenient = true
|
|
||||||
ignoreUnknownKeys = true
|
|
||||||
})
|
|
||||||
}
|
|
||||||
install(Logging) {
|
|
||||||
logger = object : Logger {
|
|
||||||
override fun log(message: String) {
|
|
||||||
Napier.d(message, tag = "LogMercuryCalls")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
level = LogLevel.INFO
|
|
||||||
}
|
|
||||||
expectSuccess = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun query(url: String): StatusAndData<MercuryModel.ParsedContent> =
|
|
||||||
bodyOrFailure(client.get("https://amine-louveau.fr/parser.php") {
|
|
||||||
parameter("link", url)
|
|
||||||
})
|
|
||||||
}
|
|
@ -1,6 +1,6 @@
|
|||||||
package bou.amine.apps.readerforselfossv2.rest
|
package bou.amine.apps.readerforselfossv2.rest
|
||||||
|
|
||||||
import bou.amine.apps.readerforselfossv2.model.*
|
import bou.amine.apps.readerforselfossv2.model.SelfossModel
|
||||||
import bou.amine.apps.readerforselfossv2.service.AppSettingsService
|
import bou.amine.apps.readerforselfossv2.service.AppSettingsService
|
||||||
import io.ktor.client.*
|
import io.ktor.client.*
|
||||||
import io.ktor.client.call.*
|
import io.ktor.client.call.*
|
||||||
@ -66,7 +66,7 @@ class SelfossApi(private val appSettingsService: AppSettingsService) {
|
|||||||
client = createHttpClient()
|
client = createHttpClient()
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun login(): SuccessResponse =
|
suspend fun login(): SelfossModel.SuccessResponse =
|
||||||
maybeResponse(client.get(url("/login")) {
|
maybeResponse(client.get(url("/login")) {
|
||||||
parameter("username", appSettingsService.getUserName())
|
parameter("username", appSettingsService.getUserName())
|
||||||
parameter("password", appSettingsService.getPassword())
|
parameter("password", appSettingsService.getPassword())
|
||||||
@ -80,7 +80,7 @@ class SelfossApi(private val appSettingsService: AppSettingsService) {
|
|||||||
search: String?,
|
search: String?,
|
||||||
updatedSince: String?,
|
updatedSince: String?,
|
||||||
items: Int? = null
|
items: Int? = null
|
||||||
): StatusAndData<List<SelfossModel.Item>> =
|
): SelfossModel.StatusAndData<List<SelfossModel.Item>> =
|
||||||
bodyOrFailure(client.get(url("/items")) {
|
bodyOrFailure(client.get(url("/items")) {
|
||||||
parameter("username", appSettingsService.getUserName())
|
parameter("username", appSettingsService.getUserName())
|
||||||
parameter("password", appSettingsService.getPassword())
|
parameter("password", appSettingsService.getPassword())
|
||||||
@ -93,64 +93,64 @@ class SelfossApi(private val appSettingsService: AppSettingsService) {
|
|||||||
parameter("offset", offset)
|
parameter("offset", offset)
|
||||||
})
|
})
|
||||||
|
|
||||||
suspend fun stats(): StatusAndData<SelfossModel.Stats> =
|
suspend fun stats(): SelfossModel.StatusAndData<SelfossModel.Stats> =
|
||||||
bodyOrFailure(client.get(url("/stats")) {
|
bodyOrFailure(client.get(url("/stats")) {
|
||||||
parameter("username", appSettingsService.getUserName())
|
parameter("username", appSettingsService.getUserName())
|
||||||
parameter("password", appSettingsService.getPassword())
|
parameter("password", appSettingsService.getPassword())
|
||||||
})
|
})
|
||||||
|
|
||||||
suspend fun tags(): StatusAndData<List<SelfossModel.Tag>> =
|
suspend fun tags(): SelfossModel.StatusAndData<List<SelfossModel.Tag>> =
|
||||||
bodyOrFailure(client.get(url("/tags")) {
|
bodyOrFailure(client.get(url("/tags")) {
|
||||||
parameter("username", appSettingsService.getUserName())
|
parameter("username", appSettingsService.getUserName())
|
||||||
parameter("password", appSettingsService.getPassword())
|
parameter("password", appSettingsService.getPassword())
|
||||||
})
|
})
|
||||||
|
|
||||||
suspend fun update(): StatusAndData<String> =
|
suspend fun update(): SelfossModel.StatusAndData<String> =
|
||||||
bodyOrFailure(client.get(url("/update")) {
|
bodyOrFailure(client.get(url("/update")) {
|
||||||
parameter("username", appSettingsService.getUserName())
|
parameter("username", appSettingsService.getUserName())
|
||||||
parameter("password", appSettingsService.getPassword())
|
parameter("password", appSettingsService.getPassword())
|
||||||
})
|
})
|
||||||
|
|
||||||
suspend fun spouts(): StatusAndData<Map<String, SelfossModel.Spout>> =
|
suspend fun spouts(): SelfossModel.StatusAndData<Map<String, SelfossModel.Spout>> =
|
||||||
bodyOrFailure(client.get(url("/sources/spouts")) {
|
bodyOrFailure(client.get(url("/sources/spouts")) {
|
||||||
parameter("username", appSettingsService.getUserName())
|
parameter("username", appSettingsService.getUserName())
|
||||||
parameter("password", appSettingsService.getPassword())
|
parameter("password", appSettingsService.getPassword())
|
||||||
})
|
})
|
||||||
|
|
||||||
suspend fun sources(): StatusAndData<ArrayList<SelfossModel.Source>> =
|
suspend fun sources(): SelfossModel.StatusAndData<ArrayList<SelfossModel.Source>> =
|
||||||
bodyOrFailure(client.get(url("/sources/list")) {
|
bodyOrFailure(client.get(url("/sources/list")) {
|
||||||
parameter("username", appSettingsService.getUserName())
|
parameter("username", appSettingsService.getUserName())
|
||||||
parameter("password", appSettingsService.getPassword())
|
parameter("password", appSettingsService.getPassword())
|
||||||
})
|
})
|
||||||
|
|
||||||
suspend fun version(): StatusAndData<SelfossModel.ApiVersion> =
|
suspend fun version(): SelfossModel.StatusAndData<SelfossModel.ApiVersion> =
|
||||||
bodyOrFailure(client.get(url("/api/about")))
|
bodyOrFailure(client.get(url("/api/about")))
|
||||||
|
|
||||||
suspend fun markAsRead(id: String): SuccessResponse =
|
suspend fun markAsRead(id: String): SelfossModel.SuccessResponse =
|
||||||
maybeResponse(client.post(url("/mark/$id")) {
|
maybeResponse(client.post(url("/mark/$id")) {
|
||||||
parameter("username", appSettingsService.getUserName())
|
parameter("username", appSettingsService.getUserName())
|
||||||
parameter("password", appSettingsService.getPassword())
|
parameter("password", appSettingsService.getPassword())
|
||||||
})
|
})
|
||||||
|
|
||||||
suspend fun unmarkAsRead(id: String): SuccessResponse =
|
suspend fun unmarkAsRead(id: String): SelfossModel.SuccessResponse =
|
||||||
maybeResponse(client.post(url("/unmark/$id")) {
|
maybeResponse(client.post(url("/unmark/$id")) {
|
||||||
parameter("username", appSettingsService.getUserName())
|
parameter("username", appSettingsService.getUserName())
|
||||||
parameter("password", appSettingsService.getPassword())
|
parameter("password", appSettingsService.getPassword())
|
||||||
})
|
})
|
||||||
|
|
||||||
suspend fun starr(id: String): SuccessResponse =
|
suspend fun starr(id: String): SelfossModel.SuccessResponse =
|
||||||
maybeResponse(client.post(url("/starr/$id")) {
|
maybeResponse(client.post(url("/starr/$id")) {
|
||||||
parameter("username", appSettingsService.getUserName())
|
parameter("username", appSettingsService.getUserName())
|
||||||
parameter("password", appSettingsService.getPassword())
|
parameter("password", appSettingsService.getPassword())
|
||||||
})
|
})
|
||||||
|
|
||||||
suspend fun unstarr(id: String): SuccessResponse =
|
suspend fun unstarr(id: String): SelfossModel.SuccessResponse =
|
||||||
maybeResponse(client.post(url("/unstarr/$id")) {
|
maybeResponse(client.post(url("/unstarr/$id")) {
|
||||||
parameter("username", appSettingsService.getUserName())
|
parameter("username", appSettingsService.getUserName())
|
||||||
parameter("password", appSettingsService.getPassword())
|
parameter("password", appSettingsService.getPassword())
|
||||||
})
|
})
|
||||||
|
|
||||||
suspend fun markAllAsRead(ids: List<String>): SuccessResponse =
|
suspend fun markAllAsRead(ids: List<String>): SelfossModel.SuccessResponse =
|
||||||
maybeResponse(client.submitForm(
|
maybeResponse(client.submitForm(
|
||||||
url = url("/mark"),
|
url = url("/mark"),
|
||||||
formParameters = Parameters.build {
|
formParameters = Parameters.build {
|
||||||
@ -167,7 +167,7 @@ class SelfossApi(private val appSettingsService: AppSettingsService) {
|
|||||||
tags: String,
|
tags: String,
|
||||||
filter: String,
|
filter: String,
|
||||||
version: Int
|
version: Int
|
||||||
): SuccessResponse =
|
): SelfossModel.SuccessResponse =
|
||||||
maybeResponse(
|
maybeResponse(
|
||||||
if (version > 1) {
|
if (version > 1) {
|
||||||
createSource2(title, url, spout, tags, filter)
|
createSource2(title, url, spout, tags, filter)
|
||||||
@ -212,9 +212,25 @@ class SelfossApi(private val appSettingsService: AppSettingsService) {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
suspend fun deleteSource(id: Int): SuccessResponse =
|
suspend fun deleteSource(id: Int): SelfossModel.SuccessResponse =
|
||||||
maybeResponse(client.delete(url("/source/$id")) {
|
maybeResponse(client.delete(url("/source/$id")) {
|
||||||
parameter("username", appSettingsService.getUserName())
|
parameter("username", appSettingsService.getUserName())
|
||||||
parameter("password", appSettingsService.getPassword())
|
parameter("password", appSettingsService.getPassword())
|
||||||
})
|
})
|
||||||
|
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@ -35,7 +35,6 @@ class AppSettingsService {
|
|||||||
private var _fontSize: Int? = null
|
private var _fontSize: Int? = null
|
||||||
private var _staticBar: Boolean? = null
|
private var _staticBar: Boolean? = null
|
||||||
private var _font: String = ""
|
private var _font: String = ""
|
||||||
private var _theme: Int? = null
|
|
||||||
|
|
||||||
|
|
||||||
init {
|
init {
|
||||||
@ -319,17 +318,6 @@ class AppSettingsService {
|
|||||||
return _font
|
return _font
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun refreshCurrentTheme() {
|
|
||||||
_theme = settings.getString(CURRENT_THEME, "-1").toInt()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getCurrentTheme(): Int {
|
|
||||||
if (_theme == null) {
|
|
||||||
refreshCurrentTheme()
|
|
||||||
}
|
|
||||||
return _theme ?: -1
|
|
||||||
}
|
|
||||||
|
|
||||||
fun refreshApiSettings() {
|
fun refreshApiSettings() {
|
||||||
refreshPassword()
|
refreshPassword()
|
||||||
refreshUsername()
|
refreshUsername()
|
||||||
@ -358,7 +346,6 @@ class AppSettingsService {
|
|||||||
refreshFontSize()
|
refreshFontSize()
|
||||||
refreshFont()
|
refreshFont()
|
||||||
refreshStaticBarEnabled()
|
refreshStaticBarEnabled()
|
||||||
refreshCurrentTheme()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun refreshLoginInformation(
|
fun refreshLoginInformation(
|
||||||
@ -457,7 +444,5 @@ class AppSettingsService {
|
|||||||
const val INFINITE_LOADING = "infinite_loading"
|
const val INFINITE_LOADING = "infinite_loading"
|
||||||
|
|
||||||
const val ITEMS_CACHING = "items_caching"
|
const val ITEMS_CACHING = "items_caching"
|
||||||
|
|
||||||
const val CURRENT_THEME = "currentMode"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user