move json de/serialization completely to room converter

This commit is contained in:
Conny Duck 2024-04-18 20:47:35 +02:00
parent cbd9f06fe9
commit 0a5714a6ee
No known key found for this signature in database
14 changed files with 150 additions and 200 deletions

View File

@ -27,19 +27,18 @@ import com.keylesspalace.tusky.entity.Report
import com.keylesspalace.tusky.viewdata.NotificationViewData import com.keylesspalace.tusky.viewdata.NotificationViewData
import com.keylesspalace.tusky.viewdata.StatusViewData import com.keylesspalace.tusky.viewdata.StatusViewData
import com.keylesspalace.tusky.viewdata.TranslationViewData import com.keylesspalace.tusky.viewdata.TranslationViewData
import com.squareup.moshi.Moshi
fun Placeholder.toNotificationEntity(tuskyAccountId: Long): NotificationEntity { fun Placeholder.toNotificationEntity(
return NotificationEntity( tuskyAccountId: Long
id = this.id, ) = NotificationEntity(
tuskyAccountId = tuskyAccountId, id = this.id,
type = null, tuskyAccountId = tuskyAccountId,
accountId = null, type = null,
statusId = null, accountId = null,
reportId = null, statusId = null,
loading = loading reportId = null,
) loading = loading
} )
fun Notification.toEntity( fun Notification.toEntity(
tuskyAccountId: Long tuskyAccountId: Long
@ -65,7 +64,6 @@ fun Report.toEntity(
) )
fun NotificationDataEntity.toViewData( fun NotificationDataEntity.toViewData(
moshi: Moshi,
translation: TranslationViewData? = null translation: TranslationViewData? = null
): NotificationViewData { ): NotificationViewData {
if (type == null || account == null) { if (type == null || account == null) {
@ -75,10 +73,10 @@ fun NotificationDataEntity.toViewData(
return NotificationViewData.Concrete( return NotificationViewData.Concrete(
id = id, id = id,
type = type, type = type,
account = account.toAccount(moshi), account = account.toAccount(),
statusViewData = if (status != null && statusAccount != null) { statusViewData = if (status != null && statusAccount != null) {
StatusViewData.Concrete( StatusViewData.Concrete(
status = status.toStatus(moshi, statusAccount), status = status.toStatus(statusAccount),
isExpanded = this.status.expanded, isExpanded = this.status.expanded,
isShowingContent = this.status.contentShowing, isShowingContent = this.status.contentShowing,
isCollapsed = this.status.contentCollapsed, isCollapsed = this.status.contentCollapsed,
@ -88,7 +86,7 @@ fun NotificationDataEntity.toViewData(
null null
}, },
report = if (report != null && reportTargetAccount != null) { report = if (report != null && reportTargetAccount != null) {
report.toReport(reportTargetAccount, moshi) report.toReport(reportTargetAccount)
} else { } else {
null null
} }
@ -96,12 +94,11 @@ fun NotificationDataEntity.toViewData(
} }
fun NotificationReportEntity.toReport( fun NotificationReportEntity.toReport(
account: TimelineAccountEntity, account: TimelineAccountEntity
moshi: Moshi
) = Report( ) = Report(
id = serverId, id = serverId,
category = category, category = category,
statusIds = statusIds, statusIds = statusIds,
createdAt = createdAt, createdAt = createdAt,
targetAccount = account.toAccount(moshi) targetAccount = account.toAccount()
) )

View File

@ -31,7 +31,6 @@ import com.keylesspalace.tusky.db.entity.TimelineStatusEntity
import com.keylesspalace.tusky.entity.Notification import com.keylesspalace.tusky.entity.Notification
import com.keylesspalace.tusky.network.MastodonApi import com.keylesspalace.tusky.network.MastodonApi
import com.keylesspalace.tusky.util.isLessThan import com.keylesspalace.tusky.util.isLessThan
import com.squareup.moshi.Moshi
import retrofit2.HttpException import retrofit2.HttpException
@OptIn(ExperimentalPagingApi::class) @OptIn(ExperimentalPagingApi::class)
@ -39,7 +38,6 @@ class NotificationsRemoteMediator(
private val accountManager: AccountManager, private val accountManager: AccountManager,
private val api: MastodonApi, private val api: MastodonApi,
private val db: AppDatabase, private val db: AppDatabase,
private val moshi: Moshi,
var excludes: Set<Notification.Type> var excludes: Set<Notification.Type>
) : RemoteMediator<Int, NotificationDataEntity>() { ) : RemoteMediator<Int, NotificationDataEntity>() {
@ -145,9 +143,9 @@ class NotificationsRemoteMediator(
} }
for (notification in notifications) { for (notification in notifications) {
accountDao.insert(notification.account.toEntity(activeAccount.id, moshi)) accountDao.insert(notification.account.toEntity(activeAccount.id))
notification.report?.let { report -> notification.report?.let { report ->
accountDao.insert(report.targetAccount.toEntity(activeAccount.id, moshi)) accountDao.insert(report.targetAccount.toEntity(activeAccount.id))
notificationsDao.insertReport(report.toEntity(activeAccount.id)) notificationsDao.insertReport(report.toEntity(activeAccount.id))
} }
@ -166,12 +164,11 @@ class NotificationsRemoteMediator(
val contentShowing = oldStatus?.contentShowing ?: (activeAccount.alwaysShowSensitiveMedia || !status.sensitive) val contentShowing = oldStatus?.contentShowing ?: (activeAccount.alwaysShowSensitiveMedia || !status.sensitive)
val contentCollapsed = oldStatus?.contentCollapsed ?: true val contentCollapsed = oldStatus?.contentCollapsed ?: true
accountDao.insert(status.account.toEntity(activeAccount.id, moshi)) accountDao.insert(status.account.toEntity(activeAccount.id))
statusDao.insert( statusDao.insert(
status.toEntity( status.toEntity(
tuskyAccountId = activeAccount.id, tuskyAccountId = activeAccount.id,
moshi = moshi,
expanded = expanded, expanded = expanded,
contentShowing = contentShowing, contentShowing = contentShowing,
contentCollapsed = contentCollapsed contentCollapsed = contentCollapsed

View File

@ -51,7 +51,6 @@ import com.keylesspalace.tusky.util.serialize
import com.keylesspalace.tusky.viewdata.NotificationViewData import com.keylesspalace.tusky.viewdata.NotificationViewData
import com.keylesspalace.tusky.viewdata.StatusViewData import com.keylesspalace.tusky.viewdata.StatusViewData
import com.keylesspalace.tusky.viewdata.TranslationViewData import com.keylesspalace.tusky.viewdata.TranslationViewData
import com.squareup.moshi.Moshi
import javax.inject.Inject import javax.inject.Inject
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job import kotlinx.coroutines.Job
@ -75,7 +74,6 @@ class NotificationsViewModel @Inject constructor(
private val preferences: SharedPreferences, private val preferences: SharedPreferences,
private val filterModel: FilterModel, private val filterModel: FilterModel,
private val db: AppDatabase, private val db: AppDatabase,
private val moshi: Moshi
) : ViewModel() { ) : ViewModel() {
private val _filters = MutableStateFlow( private val _filters = MutableStateFlow(
@ -86,7 +84,7 @@ class NotificationsViewModel @Inject constructor(
/** Map from notification id to translation. */ /** Map from notification id to translation. */
private val translations = MutableStateFlow(mapOf<String, TranslationViewData>()) private val translations = MutableStateFlow(mapOf<String, TranslationViewData>())
private var remoteMediator = NotificationsRemoteMediator(accountManager, api, db, moshi, filters.value) private var remoteMediator = NotificationsRemoteMediator(accountManager, api, db, filters.value)
private var readingOrder: ReadingOrder = private var readingOrder: ReadingOrder =
ReadingOrder.from(preferences.getString(PrefKeys.READING_ORDER, null)) ReadingOrder.from(preferences.getString(PrefKeys.READING_ORDER, null))
@ -108,10 +106,7 @@ class NotificationsViewModel @Inject constructor(
.combine(translations) { pagingData, translations -> .combine(translations) { pagingData, translations ->
pagingData.map(Dispatchers.Default.asExecutor()) { notification -> pagingData.map(Dispatchers.Default.asExecutor()) { notification ->
val translation = translations[notification.status?.serverId] val translation = translations[notification.status?.serverId]
notification.toViewData( notification.toViewData(translation = translation)
moshi,
translation = translation
)
}.filter(Dispatchers.Default.asExecutor()) { notificationViewData -> }.filter(Dispatchers.Default.asExecutor()) { notificationViewData ->
shouldFilterStatus(notificationViewData) != Filter.Action.HIDE shouldFilterStatus(notificationViewData) != Filter.Action.HIDE
} }
@ -338,18 +333,17 @@ class NotificationsViewModel @Inject constructor(
} }
for (notification in notifications) { for (notification in notifications) {
accountDao.insert(notification.account.toEntity(activeAccount.id, moshi)) accountDao.insert(notification.account.toEntity(activeAccount.id))
notification.report?.let { report -> notification.report?.let { report ->
accountDao.insert(report.targetAccount.toEntity(activeAccount.id, moshi)) accountDao.insert(report.targetAccount.toEntity(activeAccount.id))
notificationsDao.insertReport(report.toEntity(activeAccount.id)) notificationsDao.insertReport(report.toEntity(activeAccount.id))
} }
notification.status?.let { status -> notification.status?.let { status ->
accountDao.insert(status.account.toEntity(activeAccount.id, moshi)) accountDao.insert(status.account.toEntity(activeAccount.id))
statusDao.insert( statusDao.insert(
status.toEntity( status.toEntity(
tuskyAccountId = activeAccount.id, tuskyAccountId = activeAccount.id,
moshi = moshi,
expanded = activeAccount.alwaysOpenSpoiler, expanded = activeAccount.alwaysOpenSpoiler,
contentShowing = activeAccount.alwaysShowSensitiveMedia || !status.sensitive, contentShowing = activeAccount.alwaysShowSensitiveMedia || !status.sensitive,
contentCollapsed = true contentCollapsed = true

View File

@ -21,17 +21,10 @@ import com.keylesspalace.tusky.db.entity.HomeTimelineData
import com.keylesspalace.tusky.db.entity.HomeTimelineEntity import com.keylesspalace.tusky.db.entity.HomeTimelineEntity
import com.keylesspalace.tusky.db.entity.TimelineAccountEntity import com.keylesspalace.tusky.db.entity.TimelineAccountEntity
import com.keylesspalace.tusky.db.entity.TimelineStatusEntity import com.keylesspalace.tusky.db.entity.TimelineStatusEntity
import com.keylesspalace.tusky.entity.Attachment
import com.keylesspalace.tusky.entity.Card
import com.keylesspalace.tusky.entity.Emoji
import com.keylesspalace.tusky.entity.HashTag
import com.keylesspalace.tusky.entity.Poll
import com.keylesspalace.tusky.entity.Status import com.keylesspalace.tusky.entity.Status
import com.keylesspalace.tusky.entity.TimelineAccount import com.keylesspalace.tusky.entity.TimelineAccount
import com.keylesspalace.tusky.viewdata.StatusViewData import com.keylesspalace.tusky.viewdata.StatusViewData
import com.keylesspalace.tusky.viewdata.TranslationViewData import com.keylesspalace.tusky.viewdata.TranslationViewData
import com.squareup.moshi.Moshi
import com.squareup.moshi.adapter
import java.util.Date import java.util.Date
data class Placeholder( data class Placeholder(
@ -39,7 +32,7 @@ data class Placeholder(
val loading: Boolean val loading: Boolean
) )
fun TimelineAccount.toEntity(tuskyAccountId: Long, moshi: Moshi): TimelineAccountEntity { fun TimelineAccount.toEntity(tuskyAccountId: Long): TimelineAccountEntity {
return TimelineAccountEntity( return TimelineAccountEntity(
serverId = id, serverId = id,
tuskyAccountId = tuskyAccountId, tuskyAccountId = tuskyAccountId,
@ -48,12 +41,12 @@ fun TimelineAccount.toEntity(tuskyAccountId: Long, moshi: Moshi): TimelineAccoun
displayName = name, displayName = name,
url = url, url = url,
avatar = avatar, avatar = avatar,
emojis = moshi.adapter<List<Emoji>>().toJson(emojis), emojis = emojis,
bot = bot bot = bot
) )
} }
fun TimelineAccountEntity.toAccount(moshi: Moshi): TimelineAccount { fun TimelineAccountEntity.toAccount(): TimelineAccount {
return TimelineAccount( return TimelineAccount(
id = serverId, id = serverId,
localUsername = localUsername, localUsername = localUsername,
@ -63,7 +56,7 @@ fun TimelineAccountEntity.toAccount(moshi: Moshi): TimelineAccount {
url = url, url = url,
avatar = avatar, avatar = avatar,
bot = bot, bot = bot,
emojis = moshi.adapter<List<Emoji>?>().fromJson(emojis).orEmpty() emojis = emojis
) )
} }
@ -79,104 +72,90 @@ fun Placeholder.toEntity(tuskyAccountId: Long): HomeTimelineEntity {
fun Status.toEntity( fun Status.toEntity(
tuskyAccountId: Long, tuskyAccountId: Long,
moshi: Moshi,
expanded: Boolean, expanded: Boolean,
contentShowing: Boolean, contentShowing: Boolean,
contentCollapsed: Boolean contentCollapsed: Boolean
): TimelineStatusEntity { ) = TimelineStatusEntity(
return TimelineStatusEntity( serverId = id,
serverId = id, url = actionableStatus.url,
url = actionableStatus.url, tuskyAccountId = tuskyAccountId,
tuskyAccountId = tuskyAccountId, authorServerId = actionableStatus.account.id,
authorServerId = actionableStatus.account.id, inReplyToId = actionableStatus.inReplyToId,
inReplyToId = actionableStatus.inReplyToId, inReplyToAccountId = actionableStatus.inReplyToAccountId,
inReplyToAccountId = actionableStatus.inReplyToAccountId, content = actionableStatus.content,
content = actionableStatus.content, createdAt = actionableStatus.createdAt.time,
createdAt = actionableStatus.createdAt.time, editedAt = actionableStatus.editedAt?.time,
editedAt = actionableStatus.editedAt?.time, emojis = actionableStatus.emojis,
emojis = actionableStatus.emojis.let { moshi.adapter<List<Emoji>>().toJson(it) }, reblogsCount = actionableStatus.reblogsCount,
reblogsCount = actionableStatus.reblogsCount, favouritesCount = actionableStatus.favouritesCount,
favouritesCount = actionableStatus.favouritesCount, reblogged = actionableStatus.reblogged,
reblogged = actionableStatus.reblogged, favourited = actionableStatus.favourited,
favourited = actionableStatus.favourited, bookmarked = actionableStatus.bookmarked,
bookmarked = actionableStatus.bookmarked, sensitive = actionableStatus.sensitive,
sensitive = actionableStatus.sensitive, spoilerText = actionableStatus.spoilerText,
spoilerText = actionableStatus.spoilerText, visibility = actionableStatus.visibility,
visibility = actionableStatus.visibility, attachments = actionableStatus.attachments,
attachments = actionableStatus.attachments.let { moshi.adapter<List<Attachment>>().toJson(it) }, mentions = actionableStatus.mentions,
mentions = actionableStatus.mentions.let { moshi.adapter<List<Status.Mention>>().toJson(it) }, tags = actionableStatus.tags,
tags = actionableStatus.tags.let { moshi.adapter<List<HashTag>?>().toJson(it) }, application = actionableStatus.application,
application = actionableStatus.application.let { moshi.adapter<Status.Application?>().toJson(it) }, poll = actionableStatus.poll,
poll = actionableStatus.poll.let { moshi.adapter<Poll?>().toJson(it) }, muted = actionableStatus.muted,
muted = actionableStatus.muted, expanded = expanded,
expanded = expanded, contentShowing = contentShowing,
contentShowing = contentShowing, contentCollapsed = contentCollapsed,
contentCollapsed = contentCollapsed, pinned = actionableStatus.pinned,
pinned = actionableStatus.pinned, card = actionableStatus.card,
card = actionableStatus.card?.let { moshi.adapter<Card>().toJson(it) }, repliesCount = actionableStatus.repliesCount,
repliesCount = actionableStatus.repliesCount, language = actionableStatus.language,
language = actionableStatus.language, filtered = actionableStatus.filtered
filtered = actionableStatus.filtered )
)
}
fun TimelineStatusEntity.toStatus( fun TimelineStatusEntity.toStatus(
moshi: Moshi,
account: TimelineAccountEntity account: TimelineAccountEntity
): Status { ) = Status(
val attachments: List<Attachment> = moshi.adapter<List<Attachment>>().fromJson(attachments).orEmpty() id = serverId,
val mentions: List<Status.Mention> = moshi.adapter<List<Status.Mention>>().fromJson(mentions).orEmpty() url = url,
val tags: List<HashTag> = moshi.adapter<List<HashTag>>().fromJson(tags).orEmpty() account = account.toAccount(),
val application = application?.let { moshi.adapter<Status.Application?>().fromJson(it) } inReplyToId = inReplyToId,
val emojis: List<Emoji> = moshi.adapter<List<Emoji>?>().fromJson(emojis).orEmpty() inReplyToAccountId = inReplyToAccountId,
val poll: Poll? = poll?.let { moshi.adapter<Poll?>().fromJson(it) } reblog = null,
val card: Card? = card?.let { moshi.adapter<Card?>().fromJson(it) } content = content,
createdAt = Date(createdAt),
editedAt = editedAt?.let { Date(it) },
emojis = emojis,
reblogsCount = reblogsCount,
favouritesCount = favouritesCount,
reblogged = reblogged,
favourited = favourited,
bookmarked = bookmarked,
sensitive = sensitive,
spoilerText = spoilerText,
visibility = visibility,
attachments = attachments,
mentions = mentions,
tags = tags,
application = application,
pinned = false,
muted = muted,
poll = poll,
card = card,
repliesCount = repliesCount,
language = language,
filtered = filtered,
)
return Status( fun HomeTimelineData.toViewData(isDetailed: Boolean = false, translation: TranslationViewData? = null): StatusViewData {
id = serverId,
url = url,
account = account.toAccount(moshi),
inReplyToId = inReplyToId,
inReplyToAccountId = inReplyToAccountId,
reblog = null,
content = content,
createdAt = Date(createdAt),
editedAt = editedAt?.let { Date(it) },
emojis = emojis,
reblogsCount = reblogsCount,
favouritesCount = favouritesCount,
reblogged = reblogged,
favourited = favourited,
bookmarked = bookmarked,
sensitive = sensitive,
spoilerText = spoilerText,
visibility = visibility,
attachments = attachments,
mentions = mentions,
tags = tags,
application = application,
pinned = false,
muted = muted,
poll = poll,
card = card,
repliesCount = repliesCount,
language = language,
filtered = filtered,
)
}
fun HomeTimelineData.toViewData(moshi: Moshi, isDetailed: Boolean = false, translation: TranslationViewData? = null): StatusViewData {
if (this.account == null || this.status == null) { if (this.account == null || this.status == null) {
return StatusViewData.Placeholder(this.id, loading) return StatusViewData.Placeholder(this.id, loading)
} }
val originalStatus = status.toStatus(moshi, account) val originalStatus = status.toStatus(account)
val status = if (reblogAccount != null) { val status = if (reblogAccount != null) {
Status( Status(
id = id, id = id,
// no url for reblogs // no url for reblogs
url = null, url = null,
account = reblogAccount.toAccount(moshi), account = reblogAccount.toAccount(),
inReplyToId = status.inReplyToId, inReplyToId = status.inReplyToId,
inReplyToAccountId = status.inReplyToAccountId, inReplyToAccountId = status.inReplyToAccountId,
reblog = originalStatus, reblog = originalStatus,

View File

@ -31,7 +31,6 @@ import com.keylesspalace.tusky.db.entity.HomeTimelineEntity
import com.keylesspalace.tusky.db.entity.TimelineStatusEntity import com.keylesspalace.tusky.db.entity.TimelineStatusEntity
import com.keylesspalace.tusky.entity.Status import com.keylesspalace.tusky.entity.Status
import com.keylesspalace.tusky.network.MastodonApi import com.keylesspalace.tusky.network.MastodonApi
import com.squareup.moshi.Moshi
import retrofit2.HttpException import retrofit2.HttpException
@OptIn(ExperimentalPagingApi::class) @OptIn(ExperimentalPagingApi::class)
@ -39,7 +38,6 @@ class CachedTimelineRemoteMediator(
accountManager: AccountManager, accountManager: AccountManager,
private val api: MastodonApi, private val api: MastodonApi,
private val db: AppDatabase, private val db: AppDatabase,
private val moshi: Moshi
) : RemoteMediator<Int, HomeTimelineData>() { ) : RemoteMediator<Int, HomeTimelineData>() {
private var initialRefresh = false private var initialRefresh = false
@ -146,8 +144,8 @@ class CachedTimelineRemoteMediator(
} }
for (status in statuses) { for (status in statuses) {
accountDao.insert(status.account.toEntity(activeAccount.id, moshi)) accountDao.insert(status.account.toEntity(activeAccount.id))
status.reblog?.account?.toEntity(activeAccount.id, moshi)?.let { rebloggedAccount -> status.reblog?.account?.toEntity(activeAccount.id)?.let { rebloggedAccount ->
accountDao.insert(rebloggedAccount) accountDao.insert(rebloggedAccount)
} }
@ -168,7 +166,6 @@ class CachedTimelineRemoteMediator(
statusDao.insert( statusDao.insert(
status.actionableStatus.toEntity( status.actionableStatus.toEntity(
tuskyAccountId = activeAccount.id, tuskyAccountId = activeAccount.id,
moshi = moshi,
expanded = expanded, expanded = expanded,
contentShowing = contentShowing, contentShowing = contentShowing,
contentCollapsed = contentCollapsed contentCollapsed = contentCollapsed

View File

@ -48,7 +48,6 @@ import com.keylesspalace.tusky.usecase.TimelineCases
import com.keylesspalace.tusky.util.EmptyPagingSource import com.keylesspalace.tusky.util.EmptyPagingSource
import com.keylesspalace.tusky.viewdata.StatusViewData import com.keylesspalace.tusky.viewdata.StatusViewData
import com.keylesspalace.tusky.viewdata.TranslationViewData import com.keylesspalace.tusky.viewdata.TranslationViewData
import com.squareup.moshi.Moshi
import javax.inject.Inject import javax.inject.Inject
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.asExecutor import kotlinx.coroutines.asExecutor
@ -68,8 +67,7 @@ class CachedTimelineViewModel @Inject constructor(
accountManager: AccountManager, accountManager: AccountManager,
sharedPreferences: SharedPreferences, sharedPreferences: SharedPreferences,
filterModel: FilterModel, filterModel: FilterModel,
private val db: AppDatabase, private val db: AppDatabase
private val moshi: Moshi
) : TimelineViewModel( ) : TimelineViewModel(
timelineCases, timelineCases,
api, api,
@ -87,7 +85,7 @@ class CachedTimelineViewModel @Inject constructor(
@OptIn(ExperimentalPagingApi::class) @OptIn(ExperimentalPagingApi::class)
override val statuses = Pager( override val statuses = Pager(
config = PagingConfig(pageSize = LOAD_AT_ONCE), config = PagingConfig(pageSize = LOAD_AT_ONCE),
remoteMediator = CachedTimelineRemoteMediator(accountManager, api, db, moshi), remoteMediator = CachedTimelineRemoteMediator(accountManager, api, db),
pagingSourceFactory = { pagingSourceFactory = {
val activeAccount = accountManager.activeAccount val activeAccount = accountManager.activeAccount
if (activeAccount == null) { if (activeAccount == null) {
@ -108,7 +106,6 @@ class CachedTimelineViewModel @Inject constructor(
pagingData.map(Dispatchers.Default.asExecutor()) { timelineData -> pagingData.map(Dispatchers.Default.asExecutor()) { timelineData ->
val translation = translations[timelineData.status?.serverId] val translation = translations[timelineData.status?.serverId]
timelineData.toViewData( timelineData.toViewData(
moshi,
isDetailed = false, isDetailed = false,
translation = translation translation = translation
) )
@ -209,15 +206,14 @@ class CachedTimelineViewModel @Inject constructor(
} }
for (status in statuses) { for (status in statuses) {
accountDao.insert(status.account.toEntity(activeAccount.id, moshi)) accountDao.insert(status.account.toEntity(activeAccount.id))
status.reblog?.account?.toEntity(activeAccount.id, moshi) status.reblog?.account?.toEntity(activeAccount.id)
?.let { rebloggedAccount -> ?.let { rebloggedAccount ->
accountDao.insert(rebloggedAccount) accountDao.insert(rebloggedAccount)
} }
statusDao.insert( statusDao.insert(
status.actionableStatus.toEntity( status.actionableStatus.toEntity(
tuskyAccountId = activeAccount.id, tuskyAccountId = activeAccount.id,
moshi = moshi,
expanded = activeAccount.alwaysOpenSpoiler, expanded = activeAccount.alwaysOpenSpoiler,
contentShowing = activeAccount.alwaysShowSensitiveMedia || !status.actionableStatus.sensitive, contentShowing = activeAccount.alwaysShowSensitiveMedia || !status.actionableStatus.sensitive,
contentCollapsed = true contentCollapsed = true

View File

@ -114,7 +114,7 @@ class ViewThreadViewModel @Inject constructor(
var detailedStatus = if (statusAndAccount != null) { var detailedStatus = if (statusAndAccount != null) {
Log.d(TAG, "Loaded status from local timeline") Log.d(TAG, "Loaded status from local timeline")
StatusViewData.Concrete( StatusViewData.Concrete(
status = statusAndAccount.first.toStatus(moshi, statusAndAccount.second), status = statusAndAccount.first.toStatus(statusAndAccount.second),
isExpanded = statusAndAccount.first.expanded, isExpanded = statusAndAccount.first.expanded,
isShowingContent = statusAndAccount.first.contentShowing, isShowingContent = statusAndAccount.first.contentShowing,
isCollapsed = statusAndAccount.first.contentCollapsed, isCollapsed = statusAndAccount.first.contentCollapsed,

View File

@ -189,6 +189,11 @@ class Converters @Inject constructor(
return moshi.adapter<Card?>().toJson(card) return moshi.adapter<Card?>().toJson(card)
} }
@TypeConverter
fun jsonToCard(cardJson: String?): Card? {
return cardJson?.let { moshi.adapter<Card?>().fromJson(cardJson) }
}
@TypeConverter @TypeConverter
fun stringListToJson(list: List<String>?): String? { fun stringListToJson(list: List<String>?): String? {
return moshi.adapter<List<String>?>().toJson(list) return moshi.adapter<List<String>?>().toJson(list)
@ -198,4 +203,14 @@ class Converters @Inject constructor(
fun jsonToStringList(listJson: String?): List<String>? { fun jsonToStringList(listJson: String?): List<String>? {
return listJson?.let { moshi.adapter<List<String>?>().fromJson(it) } return listJson?.let { moshi.adapter<List<String>?>().fromJson(it) }
} }
@TypeConverter
fun applicationToJson(application: Status.Application?): String {
return moshi.adapter<Status.Application?>().toJson(application)
}
@TypeConverter
fun jsonToApplication(applicationJson: String?): Status.Application? {
return applicationJson?.let { moshi.adapter<Status.Application?>().fromJson(it) }
}
} }

View File

@ -16,10 +16,14 @@
package com.keylesspalace.tusky.db.entity package com.keylesspalace.tusky.db.entity
import androidx.room.Entity import androidx.room.Entity
import androidx.room.TypeConverters
import com.keylesspalace.tusky.db.Converters
import com.keylesspalace.tusky.entity.Emoji
@Entity( @Entity(
primaryKeys = ["serverId", "tuskyAccountId"] primaryKeys = ["serverId", "tuskyAccountId"]
) )
@TypeConverters(Converters::class)
data class TimelineAccountEntity( data class TimelineAccountEntity(
val serverId: String, val serverId: String,
val tuskyAccountId: Long, val tuskyAccountId: Long,
@ -28,6 +32,6 @@ data class TimelineAccountEntity(
val displayName: String, val displayName: String,
val url: String, val url: String,
val avatar: String, val avatar: String,
val emojis: String, val emojis: List<Emoji>,
val bot: Boolean val bot: Boolean
) )

View File

@ -20,7 +20,12 @@ import androidx.room.ForeignKey
import androidx.room.Index import androidx.room.Index
import androidx.room.TypeConverters import androidx.room.TypeConverters
import com.keylesspalace.tusky.db.Converters import com.keylesspalace.tusky.db.Converters
import com.keylesspalace.tusky.entity.Attachment
import com.keylesspalace.tusky.entity.Card
import com.keylesspalace.tusky.entity.Emoji
import com.keylesspalace.tusky.entity.FilterResult import com.keylesspalace.tusky.entity.FilterResult
import com.keylesspalace.tusky.entity.HashTag
import com.keylesspalace.tusky.entity.Poll
import com.keylesspalace.tusky.entity.Status import com.keylesspalace.tusky.entity.Status
/** /**
@ -54,7 +59,7 @@ data class TimelineStatusEntity(
val content: String, val content: String,
val createdAt: Long, val createdAt: Long,
val editedAt: Long?, val editedAt: Long?,
val emojis: String, val emojis: List<Emoji>,
val reblogsCount: Int, val reblogsCount: Int,
val favouritesCount: Int, val favouritesCount: Int,
val repliesCount: Int, val repliesCount: Int,
@ -64,19 +69,19 @@ data class TimelineStatusEntity(
val sensitive: Boolean, val sensitive: Boolean,
val spoilerText: String, val spoilerText: String,
val visibility: Status.Visibility, val visibility: Status.Visibility,
val attachments: String, val attachments: List<Attachment>,
val mentions: String, val mentions: List<Status.Mention>,
val tags: String, val tags: List<HashTag>,
val application: String?, val application: Status.Application?,
// 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 poll: String?, val poll: Poll?,
val muted: Boolean, val muted: Boolean,
/** Also used as the "loading" attribute when this TimelineStatusEntity is a placeholder */ /** Also used as the "loading" attribute when this TimelineStatusEntity is a placeholder */
val expanded: Boolean, val expanded: Boolean,
val contentCollapsed: Boolean, val contentCollapsed: Boolean,
val contentShowing: Boolean, val contentShowing: Boolean,
val pinned: Boolean, val pinned: Boolean,
val card: String?, val card: Card?,
val language: String?, val language: String?,
val filtered: List<FilterResult> val filtered: List<FilterResult>
) )

View File

@ -9,7 +9,6 @@ import com.keylesspalace.tusky.components.timeline.toEntity
import com.keylesspalace.tusky.db.AppDatabase import com.keylesspalace.tusky.db.AppDatabase
import com.keylesspalace.tusky.db.entity.NotificationDataEntity import com.keylesspalace.tusky.db.entity.NotificationDataEntity
import com.keylesspalace.tusky.db.entity.NotificationEntity import com.keylesspalace.tusky.db.entity.NotificationEntity
import com.keylesspalace.tusky.di.NetworkModule
import com.keylesspalace.tusky.entity.Notification import com.keylesspalace.tusky.entity.Notification
import com.keylesspalace.tusky.entity.Report import com.keylesspalace.tusky.entity.Report
import com.keylesspalace.tusky.entity.Status import com.keylesspalace.tusky.entity.Status
@ -49,25 +48,21 @@ fun Notification.toNotificationDataEntity(
tuskyAccountId: Long, tuskyAccountId: Long,
isStatusExpanded: Boolean = false, isStatusExpanded: Boolean = false,
isStatusContentShowing: Boolean = false isStatusContentShowing: Boolean = false
): NotificationDataEntity { ) = NotificationDataEntity(
val moshi = NetworkModule.providesMoshi() tuskyAccountId = tuskyAccountId,
return NotificationDataEntity( type = type,
id = id,
account = account.toEntity(tuskyAccountId),
status = status?.toEntity(
tuskyAccountId = tuskyAccountId, tuskyAccountId = tuskyAccountId,
type = type, expanded = isStatusExpanded,
id = id, contentShowing = isStatusContentShowing,
account = account.toEntity(tuskyAccountId, moshi), contentCollapsed = true
status = status?.toEntity( ),
tuskyAccountId = tuskyAccountId, statusAccount = status?.account?.toEntity(tuskyAccountId),
moshi = moshi, report = report?.toEntity(tuskyAccountId),
expanded = isStatusExpanded, reportTargetAccount = report?.targetAccount?.toEntity(tuskyAccountId)
contentShowing = isStatusContentShowing, )
contentCollapsed = true
),
statusAccount = status?.account?.toEntity(tuskyAccountId, moshi),
report = report?.toEntity(tuskyAccountId),
reportTargetAccount = report?.targetAccount?.toEntity(tuskyAccountId, moshi)
)
}
fun Placeholder.toNotificationDataEntity( fun Placeholder.toNotificationDataEntity(
tuskyAccountId: Long tuskyAccountId: Long
@ -83,18 +78,16 @@ fun Placeholder.toNotificationDataEntity(
) )
suspend fun AppDatabase.insert(notifications: List<Notification>, tuskyAccountId: Long = 1) = withTransaction { suspend fun AppDatabase.insert(notifications: List<Notification>, tuskyAccountId: Long = 1) = withTransaction {
val moshi = NetworkModule.providesMoshi()
notifications.forEach { notification -> notifications.forEach { notification ->
timelineAccountDao().insert( timelineAccountDao().insert(
notification.account.toEntity(tuskyAccountId, moshi) notification.account.toEntity(tuskyAccountId)
) )
notification.report?.let { report -> notification.report?.let { report ->
timelineAccountDao().insert( timelineAccountDao().insert(
report.targetAccount.toEntity( report.targetAccount.toEntity(
tuskyAccountId = tuskyAccountId, tuskyAccountId = tuskyAccountId,
moshi = moshi
) )
) )
notificationsDao().insertReport(report.toEntity(tuskyAccountId)) notificationsDao().insertReport(report.toEntity(tuskyAccountId))
@ -103,13 +96,11 @@ suspend fun AppDatabase.insert(notifications: List<Notification>, tuskyAccountId
timelineAccountDao().insert( timelineAccountDao().insert(
status.account.toEntity( status.account.toEntity(
tuskyAccountId = tuskyAccountId, tuskyAccountId = tuskyAccountId,
moshi = moshi
) )
) )
timelineStatusDao().insert( timelineStatusDao().insert(
status.toEntity( status.toEntity(
tuskyAccountId = tuskyAccountId, tuskyAccountId = tuskyAccountId,
moshi = moshi,
expanded = false, expanded = false,
contentShowing = false, contentShowing = false,
contentCollapsed = true contentCollapsed = true

View File

@ -82,7 +82,6 @@ class NotificationsRemoteMediatorTest {
onBlocking { notifications(anyOrNull(), anyOrNull(), anyOrNull(), anyOrNull(), anyOrNull()) } doReturn Response.error(500, "".toResponseBody()) onBlocking { notifications(anyOrNull(), anyOrNull(), anyOrNull(), anyOrNull(), anyOrNull()) } doReturn Response.error(500, "".toResponseBody())
}, },
db = db, db = db,
moshi = moshi,
excludes = emptySet() excludes = emptySet()
) )
@ -102,7 +101,6 @@ class NotificationsRemoteMediatorTest {
onBlocking { notifications(anyOrNull(), anyOrNull(), anyOrNull(), anyOrNull(), anyOrNull()) } doThrow IOException() onBlocking { notifications(anyOrNull(), anyOrNull(), anyOrNull(), anyOrNull(), anyOrNull()) } doThrow IOException()
}, },
db = db, db = db,
moshi = moshi,
excludes = emptySet() excludes = emptySet()
) )
@ -119,7 +117,6 @@ class NotificationsRemoteMediatorTest {
accountManager = accountManager, accountManager = accountManager,
api = mock(), api = mock(),
db = db, db = db,
moshi = moshi,
excludes = emptySet() excludes = emptySet()
) )
@ -171,7 +168,6 @@ class NotificationsRemoteMediatorTest {
) )
}, },
db = db, db = db,
moshi = moshi,
excludes = emptySet() excludes = emptySet()
) )
@ -233,7 +229,6 @@ class NotificationsRemoteMediatorTest {
) )
}, },
db = db, db = db,
moshi = moshi,
excludes = emptySet() excludes = emptySet()
) )
@ -294,7 +289,6 @@ class NotificationsRemoteMediatorTest {
) )
}, },
db = db, db = db,
moshi = moshi,
excludes = emptySet() excludes = emptySet()
) )
@ -340,7 +334,6 @@ class NotificationsRemoteMediatorTest {
) )
}, },
db = db, db = db,
moshi = moshi,
excludes = emptySet() excludes = emptySet()
) )
@ -395,7 +388,6 @@ class NotificationsRemoteMediatorTest {
) )
}, },
db = db, db = db,
moshi = moshi,
excludes = emptySet() excludes = emptySet()
) )
@ -457,7 +449,6 @@ class NotificationsRemoteMediatorTest {
) )
}, },
db = db, db = db,
moshi = moshi,
excludes = emptySet() excludes = emptySet()
) )
@ -510,7 +501,6 @@ class NotificationsRemoteMediatorTest {
) )
}, },
db = db, db = db,
moshi = moshi,
excludes = emptySet() excludes = emptySet()
) )

View File

@ -82,7 +82,6 @@ class CachedTimelineRemoteMediatorTest {
onBlocking { homeTimeline(anyOrNull(), anyOrNull(), anyOrNull(), anyOrNull()) } doReturn Response.error(500, "".toResponseBody()) onBlocking { homeTimeline(anyOrNull(), anyOrNull(), anyOrNull(), anyOrNull()) } doReturn Response.error(500, "".toResponseBody())
}, },
db = db, db = db,
moshi = moshi
) )
val result = remoteMediator.load(LoadType.REFRESH, state()) val result = remoteMediator.load(LoadType.REFRESH, state())
@ -101,7 +100,6 @@ class CachedTimelineRemoteMediatorTest {
onBlocking { homeTimeline(anyOrNull(), anyOrNull(), anyOrNull(), anyOrNull()) } doThrow IOException() onBlocking { homeTimeline(anyOrNull(), anyOrNull(), anyOrNull(), anyOrNull()) } doThrow IOException()
}, },
db = db, db = db,
moshi = moshi
) )
val result = remoteMediator.load(LoadType.REFRESH, state()) val result = remoteMediator.load(LoadType.REFRESH, state())
@ -117,7 +115,6 @@ class CachedTimelineRemoteMediatorTest {
accountManager = accountManager, accountManager = accountManager,
api = mock(), api = mock(),
db = db, db = db,
moshi = moshi
) )
val state = state( val state = state(
@ -168,7 +165,6 @@ class CachedTimelineRemoteMediatorTest {
) )
}, },
db = db, db = db,
moshi = moshi
) )
val state = state( val state = state(
@ -229,7 +225,6 @@ class CachedTimelineRemoteMediatorTest {
) )
}, },
db = db, db = db,
moshi = moshi
) )
val state = state( val state = state(
@ -289,7 +284,6 @@ class CachedTimelineRemoteMediatorTest {
) )
}, },
db = db, db = db,
moshi = moshi
) )
val state = state( val state = state(
@ -334,7 +328,6 @@ class CachedTimelineRemoteMediatorTest {
) )
}, },
db = db, db = db,
moshi = moshi
) )
val state = state( val state = state(
@ -385,7 +378,6 @@ class CachedTimelineRemoteMediatorTest {
) )
}, },
db = db, db = db,
moshi = moshi
) )
val state = state( val state = state(
@ -441,7 +433,6 @@ class CachedTimelineRemoteMediatorTest {
) )
}, },
db = db, db = db,
moshi = moshi
) )
val state = state( val state = state(
@ -493,7 +484,6 @@ class CachedTimelineRemoteMediatorTest {
) )
}, },
db = db, db = db,
moshi = moshi
) )
val state = state( val state = state(

View File

@ -5,7 +5,6 @@ import androidx.room.withTransaction
import com.keylesspalace.tusky.db.AppDatabase import com.keylesspalace.tusky.db.AppDatabase
import com.keylesspalace.tusky.db.entity.HomeTimelineData import com.keylesspalace.tusky.db.entity.HomeTimelineData
import com.keylesspalace.tusky.db.entity.HomeTimelineEntity import com.keylesspalace.tusky.db.entity.HomeTimelineEntity
import com.keylesspalace.tusky.di.NetworkModule
import com.keylesspalace.tusky.entity.Status import com.keylesspalace.tusky.entity.Status
import com.keylesspalace.tusky.entity.TimelineAccount import com.keylesspalace.tusky.entity.TimelineAccount
import com.keylesspalace.tusky.viewdata.StatusViewData import com.keylesspalace.tusky.viewdata.StatusViewData
@ -114,27 +113,23 @@ fun mockHomeTimelineData(
authorServerId = authorServerId, authorServerId = authorServerId,
domain = domain domain = domain
) )
val moshi = NetworkModule.providesMoshi()
return HomeTimelineData( return HomeTimelineData(
id = id, id = id,
status = mockedStatus.toEntity( status = mockedStatus.toEntity(
tuskyAccountId = tuskyAccountId, tuskyAccountId = tuskyAccountId,
moshi = moshi,
expanded = expanded, expanded = expanded,
contentShowing = false, contentShowing = false,
contentCollapsed = true contentCollapsed = true
), ),
account = mockedStatus.account.toEntity( account = mockedStatus.account.toEntity(
tuskyAccountId = tuskyAccountId, tuskyAccountId = tuskyAccountId,
moshi = moshi
), ),
reblogAccount = reblogAuthorServerId?.let { reblogAuthorId -> reblogAccount = reblogAuthorServerId?.let { reblogAuthorId ->
mockAccount( mockAccount(
id = reblogAuthorId id = reblogAuthorId
).toEntity( ).toEntity(
tuskyAccountId = tuskyAccountId, tuskyAccountId = tuskyAccountId,
moshi = moshi
) )
}, },
loading = false loading = false