Compare commits
1 Commits
v125010241
...
eaa6eee531
Author | SHA1 | Date | |
---|---|---|---|
eaa6eee531 |
17
CHANGELOG.md
17
CHANGELOG.md
@ -1,20 +1,3 @@
|
||||
**v125010201
|
||||
|
||||
- fix: Handle empty url issue.
|
||||
- Merge pull request 'Removed the floating bar.' (#177) from floating-bar into master
|
||||
- chore: changing actions in reader fragment.
|
||||
- Changelog for v125010131
|
||||
|
||||
--------------------------------------------------------------------
|
||||
|
||||
**v125010131
|
||||
|
||||
- fix: reload the adapter when it's needed. Fixes #128. (#176)
|
||||
- feat: basic auth and images loading. Fixes #172. (#175)
|
||||
- Changelog for v125010111
|
||||
|
||||
--------------------------------------------------------------------
|
||||
|
||||
**v125010111
|
||||
|
||||
- Debug trying to fix context issues. (#174)
|
||||
|
@ -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.openUrlInBrowserAsNewTask
|
||||
import bou.amine.apps.readerforselfossv2.android.utils.openUrlInBrowser
|
||||
import bou.amine.apps.readerforselfossv2.model.SelfossModel
|
||||
import bou.amine.apps.readerforselfossv2.repository.Repository
|
||||
import bou.amine.apps.readerforselfossv2.service.AppSettingsService
|
||||
@ -317,44 +317,50 @@ class HomeActivity :
|
||||
|
||||
private fun reloadLayoutManager() {
|
||||
val currentManager = binding.recyclerView.layoutManager
|
||||
val layoutManager: RecyclerView.LayoutManager
|
||||
|
||||
fun gridLayoutManager() {
|
||||
val layoutManager =
|
||||
GridLayoutManager(
|
||||
this,
|
||||
calculateNoOfColumns(),
|
||||
)
|
||||
binding.recyclerView.layoutManager = layoutManager
|
||||
}
|
||||
|
||||
fun staggererdGridLayoutManager() {
|
||||
var layoutManager =
|
||||
StaggeredGridLayoutManager(
|
||||
calculateNoOfColumns(),
|
||||
StaggeredGridLayoutManager.VERTICAL,
|
||||
)
|
||||
layoutManager.gapStrategy =
|
||||
StaggeredGridLayoutManager.GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS
|
||||
binding.recyclerView.layoutManager = layoutManager
|
||||
}
|
||||
|
||||
// This will only update the layout manager if settings changed
|
||||
when (currentManager) {
|
||||
is StaggeredGridLayoutManager ->
|
||||
if (!appSettingsService.isCardViewEnabled()) {
|
||||
gridLayoutManager()
|
||||
layoutManager =
|
||||
GridLayoutManager(
|
||||
this,
|
||||
calculateNoOfColumns(),
|
||||
)
|
||||
binding.recyclerView.layoutManager = layoutManager
|
||||
}
|
||||
|
||||
is GridLayoutManager ->
|
||||
if (appSettingsService.isCardViewEnabled()) {
|
||||
staggererdGridLayoutManager()
|
||||
layoutManager =
|
||||
StaggeredGridLayoutManager(
|
||||
calculateNoOfColumns(),
|
||||
StaggeredGridLayoutManager.VERTICAL,
|
||||
)
|
||||
layoutManager.gapStrategy =
|
||||
StaggeredGridLayoutManager.GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS
|
||||
binding.recyclerView.layoutManager = layoutManager
|
||||
}
|
||||
|
||||
else ->
|
||||
if (currentManager == null) {
|
||||
if (!appSettingsService.isCardViewEnabled()) {
|
||||
gridLayoutManager()
|
||||
layoutManager =
|
||||
GridLayoutManager(
|
||||
this,
|
||||
calculateNoOfColumns(),
|
||||
)
|
||||
binding.recyclerView.layoutManager = layoutManager
|
||||
} else {
|
||||
staggererdGridLayoutManager()
|
||||
layoutManager =
|
||||
StaggeredGridLayoutManager(
|
||||
calculateNoOfColumns(),
|
||||
StaggeredGridLayoutManager.VERTICAL,
|
||||
)
|
||||
layoutManager.gapStrategy =
|
||||
StaggeredGridLayoutManager.GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS
|
||||
binding.recyclerView.layoutManager = layoutManager
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -479,8 +485,8 @@ class HomeActivity :
|
||||
}
|
||||
|
||||
private fun handleListResult(appendResults: Boolean = false) {
|
||||
val oldManager = binding.recyclerView.layoutManager
|
||||
if (appendResults) {
|
||||
val oldManager = binding.recyclerView.layoutManager
|
||||
firstVisible =
|
||||
when (oldManager) {
|
||||
is StaggeredGridLayoutManager ->
|
||||
@ -493,13 +499,7 @@ class HomeActivity :
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("detekt:ComplexCondition")
|
||||
if (recyclerAdapter == null ||
|
||||
(
|
||||
(recyclerAdapter is ItemListAdapter && appSettingsService.isCardViewEnabled()) ||
|
||||
(recyclerAdapter is ItemCardAdapter && !appSettingsService.isCardViewEnabled())
|
||||
)
|
||||
) {
|
||||
if (recyclerAdapter == null) {
|
||||
if (appSettingsService.isCardViewEnabled()) {
|
||||
recyclerAdapter =
|
||||
ItemCardAdapter(
|
||||
@ -599,7 +599,7 @@ class HomeActivity :
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
when (item.itemId) {
|
||||
R.id.issue_tracker -> {
|
||||
baseContext.openUrlInBrowserAsNewTask(AppSettingsService.BUG_URL)
|
||||
baseContext.openUrlInBrowser(AppSettingsService.BUG_URL)
|
||||
return true
|
||||
}
|
||||
|
||||
|
@ -33,9 +33,8 @@ 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.openUrlInBrowserAsNewTask
|
||||
import bou.amine.apps.readerforselfossv2.android.utils.openUrlInBrowser
|
||||
import bou.amine.apps.readerforselfossv2.android.utils.shareLink
|
||||
import bou.amine.apps.readerforselfossv2.model.MercuryModel
|
||||
import bou.amine.apps.readerforselfossv2.model.SelfossModel
|
||||
@ -118,8 +117,8 @@ class ArticleFragment :
|
||||
e.sendSilentlyWithAcra()
|
||||
}
|
||||
|
||||
colorOnSurface = getColorFromAttr(R.attr.colorOnSurface)
|
||||
colorSurface = getColorFromAttr(R.attr.colorSurface)
|
||||
colorOnSurface = requireContext().getColorFromAttr(R.attr.colorOnSurface)
|
||||
colorSurface = requireContext().getColorFromAttr(R.attr.colorSurface)
|
||||
|
||||
contentText = item.content
|
||||
contentTitle = item.title.getHtmlDecoded()
|
||||
@ -148,11 +147,11 @@ class ArticleFragment :
|
||||
handleContent()
|
||||
} catch (e: InflateException) {
|
||||
e.sendSilentlyWithAcraWithName("webview not available")
|
||||
maybeIfContext {
|
||||
try {
|
||||
AlertDialog
|
||||
.Builder(it)
|
||||
.setMessage(it.getString(R.string.webview_dialog_issue_message))
|
||||
.setTitle(it.getString(R.string.webview_dialog_issue_title))
|
||||
.Builder(requireContext())
|
||||
.setMessage(requireContext().getString(R.string.webview_dialog_issue_message))
|
||||
.setTitle(requireContext().getString(R.string.webview_dialog_issue_title))
|
||||
.setPositiveButton(
|
||||
android.R.string.ok,
|
||||
) { _, _ ->
|
||||
@ -160,6 +159,8 @@ class ArticleFragment :
|
||||
requireActivity().finish()
|
||||
}.create()
|
||||
.show()
|
||||
} catch (e: IllegalStateException) {
|
||||
e.sendSilentlyWithAcraWithName("Context required is null")
|
||||
}
|
||||
}
|
||||
|
||||
@ -181,7 +182,7 @@ class ArticleFragment :
|
||||
|
||||
if (!contentImage.isEmptyOrNullOrNullString() && context != null) {
|
||||
binding.imageView.visibility = View.VISIBLE
|
||||
maybeIfContext { it.bitmapFitCenter(contentImage, binding.imageView, appSettingsService) }
|
||||
requireContext().bitmapFitCenter(contentImage, binding.imageView, appSettingsService)
|
||||
} else {
|
||||
binding.imageView.visibility = View.GONE
|
||||
}
|
||||
@ -193,7 +194,7 @@ class ArticleFragment :
|
||||
fab.mainFabClosedIconColor = colorOnSurface
|
||||
fab.mainFabOpenedIconColor = colorOnSurface
|
||||
|
||||
maybeIfContext { context -> handleFloatingToolbarActionItems(context) }
|
||||
handleFloatingToolbarActionItems()
|
||||
|
||||
fab.setOnActionSelectedListener { actionItem ->
|
||||
when (actionItem.id) {
|
||||
@ -206,14 +207,12 @@ class ArticleFragment :
|
||||
repository.markAsRead(this@ArticleFragment.item)
|
||||
}
|
||||
this@ArticleFragment.item.unread = false
|
||||
maybeIfContext {
|
||||
Toast
|
||||
.makeText(
|
||||
it,
|
||||
R.string.marked_as_read,
|
||||
Toast.LENGTH_LONG,
|
||||
).show()
|
||||
}
|
||||
Toast
|
||||
.makeText(
|
||||
requireContext(),
|
||||
R.string.marked_as_read,
|
||||
Toast.LENGTH_LONG,
|
||||
).show()
|
||||
} else {
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
repository.unmarkAsRead(this@ArticleFragment.item)
|
||||
@ -227,7 +226,7 @@ class ArticleFragment :
|
||||
).show()
|
||||
}
|
||||
} catch (e: IllegalStateException) {
|
||||
e.sendSilentlyWithAcraWithName("Toolbar context required is null")
|
||||
e.sendSilentlyWithAcraWithName("Context required is null")
|
||||
}
|
||||
|
||||
else -> Unit
|
||||
@ -236,14 +235,14 @@ class ArticleFragment :
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleFloatingToolbarActionItems(c: Context) {
|
||||
private fun handleFloatingToolbarActionItems() {
|
||||
fab.addHomeMadeActionItem(
|
||||
R.id.share_action,
|
||||
resources.getDrawable(R.drawable.ic_share_white_24dp),
|
||||
R.string.reader_action_share,
|
||||
colorOnSurface,
|
||||
colorSurface,
|
||||
c,
|
||||
requireContext(),
|
||||
)
|
||||
fab.addHomeMadeActionItem(
|
||||
R.id.open_action,
|
||||
@ -251,7 +250,7 @@ class ArticleFragment :
|
||||
R.string.reader_action_open,
|
||||
colorOnSurface,
|
||||
colorSurface,
|
||||
c,
|
||||
requireContext(),
|
||||
)
|
||||
fab.addHomeMadeActionItem(
|
||||
R.id.unread_action,
|
||||
@ -259,7 +258,7 @@ class ArticleFragment :
|
||||
R.string.unmark,
|
||||
colorOnSurface,
|
||||
colorSurface,
|
||||
c,
|
||||
requireContext(),
|
||||
)
|
||||
}
|
||||
|
||||
@ -312,11 +311,9 @@ class ArticleFragment :
|
||||
}
|
||||
|
||||
private fun handleLeadImage(leadImageUrl: String?) {
|
||||
if (!leadImageUrl.isNullOrEmpty()) {
|
||||
if (!leadImageUrl.isNullOrEmpty() && context != null) {
|
||||
binding.imageView.visibility = View.VISIBLE
|
||||
maybeIfContext {
|
||||
it.bitmapFitCenter(leadImageUrl, binding.imageView, appSettingsService)
|
||||
}
|
||||
requireContext().bitmapFitCenter(leadImageUrl, binding.imageView, appSettingsService)
|
||||
} else {
|
||||
binding.imageView.visibility = View.GONE
|
||||
}
|
||||
@ -330,10 +327,11 @@ class ArticleFragment :
|
||||
view: WebView?,
|
||||
url: String,
|
||||
): Boolean =
|
||||
if (url.isUrlValid() &&
|
||||
if (context != null &&
|
||||
url.isUrlValid() &&
|
||||
binding.webcontent.hitTestResult.type != WebView.HitTestResult.SRC_IMAGE_ANCHOR_TYPE
|
||||
) {
|
||||
maybeIfContext { it.openUrlInBrowserAsNewTask(url) }
|
||||
requireContext().openUrlInBrowser(url)
|
||||
true
|
||||
} else {
|
||||
false
|
||||
@ -376,14 +374,23 @@ class ArticleFragment :
|
||||
|
||||
@Suppress("detekt:LongMethod", "detekt:ImplicitDefaultLocale")
|
||||
private fun htmlToWebview() {
|
||||
maybeIfContext {
|
||||
val context: Context
|
||||
try {
|
||||
context = requireContext()
|
||||
} catch (e: IllegalStateException) {
|
||||
e.sendSilentlyWithAcraWithName("Context required is null")
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
val attrs: IntArray = intArrayOf(android.R.attr.fontFamily)
|
||||
val a: TypedArray = it.obtainStyledAttributes(resId, attrs)
|
||||
val a: TypedArray = context.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(
|
||||
@ -476,7 +483,7 @@ class ArticleFragment :
|
||||
| color: ${
|
||||
String.format(
|
||||
"#%06X",
|
||||
WHITE_COLOR_HEX and (maybeIfContext { it.resources.getColor(R.color.colorAccent) } as Int),
|
||||
WHITE_COLOR_HEX and context.resources.getColor(R.color.colorAccent),
|
||||
)
|
||||
} !important;
|
||||
| }
|
||||
@ -533,8 +540,10 @@ class ArticleFragment :
|
||||
|
||||
private fun openInBrowserAfterFailing() {
|
||||
binding.progressBar.visibility = View.GONE
|
||||
maybeIfContext {
|
||||
it.openItemUrlInBrowserAsNewTask(this@ArticleFragment.item)
|
||||
try {
|
||||
requireContext().openItemUrlInBrowserAsNewTask(this@ArticleFragment.item)
|
||||
} catch (e: IllegalStateException) {
|
||||
e.sendSilentlyWithAcraWithName("Context required is null")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
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
|
||||
@ -16,7 +17,6 @@ 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()
|
||||
handleSourceChips()
|
||||
handleTagChips(requireContext())
|
||||
handleSourceChips(requireContext())
|
||||
|
||||
binding.progressBar2.visibility = GONE
|
||||
binding.filterView.visibility = VISIBLE
|
||||
@ -79,31 +79,29 @@ class FilterSheetFragment :
|
||||
return binding.root
|
||||
}
|
||||
|
||||
private suspend fun handleSourceChips() {
|
||||
private suspend fun handleSourceChips(context: Context) {
|
||||
val sourceGroup = binding.sourcesGroup
|
||||
|
||||
repository.getSourcesDetailsOrStats().forEachIndexed { _, source ->
|
||||
val c = Chip(context)
|
||||
c.ellipsize = TextUtils.TruncateAt.END
|
||||
|
||||
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")
|
||||
}
|
||||
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")
|
||||
}
|
||||
},
|
||||
appSettingsService,
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
appSettingsService,
|
||||
)
|
||||
|
||||
c.text = source.title.getHtmlDecoded()
|
||||
|
||||
@ -139,7 +137,7 @@ class FilterSheetFragment :
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun handleTagChips() {
|
||||
private suspend fun handleTagChips(context: Context) {
|
||||
val tagGroup = binding.tagsGroup
|
||||
|
||||
val tags = repository.getTags()
|
||||
|
@ -5,7 +5,6 @@ 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
|
||||
@ -30,30 +29,15 @@ fun Context.shareLink(
|
||||
}
|
||||
|
||||
@ColorInt
|
||||
fun Fragment.getColorFromAttr(
|
||||
fun Context.getColorFromAttr(
|
||||
@AttrRes attrColor: Int,
|
||||
resolveRefs: Boolean = true,
|
||||
): Int {
|
||||
val typedValue = TypedValue()
|
||||
maybeIfContextWithLog { this.requireContext().theme.resolveAttribute(attrColor, typedValue, resolveRefs) }
|
||||
try {
|
||||
this.theme.resolveAttribute(attrColor, typedValue, resolveRefs)
|
||||
} catch (e: Throwable) {
|
||||
e.sendSilentlyWithAcraWithName("ColorFromAttr")
|
||||
}
|
||||
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
|
||||
}
|
||||
}
|
||||
|
@ -7,7 +7,6 @@ import android.webkit.WebView
|
||||
import android.widget.ImageView
|
||||
import bou.amine.apps.readerforselfossv2.android.utils.CircleImageView
|
||||
import bou.amine.apps.readerforselfossv2.service.AppSettingsService
|
||||
import bou.amine.apps.readerforselfossv2.utils.isEmptyOrNullOrNullString
|
||||
import com.bumptech.glide.Glide
|
||||
import com.bumptech.glide.load.engine.DiskCacheStrategy
|
||||
import com.bumptech.glide.load.model.GlideUrl
|
||||
@ -23,12 +22,8 @@ import kotlin.io.encoding.ExperimentalEncodingApi
|
||||
|
||||
private const val PRELOAD_IMAGE_TIMEOUT = 10000
|
||||
|
||||
@Suppress("detekt:ReturnCount")
|
||||
@OptIn(ExperimentalEncodingApi::class)
|
||||
fun String.toGlideUrl(appSettingsService: AppSettingsService): Any { // GlideUrl Or String
|
||||
if (this.isEmptyOrNullOrNullString()) {
|
||||
return ""
|
||||
}
|
||||
fun String.toGlideUrl(appSettingsService: AppSettingsService): GlideUrl {
|
||||
if (appSettingsService.getBasicUserName().isNotEmpty()) {
|
||||
val authString = "${appSettingsService.getBasicUserName()}:${appSettingsService.getBasicPassword()}"
|
||||
val authBuf = Base64.encode(authString.toByteArray(Charsets.UTF_8))
|
||||
|
@ -1,5 +0,0 @@
|
||||
**v125010131**
|
||||
|
||||
- fix: reload the adapter when it's needed. Fixes #128. (#176)
|
||||
- feat: basic auth and images loading. Fixes #172. (#175)
|
||||
- Changelog for v125010111
|
@ -1,6 +0,0 @@
|
||||
**v125010201**
|
||||
|
||||
- fix: Handle empty url issue.
|
||||
- Merge pull request 'Removed the floating bar.' (#177) from floating-bar into master
|
||||
- chore: changing actions in reader fragment.
|
||||
- Changelog for v125010131
|
Reference in New Issue
Block a user