Discord RPC
parent
b667e32598
commit
4d4c9c7a48
@ -0,0 +1,105 @@
|
||||
package org.koitharu.kotatsu.scrobbling.discord
|
||||
|
||||
import android.content.Context
|
||||
import com.my.kizzyrpc.KizzyRPC
|
||||
import com.my.kizzyrpc.entities.presence.Activity
|
||||
import com.my.kizzyrpc.entities.presence.Assets
|
||||
import com.my.kizzyrpc.entities.presence.Metadata
|
||||
import com.my.kizzyrpc.entities.presence.Timestamps
|
||||
import dagger.hilt.android.ViewModelLifecycle
|
||||
import dagger.hilt.android.lifecycle.RetainedLifecycle
|
||||
import dagger.hilt.android.scopes.ViewModelScoped
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.plus
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.core.LocalizedAppContext
|
||||
import org.koitharu.kotatsu.core.model.appUrl
|
||||
import org.koitharu.kotatsu.core.model.getTitle
|
||||
import org.koitharu.kotatsu.core.prefs.AppSettings
|
||||
import org.koitharu.kotatsu.core.util.ext.lifecycleScope
|
||||
import org.koitharu.kotatsu.parsers.model.Manga
|
||||
import org.koitharu.kotatsu.reader.ui.pager.ReaderUiState
|
||||
import javax.inject.Inject
|
||||
|
||||
private const val STATUS_ONLINE = "online"
|
||||
private const val STATUS_IDLE = "idle"
|
||||
|
||||
@ViewModelScoped
|
||||
class DiscordRpc @Inject constructor(
|
||||
@LocalizedAppContext private val context: Context,
|
||||
private val settings: AppSettings,
|
||||
lifecycle: ViewModelLifecycle,
|
||||
) : RetainedLifecycle.OnClearedListener {
|
||||
|
||||
private val coroutineScope = lifecycle.lifecycleScope + Dispatchers.Default
|
||||
private val appId = context.getString(R.string.discord_app_id)
|
||||
private val appName = context.getString(R.string.app_name)
|
||||
private val rpc = if (settings.isDiscordRpcEnabled) {
|
||||
settings.discordToken?.let { KizzyRPC(it) }
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
||||
private var lastActivity: Activity? = null
|
||||
|
||||
init {
|
||||
lifecycle.addOnClearedListener(this)
|
||||
}
|
||||
|
||||
override fun onCleared() {
|
||||
clearRpc()
|
||||
}
|
||||
|
||||
fun clearRpc() {
|
||||
rpc?.closeRPC()
|
||||
}
|
||||
|
||||
fun setIdle() {
|
||||
if (rpc != null) {
|
||||
lastActivity?.let { activity ->
|
||||
updateRpcAsync(activity, idle = true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun updateRpc(manga: Manga, state: ReaderUiState) {
|
||||
if (rpc != null) {
|
||||
updateRpcAsync(
|
||||
activity = Activity(
|
||||
applicationId = appId,
|
||||
name = appName,
|
||||
details = manga.title,
|
||||
state = context.getString(R.string.chapter_d_of_d, state.chapterNumber, state.chaptersTotal),
|
||||
type = 3,
|
||||
timestamps = Timestamps(
|
||||
start = System.currentTimeMillis(),
|
||||
),
|
||||
assets = Assets(
|
||||
largeImage = "mp:attachments/1396092865544716390/1396123149921419465/Kotatsu.png?ex=687d9941&is=687c47c1&hm=61da2b66445adaea18ad16cc2c7f829d1c97f0622beec332f123a56f4d294820&=&format=webp&quality=lossless&width=256&height=256",
|
||||
largeText = "Reading manga on Kotatsu - A manga reader app",
|
||||
smallText = "Reading: ${manga.title}",
|
||||
smallImage = "mp:attachments/1282576939831529473/1395712714415800392/button.png?ex=687b7242&is=687a20c2&hm=828ad97537c94128504402b43512523fe30801d534a48258f80c6fd29fda67c2&=&format=webp&quality=lossless",
|
||||
),
|
||||
buttons = listOf(
|
||||
context.getString(R.string.link_to_manga_in_app),
|
||||
context.getString(R.string.link_to_manga_on_s, manga.source.getTitle(context)),
|
||||
),
|
||||
metadata = Metadata(listOf(manga.appUrl.toString(), manga.publicUrl)),
|
||||
),
|
||||
idle = false,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateRpcAsync(activity: Activity, idle: Boolean) {
|
||||
val rpc = rpc ?: return
|
||||
lastActivity = activity
|
||||
coroutineScope.launch {
|
||||
rpc.updateRPC(
|
||||
activity = activity,
|
||||
status = if (idle) STATUS_IDLE else STATUS_ONLINE,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,44 @@
|
||||
package org.koitharu.kotatsu.settings
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import androidx.preference.EditTextPreference
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.core.prefs.AppSettings
|
||||
import org.koitharu.kotatsu.core.ui.BasePreferenceFragment
|
||||
import org.koitharu.kotatsu.core.util.ext.observe
|
||||
import org.koitharu.kotatsu.settings.utils.EditTextFallbackSummaryProvider
|
||||
|
||||
class DiscordSettingsFragment : BasePreferenceFragment(R.string.discord) {
|
||||
|
||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||
addPreferencesFromResource(R.xml.pref_discord)
|
||||
findPreference<EditTextPreference>(AppSettings.KEY_DISCORD_TOKEN)?.let { pref ->
|
||||
pref.summaryProvider = EditTextFallbackSummaryProvider(R.string.discord_token_summary)
|
||||
pref.setDialogMessage(R.string.discord_token_summary)
|
||||
pref.setOnBindEditTextListener {
|
||||
it.setHint(R.string.discord_token_hint)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
settings.observe(
|
||||
AppSettings.KEY_DISCORD_RPC,
|
||||
AppSettings.KEY_DISCORD_TOKEN,
|
||||
).observe(viewLifecycleOwner) {
|
||||
bindTokenWarning()
|
||||
}
|
||||
}
|
||||
|
||||
private fun bindTokenWarning() {
|
||||
val pref = findPreference<EditTextPreference>(AppSettings.KEY_DISCORD_TOKEN) ?: return
|
||||
val shouldShowError = settings.isDiscordRpcEnabled && settings.discordToken == null
|
||||
pref.icon = if (shouldShowError) {
|
||||
getWarningIcon()
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
<vector
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="?attr/colorControlNormal"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M19.27,5.33C17.94,4.71 16.5,4.26 15,4c-0.03,0 -0.05,0.01 -0.07,0.03c-0.18,0.33 -0.39,0.76 -0.53,1.09c-1.61,-0.24 -3.22,-0.24 -4.8,0C9.46,4.78 9.25,4.36 9.06,4.03C9.05,4.01 9.02,4 8.99,4c-1.5,0.26 -2.93,0.71 -4.27,1.33c-0.01,0 -0.02,0.01 -0.03,0.02c-2.72,4.07 -3.47,8.03 -3.1,11.95c0,0.02 0.01,0.04 0.03,0.05c1.8,1.32 3.53,2.12 5.24,2.65c0.03,0.01 0.06,0 0.07,-0.02c0.4,-0.55 0.76,-1.13 1.07,-1.74c0.02,-0.04 0,-0.08 -0.04,-0.09c-0.57,-0.22 -1.11,-0.48 -1.64,-0.78c-0.04,-0.02 -0.04,-0.08 -0.01,-0.11c0.11,-0.08 0.22,-0.17 0.33,-0.25c0.02,-0.02 0.05,-0.02 0.07,-0.01c3.44,1.57 7.15,1.57 10.55,0c0.02,-0.01 0.05,-0.01 0.07,0.01c0.11,0.09 0.22,0.17 0.33,0.26c0.04,0.03 0.04,0.09 -0.01,0.11c-0.52,0.31 -1.07,0.56 -1.64,0.78c-0.04,0.01 -0.05,0.06 -0.04,0.09c0.32,0.61 0.68,1.19 1.07,1.74C17.07,20 17.1,20.01 17.13,20c1.72,-0.53 3.45,-1.33 5.25,-2.65c0.02,-0.01 0.03,-0.03 0.03,-0.05c0.44,-4.53 -0.73,-8.46 -3.1,-11.95C19.3,5.34 19.29,5.33 19.27,5.33zM8.52,14.91c-1.03,0 -1.89,-0.95 -1.89,-2.12s0.84,-2.12 1.89,-2.12c1.06,0 1.9,0.96 1.89,2.12C10.41,13.96 9.57,14.91 8.52,14.91zM15.49,14.91c-1.03,0 -1.89,-0.95 -1.89,-2.12s0.84,-2.12 1.89,-2.12c1.06,0 1.9,0.96 1.89,2.12C17.38,13.96 16.55,14.91 15.49,14.91z" />
|
||||
</vector>
|
||||
@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.preference.PreferenceScreen
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:defaultValue="false"
|
||||
android:key="discord_rpc"
|
||||
android:layout="@layout/preference_toggle_header"
|
||||
android:title="@string/discord_rpc" />
|
||||
|
||||
<EditTextPreference
|
||||
android:dependency="discord_rpc"
|
||||
android:key="discord_token"
|
||||
android:summary="@string/discord_token_summary"
|
||||
android:title="@string/discord_token" />
|
||||
|
||||
</androidx.preference.PreferenceScreen>
|
||||
Loading…
Reference in New Issue