Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: move to folder [WPB-14627] #3787

Merged
merged 20 commits into from
Jan 14, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions app/src/main/kotlin/com/wire/android/di/ViewModelScoped.kt
Original file line number Diff line number Diff line change
Expand Up @@ -87,3 +87,7 @@ interface ScopedArgs {
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.SOURCE)
annotation class ViewModelScopedPreview

interface AssistedViewModelFactory<VM : ViewModel, R : ScopedArgs> {
fun create(args: R): VM
}
Original file line number Diff line number Diff line change
Expand Up @@ -342,4 +342,9 @@ class ConversationModule {
@Provides
fun provideObserveUserFoldersUseCase(conversationScope: ConversationScope) =
conversationScope.observeUserFolders

@ViewModelScoped
@Provides
fun provideMoveConversationToFolderUseCase(conversationScope: ConversationScope) =
conversationScope.moveConversationToFolder
}
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,8 @@ fun ConversationDetailsWithEvents.toConversationItem(
proteusVerificationStatus = conversationDetails.conversation.proteusVerificationStatus,
hasNewActivitiesToShow = hasNewActivitiesToShow,
searchQuery = searchQuery,
isFavorite = conversationDetails.isFavorite
isFavorite = conversationDetails.isFavorite,
folder = conversationDetails.folder
)
}

