Compare commits
	
		
			10 Commits
		
	
	
		
			v125020411
			...
			55bd76a7c6
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 55bd76a7c6 | |||
| a1c0241a58 | |||
|  | f38936f9b4 | ||
| a90ccec707 | |||
|  | 2564b19726 | ||
| 61c7bb20cc | |||
| 6a0f5baf0a | |||
| 39f9505c00 | |||
| 6a6d447456 | |||
|  | 0bb4fe6aed | 
							
								
								
									
										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 | ||||||
| @@ -26,9 +26,10 @@ jobs: | |||||||
|       - uses: KengoTODA/actions-setup-docker-compose@v1 |       - uses: KengoTODA/actions-setup-docker-compose@v1 | ||||||
|         with: |         with: | ||||||
|           version: "2.23.3" |           version: "2.23.3" | ||||||
|       - name: run selfoss |       #      TESTS ARE RUN LOCALLY | ||||||
|         run: | |       #      - name: run selfoss | ||||||
|           docker compose -f .gitea/workflows/assets/docker-compose.yml up -d |       #        run: | | ||||||
|  |       #          docker compose -f .gitea/workflows/assets/docker-compose.yml up -d | ||||||
|       - name: coverage |       - name: coverage | ||||||
|         run: | |         run: | | ||||||
|           ./gradlew :koverHtmlReport |           ./gradlew :koverHtmlReport | ||||||
| @@ -39,7 +40,8 @@ jobs: | |||||||
|           retention-days: 1 |           retention-days: 1 | ||||||
|           overwrite: true |           overwrite: true | ||||||
|           include-hidden-files: true |           include-hidden-files: true | ||||||
|       - name: Clean | #      TESTS ARE RUN LOCALLY | ||||||
|         if: always() | #      - name: Clean | ||||||
|         run: | | #        if: always() | ||||||
|           docker compose -f .gitea/workflows/assets/docker-compose.yml stop | #        run: | | ||||||
|  | #          docker compose -f .gitea/workflows/assets/docker-compose.yml stop | ||||||
|   | |||||||
| @@ -3,26 +3,41 @@ on: | |||||||
|   pull_request: |   pull_request: | ||||||
|     branches: |     branches: | ||||||
|       - master |       - master | ||||||
|  |       - chore-crowdin-ci | ||||||
|  |  | ||||||
| jobs: | 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 |     runs-on: ubuntu-latest | ||||||
|     steps: |     steps: | ||||||
|       - name: Check out repository code |       - name: crowdin action | ||||||
|         uses: actions/checkout@v4 |         uses: crowdin/github-action@v2 | ||||||
|       - uses: actions/setup-java@v4 |  | ||||||
|         with: |         with: | ||||||
|           distribution: 'temurin' |           config: './.gitea/workflows/assets/crowdin.yml' | ||||||
|           java-version: '17' |           upload_sources: true | ||||||
|           cache: gradle |           upload_translations: false | ||||||
|       - name: Install klint |           download_translations: true | ||||||
|         run: curl -sSLO https://github.com/pinterest/ktlint/releases/download/1.5.0/ktlint && chmod a+x ktlint && mv ktlint /usr/local/bin/ |           create_pull_request: false | ||||||
|       - name: Install detekt |         env: | ||||||
|         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 |           CROWDIN_PROJECT_ID: ${{ secrets.CROWDIN_PROJECT_ID }} | ||||||
|       - name: Linting... |           CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_PERSONAL_TOKEN }} | ||||||
|         run: ktlint 'shared/**/*.kt' 'androidApp/**/*.kt' '!shared/build' | #  build: | ||||||
|       - name: Detecting... | #    needs: Lint | ||||||
|         run: ./detekt-cli-1.23.7/bin/detekt-cli -c detekt.yml --excludes '**/shared/build/**/*.kt' | #    uses: ./.gitea/workflows/common_build.yml | ||||||
|   build: |  | ||||||
|     needs: Lint |  | ||||||
|     uses: ./.gitea/workflows/common_build.yml |  | ||||||
|   | |||||||
							
								
								
									
										4
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -323,4 +323,6 @@ fabric.properties | |||||||
| crowdin.properties | crowdin.properties | ||||||
|  |  | ||||||
| .kotlin/ | .kotlin/ | ||||||
| build-cache/ | build-cache/ | ||||||
|  |  | ||||||
|  | act | ||||||
|   | |||||||
							
								
								
									
										27
									
								
								CHANGELOG.md
									
									
									
									
									
								
							
							
						
						
									
										27
									
								
								CHANGELOG.md
									
									
									
									
									
								
							| @@ -1,3 +1,30 @@ | |||||||
