Compare commits
	
		
			15 Commits
		
	
	
		
			v125010291
			...
			e2209643d5
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| e2209643d5 | |||
| a1c0241a58 | |||
|  | f38936f9b4 | ||
| a90ccec707 | |||
|  | 2564b19726 | ||
| 61c7bb20cc | |||
| 6a0f5baf0a | |||
| 39f9505c00 | |||
| 6a6d447456 | |||
|  | 0bb4fe6aed | ||
| 7df4c3368c | |||
| c69635b5ae | |||
| 3a829df70e | |||
| 7a0202689f | |||
| b20f6888f5 | 
							
								
								
									
										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 | ||||
|         with: | ||||
|           version: "2.23.3" | ||||
|       - name: run selfoss | ||||
|         run: | | ||||
|           docker compose -f .gitea/workflows/assets/docker-compose.yml up -d | ||||
|       #      TESTS ARE RUN LOCALLY | ||||
|       #      - name: run selfoss | ||||
|       #        run: | | ||||
|       #          docker compose -f .gitea/workflows/assets/docker-compose.yml up -d | ||||
|       - name: coverage | ||||
|         run: | | ||||
|           ./gradlew :koverHtmlReport | ||||
| @@ -39,7 +40,8 @@ jobs: | ||||
|           retention-days: 1 | ||||
|           overwrite: true | ||||
|           include-hidden-files: true | ||||
|       - name: Clean | ||||
|         if: always() | ||||
|         run: | | ||||
|           docker compose -f .gitea/workflows/assets/docker-compose.yml stop | ||||
| #      TESTS ARE RUN LOCALLY | ||||
| #      - name: Clean | ||||
| #        if: always() | ||||
| #        run: | | ||||
| #          docker compose -f .gitea/workflows/assets/docker-compose.yml stop | ||||
|   | ||||
| @@ -16,6 +16,7 @@ jobs: | ||||
|         uses: actions/checkout@v4 | ||||
|         with: | ||||
|           fetch-depth: 0 | ||||
|           ref: master | ||||
|       - name: Config git | ||||
|         run: | | ||||
|           git config --global user.email aminecmi+giteadrone@pm.me | ||||
| @@ -50,7 +51,7 @@ jobs: | ||||
|           followtags: true | ||||
|           ssh_key: ${{ secrets.PRIVATE_KEY }} | ||||
|           tags: true | ||||
|           branch: release | ||||
|           branch: master | ||||
|       - name: copy file via ssh password | ||||
|         uses: appleboy/scp-action@v0.1.7 | ||||
|         with: | ||||
|   | ||||
| @@ -3,26 +3,49 @@ 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: Check | ||||
|         run: cat ./androidApp/src/main/res/values/strings.xml | ||||
|       - 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 | ||||
|           config: './.gitea/workflows/assets/crowdin.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 | ||||
|   | ||||
							
								
								
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -324,3 +324,5 @@ crowdin.properties | ||||
|  | ||||
| .kotlin/ | ||||
| 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 | ||||
|  | ||||
| - Merge pull request 'fix: Link not opening.' (#178) from fix-open-link into master | ||||
|   | ||||
| @@ -56,7 +56,7 @@ class HomeActivityTest { | ||||
|     fun testMenuActions() { | ||||
|         onView(withId(R.id.action_search)).perform(click()) | ||||
|         onView( | ||||
|             withId(R.id.search_src_text), | ||||
|             withId(com.google.android.material.R.id.search_src_text), | ||||
|         ).check(matches(isFocused())) | ||||
|         onView(isRoot()).perform(ViewActions.pressBack()) | ||||
|  | ||||
|   | ||||
| @@ -161,6 +161,7 @@ class ReaderActivity : | ||||
|                     override fun onPageSelected(position: Int) { | ||||
|                         super.onPageSelected(position) | ||||
|  | ||||
|                         if (!allItems.isNullOrEmpty() && allItems.size >= position) { | ||||
|                             if (allItems[position].starred) { | ||||
|                                 canRemoveFromFavorite() | ||||
|                             } else { | ||||
| @@ -168,6 +169,7 @@ class ReaderActivity : | ||||
|                             } | ||||
|                             readItem(allItems[position]) | ||||
|                         } | ||||
|                     } | ||||
|                 }, | ||||
|             ) | ||||
|         } | ||||
|   | ||||
| @@ -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,33 +31,82 @@ 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] | ||||
|         holder.bind(items[position], position) | ||||
|     } | ||||
|  | ||||
|         val deleteBtn: Button = holder.mView.findViewById(R.id.deleteBtn) | ||||
|     override fun getItemId(position: Int) = position.toLong() | ||||
|  | ||||
|         deleteBtn.setOnClickListener { | ||||
|             val (id, title) = items[position] | ||||
|     override fun getItemViewType(position: Int) = position | ||||
|  | ||||
|     override fun getItemCount(): Int = items.size | ||||
|  | ||||
|     inner class ViewHolder( | ||||
|         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(id, title) | ||||
|                 val successfullyDeletedSource = repository.deleteSource(source.id, source.title) | ||||
|                 launch(Dispatchers.Main) { | ||||
|                     if (successfullyDeletedSource) { | ||||
|                         items.removeAt(position) | ||||
|                         notifyItemRemoved(position) | ||||
| @@ -73,37 +121,6 @@ class SourcesListAdapter( | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|         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 getItemViewType(position: Int) = position | ||||
|  | ||||
|     override fun getItemCount(): Int = items.size | ||||
|  | ||||
|     inner class ViewHolder( | ||||
|         val mView: ConstraintLayout, | ||||
|     ) : RecyclerView.ViewHolder(mView) | ||||
| } | ||||
|   | ||||
| @@ -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 | ||||
| @@ -118,8 +118,8 @@ class ArticleFragment : | ||||
|                 e.sendSilentlyWithAcra() | ||||
|             } | ||||
|  | ||||
|             colorOnSurface = getColorFromAttr(R.attr.colorOnSurface) | ||||
|             colorSurface = getColorFromAttr(R.attr.colorSurface) | ||||
|             colorOnSurface = getColorFromAttr(com.google.android.material.R.attr.colorOnSurface) | ||||
|             colorSurface = getColorFromAttr(com.google.android.material.R.attr.colorSurface) | ||||
|  | ||||
|             contentText = item.content | ||||
|             contentTitle = item.title.getHtmlDecoded() | ||||
| @@ -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 = | ||||
|   | ||||
| @@ -83,7 +83,15 @@ class FilterSheetFragment : | ||||
|         val sourceGroup = binding.sourcesGroup | ||||
|  | ||||
|         repository.getSourcesDetailsOrStats().forEachIndexed { _, source -> | ||||
|             val c = Chip(context) | ||||
|             val c: Chip? = | ||||
|                 maybeIfContext { | ||||
|                     Chip(it) | ||||
|                 } as Chip? | ||||
|  | ||||
|             if (c == null) { | ||||
|                 return | ||||
|             } | ||||
|  | ||||
|             c.ellipsize = TextUtils.TruncateAt.END | ||||
|  | ||||
|             maybeIfContext { | ||||
| @@ -145,7 +153,11 @@ class FilterSheetFragment : | ||||
|         val tags = repository.getTags() | ||||
|  | ||||
|         tags.forEachIndexed { _, tag -> | ||||
|             val c = Chip(context) | ||||
|             val c: Chip? = maybeIfContext { Chip(it) } as Chip? | ||||
|             if (c == null) { | ||||
|                 return | ||||
|             } | ||||
|  | ||||
|             c.ellipsize = TextUtils.TruncateAt.END | ||||
|             c.text = tag.tag | ||||
|  | ||||
|   | ||||
| @@ -11,13 +11,14 @@ 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, | ||||
| ) { | ||||
|     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_TEXT, itemUrl!!.toStringUriWithHttp()) | ||||
|         sendIntent.putExtra(Intent.EXTRA_SUBJECT, itemTitle) | ||||
|         sendIntent.type = "text/plain" | ||||
|         startActivity( | ||||
| @@ -28,6 +29,7 @@ fun Context.shareLink( | ||||
|                 ).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK), | ||||
|         ) | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ColorInt | ||||
| fun Fragment.getColorFromAttr( | ||||
|   | ||||
| @@ -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,15 +57,17 @@ fun String.isBaseUrlInvalid(): Boolean { | ||||
| } | ||||
|  | ||||
| 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?) { | ||||
|     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) { | ||||
|     val intent = Intent(Intent.ACTION_VIEW) | ||||
|   | ||||
| @@ -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> | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| plugins { | ||||
|     // trick: for the same plugin versions in all sub-modules | ||||
|     id("com.android.application").version("8.7.3").apply(false) | ||||
|     id("com.android.library").version("8.7.3").apply(false) | ||||
|     id("com.android.application").version("8.8.1").apply(false) | ||||
|     id("com.android.library").version("8.8.1").apply(false) | ||||
|     id("org.jetbrains.kotlin.android").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) | ||||
| @@ -16,7 +16,6 @@ allprojects { | ||||
|     } | ||||
| } | ||||
|  | ||||
|  | ||||
| tasks.register("clean", Delete::class) { | ||||
|     delete(layout.buildDirectory) | ||||
| } | ||||
|   | ||||
| @@ -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 | ||||
| @@ -19,7 +19,7 @@ kotlin.code.style=official | ||||
| android.useAndroidX=true | ||||
| #android.nonTransitiveRClass=true | ||||
| android.enableJetifier=false | ||||
| android.nonTransitiveRClass=false | ||||
| android.nonTransitiveRClass=true | ||||
| #MPP | ||||
| kotlin.mpp.enableCInteropCommonization=true | ||||
| org.gradle.parallel=true | ||||
|   | ||||
							
								
								
									
										4
									
								
								gradle/wrapper/gradle-wrapper.properties
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								gradle/wrapper/gradle-wrapper.properties
									
									
									
									
										vendored
									
									
								
							| @@ -1,6 +1,6 @@ | ||||
| #Mon Nov 25 22:48:24 CET 2024 | ||||
| #Sun Feb 09 14:44:52 CET 2025 | ||||
| distributionBase=GRADLE_USER_HOME | ||||
| distributionPath=wrapper/dists | ||||
| distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip | ||||
| distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip | ||||
| zipStoreBase=GRADLE_USER_HOME | ||||
| zipStorePath=wrapper/dists | ||||
|   | ||||
| @@ -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