Allow adding and removing from context menu.
This commit is contained in:
parent
94d6bfd9ad
commit
6fcfd8fdb1
13 changed files with 330 additions and 7 deletions
|
@ -1,17 +1,23 @@
|
|||
package org.thoughtcrime.securesms.components.settings.app.chats.folders
|
||||
|
||||
import android.os.Parcelable
|
||||
import kotlinx.parcelize.IgnoredOnParcel
|
||||
import kotlinx.parcelize.Parcelize
|
||||
import org.thoughtcrime.securesms.recipients.Recipient
|
||||
|
||||
/**
|
||||
* Represents an entry in the [org.thoughtcrime.securesms.database.ChatFolderTables].
|
||||
*/
|
||||
@Parcelize
|
||||
data class ChatFolderRecord(
|
||||
val id: Long = -1,
|
||||
val name: String = "",
|
||||
val position: Int = -1,
|
||||
val includedChats: List<Long> = emptyList(),
|
||||
val excludedChats: List<Long> = emptyList(),
|
||||
@IgnoredOnParcel
|
||||
val includedRecipients: Set<Recipient> = emptySet(),
|
||||
@IgnoredOnParcel
|
||||
val excludedRecipients: Set<Recipient> = emptySet(),
|
||||
val showUnread: Boolean = false,
|
||||
val showMutedChats: Boolean = true,
|
||||
|
@ -20,7 +26,7 @@ data class ChatFolderRecord(
|
|||
val isMuted: Boolean = false,
|
||||
val folderType: FolderType = FolderType.CUSTOM,
|
||||
val unreadCount: Int = 0
|
||||
) {
|
||||
) : Parcelable {
|
||||
enum class FolderType(val value: Int) {
|
||||
/** Folder containing all chats */
|
||||
ALL(0),
|
||||
|
|
|
@ -135,7 +135,7 @@ fun FoldersScreen(
|
|||
val elevation = if (isDragging) 1.dp else 0.dp
|
||||
val isAllChats = folder.folderType == ChatFolderRecord.FolderType.ALL
|
||||
FolderRow(
|
||||
icon = R.drawable.ic_chat_folder_24,
|
||||
icon = R.drawable.symbol_folder_24,
|
||||
title = if (isAllChats) stringResource(R.string.ChatFoldersFragment__all_chats) else folder.name,
|
||||
subtitle = getFolderDescription(folder),
|
||||
onClick = if (!isAllChats) {
|
||||
|
|
|
@ -0,0 +1,177 @@
|
|||
package org.thoughtcrime.securesms.conversationlist
|
||||
|
||||
import android.widget.Toast
|
||||
import androidx.compose.foundation.Image
|
||||
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.defaultMinSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
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.shape.RoundedCornerShape
|
||||
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.ColorFilter
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.res.dimensionResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.res.vectorResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.core.os.bundleOf
|
||||
import org.signal.core.ui.BottomSheets
|
||||
import org.signal.core.ui.Previews
|
||||
import org.signal.core.ui.SignalPreview
|
||||
import org.signal.core.util.getParcelableArrayListCompat
|
||||
import org.thoughtcrime.securesms.R
|
||||
import org.thoughtcrime.securesms.components.settings.app.AppSettingsActivity
|
||||
import org.thoughtcrime.securesms.components.settings.app.chats.folders.ChatFolderRecord
|
||||
import org.thoughtcrime.securesms.compose.ComposeBottomSheetDialogFragment
|
||||
import org.thoughtcrime.securesms.util.viewModel
|
||||
|
||||
/**
|
||||
* Bottom sheet shown when choosing to add a chat to a folder
|
||||
*/
|
||||
class AddToFolderBottomSheet private constructor() : ComposeBottomSheetDialogFragment() {
|
||||
|
||||
override val peekHeightPercentage: Float = 1f
|
||||
|
||||
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"
|
||||
|
||||
@JvmStatic
|
||||
fun showChatFolderSheet(folders: List<ChatFolderRecord>, threadId: Long): ComposeBottomSheetDialogFragment {
|
||||
return AddToFolderBottomSheet().apply {
|
||||
arguments = bundleOf(
|
||||
ARG_FOLDERS to folders,
|
||||
ARG_THREAD_ID to threadId
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@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)
|
||||
|
||||
AddToChatFolderSheetContent(
|
||||
folders = remember { folders ?: emptyList() },
|
||||
onClick = { folder ->
|
||||
if (threadId != null) {
|
||||
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))
|
||||
dismissAllowingStateLoss()
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun AddToChatFolderSheetContent(
|
||||
folders: List<ChatFolderRecord>,
|
||||
onClick: (ChatFolderRecord) -> Unit = {},
|
||||
onCreate: () -> Unit = {}
|
||||
) {
|
||||
Column(
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
BottomSheets.Handle()
|
||||
|
||||
Text(
|
||||
text = stringResource(R.string.AddToFolderBottomSheet_choose_a_folder),
|
||||
style = MaterialTheme.typography.titleLarge,
|
||||
color = MaterialTheme.colorScheme.onSurface,
|
||||
textAlign = TextAlign.Center,
|
||||
modifier = Modifier.padding(top = 30.dp)
|
||||
)
|
||||
|
||||
LazyColumn(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(start = 24.dp, end = 24.dp, top = 36.dp, bottom = 60.dp)
|
||||
.background(color = MaterialTheme.colorScheme.surface, shape = RoundedCornerShape(18.dp))
|
||||
) {
|
||||
items(folders) { folder ->
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier
|
||||
.clickable(onClick = { onClick(folder) })
|
||||
.padding(start = 24.dp)
|
||||
.fillMaxWidth()
|
||||
.defaultMinSize(minHeight = dimensionResource(id = R.dimen.chat_folder_row_height))
|
||||
) {
|
||||
Image(
|
||||
colorFilter = ColorFilter.tint(MaterialTheme.colorScheme.onSurface),
|
||||
imageVector = ImageVector.vectorResource(id = R.drawable.symbol_folder_24),
|
||||
contentDescription = null,
|
||||
modifier = Modifier
|
||||
.size(40.dp)
|
||||
.background(color = MaterialTheme.colorScheme.surfaceVariant, shape = CircleShape)
|
||||
.padding(8.dp)
|
||||
)
|
||||
|
||||
Text(
|
||||
text = folder.name,
|
||||
style = MaterialTheme.typography.bodyLarge,
|
||||
modifier = Modifier.padding(start = 16.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
item {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier
|
||||
.clickable(onClick = onCreate)
|
||||
.padding(start = 24.dp)
|
||||
.fillMaxWidth()
|
||||
.defaultMinSize(minHeight = dimensionResource(id = R.dimen.chat_folder_row_height))
|
||||
) {
|
||||
Image(
|
||||
colorFilter = ColorFilter.tint(MaterialTheme.colorScheme.onSurface),
|
||||
imageVector = ImageVector.vectorResource(id = R.drawable.symbol_plus_24),
|
||||
contentDescription = null,
|
||||
modifier = Modifier
|
||||
.size(40.dp)
|
||||
.background(color = MaterialTheme.colorScheme.surfaceVariant, shape = CircleShape)
|
||||
.padding(8.dp)
|
||||
)
|
||||
|
||||
Text(
|
||||
text = stringResource(id = R.string.ChatFoldersFragment__create_a_folder),
|
||||
style = MaterialTheme.typography.bodyLarge,
|
||||
modifier = Modifier.padding(start = 16.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SignalPreview
|
||||
@Composable
|
||||
private fun AddToChatFolderSheetContentPreview() {
|
||||
Previews.BottomSheetPreview {
|
||||
AddToChatFolderSheetContent(
|
||||
folders = listOf(ChatFolderRecord(name = "Friends"), ChatFolderRecord(name = "Work"))
|
||||
)
|
||||
}
|
||||
}
|
|
@ -33,7 +33,7 @@ class ChatFolderAdapter(val callbacks: Callbacks) : MappingAdapter() {
|
|||
val folder = model.chatFolder
|
||||
name.text = getName(itemView.context, folder)
|
||||
unreadCount.visible = folder.unreadCount > 0
|
||||
unreadCount.text = folder.unreadCount.toString()
|
||||
unreadCount.text = if (folder.unreadCount > 99) itemView.context.getString(R.string.ChatFolderAdapter__99p) else folder.unreadCount.toString()
|
||||
itemView.setOnClickListener {
|
||||
callbacks.onChatFolderClicked(model.chatFolder)
|
||||
}
|
||||
|
|
|
@ -166,6 +166,7 @@ import org.thoughtcrime.securesms.stories.tabs.ConversationListTab;
|
|||
import org.thoughtcrime.securesms.stories.tabs.ConversationListTabsViewModel;
|
||||
import org.thoughtcrime.securesms.util.AppForegroundObserver;
|
||||
import org.thoughtcrime.securesms.util.AppStartup;
|
||||
import org.thoughtcrime.securesms.util.BottomSheetUtil;
|
||||
import org.thoughtcrime.securesms.util.CachedInflater;
|
||||
import org.thoughtcrime.securesms.util.ConversationUtil;
|
||||
import org.thoughtcrime.securesms.util.RemoteConfig;
|
||||
|
@ -1466,6 +1467,14 @@ 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) {
|
||||
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()){
|
||||
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)));
|
||||
}
|
||||
|
||||
|
|
|
@ -297,6 +297,18 @@ class ConversationListViewModel(
|
|||
}
|
||||
}
|
||||
|
||||
fun removeChatFromFolder(threadId: Long) {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
SignalDatabase.chatFolders.removeFromFolder(currentFolder.id, threadId)
|
||||
}
|
||||
}
|
||||
|
||||
fun addToFolder(folderId: Long, threadId: Long) {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
SignalDatabase.chatFolders.addToFolder(folderId, threadId)
|
||||
}
|
||||
}
|
||||
|
||||
private data class ConversationListState(
|
||||
val chatFolders: List<ChatFolderMappingModel> = emptyList(),
|
||||
val currentFolder: ChatFolderRecord = ChatFolderRecord(),
|
||||
|
|
|
@ -99,12 +99,12 @@ class ChatFolderTables(context: Context?, databaseHelper: SignalDatabase?) : Dat
|
|||
$ID INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
$CHAT_FOLDER_ID INTEGER NOT NULL REFERENCES ${ChatFolderTable.TABLE_NAME} (${ChatFolderTable.ID}) ON DELETE CASCADE,
|
||||
$THREAD_ID INTEGER NOT NULL REFERENCES ${ThreadTable.TABLE_NAME} (${ThreadTable.ID}) ON DELETE CASCADE,
|
||||
$MEMBERSHIP_TYPE INTEGER DEFAULT 1
|
||||
$MEMBERSHIP_TYPE INTEGER DEFAULT 1,
|
||||
UNIQUE(${CHAT_FOLDER_ID}, ${THREAD_ID}) ON CONFLICT REPLACE
|
||||
)
|
||||
"""
|
||||
|
||||
val CREATE_INDEXES = arrayOf(
|
||||
"CREATE INDEX chat_folder_membership_chat_folder_id_index ON $TABLE_NAME ($CHAT_FOLDER_ID)",
|
||||
"CREATE INDEX chat_folder_membership_thread_id_index ON $TABLE_NAME ($THREAD_ID)",
|
||||
"CREATE INDEX chat_folder_membership_membership_type_index ON $TABLE_NAME ($MEMBERSHIP_TYPE)"
|
||||
)
|
||||
|
@ -347,6 +347,40 @@ class ChatFolderTables(context: Context?, databaseHelper: SignalDatabase?) : Dat
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a thread from a chat folder
|
||||
*/
|
||||
fun removeFromFolder(folderId: Long, threadId: 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.EXCLUDED.value
|
||||
)
|
||||
.run(SQLiteDatabase.CONFLICT_REPLACE)
|
||||
|
||||
AppDependencies.databaseObserver.notifyChatFolderObservers()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a thread to a chat folder
|
||||
*/
|
||||
fun addToFolder(folderId: Long, threadId: 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)
|
||||
|
||||
AppDependencies.databaseObserver.notifyChatFolderObservers()
|
||||
}
|
||||
}
|
||||
|
||||
private fun Collection<Long>.toContentValues(chatFolderId: Long, membershipType: MembershipType): List<ContentValues> {
|
||||
return map {
|
||||
contentValuesOf(
|
||||
|
|
|
@ -110,6 +110,7 @@ import org.thoughtcrime.securesms.database.helpers.migration.V250_ClearUploadTim
|
|||
import org.thoughtcrime.securesms.database.helpers.migration.V251_ArchiveTransferStateIndex
|
||||
import org.thoughtcrime.securesms.database.helpers.migration.V252_AttachmentOffloadRestoredAtColumn
|
||||
import org.thoughtcrime.securesms.database.helpers.migration.V253_CreateChatFolderTables
|
||||
import org.thoughtcrime.securesms.database.helpers.migration.V254_AddChatFolderConstraint
|
||||
|
||||
/**
|
||||
* Contains all of the database migrations for [SignalDatabase]. Broken into a separate file for cleanliness.
|
||||
|
@ -222,10 +223,11 @@ object SignalDatabaseMigrations {
|
|||
250 to V250_ClearUploadTimestampV2,
|
||||
251 to V251_ArchiveTransferStateIndex,
|
||||
252 to V252_AttachmentOffloadRestoredAtColumn,
|
||||
253 to V253_CreateChatFolderTables
|
||||
253 to V253_CreateChatFolderTables,
|
||||
254 to V254_AddChatFolderConstraint
|
||||
)
|
||||
|
||||
const val DATABASE_VERSION = 253
|
||||
const val DATABASE_VERSION = 254
|
||||
|
||||
@JvmStatic
|
||||
fun migrate(context: Application, db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
package org.thoughtcrime.securesms.database.helpers.migration
|
||||
|
||||
import android.app.Application
|
||||
import net.zetetic.database.sqlcipher.SQLiteDatabase
|
||||
|
||||
/**
|
||||
* Adds a unique constraint to chat folder membership
|
||||
*/
|
||||
@Suppress("ClassName")
|
||||
object V254_AddChatFolderConstraint : SignalDatabaseMigration {
|
||||
override fun migrate(context: Application, db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
|
||||
db.execSQL("DROP INDEX IF EXISTS chat_folder_membership_chat_folder_id_index")
|
||||
db.execSQL("DROP INDEX IF EXISTS chat_folder_membership_thread_id_index")
|
||||
db.execSQL("DROP INDEX IF EXISTS chat_folder_membership_membership_type_index")
|
||||
|
||||
db.execSQL(
|
||||
"""
|
||||
CREATE TABLE chat_folder_membership_tmp (
|
||||
_id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
chat_folder_id INTEGER NOT NULL REFERENCES chat_folder (_id) ON DELETE CASCADE,
|
||||
thread_id INTEGER NOT NULL REFERENCES thread (_id) ON DELETE CASCADE,
|
||||
membership_type INTEGER DEFAULT 1,
|
||||
UNIQUE(chat_folder_id, thread_id) ON CONFLICT REPLACE
|
||||
)
|
||||
"""
|
||||
)
|
||||
|
||||
db.execSQL(
|
||||
"""
|
||||
INSERT INTO chat_folder_membership_tmp
|
||||
SELECT
|
||||
_id,
|
||||
chat_folder_id,
|
||||
thread_id,
|
||||
membership_type
|
||||
FROM chat_folder_membership
|
||||
"""
|
||||
)
|
||||
|
||||
db.execSQL("DROP TABLE chat_folder_membership")
|
||||
db.execSQL("ALTER TABLE chat_folder_membership_tmp RENAME TO chat_folder_membership")
|
||||
|
||||
db.execSQL("CREATE INDEX chat_folder_membership_thread_id_index ON chat_folder_membership (thread_id)")
|
||||
db.execSQL("CREATE INDEX chat_folder_membership_membership_type_index ON chat_folder_membership (membership_type)")
|
||||
}
|
||||
}
|
13
app/src/main/res/drawable/symbol_folder_add.xml
Normal file
13
app/src/main/res/drawable/symbol_folder_add.xml
Normal file
|
@ -0,0 +1,13 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="M12.774,4.125L10.989,4.125C10.576,4.125 10.178,3.968 9.877,3.685L9.72,3.538C9.094,2.951 8.269,2.625 7.411,2.625H5C3.136,2.625 1.625,4.136 1.625,6V13.202V13.263V15.237V15.237C1.625,16.046 1.625,16.706 1.669,17.242C1.714,17.796 1.811,18.294 2.047,18.759C2.419,19.488 3.012,20.081 3.741,20.453C4.206,20.69 4.704,20.786 5.258,20.831C5.794,20.875 6.454,20.875 7.263,20.875H16.737C17.546,20.875 18.206,20.875 18.742,20.831C19.296,20.786 19.794,20.69 20.259,20.453C20.988,20.081 21.581,19.488 21.953,18.759C22.19,18.294 22.286,17.796 22.331,17.242C22.375,16.706 22.375,16.045 22.375,15.237L22.375,11.556C21.837,11.884 21.247,12.135 20.621,12.296C20.625,12.585 20.625,12.916 20.625,13.3V15.2C20.625,16.055 20.624,16.643 20.587,17.099C20.551,17.545 20.484,17.788 20.393,17.965C20.19,18.365 19.865,18.69 19.465,18.893C19.288,18.984 19.045,19.051 18.599,19.087C18.143,19.124 17.555,19.125 16.7,19.125H7.3C6.445,19.125 5.857,19.124 5.401,19.087C4.955,19.051 4.712,18.984 4.535,18.893C4.135,18.69 3.81,18.365 3.607,17.965C3.516,17.788 3.449,17.545 3.413,17.099C3.376,16.643 3.375,16.055 3.375,15.2V13.3C3.375,12.446 3.376,11.857 3.413,11.401C3.449,10.955 3.516,10.712 3.607,10.535C3.81,10.135 4.135,9.81 4.535,9.607C4.712,9.516 4.955,9.449 5.401,9.413C5.857,9.376 6.445,9.375 7.3,9.375H13.444C13.117,8.838 12.866,8.25 12.705,7.625H7.263C6.454,7.625 5.794,7.625 5.258,7.669C4.704,7.714 4.206,7.811 3.741,8.047C3.451,8.195 3.183,8.377 2.942,8.589L2.861,8.515C3.284,8.087 3.375,7.907 3.375,7.538V6C3.375,5.103 4.103,4.375 5,4.375H7.411C7.824,4.375 8.222,4.532 8.523,4.815L8.68,4.962C9.306,5.549 10.131,5.875 10.989,5.875L12.501,5.875C12.513,5.268 12.607,4.681 12.774,4.125Z"
|
||||
android:fillColor="#000000"
|
||||
android:fillType="evenOdd"/>
|
||||
<path
|
||||
android:pathData="M19,11C18.314,11 17.67,10.87 17.068,10.612C16.466,10.353 15.935,9.994 15.476,9.534C15.016,9.068 14.654,8.534 14.388,7.932C14.129,7.33 14,6.686 14,6C14,5.314 14.129,4.67 14.388,4.068C14.654,3.466 15.016,2.935 15.476,2.476C15.935,2.01 16.466,1.647 17.068,1.388C17.67,1.129 18.314,1 19,1C19.686,1 20.33,1.129 20.932,1.388C21.534,1.647 22.065,2.006 22.524,2.466C22.984,2.926 23.343,3.46 23.602,4.068C23.867,4.67 24,5.314 24,6C24,6.68 23.867,7.324 23.602,7.932C23.343,8.534 22.981,9.065 22.515,9.524C22.055,9.984 21.521,10.346 20.913,10.612C20.311,10.87 19.673,11 19,11ZM19,9.165C19.201,9.165 19.359,9.104 19.476,8.981C19.599,8.858 19.66,8.699 19.66,8.505V6.66H21.505C21.699,6.66 21.858,6.602 21.981,6.485C22.104,6.362 22.165,6.201 22.165,6C22.165,5.799 22.104,5.641 21.981,5.524C21.858,5.401 21.699,5.34 21.505,5.34H19.66V3.495C19.66,3.301 19.599,3.142 19.476,3.019C19.359,2.896 19.201,2.835 19,2.835C18.799,2.835 18.638,2.896 18.515,3.019C18.398,3.142 18.34,3.301 18.34,3.495V5.34H16.495C16.301,5.34 16.142,5.401 16.019,5.524C15.896,5.641 15.835,5.799 15.835,6C15.835,6.201 15.896,6.362 16.019,6.485C16.142,6.602 16.301,6.66 16.495,6.66H18.34V8.505C18.34,8.699 18.398,8.858 18.515,8.981C18.638,9.104 18.799,9.165 19,9.165Z"
|
||||
android:fillColor="#000000"/>
|
||||
</vector>
|
13
app/src/main/res/drawable/symbol_folder_minus.xml
Normal file
13
app/src/main/res/drawable/symbol_folder_minus.xml
Normal file
|
@ -0,0 +1,13 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="M12.774,4.125L10.989,4.125C10.576,4.125 10.178,3.968 9.877,3.685L9.72,3.538C9.094,2.951 8.269,2.625 7.411,2.625H5C3.136,2.625 1.625,4.136 1.625,6V13.202V13.263V15.237V15.237C1.625,16.046 1.625,16.706 1.669,17.242C1.714,17.796 1.811,18.294 2.047,18.759C2.419,19.488 3.012,20.081 3.741,20.453C4.206,20.69 4.704,20.786 5.258,20.831C5.794,20.875 6.454,20.875 7.263,20.875H16.737C17.546,20.875 18.206,20.875 18.742,20.831C19.296,20.786 19.794,20.69 20.259,20.453C20.988,20.081 21.581,19.488 21.953,18.759C22.19,18.294 22.286,17.796 22.331,17.242C22.375,16.706 22.375,16.045 22.375,15.237L22.375,11.556C21.837,11.884 21.247,12.135 20.621,12.296C20.625,12.585 20.625,12.916 20.625,13.3V15.2C20.625,16.055 20.624,16.643 20.587,17.099C20.551,17.545 20.484,17.788 20.393,17.965C20.19,18.365 19.865,18.69 19.465,18.893C19.288,18.984 19.045,19.051 18.599,19.087C18.143,19.124 17.555,19.125 16.7,19.125H7.3C6.445,19.125 5.857,19.124 5.401,19.087C4.955,19.051 4.712,18.984 4.535,18.893C4.135,18.69 3.81,18.365 3.607,17.965C3.516,17.788 3.449,17.545 3.413,17.099C3.376,16.643 3.375,16.055 3.375,15.2V13.3C3.375,12.446 3.376,11.857 3.413,11.401C3.449,10.955 3.516,10.712 3.607,10.535C3.81,10.135 4.135,9.81 4.535,9.607C4.712,9.516 4.955,9.449 5.401,9.413C5.857,9.376 6.445,9.375 7.3,9.375H13.444C13.117,8.838 12.866,8.25 12.705,7.625H7.263C6.454,7.625 5.794,7.625 5.258,7.669C4.704,7.714 4.206,7.811 3.741,8.047C3.451,8.195 3.183,8.377 2.942,8.589L2.861,8.515C3.284,8.087 3.375,7.907 3.375,7.538V6C3.375,5.103 4.103,4.375 5,4.375H7.411C7.824,4.375 8.222,4.532 8.523,4.815L8.68,4.962C9.306,5.549 10.131,5.875 10.989,5.875L12.501,5.875C12.513,5.268 12.607,4.681 12.774,4.125Z"
|
||||
android:fillColor="#000000"
|
||||
android:fillType="evenOdd"/>
|
||||
<path
|
||||
android:pathData="M19,11C18.314,11 17.67,10.871 17.068,10.612C16.466,10.353 15.935,9.994 15.476,9.534C15.016,9.068 14.654,8.534 14.388,7.932C14.129,7.33 14,6.686 14,6C14,5.314 14.129,4.67 14.388,4.068C14.654,3.466 15.016,2.935 15.476,2.476C15.935,2.01 16.466,1.647 17.068,1.388C17.67,1.129 18.314,1 19,1C19.686,1 20.33,1.129 20.932,1.388C21.534,1.647 22.065,2.006 22.524,2.466C22.984,2.926 23.343,3.46 23.602,4.068C23.867,4.67 24,5.314 24,6C24,6.68 23.867,7.324 23.602,7.932C23.343,8.534 22.981,9.065 22.515,9.524C22.055,9.984 21.521,10.346 20.913,10.612C20.311,10.871 19.673,11 19,11ZM16.485,6.66H21.495C21.676,6.66 21.832,6.595 21.961,6.466C22.097,6.33 22.165,6.175 22.165,6C22.165,5.825 22.097,5.673 21.961,5.544C21.832,5.408 21.676,5.34 21.495,5.34H16.485C16.304,5.34 16.149,5.408 16.019,5.544C15.89,5.673 15.825,5.825 15.825,6C15.825,6.175 15.89,6.33 16.019,6.466C16.149,6.595 16.304,6.66 16.485,6.66Z"
|
||||
android:fillColor="#000000"/>
|
||||
</vector>
|
|
@ -740,6 +740,15 @@
|
|||
<item quantity="one">%d selected</item>
|
||||
<item quantity="other">%d selected</item>
|
||||
</plurals>
|
||||
<!-- Context menu option to add a chat to a folder -->
|
||||
<string name="ConversationListFragment_add_to_folder">Add to folder</string>
|
||||
<!-- Context menu option to remove a chat from a folder -->
|
||||
<string name="ConversationListFragment_remove_from_folder">Remove from folder</string>
|
||||
|
||||
<!-- Bottom sheet title when choosing a folder to add a chat to -->
|
||||
<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>
|
||||
|
||||
<!-- Show in conversation list overflow menu to open selection bottom sheet -->
|
||||
<string name="ConversationListFragment__notification_profile">Notification profile</string>
|
||||
|
@ -5117,6 +5126,8 @@
|
|||
<item quantity="one">%1$d chat excluded</item>
|
||||
<item quantity="other">%1$d chats excluded</item>
|
||||
</plurals>
|
||||
<!-- Badge shown in chat folder tab when unread count is greater than 99 -->
|
||||
<string name="ChatFolderAdapter__99p">99+</string>
|
||||
|
||||
<!-- CreateFoldersFragment -->
|
||||
<!-- Title of the screen when creating a folder, displayed in the toolbar -->
|
||||
|
|
Loading…
Add table
Reference in a new issue