Skip to content

Commit

Permalink
feat: Create team upgrade flow (WPB-11268) (#3517)
Browse files Browse the repository at this point in the history
ohassine authored Oct 23, 2024
1 parent 44292c7 commit acf4562
Showing 15 changed files with 1,271 additions and 4 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* Wire
* Copyright (C) 2024 Wire Swiss GmbH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://www.gnu.org/licenses/.
*/
package com.wire.android.navigation

import com.ramcosta.composedestinations.spec.Direction
import com.wire.android.ui.destinations.TeamMigrationConfirmationStepScreenDestination
import com.wire.android.ui.destinations.TeamMigrationDoneStepScreenDestination

sealed class TeamMigrationDestination(
val direction: Direction
) {

data object Confirmation : TeamMigrationDestination(
direction = TeamMigrationConfirmationStepScreenDestination
)

data object MigrationDone : TeamMigrationDestination(
direction = TeamMigrationDoneStepScreenDestination
)

val itemName: String get() = ITEM_NAME_PREFIX + this

companion object {
private const val ITEM_NAME_PREFIX = "TeamMigrationNavigationItem."
fun fromRoute(fullRoute: String): TeamMigrationDestination? =
values().find { it.direction.route.getBaseRoute() == fullRoute.getBaseRoute() }

fun values(): Array<TeamMigrationDestination> =
arrayOf(Confirmation, MigrationDone)
}
}
Original file line number Diff line number Diff line change
@@ -79,6 +79,7 @@ import com.wire.android.ui.common.visbility.rememberVisibilityState
import com.wire.android.ui.destinations.AppSettingsScreenDestination
import com.wire.android.ui.destinations.AvatarPickerScreenDestination
import com.wire.android.ui.destinations.SelfQRCodeScreenDestination
import com.wire.android.ui.destinations.TeamMigrationScreenDestination
import com.wire.android.ui.destinations.WelcomeScreenDestination
import com.wire.android.ui.home.conversations.search.HighlightName
import com.wire.android.ui.home.conversations.search.HighlightSubtitle
@@ -137,7 +138,7 @@ fun SelfUserProfileScreen(
navigator.navigate(NavigationCommand(SelfQRCodeScreenDestination(viewModelSelf.userProfileState.userName)))
},
onCreateAccount = {
// TODO: open screen to create a team
navigator.navigate(NavigationCommand(TeamMigrationScreenDestination))
},
isUserInCall = viewModelSelf::isUserInCall,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
/*
* Wire
* Copyright (C) 2024 Wire Swiss GmbH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://www.gnu.org/licenses/.
*/
package com.wire.android.ui.userprofile.teammigration

import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.ExperimentalLayoutApi
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.imePadding
import androidx.compose.foundation.layout.isImeVisible
import androidx.compose.foundation.layout.padding
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import com.wire.android.R
import com.wire.android.ui.common.button.WireButtonState
import com.wire.android.ui.common.button.WirePrimaryButton
import com.wire.android.ui.common.button.WireSecondaryButton
import com.wire.android.ui.common.dimensions
import com.wire.android.ui.common.preview.MultipleThemePreviews
import com.wire.android.ui.theme.WireTheme

@OptIn(ExperimentalLayoutApi::class)
@Composable
fun BottomLineButtons(
isContinueButtonEnabled: Boolean,
modifier: Modifier = Modifier,
isBackButtonVisible: Boolean = true,
onBack: () -> Unit = { },
onContinue: () -> Unit = { }
) {
Column(
modifier = modifier
.padding(
top = dimensions().spacing16x,
start = dimensions().spacing16x,
end = dimensions().spacing16x,
bottom = if (!WindowInsets.isImeVisible) {
dimensions().spacing32x
} else {
dimensions().spacing16x
}
)
.imePadding()
) {
if (isBackButtonVisible) {
WireSecondaryButton(
modifier = Modifier.fillMaxWidth(),
text = stringResource(R.string.personal_to_team_migration_back_button_label),
onClick = onBack
)
}

WirePrimaryButton(
modifier = Modifier
.fillMaxWidth()
.padding(top = dimensions().spacing6x),
text = stringResource(R.string.label_continue),
onClick = onContinue,
state = if (isContinueButtonEnabled) {
WireButtonState.Default
} else {
WireButtonState.Disabled
}
)
}
}

@MultipleThemePreviews
@Composable
private fun BottomLineButtonsPreview() {
WireTheme {
BottomLineButtons(
isContinueButtonEnabled = true
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*
* Wire
* Copyright (C) 2024 Wire Swiss GmbH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://www.gnu.org/licenses/.
*/
package com.wire.android.ui.userprofile.teammigration

import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.ParagraphStyle
import androidx.compose.ui.text.buildAnnotatedString
import androidx.compose.ui.text.style.TextIndent
import androidx.compose.ui.text.withStyle
import androidx.compose.ui.unit.sp
import com.wire.android.ui.common.colorsScheme
import com.wire.android.ui.theme.WireTheme
import com.wire.android.ui.theme.wireTypography
import com.wire.android.util.ui.PreviewMultipleThemes

@Composable
fun BulletList(messages: List<String>, modifier: Modifier = Modifier) {
val bullet = "\u2022"
val paragraphStyle = ParagraphStyle(textIndent = TextIndent(restLine = 12.sp))
Text(
modifier = modifier,
text = buildAnnotatedString {
messages.forEach {
withStyle(style = paragraphStyle) {
append(bullet)
append("\t\t")
append(it)
}
}
},
style = MaterialTheme.wireTypography.body01,
color = colorsScheme().onBackground
)
}

@PreviewMultipleThemes
@Composable
private fun BulletListPreview() {
WireTheme {
BulletList(
messages = listOf(
"Item 1",
"Item 2",
"Item 3"
)
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*
* Wire
* Copyright (C) 2024 Wire Swiss GmbH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://www.gnu.org/licenses/.
*/
package com.wire.android.ui.userprofile.teammigration

import com.ramcosta.composedestinations.annotation.NavGraph
import com.ramcosta.composedestinations.annotation.RootNavGraph

@RootNavGraph
@NavGraph
annotation class PersonalToTeamMigrationNavGraph(
val start: Boolean = false
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
/*
* Wire
* Copyright (C) 2024 Wire Swiss GmbH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://www.gnu.org/licenses/.
*/
package com.wire.android.ui.userprofile.teammigration

import android.graphics.drawable.ColorDrawable
import androidx.compose.animation.ExperimentalAnimationApi
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.toArgb
import androidx.compose.ui.platform.LocalInspectionMode
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.hilt.navigation.compose.hiltViewModel
import com.google.accompanist.navigation.material.ExperimentalMaterialNavigationApi
import com.ramcosta.composedestinations.DestinationsNavHost
import com.ramcosta.composedestinations.animations.defaults.RootNavGraphDefaultAnimations
import com.ramcosta.composedestinations.animations.rememberAnimatedNavHostEngine
import com.ramcosta.composedestinations.navigation.dependency
import com.wire.android.R
import com.wire.android.navigation.Navigator
import com.wire.android.navigation.TeamMigrationDestination
import com.wire.android.navigation.WireDestination
import com.wire.android.navigation.rememberNavigator
import com.wire.android.navigation.rememberTrackingAnimatedNavController
import com.wire.android.navigation.style.PopUpNavigationAnimation
import com.wire.android.ui.LocalActivity
import com.wire.android.ui.NavGraphs
import com.wire.android.ui.common.colorsScheme
import com.wire.android.ui.common.dimensions
import com.wire.android.ui.common.preview.MultipleThemePreviews
import com.wire.android.ui.theme.WireTheme

@OptIn(ExperimentalMaterialNavigationApi::class, ExperimentalAnimationApi::class)
@WireDestination(style = PopUpNavigationAnimation::class)
@Composable
fun TeamMigrationScreen(
navigator: Navigator,
modifier: Modifier = Modifier
) {
val navHostEngine = rememberAnimatedNavHostEngine(
rootDefaultAnimations = RootNavGraphDefaultAnimations.ACCOMPANIST_FADING
)
val navController = rememberTrackingAnimatedNavController {
TeamMigrationDestination.fromRoute(it)?.itemName
}

val isRunInPreview = LocalInspectionMode.current

if (!isRunInPreview) {
val activity = LocalActivity.current
activity.window.setBackgroundDrawable(
ColorDrawable(colorsScheme().windowPersonalToTeamMigration.toArgb())
)
}

Column(
modifier = modifier
.padding(top = dimensions().spacing32x)
.clip(
shape = RoundedCornerShape(
dimensions().corner16x,
dimensions().corner16x
)
)
.fillMaxSize()
.background(color = colorsScheme().surface)
) {
IconButton(
modifier = Modifier.align(alignment = Alignment.End),
onClick = {
// TODO(next PR): show dialog to confirm exit before navigating back
navigator.navigateBack()
}
) {
Icon(
painter = painterResource(id = R.drawable.ic_close),
contentDescription = stringResource(R.string.personal_to_team_migration_close_icon_content_description)
)
}

DestinationsNavHost(
navGraph = NavGraphs.personalToTeamMigration,
engine = navHostEngine,
navController = navController,
dependenciesContainerBuilder = {
dependency(navigator)
dependency(NavGraphs.personalToTeamMigration) {
val parentEntry = remember(navBackStackEntry) {
navController.getBackStackEntry(NavGraphs.personalToTeamMigration.route)
}
hiltViewModel<TeamMigrationViewModel>(parentEntry)
}
}
)
}
}

@MultipleThemePreviews
@Composable
private fun TeamMigrationScreenPreview() {
WireTheme {
TeamMigrationScreen(navigator = rememberNavigator { })
}
}
Loading

0 comments on commit acf4562

Please sign in to comment.