Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
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
Original file line number Diff line number Diff line change
Expand Up @@ -43,23 +43,23 @@ class GroupInviteException(

if (second != null && third != null) {
val errorString =
if (isPromotion) R.string.adminPromotionFailedDescriptionMultiple else
if (isPromotion) if (isReinvite) R.string.failedResendPromotionMultiple else R.string.adminPromotionFailedDescriptionMultiple else
if (isReinvite) R.string.failedResendInviteMultiple else R.string.groupInviteFailedMultiple
return Phrase.from(context, errorString)
.put(NAME_KEY, first)
.put(COUNT_KEY, inviteeAccountIds.size - 1)
.put(GROUP_NAME_KEY, groupName)
.format()
} else if (second != null) {
val errorString = if (isPromotion) R.string.adminPromotionFailedDescriptionTwo else
val errorString = if (isPromotion) if (isReinvite) R.string.failedResendPromotionTwo else R.string.adminPromotionFailedDescriptionTwo else
if (isReinvite) R.string.failedResendInviteTwo else R.string.groupInviteFailedTwo
return Phrase.from(context, errorString)
.put(NAME_KEY, first)
.put(OTHER_NAME_KEY, second)
.put(GROUP_NAME_KEY, groupName)
.format()
} else {
val errorString = if (isPromotion) R.string.adminPromotionFailedDescription else
val errorString = if (isPromotion) if (isReinvite) R.string.failedResendPromotion else R.string.adminPromotionFailedDescription else
if (isReinvite) R.string.failedResendInvite else R.string.groupInviteFailedUser
return Phrase.from(context, errorString)
.put(NAME_KEY, first)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,10 @@ interface GroupManagerV2 {

fun getLeaveGroupConfirmationDialogData(groupId: AccountId, name: String): ConfirmDialogData?

fun getAdminLeaveGroupDialogData(groupId : AccountId, name : String) : ConfirmDialogData?

fun isCurrentUserLastAdmin(groupId : AccountId) : Boolean

data class ConfirmDialogData(
val title: String,
val message: CharSequence,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@ fun ConversationSettingsDialogs(
buttons.add(
DialogButtonData(
text = GetString(dialogsState.showSimpleDialog.negativeText),
color = if (dialogsState.showSimpleDialog.negativeStyleDanger) LocalColors.current.danger
else LocalColors.current.text,
qaTag = dialogsState.showSimpleDialog.negativeQaTag,
onClick = dialogsState.showSimpleDialog.onNegative
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import androidx.lifecycle.Lifecycle
import androidx.lifecycle.compose.LocalLifecycleOwner
import androidx.lifecycle.compose.dropUnlessResumed
import androidx.lifecycle.repeatOnLifecycle
import androidx.navigation.NavBackStackEntry
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.rememberNavController
import androidx.navigation.toRoute
Expand All @@ -31,10 +32,14 @@ import org.thoughtcrime.securesms.conversation.v2.settings.notification.Notifica
import org.thoughtcrime.securesms.groups.ManageGroupMembersViewModel
import org.thoughtcrime.securesms.groups.GroupMembersViewModel
import org.thoughtcrime.securesms.groups.InviteMembersViewModel
import org.thoughtcrime.securesms.groups.ManageGroupAdminsViewModel
import org.thoughtcrime.securesms.groups.PromoteMembersViewModel
import org.thoughtcrime.securesms.groups.compose.ManageGroupMembersScreen
import org.thoughtcrime.securesms.groups.compose.GroupMembersScreen
import org.thoughtcrime.securesms.groups.compose.InviteAccountIdScreen
import org.thoughtcrime.securesms.groups.compose.InviteContactsScreen
import org.thoughtcrime.securesms.groups.compose.ManageGroupAdminsScreen
import org.thoughtcrime.securesms.groups.compose.PromoteMembersScreen
import org.thoughtcrime.securesms.home.startconversation.newmessage.NewMessageViewModel
import org.thoughtcrime.securesms.home.startconversation.newmessage.State
import org.thoughtcrime.securesms.media.MediaOverviewScreen
Expand Down Expand Up @@ -71,6 +76,30 @@ sealed interface ConversationSettingsDestination: Parcelable {
val groupAddress: Address.Group get() = Address.Group(AccountId(address))
}

@Serializable
@Parcelize
data class RouteManageAdmins private constructor(
private val address: String,
val navigateToPromoteMembers: Boolean = false
) : ConversationSettingsDestination {
constructor(groupAddress: Address.Group, navigateToPromoteMembers: Boolean = false) : this(
groupAddress.address,
navigateToPromoteMembers
)

val groupAddress: Address.Group get() = Address.Group(AccountId(address))
}

@Serializable
@Parcelize
data class RoutePromoteMembers(
private val address: String
): ConversationSettingsDestination {
constructor(groupAddress: Address.Group): this(groupAddress.address)

val groupAddress: Address.Group get() = Address.Group(AccountId(address))
}

@Serializable
@Parcelize
data class RouteInviteToGroup private constructor(
Expand Down Expand Up @@ -213,6 +242,23 @@ fun ConversationSettingsNavHost(
)
}

// Manage group Admins
horizontalSlideComposable<RouteManageAdmins> { backStackEntry ->
val data: RouteManageAdmins = backStackEntry.toRoute()

val viewModel =
hiltViewModel<ManageGroupAdminsViewModel, ManageGroupAdminsViewModel.Factory> { factory ->
factory.create(data.groupAddress, navigator, data.navigateToPromoteMembers)
}

ManageGroupAdminsScreen(
viewModel = viewModel,
onBack = dropUnlessResumed {
handleBack()
},
)
}

// Invite Contacts to group
horizontalSlideComposable<RouteInviteToGroup> { backStackEntry ->
val data: RouteInviteToGroup = backStackEntry.toRoute()
Expand Down Expand Up @@ -335,6 +381,32 @@ fun ConversationSettingsNavHost(
)
}

// Promote Members to group Admin
horizontalSlideComposable<RoutePromoteMembers> { backStackEntry ->
val data: RoutePromoteMembers = backStackEntry.toRoute()

val viewModel =
hiltViewModel<PromoteMembersViewModel, PromoteMembersViewModel.Factory> { factory ->
factory.create(groupAddress = data.groupAddress)
}

val parentEntry = remember(backStackEntry) {
navController.previousBackStackEntry ?: error("RouteManageAdmin not in backstack")
}
val manageGroupAdminsViewModel: ManageGroupAdminsViewModel = hiltViewModel(parentEntry)

PromoteMembersScreen(
viewModel = viewModel,
onBack = dropUnlessResumed {
handleBack()
},
onPromoteClicked = { selectedMembers ->
manageGroupAdminsViewModel.onSendPromotionsClicked(selectedMembers)
handleBack()
}
)
}

// Disappearing Messages
horizontalSlideComposable<RouteDisappearingMessages> {
val viewModel: DisappearingMessagesViewModel =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import kotlinx.coroutines.withContext
import network.loki.messenger.R
import network.loki.messenger.libsession_util.PRIORITY_HIDDEN
import network.loki.messenger.libsession_util.PRIORITY_VISIBLE
import network.loki.messenger.libsession_util.allWithStatus
import network.loki.messenger.libsession_util.util.ExpiryMode
import org.session.libsession.database.StorageProtocol
import org.session.libsession.messaging.groups.GroupManagerV2
Expand Down Expand Up @@ -284,10 +285,10 @@ class ConversationSettingsViewModel @AssistedInject constructor(
OptionsItem(
name = context.getString(R.string.manageAdmins),
icon = R.drawable.ic_add_admin_custom,
qaTag = R.string.qa_conversation_settings_manage_members,
qaTag = R.string.qa_conversation_settings_manage_admins,
onClick = {
(address as? Address.Group)?.let {
navigateTo(ConversationSettingsDestination.RouteManageMembers(it))
navigateTo(ConversationSettingsDestination.RouteManageAdmins(it))

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You might want to update the qaTag above by creating a new one so QA can have automated tests linking to this button, because right now you are reusing the manage members one.

}
}
)
Expand All @@ -311,6 +312,16 @@ class ConversationSettingsViewModel @AssistedInject constructor(
)
}

private val optionAdminLeaveGroup: OptionsItem by lazy{
OptionsItem(
name = context.getString(R.string.groupLeave),
icon = R.drawable.ic_log_out,
qaTag = R.string.qa_conversation_settings_leave_group,
onClick = ::confirmAdminLeaveGroup
)
}


// Community
private val optionCopyCommunityURL: OptionsItem by lazy{
OptionsItem(
Expand Down Expand Up @@ -580,7 +591,7 @@ class ConversationSettingsViewModel @AssistedInject constructor(
dangerOptions.addAll(
listOf(
optionClearMessages,
optionLeaveGroup,
optionAdminLeaveGroup,
optionDeleteGroup
)
)
Expand Down Expand Up @@ -1026,8 +1037,50 @@ class ConversationSettingsViewModel @AssistedInject constructor(
}
}

private fun confirmAdminLeaveGroup(){
val groupV2Id = (address as? Address.Group)?.accountId ?: return
val isUserLastAdmin = groupManager.isCurrentUserLastAdmin(groupV2Id)
_dialogState.update { state ->
val dialogData = groupManager.getAdminLeaveGroupDialogData(
groupV2Id,
_uiState.value.name
) ?: return

state.copy(
showSimpleDialog = SimpleDialogData(
title = dialogData.title,
message = dialogData.message,
positiveText = context.getString(dialogData.positiveText),
negativeText = context.getString(dialogData.negativeText),
positiveQaTag = dialogData.positiveQaTag?.let { context.getString(it) },
negativeQaTag = dialogData.negativeQaTag?.let { context.getString(it) },
onPositive = {
if (isUserLastAdmin){
// Calling this to have the ManageAdminScreen in the backstack so we can
// get its VM and PromoteMembersScreen can navigate back to it after sending promotions
navigateTo(
ConversationSettingsDestination.RouteManageAdmins(
groupAddress = address,
navigateToPromoteMembers = true
)
)
}else{
leaveGroup()
}
},
positiveStyleDanger = !isUserLastAdmin,
onNegative = {
if (isUserLastAdmin) confirmLeaveGroup()
},
negativeStyleDanger = isUserLastAdmin // red color on the right
)
)
}
}

private fun confirmLeaveGroup(){
val groupV2Id = (address as? Address.Group)?.accountId ?: return

_dialogState.update { state ->
val dialogData = groupManager.getLeaveGroupConfirmationDialogData(
groupV2Id,
Expand All @@ -1040,8 +1093,8 @@ class ConversationSettingsViewModel @AssistedInject constructor(
message = dialogData.message,
positiveText = context.getString(dialogData.positiveText),
negativeText = context.getString(dialogData.negativeText),
positiveQaTag = dialogData.positiveQaTag?.let{ context.getString(it) },
negativeQaTag = dialogData.negativeQaTag?.let{ context.getString(it) },
positiveQaTag = dialogData.positiveQaTag?.let { context.getString(it) },
negativeQaTag = dialogData.negativeQaTag?.let { context.getString(it) },
onPositive = ::leaveGroup,
onNegative = {}
)
Expand Down
Loading