bugfix: No browser, no link.

This commit is contained in:
Amine Bouabdallaoui 2024-12-30 13:51:14 +01:00
parent 27c1bba146
commit 162a350a8f
5 changed files with 66 additions and 45 deletions

View File

@ -1,7 +1,6 @@
package bou.amine.apps.readerforselfossv2.android package bou.amine.apps.readerforselfossv2.android
import android.content.Intent import android.content.Intent
import android.net.Uri
import android.os.Bundle import android.os.Bundle
import android.view.Menu import android.view.Menu
import android.view.MenuItem import android.view.MenuItem
@ -32,6 +31,7 @@ import bou.amine.apps.readerforselfossv2.android.settings.SettingsActivity
import bou.amine.apps.readerforselfossv2.android.testing.CountingIdlingResourceSingleton import bou.amine.apps.readerforselfossv2.android.testing.CountingIdlingResourceSingleton
import bou.amine.apps.readerforselfossv2.android.utils.bottombar.maybeShow import bou.amine.apps.readerforselfossv2.android.utils.bottombar.maybeShow
import bou.amine.apps.readerforselfossv2.android.utils.bottombar.removeBadge import bou.amine.apps.readerforselfossv2.android.utils.bottombar.removeBadge
import bou.amine.apps.readerforselfossv2.android.utils.openUrlInBrowser
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.service.AppSettingsService import bou.amine.apps.readerforselfossv2.service.AppSettingsService
@ -589,9 +589,7 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
override fun onOptionsItemSelected(item: MenuItem): Boolean { override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) { when (item.itemId) {
R.id.issue_tracker -> { R.id.issue_tracker -> {
val browserIntent = baseContext.openUrlInBrowser(AppSettingsService.trackerUrl)
Intent(Intent.ACTION_VIEW, Uri.parse(AppSettingsService.trackerUrl))
startActivity(browserIntent)
return true return true
} }

View File

@ -12,7 +12,7 @@ import bou.amine.apps.readerforselfossv2.android.sendSilentlyWithAcraWithName
import bou.amine.apps.readerforselfossv2.android.utils.LinkOnTouchListener import bou.amine.apps.readerforselfossv2.android.utils.LinkOnTouchListener
import bou.amine.apps.readerforselfossv2.android.utils.glide.bitmapCenterCrop import bou.amine.apps.readerforselfossv2.android.utils.glide.bitmapCenterCrop
import bou.amine.apps.readerforselfossv2.android.utils.glide.circularDrawable import bou.amine.apps.readerforselfossv2.android.utils.glide.circularDrawable
import bou.amine.apps.readerforselfossv2.android.utils.openInBrowserAsNewTask import bou.amine.apps.readerforselfossv2.android.utils.openItemUrlInBrowserAsNewTask
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
@ -71,7 +71,7 @@ class ItemCardAdapter(
} }
binding.browserBtn.setOnClickListener { binding.browserBtn.setOnClickListener {
c.openInBrowserAsNewTask(items[position]) c.openItemUrlInBrowserAsNewTask(items[position])
} }
} }

View File

