Compare commits
	
		
			9 Commits
		
	
	
		
			v124010031
			...
			v124020451
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | 41910cc4cd | ||
|  | db166ca9d4 | ||
|  | db0d5a4a85 | ||
|  | 3bc0d7cf95 | ||
|  | 8f464d95fd | ||
|  | 5ccd6a3368 | ||
|  | cdbded246e | ||
|  | 750c7758bd | ||
|  | 22f8b14ecd | 
							
								
								
									
										30
									
								
								CHANGELOG.md
									
									
									
									
									
								
							
							
						
						
									
										30
									
								
								CHANGELOG.md
									
									
									
									
									
								
							| @@ -1,3 +1,33 @@ | ||||
| **v124010301** | ||||
|  | ||||
| - fix: This may fix the oom errors. | ||||
| - Changelog for v124010191 [CI SKIP] | ||||
|  | ||||
| -------------------------------------------------------------------- | ||||
|  | ||||
| **v124010191** | ||||
|  | ||||
| - fix: moving listeners. | ||||
| - chore: removed a useless log. | ||||
| - Changelog for v124010032 [CI SKIP] | ||||
|  | ||||
| -------------------------------------------------------------------- | ||||
|  | ||||
| **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** | ||||
|  | ||||
| - chore: Source tracker url in the menu. | ||||
|   | ||||
| @@ -34,6 +34,7 @@ class ItemCardAdapter( | ||||
|     override var items: ArrayList<SelfossModel.Item>, | ||||
|     override val updateItems: (ArrayList<SelfossModel.Item>) -> Unit, | ||||
| ) : ItemsAdapter<ItemCardAdapter.ViewHolder>() { | ||||
|     private lateinit var binding: CardItemBinding | ||||
|     private val c: Context = app.baseContext | ||||
|     private val imageMaxHeight: Int = | ||||
|         c.resources.getDimension(R.dimen.card_image_max_height).toInt() | ||||
| @@ -46,16 +47,57 @@ class ItemCardAdapter( | ||||
|         parent: ViewGroup, | ||||
|         viewType: Int, | ||||
|     ): ViewHolder { | ||||
|         val binding = CardItemBinding.inflate(LayoutInflater.from(parent.context), parent, false) | ||||
|         binding = CardItemBinding.inflate(LayoutInflater.from(parent.context), parent, false) | ||||
|         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( | ||||
|         holder: ViewHolder, | ||||
|         position: Int, | ||||
|     ) { | ||||
|         with(holder) { | ||||
|             val itm = items[position] | ||||
|             val itm = items[holder.bindingAdapterPosition] | ||||
|  | ||||
|             handleClickListeners(holder.bindingAdapterPosition) | ||||
|             handleLinkOpening(holder.bindingAdapterPosition) | ||||
|  | ||||
|             binding.favButton.isSelected = itm.starred | ||||
|             if (appSettingsService.getPublicAccess()) { | ||||
| @@ -96,48 +138,5 @@ class ItemCardAdapter( | ||||
|         return items.size | ||||
|     } | ||||
|  | ||||
|     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, | ||||
|                 ) | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     inner class ViewHolder(val binding: CardItemBinding) : RecyclerView.ViewHolder(binding.root) | ||||
| } | ||||
|   | ||||
| @@ -25,6 +25,7 @@ class ItemListAdapter( | ||||
|     override var items: ArrayList<SelfossModel.Item>, | ||||
|     override val updateItems: (ArrayList<SelfossModel.Item>) -> Unit, | ||||
| ) : ItemsAdapter<ItemListAdapter.ViewHolder>() { | ||||
|     private lateinit var binding: ListItemBinding | ||||
|     private val c: Context = app.baseContext | ||||
|  | ||||
|     override val di: DI by closestDI(app) | ||||
| @@ -35,7 +36,7 @@ class ItemListAdapter( | ||||
|         parent: ViewGroup, | ||||
|         viewType: Int, | ||||
|     ): ViewHolder { | ||||
|         val binding = ListItemBinding.inflate(LayoutInflater.from(parent.context), parent, false) | ||||
|         binding = ListItemBinding.inflate(LayoutInflater.from(parent.context), parent, false) | ||||
|         return ViewHolder(binding) | ||||
|     } | ||||
|  | ||||
| @@ -44,7 +45,17 @@ class ItemListAdapter( | ||||
|         position: Int, | ||||
|     ) { | ||||
|         with(holder) { | ||||
|             val itm = items[position] | ||||
|             val itm = items[holder.bindingAdapterPosition] | ||||
|  | ||||
|             binding.root.setOnClickListener { | ||||
|                 repository.setReaderItems(items) | ||||
|                 c.openItemUrl( | ||||
|                     holder.bindingAdapterPosition, | ||||
|                     items[holder.bindingAdapterPosition].getLinkDecoded(), | ||||
|                     appSettingsService.isArticleViewerEnabled(), | ||||
|                     app, | ||||
|                 ) | ||||
|             } | ||||
|  | ||||
|             binding.title.text = itm.title.getHtmlDecoded() | ||||
|  | ||||
| @@ -68,21 +79,5 @@ class ItemListAdapter( | ||||
|  | ||||
|     override fun getItemCount(): Int = items.size | ||||
|  | ||||
|     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, | ||||
|                 ) | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     inner class ViewHolder(val binding: ListItemBinding) : RecyclerView.ViewHolder(binding.root) | ||||
| } | ||||
|   | ||||
| @@ -89,6 +89,7 @@ abstract class ItemsAdapter<VH : RecyclerView.ViewHolder?> : RecyclerView.Adapte | ||||
|         if (repository.displayedItems == ItemType.UNREAD) { | ||||
|             items.remove(item) | ||||
|             notifyItemRemoved(position) | ||||
|             notifyItemRangeChanged(position, itemCount) | ||||
|             updateItems(items) | ||||
|         } else { | ||||
|             notifyItemChanged(position) | ||||
|   | ||||
| @@ -50,6 +50,33 @@ class SourcesListAdapter( | ||||
|     ) { | ||||
|         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()) { | ||||
|             binding.itemImage.setBackgroundAndText(itm.title.getHtmlDecoded()) | ||||
|         } else { | ||||
| @@ -72,38 +99,5 @@ class SourcesListAdapter( | ||||
|  | ||||
|     override fun getItemCount(): Int = items.size | ||||
|  | ||||
|     inner class ViewHolder(private 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)) | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     inner class ViewHolder(val mView: ConstraintLayout) : RecyclerView.ViewHolder(mView) | ||||
| } | ||||
|   | ||||
| @@ -52,7 +52,6 @@ import org.kodein.di.DIAware | ||||
| import org.kodein.di.android.x.closestDI | ||||
| import org.kodein.di.instance | ||||
| import java.net.MalformedURLException | ||||
| import java.net.SocketTimeoutException | ||||
| import java.net.URL | ||||
| import java.util.* | ||||
| import java.util.concurrent.ExecutionException | ||||
| @@ -264,10 +263,7 @@ class ArticleFragment : Fragment(), DIAware { | ||||
|                 } else { | ||||
|                     openInBrowserAfterFailing() | ||||
|                 } | ||||
|             } catch (e: SocketTimeoutException) { | ||||
|                 openInBrowserAfterFailing() | ||||
|             } catch (e: Exception) { | ||||
|                 e.sendSilentlyWithAcraWithName("getContentFromMercury > $url") | ||||
|                 openInBrowserAfterFailing() | ||||
|             } | ||||
|         } | ||||
|   | ||||
| @@ -13,6 +13,8 @@ class DatesTest { | ||||
|     private val oldVersionDate = "2013-05-07 13:46:00" | ||||
|     private val oldVersionDateVariant = "2021-03-21 10:32:00.000000" | ||||
|  | ||||
|     private val bugVersionDate = "2023-12-19T10:30:53-05:00" | ||||
|  | ||||
|     @Test | ||||
|     fun new_version_date_should_be_parsed() { | ||||
|         val date = DateUtils.parseDate(newVersionDate) | ||||
| @@ -52,4 +54,14 @@ class DatesTest { | ||||
|  | ||||
|         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 | ||||
|  | ||||
| import android.text.format.DateUtils | ||||
| import io.github.aakira.napier.Napier | ||||
| import kotlinx.datetime.* | ||||
|  | ||||
| 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 | ||||
|         actual fun parseDate(dateString: String): Long { | ||||
|             var isoDateString: String = | ||||
|                 try { | ||||
|                     if (dateString.matches(oldVersionFormat)) { | ||||
|                         dateString.replace(" ", "T") | ||||
|                     } else if (dateString.matches(newVersionFormat)) { | ||||
| @@ -23,6 +25,10 @@ actual class DateUtils { | ||||
|                     } else { | ||||
|                         throw Exception("Unrecognized format for $dateString") | ||||
|                     } | ||||
|                 } catch (e: Exception) { | ||||
|                     Napier.e("parseDate failed", e, tag = "DateUtils.parseDate") | ||||
|                     "1991-03-18T03:00:00" | ||||
|                 } | ||||
|  | ||||
|             return LocalDateTime.parse(isoDateString).toInstant(TimeZone.currentSystemDefault()).toEpochMilliseconds() | ||||
|         } | ||||
|   | ||||
| @@ -422,7 +422,7 @@ class Repository( | ||||
|                 val response = api.login() | ||||
|                 result = response.isSuccess == true | ||||
|             } catch (cause: Throwable) { | ||||
|                 Napier.e(cause.stackTraceToString(), tag = "RepositoryImpl.login") | ||||
|                 Napier.e("login failed", cause, tag = "RepositoryImpl.login") | ||||
|             } | ||||
|         } | ||||
|         return result | ||||
| @@ -436,7 +436,7 @@ class Repository( | ||||
|                 // a random rss feed, that would throw a NoTransformationFoundException | ||||
|                 fetchFailed = !api.getItemsWithoutCatch().success | ||||
|             } catch (e: Throwable) { | ||||
|                 Napier.e(e.stackTraceToString(), tag = "RepositoryImpl.shouldBeSelfossInstance") | ||||
|                 Napier.e("checkIfFetchFails failed", e, tag = "RepositoryImpl.shouldBeSelfossInstance") | ||||
|             } | ||||
|         } | ||||
|  | ||||
| @@ -451,7 +451,7 @@ class Repository( | ||||
|                     Napier.e("Couldn't logout.", tag = "RepositoryImpl.logout") | ||||
|                 } | ||||
|             } catch (cause: Throwable) { | ||||
|                 Napier.e(cause.stackTraceToString(), tag = "RepositoryImpl.logout") | ||||
|                 Napier.e("logout failed", cause, tag = "RepositoryImpl.logout") | ||||
|             } | ||||
|             appSettingsService.clearAll() | ||||
|         } else { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user