Expand Down Expand Up @@ -103,7 +104,8 @@ fun ConversationDetailsWithEvents.toConversationItem(
proteusVerificationStatus = conversationDetails.conversation.proteusVerificationStatus,
hasNewActivitiesToShow = hasNewActivitiesToShow,
searchQuery = searchQuery,
isFavorite = conversationDetails.isFavorite
isFavorite = conversationDetails.isFavorite,
folder = conversationDetails.folder
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,13 @@ fun SelectableMenuBottomSheetItem(
.wrapContentHeight()
.wrapContentWidth()
.defaultMinSize(minHeight = dimensions().spacing48x)
.let { if (isSelectedItem(state)) it.background(MaterialTheme.wireColorScheme.secondaryButtonSelected) else it }
.background(
if (isSelectedItem(state)) {
MaterialTheme.wireColorScheme.secondaryButtonSelected
} else {
MaterialTheme.wireColorScheme.surface
}
)
.clickable(onItemClick)
.semantics { if (isSelectedItem(state)) selected = true }
.padding(vertical = dimensions().spacing12x, horizontal = dimensions().spacing16x)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,12 @@ import com.wire.android.R
import com.wire.android.model.ImageAsset.UserAvatarAsset
import com.wire.android.ui.common.dialogs.BlockUserDialogState
import com.wire.android.ui.common.dialogs.UnblockUserDialogState
import com.wire.android.ui.home.conversations.folder.ConversationFoldersNavArgs
import com.wire.android.ui.home.conversationslist.model.BlockingState
import com.wire.android.ui.home.conversationslist.model.DialogState
import com.wire.android.ui.home.conversationslist.model.GroupDialogState
import com.wire.kalium.logic.data.conversation.Conversation
import com.wire.kalium.logic.data.conversation.ConversationFolder
import com.wire.kalium.logic.data.conversation.MutedConversationStatus
import com.wire.kalium.logic.data.id.ConversationId
import com.wire.kalium.logic.data.user.UserId
Expand All @@ -38,7 +40,7 @@ fun ConversationSheetContent(
conversationSheetState: ConversationSheetState,
onMutingConversationStatusChange: () -> Unit,
changeFavoriteState: (GroupDialogState, addToFavorite: Boolean) -> Unit,
moveConversationToFolder: () -> Unit,
moveConversationToFolder: ((ConversationFoldersNavArgs) -> Unit)?,
updateConversationArchiveStatus: (DialogState) -> Unit,
clearConversationContent: (DialogState) -> Unit,
blockUser: (BlockUserDialogState) -> Unit,
Expand All @@ -56,8 +58,7 @@ fun ConversationSheetContent(
ConversationMainSheetContent(
conversationSheetContent = conversationSheetState.conversationSheetContent!!,
changeFavoriteState = changeFavoriteState,
// TODO(profile): enable when implemented
// moveConversationToFolder = moveConversationToFolder,
moveConversationToFolder = moveConversationToFolder,
updateConversationArchiveStatus = updateConversationArchiveStatus,
clearConversationContent = clearConversationContent,
blockUserClick = blockUser,
Expand Down Expand Up @@ -128,6 +129,7 @@ data class ConversationSheetContent(
val proteusVerificationStatus: Conversation.VerificationStatus,
val isUnderLegalHold: Boolean,
val isFavorite: Boolean?,
val folder: ConversationFolder?,
val isDeletingConversationLocallyRunning: Boolean
) {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ fun rememberConversationSheetState(
proteusVerificationStatus = Conversation.VerificationStatus.VERIFIED,
isUnderLegalHold = showLegalHoldIndicator,
isFavorite = isFavorite,
folder = folder,
isDeletingConversationLocallyRunning = isConversationDeletionLocallyRunning
)
}
Expand Down Expand Up @@ -108,6 +109,7 @@ fun rememberConversationSheetState(
proteusVerificationStatus = Conversation.VerificationStatus.VERIFIED,
isUnderLegalHold = showLegalHoldIndicator,
isFavorite = isFavorite,
folder = folder,
isDeletingConversationLocallyRunning = false
)
}
Expand All @@ -130,6 +132,7 @@ fun rememberConversationSheetState(
proteusVerificationStatus = Conversation.VerificationStatus.VERIFIED,
isUnderLegalHold = showLegalHoldIndicator,
isFavorite = null,
folder = null,
isDeletingConversationLocallyRunning = false
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ import com.wire.android.ui.common.conversationColor
import com.wire.android.ui.common.dialogs.BlockUserDialogState
import com.wire.android.ui.common.dialogs.UnblockUserDialogState
import com.wire.android.ui.common.dimensions
import com.wire.android.ui.home.conversations.folder.ConversationFoldersNavArgs
import com.wire.android.ui.home.conversationslist.common.GroupConversationAvatar
import com.wire.android.ui.home.conversationslist.model.BlockingState
import com.wire.android.ui.home.conversationslist.model.DialogState
Expand All @@ -59,8 +60,7 @@ import com.wire.kalium.logic.data.user.ConnectionState
internal fun ConversationMainSheetContent(
conversationSheetContent: ConversationSheetContent,
changeFavoriteState: (dialogState: GroupDialogState, addToFavorite: Boolean) -> Unit,
// TODO(profile): enable when implemented
// moveConversationToFolder: () -> Unit,
moveConversationToFolder: ((ConversationFoldersNavArgs) -> Unit)?,
updateConversationArchiveStatus: (DialogState) -> Unit,
clearConversationContent: (DialogState) -> Unit,
blockUserClick: (BlockUserDialogState) -> Unit,
Expand Down Expand Up @@ -142,19 +142,28 @@ internal fun ConversationMainSheetContent(
}
}
}
// TODO(profile): enable when implemented
// add {
// MenuBottomSheetItem(
// icon = {
// MenuItemIcon(
// id = R.drawable.ic_folder,
// contentDescription = stringResource(R.string.content_description_move_to_folder),
// )
// },
// title = stringResource(R.string.label_move_to_folder),
// onItemClick = moveConversationToFolder
// )
// }
if (moveConversationToFolder != null) {
add {
MenuBottomSheetItem(
leading = {
MenuItemIcon(
id = R.drawable.ic_folder,
contentDescription = null,
)
},
title = stringResource(R.string.label_move_to_folder),
onItemClick = {
moveConversationToFolder(
ConversationFoldersNavArgs(
conversationId = conversationSheetContent.conversationId,
conversationName = conversationSheetContent.title,
currentFolderId = conversationSheetContent.folder?.id
)
)
}
)
}
}
add {
MenuBottomSheetItem(
leading = {
Expand Down
22 changes: 18 additions & 4 deletions app/src/main/kotlin/com/wire/android/ui/home/HomeScreen.kt
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,6 @@ import com.ramcosta.composedestinations.result.NavResult
import com.ramcosta.composedestinations.result.ResultRecipient
import com.wire.android.R
import com.wire.android.appLogger
import com.wire.android.di.hiltViewModelScoped
import com.wire.android.navigation.HomeDestination
import com.wire.android.navigation.NavigationCommand
import com.wire.android.navigation.Navigator
Expand All @@ -79,13 +78,15 @@ import com.wire.android.ui.common.dimensions
import com.wire.android.ui.common.snackbar.LocalSnackbarHostState
import com.wire.android.ui.common.topappbar.search.SearchTopBar
import com.wire.android.ui.common.visbility.rememberVisibilityState
import com.wire.android.ui.destinations.ConversationFoldersScreenDestination
import com.wire.android.ui.destinations.ConversationScreenDestination
import com.wire.android.ui.destinations.NewConversationSearchPeopleScreenDestination
import com.wire.android.ui.destinations.OtherUserProfileScreenDestination
import com.wire.android.ui.destinations.SelfUserProfileScreenDestination
import com.wire.android.ui.home.conversations.PermissionPermanentlyDeniedDialogState
import com.wire.android.ui.home.conversations.details.GroupConversationActionType
import com.wire.android.ui.home.conversations.details.GroupConversationDetailsNavBackArgs
import com.wire.android.ui.home.conversations.folder.ConversationFoldersNavBackArgs
import com.wire.android.ui.home.conversations.folder.ConversationFoldersStateArgs
import com.wire.android.ui.home.conversations.folder.ConversationFoldersVM
import com.wire.android.ui.home.conversations.folder.ConversationFoldersVMImpl
Expand All @@ -108,16 +109,19 @@ fun HomeScreen(
navigator: Navigator,
groupDetailsScreenResultRecipient: ResultRecipient<ConversationScreenDestination, GroupConversationDetailsNavBackArgs>,
otherUserProfileScreenResultRecipient: ResultRecipient<OtherUserProfileScreenDestination, String>,
conversationFoldersScreenResultRecipient:
ResultRecipient<ConversationFoldersScreenDestination, ConversationFoldersNavBackArgs>,
homeViewModel: HomeViewModel = hiltViewModel(),
appSyncViewModel: AppSyncViewModel = hiltViewModel(),
homeDrawerViewModel: HomeDrawerViewModel = hiltViewModel(),
analyticsUsageViewModel: AnalyticsUsageViewModel = hiltViewModel(),
foldersViewModel: ConversationFoldersVM =
hiltViewModelScoped<ConversationFoldersVMImpl, ConversationFoldersVM, ConversationFoldersStateArgs>(
ConversationFoldersStateArgs
hiltViewModel<ConversationFoldersVMImpl, ConversationFoldersVMImpl.Factory>(
creationCallback = { it.create(ConversationFoldersStateArgs(null)) }
)
) {
homeViewModel.checkRequirements { it.navigate(navigator::navigate) }
val context = LocalContext.current

val homeScreenState = rememberHomeScreenState(navigator)
val notificationsPermissionDeniedDialogState = rememberVisibilityState<PermissionPermanentlyDeniedDialogState>()
Expand All @@ -137,7 +141,6 @@ fun HomeScreen(
)

val lifecycleOwner = LocalLifecycleOwner.current
val context = LocalContext.current
val snackbarHostState = LocalSnackbarHostState.current
val coroutineScope = rememberCoroutineScope()

Expand Down Expand Up @@ -237,6 +240,17 @@ fun HomeScreen(
}
}

conversationFoldersScreenResultRecipient.onNavResult { result ->
when (result) {
NavResult.Canceled -> {}
is NavResult.Value -> {
coroutineScope.launch {
snackbarHostState.showSnackbar(result.value.message)
}
}
}
}

PermissionPermanentlyDeniedDialog(
dialogState = notificationsPermissionDeniedDialogState,
hideDialog = notificationsPermissionDeniedDialogState::dismiss
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ import com.wire.android.ui.common.topappbar.WireCenterAlignedTopAppBar
import com.wire.android.ui.common.topappbar.WireTopAppBarTitle
import com.wire.android.ui.common.visbility.rememberVisibilityState
import com.wire.android.ui.destinations.AddMembersSearchScreenDestination
import com.wire.android.ui.destinations.ConversationFoldersScreenDestination
import com.wire.android.ui.destinations.ConversationMediaScreenDestination
import com.wire.android.ui.destinations.EditConversationNameScreenDestination
import com.wire.android.ui.destinations.EditGuestAccessScreenDestination
Expand All @@ -111,6 +112,8 @@ import com.wire.android.ui.home.conversations.details.options.GroupConversationO
import com.wire.android.ui.home.conversations.details.participants.GroupConversationParticipants
import com.wire.android.ui.home.conversations.details.participants.GroupConversationParticipantsState
import com.wire.android.ui.home.conversations.details.participants.model.UIParticipant
import com.wire.android.ui.home.conversations.folder.ConversationFoldersNavArgs
import com.wire.android.ui.home.conversations.folder.ConversationFoldersNavBackArgs
import com.wire.android.ui.home.conversationslist.model.DialogState
import com.wire.android.ui.home.conversationslist.model.GroupDialogState
import com.wire.android.ui.legalhold.dialog.subject.LegalHoldSubjectConversationDialog
Expand Down Expand Up @@ -138,6 +141,8 @@ fun GroupConversationDetailsScreen(
navigator: Navigator,
resultNavigator: ResultBackNavigator<GroupConversationDetailsNavBackArgs>,
groupConversationDetailResultRecipient: ResultRecipient<EditConversationNameScreenDestination, Boolean>,
conversationFoldersScreenResultRecipient:
ResultRecipient<ConversationFoldersScreenDestination, ConversationFoldersNavBackArgs>,
viewModel: GroupConversationDetailsViewModel = hiltViewModel()
) {
val scope = rememberCoroutineScope()
Expand Down Expand Up @@ -246,8 +251,10 @@ fun GroupConversationDetailsScreen(
onConversationMediaClick = onConversationMediaClick,
isAbandonedOneOnOneConversation = viewModel.conversationSheetContent?.isAbandonedOneOnOneConversation(
viewModel.groupParticipantsState.data.allCount
) ?: false

) ?: false,
onMoveToFolder = {
navigator.navigate(NavigationCommand(ConversationFoldersScreenDestination(it)))
}
)

val tryAgainSnackBarMessage = stringResource(id = R.string.error_unknown_message)
Expand All @@ -270,6 +277,17 @@ fun GroupConversationDetailsScreen(
}
}
}

conversationFoldersScreenResultRecipient.onNavResult { result ->
when (result) {
NavResult.Canceled -> {}
is NavResult.Value -> {
scope.launch {
snackbarHostState.showSnackbar(result.value.message)
}
}
}
}
}

@OptIn(ExperimentalFoundationApi::class)
Expand All @@ -290,6 +308,7 @@ private fun GroupConversationDetailsContent(
isAbandonedOneOnOneConversation: Boolean,
onSearchConversationMessagesClick: () -> Unit,
onConversationMediaClick: () -> Unit,
onMoveToFolder: (ConversationFoldersNavArgs) -> Unit = {},
initialPageIndex: GroupConversationDetailsTabItem = GroupConversationDetailsTabItem.OPTIONS,
changeConversationFavoriteStateViewModel: ChangeConversationFavoriteVM =
hiltViewModelScoped<ChangeConversationFavoriteVMImpl, ChangeConversationFavoriteVM, ChangeConversationFavoriteStateArgs>(
Expand Down Expand Up @@ -473,7 +492,7 @@ private fun GroupConversationDetailsContent(
}
},
changeFavoriteState = changeConversationFavoriteStateViewModel::changeFavoriteState,
moveConversationToFolder = bottomSheetEventsHandler::onMoveConversationToFolder,
moveConversationToFolder = onMoveToFolder,
updateConversationArchiveStatus = {
// Only show the confirmation dialog if the conversation is not archived
if (!it.isArchived) {
Expand Down Expand Up @@ -611,6 +630,7 @@ fun PreviewGroupConversationDetails() {
isUnderLegalHold = false,
proteusVerificationStatus = Conversation.VerificationStatus.VERIFIED,
isFavorite = false,
folder = null,
isDeletingConversationLocallyRunning = false
),
bottomSheetEventsHandler = GroupConversationDetailsBottomSheetEventsHandler.PREVIEW,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ import com.wire.kalium.logic.feature.user.GetSelfUserUseCase
import com.wire.kalium.logic.feature.user.IsMLSEnabledUseCase
import com.wire.kalium.logic.functional.getOrNull
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
Expand Down Expand Up @@ -122,16 +123,17 @@ class GroupConversationDetailsViewModel @Inject constructor(
observeConversationDetails()
}

private suspend fun groupDetailsFlow(): Flow<ConversationDetails.Group> = observeConversationDetails(conversationId)
.filterIsInstance<ObserveConversationDetailsUseCase.Result.Success>()
.map { it.conversationDetails }
.filterIsInstance<ConversationDetails.Group>()
.distinctUntilChanged()
.flowOn(dispatcher.io())

private fun observeConversationDetails() {
viewModelScope.launch {
val groupDetailsFlow =
observeConversationDetails(conversationId)
.filterIsInstance<ObserveConversationDetailsUseCase.Result.Success>()
.map { it.conversationDetails }
.filterIsInstance<ConversationDetails.Group>()
.distinctUntilChanged()
.flowOn(dispatcher.io())
.shareIn(this, SharingStarted.WhileSubscribed(), 1)
val groupDetailsFlow = groupDetailsFlow()
.shareIn(this, SharingStarted.WhileSubscribed(), 1)

val selfTeam = getSelfTeam().getOrNull()
val selfUser = observerSelfUser().first()
Expand All @@ -141,7 +143,6 @@ class GroupConversationDetailsViewModel @Inject constructor(
groupDetailsFlow,
observeSelfDeletionTimerSettingsForConversation(conversationId, considerSelfUserSettings = false),
) { groupDetails, selfDeletionTimer ->

val isSelfInOwnerTeam = selfTeam?.id != null && selfTeam.id == groupDetails.conversation.teamId?.value
val isSelfExternalMember = selfUser.userType == UserType.EXTERNAL
val isSelfAnAdmin = groupDetails.selfRole == Conversation.Member.Role.Admin
Expand All @@ -163,6 +164,7 @@ class GroupConversationDetailsViewModel @Inject constructor(
proteusVerificationStatus = groupDetails.conversation.proteusVerificationStatus,
isUnderLegalHold = groupDetails.conversation.legalHoldStatus.showLegalHoldIndicator(),
isFavorite = groupDetails.isFavorite,
folder = groupDetails.folder,
isDeletingConversationLocallyRunning = false
)

Expand Down
Loading
Loading