upgrade ktlint plugin to 12.0.3 (#4169)

There are some new rules, I think they mostly make sense, except for the
max line length which I had to disable because we are over it in a lot
of places.

---------

Co-authored-by: Goooler <wangzongler@gmail.com>
This commit is contained in:
Konrad Pozniak 2024-01-04 17:00:55 +01:00 committed by GitHub
commit 5192fb08a5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
215 changed files with 2813 additions and 1177 deletions

View file

@ -38,8 +38,10 @@ data class AccountEntity(
@field:PrimaryKey(autoGenerate = true) var id: Long,
val domain: String,
var accessToken: String,
var clientId: String?, // nullable for backward compatibility
var clientSecret: String?, // nullable for backward compatibility
// nullable for backward compatibility
var clientId: String?,
// nullable for backward compatibility
var clientSecret: String?,
var isActive: Boolean,
var accountId: String = "",
var username: String = "",
@ -111,7 +113,7 @@ data class AccountEntity(
var isShowHomeBoosts: Boolean = true,
var isShowHomeReplies: Boolean = true,
var isShowHomeSelfBoosts: Boolean = true,
var isShowHomeSelfBoosts: Boolean = true
) {
val identifier: String

View file

@ -236,7 +236,10 @@ class AccountManager @Inject constructor(db: AppDatabase) {
*/
fun shouldDisplaySelfUsername(context: Context): Boolean {
val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)
val showUsernamePreference = sharedPreferences.getString(PrefKeys.SHOW_SELF_USERNAME, "disambiguate")
val showUsernamePreference = sharedPreferences.getString(
PrefKeys.SHOW_SELF_USERNAME,
"disambiguate"
)
if (showUsernamePreference == "always") {
return true
}

View file

@ -66,14 +66,19 @@ class Converters @Inject constructor(
return str?.split(";")
?.map {
val data = it.split(":")
createTabDataFromId(data[0], data.drop(1).map { s -> URLDecoder.decode(s, "UTF-8") })
createTabDataFromId(
data[0],
data.drop(1).map { s -> URLDecoder.decode(s, "UTF-8") }
)
}
}
@TypeConverter
fun tabDataToString(tabData: List<TabData>?): String? {
// List name may include ":"
return tabData?.joinToString(";") { it.id + ":" + it.arguments.joinToString(":") { s -> URLEncoder.encode(s, "UTF-8") } }
return tabData?.joinToString(";") {
it.id + ":" + it.arguments.joinToString(":") { s -> URLEncoder.encode(s, "UTF-8") }
}
}
@TypeConverter
@ -93,7 +98,10 @@ class Converters @Inject constructor(
@TypeConverter
fun jsonToAccountList(accountListJson: String?): List<ConversationAccountEntity>? {
return gson.fromJson(accountListJson, object : TypeToken<List<ConversationAccountEntity>>() {}.type)
return gson.fromJson(
accountListJson,
object : TypeToken<List<ConversationAccountEntity>>() {}.type
)
}
@TypeConverter
@ -163,7 +171,10 @@ class Converters @Inject constructor(
@TypeConverter
fun jsonToDraftAttachmentList(draftAttachmentListJson: String?): List<DraftAttachment>? {
return gson.fromJson(draftAttachmentListJson, object : TypeToken<List<DraftAttachment>>() {}.type)
return gson.fromJson(
draftAttachmentListJson,
object : TypeToken<List<DraftAttachment>>() {}.type
)
}
@TypeConverter

View file

@ -34,7 +34,9 @@ interface DraftDao {
@Query("SELECT COUNT(*) FROM DraftEntity WHERE accountId = :accountId AND failedToSendNew = 1")
fun draftsNeedUserAlert(accountId: Long): LiveData<Int>
@Query("UPDATE DraftEntity SET failedToSendNew = 0 WHERE accountId = :accountId AND failedToSendNew = 1")
@Query(
"UPDATE DraftEntity SET failedToSendNew = 0 WHERE accountId = :accountId AND failedToSendNew = 1"
)
suspend fun draftsClearNeedUserAlert(accountId: Long)
@Query("SELECT * FROM DraftEntity WHERE accountId = :accountId")

View file

@ -62,6 +62,8 @@ data class DraftAttachment(
get() = uriString.toUri()
enum class Type {
IMAGE, VIDEO, AUDIO;
IMAGE,
VIDEO,
AUDIO
}
}

View file

@ -1,99 +1,99 @@
/* Copyright 2023 Andi McClure
*
* 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.db
import android.content.Context
import android.content.DialogInterface
import android.util.Log
import androidx.appcompat.app.AlertDialog
import androidx.lifecycle.LifecycleCoroutineScope
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.lifecycleScope
import com.keylesspalace.tusky.R
import com.keylesspalace.tusky.components.drafts.DraftsActivity
import kotlinx.coroutines.launch
import javax.inject.Inject
import javax.inject.Singleton
/**
* This class manages an alert popup when a post has failed and been saved to drafts.
* It must be separately registered in each lifetime in which it is to appear,
* and it only appears if the post failure belongs to the current user.
*/
private const val TAG = "DraftsAlert"
@Singleton
class DraftsAlert @Inject constructor(db: AppDatabase) {
// For tracking when a media upload fails in the service
private val draftDao: DraftDao = db.draftDao()
@Inject
lateinit var accountManager: AccountManager
fun <T> observeInContext(context: T, showAlert: Boolean) where T : Context, T : LifecycleOwner {
accountManager.activeAccount?.let { activeAccount ->
val coroutineScope = context.lifecycleScope
// Assume a single MainActivity, AccountActivity or DraftsActivity never sees more then one user id in its lifetime.
val activeAccountId = activeAccount.id
// This LiveData will be automatically disposed when the activity is destroyed.
val draftsNeedUserAlert = draftDao.draftsNeedUserAlert(activeAccountId)
// observe ensures that this gets called at the most appropriate moment wrt the context lifecycle—
// at init, at next onResume, or immediately if the context is resumed already.
if (showAlert) {
draftsNeedUserAlert.observe(context) { count ->
Log.d(TAG, "User id $activeAccountId changed: Notification-worthy draft count $count")
if (count > 0) {
AlertDialog.Builder(context)
.setTitle(R.string.action_post_failed)
.setMessage(
context.resources.getQuantityString(R.plurals.action_post_failed_detail, count)
)
.setPositiveButton(R.string.action_post_failed_show_drafts) { _: DialogInterface?, _: Int ->
clearDraftsAlert(coroutineScope, activeAccountId) // User looked at drafts
val intent = DraftsActivity.newIntent(context)
context.startActivity(intent)
}
.setNegativeButton(R.string.action_post_failed_do_nothing) { _: DialogInterface?, _: Int ->
clearDraftsAlert(coroutineScope, activeAccountId) // User doesn't care
}
.show()
}
}
} else {
draftsNeedUserAlert.observe(context) {
Log.d(TAG, "User id $activeAccountId: Clean out notification-worthy drafts")
clearDraftsAlert(coroutineScope, activeAccountId)
}
}
} ?: run {
Log.w(TAG, "Attempted to observe drafts, but there is no active account")
}
}
/**
* Clear drafts alert for specified user
*/
private fun clearDraftsAlert(coroutineScope: LifecycleCoroutineScope, id: Long) {
coroutineScope.launch {
draftDao.draftsClearNeedUserAlert(id)
}
}
}
/* Copyright 2023 Andi McClure
*
* 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.db
import android.content.Context
import android.content.DialogInterface
import android.util.Log
import androidx.appcompat.app.AlertDialog
import androidx.lifecycle.LifecycleCoroutineScope
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.lifecycleScope
import com.keylesspalace.tusky.R
import com.keylesspalace.tusky.components.drafts.DraftsActivity
import javax.inject.Inject
import javax.inject.Singleton
import kotlinx.coroutines.launch
/**
* This class manages an alert popup when a post has failed and been saved to drafts.
* It must be separately registered in each lifetime in which it is to appear,
* and it only appears if the post failure belongs to the current user.
*/
private const val TAG = "DraftsAlert"
@Singleton
class DraftsAlert @Inject constructor(db: AppDatabase) {
// For tracking when a media upload fails in the service
private val draftDao: DraftDao = db.draftDao()
@Inject
lateinit var accountManager: AccountManager
fun <T> observeInContext(context: T, showAlert: Boolean) where T : Context, T : LifecycleOwner {
accountManager.activeAccount?.let { activeAccount ->
val coroutineScope = context.lifecycleScope
// Assume a single MainActivity, AccountActivity or DraftsActivity never sees more then one user id in its lifetime.
val activeAccountId = activeAccount.id
// This LiveData will be automatically disposed when the activity is destroyed.
val draftsNeedUserAlert = draftDao.draftsNeedUserAlert(activeAccountId)
// observe ensures that this gets called at the most appropriate moment wrt the context lifecycle—
// at init, at next onResume, or immediately if the context is resumed already.
if (showAlert) {
draftsNeedUserAlert.observe(context) { count ->
Log.d(TAG, "User id $activeAccountId changed: Notification-worthy draft count $count")
if (count > 0) {
AlertDialog.Builder(context)
.setTitle(R.string.action_post_failed)
.setMessage(
context.resources.getQuantityString(R.plurals.action_post_failed_detail, count)
)
.setPositiveButton(R.string.action_post_failed_show_drafts) { _: DialogInterface?, _: Int ->
clearDraftsAlert(coroutineScope, activeAccountId) // User looked at drafts
val intent = DraftsActivity.newIntent(context)
context.startActivity(intent)
}
.setNegativeButton(R.string.action_post_failed_do_nothing) { _: DialogInterface?, _: Int ->
clearDraftsAlert(coroutineScope, activeAccountId) // User doesn't care
}
.show()
}
}
} else {
draftsNeedUserAlert.observe(context) {
Log.d(TAG, "User id $activeAccountId: Clean out notification-worthy drafts")
clearDraftsAlert(coroutineScope, activeAccountId)
}
}
} ?: run {
Log.w(TAG, "Attempted to observe drafts, but there is no active account")
}
}
/**
* Clear drafts alert for specified user
*/
private fun clearDraftsAlert(coroutineScope: LifecycleCoroutineScope, id: Long) {
coroutineScope.launch {
draftDao.draftsClearNeedUserAlert(id)
}
}
}

View file

@ -255,13 +255,21 @@ WHERE timelineUserId = :accountId AND (serverId = :statusId OR reblogServerId =
"""UPDATE TimelineStatusEntity SET contentShowing = :contentShowing
WHERE timelineUserId = :accountId AND (serverId = :statusId OR reblogServerId = :statusId)"""
)
abstract suspend fun setContentShowing(accountId: Long, statusId: String, contentShowing: Boolean)
abstract suspend fun setContentShowing(
accountId: Long,
statusId: String,
contentShowing: Boolean
)
@Query(
"""UPDATE TimelineStatusEntity SET contentCollapsed = :contentCollapsed
WHERE timelineUserId = :accountId AND (serverId = :statusId OR reblogServerId = :statusId)"""
)
abstract suspend fun setContentCollapsed(accountId: Long, statusId: String, contentCollapsed: Boolean)
abstract suspend fun setContentCollapsed(
accountId: Long,
statusId: String,
contentCollapsed: Boolean
)
@Query(
"""UPDATE TimelineStatusEntity SET pinned = :pinned
@ -278,39 +286,53 @@ AND timelineUserId = :accountId
)
abstract suspend fun deleteAllFromInstance(accountId: Long, instanceDomain: String)
@Query("UPDATE TimelineStatusEntity SET filtered = NULL WHERE timelineUserId = :accountId AND (serverId = :statusId OR reblogServerId = :statusId)")
@Query(
"UPDATE TimelineStatusEntity SET filtered = NULL WHERE timelineUserId = :accountId AND (serverId = :statusId OR reblogServerId = :statusId)"
)
abstract suspend fun clearWarning(accountId: Long, statusId: String): Int
@Query("SELECT serverId FROM TimelineStatusEntity WHERE timelineUserId = :accountId ORDER BY LENGTH(serverId) DESC, serverId DESC LIMIT 1")
@Query(
"SELECT serverId FROM TimelineStatusEntity WHERE timelineUserId = :accountId ORDER BY LENGTH(serverId) DESC, serverId DESC LIMIT 1"
)
abstract suspend fun getTopId(accountId: Long): String?
@Query("SELECT serverId FROM TimelineStatusEntity WHERE timelineUserId = :accountId AND authorServerId IS NULL ORDER BY LENGTH(serverId) DESC, serverId DESC LIMIT 1")
@Query(
"SELECT serverId FROM TimelineStatusEntity WHERE timelineUserId = :accountId AND authorServerId IS NULL ORDER BY LENGTH(serverId) DESC, serverId DESC LIMIT 1"
)
abstract suspend fun getTopPlaceholderId(accountId: Long): String?
/**
* Returns the id directly above [serverId], or null if [serverId] is the id of the top status
*/
@Query("SELECT serverId FROM TimelineStatusEntity WHERE timelineUserId = :accountId AND (LENGTH(:serverId) < LENGTH(serverId) OR (LENGTH(:serverId) = LENGTH(serverId) AND :serverId < serverId)) ORDER BY LENGTH(serverId) ASC, serverId ASC LIMIT 1")
@Query(
"SELECT serverId FROM TimelineStatusEntity WHERE timelineUserId = :accountId AND (LENGTH(:serverId) < LENGTH(serverId) OR (LENGTH(:serverId) = LENGTH(serverId) AND :serverId < serverId)) ORDER BY LENGTH(serverId) ASC, serverId ASC LIMIT 1"
)
abstract suspend fun getIdAbove(accountId: Long, serverId: String): String?
/**
* Returns the ID directly below [serverId], or null if [serverId] is the ID of the bottom
* status
*/
@Query("SELECT serverId FROM TimelineStatusEntity WHERE timelineUserId = :accountId AND (LENGTH(:serverId) > LENGTH(serverId) OR (LENGTH(:serverId) = LENGTH(serverId) AND :serverId > serverId)) ORDER BY LENGTH(serverId) DESC, serverId DESC LIMIT 1")
@Query(
"SELECT serverId FROM TimelineStatusEntity WHERE timelineUserId = :accountId AND (LENGTH(:serverId) > LENGTH(serverId) OR (LENGTH(:serverId) = LENGTH(serverId) AND :serverId > serverId)) ORDER BY LENGTH(serverId) DESC, serverId DESC LIMIT 1"
)
abstract suspend fun getIdBelow(accountId: Long, serverId: String): String?
/**
* Returns the id of the next placeholder after [serverId]
*/
@Query("SELECT serverId FROM TimelineStatusEntity WHERE timelineUserId = :accountId AND authorServerId IS NULL AND (LENGTH(:serverId) > LENGTH(serverId) OR (LENGTH(:serverId) = LENGTH(serverId) AND :serverId > serverId)) ORDER BY LENGTH(serverId) DESC, serverId DESC LIMIT 1")
@Query(
"SELECT serverId FROM TimelineStatusEntity WHERE timelineUserId = :accountId AND authorServerId IS NULL AND (LENGTH(:serverId) > LENGTH(serverId) OR (LENGTH(:serverId) = LENGTH(serverId) AND :serverId > serverId)) ORDER BY LENGTH(serverId) DESC, serverId DESC LIMIT 1"
)
abstract suspend fun getNextPlaceholderIdAfter(accountId: Long, serverId: String): String?
@Query("SELECT COUNT(*) FROM TimelineStatusEntity WHERE timelineUserId = :accountId")
abstract suspend fun getStatusCount(accountId: Long): Int
/** Developer tools: Find N most recent status IDs */
@Query("SELECT serverId FROM TimelineStatusEntity WHERE timelineUserId = :accountId ORDER BY LENGTH(serverId) DESC, serverId DESC LIMIT :count")
@Query(
"SELECT serverId FROM TimelineStatusEntity WHERE timelineUserId = :accountId ORDER BY LENGTH(serverId) DESC, serverId DESC LIMIT :count"
)
abstract suspend fun getMostRecentNStatusIds(accountId: Long, count: Int): List<String>
/** Developer tools: Convert a status to a placeholder */

View file

@ -50,7 +50,8 @@ import com.keylesspalace.tusky.entity.Status
)
@TypeConverters(Converters::class)
data class TimelineStatusEntity(
val serverId: String, // id never flips: we need it for sorting so it's a real id
// id never flips: we need it for sorting so it's a real id
val serverId: String,
val url: String?,
// our local id for the logged in user in case there are multiple accounts per instance
val timelineUserId: Long,
@ -74,7 +75,8 @@ data class TimelineStatusEntity(
val mentions: String?,
val tags: String?,
val application: String?,
val reblogServerId: String?, // if it has a reblogged status, it's id is stored here
// if it has a reblogged status, it's id is stored here
val reblogServerId: String?,
val reblogAccountId: String?,
val poll: String?,
val muted: Boolean?,
@ -109,8 +111,10 @@ data class TimelineAccountEntity(
data class TimelineStatusWithAccount(
@Embedded
val status: TimelineStatusEntity,
// null when placeholder
@Embedded(prefix = "a_")
val account: TimelineAccountEntity? = null, // null when placeholder
val account: TimelineAccountEntity? = null,
// null when no reblog
@Embedded(prefix = "rb_")
val reblogAccount: TimelineAccountEntity? = null // null when no reblog
val reblogAccount: TimelineAccountEntity? = null
)