Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Receipt UI #53

Merged
merged 10 commits into from
Apr 6, 2024
6 changes: 5 additions & 1 deletion app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,13 @@ dependencies {
implementation("androidx.core:core-ktx:1.12.0")
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.7.0")
implementation("androidx.activity:activity-compose:1.8.2")

implementation("androidx.compose.material3:material3:1.2.1")
implementation("androidx.compose.material3:material3-android:1.2.1")
implementation("androidx.navigation:navigation-compose:2.6.0-rc01")

implementation("androidx.compose.ui:ui:1.6.4")
implementation("androidx.compose.ui:ui-tooling-preview:1.6.4")
implementation("androidx.compose.material:material:1.6.4")
implementation("androidx.compose.material3:material3:1.2.1")
implementation("androidx.navigation:navigation-compose:2.7.7")

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package com.github.se.assocify.screens

import androidx.compose.ui.test.assertIsDisplayed
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onNodeWithTag
import androidx.compose.ui.test.performClick
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.github.se.assocify.navigation.NavigationActions
import com.github.se.assocify.ui.screens.treasury.receipt.ReceiptScreen
import com.kaspersky.components.composesupport.config.withComposeSupport
import com.kaspersky.kaspresso.kaspresso.Kaspresso
import com.kaspersky.kaspresso.testcases.api.testcase.TestCase
import io.mockk.every
import io.mockk.mockk
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith

@RunWith(AndroidJUnit4::class)
class ReceiptScreenTest : TestCase(kaspressoBuilder = Kaspresso.Builder.withComposeSupport()) {
@get:Rule val composeTestRule = createComposeRule()

private val navActions = mockk<NavigationActions>()
private var tabSelected = false

@Before
fun testSetup() {
every { navActions.back() } answers { tabSelected = true }
composeTestRule.setContent { ReceiptScreen(navActions = navActions) }
}

@Test
fun display() {
with(composeTestRule) {
onNodeWithTag("receiptScreen").assertIsDisplayed()
onNodeWithTag("titleField").assertIsDisplayed()
onNodeWithTag("descriptionField").assertIsDisplayed()
onNodeWithTag("dateField").assertIsDisplayed()
onNodeWithTag("backButton").assertIsDisplayed()
}
}

@Test
fun back() {
with(composeTestRule) {
onNodeWithTag("backButton").performClick()
assert(tabSelected)
}
}

@Test
fun datePicker() {
with(composeTestRule) {
onNodeWithTag("dateField").performClick()
onNodeWithTag("datePickerDialog").assertIsDisplayed()
onNodeWithTag("datePickerDialogDismiss").performClick()
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@ sealed class Destination(
data object Profile :
Destination("profile", R.string.profile_tab_label, R.drawable.profile_tab_icon)

data object Login : Destination("login", R.string.login_page_label)
data object Login : Destination("login")

// data class Receipt(val id: String) : Destination("receipt/$id")
}

val MAIN_TABS_LIST =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,8 @@ class NavigationActions(private val navController: NavHostController) {
fun onAuthError() {
/* Handle auth error */
}

fun back() {
/*TODO handle back navigation*/
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it intentional or did you forget to modify the TODO?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Everything seems to work well. I wrote a preview that seems to work as intended, the application still works as before and the test pass. However all the TODOS make it difficult to understand what was forgetten and what is expected to be finished in the next weeks.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Many of them will be fixed next week when I do the functionality of this part and link things together. I'll make sure to double check that I fix all of them in my next PR :)

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package com.github.se.assocify.ui.composables

import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.material3.Button
import androidx.compose.material3.DatePicker
import androidx.compose.material3.DatePickerDialog
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.SelectableDates
import androidx.compose.material3.Text
import androidx.compose.material3.rememberDatePickerState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.platform.testTag
import java.time.Instant
import java.time.LocalDate
import java.time.ZoneId

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun DatePickerWithDialog(
modifier: Modifier = Modifier,
label: @Composable () -> Unit,
dateValue: String,
onDateSelected: (LocalDate?) -> Unit
) {
var showDialog by remember { mutableStateOf(false) }
val datePickerState =
rememberDatePickerState(
selectableDates =
object : SelectableDates {
override fun isSelectableDate(utcTimeMillis: Long): Boolean {
return utcTimeMillis >=
LocalDate.now()
.atStartOfDay()
.atZone(ZoneId.systemDefault())
.toInstant()
.toEpochMilli()
}
})
val selectedDate =
datePickerState.selectedDateMillis?.let {
Instant.ofEpochMilli(it).atZone(ZoneId.systemDefault()).toLocalDate()
}

Box {
OutlinedTextField(
modifier = modifier,
value = dateValue,
onValueChange = {},
readOnly = true,
label = { label() },
placeholder = { Text("--/--/--") })
Box(modifier = Modifier.matchParentSize().alpha(0f).clickable(onClick = { showDialog = true }))
}

if (showDialog) {
DatePickerDialog(
modifier = Modifier.testTag("datePickerDialog"),
onDismissRequest = { showDialog = false },
confirmButton = {
Button(
onClick = {
showDialog = false
onDateSelected(selectedDate)
}) {
Text(text = "OK")
}
},
dismissButton = {
Button(
modifier = Modifier.testTag("datePickerDialogDismiss"),
onClick = { showDialog = false }) {
Text(text = "Cancel")
}
}) {
DatePicker(state = datePickerState, showModeToggle = true)
}
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
package com.github.se.assocify.ui.screens.treasury

import androidx.compose.foundation.layout.padding
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Add
import androidx.compose.material3.FloatingActionButton
import androidx.compose.material3.Icon
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
Expand All @@ -20,6 +24,11 @@ fun TreasuryScreen(navActions: NavigationActions) {
onTabSelect = { navActions.navigateToMainTab(it) },
tabList = MAIN_TABS_LIST,
selectedTab = Destination.Treasury)
},
floatingActionButton = {
FloatingActionButton(onClick = { /*TODO*/}) {
Icon(Icons.Filled.Add, contentDescription = "Add")
}
}) {
Text(modifier = Modifier.padding(it), text = "Treasury Screen")
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package com.github.se.assocify.ui.screens.treasury.receipt

import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MediumTopAppBar
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.testTag
import com.github.se.assocify.navigation.NavigationActions
import com.github.se.assocify.ui.composables.DatePickerWithDialog

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun ReceiptScreen(navActions: NavigationActions) {
Scaffold(
modifier = Modifier.testTag("receiptScreen"),
topBar = {
MediumTopAppBar(
title = { Text("New Receipt") },
navigationIcon = {
IconButton(
modifier = Modifier.testTag("backButton"), onClick = { navActions.back() }) {
Icon(Icons.Default.ArrowBack, contentDescription = "Back")
}
})
},
) {
LazyColumn(
modifier = Modifier.fillMaxSize(),
contentPadding = it,
horizontalAlignment = Alignment.CenterHorizontally) {
item {
OutlinedTextField(
modifier = Modifier.testTag("titleField"),
value = "",
onValueChange = { /*TODO*/},
label = { Text("Title") })
OutlinedTextField(
modifier = Modifier.testTag("descriptionField"),
value = "",
onValueChange = { /*TODO*/},
label = { Text("Description") },
minLines = 3)
DatePickerWithDialog(
modifier = Modifier.testTag("dateField"),
label = { Text("Date") },
dateValue = "",
onDateSelected = { /*TODO*/})
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,5 +35,7 @@ class NavigationActionsTest {

navActions.onAuthError()
navActions.onLogin(user)

navActions.back()
}
}
Loading