Compare commits
10 Commits
v125020411
...
4a093fd969
Author | SHA1 | Date | |
---|---|---|---|
4a093fd969 | |||
03ea12000c | |||
f38936f9b4 | |||
a90ccec707 | |||
2564b19726 | |||
61c7bb20cc | |||
6a0f5baf0a | |||
39f9505c00 | |||
6a6d447456 | |||
0bb4fe6aed |
@ -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
|
||||
|
4
.gitignore
vendored
4
.gitignore
vendored
@ -323,4 +323,6 @@ fabric.properties
|
||||
crowdin.properties
|
||||
|
||||
.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
|
||||
|
||||
- Merge pull request 'fix: Link not opening.' (#178) from fix-open-link into master
|
||||
|
@ -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())
|
||||
|
@ -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(
|
||||
|
@ -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])
|
||||
}
|
||||
},
|
||||
)
|
||||
|
@ -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")
|
||||
|
@ -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) {
|
||||
|
@ -1,7 +1,7 @@
|
||||
plugins {
|
||||
// trick: for the same plugin versions in all sub-modules
|
||||
id("com.android.application").version("8.8.0").apply(false)
|
||||
id("com.android.library").version("8.8.0").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)
|
||||
|
@ -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 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