Skip to content
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
38 changes: 23 additions & 15 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,12 @@ android {
val domainKeysJson: String? = System.getenv(domainRemovalKeysForRepair) ?: project.getLocalProperty(domainRemovalKeysForRepair, null)
val domainKeysHashMap = if (domainKeysJson != null) {
try {
val jsonMap = groovy.json.JsonSlurper().parseText(domainKeysJson) as Map<String, List<String>>
val parsed = groovy.json.JsonSlurper().parseText(domainKeysJson)
val jsonMap = (parsed as? Map<*, *>)?.mapNotNull { (domain, keys) ->
val domainName = domain as? String ?: return@mapNotNull null
val domainKeys = (keys as? List<*>)?.mapNotNull { it as? String } ?: return@mapNotNull null
domainName to domainKeys
}?.toMap().orEmpty()
val javaMapEntries = jsonMap.entries.joinToString("; ") { (domain, keys) ->
val keysList = keys.joinToString("\", \"", "\"", "\"")
"put(\"$domain\", java.util.Arrays.asList($keysList))"
Expand Down Expand Up @@ -117,7 +122,9 @@ android {
resources.pickFirsts.add("google/protobuf/*.proto")
jniLibs.pickFirsts.add("**/libsodium.so")
}
android.buildFeatures.buildConfig = true
buildFeatures {
buildConfig = true
}
experimentalProperties["android.experimental.enableScreenshotTest"] = true

testOptions {
Expand All @@ -130,29 +137,30 @@ android {
allFlavors.forEach { flavor ->
getByName(flavor) {
if (flavor in internalFlavors) {
java.srcDirs("src/private/kotlin")
kotlin.directories.add("src/private/kotlin")
println("Adding external datadog logger internal sourceSets to '$flavor' flavor")
} else {
java.srcDirs("src/public/kotlin")
kotlin.directories.add("src/public/kotlin")
println("Adding external datadog logger sourceSets to '$flavor' flavor")
}

if (flavor in fossFlavors) {
java.srcDirs("src/foss/kotlin", "src/prod/kotlin")
res.srcDirs("src/prod/res")
kotlin.directories.add("src/foss/kotlin")
kotlin.directories.add("src/prod/kotlin")
res.directories.add("src/prod/res")
println("Adding FOSS sourceSets to '$flavor' flavor")
} else {
java.srcDirs("src/nonfree/kotlin")
kotlin.directories.add("src/nonfree/kotlin")
println("Adding non-free sourceSets to '$flavor' flavor")
}
}
}
getByName("androidTest") {
java.srcDirs("src/androidTest/kotlin")
kotlin.directories.add("src/androidTest/kotlin")
}
create("screenshotTest") {
java.srcDirs("src/screenshotTest/kotlin")
res.srcDirs("src/main/res")
kotlin.directories.add("src/screenshotTest/kotlin")
res.directories.add("src/main/res")
}
}

Expand All @@ -161,10 +169,13 @@ android {
}
}

ksp {
arg("compose-destinations.moduleName", "app")
}

// Skip AboutLibraries configuration when running lint to reduce memory usage
if (!project.hasProperty("skip.aboutlibraries")) {
aboutLibraries {
android.registerAndroidTasks = true
export.excludeFields.add("generated")
}
}
Expand All @@ -178,7 +189,6 @@ dependencies {

fun implementationWithCoverage(dependency: ProjectDependency) {
implementation(dependency)
kover(dependency)
}
implementationWithCoverage(projects.core.uiCommon)
implementationWithCoverage(projects.core.di)
Expand All @@ -196,14 +206,12 @@ dependencies {
if (configs["analytics_enabled"] as? Boolean == true && !isCustomBuild) {
println(">> Dependency Anonymous Analytics is enabled for [$key] flavor")
add("${key}Implementation", project(":core:analytics-enabled"))
add("test${key.capitalize()}Implementation", project(":core:analytics-disabled"))
add("test${key.replaceFirstChar(Char::titlecase)}Implementation", project(":core:analytics-disabled"))
} else {
println(">> Dependency Anonymous Analytics is disabled for [$key] flavor")
add("${key}Implementation", project(":core:analytics-disabled"))
}
}
// Analytics may not be added to the app build, but we always want the merged coverage report
kover(projects.core.analyticsEnabled)

// Application dependencies
implementation(libs.androidx.appcompat)
Expand Down
3 changes: 1 addition & 2 deletions app/src/debug/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.wire.android">
xmlns:tools="http://schemas.android.com/tools">

<application android:name=".WireApplication">
<activity android:name=".ui.WireActivity">
Expand Down
1 change: 0 additions & 1 deletion app/src/fdroid/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.wire.android"
android:sharedUserId="${sharedUserId}">
<application>
<provider
Expand Down
2 changes: 0 additions & 2 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.wire.android"
android:installLocation="internalOnly"
android:sharedUserId="${sharedUserId}">

Expand Down Expand Up @@ -74,7 +73,6 @@
android:hardwareAccelerated="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:requestLegacyExternalStorage="true"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="false"
android:theme="@style/AppTheme.SplashScreen"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,8 @@ class KaliumConfigsModule {
isMlsResetEnabled = BuildConfig.IS_MLS_RESET_ENABLED,
collaboraIntegration = BuildConfig.COLLABORA_INTEGRATION_ENABLED,
dbInvalidationControlEnabled = BuildConfig.DB_INVALIDATION_CONTROL_ENABLED,
domainWithFaultyKeysMap = BuildConfig.DOMAIN_REMOVAL_KEYS_FOR_REPAIR
domainWithFaultyKeysMap = BuildConfig.DOMAIN_REMOVAL_KEYS_FOR_REPAIR,
isDebug = BuildConfig.DEBUG
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@ import com.wire.android.appLogger
import com.wire.android.di.ApplicationScope
import com.wire.android.navigation.BackStackMode
import com.wire.android.navigation.NavigationCommand
import com.wire.android.ui.destinations.HomeScreenDestination
import com.wire.android.ui.destinations.NewLoginScreenDestination
import com.wire.android.ui.destinations.WelcomeScreenDestination
import com.ramcosta.composedestinations.generated.app.destinations.HomeScreenDestination
import com.ramcosta.composedestinations.generated.app.destinations.NewLoginScreenDestination
import com.ramcosta.composedestinations.generated.app.destinations.WelcomeScreenDestination
import com.wire.kalium.logic.data.auth.AccountInfo
import com.wire.kalium.logic.data.logout.LogoutReason
import com.wire.kalium.logic.data.user.UserId
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,13 @@ import androidx.annotation.DrawableRes
import androidx.annotation.StringRes
import com.ramcosta.composedestinations.spec.Direction
import com.wire.android.R
import com.wire.android.ui.destinations.AllConversationsScreenDestination
import com.wire.android.ui.destinations.ArchiveScreenDestination
import com.wire.android.ui.destinations.GlobalCellsScreenDestination
import com.wire.android.ui.destinations.MeetingsScreenDestination
import com.wire.android.ui.destinations.SettingsScreenDestination
import com.wire.android.ui.destinations.VaultScreenDestination
import com.wire.android.ui.destinations.WhatsNewScreenDestination
import com.ramcosta.composedestinations.generated.app.destinations.AllConversationsScreenDestination
import com.ramcosta.composedestinations.generated.app.destinations.ArchiveScreenDestination
import com.ramcosta.composedestinations.generated.app.destinations.GlobalCellsScreenDestination
import com.ramcosta.composedestinations.generated.app.destinations.MeetingsScreenDestination
import com.ramcosta.composedestinations.generated.app.destinations.SettingsScreenDestination
import com.ramcosta.composedestinations.generated.app.destinations.VaultScreenDestination
import com.ramcosta.composedestinations.generated.app.destinations.WhatsNewScreenDestination
import com.wire.android.util.ui.UIText

@Suppress("LongParameterList")
Expand Down
109 changes: 66 additions & 43 deletions app/src/main/kotlin/com/wire/android/navigation/MainNavHost.kt
Original file line number Diff line number Diff line change
Expand Up @@ -21,25 +21,36 @@ package com.wire.android.navigation
import androidx.compose.animation.ExperimentalAnimationApi
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.hilt.navigation.compose.hiltViewModel
import com.ramcosta.composedestinations.DestinationsNavHost
import com.ramcosta.composedestinations.animations.rememberAnimatedNavHostEngine
import com.ramcosta.composedestinations.generated.app.destinations.ConversationScreenDestination
import com.ramcosta.composedestinations.generated.app.destinations.LoginScreenDestination
import com.ramcosta.composedestinations.generated.app.destinations.NewLoginPasswordScreenDestination
import com.ramcosta.composedestinations.generated.app.destinations.NewLoginScreenDestination
import com.ramcosta.composedestinations.generated.app.destinations.NewLoginVerificationCodeScreenDestination
import com.ramcosta.composedestinations.generated.app.navgraphs.LoginGraph
import com.ramcosta.composedestinations.generated.app.navgraphs.NewConversationGraph
import com.ramcosta.composedestinations.generated.app.navgraphs.NewLoginGraph
import com.ramcosta.composedestinations.generated.app.navgraphs.PersonalToTeamMigrationGraph
import com.ramcosta.composedestinations.generated.app.navgraphs.WireRootGraph
import com.ramcosta.composedestinations.generated.app.navtype.groupConversationDetailsNavBackArgsNavType
import com.ramcosta.composedestinations.generated.app.navtype.imagesPreviewNavBackArgsNavType
import com.ramcosta.composedestinations.generated.app.navtype.mediaGalleryNavBackArgsNavType
import com.ramcosta.composedestinations.generated.sketch.destinations.DrawingCanvasScreenDestination
import com.ramcosta.composedestinations.generated.sketch.navtype.drawingCanvasNavBackArgsNavType
import com.ramcosta.composedestinations.manualcomposablecalls.composable
import com.ramcosta.composedestinations.navigation.dependency
import com.ramcosta.composedestinations.navigation.destination
import com.ramcosta.composedestinations.navigation.navGraph
import com.ramcosta.composedestinations.scope.resultBackNavigator
import com.ramcosta.composedestinations.scope.resultRecipient
import com.ramcosta.composedestinations.spec.Route
import com.wire.android.feature.sketch.destinations.DrawingCanvasScreenDestination
import com.ramcosta.composedestinations.spec.Direction
import com.wire.android.feature.sketch.model.DrawingCanvasNavBackArgs
import com.wire.android.navigation.style.DefaultNestedNavGraphAnimations
import com.wire.android.navigation.style.DefaultRootNavGraphAnimations
import com.wire.android.ui.NavGraphs
import com.wire.android.ui.authentication.login.email.LoginEmailViewModel
import com.wire.android.ui.authentication.login.sso.SSOUrlConfigHolder
import com.wire.android.ui.authentication.login.sso.SSOUrlConfigHolderImpl
import com.wire.android.ui.destinations.ConversationScreenDestination
import com.wire.android.ui.destinations.NewLoginPasswordScreenDestination
import com.wire.android.ui.destinations.NewLoginVerificationCodeScreenDestination
import com.wire.android.ui.home.conversations.ConversationScreen
import com.wire.android.ui.home.newconversation.NewConversationViewModel
import com.wire.android.ui.userprofile.teammigration.TeamMigrationViewModel
Expand All @@ -49,88 +60,100 @@ import com.wire.android.ui.userprofile.teammigration.TeamMigrationViewModel
fun MainNavHost(
navigator: Navigator,
loginTypeSelector: LoginTypeSelector?,
startDestination: Route,
startDestination: Direction,
modifier: Modifier = Modifier,
) {
val navHostEngine = rememberAnimatedNavHostEngine(
rootDefaultAnimations = DefaultRootNavGraphAnimations,
defaultAnimationsForNestedNavGraph = mapOf(
NavGraphs.createPersonalAccount to DefaultNestedNavGraphAnimations,
NavGraphs.createTeamAccount to DefaultNestedNavGraphAnimations,
NavGraphs.newConversation to DefaultNestedNavGraphAnimations,
)
)

AdjustDestinationStylesForTablets()
val navHostEngine = rememberWireNavHostEngine(Alignment.Center)
DestinationsNavHost(
modifier = modifier,
navGraph = WireMainNavGraph,
navGraph = WireRootGraph,
defaultTransitions = WireRootGraph.defaultTransitions,
engine = navHostEngine,
startRoute = startDestination,
start = startDestination,
navController = navigator.navController,
dependenciesContainerBuilder = {
// 👇 To make Navigator available to all destinations as a non-navigation parameter
dependency(navigator)

// Always provide a default SSO holder at root scope so destinations can resolve it
// even when navigated directly without going through the expected nested graph route.
val rootEntry = remember(navBackStackEntry) {
navController.getBackStackEntry(WireRootGraph.route)
}
val rootSSOHolder: SSOUrlConfigHolder = SSOUrlConfigHolderImpl(rootEntry.savedStateHandle)
dependency(rootSSOHolder)

// 👇 To make LoginTypeSelector available to all destinations as a non-navigation parameter if provided
if (loginTypeSelector != null) dependency(loginTypeSelector)

// 👇 To tie NewConversationViewModel to nested NewConversationNavGraph, making it shared between all screens that belong to it
dependency(NavGraphs.newConversation) {
navGraph(NewConversationGraph) {
val parentEntry = remember(navBackStackEntry) {
navController.getBackStackEntry(NavGraphs.newConversation.route)
navController.getBackStackEntry(NewConversationGraph.route)
}
hiltViewModel<NewConversationViewModel>(parentEntry)
}

// 👇 To reuse LoginEmailViewModel from NewLoginPasswordScreen on NewLoginVerificationCodeScreen
dependency(NewLoginVerificationCodeScreenDestination) {
destination(NewLoginVerificationCodeScreenDestination) {
val loginPasswordEntry = remember(navBackStackEntry) {
navController.getBackStackEntry(NewLoginPasswordScreenDestination.route)
}
hiltViewModel<LoginEmailViewModel>(loginPasswordEntry)
}

// 👇 To tie SSOUrlConfigHolder to nested LoginNavGraph, making it shared between all screens that belong to it
dependency(NavGraphs.login) {
navGraph(LoginGraph) {
val parentEntry = remember(navBackStackEntry) {
navController.getBackStackEntry(NavGraphs.login.route)
navController.getBackStackEntry(LoginGraph.route)
}
SSOUrlConfigHolderImpl(parentEntry.savedStateHandle)
val holder: SSOUrlConfigHolder = SSOUrlConfigHolderImpl(parentEntry.savedStateHandle)
dependency(holder)
}

// 👇 To tie SSOUrlConfigHolder to nested NewLoginNavGraph, making it shared between all screens that belong to it
dependency(NavGraphs.newLogin) {
navGraph(NewLoginGraph) {
val parentEntry = remember(navBackStackEntry) {
navController.getBackStackEntry(NavGraphs.newLogin.route)
navController.getBackStackEntry(NewLoginGraph.route)
}
SSOUrlConfigHolderImpl(parentEntry.savedStateHandle)
val holder: SSOUrlConfigHolder = SSOUrlConfigHolderImpl(parentEntry.savedStateHandle)
dependency(holder)
}

// Some flows navigate directly to screen destinations instead of the nav graph route.
// Provide the dependency at destination scope as a safe fallback.
destination(LoginScreenDestination) {
val holder: SSOUrlConfigHolder = SSOUrlConfigHolderImpl(navBackStackEntry.savedStateHandle)
dependency(holder)
}
destination(NewLoginScreenDestination) {
val holder: SSOUrlConfigHolder = SSOUrlConfigHolderImpl(navBackStackEntry.savedStateHandle)
dependency(holder)
}

// 👇 To tie TeamMigrationViewModel to PersonalToTeamMigrationNavGraph, making it shared between all screens that belong to it
dependency(NavGraphs.personalToTeamMigration) {
navGraph(PersonalToTeamMigrationGraph) {
val parentEntry = remember(navBackStackEntry) {
navController.getBackStackEntry(NavGraphs.personalToTeamMigration.route)
navController.getBackStackEntry(PersonalToTeamMigrationGraph.route)
}
hiltViewModel<TeamMigrationViewModel>(parentEntry)
}
},
manualComposableCallsBuilder = {
/**
* In compose-destinations v1 it's not possible for code generation to use destination generated in another module,
* that's why it's necessary to use "open" approach and manually call the composable function for the destination.
* In v2 this will be possible, so that we will be able to use regular `ResultRecipient` instead of `OpenResultRecipient`
* and provide it directly inside the destination's composable without the need to passing it manually.
* https://github.com/raamcosta/compose-destinations/issues/508#issuecomment-1883166574
* Keep manual composable calls for cross-module result wiring until we refactor
* those destinations to rely on generated dependencies directly.
*/
composable(ConversationScreenDestination) {
ConversationScreen(
navigator = navigator,
groupDetailsScreenResultRecipient = resultRecipient(),
mediaGalleryScreenResultRecipient = resultRecipient(),
imagePreviewScreenResultRecipient = resultRecipient(),
drawingCanvasScreenResultRecipient = resultRecipient<DrawingCanvasScreenDestination, DrawingCanvasNavBackArgs>(),
resultNavigator = resultBackNavigator(),
groupDetailsScreenResultRecipient = resultRecipient(groupConversationDetailsNavBackArgsNavType),
mediaGalleryScreenResultRecipient = resultRecipient(mediaGalleryNavBackArgsNavType),
imagePreviewScreenResultRecipient = resultRecipient(imagesPreviewNavBackArgsNavType),
drawingCanvasScreenResultRecipient = resultRecipient<DrawingCanvasScreenDestination, DrawingCanvasNavBackArgs>(
drawingCanvasNavBackArgsNavType
),
resultNavigator = resultBackNavigator(groupConversationDetailsNavBackArgsNavType),
)
}
}
Expand Down
Loading
Loading