commit f854b217a2510ce5822717abc10fcc9ad190b289
parent bf5d57758c330c4a05cf1b1e0bbb081e71d1289b
Author: rhunk <101876869+rhunk@users.noreply.github.com>
Date:   Thu,  2 Jan 2025 17:41:50 +0100

fix(core): feed entry table

Signed-off-by: rhunk <101876869+rhunk@users.noreply.github.com>

Diffstat:
Mapp/src/main/kotlin/me/rhunk/snapenhance/ui/manager/pages/social/AddFriendDialog.kt | 22++++++++++++++++++----
Mcommon/src/main/assets/lang/en_US.json | 3++-
Mcommon/src/main/kotlin/me/rhunk/snapenhance/common/database/impl/FriendFeedEntry.kt | 25+++++++++++++++----------
Mcore/src/main/kotlin/me/rhunk/snapenhance/core/SnapEnhance.kt | 23+++++++++++++----------
Mcore/src/main/kotlin/me/rhunk/snapenhance/core/action/impl/ExportChatMessages.kt | 34+++++++++++++++++++++++++++-------
Mcore/src/main/kotlin/me/rhunk/snapenhance/core/database/DatabaseAccess.kt | 42++++++++++++++++++++++++++----------------
Mcore/src/main/kotlin/me/rhunk/snapenhance/core/features/impl/spying/HalfSwipeNotifier.kt | 8++++----
7 files changed, 105 insertions(+), 52 deletions(-)

