fix: Link not opening. #178

Merged
AmineB merged 4 commits from fix-open-link into master 2025-01-24 21:48:16 +00:00
5 changed files with 85 additions and 75 deletions

View File

@ -31,7 +31,7 @@ import bou.amine.apps.readerforselfossv2.android.settings.SettingsActivity
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.removeBadge
import bou.amine.apps.readerforselfossv2.android.utils.openUrlInBrowser
import bou.amine.apps.readerforselfossv2.android.utils.openUrlInBrowserAsNewTask
import bou.amine.apps.readerforselfossv2.model.SelfossModel
import bou.amine.apps.readerforselfossv2.repository.Repository
import bou.amine.apps.readerforselfossv2.service.AppSettingsService
@ -599,7 +599,7 @@ class HomeActivity :
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
R.id.issue_tracker -> {
baseContext.openUrlInBrowser(AppSettingsService.BUG_URL)
baseContext.openUrlInBrowserAsNewTask(AppSettingsService.BUG_URL)
return true
}

View File

@ -33,8 +33,9 @@ import bou.amine.apps.readerforselfossv2.android.utils.glide.bitmapFitCenter
import bou.amine.apps.readerforselfossv2.android.utils.glide.getBitmapInputStream
import bou.amine.apps.readerforselfossv2.android.utils.glide.getGlideImageForResource
import bou.amine.apps.readerforselfossv2.android.utils.isUrlValid
import bou.amine.apps.readerforselfossv2.android.utils.maybeIfContext
import bou.amine.apps.readerforselfossv2.android.utils.openItemUrlInBrowserAsNewTask
import bou.amine.apps.readerforselfossv2.android.utils.openUrlInBrowser
import bou.amine.apps.readerforselfossv2.android.utils.openUrlInBrowserAsNewTask
import bou.amine.apps.readerforselfossv2.android.utils.shareLink
import bou.amine.apps.readerforselfossv2.model.MercuryModel
import bou.amine.apps.readerforselfossv2.model.SelfossModel
@ -117,8 +118,8 @@ class ArticleFragment :
e.sendSilentlyWithAcra()
}
colorOnSurface = requireContext().getColorFromAttr(R.attr.colorOnSurface)
colorSurface = requireContext().getColorFromAttr(R.attr.colorSurface)
colorOnSurface = getColorFromAttr(R.attr.colorOnSurface)
colorSurface = getColorFromAttr(R.attr.colorSurface)
contentText = item.content
contentTitle = item.title.getHtmlDecoded()
@ -147,11 +148,11 @@ class ArticleFragment :
handleContent()
} catch (e: InflateException) {
e.sendSilentlyWithAcraWithName("webview not available")
try {
maybeIfContext {
AlertDialog
.Builder(requireContext())
.setMessage(requireContext().getString(R.string.webview_dialog_issue_message))
.setTitle(requireContext().getString(R.string.webview_dialog_issue_title))
.Builder(it)
.setMessage(it.getString(R.string.webview_dialog_issue_message))
.setTitle(it.getString(R.string.webview_dialog_issue_title))
.setPositiveButton(
android.R.string.ok,
) { _, _ ->
@ -159,8 +160,6 @@ class ArticleFragment :
requireActivity().finish()
}.create()
.show()
} catch (e: IllegalStateException) {
e.sendSilentlyWithAcraWithName("Context required is null")
}
}
@ -182,7 +181,7 @@ class ArticleFragment :
if (!contentImage.isEmptyOrNullOrNullString() && context != null) {
binding.imageView.visibility = View.VISIBLE
requireContext().bitmapFitCenter(contentImage, binding.imageView, appSettingsService)
maybeIfContext { it.bitmapFitCenter(contentImage, binding.imageView, appSettingsService) }
} else {
binding.imageView.visibility = View.GONE
}
@ -194,7 +193,7 @@ class ArticleFragment :
fab.mainFabClosedIconColor = colorOnSurface
fab.mainFabOpenedIconColor = colorOnSurface
handleFloatingToolbarActionItems()
maybeIfContext { context -> handleFloatingToolbarActionItems(context) }
fab.setOnActionSelectedListener { actionItem ->
when (actionItem.id) {
@ -207,12 +206,14 @@ class ArticleFragment :
repository.markAsRead(this@ArticleFragment.item)
}
this@ArticleFragment.item.unread = false
Toast
.makeText(
requireContext(),
R.string.marked_as_read,
Toast.LENGTH_LONG,
).show()
maybeIfContext {
Toast
.makeText(
it,
R.string.marked_as_read,
Toast.LENGTH_LONG,
).show()
}
} else {
CoroutineScope(Dispatchers.IO).launch {
repository.unmarkAsRead(this@ArticleFragment.item)
@ -226,7 +227,7 @@ class ArticleFragment :
).show()
}
} catch (e: IllegalStateException) {
e.sendSilentlyWithAcraWithName("Context required is null")
e.sendSilentlyWithAcraWithName("Toolbar context required is null")
}
else -> Unit
@ -235,14 +236,14 @@ class ArticleFragment :
}
}
private fun handleFloatingToolbarActionItems() {
private fun handleFloatingToolbarActionItems(c: Context) {
fab.addHomeMadeActionItem(
R.id.share_action,
resources.getDrawable(R.drawable.ic_share_white_24dp),
R.string.reader_action_share,
colorOnSurface,
colorSurface,
requireContext(),
c,
)
fab.addHomeMadeActionItem(
R.id.open_action,
@ -250,7 +251,7 @@ class ArticleFragment :
R.string.reader_action_open,
colorOnSurface,
colorSurface,
requireContext(),
c,
)
fab.addHomeMadeActionItem(
R.id.unread_action,
@ -258,7 +259,7 @@ class ArticleFragment :
R.string.unmark,
colorOnSurface,
colorSurface,
requireContext(),
c,
)
}
@ -311,9 +312,11 @@ class ArticleFragment :
}
private fun handleLeadImage(leadImageUrl: String?) {
if (!leadImageUrl.isNullOrEmpty() && context != null) {
if (!leadImageUrl.isNullOrEmpty()) {
binding.imageView.visibility = View.VISIBLE
requireContext().bitmapFitCenter(leadImageUrl, binding.imageView, appSettingsService)
maybeIfContext {
it.bitmapFitCenter(leadImageUrl, binding.imageView, appSettingsService)
}
} else {
binding.imageView.visibility = View.GONE
}
@ -327,11 +330,10 @@ class ArticleFragment :
view: WebView?,
url: String,
): Boolean =
if (context != null &&
url.isUrlValid() &&
if (url.isUrlValid() &&
binding.webcontent.hitTestResult.type != WebView.HitTestResult.SRC_IMAGE_ANCHOR_TYPE
) {
requireContext().openUrlInBrowser(url)
maybeIfContext { it.openUrlInBrowserAsNewTask(url) }
true
} else {
false
@ -374,23 +376,14 @@ class ArticleFragment :
@Suppress("detekt:LongMethod", "detekt:ImplicitDefaultLocale")
private fun htmlToWebview() {
val context: Context
try {
context = requireContext()
} catch (e: IllegalStateException) {
e.sendSilentlyWithAcraWithName("Context required is null")
return
}
try {
maybeIfContext {
val attrs: IntArray = intArrayOf(android.R.attr.fontFamily)
val a: TypedArray = context.obtainStyledAttributes(resId, attrs)
val a: TypedArray = it.obtainStyledAttributes(resId, attrs)
binding.webcontent.settings.standardFontFamily = a.getString(0)
binding.webcontent.visibility = View.VISIBLE
} catch (e: IllegalStateException) {
e.sendSilentlyWithAcraWithName("Context issue when setting attributes, but context wasn't null before")
""
}
binding.webcontent.visibility = View.VISIBLE
val colorSurfaceString =
String.format(
@ -483,7 +476,7 @@ class ArticleFragment :
| color: ${
String.format(
"#%06X",
WHITE_COLOR_HEX and context.resources.getColor(R.color.colorAccent),
WHITE_COLOR_HEX and (maybeIfContext { it.resources.getColor(R.color.colorAccent) } as Int),
)
} !important;
| }
@ -540,10 +533,8 @@ class ArticleFragment :
private fun openInBrowserAfterFailing() {
binding.progressBar.visibility = View.GONE
try {
requireContext().openItemUrlInBrowserAsNewTask(this@ArticleFragment.item)
} catch (e: IllegalStateException) {
e.sendSilentlyWithAcraWithName("Context required is null")
maybeIfContext {
it.openItemUrlInBrowserAsNewTask(this@ArticleFragment.item)
}
}

View File

@ -1,6 +1,5 @@
package bou.amine.apps.readerforselfossv2.android.fragments
import android.content.Context
import android.graphics.Color
import android.graphics.drawable.Drawable
import android.graphics.drawable.GradientDrawable
@ -17,6 +16,7 @@ import bou.amine.apps.readerforselfossv2.android.R
import bou.amine.apps.readerforselfossv2.android.databinding.FilterFragmentBinding
import bou.amine.apps.readerforselfossv2.android.utils.acra.sendSilentlyWithAcraWithName
import bou.amine.apps.readerforselfossv2.android.utils.glide.imageIntoViewTarget
import bou.amine.apps.readerforselfossv2.android.utils.maybeIfContext
import bou.amine.apps.readerforselfossv2.repository.Repository
import bou.amine.apps.readerforselfossv2.service.AppSettingsService
import bou.amine.apps.readerforselfossv2.utils.getColorHexCode
@ -60,8 +60,8 @@ class FilterSheetFragment :
try {
CoroutineScope(Dispatchers.Main).launch {
handleTagChips(requireContext())
handleSourceChips(requireContext())
handleTagChips()
handleSourceChips()
binding.progressBar2.visibility = GONE
binding.filterView.visibility = VISIBLE
@ -79,29 +79,31 @@ class FilterSheetFragment :
return binding.root
}
private suspend fun handleSourceChips(context: Context) {
private suspend fun handleSourceChips() {
val sourceGroup = binding.sourcesGroup
repository.getSourcesDetailsOrStats().forEachIndexed { _, source ->
val c = Chip(context)
c.ellipsize = TextUtils.TruncateAt.END
context.imageIntoViewTarget(
source.getIcon(repository.baseUrl),
object : ViewTarget<Chip?, Drawable?>(c) {
override fun onResourceReady(
resource: Drawable,
transition: Transition<in Drawable?>?,
) {
try {
c.chipIcon = resource
} catch (e: Exception) {
e.sendSilentlyWithAcraWithName("sources > onResourceReady")
maybeIfContext {
it.imageIntoViewTarget(
source.getIcon(repository.baseUrl),
object : ViewTarget<Chip?, Drawable?>(c) {
override fun onResourceReady(
resource: Drawable,
transition: Transition<in Drawable?>?,
) {
try {
c.chipIcon = resource
} catch (e: Exception) {
e.sendSilentlyWithAcraWithName("sources > onResourceReady")
}
}
}
},
appSettingsService,
)
},
appSettingsService,
)
}
c.text = source.title.getHtmlDecoded()
@ -137,7 +139,7 @@ class FilterSheetFragment :
}
}
private suspend fun handleTagChips(context: Context) {
private suspend fun handleTagChips() {
val tagGroup = binding.tagsGroup
val tags = repository.getTags()

View File

@ -5,6 +5,7 @@ import android.content.Intent
import android.util.TypedValue
import androidx.annotation.AttrRes
import androidx.annotation.ColorInt
import androidx.fragment.app.Fragment
import bou.amine.apps.readerforselfossv2.android.R
import bou.amine.apps.readerforselfossv2.android.utils.acra.sendSilentlyWithAcraWithName
import bou.amine.apps.readerforselfossv2.utils.toStringUriWithHttp
@ -29,15 +30,30 @@ fun Context.shareLink(
}
@ColorInt
fun Context.getColorFromAttr(
fun Fragment.getColorFromAttr(
@AttrRes attrColor: Int,
resolveRefs: Boolean = true,
): Int {
val typedValue = TypedValue()
try {
this.theme.resolveAttribute(attrColor, typedValue, resolveRefs)
} catch (e: Throwable) {
e.sendSilentlyWithAcraWithName("ColorFromAttr")
}
maybeIfContextWithLog { this.requireContext().theme.resolveAttribute(attrColor, typedValue, resolveRefs) }
return typedValue.data
}
@Suppress("detekt:SwallowedException")
fun Fragment.maybeIfContext(fn: (Context) -> Any): Any? {
try {
return fn(this.requireContext())
} catch (e: Exception) {
// Do nothing
return null
}
}
fun Fragment.maybeIfContextWithLog(fn: (Context) -> Any): Any? {
try {
return fn(this.requireContext())
} catch (e: Exception) {
e.sendSilentlyWithAcraWithName("Fragment context issue...")
return null
}
}

View File

@ -23,10 +23,11 @@ import kotlin.io.encoding.ExperimentalEncodingApi
private const val PRELOAD_IMAGE_TIMEOUT = 10000
@Suppress("detekt:ReturnCount")
@OptIn(ExperimentalEncodingApi::class)
fun String.toGlideUrl(appSettingsService: AppSettingsService): GlideUrl {
fun String.toGlideUrl(appSettingsService: AppSettingsService): Any { // GlideUrl Or String
if (this.isEmptyOrNullOrNullString()) {
return GlideUrl("")
return ""
}
if (appSettingsService.getBasicUserName().isNotEmpty()) {
val authString = "${appSettingsService.getBasicUserName()}:${appSettingsService.getBasicPassword()}"