mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-04-23 02:10:44 +01:00
Improve various UI for chat folders.
This commit is contained in:
@@ -71,7 +71,8 @@ class AppSettingsActivity : DSLSettingsActivity(), InAppPaymentComponent {
|
||||
StartLocation.REMOTE_BACKUPS -> AppSettingsFragmentDirections.actionDirectToRemoteBackupsSettingsFragment()
|
||||
StartLocation.CHAT_FOLDERS -> AppSettingsFragmentDirections.actionDirectToChatFoldersFragment()
|
||||
StartLocation.CREATE_CHAT_FOLDER -> AppSettingsFragmentDirections.actionDirectToCreateFoldersFragment(
|
||||
CreateFoldersFragmentArgs.fromBundle(intent.getBundleExtra(START_ARGUMENTS)!!).folderId
|
||||
CreateFoldersFragmentArgs.fromBundle(intent.getBundleExtra(START_ARGUMENTS)!!).folderId,
|
||||
CreateFoldersFragmentArgs.fromBundle(intent.getBundleExtra(START_ARGUMENTS)!!).threadId
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -207,8 +208,8 @@ class AppSettingsActivity : DSLSettingsActivity(), InAppPaymentComponent {
|
||||
fun chatFolders(context: Context): Intent = getIntentForStartLocation(context, StartLocation.CHAT_FOLDERS)
|
||||
|
||||
@JvmStatic
|
||||
fun createChatFolder(context: Context, id: Long = -1): Intent {
|
||||
val arguments = CreateFoldersFragmentArgs.Builder(id)
|
||||
fun createChatFolder(context: Context, id: Long = -1, threadId: Long?): Intent {
|
||||
val arguments = CreateFoldersFragmentArgs.Builder(id, threadId ?: -1)
|
||||
.build()
|
||||
.toBundle()
|
||||
|
||||
|
||||
@@ -84,7 +84,7 @@ class ChatFoldersFragment : ComposeFragment() {
|
||||
navController = navController,
|
||||
modifier = Modifier.padding(contentPadding),
|
||||
onFolderClicked = {
|
||||
navController.safeNavigate(ChatFoldersFragmentDirections.actionChatFoldersFragmentToCreateFoldersFragment(it.id))
|
||||
navController.safeNavigate(ChatFoldersFragmentDirections.actionChatFoldersFragmentToCreateFoldersFragment(it.id, -1))
|
||||
},
|
||||
onAdd = { folder ->
|
||||
Toast.makeText(requireContext(), getString(R.string.ChatFoldersFragment__folder_added, folder.name), Toast.LENGTH_SHORT).show()
|
||||
|
||||
@@ -225,6 +225,25 @@ class ChatFoldersViewModel : ViewModel() {
|
||||
}
|
||||
}
|
||||
|
||||
fun addThreadToIncludedChat(threadId: Long?) {
|
||||
if (threadId == null || threadId == -1L) {
|
||||
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)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun addIncludedChat(recipientId: RecipientId) {
|
||||
val includedChats = internalState.value.pendingIncludedRecipients.plus(recipientId)
|
||||
internalState.update {
|
||||
@@ -325,4 +344,8 @@ class ChatFoldersViewModel : ViewModel() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun hasEmptyName(): Boolean {
|
||||
return state.value.currentFolder.name.isEmpty()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Person
|
||||
import androidx.compose.material3.ButtonDefaults
|
||||
@@ -44,6 +45,7 @@ import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalInspectionMode
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.input.KeyboardCapitalization
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.fragment.app.activityViewModels
|
||||
import androidx.navigation.NavController
|
||||
@@ -57,6 +59,7 @@ import org.signal.core.ui.SignalPreview
|
||||
import org.thoughtcrime.securesms.R
|
||||
import org.thoughtcrime.securesms.avatar.AvatarImage
|
||||
import org.thoughtcrime.securesms.compose.ComposeFragment
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
||||
import org.thoughtcrime.securesms.recipients.Recipient
|
||||
import org.thoughtcrime.securesms.util.navigation.safeNavigate
|
||||
|
||||
@@ -76,7 +79,7 @@ class CreateFoldersFragment : ComposeFragment() {
|
||||
viewLifecycleOwner,
|
||||
object : OnBackPressedCallback(true) {
|
||||
override fun handleOnBackPressed() {
|
||||
if (viewModel.hasChanges()) {
|
||||
if (viewModel.hasChanges() && !viewModel.hasEmptyName()) {
|
||||
viewModel.showConfirmationDialog(true)
|
||||
} else {
|
||||
findNavController().popBackStack()
|
||||
@@ -96,13 +99,21 @@ 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))
|
||||
}
|
||||
}
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
if (!SignalStore.uiHints.hasSeenChatFoldersEducationSheet) {
|
||||
SignalStore.uiHints.hasSeenChatFoldersEducationSheet = true
|
||||
navController.safeNavigate(R.id.action_createFoldersFragment_to_chatFoldersEducationSheet)
|
||||
}
|
||||
}
|
||||
|
||||
Scaffolds.Settings(
|
||||
title = if (isNewFolder) stringResource(id = R.string.CreateFoldersFragment__create_a_folder) else stringResource(id = R.string.CreateFoldersFragment__edit_folder),
|
||||
onNavigationClick = {
|
||||
if (viewModel.hasChanges()) {
|
||||
if (viewModel.hasChanges() && !viewModel.hasEmptyName()) {
|
||||
viewModel.showConfirmationDialog(true)
|
||||
} else {
|
||||
navController.popBackStack()
|
||||
@@ -161,6 +172,7 @@ class CreateFoldersFragment : ComposeFragment() {
|
||||
|
||||
companion object {
|
||||
private val KEY_FOLDER_ID = "folder_id"
|
||||
private val KEY_THREAD_ID = "thread_id"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -195,24 +207,14 @@ fun CreateFolderScreen(
|
||||
dismiss = stringResource(id = android.R.string.cancel),
|
||||
onDismiss = onDeleteDismissed
|
||||
)
|
||||
} else if (state.showConfirmationDialog && isNewFolder) {
|
||||
Dialogs.SimpleAlertDialog(
|
||||
title = stringResource(id = R.string.CreateFoldersFragment__create_folder_title),
|
||||
body = stringResource(id = R.string.CreateFoldersFragment__do_you_want_to_create, state.currentFolder.name),
|
||||
confirm = stringResource(id = R.string.CreateFoldersFragment__create_folder),
|
||||
onConfirm = { onCreateConfirmed(false) },
|
||||
dismiss = stringResource(id = R.string.CreateFoldersFragment__discard),
|
||||
onDismiss = { onCreateDismissed(true) },
|
||||
onDismissRequest = { onCreateDismissed(false) }
|
||||
)
|
||||
} else if (state.showConfirmationDialog) {
|
||||
Dialogs.SimpleAlertDialog(
|
||||
title = stringResource(id = R.string.CreateFoldersFragment__save_changes_title),
|
||||
body = stringResource(id = R.string.CreateFoldersFragment__do_you_want_to_save),
|
||||
confirm = stringResource(id = R.string.CreateFoldersFragment__save_changes),
|
||||
onConfirm = { onCreateConfirmed(false) },
|
||||
dismiss = stringResource(id = R.string.CreateFoldersFragment__discard),
|
||||
onDismiss = { onCreateDismissed(true) },
|
||||
title = stringResource(id = R.string.CreateFoldersFragment__discard_changes_title),
|
||||
body = stringResource(id = R.string.CreateFoldersFragment__you_will_lose_changes),
|
||||
confirm = stringResource(id = R.string.CreateFoldersFragment__discard),
|
||||
onConfirm = { onCreateDismissed(true) },
|
||||
dismiss = stringResource(id = android.R.string.cancel),
|
||||
onDismiss = { onCreateDismissed(false) },
|
||||
onDismissRequest = { onCreateDismissed(false) }
|
||||
)
|
||||
}
|
||||
@@ -224,6 +226,7 @@ fun CreateFolderScreen(
|
||||
value = state.currentFolder.name,
|
||||
label = { Text(text = stringResource(id = R.string.CreateFoldersFragment__folder_name)) },
|
||||
onValueChange = onNameChange,
|
||||
keyboardOptions = KeyboardOptions(capitalization = KeyboardCapitalization.Sentences),
|
||||
singleLine = true,
|
||||
modifier = modifier
|
||||
.fillMaxWidth()
|
||||
|
||||
@@ -77,7 +77,7 @@ class AddToFolderBottomSheet private constructor() : ComposeBottomSheetDialogFra
|
||||
dismissAllowingStateLoss()
|
||||
},
|
||||
onCreate = {
|
||||
requireContext().startActivity(AppSettingsActivity.createChatFolder(requireContext(), -1))
|
||||
requireContext().startActivity(AppSettingsActivity.createChatFolder(requireContext(), -1, threadId))
|
||||
dismissAllowingStateLoss()
|
||||
}
|
||||
)
|
||||
|
||||
@@ -53,7 +53,11 @@ class ChatFolderAdapter(val callbacks: Callbacks) : MappingAdapter() {
|
||||
true
|
||||
}
|
||||
if (model.isSelected) {
|
||||
itemView.backgroundTintList = ColorStateList.valueOf(ContextCompat.getColor(itemView.context, R.color.signal_colorSurface2))
|
||||
itemView.backgroundTintList = if (callbacks.isScrolled()) {
|
||||
ColorStateList.valueOf(ContextCompat.getColor(itemView.context, R.color.signal_colorBackground))
|
||||
} else {
|
||||
ColorStateList.valueOf(ContextCompat.getColor(itemView.context, R.color.signal_colorSurface2))
|
||||
}
|
||||
} else {
|
||||
itemView.backgroundTintList = ColorStateList.valueOf(ContextCompat.getColor(itemView.context, R.color.transparent))
|
||||
}
|
||||
@@ -75,5 +79,6 @@ class ChatFolderAdapter(val callbacks: Callbacks) : MappingAdapter() {
|
||||
fun onUnmuteAll(chatFolder: ChatFolderRecord)
|
||||
fun onReadAll(chatFolder: ChatFolderRecord)
|
||||
fun onFolderSettings()
|
||||
fun isScrolled(): Boolean
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1485,12 +1485,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 (RemoteConfig.internalUser() && viewModel.getCurrentFolder().getFolderType() == ChatFolderRecord.FolderType.ALL) {
|
||||
if (viewModel.getCurrentFolder().getFolderType() == ChatFolderRecord.FolderType.ALL) {
|
||||
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)
|
||||
));
|
||||
} else if (RemoteConfig.internalUser()){
|
||||
} else {
|
||||
items.add(new ActionItem(R.drawable.symbol_folder_minus, getString(R.string.ConversationListFragment_remove_from_folder), () -> viewModel.removeChatFromFolder(conversation.getThreadRecord().getThreadId())));
|
||||
}
|
||||
items.add(new ActionItem(R.drawable.symbol_archive_24, getResources().getString(R.string.ConversationListFragment_archive), () -> handleArchive(id, false)));
|
||||
@@ -1689,6 +1689,11 @@ public class ConversationListFragment extends MainFragment implements ActionMode
|
||||
pullViewAppBarLayout.setExpanded(false, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isScrolled() {
|
||||
return list.canScrollVertically(-1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChatFolderClicked(@NonNull ChatFolderRecord chatFolder) {
|
||||
int oldIndex = -1;
|
||||
@@ -1724,7 +1729,7 @@ public class ConversationListFragment extends MainFragment implements ActionMode
|
||||
|
||||
@Override
|
||||
public void onEdit(@NonNull ChatFolderRecord chatFolder) {
|
||||
startActivity(AppSettingsActivity.createChatFolder(requireContext(), chatFolder.getId()));
|
||||
startActivity(AppSettingsActivity.createChatFolder(requireContext(), chatFolder.getId(), null));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -143,7 +143,9 @@ class ConversationListViewModel(
|
||||
if (conversations.isNotEmpty()) {
|
||||
false
|
||||
} else {
|
||||
SignalDatabase.threads.getArchivedConversationListCount(filterRequest.filter) == 0
|
||||
val archivedCount = SignalDatabase.threads.getArchivedConversationListCount(filterRequest.filter)
|
||||
val unarchivedCount = SignalDatabase.threads.getUnarchivedConversationListCount(filterRequest.filter)
|
||||
(archivedCount + unarchivedCount) == 0
|
||||
}
|
||||
}
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
|
||||
Reference in New Issue
Block a user