Merge pull request 'Sources Upsert' (#119) from sources-edit into master
Some checks failed
continuous-integration/drone/push Build is passing
continuous-integration/drone Build is failing

Reviewed-on: https://gitea.amine-louveau.fr/Louvorg/ReaderForSelfoss-multiplatform/pulls/119
This commit is contained in:
Amine Louveau 2022-12-28 21:31:49 +00:00
commit 89992967be
33 changed files with 258 additions and 102 deletions

View File

@ -52,7 +52,7 @@
android:value=".HomeActivity" />
</activity>
<activity
android:name=".AddSourceActivity"
android:name=".UpsertSourceActivity"
android:parentActivityName=".SourcesActivity"
android:exported="true">
<meta-data

View File

@ -603,6 +603,10 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
settingsLauncher.launch(Intent(this, SettingsActivity::class.java))
return true
}
R.id.action_sources -> {
startActivity(Intent(this, SourcesActivity::class.java))
return true
}
else -> return super.onOptionsItemSelected(item)
}
}

View File

@ -73,7 +73,7 @@ class SourcesActivity : AppCompatActivity(), DIAware {
}
binding.fab.setOnClickListener {
startActivity(Intent(this@SourcesActivity, AddSourceActivity::class.java))
startActivity(Intent(this@SourcesActivity, UpsertSourceActivity::class.java))
}
}
}

View File

