Indicate when chats already belong in folder.

This commit is contained in:
Michelle Tang
2024-10-29 14:14:20 -04:00
committed by GitHub
parent 1b9129b4a0
commit 0b66e9409d
3 changed files with 75 additions and 14 deletions

View File

@@ -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()
}
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
)
}
}

View File

@@ -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

View File

@@ -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>