Compare commits

..

No commits in common. "20aab0ea62c9ade648152b60cdee5f7ffd3bf9a1" and "172362b53320d805c7ad92bf8cc048951ceb44c6" have entirely different histories.

16 changed files with 142 additions and 192 deletions

View File

@ -8,15 +8,15 @@ plugins {
kotlin("android")
kotlin("kapt")
id("com.mikepenz.aboutlibraries.plugin")
id("org.jetbrains.kotlinx.kover")
id("org.jetbrains.kotlinx.kover") version "0.6.1"
}
fun Project.execWithOutput(cmd: String, ignore: Boolean = false): String {
val result: String = ByteArrayOutputStream().use { outputStream ->
var result: String = ByteArrayOutputStream().use { outputStream ->
project.exec {
commandLine = cmd.split(" ")
standardOutput = outputStream
isIgnoreExitValue = ignore
isIgnoreExitValue = ignore ?: false
}
outputStream.toString()
}
@ -24,8 +24,9 @@ fun Project.execWithOutput(cmd: String, ignore: Boolean = false): String {
}
fun gitVersion(): String {
var process = ""
val maybeTagOfCurrentCommit = execWithOutput("git -C ../ describe --contains HEAD", true)
val process = if (maybeTagOfCurrentCommit.isEmpty()) {
process = if (maybeTagOfCurrentCommit.isEmpty()) {
println("No tag on current commit. Will take the latest one.")
execWithOutput("git -C ../ for-each-ref refs/tags --sort=-refname --format='%(refname:short)' --count=1")
} else {
@ -57,22 +58,23 @@ android {
compileOptions {
isCoreLibraryDesugaringEnabled = true
// Flag to enable support for the new language APIs
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
// For Kotlin projects
kotlinOptions {
jvmTarget = "17"
jvmTarget = "11"
}
compileSdk = 34
compileSdk = 33
buildToolsVersion = "33.0.0"
buildFeatures {
viewBinding = true
}
defaultConfig {
applicationId = "bou.amine.apps.readerforselfossv2.android"
minSdk = 21
targetSdk = 34
targetSdk = 33
versionCode = versionCodeFromGit()
versionName = versionNameFromGit()
@ -85,7 +87,7 @@ android {
// tests
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}
packaging {
packagingOptions {
resources {
excludes += "/META-INF/{AL2.0,LGPL2.1}"
}
@ -114,25 +116,25 @@ dependencies {
coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.0.3")
implementation(project(":shared"))
implementation("com.google.android.material:material:1.9.0")
implementation("androidx.appcompat:appcompat:1.6.1")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.1")
implementation("com.google.android.material:material:1.5.0")
implementation("androidx.appcompat:appcompat:1.4.1")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.0")
implementation("androidx.preference:preference-ktx:1.2.1")
implementation("androidx.preference:preference-ktx:1.1.1")
implementation(fileTree(mapOf("include" to listOf("*.jar"), "dir" to "libs")))
// Android Support
implementation("androidx.appcompat:appcompat:1.6.1")
implementation("com.google.android.material:material:1.9.0")
implementation("androidx.recyclerview:recyclerview:1.3.1")
implementation("androidx.appcompat:appcompat:1.4.1")
implementation("com.google.android.material:material:1.5.0")
implementation("androidx.recyclerview:recyclerview:1.3.0-alpha01")
implementation("androidx.legacy:legacy-support-v4:1.0.0")
implementation("androidx.vectordrawable:vectordrawable:1.2.0-beta01")
implementation("androidx.vectordrawable:vectordrawable:1.2.0-alpha02")
implementation("androidx.cardview:cardview:1.0.0")
implementation("androidx.annotation:annotation:1.7.0")
implementation("androidx.work:work-runtime-ktx:2.8.1")
implementation("androidx.annotation:annotation:1.3.0")
implementation("androidx.work:work-runtime-ktx:2.7.1")
implementation("androidx.constraintlayout:constraintlayout:2.1.4")
implementation("org.jsoup:jsoup:1.15.4")
implementation("org.jsoup:jsoup:1.14.3")
//multidex
implementation("androidx.multidex:multidex:2.0.1")
@ -153,7 +155,7 @@ dependencies {
// Pager
implementation("me.relex:circleindicator:2.1.6")
implementation("androidx.viewpager2:viewpager2:1.1.0-beta02")
implementation("androidx.viewpager2:viewpager2:1.1.0-beta01")
//Dependency Injection
implementation("org.kodein.di:kodein-di:7.14.0")
@ -169,7 +171,7 @@ dependencies {
//PhotoView
implementation("com.github.chrisbanes:PhotoView:2.3.0")
implementation("androidx.core:core-ktx:1.12.0")
implementation("androidx.core:core-ktx:1.8.0")
implementation("androidx.lifecycle:lifecycle-extensions:2.2.0")
@ -182,7 +184,7 @@ dependencies {
//test
testImplementation("junit:junit:4.13.2")
testImplementation("io.mockk:mockk:1.12.0")
testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1")
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")

View File

@ -55,7 +55,6 @@
# maybe remove later ?
-keep class * extends androidx.fragment.app.Fragment
-dontwarn org.slf4j.impl.StaticLoggerBinder
# Keep `Companion` object fields of serializable classes.
# This avoids serializer lookup through `getDeclaredClasses` as done for named companion objects.

View File

@ -5,7 +5,6 @@ import android.content.res.ColorStateList
import android.os.Bundle
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.LinearLayoutManager
import bou.amine.apps.readerforselfossv2.android.adapters.SourcesListAdapter
import bou.amine.apps.readerforselfossv2.android.databinding.ActivitySourcesBinding
@ -37,10 +36,8 @@ class SourcesActivity : AppCompatActivity(), DIAware {
supportActionBar?.setDisplayHomeAsUpEnabled(true)
supportActionBar?.setDisplayShowHomeEnabled(true)
binding.fab.rippleColor = ContextCompat.getColor(this, R.color.colorAccentDark)
binding.fab.backgroundTintList =
ColorStateList.valueOf(ContextCompat.getColor(this, R.color.colorAccent))
binding.fab.rippleColor = resources.getColor(R.color.colorAccentDark)
binding.fab.backgroundTintList = ColorStateList.valueOf(resources.getColor(R.color.colorAccent))
}
override fun onStop() {

View File

@ -6,7 +6,6 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView.ScaleType
import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.RecyclerView
import bou.amine.apps.readerforselfossv2.android.R
import bou.amine.apps.readerforselfossv2.android.databinding.CardItemBinding
@ -61,7 +60,7 @@ class ItemCardAdapter(
binding.title.setOnTouchListener(LinkOnTouchListener())
binding.title.setLinkTextColor(ContextCompat.getColor(c, R.color.colorAccent))
binding.title.setLinkTextColor(c.resources.getColor(R.color.colorAccent))
binding.sourceTitleAndDate.text = itm.sourceAuthorAndDate()

View File

@ -4,7 +4,6 @@ import android.app.Activity
import android.content.Context
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.RecyclerView
import bou.amine.apps.readerforselfossv2.android.R
import bou.amine.apps.readerforselfossv2.android.databinding.ListItemBinding
@ -45,8 +44,7 @@ class ItemListAdapter(
binding.title.setOnTouchListener(LinkOnTouchListener())
binding.title.setLinkTextColor(ContextCompat.getColor(c, R.color.colorAccent))
binding.title.setLinkTextColor(c.resources.getColor(R.color.colorAccent))
binding.sourceTitleAndDate.text = itm.sourceAuthorAndDate()

View File

@ -10,21 +10,13 @@ import android.graphics.drawable.ColorDrawable
import android.net.Uri
import android.os.Bundle
import android.util.TypedValue
import android.view.GestureDetector
import android.view.InflateException
import android.view.LayoutInflater
import android.view.MenuItem
import android.view.MotionEvent
import android.view.View
import android.view.ViewGroup
import android.webkit.WebResourceRequest
import android.view.*
import android.webkit.WebResourceResponse
import android.webkit.WebSettings
import android.webkit.WebView
import android.webkit.WebViewClient
import android.widget.Toast
import androidx.appcompat.app.AlertDialog
import androidx.core.content.ContextCompat
import androidx.core.widget.NestedScrollView
import androidx.fragment.app.Fragment
import bou.amine.apps.readerforselfossv2.android.ImageActivity
@ -43,7 +35,6 @@ import bou.amine.apps.readerforselfossv2.model.SelfossModel
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.utils.ImageMimeType
import bou.amine.apps.readerforselfossv2.utils.getHtmlDecoded
import bou.amine.apps.readerforselfossv2.utils.getImages
import bou.amine.apps.readerforselfossv2.utils.getThumbnail
@ -63,7 +54,7 @@ import org.kodein.di.instance
import java.net.MalformedURLException
import java.net.SocketTimeoutException
import java.net.URL
import java.util.Locale
import java.util.*
import java.util.concurrent.ExecutionException
@ -125,15 +116,9 @@ class ArticleFragment : Fragment(), DIAware {
fab = binding.fab
fab.backgroundTintList =
ColorStateList.valueOf(
ContextCompat.getColor(
requireContext(),
R.color.colorAccent
)
)
fab.backgroundTintList = ColorStateList.valueOf(resources.getColor(R.color.colorAccent))
fab.rippleColor = ContextCompat.getColor(requireContext(), R.color.colorAccentDark)
fab.rippleColor = resources.getColor(R.color.colorAccentDark)
val floatingToolbar: FloatingToolbar = handleFloatingToolbar()
@ -218,8 +203,7 @@ class ArticleFragment : Fragment(), DIAware {
}
floatingToolbar.attachFab(fab)
floatingToolbar.background =
ColorDrawable(ContextCompat.getColor(requireContext(), R.color.colorAccent))
floatingToolbar.background = ColorDrawable(resources.getColor(R.color.colorAccent))
floatingToolbar.setClickListener(
object : FloatingToolbar.ItemClickListener {
@ -304,7 +288,7 @@ class ArticleFragment : Fragment(), DIAware {
contentText = data.content.orEmpty()
htmlToWebview()
handleLeadImage(data.lead_image_url)
handleLeadImage(data?.lead_image_url)
binding.nestedScrollView.scrollTo(0, 0)
binding.progressBar.visibility = View.GONE
@ -329,19 +313,11 @@ class ArticleFragment : Fragment(), DIAware {
private fun handleImageLoading() {
binding.webcontent.webViewClient = object : WebViewClient() {
override fun shouldOverrideUrlLoading(
view: WebView?,
request: WebResourceRequest?
): Boolean {
val url = request?.url?.toString()
return if (context != null && url != null && url.isUrlValid() && binding.webcontent.hitTestResult.type != WebView.HitTestResult.SRC_IMAGE_ANCHOR_TYPE) {
@Deprecated("Deprecated in Java")
override fun shouldOverrideUrlLoading(view: WebView?, url: String): Boolean {
return if (context != null && url.isUrlValid() && binding.webcontent.hitTestResult.type != WebView.HitTestResult.SRC_IMAGE_ANCHOR_TYPE) {
try {
requireContext().startActivity(
Intent(
Intent.ACTION_VIEW,
Uri.parse(url)
)
)
requireContext().startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(url)))
} catch (e: ActivityNotFoundException) {
e.sendSilentlyWithAcraWithName("activityNotFound > $url")
}
@ -351,42 +327,50 @@ class ArticleFragment : Fragment(), DIAware {
}
}
override fun shouldInterceptRequest(
view: WebView,
request: WebResourceRequest
): WebResourceResponse? {
val url = request.url.toString()
@Deprecated("Deprecated in Java")
override fun shouldInterceptRequest(view: WebView, url: String): WebResourceResponse? {
val glideOptions = RequestOptions.diskCacheStrategyOf(DiskCacheStrategy.ALL)
val supportedExtensions = ImageMimeType.values().map { it.extension }
val matchingExtension = supportedExtensions.find {
url.lowercase(Locale.US).contains(it)
}
matchingExtension?.let {
if (url.lowercase(Locale.US).contains(".jpg") || url.lowercase(Locale.US)
.contains(".jpeg")
) {
try {
val image = Glide.with(view)
.asBitmap()
.apply(glideOptions)
.load(url)
.submit()
.get()
val mimeType = ImageMimeType.findMimeTypeByExtension(it)
if (mimeType != null) {
return WebResourceResponse(
mimeType,
"UTF-8",
getBitmapInputStream(image, Bitmap.CompressFormat.WEBP)
)
}
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) {
// Do nothing
}
} 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) {
// Do nothing
}
} 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) {
// Do nothing
}
}
return super.shouldInterceptRequest(view, request)
return super.shouldInterceptRequest(view, url)
}
}
}
@ -398,23 +382,13 @@ class ArticleFragment : Fragment(), DIAware {
binding.webcontent.settings.standardFontFamily = a.getString(0)
a.recycle()
binding.webcontent.visibility = View.VISIBLE
val colorOnSurface = TypedValue()
requireContext().theme.resolveAttribute(
com.google.android.material.R.attr.colorOnSurface,
colorOnSurface,
true
)
requireContext().theme.resolveAttribute(R.attr.colorOnSurface, colorOnSurface, true)
val colorSurface = TypedValue()
requireContext().theme.resolveAttribute(
com.google.android.material.R.attr.colorSurface,
colorSurface,
true
)
requireContext().theme.resolveAttribute(R.attr.colorSurface, colorSurface, true)
binding.webcontent.settings.useWideViewPort = true
binding.webcontent.settings.loadWithOverviewMode = true
@ -483,7 +457,7 @@ class ArticleFragment : Fragment(), DIAware {
| color: ${
String.format(
"#%06X",
0xFFFFFF and ContextCompat.getColor(requireContext(), R.color.colorAccent)
0xFFFFFF and resources.getColor(R.color.colorAccent)
)
} !important;
| }

View File

@ -12,7 +12,6 @@ import android.view.View
import android.view.View.GONE
import android.view.View.VISIBLE
import android.view.ViewGroup
import androidx.core.content.ContextCompat
import bou.amine.apps.readerforselfossv2.android.HomeActivity
import bou.amine.apps.readerforselfossv2.android.R
import bou.amine.apps.readerforselfossv2.android.databinding.FilterFragmentBinding
@ -21,7 +20,7 @@ import bou.amine.apps.readerforselfossv2.repository.Repository
import bou.amine.apps.readerforselfossv2.utils.getHtmlDecoded
import bou.amine.apps.readerforselfossv2.utils.getIcon
import com.bumptech.glide.Glide
import com.bumptech.glide.request.target.CustomViewTarget
import com.bumptech.glide.request.target.ViewTarget
import com.bumptech.glide.request.transition.Transition
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
import com.google.android.material.chip.Chip
@ -83,13 +82,13 @@ class FilterSheetFragment : BottomSheetDialogFragment(), DIAware {
) {
val sourceGroup = binding.sourcesGroup
repository.getSourcesDetailsOrStats().forEachIndexed { _, source ->
repository.getSourcesDetailsOrStats().forEach { source ->
val c = Chip(context)
c.ellipsize = TextUtils.TruncateAt.END
Glide.with(context)
.load(source.getIcon(repository.baseUrl))
.into(object : CustomViewTarget<Chip, Drawable>(c) {
.into(object : ViewTarget<Chip?, Drawable?>(c) {
override fun onResourceReady(
resource: Drawable,
transition: Transition<in Drawable?>?
@ -101,13 +100,6 @@ class FilterSheetFragment : BottomSheetDialogFragment(), DIAware {
}
}
override fun onLoadFailed(errorDrawable: Drawable?) {
c.chipIcon = errorDrawable
}
override fun onResourceCleared(placeholder: Drawable?) {
c.chipIcon = placeholder
}
})
c.text = source.title.getHtmlDecoded()
@ -152,7 +144,7 @@ class FilterSheetFragment : BottomSheetDialogFragment(), DIAware {
val tags = repository.getTags()
tags.forEachIndexed { _, tag ->
tags.forEach { tag ->
val c = Chip(context)
c.ellipsize = TextUtils.TruncateAt.END
c.text = tag.tag
@ -164,7 +156,7 @@ class FilterSheetFragment : BottomSheetDialogFragment(), DIAware {
Color.parseColor(tag.color)
} catch (e: IllegalArgumentException) {
e.sendSilentlyWithAcraWithName("color issue " + tag.color)
ContextCompat.getColor(context, R.color.colorPrimary)
resources.getColor(R.color.colorPrimary)
}
gd.setColor(gdColor)
gd.shape = GradientDrawable.RECTANGLE

View File

@ -71,25 +71,23 @@ class SettingsActivity : AppCompatActivity(),
}
override fun onPreferenceStartFragment(
caller: PreferenceFragmentCompat,
pref: Preference
caller: PreferenceFragmentCompat,
pref: Preference
): Boolean {
val fragmentClassName = pref.fragment ?: return false
// Instantiate the new Fragment
val args = pref.extras
val fragment = supportFragmentManager.fragmentFactory.instantiate(
classLoader,
fragmentClassName
classLoader,
pref.fragment
).apply {
arguments = args
setTargetFragment(caller, 0)
}
// Replace the existing Fragment with the new Fragment
supportFragmentManager.beginTransaction()
.replace(R.id.settings, fragment)
.addToBackStack(null)
.commit()
.replace(R.id.settings, fragment)
.addToBackStack(null)
.commit()
title = pref.title
supportActionBar?.title = title
return true

View File

@ -95,7 +95,6 @@ class LinkOnTouchListener : View.OnTouchListener {
if (link.isNotEmpty()) {
if (action == MotionEvent.ACTION_UP) {
link[0].onClick(widget)
widget.performClick()
}
ret = true
}

View File

@ -1,18 +1,18 @@
buildscript {
dependencies {
// SqlDelight
classpath("com.squareup.sqldelight:gradle-plugin:1.5.5")
classpath("com.squareup.sqldelight:gradle-plugin:1.5.4")
}
}
plugins {
//trick: for the same plugin versions in all sub-modules
id("com.android.application").version("8.1.0").apply(false)
id("com.android.library").version("8.1.0").apply(false)
id("org.jetbrains.kotlin.android").version("1.9.10").apply(false)
kotlin("multiplatform").version("1.9.10").apply(false)
id("com.android.application").version("7.4.0").apply(false)
id("com.android.library").version("7.4.0").apply(false)
kotlin("android").version("1.7.20").apply(false)
kotlin("multiplatform").version("1.7.20").apply(false)
id("com.mikepenz.aboutlibraries.plugin").version("10.5.1").apply(false)
id("org.jetbrains.kotlinx.kover").version("0.6.1").apply(true)
id("org.jetbrains.kotlinx.kover") version "0.6.1"
}
allprojects {
@ -20,6 +20,7 @@ allprojects {
// maven { url = uri("https://nexus.amine-louveau.fr/repository/maven-public/")}
google()
mavenCentral()
jcenter()
maven { url = uri("https://www.jitpack.io") }
}
}

View File

@ -13,15 +13,22 @@
#Tue Mar 22 16:50:00 CET 2022
#Gradle
org.gradle.jvmargs=-Xmx2048M -Dfile.encoding=UTF-8 -Dkotlin.daemon.jvm.options\="-Xmx2048M"
#Kotlin
kotlin.code.style=official
#Android
android.useAndroidX=true
kotlin.native.enableDependencyPropagation=false
#android.nonTransitiveRClass=true
android.enableJetifier=true
android.nonTransitiveRClass=true
#MPP
kotlin.mpp.enableCInteropCommonization=true
kotlin.mpp.enableGranularSourceSetsMetadata=true
org.gradle.parallel=true
org.gradle.caching=true
ignoreGitVersion=false

View File

@ -1,6 +1,6 @@
#Thu Jul 13 11:41:19 CEST 2023
#Mon Jan 23 20:47:46 CET 2023
distributionBase=GRADLE_USER_HOME
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME

View File

@ -1,5 +1,3 @@
val ktorVersion = "2.3.2"
object SqlDelight {
const val runtime = "com.squareup.sqldelight:runtime:1.5.4"
const val android = "com.squareup.sqldelight:android-driver:1.5.4"
@ -11,12 +9,12 @@ plugins {
kotlin("multiplatform")
id("com.android.library")
id("com.squareup.sqldelight")
kotlin("plugin.serialization") version "1.9.0"
id("org.jetbrains.kotlinx.kover")
kotlin("plugin.serialization") version "1.4.10"
id("org.jetbrains.kotlinx.kover") version "0.6.1"
}
kotlin {
androidTarget()
android()
listOf(
iosX64(),
@ -31,17 +29,16 @@ kotlin {
sourceSets {
val commonMain by getting {
dependencies {
implementation("io.ktor:ktor-client-core:$ktorVersion")
implementation("io.ktor:ktor-client-content-negotiation:$ktorVersion")
implementation("io.ktor:ktor-serialization-kotlinx-json:$ktorVersion")
implementation("io.ktor:ktor-client-logging:$ktorVersion")
implementation("io.ktor:ktor-client-auth:$ktorVersion")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1")
implementation("org.jsoup:jsoup:1.15.4")
implementation("io.ktor:ktor-client-core:2.1.1")
implementation("io.ktor:ktor-client-content-negotiation:2.1.1")
implementation("io.ktor:ktor-serialization-kotlinx-json:2.1.1")
implementation("io.ktor:ktor-client-logging:2.1.1")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.0")
implementation("io.ktor:ktor-client-auth:2.1.1")
implementation("org.jsoup:jsoup:1.14.3")
//Dependency Injection
implementation("org.kodein.di:kodein-di:7.14.0")
implementation("org.kodein.di:kodein-di:7.12.0")
//Settings
implementation("com.russhwolf:multiplatform-settings-no-arg:1.0.0-RC")
@ -61,15 +58,14 @@ kotlin {
}
val androidMain by getting {
dependencies {
implementation("com.squareup.okhttp3:okhttp:4.11.0")
implementation("io.ktor:ktor-client-okhttp:2.2.4")
implementation("io.ktor:ktor-client-okhttp:2.1.1")
implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.4.0")
// Sql
implementation(SqlDelight.android)
}
}
val androidUnitTest by getting {
val androidTest by getting {
dependencies {
implementation(kotlin("test-junit"))
implementation("junit:junit:4.13.2")
@ -102,14 +98,15 @@ kotlin {
}
android {
compileSdk = 33
compileSdk = 32
sourceSets["main"].manifest.srcFile("src/androidMain/AndroidManifest.xml")
defaultConfig {
minSdk = 21
targetSdk = 32
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
namespace = "bou.amine.apps.readerforselfossv2"
}

View File

@ -1,19 +1,13 @@
package bou.amine.apps.readerforselfossv2.utils
import android.net.Uri
import android.os.Build
import android.text.Html
import bou.amine.apps.readerforselfossv2.model.SelfossModel
import org.jsoup.Jsoup
import java.util.*
actual fun String.getHtmlDecoded(): String {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
Html.fromHtml(this, Html.FROM_HTML_MODE_COMPACT).toString()
} else {
@Suppress("DEPRECATION")
Html.fromHtml(this).toString()
}
return Html.fromHtml(this).toString()
}
actual fun SelfossModel.Item.getIcon(baseUrl: String): String {
@ -25,10 +19,19 @@ actual fun SelfossModel.Item.getThumbnail(baseUrl: String): String {
}
actual fun SelfossModel.Item.getImages(): ArrayList<String> {
val doc = Jsoup.parse(content)
val images = doc.getElementsByTag("img")
val allImages = ArrayList<String>()
return ArrayList(images.map { it.attr("src") })
for ( image in Jsoup.parse(content).getElementsByTag("img")) {
val url = image.attr("src")
if (url.lowercase(Locale.US).contains(".jpg") ||
url.lowercase(Locale.US).contains(".jpeg") ||
url.lowercase(Locale.US).contains(".png") ||
url.lowercase(Locale.US).contains(".webp"))
{
allImages.add(url)
}
}
return allImages
}
actual fun SelfossModel.Source.getIcon(baseUrl: String): String {

View File

@ -17,7 +17,7 @@ fun SOURCE.toView(): SelfossModel.SourceDetail =
this.id.toInt(),
this.title,
null,
this.tags.split(","),
this.tags?.split(","),
this.spout,
this.error,
this.icon,

View File

@ -8,20 +8,4 @@ enum class ItemType(val position: Int, val type: String) {
companion object {
fun fromInt(value: Int) = values().first { it.position == value }
}
}
enum class ImageMimeType(val extension: String, val mimeType: String) {
JPG(".jpg", "image/jpeg"),
JPEG(".jpeg", "image/jpeg"),
PNG(".png", "image/png"),
WEBP(".webp", "image/webp"),
GIF(".gif", "image/gif"),
SVG(".svg", "image/svg+xml"),
BMP(".bmp", "image/bmp"),
TIFF(".tiff", "image/tiff"),
TIF(".tif", "image/tiff");
companion object {
fun findMimeTypeByExtension(ext: String) = values().find { it.extension == ext }?.mimeType
}
}