@ -3,12 +3,15 @@ package bou.amine.apps.readerforselfossv2.android
import android.content.Intent
import android.os.Bundle
import android.view.View
import android.widget.*
import android.widget.AdapterView
import android.widget.ArrayAdapter
import android.widget.TextView
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.constraintlayout.widget.ConstraintLayout
import bou.amine.apps.readerforselfossv2.android.databinding.ActivityAddSourceBinding
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
import bou.amine.apps.readerforselfossv2.service.AppSettingsService
import kotlinx.coroutines.CoroutineScope
@ -19,38 +22,59 @@ import org.kodein.di.android.closestDI
import org.kodein.di.instance
class AddSourceActivity : AppCompatActivity(), DIAware {
class UpsertSourceActivity : AppCompatActivity(), DIAware {
private var existingSource: SelfossModel.Source? = null
private var mSpoutsValue: String? = null
private lateinit var binding: ActivityAddSourceBinding
private lateinit var binding: ActivityUpsertSourceBinding
override val di by closestDI()
private val repository : Repository by instance()
private val appSettingsService : AppSettingsService by instance()
private val repository: Repository by instance()
private val appSettingsService: AppSettingsService by instance()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityAddSourceBinding.inflate(layoutInflater)
binding = ActivityUpsertSourceBinding.inflate(layoutInflater)
val view = binding.root
existingSource = repository.getSelectedSource()
if (existingSource != null) {
binding.formContainer.visibility = View.GONE
binding.progress.visibility = View.VISIBLE
}
val title = if (existingSource == null) R.string.add_source else R.string.update_source
supportFragmentManager.addOnBackStackChangedListener {
if (supportFragmentManager.backStackEntryCount == 0) {
setTitle(title)
}
}
setContentView(view)
setSupportActionBar(binding.toolbar)
supportActionBar?.setDisplayHomeAsUpEnabled(true)
supportActionBar?.setDisplayShowHomeEnabled(true)
supportActionBar?.title = resources.getString(title)
maybeGetDetailsFromIntentSharing(intent, binding.sourceUri, binding.nameInput)
maybeGetDetailsFromIntentSharing(intent)
binding.saveBtn.setOnClickListener {
handleSaveSource(
binding.tags,
binding.nameInput.text.toString(),
binding.sourceUri.text.toString()
)
handleSaveSource()
}
}
private fun initFields(items: Map<String, SelfossModel.Spout>) {
binding.nameInput.setText(existingSource!!.title)
binding.tags.setText(existingSource!!.tags.joinToString(", "))
binding.sourceUri.setText(existingSource!!.params?.url)
binding.spoutsSpinner.setSelection(items.keys.indexOf(existingSource!!.spout))
binding.progress.visibility = View.GONE
binding.formContainer.visibility = View.VISIBLE
}
override fun onResume() {
super.onResume()
@ -58,17 +82,13 @@ class AddSourceActivity : AppCompatActivity(), DIAware {
if (baseUrl.isEmpty() || baseUrl.isBaseUrlInvalid()) {
mustLoginToAddSource()
} else {
handleSpoutsSpinner(binding.spoutsSpinner, binding.progress, binding.formContainer)
handleSpoutsSpinner()
}
}
private fun handleSpoutsSpinner(
spoutsSpinner: Spinner,
mProgress: ProgressBar,
formContainer: ConstraintLayout
) {
private fun handleSpoutsSpinner() {
val spoutsKV = HashMap<String, String>()
spoutsSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
binding.spoutsSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
override fun onItemSelected(adapterView: AdapterView<*>, view: View?, i: Int, l: Long) {
if (view != null) {
val spoutName = (view as TextView).text.toString()
@ -84,11 +104,11 @@ class AddSourceActivity : AppCompatActivity(), DIAware {
fun handleSpoutFailure(networkIssue: Boolean = false) {
Toast.makeText(
this@AddSourceActivity,
this@UpsertSourceActivity,
if (networkIssue) R.string.cant_get_spouts_no_network else R.string.cant_get_spouts,
Toast.LENGTH_SHORT
).show()
mProgress.visibility = View.GONE
binding.progress.visibility = View.GONE
}
CoroutineScope(Dispatchers.Main).launch {
@ -100,17 +120,21 @@ class AddSourceActivity : AppCompatActivity(), DIAware {
spoutsKV[value.name] = key
}
mProgress.visibility = View.GONE
formContainer.visibility = View.VISIBLE
binding.progress.visibility = View.GONE
binding.formContainer.visibility = View.VISIBLE
val spinnerArrayAdapter =
ArrayAdapter(
this@AddSourceActivity,
this@UpsertSourceActivity,
android.R.layout.simple_spinner_item,
itemsStrings
)
spinnerArrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
spoutsSpinner.adapter = spinnerArrayAdapter
binding.spoutsSpinner.adapter = spinnerArrayAdapter
if (existingSource != null) {
initFields(items)
}
} else {
handleSpoutFailure()
}
@ -121,13 +145,11 @@ class AddSourceActivity : AppCompatActivity(), DIAware {
}
private fun maybeGetDetailsFromIntentSharing(
intent: Intent,
sourceUri: EditText,
nameInput: EditText
intent: Intent
) {
if (Intent.ACTION_SEND == intent.action && "text/plain" == intent.type) {
sourceUri.setText(intent.getStringExtra(Intent.EXTRA_TEXT))
nameInput.setText(intent.getStringExtra(Intent.EXTRA_TITLE))
binding.sourceUri.setText(intent.getStringExtra(Intent.EXTRA_TEXT))
binding.nameInput.setText(intent.getStringExtra(Intent.EXTRA_TITLE))
}
}
@ -138,7 +160,8 @@ class AddSourceActivity : AppCompatActivity(), DIAware {
finish()
}
private fun handleSaveSource(tags: EditText, title: String, url: String) {
private fun handleSaveSource() {
val url = binding.sourceUri.text.toString()
val sourceDetailsUnavailable =
title.isEmpty() || url.isEmpty() || mSpoutsValue == null || mSpoutsValue!!.isEmpty()
@ -149,18 +172,27 @@ class AddSourceActivity : AppCompatActivity(), DIAware {
}
else -> {
CoroutineScope(Dispatchers.Main).launch {
val successfullyAddedSource = repository.createSource(
title,
val successfullyAddedSource = if (existingSource != null) {
repository.updateSource(
existingSource!!.id,
binding.nameInput.text.toString(),
url,
mSpoutsValue!!,
tags.text.toString(),
"",
binding.tags.text.toString()
)
} else {
repository.createSource(
binding.nameInput.text.toString(),
url,
mSpoutsValue!!,
binding.tags.text.toString(),
)
}
if (successfullyAddedSource) {
finish()
} else {
Toast.makeText(
this@AddSourceActivity,
this@UpsertSourceActivity,
R.string.cant_create_source,
Toast.LENGTH_SHORT
).show()
@ -169,4 +201,9 @@ class AddSourceActivity : AppCompatActivity(), DIAware {
}
}
}
override fun onDestroy() {
super.onDestroy()
repository.unsetSelectedSource()
}
}

View File

@ -2,12 +2,14 @@ package bou.amine.apps.readerforselfossv2.android.adapters
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.view.LayoutInflater
import android.view.ViewGroup
import android.widget.Button
import android.widget.Toast
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.recyclerview.widget.RecyclerView
import bou.amine.apps.readerforselfossv2.android.UpsertSourceActivity
import bou.amine.apps.readerforselfossv2.android.R
import bou.amine.apps.readerforselfossv2.android.databinding.SourceListItemBinding
import bou.amine.apps.readerforselfossv2.android.model.toTextDrawableString
@ -94,6 +96,14 @@ class SourcesListAdapter(
}
}
}
mView.setOnClickListener {
val source = items[bindingAdapterPosition]
repository.setSelectedSource(source)
app.startActivity(Intent(app, UpsertSourceActivity::class.java))
}
}
}
}

View File

@ -4,7 +4,7 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="bou.amine.apps.readerforselfossv2.android.AddSourceActivity">
tools:context="bou.amine.apps.readerforselfossv2.android.UpsertSourceActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
@ -41,36 +41,20 @@
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintVertical_bias="0.0">
<TextView
android:text="@string/add_source"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/textView2"
android:textAppearance="@style/TextAppearance.AppCompat.Large"
android:textAlignment="center"
android:layout_marginTop="16dp"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginEnd="16dp"
app:layout_constraintRight_toRightOf="parent"
android:layout_marginRight="16dp"
android:layout_marginStart="16dp"
app:layout_constraintLeft_toLeftOf="parent"
android:layout_marginLeft="16dp"
android:gravity="center_horizontal" />
<EditText
android:id="@+id/nameInput"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:autofillHints="false"
android:ems="10"
android:id="@+id/nameInput"
android:layout_marginTop="32dp"
app:layout_constraintTop_toBottomOf="@+id/textView2"
android:hint="@string/add_source_hint_name"
android:inputType="text"
android:textColorHint="?android:textColorPrimary"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
android:inputType="text"
android:hint="@string/add_source_hint_name"
android:textColorHint="?android:textColorPrimary"
android:autofillHints="false" />
app:layout_constraintTop_toTopOf="parent" />
<EditText
android:layout_width="match_parent"

View File

@ -20,6 +20,11 @@
android:orderInCategory="2"
app:showAsAction="ifRoom"/>
<item android:id="@+id/action_sources"
android:title="@string/menu_home_sources"
android:orderInCategory="97"
app:showAsAction="never"/>
<item android:id="@+id/action_settings"
android:title="@string/title_activity_settings"
android:orderInCategory="98"

View File

@ -126,4 +126,6 @@
<string name="pref_switch_disable_acra">"Disable automatic bug reporting. "</string>
<string name="menu_home_filter">Filters</string>
<string name="application_selfoss_only">This app only works with a Selfoss instance, and no other RSS feed.</string>
<string name="menu_home_sources">Sources</string>
<string name="update_source">Update source</string>
</resources>

View File

@ -126,4 +126,6 @@
<string name="pref_switch_disable_acra">"Disable automatic bug reporting. "</string>
<string name="menu_home_filter">Filters</string>
<string name="application_selfoss_only">This app only works with a Selfoss instance, and no other RSS feed.</string>
<string name="menu_home_sources">Sources</string>
<string name="update_source">Update source</string>
</resources>

View File

@ -126,4 +126,6 @@
<string name="pref_switch_disable_acra">"Disable automatic bug reporting. "</string>
<string name="menu_home_filter">Filters</string>
<string name="application_selfoss_only">This app only works with a Selfoss instance, and no other RSS feed.</string>
<string name="menu_home_sources">Sources</string>
<string name="update_source">Update source</string>
</resources>

View File

@ -126,4 +126,6 @@
<string name="pref_switch_disable_acra">"Disable automatic bug reporting. "</string>
<string name="menu_home_filter">Filters</string>
<string name="application_selfoss_only">This app only works with a Selfoss instance, and no other RSS feed.</string>
<string name="menu_home_sources">Sources</string>
<string name="update_source">Update source</string>
</resources>

View File

@ -126,4 +126,6 @@
<string name="pref_switch_disable_acra">"Disable automatic bug reporting. "</string>
<string name="menu_home_filter">Filters</string>
<string name="application_selfoss_only">This app only works with a Selfoss instance, and no other RSS feed.</string>
<string name="menu_home_sources">Sources</string>
<string name="update_source">Update source</string>
</resources>

View File

@ -126,4 +126,6 @@
<string name="pref_switch_disable_acra">"Disable automatic bug reporting. "</string>
<string name="menu_home_filter">Filters</string>
<string name="application_selfoss_only">This app only works with a Selfoss instance, and no other RSS feed.</string>
<string name="menu_home_sources">Sources</string>
<string name="update_source">Update source</string>
</resources>

View File

@ -126,4 +126,6 @@
<string name="pref_switch_disable_acra">"Disable automatic bug reporting. "</string>
<string name="menu_home_filter">Filters</string>
<string name="application_selfoss_only">This app only works with a Selfoss instance, and no other RSS feed.</string>
<string name="menu_home_sources">Sources</string>
<string name="update_source">Update source</string>
</resources>

View File

@ -126,4 +126,6 @@
<string name="pref_switch_disable_acra">"Disable automatic bug reporting. "</string>
<string name="menu_home_filter">Filters</string>
<string name="application_selfoss_only">This app only works with a Selfoss instance, and no other RSS feed.</string>
<string name="menu_home_sources">Sources</string>
<string name="update_source">Update source</string>
</resources>

View File

@ -126,4 +126,6 @@
<string name="pref_switch_disable_acra">"Disable automatic bug reporting. "</string>
<string name="menu_home_filter">Filters</string>
<string name="application_selfoss_only">This app only works with a Selfoss instance, and no other RSS feed.</string>
<string name="menu_home_sources">Sources</string>
<string name="update_source">Update source</string>
</resources>

View File

@ -6,4 +6,6 @@
<string name="pref_switch_disable_acra">"Disable automatic bug reporting. "</string>
<string name="menu_home_filter">Filters</string>
<string name="application_selfoss_only">This app only works with a Selfoss instance, and no other RSS feed.</string>
<string name="menu_home_sources">Sources</string>
<string name="update_source">Update source</string>
</resources>

View File

@ -126,4 +126,6 @@
<string name="pref_switch_disable_acra">"Disable automatic bug reporting. "</string>
<string name="menu_home_filter">Filters</string>
<string name="application_selfoss_only">This app only works with a Selfoss instance, and no other RSS feed.</string>
<string name="menu_home_sources">Sources</string>
<string name="update_source">Update source</string>
</resources>

View File

@ -126,4 +126,6 @@
<string name="pref_switch_disable_acra">"Disable automatic bug reporting. "</string>
<string name="menu_home_filter">Filters</string>
<string name="application_selfoss_only">This app only works with a Selfoss instance, and no other RSS feed.</string>
<string name="menu_home_sources">Sources</string>
<string name="update_source">Update source</string>
</resources>

View File

@ -126,4 +126,6 @@
<string name="pref_switch_disable_acra">"Disable automatic bug reporting. "</string>
<string name="menu_home_filter">Filters</string>
<string name="application_selfoss_only">This app only works with a Selfoss instance, and no other RSS feed.</string>
<string name="menu_home_sources">Sources</string>
<string name="update_source">Update source</string>
</resources>

View File

@ -126,4 +126,6 @@
<string name="pref_switch_disable_acra">"Disable automatic bug reporting. "</string>
<string name="menu_home_filter">Filters</string>
<string name="application_selfoss_only">This app only works with a Selfoss instance, and no other RSS feed.</string>
<string name="menu_home_sources">Sources</string>
<string name="update_source">Update source</string>
</resources>

View File

@ -126,4 +126,6 @@
<string name="pref_switch_disable_acra">"Disable automatic bug reporting. "</string>
<string name="menu_home_filter">Filters</string>
<string name="application_selfoss_only">This app only works with a Selfoss instance, and no other RSS feed.</string>
<string name="menu_home_sources">Sources</string>
<string name="update_source">Update source</string>
</resources>

View File

@ -126,4 +126,6 @@
<string name="pref_switch_disable_acra">"禁用自动错误报告 "</string>
<string name="menu_home_filter">筛选器</string>
<string name="application_selfoss_only">This app only works with a Selfoss instance, and no other RSS feed.</string>
<string name="menu_home_sources">Sources</string>
<string name="update_source">Update source</string>
</resources>

View File

@ -126,4 +126,6 @@
<string name="pref_switch_disable_acra">"Disable automatic bug reporting. "</string>
<string name="menu_home_filter">Filters</string>
<string name="application_selfoss_only">This app only works with a Selfoss instance, and no other RSS feed.</string>
<string name="menu_home_sources">Sources</string>
<string name="update_source">Update source</string>
</resources>

View File

@ -129,4 +129,6 @@
<string name="pref_switch_disable_acra">"Disable automatic bug reporting. "</string>
<string name="menu_home_filter">Filters</string>
<string name="application_selfoss_only">This app only works with a Selfoss instance, and no other RSS feed.</string>
<string name="menu_home_sources">Sources</string>
<string name="update_source">Update source</string>
</resources>

View File

@ -231,7 +231,8 @@ class RepositoryTest {
listOf("tags"),
"spouts\\rss\\fulltextrss",
"",
"b3aa8a664d08eb15d6ff1db2fa83e0d9.png"
"b3aa8a664d08eb15d6ff1db2fa83e0d9.png",
SelfossModel.SourceParams("url")
))
runBlocking {
repository.getNewerItems()
@ -551,7 +552,8 @@ class RepositoryTest {
listOf("Test", "second"),
"spouts\\rss\\fulltextrss",
"",
"d8c92cdb1ef119ea85c4b9205c879ca7.png"
"d8c92cdb1ef119ea85c4b9205c879ca7.png",
SelfossModel.SourceParams("url")
),
SelfossModel.Source(
2,
@ -559,7 +561,8 @@ class RepositoryTest {
listOf("second"),
"spouts\\rss\\fulltextrss",
"",
"b3aa8a664d08eb15d6ff1db2fa83e0d9.png"
"b3aa8a664d08eb15d6ff1db2fa83e0d9.png",
SelfossModel.SourceParams("url")
)
)
val sourcesDB = listOf(
@ -569,7 +572,8 @@ class RepositoryTest {
"Test,second",
"spouts\\rss\\fulltextrss",
"",
"d8c92cdb1ef119ea85c4b9205c879ca7.png"
"d8c92cdb1ef119ea85c4b9205c879ca7.png",
"url"
),
SOURCE(
"2",
@ -577,7 +581,8 @@ class RepositoryTest {
"second",
"spouts\\rss\\fulltextrss",
"",
"b3aa8a664d08eb15d6ff1db2fa83e0d9.png"
"b3aa8a664d08eb15d6ff1db2fa83e0d9.png",
"url"
)
)
@ -707,7 +712,7 @@ class RepositoryTest {
@Test
fun create_source() {
coEvery { api.createSourceForVersion(any(), any(), any(), any(), any()) } returns
coEvery { api.createSourceForVersion(any(), any(), any(), any()) } returns
SuccessResponse(true)
initializeRepository()
@ -718,7 +723,6 @@ class RepositoryTest {
"https://test.com/feed",
"spouts\\rss\\fulltextrss",
"Test, New",
""
)
}
@ -728,7 +732,6 @@ class RepositoryTest {
any(),
any(),
any(),
any(),
)
}
assertSame(true, response)
@ -736,7 +739,7 @@ class RepositoryTest {
@Test
fun create_source_but_response_fails() {
coEvery { api.createSourceForVersion(any(), any(), any(), any(), any()) } returns
coEvery { api.createSourceForVersion(any(), any(), any(), any()) } returns
SuccessResponse(false)
initializeRepository()
@ -746,8 +749,7 @@ class RepositoryTest {
"test",
"https://test.com/feed",
"spouts\\rss\\fulltextrss",
"Test, New",
""
"Test, New"
)
}
@ -756,8 +758,7 @@ class RepositoryTest {
any(),
any(),
any(),
any(),
any(),
any()
)
}
assertSame(false, response)
@ -765,7 +766,7 @@ class RepositoryTest {
@Test
fun create_source_without_connection() {
coEvery { api.createSourceForVersion(any(), any(), any(), any(), any()) } returns
coEvery { api.createSourceForVersion(any(), any(), any(), any()) } returns
SuccessResponse(true)
initializeRepository(MutableStateFlow(false))
@ -775,8 +776,7 @@ class RepositoryTest {
"test",
"https://test.com/feed",
"spouts\\rss\\fulltextrss",
"Test, New",
""
"Test, New"
)
}
@ -786,7 +786,6 @@ class RepositoryTest {
any(),
any(),
any(),
any()
)
}
assertSame(false, response)
@ -1034,7 +1033,8 @@ class RepositoryTest {
listOf("Test", "second"),
"spouts\\rss\\fulltextrss",
"",
"d8c92cdb1ef119ea85c4b9205c879ca7.png"
"d8c92cdb1ef119ea85c4b9205c879ca7.png",
SelfossModel.SourceParams("url")
)
)
repository.searchFilter = "search"

View File

@ -9,6 +9,7 @@ import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
import kotlinx.serialization.encoding.encodeCollection
import kotlinx.serialization.json.*
class SelfossModel {
@ -55,7 +56,12 @@ class SelfossModel {
val tags: List<String>,
val spout: String,
val error: String,
val icon: String?
val icon: String?,
val params: SourceParams?
)
@Serializable
data class SourceParams(
val url: String
)
@Serializable
data class Item(
@ -122,7 +128,7 @@ class SelfossModel {
object TagsListSerializer : KSerializer<List<String>> {
override fun deserialize(decoder: Decoder): List<String> {
return when(val json = ((decoder as JsonDecoder).decodeJsonElement())) {
is JsonArray -> json.toList().map { it.toString() }
is JsonArray -> json.toList().map { it.toString().replace("^\"|\"$".toRegex(), "") }
else -> json.toString().split(",")
}
@ -132,7 +138,7 @@ class SelfossModel {
get() = PrimitiveSerialDescriptor("tags", PrimitiveKind.STRING)
override fun serialize(encoder: Encoder, value: List<String>) {
TODO("Not yet implemented")
encoder.encodeCollection(PrimitiveSerialDescriptor("tags", PrimitiveKind.STRING), value.size) { this.toString() }
}
}

View File

@ -48,6 +48,7 @@ class Repository(
private var fetchedTags = false
private var _readerItems = ArrayList<SelfossModel.Item>()
private var _selectedSource: SelfossModel.Source? = null
suspend fun getNewerItems(): ArrayList<SelfossModel.Item> {
// TODO: Use the updatedSince parameter
@ -343,7 +344,6 @@ class Repository(
url: String,
spout: String,
tags: String,
filter: String
): Boolean {
var response = false
if (isNetworkAvailable()) {
@ -352,13 +352,27 @@ class Repository(
url,
spout,
tags,
filter
).isSuccess == true
}
return response
}
suspend fun updateSource(
id: Int,
title: String,
url: String,
spout: String,
tags: String
): Boolean {
var response = false
if (isNetworkAvailable()) {
response = api.updateSourceForVersion(id, title, url, spout, tags).isSuccess == true
}
return response
}
suspend fun deleteSource(id: Int, title: String): Boolean {
var success = false
if (isNetworkAvailable()) {
@ -580,4 +594,16 @@ class Repository(
fun migrate(driverFactory: DriverFactory) {
ReaderForSelfossDB.Schema.migrate(driverFactory.createDriver(), 0, 1)
}
fun setSelectedSource(source: SelfossModel.Source) {
_selectedSource = source
}
fun unsetSelectedSource() {
_selectedSource = null
}
fun getSelectedSource(): SelfossModel.Source? {
return _selectedSource
}
}

View File

@ -23,6 +23,9 @@ suspend fun maybeResponse(r: HttpResponse?): SuccessResponse {
return if (r != null && r.status.isSuccess()) {
r.body()
} else {
if (r != null) {
Napier.i("Error ${r.status}", tag = "maybeResponse")
}
SuccessResponse(false)
}
}

View File

@ -76,10 +76,14 @@ class SelfossApi(private val appSettingsService: AppSettingsService) {
// Api version was introduces after the POST login, so when there is a version, it should be available
private fun shouldHavePostLogin() = appSettingsService.getApiVersion() != -1
private fun hasLoginInfo() = appSettingsService.getUserName().isNotEmpty() && appSettingsService.getPassword().isNotEmpty()
private fun hasLoginInfo() =
appSettingsService.getUserName().isNotEmpty() && appSettingsService.getPassword()
.isNotEmpty()
suspend fun login(): SuccessResponse =
if (appSettingsService.getUserName().isNotEmpty() && appSettingsService.getPassword().isNotEmpty()) {
if (appSettingsService.getUserName().isNotEmpty() && appSettingsService.getPassword()
.isNotEmpty()
) {
if (shouldHavePostLogin()) {
postLogin()
} else {
@ -99,7 +103,9 @@ class SelfossApi(private val appSettingsService: AppSettingsService) {
parameter("password", appSettingsService.getPassword())
})
private fun shouldHaveNewLogout() = appSettingsService.getApiVersion() >= 5 // We are missing 4.1.0
private fun shouldHaveNewLogout() =
appSettingsService.getApiVersion() >= 5 // We are missing 4.1.0
suspend fun logout(): SuccessResponse =
if (shouldHaveNewLogout()) {
doLogout()
@ -107,7 +113,8 @@ class SelfossApi(private val appSettingsService: AppSettingsService) {
maybeLogoutIfAvailable()
}
private suspend fun maybeLogoutIfAvailable() = responseOrSuccessIf404(client.tryToGet(url("/logout")))
private suspend fun maybeLogoutIfAvailable() =
responseOrSuccessIf404(client.tryToGet(url("/logout")))
private suspend fun doLogout() = maybeResponse(client.tryToDelete(url("/api/session/current")))
@ -236,13 +243,12 @@ class SelfossApi(private val appSettingsService: AppSettingsService) {
url: String,
spout: String,
tags: String,
filter: String
): SuccessResponse =
maybeResponse(
if (appSettingsService.getApiVersion() > 1) {
createSource("tags[]", title, url, spout, tags, filter)
createSource("tags[]", title, url, spout, tags)
} else {
createSource("tags", title, url, spout, tags, filter)
createSource("tags", title, url, spout, tags)
}
)
@ -251,8 +257,7 @@ class SelfossApi(private val appSettingsService: AppSettingsService) {
title: String,
url: String,
spout: String,
tags: String,
filter: String
tags: String
): HttpResponse? =
client.tryToSubmitForm(
url = url("/source"),
@ -265,7 +270,43 @@ class SelfossApi(private val appSettingsService: AppSettingsService) {
append("url", url)
append("spout", spout)
append(tagsParamName, tags)
append("filter", filter)
}
)
suspend fun updateSourceForVersion(
id: Int,
title: String,
url: String,
spout: String,
tags: String
): SuccessResponse =
maybeResponse(
if (appSettingsService.getApiVersion() > 1) {
updateSource(id, "tags[]", title, url, spout, tags)
} else {
updateSource(id, "tags", title, url, spout, tags)
}
)
private suspend fun updateSource(
id: Int,
tagsParamName: String,
title: String,
url: String,
spout: String,
tags: String,
): HttpResponse? =
client.tryToSubmitForm(
url = url("/source/$id"),
formParameters = Parameters.build {
if (!shouldHavePostLogin()) {
append("username", appSettingsService.getUserName())
append("password", appSettingsService.getPassword())
}
append("title", title)
append("url", url)
append("spout", spout)
append(tagsParamName, tags)
}
)

View File

@ -19,7 +19,8 @@ fun SOURCE.toView(): SelfossModel.Source =
this.tags.split(","),
this.spout,
this.error,
this.icon
this.icon,
if (this.url != null) SelfossModel.SourceParams(this.url) else null
)
fun SelfossModel.Source.toEntity(): SOURCE =
@ -29,7 +30,8 @@ fun SelfossModel.Source.toEntity(): SOURCE =
this.tags.joinToString(","),
this.spout,
this.error,
this.icon.orEmpty()
this.icon.orEmpty(),
this.params?.url
)
fun SelfossModel.Tag.toEntity(): TAG =

View File

@ -0,0 +1 @@
ALTER TABLE SOURCE ADD COLUMN `url` TEXT;

View File

@ -5,6 +5,7 @@ CREATE TABLE SOURCE (
`spout` TEXT NOT NULL,
`error` TEXT NOT NULL,
`icon` TEXT NOT NULL,
`url` TEXT,
PRIMARY KEY(`id`)
);