diff --git a/androidApp/build.gradle.kts b/androidApp/build.gradle.kts index df60d29..ed8c38c 100644 --- a/androidApp/build.gradle.kts +++ b/androidApp/build.gradle.kts @@ -101,6 +101,7 @@ android { kotlinOptions { jvmTarget = "1.8" } + namespace = "bou.amine.apps.readerforselfossv2.android" } diff --git a/androidApp/src/main/AndroidManifest.xml b/androidApp/src/main/AndroidManifest.xml index d46e8e1..21addf9 100644 --- a/androidApp/src/main/AndroidManifest.xml +++ b/androidApp/src/main/AndroidManifest.xml @@ -1,7 +1,6 @@ + xmlns:tools="http://schemas.android.com/tools"> diff --git a/androidApp/src/main/java/bou/amine/apps/readerforselfossv2/android/AddSourceActivity.kt b/androidApp/src/main/java/bou/amine/apps/readerforselfossv2/android/AddSourceActivity.kt index 0c7093c..3cec99e 100644 --- a/androidApp/src/main/java/bou/amine/apps/readerforselfossv2/android/AddSourceActivity.kt +++ b/androidApp/src/main/java/bou/amine/apps/readerforselfossv2/android/AddSourceActivity.kt @@ -9,7 +9,7 @@ import androidx.constraintlayout.widget.ConstraintLayout import bou.amine.apps.readerforselfossv2.android.databinding.ActivityAddSourceBinding import bou.amine.apps.readerforselfossv2.android.themes.AppColors import bou.amine.apps.readerforselfossv2.android.themes.Toppings -import bou.amine.apps.readerforselfossv2.android.utils.isBaseUrlValid +import bou.amine.apps.readerforselfossv2.android.utils.isBaseUrlInvalid import bou.amine.apps.readerforselfossv2.model.NetworkUnavailableException import bou.amine.apps.readerforselfossv2.repository.Repository import bou.amine.apps.readerforselfossv2.service.AppSettingsService @@ -84,7 +84,7 @@ class AddSourceActivity : AppCompatActivity(), DIAware { super.onResume() val baseUrl = appSettingsService.getBaseUrl() - if (baseUrl.isEmpty() || !baseUrl.isBaseUrlValid(this@AddSourceActivity)) { + if (baseUrl.isEmpty() || baseUrl.isBaseUrlInvalid(this@AddSourceActivity)) { mustLoginToAddSource() } else { handleSpoutsSpinner(binding.spoutsSpinner, binding.progress, binding.formContainer) diff --git a/androidApp/src/main/java/bou/amine/apps/readerforselfossv2/android/LoginActivity.kt b/androidApp/src/main/java/bou/amine/apps/readerforselfossv2/android/LoginActivity.kt index c7883b6..bc32762 100644 --- a/androidApp/src/main/java/bou/amine/apps/readerforselfossv2/android/LoginActivity.kt +++ b/androidApp/src/main/java/bou/amine/apps/readerforselfossv2/android/LoginActivity.kt @@ -14,7 +14,7 @@ import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AppCompatActivity import bou.amine.apps.readerforselfossv2.android.databinding.ActivityLoginBinding import bou.amine.apps.readerforselfossv2.android.themes.AppColors -import bou.amine.apps.readerforselfossv2.android.utils.isBaseUrlValid +import bou.amine.apps.readerforselfossv2.android.utils.isBaseUrlInvalid import bou.amine.apps.readerforselfossv2.repository.Repository import bou.amine.apps.readerforselfossv2.service.AppSettingsService import com.mikepenz.aboutlibraries.LibsBuilder @@ -115,14 +115,14 @@ class LoginActivity : AppCompatActivity(), DIAware { binding.passwordView.error = null // Store values at the time of the login attempt. - val url = binding.urlView.text.toString() - val login = binding.loginView.text.toString() - val password = binding.passwordView.text.toString() + val url = binding.urlView.text.toString().trim() + val login = binding.loginView.text.toString().trim() + val password = binding.passwordView.text.toString().trim() var cancel = false var focusView: View? = null - if (!url.isBaseUrlValid(this@LoginActivity)) { + if (url.isBaseUrlInvalid(this@LoginActivity)) { binding.urlView.error = getString(R.string.login_url_problem) focusView = binding.urlView cancel = true diff --git a/androidApp/src/main/java/bou/amine/apps/readerforselfossv2/android/fragments/ArticleFragment.kt b/androidApp/src/main/java/bou/amine/apps/readerforselfossv2/android/fragments/ArticleFragment.kt index f50786a..7e24dea 100644 --- a/androidApp/src/main/java/bou/amine/apps/readerforselfossv2/android/fragments/ArticleFragment.kt +++ b/androidApp/src/main/java/bou/amine/apps/readerforselfossv2/android/fragments/ArticleFragment.kt @@ -268,8 +268,8 @@ class ArticleFragment : Fragment(), DIAware { private fun getContentFromMercury(customTabsIntent: CustomTabsIntent) { if (repository.isNetworkAvailable()) { - binding.progressBar.visibility = View.VISIBLE - val parser = MercuryApi() + binding.progressBar.visibility = View.VISIBLE + val parser = MercuryApi() parser.parseUrl(url).enqueue( object : Callback { diff --git a/androidApp/src/main/java/bou/amine/apps/readerforselfossv2/android/utils/LinksUtils.kt b/androidApp/src/main/java/bou/amine/apps/readerforselfossv2/android/utils/LinksUtils.kt index 1fc608a..600864b 100644 --- a/androidApp/src/main/java/bou/amine/apps/readerforselfossv2/android/utils/LinksUtils.kt +++ b/androidApp/src/main/java/bou/amine/apps/readerforselfossv2/android/utils/LinksUtils.kt @@ -163,7 +163,7 @@ private fun openInBrowser(linkDecoded: String, app: Activity) { fun String.isUrlValid(): Boolean = this.toHttpUrlOrNull() != null && Patterns.WEB_URL.matcher(this).matches() -fun String.isBaseUrlValid(ctx: Context): Boolean { +fun String.isBaseUrlInvalid(ctx: Context): Boolean { val baseUrl = this.toHttpUrlOrNull() var existsAndEndsWithSlash = false if (baseUrl != null) { @@ -171,7 +171,7 @@ fun String.isBaseUrlValid(ctx: Context): Boolean { existsAndEndsWithSlash = "" == pathSegments[pathSegments.size - 1] } - return Patterns.WEB_URL.matcher(this).matches() && existsAndEndsWithSlash + return !(Patterns.WEB_URL.matcher(this).matches() && existsAndEndsWithSlash) } fun Context.openInBrowserAsNewTask(i: SelfossModel.Item) { diff --git a/build.gradle.kts b/build.gradle.kts index 8be2b47..27db859 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -6,7 +6,7 @@ buildscript { } dependencies { classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.10") - classpath("com.android.tools.build:gradle:7.2.2") + classpath("com.android.tools.build:gradle:7.3.0") // sonarquve classpath("org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:3.4.0.2513") diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index e4ddf24..b8c9f22 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ #Wed Feb 09 17:05:19 CET 2022 distributionBase=GRADLE_USER_HOME -distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip distributionPath=wrapper/dists zipStorePath=wrapper/dists zipStoreBase=GRADLE_USER_HOME diff --git a/shared/build.gradle.kts b/shared/build.gradle.kts index 725d301..0a348ad 100644 --- a/shared/build.gradle.kts +++ b/shared/build.gradle.kts @@ -112,6 +112,7 @@ android { sourceCompatibility = JavaVersion.VERSION_1_8 targetCompatibility = JavaVersion.VERSION_1_8 } + namespace = "bou.amine.apps.readerforselfossv2" } sqldelight { diff --git a/shared/src/androidMain/AndroidManifest.xml b/shared/src/androidMain/AndroidManifest.xml index 1829faa..568741e 100644 --- a/shared/src/androidMain/AndroidManifest.xml +++ b/shared/src/androidMain/AndroidManifest.xml @@ -1,2 +1,2 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/model/SelfossModel.kt b/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/model/SelfossModel.kt index 15decfb..e392786 100644 --- a/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/model/SelfossModel.kt +++ b/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/model/SelfossModel.kt @@ -105,4 +105,16 @@ class SelfossModel { return this } } + + class StatusAndData(val success: Boolean, val data: T? = null) { + companion object { + fun succes(d: T): StatusAndData { + return StatusAndData(true, d) + } + + fun error(): StatusAndData { + return StatusAndData(false) + } + } + } } \ No newline at end of file diff --git a/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryImpl.kt b/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryImpl.kt index c970507..db9a789 100644 --- a/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryImpl.kt +++ b/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryImpl.kt @@ -47,7 +47,7 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap suspend fun getNewerItems(): ArrayList { // TODO: Use the updatedSince parameter - var fetchedItems: List? = null + var fetchedItems: SelfossModel.StatusAndData> = SelfossModel.StatusAndData.error() if (isNetworkAvailable()) { fetchedItems = api.getItems( displayedItems.type, @@ -59,23 +59,25 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap ) } else { if (appSettingsService.isItemCachingEnabled()) { - fetchedItems = getDBItems().filter { - displayedItems == ItemType.ALL || - (it.unread && displayedItems == ItemType.UNREAD) || - (it.starred && displayedItems == ItemType.STARRED) - }.map { it.toView() } + fetchedItems = SelfossModel.StatusAndData.succes( + getDBItems().filter { + displayedItems == ItemType.ALL || + (it.unread && displayedItems == ItemType.UNREAD) || + (it.starred && displayedItems == ItemType.STARRED) + }.map { it.toView() } + ) } } - if (fetchedItems != null) { - items = ArrayList(fetchedItems) + if (fetchedItems.success && fetchedItems.data != null) { + items = ArrayList(fetchedItems.data!!) sortItems() } return items } suspend fun getOlderItems(): ArrayList { - var fetchedItems: List? = null + var fetchedItems: SelfossModel.StatusAndData> = SelfossModel.StatusAndData.error() if (isNetworkAvailable()) { val offset = items.size fetchedItems = api.getItems( @@ -88,16 +90,16 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap ) } // When using the db cache, we load everything the first time, so there should be nothing more to load. - if (fetchedItems != null) { - items.addAll(fetchedItems) + if (fetchedItems.success && fetchedItems.data != null) { + items.addAll(fetchedItems.data!!) sortItems() } return items } - private suspend fun getMaxItemsForBackground(itemType: ItemType): List? { + private suspend fun getMaxItemsForBackground(itemType: ItemType): List { return if (isNetworkAvailable()) { - api.getItems( + val items = api.getItems( itemType.type, 0, tagFilter?.tag, @@ -106,6 +108,11 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap null, 200 ) + return if (items.success && items.data != null) { + items.data + } else { + emptyList() + } } else { emptyList() } @@ -119,10 +126,10 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap var success = false if (isNetworkAvailable()) { val response = api.stats() - if (response != null) { - badgeUnread = response.unread - badgeAll = response.total - badgeStarred = response.starred + if (response.success && response.data != null) { + badgeUnread = response.data.unread + badgeAll = response.data.total + badgeStarred = response.data.starred success = true } } else { @@ -138,10 +145,10 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap suspend fun getTags(): List? { return if (isNetworkAvailable()) { val apiTags = api.tags() - if (apiTags != null && (appSettingsService.isItemCachingEnabled() || !appSettingsService.isUpdateSourcesEnabled())) { - resetDBTagsWithData(apiTags) + if (apiTags.success && apiTags.data != null && (appSettingsService.isItemCachingEnabled() || !appSettingsService.isUpdateSourcesEnabled())) { + resetDBTagsWithData(apiTags.data) } - apiTags + apiTags.data } else { getDBTags().map { it.toView() } } @@ -149,7 +156,12 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap suspend fun getSpouts(): Map? { return if (isNetworkAvailable()) { - api.spouts() + val spouts = api.spouts() + return if (spouts.success && spouts.data != null) { + spouts.data + } else { + emptyMap() // TODO: do something here + } } else { throw NetworkUnavailableException() } @@ -158,10 +170,10 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap suspend fun getSources(): ArrayList? { return if (isNetworkAvailable()) { val apiSources = api.sources() - if (apiSources != null && (appSettingsService.isItemCachingEnabled() || !appSettingsService.isUpdateSourcesEnabled())) { - resetDBSourcesWithData(apiSources) + if (apiSources.success && apiSources.data != null && (appSettingsService.isItemCachingEnabled() || !appSettingsService.isUpdateSourcesEnabled())) { + resetDBSourcesWithData(apiSources.data) } - apiSources + apiSources.data } else { ArrayList(getDBSources().map { it.toView() }) } @@ -178,7 +190,7 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap private suspend fun markAsReadById(id: Int): Boolean { return if (isNetworkAvailable()) { - api.markAsRead(id.toString())?.isSuccess == true + api.markAsRead(id.toString())?.isSuccess } else { insertDBAction(id.toString(), read = true) true @@ -197,7 +209,7 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap private suspend fun unmarkAsReadById(id: Int): Boolean { return if (isNetworkAvailable()) { - api.unmarkAsRead(id.toString())?.isSuccess == true + api.unmarkAsRead(id.toString())?.isSuccess } else { insertDBAction(id.toString(), unread = true) true @@ -215,7 +227,7 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap private suspend fun starrById(id: Int): Boolean { return if (isNetworkAvailable()) { - api.starr(id.toString())?.isSuccess == true + api.starr(id.toString())?.isSuccess } else { insertDBAction(id.toString(), starred = true) true @@ -233,7 +245,7 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap private suspend fun unstarrById(id: Int): Boolean { return if (isNetworkAvailable()) { - api.unstarr(id.toString())?.isSuccess == true + api.unstarr(id.toString())?.isSuccess } else { insertDBAction(id.toString(), starred = true) true @@ -243,7 +255,7 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap suspend fun markAllAsRead(items: ArrayList): Boolean { var success = false - if (isNetworkAvailable() && api.markAllAsRead(items.map { it.id.toString() })?.isSuccess == true) { + if (isNetworkAvailable() && api.markAllAsRead(items.map { it.id.toString() })?.isSuccess) { success = true for (item in items) { markAsReadLocally(item) @@ -332,7 +344,7 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap suspend fun updateRemote(): Boolean { return if (isNetworkAvailable()) { - api.update()?.equals("finished") ?: false + api.update()?.equals("finished") } else { false } @@ -365,8 +377,8 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap if (isNetworkAvailable()) { val fetchedVersion = api.version() - if (fetchedVersion != null && fetchedVersion.getApiMajorVersion() != apiMajorVersion) { - appSettingsService.updateApiVersion(fetchedVersion.getApiMajorVersion()) + if (fetchedVersion.success && fetchedVersion.data != null && fetchedVersion.data.getApiMajorVersion() != apiMajorVersion) { + appSettingsService.updateApiVersion(fetchedVersion.data.getApiMajorVersion()) } } } @@ -383,7 +395,7 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap fun getDBSources(): List = db.sourcesQueries.sources().executeAsList() - fun resetDBTagsWithData(tagEntities: List) { + private fun resetDBTagsWithData(tagEntities: List) { db.tagsQueries.deleteAllTags() db.tagsQueries.transaction { @@ -393,7 +405,7 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap } } - fun resetDBSourcesWithData(sources: List) { + private fun resetDBSourcesWithData(sources: List) { db.sourcesQueries.deleteAllSources() db.sourcesQueries.transaction { @@ -425,7 +437,7 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap val newItems = getMaxItemsForBackground(ItemType.UNREAD) val allItems = getMaxItemsForBackground(ItemType.ALL) val starredItems = getMaxItemsForBackground(ItemType.STARRED) - insertDBItems(newItems.orEmpty() + allItems.orEmpty() + starredItems.orEmpty()) + insertDBItems(newItems + allItems + starredItems) return newItems } catch (e: Throwable) { // We do nothing diff --git a/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/rest/SelfossApi.kt b/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/rest/SelfossApi.kt index c094532..c9f5c9a 100644 --- a/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/rest/SelfossApi.kt +++ b/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/rest/SelfossApi.kt @@ -10,6 +10,7 @@ import io.ktor.client.plugins.contentnegotiation.* import io.ktor.client.plugins.logging.* import io.ktor.client.request.* import io.ktor.client.request.forms.* +import io.ktor.client.statement.* import io.ktor.http.* import io.ktor.serialization.kotlinx.json.* import kotlinx.serialization.json.Json @@ -34,7 +35,7 @@ class SelfossApi(private val appSettingsService: AppSettingsService) { appSettingsService.logApiCalls(message) } } - level = LogLevel.ALL + level = LogLevel.INFO } install(HttpTimeout) { requestTimeoutMillis = appSettingsService.getApiTimeout() @@ -65,11 +66,11 @@ class SelfossApi(private val appSettingsService: AppSettingsService) { client = createHttpClient() } - suspend fun login(): SelfossModel.SuccessResponse? = - client.get(url("/login")) { + suspend fun login(): SelfossModel.SuccessResponse = + maybeResponse(client.get(url("/login")) { parameter("username", appSettingsService.getUserName()) parameter("password", appSettingsService.getPassword()) - }.body() + }) suspend fun getItems( type: String, @@ -79,8 +80,8 @@ class SelfossApi(private val appSettingsService: AppSettingsService) { search: String?, updatedSince: String?, items: Int? = null - ): List? = - client.get(url("/items")) { + ): SelfossModel.StatusAndData> = + bodyOrFailure(client.get(url("/items")) { parameter("username", appSettingsService.getUserName()) parameter("password", appSettingsService.getPassword()) parameter("type", type) @@ -90,74 +91,74 @@ class SelfossApi(private val appSettingsService: AppSettingsService) { parameter("updatedsince", updatedSince) parameter("items", items ?: appSettingsService.getItemsNumber()) parameter("offset", offset) - }.body() + }) - suspend fun stats(): SelfossModel.Stats? = - client.get(url("/stats")) { + suspend fun stats(): SelfossModel.StatusAndData = + bodyOrFailure(client.get(url("/stats")) { parameter("username", appSettingsService.getUserName()) parameter("password", appSettingsService.getPassword()) - }.body() + }) - suspend fun tags(): List? = - client.get(url("/tags")) { + suspend fun tags(): SelfossModel.StatusAndData> = + bodyOrFailure(client.get(url("/tags")) { parameter("username", appSettingsService.getUserName()) parameter("password", appSettingsService.getPassword()) - }.body() + }) - suspend fun update(): String? = - client.get(url("/update")) { + suspend fun update(): SelfossModel.StatusAndData = + bodyOrFailure(client.get(url("/update")) { parameter("username", appSettingsService.getUserName()) parameter("password", appSettingsService.getPassword()) - }.body() + }) - suspend fun spouts(): Map? = - client.get(url("/sources/spouts")) { + suspend fun spouts(): SelfossModel.StatusAndData> = + bodyOrFailure(client.get(url("/sources/spouts")) { parameter("username", appSettingsService.getUserName()) parameter("password", appSettingsService.getPassword()) - }.body() + }) - suspend fun sources(): ArrayList? = - client.get(url("/sources/list")) { + suspend fun sources(): SelfossModel.StatusAndData> = + bodyOrFailure(client.get(url("/sources/list")) { parameter("username", appSettingsService.getUserName()) parameter("password", appSettingsService.getPassword()) - }.body() + }) - suspend fun version(): SelfossModel.ApiVersion? = - client.get(url("/api/about")).body() + suspend fun version(): SelfossModel.StatusAndData = + bodyOrFailure(client.get(url("/api/about"))) - suspend fun markAsRead(id: String): SelfossModel.SuccessResponse? = - client.post(url("/mark/$id")) { + suspend fun markAsRead(id: String): SelfossModel.SuccessResponse = + maybeResponse(client.post(url("/mark/$id")) { parameter("username", appSettingsService.getUserName()) parameter("password", appSettingsService.getPassword()) - }.body() + }) - suspend fun unmarkAsRead(id: String): SelfossModel.SuccessResponse? = - client.post(url("/unmark/$id")) { + suspend fun unmarkAsRead(id: String): SelfossModel.SuccessResponse = + maybeResponse(client.post(url("/unmark/$id")) { parameter("username", appSettingsService.getUserName()) parameter("password", appSettingsService.getPassword()) - }.body() + }) - suspend fun starr(id: String): SelfossModel.SuccessResponse? = - client.post(url("/starr/$id")) { + suspend fun starr(id: String): SelfossModel.SuccessResponse = + maybeResponse(client.post(url("/starr/$id")) { parameter("username", appSettingsService.getUserName()) parameter("password", appSettingsService.getPassword()) - }.body() + }) - suspend fun unstarr(id: String): SelfossModel.SuccessResponse? = - client.post(url("/unstarr/$id")) { + suspend fun unstarr(id: String): SelfossModel.SuccessResponse = + maybeResponse(client.post(url("/unstarr/$id")) { parameter("username", appSettingsService.getUserName()) parameter("password", appSettingsService.getPassword()) - }.body() + }) - suspend fun markAllAsRead(ids: List): SelfossModel.SuccessResponse? = - client.submitForm( + suspend fun markAllAsRead(ids: List): SelfossModel.SuccessResponse = + maybeResponse(client.submitForm( url = url("/mark"), formParameters = Parameters.build { append("username", appSettingsService.getUserName()) append("password", appSettingsService.getPassword()) ids.map { append("ids[]", it) } } - ).body() + )) suspend fun createSourceForVersion( title: String, @@ -166,12 +167,14 @@ class SelfossApi(private val appSettingsService: AppSettingsService) { tags: String, filter: String, version: Int - ): SelfossModel.SuccessResponse? = - if (version > 1) { - createSource2(title, url, spout, tags, filter) - } else { - createSource(title, url, spout, tags, filter) - } + ): SelfossModel.SuccessResponse = + maybeResponse( + if (version > 1) { + createSource2(title, url, spout, tags, filter) + } else { + createSource(title, url, spout, tags, filter) + } + ) suspend fun createSource( title: String, @@ -179,7 +182,7 @@ class SelfossApi(private val appSettingsService: AppSettingsService) { spout: String, tags: String, filter: String - ): SelfossModel.SuccessResponse? = + ): HttpResponse = client.submitForm( url = url("/source?username=${appSettingsService.getUserName()}&password=${appSettingsService.getPassword()}"), formParameters = Parameters.build { @@ -189,7 +192,7 @@ class SelfossApi(private val appSettingsService: AppSettingsService) { append("tags", tags) append("filter", filter) } - ).body() + ) suspend fun createSource2( title: String, @@ -197,7 +200,7 @@ class SelfossApi(private val appSettingsService: AppSettingsService) { spout: String, tags: String, filter: String - ): SelfossModel.SuccessResponse? = + ): HttpResponse = client.submitForm( url = url("/source?username=${appSettingsService.getUserName()}&password=${appSettingsService.getPassword()}"), formParameters = Parameters.build { @@ -207,11 +210,27 @@ class SelfossApi(private val appSettingsService: AppSettingsService) { append("tags[]", tags) append("filter", filter) } - ).body() + ) - suspend fun deleteSource(id: Int): SelfossModel.SuccessResponse? = - client.delete(url("/source/$id")) { + suspend fun deleteSource(id: Int): SelfossModel.SuccessResponse = + maybeResponse(client.delete(url("/source/$id")) { parameter("username", appSettingsService.getUserName()) parameter("password", appSettingsService.getPassword()) - }.body() + }) + + suspend fun maybeResponse(r: HttpResponse): SelfossModel.SuccessResponse { + return if (r.status.isSuccess()) { + r.body() + } else { + SelfossModel.SuccessResponse(false) + } + } + + suspend inline fun bodyOrFailure(r: HttpResponse): SelfossModel.StatusAndData { + return if (r.status.isSuccess()) { + SelfossModel.StatusAndData.succes(r.body()) + } else { + SelfossModel.StatusAndData.error() + } + } } \ No newline at end of file