feature/kitsu
Zakhar Timoshenko 3 years ago
parent d5c24cd5c8
commit 41551451b0

@ -161,6 +161,10 @@
</intent-filter> </intent-filter>
</activity> </activity>
<activity
android:name=".scrobbling.kitsu.ui.KitsuAuthActivity"
android:exported="false"
android:label="@string/kitsu" />
<service <service
android:name="org.koitharu.kotatsu.download.ui.service.DownloadService" android:name="org.koitharu.kotatsu.download.ui.service.DownloadService"

@ -13,5 +13,5 @@ enum class ScrobblerService(
SHIKIMORI(1, R.string.shikimori, R.drawable.ic_shikimori), SHIKIMORI(1, R.string.shikimori, R.drawable.ic_shikimori),
ANILIST(2, R.string.anilist, R.drawable.ic_anilist), ANILIST(2, R.string.anilist, R.drawable.ic_anilist),
MAL(3, R.string.mal, R.drawable.ic_mal), MAL(3, R.string.mal, R.drawable.ic_mal),
KITSU(4, R.string.kitsu, R.drawable.ic_script) KITSU(4, R.string.kitsu, R.drawable.ic_kitsu)
} }

@ -2,14 +2,19 @@ package org.koitharu.kotatsu.scrobbling.kitsu.data
import android.content.Context import android.content.Context
import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.android.qualifiers.ApplicationContext
import okhttp3.FormBody
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import okhttp3.Request
import org.koitharu.kotatsu.R import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.db.MangaDatabase import org.koitharu.kotatsu.core.db.MangaDatabase
import org.koitharu.kotatsu.parsers.model.MangaChapter import org.koitharu.kotatsu.parsers.model.MangaChapter
import org.koitharu.kotatsu.parsers.util.await
import org.koitharu.kotatsu.parsers.util.parseJson
import org.koitharu.kotatsu.scrobbling.common.data.ScrobblerRepository import org.koitharu.kotatsu.scrobbling.common.data.ScrobblerRepository
import org.koitharu.kotatsu.scrobbling.common.data.ScrobblerStorage import org.koitharu.kotatsu.scrobbling.common.data.ScrobblerStorage
import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblerManga 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.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.ScrobblerUser
private const val BASE_WEB_URL = "https://kitsu.io" private const val BASE_WEB_URL = "https://kitsu.io"
@ -24,22 +29,32 @@ class KitsuRepository(
private val clientId = context.getString(R.string.kitsu_clientId) private val clientId = context.getString(R.string.kitsu_clientId)
private val clientSecret = context.getString(R.string.kitsu_clientSecret) private val clientSecret = context.getString(R.string.kitsu_clientSecret)
override val oauthUrl: String override val oauthUrl: String = ""
get() = "${BASE_WEB_URL}/api/oauth2/token" +
"?username=..." + // Get from AlertDialog...
"&password=..." + // Get from AlertDialog...
"&grant_type=password" +
"&client_id=$clientId" +
"&client_secret=$clientSecret"
override val isAuthorized: Boolean override val isAuthorized: Boolean
get() = TODO("Not yet implemented") get() = storage.accessToken != null
override val cachedUser: ScrobblerUser? override val cachedUser: ScrobblerUser?
get() = TODO("Not yet implemented") get() {
return storage.user
}
override suspend fun authorize(code: String?) { override suspend fun authorize(code: String?) {
TODO("Not yet implemented") val body = FormBody.Builder()
if (code != null) {
body.add("grant_type", "password")
body.add("username", "test@test")
body.add("password", "test")
} else {
body.add("grant_type", "refresh_token")
body.add("refresh_token", checkNotNull(storage.refreshToken))
}
val request = Request.Builder()
.post(body.build())
.url("${BASE_WEB_URL}/api/oauth/token")
val response = okHttp.newCall(request.build()).await().parseJson()
storage.accessToken = response.getString("access_token")
storage.refreshToken = response.getString("refresh_token")
} }
override suspend fun loadUser(): ScrobblerUser { override suspend fun loadUser(): ScrobblerUser {
@ -51,7 +66,7 @@ class KitsuRepository(
} }
override suspend fun unregister(mangaId: Long) { override suspend fun unregister(mangaId: Long) {
TODO("Not yet implemented") return db.scrobblingDao.delete(ScrobblerService.KITSU.id, mangaId)
} }
override suspend fun findManga(query: String, offset: Int): List<ScrobblerManga> { override suspend fun findManga(query: String, offset: Int): List<ScrobblerManga> {

@ -0,0 +1,32 @@
package org.koitharu.kotatsu.scrobbling.kitsu.ui
import android.content.Context
import android.content.Intent
import android.os.Bundle
import androidx.core.graphics.Insets
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.base.ui.BaseActivity
import org.koitharu.kotatsu.databinding.ActivityKitsuAuthBinding
class KitsuAuthActivity : BaseActivity<ActivityKitsuAuthBinding>() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(ActivityKitsuAuthBinding.inflate(layoutInflater))
}
override fun onWindowInsetsChanged(insets: Insets) {
val basePadding = resources.getDimensionPixelOffset(R.dimen.screen_padding)
binding.root.setPadding(
basePadding + insets.left,
basePadding + insets.top,
basePadding + insets.right,
basePadding + insets.bottom,
)
}
companion object {
fun newIntent(context: Context) = Intent(context, KitsuAuthActivity::class.java)
}
}

@ -18,6 +18,7 @@ import org.koitharu.kotatsu.scrobbling.anilist.data.AniListRepository
import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblerService import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblerService
import org.koitharu.kotatsu.scrobbling.common.ui.config.ScrobblerConfigActivity import org.koitharu.kotatsu.scrobbling.common.ui.config.ScrobblerConfigActivity
import org.koitharu.kotatsu.scrobbling.kitsu.data.KitsuRepository import org.koitharu.kotatsu.scrobbling.kitsu.data.KitsuRepository
import org.koitharu.kotatsu.scrobbling.kitsu.ui.KitsuAuthActivity
import org.koitharu.kotatsu.scrobbling.mal.data.MALRepository import org.koitharu.kotatsu.scrobbling.mal.data.MALRepository
import org.koitharu.kotatsu.scrobbling.shikimori.data.ShikimoriRepository import org.koitharu.kotatsu.scrobbling.shikimori.data.ShikimoriRepository
import org.koitharu.kotatsu.sync.domain.SyncController import org.koitharu.kotatsu.sync.domain.SyncController
@ -146,6 +147,9 @@ class ServicesSettingsFragment : BasePreferenceFragment(R.string.services) {
private fun launchScrobblerAuth(repository: org.koitharu.kotatsu.scrobbling.common.data.ScrobblerRepository) { private fun launchScrobblerAuth(repository: org.koitharu.kotatsu.scrobbling.common.data.ScrobblerRepository) {
runCatching { runCatching {
if (repository.oauthUrl.isBlank()) {
startActivity(KitsuAuthActivity.newIntent(requireContext()))
}
val intent = Intent(Intent.ACTION_VIEW) val intent = Intent(Intent.ACTION_VIEW)
intent.data = Uri.parse(repository.oauthUrl) intent.data = Uri.parse(repository.oauthUrl)
startActivity(intent) startActivity(intent)

@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="?colorControlNormal"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M1.429,5.441a12.478,12.478 0,0 0,1.916 2.056c0.011,0.011 0.022,0.011 0.022,0.022 0.452,0.387 1.313,0.947 1.937,1.173 0,0 3.886,1.496 4.091,1.582a1.4,1.4 0,0 0,0.237 0.075,0.694 0.694,0 0,0 0.808,-0.549c0.011,-0.065 0.022,-0.172 0.022,-0.248L10.462,5.161c0.011,-0.667 -0.205,-1.679 -0.398,-2.239 0,-0.011 -0.011,-0.022 -0.011,-0.032A11.979,11.979 0,0 0,8.824 0.36L8.781,0.285a0.697,0.697 0,0 0,-0.958 -0.162c-0.054,0.032 -0.086,0.075 -0.129,0.119L7.608,0.36a4.743,4.743 0,0 0,-0.786 3.412,8.212 8.212,0 0,0 -0.775,0.463c-0.043,0.032 -0.42,0.291 -0.71,0.56A4.803,4.803 0,0 0,1.87 4.3c-0.043,0.011 -0.097,0.021 -0.14,0.032 -0.054,0.022 -0.107,0.043 -0.151,0.076a0.702,0.702 0,0 0,-0.193 0.958l0.043,0.075zM8.222,1.07c0.366,0.614 0.678,1.249 0.925,1.917 -0.495,0.086 -0.98,0.215 -1.453,0.388a3.918,3.918 0,0 1,0.528 -2.305zM4.658,5.463a7.467,7.467 0,0 0,-0.893 1.216,11.68 11.68,0 0,1 -1.453,-1.55 3.825,3.825 0,0 1,2.346 0.334zM17.706,5.161a7.673,7.673 0,0 0,-2.347 -0.474,7.583 7.583,0 0,0 -3.811,0.818l-0.215,0.108v3.918c0,0.054 0,0.258 -0.032,0.431a1.535,1.535 0,0 1,-0.646 0.98,1.545 1.545,0 0,1 -1.152,0.247 2.618,2.618 0,0 1,-0.409 -0.118,747.6 747.6,0 0,1 -3.402,-1.313 8.9,8.9 0,0 0,-0.323 -0.129,30.597 30.597,0 0,0 -3.822,3.832l-0.075,0.086a0.698,0.698 0,0 0,0.538 1.098,0.676 0.676,0 0,0 0.42,-0.118c0.011,-0.011 0.022,-0.022 0.043,-0.032 1.313,-0.947 2.756,-1.712 4.284,-2.325a0.7,0.7 0,0 1,0.818 0.13,0.704 0.704,0 0,1 0.054,0.915l-0.237,0.388a20.277,20.277 0,0 0,-1.97 4.306l-0.032,0.129a0.646,0.646 0,0 0,0.108 0.538,0.713 0.713,0 0,0 0.549,0.301 0.657,0.657 0,0 0,0.42 -0.118c0.054,-0.043 0.108,-0.086 0.151,-0.14l0.043,-0.065a18.95,18.95 0,0 1,1.765 -2.153,20.156 20.156,0 0,1 10.797,-6.018c0.032,-0.011 0.065,-0.011 0.097,-0.011 0.237,0.011 0.42,0.215 0.409,0.452a0.424,0.424 0,0 1,-0.344 0.398c-3.908,0.829 -10.948,5.469 -8.483,12.208 0.043,0.108 0.075,0.172 0.129,0.269a0.71,0.71 0,0 0,0.538 0.301,0.742 0.742,0 0,0 0.657,-0.398c0.398,-0.754 1.152,-1.593 3.326,-2.497 6.061,-2.508 7.062,-6.093 7.17,-8.364v-0.129a7.716,7.716 0,0 0,-5.016 -7.451zM11.623,22.923c-0.56,-1.669 -0.506,-3.283 0.151,-4.823 1.26,2.035 3.456,2.207 3.456,2.207 -2.25,0.937 -3.133,1.863 -3.607,2.616z"
android:fillColor="#000000"/>
</vector>

@ -0,0 +1,130 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="@dimen/screen_padding">
<TextView
android:id="@+id/textView_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:drawablePadding="16dp"
android:gravity="center_horizontal"
android:text="@string/kitsu"
android:textAppearance="?textAppearanceHeadline5"
app:drawableTint="?colorPrimary"
app:drawableTopCompat="@drawable/ic_kitsu"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/textView_subtitle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:layout_alignParentEnd="true"
android:layout_marginTop="12dp"
android:gravity="center_horizontal"
android:text="@string/email_password_enter_hint"
android:textAppearance="?textAppearanceSubtitle1" />
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/layout_email"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_below="@id/textView_subtitle"
android:layout_alignParentStart="true"
android:layout_alignParentEnd="true"
android:layout_marginTop="30dp"
app:errorIconDrawable="@null"
app:hintEnabled="false">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/edit_email"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:autofillHints="emailAddress"
android:imeOptions="actionDone"
android:inputType="textEmailAddress"
android:singleLine="true"
android:textSize="16sp"
tools:hint="Email" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/layout_password"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_below="@id/layout_email"
android:layout_alignParentStart="true"
android:layout_alignParentEnd="true"
android:layout_marginTop="8dp"
app:endIconMode="password_toggle"
app:errorIconDrawable="@null"
app:hintEnabled="false">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/edit_password"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:autofillHints="password"
android:imeOptions="actionDone"
android:inputType="textPassword"
android:maxLength="24"
android:singleLine="true"
android:textSize="16sp"
tools:hint="Password" />
</com.google.android.material.textfield.TextInputLayout>
<Button
android:id="@+id/button_cancel"
style="@style/Widget.Material3.Button.OutlinedButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_alignParentBottom="true"
android:text="@android:string/cancel" />
<Button
android:id="@+id/button_done"
style="@style/Widget.Material3.Button.TonalButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_alignParentBottom="true"
android:enabled="false"
android:text="@string/done"
tools:ignore="RelativeOverlap" />
</RelativeLayout>
<FrameLayout
android:id="@+id/layout_progress"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone">
<com.google.android.material.progressindicator.CircularProgressIndicator
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:indeterminate="true" />
</FrameLayout>
</LinearLayout>

@ -436,4 +436,5 @@
<string name="sync_auth_hint">You can sign in into an existing account or create a new one</string> <string name="sync_auth_hint">You can sign in into an existing account or create a new one</string>
<string name="find_similar">Find similar</string> <string name="find_similar">Find similar</string>
<string name="kitsu" translatable="false">Kitsu</string> <string name="kitsu" translatable="false">Kitsu</string>
<string name="email_password_enter_hint">Enter your email and password to continue</string>
</resources> </resources>

@ -12,21 +12,26 @@
<PreferenceCategory android:title="@string/tracking"> <PreferenceCategory android:title="@string/tracking">
<Preference
android:key="shikimori"
android:title="@string/shikimori"
app:icon="@drawable/ic_shikimori" />
<Preference <Preference
android:key="anilist" android:key="anilist"
android:title="@string/anilist" android:title="@string/anilist"
app:icon="@drawable/ic_anilist" /> app:icon="@drawable/ic_anilist" />
<Preference
android:key="kitsu"
android:title="@string/kitsu"
app:icon="@drawable/ic_kitsu" />
<Preference <Preference
android:key="mal" android:key="mal"
android:title="@string/mal" android:title="@string/mal"
app:icon="@drawable/ic_mal" /> app:icon="@drawable/ic_mal" />
<Preference
android:key="shikimori"
android:title="@string/shikimori"
app:icon="@drawable/ic_shikimori" />
</PreferenceCategory> </PreferenceCategory>
</PreferenceScreen> </PreferenceScreen>

Loading…
Cancel
Save