mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-03-03 07:48:36 +00:00
Add context menus to chat folders.
This commit is contained in:
committed by
Greyson Parrelli
parent
6b66e4666b
commit
bfa5703aaa
@@ -11,6 +11,7 @@ import org.signal.donations.InAppPaymentType
|
||||
import org.thoughtcrime.securesms.MainActivity
|
||||
import org.thoughtcrime.securesms.R
|
||||
import org.thoughtcrime.securesms.components.settings.DSLSettingsActivity
|
||||
import org.thoughtcrime.securesms.components.settings.app.chats.folders.CreateFoldersFragmentArgs
|
||||
import org.thoughtcrime.securesms.components.settings.app.notifications.profiles.EditNotificationProfileScheduleFragmentArgs
|
||||
import org.thoughtcrime.securesms.components.settings.app.subscription.InAppPaymentComponent
|
||||
import org.thoughtcrime.securesms.components.settings.app.subscription.StripeRepository
|
||||
@@ -68,6 +69,10 @@ class AppSettingsActivity : DSLSettingsActivity(), InAppPaymentComponent {
|
||||
StartLocation.USERNAME_LINK -> AppSettingsFragmentDirections.actionDirectToUsernameLinkSettings()
|
||||
StartLocation.RECOVER_USERNAME -> AppSettingsFragmentDirections.actionDirectToUsernameRecovery()
|
||||
StartLocation.REMOTE_BACKUPS -> AppSettingsFragmentDirections.actionDirectToRemoteBackupsSettingsFragment()
|
||||
StartLocation.CHAT_FOLDERS -> AppSettingsFragmentDirections.actionDirectToChatFoldersFragment()
|
||||
StartLocation.CREATE_CHAT_FOLDER -> AppSettingsFragmentDirections.actionDirectToCreateFoldersFragment(
|
||||
CreateFoldersFragmentArgs.fromBundle(intent.getBundleExtra(START_ARGUMENTS)!!).folderId
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -198,6 +203,18 @@ class AppSettingsActivity : DSLSettingsActivity(), InAppPaymentComponent {
|
||||
@JvmStatic
|
||||
fun remoteBackups(context: Context): Intent = getIntentForStartLocation(context, StartLocation.REMOTE_BACKUPS)
|
||||
|
||||
@JvmStatic
|
||||
fun chatFolders(context: Context): Intent = getIntentForStartLocation(context, StartLocation.CHAT_FOLDERS)
|
||||
|
||||
@JvmStatic
|
||||
fun createChatFolder(context: Context, id: Long = -1): Intent {
|
||||
val arguments = CreateFoldersFragmentArgs.Builder(id)
|
||||
.build()
|
||||
.toBundle()
|
||||
|
||||
return getIntentForStartLocation(context, StartLocation.CREATE_CHAT_FOLDER).putExtra(START_ARGUMENTS, arguments)
|
||||
}
|
||||
|
||||
private fun getIntentForStartLocation(context: Context, startLocation: StartLocation): Intent {
|
||||
return Intent(context, AppSettingsActivity::class.java)
|
||||
.putExtra(ARG_NAV_GRAPH, R.navigation.app_settings_with_change_number)
|
||||
@@ -222,7 +239,9 @@ class AppSettingsActivity : DSLSettingsActivity(), InAppPaymentComponent {
|
||||
LINKED_DEVICES(13),
|
||||
USERNAME_LINK(14),
|
||||
RECOVER_USERNAME(15),
|
||||
REMOTE_BACKUPS(16);
|
||||
REMOTE_BACKUPS(16),
|
||||
CHAT_FOLDERS(17),
|
||||
CREATE_CHAT_FOLDER(18);
|
||||
|
||||
companion object {
|
||||
fun fromCode(code: Int?): StartLocation {
|
||||
|
||||
@@ -0,0 +1,122 @@
|
||||
package org.thoughtcrime.securesms.components.settings.app.chats.folders
|
||||
|
||||
import android.content.Context
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import org.signal.core.util.DimensionUnit
|
||||
import org.thoughtcrime.securesms.R
|
||||
import org.thoughtcrime.securesms.components.menu.ActionItem
|
||||
import org.thoughtcrime.securesms.components.menu.SignalContextMenu
|
||||
|
||||
/**
|
||||
* A context menu shown when long pressing on a chat folder.
|
||||
*/
|
||||
object ChatFolderContextMenu {
|
||||
|
||||
fun show(
|
||||
context: Context,
|
||||
anchorView: View,
|
||||
rootView: ViewGroup = anchorView.rootView as ViewGroup,
|
||||
folderType: ChatFolderRecord.FolderType,
|
||||
onEdit: () -> Unit = {},
|
||||
onAdd: () -> Unit = {},
|
||||
onMuteAll: () -> Unit = {},
|
||||
onReadAll: () -> Unit = {},
|
||||
onDelete: () -> Unit = {},
|
||||
onReorder: () -> Unit = {}
|
||||
) {
|
||||
show(
|
||||
context = context,
|
||||
anchorView = anchorView,
|
||||
rootView = rootView,
|
||||
folderType = folderType,
|
||||
callbacks = object : Callbacks {
|
||||
override fun onEdit() = onEdit()
|
||||
override fun onAdd() = onAdd()
|
||||
override fun onMuteAll() = onMuteAll()
|
||||
override fun onReadAll() = onReadAll()
|
||||
override fun onDelete() = onDelete()
|
||||
override fun onReorder() = onReorder()
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
private fun show(
|
||||
context: Context,
|
||||
anchorView: View,
|
||||
rootView: ViewGroup,
|
||||
folderType: ChatFolderRecord.FolderType,
|
||||
callbacks: Callbacks
|
||||
) {
|
||||
val actions = mutableListOf<ActionItem>().apply {
|
||||
if (folderType == ChatFolderRecord.FolderType.ALL) {
|
||||
add(
|
||||
ActionItem(R.drawable.symbol_plus_24, context.getString(R.string.ChatFoldersFragment__add_new_folder)) {
|
||||
callbacks.onAdd()
|
||||
}
|
||||
)
|
||||
add(
|
||||
ActionItem(R.drawable.symbol_bell_slash_24, context.getString(R.string.ChatFoldersFragment__mute_all)) {
|
||||
callbacks.onMuteAll()
|
||||
}
|
||||
)
|
||||
add(
|
||||
ActionItem(R.drawable.symbol_chat_check, context.getString(R.string.ChatFoldersFragment__mark_all_read)) {
|
||||
callbacks.onReadAll()
|
||||
}
|
||||
)
|
||||
add(
|
||||
ActionItem(R.drawable.symbol_exchange_24, context.getString(R.string.ChatFoldersFragment__reorder_folder)) {
|
||||
callbacks.onReorder()
|
||||
}
|
||||
)
|
||||
} else {
|
||||
add(
|
||||
ActionItem(R.drawable.symbol_edit_24, context.getString(R.string.ChatFoldersFragment__edit_folder)) {
|
||||
callbacks.onEdit()
|
||||
}
|
||||
)
|
||||
add(
|
||||
ActionItem(R.drawable.symbol_plus_24, context.getString(R.string.ChatFoldersFragment__add_new_folder)) {
|
||||
callbacks.onAdd()
|
||||
}
|
||||
)
|
||||
add(
|
||||
ActionItem(R.drawable.symbol_bell_slash_24, context.getString(R.string.ChatFoldersFragment__mute_all)) {
|
||||
callbacks.onMuteAll()
|
||||
}
|
||||
)
|
||||
add(
|
||||
ActionItem(R.drawable.symbol_chat_check, context.getString(R.string.ChatFoldersFragment__mark_all_read)) {
|
||||
callbacks.onReadAll()
|
||||
}
|
||||
)
|
||||
add(
|
||||
ActionItem(R.drawable.symbol_trash_24, context.getString(R.string.ChatFoldersFragment__delete_folder)) {
|
||||
callbacks.onDelete()
|
||||
}
|
||||
)
|
||||
add(
|
||||
ActionItem(R.drawable.symbol_exchange_24, context.getString(R.string.ChatFoldersFragment__reorder_folder)) {
|
||||
callbacks.onReorder()
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
SignalContextMenu.Builder(anchorView, rootView)
|
||||
.preferredHorizontalPosition(SignalContextMenu.HorizontalPosition.START)
|
||||
.preferredVerticalPosition(SignalContextMenu.VerticalPosition.BELOW)
|
||||
.offsetY(DimensionUnit.DP.toPixels(8f).toInt())
|
||||
.show(actions)
|
||||
}
|
||||
|
||||
private interface Callbacks {
|
||||
fun onEdit()
|
||||
fun onAdd()
|
||||
fun onMuteAll()
|
||||
fun onReadAll()
|
||||
fun onDelete()
|
||||
fun onReorder()
|
||||
}
|
||||
}
|
||||
@@ -77,8 +77,7 @@ class ChatFoldersFragment : ComposeFragment() {
|
||||
state = state,
|
||||
modifier = Modifier.padding(contentPadding),
|
||||
onFolderClicked = {
|
||||
viewModel.setCurrentFolder(it)
|
||||
navController.safeNavigate(R.id.action_chatFoldersFragment_to_createFoldersFragment)
|
||||
navController.safeNavigate(ChatFoldersFragmentDirections.actionChatFoldersFragmentToCreateFoldersFragment(it.id))
|
||||
},
|
||||
onAdd = { folder ->
|
||||
Toast.makeText(requireContext(), getString(R.string.ChatFoldersFragment__folder_added, folder.name), Toast.LENGTH_SHORT).show()
|
||||
|
||||
@@ -40,4 +40,8 @@ object ChatFoldersRepository {
|
||||
fun updatePositions(folders: List<ChatFolderRecord>) {
|
||||
SignalDatabase.chatFolders.updatePositions(folders)
|
||||
}
|
||||
|
||||
fun getFolder(id: Long): ChatFolderRecord {
|
||||
return SignalDatabase.chatFolders.getChatFolder(id)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,7 +28,12 @@ class ChatFoldersViewModel : ViewModel() {
|
||||
val suggestedFolders = getSuggestedFolders(context, folders)
|
||||
|
||||
internalState.update {
|
||||
it.copy(folders = folders, suggestedFolders = suggestedFolders)
|
||||
it.copy(
|
||||
folders = folders,
|
||||
suggestedFolders = suggestedFolders,
|
||||
currentFolder = ChatFolderRecord(),
|
||||
originalFolder = ChatFolderRecord()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -310,4 +315,13 @@ class ChatFoldersViewModel : ViewModel() {
|
||||
originalFolder.excludedRecipients != currentFolder.excludedRecipients
|
||||
}
|
||||
}
|
||||
|
||||
fun setCurrentFolderId(folderId: Long) {
|
||||
if (folderId != -1L) {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
val folder = ChatFoldersRepository.getFolder(folderId)
|
||||
setCurrentFolder(folder)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ import androidx.compose.material3.Switch
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextField
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
@@ -87,6 +88,12 @@ class CreateFoldersFragment : ComposeFragment() {
|
||||
val focusRequester = remember { FocusRequester() }
|
||||
val isNewFolder = state.originalFolder.id == -1L
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
if (state.originalFolder == state.currentFolder) {
|
||||
viewModel.setCurrentFolderId(arguments?.getLong(KEY_FOLDER_ID) ?: -1)
|
||||
}
|
||||
}
|
||||
|
||||
Scaffolds.Settings(
|
||||
title = if (isNewFolder) stringResource(id = R.string.CreateFoldersFragment__create_a_folder) else stringResource(id = R.string.CreateFoldersFragment__edit_folder),
|
||||
onNavigationClick = {
|
||||
@@ -143,6 +150,10 @@ class CreateFoldersFragment : ComposeFragment() {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val KEY_FOLDER_ID = "folder_id"
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
|
||||
@@ -6,6 +6,7 @@ import android.view.View
|
||||
import android.widget.TextView
|
||||
import androidx.core.content.ContextCompat
|
||||
import org.thoughtcrime.securesms.R
|
||||
import org.thoughtcrime.securesms.components.settings.app.chats.folders.ChatFolderContextMenu
|
||||
import org.thoughtcrime.securesms.components.settings.app.chats.folders.ChatFolderRecord
|
||||
import org.thoughtcrime.securesms.util.adapter.mapping.LayoutFactory
|
||||
import org.thoughtcrime.securesms.util.adapter.mapping.MappingAdapter
|
||||
@@ -36,6 +37,20 @@ class ChatFolderAdapter(val callbacks: Callbacks) : MappingAdapter() {
|
||||
itemView.setOnClickListener {
|
||||
callbacks.onChatFolderClicked(model.chatFolder)
|
||||
}
|
||||
itemView.setOnLongClickListener { view ->
|
||||
ChatFolderContextMenu.show(
|
||||
context = itemView.context,
|
||||
anchorView = view,
|
||||
folderType = model.chatFolder.folderType,
|
||||
onEdit = { callbacks.onEdit(model.chatFolder) },
|
||||
onAdd = { callbacks.onAdd() },
|
||||
onMuteAll = { callbacks.onMuteAll(model.chatFolder) },
|
||||
onReadAll = { callbacks.onReadAll(model.chatFolder) },
|
||||
onDelete = { callbacks.onDelete(model.chatFolder) },
|
||||
onReorder = { callbacks.onReorder() }
|
||||
)
|
||||
true
|
||||
}
|
||||
if (model.isSelected) {
|
||||
itemView.backgroundTintList = ColorStateList.valueOf(ContextCompat.getColor(itemView.context, R.color.signal_colorSurfaceVariant))
|
||||
} else {
|
||||
@@ -54,5 +69,11 @@ class ChatFolderAdapter(val callbacks: Callbacks) : MappingAdapter() {
|
||||
|
||||
interface Callbacks {
|
||||
fun onChatFolderClicked(chatFolder: ChatFolderRecord)
|
||||
fun onEdit(chatFolder: ChatFolderRecord)
|
||||
fun onAdd()
|
||||
fun onMuteAll(chatFolder: ChatFolderRecord)
|
||||
fun onReadAll(chatFolder: ChatFolderRecord)
|
||||
fun onDelete(chatFolder: ChatFolderRecord)
|
||||
fun onReorder()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1666,6 +1666,44 @@ public class ConversationListFragment extends MainFragment implements ActionMode
|
||||
viewModel.select(chatFolder);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEdit(@NonNull ChatFolderRecord chatFolder) {
|
||||
startActivity(AppSettingsActivity.createChatFolder(requireContext(), chatFolder.getId()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAdd() {
|
||||
startActivity(AppSettingsActivity.createChatFolder(requireContext(), -1));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMuteAll(@NonNull ChatFolderRecord chatFolder) {
|
||||
MuteDialog.show(requireContext(), until -> viewModel.onMuteChatFolder(chatFolder, until));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReadAll(@NonNull ChatFolderRecord chatFolder) {
|
||||
if (chatFolder.getFolderType() == ChatFolderRecord.FolderType.ALL) {
|
||||
handleMarkAllRead();
|
||||
} else {
|
||||
viewModel.markChatFolderRead(chatFolder);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDelete(@NonNull ChatFolderRecord chatFolder) {
|
||||
new MaterialAlertDialogBuilder(requireActivity())
|
||||
.setMessage(getString(R.string.CreateFoldersFragment__delete_this_chat_folder))
|
||||
.setPositiveButton(R.string.delete, (dialog, which) -> viewModel.deleteChatFolder(chatFolder))
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReorder() {
|
||||
startActivity(AppSettingsActivity.chatFolders(requireContext()));
|
||||
}
|
||||
|
||||
private class ArchiveListenerCallback extends ItemTouchHelper.SimpleCallback {
|
||||
|
||||
private static final long SWIPE_ANIMATION_DURATION = 175;
|
||||
|
||||
@@ -31,7 +31,10 @@ import org.thoughtcrime.securesms.keyvalue.SignalStore
|
||||
import org.thoughtcrime.securesms.megaphone.Megaphone
|
||||
import org.thoughtcrime.securesms.megaphone.MegaphoneRepository
|
||||
import org.thoughtcrime.securesms.megaphone.Megaphones
|
||||
import org.thoughtcrime.securesms.notifications.MarkReadReceiver
|
||||
import org.thoughtcrime.securesms.notifications.profiles.NotificationProfile
|
||||
import org.thoughtcrime.securesms.recipients.Recipient
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId
|
||||
import org.thoughtcrime.securesms.util.rx.RxStore
|
||||
import org.whispersystems.signalservice.api.websocket.WebSocketConnectionState
|
||||
import java.util.concurrent.TimeUnit
|
||||
@@ -259,6 +262,41 @@ class ConversationListViewModel(
|
||||
}
|
||||
}
|
||||
|
||||
fun onMuteChatFolder(chatFolder: ChatFolderRecord, until: Long) {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
val ids = SignalDatabase.threads.getRecipientIdsByChatFolder(chatFolder)
|
||||
val recipientIds: List<RecipientId> = ids.filter { id ->
|
||||
Recipient.resolved(id).muteUntil != until
|
||||
}
|
||||
if (recipientIds.isNotEmpty()) {
|
||||
SignalDatabase.recipients.setMuted(recipientIds, until)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun deleteChatFolder(chatFolder: ChatFolderRecord) {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
SignalDatabase.chatFolders.deleteChatFolder(chatFolder)
|
||||
val updatedFolders = folders.filter { folder -> folder.chatFolder.id != chatFolder.id }
|
||||
|
||||
store.update {
|
||||
it.copy(
|
||||
currentFolder = updatedFolders.first().chatFolder,
|
||||
chatFolders = updatedFolders
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun markChatFolderRead(chatFolder: ChatFolderRecord) {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
val ids = SignalDatabase.threads.getThreadIdsByChatFolder(chatFolder)
|
||||
val messageIds = SignalDatabase.threads.setRead(ids, false)
|
||||
AppDependencies.messageNotifier.updateNotification(AppDependencies.application)
|
||||
MarkReadReceiver.process(messageIds)
|
||||
}
|
||||
}
|
||||
|
||||
private data class ConversationListState(
|
||||
val chatFolders: List<ChatFolderMappingModel> = emptyList(),
|
||||
val currentFolder: ChatFolderRecord = ChatFolderRecord(),
|
||||
|
||||
@@ -9,6 +9,7 @@ import org.signal.core.util.groupBy
|
||||
import org.signal.core.util.insertInto
|
||||
import org.signal.core.util.readToList
|
||||
import org.signal.core.util.readToSingleInt
|
||||
import org.signal.core.util.readToSingleObject
|
||||
import org.signal.core.util.requireBoolean
|
||||
import org.signal.core.util.requireInt
|
||||
import org.signal.core.util.requireLong
|
||||
@@ -117,6 +118,37 @@ class ChatFolderTables(context: Context?, databaseHelper: SignalDatabase?) : Dat
|
||||
.run()
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a single chat folder that corresponds to that id
|
||||
*/
|
||||
fun getChatFolder(id: Long): ChatFolderRecord {
|
||||
val includedChats: Map<Long, List<Long>> = getIncludedChats(id)
|
||||
val excludedChats: Map<Long, List<Long>> = getExcludedChats(id)
|
||||
|
||||
val folder = readableDatabase
|
||||
.select()
|
||||
.from(ChatFolderTable.TABLE_NAME)
|
||||
.where("${ChatFolderTable.ID} = ?", id)
|
||||
.run()
|
||||
.readToSingleObject { cursor ->
|
||||
ChatFolderRecord(
|
||||
id = id,
|
||||
name = cursor.requireString(ChatFolderTable.NAME) ?: "",
|
||||
position = cursor.requireInt(ChatFolderTable.POSITION),
|
||||
showUnread = cursor.requireBoolean(ChatFolderTable.SHOW_UNREAD),
|
||||
showMutedChats = cursor.requireBoolean(ChatFolderTable.SHOW_MUTED),
|
||||
showIndividualChats = cursor.requireBoolean(ChatFolderTable.SHOW_INDIVIDUAL),
|
||||
showGroupChats = cursor.requireBoolean(ChatFolderTable.SHOW_GROUPS),
|
||||
isMuted = cursor.requireBoolean(ChatFolderTable.IS_MUTED),
|
||||
folderType = ChatFolderRecord.FolderType.deserialize(cursor.requireInt(ChatFolderTable.FOLDER_TYPE)),
|
||||
includedChats = includedChats[id] ?: emptyList(),
|
||||
excludedChats = excludedChats[id] ?: emptyList()
|
||||
)
|
||||
}
|
||||
|
||||
return folder ?: ChatFolderRecord()
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps the chat folder ids to its corresponding chat folder
|
||||
*/
|
||||
@@ -158,13 +190,20 @@ class ChatFolderTables(context: Context?, databaseHelper: SignalDatabase?) : Dat
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps chat folder ids to all of its corresponding included chats
|
||||
* Maps a chat folder id to all of its corresponding included chats.
|
||||
* If an id is not specified, all chat folder ids will be mapped.
|
||||
*/
|
||||
private fun getIncludedChats(): Map<Long, List<Long>> {
|
||||
private fun getIncludedChats(id: Long? = null): Map<Long, List<Long>> {
|
||||
val whereQuery = if (id != null) {
|
||||
"${ChatFolderMembershipTable.MEMBERSHIP_TYPE} = ${MembershipType.INCLUDED.value} AND ${ChatFolderMembershipTable.CHAT_FOLDER_ID} = $id"
|
||||
} else {
|
||||
"${ChatFolderMembershipTable.MEMBERSHIP_TYPE} = ${MembershipType.INCLUDED.value}"
|
||||
}
|
||||
|
||||
return readableDatabase
|
||||
.select()
|
||||
.from(ChatFolderMembershipTable.TABLE_NAME)
|
||||
.where("${ChatFolderMembershipTable.MEMBERSHIP_TYPE} = ${MembershipType.INCLUDED.value}")
|
||||
.where(whereQuery)
|
||||
.run()
|
||||
.groupBy { cursor ->
|
||||
cursor.requireLong(ChatFolderMembershipTable.CHAT_FOLDER_ID) to cursor.requireLong(ChatFolderMembershipTable.THREAD_ID)
|
||||
@@ -172,13 +211,20 @@ class ChatFolderTables(context: Context?, databaseHelper: SignalDatabase?) : Dat
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps the chat folder ids to all of its corresponding excluded chats
|
||||
* Maps a chat folder id to all of its corresponding excluded chats.
|
||||
* If an id is not specified, all chat folder ids will be mapped.
|
||||
*/
|
||||
private fun getExcludedChats(): Map<Long, List<Long>> {
|
||||
private fun getExcludedChats(id: Long? = null): Map<Long, List<Long>> {
|
||||
val whereQuery = if (id != null) {
|
||||
"${ChatFolderMembershipTable.MEMBERSHIP_TYPE} = ${MembershipType.EXCLUDED.value} AND ${ChatFolderMembershipTable.CHAT_FOLDER_ID} = $id"
|
||||
} else {
|
||||
"${ChatFolderMembershipTable.MEMBERSHIP_TYPE} = ${MembershipType.EXCLUDED.value}"
|
||||
}
|
||||
|
||||
return readableDatabase
|
||||
.select()
|
||||
.from(ChatFolderMembershipTable.TABLE_NAME)
|
||||
.where("${ChatFolderMembershipTable.MEMBERSHIP_TYPE} = ${MembershipType.EXCLUDED.value}")
|
||||
.where(whereQuery)
|
||||
.run()
|
||||
.groupBy { cursor ->
|
||||
cursor.requireLong(ChatFolderMembershipTable.CHAT_FOLDER_ID) to cursor.requireLong(ChatFolderMembershipTable.THREAD_ID)
|
||||
|
||||
@@ -1041,6 +1041,47 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa
|
||||
}
|
||||
}
|
||||
|
||||
fun getThreadIdsByChatFolder(chatFolder: ChatFolderRecord): List<Long> {
|
||||
val folderQuery = chatFolder.toQuery()
|
||||
val query =
|
||||
"""
|
||||
SELECT ${TABLE_NAME}.$ID
|
||||
FROM $TABLE_NAME
|
||||
LEFT OUTER JOIN ${RecipientTable.TABLE_NAME} ON $TABLE_NAME.$RECIPIENT_ID = ${RecipientTable.TABLE_NAME}.${RecipientTable.ID}
|
||||
WHERE
|
||||
$ACTIVE = 1
|
||||
$folderQuery
|
||||
"""
|
||||
return readableDatabase.rawQuery(query, null).readToList { cursor -> cursor.requireLong(ID) }
|
||||
}
|
||||
|
||||
fun getRecipientIdsByChatFolder(chatFolder: ChatFolderRecord): List<RecipientId> {
|
||||
return if (chatFolder.folderType == ChatFolderRecord.FolderType.ALL) {
|
||||
readableDatabase
|
||||
.select(RECIPIENT_ID)
|
||||
.from(TABLE_NAME)
|
||||
.where("$ACTIVE = 1")
|
||||
.run()
|
||||
.readToList { cursor ->
|
||||
RecipientId.from(cursor.requireLong(RECIPIENT_ID))
|
||||
}
|
||||
} else {
|
||||
val folderQuery = chatFolder.toQuery()
|
||||
val query =
|
||||
"""
|
||||
SELECT $RECIPIENT_ID
|
||||
FROM $TABLE_NAME
|
||||
LEFT OUTER JOIN ${RecipientTable.TABLE_NAME} ON $TABLE_NAME.$RECIPIENT_ID = ${RecipientTable.TABLE_NAME}.${RecipientTable.ID}
|
||||
WHERE
|
||||
$ACTIVE = 1
|
||||
$folderQuery
|
||||
"""
|
||||
readableDatabase.rawQuery(query, null).readToList { cursor ->
|
||||
RecipientId.from(cursor.requireLong(RECIPIENT_ID))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Pinned recipients, in order from top to bottom.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user