diff --git a/app/src/main/java/com/infomaniak/swisstransfer/ui/components/NewTransferFab.kt b/app/src/main/java/com/infomaniak/swisstransfer/ui/components/NewTransferFab.kt new file mode 100644 index 000000000..51ebd35c3 --- /dev/null +++ b/app/src/main/java/com/infomaniak/swisstransfer/ui/components/NewTransferFab.kt @@ -0,0 +1,58 @@ +/* + * Infomaniak SwissTransfer - Android + * Copyright (C) 2024 Infomaniak Network SA + * + * 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 . + */ + +package com.infomaniak.swisstransfer.ui.components + +import androidx.compose.material3.FloatingActionButtonDefaults +import androidx.compose.material3.FloatingActionButtonElevation +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.dp +import com.infomaniak.swisstransfer.ui.NewTransferActivity +import com.infomaniak.swisstransfer.ui.utils.launchActivity + +@Composable +fun NewTransferFab( + modifier: Modifier = Modifier, + newTransferFabType: NewTransferFabType +) { + val context = LocalContext.current + SwissTransferFab( + modifier = modifier, + fabType = newTransferFabType.fabType, + elevation = newTransferFabType.elevation(), + onClick = { context.launchActivity(NewTransferActivity::class) }, + ) +} + +enum class NewTransferFabType(val fabType: FabType, private val defaultElevation: Dp?) { + BOTTOM_BAR(FabType.NORMAL, null), + EMPTY_STATE(FabType.BIG, null), + NAVIGATION_RAIL(FabType.NORMAL, 0.dp); + + @Composable + fun elevation(): FloatingActionButtonElevation { + return if (defaultElevation != null) { + FloatingActionButtonDefaults.elevation(defaultElevation) + } else { + FloatingActionButtonDefaults.elevation() + } + } +} diff --git a/app/src/main/java/com/infomaniak/swisstransfer/ui/components/SwissTransferFab.kt b/app/src/main/java/com/infomaniak/swisstransfer/ui/components/SwissTransferFab.kt new file mode 100644 index 000000000..5bf88dd2d --- /dev/null +++ b/app/src/main/java/com/infomaniak/swisstransfer/ui/components/SwissTransferFab.kt @@ -0,0 +1,82 @@ +/* + * Infomaniak SwissTransfer - Android + * Copyright (C) 2024 Infomaniak Network SA + * + * 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 . + */ + +package com.infomaniak.swisstransfer.ui.components + +import android.content.res.Configuration +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.shape.CornerBasedShape +import androidx.compose.material3.FloatingActionButton +import androidx.compose.material3.FloatingActionButtonDefaults +import androidx.compose.material3.FloatingActionButtonElevation +import androidx.compose.material3.Icon +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.infomaniak.swisstransfer.R +import com.infomaniak.swisstransfer.ui.icons.AppIcons +import com.infomaniak.swisstransfer.ui.icons.app.Add +import com.infomaniak.swisstransfer.ui.theme.Shapes +import com.infomaniak.swisstransfer.ui.theme.SwissTransferTheme + +@Composable +fun SwissTransferFab( + modifier: Modifier = Modifier, + fabType: FabType = FabType.NORMAL, + elevation: FloatingActionButtonElevation = FloatingActionButtonDefaults.elevation(), + onClick: () -> Unit, +) { + FloatingActionButton( + modifier = modifier.let { if (fabType == FabType.BIG) it.size(80.dp) else it }, + onClick = onClick, + containerColor = SwissTransferTheme.materialColors.primary, + shape = fabType.shape, + elevation = elevation, + ) { + Icon( + imageVector = AppIcons.Add, + contentDescription = stringResource(id = R.string.contentDescriptionCreateNewTransferButton), + ) + } +} + +enum class FabType(val shape: CornerBasedShape) { + NORMAL(Shapes.medium), + BIG(Shapes.large), +} + + +@Preview +@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES or Configuration.UI_MODE_TYPE_NORMAL) +@Composable +private fun SwissTransferFabPreview() { + SwissTransferTheme { + SwissTransferFab(onClick = {}) + } +} + +@Preview +@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES or Configuration.UI_MODE_TYPE_NORMAL) +@Composable +private fun SwissTransferFabBigPreview() { + SwissTransferTheme { + SwissTransferFab(fabType = FabType.BIG, onClick = {}) + } +} diff --git a/app/src/main/java/com/infomaniak/swisstransfer/ui/icons/app/Add.kt b/app/src/main/java/com/infomaniak/swisstransfer/ui/icons/app/Add.kt new file mode 100644 index 000000000..a60af7e80 --- /dev/null +++ b/app/src/main/java/com/infomaniak/swisstransfer/ui/icons/app/Add.kt @@ -0,0 +1,65 @@ +package com.infomaniak.swisstransfer.ui.icons.app + +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.size +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.PathFillType.Companion.NonZero +import androidx.compose.ui.graphics.SolidColor +import androidx.compose.ui.graphics.StrokeCap.Companion.Round +import androidx.compose.ui.graphics.StrokeJoin +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.graphics.vector.ImageVector.Builder +import androidx.compose.ui.graphics.vector.group +import androidx.compose.ui.graphics.vector.path +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.infomaniak.swisstransfer.ui.icons.AppIcons + +val AppIcons.Add: ImageVector + get() { + if (_add != null) { + return _add!! + } + _add = Builder( + name = "Add", + defaultWidth = 24.0.dp, + defaultHeight = 24.0.dp, + viewportWidth = 24.0f, + viewportHeight = 24.0f + ).apply { + group { + path( + fill = null, + stroke = SolidColor(Color(0xFF9f9f9f)), + strokeLineWidth = 2.0f, + strokeLineCap = Round, + strokeLineJoin = StrokeJoin.Round, + strokeLineMiter = 4.0f, + pathFillType = NonZero + ) { + moveTo(1.5f, 12.0f) + horizontalLineToRelative(21.0f) + moveTo(12.0f, 1.5f) + verticalLineToRelative(21.0f) + } + } + }.build() + return _add!! + } + +private var _add: ImageVector? = null + +@Preview +@Composable +private fun Preview() { + Box { + Image( + imageVector = AppIcons.Add, + contentDescription = null, + modifier = Modifier.size(250.dp) + ) + } +} diff --git a/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/main/components/AppNavigationSuiteScaffold.kt b/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/main/components/AppNavigationSuiteScaffold.kt index 4a4baf198..663b0e5bc 100644 --- a/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/main/components/AppNavigationSuiteScaffold.kt +++ b/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/main/components/AppNavigationSuiteScaffold.kt @@ -19,8 +19,6 @@ package com.infomaniak.swisstransfer.ui.screen.main.components import androidx.compose.foundation.layout.* -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.Add import androidx.compose.material3.* import androidx.compose.material3.adaptive.navigationsuite.NavigationSuite import androidx.compose.material3.adaptive.navigationsuite.NavigationSuiteScaffold @@ -29,6 +27,8 @@ import androidx.compose.material3.adaptive.navigationsuite.NavigationSuiteType import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource +import com.infomaniak.swisstransfer.ui.components.NewTransferFab +import com.infomaniak.swisstransfer.ui.components.NewTransferFabType import com.infomaniak.swisstransfer.ui.navigation.MainNavigation import com.infomaniak.swisstransfer.ui.navigation.NavigationItem import com.infomaniak.swisstransfer.ui.theme.Margin @@ -116,9 +116,10 @@ private fun AppNavigationRail( ) { NavigationRail( header = { - FloatingActionButton(onClick = {}, modifier = Modifier.padding(bottom = Margin.Large)) { - Icon(Icons.Default.Add, contentDescription = null) - } + NewTransferFab( + modifier = Modifier.padding(vertical = Margin.Medium), + newTransferFabType = NewTransferFabType.NAVIGATION_RAIL, + ) }, containerColor = SwissTransferTheme.colors.navigationItemBackground ) { @@ -142,4 +143,4 @@ private fun NavigationIcon(isNavigationBar: Boolean, navigationItem: NavigationI @Composable private fun NavigationLabel(navigationItem: NavigationItem) { Text(stringResource(navigationItem.label)) -} \ No newline at end of file +} diff --git a/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/main/received/ReceivedScreen.kt b/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/main/received/ReceivedScreen.kt index 032c1b136..ce5155265 100644 --- a/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/main/received/ReceivedScreen.kt +++ b/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/main/received/ReceivedScreen.kt @@ -18,10 +18,55 @@ package com.infomaniak.swisstransfer.ui.screen.main.received +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Surface import androidx.compose.material3.Text +import androidx.compose.material3.adaptive.navigationsuite.NavigationSuiteType import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import com.infomaniak.swisstransfer.ui.components.NewTransferFab +import com.infomaniak.swisstransfer.ui.components.NewTransferFabType +import com.infomaniak.swisstransfer.ui.screen.main.LocalNavType +import com.infomaniak.swisstransfer.ui.theme.SwissTransferTheme +import com.infomaniak.swisstransfer.ui.utils.PreviewMobile +import com.infomaniak.swisstransfer.ui.utils.PreviewTablet @Composable fun ReceivedScreen(navigateToDetails: (transferId: Int) -> Unit) { - Text("Received screen") + ReceivedScreen(navType = LocalNavType.current) +} + +@Composable +private fun ReceivedScreen(navType: NavigationSuiteType) { + Scaffold( + floatingActionButton = { + if (navType == NavigationSuiteType.NavigationBar) NewTransferFab(newTransferFabType = NewTransferFabType.BOTTOM_BAR) + } + ) { contentPadding -> + Text( + text = "Received screen", + modifier = Modifier.padding(contentPadding), + ) + } +} + +@PreviewMobile +@Composable +private fun ReceivedScreenMobilePreview() { + SwissTransferTheme { + Surface { + ReceivedScreen(navType = NavigationSuiteType.NavigationBar) + } + } +} + +@PreviewTablet +@Composable +private fun ReceivedScreenTabletPreview() { + SwissTransferTheme { + Surface { + ReceivedScreen(navType = NavigationSuiteType.NavigationRail) + } + } } diff --git a/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/main/sent/SentScreen.kt b/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/main/sent/SentScreen.kt index 937ea0cca..a46b20ebb 100644 --- a/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/main/sent/SentScreen.kt +++ b/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/main/sent/SentScreen.kt @@ -18,13 +18,117 @@ package com.infomaniak.swisstransfer.ui.screen.main.sent +import androidx.compose.foundation.layout.* +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Surface import androidx.compose.material3.Text +import androidx.compose.material3.adaptive.navigationsuite.NavigationSuiteType import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.dp +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import androidx.lifecycle.viewmodel.compose.viewModel +import com.infomaniak.swisstransfer.R +import com.infomaniak.swisstransfer.ui.components.NewTransferFab +import com.infomaniak.swisstransfer.ui.components.NewTransferFabType import com.infomaniak.swisstransfer.ui.screen.main.LocalNavType +import com.infomaniak.swisstransfer.ui.theme.Margin +import com.infomaniak.swisstransfer.ui.theme.SwissTransferTheme +import com.infomaniak.swisstransfer.ui.utils.PreviewMobile +import com.infomaniak.swisstransfer.ui.utils.PreviewTablet @Composable -fun SentScreen(navigateToDetails: (transferId: Int) -> Unit) { - val navType = LocalNavType.current +fun SentScreen( + navigateToDetails: (transferId: Int) -> Unit, + sentViewModel: SentViewModel = viewModel(), +) { + val transfers by sentViewModel.transfers.collectAsStateWithLifecycle() + SentScreen( + transfers = transfers, + navType = LocalNavType.current, + ) +} + +@Composable +private fun SentScreen(transfers: List?, navType: NavigationSuiteType) { + if (transfers == null) return + + if (transfers.isEmpty()) { + EmptyScreen() + } else { + TransferScreen(navType) + } +} + +@Composable +fun EmptyScreen() { + Column( + modifier = Modifier.fillMaxSize(), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.Center, + ) { + val maxWidth = 300.dp + Text( + modifier = Modifier.widthIn(max = maxWidth), + text = stringResource(id = R.string.sentEmptyTitle), + style = SwissTransferTheme.typography.specificMedium32, + textAlign = TextAlign.Center, + ) + Spacer(modifier = Modifier.height(Margin.Medium)) + Text( + modifier = Modifier.widthIn(max = maxWidth), + text = stringResource(id = R.string.firstTransferDescription), + style = SwissTransferTheme.typography.bodyRegular + ) + NewTransferFab( + modifier = Modifier.padding(top = Margin.ExtraLarge), + newTransferFabType = NewTransferFabType.EMPTY_STATE, + ) + } +} - Text("Sent screen $navType") +@Composable +private fun TransferScreen( + navType: NavigationSuiteType, +) { + Scaffold( + floatingActionButton = { + if (navType == NavigationSuiteType.NavigationBar) NewTransferFab(newTransferFabType = NewTransferFabType.BOTTOM_BAR) + } + ) { contentPadding -> + Text( + text = "Sent screen", + modifier = Modifier.padding(contentPadding), + ) + } +} + +@PreviewMobile +@Composable +private fun SentScreenMobilePreview() { + SwissTransferTheme { + Surface { + SentScreen( + transfers = emptyList(), + navType = NavigationSuiteType.NavigationBar, + ) + } + } +} + +@PreviewTablet +@Composable +private fun SentScreenTabletPreview() { + SwissTransferTheme { + Surface { + SentScreen( + transfers = emptyList(), + navType = NavigationSuiteType.NavigationRail, + ) + } + } } diff --git a/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/main/sent/SentViewModel.kt b/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/main/sent/SentViewModel.kt new file mode 100644 index 000000000..51e431c74 --- /dev/null +++ b/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/main/sent/SentViewModel.kt @@ -0,0 +1,29 @@ +/* + * Infomaniak SwissTransfer - Android + * Copyright (C) 2024 Infomaniak Network SA + * + * 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 . + */ + +package com.infomaniak.swisstransfer.ui.screen.main.sent + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.flow +import kotlinx.coroutines.flow.stateIn + +class SentViewModel : ViewModel() { + val transfers = flow> { emit(emptyList()) }.stateIn(viewModelScope, SharingStarted.Eagerly, null) +} diff --git a/app/src/main/java/com/infomaniak/swisstransfer/ui/theme/Shapes.kt b/app/src/main/java/com/infomaniak/swisstransfer/ui/theme/Shapes.kt index 5775df830..2e7adb22a 100644 --- a/app/src/main/java/com/infomaniak/swisstransfer/ui/theme/Shapes.kt +++ b/app/src/main/java/com/infomaniak/swisstransfer/ui/theme/Shapes.kt @@ -26,5 +26,6 @@ val Shapes = Shapes( extraSmall = RoundedCornerShape(4.dp), small = RoundedCornerShape(8.dp), medium = RoundedCornerShape(16.dp), + large = RoundedCornerShape(24.dp), extraLarge = RoundedCornerShape(50), ) diff --git a/app/src/main/java/com/infomaniak/swisstransfer/ui/utils/ContextExt.kt b/app/src/main/java/com/infomaniak/swisstransfer/ui/utils/ContextExt.kt new file mode 100644 index 000000000..c30aa7321 --- /dev/null +++ b/app/src/main/java/com/infomaniak/swisstransfer/ui/utils/ContextExt.kt @@ -0,0 +1,30 @@ +/* + * Infomaniak SwissTransfer - Android + * Copyright (C) 2024 Infomaniak Network SA + * + * 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 . + */ + +package com.infomaniak.swisstransfer.ui.utils + +import android.app.Activity +import android.content.Context +import android.content.Intent +import android.os.Bundle +import kotlin.reflect.KClass + + +fun Context.launchActivity(kClass: KClass, options: Bundle? = null) { + startActivity(Intent(this, kClass.java), options) +} diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 3ed730b9a..d93235ceb 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -16,7 +16,10 @@ ~ along with this program. If not, see . --> + New transfer + Make your first transfer! Received + Our story begins here Sent Settings diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index 3ed730b9a..d93235ceb 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -16,7 +16,10 @@ ~ along with this program. If not, see . --> + New transfer + Make your first transfer! Received + Our story begins here Sent Settings diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index c9b45e348..1506968a2 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -16,7 +16,10 @@ ~ along with this program. If not, see . --> + Nouveau transfert + Fais ton premier transfert ! Recu + Notre histoire commence ici Envoyé Paramètres diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index 3ed730b9a..d93235ceb 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -16,7 +16,10 @@ ~ along with this program. If not, see . --> + New transfer + Make your first transfer! Received + Our story begins here Sent Settings diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 65215d957..45f00150a 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -19,7 +19,10 @@ SwissTransfer + New transfer + Make your first transfer! Received + Our story begins here Sent Settings