Compare commits
	
		
			5 Commits
		
	
	
		
			v125020471
			...
			e518984e27
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| e518984e27 | |||
| a1c0241a58 | |||
|  | f38936f9b4 | ||
| a90ccec707 | |||
|  | 2564b19726 | 
							
								
								
									
										9
									
								
								.gitea/workflows/assets/crowdin.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								.gitea/workflows/assets/crowdin.yml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | ||||
| project_id_env: CROWDIN_PROJECT_ID | ||||
| api_token_env: CROWDIN_PERSONAL_TOKEN | ||||
|  | ||||
| files: | ||||
|   - source: /androidApp/src/main/res/values/strings.xml | ||||
|     translation: /androidApp/src/main/res/values-%android_code%/%original_file_name% | ||||
|     translate_attributes: '0' | ||||
|     content_segmentation: '0' | ||||
| preserve_hierarchy: true | ||||
| @@ -3,26 +3,46 @@ on: | ||||
|   pull_request: | ||||
|     branches: | ||||
|       - master | ||||
|       - chore-crowdin-ci | ||||
|  | ||||
| jobs: | ||||
|   Lint: | ||||
|   #  Lint: | ||||
|   #    runs-on: ubuntu-latest | ||||
|   #    steps: | ||||
|   #      - name: Check out repository code | ||||
|   #        uses: actions/checkout@v4 | ||||
|   #      - uses: actions/setup-java@v4 | ||||
|   #        with: | ||||
|   #          distribution: 'temurin' | ||||
|   #          java-version: '17' | ||||
|   #          cache: gradle | ||||
|   #      - name: Install klint | ||||
|   #        run: curl -sSLO https://github.com/pinterest/ktlint/releases/download/1.5.0/ktlint && chmod a+x ktlint && mv ktlint /usr/local/bin/ | ||||
|   #      - name: Install detekt | ||||
|   #        run: curl -sSLO https://github.com/detekt/detekt/releases/download/v1.23.7/detekt-cli-1.23.7.zip && unzip detekt-cli-1.23.7.zip | ||||
|   #      - name: Linting... | ||||
|   #        run: ktlint 'shared/**/*.kt' 'androidApp/**/*.kt' '!shared/build' | ||||
|   #      - name: Detecting... | ||||
|   #        run: ./detekt-cli-1.23.7/bin/detekt-cli -c detekt.yml --excludes '**/shared/build/**/*.kt' | ||||
|   translations: | ||||
|     runs-on: ubuntu-latest | ||||
|     steps: | ||||
|       - name: Check out repository code | ||||
|         uses: actions/checkout@v4 | ||||
|       - uses: actions/setup-java@v4 | ||||
|       - name: crowdin action | ||||
|         uses: crowdin/github-action@v2 | ||||
|         with: | ||||
|           distribution: 'temurin' | ||||
|           java-version: '17' | ||||
|           cache: gradle | ||||
|       - name: Install klint | ||||
|         run: curl -sSLO https://github.com/pinterest/ktlint/releases/download/1.5.0/ktlint && chmod a+x ktlint && mv ktlint /usr/local/bin/ | ||||
|       - name: Install detekt | ||||
|         run: curl -sSLO https://github.com/detekt/detekt/releases/download/v1.23.7/detekt-cli-1.23.7.zip && unzip detekt-cli-1.23.7.zip | ||||
|       - name: Linting... | ||||
|         run: ktlint 'shared/**/*.kt' 'androidApp/**/*.kt' '!shared/build' | ||||
|       - name: Detecting... | ||||
|         run: ./detekt-cli-1.23.7/bin/detekt-cli -c detekt.yml --excludes '**/shared/build/**/*.kt' | ||||
|   build: | ||||
|     needs: Lint | ||||
|     uses: ./.gitea/workflows/common_build.yml | ||||
|           upload_sources: true | ||||
|           upload_translations: false | ||||
|           download_translations: true | ||||
|           create_pull_request: false | ||||
|           upload_sources_args: '-c ./.gitea/workflows/assets/crowdin.yml' | ||||
|           download_translations_args: '-c ./.gitea/workflows/assets/crowdin.yml' | ||||
|         env: | ||||
|           CROWDIN_PROJECT_ID: ${{ secrets.CROWDIN_PROJECT_ID }} | ||||
|           CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_PERSONAL_TOKEN }} | ||||
|       - name: Check | ||||
|         run: git status | ||||
| #  build: | ||||
| #    needs: Lint | ||||
| #    uses: ./.gitea/workflows/common_build.yml | ||||
|   | ||||
							
								
								
									
										17
									
								
								CHANGELOG.md
									
									
									
									
									
								
							
							
						
						
									
										17
									
								
								CHANGELOG.md
									
									
									
									
									
								
							| @@ -1,3 +1,20 @@ | ||||
