Compare commits
	
		
			13 Commits
		
	
	
		
			27eafe4ff4
			...
			v122123631
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					cc4c1c9201 | ||
| 
						 | 
					ff021d572c | ||
| 
						 | 
					89992967be | ||
| 
						 | 
					3c68bde62b | ||
| 
						 | 
					c38251f5b3 | ||
| 
						 | 
					a01f6d2322 | ||
| 
						 | 
					417a33eb25 | ||
| 
						 | 
					2e7f7f23b3 | ||
| 
						 | 
					e5e182761e | ||
| 
						 | 
					a094d88799 | ||
| e51915d1cd | |||
| 3a654f6ede | |||
| 5227751dca | 
							
								
								
									
										10
									
								
								.drone.yml
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								.drone.yml
									
									
									
									
									
								
							@@ -35,7 +35,6 @@ steps:
 | 
			
		||||
trigger:
 | 
			
		||||
  event:
 | 
			
		||||
    - push
 | 
			
		||||
    - pull_request
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
kind: pipeline
 | 
			
		||||
@@ -43,12 +42,19 @@ type: docker
 | 
			
		||||
name: Publish
 | 
			
		||||
 | 
			
		||||
steps:
 | 
			
		||||
  - name: createTag
 | 
			
		||||
  - name: createTagAndChangelog
 | 
			
		||||
    image: ubuntu:latest
 | 
			
		||||
    commands:
 | 
			
		||||
      - apt-get update && apt-get install -y git
 | 
			
		||||
      - git fetch --tags -p
 | 
			
		||||
      - VER=$(git describe --tags --abbrev=0)
 | 
			
		||||
      - CHANGELOG=$(git log $VER..HEAD --pretty="- %s")
 | 
			
		||||
      - echo "**$VER**\n\n$CHANGELOG\n\n--------------------------------------------------------------------\n\n$(cat CHANGELOG.md)" > CHANGELOG.md
 | 
			
		||||
      - git add CHANGELOG.md
 | 
			
		||||
      - git commit -m "Changelog for $VER"
 | 
			
		||||
      - ./build.sh --publish --from-ci
 | 
			
		||||
      - git remote add pushing https://$GITEA_USR:$GITEA_PASS@gitea.amine-louveau.fr/Louvorg/ReaderForSelfoss-multiplatform.git
 | 
			
		||||
      - git push pushing master
 | 
			
		||||
      - git push pushing --tags
 | 
			
		||||
    environment:
 | 
			
		||||
      TZ: Europe/Paris
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										10
									
								
								CHANGELOG.md
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								CHANGELOG.md
									
									
									
									
									
								
							@@ -1,3 +1,13 @@
 | 
			
		||||
**v122123621**
 | 
			
		||||
 | 
			
		||||
- fix: Automatic CHANGELOG generation.
 | 
			
		||||
- Merge pull request 'Sources Upsert' (#119) from sources-edit into master
 | 
			
		||||
- Source update screen.
 | 
			
		||||
- Sources menu.
 | 
			
		||||
- chore: Automatic CHANGELOG generation.
 | 
			
		||||
 | 
			
		||||
--------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
# V2/Multiplatform rewrite
 | 
			
		||||
 | 
			
		||||
**v1**
 | 
			
		||||
 
 | 
			
		||||
@@ -52,7 +52,7 @@
 | 
			
		||||
                android:value=".HomeActivity" />
 | 
			
		||||
        </activity>
 | 
			
		||||
        <activity
 | 
			
		||||
            android:name=".AddSourceActivity"
 | 
			
		||||
            android:name=".UpsertSourceActivity"
 | 
			
		||||
            android:parentActivityName=".SourcesActivity"
 | 
			
		||||
            android:exported="true">
 | 
			
		||||
            <meta-data
 | 
			
		||||
 
 | 
			
		||||
@@ -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)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -3,10 +3,7 @@ package bou.amine.apps.readerforselfossv2.android
 | 
			
		||||
import android.app.NotificationChannel
 | 
			
		||||
import android.app.NotificationManager
 | 
			
		||||
import android.content.Context
 | 
			
		||||
import android.graphics.drawable.Drawable
 | 
			
		||||
