Compare commits

...

15 Commits

Author SHA1 Message Date
4a093fd969 chore: we don't need to check if the url is valid in upsert screen.
Some checks failed
Check PR code / Lint (pull_request) Failing after 1m39s
Check PR code / build (pull_request) Has been skipped
2025-03-09 14:48:29 +01:00
03ea12000c fix: Url validation was not failing login. Added tests.
Some checks failed
Check PR code / Lint (pull_request) Successful in 2m36s
Check PR code / build (pull_request) Has been cancelled
2025-03-09 14:41:56 +01:00
f38936f9b4 Changelog for v125020581 2025-02-27 21:08:25 +00:00
a90ccec707 fix: url can be empty ?
All checks were successful
Check master code / build (push) Successful in 14m37s
Create tag / build (push) Successful in 7m25s
Create tag / createTagAndChangelog (push) Successful in 44s
Create tag / release (push) Successful in 5m12s
2025-02-27 21:40:06 +01:00
2564b19726 Changelog for v125020471 2025-02-16 14:43:28 +00:00
61c7bb20cc chore: no more docker-compose.
All checks were successful
Create tag / build (push) Successful in 21m1s
Create tag / createTagAndChangelog (push) Successful in 1m21s
Create tag / release (push) Successful in 9m3s
Check master code / build (push) Successful in 34m35s
2025-02-16 15:17:51 +01:00
6a0f5baf0a bump: gradle plugin.
Some checks failed
Check master code / build (push) Has been cancelled
2025-02-16 14:57:34 +01:00
39f9505c00 Merge pull request 'fix: check index exists.' (#183) from fix-index into master
All checks were successful
Check master code / build (push) Successful in 8m3s
Reviewed-on: #183
2025-02-16 13:37:42 +00:00
6a6d447456 fix: check index exists.
All checks were successful
Check PR code / Lint (pull_request) Successful in 3m57s
Check PR code / build (pull_request) Successful in 13m44s
2025-02-16 13:57:42 +01:00
0bb4fe6aed Changelog for v125020411 2025-02-10 20:16:56 +00:00
7df4c3368c Merge pull request 'bump' (#182) from bump into master
All checks were successful
Check master code / build (push) Successful in 11m6s
Create tag / build (push) Successful in 7m35s
Create tag / createTagAndChangelog (push) Successful in 44s
Create tag / release (push) Successful in 4m35s
Reviewed-on: #182
2025-02-10 19:35:40 +00:00
c69635b5ae chore: non transiant R classes.
All checks were successful
Check PR code / Lint (pull_request) Successful in 3m36s
Check PR code / build (pull_request) Successful in 16m13s
2025-02-09 22:27:53 +01:00
3a829df70e Merge pull request 'fix: One more missing context.' (#181) from fix-one-more-context into master
All checks were successful
Check master code / build (push) Successful in 13m26s
Reviewed-on: #181
2025-02-09 20:44:29 +00:00
7a0202689f bump
All checks were successful
Check PR code / Lint (pull_request) Successful in 4m42s
Check PR code / build (pull_request) Successful in 16m9s
2025-02-09 21:44:02 +01:00
b20f6888f5 fix: One more missing context.
All checks were successful
Check PR code / Lint (pull_request) Successful in 1m1s
Check PR code / build (pull_request) Successful in 15m1s
2025-02-09 14:42:17 +01:00
20 changed files with 153 additions and 79 deletions

View File

@ -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

View File

@ -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:
@ -124,4 +125,4 @@ jobs:
priority: high
convert_markdown: true
body: Nouveau fichier de mapping pour la version ${{ steps.version.outputs.VERSION }}
attachments: androidApp/build/outputs/mapping/githubConfigRelease/mapping.txt
attachments: androidApp/build/outputs/mapping/githubConfigRelease/mapping.txt

4
.gitignore vendored
View File

@ -323,4 +323,6 @@ fabric.properties
crowdin.properties
.kotlin/
build-cache/
build-cache/
act

View File

@ -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

View File

@ -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())

View File

@ -60,9 +60,23 @@ class LoginActivityTest {
fun urlError() {
performLogin("10.0.2.2:8888")
onView(withId(R.id.urlView)).perform(click())
onView(withId(R.id.urlView)).check(matches(withError(R.string.login_url_problem)))
}
@Test
fun connectError() {
performLogin("http://10.0.2.2:8889")
onView(withId(R.id.urlView)).perform(click())
onView(withId(R.id.urlView)).check(matches(withError(R.string.wrong_infos)))
}
@Test
fun urlSlashError() {
performLogin("https://google.fr/toto")
onView(withId(R.id.urlView)).perform(click())
onView(withId(R.id.urlView)).check(matches(withError(R.string.login_url_problem)))
}
@Test
fun multiError() {
onView(withId(R.id.signInButton)).perform(click())

View File

@ -149,9 +149,10 @@ class LoginActivity :
.toString()
.trim()
failInvalidUrl(url)
failLoginDetails(password, login)
val cancelUrl = failInvalidUrl(url)
if (cancelUrl) return
val cancelDetails = failLoginDetails(password, login)
if (cancelDetails) return
showProgress(true)
appSettingsService.updateSelfSigned(binding.selfSigned.isChecked)
@ -193,7 +194,7 @@ class LoginActivity :
private fun failLoginDetails(
password: String,
login: String,
) {
): Boolean {
var lastFocusedView: View? = null
var cancel = false
if (isWithLogin) {
@ -210,9 +211,10 @@ class LoginActivity :
}
}
maybeCancelAndFocusView(cancel, lastFocusedView)
return cancel
}
private fun failInvalidUrl(url: String) {
private fun failInvalidUrl(url: String): Boolean {
val focusView = binding.urlView
var cancel = false
if (url.isBaseUrlInvalid()) {
@ -232,6 +234,7 @@ class LoginActivity :
}
}
maybeCancelAndFocusView(cancel, focusView)
return cancel
}
private fun maybeCancelAndFocusView(

View File

@ -161,12 +161,14 @@ class ReaderActivity :
override fun onPageSelected(position: Int) {
super.onPageSelected(position)
if (allItems[position].starred) {
canRemoveFromFavorite()
} else {
canFavorite()
if (!allItems.isNullOrEmpty() && allItems.size >= position) {
if (allItems[position].starred) {
canRemoveFromFavorite()
} else {
canFavorite()
}
readItem(allItems[position])
}
readItem(allItems[position])
}
},
)

View File

@ -9,7 +9,6 @@ import android.widget.TextView
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import bou.amine.apps.readerforselfossv2.android.databinding.ActivityUpsertSourceBinding
import bou.amine.apps.readerforselfossv2.android.utils.isBaseUrlInvalid
import bou.amine.apps.readerforselfossv2.model.NetworkUnavailableException
import bou.amine.apps.readerforselfossv2.model.SelfossModel
import bou.amine.apps.readerforselfossv2.repository.Repository
@ -76,13 +75,7 @@ class UpsertSourceActivity :
override fun onResume() {
super.onResume()
val baseUrl = appSettingsService.getBaseUrl()
if (baseUrl.isEmpty() || baseUrl.isBaseUrlInvalid()) {
mustLoginToAddSource()
} else {
handleSpoutsSpinner()
}
handleSpoutsSpinner()
}
@Suppress("detekt:SwallowedException")

View File

@ -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 =

View File

@ -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

View File

@ -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

View File

@ -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) {

View File

@ -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)
// trick: for the same plugin versions in all sub-modules
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)
}
@ -24,4 +23,4 @@ tasks.register("clean", Delete::class) {
dependencies {
kover(project(":shared"))
kover(project(":androidApp"))
}
}

View File

@ -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.

View File

@ -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

View File

@ -0,0 +1,4 @@
**v125020581**
- fix: url can be empty ?
- Changelog for v125020471

View File

@ -19,11 +19,11 @@ 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
org.gradle.caching=true
ignoreGitVersion=false
kotlin.native.cacheKind.iosX64=none
org.gradle.configureondemand=true
org.gradle.configureondemand=true

View File

@ -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

View File

@ -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("&amp;url=")) {
link.substringAfter("&amp;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 {