|  | **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 | ||||||
|  | - chore: non transiant R classes. | ||||||
|  | - Merge pull request 'fix: One more missing context.' (#181) from fix-one-more-context into master | ||||||
|  | - bump | ||||||
|  | - fix: One more missing context. | ||||||
|  |  | ||||||
|  | -------------------------------------------------------------------- | ||||||
|  |  | ||||||
| **v125010241 | **v125010241 | ||||||
|  |  | ||||||
| - Merge pull request 'fix: Link not opening.' (#178) from fix-open-link into master | - Merge pull request 'fix: Link not opening.' (#178) from fix-open-link into master | ||||||
|   | |||||||
| @@ -161,12 +161,14 @@ class ReaderActivity : | |||||||
|                     override fun onPageSelected(position: Int) { |                     override fun onPageSelected(position: Int) { | ||||||
|                         super.onPageSelected(position) |                         super.onPageSelected(position) | ||||||
|  |  | ||||||
|                         if (allItems[position].starred) { |                         if (!allItems.isNullOrEmpty() && allItems.size >= position) { | ||||||
|                             canRemoveFromFavorite() |                             if (allItems[position].starred) { | ||||||
|                         } else { |                                 canRemoveFromFavorite() | ||||||
|                             canFavorite() |                             } else { | ||||||
|  |                                 canFavorite() | ||||||
|  |                             } | ||||||
|  |                             readItem(allItems[position]) | ||||||
|                         } |                         } | ||||||
|                         readItem(allItems[position]) |  | ||||||
|                     } |                     } | ||||||
|                 }, |                 }, | ||||||
|             ) |             ) | ||||||
|   | |||||||
| @@ -6,9 +6,8 @@ import android.content.Intent | |||||||
| import android.view.LayoutInflater | import android.view.LayoutInflater | ||||||
| import android.view.View | import android.view.View | ||||||
| import android.view.ViewGroup | import android.view.ViewGroup | ||||||
| import android.widget.Button |  | ||||||
| import android.widget.Toast | import android.widget.Toast | ||||||
| import androidx.constraintlayout.widget.ConstraintLayout | import androidx.appcompat.app.AlertDialog | ||||||
| import androidx.recyclerview.widget.RecyclerView | import androidx.recyclerview.widget.RecyclerView | ||||||
| import bou.amine.apps.readerforselfossv2.android.R | import bou.amine.apps.readerforselfossv2.android.R | ||||||
| import bou.amine.apps.readerforselfossv2.android.UpsertSourceActivity | import bou.amine.apps.readerforselfossv2.android.UpsertSourceActivity | ||||||
| @@ -32,69 +31,21 @@ class SourcesListAdapter( | |||||||
|     private val items: ArrayList<SelfossModel.SourceDetail>, |     private val items: ArrayList<SelfossModel.SourceDetail>, | ||||||
| ) : RecyclerView.Adapter<SourcesListAdapter.ViewHolder>(), | ) : RecyclerView.Adapter<SourcesListAdapter.ViewHolder>(), | ||||||
|     DIAware { |     DIAware { | ||||||
|     private val c: Context = app.baseContext |  | ||||||
|     private lateinit var binding: SourceListItemBinding |  | ||||||
|  |  | ||||||
|     override val di: DI by closestDI(app) |     override val di: DI by closestDI(app) | ||||||
|     private val repository: Repository by instance() |  | ||||||
|     private val appSettingsService: AppSettingsService by instance() |  | ||||||
|  |  | ||||||
|     override fun onCreateViewHolder( |     override fun onCreateViewHolder( | ||||||
|         parent: ViewGroup, |         parent: ViewGroup, | ||||||
|         viewType: Int, |         viewType: Int, | ||||||
|     ): ViewHolder { |     ): ViewHolder { | ||||||
|         binding = SourceListItemBinding.inflate(LayoutInflater.from(parent.context), parent, false) |         val binding = SourceListItemBinding.inflate(LayoutInflater.from(parent.context), parent, false) | ||||||
|         return ViewHolder(binding.root) |         return ViewHolder(binding) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     override fun onBindViewHolder( |     override fun onBindViewHolder( | ||||||
|         holder: ViewHolder, |         holder: ViewHolder, | ||||||
|         position: Int, |         position: Int, | ||||||
|     ) { |     ) { | ||||||
|         val itm = items[position] |         holder.bind(items[position], 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() |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     override fun getItemId(position: Int) = position.toLong() |     override fun getItemId(position: Int) = position.toLong() | ||||||
| @@ -104,6 +55,72 @@ class SourcesListAdapter( | |||||||
|     override fun getItemCount(): Int = items.size |     override fun getItemCount(): Int = items.size | ||||||
|  |  | ||||||
|     inner class ViewHolder( |     inner class ViewHolder( | ||||||
|         val mView: ConstraintLayout, |         val binding: SourceListItemBinding, | ||||||
|     ) : RecyclerView.ViewHolder(mView) |     ) : 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 colorSurface: Int = 0 | ||||||
|     private var fontSize: Int = DEFAULT_FONT_SIZE |     private var fontSize: Int = DEFAULT_FONT_SIZE | ||||||
|     private lateinit var item: SelfossModel.Item |     private lateinit var item: SelfossModel.Item | ||||||
|     private lateinit var url: String |     private var url: String? = null | ||||||
|     private lateinit var contentText: String |     private lateinit var contentText: String | ||||||
|     private lateinit var contentSource: String |     private lateinit var contentSource: String | ||||||
|     private lateinit var contentImage: String |     private lateinit var contentImage: String | ||||||
| @@ -168,8 +168,8 @@ class ArticleFragment : | |||||||
|  |  | ||||||
|     private fun handleContent() { |     private fun handleContent() { | ||||||
|         if (contentText.isEmptyOrNullOrNullString()) { |         if (contentText.isEmptyOrNullOrNullString()) { | ||||||
|             if (repository.isNetworkAvailable()) { |             if (repository.isNetworkAvailable() && url.isUrlValid()) { | ||||||
|                 getContentFromMercury() |                 getContentFromMercury(url!!) | ||||||
|             } |             } | ||||||
|         } else { |         } else { | ||||||
|             binding.titleView.text = contentTitle |             binding.titleView.text = contentTitle | ||||||
| @@ -271,7 +271,7 @@ class ArticleFragment : | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Suppress("detekt:SwallowedException") |     @Suppress("detekt:SwallowedException") | ||||||
|     private fun getContentFromMercury() { |     private fun getContentFromMercury(url: String) { | ||||||
|         binding.progressBar.visibility = View.VISIBLE |         binding.progressBar.visibility = View.VISIBLE | ||||||
|  |  | ||||||
|         CoroutineScope(Dispatchers.Main).launch { |         CoroutineScope(Dispatchers.Main).launch { | ||||||
| @@ -424,10 +424,10 @@ class ArticleFragment : | |||||||
|  |  | ||||||
|         var baseUrl: String? = null |         var baseUrl: String? = null | ||||||
|         try { |         try { | ||||||
|             val itemUrl = URL(url) |             val itemUrl = URL(url.orEmpty()) | ||||||
|             baseUrl = itemUrl.protocol + "://" + itemUrl.host |             baseUrl = itemUrl.protocol + "://" + itemUrl.host | ||||||
|         } catch (e: MalformedURLException) { |         } catch (e: MalformedURLException) { | ||||||
|             e.sendSilentlyWithAcraWithName("htmlToWebview > $url") |             e.sendSilentlyWithAcraWithName("htmlToWebview > ${url.orEmpty()}") | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         val fontName: String = |         val fontName: String = | ||||||
|   | |||||||
| @@ -11,22 +11,24 @@ import bou.amine.apps.readerforselfossv2.android.utils.acra.sendSilentlyWithAcra | |||||||
| import bou.amine.apps.readerforselfossv2.utils.toStringUriWithHttp | import bou.amine.apps.readerforselfossv2.utils.toStringUriWithHttp | ||||||
|  |  | ||||||
| fun Context.shareLink( | fun Context.shareLink( | ||||||
|     itemUrl: String, |     itemUrl: String?, | ||||||
|     itemTitle: String, |     itemTitle: String, | ||||||
| ) { | ) { | ||||||
|     val sendIntent = Intent() |     if (itemUrl.isUrlValid()) { | ||||||
|     sendIntent.flags = Intent.FLAG_ACTIVITY_NEW_TASK |         val sendIntent = Intent() | ||||||
|     sendIntent.action = Intent.ACTION_SEND |         sendIntent.flags = Intent.FLAG_ACTIVITY_NEW_TASK | ||||||
|     sendIntent.putExtra(Intent.EXTRA_TEXT, itemUrl.toStringUriWithHttp()) |         sendIntent.action = Intent.ACTION_SEND | ||||||
|     sendIntent.putExtra(Intent.EXTRA_SUBJECT, itemTitle) |         sendIntent.putExtra(Intent.EXTRA_TEXT, itemUrl!!.toStringUriWithHttp()) | ||||||
|     sendIntent.type = "text/plain" |         sendIntent.putExtra(Intent.EXTRA_SUBJECT, itemTitle) | ||||||
|     startActivity( |         sendIntent.type = "text/plain" | ||||||
|         Intent |         startActivity( | ||||||
|             .createChooser( |             Intent | ||||||
|                 sendIntent, |                 .createChooser( | ||||||
|                 getString(R.string.share), |                     sendIntent, | ||||||
|             ).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK), |                     getString(R.string.share), | ||||||
|     ) |                 ).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK), | ||||||
|  |         ) | ||||||
|  |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| @ColorInt | @ColorInt | ||||||
|   | |||||||
| @@ -15,12 +15,12 @@ import android.widget.Toast | |||||||
| import bou.amine.apps.readerforselfossv2.android.R | import bou.amine.apps.readerforselfossv2.android.R | ||||||
| import bou.amine.apps.readerforselfossv2.android.ReaderActivity | import bou.amine.apps.readerforselfossv2.android.ReaderActivity | ||||||
| import bou.amine.apps.readerforselfossv2.model.SelfossModel | 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 | import okhttp3.HttpUrl.Companion.toHttpUrlOrNull | ||||||
|  |  | ||||||
| fun Context.openItemUrl( | fun Context.openItemUrl( | ||||||
|     currentItem: Int, |     currentItem: Int, | ||||||
|     linkDecoded: String, |     linkDecoded: String?, | ||||||
|     articleViewer: Boolean, |     articleViewer: Boolean, | ||||||
|     app: Activity, |     app: Activity, | ||||||
| ) { | ) { | ||||||
| @@ -37,12 +37,13 @@ fun Context.openItemUrl( | |||||||
|             intent.putExtra("currentItem", currentItem) |             intent.putExtra("currentItem", currentItem) | ||||||
|             app.startActivity(intent) |             app.startActivity(intent) | ||||||
|         } else { |         } 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 { | fun String.isBaseUrlInvalid(): Boolean { | ||||||
|     val baseUrl = this.toHttpUrlOrNull() |     val baseUrl = this.toHttpUrlOrNull() | ||||||
| @@ -56,14 +57,16 @@ fun String.isBaseUrlInvalid(): Boolean { | |||||||
| } | } | ||||||
|  |  | ||||||
| fun Context.openItemUrlInBrowserAsNewTask(i: SelfossModel.Item) { | fun Context.openItemUrlInBrowserAsNewTask(i: SelfossModel.Item) { | ||||||
|     this.openUrlInBrowserAsNewTask(i.getLinkDecoded().toStringUriWithHttp()) |     this.openUrlInBrowserAsNewTask(i.getLinkDecoded()) | ||||||
| } | } | ||||||
|  |  | ||||||
| fun Context.openUrlInBrowserAsNewTask(url: String) { | fun Context.openUrlInBrowserAsNewTask(url: String?) { | ||||||
|     val intent = Intent(Intent.ACTION_VIEW) |     if (url.isUrlValid()) { | ||||||
|     intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK |         val intent = Intent(Intent.ACTION_VIEW) | ||||||
|     intent.data = Uri.parse(url) |         intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK | ||||||
|     this.mayBeStartActivity(intent) |         intent.data = Uri.parse(url) | ||||||
|  |         this.mayBeStartActivity(intent) | ||||||
|  |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| fun Context.openUrlInBrowser(url: String) { | fun Context.openUrlInBrowser(url: String) { | ||||||
|   | |||||||
| @@ -129,4 +129,6 @@ | |||||||
|     <string name="action_about">"Quant a"</string> |     <string name="action_about">"Quant a"</string> | ||||||
|     <string name="marked_as_read">"Element llegit"</string> |     <string name="marked_as_read">"Element llegit"</string> | ||||||
|     <string name="marked_as_unread">"Item unread"</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> | </resources> | ||||||
|   | |||||||
| @@ -129,4 +129,6 @@ | |||||||
|     <string name="action_about">"Über"</string> |     <string name="action_about">"Über"</string> | ||||||
|     <string name="marked_as_read">"Artikel gelesen"</string> |     <string name="marked_as_read">"Artikel gelesen"</string> | ||||||
|     <string name="marked_as_unread">"Item unread"</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> | </resources> | ||||||
|   | |||||||
| @@ -129,4 +129,6 @@ | |||||||
|     <string name="action_about">"Acerca de"</string> |     <string name="action_about">"Acerca de"</string> | ||||||
|     <string name="marked_as_read">"Artículo leído"</string> |     <string name="marked_as_read">"Artículo leído"</string> | ||||||
|     <string name="marked_as_unread">"Artículo no 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> | </resources> | ||||||
|   | |||||||
| @@ -129,4 +129,6 @@ | |||||||
|     <string name="action_about">"À propos"</string> |     <string name="action_about">"À propos"</string> | ||||||
|     <string name="marked_as_read">"Marqué comme lu"</string> |     <string name="marked_as_read">"Marqué comme lu"</string> | ||||||
|     <string name="marked_as_unread">"Marqué comme non 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> | </resources> | ||||||
|   | |||||||
| @@ -129,4 +129,6 @@ | |||||||
|     <string name="action_about">"Acerca de"</string> |     <string name="action_about">"Acerca de"</string> | ||||||
|     <string name="marked_as_read">"Elemento lido"</string> |     <string name="marked_as_read">"Elemento lido"</string> | ||||||
|     <string name="marked_as_unread">"Elemento non 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> | </resources> | ||||||
|   | |||||||
| @@ -129,4 +129,6 @@ | |||||||
|     <string name="action_about">"Tentang"</string> |     <string name="action_about">"Tentang"</string> | ||||||
|     <string name="marked_as_read">"Membaca item"</string> |     <string name="marked_as_read">"Membaca item"</string> | ||||||
|     <string name="marked_as_unread">"Item unread"</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> | </resources> | ||||||
|   | |||||||
| @@ -129,4 +129,6 @@ | |||||||
|     <string name="action_about">"Informazioni"</string> |     <string name="action_about">"Informazioni"</string> | ||||||
|     <string name="marked_as_read">"Articolo letto"</string> |     <string name="marked_as_read">"Articolo letto"</string> | ||||||
|     <string name="marked_as_unread">"Item unread"</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> | </resources> | ||||||
|   | |||||||
| @@ -129,4 +129,6 @@ | |||||||
|     <string name="action_about">"정보"</string> |     <string name="action_about">"정보"</string> | ||||||
|     <string name="marked_as_read">"항목 읽기"</string> |     <string name="marked_as_read">"항목 읽기"</string> | ||||||
|     <string name="marked_as_unread">"Item unread"</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> | </resources> | ||||||
|   | |||||||
| @@ -129,4 +129,6 @@ | |||||||
|     <string name="action_about">"Over"</string> |     <string name="action_about">"Over"</string> | ||||||
|     <string name="marked_as_read">"Artikel gelezen"</string> |     <string name="marked_as_read">"Artikel gelezen"</string> | ||||||
|     <string name="marked_as_unread">"Item unread"</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> | </resources> | ||||||
|   | |||||||
| @@ -129,4 +129,6 @@ | |||||||
|     <string name="action_about">"Sobre"</string> |     <string name="action_about">"Sobre"</string> | ||||||
|     <string name="marked_as_read">"Item lido"</string> |     <string name="marked_as_read">"Item lido"</string> | ||||||
|     <string name="marked_as_unread">"Item unread"</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> | </resources> | ||||||
|   | |||||||
| @@ -129,4 +129,6 @@ | |||||||
|     <string name="action_about">"Sobre"</string> |     <string name="action_about">"Sobre"</string> | ||||||
|     <string name="marked_as_read">"Item lido"</string> |     <string name="marked_as_read">"Item lido"</string> | ||||||
|     <string name="marked_as_unread">"Item unread"</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> | </resources> | ||||||
|   | |||||||
| @@ -129,4 +129,6 @@ | |||||||
|     <string name="action_about">"මේ ගැන"</string> |     <string name="action_about">"මේ ගැන"</string> | ||||||
|     <string name="marked_as_read">"Item read"</string> |     <string name="marked_as_read">"Item read"</string> | ||||||
|     <string name="marked_as_unread">"Item unread"</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> | </resources> | ||||||
|   | |||||||
| @@ -129,4 +129,6 @@ | |||||||
|     <string name="action_about">"Hakkında"</string> |     <string name="action_about">"Hakkında"</string> | ||||||
|     <string name="marked_as_read">"Öğeleri oku"</string> |     <string name="marked_as_read">"Öğeleri oku"</string> | ||||||
|     <string name="marked_as_unread">"Item unread"</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> | </resources> | ||||||
|   | |||||||
| @@ -129,4 +129,6 @@ | |||||||
|     <string name="action_about">"关于我们"</string> |     <string name="action_about">"关于我们"</string> | ||||||
|     <string name="marked_as_read">"已读"</string> |     <string name="marked_as_read">"已读"</string> | ||||||
|     <string name="marked_as_unread">"未读条目"</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> | </resources> | ||||||
|   | |||||||
| @@ -129,4 +129,6 @@ | |||||||
|     <string name="action_about">"关于我们"</string> |     <string name="action_about">"关于我们"</string> | ||||||
|     <string name="marked_as_read">"已读"</string> |     <string name="marked_as_read">"已读"</string> | ||||||
|     <string name="marked_as_unread">"未讀項目"</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> | </resources> | ||||||
|   | |||||||
| @@ -131,4 +131,7 @@ | |||||||
|     <string name="action_about">"About"</string> |     <string name="action_about">"About"</string> | ||||||
|     <string name="marked_as_read">"Item read"</string> |     <string name="marked_as_read">"Item read"</string> | ||||||
|     <string name="marked_as_unread">"Item unread"</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> | </resources> | ||||||
|   | |||||||
| @@ -1,7 +1,7 @@ | |||||||
| plugins { | plugins { | ||||||
|     // trick: for the same plugin versions in all sub-modules |     // trick: for the same plugin versions in all sub-modules | ||||||
|     id("com.android.application").version("8.8.0").apply(false) |     id("com.android.application").version("8.8.1").apply(false) | ||||||
|     id("com.android.library").version("8.8.0").apply(false) |     id("com.android.library").version("8.8.1").apply(false) | ||||||
|     id("org.jetbrains.kotlin.android").version("2.1.0").apply(false) |     id("org.jetbrains.kotlin.android").version("2.1.0").apply(false) | ||||||
|     kotlin("multiplatform").version("2.1.0").apply(false) |     kotlin("multiplatform").version("2.1.0").apply(false) | ||||||
|     id("com.mikepenz.aboutlibraries.plugin").version("10.5.1").apply(false) |     id("com.mikepenz.aboutlibraries.plugin").version("10.5.1").apply(false) | ||||||
|   | |||||||
| @@ -0,0 +1,7 @@ | |||||||
|  | **v125020411** | ||||||
|  |  | ||||||
|  | - Merge pull request 'bump' (#182) from bump into master | ||||||
|  | - chore: non transiant R classes. | ||||||
|  | - Merge pull request 'fix: One more missing context.' (#181) from fix-one-more-context into master | ||||||
|  | - bump | ||||||
|  | - fix: One more missing context. | ||||||
| @@ -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 tags: List<String>, | ||||||
|         val author: String? = null, |         val author: String? = null, | ||||||
|     ) { |     ) { | ||||||
|         fun getLinkDecoded(): String { |         fun getLinkDecoded(): String? { | ||||||
|             var stringUrl: String |             var stringUrl: String? | ||||||
|             stringUrl = |             stringUrl = | ||||||
|                 if (link.contains("//news.google.com/news/") && link.contains("&url=")) { |                 if (link.contains("//news.google.com/news/") && link.contains("&url=")) { | ||||||
|                     link.substringAfter("&url=") |                     link.substringAfter("&url=") | ||||||
| @@ -146,11 +146,7 @@ class SelfossModel { | |||||||
|                 stringUrl = "http:$stringUrl" |                 stringUrl = "http:$stringUrl" | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             if (stringUrl.isEmptyOrNullOrNullString()) { |             return if (stringUrl.isEmptyOrNullOrNullString()) null else stringUrl | ||||||
|                 throw ModelException("Link $link was translated to $stringUrl, but was empty. Handle this.") |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             return stringUrl |  | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         fun sourceAuthorAndDate(): String { |         fun sourceAuthorAndDate(): String { | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user