commit 31570694a015c91a8fa67cdbfd2e1b58531033cf
parent cb301f8a423b83bf80ca130d7e396228732e122e
Author: rhunk <101876869+rhunk@users.noreply.github.com>
Date:   Sun, 20 Aug 2023 15:27:42 +0200

feat: scope content
- refactor image loader
- rules

Diffstat:
Mapp/src/main/kotlin/me/rhunk/snapenhance/RemoteSideContext.kt | 15+++++++++++++++
Mapp/src/main/kotlin/me/rhunk/snapenhance/bridge/BridgeService.kt | 4++--
Mapp/src/main/kotlin/me/rhunk/snapenhance/messaging/ModDatabase.kt | 32+++++++++++++++++++++++---------
Mapp/src/main/kotlin/me/rhunk/snapenhance/ui/manager/sections/downloads/DownloadsSection.kt | 51++++++++-------------------------------------------
Aapp/src/main/kotlin/me/rhunk/snapenhance/ui/manager/sections/social/ScopeContent.kt | 117+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dapp/src/main/kotlin/me/rhunk/snapenhance/ui/manager/sections/social/ScopeTab.kt | 73-------------------------------------------------------------------------
Mapp/src/main/kotlin/me/rhunk/snapenhance/ui/manager/sections/social/SocialSection.kt | 160++++++++++++++++++++++++++++++++++++++++++++++---------------------------------
Aapp/src/main/kotlin/me/rhunk/snapenhance/ui/util/ComposeImageHelper.kt | 54++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mcore/src/main/kotlin/me/rhunk/snapenhance/bridge/BridgeClient.kt | 4++--
Mcore/src/main/kotlin/me/rhunk/snapenhance/core/messaging/MessagingCoreObjects.kt | 26++++++++++++++------------
10 files changed, 328 insertions(+), 208 deletions(-)