| **v125020581 | ||||
|  | ||||
| - fix: url can be empty ? | ||||
| - Changelog for v125020471 | ||||
|  | ||||
| -------------------------------------------------------------------- | ||||
|  | ||||
| **v125020471 | ||||
|  | ||||
| - chore: no more docker-compose. | ||||
| - bump: gradle plugin. | ||||
| - Merge pull request 'fix: check index exists.' (#183) from fix-index into master | ||||
| - fix: check index exists. | ||||
| - Changelog for v125020411 | ||||
|  | ||||
| -------------------------------------------------------------------- | ||||
|  | ||||
| **v125020411 | ||||
|  | ||||
| - Merge pull request 'bump' (#182) from bump into master | ||||
|   | ||||
| @@ -6,9 +6,8 @@ import android.content.Intent | ||||
| import android.view.LayoutInflater | ||||
| import android.view.View | ||||
| import android.view.ViewGroup | ||||
| import android.widget.Button | ||||
| import android.widget.Toast | ||||
| import androidx.constraintlayout.widget.ConstraintLayout | ||||
| import androidx.appcompat.app.AlertDialog | ||||
| import androidx.recyclerview.widget.RecyclerView | ||||
| import bou.amine.apps.readerforselfossv2.android.R | ||||
| import bou.amine.apps.readerforselfossv2.android.UpsertSourceActivity | ||||
| @@ -32,69 +31,21 @@ class SourcesListAdapter( | ||||
|     private val items: ArrayList<SelfossModel.SourceDetail>, | ||||
| ) : RecyclerView.Adapter<SourcesListAdapter.ViewHolder>(), | ||||
|     DIAware { | ||||
|     private val c: Context = app.baseContext | ||||
|     private lateinit var binding: SourceListItemBinding | ||||
|  | ||||
|     override val di: DI by closestDI(app) | ||||
|     private val repository: Repository by instance() | ||||
|     private val appSettingsService: AppSettingsService by instance() | ||||
|  | ||||
|     override fun onCreateViewHolder( | ||||
|         parent: ViewGroup, | ||||
|         viewType: Int, | ||||
|     ): ViewHolder { | ||||
|         binding = SourceListItemBinding.inflate(LayoutInflater.from(parent.context), parent, false) | ||||
|         return ViewHolder(binding.root) | ||||
|         val binding = SourceListItemBinding.inflate(LayoutInflater.from(parent.context), parent, false) | ||||
|         return ViewHolder(binding) | ||||
|     } | ||||
|  | ||||
|     override fun onBindViewHolder( | ||||
|         holder: ViewHolder, | ||||
|         position: Int, | ||||
|     ) { | ||||
|         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 { | ||||
|             c.circularDrawable(itm.getIcon(repository.baseUrl), binding.itemImage, appSettingsService) | ||||
|         } | ||||
|  | ||||
|         if (!itm.error.isNullOrBlank()) { | ||||
|             binding.errorText.visibility = View.VISIBLE | ||||
|             binding.errorText.text = itm.error | ||||
|         } else { | ||||
|             binding.errorText.visibility = View.GONE | ||||
|         } | ||||
|  | ||||
|         binding.sourceTitle.text = itm.title.getHtmlDecoded() | ||||
|         holder.bind(items[position], position) | ||||
|     } | ||||
|  | ||||
|     override fun getItemId(position: Int) = position.toLong() | ||||
| @@ -104,6 +55,72 @@ class SourcesListAdapter( | ||||
|     override fun getItemCount(): Int = items.size | ||||
|  | ||||
|     inner class ViewHolder( | ||||
|         val mView: ConstraintLayout, | ||||
|     ) : RecyclerView.ViewHolder(mView) | ||||
|         val binding: SourceListItemBinding, | ||||
|     ) : RecyclerView.ViewHolder(binding.root) { | ||||
|         private val context: Context = app.applicationContext | ||||
|         private val repository: Repository by instance() | ||||
|         private val appSettingsService: AppSettingsService by instance() | ||||
|  | ||||
|         fun bind( | ||||
|             source: SelfossModel.SourceDetail, | ||||
|             position: Int, | ||||
|         ) { | ||||
|             binding.apply { | ||||
|                 sourceTitle.text = source.title.getHtmlDecoded() | ||||
|                 if (source.getIcon(repository.baseUrl).isEmpty()) { | ||||
|                     itemImage.setBackgroundAndText(source.title.getHtmlDecoded()) | ||||
|                 } else { | ||||
|                     context.circularDrawable(source.getIcon(repository.baseUrl), itemImage, appSettingsService) | ||||
|                 } | ||||
|  | ||||
|                 errorText.apply { | ||||
|                     visibility = if (!source.error.isNullOrBlank()) View.VISIBLE else View.GONE | ||||
|                     text = source.error | ||||
|                 } | ||||
|  | ||||
|                 deleteBtn.setOnClickListener { showDeleteConfirmationDialog(source, position) } | ||||
|  | ||||
|                 root.setOnClickListener { | ||||
|                     repository.setSelectedSource(source) | ||||
|                     app.startActivity(Intent(app, UpsertSourceActivity::class.java)) | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         private fun showDeleteConfirmationDialog( | ||||
|             source: SelfossModel.SourceDetail, | ||||
|             position: Int, | ||||
|         ) { | ||||
|             AlertDialog | ||||
|                 .Builder(app) | ||||
|                 .setTitle(app.getString(R.string.confirm_delete_title)) | ||||
|                 .setMessage(app.getString(R.string.confirm_delete_message, source.title)) | ||||
|                 .setPositiveButton(android.R.string.ok) { _, _ -> deleteSource(source, position) } | ||||
|                 .setNegativeButton(android.R.string.cancel, null) | ||||
|                 .show() | ||||
|         } | ||||
|  | ||||
|         private fun deleteSource( | ||||
|             source: SelfossModel.SourceDetail, | ||||
|             position: Int, | ||||
|         ) { | ||||
|             CoroutineScope(Dispatchers.IO).launch { | ||||
|                 val successfullyDeletedSource = repository.deleteSource(source.id, source.title) | ||||
|                 launch(Dispatchers.Main) { | ||||
|                     if (successfullyDeletedSource) { | ||||
|                         items.removeAt(position) | ||||
|                         notifyItemRemoved(position) | ||||
|                         notifyItemRangeChanged(position, itemCount) | ||||
|                     } else { | ||||
|                         Toast | ||||
|                             .makeText( | ||||
|                                 app, | ||||
|                                 R.string.can_delete_source, | ||||
|                                 Toast.LENGTH_SHORT, | ||||
|                             ).show() | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -75,7 +75,7 @@ class ArticleFragment : | ||||
|     private var colorSurface: Int = 0 | ||||
|     private var fontSize: Int = DEFAULT_FONT_SIZE | ||||
|     private lateinit var item: SelfossModel.Item | ||||
|     private lateinit var url: String | ||||
|     private var url: String? = null | ||||
|     private lateinit var contentText: String | ||||
|     private lateinit var contentSource: String | ||||
|     private lateinit var contentImage: String | ||||
| @@ -168,8 +168,8 @@ class ArticleFragment : | ||||
|  | ||||
|     private fun handleContent() { | ||||
|         if (contentText.isEmptyOrNullOrNullString()) { | ||||
|             if (repository.isNetworkAvailable()) { | ||||
|                 getContentFromMercury() | ||||
|             if (repository.isNetworkAvailable() && url.isUrlValid()) { | ||||
|                 getContentFromMercury(url!!) | ||||
|             } | ||||
|         } else { | ||||
|             binding.titleView.text = contentTitle | ||||
| @@ -271,7 +271,7 @@ class ArticleFragment : | ||||
|     } | ||||
|  | ||||
|     @Suppress("detekt:SwallowedException") | ||||
|     private fun getContentFromMercury() { | ||||
|     private fun getContentFromMercury(url: String) { | ||||
|         binding.progressBar.visibility = View.VISIBLE | ||||
|  | ||||
|         CoroutineScope(Dispatchers.Main).launch { | ||||
| @@ -424,10 +424,10 @@ class ArticleFragment : | ||||
|  | ||||
|         var baseUrl: String? = null | ||||
|         try { | ||||
|             val itemUrl = URL(url) | ||||
|             val itemUrl = URL(url.orEmpty()) | ||||
|             baseUrl = itemUrl.protocol + "://" + itemUrl.host | ||||
|         } catch (e: MalformedURLException) { | ||||
|             e.sendSilentlyWithAcraWithName("htmlToWebview > $url") | ||||
|             e.sendSilentlyWithAcraWithName("htmlToWebview > ${url.orEmpty()}") | ||||
|         } | ||||
|  | ||||
|         val fontName: String = | ||||
|   | ||||
| @@ -11,22 +11,24 @@ import bou.amine.apps.readerforselfossv2.android.utils.acra.sendSilentlyWithAcra | ||||
| import bou.amine.apps.readerforselfossv2.utils.toStringUriWithHttp | ||||
|  | ||||
| fun Context.shareLink( | ||||
|     itemUrl: String, | ||||
|     itemUrl: String?, | ||||
|     itemTitle: String, | ||||
| ) { | ||||
|     val sendIntent = Intent() | ||||
|     sendIntent.flags = Intent.FLAG_ACTIVITY_NEW_TASK | ||||
|     sendIntent.action = Intent.ACTION_SEND | ||||
|     sendIntent.putExtra(Intent.EXTRA_TEXT, itemUrl.toStringUriWithHttp()) | ||||
|     sendIntent.putExtra(Intent.EXTRA_SUBJECT, itemTitle) | ||||
|     sendIntent.type = "text/plain" | ||||
|     startActivity( | ||||
|         Intent | ||||
|             .createChooser( | ||||
|                 sendIntent, | ||||
|                 getString(R.string.share), | ||||
|             ).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK), | ||||
|     ) | ||||
|     if (itemUrl.isUrlValid()) { | ||||
|         val sendIntent = Intent() | ||||
|         sendIntent.flags = Intent.FLAG_ACTIVITY_NEW_TASK | ||||
|         sendIntent.action = Intent.ACTION_SEND | ||||
|         sendIntent.putExtra(Intent.EXTRA_TEXT, itemUrl!!.toStringUriWithHttp()) | ||||
|         sendIntent.putExtra(Intent.EXTRA_SUBJECT, itemTitle) | ||||
|         sendIntent.type = "text/plain" | ||||
|         startActivity( | ||||
|             Intent | ||||
|                 .createChooser( | ||||
|                     sendIntent, | ||||
|                     getString(R.string.share), | ||||
|                 ).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK), | ||||
|         ) | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ColorInt | ||||
|   | ||||
| @@ -15,12 +15,12 @@ import android.widget.Toast | ||||
| import bou.amine.apps.readerforselfossv2.android.R | ||||
| import bou.amine.apps.readerforselfossv2.android.ReaderActivity | ||||
| import bou.amine.apps.readerforselfossv2.model.SelfossModel | ||||
| import bou.amine.apps.readerforselfossv2.utils.toStringUriWithHttp | ||||
| import bou.amine.apps.readerforselfossv2.utils.isEmptyOrNullOrNullString | ||||
| import okhttp3.HttpUrl.Companion.toHttpUrlOrNull | ||||
|  | ||||
| fun Context.openItemUrl( | ||||
|     currentItem: Int, | ||||
|     linkDecoded: String, | ||||
|     linkDecoded: String?, | ||||
|     articleViewer: Boolean, | ||||
|     app: Activity, | ||||
| ) { | ||||
| @@ -37,12 +37,13 @@ fun Context.openItemUrl( | ||||
|             intent.putExtra("currentItem", currentItem) | ||||
|             app.startActivity(intent) | ||||
|         } else { | ||||
|             this.openUrlInBrowserAsNewTask(linkDecoded) | ||||
|             this.openUrlInBrowserAsNewTask(linkDecoded!!) | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| fun String.isUrlValid(): Boolean = this.toHttpUrlOrNull() != null && Patterns.WEB_URL.matcher(this).matches() | ||||
| fun String?.isUrlValid(): Boolean = | ||||
|     !this.isEmptyOrNullOrNullString() && this!!.toHttpUrlOrNull() != null && Patterns.WEB_URL.matcher(this).matches() | ||||
|  | ||||
| fun String.isBaseUrlInvalid(): Boolean { | ||||
|     val baseUrl = this.toHttpUrlOrNull() | ||||
| @@ -56,14 +57,16 @@ fun String.isBaseUrlInvalid(): Boolean { | ||||
| } | ||||
|  | ||||
| fun Context.openItemUrlInBrowserAsNewTask(i: SelfossModel.Item) { | ||||
|     this.openUrlInBrowserAsNewTask(i.getLinkDecoded().toStringUriWithHttp()) | ||||
|     this.openUrlInBrowserAsNewTask(i.getLinkDecoded()) | ||||
| } | ||||
|  | ||||
| fun Context.openUrlInBrowserAsNewTask(url: String) { | ||||
|     val intent = Intent(Intent.ACTION_VIEW) | ||||
|     intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK | ||||
|     intent.data = Uri.parse(url) | ||||
|     this.mayBeStartActivity(intent) | ||||
| fun Context.openUrlInBrowserAsNewTask(url: String?) { | ||||
|     if (url.isUrlValid()) { | ||||
|         val intent = Intent(Intent.ACTION_VIEW) | ||||
|         intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK | ||||
|         intent.data = Uri.parse(url) | ||||
|         this.mayBeStartActivity(intent) | ||||
|     } | ||||
| } | ||||
|  | ||||
| fun Context.openUrlInBrowser(url: String) { | ||||
|   | ||||
| @@ -129,4 +129,6 @@ | ||||
|     <string name="action_about">"Quant a"</string> | ||||
|     <string name="marked_as_read">"Element llegit"</string> | ||||
|     <string name="marked_as_unread">"Item unread"</string> | ||||
|     <string name="confirm_delete_title">Confirm Deletion</string> | ||||
|     <string name="confirm_delete_message">Are you sure you want to delete the following source?\n%s</string> | ||||
| </resources> | ||||
|   | ||||
| @@ -129,4 +129,6 @@ | ||||
|     <string name="action_about">"Über"</string> | ||||
|     <string name="marked_as_read">"Artikel gelesen"</string> | ||||
|     <string name="marked_as_unread">"Item unread"</string> | ||||
|     <string name="confirm_delete_title">Confirm Deletion</string> | ||||
|     <string name="confirm_delete_message">Are you sure you want to delete the following source?\n%s</string> | ||||
| </resources> | ||||
|   | ||||
| @@ -129,4 +129,6 @@ | ||||
|     <string name="action_about">"Acerca de"</string> | ||||
|     <string name="marked_as_read">"Artículo leído"</string> | ||||
|     <string name="marked_as_unread">"Artículo no leído"</string> | ||||
|     <string name="confirm_delete_title">Confirm Deletion</string> | ||||
|     <string name="confirm_delete_message">Are you sure you want to delete the following source?\n%s</string> | ||||
| </resources> | ||||
|   | ||||
| @@ -129,4 +129,6 @@ | ||||
|     <string name="action_about">"À propos"</string> | ||||
|     <string name="marked_as_read">"Marqué comme lu"</string> | ||||
|     <string name="marked_as_unread">"Marqué comme non lu"</string> | ||||
|     <string name="confirm_delete_title">Confirm Deletion</string> | ||||
|     <string name="confirm_delete_message">Are you sure you want to delete the following source?\n%s</string> | ||||
| </resources> | ||||
|   | ||||
| @@ -129,4 +129,6 @@ | ||||
|     <string name="action_about">"Acerca de"</string> | ||||
|     <string name="marked_as_read">"Elemento lido"</string> | ||||
|     <string name="marked_as_unread">"Elemento non lido"</string> | ||||
|     <string name="confirm_delete_title">Confirm Deletion</string> | ||||
|     <string name="confirm_delete_message">Are you sure you want to delete the following source?\n%s</string> | ||||
| </resources> | ||||
|   | ||||
| @@ -129,4 +129,6 @@ | ||||
|     <string name="action_about">"Tentang"</string> | ||||
|     <string name="marked_as_read">"Membaca item"</string> | ||||
|     <string name="marked_as_unread">"Item unread"</string> | ||||
|     <string name="confirm_delete_title">Confirm Deletion</string> | ||||
|     <string name="confirm_delete_message">Are you sure you want to delete the following source?\n%s</string> | ||||
| </resources> | ||||
|   | ||||
| @@ -129,4 +129,6 @@ | ||||
|     <string name="action_about">"Informazioni"</string> | ||||
|     <string name="marked_as_read">"Articolo letto"</string> | ||||
|     <string name="marked_as_unread">"Item unread"</string> | ||||
|     <string name="confirm_delete_title">Confirm Deletion</string> | ||||
|     <string name="confirm_delete_message">Are you sure you want to delete the following source?\n%s</string> | ||||
| </resources> | ||||
|   | ||||
| @@ -129,4 +129,6 @@ | ||||
|     <string name="action_about">"정보"</string> | ||||
|     <string name="marked_as_read">"항목 읽기"</string> | ||||
|     <string name="marked_as_unread">"Item unread"</string> | ||||
|     <string name="confirm_delete_title">Confirm Deletion</string> | ||||
|     <string name="confirm_delete_message">Are you sure you want to delete the following source?\n%s</string> | ||||
| </resources> | ||||
|   | ||||
| @@ -129,4 +129,6 @@ | ||||
|     <string name="action_about">"Over"</string> | ||||
|     <string name="marked_as_read">"Artikel gelezen"</string> | ||||
|     <string name="marked_as_unread">"Item unread"</string> | ||||
|     <string name="confirm_delete_title">Confirm Deletion</string> | ||||
|     <string name="confirm_delete_message">Are you sure you want to delete the following source?\n%s</string> | ||||
| </resources> | ||||
|   | ||||
| @@ -129,4 +129,6 @@ | ||||
|     <string name="action_about">"Sobre"</string> | ||||
|     <string name="marked_as_read">"Item lido"</string> | ||||
|     <string name="marked_as_unread">"Item unread"</string> | ||||
|     <string name="confirm_delete_title">Confirm Deletion</string> | ||||
|     <string name="confirm_delete_message">Are you sure you want to delete the following source?\n%s</string> | ||||
| </resources> | ||||
|   | ||||
| @@ -129,4 +129,6 @@ | ||||
|     <string name="action_about">"Sobre"</string> | ||||
|     <string name="marked_as_read">"Item lido"</string> | ||||
|     <string name="marked_as_unread">"Item unread"</string> | ||||
|     <string name="confirm_delete_title">Confirm Deletion</string> | ||||
|     <string name="confirm_delete_message">Are you sure you want to delete the following source?\n%s</string> | ||||
| </resources> | ||||
|   | ||||
| @@ -129,4 +129,6 @@ | ||||
|     <string name="action_about">"මේ ගැන"</string> | ||||
|     <string name="marked_as_read">"Item read"</string> | ||||
|     <string name="marked_as_unread">"Item unread"</string> | ||||
|     <string name="confirm_delete_title">Confirm Deletion</string> | ||||
|     <string name="confirm_delete_message">Are you sure you want to delete the following source?\n%s</string> | ||||
| </resources> | ||||
|   | ||||
| @@ -129,4 +129,6 @@ | ||||
|     <string name="action_about">"Hakkında"</string> | ||||
|     <string name="marked_as_read">"Öğeleri oku"</string> | ||||
|     <string name="marked_as_unread">"Item unread"</string> | ||||
|     <string name="confirm_delete_title">Confirm Deletion</string> | ||||
|     <string name="confirm_delete_message">Are you sure you want to delete the following source?\n%s</string> | ||||
| </resources> | ||||
|   | ||||
| @@ -129,4 +129,6 @@ | ||||
|     <string name="action_about">"关于我们"</string> | ||||
|     <string name="marked_as_read">"已读"</string> | ||||
|     <string name="marked_as_unread">"未读条目"</string> | ||||
|     <string name="confirm_delete_title">Confirm Deletion</string> | ||||
|     <string name="confirm_delete_message">Are you sure you want to delete the following source?\n%s</string> | ||||
| </resources> | ||||
|   | ||||
| @@ -129,4 +129,6 @@ | ||||
|     <string name="action_about">"关于我们"</string> | ||||
|     <string name="marked_as_read">"已读"</string> | ||||
|     <string name="marked_as_unread">"未讀項目"</string> | ||||
|     <string name="confirm_delete_title">Confirm Deletion</string> | ||||
|     <string name="confirm_delete_message">Are you sure you want to delete the following source?\n%s</string> | ||||
| </resources> | ||||
|   | ||||
| @@ -131,4 +131,7 @@ | ||||
|     <string name="action_about">"About"</string> | ||||
|     <string name="marked_as_read">"Item read"</string> | ||||
|     <string name="marked_as_unread">"Item unread"</string> | ||||
|     <string name="confirm_delete_title">Confirm Deletion</string> | ||||
|     <string name="confirm_delete_message">Are you sure you want to delete the following source?\n%s</string> | ||||
|     <string name="test_only_delete_late">Tototta</string> | ||||
| </resources> | ||||
|   | ||||
| @@ -0,0 +1,7 @@ | ||||
| **v125020471** | ||||
|  | ||||
| - chore: no more docker-compose. | ||||
| - bump: gradle plugin. | ||||
| - Merge pull request 'fix: check index exists.' (#183) from fix-index into master | ||||
| - fix: check index exists. | ||||
| - Changelog for v125020411 | ||||
| @@ -0,0 +1,4 @@ | ||||
| **v125020581** | ||||
|  | ||||
| - fix: url can be empty ? | ||||
| - Changelog for v125020471 | ||||
| @@ -127,8 +127,8 @@ class SelfossModel { | ||||
|         val tags: List<String>, | ||||
|         val author: String? = null, | ||||
|     ) { | ||||
|         fun getLinkDecoded(): String { | ||||
|             var stringUrl: String | ||||
|         fun getLinkDecoded(): String? { | ||||
|             var stringUrl: String? | ||||
|             stringUrl = | ||||
|                 if (link.contains("//news.google.com/news/") && link.contains("&url=")) { | ||||
|                     link.substringAfter("&url=") | ||||
| @@ -146,11 +146,7 @@ class SelfossModel { | ||||
|                 stringUrl = "http:$stringUrl" | ||||
|             } | ||||
|  | ||||
|             if (stringUrl.isEmptyOrNullOrNullString()) { | ||||
|                 throw ModelException("Link $link was translated to $stringUrl, but was empty. Handle this.") | ||||
|             } | ||||
|  | ||||
|             return stringUrl | ||||
|             return if (stringUrl.isEmptyOrNullOrNullString()) null else stringUrl | ||||
|         } | ||||
|  | ||||
|         fun sourceAuthorAndDate(): String { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user