2021-06-28 09:09:00 +02:00
|
|
|
package jp.juggler.subwaytooter.column
|
2019-06-05 23:06:37 +02:00
|
|
|
|
|
|
|
import android.content.Context
|
|
|
|
import android.content.SharedPreferences
|
2020-01-28 02:12:08 +01:00
|
|
|
import android.os.SystemClock
|
2021-05-17 16:13:04 +02:00
|
|
|
import jp.juggler.subwaytooter.api.ApiPath
|
2020-01-28 02:12:08 +01:00
|
|
|
import jp.juggler.subwaytooter.api.TootApiClient
|
2019-06-05 23:06:37 +02:00
|
|
|
import jp.juggler.subwaytooter.api.TootApiResult
|
|
|
|
import jp.juggler.subwaytooter.api.TootParser
|
2021-05-22 00:03:16 +02:00
|
|
|
import jp.juggler.subwaytooter.api.entity.TimelineItem
|
|
|
|
import jp.juggler.subwaytooter.api.entity.TootAnnouncement
|
|
|
|
import jp.juggler.subwaytooter.api.entity.TootInstance
|
|
|
|
import jp.juggler.subwaytooter.api.entity.parseList
|
2019-06-05 23:06:37 +02:00
|
|
|
import jp.juggler.subwaytooter.table.SavedAccount
|
2021-05-22 00:03:16 +02:00
|
|
|
import jp.juggler.util.*
|
2020-04-07 06:52:54 +02:00
|
|
|
import kotlinx.coroutines.*
|
2019-06-05 23:06:37 +02:00
|
|
|
import java.util.concurrent.atomic.AtomicBoolean
|
|
|
|
|
2021-06-20 15:12:25 +02:00
|
|
|
enum class ColumnTaskType(val marker: Char) {
|
|
|
|
LOADING('L'),
|
|
|
|
REFRESH_TOP('T'),
|
|
|
|
REFRESH_BOTTOM('B'),
|
|
|
|
GAP('G')
|
2019-06-05 23:06:37 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
abstract class ColumnTask(
|
2021-06-20 15:12:25 +02:00
|
|
|
val column: Column,
|
|
|
|
val ctType: ColumnTaskType
|
2020-09-12 19:47:00 +02:00
|
|
|
) {
|
2021-06-20 15:12:25 +02:00
|
|
|
|
|
|
|
val ctStarted = AtomicBoolean(false)
|
|
|
|
val ctClosed = AtomicBoolean(false)
|
|
|
|
|
|
|
|
private var job: Job? = null
|
|
|
|
|
|
|
|
val isCancelled: Boolean
|
|
|
|
get() = job?.isCancelled ?: false
|
|
|
|
|
|
|
|
var parser = TootParser(context, accessInfo, highlightTrie = highlightTrie)
|
|
|
|
|
|
|
|
var listTmp: ArrayList<TimelineItem>? = null
|
|
|
|
|
|
|
|
val context: Context
|
|
|
|
get() = column.context
|
|
|
|
|
|
|
|
val accessInfo: SavedAccount
|
|
|
|
get() = column.accessInfo
|
|
|
|
|
|
|
|
val highlightTrie: WordTrieTree?
|
|
|
|
get() = column.highlightTrie
|
|
|
|
|
|
|
|
val isPseudo: Boolean
|
|
|
|
get() = accessInfo.isPseudo
|
|
|
|
|
|
|
|
private val isMastodon: Boolean
|
|
|
|
get() = accessInfo.isMastodon
|
|
|
|
|
|
|
|
val isMisskey: Boolean
|
|
|
|
get() = accessInfo.isMisskey
|
|
|
|
|
|
|
|
val misskeyVersion: Int
|
|
|
|
get() = accessInfo.misskeyVersion
|
|
|
|
|
|
|
|
val pref: SharedPreferences
|
|
|
|
get() = column.appState.pref
|
|
|
|
|
|
|
|
internal fun JsonObject.addMisskeyNotificationFilter() = addMisskeyNotificationFilter(column)
|
|
|
|
internal fun JsonObject.addRangeMisskey(bBottom: Boolean) = addRangeMisskey(column, bBottom)
|
|
|
|
|
|
|
|
internal val profileDirectoryPath: String
|
|
|
|
get() {
|
|
|
|
val order = when (val q = column.searchQuery) {
|
|
|
|
"new" -> q
|
|
|
|
else -> "active"
|
|
|
|
}
|
|
|
|
val local = !column.searchResolve
|
|
|
|
return "${ApiPath.PATH_PROFILE_DIRECTORY}&order=$order&local=$local"
|
|
|
|
}
|
|
|
|
|
|
|
|
internal suspend fun getAnnouncements(
|
|
|
|
client: TootApiClient,
|
|
|
|
force: Boolean = false
|
|
|
|
): TootApiResult? {
|
|
|
|
// announcements is shown only mastodon home timeline, not pseudo.
|
|
|
|
if (isMastodon && !isPseudo) {
|
|
|
|
// force (initial loading) always reload announcements
|
|
|
|
// other (refresh,gap) may reload announcements if last load is too old
|
|
|
|
if (force || SystemClock.elapsedRealtime() - column.announcementUpdated >= 15 * 60000L) {
|
|
|
|
if (force) {
|
|
|
|
column.announcements = null
|
|
|
|
column.announcementUpdated = SystemClock.elapsedRealtime()
|
|
|
|
client.publishApiProgress("announcements reset")
|
|
|
|
}
|
|
|
|
val (instance, _) = TootInstance.get(client)
|
|
|
|
if (instance?.versionGE(TootInstance.VERSION_3_1_0_rc1) == true) {
|
|
|
|
val result = client.request("/api/v1/announcements")
|
|
|
|
?: return null // cancelled.
|
|
|
|
when (result.response?.code ?: 0) {
|
|
|
|
// just skip load announcements for 4xx error if server does not support announcements.
|
|
|
|
in 400 until 500 -> {
|
|
|
|
}
|
|
|
|
|
|
|
|
else -> {
|
|
|
|
column.announcements =
|
|
|
|
parseList(::TootAnnouncement, parser, result.jsonArray)
|
|
|
|
.notEmpty()
|
|
|
|
column.announcementUpdated = SystemClock.elapsedRealtime()
|
|
|
|
client.publishApiProgress("announcements loaded")
|
|
|
|
// other errors such as network or server fails will stop column loading.
|
|
|
|
return result
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return TootApiResult()
|
|
|
|
}
|
|
|
|
|
|
|
|
abstract suspend fun background(): TootApiResult?
|
|
|
|
abstract suspend fun handleResult(result: TootApiResult?)
|
|
|
|
|
|
|
|
fun cancel() {
|
|
|
|
job?.cancel()
|
|
|
|
}
|
|
|
|
|
|
|
|
fun start() {
|
|
|
|
job = launchMain {
|
|
|
|
val result = try {
|
|
|
|
withContext(Dispatchers.IO) { background() }
|
|
|
|
} catch (ignored: CancellationException) {
|
|
|
|
null // キャンセルされたらresult==nullとする
|
|
|
|
} catch (ex: Throwable) {
|
|
|
|
// その他のエラー
|
|
|
|
TootApiResult(ex.withCaption("error"))
|
|
|
|
}
|
|
|
|
handleResult(result)
|
|
|
|
}
|
|
|
|
}
|
2019-06-05 23:06:37 +02:00
|
|
|
}
|