mirror of
https://github.com/sudosylabs/vnidrop.git
synced 2026-08-05 10:29:58 +02:00
feat(ui): align Android empty states
This commit is contained in:
@@ -11,7 +11,6 @@ androidx-lifecycle = "2.11.0-beta01"
|
|||||||
androidx-datastore = "1.2.1"
|
androidx-datastore = "1.2.1"
|
||||||
androidx-testExt = "1.3.0"
|
androidx-testExt = "1.3.0"
|
||||||
composeMultiplatform = "1.11.1"
|
composeMultiplatform = "1.11.1"
|
||||||
compottie = "2.2.4"
|
|
||||||
filekit = "0.14.2"
|
filekit = "0.14.2"
|
||||||
gobley = "0.3.7"
|
gobley = "0.3.7"
|
||||||
junit = "4.13.2"
|
junit = "4.13.2"
|
||||||
@@ -42,7 +41,6 @@ compose-ui = { module = "org.jetbrains.compose.ui:ui", version.ref = "composeMul
|
|||||||
compose-uiTest = { module = "org.jetbrains.compose.ui:ui-test", version.ref = "composeMultiplatform" }
|
compose-uiTest = { module = "org.jetbrains.compose.ui:ui-test", version.ref = "composeMultiplatform" }
|
||||||
compose-components-resources = { module = "org.jetbrains.compose.components:components-resources", version.ref = "composeMultiplatform" }
|
compose-components-resources = { module = "org.jetbrains.compose.components:components-resources", version.ref = "composeMultiplatform" }
|
||||||
compose-uiToolingPreview = { module = "org.jetbrains.compose.ui:ui-tooling-preview", version.ref = "composeMultiplatform" }
|
compose-uiToolingPreview = { module = "org.jetbrains.compose.ui:ui-tooling-preview", version.ref = "composeMultiplatform" }
|
||||||
compottie-lite = { module = "io.github.alexzhirkevich:compottie-lite", version.ref = "compottie" }
|
|
||||||
filekit-dialogs = { module = "io.github.vinceglb:filekit-dialogs", version.ref = "filekit" }
|
filekit-dialogs = { module = "io.github.vinceglb:filekit-dialogs", version.ref = "filekit" }
|
||||||
kotlinx-coroutinesCore = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlinx-coroutines" }
|
kotlinx-coroutinesCore = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlinx-coroutines" }
|
||||||
kotlinx-coroutinesTest = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-test", version.ref = "kotlinx-coroutines" }
|
kotlinx-coroutinesTest = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-test", version.ref = "kotlinx-coroutines" }
|
||||||
|
|||||||
@@ -139,7 +139,6 @@ kotlin {
|
|||||||
implementation(libs.compose.ui)
|
implementation(libs.compose.ui)
|
||||||
implementation(libs.compose.components.resources)
|
implementation(libs.compose.components.resources)
|
||||||
implementation(libs.compose.uiToolingPreview)
|
implementation(libs.compose.uiToolingPreview)
|
||||||
implementation(libs.compottie.lite)
|
|
||||||
implementation(libs.androidx.lifecycle.viewmodelCompose)
|
implementation(libs.androidx.lifecycle.viewmodelCompose)
|
||||||
implementation(libs.androidx.lifecycle.runtimeCompose)
|
implementation(libs.androidx.lifecycle.runtimeCompose)
|
||||||
implementation(libs.androidx.datastore)
|
implementation(libs.androidx.datastore)
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -47,11 +47,9 @@ import com.vnidrop.app.core.FolderAccessStatus
|
|||||||
import com.vnidrop.app.core.Transfer
|
import com.vnidrop.app.core.Transfer
|
||||||
import com.vnidrop.app.core.TransferDirection
|
import com.vnidrop.app.core.TransferDirection
|
||||||
import com.vnidrop.app.core.TransferStatus
|
import com.vnidrop.app.core.TransferStatus
|
||||||
import com.vnidrop.app.isDesktop
|
|
||||||
import com.vnidrop.app.ui.components.AdaptiveDrawer
|
import com.vnidrop.app.ui.components.AdaptiveDrawer
|
||||||
import com.vnidrop.app.ui.components.DestructiveButton
|
import com.vnidrop.app.ui.components.DestructiveButton
|
||||||
import com.vnidrop.app.ui.components.DestructiveQuietButton
|
import com.vnidrop.app.ui.components.DestructiveQuietButton
|
||||||
import com.vnidrop.app.ui.components.EmptyStateAnimation
|
|
||||||
import com.vnidrop.app.ui.components.Field
|
import com.vnidrop.app.ui.components.Field
|
||||||
import com.vnidrop.app.ui.components.PrimaryButton
|
import com.vnidrop.app.ui.components.PrimaryButton
|
||||||
import com.vnidrop.app.ui.components.ProgressRow
|
import com.vnidrop.app.ui.components.ProgressRow
|
||||||
@@ -166,9 +164,6 @@ private fun ReceiveHeader(showAction: Boolean, onOpen: () -> Unit) {
|
|||||||
Row(Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) {
|
Row(Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) {
|
||||||
Column(Modifier.weight(1f), verticalArrangement = Arrangement.spacedBy(4.dp)) {
|
Column(Modifier.weight(1f), verticalArrangement = Arrangement.spacedBy(4.dp)) {
|
||||||
Text(stringResource(Res.string.receive_title), style = MaterialTheme.typography.headlineMedium, fontWeight = FontWeight.Bold)
|
Text(stringResource(Res.string.receive_title), style = MaterialTheme.typography.headlineMedium, fontWeight = FontWeight.Bold)
|
||||||
if (!LocalUiPlatform.current.isDesktop) {
|
|
||||||
Text(stringResource(Res.string.receive_new_subtitle), color = LocalVniDropColors.current.foregroundLighter)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (showAction) {
|
if (showAction) {
|
||||||
Spacer(Modifier.width(16.dp))
|
Spacer(Modifier.width(16.dp))
|
||||||
@@ -180,13 +175,11 @@ private fun ReceiveHeader(showAction: Boolean, onOpen: () -> Unit) {
|
|||||||
@Composable
|
@Composable
|
||||||
private fun ReceiveEmptyState(onOpen: () -> Unit) {
|
private fun ReceiveEmptyState(onOpen: () -> Unit) {
|
||||||
val colors = LocalVniDropColors.current
|
val colors = LocalVniDropColors.current
|
||||||
val desktop = LocalUiPlatform.current.isDesktop
|
|
||||||
Column(
|
Column(
|
||||||
Modifier.fillMaxWidth().heightIn(min = 430.dp).padding(horizontal = 20.dp),
|
Modifier.fillMaxWidth().heightIn(min = 430.dp).padding(horizontal = 20.dp),
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
verticalArrangement = Arrangement.Center,
|
verticalArrangement = Arrangement.Center,
|
||||||
) {
|
) {
|
||||||
if (desktop) {
|
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = VniDropIcons.Receive,
|
imageVector = VniDropIcons.Receive,
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
@@ -195,12 +188,6 @@ private fun ReceiveEmptyState(onOpen: () -> Unit) {
|
|||||||
.size(88.dp)
|
.size(88.dp)
|
||||||
.testTag("receive-empty-icon"),
|
.testTag("receive-empty-icon"),
|
||||||
)
|
)
|
||||||
} else {
|
|
||||||
EmptyStateAnimation(
|
|
||||||
assetPath = "files/animations/receive_empty_state.json",
|
|
||||||
modifier = Modifier.size(168.dp),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Text(stringResource(Res.string.receive_empty_title), modifier = Modifier.padding(top = 12.dp), style = MaterialTheme.typography.headlineSmall, fontWeight = FontWeight.Bold)
|
Text(stringResource(Res.string.receive_empty_title), modifier = Modifier.padding(top = 12.dp), style = MaterialTheme.typography.headlineSmall, fontWeight = FontWeight.Bold)
|
||||||
Text(
|
Text(
|
||||||
stringResource(Res.string.receive_empty_body),
|
stringResource(Res.string.receive_empty_body),
|
||||||
|
|||||||
@@ -38,8 +38,6 @@ import androidx.compose.ui.unit.dp
|
|||||||
import com.vnidrop.app.core.CoreEventModel
|
import com.vnidrop.app.core.CoreEventModel
|
||||||
import com.vnidrop.app.core.Transfer
|
import com.vnidrop.app.core.Transfer
|
||||||
import com.vnidrop.app.core.TransferStatus
|
import com.vnidrop.app.core.TransferStatus
|
||||||
import com.vnidrop.app.isDesktop
|
|
||||||
import com.vnidrop.app.ui.components.EmptyStateAnimation
|
|
||||||
import com.vnidrop.app.ui.components.PillTone
|
import com.vnidrop.app.ui.components.PillTone
|
||||||
import com.vnidrop.app.ui.components.PrimaryButton
|
import com.vnidrop.app.ui.components.PrimaryButton
|
||||||
import com.vnidrop.app.ui.components.ProgressRow
|
import com.vnidrop.app.ui.components.ProgressRow
|
||||||
@@ -62,7 +60,6 @@ import vnidrop.shared.generated.resources.send_empty_body
|
|||||||
import vnidrop.shared.generated.resources.send_empty_title
|
import vnidrop.shared.generated.resources.send_empty_title
|
||||||
import vnidrop.shared.generated.resources.send_new_transfer_description
|
import vnidrop.shared.generated.resources.send_new_transfer_description
|
||||||
import vnidrop.shared.generated.resources.send_new_transfer_title
|
import vnidrop.shared.generated.resources.send_new_transfer_title
|
||||||
import vnidrop.shared.generated.resources.send_subtitle
|
|
||||||
import vnidrop.shared.generated.resources.send_title
|
import vnidrop.shared.generated.resources.send_title
|
||||||
import vnidrop.shared.generated.resources.send_transfers_title
|
import vnidrop.shared.generated.resources.send_transfers_title
|
||||||
|
|
||||||
@@ -131,13 +128,6 @@ private fun CatalogHeader(showAction: Boolean, onOpenComposer: () -> Unit) {
|
|||||||
Row(modifier = Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) {
|
Row(modifier = Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) {
|
||||||
Column(Modifier.weight(1f), verticalArrangement = Arrangement.spacedBy(4.dp)) {
|
Column(Modifier.weight(1f), verticalArrangement = Arrangement.spacedBy(4.dp)) {
|
||||||
Text(stringResource(Res.string.send_title), style = MaterialTheme.typography.headlineMedium, fontWeight = FontWeight.Bold)
|
Text(stringResource(Res.string.send_title), style = MaterialTheme.typography.headlineMedium, fontWeight = FontWeight.Bold)
|
||||||
if (!LocalUiPlatform.current.isDesktop) {
|
|
||||||
Text(
|
|
||||||
stringResource(Res.string.send_subtitle),
|
|
||||||
color = LocalVniDropColors.current.foregroundLighter,
|
|
||||||
style = MaterialTheme.typography.bodyMedium,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (showAction) {
|
if (showAction) {
|
||||||
Spacer(Modifier.width(16.dp))
|
Spacer(Modifier.width(16.dp))
|
||||||
@@ -149,13 +139,11 @@ private fun CatalogHeader(showAction: Boolean, onOpenComposer: () -> Unit) {
|
|||||||
@Composable
|
@Composable
|
||||||
private fun SendEmptyState(onOpenComposer: () -> Unit) {
|
private fun SendEmptyState(onOpenComposer: () -> Unit) {
|
||||||
val colors = LocalVniDropColors.current
|
val colors = LocalVniDropColors.current
|
||||||
val desktop = LocalUiPlatform.current.isDesktop
|
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier.fillMaxWidth().heightIn(min = 430.dp).padding(horizontal = 20.dp),
|
modifier = Modifier.fillMaxWidth().heightIn(min = 430.dp).padding(horizontal = 20.dp),
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
verticalArrangement = Arrangement.Center,
|
verticalArrangement = Arrangement.Center,
|
||||||
) {
|
) {
|
||||||
if (desktop) {
|
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = VniDropIcons.Send,
|
imageVector = VniDropIcons.Send,
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
@@ -164,12 +152,6 @@ private fun SendEmptyState(onOpenComposer: () -> Unit) {
|
|||||||
.size(88.dp)
|
.size(88.dp)
|
||||||
.testTag("send-empty-icon"),
|
.testTag("send-empty-icon"),
|
||||||
)
|
)
|
||||||
} else {
|
|
||||||
EmptyStateAnimation(
|
|
||||||
assetPath = "files/animations/send_empty_state.json",
|
|
||||||
modifier = Modifier.size(168.dp),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Text(
|
Text(
|
||||||
stringResource(Res.string.send_empty_title),
|
stringResource(Res.string.send_empty_title),
|
||||||
modifier = Modifier.padding(top = 12.dp),
|
modifier = Modifier.padding(top = 12.dp),
|
||||||
|
|||||||
@@ -7,11 +7,8 @@ import androidx.compose.material3.Text
|
|||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import com.vnidrop.app.isDesktop
|
|
||||||
import com.vnidrop.app.ui.platform.LocalUiPlatform
|
|
||||||
import com.vnidrop.app.ui.theme.ThemeMode
|
import com.vnidrop.app.ui.theme.ThemeMode
|
||||||
import org.jetbrains.compose.resources.stringResource
|
import org.jetbrains.compose.resources.stringResource
|
||||||
import com.vnidrop.app.ui.theme.LocalVniDropColors
|
|
||||||
import vnidrop.shared.generated.resources.Res
|
import vnidrop.shared.generated.resources.Res
|
||||||
import vnidrop.shared.generated.resources.about_title
|
import vnidrop.shared.generated.resources.about_title
|
||||||
import vnidrop.shared.generated.resources.appearance_dark_mode
|
import vnidrop.shared.generated.resources.appearance_dark_mode
|
||||||
@@ -20,7 +17,6 @@ import vnidrop.shared.generated.resources.appearance_system_mode
|
|||||||
import vnidrop.shared.generated.resources.appearance_title
|
import vnidrop.shared.generated.resources.appearance_title
|
||||||
import vnidrop.shared.generated.resources.notifications_title
|
import vnidrop.shared.generated.resources.notifications_title
|
||||||
import vnidrop.shared.generated.resources.preferences_title
|
import vnidrop.shared.generated.resources.preferences_title
|
||||||
import vnidrop.shared.generated.resources.settings_subtitle
|
|
||||||
import vnidrop.shared.generated.resources.settings_title
|
import vnidrop.shared.generated.resources.settings_title
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
@@ -30,20 +26,11 @@ internal fun SettingsOverview(
|
|||||||
largeTitle: Boolean,
|
largeTitle: Boolean,
|
||||||
) {
|
) {
|
||||||
Column(verticalArrangement = Arrangement.spacedBy(16.dp)) {
|
Column(verticalArrangement = Arrangement.spacedBy(16.dp)) {
|
||||||
Column(verticalArrangement = Arrangement.spacedBy(4.dp)) {
|
|
||||||
Text(
|
Text(
|
||||||
stringResource(Res.string.settings_title),
|
stringResource(Res.string.settings_title),
|
||||||
style = if (largeTitle) MaterialTheme.typography.headlineLarge else MaterialTheme.typography.headlineMedium,
|
style = if (largeTitle) MaterialTheme.typography.headlineLarge else MaterialTheme.typography.headlineMedium,
|
||||||
fontWeight = FontWeight.Bold,
|
fontWeight = FontWeight.Bold,
|
||||||
)
|
)
|
||||||
if (!LocalUiPlatform.current.isDesktop) {
|
|
||||||
Text(
|
|
||||||
stringResource(Res.string.settings_subtitle),
|
|
||||||
color = LocalVniDropColors.current.foregroundLighter,
|
|
||||||
style = MaterialTheme.typography.bodyMedium,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
SettingsGroup {
|
SettingsGroup {
|
||||||
SettingsRow(
|
SettingsRow(
|
||||||
icon = SettingsIcons.Device,
|
icon = SettingsIcons.Device,
|
||||||
|
|||||||
@@ -1,34 +0,0 @@
|
|||||||
package com.vnidrop.app.ui.components
|
|
||||||
|
|
||||||
import androidx.compose.foundation.Image
|
|
||||||
import androidx.compose.runtime.Composable
|
|
||||||
import androidx.compose.runtime.getValue
|
|
||||||
import androidx.compose.ui.Modifier
|
|
||||||
import androidx.compose.ui.layout.ContentScale
|
|
||||||
import io.github.alexzhirkevich.compottie.Compottie
|
|
||||||
import io.github.alexzhirkevich.compottie.LottieCompositionSpec
|
|
||||||
import io.github.alexzhirkevich.compottie.rememberLottieComposition
|
|
||||||
import io.github.alexzhirkevich.compottie.rememberLottiePainter
|
|
||||||
import vnidrop.shared.generated.resources.Res
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
internal fun EmptyStateAnimation(
|
|
||||||
assetPath: String,
|
|
||||||
modifier: Modifier = Modifier,
|
|
||||||
) {
|
|
||||||
val composition by rememberLottieComposition {
|
|
||||||
LottieCompositionSpec.JsonString(
|
|
||||||
Res.readBytes(assetPath).decodeToString(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
Image(
|
|
||||||
painter = rememberLottiePainter(
|
|
||||||
composition = composition,
|
|
||||||
iterations = Compottie.IterateForever,
|
|
||||||
),
|
|
||||||
contentDescription = null,
|
|
||||||
modifier = modifier,
|
|
||||||
contentScale = ContentScale.Fit,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -291,7 +291,7 @@ class FoundationComposeTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun desktopPagesUseStaticFeatureIconsWithoutTitleDescriptions() = runComposeUiTest {
|
fun androidPagesUseStaticFeatureIconsWithoutTitleDescriptions() = runComposeUiTest {
|
||||||
val actions = object : ReceiveInvitationActions {
|
val actions = object : ReceiveInvitationActions {
|
||||||
override val fileAvailability = ReceiveMethodAvailability.Hidden
|
override val fileAvailability = ReceiveMethodAvailability.Hidden
|
||||||
override val qrAvailability = ReceiveMethodAvailability.Hidden
|
override val qrAvailability = ReceiveMethodAvailability.Hidden
|
||||||
@@ -302,14 +302,14 @@ class FoundationComposeTest {
|
|||||||
override fun cancel() = Unit
|
override fun cancel() = Unit
|
||||||
}
|
}
|
||||||
setContent {
|
setContent {
|
||||||
CompositionLocalProvider(LocalUiPlatform provides UiPlatform.Linux) {
|
CompositionLocalProvider(LocalUiPlatform provides UiPlatform.Android) {
|
||||||
VniDropTheme(isDarkTheme = false) {
|
VniDropTheme(isDarkTheme = false) {
|
||||||
Row {
|
Row {
|
||||||
Box(Modifier.size(500.dp)) {
|
Box(Modifier.size(500.dp)) {
|
||||||
TransferCatalog(
|
TransferCatalog(
|
||||||
transfers = emptyList(),
|
transfers = emptyList(),
|
||||||
transferThumbnails = emptyMap(),
|
transferThumbnails = emptyMap(),
|
||||||
windowClass = WindowClass.Desktop,
|
windowClass = WindowClass.Phone,
|
||||||
onOpenComposer = {},
|
onOpenComposer = {},
|
||||||
onTransferSelected = {},
|
onTransferSelected = {},
|
||||||
)
|
)
|
||||||
@@ -318,7 +318,7 @@ class FoundationComposeTest {
|
|||||||
ReceiveScreen(
|
ReceiveScreen(
|
||||||
coreState = CoreState(isInitialized = true),
|
coreState = CoreState(isInitialized = true),
|
||||||
state = ReceiveState(),
|
state = ReceiveState(),
|
||||||
windowClass = WindowClass.Desktop,
|
windowClass = WindowClass.Phone,
|
||||||
actions = actions,
|
actions = actions,
|
||||||
onOpenAcquisition = {},
|
onOpenAcquisition = {},
|
||||||
onDismissAcquisition = {},
|
onDismissAcquisition = {},
|
||||||
|
|||||||
Reference in New Issue
Block a user