Compare commits
	
		
			10 Commits
		
	
	
		
			v124010191
			...
			61e0087894
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | 61e0087894 | ||
|  | 1ec05d9913 | ||
|  | 859bd91bbb | ||
|  | 204b736c53 | ||
|  | f24609c143 | ||
|  | b94d7dc537 | ||
|  | 41910cc4cd | ||
|  | db166ca9d4 | ||
|  | db0d5a4a85 | ||
|  | 3bc0d7cf95 | 
							
								
								
									
										37
									
								
								CHANGELOG.md
									
									
									
									
									
								
							
							
						
						
									
										37
									
								
								CHANGELOG.md
									
									
									
									
									
								
							| @@ -1,3 +1,40 @@ | ||||
| **v124041081** | ||||
|  | ||||
| - chore: comment. | ||||
| - fix: Last time fixing the parsing date hack before moving it to os version. | ||||
| - Changelog for v124030731 [CI SKIP] | ||||
|  | ||||
| -------------------------------------------------------------------- | ||||
|  | ||||
| **v124030731** | ||||
|  | ||||
| - fix: Basic auth and password can have non whitspace characters. Fixes 142. | ||||
| - Changelog for v124020451 [CI SKIP] | ||||
|  | ||||
| -------------------------------------------------------------------- | ||||
|  | ||||
| **v124020451** | ||||
|  | ||||
| - fix: Fixed handling of position in card adapter. | ||||
| - Changelog for v124010301 [CI SKIP] | ||||
|  | ||||
| -------------------------------------------------------------------- | ||||
|  | ||||
| **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. | ||||
|   | ||||
| @@ -9,6 +9,7 @@ import android.widget.ImageView.ScaleType | ||||
| import androidx.recyclerview.widget.RecyclerView | ||||
| import bou.amine.apps.readerforselfossv2.android.R | ||||
| import bou.amine.apps.readerforselfossv2.android.databinding.CardItemBinding | ||||
| import bou.amine.apps.readerforselfossv2.android.sendSilentlyWithAcraWithName | ||||
| 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.circularDrawable | ||||
| @@ -94,10 +95,10 @@ class ItemCardAdapter( | ||||
|         position: Int, | ||||
|     ) { | ||||
|         with(holder) { | ||||
|             val itm = items[position] | ||||
|             val itm = items[holder.bindingAdapterPosition] | ||||
|  | ||||
|             handleClickListeners(position) | ||||
|             handleLinkOpening(position) | ||||
|             handleClickListeners(holder.bindingAdapterPosition) | ||||
|             handleLinkOpening(holder.bindingAdapterPosition) | ||||
|  | ||||
|             binding.favButton.isSelected = itm.starred | ||||
|             if (appSettingsService.getPublicAccess()) { | ||||
| @@ -110,7 +111,12 @@ class ItemCardAdapter( | ||||
|  | ||||
|             binding.title.setLinkTextColor(c.resources.getColor(R.color.colorAccent)) | ||||
|  | ||||
|             binding.sourceTitleAndDate.text = itm.sourceAuthorAndDate() | ||||
|             binding.sourceTitleAndDate.text = try { | ||||
|                 itm.sourceAuthorAndDate() | ||||
|             } catch (e: Exception) { | ||||
|                 e.sendSilentlyWithAcraWithName("ItemCardAdapter parse date") | ||||
|                 itm.sourceAuthorOnly() | ||||
|             } | ||||
|  | ||||
|             if (!appSettingsService.isFullHeightCardsEnabled()) { | ||||
|                 binding.itemImage.maxHeight = imageMaxHeight | ||||
|   | ||||
| @@ -7,6 +7,7 @@ import android.view.ViewGroup | ||||
| import androidx.recyclerview.widget.RecyclerView | ||||
| import bou.amine.apps.readerforselfossv2.android.R | ||||
| import bou.amine.apps.readerforselfossv2.android.databinding.ListItemBinding | ||||
| import bou.amine.apps.readerforselfossv2.android.sendSilentlyWithAcraWithName | ||||
| import bou.amine.apps.readerforselfossv2.android.utils.LinkOnTouchListener | ||||
| import bou.amine.apps.readerforselfossv2.android.utils.glide.circularDrawable | ||||
| import bou.amine.apps.readerforselfossv2.android.utils.openItemUrl | ||||
| @@ -45,13 +46,13 @@ class ItemListAdapter( | ||||
|         position: Int, | ||||
|     ) { | ||||
|         with(holder) { | ||||
|             val itm = items[position] | ||||
|             val itm = items[holder.bindingAdapterPosition] | ||||
|  | ||||
|             binding.root.setOnClickListener { | ||||
|                 repository.setReaderItems(items) | ||||
|                 c.openItemUrl( | ||||
|                     bindingAdapterPosition, | ||||
|                     items[bindingAdapterPosition].getLinkDecoded(), | ||||
|                     holder.bindingAdapterPosition, | ||||
|                     items[holder.bindingAdapterPosition].getLinkDecoded(), | ||||
|                     appSettingsService.isArticleViewerEnabled(), | ||||
|                     app, | ||||
|                 ) | ||||
| @@ -63,7 +64,12 @@ class ItemListAdapter( | ||||
|  | ||||
|             binding.title.setLinkTextColor(c.resources.getColor(R.color.colorAccent)) | ||||
|  | ||||
|             binding.sourceTitleAndDate.text = itm.sourceAuthorAndDate() | ||||
|             binding.sourceTitleAndDate.text = try { | ||||
|                 itm.sourceAuthorAndDate() | ||||
|             } catch (e: Exception) { | ||||
|                 e.sendSilentlyWithAcraWithName("ItemListAdapter parse date") | ||||
|                 itm.sourceAuthorOnly() | ||||
|             } | ||||
|  | ||||
|             if (itm.getThumbnail(repository.baseUrl).isEmpty()) { | ||||
|                 if (itm.getIcon(repository.baseUrl).isEmpty()) { | ||||
|   | ||||
| @@ -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) | ||||
|   | ||||
| @@ -102,7 +102,12 @@ class ArticleFragment : Fragment(), DIAware { | ||||
|             contentText = item.content | ||||
|             contentTitle = item.title.getHtmlDecoded() | ||||
|             contentImage = item.getThumbnail(repository.baseUrl) | ||||
|             contentSource = item.sourceAuthorAndDate() | ||||
|             contentSource = try { | ||||
|                 item.sourceAuthorAndDate() | ||||
|             } catch (e: Exception) { | ||||
|                 e.sendSilentlyWithAcraWithName("Article Fragment parse date") | ||||
|                 item.sourceAuthorOnly() | ||||
|             } | ||||
|             allImages = item.getImages() | ||||
|  | ||||
|             fontSize = appSettingsService.getFontSize() | ||||
|   | ||||
| @@ -8,12 +8,12 @@ import kotlinx.datetime.toInstant | ||||
| import org.junit.Test | ||||
|  | ||||
| class DatesTest { | ||||
|     private val newVersionDateVariant = "2022-12-24T17:00:08+00" | ||||
|     private val newVersionDate = "2013-04-07T13:43:00+01:00" | ||||
|     private val oldVersionDate = "2013-05-07 13:46:00" | ||||
|     private val oldVersionDateVariant = "2021-03-21 10:32:00.000000" | ||||
|     private val newVersionDateVariant =     "2022-12-24T17:00:08+00" | ||||
|     private val newVersionDate =            "2013-04-07T13:43:00+01:00" | ||||
|     private val newVersionDate2 =            "2013-04-07T13:43:00-01:00" | ||||
|     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() { | ||||
| @@ -24,6 +24,15 @@ class DatesTest { | ||||
|  | ||||
|         assertEquals(expected, date) | ||||
|     } | ||||
|     @Test | ||||
|     fun new_version_date2_should_be_parsed() { | ||||
|         val date = DateUtils.parseDate(newVersionDate2) | ||||
|         val expected = | ||||
|             LocalDateTime(2013, 4, 7, 13, 43, 0, 0).toInstant(TimeZone.currentSystemDefault()) | ||||
|                 .toEpochMilliseconds() | ||||
|  | ||||
|         assertEquals(expected, date) | ||||
|     } | ||||
|  | ||||
|     @Test | ||||
|     fun old_version_date_should_be_parsed() { | ||||
| @@ -54,14 +63,4 @@ 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) | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -11,23 +11,21 @@ actual class DateUtils { | ||||
|         private val oldVersionFormat = "\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}(.()\\d*)?".toRegex() | ||||
|  | ||||
|         // yyyy-MM-dd'T'HH:mm:ss[.SSS]XXX (RFC3339) | ||||
|         private val newVersionFormat = "\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\+\\d{2}(:\\d{2})?".toRegex() | ||||
|         private val newVersionFormat = "(\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2})[+-](\\d{2}(:\\d{2})?)?".toRegex() | ||||
|  | ||||
|         // We may need to consider moving the formatting to platform specific code, even if the tests are doubled | ||||
|         // For now, we handle this in a hacky way, because kotlin only accepts iso formats | ||||
|         // TODO: do not fix any more issues here. Move everything to plateform specific code. | ||||
|         actual fun parseDate(dateString: String): Long { | ||||
|             var isoDateString: String = | ||||
|                 try { | ||||
|                     if (dateString.matches(oldVersionFormat)) { | ||||
|                         dateString.replace(" ", "T") | ||||
|                     } else if (dateString.matches(newVersionFormat)) { | ||||
|                         dateString.split("+")[0] | ||||
|                         newVersionFormat.find(dateString)?.groups?.get(1)?.value ?: throw Exception("Couldn't parse $dateString") | ||||
|                     } else { | ||||
|                         throw Exception("Unrecognized format for $dateString") | ||||
|                     } | ||||
|                 } catch (e: Exception) { | ||||
|                     Napier.e(e.stackTraceToString(), tag = "DateUtils.parseDate") | ||||
|                     "1991-03-18T03:00:00" | ||||
|                     throw Exception("parseDate failed for $dateString", e) | ||||
|                 } | ||||
|  | ||||
|             return LocalDateTime.parse(isoDateString).toInstant(TimeZone.currentSystemDefault()).toEpochMilliseconds() | ||||
|   | ||||
| @@ -146,6 +146,14 @@ class SelfossModel { | ||||
|             return txt | ||||
|         } | ||||
|  | ||||
|         fun sourceAuthorOnly(): String { | ||||
|             var txt = this.sourcetitle.getHtmlDecoded() | ||||
|             if (!this.author.isNullOrBlank()) { | ||||
|                 txt += " (by ${this.author}) " | ||||
|             } | ||||
|             return txt | ||||
|         } | ||||
|  | ||||
|         fun toggleStar(): Item { | ||||
|             this.starred = !this.starred | ||||
|             return this | ||||
|   | ||||
| @@ -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 { | ||||
|   | ||||
| @@ -441,7 +441,7 @@ class AppSettingsService(acraSenderServiceProcess: Boolean = false) { | ||||
|         login: String, | ||||
|         password: String, | ||||
|     ) { | ||||
|         val regex = """\/\/(\D+):(\D+)@""".toRegex() | ||||
|         val regex = """\/\/(\S+):(\S+)@""".toRegex() | ||||
|         val matchResult = regex.find(url) | ||||
|         if (matchResult != null) { | ||||
|             val (basicLogin, basicPassword) = matchResult.destructured | ||||
|   | ||||
		Reference in New Issue
	
	Block a user