diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index c3f2bd0ab..5483b2063 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -85,16 +85,7 @@
-
-
-
-
-
-
-
-
-
+ android:label="@string/settings" />
+
+
+
+
+
+
+
+
+
+
+
+
(
{ inflater, parent -> ItemEmptyStateBinding.inflate(inflater, parent, false) },
) {
- binding.buttonRetry.setOnClickListener { listener.onEmptyActionClick() }
+
+ if (listener != null) {
+ binding.buttonRetry.setOnClickListener { listener.onEmptyActionClick() }
+ }
bind {
binding.icon.newImageRequest(item.icon)?.enqueueWith(coil)
binding.textPrimary.setText(item.textPrimary)
binding.textSecondary.setTextAndVisible(item.textSecondary)
- binding.buttonRetry.setTextAndVisible(item.actionStringRes)
+ if (listener != null) {
+ binding.buttonRetry.setTextAndVisible(item.actionStringRes)
+ }
}
onViewRecycled {
diff --git a/app/src/main/java/org/koitharu/kotatsu/list/ui/model/ListModel.kt b/app/src/main/java/org/koitharu/kotatsu/list/ui/model/ListModel.kt
index 1ae2536f9..ba16c8278 100644
--- a/app/src/main/java/org/koitharu/kotatsu/list/ui/model/ListModel.kt
+++ b/app/src/main/java/org/koitharu/kotatsu/list/ui/model/ListModel.kt
@@ -1,3 +1,6 @@
package org.koitharu.kotatsu.list.ui.model
-interface ListModel
\ No newline at end of file
+interface ListModel {
+
+ override fun equals(other: Any?): Boolean
+}
diff --git a/app/src/main/java/org/koitharu/kotatsu/list/ui/model/LoadingFooter.kt b/app/src/main/java/org/koitharu/kotatsu/list/ui/model/LoadingFooter.kt
index 97a63b6a6..7a754dcc6 100644
--- a/app/src/main/java/org/koitharu/kotatsu/list/ui/model/LoadingFooter.kt
+++ b/app/src/main/java/org/koitharu/kotatsu/list/ui/model/LoadingFooter.kt
@@ -1,3 +1,6 @@
package org.koitharu.kotatsu.list.ui.model
-object LoadingFooter : ListModel
\ No newline at end of file
+object LoadingFooter : ListModel {
+
+ override fun equals(other: Any?): Boolean = other === LoadingFooter
+}
diff --git a/app/src/main/java/org/koitharu/kotatsu/list/ui/model/LoadingState.kt b/app/src/main/java/org/koitharu/kotatsu/list/ui/model/LoadingState.kt
index a866e7427..ae0a3088e 100644
--- a/app/src/main/java/org/koitharu/kotatsu/list/ui/model/LoadingState.kt
+++ b/app/src/main/java/org/koitharu/kotatsu/list/ui/model/LoadingState.kt
@@ -1,3 +1,6 @@
package org.koitharu.kotatsu.list.ui.model
-object LoadingState : ListModel
\ No newline at end of file
+object LoadingState : ListModel {
+
+ override fun equals(other: Any?): Boolean = other === LoadingState
+}
diff --git a/app/src/main/java/org/koitharu/kotatsu/scrobbling/ScrobblingModule.kt b/app/src/main/java/org/koitharu/kotatsu/scrobbling/ScrobblingModule.kt
index 6145227fc..18d484565 100644
--- a/app/src/main/java/org/koitharu/kotatsu/scrobbling/ScrobblingModule.kt
+++ b/app/src/main/java/org/koitharu/kotatsu/scrobbling/ScrobblingModule.kt
@@ -15,14 +15,14 @@ import org.koitharu.kotatsu.scrobbling.anilist.data.AniListAuthenticator
import org.koitharu.kotatsu.scrobbling.anilist.data.AniListInterceptor
import org.koitharu.kotatsu.scrobbling.anilist.data.AniListRepository
import org.koitharu.kotatsu.scrobbling.anilist.domain.AniListScrobbler
-import org.koitharu.kotatsu.scrobbling.data.ScrobblerStorage
-import org.koitharu.kotatsu.scrobbling.domain.Scrobbler
+import org.koitharu.kotatsu.scrobbling.common.data.ScrobblerStorage
+import org.koitharu.kotatsu.scrobbling.common.domain.Scrobbler
+import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblerService
+import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblerType
import org.koitharu.kotatsu.scrobbling.mal.data.MALAuthenticator
import org.koitharu.kotatsu.scrobbling.mal.data.MALInterceptor
import org.koitharu.kotatsu.scrobbling.mal.data.MALRepository
import org.koitharu.kotatsu.scrobbling.mal.domain.MALScrobbler
-import org.koitharu.kotatsu.scrobbling.domain.model.ScrobblerService
-import org.koitharu.kotatsu.scrobbling.domain.model.ScrobblerType
import org.koitharu.kotatsu.scrobbling.shikimori.data.ShikimoriAuthenticator
import org.koitharu.kotatsu.scrobbling.shikimori.data.ShikimoriInterceptor
import org.koitharu.kotatsu.scrobbling.shikimori.data.ShikimoriRepository
diff --git a/app/src/main/java/org/koitharu/kotatsu/scrobbling/anilist/data/AniListAuthenticator.kt b/app/src/main/java/org/koitharu/kotatsu/scrobbling/anilist/data/AniListAuthenticator.kt
index 5fb3040d5..57f9fc517 100644
--- a/app/src/main/java/org/koitharu/kotatsu/scrobbling/anilist/data/AniListAuthenticator.kt
+++ b/app/src/main/java/org/koitharu/kotatsu/scrobbling/anilist/data/AniListAuthenticator.kt
@@ -7,9 +7,9 @@ import okhttp3.Response
import okhttp3.Route
import org.koitharu.kotatsu.BuildConfig
import org.koitharu.kotatsu.core.network.CommonHeaders
-import org.koitharu.kotatsu.scrobbling.data.ScrobblerStorage
-import org.koitharu.kotatsu.scrobbling.domain.model.ScrobblerService
-import org.koitharu.kotatsu.scrobbling.domain.model.ScrobblerType
+import org.koitharu.kotatsu.scrobbling.common.data.ScrobblerStorage
+import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblerService
+import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblerType
import javax.inject.Inject
import javax.inject.Provider
diff --git a/app/src/main/java/org/koitharu/kotatsu/scrobbling/anilist/data/AniListInterceptor.kt b/app/src/main/java/org/koitharu/kotatsu/scrobbling/anilist/data/AniListInterceptor.kt
index 9812283fb..25045c83e 100644
--- a/app/src/main/java/org/koitharu/kotatsu/scrobbling/anilist/data/AniListInterceptor.kt
+++ b/app/src/main/java/org/koitharu/kotatsu/scrobbling/anilist/data/AniListInterceptor.kt
@@ -3,7 +3,7 @@ package org.koitharu.kotatsu.scrobbling.anilist.data
import okhttp3.Interceptor
import okhttp3.Response
import org.koitharu.kotatsu.core.network.CommonHeaders
-import org.koitharu.kotatsu.scrobbling.data.ScrobblerStorage
+import org.koitharu.kotatsu.scrobbling.common.data.ScrobblerStorage
private const val JSON = "application/json"
diff --git a/app/src/main/java/org/koitharu/kotatsu/scrobbling/anilist/data/AniListRepository.kt b/app/src/main/java/org/koitharu/kotatsu/scrobbling/anilist/data/AniListRepository.kt
index b1a12c51c..571a8bef0 100644
--- a/app/src/main/java/org/koitharu/kotatsu/scrobbling/anilist/data/AniListRepository.kt
+++ b/app/src/main/java/org/koitharu/kotatsu/scrobbling/anilist/data/AniListRepository.kt
@@ -15,13 +15,12 @@ import org.koitharu.kotatsu.parsers.util.json.getStringOrNull
import org.koitharu.kotatsu.parsers.util.json.mapJSON
import org.koitharu.kotatsu.parsers.util.parseJson
import org.koitharu.kotatsu.parsers.util.toIntUp
-import org.koitharu.kotatsu.scrobbling.data.ScrobblerRepository
-import org.koitharu.kotatsu.scrobbling.data.ScrobblerStorage
-import org.koitharu.kotatsu.scrobbling.data.ScrobblingEntity
-import org.koitharu.kotatsu.scrobbling.domain.model.ScrobblerManga
-import org.koitharu.kotatsu.scrobbling.domain.model.ScrobblerMangaInfo
-import org.koitharu.kotatsu.scrobbling.domain.model.ScrobblerService
-import org.koitharu.kotatsu.scrobbling.domain.model.ScrobblerUser
+import org.koitharu.kotatsu.scrobbling.common.data.ScrobblerStorage
+import org.koitharu.kotatsu.scrobbling.common.data.ScrobblingEntity
+import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblerManga
+import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblerMangaInfo
+import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblerService
+import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblerUser
import kotlin.math.roundToInt
private const val REDIRECT_URI = "kotatsu://anilist-auth"
@@ -36,7 +35,7 @@ class AniListRepository(
private val okHttp: OkHttpClient,
private val storage: ScrobblerStorage,
private val db: MangaDatabase,
-) : ScrobblerRepository {
+) : org.koitharu.kotatsu.scrobbling.common.data.ScrobblerRepository {
override val oauthUrl: String
get() = "${BASE_URL}oauth/authorize?client_id=${BuildConfig.ANILIST_CLIENT_ID}&" +
diff --git a/app/src/main/java/org/koitharu/kotatsu/scrobbling/anilist/domain/AniListScrobbler.kt b/app/src/main/java/org/koitharu/kotatsu/scrobbling/anilist/domain/AniListScrobbler.kt
index 967a0dc3b..05b10da0a 100644
--- a/app/src/main/java/org/koitharu/kotatsu/scrobbling/anilist/domain/AniListScrobbler.kt
+++ b/app/src/main/java/org/koitharu/kotatsu/scrobbling/anilist/domain/AniListScrobbler.kt
@@ -2,9 +2,9 @@ package org.koitharu.kotatsu.scrobbling.anilist.domain
import org.koitharu.kotatsu.core.db.MangaDatabase
import org.koitharu.kotatsu.scrobbling.anilist.data.AniListRepository
-import org.koitharu.kotatsu.scrobbling.domain.Scrobbler
-import org.koitharu.kotatsu.scrobbling.domain.model.ScrobblerService
-import org.koitharu.kotatsu.scrobbling.domain.model.ScrobblingStatus
+import org.koitharu.kotatsu.scrobbling.common.domain.Scrobbler
+import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblerService
+import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblingStatus
import javax.inject.Inject
import javax.inject.Singleton
diff --git a/app/src/main/java/org/koitharu/kotatsu/scrobbling/anilist/ui/AniListSettingsFragment.kt b/app/src/main/java/org/koitharu/kotatsu/scrobbling/anilist/ui/AniListSettingsFragment.kt
deleted file mode 100644
index 5a98b7a81..000000000
--- a/app/src/main/java/org/koitharu/kotatsu/scrobbling/anilist/ui/AniListSettingsFragment.kt
+++ /dev/null
@@ -1,86 +0,0 @@
-package org.koitharu.kotatsu.scrobbling.anilist.ui
-
-import android.content.Intent
-import android.net.Uri
-import android.os.Bundle
-import android.view.View
-import androidx.preference.Preference
-import coil.ImageLoader
-import coil.request.ImageRequest
-import coil.transform.CircleCropTransformation
-import dagger.hilt.android.AndroidEntryPoint
-import org.koitharu.kotatsu.R
-import org.koitharu.kotatsu.base.ui.BasePreferenceFragment
-import org.koitharu.kotatsu.scrobbling.domain.model.ScrobblerUser
-import org.koitharu.kotatsu.utils.PreferenceIconTarget
-import org.koitharu.kotatsu.utils.ext.assistedViewModels
-import org.koitharu.kotatsu.utils.ext.enqueueWith
-import org.koitharu.kotatsu.utils.ext.withArgs
-import javax.inject.Inject
-
-@AndroidEntryPoint
-class AniListSettingsFragment : BasePreferenceFragment(R.string.anilist) {
-
- @Inject
- lateinit var coil: ImageLoader
-
- @Inject
- lateinit var viewModelFactory: AniListSettingsViewModel.Factory
-
- private val viewModel by assistedViewModels {
- viewModelFactory.create(arguments?.getString(ARG_AUTH_CODE))
- }
-
- override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
- addPreferencesFromResource(R.xml.pref_anilist)
- }
-
- override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
- super.onViewCreated(view, savedInstanceState)
- viewModel.user.observe(viewLifecycleOwner, this::onUserChanged)
- }
-
- override fun onPreferenceTreeClick(preference: Preference): Boolean {
- return when (preference.key) {
- KEY_USER -> openAuthorization()
- KEY_LOGOUT -> {
- viewModel.logout()
- true
- }
-
- else -> super.onPreferenceTreeClick(preference)
- }
- }
-
- private fun onUserChanged(user: ScrobblerUser?) {
- val pref = findPreference(KEY_USER) ?: return
- pref.isSelectable = user == null
- pref.title = user?.nickname ?: getString(R.string.sign_in)
- ImageRequest.Builder(requireContext())
- .data(user?.avatar)
- .transformations(CircleCropTransformation())
- .target(PreferenceIconTarget(pref))
- .enqueueWith(coil)
- findPreference(KEY_LOGOUT)?.isVisible = user != null
- }
-
- private fun openAuthorization(): Boolean {
- return runCatching {
- val intent = Intent(Intent.ACTION_VIEW)
- intent.data = Uri.parse(viewModel.authorizationUrl)
- startActivity(intent)
- }.isSuccess
- }
-
- companion object {
-
- private const val KEY_USER = "al_user"
- private const val KEY_LOGOUT = "al_logout"
-
- private const val ARG_AUTH_CODE = "auth_code"
-
- fun newInstance(authCode: String?) = AniListSettingsFragment().withArgs(1) {
- putString(ARG_AUTH_CODE, authCode)
- }
- }
-}
diff --git a/app/src/main/java/org/koitharu/kotatsu/scrobbling/anilist/ui/AniListSettingsViewModel.kt b/app/src/main/java/org/koitharu/kotatsu/scrobbling/anilist/ui/AniListSettingsViewModel.kt
deleted file mode 100644
index 554e5a219..000000000
--- a/app/src/main/java/org/koitharu/kotatsu/scrobbling/anilist/ui/AniListSettingsViewModel.kt
+++ /dev/null
@@ -1,57 +0,0 @@
-package org.koitharu.kotatsu.scrobbling.anilist.ui
-
-import androidx.lifecycle.MutableLiveData
-import dagger.assisted.Assisted
-import dagger.assisted.AssistedFactory
-import dagger.assisted.AssistedInject
-import kotlinx.coroutines.Dispatchers
-import org.koitharu.kotatsu.base.ui.BaseViewModel
-import org.koitharu.kotatsu.scrobbling.anilist.data.AniListRepository
-import org.koitharu.kotatsu.scrobbling.domain.model.ScrobblerUser
-
-class AniListSettingsViewModel @AssistedInject constructor(
- private val repository: AniListRepository,
- @Assisted authCode: String?,
-) : BaseViewModel() {
-
- val authorizationUrl: String
- get() = repository.oauthUrl
-
- val user = MutableLiveData()
-
- init {
- if (authCode != null) {
- authorize(authCode)
- } else {
- loadUser()
- }
- }
-
- fun logout() {
- launchJob(Dispatchers.Default) {
- repository.logout()
- user.postValue(null)
- }
- }
-
- private fun loadUser() = launchJob(Dispatchers.Default) {
- val userModel = if (repository.isAuthorized) {
- repository.cachedUser?.let(user::postValue)
- repository.loadUser()
- } else {
- null
- }
- user.postValue(userModel)
- }
-
- private fun authorize(code: String) = launchJob(Dispatchers.Default) {
- repository.authorize(code)
- user.postValue(repository.loadUser())
- }
-
- @AssistedFactory
- interface Factory {
-
- fun create(authCode: String?): AniListSettingsViewModel
- }
-}
diff --git a/app/src/main/java/org/koitharu/kotatsu/scrobbling/data/ScrobblerRepository.kt b/app/src/main/java/org/koitharu/kotatsu/scrobbling/common/data/ScrobblerRepository.kt
similarity index 71%
rename from app/src/main/java/org/koitharu/kotatsu/scrobbling/data/ScrobblerRepository.kt
rename to app/src/main/java/org/koitharu/kotatsu/scrobbling/common/data/ScrobblerRepository.kt
index 08310ae25..35ed7bd46 100644
--- a/app/src/main/java/org/koitharu/kotatsu/scrobbling/data/ScrobblerRepository.kt
+++ b/app/src/main/java/org/koitharu/kotatsu/scrobbling/common/data/ScrobblerRepository.kt
@@ -1,9 +1,9 @@
-package org.koitharu.kotatsu.scrobbling.data
+package org.koitharu.kotatsu.scrobbling.common.data
import org.koitharu.kotatsu.parsers.model.MangaChapter
-import org.koitharu.kotatsu.scrobbling.domain.model.ScrobblerManga
-import org.koitharu.kotatsu.scrobbling.domain.model.ScrobblerMangaInfo
-import org.koitharu.kotatsu.scrobbling.domain.model.ScrobblerUser
+import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblerManga
+import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblerMangaInfo
+import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblerUser
interface ScrobblerRepository {
diff --git a/app/src/main/java/org/koitharu/kotatsu/scrobbling/data/ScrobblerStorage.kt b/app/src/main/java/org/koitharu/kotatsu/scrobbling/common/data/ScrobblerStorage.kt
similarity index 88%
rename from app/src/main/java/org/koitharu/kotatsu/scrobbling/data/ScrobblerStorage.kt
rename to app/src/main/java/org/koitharu/kotatsu/scrobbling/common/data/ScrobblerStorage.kt
index c5f7973c5..b5ab50d02 100644
--- a/app/src/main/java/org/koitharu/kotatsu/scrobbling/data/ScrobblerStorage.kt
+++ b/app/src/main/java/org/koitharu/kotatsu/scrobbling/common/data/ScrobblerStorage.kt
@@ -1,10 +1,10 @@
-package org.koitharu.kotatsu.scrobbling.data
+package org.koitharu.kotatsu.scrobbling.common.data
import android.content.Context
import androidx.core.content.edit
import org.jsoup.internal.StringUtil.StringJoiner
-import org.koitharu.kotatsu.scrobbling.domain.model.ScrobblerService
-import org.koitharu.kotatsu.scrobbling.domain.model.ScrobblerUser
+import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblerService
+import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblerUser
private const val KEY_ACCESS_TOKEN = "access_token"
private const val KEY_REFRESH_TOKEN = "refresh_token"
diff --git a/app/src/main/java/org/koitharu/kotatsu/scrobbling/data/ScrobblingDao.kt b/app/src/main/java/org/koitharu/kotatsu/scrobbling/common/data/ScrobblingDao.kt
similarity index 77%
rename from app/src/main/java/org/koitharu/kotatsu/scrobbling/data/ScrobblingDao.kt
rename to app/src/main/java/org/koitharu/kotatsu/scrobbling/common/data/ScrobblingDao.kt
index 812393dee..c24a93b55 100644
--- a/app/src/main/java/org/koitharu/kotatsu/scrobbling/data/ScrobblingDao.kt
+++ b/app/src/main/java/org/koitharu/kotatsu/scrobbling/common/data/ScrobblingDao.kt
@@ -1,4 +1,4 @@
-package org.koitharu.kotatsu.scrobbling.data
+package org.koitharu.kotatsu.scrobbling.common.data
import androidx.room.*
import kotlinx.coroutines.flow.Flow
@@ -12,6 +12,9 @@ abstract class ScrobblingDao {
@Query("SELECT * FROM scrobblings WHERE scrobbler = :scrobbler AND manga_id = :mangaId")
abstract fun observe(scrobbler: Int, mangaId: Long): Flow
+ @Query("SELECT * FROM scrobblings WHERE scrobbler = :scrobbler")
+ abstract fun observe(scrobbler: Int): Flow>
+
@Upsert
abstract suspend fun upsert(entity: ScrobblingEntity)
diff --git a/app/src/main/java/org/koitharu/kotatsu/scrobbling/data/ScrobblingEntity.kt b/app/src/main/java/org/koitharu/kotatsu/scrobbling/common/data/ScrobblingEntity.kt
similarity index 94%
rename from app/src/main/java/org/koitharu/kotatsu/scrobbling/data/ScrobblingEntity.kt
rename to app/src/main/java/org/koitharu/kotatsu/scrobbling/common/data/ScrobblingEntity.kt
index 5a18cf488..32764e32b 100644
--- a/app/src/main/java/org/koitharu/kotatsu/scrobbling/data/ScrobblingEntity.kt
+++ b/app/src/main/java/org/koitharu/kotatsu/scrobbling/common/data/ScrobblingEntity.kt
@@ -1,4 +1,4 @@
-package org.koitharu.kotatsu.scrobbling.data
+package org.koitharu.kotatsu.scrobbling.common.data
import androidx.room.ColumnInfo
import androidx.room.Entity
diff --git a/app/src/main/java/org/koitharu/kotatsu/scrobbling/domain/Scrobbler.kt b/app/src/main/java/org/koitharu/kotatsu/scrobbling/common/domain/Scrobbler.kt
similarity index 62%
rename from app/src/main/java/org/koitharu/kotatsu/scrobbling/domain/Scrobbler.kt
rename to app/src/main/java/org/koitharu/kotatsu/scrobbling/common/domain/Scrobbler.kt
index 54f9ac504..5eb3ebec7 100644
--- a/app/src/main/java/org/koitharu/kotatsu/scrobbling/domain/Scrobbler.kt
+++ b/app/src/main/java/org/koitharu/kotatsu/scrobbling/common/domain/Scrobbler.kt
@@ -1,19 +1,23 @@
-package org.koitharu.kotatsu.scrobbling.domain
+package org.koitharu.kotatsu.scrobbling.common.domain
import androidx.collection.LongSparseArray
import androidx.collection.getOrElse
import androidx.core.text.parseAsHtml
+import kotlinx.coroutines.async
+import kotlinx.coroutines.awaitAll
+import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.map
import org.koitharu.kotatsu.core.db.MangaDatabase
import org.koitharu.kotatsu.parsers.model.MangaChapter
-import org.koitharu.kotatsu.scrobbling.data.ScrobblerRepository
-import org.koitharu.kotatsu.scrobbling.data.ScrobblingEntity
-import org.koitharu.kotatsu.scrobbling.domain.model.ScrobblerManga
-import org.koitharu.kotatsu.scrobbling.domain.model.ScrobblerMangaInfo
-import org.koitharu.kotatsu.scrobbling.domain.model.ScrobblerService
-import org.koitharu.kotatsu.scrobbling.domain.model.ScrobblingInfo
-import org.koitharu.kotatsu.scrobbling.domain.model.ScrobblingStatus
+import org.koitharu.kotatsu.scrobbling.common.data.ScrobblingEntity
+import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblerManga
+import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblerMangaInfo
+import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblerService
+import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblerUser
+import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblingInfo
+import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblingStatus
import org.koitharu.kotatsu.utils.ext.findKeyByValue
import org.koitharu.kotatsu.utils.ext.printStackTraceDebug
import org.koitharu.kotatsu.utils.ext.runCatchingCancellable
@@ -22,15 +26,37 @@ import java.util.EnumMap
abstract class Scrobbler(
protected val db: MangaDatabase,
val scrobblerService: ScrobblerService,
- private val repository: ScrobblerRepository,
+ private val repository: org.koitharu.kotatsu.scrobbling.common.data.ScrobblerRepository,
) {
private val infoCache = LongSparseArray()
protected val statuses = EnumMap(ScrobblingStatus::class.java)
+ val user: Flow = flow {
+ repository.cachedUser?.let {
+ emit(it)
+ }
+ runCatchingCancellable {
+ repository.loadUser()
+ }.onSuccess {
+ emit(it)
+ }.onFailure {
+ it.printStackTraceDebug()
+ }
+ }
+
val isAvailable: Boolean
get() = repository.isAuthorized
+ suspend fun authorize(authCode: String): ScrobblerUser {
+ repository.authorize(authCode)
+ return repository.loadUser()
+ }
+
+ suspend fun logout() {
+ repository.logout()
+ }
+
suspend fun findManga(query: String, offset: Int): List {
return repository.findManga(query, offset)
}
@@ -46,14 +72,27 @@ abstract class Scrobbler(
suspend fun getScrobblingInfoOrNull(mangaId: Long): ScrobblingInfo? {
val entity = db.scrobblingDao.find(scrobblerService.id, mangaId) ?: return null
- return entity.toScrobblingInfo(mangaId)
+ return entity.toScrobblingInfo()
}
abstract suspend fun updateScrobblingInfo(mangaId: Long, rating: Float, status: ScrobblingStatus?, comment: String?)
fun observeScrobblingInfo(mangaId: Long): Flow {
return db.scrobblingDao.observe(scrobblerService.id, mangaId)
- .map { it?.toScrobblingInfo(mangaId) }
+ .map { it?.toScrobblingInfo() }
+ }
+
+ fun observeAllScrobblingInfo(): Flow> {
+ return db.scrobblingDao.observe(scrobblerService.id)
+ .map { entities ->
+ coroutineScope {
+ entities.map {
+ async {
+ it.toScrobblingInfo()
+ }
+ }.awaitAll()
+ }.filterNotNull()
+ }
}
suspend fun unregisterScrobbling(mangaId: Long) {
@@ -64,7 +103,7 @@ abstract class Scrobbler(
return repository.getMangaInfo(id)
}
- private suspend fun ScrobblingEntity.toScrobblingInfo(mangaId: Long): ScrobblingInfo? {
+ private suspend fun ScrobblingEntity.toScrobblingInfo(): ScrobblingInfo? {
val mangaInfo = infoCache.getOrElse(targetId) {
runCatchingCancellable {
getMangaInfo(targetId)
diff --git a/app/src/main/java/org/koitharu/kotatsu/scrobbling/domain/model/ScrobblerManga.kt b/app/src/main/java/org/koitharu/kotatsu/scrobbling/common/domain/model/ScrobblerManga.kt
similarity index 93%
rename from app/src/main/java/org/koitharu/kotatsu/scrobbling/domain/model/ScrobblerManga.kt
rename to app/src/main/java/org/koitharu/kotatsu/scrobbling/common/domain/model/ScrobblerManga.kt
index 9e28c9d7d..b00da2c8d 100644
--- a/app/src/main/java/org/koitharu/kotatsu/scrobbling/domain/model/ScrobblerManga.kt
+++ b/app/src/main/java/org/koitharu/kotatsu/scrobbling/common/domain/model/ScrobblerManga.kt
@@ -1,4 +1,4 @@
-package org.koitharu.kotatsu.scrobbling.domain.model
+package org.koitharu.kotatsu.scrobbling.common.domain.model
import org.koitharu.kotatsu.list.ui.model.ListModel
@@ -37,4 +37,4 @@ class ScrobblerManga(
override fun toString(): String {
return "ScrobblerManga #$id \"$name\" $url"
}
-}
\ No newline at end of file
+}
diff --git a/app/src/main/java/org/koitharu/kotatsu/scrobbling/domain/model/ScrobblerMangaInfo.kt b/app/src/main/java/org/koitharu/kotatsu/scrobbling/common/domain/model/ScrobblerMangaInfo.kt
similarity index 67%
rename from app/src/main/java/org/koitharu/kotatsu/scrobbling/domain/model/ScrobblerMangaInfo.kt
rename to app/src/main/java/org/koitharu/kotatsu/scrobbling/common/domain/model/ScrobblerMangaInfo.kt
index 940262041..3aa638053 100644
--- a/app/src/main/java/org/koitharu/kotatsu/scrobbling/domain/model/ScrobblerMangaInfo.kt
+++ b/app/src/main/java/org/koitharu/kotatsu/scrobbling/common/domain/model/ScrobblerMangaInfo.kt
@@ -1,4 +1,4 @@
-package org.koitharu.kotatsu.scrobbling.domain.model
+package org.koitharu.kotatsu.scrobbling.common.domain.model
class ScrobblerMangaInfo(
val id: Long,
@@ -6,4 +6,4 @@ class ScrobblerMangaInfo(
val cover: String,
val url: String,
val descriptionHtml: String,
-)
\ No newline at end of file
+)
diff --git a/app/src/main/java/org/koitharu/kotatsu/scrobbling/domain/model/ScrobblerService.kt b/app/src/main/java/org/koitharu/kotatsu/scrobbling/common/domain/model/ScrobblerService.kt
similarity index 86%
rename from app/src/main/java/org/koitharu/kotatsu/scrobbling/domain/model/ScrobblerService.kt
rename to app/src/main/java/org/koitharu/kotatsu/scrobbling/common/domain/model/ScrobblerService.kt
index b8819b6fb..5b47a3a25 100644
--- a/app/src/main/java/org/koitharu/kotatsu/scrobbling/domain/model/ScrobblerService.kt
+++ b/app/src/main/java/org/koitharu/kotatsu/scrobbling/common/domain/model/ScrobblerService.kt
@@ -1,4 +1,4 @@
-package org.koitharu.kotatsu.scrobbling.domain.model
+package org.koitharu.kotatsu.scrobbling.common.domain.model
import androidx.annotation.DrawableRes
import androidx.annotation.StringRes
diff --git a/app/src/main/java/org/koitharu/kotatsu/scrobbling/domain/model/ScrobblerType.kt b/app/src/main/java/org/koitharu/kotatsu/scrobbling/common/domain/model/ScrobblerType.kt
similarity index 64%
rename from app/src/main/java/org/koitharu/kotatsu/scrobbling/domain/model/ScrobblerType.kt
rename to app/src/main/java/org/koitharu/kotatsu/scrobbling/common/domain/model/ScrobblerType.kt
index e2d372edb..8920e295a 100644
--- a/app/src/main/java/org/koitharu/kotatsu/scrobbling/domain/model/ScrobblerType.kt
+++ b/app/src/main/java/org/koitharu/kotatsu/scrobbling/common/domain/model/ScrobblerType.kt
@@ -1,4 +1,4 @@
-package org.koitharu.kotatsu.scrobbling.domain.model
+package org.koitharu.kotatsu.scrobbling.common.domain.model
import javax.inject.Qualifier
diff --git a/app/src/main/java/org/koitharu/kotatsu/scrobbling/domain/model/ScrobblerUser.kt b/app/src/main/java/org/koitharu/kotatsu/scrobbling/common/domain/model/ScrobblerUser.kt
similarity index 91%
rename from app/src/main/java/org/koitharu/kotatsu/scrobbling/domain/model/ScrobblerUser.kt
rename to app/src/main/java/org/koitharu/kotatsu/scrobbling/common/domain/model/ScrobblerUser.kt
index 92ecce0df..73f37ce3e 100644
--- a/app/src/main/java/org/koitharu/kotatsu/scrobbling/domain/model/ScrobblerUser.kt
+++ b/app/src/main/java/org/koitharu/kotatsu/scrobbling/common/domain/model/ScrobblerUser.kt
@@ -1,4 +1,4 @@
-package org.koitharu.kotatsu.scrobbling.domain.model
+package org.koitharu.kotatsu.scrobbling.common.domain.model
class ScrobblerUser(
val id: Long,
diff --git a/app/src/main/java/org/koitharu/kotatsu/scrobbling/domain/model/ScrobblingInfo.kt b/app/src/main/java/org/koitharu/kotatsu/scrobbling/common/domain/model/ScrobblingInfo.kt
similarity index 92%
rename from app/src/main/java/org/koitharu/kotatsu/scrobbling/domain/model/ScrobblingInfo.kt
rename to app/src/main/java/org/koitharu/kotatsu/scrobbling/common/domain/model/ScrobblingInfo.kt
index 87393d6ec..5dd798f33 100644
--- a/app/src/main/java/org/koitharu/kotatsu/scrobbling/domain/model/ScrobblingInfo.kt
+++ b/app/src/main/java/org/koitharu/kotatsu/scrobbling/common/domain/model/ScrobblingInfo.kt
@@ -1,4 +1,6 @@
-package org.koitharu.kotatsu.scrobbling.domain.model
+package org.koitharu.kotatsu.scrobbling.common.domain.model
+
+import org.koitharu.kotatsu.list.ui.model.ListModel
class ScrobblingInfo(
val scrobbler: ScrobblerService,
@@ -12,7 +14,7 @@ class ScrobblingInfo(
val coverUrl: String,
val description: CharSequence?,
val externalUrl: String,
-) {
+) : ListModel {
override fun equals(other: Any?): Boolean {
if (this === other) return true
@@ -49,4 +51,4 @@ class ScrobblingInfo(
result = 31 * result + externalUrl.hashCode()
return result
}
-}
\ No newline at end of file
+}
diff --git a/app/src/main/java/org/koitharu/kotatsu/scrobbling/common/domain/model/ScrobblingStatus.kt b/app/src/main/java/org/koitharu/kotatsu/scrobbling/common/domain/model/ScrobblingStatus.kt
new file mode 100644
index 000000000..70118d585
--- /dev/null
+++ b/app/src/main/java/org/koitharu/kotatsu/scrobbling/common/domain/model/ScrobblingStatus.kt
@@ -0,0 +1,13 @@
+package org.koitharu.kotatsu.scrobbling.common.domain.model
+
+import org.koitharu.kotatsu.list.ui.model.ListModel
+
+enum class ScrobblingStatus : ListModel {
+
+ PLANNED,
+ READING,
+ RE_READING,
+ COMPLETED,
+ ON_HOLD,
+ DROPPED,
+}
diff --git a/app/src/main/java/org/koitharu/kotatsu/scrobbling/common/ui/config/ScrobblerConfigActivity.kt b/app/src/main/java/org/koitharu/kotatsu/scrobbling/common/ui/config/ScrobblerConfigActivity.kt
new file mode 100644
index 000000000..00fa4d423
--- /dev/null
+++ b/app/src/main/java/org/koitharu/kotatsu/scrobbling/common/ui/config/ScrobblerConfigActivity.kt
@@ -0,0 +1,188 @@
+package org.koitharu.kotatsu.scrobbling.common.ui.config
+
+import android.content.Context
+import android.content.Intent
+import android.os.Bundle
+import android.view.View
+import androidx.core.graphics.Insets
+import androidx.core.view.isVisible
+import androidx.core.view.updatePadding
+import coil.ImageLoader
+import com.google.android.material.dialog.MaterialAlertDialogBuilder
+import com.google.android.material.snackbar.Snackbar
+import dagger.hilt.android.AndroidEntryPoint
+import org.koitharu.kotatsu.R
+import org.koitharu.kotatsu.base.ui.BaseActivity
+import org.koitharu.kotatsu.base.ui.list.OnListItemClickListener
+import org.koitharu.kotatsu.base.ui.list.decor.TypedSpacingItemDecoration
+import org.koitharu.kotatsu.databinding.ActivityScrobblerConfigBinding
+import org.koitharu.kotatsu.details.ui.DetailsActivity
+import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblerService
+import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblerUser
+import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblingInfo
+import org.koitharu.kotatsu.scrobbling.common.ui.config.adapter.ScrobblingMangaAdapter
+import org.koitharu.kotatsu.tracker.ui.feed.adapter.FeedAdapter
+import org.koitharu.kotatsu.utils.ext.assistedViewModels
+import org.koitharu.kotatsu.utils.ext.disposeImageRequest
+import org.koitharu.kotatsu.utils.ext.enqueueWith
+import org.koitharu.kotatsu.utils.ext.getDisplayMessage
+import org.koitharu.kotatsu.utils.ext.hideCompat
+import org.koitharu.kotatsu.utils.ext.newImageRequest
+import org.koitharu.kotatsu.utils.ext.showCompat
+import javax.inject.Inject
+
+@AndroidEntryPoint
+class ScrobblerConfigActivity : BaseActivity(),
+ OnListItemClickListener, View.OnClickListener {
+
+ @Inject
+ lateinit var viewModelFactory: ScrobblerConfigViewModel.Factory
+
+ @Inject
+ lateinit var coil: ImageLoader
+
+ private val viewModel: ScrobblerConfigViewModel by assistedViewModels {
+ viewModelFactory.create(requireNotNull(getScrobblerService(intent)))
+ }
+
+ private var paddingVertical = 0
+ private var paddingHorizontal = 0
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(ActivityScrobblerConfigBinding.inflate(layoutInflater))
+ setTitle(viewModel.titleResId)
+ supportActionBar?.setDisplayHomeAsUpEnabled(true)
+
+ val listAdapter = ScrobblingMangaAdapter(this, coil, this)
+ with(binding.recyclerView) {
+ adapter = listAdapter
+ setHasFixedSize(true)
+ val spacing = resources.getDimensionPixelOffset(R.dimen.list_spacing)
+ paddingHorizontal = spacing
+ paddingVertical = resources.getDimensionPixelOffset(R.dimen.grid_spacing_outer)
+ val decoration = TypedSpacingItemDecoration(
+ FeedAdapter.ITEM_TYPE_FEED to 0,
+ fallbackSpacing = spacing,
+ )
+ addItemDecoration(decoration)
+ }
+ binding.imageViewAvatar.setOnClickListener(this)
+
+ viewModel.content.observe(this, listAdapter::setItems)
+ viewModel.user.observe(this, this::onUserChanged)
+ viewModel.isLoading.observe(this, this::onLoadingStateChanged)
+ viewModel.onError.observe(this, this::onError)
+ viewModel.onLoggedOut.observe(this) {
+ finishAfterTransition()
+ }
+
+ processIntent(intent)
+ }
+
+ override fun onNewIntent(intent: Intent?) {
+ super.onNewIntent(intent)
+ if (intent != null) {
+ setIntent(intent)
+ processIntent(intent)
+ }
+ }
+
+ override fun onWindowInsetsChanged(insets: Insets) {
+ binding.recyclerView.updatePadding(
+ left = insets.left + paddingHorizontal,
+ right = insets.right + paddingHorizontal,
+ bottom = insets.bottom + paddingVertical,
+ )
+ }
+
+ override fun onItemClick(item: ScrobblingInfo, view: View) {
+ startActivity(
+ DetailsActivity.newIntent(this, item.mangaId),
+ )
+ }
+
+ override fun onClick(v: View) {
+ when (v.id) {
+ R.id.imageView_avatar -> showUserDialog()
+ }
+ }
+
+ private fun processIntent(intent: Intent) {
+ if (intent.action == Intent.ACTION_VIEW) {
+ val uri = intent.data ?: return
+ val code = uri.getQueryParameter("code")
+ if (!code.isNullOrEmpty()) {
+ viewModel.onAuthCodeReceived(code)
+ }
+ }
+ }
+
+ private fun onUserChanged(user: ScrobblerUser?) {
+ if (user == null) {
+ binding.imageViewAvatar.disposeImageRequest()
+ binding.imageViewAvatar.isVisible = false
+ return
+ }
+ binding.imageViewAvatar.isVisible = true
+ binding.imageViewAvatar.newImageRequest(user.avatar, null)
+ ?.enqueueWith(coil)
+ }
+
+ private fun onLoadingStateChanged(isLoading: Boolean) {
+ binding.progressBar.run {
+ if (isLoading) {
+ showCompat()
+ } else {
+ hideCompat()
+ }
+ }
+ }
+
+ private fun onError(e: Throwable) {
+ Snackbar.make(
+ binding.recyclerView,
+ e.getDisplayMessage(resources),
+ Snackbar.LENGTH_LONG,
+ ).show()
+ }
+
+ private fun showUserDialog() {
+ MaterialAlertDialogBuilder(this)
+ .setTitle(title)
+ .setMessage(getString(R.string.logged_in_as, viewModel.user.value?.nickname))
+ .setNegativeButton(R.string.close, null)
+ .setPositiveButton(R.string.logout) { _, _ ->
+ viewModel.logout()
+ }.show()
+ }
+
+ companion object {
+
+ private const val EXTRA_SERVICE_ID = "service"
+
+ private const val HOST_SHIKIMORI_AUTH = "shikimori-auth"
+ private const val HOST_ANILIST_AUTH = "anilist-auth"
+ private const val HOST_MAL_AUTH = "mal-auth"
+
+ fun newIntent(context: Context, service: ScrobblerService) =
+ Intent(context, ScrobblerConfigActivity::class.java)
+ .putExtra(EXTRA_SERVICE_ID, service.id)
+
+ private fun getScrobblerService(
+ intent: Intent
+ ): ScrobblerService? {
+ val serviceId = intent.getIntExtra(EXTRA_SERVICE_ID, 0)
+ if (serviceId != 0) {
+ return enumValues().first { it.id == serviceId }
+ }
+ val uri = intent.data ?: return null
+ return when (uri.host) {
+ HOST_SHIKIMORI_AUTH -> ScrobblerService.SHIKIMORI
+ HOST_ANILIST_AUTH -> ScrobblerService.ANILIST
+ HOST_MAL_AUTH -> ScrobblerService.MAL
+ else -> null
+ }
+ }
+ }
+}
diff --git a/app/src/main/java/org/koitharu/kotatsu/scrobbling/common/ui/config/ScrobblerConfigViewModel.kt b/app/src/main/java/org/koitharu/kotatsu/scrobbling/common/ui/config/ScrobblerConfigViewModel.kt
new file mode 100644
index 000000000..c4c3ac324
--- /dev/null
+++ b/app/src/main/java/org/koitharu/kotatsu/scrobbling/common/ui/config/ScrobblerConfigViewModel.kt
@@ -0,0 +1,98 @@
+package org.koitharu.kotatsu.scrobbling.common.ui.config
+
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.viewModelScope
+import dagger.assisted.Assisted
+import dagger.assisted.AssistedFactory
+import dagger.assisted.AssistedInject
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.flow.catch
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.flow.onStart
+import kotlinx.coroutines.plus
+import org.koitharu.kotatsu.R
+import org.koitharu.kotatsu.base.ui.BaseViewModel
+import org.koitharu.kotatsu.list.ui.model.EmptyState
+import org.koitharu.kotatsu.list.ui.model.ListModel
+import org.koitharu.kotatsu.scrobbling.common.domain.Scrobbler
+import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblerService
+import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblerUser
+import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblingInfo
+import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblingStatus
+import org.koitharu.kotatsu.utils.SingleLiveEvent
+import org.koitharu.kotatsu.utils.asFlowLiveData
+import org.koitharu.kotatsu.utils.ext.onFirst
+
+class ScrobblerConfigViewModel @AssistedInject constructor(
+ @Assisted scrobblerService: ScrobblerService,
+ scrobblers: Set<@JvmSuppressWildcards Scrobbler>,
+) : BaseViewModel() {
+
+ private val scrobbler = scrobblers.first { it.scrobblerService == scrobblerService }
+
+ val titleResId = scrobbler.scrobblerService.titleResId
+
+ val user = MutableLiveData(null)
+ val onLoggedOut = SingleLiveEvent()
+
+ val content = scrobbler.observeAllScrobblingInfo()
+ .onStart { loadingCounter.increment() }
+ .onFirst { loadingCounter.decrement() }
+ .catch { errorEvent.postCall(it) }
+ .map { buildContentList(it) }
+ .asFlowLiveData(viewModelScope.coroutineContext + Dispatchers.Default, emptyList())
+
+ init {
+ scrobbler.user
+ .onEach { user.postValue(it) }
+ .launchIn(viewModelScope + Dispatchers.Default)
+ }
+
+ fun onAuthCodeReceived(authCode: String) {
+ launchLoadingJob(Dispatchers.Default) {
+ val newUser = scrobbler.authorize(authCode)
+ user.postValue(newUser)
+ }
+ }
+
+ fun logout() {
+ launchLoadingJob(Dispatchers.Default) {
+ scrobbler.logout()
+ user.postValue(null)
+ onLoggedOut.postCall(Unit)
+ }
+ }
+
+ private fun buildContentList(list: List): List {
+ if (list.isEmpty()) {
+ return listOf(
+ EmptyState(
+ icon = R.drawable.ic_empty_history,
+ textPrimary = R.string.nothing_here,
+ textSecondary = R.string.scrobbling_empty_hint,
+ actionStringRes = 0,
+ ),
+ )
+ }
+ val grouped = list.groupBy { it.status }
+ val statuses = enumValues()
+ val result = ArrayList(list.size + statuses.size)
+ for (st in statuses) {
+ val subList = grouped[st]
+ if (subList.isNullOrEmpty()) {
+ continue
+ }
+ result.add(st)
+ result.addAll(subList)
+ }
+ return result
+ }
+
+ @AssistedFactory
+ interface Factory {
+
+ fun create(service: ScrobblerService): ScrobblerConfigViewModel
+ }
+}
diff --git a/app/src/main/java/org/koitharu/kotatsu/scrobbling/common/ui/config/adapter/ScrobblingHeaderAD.kt b/app/src/main/java/org/koitharu/kotatsu/scrobbling/common/ui/config/adapter/ScrobblingHeaderAD.kt
new file mode 100644
index 000000000..cb233abf0
--- /dev/null
+++ b/app/src/main/java/org/koitharu/kotatsu/scrobbling/common/ui/config/adapter/ScrobblingHeaderAD.kt
@@ -0,0 +1,16 @@
+package org.koitharu.kotatsu.scrobbling.common.ui.config.adapter
+
+import android.widget.TextView
+import com.hannesdorfmann.adapterdelegates4.dsl.adapterDelegate
+import org.koitharu.kotatsu.R
+import org.koitharu.kotatsu.list.ui.model.ListModel
+import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblingStatus
+
+fun scrobblingHeaderAD() = adapterDelegate(R.layout.item_header) {
+
+ bind {
+ (itemView as TextView).text = context.resources
+ .getStringArray(R.array.scrobbling_statuses)
+ .getOrNull(item.ordinal)
+ }
+}
diff --git a/app/src/main/java/org/koitharu/kotatsu/scrobbling/common/ui/config/adapter/ScrobblingMangaAD.kt b/app/src/main/java/org/koitharu/kotatsu/scrobbling/common/ui/config/adapter/ScrobblingMangaAD.kt
new file mode 100644
index 000000000..fb04299f4
--- /dev/null
+++ b/app/src/main/java/org/koitharu/kotatsu/scrobbling/common/ui/config/adapter/ScrobblingMangaAD.kt
@@ -0,0 +1,42 @@
+package org.koitharu.kotatsu.scrobbling.common.ui.config.adapter
+
+import androidx.lifecycle.LifecycleOwner
+import coil.ImageLoader
+import com.hannesdorfmann.adapterdelegates4.dsl.adapterDelegateViewBinding
+import org.koitharu.kotatsu.R
+import org.koitharu.kotatsu.base.ui.list.AdapterDelegateClickListenerAdapter
+import org.koitharu.kotatsu.base.ui.list.OnListItemClickListener
+import org.koitharu.kotatsu.databinding.ItemScrobblingMangaBinding
+import org.koitharu.kotatsu.list.ui.model.ListModel
+import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblingInfo
+import org.koitharu.kotatsu.utils.ext.disposeImageRequest
+import org.koitharu.kotatsu.utils.ext.enqueueWith
+import org.koitharu.kotatsu.utils.ext.newImageRequest
+
+fun scrobblingMangaAD(
+ clickListener: OnListItemClickListener,
+ coil: ImageLoader,
+ lifecycleOwner: LifecycleOwner,
+) = adapterDelegateViewBinding(
+ { layoutInflater, parent -> ItemScrobblingMangaBinding.inflate(layoutInflater, parent, false) },
+) {
+
+ val clickListenerAdapter = AdapterDelegateClickListenerAdapter(this, clickListener)
+ itemView.setOnClickListener(clickListenerAdapter)
+
+ bind {
+ binding.imageViewCover.newImageRequest(item.coverUrl, null)?.run {
+ placeholder(R.drawable.ic_placeholder)
+ fallback(R.drawable.ic_placeholder)
+ error(R.drawable.ic_error_placeholder)
+ lifecycle(lifecycleOwner)
+ enqueueWith(coil)
+ }
+ binding.textViewTitle.text = item.title
+ binding.ratingBar.rating = item.rating * binding.ratingBar.numStars
+ }
+
+ onViewRecycled {
+ binding.imageViewCover.disposeImageRequest()
+ }
+}
diff --git a/app/src/main/java/org/koitharu/kotatsu/scrobbling/common/ui/config/adapter/ScrobblingMangaAdapter.kt b/app/src/main/java/org/koitharu/kotatsu/scrobbling/common/ui/config/adapter/ScrobblingMangaAdapter.kt
new file mode 100644
index 000000000..301836728
--- /dev/null
+++ b/app/src/main/java/org/koitharu/kotatsu/scrobbling/common/ui/config/adapter/ScrobblingMangaAdapter.kt
@@ -0,0 +1,48 @@
+package org.koitharu.kotatsu.scrobbling.common.ui.config.adapter
+
+import androidx.lifecycle.LifecycleOwner
+import androidx.recyclerview.widget.DiffUtil
+import coil.ImageLoader
+import com.hannesdorfmann.adapterdelegates4.AsyncListDifferDelegationAdapter
+import org.koitharu.kotatsu.base.ui.list.OnListItemClickListener
+import org.koitharu.kotatsu.list.ui.adapter.emptyStateListAD
+import org.koitharu.kotatsu.list.ui.model.EmptyState
+import org.koitharu.kotatsu.list.ui.model.ListModel
+import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblingInfo
+import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblingStatus
+
+class ScrobblingMangaAdapter(
+ clickListener: OnListItemClickListener,
+ coil: ImageLoader,
+ lifecycleOwner: LifecycleOwner,
+) : AsyncListDifferDelegationAdapter(DiffCallback()) {
+
+ init {
+ delegatesManager.addDelegate(scrobblingMangaAD(clickListener, coil, lifecycleOwner))
+ .addDelegate(scrobblingHeaderAD())
+ .addDelegate(emptyStateListAD(coil, null))
+ }
+
+ private class DiffCallback : DiffUtil.ItemCallback() {
+
+ override fun areItemsTheSame(oldItem: ListModel, newItem: ListModel): Boolean {
+ return when {
+ oldItem is ScrobblingInfo && newItem is ScrobblingInfo -> {
+ oldItem.targetId == newItem.targetId && oldItem.mangaId == newItem.mangaId
+ }
+
+ oldItem is ScrobblingStatus && newItem is ScrobblingStatus -> {
+ oldItem.ordinal == newItem.ordinal
+ }
+
+ oldItem is EmptyState && newItem is EmptyState -> true
+
+ else -> false
+ }
+ }
+
+ override fun areContentsTheSame(oldItem: ListModel, newItem: ListModel): Boolean {
+ return oldItem == newItem
+ }
+ }
+}
diff --git a/app/src/main/java/org/koitharu/kotatsu/scrobbling/ui/selector/ScrobblingSelectorBottomSheet.kt b/app/src/main/java/org/koitharu/kotatsu/scrobbling/common/ui/selector/ScrobblingSelectorBottomSheet.kt
similarity index 94%
rename from app/src/main/java/org/koitharu/kotatsu/scrobbling/ui/selector/ScrobblingSelectorBottomSheet.kt
rename to app/src/main/java/org/koitharu/kotatsu/scrobbling/common/ui/selector/ScrobblingSelectorBottomSheet.kt
index 32b84b4ca..488bdd57e 100644
--- a/app/src/main/java/org/koitharu/kotatsu/scrobbling/ui/selector/ScrobblingSelectorBottomSheet.kt
+++ b/app/src/main/java/org/koitharu/kotatsu/scrobbling/common/ui/selector/ScrobblingSelectorBottomSheet.kt
@@ -1,4 +1,4 @@
-package org.koitharu.kotatsu.scrobbling.ui.selector
+package org.koitharu.kotatsu.scrobbling.common.ui.selector
import android.app.Dialog
import android.content.DialogInterface
@@ -24,10 +24,10 @@ import org.koitharu.kotatsu.core.model.parcelable.ParcelableManga
import org.koitharu.kotatsu.databinding.SheetScrobblingSelectorBinding
import org.koitharu.kotatsu.list.ui.adapter.ListStateHolderListener
import org.koitharu.kotatsu.parsers.model.Manga
-import org.koitharu.kotatsu.scrobbling.domain.model.ScrobblerManga
-import org.koitharu.kotatsu.scrobbling.domain.model.ScrobblerService
-import org.koitharu.kotatsu.scrobbling.ui.selector.adapter.ScrobblerMangaSelectionDecoration
-import org.koitharu.kotatsu.scrobbling.ui.selector.adapter.ScrobblerSelectorAdapter
+import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblerManga
+import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblerService
+import org.koitharu.kotatsu.scrobbling.common.ui.selector.adapter.ScrobblerMangaSelectionDecoration
+import org.koitharu.kotatsu.scrobbling.common.ui.selector.adapter.ScrobblerSelectorAdapter
import org.koitharu.kotatsu.utils.ext.assistedViewModels
import org.koitharu.kotatsu.utils.ext.firstVisibleItemPosition
import org.koitharu.kotatsu.utils.ext.getDisplayMessage
diff --git a/app/src/main/java/org/koitharu/kotatsu/scrobbling/ui/selector/ScrobblingSelectorViewModel.kt b/app/src/main/java/org/koitharu/kotatsu/scrobbling/common/ui/selector/ScrobblingSelectorViewModel.kt
similarity index 94%
rename from app/src/main/java/org/koitharu/kotatsu/scrobbling/ui/selector/ScrobblingSelectorViewModel.kt
rename to app/src/main/java/org/koitharu/kotatsu/scrobbling/common/ui/selector/ScrobblingSelectorViewModel.kt
index 6c8a6ada1..318d2a2f8 100644
--- a/app/src/main/java/org/koitharu/kotatsu/scrobbling/ui/selector/ScrobblingSelectorViewModel.kt
+++ b/app/src/main/java/org/koitharu/kotatsu/scrobbling/common/ui/selector/ScrobblingSelectorViewModel.kt
@@ -1,4 +1,4 @@
-package org.koitharu.kotatsu.scrobbling.ui.selector
+package org.koitharu.kotatsu.scrobbling.common.ui.selector
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
@@ -18,9 +18,9 @@ import org.koitharu.kotatsu.list.ui.model.LoadingFooter
import org.koitharu.kotatsu.list.ui.model.LoadingState
import org.koitharu.kotatsu.parsers.model.Manga
import org.koitharu.kotatsu.parsers.util.runCatchingCancellable
-import org.koitharu.kotatsu.scrobbling.domain.Scrobbler
-import org.koitharu.kotatsu.scrobbling.domain.model.ScrobblerManga
-import org.koitharu.kotatsu.scrobbling.ui.selector.model.ScrobblerHint
+import org.koitharu.kotatsu.scrobbling.common.domain.Scrobbler
+import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblerManga
+import org.koitharu.kotatsu.scrobbling.common.ui.selector.model.ScrobblerHint
import org.koitharu.kotatsu.utils.SingleLiveEvent
import org.koitharu.kotatsu.utils.ext.asLiveDataDistinct
import org.koitharu.kotatsu.utils.ext.printStackTraceDebug
diff --git a/app/src/main/java/org/koitharu/kotatsu/scrobbling/ui/selector/adapter/ScrobblerHintAD.kt b/app/src/main/java/org/koitharu/kotatsu/scrobbling/common/ui/selector/adapter/ScrobblerHintAD.kt
similarity index 88%
rename from app/src/main/java/org/koitharu/kotatsu/scrobbling/ui/selector/adapter/ScrobblerHintAD.kt
rename to app/src/main/java/org/koitharu/kotatsu/scrobbling/common/ui/selector/adapter/ScrobblerHintAD.kt
index 311615826..90926f9fa 100644
--- a/app/src/main/java/org/koitharu/kotatsu/scrobbling/ui/selector/adapter/ScrobblerHintAD.kt
+++ b/app/src/main/java/org/koitharu/kotatsu/scrobbling/common/ui/selector/adapter/ScrobblerHintAD.kt
@@ -1,10 +1,10 @@
-package org.koitharu.kotatsu.scrobbling.ui.selector.adapter
+package org.koitharu.kotatsu.scrobbling.common.ui.selector.adapter
import com.hannesdorfmann.adapterdelegates4.dsl.adapterDelegateViewBinding
import org.koitharu.kotatsu.databinding.ItemEmptyHintBinding
import org.koitharu.kotatsu.list.ui.adapter.ListStateHolderListener
import org.koitharu.kotatsu.list.ui.model.ListModel
-import org.koitharu.kotatsu.scrobbling.ui.selector.model.ScrobblerHint
+import org.koitharu.kotatsu.scrobbling.common.ui.selector.model.ScrobblerHint
import org.koitharu.kotatsu.utils.ext.getDisplayMessage
import org.koitharu.kotatsu.utils.ext.setTextAndVisible
import org.koitharu.kotatsu.utils.ext.textAndVisible
diff --git a/app/src/main/java/org/koitharu/kotatsu/scrobbling/ui/selector/adapter/ScrobblerMangaSelectionDecoration.kt b/app/src/main/java/org/koitharu/kotatsu/scrobbling/common/ui/selector/adapter/ScrobblerMangaSelectionDecoration.kt
similarity index 90%
rename from app/src/main/java/org/koitharu/kotatsu/scrobbling/ui/selector/adapter/ScrobblerMangaSelectionDecoration.kt
rename to app/src/main/java/org/koitharu/kotatsu/scrobbling/common/ui/selector/adapter/ScrobblerMangaSelectionDecoration.kt
index ced1485fa..5b74f913a 100644
--- a/app/src/main/java/org/koitharu/kotatsu/scrobbling/ui/selector/adapter/ScrobblerMangaSelectionDecoration.kt
+++ b/app/src/main/java/org/koitharu/kotatsu/scrobbling/common/ui/selector/adapter/ScrobblerMangaSelectionDecoration.kt
@@ -1,4 +1,4 @@
-package org.koitharu.kotatsu.scrobbling.ui.selector.adapter
+package org.koitharu.kotatsu.scrobbling.common.ui.selector.adapter
import android.content.Context
import android.graphics.Canvas
@@ -8,7 +8,7 @@ import android.view.View
import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.RecyclerView.NO_ID
import org.koitharu.kotatsu.list.ui.MangaSelectionDecoration
-import org.koitharu.kotatsu.scrobbling.domain.model.ScrobblerManga
+import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblerManga
import org.koitharu.kotatsu.utils.ext.getItem
class ScrobblerMangaSelectionDecoration(context: Context) : MangaSelectionDecoration(context) {
diff --git a/app/src/main/java/org/koitharu/kotatsu/scrobbling/ui/selector/adapter/ScrobblerSelectorAdapter.kt b/app/src/main/java/org/koitharu/kotatsu/scrobbling/common/ui/selector/adapter/ScrobblerSelectorAdapter.kt
similarity index 87%
rename from app/src/main/java/org/koitharu/kotatsu/scrobbling/ui/selector/adapter/ScrobblerSelectorAdapter.kt
rename to app/src/main/java/org/koitharu/kotatsu/scrobbling/common/ui/selector/adapter/ScrobblerSelectorAdapter.kt
index d0f1d78b0..e3d7af6c6 100644
--- a/app/src/main/java/org/koitharu/kotatsu/scrobbling/ui/selector/adapter/ScrobblerSelectorAdapter.kt
+++ b/app/src/main/java/org/koitharu/kotatsu/scrobbling/common/ui/selector/adapter/ScrobblerSelectorAdapter.kt
@@ -1,4 +1,4 @@
-package org.koitharu.kotatsu.scrobbling.ui.selector.adapter
+package org.koitharu.kotatsu.scrobbling.common.ui.selector.adapter
import androidx.lifecycle.LifecycleOwner
import androidx.recyclerview.widget.DiffUtil
@@ -9,8 +9,8 @@ import org.koitharu.kotatsu.list.ui.adapter.ListStateHolderListener
import org.koitharu.kotatsu.list.ui.adapter.loadingFooterAD
import org.koitharu.kotatsu.list.ui.adapter.loadingStateAD
import org.koitharu.kotatsu.list.ui.model.ListModel
-import org.koitharu.kotatsu.scrobbling.domain.model.ScrobblerManga
-import org.koitharu.kotatsu.scrobbling.ui.selector.model.ScrobblerHint
+import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblerManga
+import org.koitharu.kotatsu.scrobbling.common.ui.selector.model.ScrobblerHint
import kotlin.jvm.internal.Intrinsics
class ScrobblerSelectorAdapter(
diff --git a/app/src/main/java/org/koitharu/kotatsu/scrobbling/ui/selector/adapter/ScrobblingMangaAD.kt b/app/src/main/java/org/koitharu/kotatsu/scrobbling/common/ui/selector/adapter/ScrobblingMangaAD.kt
similarity index 90%
rename from app/src/main/java/org/koitharu/kotatsu/scrobbling/ui/selector/adapter/ScrobblingMangaAD.kt
rename to app/src/main/java/org/koitharu/kotatsu/scrobbling/common/ui/selector/adapter/ScrobblingMangaAD.kt
index 73723229a..d56427fbd 100644
--- a/app/src/main/java/org/koitharu/kotatsu/scrobbling/ui/selector/adapter/ScrobblingMangaAD.kt
+++ b/app/src/main/java/org/koitharu/kotatsu/scrobbling/common/ui/selector/adapter/ScrobblingMangaAD.kt
@@ -1,4 +1,4 @@
-package org.koitharu.kotatsu.scrobbling.ui.selector.adapter
+package org.koitharu.kotatsu.scrobbling.common.ui.selector.adapter
import androidx.lifecycle.LifecycleOwner
import coil.ImageLoader
@@ -7,7 +7,7 @@ import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.base.ui.list.OnListItemClickListener
import org.koitharu.kotatsu.databinding.ItemMangaListBinding
import org.koitharu.kotatsu.list.ui.model.ListModel
-import org.koitharu.kotatsu.scrobbling.domain.model.ScrobblerManga
+import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblerManga
import org.koitharu.kotatsu.utils.ext.disposeImageRequest
import org.koitharu.kotatsu.utils.ext.enqueueWith
import org.koitharu.kotatsu.utils.ext.newImageRequest
diff --git a/app/src/main/java/org/koitharu/kotatsu/scrobbling/ui/selector/model/ScrobblerHint.kt b/app/src/main/java/org/koitharu/kotatsu/scrobbling/common/ui/selector/model/ScrobblerHint.kt
similarity index 93%
rename from app/src/main/java/org/koitharu/kotatsu/scrobbling/ui/selector/model/ScrobblerHint.kt
rename to app/src/main/java/org/koitharu/kotatsu/scrobbling/common/ui/selector/model/ScrobblerHint.kt
index e30614da2..83c122fa7 100644
--- a/app/src/main/java/org/koitharu/kotatsu/scrobbling/ui/selector/model/ScrobblerHint.kt
+++ b/app/src/main/java/org/koitharu/kotatsu/scrobbling/common/ui/selector/model/ScrobblerHint.kt
@@ -1,4 +1,4 @@
-package org.koitharu.kotatsu.scrobbling.ui.selector.model
+package org.koitharu.kotatsu.scrobbling.common.ui.selector.model
import androidx.annotation.DrawableRes
import androidx.annotation.StringRes
diff --git a/app/src/main/java/org/koitharu/kotatsu/scrobbling/domain/model/ScrobblingStatus.kt b/app/src/main/java/org/koitharu/kotatsu/scrobbling/domain/model/ScrobblingStatus.kt
deleted file mode 100644
index cfb408094..000000000
--- a/app/src/main/java/org/koitharu/kotatsu/scrobbling/domain/model/ScrobblingStatus.kt
+++ /dev/null
@@ -1,11 +0,0 @@
-package org.koitharu.kotatsu.scrobbling.domain.model
-
-enum class ScrobblingStatus {
-
- PLANNED,
- READING,
- RE_READING,
- COMPLETED,
- ON_HOLD,
- DROPPED,
-}
\ No newline at end of file
diff --git a/app/src/main/java/org/koitharu/kotatsu/scrobbling/mal/data/MALAuthenticator.kt b/app/src/main/java/org/koitharu/kotatsu/scrobbling/mal/data/MALAuthenticator.kt
index c0c650c0a..0e43a2e6b 100644
--- a/app/src/main/java/org/koitharu/kotatsu/scrobbling/mal/data/MALAuthenticator.kt
+++ b/app/src/main/java/org/koitharu/kotatsu/scrobbling/mal/data/MALAuthenticator.kt
@@ -7,9 +7,9 @@ import okhttp3.Response
import okhttp3.Route
import org.koitharu.kotatsu.BuildConfig
import org.koitharu.kotatsu.core.network.CommonHeaders
-import org.koitharu.kotatsu.scrobbling.data.ScrobblerStorage
-import org.koitharu.kotatsu.scrobbling.domain.model.ScrobblerService
-import org.koitharu.kotatsu.scrobbling.domain.model.ScrobblerType
+import org.koitharu.kotatsu.scrobbling.common.data.ScrobblerStorage
+import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblerService
+import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblerType
import javax.inject.Inject
import javax.inject.Provider
diff --git a/app/src/main/java/org/koitharu/kotatsu/scrobbling/mal/data/MALInterceptor.kt b/app/src/main/java/org/koitharu/kotatsu/scrobbling/mal/data/MALInterceptor.kt
index e7d28b261..f023d5f75 100644
--- a/app/src/main/java/org/koitharu/kotatsu/scrobbling/mal/data/MALInterceptor.kt
+++ b/app/src/main/java/org/koitharu/kotatsu/scrobbling/mal/data/MALInterceptor.kt
@@ -3,7 +3,7 @@ package org.koitharu.kotatsu.scrobbling.mal.data
import okhttp3.Interceptor
import okhttp3.Response
import org.koitharu.kotatsu.core.network.CommonHeaders
-import org.koitharu.kotatsu.scrobbling.data.ScrobblerStorage
+import org.koitharu.kotatsu.scrobbling.common.data.ScrobblerStorage
private const val JSON = "application/json"
diff --git a/app/src/main/java/org/koitharu/kotatsu/scrobbling/mal/data/MALRepository.kt b/app/src/main/java/org/koitharu/kotatsu/scrobbling/mal/data/MALRepository.kt
index f6adf275d..b4f026298 100644
--- a/app/src/main/java/org/koitharu/kotatsu/scrobbling/mal/data/MALRepository.kt
+++ b/app/src/main/java/org/koitharu/kotatsu/scrobbling/mal/data/MALRepository.kt
@@ -9,20 +9,18 @@ import org.koitharu.kotatsu.BuildConfig
import org.koitharu.kotatsu.core.db.MangaDatabase
import org.koitharu.kotatsu.parsers.model.MangaChapter
import org.koitharu.kotatsu.parsers.util.await
-import org.koitharu.kotatsu.parsers.util.json.mapJSON
+import org.koitharu.kotatsu.parsers.util.json.mapJSONNotNull
import org.koitharu.kotatsu.parsers.util.parseJson
-import org.koitharu.kotatsu.parsers.util.toIntUp
-import org.koitharu.kotatsu.scrobbling.data.ScrobblerRepository
-import org.koitharu.kotatsu.scrobbling.data.ScrobblerStorage
-import org.koitharu.kotatsu.scrobbling.data.ScrobblingEntity
-import org.koitharu.kotatsu.scrobbling.domain.model.ScrobblerManga
-import org.koitharu.kotatsu.scrobbling.domain.model.ScrobblerMangaInfo
-import org.koitharu.kotatsu.scrobbling.domain.model.ScrobblerService
-import org.koitharu.kotatsu.scrobbling.domain.model.ScrobblerUser
+import org.koitharu.kotatsu.scrobbling.common.data.ScrobblerStorage
+import org.koitharu.kotatsu.scrobbling.common.data.ScrobblingEntity
+import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblerManga
+import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblerMangaInfo
+import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblerService
+import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblerUser
import org.koitharu.kotatsu.utils.PKCEGenerator
private const val REDIRECT_URI = "kotatsu://mal-auth"
-private const val BASE_OAUTH_URL = "https://myanimelist.net"
+private const val BASE_WEB_URL = "https://myanimelist.net"
private const val BASE_API_URL = "https://api.myanimelist.net/v2"
private const val AVATAR_STUB = "https://cdn.myanimelist.net/images/questionmark_50.gif"
@@ -30,12 +28,12 @@ class MALRepository(
private val okHttp: OkHttpClient,
private val storage: ScrobblerStorage,
private val db: MangaDatabase,
-) : ScrobblerRepository {
+) : org.koitharu.kotatsu.scrobbling.common.data.ScrobblerRepository {
private var codeVerifier: String = getPKCEChallengeCode()
override val oauthUrl: String
- get() = "$BASE_OAUTH_URL/v1/oauth2/authorize?" +
+ get() = "$BASE_WEB_URL/v1/oauth2/authorize?" +
"response_type=code" +
"&client_id=${BuildConfig.MAL_CLIENT_ID}" +
"&redirect_uri=$REDIRECT_URI" +
@@ -61,7 +59,7 @@ class MALRepository(
}
val request = Request.Builder()
.post(body.build())
- .url("${BASE_OAUTH_URL}/v1/oauth2/token")
+ .url("${BASE_WEB_URL}/v1/oauth2/token")
val response = okHttp.newCall(request.build()).await().parseJson()
storage.accessToken = response.getString("access_token")
@@ -83,17 +81,15 @@ class MALRepository(
override suspend fun findManga(query: String, offset: Int): List {
val url = BASE_API_URL.toHttpUrl().newBuilder()
.addPathSegment("manga")
- .addQueryParameter("offset", offset.toFloat().toIntUp().toString())
+ .addQueryParameter("offset", offset.toString())
.addQueryParameter("nsfw", "true")
- .addQueryParameter(
- "q",
- query.take(64)
- ) // WARNING! MAL API throws a 400 when the query is over 64 characters
+ // WARNING! MAL API throws a 400 when the query is over 64 characters
+ .addQueryParameter("q", query.take(64))
.build()
val request = Request.Builder().url(url).get().build()
val response = okHttp.newCall(request).await().parseJson()
val data = response.getJSONArray("data")
- return data.mapJSON { jsonToManga(it) }
+ return data.mapJSONNotNull { jsonToManga(it) }
}
override suspend fun getMangaInfo(id: Long): ScrobblerMangaInfo {
@@ -181,7 +177,7 @@ class MALRepository(
return codeVerifier
}
- private fun jsonToManga(json: JSONObject): ScrobblerManga {
+ private fun jsonToManga(json: JSONObject): ScrobblerManga? {
for (i in 0 until json.length()) {
val node = json.getJSONObject("node")
return ScrobblerManga(
@@ -189,23 +185,17 @@ class MALRepository(
name = node.getString("title"),
altName = null,
cover = node.getJSONObject("main_picture").getString("large"),
- url = "https://myanimelist.net/manga/${node.getLong("id")}"
+ url = "$BASE_WEB_URL/manga/${node.getLong("id")}",
)
}
- return ScrobblerManga(
- id = 1,
- name = "",
- altName = null,
- cover = "",
- url = ""
- )
+ return null
}
private fun ScrobblerMangaInfo(json: JSONObject) = ScrobblerMangaInfo(
id = json.getLong("id"),
name = json.getString("title"),
cover = json.getJSONObject("main_picture").getString("large"),
- url = "https://myanimelist.net/manga/${json.getLong("id")}",
+ url = "$BASE_WEB_URL/manga/${json.getLong("id")}",
descriptionHtml = json.getString("synopsis"),
)
diff --git a/app/src/main/java/org/koitharu/kotatsu/scrobbling/mal/domain/MALScrobbler.kt b/app/src/main/java/org/koitharu/kotatsu/scrobbling/mal/domain/MALScrobbler.kt
index 7902865fb..ce5d040ee 100644
--- a/app/src/main/java/org/koitharu/kotatsu/scrobbling/mal/domain/MALScrobbler.kt
+++ b/app/src/main/java/org/koitharu/kotatsu/scrobbling/mal/domain/MALScrobbler.kt
@@ -1,12 +1,9 @@
package org.koitharu.kotatsu.scrobbling.mal.domain
import org.koitharu.kotatsu.core.db.MangaDatabase
-import org.koitharu.kotatsu.parsers.model.MangaChapter
-import org.koitharu.kotatsu.scrobbling.domain.Scrobbler
-import org.koitharu.kotatsu.scrobbling.domain.model.ScrobblerManga
-import org.koitharu.kotatsu.scrobbling.domain.model.ScrobblerMangaInfo
-import org.koitharu.kotatsu.scrobbling.domain.model.ScrobblerService
-import org.koitharu.kotatsu.scrobbling.domain.model.ScrobblingStatus
+import org.koitharu.kotatsu.scrobbling.common.domain.Scrobbler
+import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblerService
+import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblingStatus
import org.koitharu.kotatsu.scrobbling.mal.data.MALRepository
import javax.inject.Inject
import javax.inject.Singleton
diff --git a/app/src/main/java/org/koitharu/kotatsu/scrobbling/mal/ui/MALSettingsFragment.kt b/app/src/main/java/org/koitharu/kotatsu/scrobbling/mal/ui/MALSettingsFragment.kt
deleted file mode 100644
index ec0b185cd..000000000
--- a/app/src/main/java/org/koitharu/kotatsu/scrobbling/mal/ui/MALSettingsFragment.kt
+++ /dev/null
@@ -1,86 +0,0 @@
-package org.koitharu.kotatsu.scrobbling.mal.ui
-
-import android.content.Intent
-import android.net.Uri
-import android.os.Bundle
-import android.view.View
-import androidx.preference.Preference
-import coil.ImageLoader
-import coil.request.ImageRequest
-import coil.transform.CircleCropTransformation
-import dagger.hilt.android.AndroidEntryPoint
-import org.koitharu.kotatsu.R
-import org.koitharu.kotatsu.base.ui.BasePreferenceFragment
-import org.koitharu.kotatsu.scrobbling.domain.model.ScrobblerUser
-import org.koitharu.kotatsu.utils.PreferenceIconTarget
-import org.koitharu.kotatsu.utils.ext.assistedViewModels
-import org.koitharu.kotatsu.utils.ext.enqueueWith
-import org.koitharu.kotatsu.utils.ext.withArgs
-import javax.inject.Inject
-
-@AndroidEntryPoint
-class MALSettingsFragment : BasePreferenceFragment(R.string.mal) {
-
- @Inject
- lateinit var coil: ImageLoader
-
- @Inject
- lateinit var viewModelFactory: MALSettingsViewModel.Factory
-
- private val viewModel by assistedViewModels {
- viewModelFactory.create(arguments?.getString(ARG_AUTH_CODE))
- }
-
- override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
- addPreferencesFromResource(R.xml.pref_mal)
- }
-
- override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
- super.onViewCreated(view, savedInstanceState)
- viewModel.user.observe(viewLifecycleOwner, this::onUserChanged)
- }
-
- override fun onPreferenceTreeClick(preference: Preference): Boolean {
- return when (preference.key) {
- KEY_USER -> openAuthorization()
- KEY_LOGOUT -> {
- viewModel.logout()
- true
- }
- else -> super.onPreferenceTreeClick(preference)
- }
- }
-
- private fun onUserChanged(user: ScrobblerUser?) {
- val pref = findPreference(KEY_USER) ?: return
- pref.isSelectable = user == null
- pref.title = user?.nickname ?: getString(R.string.sign_in)
- ImageRequest.Builder(requireContext())
- .data(user?.avatar)
- .transformations(CircleCropTransformation())
- .target(PreferenceIconTarget(pref))
- .enqueueWith(coil)
- findPreference(KEY_LOGOUT)?.isVisible = user != null
- }
-
- private fun openAuthorization(): Boolean {
- return runCatching {
- val intent = Intent(Intent.ACTION_VIEW)
- intent.data = Uri.parse(viewModel.authorizationUrl)
- startActivity(intent)
- }.isSuccess
- }
-
- companion object {
-
- private const val KEY_USER = "mal_user"
- private const val KEY_LOGOUT = "mal_logout"
-
- private const val ARG_AUTH_CODE = "auth_code"
-
- fun newInstance(authCode: String?) = MALSettingsFragment().withArgs(1) {
- putString(ARG_AUTH_CODE, authCode)
- }
- }
-}
-
diff --git a/app/src/main/java/org/koitharu/kotatsu/scrobbling/mal/ui/MALSettingsViewModel.kt b/app/src/main/java/org/koitharu/kotatsu/scrobbling/mal/ui/MALSettingsViewModel.kt
deleted file mode 100644
index 709837678..000000000
--- a/app/src/main/java/org/koitharu/kotatsu/scrobbling/mal/ui/MALSettingsViewModel.kt
+++ /dev/null
@@ -1,57 +0,0 @@
-package org.koitharu.kotatsu.scrobbling.mal.ui
-
-import androidx.lifecycle.MutableLiveData
-import dagger.assisted.Assisted
-import dagger.assisted.AssistedFactory
-import dagger.assisted.AssistedInject
-import kotlinx.coroutines.Dispatchers
-import org.koitharu.kotatsu.base.ui.BaseViewModel
-import org.koitharu.kotatsu.scrobbling.domain.model.ScrobblerUser
-import org.koitharu.kotatsu.scrobbling.mal.data.MALRepository
-
-class MALSettingsViewModel @AssistedInject constructor(
- private val repository: MALRepository,
- @Assisted authCode: String?,
-) : BaseViewModel() {
-
- val authorizationUrl: String
- get() = repository.oauthUrl
-
- val user = MutableLiveData()
-
- init {
- if (authCode != null) {
- authorize(authCode)
- } else {
- loadUser()
- }
- }
-
- fun logout() {
- launchJob(Dispatchers.Default) {
- repository.logout()
- user.postValue(null)
- }
- }
-
- private fun loadUser() = launchJob(Dispatchers.Default) {
- val userModel = if (repository.isAuthorized) {
- repository.cachedUser?.let(user::postValue)
- repository.loadUser()
- } else {
- null
- }
- user.postValue(userModel)
- }
-
- private fun authorize(code: String) = launchJob(Dispatchers.Default) {
- repository.authorize(code)
- user.postValue(repository.loadUser())
- }
-
- @AssistedFactory
- interface Factory {
-
- fun create(authCode: String?): MALSettingsViewModel
- }
-}
diff --git a/app/src/main/java/org/koitharu/kotatsu/scrobbling/shikimori/data/ShikimoriAuthenticator.kt b/app/src/main/java/org/koitharu/kotatsu/scrobbling/shikimori/data/ShikimoriAuthenticator.kt
index dbaad2cc7..52b3f9550 100644
--- a/app/src/main/java/org/koitharu/kotatsu/scrobbling/shikimori/data/ShikimoriAuthenticator.kt
+++ b/app/src/main/java/org/koitharu/kotatsu/scrobbling/shikimori/data/ShikimoriAuthenticator.kt
@@ -7,9 +7,9 @@ import okhttp3.Response
import okhttp3.Route
import org.koitharu.kotatsu.BuildConfig
import org.koitharu.kotatsu.core.network.CommonHeaders
-import org.koitharu.kotatsu.scrobbling.data.ScrobblerStorage
-import org.koitharu.kotatsu.scrobbling.domain.model.ScrobblerService
-import org.koitharu.kotatsu.scrobbling.domain.model.ScrobblerType
+import org.koitharu.kotatsu.scrobbling.common.data.ScrobblerStorage
+import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblerService
+import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblerType
import javax.inject.Inject
import javax.inject.Provider
diff --git a/app/src/main/java/org/koitharu/kotatsu/scrobbling/shikimori/data/ShikimoriInterceptor.kt b/app/src/main/java/org/koitharu/kotatsu/scrobbling/shikimori/data/ShikimoriInterceptor.kt
index 466382960..dfd6e93aa 100644
--- a/app/src/main/java/org/koitharu/kotatsu/scrobbling/shikimori/data/ShikimoriInterceptor.kt
+++ b/app/src/main/java/org/koitharu/kotatsu/scrobbling/shikimori/data/ShikimoriInterceptor.kt
@@ -4,7 +4,7 @@ import okhttp3.Interceptor
import okhttp3.Response
import okio.IOException
import org.koitharu.kotatsu.core.network.CommonHeaders
-import org.koitharu.kotatsu.scrobbling.data.ScrobblerStorage
+import org.koitharu.kotatsu.scrobbling.common.data.ScrobblerStorage
private const val USER_AGENT_SHIKIMORI = "Kotatsu"
diff --git a/app/src/main/java/org/koitharu/kotatsu/scrobbling/shikimori/data/ShikimoriRepository.kt b/app/src/main/java/org/koitharu/kotatsu/scrobbling/shikimori/data/ShikimoriRepository.kt
index 5b86c937b..ecee1125a 100644
--- a/app/src/main/java/org/koitharu/kotatsu/scrobbling/shikimori/data/ShikimoriRepository.kt
+++ b/app/src/main/java/org/koitharu/kotatsu/scrobbling/shikimori/data/ShikimoriRepository.kt
@@ -14,13 +14,13 @@ import org.koitharu.kotatsu.parsers.util.json.mapJSON
import org.koitharu.kotatsu.parsers.util.parseJson
import org.koitharu.kotatsu.parsers.util.parseJsonArray
import org.koitharu.kotatsu.parsers.util.toAbsoluteUrl
-import org.koitharu.kotatsu.scrobbling.data.ScrobblerRepository
-import org.koitharu.kotatsu.scrobbling.data.ScrobblerStorage
-import org.koitharu.kotatsu.scrobbling.data.ScrobblingEntity
-import org.koitharu.kotatsu.scrobbling.domain.model.ScrobblerManga
-import org.koitharu.kotatsu.scrobbling.domain.model.ScrobblerMangaInfo
-import org.koitharu.kotatsu.scrobbling.domain.model.ScrobblerService
-import org.koitharu.kotatsu.scrobbling.domain.model.ScrobblerUser
+import org.koitharu.kotatsu.scrobbling.common.data.ScrobblerRepository
+import org.koitharu.kotatsu.scrobbling.common.data.ScrobblerStorage
+import org.koitharu.kotatsu.scrobbling.common.data.ScrobblingEntity
+import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblerManga
+import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblerMangaInfo
+import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblerService
+import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblerUser
import org.koitharu.kotatsu.utils.ext.toRequestBody
private const val REDIRECT_URI = "kotatsu://shikimori-auth"
diff --git a/app/src/main/java/org/koitharu/kotatsu/scrobbling/shikimori/domain/ShikimoriScrobbler.kt b/app/src/main/java/org/koitharu/kotatsu/scrobbling/shikimori/domain/ShikimoriScrobbler.kt
index 5c73c0532..e7a06d53c 100644
--- a/app/src/main/java/org/koitharu/kotatsu/scrobbling/shikimori/domain/ShikimoriScrobbler.kt
+++ b/app/src/main/java/org/koitharu/kotatsu/scrobbling/shikimori/domain/ShikimoriScrobbler.kt
@@ -1,9 +1,9 @@
package org.koitharu.kotatsu.scrobbling.shikimori.domain
import org.koitharu.kotatsu.core.db.MangaDatabase
-import org.koitharu.kotatsu.scrobbling.domain.Scrobbler
-import org.koitharu.kotatsu.scrobbling.domain.model.ScrobblerService
-import org.koitharu.kotatsu.scrobbling.domain.model.ScrobblingStatus
+import org.koitharu.kotatsu.scrobbling.common.domain.Scrobbler
+import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblerService
+import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblingStatus
import org.koitharu.kotatsu.scrobbling.shikimori.data.ShikimoriRepository
import javax.inject.Inject
import javax.inject.Singleton
diff --git a/app/src/main/java/org/koitharu/kotatsu/scrobbling/shikimori/ui/ShikimoriSettingsFragment.kt b/app/src/main/java/org/koitharu/kotatsu/scrobbling/shikimori/ui/ShikimoriSettingsFragment.kt
deleted file mode 100644
index da45cf4ed..000000000
--- a/app/src/main/java/org/koitharu/kotatsu/scrobbling/shikimori/ui/ShikimoriSettingsFragment.kt
+++ /dev/null
@@ -1,86 +0,0 @@
-package org.koitharu.kotatsu.scrobbling.shikimori.ui
-
-import android.content.Intent
-import android.net.Uri
-import android.os.Bundle
-import android.view.View
-import androidx.preference.Preference
-import coil.ImageLoader
-import coil.request.ImageRequest
-import coil.transform.CircleCropTransformation
-import dagger.hilt.android.AndroidEntryPoint
-import org.koitharu.kotatsu.R
-import org.koitharu.kotatsu.base.ui.BasePreferenceFragment
-import org.koitharu.kotatsu.scrobbling.domain.model.ScrobblerUser
-import org.koitharu.kotatsu.utils.PreferenceIconTarget
-import org.koitharu.kotatsu.utils.ext.assistedViewModels
-import org.koitharu.kotatsu.utils.ext.enqueueWith
-import org.koitharu.kotatsu.utils.ext.withArgs
-import javax.inject.Inject
-
-@AndroidEntryPoint
-class ShikimoriSettingsFragment : BasePreferenceFragment(R.string.shikimori) {
-
- @Inject
- lateinit var coil: ImageLoader
-
- @Inject
- lateinit var viewModelFactory: ShikimoriSettingsViewModel.Factory
-
- private val viewModel by assistedViewModels {
- viewModelFactory.create(arguments?.getString(ARG_AUTH_CODE))
- }
-
- override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
- addPreferencesFromResource(R.xml.pref_shikimori)
- }
-
- override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
- super.onViewCreated(view, savedInstanceState)
- viewModel.user.observe(viewLifecycleOwner, this::onUserChanged)
- }
-
- override fun onPreferenceTreeClick(preference: Preference): Boolean {
- return when (preference.key) {
- KEY_USER -> openAuthorization()
- KEY_LOGOUT -> {
- viewModel.logout()
- true
- }
-
- else -> super.onPreferenceTreeClick(preference)
- }
- }
-
- private fun onUserChanged(user: ScrobblerUser?) {
- val pref = findPreference(KEY_USER) ?: return
- pref.isSelectable = user == null
- pref.title = user?.nickname ?: getString(R.string.sign_in)
- ImageRequest.Builder(requireContext())
- .data(user?.avatar)
- .transformations(CircleCropTransformation())
- .target(PreferenceIconTarget(pref))
- .enqueueWith(coil)
- findPreference(KEY_LOGOUT)?.isVisible = user != null
- }
-
- private fun openAuthorization(): Boolean {
- return runCatching {
- val intent = Intent(Intent.ACTION_VIEW)
- intent.data = Uri.parse(viewModel.authorizationUrl)
- startActivity(intent)
- }.isSuccess
- }
-
- companion object {
-
- private const val KEY_USER = "shiki_user"
- private const val KEY_LOGOUT = "shiki_logout"
-
- private const val ARG_AUTH_CODE = "auth_code"
-
- fun newInstance(authCode: String?) = ShikimoriSettingsFragment().withArgs(1) {
- putString(ARG_AUTH_CODE, authCode)
- }
- }
-}
diff --git a/app/src/main/java/org/koitharu/kotatsu/scrobbling/shikimori/ui/ShikimoriSettingsViewModel.kt b/app/src/main/java/org/koitharu/kotatsu/scrobbling/shikimori/ui/ShikimoriSettingsViewModel.kt
deleted file mode 100644
index 2e689e673..000000000
--- a/app/src/main/java/org/koitharu/kotatsu/scrobbling/shikimori/ui/ShikimoriSettingsViewModel.kt
+++ /dev/null
@@ -1,57 +0,0 @@
-package org.koitharu.kotatsu.scrobbling.shikimori.ui
-
-import androidx.lifecycle.MutableLiveData
-import dagger.assisted.Assisted
-import dagger.assisted.AssistedFactory
-import dagger.assisted.AssistedInject
-import kotlinx.coroutines.Dispatchers
-import org.koitharu.kotatsu.base.ui.BaseViewModel
-import org.koitharu.kotatsu.scrobbling.domain.model.ScrobblerUser
-import org.koitharu.kotatsu.scrobbling.shikimori.data.ShikimoriRepository
-
-class ShikimoriSettingsViewModel @AssistedInject constructor(
- private val repository: ShikimoriRepository,
- @Assisted authCode: String?,
-) : BaseViewModel() {
-
- val authorizationUrl: String
- get() = repository.oauthUrl
-
- val user = MutableLiveData()
-
- init {
- if (authCode != null) {
- authorize(authCode)
- } else {
- loadUser()
- }
- }
-
- fun logout() {
- launchJob(Dispatchers.Default) {
- repository.logout()
- user.postValue(null)
- }
- }
-
- private fun loadUser() = launchJob(Dispatchers.Default) {
- val userModel = if (repository.isAuthorized) {
- repository.cachedUser?.let(user::postValue)
- repository.loadUser()
- } else {
- null
- }
- user.postValue(userModel)
- }
-
- private fun authorize(code: String) = launchJob(Dispatchers.Default) {
- repository.authorize(code)
- user.postValue(repository.loadUser())
- }
-
- @AssistedFactory
- interface Factory {
-
- fun create(authCode: String?): ShikimoriSettingsViewModel
- }
-}
diff --git a/app/src/main/java/org/koitharu/kotatsu/settings/HistorySettingsFragment.kt b/app/src/main/java/org/koitharu/kotatsu/settings/HistorySettingsFragment.kt
index beccdf6f5..7833095f4 100644
--- a/app/src/main/java/org/koitharu/kotatsu/settings/HistorySettingsFragment.kt
+++ b/app/src/main/java/org/koitharu/kotatsu/settings/HistorySettingsFragment.kt
@@ -20,7 +20,8 @@ import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.local.data.CacheDir
import org.koitharu.kotatsu.local.data.LocalStorageManager
import org.koitharu.kotatsu.scrobbling.anilist.data.AniListRepository
-import org.koitharu.kotatsu.scrobbling.data.ScrobblerRepository
+import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblerService
+import org.koitharu.kotatsu.scrobbling.common.ui.config.ScrobblerConfigActivity
import org.koitharu.kotatsu.scrobbling.mal.data.MALRepository
import org.koitharu.kotatsu.scrobbling.shikimori.data.ShikimoriRepository
import org.koitharu.kotatsu.search.domain.MangaSearchRepository
@@ -130,28 +131,28 @@ class HistorySettingsFragment : BasePreferenceFragment(R.string.history_and_cach
AppSettings.KEY_SHIKIMORI -> {
if (!shikimoriRepository.isAuthorized) {
launchScrobblerAuth(shikimoriRepository)
- true
} else {
- super.onPreferenceTreeClick(preference)
+ startActivity(ScrobblerConfigActivity.newIntent(preference.context, ScrobblerService.SHIKIMORI))
}
+ true
}
AppSettings.KEY_MAL -> {
if (!malRepository.isAuthorized) {
launchScrobblerAuth(malRepository)
- true
} else {
- super.onPreferenceTreeClick(preference)
+ startActivity(ScrobblerConfigActivity.newIntent(preference.context, ScrobblerService.MAL))
}
+ true
}
AppSettings.KEY_ANILIST -> {
if (!aniListRepository.isAuthorized) {
launchScrobblerAuth(aniListRepository)
- true
} else {
- super.onPreferenceTreeClick(preference)
+ startActivity(ScrobblerConfigActivity.newIntent(preference.context, ScrobblerService.ANILIST))
}
+ true
}
else -> super.onPreferenceTreeClick(preference)
@@ -217,7 +218,10 @@ class HistorySettingsFragment : BasePreferenceFragment(R.string.history_and_cach
}.show()
}
- private fun bindScrobblerSummary(key: String, repository: ScrobblerRepository) {
+ private fun bindScrobblerSummary(
+ key: String,
+ repository: org.koitharu.kotatsu.scrobbling.common.data.ScrobblerRepository
+ ) {
val pref = findPreference(key) ?: return
if (!repository.isAuthorized) {
pref.setSummary(R.string.disabled)
@@ -242,7 +246,7 @@ class HistorySettingsFragment : BasePreferenceFragment(R.string.history_and_cach
}
}
- private fun launchScrobblerAuth(repository: ScrobblerRepository) {
+ private fun launchScrobblerAuth(repository: org.koitharu.kotatsu.scrobbling.common.data.ScrobblerRepository) {
runCatching {
val intent = Intent(Intent.ACTION_VIEW)
intent.data = Uri.parse(repository.oauthUrl)
diff --git a/app/src/main/java/org/koitharu/kotatsu/settings/SettingsActivity.kt b/app/src/main/java/org/koitharu/kotatsu/settings/SettingsActivity.kt
index 21bea36ed..eadf48103 100644
--- a/app/src/main/java/org/koitharu/kotatsu/settings/SettingsActivity.kt
+++ b/app/src/main/java/org/koitharu/kotatsu/settings/SettingsActivity.kt
@@ -3,7 +3,6 @@ package org.koitharu.kotatsu.settings
import android.content.ComponentName
import android.content.Context
import android.content.Intent
-import android.net.Uri
import android.os.Bundle
import android.view.Menu
import android.view.MenuItem
@@ -24,9 +23,6 @@ import org.koitharu.kotatsu.base.ui.util.RecyclerViewOwner
import org.koitharu.kotatsu.databinding.ActivitySettingsBinding
import org.koitharu.kotatsu.main.ui.owners.AppBarOwner
import org.koitharu.kotatsu.parsers.model.MangaSource
-import org.koitharu.kotatsu.scrobbling.anilist.ui.AniListSettingsFragment
-import org.koitharu.kotatsu.scrobbling.mal.ui.MALSettingsFragment
-import org.koitharu.kotatsu.scrobbling.shikimori.ui.ShikimoriSettingsFragment
import org.koitharu.kotatsu.settings.sources.SourcesSettingsFragment
import org.koitharu.kotatsu.settings.tracker.TrackerSettingsFragment
import org.koitharu.kotatsu.utils.ext.isScrolledToTop
@@ -126,10 +122,8 @@ class SettingsActivity :
private fun openDefaultFragment() {
val fragment = when (intent?.action) {
- Intent.ACTION_VIEW -> handleUri(intent.data) ?: return
ACTION_READER -> ReaderSettingsFragment()
ACTION_SUGGESTIONS -> SuggestionsSettingsFragment()
- ACTION_SHIKIMORI -> ShikimoriSettingsFragment()
ACTION_HISTORY -> HistorySettingsFragment()
ACTION_TRACKER -> TrackerSettingsFragment()
ACTION_SOURCE -> SourceSettingsFragment.newInstance(
@@ -145,21 +139,6 @@ class SettingsActivity :
}
}
- private fun handleUri(uri: Uri?): Fragment? {
- when (uri?.host) {
- HOST_SHIKIMORI_AUTH ->
- return ShikimoriSettingsFragment.newInstance(authCode = uri.getQueryParameter("code"))
-
- HOST_ANILIST_AUTH ->
- return AniListSettingsFragment.newInstance(authCode = uri.getQueryParameter("code"))
-
- HOST_MAL_AUTH ->
- return MALSettingsFragment.newInstance(authCode = uri.getQueryParameter("code"))
- }
- finishAfterTransition()
- return null
- }
-
companion object {
private const val ACTION_READER = "${BuildConfig.APPLICATION_ID}.action.MANAGE_READER_SETTINGS"
@@ -171,20 +150,12 @@ class SettingsActivity :
private const val ACTION_MANAGE_SOURCES = "${BuildConfig.APPLICATION_ID}.action.MANAGE_SOURCES_LIST"
private const val EXTRA_SOURCE = "source"
- private const val HOST_SHIKIMORI_AUTH = "shikimori-auth"
- private const val HOST_ANILIST_AUTH = "anilist-auth"
- private const val HOST_MAL_AUTH = "mal-auth"
-
fun newIntent(context: Context) = Intent(context, SettingsActivity::class.java)
fun newReaderSettingsIntent(context: Context) =
Intent(context, SettingsActivity::class.java)
.setAction(ACTION_READER)
- fun newShikimoriSettingsIntent(context: Context) =
- Intent(context, SettingsActivity::class.java)
- .setAction(ACTION_SHIKIMORI)
-
fun newSuggestionsSettingsIntent(context: Context) =
Intent(context, SettingsActivity::class.java)
.setAction(ACTION_SUGGESTIONS)
diff --git a/app/src/main/java/org/koitharu/kotatsu/tracker/ui/feed/FeedFragment.kt b/app/src/main/java/org/koitharu/kotatsu/tracker/ui/feed/FeedFragment.kt
index f4e7ed794..95b51d35a 100644
--- a/app/src/main/java/org/koitharu/kotatsu/tracker/ui/feed/FeedFragment.kt
+++ b/app/src/main/java/org/koitharu/kotatsu/tracker/ui/feed/FeedFragment.kt
@@ -41,8 +41,6 @@ class FeedFragment :
private val viewModel by viewModels()
private var feedAdapter: FeedAdapter? = null
- private var paddingVertical = 0
- private var paddingHorizontal = 0
override fun onInflateView(
inflater: LayoutInflater,
@@ -57,8 +55,6 @@ class FeedFragment :
setHasFixedSize(true)
addOnScrollListener(PaginationScrollListener(4, this@FeedFragment))
val spacing = resources.getDimensionPixelOffset(R.dimen.list_spacing)
- paddingHorizontal = spacing
- paddingVertical = resources.getDimensionPixelOffset(R.dimen.grid_spacing_outer)
val decoration = TypedSpacingItemDecoration(
FeedAdapter.ITEM_TYPE_FEED to 0,
fallbackSpacing = spacing,
diff --git a/app/src/main/java/org/koitharu/kotatsu/utils/ext/FlowExt.kt b/app/src/main/java/org/koitharu/kotatsu/utils/ext/FlowExt.kt
index 03ac09a19..4c08eec67 100644
--- a/app/src/main/java/org/koitharu/kotatsu/utils/ext/FlowExt.kt
+++ b/app/src/main/java/org/koitharu/kotatsu/utils/ext/FlowExt.kt
@@ -2,7 +2,12 @@ package org.koitharu.kotatsu.utils.ext
import android.os.SystemClock
import kotlinx.coroutines.delay
-import kotlinx.coroutines.flow.*
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.onCompletion
+import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.flow.transformLatest
fun Flow.onFirst(action: suspend (T) -> Unit): Flow {
var isFirstCall = true
@@ -11,6 +16,8 @@ fun Flow.onFirst(action: suspend (T) -> Unit): Flow {
action(it)
isFirstCall = false
}
+ }.onCompletion {
+ isFirstCall = true
}
}
diff --git a/app/src/main/res/drawable-hdpi/ic_shikimori.png b/app/src/main/res/drawable-hdpi/ic_shikimori_raw.png
similarity index 100%
rename from app/src/main/res/drawable-hdpi/ic_shikimori.png
rename to app/src/main/res/drawable-hdpi/ic_shikimori_raw.png
diff --git a/app/src/main/res/drawable-mdpi/ic_shikimori.png b/app/src/main/res/drawable-mdpi/ic_shikimori_raw.png
similarity index 100%
rename from app/src/main/res/drawable-mdpi/ic_shikimori.png
rename to app/src/main/res/drawable-mdpi/ic_shikimori_raw.png
diff --git a/app/src/main/res/drawable-xhdpi/ic_shikimori.png b/app/src/main/res/drawable-xhdpi/ic_shikimori_raw.png
similarity index 100%
rename from app/src/main/res/drawable-xhdpi/ic_shikimori.png
rename to app/src/main/res/drawable-xhdpi/ic_shikimori_raw.png
diff --git a/app/src/main/res/drawable-xxhdpi/ic_shikimori.png b/app/src/main/res/drawable-xxhdpi/ic_shikimori_raw.png
similarity index 100%
rename from app/src/main/res/drawable-xxhdpi/ic_shikimori.png
rename to app/src/main/res/drawable-xxhdpi/ic_shikimori_raw.png
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_shikimori.png b/app/src/main/res/drawable-xxxhdpi/ic_shikimori_raw.png
similarity index 100%
rename from app/src/main/res/drawable-xxxhdpi/ic_shikimori.png
rename to app/src/main/res/drawable-xxxhdpi/ic_shikimori_raw.png
diff --git a/app/src/main/res/drawable/ic_anilist.xml b/app/src/main/res/drawable/ic_anilist.xml
index 3be2a1500..88a718884 100644
--- a/app/src/main/res/drawable/ic_anilist.xml
+++ b/app/src/main/res/drawable/ic_anilist.xml
@@ -2,6 +2,7 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
+ android:tint="?colorControlNormal"
android:viewportWidth="18"
android:viewportHeight="18">
+
diff --git a/app/src/main/res/layout/activity_scrobbler_config.xml b/app/src/main/res/layout/activity_scrobbler_config.xml
new file mode 100644
index 000000000..1bdc1a44d
--- /dev/null
+++ b/app/src/main/res/layout/activity_scrobbler_config.xml
@@ -0,0 +1,74 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/item_scrobbling_manga.xml b/app/src/main/res/layout/item_scrobbling_manga.xml
new file mode 100644
index 000000000..512ca35e9
--- /dev/null
+++ b/app/src/main/res/layout/item_scrobbling_manga.xml
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 0aab41752..704426500 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -416,4 +416,6 @@
Mion
Rikka
Sakura
+ There is nothing here
+ To track reading progress, select Menu → Track on the manga details screen.
diff --git a/app/src/main/res/xml/pref_anilist.xml b/app/src/main/res/xml/pref_anilist.xml
deleted file mode 100644
index 7cd04cada..000000000
--- a/app/src/main/res/xml/pref_anilist.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
-
-
-
-
-
-
diff --git a/app/src/main/res/xml/pref_history.xml b/app/src/main/res/xml/pref_history.xml
index b0975f4c5..2aafbb923 100644
--- a/app/src/main/res/xml/pref_history.xml
+++ b/app/src/main/res/xml/pref_history.xml
@@ -22,23 +22,20 @@
-
-
-
+ android:title="@string/shikimori"
+ app:icon="@drawable/ic_shikimori" />
-
+ android:title="@string/anilist"
+ app:icon="@drawable/ic_anilist" />
+
+
diff --git a/app/src/main/res/xml/pref_mal.xml b/app/src/main/res/xml/pref_mal.xml
deleted file mode 100644
index 67a9fb806..000000000
--- a/app/src/main/res/xml/pref_mal.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
-
-
-
-
-
-
diff --git a/app/src/main/res/xml/pref_shikimori.xml b/app/src/main/res/xml/pref_shikimori.xml
deleted file mode 100644
index 0e8d9118f..000000000
--- a/app/src/main/res/xml/pref_shikimori.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
-
-
-
-
-
-