Compare commits
5 Commits
v124010031
...
8f464d95fd
Author | SHA1 | Date | |
---|---|---|---|
8f464d95fd | |||
5ccd6a3368 | |||
cdbded246e | |||
750c7758bd | |||
22f8b14ecd |
15
CHANGELOG.md
15
CHANGELOG.md
@ -1,3 +1,18 @@
|
|||||||
|
**v124010032**
|
||||||
|
|
||||||
|
- fix: Another date format thing.
|
||||||
|
- Changelog for v124010031 [CI SKIP]
|
||||||
|
|
||||||
|
--------------------------------------------------------------------
|
||||||
|
|
||||||
|
**v124010031**
|
||||||
|
|
||||||
|
- fix: Checking if selfoss instance.
|
||||||
|
- fix: handle three characters lenght hexcode colors.
|
||||||
|
- Changelog for v123113311 [CI SKIP]
|
||||||
|
|
||||||
|
--------------------------------------------------------------------
|
||||||
|
|
||||||
**v123113311**
|
**v123113311**
|
||||||
|
|
||||||
- chore: Source tracker url in the menu.
|
- chore: Source tracker url in the menu.
|
||||||
|
@ -34,6 +34,7 @@ class ItemCardAdapter(
|
|||||||
override var items: ArrayList<SelfossModel.Item>,
|
override var items: ArrayList<SelfossModel.Item>,
|
||||||
override val updateItems: (ArrayList<SelfossModel.Item>) -> Unit,
|
override val updateItems: (ArrayList<SelfossModel.Item>) -> Unit,
|
||||||
) : ItemsAdapter<ItemCardAdapter.ViewHolder>() {
|
) : ItemsAdapter<ItemCardAdapter.ViewHolder>() {
|
||||||
|
private lateinit var binding: CardItemBinding
|
||||||
private val c: Context = app.baseContext
|
private val c: Context = app.baseContext
|
||||||
private val imageMaxHeight: Int =
|
private val imageMaxHeight: Int =
|
||||||
c.resources.getDimension(R.dimen.card_image_max_height).toInt()
|
c.resources.getDimension(R.dimen.card_image_max_height).toInt()
|
||||||
@ -46,10 +47,48 @@ class ItemCardAdapter(
|
|||||||
parent: ViewGroup,
|
parent: ViewGroup,
|
||||||
viewType: Int,
|
viewType: Int,
|
||||||
): ViewHolder {
|
): ViewHolder {
|
||||||
val binding = CardItemBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
binding = CardItemBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
||||||
return ViewHolder(binding)
|
return ViewHolder(binding)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun handleClickListeners(position: Int) {
|
||||||
|
binding.favButton.setOnClickListener {
|
||||||
|
val item = items[position]
|
||||||
|
if (item.starred) {
|
||||||
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
|
repository.unstarr(item)
|
||||||
|
}
|
||||||
|
binding.favButton.isSelected = false
|
||||||
|
} else {
|
||||||
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
|
repository.starr(item)
|
||||||
|
}
|
||||||
|
binding.favButton.isSelected = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.shareBtn.setOnClickListener {
|
||||||
|
val item = items[position]
|
||||||
|
c.shareLink(item.getLinkDecoded(), item.title.getHtmlDecoded())
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.browserBtn.setOnClickListener {
|
||||||
|
c.openInBrowserAsNewTask(items[position])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleLinkOpening(position: Int) {
|
||||||
|
binding.root.setOnClickListener {
|
||||||
|
repository.setReaderItems(items)
|
||||||
|
c.openItemUrl(
|
||||||
|
position,
|
||||||
|
items[position].getLinkDecoded(),
|
||||||
|
appSettingsService.isArticleViewerEnabled(),
|
||||||
|
app,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun onBindViewHolder(
|
override fun onBindViewHolder(
|
||||||
holder: ViewHolder,
|
holder: ViewHolder,
|
||||||
position: Int,
|
position: Int,
|
||||||
@ -57,6 +96,9 @@ class ItemCardAdapter(
|
|||||||
with(holder) {
|
with(holder) {
|
||||||
val itm = items[position]
|
val itm = items[position]
|
||||||
|
|
||||||
|
handleClickListeners(position)
|
||||||
|
handleLinkOpening(position)
|
||||||
|
|
||||||
binding.favButton.isSelected = itm.starred
|
binding.favButton.isSelected = itm.starred
|
||||||
if (appSettingsService.getPublicAccess()) {
|
if (appSettingsService.getPublicAccess()) {
|
||||||
binding.favButton.visibility = View.GONE
|
binding.favButton.visibility = View.GONE
|
||||||
@ -96,48 +138,5 @@ class ItemCardAdapter(
|
|||||||
return items.size
|
return items.size
|
||||||
}
|
}
|
||||||
|
|
||||||
inner class ViewHolder(val binding: CardItemBinding) : RecyclerView.ViewHolder(binding.root) {
|
inner class ViewHolder(val binding: CardItemBinding) : RecyclerView.ViewHolder(binding.root)
|
||||||
init {
|
|
||||||
handleClickListeners()
|
|
||||||
handleLinkOpening()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun handleClickListeners() {
|
|
||||||
binding.favButton.setOnClickListener {
|
|
||||||
val item = items[bindingAdapterPosition]
|
|
||||||
if (item.starred) {
|
|
||||||
CoroutineScope(Dispatchers.IO).launch {
|
|
||||||
repository.unstarr(item)
|
|
||||||
}
|
|
||||||
binding.favButton.isSelected = false
|
|
||||||
} else {
|
|
||||||
CoroutineScope(Dispatchers.IO).launch {
|
|
||||||
repository.starr(item)
|
|
||||||
}
|
|
||||||
binding.favButton.isSelected = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
binding.shareBtn.setOnClickListener {
|
|
||||||
val item = items[bindingAdapterPosition]
|
|
||||||
c.shareLink(item.getLinkDecoded(), item.title.getHtmlDecoded())
|
|
||||||
}
|
|
||||||
|
|
||||||
binding.browserBtn.setOnClickListener {
|
|
||||||
c.openInBrowserAsNewTask(items[bindingAdapterPosition])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun handleLinkOpening() {
|
|
||||||
binding.root.setOnClickListener {
|
|
||||||
repository.setReaderItems(items)
|
|
||||||
c.openItemUrl(
|
|
||||||
bindingAdapterPosition,
|
|
||||||
items[bindingAdapterPosition].getLinkDecoded(),
|
|
||||||
appSettingsService.isArticleViewerEnabled(),
|
|
||||||
app,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,7 @@ class ItemListAdapter(
|
|||||||
override var items: ArrayList<SelfossModel.Item>,
|
override var items: ArrayList<SelfossModel.Item>,
|
||||||
override val updateItems: (ArrayList<SelfossModel.Item>) -> Unit,
|
override val updateItems: (ArrayList<SelfossModel.Item>) -> Unit,
|
||||||
) : ItemsAdapter<ItemListAdapter.ViewHolder>() {
|
) : ItemsAdapter<ItemListAdapter.ViewHolder>() {
|
||||||
|
private lateinit var binding: ListItemBinding
|
||||||
private val c: Context = app.baseContext
|
private val c: Context = app.baseContext
|
||||||
|
|
||||||
override val di: DI by closestDI(app)
|
override val di: DI by closestDI(app)
|
||||||
@ -35,7 +36,7 @@ class ItemListAdapter(
|
|||||||
parent: ViewGroup,
|
parent: ViewGroup,
|
||||||
viewType: Int,
|
viewType: Int,
|
||||||
): ViewHolder {
|
): ViewHolder {
|
||||||
val binding = ListItemBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
binding = ListItemBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
||||||
return ViewHolder(binding)
|
return ViewHolder(binding)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -46,6 +47,16 @@ class ItemListAdapter(
|
|||||||
with(holder) {
|
with(holder) {
|
||||||
val itm = items[position]
|
val itm = items[position]
|
||||||
|
|
||||||
|
binding.root.setOnClickListener {
|
||||||
|
repository.setReaderItems(items)
|
||||||
|
c.openItemUrl(
|
||||||
|
bindingAdapterPosition,
|
||||||
|
items[bindingAdapterPosition].getLinkDecoded(),
|
||||||
|
appSettingsService.isArticleViewerEnabled(),
|
||||||
|
app,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
binding.title.text = itm.title.getHtmlDecoded()
|
binding.title.text = itm.title.getHtmlDecoded()
|
||||||
|
|
||||||
binding.title.setOnTouchListener(LinkOnTouchListener())
|
binding.title.setOnTouchListener(LinkOnTouchListener())
|
||||||
@ -68,21 +79,5 @@ class ItemListAdapter(
|
|||||||
|
|
||||||
override fun getItemCount(): Int = items.size
|
override fun getItemCount(): Int = items.size
|
||||||
|
|
||||||
inner class ViewHolder(val binding: ListItemBinding) : RecyclerView.ViewHolder(binding.root) {
|
inner class ViewHolder(val binding: ListItemBinding) : RecyclerView.ViewHolder(binding.root)
|
||||||
init {
|
|
||||||
handleLinkOpening()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun handleLinkOpening() {
|
|
||||||
binding.root.setOnClickListener {
|
|
||||||
repository.setReaderItems(items)
|
|
||||||
c.openItemUrl(
|
|
||||||
bindingAdapterPosition,
|
|
||||||
items[bindingAdapterPosition].getLinkDecoded(),
|
|
||||||
appSettingsService.isArticleViewerEnabled(),
|
|
||||||
app,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -50,6 +50,33 @@ class SourcesListAdapter(
|
|||||||
) {
|
) {
|
||||||
val itm = items[position]
|
val itm = items[position]
|
||||||
|
|
||||||
|
val deleteBtn: Button = holder.mView.findViewById(R.id.deleteBtn)
|
||||||
|
|
||||||
|
deleteBtn.setOnClickListener {
|
||||||
|
val (id, title) = items[position]
|
||||||
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
|
val successfullyDeletedSource = repository.deleteSource(id, title)
|
||||||
|
if (successfullyDeletedSource) {
|
||||||
|
items.removeAt(position)
|
||||||
|
notifyItemRemoved(position)
|
||||||
|
notifyItemRangeChanged(position, itemCount)
|
||||||
|
} else {
|
||||||
|
Toast.makeText(
|
||||||
|
app,
|
||||||
|
R.string.can_delete_source,
|
||||||
|
Toast.LENGTH_SHORT,
|
||||||
|
).show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
holder.mView.setOnClickListener {
|
||||||
|
val source = items[position]
|
||||||
|
|
||||||
|
repository.setSelectedSource(source)
|
||||||
|
app.startActivity(Intent(app, UpsertSourceActivity::class.java))
|
||||||
|
}
|
||||||
|
|
||||||
if (itm.getIcon(repository.baseUrl).isEmpty()) {
|
if (itm.getIcon(repository.baseUrl).isEmpty()) {
|
||||||
binding.itemImage.setBackgroundAndText(itm.title.getHtmlDecoded())
|
binding.itemImage.setBackgroundAndText(itm.title.getHtmlDecoded())
|
||||||
} else {
|
} else {
|
||||||
@ -72,38 +99,5 @@ class SourcesListAdapter(
|
|||||||
|
|
||||||
override fun getItemCount(): Int = items.size
|
override fun getItemCount(): Int = items.size
|
||||||
|
|
||||||
inner class ViewHolder(private val mView: ConstraintLayout) : RecyclerView.ViewHolder(mView) {
|
inner class ViewHolder(val mView: ConstraintLayout) : RecyclerView.ViewHolder(mView)
|
||||||
init {
|
|
||||||
handleClickListeners()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun handleClickListeners() {
|
|
||||||
val deleteBtn: Button = mView.findViewById(R.id.deleteBtn)
|
|
||||||
|
|
||||||
deleteBtn.setOnClickListener {
|
|
||||||
val (id, title) = items[bindingAdapterPosition]
|
|
||||||
CoroutineScope(Dispatchers.IO).launch {
|
|
||||||
val successfullyDeletedSource = repository.deleteSource(id, title)
|
|
||||||
if (successfullyDeletedSource) {
|
|
||||||
items.removeAt(bindingAdapterPosition)
|
|
||||||
notifyItemRemoved(bindingAdapterPosition)
|
|
||||||
notifyItemRangeChanged(bindingAdapterPosition, itemCount)
|
|
||||||
} else {
|
|
||||||
Toast.makeText(
|
|
||||||
app,
|
|
||||||
R.string.can_delete_source,
|
|
||||||
Toast.LENGTH_SHORT,
|
|
||||||
).show()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mView.setOnClickListener {
|
|
||||||
val source = items[bindingAdapterPosition]
|
|
||||||
|
|
||||||
repository.setSelectedSource(source)
|
|
||||||
app.startActivity(Intent(app, UpsertSourceActivity::class.java))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -52,7 +52,6 @@ import org.kodein.di.DIAware
|
|||||||
import org.kodein.di.android.x.closestDI
|
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.SocketTimeoutException
|
|
||||||
import java.net.URL
|
import java.net.URL
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import java.util.concurrent.ExecutionException
|
import java.util.concurrent.ExecutionException
|
||||||
@ -264,10 +263,7 @@ class ArticleFragment : Fragment(), DIAware {
|
|||||||
} else {
|
} else {
|
||||||
openInBrowserAfterFailing()
|
openInBrowserAfterFailing()
|
||||||
}
|
}
|
||||||
} catch (e: SocketTimeoutException) {
|
|
||||||
openInBrowserAfterFailing()
|
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
e.sendSilentlyWithAcraWithName("getContentFromMercury > $url")
|
|
||||||
openInBrowserAfterFailing()
|
openInBrowserAfterFailing()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,8 @@ class DatesTest {
|
|||||||
private val oldVersionDate = "2013-05-07 13:46:00"
|
private val oldVersionDate = "2013-05-07 13:46:00"
|
||||||
private val oldVersionDateVariant = "2021-03-21 10:32:00.000000"
|
private val oldVersionDateVariant = "2021-03-21 10:32:00.000000"
|
||||||
|
|
||||||
|
private val bugVersionDate = "2023-12-19T10:30:53-05:00"
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun new_version_date_should_be_parsed() {
|
fun new_version_date_should_be_parsed() {
|
||||||
val date = DateUtils.parseDate(newVersionDate)
|
val date = DateUtils.parseDate(newVersionDate)
|
||||||
@ -52,4 +54,14 @@ class DatesTest {
|
|||||||
|
|
||||||
assertEquals(expected, date)
|
assertEquals(expected, date)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun bug_version_variant_date_should_be_parsed() {
|
||||||
|
val date = DateUtils.parseDate(bugVersionDate)
|
||||||
|
val expected =
|
||||||
|
LocalDateTime(1991, 3, 18, 3, 0, 0, 0).toInstant(TimeZone.currentSystemDefault())
|
||||||
|
.toEpochMilliseconds()
|
||||||
|
|
||||||
|
assertEquals(expected, date)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package bou.amine.apps.readerforselfossv2.utils
|
package bou.amine.apps.readerforselfossv2.utils
|
||||||
|
|
||||||
import android.text.format.DateUtils
|
import android.text.format.DateUtils
|
||||||
|
import io.github.aakira.napier.Napier
|
||||||
import kotlinx.datetime.*
|
import kotlinx.datetime.*
|
||||||
|
|
||||||
actual class DateUtils {
|
actual class DateUtils {
|
||||||
@ -16,6 +17,7 @@ actual class DateUtils {
|
|||||||
// For now, we handle this in a hacky way, because kotlin only accepts iso formats
|
// For now, we handle this in a hacky way, because kotlin only accepts iso formats
|
||||||
actual fun parseDate(dateString: String): Long {
|
actual fun parseDate(dateString: String): Long {
|
||||||
var isoDateString: String =
|
var isoDateString: String =
|
||||||
|
try {
|
||||||
if (dateString.matches(oldVersionFormat)) {
|
if (dateString.matches(oldVersionFormat)) {
|
||||||
dateString.replace(" ", "T")
|
dateString.replace(" ", "T")
|
||||||
} else if (dateString.matches(newVersionFormat)) {
|
} else if (dateString.matches(newVersionFormat)) {
|
||||||
@ -23,6 +25,10 @@ actual class DateUtils {
|
|||||||
} else {
|
} else {
|
||||||
throw Exception("Unrecognized format for $dateString")
|
throw Exception("Unrecognized format for $dateString")
|
||||||
}
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Napier.e(e.stackTraceToString(), tag = "DateUtils.parseDate")
|
||||||
|
"1991-03-18T03:00:00"
|
||||||
|
}
|
||||||
|
|
||||||
return LocalDateTime.parse(isoDateString).toInstant(TimeZone.currentSystemDefault()).toEpochMilliseconds()
|
return LocalDateTime.parse(isoDateString).toInstant(TimeZone.currentSystemDefault()).toEpochMilliseconds()
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user