Skip to content

[Payment Method Improvements] Create the "Record transaction details in order note" section #11569

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

Merged
merged 36 commits into from
May 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
1d30d09
Add a checkbox
backwardstruck May 22, 2024
a18e3c4
Padding and string
backwardstruck May 22, 2024
1f05fc9
Correctly style checkbox
backwardstruck May 22, 2024
dc1ecf6
Detekt
backwardstruck May 22, 2024
10cd940
Make the text larger
backwardstruck May 22, 2024
50307f8
Change to Switch
backwardstruck May 22, 2024
8b64381
Detekt
backwardstruck May 22, 2024
84b6ac4
Add string
backwardstruck May 22, 2024
ea1b9ea
Mark order as complete
backwardstruck May 22, 2024
81c807a
Mark order as complete button
backwardstruck May 22, 2024
cc675bc
Request keyboard
backwardstruck May 22, 2024
1dd1a7e
It doesn't crash
backwardstruck May 22, 2024
88129a9
Debug ff enabled
backwardstruck May 23, 2024
0249d67
Merge branch 'trunk' into 11525-change-due-calculator-ui-part-3
backwardstruck May 23, 2024
551fe3e
We don't want too toolbars
backwardstruck May 23, 2024
431a90c
Should not appear to be editable
backwardstruck May 23, 2024
d0884d2
Padding and whatnot
backwardstruck May 23, 2024
3886f6d
Restore change due label
backwardstruck May 23, 2024
4a993c1
Doesn't need to be bold
backwardstruck May 23, 2024
73f2a26
Use WCMaterialOutlinedCurrencyEditTextView
backwardstruck May 23, 2024
46bdccf
Style WCMaterialOutlinedCurrencyEditTextView
backwardstruck May 23, 2024
2afb4b7
Don't center the toggle
backwardstruck May 23, 2024
47d0c7c
Update navigation pattern
backwardstruck May 24, 2024
8cb793f
Detekt
backwardstruck May 24, 2024
959bbc7
Detekt
backwardstruck May 24, 2024
3dafe68
Detekt
backwardstruck May 24, 2024
a3d162d
Fix unit test
backwardstruck May 24, 2024
7bb9e96
Merge branch '11525-change-due-calculator-ui-part-3' into 11525-chang…
backwardstruck May 24, 2024
6af62c6
Restore the button
backwardstruck May 24, 2024
448e714
Detekt
backwardstruck May 24, 2024
605b295
Leave this false for now
backwardstruck May 24, 2024
d6768bd
Merge branch 'trunk' into 11525-change-due-calculator-ui-part-3
backwardstruck May 24, 2024
958cadc
Merge branch '11525-change-due-calculator-ui-part-3' into 11525-chang…
backwardstruck May 24, 2024
f99dc1d
Pop the keyboard
backwardstruck May 24, 2024
e4f14b7
Merge pull request #11570 from woocommerce/11525-change-due-calculato…
backwardstruck May 27, 2024
484b8d7
Merge branch 'trunk' into 11525-change-due-calculator-ui-part-3
backwardstruck May 27, 2024
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 @@ -10,18 +10,35 @@ import androidx.compose.ui.platform.ComposeView
import androidx.fragment.app.viewModels
import androidx.navigation.fragment.findNavController
import com.woocommerce.android.ui.base.BaseFragment
import com.woocommerce.android.ui.main.AppBarStatus
import dagger.hilt.android.AndroidEntryPoint

@AndroidEntryPoint
class ChangeDueCalculatorFragment : BaseFragment() {

override val activityAppBarStatus: AppBarStatus
get() = AppBarStatus.Hidden

private val viewModel: ChangeDueCalculatorViewModel by viewModels()

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
viewModel.navigationEvent.observe(
this
) {
findNavController().navigateUp()
}
}