diff --git a/app/src/main/kotlin/me/rhunk/snapenhance/RemoteSideContext.kt b/app/src/main/kotlin/me/rhunk/snapenhance/RemoteSideContext.kt @@ -5,6 +5,10 @@ import android.content.Context import android.content.Intent import android.net.Uri import androidx.documentfile.provider.DocumentFile +import coil.ImageLoader +import coil.decode.VideoFrameDecoder +import coil.memory.MemoryCache +import kotlinx.coroutines.Dispatchers import me.rhunk.snapenhance.bridge.BridgeService import me.rhunk.snapenhance.bridge.wrapper.LocaleWrapper import me.rhunk.snapenhance.bridge.wrapper.MappingsWrapper @@ -35,6 +39,17 @@ class RemoteSideContext( val downloadTaskManager = DownloadTaskManager() val modDatabase = ModDatabase(this) + //used to load bitmoji selfies and download previews + val imageLoader by lazy { + ImageLoader.Builder(androidContext) + .dispatcher(Dispatchers.IO) + .memoryCache { + MemoryCache.Builder(androidContext) + .maxSizePercent(0.25) + .build() + }.components { add(VideoFrameDecoder.Factory()) }.build() + } + init { runCatching { config.loadFromContext(androidContext) diff --git a/app/src/main/kotlin/me/rhunk/snapenhance/bridge/BridgeService.kt b/app/src/main/kotlin/me/rhunk/snapenhance/bridge/BridgeService.kt @@ -12,7 +12,7 @@ import me.rhunk.snapenhance.bridge.wrapper.LocaleWrapper import me.rhunk.snapenhance.bridge.wrapper.MessageLoggerWrapper import me.rhunk.snapenhance.core.messaging.MessagingFriendInfo import me.rhunk.snapenhance.core.messaging.MessagingGroupInfo -import me.rhunk.snapenhance.core.messaging.MessagingScope +import me.rhunk.snapenhance.core.messaging.SocialScope import me.rhunk.snapenhance.database.objects.FriendInfo import me.rhunk.snapenhance.download.DownloadProcessor import me.rhunk.snapenhance.util.SerializableDataObject @@ -112,7 +112,7 @@ class BridgeService : Service() { } override fun getRules(objectType: String, uuid: String): MutableList<String> { - remoteSideContext.modDatabase.getRulesFromId(MessagingScope.valueOf(objectType), uuid) + remoteSideContext.modDatabase.getRulesFromId(SocialScope.valueOf(objectType), uuid) .let { rules -> return rules.map { it.toJson() }.toMutableList() } diff --git a/app/src/main/kotlin/me/rhunk/snapenhance/messaging/ModDatabase.kt b/app/src/main/kotlin/me/rhunk/snapenhance/messaging/ModDatabase.kt @@ -7,8 +7,7 @@ import me.rhunk.snapenhance.core.messaging.FriendStreaks import me.rhunk.snapenhance.core.messaging.MessagingFriendInfo import me.rhunk.snapenhance.core.messaging.MessagingGroupInfo import me.rhunk.snapenhance.core.messaging.MessagingRule -import me.rhunk.snapenhance.core.messaging.Mode -import me.rhunk.snapenhance.core.messaging.MessagingScope +import me.rhunk.snapenhance.core.messaging.SocialScope import me.rhunk.snapenhance.database.objects.FriendInfo import me.rhunk.snapenhance.util.SQLiteDatabaseHelper import me.rhunk.snapenhance.util.ktx.getInteger @@ -50,8 +49,7 @@ class ModDatabase( "id INTEGER PRIMARY KEY AUTOINCREMENT", "scope VARCHAR", "targetUuid VARCHAR", - "enabled BOOLEAN", - "mode VARCHAR", + //"mode VARCHAR", "subject VARCHAR" ), "streaks" to listOf( @@ -153,16 +151,14 @@ class ModDatabase( } } - fun getRulesFromId(type: MessagingScope, targetUuid: String): List<MessagingRule> { - return database.rawQuery("SELECT * FROM rules WHERE objectType = ? AND targetUuid = ?", arrayOf(type.name, targetUuid)).use { cursor -> + fun getRulesFromId(type: SocialScope, targetUuid: String): List<MessagingRule> { + return database.rawQuery("SELECT * FROM rules WHERE scope = ? AND targetUuid = ?", arrayOf(type.name, targetUuid)).use { cursor -> val rules = mutableListOf<MessagingRule>() while (cursor.moveToNext()) { rules.add(MessagingRule( id = cursor.getInteger("id"), - messagingScope = MessagingScope.valueOf(cursor.getStringOrNull("scope")!!), + socialScope = SocialScope.valueOf(cursor.getStringOrNull("scope")!!), targetUuid = cursor.getStringOrNull("targetUuid")!!, - enabled = cursor.getInteger("enabled") == 1, - mode = Mode.valueOf(cursor.getStringOrNull("mode")!!), subject = cursor.getStringOrNull("subject")!! )) } @@ -170,6 +166,24 @@ class ModDatabase( } } + fun toggleRuleFor(type: SocialScope, targetUuid: String, subject: String, enabled: Boolean) { + executeAsync { + if (enabled) { + database.execSQL("INSERT OR REPLACE INTO rules (scope, targetUuid, subject) VALUES (?, ?, ?)", arrayOf( + type.name, + targetUuid, + subject + )) + } else { + database.execSQL("DELETE FROM rules WHERE scope = ? AND targetUuid = ? AND subject = ?", arrayOf( + type.name, + targetUuid, + subject + )) + } + } + } + fun getFriendInfo(userId: String): MessagingFriendInfo? { return database.rawQuery("SELECT * FROM friends WHERE userId = ?", arrayOf(userId)).use { cursor -> if (!cursor.moveToFirst()) return@use null diff --git a/app/src/main/kotlin/me/rhunk/snapenhance/ui/manager/sections/downloads/DownloadsSection.kt b/app/src/main/kotlin/me/rhunk/snapenhance/ui/manager/sections/downloads/DownloadsSection.kt @@ -15,7 +15,6 @@ import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.requiredWidthIn import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.material.icons.Icons @@ -49,34 +48,19 @@ import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import coil.ImageLoader import coil.compose.rememberAsyncImagePainter -import coil.decode.VideoFrameDecoder -import coil.memory.MemoryCache -import coil.request.ImageRequest -import coil.size.Precision -import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch -import me.rhunk.snapenhance.R import me.rhunk.snapenhance.data.FileType import me.rhunk.snapenhance.download.data.DownloadObject import me.rhunk.snapenhance.download.data.MediaFilter import me.rhunk.snapenhance.ui.manager.Section +import me.rhunk.snapenhance.ui.util.BitmojiImage +import me.rhunk.snapenhance.ui.util.ImageRequestHelper class DownloadsSection : Section() { private val loadedDownloads = mutableStateOf(mapOf<Int, DownloadObject>()) private var currentFilter = mutableStateOf(MediaFilter.NONE) - private val imageLoader by lazy { - ImageLoader.Builder(context.androidContext) - .dispatcher(Dispatchers.IO) - .memoryCache { - MemoryCache.Builder(context.androidContext) - .maxSizePercent(0.25) - .build() - }.components { add(VideoFrameDecoder.Factory()) }.build() - } - override fun onResumed() { super.onResumed() loadByFilter(currentFilter.value) @@ -156,12 +140,11 @@ class DownloadsSection : Section() { Box(modifier = Modifier.height(100.dp)) { Image( painter = rememberAsyncImagePainter( - model = ImageRequest.Builder(context.androidContext) - .data(download.outputFile) - .memoryCacheKey(download.outputFile) - .crossfade(true) - .build(), - imageLoader = imageLoader + model = ImageRequestHelper.newDownloadPreviewImageRequest( + context.androidContext, + download.outputFile + ), + imageLoader = context.imageLoader ), modifier = Modifier .matchParentSize() @@ -187,25 +170,7 @@ class DownloadsSection : Section() { .padding(15.dp), verticalAlignment = Alignment.CenterVertically ) { - Image( - painter = rememberAsyncImagePainter( - model = ImageRequest.Builder(context.androidContext) - .data(download.metadata.iconUrl) - .fallback(R.drawable.bitmoji_blank) - .precision(Precision.INEXACT) - .crossfade(true) - .memoryCacheKey(download.metadata.iconUrl) - .build(), - imageLoader = imageLoader - ), - contentDescription = null, - contentScale = ContentScale.Crop, - modifier = Modifier - .requiredWidthIn(min = 0.dp, max = 48.dp) - .height(48.dp) - .clip(MaterialTheme.shapes.medium) - ) - + BitmojiImage(context = context, url = download.metadata.iconUrl, size = 48) Column( modifier = Modifier .padding(start = 10.dp), diff --git a/app/src/main/kotlin/me/rhunk/snapenhance/ui/manager/sections/social/ScopeContent.kt b/app/src/main/kotlin/me/rhunk/snapenhance/ui/manager/sections/social/ScopeContent.kt @@ -0,0 +1,116 @@ +package me.rhunk.snapenhance.ui.manager.sections.social + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.height +import androidx.compose.material3.OutlinedButton +import androidx.compose.material3.Switch +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.runtime.setValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import androidx.navigation.NavController +import kotlinx.coroutines.launch +import me.rhunk.snapenhance.RemoteSideContext +import me.rhunk.snapenhance.core.messaging.MessagingRuleType +import me.rhunk.snapenhance.core.messaging.SocialScope + +class ScopeContent( + private val context: RemoteSideContext, + private val section: SocialSection, + private val navController: NavController, + private val scope: SocialScope, + private val id: String +) { + + @Composable + private fun DeleteScopeEntityButton() { + val coroutineScope = rememberCoroutineScope() + OutlinedButton(onClick = { + when (scope) { + SocialScope.FRIEND -> context.modDatabase.deleteFriend(id) + SocialScope.GROUP -> context.modDatabase.deleteGroup(id) + } + context.modDatabase.executeAsync { + coroutineScope.launch { + section.onResumed() + navController.popBackStack() + } + } + }) { + Text(text = "Delete ${scope.key}") + } + } + + @Composable + fun Content() { + Column { + when (scope) { + SocialScope.FRIEND -> Friend() + SocialScope.GROUP -> Group() + } + + Spacer(modifier = Modifier.height(16.dp)) + + val scopeRules = context.modDatabase.getRulesFromId(scope, id) + + Text(text = "Rules", maxLines = 1) + Spacer(modifier = Modifier.height(16.dp)) + + //manager anti features etc + MessagingRuleType.values().forEach { feature -> + var featureEnabled by remember { + mutableStateOf(scopeRules.any { it.subject == feature.key }) + } + val featureEnabledText = if (featureEnabled) "Enabled" else "Disabled" + Row { + Text(text = "${feature.key}: $featureEnabledText", maxLines = 1) + Switch(checked = featureEnabled, onCheckedChange = { + context.modDatabase.toggleRuleFor(scope, id, feature.key, it) + featureEnabled = it + }) + } + } + } + } + + @Composable + private fun Friend() { + //fetch the friend from the database + val friend = remember { context.modDatabase.getFriendInfo(id) } ?: run { + Text(text = "Friend not found") + return + } + Column { + Text(text = friend.displayName ?: "No display name", maxLines = 1) + Text(text = "bitmojiId: ${friend.bitmojiId ?: "No bitmojiId"}", maxLines = 1) + Text(text = "selfieId: ${friend.selfieId ?: "No selfieId"}", maxLines = 1) + + Spacer(modifier = Modifier.height(16.dp)) + DeleteScopeEntityButton() + } + + } + + @Composable + private fun Group() { + //fetch the group from the database + val group = remember { context.modDatabase.getGroupInfo(id) } ?: run { + Text(text = "Group not found") + return + } + + Column { + Text(text = group.name, maxLines = 1) + Text(text = "participantsCount: ${group.participantsCount}", maxLines = 1) + Spacer(modifier = Modifier.height(16.dp)) + DeleteScopeEntityButton() + } + } +}+ \ No newline at end of file diff --git a/app/src/main/kotlin/me/rhunk/snapenhance/ui/manager/sections/social/ScopeTab.kt b/app/src/main/kotlin/me/rhunk/snapenhance/ui/manager/sections/social/ScopeTab.kt @@ -1,72 +0,0 @@ -package me.rhunk.snapenhance.ui.manager.sections.social - -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.height -import androidx.compose.material3.OutlinedButton -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.runtime.remember -import androidx.compose.ui.Modifier -import androidx.compose.ui.unit.dp -import androidx.navigation.NavController -import me.rhunk.snapenhance.RemoteSideContext - -class ScopeTab( - private val context: RemoteSideContext, - private val section: SocialSection, - private val navController: NavController, - private val id: String -) { - @Composable - fun Friend() { - //fetch the friend from the database - val friend = remember { context.modDatabase.getFriendInfo(id) } ?: run { - Text(text = "Friend not found") - return - } - Column { - Text(text = friend.displayName ?: "No display name", maxLines = 1) - Text(text = "bitmojiId: ${friend.bitmojiId ?: "No bitmojiId"}", maxLines = 1) - Text(text = "selfieId: ${friend.selfieId ?: "No selfieId"}", maxLines = 1) - - Spacer(modifier = Modifier.height(16.dp)) - - OutlinedButton(onClick = { - context.modDatabase.deleteFriend(id) - section.onResumed() - navController.popBackStack() - }) { - Text(text = "Delete friend") - } - } - - } - - - @Composable - fun Group() { - //fetch the group from the database - val group = remember { context.modDatabase.getGroupInfo(id) } ?: run { - Text(text = "Group not found") - return - } - - Column { - Text(text = group.name, maxLines = 1) - Text(text = "participantsCount: ${group.participantsCount}", maxLines = 1) - - Spacer(modifier = Modifier.height(16.dp)) - - - OutlinedButton(onClick = { - context.modDatabase.deleteGroup(id) - section.onResumed() - navController.popBackStack() - }) { - Text(text = "Delete group") - } - } - - } -}- \ No newline at end of file diff --git a/app/src/main/kotlin/me/rhunk/snapenhance/ui/manager/sections/social/SocialSection.kt b/app/src/main/kotlin/me/rhunk/snapenhance/ui/manager/sections/social/SocialSection.kt @@ -2,9 +2,9 @@ package me.rhunk.snapenhance.ui.manager.sections.social import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.clickable -import androidx.compose.foundation.gestures.Orientation -import androidx.compose.foundation.gestures.scrollable import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height @@ -12,7 +12,6 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.pager.HorizontalPager import androidx.compose.foundation.pager.rememberPagerState -import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.icons.Icons import androidx.compose.material.icons.rounded.Add @@ -26,12 +25,13 @@ import androidx.compose.material3.TabRow import androidx.compose.material3.TabRowDefaults import androidx.compose.material3.Text import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp @@ -41,8 +41,11 @@ import androidx.navigation.navigation import kotlinx.coroutines.launch import me.rhunk.snapenhance.core.messaging.MessagingFriendInfo import me.rhunk.snapenhance.core.messaging.MessagingGroupInfo +import me.rhunk.snapenhance.core.messaging.SocialScope import me.rhunk.snapenhance.ui.manager.Section +import me.rhunk.snapenhance.ui.util.BitmojiImage import me.rhunk.snapenhance.ui.util.pagerTabIndicatorOffset +import me.rhunk.snapenhance.util.snap.BitmojiSelfie class SocialSection : Section() { private lateinit var friendList: List<MessagingFriendInfo> @@ -54,7 +57,7 @@ class SocialSection : Section() { const val GROUP_INFO_ROUTE = "group_info/{id}" } - private var currentScopeTab: ScopeTab? = null + private var currentScopeContent: ScopeContent? = null private val addFriendDialog by lazy { AddFriendDialog(context, this) @@ -69,23 +72,96 @@ class SocialSection : Section() { override fun canGoBack() = navController.currentBackStackEntry?.destination?.route != MAIN_ROUTE override fun build(navGraphBuilder: NavGraphBuilder) { - fun switchTab(id: String) = ScopeTab(context, this, navController, id).also { tab -> - currentScopeTab = tab - } - navGraphBuilder.navigation(route = enumSection.route, startDestination = MAIN_ROUTE) { composable(MAIN_ROUTE) { Content() } - composable(FRIEND_INFO_ROUTE) { - val id = it.arguments?.getString("id") ?: return@composable - remember { switchTab(id) }.Friend() + SocialScope.values().forEach { scope -> + composable(scope.tabRoute) { + val id = it.arguments?.getString("id") ?: return@composable + remember { + ScopeContent(context, this@SocialSection, navController, scope, id).also { tab -> + currentScopeContent = tab + } + }.Content() + } } + } + } - composable(GROUP_INFO_ROUTE) { - val id = it.arguments?.getString("id") ?: return@composable - remember { switchTab(id) }.Group() + + @Composable + private fun ScopeList(scope: SocialScope) { + LazyColumn( + modifier = Modifier + .padding(2.dp) + .fillMaxWidth() + .fillMaxHeight() + ) { + //check if scope list is empty + val listSize = when (scope) { + SocialScope.GROUP -> groupList.size + SocialScope.FRIEND -> friendList.size + } + + if (listSize == 0) { + item { + //TODO: i18n + Text(text = "No ${scope.key.lowercase()}s found") + } + } + + items(listSize) { index -> + val id = when (scope) { + SocialScope.GROUP -> groupList[index].conversationId + SocialScope.FRIEND -> friendList[index].userId + } + + Card( + modifier = Modifier + .padding(10.dp) + .fillMaxWidth() + .height(80.dp) + .clickable { + navController.navigate( + scope.tabRoute.replace("{id}", id) + ) + }, + ) { + when (scope) { + SocialScope.GROUP -> { + val group = groupList[index] + Column { + Text(text = group.name, maxLines = 1) + Text(text = "participantsCount: ${group.participantsCount}", maxLines = 1) + } + } + SocialScope.FRIEND -> { + val friend = friendList[index] + Row( + modifier = Modifier + .padding(10.dp) + .fillMaxSize(), + verticalAlignment = Alignment.CenterVertically + ) { + val bitmojiUrl = (friend.selfieId to friend.bitmojiId).let { (selfieId, bitmojiId) -> + if (selfieId == null || bitmojiId == null) return@let null + BitmojiSelfie.getBitmojiSelfie(selfieId, bitmojiId, BitmojiSelfie.BitmojiSelfieType.STANDARD) + } + BitmojiImage(context = context, url = bitmojiUrl) + Column( + modifier = Modifier + .padding(10.dp) + .fillMaxWidth() + ) { + Text(text = friend.displayName ?: friend.mutableUsername, maxLines = 1) + Text(text = friend.userId, maxLines = 1) + } + } + } + } + } } } } @@ -145,60 +221,10 @@ class SocialSection : Section() { } } - HorizontalPager(modifier = Modifier.padding(paddingValues), state = pagerState) { page -> when (page) { - 0 -> { - LazyColumn( - modifier = Modifier - .padding(10.dp) - .fillMaxWidth() - ) { - if (friendList.isEmpty()) { - item { - Text(text = "No friends found") - } - } - items(friendList.size) { index -> - val friend = friendList[index] - Card( - modifier = Modifier - .padding(10.dp) - .fillMaxWidth() - .height(100.dp) - .clickable { - navController.navigate( - FRIEND_INFO_ROUTE.replace( - "{id}", - friend.userId - ) - ) - }, - ) { - Text(text = friend.displayName ?: friend.mutableUsername) - } - } - } - } - 1 -> { - Column( - modifier = Modifier - .padding(10.dp) - .fillMaxSize() - .scrollable(rememberScrollState(), Orientation.Vertical) - ) { - groupList.forEach { - Card( - modifier = Modifier - .padding(10.dp) - .fillMaxWidth() - .height(100.dp), - ) { - Text(text = it.name) - } - } - } - } + 0 -> ScopeList(SocialScope.FRIEND) + 1 -> ScopeList(SocialScope.GROUP) } } } diff --git a/app/src/main/kotlin/me/rhunk/snapenhance/ui/util/ComposeImageHelper.kt b/app/src/main/kotlin/me/rhunk/snapenhance/ui/util/ComposeImageHelper.kt @@ -0,0 +1,53 @@ +package me.rhunk.snapenhance.ui.util + +import android.content.Context +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.requiredWidthIn +import androidx.compose.material3.MaterialTheme +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.unit.dp +import coil.compose.rememberAsyncImagePainter +import coil.request.ImageRequest +import coil.size.Precision +import me.rhunk.snapenhance.R +import me.rhunk.snapenhance.RemoteSideContext + +@Composable +fun BitmojiImage(context: RemoteSideContext, modifier: Modifier = Modifier, size: Int = 48, url: String?) { + Image( + painter = rememberAsyncImagePainter( + model = ImageRequestHelper.newBitmojiImageRequest( + context.androidContext, + url + ), + imageLoader = context.imageLoader + ), + contentDescription = null, + contentScale = ContentScale.Crop, + modifier = Modifier + .requiredWidthIn(min = 0.dp, max = size.dp) + .height(size.dp) + .clip(MaterialTheme.shapes.medium) + .then(modifier) + ) +} + +object ImageRequestHelper { + fun newBitmojiImageRequest(context: Context, url: String?) = ImageRequest.Builder(context) + .data(url) + .fallback(R.drawable.bitmoji_blank) + .precision(Precision.INEXACT) + .crossfade(true) + .memoryCacheKey(url) + .build() + + fun newDownloadPreviewImageRequest(context: Context, filePath: String?) = ImageRequest.Builder(context) + .data(filePath) + .memoryCacheKey(filePath) + .crossfade(true) + .build() +}+ \ No newline at end of file diff --git a/core/src/main/kotlin/me/rhunk/snapenhance/bridge/BridgeClient.kt b/core/src/main/kotlin/me/rhunk/snapenhance/bridge/BridgeClient.kt @@ -16,7 +16,7 @@ import me.rhunk.snapenhance.bridge.types.BridgeFileType import me.rhunk.snapenhance.bridge.types.FileActionType import me.rhunk.snapenhance.core.BuildConfig import me.rhunk.snapenhance.core.messaging.MessagingRule -import me.rhunk.snapenhance.core.messaging.MessagingScope +import me.rhunk.snapenhance.core.messaging.SocialScope import me.rhunk.snapenhance.data.LocalePair import me.rhunk.snapenhance.util.SerializableDataObject import java.util.concurrent.CompletableFuture @@ -136,7 +136,7 @@ class BridgeClient( fun passGroupsAndFriends(groups: List<String>, friends: List<String>) = service.passGroupsAndFriends(groups, friends) - fun getRulesFromId(type: MessagingScope, targetUuid: String): List<MessagingRule> { + fun getRulesFromId(type: SocialScope, targetUuid: String): List<MessagingRule> { return service.getRules(type.name, targetUuid).map { SerializableDataObject.fromJson(it, MessagingRule::class.java) }.toList() diff --git a/core/src/main/kotlin/me/rhunk/snapenhance/core/messaging/MessagingCoreObjects.kt b/core/src/main/kotlin/me/rhunk/snapenhance/core/messaging/MessagingCoreObjects.kt @@ -8,18 +8,21 @@ enum class Mode { WHITELIST } -enum class MessagingScope { - FRIEND, - GROUP +enum class SocialScope( + val key: String, + val tabRoute: String, +) { + FRIEND("friend", "friend_info/{id}"), + GROUP("group", "group_info/{id}"), } -enum class ConversationFeature( - val value: String, - val messagingScope: MessagingScope, +enum class MessagingRuleType( + val key: String, + val socialScope: SocialScope, ) { - DOWNLOAD("download", MessagingScope.FRIEND), - STEALTH("stealth", MessagingScope.GROUP), - AUTO_SAVE("auto_save", MessagingScope.GROUP); + DOWNLOAD("download", SocialScope.FRIEND), + STEALTH("stealth", SocialScope.GROUP), + AUTO_SAVE("auto_save", SocialScope.GROUP); } data class FriendStreaks( @@ -47,9 +50,8 @@ data class MessagingFriendInfo( data class MessagingRule( val id: Int, - val messagingScope: MessagingScope, + val socialScope: SocialScope, val targetUuid: String, - val enabled: Boolean, - val mode: Mode?, + //val mode: Mode?, val subject: String ) : SerializableDataObject() \ No newline at end of file