Feature/shikomori track (#1905)
* Add shikomori track * Fix char 'M' * Fix date in search
This commit is contained in:
parent
bf60aae9d8
commit
a62a7d5330
10 changed files with 488 additions and 1 deletions
|
@ -52,6 +52,21 @@
|
||||||
android:scheme="tachiyomi" />
|
android:scheme="tachiyomi" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
|
<activity
|
||||||
|
android:name=".ui.setting.ShikomoriLoginActivity"
|
||||||
|
android:label="Shikomori">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.VIEW" />
|
||||||
|
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
<category android:name="android.intent.category.BROWSABLE" />
|
||||||
|
|
||||||
|
<data
|
||||||
|
android:host="shikimori-auth"
|
||||||
|
android:scheme="tachiyomi" />
|
||||||
|
</intent-filter>
|
||||||
|
</activity>
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".extension.util.ExtensionInstallActivity"
|
android:name=".extension.util.ExtensionInstallActivity"
|
||||||
android:theme="@android:style/Theme.Translucent.NoTitleBar"/>
|
android:theme="@android:style/Theme.Translucent.NoTitleBar"/>
|
||||||
|
|
|
@ -4,6 +4,7 @@ import android.content.Context
|
||||||
import eu.kanade.tachiyomi.data.track.anilist.Anilist
|
import eu.kanade.tachiyomi.data.track.anilist.Anilist
|
||||||
import eu.kanade.tachiyomi.data.track.kitsu.Kitsu
|
import eu.kanade.tachiyomi.data.track.kitsu.Kitsu
|
||||||
import eu.kanade.tachiyomi.data.track.myanimelist.Myanimelist
|
import eu.kanade.tachiyomi.data.track.myanimelist.Myanimelist
|
||||||
|
import eu.kanade.tachiyomi.data.track.shikomori.Shikomori
|
||||||
|
|
||||||
class TrackManager(private val context: Context) {
|
class TrackManager(private val context: Context) {
|
||||||
|
|
||||||
|
@ -11,6 +12,7 @@ class TrackManager(private val context: Context) {
|
||||||
const val MYANIMELIST = 1
|
const val MYANIMELIST = 1
|
||||||
const val ANILIST = 2
|
const val ANILIST = 2
|
||||||
const val KITSU = 3
|
const val KITSU = 3
|
||||||
|
const val SHIKOMORI = 4
|
||||||
}
|
}
|
||||||
|
|
||||||
val myAnimeList = Myanimelist(context, MYANIMELIST)
|
val myAnimeList = Myanimelist(context, MYANIMELIST)
|
||||||
|
@ -19,7 +21,9 @@ class TrackManager(private val context: Context) {
|
||||||
|
|
||||||
val kitsu = Kitsu(context, KITSU)
|
val kitsu = Kitsu(context, KITSU)
|
||||||
|
|
||||||
val services = listOf(myAnimeList, aniList, kitsu)
|
val shikomori = Shikomori(context, SHIKOMORI)
|
||||||
|
|
||||||
|
val services = listOf(myAnimeList, aniList, kitsu, shikomori)
|
||||||
|
|
||||||
fun getService(id: Int) = services.find { it.id == id }
|
fun getService(id: Int) = services.find { it.id == id }
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
package eu.kanade.tachiyomi.data.track.shikomori
|
||||||
|
|
||||||
|
data class OAuth(
|
||||||
|
val access_token: String,
|
||||||
|
val token_type: String,
|
||||||
|
val created_at: Long,
|
||||||
|
val expires_in: Long,
|
||||||
|
val refresh_token: String?) {
|
||||||
|
|
||||||
|
// Access token lives 1 day
|
||||||
|
fun isExpired() = (System.currentTimeMillis() / 1000) > (created_at + expires_in - 3600)
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,138 @@
|
||||||
|
package eu.kanade.tachiyomi.data.track.shikomori
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.graphics.Color
|
||||||
|
import com.google.gson.Gson
|
||||||
|
import eu.kanade.tachiyomi.R
|
||||||
|
import eu.kanade.tachiyomi.data.database.models.Track
|
||||||
|
import eu.kanade.tachiyomi.data.track.TrackService
|
||||||
|
import eu.kanade.tachiyomi.data.track.model.TrackSearch
|
||||||
|
import rx.Completable
|
||||||
|
import rx.Observable
|
||||||
|
import uy.kohesive.injekt.injectLazy
|
||||||
|
|
||||||
|
class Shikomori(private val context: Context, id: Int) : TrackService(id) {
|
||||||
|
|
||||||
|
override fun getScoreList(): List<String> {
|
||||||
|
return IntRange(0, 10).map(Int::toString)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun displayScore(track: Track): String {
|
||||||
|
return track.score.toInt().toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun add(track: Track): Observable<Track> {
|
||||||
|
return api.addLibManga(track, getUsername())
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun update(track: Track): Observable<Track> {
|
||||||
|
if (track.total_chapters != 0 && track.last_chapter_read == track.total_chapters) {
|
||||||
|
track.status = COMPLETED
|
||||||
|
}
|
||||||
|
return api.updateLibManga(track, getUsername())
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun bind(track: Track): Observable<Track> {
|
||||||
|
return api.findLibManga(track, getUsername())
|
||||||
|
.flatMap { remoteTrack ->
|
||||||
|
if (remoteTrack != null) {
|
||||||
|
track.copyPersonalFrom(remoteTrack)
|
||||||
|
track.library_id = remoteTrack.library_id
|
||||||
|
update(track)
|
||||||
|
} else {
|
||||||
|
// Set default fields if it's not found in the list
|
||||||
|
track.score = DEFAULT_SCORE.toFloat()
|
||||||
|
track.status = DEFAULT_STATUS
|
||||||
|
add(track)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun search(query: String): Observable<List<TrackSearch>> {
|
||||||
|
return api.search(query)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun refresh(track: Track): Observable<Track> {
|
||||||
|
return api.findLibManga(track, getUsername())
|
||||||
|
.map { remoteTrack ->
|
||||||
|
if (remoteTrack != null) {
|
||||||
|
track.copyPersonalFrom(remoteTrack)
|
||||||
|
track.total_chapters = remoteTrack.total_chapters
|
||||||
|
}
|
||||||
|
track
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val READING = 1
|
||||||
|
const val COMPLETED = 2
|
||||||
|
const val ON_HOLD = 3
|
||||||
|
const val DROPPED = 4
|
||||||
|
const val PLANNING = 5
|
||||||
|
const val REPEATING = 6
|
||||||
|
|
||||||
|
const val DEFAULT_STATUS = READING
|
||||||
|
const val DEFAULT_SCORE = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
override val name = "Shikomori"
|
||||||
|
|
||||||
|
private val gson: Gson by injectLazy()
|
||||||
|
|
||||||
|
private val interceptor by lazy { ShikomoriInterceptor(this, gson) }
|
||||||
|
|
||||||
|
private val api by lazy { ShikomoriApi(client, interceptor) }
|
||||||
|
|
||||||
|
override fun getLogo() = R.drawable.shikomori
|
||||||
|
|
||||||
|
override fun getLogoColor() = Color.rgb(40, 40, 40)
|
||||||
|
|
||||||
|
override fun getStatusList(): List<Int> {
|
||||||
|
return listOf(READING, COMPLETED, ON_HOLD, DROPPED, PLANNING, REPEATING)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getStatus(status: Int): String = with(context) {
|
||||||
|
when (status) {
|
||||||
|
READING -> getString(R.string.reading)
|
||||||
|
COMPLETED -> getString(R.string.completed)
|
||||||
|
ON_HOLD -> getString(R.string.on_hold)
|
||||||
|
DROPPED -> getString(R.string.dropped)
|
||||||
|
PLANNING -> getString(R.string.plan_to_read)
|
||||||
|
REPEATING -> getString(R.string.repeating)
|
||||||
|
else -> ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun login(username: String, password: String) = login(password)
|
||||||
|
|
||||||
|
fun login(code: String): Completable {
|
||||||
|
return api.accessToken(code).map { oauth: OAuth? ->
|
||||||
|
interceptor.newAuth(oauth)
|
||||||
|
if (oauth != null) {
|
||||||
|
val user = api.getCurrentUser()
|
||||||
|
saveCredentials(user.toString(), oauth.access_token)
|
||||||
|
}
|
||||||
|
}.doOnError {
|
||||||
|
logout()
|
||||||
|
}.toCompletable()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun saveToken(oauth: OAuth?) {
|
||||||
|
val json = gson.toJson(oauth)
|
||||||
|
preferences.trackToken(this).set(json)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun restoreToken(): OAuth? {
|
||||||
|
return try {
|
||||||
|
gson.fromJson(preferences.trackToken(this).get(), OAuth::class.java)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun logout() {
|
||||||
|
super.logout()
|
||||||
|
preferences.trackToken(this).set(null)
|
||||||
|
interceptor.newAuth(null)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,189 @@
|
||||||
|
package eu.kanade.tachiyomi.data.track.shikomori
|
||||||
|
|
||||||
|
import android.net.Uri
|
||||||
|
import com.github.salomonbrys.kotson.array
|
||||||
|
import com.github.salomonbrys.kotson.jsonObject
|
||||||
|
import com.github.salomonbrys.kotson.nullString
|
||||||
|
import com.github.salomonbrys.kotson.obj
|
||||||
|
import com.google.gson.Gson
|
||||||
|
import com.google.gson.JsonObject
|
||||||
|
import com.google.gson.JsonParser
|
||||||
|
import eu.kanade.tachiyomi.data.database.models.Track
|
||||||
|
import eu.kanade.tachiyomi.data.track.TrackManager
|
||||||
|
import eu.kanade.tachiyomi.data.track.model.TrackSearch
|
||||||
|
import eu.kanade.tachiyomi.network.GET
|
||||||
|
import eu.kanade.tachiyomi.network.POST
|
||||||
|
import eu.kanade.tachiyomi.network.asObservableSuccess
|
||||||
|
import okhttp3.*
|
||||||
|
import rx.Observable
|
||||||
|
import uy.kohesive.injekt.injectLazy
|
||||||
|
|
||||||
|
class ShikomoriApi(private val client: OkHttpClient, interceptor: ShikomoriInterceptor) {
|
||||||
|
|
||||||
|
private val gson: Gson by injectLazy()
|
||||||
|
private val parser = JsonParser()
|
||||||
|
private val jsonime = MediaType.parse("application/json; charset=utf-8")
|
||||||
|
private val authClient = client.newBuilder().addInterceptor(interceptor).build()
|
||||||
|
|
||||||
|
fun addLibManga(track: Track, user_id: String): Observable<Track> {
|
||||||
|
val payload = jsonObject(
|
||||||
|
"user_rate" to jsonObject(
|
||||||
|
"user_id" to user_id,
|
||||||
|
"target_id" to track.media_id,
|
||||||
|
"target_type" to "Manga",
|
||||||
|
"chapters" to track.last_chapter_read,
|
||||||
|
"score" to track.score.toInt(),
|
||||||
|
"status" to track.toShikomoriStatus()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
val body = RequestBody.create(jsonime, payload.toString())
|
||||||
|
val request = Request.Builder()
|
||||||
|
.url("$apiUrl/v2/user_rates")
|
||||||
|
.post(body)
|
||||||
|
.build()
|
||||||
|
return authClient.newCall(request)
|
||||||
|
.asObservableSuccess()
|
||||||
|
.map {
|
||||||
|
track
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun updateLibManga(track: Track, user_id: String): Observable<Track> = addLibManga(track, user_id)
|
||||||
|
|
||||||
|
fun search(search: String): Observable<List<TrackSearch>> {
|
||||||
|
val url = Uri.parse("$apiUrl/mangas").buildUpon()
|
||||||
|
.appendQueryParameter("order", "popularity")
|
||||||
|
.appendQueryParameter("search", search)
|
||||||
|
.appendQueryParameter("limit", "20")
|
||||||
|
.build()
|
||||||
|
val request = Request.Builder()
|
||||||
|
.url(url.toString())
|
||||||
|
.get()
|
||||||
|
.build()
|
||||||
|
return authClient.newCall(request)
|
||||||
|
.asObservableSuccess()
|
||||||
|
.map { netResponse ->
|
||||||
|
val responseBody = netResponse.body()?.string().orEmpty()
|
||||||
|
if (responseBody.isEmpty()) {
|
||||||
|
throw Exception("Null Response")
|
||||||
|
}
|
||||||
|
val response = parser.parse(responseBody).array
|
||||||
|
response.map { jsonToSearch(it.obj) }
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun jsonToSearch(obj: JsonObject): TrackSearch {
|
||||||
|
return TrackSearch.create(TrackManager.SHIKOMORI).apply {
|
||||||
|
media_id = obj["id"].asInt
|
||||||
|
title = obj["name"].asString
|
||||||
|
total_chapters = obj["chapters"].asInt
|
||||||
|
cover_url = baseUrl + obj["image"].obj["preview"].asString
|
||||||
|
summary = ""
|
||||||
|
tracking_url = baseUrl + obj["url"].asString
|
||||||
|
publishing_status = obj["status"].asString
|
||||||
|
publishing_type = obj["kind"].asString
|
||||||
|
start_date = obj.get("aired_on").nullString.orEmpty()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun jsonToTrack(obj: JsonObject): Track {
|
||||||
|
return Track.create(TrackManager.SHIKOMORI).apply {
|
||||||
|
media_id = obj["id"].asInt
|
||||||
|
title = ""
|
||||||
|
last_chapter_read = obj["chapters"].asInt
|
||||||
|
total_chapters = obj["chapters"].asInt
|
||||||
|
score = (obj["score"].asInt).toFloat()
|
||||||
|
status = toTrackStatus(obj["status"].asString)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun findLibManga(track: Track, user_id: String): Observable<Track?> {
|
||||||
|
val url = Uri.parse("$apiUrl/v2/user_rates").buildUpon()
|
||||||
|
.appendQueryParameter("user_id", user_id)
|
||||||
|
.appendQueryParameter("target_id", track.media_id.toString())
|
||||||
|
.appendQueryParameter("target_type", "Manga")
|
||||||
|
.build()
|
||||||
|
val request = Request.Builder()
|
||||||
|
.url(url.toString())
|
||||||
|
.get()
|
||||||
|
.build()
|
||||||
|
return authClient.newCall(request)
|
||||||
|
.asObservableSuccess()
|
||||||
|
.map { netResponse ->
|
||||||
|
val responseBody = netResponse.body()?.string().orEmpty()
|
||||||
|
if (responseBody.isEmpty()) {
|
||||||
|
throw Exception("Null Response")
|
||||||
|
}
|
||||||
|
val response = parser.parse(responseBody).array
|
||||||
|
if (response.size() > 1) {
|
||||||
|
throw Exception("Too much mangas in response")
|
||||||
|
}
|
||||||
|
val entry = response.map {
|
||||||
|
jsonToTrack(it.obj)
|
||||||
|
}
|
||||||
|
entry.firstOrNull()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getCurrentUser(): Int {
|
||||||
|
val user = authClient.newCall(GET("$apiUrl/users/whoami")).execute().body()?.string()
|
||||||
|
return parser.parse(user).obj["id"].asInt
|
||||||
|
}
|
||||||
|
|
||||||
|
fun accessToken(code: String): Observable<OAuth> {
|
||||||
|
return client.newCall(accessTokenRequest(code)).asObservableSuccess().map { netResponse ->
|
||||||
|
val responseBody = netResponse.body()?.string().orEmpty()
|
||||||
|
if (responseBody.isEmpty()) {
|
||||||
|
throw Exception("Null Response")
|
||||||
|
}
|
||||||
|
gson.fromJson(responseBody, OAuth::class.java)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun accessTokenRequest(code: String) = POST(oauthUrl,
|
||||||
|
body = FormBody.Builder()
|
||||||
|
.add("grant_type", "authorization_code")
|
||||||
|
.add("client_id", clientId)
|
||||||
|
.add("client_secret", clientSecret)
|
||||||
|
.add("code", code)
|
||||||
|
.add("redirect_uri", redirectUrl)
|
||||||
|
.build()
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val clientId = "1aaf4cf232372708e98b5abc813d795b539c5a916dbbfe9ac61bf02a360832cc"
|
||||||
|
private const val clientSecret = "229942c742dd4cde803125d17d64501d91c0b12e14cb1e5120184d77d67024c0"
|
||||||
|
|
||||||
|
private const val baseUrl = "https://shikimori.org"
|
||||||
|
private const val apiUrl = "https://shikimori.org/api"
|
||||||
|
private const val oauthUrl = "https://shikimori.org/oauth/token"
|
||||||
|
private const val loginUrl = "https://shikimori.org/oauth/authorize"
|
||||||
|
|
||||||
|
private const val redirectUrl = "tachiyomi://shikimori-auth"
|
||||||
|
private const val baseMangaUrl = "$apiUrl/mangas"
|
||||||
|
|
||||||
|
fun mangaUrl(remoteId: Int): String {
|
||||||
|
return "$baseMangaUrl/$remoteId"
|
||||||
|
}
|
||||||
|
|
||||||
|
fun authUrl() =
|
||||||
|
Uri.parse(loginUrl).buildUpon()
|
||||||
|
.appendQueryParameter("client_id", clientId)
|
||||||
|
.appendQueryParameter("redirect_uri", redirectUrl)
|
||||||
|
.appendQueryParameter("response_type", "code")
|
||||||
|
.build()
|
||||||
|
|
||||||
|
|
||||||
|
fun refreshTokenRequest(token: String) = POST(oauthUrl,
|
||||||
|
body = FormBody.Builder()
|
||||||
|
.add("grant_type", "refresh_token")
|
||||||
|
.add("client_id", clientId)
|
||||||
|
.add("client_secret", clientSecret)
|
||||||
|
.add("refresh_token", token)
|
||||||
|
.build())
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,43 @@
|
||||||
|
package eu.kanade.tachiyomi.data.track.shikomori
|
||||||
|
|
||||||
|
import com.google.gson.Gson
|
||||||
|
import okhttp3.Interceptor
|
||||||
|
import okhttp3.Response
|
||||||
|
|
||||||
|
class ShikomoriInterceptor(val shikomori: Shikomori, val gson: Gson) : Interceptor {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* OAuth object used for authenticated requests.
|
||||||
|
*/
|
||||||
|
private var oauth: OAuth? = shikomori.restoreToken()
|
||||||
|
|
||||||
|
override fun intercept(chain: Interceptor.Chain): Response {
|
||||||
|
val originalRequest = chain.request()
|
||||||
|
|
||||||
|
val currAuth = oauth ?: throw Exception("Not authenticated with Shikomori")
|
||||||
|
|
||||||
|
val refreshToken = currAuth.refresh_token!!
|
||||||
|
|
||||||
|
// Refresh access token if expired.
|
||||||
|
if (currAuth.isExpired()) {
|
||||||
|
val response = chain.proceed(ShikomoriApi.refreshTokenRequest(refreshToken))
|
||||||
|
if (response.isSuccessful) {
|
||||||
|
newAuth(gson.fromJson(response.body()!!.string(), OAuth::class.java))
|
||||||
|
} else {
|
||||||
|
response.close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Add the authorization header to the original request.
|
||||||
|
val authRequest = originalRequest.newBuilder()
|
||||||
|
.addHeader("Authorization", "Bearer ${oauth!!.access_token}")
|
||||||
|
.header("User-Agent", "Tachiyomi")
|
||||||
|
.build()
|
||||||
|
|
||||||
|
return chain.proceed(authRequest)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun newAuth(oauth: OAuth?) {
|
||||||
|
this.oauth = oauth
|
||||||
|
shikomori.saveToken(oauth)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
package eu.kanade.tachiyomi.data.track.shikomori
|
||||||
|
|
||||||
|
import eu.kanade.tachiyomi.data.database.models.Track
|
||||||
|
|
||||||
|
fun Track.toShikomoriStatus() = when (status) {
|
||||||
|
Shikomori.READING -> "watching"
|
||||||
|
Shikomori.COMPLETED -> "completed"
|
||||||
|
Shikomori.ON_HOLD -> "on_hold"
|
||||||
|
Shikomori.DROPPED -> "dropped"
|
||||||
|
Shikomori.PLANNING -> "planned"
|
||||||
|
Shikomori.REPEATING -> "rewatching"
|
||||||
|
else -> throw NotImplementedError("Unknown status")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun toTrackStatus(status: String) = when (status) {
|
||||||
|
"watching" -> Shikomori.READING
|
||||||
|
"completed" -> Shikomori.COMPLETED
|
||||||
|
"on_hold" -> Shikomori.ON_HOLD
|
||||||
|
"dropped" -> Shikomori.DROPPED
|
||||||
|
"planned" -> Shikomori.PLANNING
|
||||||
|
"rewatching" -> Shikomori.REPEATING
|
||||||
|
|
||||||
|
else -> throw Exception("Unknown status")
|
||||||
|
}
|
|
@ -8,6 +8,7 @@ import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.data.track.TrackManager
|
import eu.kanade.tachiyomi.data.track.TrackManager
|
||||||
import eu.kanade.tachiyomi.data.track.TrackService
|
import eu.kanade.tachiyomi.data.track.TrackService
|
||||||
import eu.kanade.tachiyomi.data.track.anilist.AnilistApi
|
import eu.kanade.tachiyomi.data.track.anilist.AnilistApi
|
||||||
|
import eu.kanade.tachiyomi.data.track.shikomori.ShikomoriApi
|
||||||
import eu.kanade.tachiyomi.util.getResourceColor
|
import eu.kanade.tachiyomi.util.getResourceColor
|
||||||
import eu.kanade.tachiyomi.widget.preference.LoginPreference
|
import eu.kanade.tachiyomi.widget.preference.LoginPreference
|
||||||
import eu.kanade.tachiyomi.widget.preference.TrackLoginDialog
|
import eu.kanade.tachiyomi.widget.preference.TrackLoginDialog
|
||||||
|
@ -53,6 +54,15 @@ class SettingsTrackingController : SettingsController(),
|
||||||
dialog.showDialog(router)
|
dialog.showDialog(router)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
trackPreference(trackManager.shikomori) {
|
||||||
|
onClick {
|
||||||
|
val tabsIntent = CustomTabsIntent.Builder()
|
||||||
|
.setToolbarColor(context.getResourceColor(R.attr.colorPrimary))
|
||||||
|
.build()
|
||||||
|
tabsIntent.intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY)
|
||||||
|
tabsIntent.launchUrl(activity, ShikomoriApi.authUrl())
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,6 +80,7 @@ class SettingsTrackingController : SettingsController(),
|
||||||
super.onActivityResumed(activity)
|
super.onActivityResumed(activity)
|
||||||
// Manually refresh anilist holder
|
// Manually refresh anilist holder
|
||||||
updatePreference(trackManager.aniList.id)
|
updatePreference(trackManager.aniList.id)
|
||||||
|
updatePreference(trackManager.shikomori.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updatePreference(id: Int) {
|
private fun updatePreference(id: Int) {
|
||||||
|
|
|
@ -0,0 +1,50 @@
|
||||||
|
package eu.kanade.tachiyomi.ui.setting
|
||||||
|
|
||||||
|
import android.content.Intent
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.support.v7.app.AppCompatActivity
|
||||||
|
import android.view.Gravity.CENTER
|
||||||
|
import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
|
||||||
|
import android.widget.FrameLayout
|
||||||
|
import android.widget.ProgressBar
|
||||||
|
import eu.kanade.tachiyomi.data.track.TrackManager
|
||||||
|
import eu.kanade.tachiyomi.ui.main.MainActivity
|
||||||
|
import rx.android.schedulers.AndroidSchedulers
|
||||||
|
import rx.schedulers.Schedulers
|
||||||
|
import uy.kohesive.injekt.injectLazy
|
||||||
|
|
||||||
|
class ShikomoriLoginActivity : AppCompatActivity() {
|
||||||
|
|
||||||
|
private val trackManager: TrackManager by injectLazy()
|
||||||
|
|
||||||
|
override fun onCreate(savedState: Bundle?) {
|
||||||
|
super.onCreate(savedState)
|
||||||
|
|
||||||
|
val view = ProgressBar(this)
|
||||||
|
setContentView(view, FrameLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT, CENTER))
|
||||||
|
|
||||||
|
val code = intent.data?.getQueryParameter("code")
|
||||||
|
if (code != null) {
|
||||||
|
trackManager.shikomori.login(code)
|
||||||
|
.subscribeOn(Schedulers.io())
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.subscribe({
|
||||||
|
returnToSettings()
|
||||||
|
}, {
|
||||||
|
returnToSettings()
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
trackManager.shikomori.logout()
|
||||||
|
returnToSettings()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun returnToSettings() {
|
||||||
|
finish()
|
||||||
|
|
||||||
|
val intent = Intent(this, MainActivity::class.java)
|
||||||
|
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP)
|
||||||
|
startActivity(intent)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
BIN
app/src/main/res/drawable-xxxhdpi/shikomori.png
Normal file
BIN
app/src/main/res/drawable-xxxhdpi/shikomori.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 8.6 KiB |
Reference in a new issue