diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/chats/folders/ChatFoldersEducationSheet.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/chats/folders/ChatFoldersEducationSheet.kt new file mode 100644 index 0000000000..0525e35da7 --- /dev/null +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/chats/folders/ChatFoldersEducationSheet.kt @@ -0,0 +1,115 @@ +package org.thoughtcrime.securesms.components.settings.app.chats.folders + +import androidx.compose.foundation.Image +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.material3.Icon +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.painter.Painter +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.dp +import org.signal.core.ui.BottomSheets +import org.signal.core.ui.Buttons +import org.signal.core.ui.Previews +import org.signal.core.ui.SignalPreview +import org.thoughtcrime.securesms.R +import org.thoughtcrime.securesms.compose.ComposeBottomSheetDialogFragment + +/** + * Education sheet shown when clicking on chat folders for the first time + */ +class ChatFoldersEducationSheet : ComposeBottomSheetDialogFragment() { + + override val peekHeightPercentage: Float = 0.8f + + @Composable + override fun SheetContent() { + FolderEducationSheet(this::dismissAllowingStateLoss) + } +} + +@Composable +private fun FolderEducationSheet(onClick: () -> Unit) { + return Column( + modifier = Modifier.fillMaxWidth().padding(horizontal = 36.dp) + ) { + BottomSheets.Handle(modifier = Modifier.align(Alignment.CenterHorizontally)) + + Image( + painter = painterResource(R.drawable.image_folder_sheet), + contentDescription = null, + modifier = Modifier.padding(top = 36.dp).align(Alignment.CenterHorizontally) + ) + + Text( + text = stringResource(R.string.ChatsSettingsFragment__chat_folders), + style = MaterialTheme.typography.titleLarge, + textAlign = TextAlign.Center, + modifier = Modifier.padding(top = 18.dp, bottom = 12.dp).align(Alignment.CenterHorizontally), + color = MaterialTheme.colorScheme.onSurface + ) + Text( + text = stringResource(R.string.ChatFoldersFragment__organize_your_chats), + textAlign = TextAlign.Center, + style = MaterialTheme.typography.bodyLarge, + modifier = Modifier.padding(bottom = 28.dp), + color = MaterialTheme.colorScheme.onSurfaceVariant + ) + + EducationRow( + text = stringResource(R.string.ChatFoldersEducationSheet__create_folders_for_family), + painter = painterResource(R.drawable.symbol_folder_24) + ) + + EducationRow( + text = stringResource(R.string.ChatFoldersEducationSheet__choose_to_show_unread), + painter = painterResource(R.drawable.symbol_chat_badge_24) + ) + + EducationRow( + text = stringResource(R.string.ChatFoldersEducationSheet__easily_add_suggested), + painter = painterResource(R.drawable.symbol_plus_circle_24) + ) + + Buttons.LargeTonal( + onClick = onClick, + modifier = Modifier.defaultMinSize(minWidth = 220.dp).padding(top = 52.dp, bottom = 30.dp).align(Alignment.CenterHorizontally) + ) { + Text(stringResource(id = R.string.ChatFoldersEducationSheet__continue)) + } + } +} + +@Composable +fun EducationRow(text: String, painter: Painter) { + Row(modifier = Modifier.padding(start = 12.dp, end = 12.dp, bottom = 20.dp)) { + Icon( + painter = painter, + contentDescription = null, + tint = MaterialTheme.colorScheme.onSurfaceVariant + ) + Text( + text = text, + style = MaterialTheme.typography.bodyLarge, + color = MaterialTheme.colorScheme.onSurfaceVariant, + modifier = Modifier.padding(start = 16.dp) + ) + } +} + +@SignalPreview +@Composable +fun ChatFoldersEducationSheetPreview() { + Previews.BottomSheetPreview { + FolderEducationSheet(onClick = {}) + } +} diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/chats/folders/ChatFoldersFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/chats/folders/ChatFoldersFragment.kt index edfb60649b..b683a2b8a9 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/chats/folders/ChatFoldersFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/chats/folders/ChatFoldersFragment.kt @@ -21,6 +21,7 @@ import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text 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 @@ -55,6 +56,7 @@ import org.signal.core.ui.copied.androidx.compose.rememberDragDropState import org.signal.core.util.toInt import org.thoughtcrime.securesms.R import org.thoughtcrime.securesms.compose.ComposeFragment +import org.thoughtcrime.securesms.keyvalue.SignalStore import org.thoughtcrime.securesms.util.ViewUtil import org.thoughtcrime.securesms.util.navigation.safeNavigate @@ -79,6 +81,7 @@ class ChatFoldersFragment : ComposeFragment() { ) { contentPadding: PaddingValues -> FoldersScreen( state = state, + navController = navController, modifier = Modifier.padding(contentPadding), onFolderClicked = { navController.safeNavigate(ChatFoldersFragmentDirections.actionChatFoldersFragmentToCreateFoldersFragment(it.id)) @@ -106,6 +109,7 @@ class ChatFoldersFragment : ComposeFragment() { @Composable fun FoldersScreen( state: ChatFoldersSettingsState, + navController: NavController? = null, modifier: Modifier = Modifier, onFolderClicked: (ChatFolderRecord) -> Unit = {}, onAdd: (ChatFolderRecord) -> Unit = {}, @@ -122,6 +126,13 @@ fun FoldersScreen( onPositionUpdated(fromIndex, toIndex) } + LaunchedEffect(Unit) { + if (!SignalStore.uiHints.hasSeenChatFoldersEducationSheet) { + SignalStore.uiHints.hasSeenChatFoldersEducationSheet = true + navController?.safeNavigate(R.id.action_chatFoldersFragment_to_chatFoldersEducationSheet) + } + } + if (state.showDeleteDialog) { Dialogs.SimpleAlertDialog( title = "", diff --git a/app/src/main/java/org/thoughtcrime/securesms/contacts/paged/ContactSearchPagedDataSource.kt b/app/src/main/java/org/thoughtcrime/securesms/contacts/paged/ContactSearchPagedDataSource.kt index 8deb266076..4983cc8cda 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/contacts/paged/ContactSearchPagedDataSource.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/contacts/paged/ContactSearchPagedDataSource.kt @@ -351,7 +351,6 @@ class ContactSearchPagedDataSource( } } - // TODO [michelle]: Replace hardcoding chat types after building db private fun getChatTypesData(section: ContactSearchConfiguration.Section.ChatTypes): List { val data = mutableListOf() diff --git a/app/src/main/java/org/thoughtcrime/securesms/keyvalue/UiHintValues.java b/app/src/main/java/org/thoughtcrime/securesms/keyvalue/UiHintValues.java index 4ddc5a3db7..2a816a65c9 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/keyvalue/UiHintValues.java +++ b/app/src/main/java/org/thoughtcrime/securesms/keyvalue/UiHintValues.java @@ -28,6 +28,7 @@ public class UiHintValues extends SignalStoreValues { private static final String HAS_SEEN_DELETE_SYNC_EDUCATION_SHEET = "uihints.has_seen_delete_sync_education_sheet"; private static final String LAST_SUPPORT_VERSION_SEEN = "uihints.last_support_version_seen"; private static final String HAS_EVER_ENABLED_REMOTE_BACKUPS = "uihints.has_ever_enabled_remote_backups"; + private static final String HAS_SEEN_CHAT_FOLDERS_EDUCATION_SHEET = "uihints.has_seen_chat_folders_education_sheet"; UiHintValues(@NonNull KeyValueStore store) { super(store); @@ -209,4 +210,12 @@ public class UiHintValues extends SignalStoreValues { public boolean getHasEverEnabledRemoteBackups() { return getBoolean(HAS_EVER_ENABLED_REMOTE_BACKUPS, false); } + + public void setHasSeenChatFoldersEducationSheet(boolean seen) { + putBoolean(HAS_SEEN_CHAT_FOLDERS_EDUCATION_SHEET, seen); + } + + public boolean getHasSeenChatFoldersEducationSheet() { + return getBoolean(HAS_SEEN_CHAT_FOLDERS_EDUCATION_SHEET, false); + } } diff --git a/app/src/main/res/drawable/image_folder_sheet.xml b/app/src/main/res/drawable/image_folder_sheet.xml new file mode 100644 index 0000000000..8fd2f6b21b --- /dev/null +++ b/app/src/main/res/drawable/image_folder_sheet.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + diff --git a/app/src/main/res/navigation/app_settings_with_change_number.xml b/app/src/main/res/navigation/app_settings_with_change_number.xml index fb25f3f582..196fe72e27 100644 --- a/app/src/main/res/navigation/app_settings_with_change_number.xml +++ b/app/src/main/res/navigation/app_settings_with_change_number.xml @@ -384,8 +384,15 @@ app:exitAnim="@anim/fragment_open_exit" app:popEnterAnim="@anim/fragment_close_enter" app:popExitAnim="@anim/fragment_close_exit" /> + + + %1$d folders + + + Create folders for family, friends, work and more + + Choose to show only unread chats + + Easily add suggested folders + + Continue + Organize your chats into folders and quickly switch between them on your chat list.