Add context menus to chat folders.

This commit is contained in:
Michelle Tang
2024-10-11 10:59:07 -07:00
committed by Greyson Parrelli
parent 6b66e4666b
commit bfa5703aaa
16 changed files with 474 additions and 10 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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