Yuito-app-android/app/src/main/java/com/keylesspalace/tusky/components/instanceinfo/InstanceInfoRepository.kt

134 lines
5.7 KiB
Kotlin

/* Copyright 2022 Tusky contributors
*
* This file is a part of Tusky.
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* Tusky is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with Tusky; if not,
* see <http://www.gnu.org/licenses>. */
package com.keylesspalace.tusky.components.instanceinfo
import android.util.Log
import at.connyduck.calladapter.networkresult.fold
import at.connyduck.calladapter.networkresult.getOrElse
import at.connyduck.calladapter.networkresult.onSuccess
import com.keylesspalace.tusky.db.AccountManager
import com.keylesspalace.tusky.db.AppDatabase
import com.keylesspalace.tusky.db.EmojisEntity
import com.keylesspalace.tusky.db.InstanceInfoEntity
import com.keylesspalace.tusky.entity.Emoji
import com.keylesspalace.tusky.network.MastodonApi
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import javax.inject.Inject
class InstanceInfoRepository @Inject constructor(
private val api: MastodonApi,
db: AppDatabase,
accountManager: AccountManager
) {
private val dao = db.instanceDao()
private val instanceName = accountManager.activeAccount!!.domain
/**
* Returns the custom emojis of the instance.
* Will always try to fetch them from the api, falls back to cached Emojis in case it is not available.
* Never throws, returns empty list in case of error.
*/
suspend fun getEmojis(): List<Emoji> = withContext(Dispatchers.IO) {
api.getCustomEmojis()
.onSuccess { emojiList -> dao.insertOrReplace(EmojisEntity(instanceName, emojiList)) }
.getOrElse { throwable ->
Log.w(TAG, "failed to load custom emojis, falling back to cache", throwable)
getCachedEmojis()
}
}
suspend fun getCachedEmojis(): List<Emoji> =
dao.getEmojiInfo(instanceName)?.emojiList.orEmpty()
/**
* Returns information about the instance.
* Will always try to fetch the most up-to-date data from the api, falls back to cache in case it is not available.
* Never throws, returns defaults of vanilla Mastodon in case of error.
*/
suspend fun getInstanceInfo(): InstanceInfo = withContext(Dispatchers.IO) {
api.getInstance()
.fold(
{ instance ->
val instanceEntity = InstanceInfoEntity(
instance = instanceName,
maximumTootCharacters = instance.configuration?.statuses?.maxCharacters ?: instance.maxTootChars,
maxPollOptions = instance.configuration?.polls?.maxOptions ?: instance.pollConfiguration?.maxOptions,
maxPollOptionLength = instance.configuration?.polls?.maxCharactersPerOption ?: instance.pollConfiguration?.maxOptionChars,
minPollDuration = instance.configuration?.polls?.minExpiration ?: instance.pollConfiguration?.minExpiration,
maxPollDuration = instance.configuration?.polls?.maxExpiration ?: instance.pollConfiguration?.maxExpiration,
charactersReservedPerUrl = instance.configuration?.statuses?.charactersReservedPerUrl,
version = instance.version
)
dao.insertOrReplace(instanceEntity)
instanceEntity
},
{ throwable ->
Log.w(TAG, "failed to instance, falling back to cache and default values", throwable)
getCachedInstanceInfoEntity()
}
).toInstanceInfo()
}
private suspend fun getCachedInstanceInfoEntity(): InstanceInfoEntity? =
dao.getInstanceInfo(instanceName)
suspend fun getCachedInstanceInfo(): InstanceInfo =
getCachedInstanceInfoEntity().toInstanceInfo()
companion object {
private const val TAG = "InstanceInfoRepo"
const val DEFAULT_CHARACTER_LIMIT = 500
private const val DEFAULT_MAX_OPTION_COUNT = 4
private const val DEFAULT_MAX_OPTION_LENGTH = 50
private const val DEFAULT_MIN_POLL_DURATION = 300
private const val DEFAULT_MAX_POLL_DURATION = 604800
@JvmField
val CAN_USE_QUOTE_ID = arrayOf(
"odakyu.app",
"itabashi.0j0.jp",
"biwakodon.com",
"dtp-mstdn.jp",
"nitiasa.com",
"comm.cx",
"fedibird.com",
"qoto.org",
"kurage.cc",
"m.eula.dev",
"otogamer.me",
"sgp.hostdon.ne.jp",
"pomdon.work",
"obapom.work",
)
// Mastodon only counts URLs as this long in terms of status character limits
const val DEFAULT_CHARACTERS_RESERVED_PER_URL = 23
fun InstanceInfoEntity?.toInstanceInfo(): InstanceInfo =
InstanceInfo(
maxChars = this?.maximumTootCharacters ?: DEFAULT_CHARACTER_LIMIT,
pollMaxOptions = this?.maxPollOptions ?: DEFAULT_MAX_OPTION_COUNT,
pollMaxLength = this?.maxPollOptionLength ?: DEFAULT_MAX_OPTION_LENGTH,
pollMinDuration = this?.minPollDuration ?: DEFAULT_MIN_POLL_DURATION,
pollMaxDuration = this?.maxPollDuration ?: DEFAULT_MAX_POLL_DURATION,
charactersReservedPerUrl = this?.charactersReservedPerUrl ?: DEFAULT_CHARACTERS_RESERVED_PER_URL
)
}
}