import android.net.Uri
 | 
			
		||||
import android.os.Build
 | 
			
		||||
import android.widget.ImageView
 | 
			
		||||
import android.widget.Toast
 | 
			
		||||
import androidx.lifecycle.DefaultLifecycleObserver
 | 
			
		||||
import androidx.lifecycle.LifecycleOwner
 | 
			
		||||
@@ -18,8 +15,6 @@ import bou.amine.apps.readerforselfossv2.dao.DriverFactory
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.dao.ReaderForSelfossDB
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.repository.Repository
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.service.AppSettingsService
 | 
			
		||||
import com.bumptech.glide.Glide
 | 
			
		||||
import com.bumptech.glide.request.RequestOptions
 | 
			
		||||
import com.github.ln_12.library.ConnectivityStatus
 | 
			
		||||
import io.github.aakira.napier.DebugAntilog
 | 
			
		||||
import io.github.aakira.napier.Napier
 | 
			
		||||
@@ -83,6 +78,8 @@ class MyApp : MultiDexApplication(), DIAware {
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        repository.migrate(driverFactory)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun attachBaseContext(base: Context?) {
 | 
			
		||||
 
 | 
			
		||||
@@ -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))
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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,
 | 
			
		||||
                        url,
 | 
			
		||||
                        mSpoutsValue!!,
 | 
			
		||||
                        tags.text.toString(),
 | 
			
		||||
                        "",
 | 
			
		||||
                    )
 | 
			
		||||
                    val successfullyAddedSource = if (existingSource != null) {
 | 
			
		||||
                        repository.updateSource(
 | 
			
		||||
                            existingSource!!.id,
 | 
			
		||||
                            binding.nameInput.text.toString(),
 | 
			
		||||
                            url,
 | 
			
		||||
                            mSpoutsValue!!,
 | 
			
		||||
                            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()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -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))
 | 
			
		||||
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -46,7 +46,7 @@ data class ParecelableItem(
 | 
			
		||||
    val link: String,
 | 
			
		||||
    val sourcetitle: String,
 | 
			
		||||
    val tags: String,
 | 
			
		||||
    val author: String
 | 
			
		||||
    val author: String?
 | 
			
		||||
) : Parcelable {
 | 
			
		||||
 | 
			
		||||
    companion object {
 | 
			
		||||
 
 | 
			
		||||
@@ -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"
 | 
			
		||||
@@ -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"
 | 
			
		||||
 
 | 
			
		||||
@@ -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>
 | 
			
		||||
 
 | 
			
		||||
@@ -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>
 | 
			
		||||
 
 | 
			
		||||
@@ -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>
 | 
			
		||||
 
 | 
			
		||||
@@ -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>
 | 
			
		||||
 
 | 
			
		||||
@@ -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>
 | 
			
		||||
 
 | 
			
		||||
@@ -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>
 | 
			
		||||
 
 | 
			
		||||
@@ -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>
 | 
			
		||||
 
 | 
			
		||||
@@ -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>
 | 
			
		||||
 
 | 
			
		||||
@@ -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>
 | 
			
		||||
 
 | 
			
		||||
@@ -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>
 | 
			
		||||
@@ -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>
 | 
			
		||||
 
 | 
			
		||||
@@ -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>
 | 
			
		||||
 
 | 
			
		||||
@@ -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>
 | 
			
		||||
 
 | 
			
		||||
@@ -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>
 | 
			
		||||
 
 | 
			
		||||
@@ -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>
 | 
			
		||||
 
 | 
			
		||||
@@ -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>
 | 
			
		||||
 
 | 
			
		||||
@@ -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>
 | 
			
		||||
 
 | 
			
		||||
@@ -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>
 | 
			
		||||
 
 | 
			
		||||
@@ -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"
 | 
			
		||||
 
 | 
			
		||||
@@ -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(
 | 
			
		||||
@@ -73,7 +79,7 @@ class SelfossModel {
 | 
			
		||||
        val sourcetitle: String,
 | 
			
		||||
        @Serializable(with = TagsListSerializer::class)
 | 
			
		||||
        val tags: List<String>,
 | 
			
		||||
        val author: String
 | 
			
		||||
        val author: String?
 | 
			
		||||
    ) {
 | 
			
		||||
        // TODO: maybe find a better way to handle these kind of urls
 | 
			
		||||
        fun getLinkDecoded(): String {
 | 
			
		||||
@@ -104,7 +110,7 @@ class SelfossModel {
 | 
			
		||||
 | 
			
		||||
        fun sourceAuthorAndDate(): String {
 | 
			
		||||
            var txt = this.sourcetitle.getHtmlDecoded()
 | 
			
		||||
            if (this.author.isNotEmpty()) {
 | 
			
		||||
            if (!this.author.isNullOrBlank()) {
 | 
			
		||||
                txt += " (by ${this.author}) "
 | 
			
		||||
            }
 | 
			
		||||
            txt += DateUtils.parseRelativeDate(this.datetime)
 | 
			
		||||
@@ -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() }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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()) {
 | 
			
		||||
@@ -511,6 +525,7 @@ class Repository(
 | 
			
		||||
            item.link,
 | 
			
		||||
            item.sourcetitle,
 | 
			
		||||
            item.tags.joinToString(","),
 | 
			
		||||
            item.author,
 | 
			
		||||
            item.id.toString()
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
@@ -575,4 +590,20 @@ class Repository(
 | 
			
		||||
    fun getReaderItems(): ArrayList<SelfossModel.Item> {
 | 
			
		||||
        return _readerItems
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    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
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -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)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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)
 | 
			
		||||
            }
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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 =
 | 
			
		||||
 
 | 
			
		||||
@@ -1 +1,6 @@
 | 
			
		||||
ALTER TABLE ITEM ADD COLUMN `author` TEXT NOT NULL;
 | 
			
		||||
CREATE TABLE ITEM_BACKUP AS SELECT `id`, `datetime`, `title`, `content`,
 | 
			
		||||
 `unread`, `starred`, `thumbnail`, `icon`, `link`, `sourcetitle`,
 | 
			
		||||
 `tags` FROM ITEM;
 | 
			
		||||
ALTER TABLE ITEM_BACKUP ADD COLUMN `author` TEXT;
 | 
			
		||||
DROP TABLE ITEM;
 | 
			
		||||
ALTER TABLE ITEM_BACKUP RENAME TO ITEM;
 | 
			
		||||
@@ -0,0 +1 @@
 | 
			
		||||
ALTER TABLE SOURCE ADD COLUMN `url` TEXT;
 | 
			
		||||
@@ -10,7 +10,7 @@ CREATE TABLE ITEM (
 | 
			
		||||
    `link` TEXT NOT NULL,
 | 
			
		||||
    `sourcetitle` TEXT NOT NULL,
 | 
			
		||||
    `tags` TEXT NOT NULL,
 | 
			
		||||
    `author` TEXT NOT NULL,
 | 
			
		||||
    `author` TEXT,
 | 
			
		||||
    PRIMARY KEY(`id`)
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
@@ -31,4 +31,4 @@ deleteItemsWhereSource:
 | 
			
		||||
DELETE FROM ITEM WHERE `sourcetitle` = ?;
 | 
			
		||||
 | 
			
		||||
updateItem:
 | 
			
		||||
UPDATE ITEM SET `datetime` = ?, `title` = ?, `content` = ?, `unread` = ?, `starred` = ?, `thumbnail` = ?, `icon` = ?, `link` = ?, `sourcetitle` = ?, `tags` = ? WHERE `id` = ?;
 | 
			
		||||
UPDATE ITEM SET `datetime` = ?, `title` = ?, `content` = ?, `unread` = ?, `starred` = ?, `thumbnail` = ?, `icon` = ?, `link` = ?, `sourcetitle` = ?, `tags` = ?, `author` = ? WHERE `id` = ?;
 | 
			
		||||
@@ -5,6 +5,7 @@ CREATE TABLE SOURCE (
 | 
			
		||||
    `spout` TEXT NOT NULL,
 | 
			
		||||
    `error` TEXT NOT NULL,
 | 
			
		||||
    `icon` TEXT NOT NULL,
 | 
			
		||||
    `url` TEXT,
 | 
			
		||||
    PRIMARY KEY(`id`)
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user