diff --git a/app/src/main/kotlin/me/rhunk/snapenhance/ui/manager/pages/social/AddFriendDialog.kt b/app/src/main/kotlin/me/rhunk/snapenhance/ui/manager/pages/social/AddFriendDialog.kt @@ -45,6 +45,7 @@ class AddFriendDialog( id: String, bitmoji: String? = null, name: String, + participantsCount: Int? = null, getCurrentState: () -> Boolean, onState: (Boolean) -> Unit = {}, ) { @@ -74,12 +75,24 @@ class AddFriendDialog( size = 32, ) - Text( - text = name, - fontSize = 15.sp, + Column( modifier = Modifier .weight(1f) - ) + ) { + Text( + text = name, + fontSize = 15.sp, + ) + + participantsCount?.let { + Text( + text = translation.format("participants_text", "count" to it.toString()), + fontSize = 12.sp, + lineHeight = 12.sp, + color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.6f) + ) + } + } Checkbox( checked = currentState, @@ -249,6 +262,7 @@ class AddFriendDialog( ListCardEntry( id = group.conversationId, name = group.name, + participantsCount = group.participantsCount, getCurrentState = { actionHandler.getGroupState(group) } ) { state -> actionHandler.onGroupState(group, state) diff --git a/common/src/main/assets/lang/en_US.json b/common/src/main/assets/lang/en_US.json @@ -198,7 +198,8 @@ "search_hint": "Search", "fetch_error": "Failed to fetch data", "category_groups": "Groups", - "category_friends": "Friends" + "category_friends": "Friends", + "participants_text": "{count} participants" }, "scripting_warning": { "title": "Warning", diff --git a/common/src/main/kotlin/me/rhunk/snapenhance/common/database/impl/FriendFeedEntry.kt b/common/src/main/kotlin/me/rhunk/snapenhance/common/database/impl/FriendFeedEntry.kt @@ -3,13 +3,14 @@ package me.rhunk.snapenhance.common.database.impl import android.annotation.SuppressLint import android.database.Cursor import me.rhunk.snapenhance.common.database.DatabaseObject +import me.rhunk.snapenhance.common.util.ktx.getBlobOrNull import me.rhunk.snapenhance.common.util.ktx.getIntOrNull -import me.rhunk.snapenhance.common.util.ktx.getInteger -import me.rhunk.snapenhance.common.util.ktx.getLong +import me.rhunk.snapenhance.common.util.ktx.getLongOrNull import me.rhunk.snapenhance.common.util.ktx.getStringOrNull +import java.nio.ByteBuffer +import java.util.UUID data class FriendFeedEntry( - var id: Int = 0, var feedDisplayName: String? = null, var participantsSize: Int = 0, var lastInteractionTimestamp: Long = 0, @@ -18,24 +19,28 @@ data class FriendFeedEntry( var lastInteractionUserId: Int? = null, var key: String? = null, var friendUserId: String? = null, + var participants: List<String>? = null, + var conversationType: Int? = null, var friendDisplayName: String? = null, var friendDisplayUsername: String? = null, var friendLinkType: Int? = null, var bitmojiAvatarId: String? = null, var bitmojiSelfieId: String? = null, ) : DatabaseObject { - @SuppressLint("Range") override fun write(cursor: Cursor) { with(cursor) { - id = getInteger("_id") - feedDisplayName = getStringOrNull("feedDisplayName") - participantsSize = getInteger("participantsSize") - lastInteractionTimestamp = getLong("lastInteractionTimestamp") - displayTimestamp = getLong("displayTimestamp") + key = getStringOrNull("client_conversation_id") ?: getStringOrNull("key") + feedDisplayName = (getStringOrNull("conversation_title") ?: getStringOrNull("feedDisplayName"))?.takeIf { it.isNotBlank() } + lastInteractionTimestamp = getLongOrNull("last_updated_timestamp") ?: getLongOrNull("lastInteractionTimestamp") ?: 0L + + participants = getBlobOrNull("participants")?.toList()?.chunked(16)?.map { ByteBuffer.wrap(it.toByteArray()).run { UUID(long, long) }.toString() } ?: emptyList() + participantsSize = getIntOrNull("participantsSize") ?: participants?.size ?: 0 + conversationType = getIntOrNull("conversation_type") ?: getIntOrNull("kind") + + displayTimestamp = getLongOrNull("displayTimestamp") ?: 0L displayInteractionType = getStringOrNull("displayInteractionType") lastInteractionUserId = getIntOrNull("lastInteractionUserId") - key = getStringOrNull("key") friendUserId = getStringOrNull("friendUserId") friendDisplayName = getStringOrNull("friendDisplayName") friendDisplayUsername = getStringOrNull("friendDisplayUsername") diff --git a/core/src/main/kotlin/me/rhunk/snapenhance/core/SnapEnhance.kt b/core/src/main/kotlin/me/rhunk/snapenhance/core/SnapEnhance.kt @@ -330,22 +330,25 @@ class SnapEnhance { event.canceled = true val feedEntries = appContext.database.getFeedEntries(Int.MAX_VALUE) - val groups = feedEntries.filter { it.friendUserId == null }.map { + val groups = feedEntries.filter { it.conversationType == 1 }.map { MessagingGroupInfo( it.key!!, - it.feedDisplayName!!, + it.feedDisplayName ?: "", it.participantsSize ) } - val friends = feedEntries.filter { it.friendUserId != null }.map { + val friends = feedEntries.filter { it.conversationType == 0 }.mapNotNull { + val friendUserId = it.friendUserId ?: it.participants?.filter { it != appContext.database.myUserId }?.firstOrNull() ?: return@mapNotNull null + val friend = appContext.database.getFriendInfo(friendUserId) ?: return@mapNotNull null + MessagingFriendInfo( - it.friendUserId!!, - appContext.database.getConversationLinkFromUserId(it.friendUserId!!)?.clientConversationId, - it.friendDisplayName, - it.friendDisplayUsername!!.split("|")[1], - it.bitmojiAvatarId, - it.bitmojiSelfieId, + friendUserId, + appContext.database.getConversationLinkFromUserId(friendUserId)?.clientConversationId, + friend.displayName, + friend.mutableUsername ?: friend.usernameForSorting!!, + friend.bitmojiAvatarId, + friend.bitmojiSelfieId, streaks = null ) } @@ -379,7 +382,7 @@ class SnapEnhance { return appContext.database.getFeedEntryByConversationId(uuid)?.let { MessagingGroupInfo( it.key!!, - it.feedDisplayName!!, + it.feedDisplayName ?: "", it.participantsSize ).toSerialized() } diff --git a/core/src/main/kotlin/me/rhunk/snapenhance/core/action/impl/ExportChatMessages.kt b/core/src/main/kotlin/me/rhunk/snapenhance/core/action/impl/ExportChatMessages.kt @@ -22,10 +22,12 @@ import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp import kotlinx.coroutines.* import me.rhunk.snapenhance.common.data.ContentType import me.rhunk.snapenhance.common.database.impl.FriendFeedEntry import me.rhunk.snapenhance.common.ui.createComposeAlertDialog +import me.rhunk.snapenhance.common.ui.rememberAsyncMutableState import me.rhunk.snapenhance.core.action.AbstractAction import me.rhunk.snapenhance.core.features.impl.messaging.Messaging import me.rhunk.snapenhance.core.logger.CoreLogger @@ -72,6 +74,8 @@ class ExportChatMessages : AbstractAction() { val messageTypeFilter = remember { mutableStateListOf<ContentType>() } var amountOfMessages by remember { mutableIntStateOf(-1) } var downloadMedias by remember { mutableStateOf(false) } + val allFriends by rememberAsyncMutableState(null) { context.database.getAllFriends().associateBy { it.userId!! } } + val myUserId = context.database.myUserId Column( modifier = Modifier @@ -102,7 +106,7 @@ class ExportChatMessages : AbstractAction() { LazyColumn( modifier = Modifier.size(LocalConfiguration.current.screenWidthDp.dp, 300.dp) ) { - items(feedEntries) { feedEntry -> + items(feedEntries, key = { it.key!! }) { feedEntry -> DropdownMenuItem( modifier = Modifier.fillMaxWidth(), onClick = { @@ -114,11 +118,26 @@ class ExportChatMessages : AbstractAction() { verticalAlignment = Alignment.CenterVertically ) { Checkbox(checked = selectedFeedEntries.contains(feedEntry), onCheckedChange = null) - Text( - text = feedEntry.feedDisplayName ?: feedEntry.friendDisplayName ?: "unknown", - overflow = TextOverflow.Ellipsis, - maxLines = 1 - ) + Column { + Text( + text = remember(feedEntry) { + (if (feedEntry.conversationType == 1) feedEntry.feedDisplayName else feedEntry.participants?.filter { it != myUserId }?.firstOrNull()?.let { userId -> + allFriends?.get(userId)?.let { friend -> friend.displayName?.let { "$it (${friend.mutableUsername})" } ?: friend.mutableUsername } + }) ?: "Unknown" + }, + overflow = TextOverflow.Ellipsis, + lineHeight = 15.sp, + maxLines = 1 + ) + if (feedEntry.conversationType == 1) { + Text( + text = "${feedEntry.participantsSize} participants", + fontSize = 10.sp, + lineHeight = 15.sp, + overflow = TextOverflow.Ellipsis, + ) + } + } } } ) @@ -332,12 +351,13 @@ class ExportChatMessages : AbstractAction() { ) { //first fetch the first message val conversationId = feedEntry.key!! - val conversationName = feedEntry.feedDisplayName ?: feedEntry.friendDisplayName!!.split("|").lastOrNull() ?: "unknown" val conversationParticipants = context.database.getConversationParticipants(feedEntry.key!!, useCache = false) ?.mapNotNull { context.database.getFriendInfo(it) }?.associateBy { it.userId!! } ?: emptyMap() + val conversationName = feedEntry.feedDisplayName ?: conversationParticipants.values.take(3).joinToString("_") { it.mutableUsername ?: "" } + val publicFolder = File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), "SnapEnhance").also { if (!it.exists()) it.mkdirs() } val outputFile = publicFolder.resolve("conversation_${conversationName}_${System.currentTimeMillis()}.${exportParams.exportFormat.extension}") diff --git a/core/src/main/kotlin/me/rhunk/snapenhance/core/database/DatabaseAccess.kt b/core/src/main/kotlin/me/rhunk/snapenhance/core/database/DatabaseAccess.kt @@ -152,17 +152,6 @@ class DatabaseAccess( obj } - fun getFeedEntryByUserId(userId: String): FriendFeedEntry? { - return useDatabase(DatabaseType.MAIN)?.performOperation { - readDatabaseObject( - FriendFeedEntry(), - "FriendsFeedView", - "friendUserId = ?", - arrayOf(userId) - ) - } - } - val myUserId by lazy { context.androidContext.getSharedPreferences("user_session_shared_pref", 0).getString("key_user_id", null) ?: useDatabase(DatabaseType.ARROYO)?.performOperation { @@ -178,7 +167,14 @@ class DatabaseAccess( } fun getFeedEntryByConversationId(conversationId: String): FriendFeedEntry? { - return useDatabase(DatabaseType.MAIN)?.performOperation { + return useDatabase(DatabaseType.ARROYO)?.performOperation { + readDatabaseObject( + FriendFeedEntry(), + "feed_entry", + "client_conversation_id = ?", + arrayOf(conversationId) + ) + } ?: useDatabase(DatabaseType.MAIN)?.performOperation { readDatabaseObject( FriendFeedEntry(), "FriendsFeedView", @@ -230,20 +226,34 @@ class DatabaseAccess( } fun getFeedEntries(limit: Int): List<FriendFeedEntry> { - return useDatabase(DatabaseType.MAIN)?.performOperation { + val entries = mutableListOf<FriendFeedEntry>() + return useDatabase(DatabaseType.ARROYO)?.performOperation { + safeRawQuery( + "SELECT * FROM feed_entry ORDER BY last_updated_timestamp DESC LIMIT ?", + arrayOf(limit.toString()) + )?.use { query -> + while (query.moveToNext()) { + val friendFeedEntry = FriendFeedEntry() + try { + friendFeedEntry.write(query) + } catch (_: Throwable) {} + entries.add(friendFeedEntry) + } + entries + } + }?.takeIf { it.isNotEmpty() } ?: useDatabase(DatabaseType.MAIN)?.performOperation { safeRawQuery( "SELECT * FROM FriendsFeedView ORDER BY _id LIMIT ?", arrayOf(limit.toString()) )?.use { query -> - val list = mutableListOf<FriendFeedEntry>() while (query.moveToNext()) { val friendFeedEntry = FriendFeedEntry() try { friendFeedEntry.write(query) } catch (_: Throwable) {} - list.add(friendFeedEntry) + entries.add(friendFeedEntry) } - list + entries } } ?: emptyList() } diff --git a/core/src/main/kotlin/me/rhunk/snapenhance/core/features/impl/spying/HalfSwipeNotifier.kt b/core/src/main/kotlin/me/rhunk/snapenhance/core/features/impl/spying/HalfSwipeNotifier.kt @@ -91,15 +91,15 @@ class HalfSwipeNotifier : Feature("Half Swipe Notifier") { if (minDuration > peekingDuration || maxDuration < peekingDuration) return - val groupName = context.database.getFeedEntryByConversationId(conversationId)?.feedDisplayName + val feedEntry = context.database.getFeedEntryByConversationId(conversationId) val friendInfo = context.database.getFriendInfo(userId) ?: return Notification.Builder(context.androidContext, channelId) - .setContentTitle(groupName ?: friendInfo.displayName ?: friendInfo.mutableUsername) - .setContentText(if (groupName != null) { + .setContentTitle(feedEntry?.feedDisplayName ?: friendInfo.displayName ?: friendInfo.mutableUsername) + .setContentText(if (feedEntry?.conversationType == 1) { translation.format("notification_content_group", "friend" to (friendInfo.displayName ?: friendInfo.mutableUsername).toString(), - "group" to groupName, + "group" to (feedEntry.feedDisplayName ?: "Group"), "duration" to peekingDuration.toString() ) } else {