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
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ import com.wire.android.feature.cells.ui.destinations.ConversationFilesScreenDes
import com.wire.android.feature.cells.ui.destinations.ConversationFilesWithSlideInTransitionScreenDestination
import com.wire.android.feature.cells.ui.destinations.CreateFolderScreenDestination
import com.wire.android.feature.cells.ui.destinations.MoveToFolderScreenDestination
import com.wire.android.feature.cells.ui.destinations.PublicLinkExpirationScreenDestination
import com.wire.android.feature.cells.ui.destinations.PublicLinkPasswordScreenDestination
import com.wire.android.feature.cells.ui.destinations.PublicLinkScreenDestination
import com.wire.android.feature.cells.ui.destinations.RecycleBinScreenDestination
import com.wire.android.feature.cells.ui.destinations.RenameNodeScreenDestination
Expand All @@ -44,6 +46,8 @@ object WireMainNavGraph : NavGraphSpec {
.plus(RecycleBinScreenDestination)
.plus(RenameNodeScreenDestination)
.plus(AddRemoveTagsScreenDestination)
.plus(PublicLinkPasswordScreenDestination)
.plus(PublicLinkExpirationScreenDestination)
override val destinationsByRoute = destinations.associateBy { it.route }
override val nestedNavGraphs = NavGraphs.wireRoot.nestedNavGraphs
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,20 @@ import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.AnnotatedString
import androidx.hilt.navigation.compose.hiltViewModel
import com.ramcosta.composedestinations.result.NavResult
import com.ramcosta.composedestinations.result.ResultBackNavigator
import com.ramcosta.composedestinations.result.ResultRecipient
import com.ramcosta.composedestinations.spec.DestinationSpec
import com.wire.android.feature.cells.R
import com.wire.android.feature.cells.ui.destinations.PublicLinkExpirationScreenDestination
import com.wire.android.feature.cells.ui.destinations.PublicLinkPasswordScreenDestination
import com.wire.android.feature.cells.ui.publiclink.settings.PublicLinkSettingsSection
import com.wire.android.feature.cells.ui.util.PreviewMultipleThemes
import com.wire.android.navigation.NavigationCommand
import com.wire.android.navigation.WireNavigator
import com.wire.android.navigation.annotation.features.cells.WireDestination
import com.wire.android.navigation.style.PopUpNavigationAnimation
import com.wire.android.ui.common.HandleActions
import com.wire.android.ui.common.button.WireSecondaryButton
import com.wire.android.ui.common.button.WireSwitch
import com.wire.android.ui.common.colorsScheme
import com.wire.android.ui.common.dimensions
Expand All @@ -63,7 +70,10 @@ import com.wire.android.ui.theme.WireTheme
)
@Composable
fun PublicLinkScreen(
navigator: WireNavigator,
resultNavigator: ResultBackNavigator<Unit>,
onPasswordChange: ResultRecipient<PublicLinkPasswordScreenDestination, Boolean>,
onExpirationChange: ResultRecipient<PublicLinkExpirationScreenDestination, Boolean>,
modifier: Modifier = Modifier,
viewModel: PublicLinkViewModel = hiltViewModel(),
) {
Expand All @@ -77,7 +87,7 @@ fun PublicLinkScreen(
topBar = {
WireCenterAlignedTopAppBar(
onNavigationPressed = { resultNavigator.navigateBack() },
title = if (viewModel.isFolder()) {
title = if (state.isFolder) {
stringResource(R.string.share_folder_via_link)
} else {
stringResource(R.string.share_file_via_link)
Expand All @@ -91,32 +101,37 @@ fun PublicLinkScreen(
modifier = Modifier.padding(innerPadding)
) {
EnableLinkSection(
checked = state.enabled,
isFolder = viewModel.isFolder(),
checked = state.isEnabled,
isFolder = state.isFolder,
onCheckChange = {
viewModel.onEnabled(it)
}
)

AnimatedVisibility(
visible = state.enabled,
visible = state.isLinkAvailable,
enter = fadeIn(),
exit = fadeOut()
) {
PublicLinkSection(
url = state.url,
onShareLink = {
state.url?.let { url ->
viewModel.shareLink(url)
}
},
onCopyLink = {
state.url?.let { url ->
clipboardManager.setText(AnnotatedString(url))
showLinkCopiedToast(context)
}
Column {
state.settings?.let {
PublicLinkSettingsSection(
settings = it,
onPasswordClick = {
navigator.navigate(NavigationCommand(PublicLinkPasswordScreenDestination()))
},
onExpirationClick = {
navigator.navigate(NavigationCommand(PublicLinkExpirationScreenDestination()))
},
)
}
)

PublicLinkSection(
state = state.linkState,
onShareLink = viewModel::shareLink,
onCopyLink = viewModel::copyLink,
)
}
}
}
}
Expand All @@ -131,6 +146,23 @@ fun PublicLinkScreen(
resultNavigator.navigateBack()
}
}

is CopyLink -> {
clipboardManager.setText(AnnotatedString(action.url))
showLinkCopiedToast(context)
}
}
}

onPasswordChange.handleNavResult { result ->
if (result) {
viewModel.onPasswordUpdate()
}
}

onExpirationChange.handleNavResult { result ->
if (result) {
viewModel.onExpirationUpdate()
}
}
}
Expand Down Expand Up @@ -179,46 +211,6 @@ private fun EnableLinkSection(
}
}

@Composable
private fun PublicLinkSection(
url: String?,
onShareLink: () -> Unit,
onCopyLink: () -> Unit,
) {
Column {
Text(
text = stringResource(R.string.share_link).uppercase(),
style = typography().title03,
modifier = Modifier.padding(dimensions().spacing16x)
)

Column(
modifier = Modifier
.fillMaxWidth()
.background(colorsScheme().surface)
.padding(dimensions().spacing16x)
) {
Text(
text = url ?: stringResource(R.string.creating_link),
style = typography().body01,
minLines = 2,
)

Spacer(modifier = Modifier.height(dimensions().spacing24x))

WireSecondaryButton(
text = stringResource(R.string.share_link),
onClick = onShareLink
)
Spacer(modifier = Modifier.height(dimensions().spacing8x))
WireSecondaryButton(
text = stringResource(R.string.copy_link),
onClick = onCopyLink
)
}
}
}

/**
* Show a toast message when the link is copied to the clipboard.
* Only for API levels lower than 33. On new versions, the system will show a clipboard
Expand All @@ -230,6 +222,16 @@ private fun showLinkCopiedToast(context: Context) {
}
}

@Composable
private fun <D : DestinationSpec<*>, R> ResultRecipient<D, R>.handleNavResult(block: (R) -> Unit) {
onNavResult { result ->
when (result) {
is NavResult.Value<R> -> block(result.value)
NavResult.Canceled -> {}
}
}
}

@PreviewMultipleThemes
@Composable
private fun PreviewCreatePublicLinkScreen() {
Expand All @@ -241,7 +243,7 @@ private fun PreviewCreatePublicLinkScreen() {
onCheckChange = {}
)
PublicLinkSection(
url = "http://test.url",
state = PublicLinkState.READY,
onShareLink = {},
onCopyLink = {}
)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/*
* Wire
* Copyright (C) 2025 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.feature.cells.ui.publiclink

import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import com.wire.android.feature.cells.R
import com.wire.android.ui.common.button.WireButtonState
import com.wire.android.ui.common.button.WireSecondaryButton
import com.wire.android.ui.common.colorsScheme
import com.wire.android.ui.common.dimensions
import com.wire.android.ui.common.typography

@Composable
internal fun PublicLinkSection(
state: PublicLinkState,
onShareLink: () -> Unit,
onCopyLink: () -> Unit,
) {

val isLoading = state == PublicLinkState.LOADING

Column {
Text(
text = stringResource(R.string.share_link).uppercase(),
style = typography().title03,
modifier = Modifier.padding(dimensions().spacing16x)
)

Column(
modifier = Modifier
.fillMaxWidth()
.background(colorsScheme().surface)
.padding(dimensions().spacing16x)
) {
WireSecondaryButton(
text = stringResource(R.string.share_link),
state = if (isLoading) WireButtonState.Disabled else WireButtonState.Default,
loading = isLoading,
onClick = onShareLink,
)
Spacer(modifier = Modifier.height(dimensions().spacing8x))
WireSecondaryButton(
text = stringResource(R.string.copy_link),
state = if (isLoading) WireButtonState.Disabled else WireButtonState.Default,
loading = isLoading,
onClick = onCopyLink
)
}
}
}
Loading