mirror of
https://github.com/signalapp/Signal-Android.git
synced 2025-12-24 04:58:45 +00:00
Support selecting multiple threads to add to chat folder.
Resolves #13973
This commit is contained in:
@@ -72,7 +72,7 @@ class AppSettingsActivity : DSLSettingsActivity(), InAppPaymentComponent {
|
||||
StartLocation.CHAT_FOLDERS -> AppSettingsFragmentDirections.actionDirectToChatFoldersFragment()
|
||||
StartLocation.CREATE_CHAT_FOLDER -> AppSettingsFragmentDirections.actionDirectToCreateFoldersFragment(
|
||||
CreateFoldersFragmentArgs.fromBundle(intent.getBundleExtra(START_ARGUMENTS)!!).folderId,
|
||||
CreateFoldersFragmentArgs.fromBundle(intent.getBundleExtra(START_ARGUMENTS)!!).threadId
|
||||
CreateFoldersFragmentArgs.fromBundle(intent.getBundleExtra(START_ARGUMENTS)!!).threadIds
|
||||
)
|
||||
StartLocation.BACKUPS_SETTINGS -> AppSettingsFragmentDirections.actionDirectToBackupsSettingsFragment()
|
||||
}
|
||||
@@ -209,8 +209,8 @@ class AppSettingsActivity : DSLSettingsActivity(), InAppPaymentComponent {
|
||||
fun chatFolders(context: Context): Intent = getIntentForStartLocation(context, StartLocation.CHAT_FOLDERS)
|
||||
|
||||
@JvmStatic
|
||||
fun createChatFolder(context: Context, id: Long = -1, threadId: Long?): Intent {
|
||||
val arguments = CreateFoldersFragmentArgs.Builder(id, threadId ?: -1)
|
||||
fun createChatFolder(context: Context, id: Long = -1, threadIds: LongArray?): Intent {
|
||||
val arguments = CreateFoldersFragmentArgs.Builder(id, threadIds ?: longArrayOf())
|
||||
.build()
|
||||
.toBundle()
|
||||
|
||||
|
||||
@@ -84,7 +84,7 @@ class ChatFoldersFragment : ComposeFragment() {
|
||||
navController = navController,
|
||||
modifier = Modifier.padding(contentPadding),
|
||||
onFolderClicked = {
|
||||
navController.safeNavigate(ChatFoldersFragmentDirections.actionChatFoldersFragmentToCreateFoldersFragment(it.id, -1))
|
||||
navController.safeNavigate(ChatFoldersFragmentDirections.actionChatFoldersFragmentToCreateFoldersFragment(it.id, null))
|
||||
},
|
||||
onAdd = { folder ->
|
||||
Toast.makeText(requireContext(), getString(R.string.ChatFoldersFragment__folder_added, folder.name), Toast.LENGTH_SHORT).show()
|
||||
|
||||
@@ -225,22 +225,27 @@ class ChatFoldersViewModel : ViewModel() {
|
||||
}
|
||||
}
|
||||
|
||||
fun addThreadToIncludedChat(threadId: Long?) {
|
||||
if (threadId == null || threadId == -1L) {
|
||||
fun addThreadsToFolder(threadIds: LongArray?) {
|
||||
if (threadIds == null || threadIds.isEmpty()) {
|
||||
return
|
||||
}
|
||||
viewModelScope.launch {
|
||||
val updatedFolder = internalState.value.currentFolder
|
||||
val recipient = SignalDatabase.threads.getRecipientForThreadId(threadId)
|
||||
if (recipient != null) {
|
||||
internalState.update {
|
||||
it.copy(
|
||||
currentFolder = updatedFolder.copy(
|
||||
includedRecipients = setOf(recipient)
|
||||
)
|
||||
)
|
||||
val includedRecipients = mutableSetOf<Recipient>()
|
||||
threadIds.forEach { threadId ->
|
||||
val recipient = SignalDatabase.threads.getRecipientForThreadId(threadId)
|
||||
if (recipient != null) {
|
||||
includedRecipients.add(recipient)
|
||||
}
|
||||
}
|
||||
|
||||
internalState.update {
|
||||
it.copy(
|
||||
currentFolder = updatedFolder.copy(
|
||||
includedRecipients = includedRecipients
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -99,7 +99,7 @@ class CreateFoldersFragment : ComposeFragment() {
|
||||
LaunchedEffect(Unit) {
|
||||
if (state.originalFolder == state.currentFolder) {
|
||||
viewModel.setCurrentFolderId(arguments?.getLong(KEY_FOLDER_ID) ?: -1)
|
||||
viewModel.addThreadToIncludedChat(arguments?.getLong(KEY_THREAD_ID))
|
||||
viewModel.addThreadsToFolder(arguments?.getLongArray(KEY_THREAD_IDS))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -170,7 +170,7 @@ class CreateFoldersFragment : ComposeFragment() {
|
||||
|
||||
companion object {
|
||||
private val KEY_FOLDER_ID = "folder_id"
|
||||
private val KEY_THREAD_ID = "thread_id"
|
||||
private val KEY_THREAD_IDS = "thread_ids"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -45,31 +45,41 @@ import org.thoughtcrime.securesms.util.viewModel
|
||||
/**
|
||||
* Bottom sheet shown when choosing to add a chat to a folder
|
||||
*/
|
||||
class AddToFolderBottomSheet private constructor() : ComposeBottomSheetDialogFragment() {
|
||||
class AddToFolderBottomSheet private constructor(private val onDismissListener: OnDismissListener) : ComposeBottomSheetDialogFragment() {
|
||||
|
||||
override val peekHeightPercentage: Float = 1f
|
||||
|
||||
interface OnDismissListener {
|
||||
fun onDismiss()
|
||||
}
|
||||
|
||||
enum class ThreadType(val value: Int) {
|
||||
INDIVIDUAL(1),
|
||||
GROUP(2),
|
||||
OTHER(3)
|
||||
}
|
||||
|
||||
private val viewModel by viewModel { ConversationListViewModel(isArchived = false) }
|
||||
|
||||
companion object {
|
||||
private const val ARG_FOLDERS = "argument.folders"
|
||||
private const val ARG_THREAD_ID = "argument.thread.id"
|
||||
private const val ARG_IS_INDIVIDUAL_CHAT = "argument.is.individual.chat"
|
||||
private const val ARG_THREAD_IDS = "argument.thread.ids"
|
||||
private const val ARG_THREAD_TYPES = "argument.thread.types"
|
||||
|
||||
/**
|
||||
* Shows a bottom sheet that allows a thread to be added to a folder.
|
||||
*
|
||||
* @param folders list of available folders to add a thread to
|
||||
* @param threadId the thread that is going to be added
|
||||
* @param isIndividualChat whether the thread is an individual/1:1 chat as opposed to a group chat
|
||||
* @param threadIds list of threads that are going to be added
|
||||
* @param threadTypes list of ThreadType of threads present in threadIds
|
||||
*/
|
||||
@JvmStatic
|
||||
fun showChatFolderSheet(folders: List<ChatFolderRecord>, threadId: Long, isIndividualChat: Boolean): ComposeBottomSheetDialogFragment {
|
||||
return AddToFolderBottomSheet().apply {
|
||||
fun showChatFolderSheet(folders: List<ChatFolderRecord>, threadIds: List<Long>, threadTypes: List<Int>, onDismissListener: OnDismissListener): ComposeBottomSheetDialogFragment {
|
||||
return AddToFolderBottomSheet(onDismissListener).apply {
|
||||
arguments = bundleOf(
|
||||
ARG_FOLDERS to folders,
|
||||
ARG_THREAD_ID to threadId,
|
||||
ARG_IS_INDIVIDUAL_CHAT to isIndividualChat
|
||||
ARG_THREAD_IDS to threadIds.toLongArray(),
|
||||
ARG_THREAD_TYPES to threadTypes.toIntArray()
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -78,25 +88,31 @@ class AddToFolderBottomSheet private constructor() : ComposeBottomSheetDialogFra
|
||||
@Composable
|
||||
override fun SheetContent() {
|
||||
val folders = requireArguments().getParcelableArrayListCompat(ARG_FOLDERS, ChatFolderRecord::class.java)?.filter { it.folderType != ChatFolderRecord.FolderType.ALL }
|
||||
val threadId = requireArguments().getLong(ARG_THREAD_ID)
|
||||
val isIndividualChat = requireArguments().getBoolean(ARG_IS_INDIVIDUAL_CHAT)
|
||||
|
||||
val threadIds = requireArguments().getLongArray(ARG_THREAD_IDS)?.asList() ?: throw IllegalArgumentException("At least one ThreadId is expected!")
|
||||
val threadTypes = requireArguments().getIntArray(ARG_THREAD_TYPES)?.asList() ?: throw IllegalArgumentException("At least one ThreadId is expected!")
|
||||
AddToChatFolderSheetContent(
|
||||
threadId = threadId,
|
||||
isIndividualChat = isIndividualChat,
|
||||
threadIds = threadIds,
|
||||
threadTypes = threadTypes,
|
||||
folders = remember { folders ?: emptyList() },
|
||||
onClick = { folder, isAlreadyAdded ->
|
||||
if (isAlreadyAdded) {
|
||||
Toast.makeText(context, requireContext().getString(R.string.AddToFolderBottomSheet_this_chat_is_already, folder.name), Toast.LENGTH_SHORT).show()
|
||||
val message = requireContext().resources.getQuantityString(
|
||||
R.plurals.AddToFolderBottomSheet_these_chat_are_already_in_s,
|
||||
threadIds.size,
|
||||
folder.name
|
||||
)
|
||||
Toast.makeText(context, message, Toast.LENGTH_SHORT).show()
|
||||
} else {
|
||||
viewModel.addToFolder(folder.id, threadId)
|
||||
viewModel.addToFolder(folder.id, threadIds)
|
||||
Toast.makeText(context, requireContext().getString(R.string.AddToFolderBottomSheet_added_to_s, folder.name), Toast.LENGTH_SHORT).show()
|
||||
dismissAllowingStateLoss()
|
||||
onDismissListener.onDismiss()
|
||||
}
|
||||
},
|
||||
onCreate = {
|
||||
requireContext().startActivity(AppSettingsActivity.createChatFolder(requireContext(), -1, threadId))
|
||||
requireContext().startActivity(AppSettingsActivity.createChatFolder(requireContext(), -1, threadIds.toLongArray()))
|
||||
dismissAllowingStateLoss()
|
||||
onDismissListener.onDismiss()
|
||||
}
|
||||
)
|
||||
}
|
||||
@@ -104,8 +120,8 @@ class AddToFolderBottomSheet private constructor() : ComposeBottomSheetDialogFra
|
||||
|
||||
@Composable
|
||||
private fun AddToChatFolderSheetContent(
|
||||
threadId: Long,
|
||||
isIndividualChat: Boolean,
|
||||
threadIds: List<Long>,
|
||||
threadTypes: List<Int>,
|
||||
folders: List<ChatFolderRecord>,
|
||||
onClick: (ChatFolderRecord, Boolean) -> Unit = { _, _ -> },
|
||||
onCreate: () -> Unit = {}
|
||||
@@ -130,11 +146,7 @@ private fun AddToChatFolderSheetContent(
|
||||
.background(color = MaterialTheme.colorScheme.surface, shape = RoundedCornerShape(18.dp))
|
||||
) {
|
||||
items(folders) { folder ->
|
||||
val isIncludedViaChatType = (isIndividualChat && folder.showIndividualChats) || (!isIndividualChat && folder.showGroupChats)
|
||||
val isIncludedExplicitly = folder.includedChats.contains(threadId)
|
||||
val isExcludedExplicitly = folder.excludedChats.contains(threadId)
|
||||
|
||||
val isAlreadyAdded = (isIncludedExplicitly || isIncludedViaChatType) && !isExcludedExplicitly
|
||||
val isAlreadyAdded = isThreadListAlreadyAdded(folder, threadIds, threadTypes)
|
||||
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
@@ -210,14 +222,36 @@ private fun AddToChatFolderSheetContent(
|
||||
}
|
||||
}
|
||||
|
||||
private fun isThreadListAlreadyAdded(folder: ChatFolderRecord, threadIds: List<Long>, threadTypes: List<Int>): Boolean {
|
||||
val isAnyExcluded = threadIds.any {
|
||||
folder.excludedChats.contains(it)
|
||||
}
|
||||
if (isAnyExcluded) {
|
||||
return false
|
||||
}
|
||||
|
||||
if (folder.showIndividualChats) {
|
||||
return threadTypes.indices.all { index ->
|
||||
threadTypes[index] == AddToFolderBottomSheet.ThreadType.INDIVIDUAL.value || folder.includedChats.contains(threadIds[index])
|
||||
}
|
||||
}
|
||||
if (folder.showGroupChats) {
|
||||
return threadTypes.indices.all { index ->
|
||||
threadTypes[index] == AddToFolderBottomSheet.ThreadType.GROUP.value || folder.includedChats.contains(threadIds[index])
|
||||
}
|
||||
}
|
||||
|
||||
return folder.includedChats.containsAll(threadIds)
|
||||
}
|
||||
|
||||
@SignalPreview
|
||||
@Composable
|
||||
private fun AddToChatFolderSheetContentPreview() {
|
||||
Previews.BottomSheetPreview {
|
||||
AddToChatFolderSheetContent(
|
||||
folders = listOf(ChatFolderRecord(name = "Friends"), ChatFolderRecord(name = "Work")),
|
||||
threadId = 1,
|
||||
isIndividualChat = false
|
||||
threadIds = listOf(1),
|
||||
threadTypes = listOf(0)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -160,7 +160,6 @@ import org.thoughtcrime.securesms.megaphone.MegaphoneActionController;
|
||||
import org.thoughtcrime.securesms.megaphone.MegaphoneViewBuilder;
|
||||
import org.thoughtcrime.securesms.megaphone.Megaphones;
|
||||
import org.thoughtcrime.securesms.notifications.MarkReadReceiver;
|
||||
import org.thoughtcrime.securesms.notifications.profiles.NotificationProfile;
|
||||
import org.thoughtcrime.securesms.permissions.Permissions;
|
||||
import org.thoughtcrime.securesms.profiles.manage.UsernameEditFragment;
|
||||
import org.thoughtcrime.securesms.ratelimit.RecaptchaProofBottomSheetFragment;
|
||||
@@ -220,9 +219,9 @@ public class ConversationListFragment extends MainFragment implements ActionMode
|
||||
|
||||
private static final String TAG = Log.tag(ConversationListFragment.class);
|
||||
|
||||
private static final int MAXIMUM_PINNED_CONVERSATIONS = 4;
|
||||
private static final int MAX_CHATS_ABOVE_FOLD = 7;
|
||||
private static final int MAX_CONTACTS_ABOVE_FOLD = 5;
|
||||
private static final int MAXIMUM_PINNED_CONVERSATIONS = 4;
|
||||
private static final int MAX_CHATS_ABOVE_FOLD = 7;
|
||||
private static final int MAX_CONTACTS_ABOVE_FOLD = 5;
|
||||
private static final int MAX_GROUP_MEMBERSHIPS_ABOVE_FOLD = 5;
|
||||
|
||||
private ActionMode actionMode;
|
||||
@@ -396,7 +395,7 @@ public class ConversationListFragment extends MainFragment implements ActionMode
|
||||
archiveDecoration = new ConversationListArchiveItemDecoration(new ColorDrawable(getResources().getColor(R.color.conversation_list_archive_background_end)));
|
||||
itemAnimator = new ConversationListItemAnimator();
|
||||
|
||||
chatFolderAdapter = new ChatFolderAdapter(this);
|
||||
chatFolderAdapter = new ChatFolderAdapter(this);
|
||||
DefaultItemAnimator chatFolderItemAnimator = getChatFolderItemAnimator();
|
||||
|
||||
chatFolderList.setLayoutManager(new LinearLayoutManager(requireActivity(), LinearLayoutManager.HORIZONTAL, false));
|
||||
@@ -484,7 +483,7 @@ public class ConversationListFragment extends MainFragment implements ActionMode
|
||||
}
|
||||
|
||||
private @NonNull DefaultItemAnimator getChatFolderItemAnimator() {
|
||||
int duration = 150;
|
||||
int duration = 150;
|
||||
DefaultItemAnimator animator = new DefaultItemAnimator();
|
||||
animator.setAddDuration(duration);
|
||||
animator.setMoveDuration(duration);
|
||||
@@ -669,10 +668,10 @@ public class ConversationListFragment extends MainFragment implements ActionMode
|
||||
builder.addSection(new ContactSearchConfiguration.Section.Chats(
|
||||
unreadOnly,
|
||||
true,
|
||||
new ContactSearchConfiguration.ExpandConfig(
|
||||
state.getExpandedSections().contains(ContactSearchConfiguration.SectionKey.CHATS),
|
||||
(a) -> MAX_CHATS_ABOVE_FOLD
|
||||
)
|
||||
new ContactSearchConfiguration.ExpandConfig(
|
||||
state.getExpandedSections().contains(ContactSearchConfiguration.SectionKey.CHATS),
|
||||
(a) -> MAX_CHATS_ABOVE_FOLD
|
||||
)
|
||||
));
|
||||
|
||||
if (!unreadOnly) {
|
||||
@@ -704,8 +703,8 @@ public class ConversationListFragment extends MainFragment implements ActionMode
|
||||
} else {
|
||||
builder.arbitrary(
|
||||
conversationFilterRequest.getSource() == ConversationFilterSource.DRAG
|
||||
? ConversationListSearchAdapter.ChatFilterOptions.WITHOUT_TIP.getCode()
|
||||
: ConversationListSearchAdapter.ChatFilterOptions.WITH_TIP.getCode()
|
||||
? ConversationListSearchAdapter.ChatFilterOptions.WITHOUT_TIP.getCode()
|
||||
: ConversationListSearchAdapter.ChatFilterOptions.WITH_TIP.getCode()
|
||||
);
|
||||
}
|
||||
|
||||
@@ -958,7 +957,7 @@ public class ConversationListFragment extends MainFragment implements ActionMode
|
||||
|
||||
|
||||
private void initializeListAdapters() {
|
||||
defaultAdapter = new ConversationListAdapter(getViewLifecycleOwner(), Glide.with(this), this, this, this);
|
||||
defaultAdapter = new ConversationListAdapter(getViewLifecycleOwner(), Glide.with(this), this, this, this);
|
||||
|
||||
setAdapter(defaultAdapter);
|
||||
|
||||
@@ -1509,10 +1508,10 @@ public class ConversationListFragment extends MainFragment implements ActionMode
|
||||
} else {
|
||||
if (viewModel.getCurrentFolder().getFolderType() == ChatFolderRecord.FolderType.ALL &&
|
||||
(conversation.getThreadRecord().getRecipient().isIndividual() ||
|
||||
conversation.getThreadRecord().getRecipient().isPushV2Group())) {
|
||||
List<ChatFolderRecord> folders = viewModel.getFolders().stream().map(ChatFolderMappingModel::getChatFolder).collect(Collectors.toList());
|
||||
conversation.getThreadRecord().getRecipient().isPushV2Group()))
|
||||
{
|
||||
items.add(new ActionItem(R.drawable.symbol_folder_add, getString(R.string.ConversationListFragment_add_to_folder), () ->
|
||||
AddToFolderBottomSheet.showChatFolderSheet(folders, conversation.getThreadRecord().getThreadId(), conversation.getThreadRecord().getRecipient().isIndividual()).show(getParentFragmentManager(), BottomSheetUtil.STANDARD_BOTTOM_SHEET_FRAGMENT_TAG)
|
||||
showAddToFolderBottomSheet(conversation)
|
||||
));
|
||||
} else if (viewModel.getCurrentFolder().getFolderType() != ChatFolderRecord.FolderType.ALL) {
|
||||
items.add(new ActionItem(R.drawable.symbol_folder_minus, getString(R.string.ConversationListFragment_remove_from_folder), () -> viewModel.removeChatFromFolder(conversation.getThreadRecord().getThreadId())));
|
||||
@@ -1582,6 +1581,52 @@ public class ConversationListFragment extends MainFragment implements ActionMode
|
||||
closeSearchIfOpen();
|
||||
}
|
||||
|
||||
private void showAddToFolderBottomSheet(Conversation conversation) {
|
||||
showAddToFolderBottomSheet(
|
||||
Collections.singletonList(conversation.getThreadRecord().getThreadId()),
|
||||
Collections.singletonList(getThreadType(conversation))
|
||||
);
|
||||
}
|
||||
|
||||
private void showAddToFolderBottomSheet(Set<Conversation> conversations) {
|
||||
List<Long> threadIds = new ArrayList<>();
|
||||
List<Integer> threadTypes = new ArrayList<>();
|
||||
|
||||
for (Conversation conversation : conversations) {
|
||||
threadIds.add(conversation.getThreadRecord().getThreadId());
|
||||
threadTypes.add(getThreadType(conversation));
|
||||
}
|
||||
|
||||
showAddToFolderBottomSheet(
|
||||
threadIds,
|
||||
threadTypes
|
||||
);
|
||||
}
|
||||
|
||||
private int getThreadType(Conversation conversation) {
|
||||
boolean isIndividual = conversation.getThreadRecord().getRecipient().isIndividual();
|
||||
boolean isGroup = conversation.getThreadRecord().getRecipient().isPushGroup();
|
||||
int type;
|
||||
if (isIndividual) {
|
||||
type = AddToFolderBottomSheet.ThreadType.INDIVIDUAL.getValue();
|
||||
} else if (isGroup) {
|
||||
type = AddToFolderBottomSheet.ThreadType.GROUP.getValue();
|
||||
} else {
|
||||
type = AddToFolderBottomSheet.ThreadType.OTHER.getValue();
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
private void showAddToFolderBottomSheet(List<Long> threadIds, List<Integer> threadTypes) {
|
||||
List<ChatFolderRecord> folders = viewModel.getFolders().stream().map(ChatFolderMappingModel::getChatFolder).collect(Collectors.toList());
|
||||
AddToFolderBottomSheet.showChatFolderSheet(
|
||||
folders,
|
||||
threadIds,
|
||||
threadTypes,
|
||||
this::endActionModeIfActive
|
||||
).show(getParentFragmentManager(), BottomSheetUtil.STANDARD_BOTTOM_SHEET_FRAGMENT_TAG);
|
||||
}
|
||||
|
||||
private void updateMultiSelectState() {
|
||||
int count = viewModel.currentSelectedConversations().size();
|
||||
boolean hasUnread = Stream.of(viewModel.currentSelectedConversations()).anyMatch(conversation -> !conversation.getThreadRecord().isRead());
|
||||
@@ -1628,6 +1673,12 @@ public class ConversationListFragment extends MainFragment implements ActionMode
|
||||
|
||||
items.add(new ActionItem(R.drawable.symbol_check_circle_24, getString(R.string.ConversationListFragment_select_all), viewModel::onSelectAllClick));
|
||||
|
||||
if (!isArchived()) {
|
||||
items.add(new ActionItem(R.drawable.symbol_folder_add, getString(R.string.ConversationListFragment_add_to_folder), () -> {
|
||||
showAddToFolderBottomSheet(viewModel.currentSelectedConversations());
|
||||
}));
|
||||
}
|
||||
|
||||
bottomActionBar.setItems(items);
|
||||
}
|
||||
|
||||
|
||||
@@ -283,9 +283,13 @@ class ConversationListViewModel(
|
||||
}
|
||||
}
|
||||
|
||||
fun addToFolder(folderId: Long, threadId: Long) {
|
||||
fun addToFolder(folderId: Long, threadIds: List<Long>) {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
SignalDatabase.chatFolders.addToFolder(folderId, threadId)
|
||||
val includedChats = folders.find { it.chatFolder.id == folderId }?.chatFolder?.includedChats
|
||||
val threadIdsNotIncluded = threadIds.filterNot { threadId ->
|
||||
includedChats?.contains(threadId) ?: false
|
||||
}
|
||||
SignalDatabase.chatFolders.addToFolder(folderId, threadIdsNotIncluded)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -380,15 +380,17 @@ class ChatFolderTables(context: Context?, databaseHelper: SignalDatabase?) : Dat
|
||||
/**
|
||||
* Adds a thread to a chat folder
|
||||
*/
|
||||
fun addToFolder(folderId: Long, threadId: Long) {
|
||||
fun addToFolder(folderId: Long, threadIds: List<Long>) {
|
||||
writableDatabase.withinTransaction { db ->
|
||||
db.insertInto(ChatFolderMembershipTable.TABLE_NAME)
|
||||
.values(
|
||||
ChatFolderMembershipTable.CHAT_FOLDER_ID to folderId,
|
||||
ChatFolderMembershipTable.THREAD_ID to threadId,
|
||||
ChatFolderMembershipTable.MEMBERSHIP_TYPE to MembershipType.INCLUDED.value
|
||||
)
|
||||
.run(SQLiteDatabase.CONFLICT_REPLACE)
|
||||
threadIds.forEach { threadId ->
|
||||
db.insertInto(ChatFolderMembershipTable.TABLE_NAME)
|
||||
.values(
|
||||
ChatFolderMembershipTable.CHAT_FOLDER_ID to folderId,
|
||||
ChatFolderMembershipTable.THREAD_ID to threadId,
|
||||
ChatFolderMembershipTable.MEMBERSHIP_TYPE to MembershipType.INCLUDED.value
|
||||
)
|
||||
.run(SQLiteDatabase.CONFLICT_REPLACE)
|
||||
}
|
||||
|
||||
AppDependencies.databaseObserver.notifyChatFolderObservers()
|
||||
}
|
||||
|
||||
@@ -427,8 +427,9 @@
|
||||
app:argType="long" />
|
||||
|
||||
<argument
|
||||
android:name="thread_id"
|
||||
app:argType="long" />
|
||||
android:name="thread_ids"
|
||||
app:argType="long[]"
|
||||
app:nullable="true" />
|
||||
|
||||
<action
|
||||
android:id="@+id/action_createFoldersFragment_to_chooseChatsFragment"
|
||||
|
||||
@@ -787,8 +787,11 @@
|
||||
<string name="AddToFolderBottomSheet_choose_a_folder">Choose a folder</string>
|
||||
<!-- Toast shown when a chat has been added to a folder, where %s is the name of the folder -->
|
||||
<string name="AddToFolderBottomSheet_added_to_s">Added to \"%1$s\"</string>
|
||||
<!-- Toast shown when a user tries to add a chat to a folder, but the folder already has that chat. %s is the name of the folder -->
|
||||
<string name="AddToFolderBottomSheet_this_chat_is_already">This chat is already in the folder \"%1$s\"</string>
|
||||
<!-- Toast shown when a user tries to add chats to a folder, but the folder already has those chats. %s is the name of the folder -->
|
||||
<plurals name="AddToFolderBottomSheet_these_chat_are_already_in_s">
|
||||
<item quantity="one">This chat is already in \"%1$s\"</item>
|
||||
<item quantity="other">These chats are already in \"%1$s\"</item>
|
||||
</plurals>
|
||||
|
||||
<!-- Show in conversation list overflow menu to open selection bottom sheet -->
|
||||
<string name="ConversationListFragment__notification_profile">Notification profile</string>
|
||||
|
||||
Reference in New Issue
Block a user