Compare commits
12 Commits
v122113172
...
v122123391
Author | SHA1 | Date | |
---|---|---|---|
7f0ba193ec | |||
87ed5b0fa8 | |||
6947743ac0 | |||
07e3710d44 | |||
e68da7764f | |||
c3ff894027 | |||
f09f731d30 | |||
956c4341c7 | |||
7b68264dd7 | |||
cfcf030bf8 | |||
0e7d7a5835 | |||
0856ebb889 |
12
.drone.yml
12
.drone.yml
@ -8,7 +8,7 @@ steps:
|
||||
commands:
|
||||
- echo "---------------------------------------------------------"
|
||||
- echo "Configure gradle..."
|
||||
- mkdir -p ~/.gradle && echo "org.gradle.daemon=false\nignoreGitVersion=true\npushCache=false\nmatomoUrl=\"$MATOMO_URL\"\nmatomoSite=\"$MATOMO_SITE\"\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\npushCache=false\nsystemProp.org.gradle.internal.http.connectionTimeout=180000\nsystemProp.org.gradle.internal.http.socketTimeout=180000" >> ~/.gradle/gradle.properties
|
||||
- echo "---------------------------------------------------------"
|
||||
- echo "Analysing..."
|
||||
- ./gradlew sonarqube -Dsonar.projectKey=RFS2 -Dsonar.host.url=$SONAR_HOST_URL -Dsonar.login=$SONAR_LOGIN
|
||||
@ -24,10 +24,6 @@ steps:
|
||||
from_secret: sonarScannerHostUrl
|
||||
SONAR_LOGIN:
|
||||
from_secret: sonarScannerLogin
|
||||
MATOMO_URL:
|
||||
from_secret: matomoUrl
|
||||
MATOMO_SITE:
|
||||
from_secret: matomoSite
|
||||
trigger:
|
||||
event:
|
||||
- push
|
||||
@ -94,7 +90,7 @@ steps:
|
||||
commands:
|
||||
- echo "---------------------------------------------------------"
|
||||
- echo "Configure gradle..."
|
||||
- mkdir -p ~/.gradle && echo "org.gradle.daemon=false\nignoreGitVersion=true\nmatomoUrl=\"$MATOMO_URL\"\nmatomoSite=\"$MATOMO_SITE\"\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\npushCache=false\nsystemProp.org.gradle.internal.http.connectionTimeout=180000\nsystemProp.org.gradle.internal.http.socketTimeout=180000" >> ~/.gradle/gradle.properties
|
||||
- echo "---------------------------------------------------------"
|
||||
- echo "Generate APK"
|
||||
- ./gradlew :androidApp:assembleGithubConfigRelease -P pushCache=false
|
||||
@ -115,10 +111,6 @@ steps:
|
||||
from_secret: keyPass
|
||||
YOUR_KEY_ALIAS:
|
||||
from_secret: keyAlias
|
||||
MATOMO_URL:
|
||||
from_secret: matomoUrl
|
||||
MATOMO_SITE:
|
||||
from_secret: matomoSite
|
||||
|
||||
- name: gitea_release
|
||||
image: plugins/gitea-release
|
||||
|
24
.github/CONTRIBUTING.md
vendored
24
.github/CONTRIBUTING.md
vendored
@ -46,27 +46,3 @@ Always check if the web version of your instance is working.
|
||||
I won't provide any selfoss instance url. If you want to help, but to not have one, you'll have to install one, and use it.
|
||||
|
||||
All the details to need are [here](https://selfoss.aditu.de/).
|
||||
|
||||
# Build the project
|
||||
|
||||
You can directly import this project into IntellIJ/Android Studio.
|
||||
|
||||
You'll have to:
|
||||
|
||||
- Define some parameters either in `~/.gradle/gradle.properties` or as gradle parameters (see the examples)
|
||||
|
||||
- matomoUrl and matomoSite: url and siteId for a matomo instance
|
||||
|
||||
### Examples:
|
||||
#### Inside ~/.gradle/gradle.properties
|
||||
|
||||
```
|
||||
matomoUrl="URL" # It can be empty.
|
||||
matomoSite="1" # It can be empty, but needs to be an integer
|
||||
```
|
||||
|
||||
#### As gradle parameters
|
||||
|
||||
```
|
||||
./gradlew .... -P matomoUrl="URL" -P matomoSite="1"
|
||||
```
|
||||
|
@ -1,6 +1,7 @@
|
||||
import java.io.ByteArrayOutputStream
|
||||
|
||||
val ignoreGitVersion: String by project
|
||||
val acraVersion = "5.9.7"
|
||||
|
||||
plugins {
|
||||
id("com.android.application")
|
||||
@ -83,9 +84,6 @@ android {
|
||||
|
||||
// tests
|
||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||
|
||||
buildConfigField("String", "MATOMO_URL", properties["matomoUrl"] as String)
|
||||
buildConfigField("String", "MATOMO_SITE", properties["matomoSite"] as String)
|
||||
}
|
||||
packagingOptions {
|
||||
resources {
|
||||
@ -190,6 +188,9 @@ dependencies {
|
||||
testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.0")
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.4.0")
|
||||
|
||||
implementation("ch.acra:acra-http:$acraVersion")
|
||||
implementation("ch.acra:acra-toast:$acraVersion")
|
||||
|
||||
// Matomo
|
||||
implementation("com.github.matomo-org:matomo-sdk-android:4.1.4")
|
||||
}
|
||||
|
@ -79,8 +79,5 @@
|
||||
android:value="true" />
|
||||
|
||||
<meta-data android:name="android.max_aspect" android:value="2.1" />
|
||||
<meta-data
|
||||
android:name="preloaded_fonts"
|
||||
android:resource="@array/preloaded_fonts" />
|
||||
</application>
|
||||
</manifest>
|
@ -0,0 +1,9 @@
|
||||
package bou.amine.apps.readerforselfossv2.android
|
||||
|
||||
import org.acra.ACRA
|
||||
import org.acra.ktx.sendSilentlyWithAcra
|
||||
|
||||
fun Throwable.sendSilentlyWithAcraWithName(name: String) {
|
||||
ACRA.errorReporter.putCustomData("error_source", name)
|
||||
this.sendSilentlyWithAcra()
|
||||
}
|
@ -63,8 +63,8 @@ import org.kodein.di.DIAware
|
||||
import org.kodein.di.android.closestDI
|
||||
import org.kodein.di.instance
|
||||
import org.matomo.sdk.Tracker
|
||||
import org.matomo.sdk.extra.DimensionQueue
|
||||
import org.matomo.sdk.extra.TrackHelper
|
||||
import java.security.MessageDigest
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
|
||||
@ -307,6 +307,8 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
||||
|
||||
handleBottomBarActions()
|
||||
|
||||
handleGDPRDialog(appSettingsService.settings.getBoolean("GDPR_shown", false))
|
||||
|
||||
handleRecurringTask()
|
||||
|
||||
CoroutineScope(Dispatchers.Main).launch {
|
||||
@ -316,6 +318,25 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
||||
getElementsAccordingToTab()
|
||||
}
|
||||
|
||||
|
||||
private fun handleGDPRDialog(GDPRShown: Boolean) {
|
||||
val messageDigest: MessageDigest = MessageDigest.getInstance("SHA-256")
|
||||
messageDigest.update(appSettingsService.getBaseUrl().toByteArray())
|
||||
if (!GDPRShown) {
|
||||
val alertDialog = AlertDialog.Builder(this).create()
|
||||
alertDialog.setTitle(getString(R.string.gdpr_dialog_title))
|
||||
alertDialog.setMessage(getString(R.string.gdpr_dialog_message))
|
||||
alertDialog.setButton(
|
||||
AlertDialog.BUTTON_NEUTRAL,
|
||||
"OK"
|
||||
) { dialog, _ ->
|
||||
appSettingsService.settings.putBoolean("GDPR_shown", true)
|
||||
dialog.dismiss()
|
||||
}
|
||||
alertDialog.show()
|
||||
}
|
||||
}
|
||||
|
||||
private fun initDrawer() {
|
||||
DrawerImageLoader.init(object : AbstractDrawerImageLoader() {
|
||||
override fun set(imageView: ImageView, uri: Uri, placeholder: Drawable, tag: String?) {
|
||||
@ -488,6 +509,7 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
||||
val gdColor = try {
|
||||
Color.parseColor(it.color)
|
||||
} catch (e: IllegalArgumentException) {
|
||||
e.sendSilentlyWithAcraWithName("color issue " + it.color)
|
||||
resources.getColor(R.color.colorPrimary)
|
||||
}
|
||||
gd.setColor(gdColor)
|
||||
@ -870,7 +892,9 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
||||
return true
|
||||
}
|
||||
R.id.action_disconnect -> {
|
||||
appSettingsService.clearAll()
|
||||
CoroutineScope(Dispatchers.Main).launch {
|
||||
repository.logout()
|
||||
}
|
||||
val intent = Intent(this, LoginActivity::class.java)
|
||||
this.startActivity(intent)
|
||||
this@HomeActivity.finish()
|
||||
|
@ -29,6 +29,13 @@ import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.launch
|
||||
import org.acra.ACRA
|
||||
import org.acra.ReportField
|
||||
import org.acra.config.httpSender
|
||||
import org.acra.config.toast
|
||||
import org.acra.data.StringFormat
|
||||
import org.acra.ktx.initAcra
|
||||
import org.acra.sender.HttpSender
|
||||
import org.kodein.di.*
|
||||
import org.matomo.sdk.Matomo
|
||||
import org.matomo.sdk.Tracker
|
||||
@ -43,7 +50,7 @@ class MyApp : MultiDexApplication(), DIAware {
|
||||
bind<Repository>() with singleton { Repository(instance(), instance(), isConnectionAvailable, instance()) }
|
||||
bind<ConnectivityStatus>() with singleton { ConnectivityStatus(applicationContext) }
|
||||
bind<AppViewModel>() with singleton { AppViewModel(repository = instance()) }
|
||||
bind<Tracker>() with singleton { TrackerBuilder.createDefault(BuildConfig.MATOMO_URL, BuildConfig.MATOMO_SITE.toInt()).build(
|
||||
bind<Tracker>() with singleton { TrackerBuilder.createDefault("https://matomo.amine-louveau.fr/matomo.php", if (BuildConfig.DEBUG) 4 else 5).build(
|
||||
Matomo.getInstance(applicationContext)) }
|
||||
}
|
||||
|
||||
@ -51,7 +58,6 @@ class MyApp : MultiDexApplication(), DIAware {
|
||||
private val viewModel: AppViewModel by instance()
|
||||
private val connectivityStatus: ConnectivityStatus by instance()
|
||||
private val driverFactory: DriverFactory by instance()
|
||||
private val tracker: Tracker by instance()
|
||||
|
||||
// TODO: handle with the "previous" way
|
||||
private val isConnectionAvailable: MutableStateFlow<Boolean> = MutableStateFlow(true)
|
||||
@ -60,28 +66,57 @@ class MyApp : MultiDexApplication(), DIAware {
|
||||
super.onCreate()
|
||||
Napier.base(DebugAntilog())
|
||||
|
||||
initDrawerImageLoader()
|
||||
if (!ACRA.isACRASenderServiceProcess()) {
|
||||
initDrawerImageLoader()
|
||||
|
||||
tryToHandleBug()
|
||||
tryToHandleBug()
|
||||
|
||||
handleNotificationChannels()
|
||||
handleNotificationChannels()
|
||||
|
||||
ProcessLifecycleOwner.get().lifecycle.addObserver(AppLifeCycleObserver(connectivityStatus, repository))
|
||||
ProcessLifecycleOwner.get().lifecycle.addObserver(AppLifeCycleObserver(connectivityStatus, repository))
|
||||
|
||||
CoroutineScope(Dispatchers.Main).launch {
|
||||
viewModel.networkAvailableProvider.collect { networkAvailable ->
|
||||
val toastMessage = if (networkAvailable) {
|
||||
repository.handleDBActions()
|
||||
R.string.network_connectivity_retrieved
|
||||
} else {
|
||||
R.string.network_connectivity_lost
|
||||
CoroutineScope(Dispatchers.Main).launch {
|
||||
viewModel.networkAvailableProvider.collect { networkAvailable ->
|
||||
val toastMessage = if (networkAvailable) {
|
||||
repository.handleDBActions()
|
||||
R.string.network_connectivity_retrieved
|
||||
} else {
|
||||
R.string.network_connectivity_lost
|
||||
}
|
||||
|
||||
Toast.makeText(
|
||||
applicationContext,
|
||||
toastMessage,
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Toast.makeText(
|
||||
applicationContext,
|
||||
toastMessage,
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
override fun attachBaseContext(base: Context?) {
|
||||
super.attachBaseContext(base)
|
||||
|
||||
initAcra {
|
||||
reportFormat = StringFormat.JSON
|
||||
reportContent = listOf(
|
||||
ReportField.REPORT_ID, ReportField.INSTALLATION_ID,
|
||||
ReportField.APP_VERSION_CODE, ReportField.APP_VERSION_NAME,
|
||||
ReportField.BUILD, ReportField.ANDROID_VERSION, ReportField.BRAND, ReportField.PHONE_MODEL,
|
||||
ReportField.AVAILABLE_MEM_SIZE, ReportField.TOTAL_MEM_SIZE,
|
||||
ReportField.STACK_TRACE, ReportField.APPLICATION_LOG, ReportField.LOGCAT,
|
||||
ReportField.INITIAL_CONFIGURATION, ReportField.CRASH_CONFIGURATION, ReportField.IS_SILENT,
|
||||
ReportField.USER_APP_START_DATE, ReportField.USER_COMMENT, ReportField.USER_CRASH_DATE, ReportField.USER_EMAIL, ReportField.CUSTOM_DATA)
|
||||
toast {
|
||||
//required
|
||||
text = getString(R.string.crash_toast_text)
|
||||
length = Toast.LENGTH_SHORT
|
||||
}
|
||||
httpSender {
|
||||
uri = "https://bugs.amine-louveau.fr/report" /*best guess, you may need to adjust this*/
|
||||
basicAuthLogin = "LMTlLZuazADohTCm"
|
||||
basicAuthPassword = "he6ghHp83F0PYPfh"
|
||||
httpMethod = HttpSender.Method.POST
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -25,6 +25,7 @@ import bou.amine.apps.readerforselfossv2.android.databinding.FragmentArticleBind
|
||||
import bou.amine.apps.readerforselfossv2.android.model.ParecelableItem
|
||||
import bou.amine.apps.readerforselfossv2.android.model.toModel
|
||||
import bou.amine.apps.readerforselfossv2.android.model.toParcelable
|
||||
import bou.amine.apps.readerforselfossv2.android.sendSilentlyWithAcraWithName
|
||||
import bou.amine.apps.readerforselfossv2.android.utils.glide.getBitmapInputStream
|
||||
import bou.amine.apps.readerforselfossv2.android.utils.openInBrowserAsNewTask
|
||||
import bou.amine.apps.readerforselfossv2.android.utils.shareLink
|
||||
@ -44,11 +45,14 @@ import com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import org.acra.ktx.sendSilentlyWithAcra
|
||||
import org.acra.ktx.sendWithAcra
|
||||
import org.kodein.di.DI
|
||||
import org.kodein.di.DIAware
|
||||
import org.kodein.di.android.x.closestDI
|
||||
import org.kodein.di.instance
|
||||
import java.net.MalformedURLException
|
||||
import java.net.SocketTimeoutException
|
||||
import java.net.URL
|
||||
import java.util.*
|
||||
import java.util.concurrent.ExecutionException
|
||||
@ -107,16 +111,6 @@ class ArticleFragment : Fragment(), DIAware {
|
||||
staticBar = appSettingsService.isStaticBarEnabled()
|
||||
font = appSettingsService.getFont()
|
||||
|
||||
if (font.isNotEmpty()) {
|
||||
resId = requireContext().resources.getIdentifier(font, "font", requireContext().packageName)
|
||||
typeface = try {
|
||||
ResourcesCompat.getFont(requireContext(), resId)!!
|
||||
} catch (e: java.lang.Exception) {
|
||||
// Just to be sure
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
refreshAlignment()
|
||||
|
||||
fab = binding.fab
|
||||
@ -217,6 +211,7 @@ class ArticleFragment : Fragment(), DIAware {
|
||||
)
|
||||
|
||||
} catch (e: InflateException) {
|
||||
e.sendSilentlyWithAcraWithName("webview not available")
|
||||
AlertDialog.Builder(requireContext())
|
||||
.setMessage(requireContext().getString(R.string.webview_dialog_issue_message))
|
||||
.setTitle(requireContext().getString(R.string.webview_dialog_issue_title))
|
||||
@ -250,74 +245,69 @@ class ArticleFragment : Fragment(), DIAware {
|
||||
binding.progressBar.visibility = View.VISIBLE
|
||||
|
||||
CoroutineScope(Dispatchers.Main).launch {
|
||||
val response = mercuryApi.query(url)
|
||||
if (response.success) {
|
||||
try {
|
||||
if (response.data != null && response.data!!.content != null && !response.data!!.content.isNullOrEmpty()) {
|
||||
try {
|
||||
val response = mercuryApi.query(url)
|
||||
if (response.success && response.data != null && !response.data?.content.isNullOrEmpty()) {
|
||||
binding.titleView.text = response.data!!.title.orEmpty()
|
||||
try {
|
||||
if (typeface != null) {
|
||||
binding.titleView.typeface = typeface
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
e.sendSilentlyWithAcraWithName("getContentFromMercury > typeface")
|
||||
}
|
||||
|
||||
try {
|
||||
// Note: Mercury may return relative urls... If it does the url val will not be changed.
|
||||
URL(response.data!!.url)
|
||||
url = response.data!!.url
|
||||
} catch (e: MalformedURLException) {
|
||||
// Mercury returned a relative url
|
||||
e.sendSilentlyWithAcraWithName("getContentFromMercury > malformedurlexception")
|
||||
}
|
||||
|
||||
try {
|
||||
contentText = response.data!!.content.orEmpty()
|
||||
htmlToWebview()
|
||||
} catch (e: Exception) {
|
||||
e.sendSilentlyWithAcraWithName("getContentFromMercury > contenttext or html")
|
||||
}
|
||||
|
||||
if (!response.data?.lead_image_url.isNullOrEmpty() && context != null) {
|
||||
try {
|
||||
binding.titleView.text = response.data!!.title
|
||||
if (typeface != null) {
|
||||
binding.titleView.typeface = typeface
|
||||
}
|
||||
binding.imageView.visibility = View.VISIBLE
|
||||
try {
|
||||
// Note: Mercury may return relative urls... If it does the url val will not be changed.
|
||||
URL(response.data!!.url)
|
||||
url = response.data!!.url
|
||||
} catch (e: MalformedURLException) {
|
||||
// Mercury returned a relative url. We do nothing.
|
||||
Glide
|
||||
.with(requireContext())
|
||||
.asBitmap()
|
||||
.load(
|
||||
response.data!!.lead_image_url.orEmpty()
|
||||
)
|
||||
.apply(RequestOptions.fitCenterTransform())
|
||||
.into(binding.imageView)
|
||||
} catch (e: Exception) {
|
||||
e.sendSilentlyWithAcraWithName("getContentFromMercury > glide lead image")
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
}
|
||||
|
||||
try {
|
||||
contentText = response.data!!.content.orEmpty()
|
||||
htmlToWebview()
|
||||
} catch (e: Exception) {
|
||||
}
|
||||
|
||||
try {
|
||||
if (response.data!!.lead_image_url != null && !response.data!!.lead_image_url.isNullOrEmpty() && context != null) {
|
||||
binding.imageView.visibility = View.VISIBLE
|
||||
try {
|
||||
Glide
|
||||
.with(requireContext())
|
||||
.asBitmap()
|
||||
.load(
|
||||
response.data!!.lead_image_url.orEmpty()
|
||||
)
|
||||
.apply(RequestOptions.fitCenterTransform())
|
||||
.into(binding.imageView)
|
||||
} catch (e: Exception) {
|
||||
}
|
||||
} else {
|
||||
binding.imageView.visibility = View.GONE
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
if (context != null) {
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
binding.nestedScrollView.scrollTo(0, 0)
|
||||
|
||||
binding.progressBar.visibility = View.GONE
|
||||
} catch (e: Exception) {
|
||||
if (context != null) {
|
||||
}
|
||||
e.sendSilentlyWithAcraWithName("getContentFromMercury > outside glide lead image")
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
openInBrowserAfterFailing()
|
||||
} catch (e: Exception) {
|
||||
if (context != null) {
|
||||
}
|
||||
}
|
||||
binding.imageView.visibility = View.GONE
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
if (context != null) {
|
||||
|
||||
try {
|
||||
binding.nestedScrollView.scrollTo(0, 0)
|
||||
binding.progressBar.visibility = View.GONE
|
||||
} catch (e: Exception) {
|
||||
e.sendSilentlyWithAcraWithName("getContentFromMercury > scrollview")
|
||||
}
|
||||
} else {
|
||||
openInBrowserAfterFailing()
|
||||
}
|
||||
} else {
|
||||
} catch (e: SocketTimeoutException) {
|
||||
openInBrowserAfterFailing()
|
||||
} catch (e: Exception) {
|
||||
e.sendSilentlyWithAcraWithName("getContentFromMercury > whole thing")
|
||||
openInBrowserAfterFailing()
|
||||
}
|
||||
}
|
||||
@ -359,19 +349,25 @@ class ArticleFragment : Fragment(), DIAware {
|
||||
try {
|
||||
val image = Glide.with(view).asBitmap().apply(glideOptions).load(url).submit().get()
|
||||
return WebResourceResponse("image/jpg", "UTF-8", getBitmapInputStream(image, Bitmap.CompressFormat.JPEG))
|
||||
}catch ( e : ExecutionException) {}
|
||||
} catch ( e : ExecutionException) {
|
||||
e.sendSilentlyWithAcraWithName("shouldInterceptRequest > jpeg")
|
||||
}
|
||||
}
|
||||
else if (url.lowercase(Locale.US).contains(".png")) {
|
||||
try {
|
||||
val image = Glide.with(view).asBitmap().apply(glideOptions).load(url).submit().get()
|
||||
return WebResourceResponse("image/jpg", "UTF-8", getBitmapInputStream(image, Bitmap.CompressFormat.PNG))
|
||||
}catch ( e : ExecutionException) {}
|
||||
} catch ( e : ExecutionException) {
|
||||
e.sendSilentlyWithAcraWithName("shouldInterceptRequest > png")
|
||||
}
|
||||
}
|
||||
else if (url.lowercase(Locale.US).contains(".webp")) {
|
||||
try {
|
||||
val image = Glide.with(view).asBitmap().apply(glideOptions).load(url).submit().get()
|
||||
return WebResourceResponse("image/jpg", "UTF-8", getBitmapInputStream(image, Bitmap.CompressFormat.WEBP))
|
||||
}catch ( e : ExecutionException) {}
|
||||
} catch ( e : ExecutionException) {
|
||||
e.sendSilentlyWithAcraWithName("shouldInterceptRequest > webp")
|
||||
}
|
||||
}
|
||||
|
||||
return super.shouldInterceptRequest(view, url)
|
||||
@ -395,6 +391,7 @@ class ArticleFragment : Fragment(), DIAware {
|
||||
val itemUrl = URL(url)
|
||||
baseUrl = itemUrl.protocol + "://" + itemUrl.host
|
||||
} catch (e: MalformedURLException) {
|
||||
e.sendSilentlyWithAcraWithName("htmlToWebview > item url")
|
||||
}
|
||||
|
||||
val fontName = when (font) {
|
||||
|
@ -2,11 +2,13 @@ package bou.amine.apps.readerforselfossv2.android.model
|
||||
|
||||
import android.content.Context
|
||||
import android.webkit.URLUtil
|
||||
import bou.amine.apps.readerforselfossv2.android.sendSilentlyWithAcraWithName
|
||||
import bou.amine.apps.readerforselfossv2.model.SelfossModel
|
||||
import bou.amine.apps.readerforselfossv2.utils.getImages
|
||||
import com.bumptech.glide.Glide
|
||||
import com.bumptech.glide.load.engine.DiskCacheStrategy
|
||||
import com.bumptech.glide.request.RequestOptions
|
||||
import org.acra.ktx.sendSilentlyWithAcra
|
||||
|
||||
fun SelfossModel.Item.preloadImages(context: Context) : Boolean {
|
||||
val imageUrls = this.getImages()
|
||||
@ -23,6 +25,7 @@ fun SelfossModel.Item.preloadImages(context: Context) : Boolean {
|
||||
}
|
||||
}
|
||||
} catch (e : Error) {
|
||||
e.sendSilentlyWithAcraWithName("preloadImages")
|
||||
return false
|
||||
}
|
||||
|
||||
@ -35,7 +38,7 @@ fun String.toTextDrawableString(): String {
|
||||
try {
|
||||
textDrawable.append(s[0])
|
||||
} catch (e: StringIndexOutOfBoundsException) {
|
||||
// We do nothing
|
||||
e.sendSilentlyWithAcraWithName("toTextDrawableString")
|
||||
}
|
||||
}
|
||||
return textDrawable.toString()
|
||||
|
@ -16,7 +16,10 @@ import androidx.preference.Preference
|
||||
import androidx.preference.PreferenceFragmentCompat
|
||||
import bou.amine.apps.readerforselfossv2.android.R
|
||||
import bou.amine.apps.readerforselfossv2.android.databinding.ActivitySettingsBinding
|
||||
import bou.amine.apps.readerforselfossv2.android.sendSilentlyWithAcraWithName
|
||||
import bou.amine.apps.readerforselfossv2.service.AppSettingsService
|
||||
import org.acra.ktx.sendSilentlyWithAcra
|
||||
import org.acra.ktx.sendWithAcra
|
||||
import org.kodein.di.DIAware
|
||||
import org.kodein.di.android.closestDI
|
||||
import org.kodein.di.instance
|
||||
@ -101,6 +104,11 @@ class SettingsActivity : AppCompatActivity(),
|
||||
class MainPreferenceFragment : PreferenceFragmentCompat() {
|
||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||
setPreferencesFromResource(R.xml.pref_main, rootKey)
|
||||
|
||||
preferenceManager.findPreference<Preference>("currentMode")?.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, newValue ->
|
||||
AppCompatDelegate.setDefaultNightMode(newValue.toString().toInt()) // ListPreference Only takes string-arrays ¯\_(ツ)_/¯
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -117,6 +125,7 @@ class SettingsActivity : AppCompatActivity(),
|
||||
val input: Int = (dest.toString() + source.toString()).toInt()
|
||||
if (input in 1..200) return@InputFilter null
|
||||
} catch (nfe: NumberFormatException) {
|
||||
nfe.sendSilentlyWithAcraWithName("GeneralPreferenceFragment")
|
||||
Toast.makeText(activity, R.string.items_number_should_be_number, Toast.LENGTH_LONG).show()
|
||||
}
|
||||
""
|
||||
@ -140,6 +149,7 @@ class SettingsActivity : AppCompatActivity(),
|
||||
try {
|
||||
editText.textSize = editable.toString().toInt().toFloat()
|
||||
} catch (e: NumberFormatException) {
|
||||
e.sendSilentlyWithAcraWithName("ArticleViewerPreferenceFragment > afterTextChanged")
|
||||
}
|
||||
}
|
||||
} }
|
||||
@ -149,6 +159,7 @@ class SettingsActivity : AppCompatActivity(),
|
||||
val input = (dest.toString() + source.toString()).toInt()
|
||||
if (input > 0) return@InputFilter null
|
||||
} catch (nfe: NumberFormatException) {
|
||||
nfe.sendSilentlyWithAcraWithName("ArticleViewerPreferenceFragment > filters")
|
||||
}
|
||||
""
|
||||
}
|
||||
|
@ -1,13 +1,9 @@
|
||||
package bou.amine.apps.readerforselfossv2.android.utils
|
||||
|
||||
import android.app.Activity
|
||||
import android.app.PendingIntent
|
||||
import android.content.ActivityNotFoundException
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.graphics.BitmapFactory
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.text.Spannable
|
||||
import android.text.style.ClickableSpan
|
||||
import android.util.Patterns
|
||||
|
@ -0,0 +1,5 @@
|
||||
<vector android:height="24dp" android:tint="#000000"
|
||||
android:viewportHeight="24" android:viewportWidth="24"
|
||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="@android:color/white" android:pathData="M20,8h-2.81c-0.45,-0.78 -1.07,-1.45 -1.82,-1.96L17,4.41 15.59,3l-2.17,2.17C12.96,5.06 12.49,5 12,5c-0.49,0 -0.96,0.06 -1.41,0.17L8.41,3 7,4.41l1.62,1.63C7.88,6.55 7.26,7.22 6.81,8L4,8v2h2.09c-0.05,0.33 -0.09,0.66 -0.09,1v1L4,12v2h2v1c0,0.34 0.04,0.67 0.09,1L4,16v2h2.81c1.04,1.79 2.97,3 5.19,3s4.15,-1.21 5.19,-3L20,18v-2h-2.09c0.05,-0.33 0.09,-0.66 0.09,-1v-1h2v-2h-2v-1c0,-0.34 -0.04,-0.67 -0.09,-1L20,10L20,8zM14,16h-4v-2h4v2zM14,12h-4v-2h4v2z"/>
|
||||
</vector>
|
@ -0,0 +1,7 @@
|
||||
<vector android:height="24dp" android:tint="#000000"
|
||||
android:viewportHeight="24" android:viewportWidth="24"
|
||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="@android:color/white" android:pathData="M21,8c-1.45,0 -2.26,1.44 -1.93,2.51l-3.55,3.56c-0.3,-0.09 -0.74,-0.09 -1.04,0l-2.55,-2.55C12.27,10.45 11.46,9 10,9c-1.45,0 -2.27,1.44 -1.93,2.52l-4.56,4.55C2.44,15.74 1,16.55 1,18c0,1.1 0.9,2 2,2c1.45,0 2.26,-1.44 1.93,-2.51l4.55,-4.56c0.3,0.09 0.74,0.09 1.04,0l2.55,2.55C12.73,16.55 13.54,18 15,18c1.45,0 2.27,-1.44 1.93,-2.52l3.56,-3.55C21.56,12.26 23,11.45 23,10C23,8.9 22.1,8 21,8z"/>
|
||||
<path android:fillColor="@android:color/white" android:pathData="M15,9l0.94,-2.07l2.06,-0.93l-2.06,-0.93l-0.94,-2.07l-0.92,2.07l-2.08,0.93l2.08,0.93z"/>
|
||||
<path android:fillColor="@android:color/white" android:pathData="M3.5,11l0.5,-2l2,-0.5l-2,-0.5l-0.5,-2l-0.5,2l-2,0.5l2,0.5z"/>
|
||||
</vector>
|
@ -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="Open Sans"
|
||||
app:fontProviderCerts="@array/com_google_android_gms_fonts_certs">
|
||||
</font-family>
|
@ -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="Roboto"
|
||||
app:fontProviderCerts="@array/com_google_android_gms_fonts_certs">
|
||||
</font-family>
|
@ -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>
|
@ -134,4 +134,8 @@
|
||||
<string name="mode_light">Light mode</string>
|
||||
<string name="drawer_error_loading_sources">Error loading sources…</string>
|
||||
<string name="pref_switch_enable_analytics">Enable analytics</string>
|
||||
<string name="gdpr_dialog_title">The app does not share any personal data about you.</string>
|
||||
<string name="gdpr_dialog_message"><![CDATA[Crash reports sending is now enabled. It can be disabled from the settings page. Keep in mind that crash reports are essential for the app development.]]></string>
|
||||
<string name="crash_toast_text">A crash occured. Sending the details to the developper.</string>
|
||||
<string name="pref_switch_disable_acra">"Disable automatic bug reporting. "</string>
|
||||
</resources>
|
||||
|
@ -134,4 +134,8 @@
|
||||
<string name="mode_light">Light mode</string>
|
||||
<string name="drawer_error_loading_sources">Error loading sources…</string>
|
||||
<string name="pref_switch_enable_analytics">Enable analytics</string>
|
||||
<string name="gdpr_dialog_title">The app does not share any personal data about you.</string>
|
||||
<string name="gdpr_dialog_message"><![CDATA[Crash reports sending is now enabled. It can be disabled from the settings page. Keep in mind that crash reports are essential for the app development.]]></string>
|
||||
<string name="crash_toast_text">A crash occured. Sending the details to the developper.</string>
|
||||
<string name="pref_switch_disable_acra">"Disable automatic bug reporting. "</string>
|
||||
</resources>
|
||||
|
@ -134,4 +134,8 @@
|
||||
<string name="mode_light">Light mode</string>
|
||||
<string name="drawer_error_loading_sources">Error loading sources…</string>
|
||||
<string name="pref_switch_enable_analytics">Enable analytics</string>
|
||||
<string name="gdpr_dialog_title">The app does not share any personal data about you.</string>
|
||||
<string name="gdpr_dialog_message"><![CDATA[Crash reports sending is now enabled. It can be disabled from the settings page. Keep in mind that crash reports are essential for the app development.]]></string>
|
||||
<string name="crash_toast_text">A crash occured. Sending the details to the developper.</string>
|
||||
<string name="pref_switch_disable_acra">"Disable automatic bug reporting. "</string>
|
||||
</resources>
|
||||
|
@ -134,4 +134,8 @@
|
||||
<string name="mode_light">Light mode</string>
|
||||
<string name="drawer_error_loading_sources">Error loading sources…</string>
|
||||
<string name="pref_switch_enable_analytics">Enable analytics</string>
|
||||
<string name="gdpr_dialog_title">The app does not share any personal data about you.</string>
|
||||
<string name="gdpr_dialog_message"><![CDATA[Crash reports sending is now enabled. It can be disabled from the settings page. Keep in mind that crash reports are essential for the app development.]]></string>
|
||||
<string name="crash_toast_text">A crash occured. Sending the details to the developper.</string>
|
||||
<string name="pref_switch_disable_acra">"Disable automatic bug reporting. "</string>
|
||||
</resources>
|
||||
|
@ -134,4 +134,8 @@
|
||||
<string name="mode_light">Thème clair</string>
|
||||
<string name="drawer_error_loading_sources">Error loading sources…</string>
|
||||
<string name="pref_switch_enable_analytics">Enable analytics</string>
|
||||
<string name="gdpr_dialog_title">The app does not share any personal data about you.</string>
|
||||
<string name="gdpr_dialog_message"><![CDATA[Crash reports sending is now enabled. It can be disabled from the settings page. Keep in mind that crash reports are essential for the app development.]]></string>
|
||||
<string name="crash_toast_text">A crash occured. Sending the details to the developper.</string>
|
||||
<string name="pref_switch_disable_acra">"Disable automatic bug reporting. "</string>
|
||||
</resources>
|
||||
|
@ -134,4 +134,8 @@
|
||||
<string name="mode_light">Light mode</string>
|
||||
<string name="drawer_error_loading_sources">Error loading sources…</string>
|
||||
<string name="pref_switch_enable_analytics">Enable analytics</string>
|
||||
<string name="gdpr_dialog_title">The app does not share any personal data about you.</string>
|
||||
<string name="gdpr_dialog_message"><![CDATA[Crash reports sending is now enabled. It can be disabled from the settings page. Keep in mind that crash reports are essential for the app development.]]></string>
|
||||
<string name="crash_toast_text">A crash occured. Sending the details to the developper.</string>
|
||||
<string name="pref_switch_disable_acra">"Disable automatic bug reporting. "</string>
|
||||
</resources>
|
||||
|
@ -134,4 +134,8 @@
|
||||
<string name="mode_light">Light mode</string>
|
||||
<string name="drawer_error_loading_sources">Error loading sources…</string>
|
||||
<string name="pref_switch_enable_analytics">Enable analytics</string>
|
||||
<string name="gdpr_dialog_title">The app does not share any personal data about you.</string>
|
||||
<string name="gdpr_dialog_message"><![CDATA[Crash reports sending is now enabled. It can be disabled from the settings page. Keep in mind that crash reports are essential for the app development.]]></string>
|
||||
<string name="crash_toast_text">A crash occured. Sending the details to the developper.</string>
|
||||
<string name="pref_switch_disable_acra">"Disable automatic bug reporting. "</string>
|
||||
</resources>
|
||||
|
@ -134,4 +134,8 @@
|
||||
<string name="mode_light">Light mode</string>
|
||||
<string name="drawer_error_loading_sources">Error loading sources…</string>
|
||||
<string name="pref_switch_enable_analytics">Enable analytics</string>
|
||||
<string name="gdpr_dialog_title">The app does not share any personal data about you.</string>
|
||||
<string name="gdpr_dialog_message"><![CDATA[Crash reports sending is now enabled. It can be disabled from the settings page. Keep in mind that crash reports are essential for the app development.]]></string>
|
||||
<string name="crash_toast_text">A crash occured. Sending the details to the developper.</string>
|
||||
<string name="pref_switch_disable_acra">"Disable automatic bug reporting. "</string>
|
||||
</resources>
|
||||
|
@ -134,4 +134,8 @@
|
||||
<string name="mode_light">Light mode</string>
|
||||
<string name="drawer_error_loading_sources">Error loading sources…</string>
|
||||
<string name="pref_switch_enable_analytics">Enable analytics</string>
|
||||
<string name="gdpr_dialog_title">The app does not share any personal data about you.</string>
|
||||
<string name="gdpr_dialog_message"><![CDATA[Crash reports sending is now enabled. It can be disabled from the settings page. Keep in mind that crash reports are essential for the app development.]]></string>
|
||||
<string name="crash_toast_text">A crash occured. Sending the details to the developper.</string>
|
||||
<string name="pref_switch_disable_acra">"Disable automatic bug reporting. "</string>
|
||||
</resources>
|
||||
|
@ -1,4 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="pref_switch_enable_analytics">Enable analytics</string>
|
||||
<string name="gdpr_dialog_title">The app does not share any personal data about you.</string>
|
||||
<string name="gdpr_dialog_message"><![CDATA[Crash reports sending is now enabled. It can be disabled from the settings page. Keep in mind that crash reports are essential for the app development.]]></string>
|
||||
<string name="crash_toast_text">A crash occured. Sending the details to the developper.</string>
|
||||
<string name="pref_switch_disable_acra">"Disable automatic bug reporting. "</string>
|
||||
</resources>
|
@ -134,4 +134,8 @@
|
||||
<string name="mode_light">Light mode</string>
|
||||
<string name="drawer_error_loading_sources">Error loading sources…</string>
|
||||
<string name="pref_switch_enable_analytics">Enable analytics</string>
|
||||
<string name="gdpr_dialog_title">The app does not share any personal data about you.</string>
|
||||
<string name="gdpr_dialog_message"><![CDATA[Crash reports sending is now enabled. It can be disabled from the settings page. Keep in mind that crash reports are essential for the app development.]]></string>
|
||||
<string name="crash_toast_text">A crash occured. Sending the details to the developper.</string>
|
||||
<string name="pref_switch_disable_acra">"Disable automatic bug reporting. "</string>
|
||||
</resources>
|
||||
|
@ -134,4 +134,8 @@
|
||||
<string name="mode_light">Light mode</string>
|
||||
<string name="drawer_error_loading_sources">Error loading sources…</string>
|
||||
<string name="pref_switch_enable_analytics">Enable analytics</string>
|
||||
<string name="gdpr_dialog_title">The app does not share any personal data about you.</string>
|
||||
<string name="gdpr_dialog_message"><![CDATA[Crash reports sending is now enabled. It can be disabled from the settings page. Keep in mind that crash reports are essential for the app development.]]></string>
|
||||
<string name="crash_toast_text">A crash occured. Sending the details to the developper.</string>
|
||||
<string name="pref_switch_disable_acra">"Disable automatic bug reporting. "</string>
|
||||
</resources>
|
||||
|
@ -134,4 +134,8 @@
|
||||
<string name="mode_light">Light mode</string>
|
||||
<string name="drawer_error_loading_sources">Error loading sources…</string>
|
||||
<string name="pref_switch_enable_analytics">Enable analytics</string>
|
||||
<string name="gdpr_dialog_title">The app does not share any personal data about you.</string>
|
||||
<string name="gdpr_dialog_message"><![CDATA[Crash reports sending is now enabled. It can be disabled from the settings page. Keep in mind that crash reports are essential for the app development.]]></string>
|
||||
<string name="crash_toast_text">A crash occured. Sending the details to the developper.</string>
|
||||
<string name="pref_switch_disable_acra">"Disable automatic bug reporting. "</string>
|
||||
</resources>
|
||||
|
@ -134,4 +134,8 @@
|
||||
<string name="mode_light">Light mode</string>
|
||||
<string name="drawer_error_loading_sources">Error loading sources…</string>
|
||||
<string name="pref_switch_enable_analytics">Enable analytics</string>
|
||||
<string name="gdpr_dialog_title">The app does not share any personal data about you.</string>
|
||||
<string name="gdpr_dialog_message"><![CDATA[Crash reports sending is now enabled. It can be disabled from the settings page. Keep in mind that crash reports are essential for the app development.]]></string>
|
||||
<string name="crash_toast_text">A crash occured. Sending the details to the developper.</string>
|
||||
<string name="pref_switch_disable_acra">"Disable automatic bug reporting. "</string>
|
||||
</resources>
|
||||
|
@ -134,4 +134,8 @@
|
||||
<string name="mode_light">Light mode</string>
|
||||
<string name="drawer_error_loading_sources">Error loading sources…</string>
|
||||
<string name="pref_switch_enable_analytics">Enable analytics</string>
|
||||
<string name="gdpr_dialog_title">The app does not share any personal data about you.</string>
|
||||
<string name="gdpr_dialog_message"><![CDATA[Crash reports sending is now enabled. It can be disabled from the settings page. Keep in mind that crash reports are essential for the app development.]]></string>
|
||||
<string name="crash_toast_text">A crash occured. Sending the details to the developper.</string>
|
||||
<string name="pref_switch_disable_acra">"Disable automatic bug reporting. "</string>
|
||||
</resources>
|
||||
|
@ -134,4 +134,8 @@
|
||||
<string name="mode_light">浅色模式</string>
|
||||
<string name="drawer_error_loading_sources">Error loading sources…</string>
|
||||
<string name="pref_switch_enable_analytics">Enable analytics</string>
|
||||
<string name="gdpr_dialog_title">The app does not share any personal data about you.</string>
|
||||
<string name="gdpr_dialog_message"><![CDATA[Crash reports sending is now enabled. It can be disabled from the settings page. Keep in mind that crash reports are essential for the app development.]]></string>
|
||||
<string name="crash_toast_text">A crash occured. Sending the details to the developper.</string>
|
||||
<string name="pref_switch_disable_acra">"Disable automatic bug reporting. "</string>
|
||||
</resources>
|
||||
|
@ -134,4 +134,8 @@
|
||||
<string name="mode_light">Light mode</string>
|
||||
<string name="drawer_error_loading_sources">Error loading sources…</string>
|
||||
<string name="pref_switch_enable_analytics">Enable analytics</string>
|
||||
<string name="gdpr_dialog_title">The app does not share any personal data about you.</string>
|
||||
<string name="gdpr_dialog_message"><![CDATA[Crash reports sending is now enabled. It can be disabled from the settings page. Keep in mind that crash reports are essential for the app development.]]></string>
|
||||
<string name="crash_toast_text">A crash occured. Sending the details to the developper.</string>
|
||||
<string name="pref_switch_disable_acra">"Disable automatic bug reporting. "</string>
|
||||
</resources>
|
||||
|
@ -1,17 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<array name="com_google_android_gms_fonts_certs">
|
||||
<item>@array/com_google_android_gms_fonts_certs_dev</item>
|
||||
<item>@array/com_google_android_gms_fonts_certs_prod</item>
|
||||
</array>
|
||||
<string-array name="com_google_android_gms_fonts_certs_dev">
|
||||
<item>
|
||||
MIIEqDCCA5CgAwIBAgIJANWFuGx90071MA0GCSqGSIb3DQEBBAUAMIGUMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTAeFw0wODA0MTUyMzM2NTZaFw0zNTA5MDEyMzM2NTZaMIGUMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTCCASAwDQYJKoZIhvcNAQEBBQADggENADCCAQgCggEBANbOLggKv+IxTdGNs8/TGFy0PTP6DHThvbbR24kT9ixcOd9W+EaBPWW+wPPKQmsHxajtWjmQwWfna8mZuSeJS48LIgAZlKkpFeVyxW0qMBujb8X8ETrWy550NaFtI6t9+u7hZeTfHwqNvacKhp1RbE6dBRGWynwMVX8XW8N1+UjFaq6GCJukT4qmpN2afb8sCjUigq0GuMwYXrFVee74bQgLHWGJwPmvmLHC69EH6kWr22ijx4OKXlSIx2xT1AsSHee70w5iDBiK4aph27yH3TxkXy9V89TDdexAcKk/cVHYNnDBapcavl7y0RiQ4biu8ymM8Ga/nmzhRKya6G0cGw8CAQOjgfwwgfkwHQYDVR0OBBYEFI0cxb6VTEM8YYY6FbBMvAPyT+CyMIHJBgNVHSMEgcEwgb6AFI0cxb6VTEM8YYY6FbBMvAPyT+CyoYGapIGXMIGUMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbYIJANWFuGx90071MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEEBQADggEBABnTDPEF+3iSP0wNfdIjIz1AlnrPzgAIHVvXxunW7SBrDhEglQZBbKJEk5kT0mtKoOD1JMrSu1xuTKEBahWRbqHsXclaXjoBADb0kkjVEJu/Lh5hgYZnOjvlba8Ld7HCKePCVePoTJBdI4fvugnL8TsgK05aIskyY0hKI9L8KfqfGTl1lzOv2KoWD0KWwtAWPoGChZxmQ+nBli+gwYMzM1vAkP+aayLe0a1EQimlOalO762r0GXO0ks+UeXde2Z4e+8S/pf7pITEI/tP+MxJTALw9QUWEv9lKTk+jkbqxbsh8nfBUapfKqYn0eidpwq2AzVp3juYl7//fKnaPhJD9gs=
|
||||
</item>
|
||||
</string-array>
|
||||
<string-array name="com_google_android_gms_fonts_certs_prod">
|
||||
<item>
|
||||
MIIEQzCCAyugAwIBAgIJAMLgh0ZkSjCNMA0GCSqGSIb3DQEBBAUAMHQxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRQwEgYDVQQKEwtHb29nbGUgSW5jLjEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDAeFw0wODA4MjEyMzEzMzRaFw0zNjAxMDcyMzEzMzRaMHQxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRQwEgYDVQQKEwtHb29nbGUgSW5jLjEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDCCASAwDQYJKoZIhvcNAQEBBQADggENADCCAQgCggEBAKtWLgDYO6IIrgqWbxJOKdoR8qtW0I9Y4sypEwPpt1TTcvZApxsdyxMJZ2JORland2qSGT2y5b+3JKkedxiLDmpHpDsz2WCbdxgxRczfey5YZnTJ4VZbH0xqWVW/8lGmPav5xVwnIiJS6HXk+BVKZF+JcWjAsb/GEuq/eFdpuzSqeYTcfi6idkyugwfYwXFU1+5fZKUaRKYCwkkFQVfcAs1fXA5V+++FGfvjJ/CxURaSxaBvGdGDhfXE28LWuT9ozCl5xw4Yq5OGazvV24mZVSoOO0yZ31j7kYvtwYK6NeADwbSxDdJEqO4k//0zOHKrUiGYXtqw/A0LFFtqoZKFjnkCAQOjgdkwgdYwHQYDVR0OBBYEFMd9jMIhF1Ylmn/Tgt9r45jk14alMIGmBgNVHSMEgZ4wgZuAFMd9jMIhF1Ylmn/Tgt9r45jk14aloXikdjB0MQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEUMBIGA1UEChMLR29vZ2xlIEluYy4xEDAOBgNVBAsTB0FuZHJvaWQxEDAOBgNVBAMTB0FuZHJvaWSCCQDC4IdGZEowjTAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBAUAA4IBAQBt0lLO74UwLDYKqs6Tm8/yzKkEu116FmH4rkaymUIE0P9KaMftGlMexFlaYjzmB2OxZyl6euNXEsQH8gjwyxCUKRJNexBiGcCEyj6z+a1fuHHvkiaai+KL8W1EyNmgjmyy8AW7P+LLlkR+ho5zEHatRbM/YAnqGcFh5iZBqpknHf1SKMXFh4dd239FJ1jWYfbMDMy3NS5CTMQ2XFI1MvcyUTdZPErjQfTbQe3aDQsQcafEQPD+nqActifKZ0Np0IS9L9kR/wbNvyz6ENwPiTrjV2KRkEjH78ZMcUQXg0L3BYHJ3lc69Vs5Ddf9uUGGMYldX3WfMBEmh/9iFBDAaTCK
|
||||
</item>
|
||||
</string-array>
|
||||
</resources>
|
@ -1,8 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<array name="preloaded_fonts" translatable="false">
|
||||
<item>@font/open_sans</item>
|
||||
<item>@font/roboto</item>
|
||||
<item>@font/source_code_pro_medium</item>
|
||||
</array>
|
||||
</resources>
|
@ -137,4 +137,8 @@
|
||||
<string name="mode_system">Follow the system setting</string>
|
||||
<string name="mode_light">Light mode</string>
|
||||
<string name="pref_switch_enable_analytics">Enable analytics</string>
|
||||
<string name="gdpr_dialog_title">The app does not share any personal data about you.</string>
|
||||
<string name="gdpr_dialog_message"><![CDATA[Crash reports sending is now enabled. It can be disabled from the settings page. Keep in mind that crash reports are essential for the app development.]]></string>
|
||||
<string name="crash_toast_text">A crash occured. Sending the details to the developper.</string>
|
||||
<string name="pref_switch_disable_acra">"Disable automatic bug reporting. "</string>
|
||||
</resources>
|
||||
|
@ -1,12 +1,6 @@
|
||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<SwitchPreference
|
||||
android:defaultValue="true"
|
||||
app:iconSpaceReserved="false"
|
||||
android:key="enable_analytics"
|
||||
android:title="@string/pref_switch_enable_analytics" />
|
||||
|
||||
<EditTextPreference
|
||||
android:inputType="number"
|
||||
android:key="api_timeout"
|
||||
|
@ -1,5 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:title="@string/title_activity_settings">
|
||||
|
||||
<Preference
|
||||
@ -17,9 +18,13 @@
|
||||
android:title="@string/pref_header_offline"
|
||||
android:icon="@drawable/ic_signal_wifi_off_black_24dp" />
|
||||
|
||||
<Preference
|
||||
android:fragment="bou.amine.apps.readerforselfossv2.android.settings.SettingsActivity$ThemePreferenceFragment"
|
||||
<ListPreference
|
||||
android:defaultValue="0"
|
||||
android:entries="@array/ModeTitles"
|
||||
android:entryValues="@array/ModeValues"
|
||||
android:key="currentMode"
|
||||
android:title="@string/pref_header_theme"
|
||||
app:useSimpleSummaryProvider="false"
|
||||
android:icon="@drawable/ic_color_lens_black_24dp" />
|
||||
|
||||
<Preference
|
||||
@ -32,4 +37,18 @@
|
||||
android:title="@string/pref_header_experimental"
|
||||
android:icon="@drawable/ic_widgets_black_24dp" />
|
||||
|
||||
|
||||
<SwitchPreference
|
||||
android:defaultValue="false"
|
||||
android:key="enable_analytics"
|
||||
android:title="@string/pref_switch_enable_analytics"
|
||||
android:icon="@drawable/ic_baseline_insights_24"/>
|
||||
|
||||
|
||||
<SwitchPreference
|
||||
android:defaultValue="false"
|
||||
android:key="acra.disable"
|
||||
android:title="@string/pref_switch_disable_acra"
|
||||
android:icon="@drawable/ic_baseline_bug_report_24"/>
|
||||
|
||||
</PreferenceScreen>
|
@ -1023,7 +1023,7 @@ class RepositoryTest {
|
||||
|
||||
@Test
|
||||
fun create_source() {
|
||||
coEvery { api.createSourceForVersion(any(), any(), any(), any(), any(), any()) } returns
|
||||
coEvery { api.createSourceForVersion(any(), any(), any(), any(), any()) } returns
|
||||
SuccessResponse(true)
|
||||
|
||||
initializeRepository()
|
||||
@ -1045,7 +1045,6 @@ class RepositoryTest {
|
||||
any(),
|
||||
any(),
|
||||
any(),
|
||||
any()
|
||||
)
|
||||
}
|
||||
assertSame(true, response)
|
||||
@ -1053,7 +1052,7 @@ class RepositoryTest {
|
||||
|
||||
@Test
|
||||
fun create_source_but_response_fails() {
|
||||
coEvery { api.createSourceForVersion(any(), any(), any(), any(), any(), any()) } returns
|
||||
coEvery { api.createSourceForVersion(any(), any(), any(), any(), any()) } returns
|
||||
SuccessResponse(false)
|
||||
|
||||
initializeRepository()
|
||||
@ -1075,7 +1074,6 @@ class RepositoryTest {
|
||||
any(),
|
||||
any(),
|
||||
any(),
|
||||
any()
|
||||
)
|
||||
}
|
||||
assertSame(false, response)
|
||||
@ -1083,7 +1081,7 @@ class RepositoryTest {
|
||||
|
||||
@Test
|
||||
fun create_source_without_connection() {
|
||||
coEvery { api.createSourceForVersion(any(), any(), any(), any(), any(), any()) } returns
|
||||
coEvery { api.createSourceForVersion(any(), any(), any(), any(), any()) } returns
|
||||
SuccessResponse(true)
|
||||
|
||||
initializeRepository(MutableStateFlow(false))
|
||||
@ -1104,7 +1102,6 @@ class RepositoryTest {
|
||||
any(),
|
||||
any(),
|
||||
any(),
|
||||
any(),
|
||||
any()
|
||||
)
|
||||
}
|
||||
|
@ -23,6 +23,14 @@ class StatusAndData<T>(val success: Boolean, val data: T? = null) {
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun responseOrSuccessIf404(r: HttpResponse): SuccessResponse {
|
||||
return if (r.status === HttpStatusCode.NotFound) {
|
||||
SuccessResponse(true)
|
||||
} else {
|
||||
maybeResponse(r)
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun maybeResponse(r: HttpResponse): SuccessResponse {
|
||||
return if (r.status.isSuccess()) {
|
||||
r.body()
|
||||
|
@ -340,8 +340,7 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap
|
||||
url,
|
||||
spout,
|
||||
tags,
|
||||
filter,
|
||||
appSettingsService.getApiVersion()
|
||||
filter
|
||||
).isSuccess == true
|
||||
}
|
||||
|
||||
@ -373,12 +372,29 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap
|
||||
val response = api.login()
|
||||
result = response.isSuccess == true
|
||||
} catch (cause: Throwable) {
|
||||
Napier.e(cause.stackTraceToString(), tag = "RepositoryImpl.updateRemote")
|
||||
Napier.e(cause.stackTraceToString(), tag = "RepositoryImpl.login")
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
suspend fun logout() {
|
||||
if (isNetworkAvailable()) {
|
||||
try {
|
||||
val response = api.logout()
|
||||
if (response.isSuccess) {
|
||||
Napier.e("Couldn't logout.", tag = "RepositoryImpl.logout")
|
||||
}
|
||||
} catch (cause: Throwable) {
|
||||
Napier.e(cause.stackTraceToString(), tag = "RepositoryImpl.logout")
|
||||
} finally {
|
||||
appSettingsService.clearAll()
|
||||
}
|
||||
} else {
|
||||
appSettingsService.clearAll()
|
||||
}
|
||||
}
|
||||
|
||||
fun refreshLoginInformation(url: String, login: String, password: String) {
|
||||
appSettingsService.refreshLoginInformation(url, login, password)
|
||||
baseUrl = url
|
||||
|
@ -2,11 +2,12 @@ package bou.amine.apps.readerforselfossv2.rest
|
||||
|
||||
import bou.amine.apps.readerforselfossv2.model.*
|
||||
import bou.amine.apps.readerforselfossv2.service.AppSettingsService
|
||||
import io.github.aakira.napier.Napier
|
||||
import io.ktor.client.*
|
||||
import io.ktor.client.call.*
|
||||
import io.ktor.client.plugins.*
|
||||
import io.ktor.client.plugins.cache.*
|
||||
import io.ktor.client.plugins.contentnegotiation.*
|
||||
import io.ktor.client.plugins.cookies.*
|
||||
import io.ktor.client.plugins.logging.*
|
||||
import io.ktor.client.request.*
|
||||
import io.ktor.client.request.forms.*
|
||||
@ -20,7 +21,7 @@ class SelfossApi(private val appSettingsService: AppSettingsService) {
|
||||
var client = createHttpClient()
|
||||
|
||||
private fun createHttpClient(): HttpClient {
|
||||
return HttpClient {
|
||||
val client = HttpClient {
|
||||
install(ContentNegotiation) {
|
||||
install(HttpCache)
|
||||
json(Json {
|
||||
@ -32,7 +33,7 @@ class SelfossApi(private val appSettingsService: AppSettingsService) {
|
||||
install(Logging) {
|
||||
logger = object : Logger {
|
||||
override fun log(message: String) {
|
||||
appSettingsService.logApiCalls(message)
|
||||
Napier.d(message, tag = "LogApiCalls")
|
||||
}
|
||||
}
|
||||
level = LogLevel.INFO
|
||||
@ -40,22 +41,26 @@ class SelfossApi(private val appSettingsService: AppSettingsService) {
|
||||
install(HttpTimeout) {
|
||||
requestTimeoutMillis = appSettingsService.getApiTimeout()
|
||||
}
|
||||
/* TODO: Auth as basic
|
||||
if (apiDetailsService.getUserName().isNotEmpty() && apiDetailsService.getPassword().isNotEmpty()) {
|
||||
|
||||
install(Auth) {
|
||||
basic {
|
||||
credentials {
|
||||
BasicAuthCredentials(username = apiDetailsService.getUserName(), password = apiDetailsService.getPassword())
|
||||
}
|
||||
sendWithoutRequest {
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
}*/
|
||||
install(HttpCookies)
|
||||
expectSuccess = false
|
||||
}
|
||||
|
||||
client.plugin(HttpSend).intercept { request ->
|
||||
val originalCall = execute(request)
|
||||
if (originalCall.response.status == HttpStatusCode.Forbidden && shouldHavePostLogin() && hasLoginInfo()) {
|
||||
Napier.i("Forbidden action, will try to login and retry", tag = "HttpSend")
|
||||
|
||||
if (login().isSuccess) {
|
||||
Napier.i("Logged in worked", tag = "HttpSend")
|
||||
execute(request)
|
||||
}
|
||||
originalCall
|
||||
} else {
|
||||
originalCall
|
||||
}
|
||||
}
|
||||
|
||||
return client
|
||||
}
|
||||
|
||||
fun url(path: String) =
|
||||
@ -66,11 +71,38 @@ class SelfossApi(private val appSettingsService: AppSettingsService) {
|
||||
client = createHttpClient()
|
||||
}
|
||||
|
||||
// Api version was introduces after the POST login, so when there is a version, it should be available
|
||||
private fun shouldHavePostLogin() = appSettingsService.getApiVersion() != -1
|
||||
private fun hasLoginInfo() = appSettingsService.getUserName() != null && appSettingsService.getPassword() != null
|
||||
|
||||
suspend fun login(): SuccessResponse =
|
||||
maybeResponse(client.get(url("/login")) {
|
||||
parameter("username", appSettingsService.getUserName())
|
||||
parameter("password", appSettingsService.getPassword())
|
||||
})
|
||||
if (shouldHavePostLogin()) {
|
||||
postLogin()
|
||||
} else {
|
||||
getLogin()
|
||||
}
|
||||
|
||||
private suspend fun getLogin() = maybeResponse(client.get(url("/login")) {
|
||||
parameter("username", appSettingsService.getUserName())
|
||||
parameter("password", appSettingsService.getPassword())
|
||||
})
|
||||
|
||||
private suspend fun postLogin() = maybeResponse(client.post(url("/login")) {
|
||||
parameter("username", appSettingsService.getUserName())
|
||||
parameter("password", appSettingsService.getPassword())
|
||||
})
|
||||
|
||||
private fun shouldHaveNewLogout() = appSettingsService.getApiVersion() >= 5 // We are missing 4.1.0
|
||||
suspend fun logout(): SuccessResponse =
|
||||
if (shouldHaveNewLogout()) {
|
||||
doLogout()
|
||||
} else {
|
||||
maybeLogoutIfAvailable()
|
||||
}
|
||||
|
||||
private suspend fun maybeLogoutIfAvailable() = responseOrSuccessIf404(client.get(url("/logout")))
|
||||
|
||||
private suspend fun doLogout() = maybeResponse(client.delete(url("/api/session/current")))
|
||||
|
||||
suspend fun getItems(
|
||||
type: String,
|
||||
@ -82,80 +114,102 @@ class SelfossApi(private val appSettingsService: AppSettingsService) {
|
||||
items: Int? = null
|
||||
): StatusAndData<List<SelfossModel.Item>> =
|
||||
bodyOrFailure(client.get(url("/items")) {
|
||||
if (!shouldHavePostLogin()) {
|
||||
parameter("username", appSettingsService.getUserName())
|
||||
parameter("password", appSettingsService.getPassword())
|
||||
parameter("type", type)
|
||||
parameter("tag", tag)
|
||||
parameter("source", source)
|
||||
parameter("search", search)
|
||||
parameter("updatedsince", updatedSince)
|
||||
parameter("items", items ?: appSettingsService.getItemsNumber())
|
||||
parameter("offset", offset)
|
||||
})
|
||||
}
|
||||
parameter("type", type)
|
||||
parameter("tag", tag)
|
||||
parameter("source", source)
|
||||
parameter("search", search)
|
||||
parameter("updatedsince", updatedSince)
|
||||
parameter("items", items ?: appSettingsService.getItemsNumber())
|
||||
parameter("offset", offset)
|
||||
})
|
||||
|
||||
suspend fun stats(): StatusAndData<SelfossModel.Stats> =
|
||||
bodyOrFailure(client.get(url("/stats")) {
|
||||
if (!shouldHavePostLogin()) {
|
||||
parameter("username", appSettingsService.getUserName())
|
||||
parameter("password", appSettingsService.getPassword())
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
suspend fun tags(): StatusAndData<List<SelfossModel.Tag>> =
|
||||
bodyOrFailure(client.get(url("/tags")) {
|
||||
if (!shouldHavePostLogin()) {
|
||||
parameter("username", appSettingsService.getUserName())
|
||||
parameter("password", appSettingsService.getPassword())
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
suspend fun update(): StatusAndData<String> =
|
||||
bodyOrFailure(client.get(url("/update")) {
|
||||
if (!shouldHavePostLogin()) {
|
||||
parameter("username", appSettingsService.getUserName())
|
||||
parameter("password", appSettingsService.getPassword())
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
suspend fun spouts(): StatusAndData<Map<String, SelfossModel.Spout>> =
|
||||
bodyOrFailure(client.get(url("/sources/spouts")) {
|
||||
if (!shouldHavePostLogin()) {
|
||||
parameter("username", appSettingsService.getUserName())
|
||||
parameter("password", appSettingsService.getPassword())
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
suspend fun sources(): StatusAndData<ArrayList<SelfossModel.Source>> =
|
||||
bodyOrFailure(client.get(url("/sources/list")) {
|
||||
if (!shouldHavePostLogin()) {
|
||||
parameter("username", appSettingsService.getUserName())
|
||||
parameter("password", appSettingsService.getPassword())
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
suspend fun version(): StatusAndData<SelfossModel.ApiVersion> =
|
||||
bodyOrFailure(client.get(url("/api/about")))
|
||||
|
||||
suspend fun markAsRead(id: String): SuccessResponse =
|
||||
maybeResponse(client.post(url("/mark/$id")) {
|
||||
parameter("username", appSettingsService.getUserName())
|
||||
parameter("password", appSettingsService.getPassword())
|
||||
if (!shouldHavePostLogin()) {
|
||||
parameter("username", appSettingsService.getUserName())
|
||||
parameter("password", appSettingsService.getPassword())
|
||||
}
|
||||
})
|
||||
|
||||
suspend fun unmarkAsRead(id: String): SuccessResponse =
|
||||
maybeResponse(client.post(url("/unmark/$id")) {
|
||||
parameter("username", appSettingsService.getUserName())
|
||||
parameter("password", appSettingsService.getPassword())
|
||||
if (!shouldHavePostLogin()) {
|
||||
parameter("username", appSettingsService.getUserName())
|
||||
parameter("password", appSettingsService.getPassword())
|
||||
}
|
||||
})
|
||||
|
||||
suspend fun starr(id: String): SuccessResponse =
|
||||
maybeResponse(client.post(url("/starr/$id")) {
|
||||
parameter("username", appSettingsService.getUserName())
|
||||
parameter("password", appSettingsService.getPassword())
|
||||
if (!shouldHavePostLogin()) {
|
||||
parameter("username", appSettingsService.getUserName())
|
||||
parameter("password", appSettingsService.getPassword())
|
||||
}
|
||||
})
|
||||
|
||||
suspend fun unstarr(id: String): SuccessResponse =
|
||||
maybeResponse(client.post(url("/unstarr/$id")) {
|
||||
parameter("username", appSettingsService.getUserName())
|
||||
parameter("password", appSettingsService.getPassword())
|
||||
if (!shouldHavePostLogin()) {
|
||||
parameter("username", appSettingsService.getUserName())
|
||||
parameter("password", appSettingsService.getPassword())
|
||||
}
|
||||
})
|
||||
|
||||
suspend fun markAllAsRead(ids: List<String>): SuccessResponse =
|
||||
maybeResponse(client.submitForm(
|
||||
url = url("/mark"),
|
||||
formParameters = Parameters.build {
|
||||
append("username", appSettingsService.getUserName())
|
||||
append("password", appSettingsService.getPassword())
|
||||
if (!shouldHavePostLogin()) {
|
||||
append("username", appSettingsService.getUserName())
|
||||
append("password", appSettingsService.getPassword())
|
||||
}
|
||||
ids.map { append("ids[]", it) }
|
||||
}
|
||||
))
|
||||
@ -165,18 +219,17 @@ class SelfossApi(private val appSettingsService: AppSettingsService) {
|
||||
url: String,
|
||||
spout: String,
|
||||
tags: String,
|
||||
filter: String,
|
||||
version: Int
|
||||
filter: String
|
||||
): SuccessResponse =
|
||||
maybeResponse(
|
||||
if (version > 1) {
|
||||
if (appSettingsService.getApiVersion() > 1) {
|
||||
createSource2(title, url, spout, tags, filter)
|
||||
} else {
|
||||
createSource(title, url, spout, tags, filter)
|
||||
}
|
||||
)
|
||||
|
||||
suspend fun createSource(
|
||||
private suspend fun createSource(
|
||||
title: String,
|
||||
url: String,
|
||||
spout: String,
|
||||
@ -184,8 +237,13 @@ class SelfossApi(private val appSettingsService: AppSettingsService) {
|
||||
filter: String
|
||||
): HttpResponse =
|
||||
client.submitForm(
|
||||
url = url("/source?username=${appSettingsService.getUserName()}&password=${appSettingsService.getPassword()}"),
|
||||
url = url("/source"),
|
||||
formParameters = Parameters.build {
|
||||
// TODO: test this
|
||||
if (!shouldHavePostLogin()) {
|
||||
append("username", appSettingsService.getUserName())
|
||||
append("password", appSettingsService.getPassword())
|
||||
}
|
||||
append("title", title)
|
||||
append("url", url)
|
||||
append("spout", spout)
|
||||
@ -194,7 +252,7 @@ class SelfossApi(private val appSettingsService: AppSettingsService) {
|
||||
}
|
||||
)
|
||||
|
||||
suspend fun createSource2(
|
||||
private suspend fun createSource2(
|
||||
title: String,
|
||||
url: String,
|
||||
spout: String,
|
||||
@ -202,8 +260,12 @@ class SelfossApi(private val appSettingsService: AppSettingsService) {
|
||||
filter: String
|
||||
): HttpResponse =
|
||||
client.submitForm(
|
||||
url = url("/source?username=${appSettingsService.getUserName()}&password=${appSettingsService.getPassword()}"),
|
||||
url = url("/source"),
|
||||
formParameters = Parameters.build {
|
||||
if (!shouldHavePostLogin()) {
|
||||
append("username", appSettingsService.getUserName())
|
||||
append("password", appSettingsService.getPassword())
|
||||
}
|
||||
append("title", title)
|
||||
append("url", url)
|
||||
append("spout", spout)
|
||||
@ -214,7 +276,9 @@ class SelfossApi(private val appSettingsService: AppSettingsService) {
|
||||
|
||||
suspend fun deleteSource(id: Int): SuccessResponse =
|
||||
maybeResponse(client.delete(url("/source/$id")) {
|
||||
if (!shouldHavePostLogin()) {
|
||||
parameter("username", appSettingsService.getUserName())
|
||||
parameter("password", appSettingsService.getPassword())
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
@ -44,10 +44,6 @@ class AppSettingsService {
|
||||
refreshUserSettings()
|
||||
}
|
||||
|
||||
fun logApiCalls(message: String) {
|
||||
Napier.d(message, tag = "LogApiCalls")
|
||||
}
|
||||
|
||||
fun getApiVersion(): Int {
|
||||
if (_apiVersion == -1) {
|
||||
refreshApiVersion()
|
||||
|
Reference in New Issue
Block a user