mirror of
https://github.com/signalapp/Signal-Android.git
synced 2025-12-20 19:18:37 +00:00
Indicate when chats already belong in folder.
This commit is contained in:
@@ -6,6 +6,7 @@ import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.defaultMinSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
@@ -14,15 +15,18 @@ import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.ColorFilter
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.res.dimensionResource
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.res.vectorResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
@@ -50,13 +54,22 @@ class AddToFolderBottomSheet private constructor() : ComposeBottomSheetDialogFra
|
||||
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"
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
@JvmStatic
|
||||
fun showChatFolderSheet(folders: List<ChatFolderRecord>, threadId: Long): ComposeBottomSheetDialogFragment {
|
||||
fun showChatFolderSheet(folders: List<ChatFolderRecord>, threadId: Long, isIndividualChat: Boolean): ComposeBottomSheetDialogFragment {
|
||||
return AddToFolderBottomSheet().apply {
|
||||
arguments = bundleOf(
|
||||
ARG_FOLDERS to folders,
|
||||
ARG_THREAD_ID to threadId
|
||||
ARG_THREAD_ID to threadId,
|
||||
ARG_IS_INDIVIDUAL_CHAT to isIndividualChat
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -64,17 +77,22 @@ class AddToFolderBottomSheet private constructor() : ComposeBottomSheetDialogFra
|
||||
|
||||
@Composable
|
||||
override fun SheetContent() {
|
||||
val folders = arguments?.getParcelableArrayListCompat(ARG_FOLDERS, ChatFolderRecord::class.java)?.filter { it.folderType != ChatFolderRecord.FolderType.ALL }
|
||||
val threadId = arguments?.getLong(ARG_THREAD_ID)
|
||||
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)
|
||||
|
||||
AddToChatFolderSheetContent(
|
||||
threadId = threadId,
|
||||
isIndividualChat = isIndividualChat,
|
||||
folders = remember { folders ?: emptyList() },
|
||||
onClick = { folder ->
|
||||
if (threadId != null) {
|
||||
onClick = { folder, isAlreadyAdded ->
|
||||
if (isAlreadyAdded) {
|
||||
Toast.makeText(context, requireContext().getString(R.string.AddToFolderBottomSheet_this_chat_is_already, folder.name), Toast.LENGTH_SHORT).show()
|
||||
} else {
|
||||
viewModel.addToFolder(folder.id, threadId)
|
||||
Toast.makeText(context, requireContext().getString(R.string.AddToFolderBottomSheet_added_to_s, folder.name), Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
dismissAllowingStateLoss()
|
||||
}
|
||||
},
|
||||
onCreate = {
|
||||
requireContext().startActivity(AppSettingsActivity.createChatFolder(requireContext(), -1, threadId))
|
||||
@@ -86,8 +104,10 @@ class AddToFolderBottomSheet private constructor() : ComposeBottomSheetDialogFra
|
||||
|
||||
@Composable
|
||||
private fun AddToChatFolderSheetContent(
|
||||
threadId: Long,
|
||||
isIndividualChat: Boolean,
|
||||
folders: List<ChatFolderRecord>,
|
||||
onClick: (ChatFolderRecord) -> Unit = {},
|
||||
onClick: (ChatFolderRecord, Boolean) -> Unit = { _, _ -> },
|
||||
onCreate: () -> Unit = {}
|
||||
) {
|
||||
Column(
|
||||
@@ -110,10 +130,16 @@ 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
|
||||
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier
|
||||
.clickable(onClick = { onClick(folder) })
|
||||
.clickable(onClick = { onClick(folder, isAlreadyAdded) })
|
||||
.padding(start = 24.dp)
|
||||
.fillMaxWidth()
|
||||
.defaultMinSize(minHeight = dimensionResource(id = R.dimen.chat_folder_row_height))
|
||||
@@ -133,6 +159,24 @@ private fun AddToChatFolderSheetContent(
|
||||
style = MaterialTheme.typography.bodyLarge,
|
||||
modifier = Modifier.padding(start = 16.dp)
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
|
||||
if (isAlreadyAdded) {
|
||||
Icon(
|
||||
painterResource(R.drawable.symbol_check_white_24),
|
||||
contentDescription = null,
|
||||
tint = Color.White,
|
||||
modifier = Modifier
|
||||
.padding(end = 16.dp)
|
||||
.size(24.dp)
|
||||
.background(
|
||||
color = Color.Black.copy(.40f),
|
||||
shape = CircleShape
|
||||
)
|
||||
.padding(4.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -171,7 +215,9 @@ private fun AddToChatFolderSheetContent(
|
||||
private fun AddToChatFolderSheetContentPreview() {
|
||||
Previews.BottomSheetPreview {
|
||||
AddToChatFolderSheetContent(
|
||||
folders = listOf(ChatFolderRecord(name = "Friends"), ChatFolderRecord(name = "Work"))
|
||||
folders = listOf(ChatFolderRecord(name = "Friends"), ChatFolderRecord(name = "Work")),
|
||||
threadId = 1,
|
||||
isIndividualChat = false
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@ import android.net.Uri;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Parcelable;
|
||||
import android.text.TextUtils;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
@@ -1066,7 +1067,10 @@ public class ConversationListFragment extends MainFragment implements ActionMode
|
||||
|
||||
private void onChatFoldersChanged(List<ChatFolderMappingModel> folders) {
|
||||
chatFolderList.setVisibility(folders.size() > 1 && !isArchived() ? View.VISIBLE : View.GONE);
|
||||
chatFolderAdapter.submitList(new ArrayList<>(folders));
|
||||
if (chatFolderList.getLayoutManager() != null) {
|
||||
Parcelable savedState = chatFolderList.getLayoutManager().onSaveInstanceState();
|
||||
chatFolderAdapter.submitList(new ArrayList<>(folders), () -> chatFolderList.getLayoutManager().onRestoreInstanceState(savedState));
|
||||
}
|
||||
}
|
||||
|
||||
private void onMegaphoneChanged(@NonNull Megaphone megaphone) {
|
||||
@@ -1485,10 +1489,12 @@ public class ConversationListFragment extends MainFragment implements ActionMode
|
||||
if (conversation.getThreadRecord().isArchived()) {
|
||||
items.add(new ActionItem(R.drawable.symbol_archive_up_24, getResources().getString(R.string.ConversationListFragment_unarchive), () -> handleArchive(id, false)));
|
||||
} else {
|
||||
if (viewModel.getCurrentFolder().getFolderType() == ChatFolderRecord.FolderType.ALL) {
|
||||
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());
|
||||
items.add(new ActionItem(R.drawable.symbol_folder_add, getString(R.string.ConversationListFragment_add_to_folder), () ->
|
||||
AddToFolderBottomSheet.showChatFolderSheet(folders, conversation.getThreadRecord().getThreadId()).show(getParentFragmentManager(), BottomSheetUtil.STANDARD_BOTTOM_SHEET_FRAGMENT_TAG)
|
||||
AddToFolderBottomSheet.showChatFolderSheet(folders, conversation.getThreadRecord().getThreadId(), conversation.getThreadRecord().getRecipient().isIndividual()).show(getParentFragmentManager(), BottomSheetUtil.STANDARD_BOTTOM_SHEET_FRAGMENT_TAG)
|
||||
));
|
||||
} else {
|
||||
items.add(new ActionItem(R.drawable.symbol_folder_minus, getString(R.string.ConversationListFragment_remove_from_folder), () -> viewModel.removeChatFromFolder(conversation.getThreadRecord().getThreadId())));
|
||||
@@ -1713,6 +1719,14 @@ public class ConversationListFragment extends MainFragment implements ActionMode
|
||||
}
|
||||
}
|
||||
|
||||
if (isScrolled()) {
|
||||
list.smoothScrollToPosition(0);
|
||||
}
|
||||
|
||||
if (oldIndex == newIndex) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (oldIndex < newIndex) {
|
||||
smoothScroller.setTargetPosition(Math.min(newIndex + 1, viewModel.getFolders().size()));
|
||||
} else {
|
||||
@@ -1724,7 +1738,6 @@ public class ConversationListFragment extends MainFragment implements ActionMode
|
||||
}
|
||||
|
||||
viewModel.select(chatFolder);
|
||||
list.smoothScrollToPosition(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -749,6 +749,8 @@
|
||||
<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>
|
||||
|
||||
<!-- 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