@ -1,16 +1,20 @@
package bou.amine.apps.readerforselfossv2.android.fragments package bou.amine.apps.readerforselfossv2.android.fragments
import android.content.ActivityNotFoundException
import android.content.Intent import android.content.Intent
import android.content.res.ColorStateList import android.content.res.ColorStateList
import android.content.res.TypedArray import android.content.res.TypedArray
import android.graphics.Bitmap import android.graphics.Bitmap
import android.graphics.Typeface import android.graphics.Typeface
import android.graphics.drawable.ColorDrawable import android.graphics.drawable.ColorDrawable
import android.net.Uri
import android.os.Bundle import android.os.Bundle
import android.util.TypedValue import android.util.TypedValue
import android.view.* 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.WebResourceResponse import android.webkit.WebResourceResponse
import android.webkit.WebSettings import android.webkit.WebSettings
import android.webkit.WebView import android.webkit.WebView
@ -28,7 +32,8 @@ import bou.amine.apps.readerforselfossv2.android.model.toParcelable
import bou.amine.apps.readerforselfossv2.android.sendSilentlyWithAcraWithName import bou.amine.apps.readerforselfossv2.android.sendSilentlyWithAcraWithName
import bou.amine.apps.readerforselfossv2.android.utils.glide.getBitmapInputStream import bou.amine.apps.readerforselfossv2.android.utils.glide.getBitmapInputStream
import bou.amine.apps.readerforselfossv2.android.utils.isUrlValid import bou.amine.apps.readerforselfossv2.android.utils.isUrlValid
import bou.amine.apps.readerforselfossv2.android.utils.openInBrowserAsNewTask import bou.amine.apps.readerforselfossv2.android.utils.openItemUrlInBrowserAsNewTask
import bou.amine.apps.readerforselfossv2.android.utils.openUrlInBrowser
import bou.amine.apps.readerforselfossv2.android.utils.shareLink import bou.amine.apps.readerforselfossv2.android.utils.shareLink
import bou.amine.apps.readerforselfossv2.model.MercuryModel import bou.amine.apps.readerforselfossv2.model.MercuryModel
import bou.amine.apps.readerforselfossv2.model.SelfossModel import bou.amine.apps.readerforselfossv2.model.SelfossModel
@ -53,7 +58,7 @@ import org.kodein.di.android.x.closestDI
import org.kodein.di.instance import org.kodein.di.instance
import java.net.MalformedURLException import java.net.MalformedURLException
import java.net.URL import java.net.URL
import java.util.* import java.util.Locale
import java.util.concurrent.ExecutionException import java.util.concurrent.ExecutionException
private const val IMAGE_JPG = "image/jpg" private const val IMAGE_JPG = "image/jpg"
@ -211,7 +216,7 @@ class ArticleFragment : Fragment(), DIAware {
override fun onItemClick(item: MenuItem) { override fun onItemClick(item: MenuItem) {
when (item.itemId) { when (item.itemId) {
R.id.share_action -> requireActivity().shareLink(url, contentTitle) R.id.share_action -> requireActivity().shareLink(url, contentTitle)
R.id.open_action -> requireActivity().openInBrowserAsNewTask(this@ArticleFragment.item) R.id.open_action -> requireActivity().openItemUrlInBrowserAsNewTask(this@ArticleFragment.item)
R.id.unread_action -> R.id.unread_action ->
if (context != null) { if (context != null) {
if (this@ArticleFragment.item.unread) { if (this@ArticleFragment.item.unread) {
@ -236,6 +241,7 @@ class ArticleFragment : Fragment(), DIAware {
).show() ).show()
} }
} }
else -> Unit else -> Unit
} }
} }
@ -288,7 +294,7 @@ class ArticleFragment : Fragment(), DIAware {
contentText = data.content.orEmpty() contentText = data.content.orEmpty()
htmlToWebview() htmlToWebview()
handleLeadImage(data?.lead_image_url) handleLeadImage(data.lead_image_url)
binding.nestedScrollView.scrollTo(0, 0) binding.nestedScrollView.scrollTo(0, 0)
binding.progressBar.visibility = View.GONE binding.progressBar.visibility = View.GONE
@ -320,11 +326,7 @@ class ArticleFragment : Fragment(), DIAware {
url: String, url: String,
): Boolean { ): Boolean {
return if (context != null && url.isUrlValid() && binding.webcontent.hitTestResult.type != WebView.HitTestResult.SRC_IMAGE_ANCHOR_TYPE) { return if (context != null && url.isUrlValid() && binding.webcontent.hitTestResult.type != WebView.HitTestResult.SRC_IMAGE_ANCHOR_TYPE) {
try { requireContext().openUrlInBrowser(url)
requireContext().startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(url)))
} catch (e: ActivityNotFoundException) {
e.sendSilentlyWithAcraWithName("activityNotFound > $url")
}
true true
} else { } else {
false false
@ -343,7 +345,8 @@ class ArticleFragment : Fragment(), DIAware {
) { ) {
try { try {
val image = val image =
Glide.with(view).asBitmap().apply(glideOptions).load(url).submit().get() Glide.with(view).asBitmap().apply(glideOptions).load(url).submit()
.get()
return WebResourceResponse( return WebResourceResponse(
IMAGE_JPG, IMAGE_JPG,
"UTF-8", "UTF-8",
@ -355,7 +358,8 @@ class ArticleFragment : Fragment(), DIAware {
} else if (url.lowercase(Locale.US).contains(".png")) { } else if (url.lowercase(Locale.US).contains(".png")) {
try { try {
val image = val image =
Glide.with(view).asBitmap().apply(glideOptions).load(url).submit().get() Glide.with(view).asBitmap().apply(glideOptions).load(url).submit()
.get()
return WebResourceResponse( return WebResourceResponse(
IMAGE_JPG, IMAGE_JPG,
"UTF-8", "UTF-8",
@ -367,7 +371,8 @@ class ArticleFragment : Fragment(), DIAware {
} else if (url.lowercase(Locale.US).contains(".webp")) { } else if (url.lowercase(Locale.US).contains(".webp")) {
try { try {
val image = val image =
Glide.with(view).asBitmap().apply(glideOptions).load(url).submit().get() Glide.with(view).asBitmap().apply(glideOptions).load(url).submit()
.get()
return WebResourceResponse( return WebResourceResponse(
IMAGE_JPG, IMAGE_JPG,
"UTF-8", "UTF-8",
@ -545,7 +550,7 @@ class ArticleFragment : Fragment(), DIAware {
private fun openInBrowserAfterFailing() { private fun openInBrowserAfterFailing() {
binding.progressBar.visibility = View.GONE binding.progressBar.visibility = View.GONE
if (context != null) { if (context != null) {
requireContext().openInBrowserAsNewTask(this@ArticleFragment.item) requireContext().openItemUrlInBrowserAsNewTask(this@ArticleFragment.item)
} else { } else {
Exception("openInBrowserAfterFailing context is null").sendSilentlyWithAcraWithName("openInBrowserAfterFailing > $context") Exception("openInBrowserAfterFailing context is null").sendSilentlyWithAcraWithName("openInBrowserAfterFailing > $context")
} }
@ -565,9 +570,9 @@ class ArticleFragment : Fragment(), DIAware {
fun performClick(): Boolean { fun performClick(): Boolean {
if (allImages != null && ( if (allImages != null && (
binding.webcontent.hitTestResult.type == WebView.HitTestResult.IMAGE_TYPE || binding.webcontent.hitTestResult.type == WebView.HitTestResult.IMAGE_TYPE ||
binding.webcontent.hitTestResult.type == WebView.HitTestResult.SRC_IMAGE_ANCHOR_TYPE binding.webcontent.hitTestResult.type == WebView.HitTestResult.SRC_IMAGE_ANCHOR_TYPE
) )
) { ) {
val position: Int = allImages.indexOf(binding.webcontent.hitTestResult.extra) val position: Int = allImages.indexOf(binding.webcontent.hitTestResult.extra)

View File

@ -1,7 +1,5 @@
package bou.amine.apps.readerforselfossv2.android.settings package bou.amine.apps.readerforselfossv2.android.settings
import android.content.Intent
import android.net.Uri
import android.os.Bundle import android.os.Bundle
import android.text.Editable import android.text.Editable
import android.text.InputFilter import android.text.InputFilter
@ -17,6 +15,7 @@ import androidx.preference.PreferenceFragmentCompat
import bou.amine.apps.readerforselfossv2.android.R import bou.amine.apps.readerforselfossv2.android.R
import bou.amine.apps.readerforselfossv2.android.databinding.ActivitySettingsBinding import bou.amine.apps.readerforselfossv2.android.databinding.ActivitySettingsBinding
import bou.amine.apps.readerforselfossv2.android.sendSilentlyWithAcraWithName import bou.amine.apps.readerforselfossv2.android.sendSilentlyWithAcraWithName
import bou.amine.apps.readerforselfossv2.android.utils.openUrlInBrowser
import bou.amine.apps.readerforselfossv2.service.AppSettingsService import bou.amine.apps.readerforselfossv2.service.AppSettingsService
import com.mikepenz.aboutlibraries.LibsBuilder import com.mikepenz.aboutlibraries.LibsBuilder
import org.kodein.di.DIAware import org.kodein.di.DIAware
@ -237,9 +236,8 @@ class SettingsActivity :
} }
class LinksPreferenceFragment : PreferenceFragmentCompat() { class LinksPreferenceFragment : PreferenceFragmentCompat() {
private fun openUrl(uri: Uri?) { private fun openUrl(url: String) {
val browserIntent = Intent(Intent.ACTION_VIEW, uri) context?.openUrlInBrowser(url)
startActivity(browserIntent)
} }
override fun onCreatePreferences( override fun onCreatePreferences(
@ -250,19 +248,19 @@ class SettingsActivity :
preferenceManager.findPreference<Preference>("trackerLink")?.onPreferenceClickListener = preferenceManager.findPreference<Preference>("trackerLink")?.onPreferenceClickListener =
Preference.OnPreferenceClickListener { Preference.OnPreferenceClickListener {
openUrl(Uri.parse(AppSettingsService.trackerUrl)) openUrl(AppSettingsService.trackerUrl)
true true
} }
preferenceManager.findPreference<Preference>("sourceLink")?.onPreferenceClickListener = preferenceManager.findPreference<Preference>("sourceLink")?.onPreferenceClickListener =
Preference.OnPreferenceClickListener { Preference.OnPreferenceClickListener {
openUrl(Uri.parse(AppSettingsService.sourceUrl)) openUrl(AppSettingsService.sourceUrl)
false false
} }
preferenceManager.findPreference<Preference>("translation")?.onPreferenceClickListener = preferenceManager.findPreference<Preference>("translation")?.onPreferenceClickListener =
Preference.OnPreferenceClickListener { Preference.OnPreferenceClickListener {
openUrl(Uri.parse(AppSettingsService.translationUrl)) openUrl(AppSettingsService.translationUrl)
false false
} }
} }

View File

@ -1,6 +1,7 @@
package bou.amine.apps.readerforselfossv2.android.utils package bou.amine.apps.readerforselfossv2.android.utils
import android.app.Activity import android.app.Activity
import android.content.ActivityNotFoundException
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.net.Uri import android.net.Uri
@ -17,6 +18,7 @@ import bou.amine.apps.readerforselfossv2.model.SelfossModel
import bou.amine.apps.readerforselfossv2.utils.toStringUriWithHttp import bou.amine.apps.readerforselfossv2.utils.toStringUriWithHttp
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
fun Context.openItemUrl( fun Context.openItemUrl(
currentItem: Int, currentItem: Int,
linkDecoded: String, linkDecoded: String,
@ -35,15 +37,13 @@ fun Context.openItemUrl(
intent.putExtra("currentItem", currentItem) intent.putExtra("currentItem", currentItem)
app.startActivity(intent) app.startActivity(intent)
} else { } else {
val intent = Intent(Intent.ACTION_VIEW) this.openUrlInBrowserAsNewTask(linkDecoded)
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
intent.data = Uri.parse(linkDecoded.toStringUriWithHttp())
startActivity(intent)
} }
} }
} }
fun String.isUrlValid(): Boolean = this.toHttpUrlOrNull() != null && Patterns.WEB_URL.matcher(this).matches() fun String.isUrlValid(): Boolean =
this.toHttpUrlOrNull() != null && Patterns.WEB_URL.matcher(this).matches()
fun String.isBaseUrlInvalid(): Boolean { fun String.isBaseUrlInvalid(): Boolean {
val baseUrl = this.toHttpUrlOrNull() val baseUrl = this.toHttpUrlOrNull()
@ -56,11 +56,31 @@ fun String.isBaseUrlInvalid(): Boolean {
return !(Patterns.WEB_URL.matcher(this).matches() && existsAndEndsWithSlash) return !(Patterns.WEB_URL.matcher(this).matches() && existsAndEndsWithSlash)
} }
fun Context.openInBrowserAsNewTask(i: SelfossModel.Item) { fun Context.openItemUrlInBrowserAsNewTask(i: SelfossModel.Item) {
this.openUrlInBrowserAsNewTask(i.getLinkDecoded().toStringUriWithHttp())
}
fun Context.openUrlInBrowserAsNewTask(url: String) {
val intent = Intent(Intent.ACTION_VIEW) val intent = Intent(Intent.ACTION_VIEW)
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
intent.data = Uri.parse(i.getLinkDecoded().toStringUriWithHttp()) intent.data = Uri.parse(url)
startActivity(intent) this.mayBeStartActivity(intent)
}
fun Context.openUrlInBrowser(url: String) {
val intent = Intent(Intent.ACTION_VIEW)
intent.data = Uri.parse(url)
this.mayBeStartActivity(intent)
}
fun Context.mayBeStartActivity(intent: Intent) {
try {
this.startActivity(intent)
} catch (e: ActivityNotFoundException) {
Toast.makeText(this, getString(R.string.no_browser), Toast.LENGTH_SHORT).show()
}
} }
class LinkOnTouchListener : View.OnTouchListener { class LinkOnTouchListener : View.OnTouchListener {