override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
return ComposeView(requireContext()).apply {
setContent {
val uiState by viewModel.uiState.collectAsState()
ChangeDueCalculatorScreen(uiState = uiState, onNavigateUp = { findNavController().navigateUp() })
ChangeDueCalculatorScreen(
uiState = uiState,
onNavigateUp = { viewModel.onBackPressed() },
onCompleteOrderClick = {}
)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,41 +1,56 @@
package com.woocommerce.android.ui.payments.changeduecalculator

import android.view.ViewGroup
import android.view.inputmethod.InputMethodManager
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material.Button
import androidx.compose.material.Icon
import androidx.compose.material.IconButton
import androidx.compose.material.LocalTextStyle
import androidx.compose.material.MaterialTheme
import androidx.compose.material.OutlinedTextField
import androidx.compose.material.Scaffold
import androidx.compose.material.Switch
import androidx.compose.material.Text
import androidx.compose.material.TextField
import androidx.compose.material.TopAppBar
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.tooling.preview.PreviewLightDark
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.TextUnit
import androidx.compose.ui.unit.TextUnitType
import androidx.compose.ui.unit.dp
import androidx.compose.ui.viewinterop.AndroidView
import com.woocommerce.android.R
import com.woocommerce.android.ui.compose.theme.WooThemeWithBackground
import com.woocommerce.android.widgets.WCMaterialOutlinedCurrencyEditTextView
import java.math.BigDecimal

@Composable
fun ChangeDueCalculatorScreen(
uiState: ChangeDueCalculatorViewModel.UiState,
onNavigateUp: () -> Unit
onNavigateUp: () -> Unit,
onCompleteOrderClick: () -> Unit
) {
val context = LocalContext.current

WooThemeWithBackground {
Scaffold(
topBar = {
Expand Down Expand Up @@ -63,54 +78,127 @@ fun ChangeDueCalculatorScreen(
) {
when (uiState) {
is ChangeDueCalculatorViewModel.UiState.Loading -> Text(
stringResource(
R.string.loading,
),
stringResource(R.string.loading),
style = MaterialTheme.typography.h6
)

is ChangeDueCalculatorViewModel.UiState.Success -> {
OutlinedTextField(
value = uiState.amountDue,
onValueChange = {
// TODO
val hintString = stringResource(R.string.cash_payments_cash_received)
var view: WCMaterialOutlinedCurrencyEditTextView? by remember { mutableStateOf(null) }

LaunchedEffect(view) {
view?.let {
it.requestFocus()
context.getSystemService(
InputMethodManager::class.java
).showSoftInput(it, InputMethodManager.SHOW_IMPLICIT)
}
}

AndroidView(
factory = { ctx ->
WCMaterialOutlinedCurrencyEditTextView(ctx).apply {
layoutParams = ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT
)
gravity = android.view.Gravity.START
imeOptions = android.view.inputmethod.EditorInfo.IME_FLAG_NO_FULLSCREEN
visibility = android.view.View.VISIBLE
supportsEmptyState = false
supportsNegativeValues = false
hint = hintString
setValueIfDifferent(uiState.amountDue)
view = this
}
},
modifier = Modifier
.fillMaxWidth()
.padding(top = 8.dp, bottom = 8.dp, start = 16.dp),
label = { Text(stringResource(R.string.cash_payments_cash_received)) },
textStyle = LocalTextStyle.current.copy(
fontWeight = FontWeight.Bold,
fontSize = TextUnit(44f, TextUnitType.Sp)
),
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number),
.padding(top = 8.dp, bottom = 8.dp, start = 16.dp)
)

TextField(
value = "$0.00",
onValueChange = {},
Column(
modifier = Modifier
.fillMaxWidth()
.padding(top = 48.dp, bottom = 16.dp, start = 32.dp),
) {
Text(
text = stringResource(R.string.cash_payments_change_due),
style = LocalTextStyle.current.copy(
fontSize = TextUnit(16f, TextUnitType.Sp)
)
)
Spacer(modifier = Modifier.height(8.dp))
Text(
text = "$0.00",
style = LocalTextStyle.current.copy(
fontWeight = FontWeight.Bold,
fontSize = TextUnit(44f, TextUnitType.Sp)
),
maxLines = 1
)
}

RecordTransactionDetailsNote(
modifier = Modifier
.padding(top = 16.dp, bottom = 16.dp, start = 16.dp)
.fillMaxWidth()
.padding(top = 8.dp, bottom = 8.dp, start = 16.dp),
label = { Text(stringResource(R.string.cash_payments_change_due)) },
textStyle = LocalTextStyle.current.copy(
fontWeight = FontWeight.Bold,
fontSize = TextUnit(44f, TextUnitType.Sp)
),
enabled = false,
readOnly = true
)

MarkOrderAsCompleteButton(
onClick = onCompleteOrderClick,
modifier = Modifier.padding(top = 16.dp)
)
}

is ChangeDueCalculatorViewModel.UiState.Error -> {
Text(text = stringResource(R.string.error_generic), style = MaterialTheme.typography.h6)
Text(
text = stringResource(R.string.error_generic),
style = MaterialTheme.typography.h6
)
}
}
}
}
}
}

@Composable
fun RecordTransactionDetailsNote(
modifier: Modifier = Modifier,
checked: Boolean = false,
onCheckedChange: (Boolean) -> Unit = {},
) {
Row(
modifier = modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween
) {
Text(
text = stringResource(R.string.cash_payments_record_transaction_details),
modifier = Modifier.align(Alignment.CenterVertically),
style = LocalTextStyle.current.copy(
fontSize = TextUnit(16f, TextUnitType.Sp)
)
)
Switch(
checked = checked,
onCheckedChange = onCheckedChange
)
}
}

@Composable
fun MarkOrderAsCompleteButton(onClick: () -> Unit, modifier: Modifier = Modifier) {
Button(
onClick = onClick,
modifier = modifier
.fillMaxWidth()
.padding(start = 16.dp, top = 8.dp, end = 16.dp)
) {
Text(text = stringResource(R.string.cash_payments_mark_order_as_complete))
}
}

@Composable
private fun getTitleText(uiState: ChangeDueCalculatorViewModel.UiState): String {
return when (uiState) {
Expand All @@ -124,13 +212,14 @@ private fun getTitleText(uiState: ChangeDueCalculatorViewModel.UiState): String
}

@Composable
@PreviewLightDark()
@Preview(showBackground = true)
fun ChangeDueCalculatorScreenSuccessPreview() {
ChangeDueCalculatorScreen(
uiState = ChangeDueCalculatorViewModel.UiState.Success(
amountDue = "$666.00",
change = 0.00.toBigDecimal()
amountDue = BigDecimal("666.00"),
change = BigDecimal("0.00")
),
onNavigateUp = {}
onNavigateUp = {},
onCompleteOrderClick = {}
)
}
Original file line number Diff line number Diff line change
@@ -1,52 +1,55 @@
package com.woocommerce.android.ui.payments.changeduecalculator

import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.SavedStateHandle
import com.woocommerce.android.tools.SelectedSite
import com.woocommerce.android.ui.orders.details.OrderDetailRepository
import com.woocommerce.android.util.CurrencyFormatter
import com.woocommerce.android.viewmodel.ScopedViewModel
import com.woocommerce.android.viewmodel.navArgs
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.launch
import org.wordpress.android.fluxc.store.WooCommerceStore
import java.math.BigDecimal
import javax.inject.Inject

@HiltViewModel
class ChangeDueCalculatorViewModel @Inject constructor(
private val selectedSite: SelectedSite,
private val currencyFormatter: CurrencyFormatter,
savedStateHandle: SavedStateHandle,
private val wooCommerceStore: WooCommerceStore,
private val orderDetailRepository: OrderDetailRepository
) : ScopedViewModel(savedStateHandle) {

val navArgs: ChangeDueCalculatorFragmentArgs by savedStateHandle.navArgs()
private val orderId: Long = navArgs.orderId

sealed class UiState {
data object Loading : UiState()
data class Success(val amountDue: String, val change: BigDecimal) : UiState()
data class Success(val amountDue: BigDecimal, val change: BigDecimal) : UiState()
data object Error : UiState()
}

private val _uiState = MutableStateFlow<UiState>(UiState.Loading)
val uiState: StateFlow<UiState> = _uiState

private val _navigationEvent = MutableLiveData<Unit>()
val navigationEvent: LiveData<Unit> = _navigationEvent

init {
loadOrderDetails()
}

private fun loadOrderDetails() {
launch {
val order = orderDetailRepository.getOrderById(orderId)!!
_uiState.value = UiState.Success(amountDue = formatOrderTotal(order.total), 0.00.toBigDecimal())
val order = orderDetailRepository.getOrderById(orderId)
order?.let {
_uiState.value = UiState.Success(amountDue = order.total, change = BigDecimal.ZERO)
} ?: run {
_uiState.value = UiState.Error
}
}
}

private fun formatOrderTotal(total: BigDecimal): String {
val currencyCode = wooCommerceStore.getSiteSettings(selectedSite.get())?.currencyCode ?: ""
return currencyFormatter.formatCurrency(total, currencyCode)
fun onBackPressed() {
_navigationEvent.value = Unit
}
}
2 changes: 2 additions & 0 deletions WooCommerce/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -578,6 +578,8 @@
<string name="cash_payments_take_payment_title">Take payment (%s)</string>
<string name="cash_payments_cash_received">Cash received</string>
<string name="cash_payments_change_due">Change due</string>
<string name="cash_payments_record_transaction_details">Record transaction details in order note</string>
<string name="cash_payments_mark_order_as_complete">Mark Order as Complete</string>

<!--
Custom Amounts
Expand Down
Loading
Loading