mirror of
https://github.com/openMF/mobile-wallet.git
synced 2026-02-06 11:36:57 +00:00
moved invoice to feature module (#1663)
This commit is contained in:
parent
eea58d0464
commit
85c15b4bd5
1
feature/invoices/.gitignore
vendored
Normal file
1
feature/invoices/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
/build
|
||||
14
feature/invoices/build.gradle.kts
Normal file
14
feature/invoices/build.gradle.kts
Normal file
@ -0,0 +1,14 @@
|
||||
plugins {
|
||||
alias(libs.plugins.mifospay.android.feature)
|
||||
alias(libs.plugins.mifospay.android.library.compose)
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "org.mifospay.invoices"
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(projects.core.data)
|
||||
implementation(projects.feature.receipt)
|
||||
implementation(libs.androidx.appcompat)
|
||||
}
|
||||
0
feature/invoices/consumer-rules.pro
Normal file
0
feature/invoices/consumer-rules.pro
Normal file
21
feature/invoices/proguard-rules.pro
vendored
Normal file
21
feature/invoices/proguard-rules.pro
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
# Add project specific ProGuard rules here.
|
||||
# You can control the set of applied configuration files using the
|
||||
# proguardFiles setting in build.gradle.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# If your project uses WebView with JS, uncomment the following
|
||||
# and specify the fully qualified class name to the JavaScript interface
|
||||
# class:
|
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||
# public *;
|
||||
#}
|
||||
|
||||
# Uncomment this to preserve the line number information for
|
||||
# debugging stack traces.
|
||||
#-keepattributes SourceFile,LineNumberTable
|
||||
|
||||
# If you keep the line number information, uncomment this to
|
||||
# hide the original source file name.
|
||||
#-renamesourcefileattribute SourceFile
|
||||
@ -0,0 +1,24 @@
|
||||
package org.mifospay.invoices
|
||||
|
||||
import androidx.test.platform.app.InstrumentationRegistry
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
import org.junit.Assert.*
|
||||
|
||||
/**
|
||||
* Instrumented test, which will execute on an Android device.
|
||||
*
|
||||
* See [testing documentation](http://d.android.com/tools/testing).
|
||||
*/
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class ExampleInstrumentedTest {
|
||||
@Test
|
||||
fun useAppContext() {
|
||||
// Context of the app under test.
|
||||
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
|
||||
assertEquals("org.mifospay.invoices.test", appContext.packageName)
|
||||
}
|
||||
}
|
||||
4
feature/invoices/src/main/AndroidManifest.xml
Normal file
4
feature/invoices/src/main/AndroidManifest.xml
Normal file
@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
</manifest>
|
||||
@ -0,0 +1,21 @@
|
||||
package org.mifospay.feature.invoices
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import org.mifospay.core.designsystem.theme.MifosTheme
|
||||
|
||||
|
||||
@AndroidEntryPoint
|
||||
class InvoiceActivity : AppCompatActivity() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
val data = intent.data
|
||||
setContent {
|
||||
MifosTheme {
|
||||
InvoiceDetailScreen(data = data,onBackPress = { finish() })
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,309 @@
|
||||
package org.mifospay.feature.invoices
|
||||
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.gestures.detectTapGestures
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
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.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.input.pointer.pointerInput
|
||||
import androidx.compose.ui.platform.LocalClipboardManager
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.AnnotatedString
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.mifospay.core.model.entity.Invoice
|
||||
import com.mifospay.core.model.utils.DateHelper
|
||||
|
||||
import org.mifospay.common.Constants
|
||||
import org.mifospay.core.designsystem.component.MfOverlayLoadingWheel
|
||||
import org.mifospay.core.designsystem.component.MifosScaffold
|
||||
import org.mifospay.core.designsystem.theme.MifosTheme
|
||||
import org.mifospay.core.designsystem.theme.primaryDarkBlue
|
||||
import org.mifospay.core.ui.ErrorScreenContent
|
||||
import org.mifospay.feature.receipt.ReceiptActivity
|
||||
import org.mifospay.invoices.R
|
||||
|
||||
@Composable
|
||||
fun InvoiceDetailScreen(
|
||||
viewModel: InvoiceDetailViewModel = hiltViewModel(),
|
||||
data: Uri?,
|
||||
onBackPress: () -> Unit
|
||||
) {
|
||||
val invoiceDetailUiState by viewModel.invoiceDetailUiState.collectAsStateWithLifecycle()
|
||||
InvoiceDetailScreen(invoiceDetailUiState = invoiceDetailUiState, onBackPress = onBackPress)
|
||||
LaunchedEffect(key1 = true) {
|
||||
viewModel.getInvoiceDetails(data)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun InvoiceDetailScreen(
|
||||
invoiceDetailUiState: InvoiceDetailUiState, onBackPress: () -> Unit
|
||||
) {
|
||||
MifosScaffold(
|
||||
topBarTitle = R.string.feature_invoices_invoice,
|
||||
backPress = { onBackPress.invoke() },
|
||||
scaffoldContent = {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.background(Color.White)
|
||||
.padding(it)
|
||||
) {
|
||||
when (invoiceDetailUiState) {
|
||||
is InvoiceDetailUiState.Error -> {
|
||||
ErrorScreenContent()
|
||||
}
|
||||
|
||||
InvoiceDetailUiState.Loading -> {
|
||||
MfOverlayLoadingWheel(
|
||||
contentDesc = stringResource(R.string.feature_invoices_loading)
|
||||
)
|
||||
}
|
||||
|
||||
is InvoiceDetailUiState.Success -> {
|
||||
InvoiceDetailsContent(
|
||||
invoiceDetailUiState.invoice,
|
||||
invoiceDetailUiState.merchantId,
|
||||
invoiceDetailUiState.paymentLink
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun InvoiceDetailsContent(invoice: Invoice?, merchantId: String?, paymentLink: String?) {
|
||||
val clipboardManager = LocalClipboardManager.current
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp)
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
Text(
|
||||
text = stringResource(R.string.feature_invoices_invoice_details),
|
||||
modifier = Modifier.padding(top = 16.dp)
|
||||
)
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Text(
|
||||
text = stringResource(R.string.feature_invoices_merchant_id),
|
||||
modifier = Modifier.padding(top = 16.dp)
|
||||
)
|
||||
Text(
|
||||
text = merchantId.toString(),
|
||||
modifier = Modifier.padding(top = 16.dp)
|
||||
)
|
||||
}
|
||||
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Text(
|
||||
text = stringResource(R.string.feature_invoices_consumer_id),
|
||||
modifier = Modifier.padding(top = 8.dp)
|
||||
)
|
||||
Text(
|
||||
text = (invoice?.consumerName + " " + invoice?.consumerId),
|
||||
modifier = Modifier.padding(top = 8.dp)
|
||||
)
|
||||
}
|
||||
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Text(
|
||||
text = stringResource(id = R.string.feature_invoices_amount),
|
||||
modifier = Modifier.padding(top = 8.dp)
|
||||
)
|
||||
Text(
|
||||
text = Constants.INR + " " + invoice?.amount + "",
|
||||
modifier = Modifier.padding(top = 8.dp)
|
||||
)
|
||||
}
|
||||
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Text(
|
||||
text = stringResource(id = R.string.feature_invoices_items_bought),
|
||||
modifier = Modifier.padding(top = 8.dp)
|
||||
)
|
||||
Text(
|
||||
text = invoice?.itemsBought.toString(),
|
||||
modifier = Modifier.padding(top = 8.dp)
|
||||
)
|
||||
}
|
||||
|
||||
if (invoice?.status == 1L) {
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Text(
|
||||
text = stringResource(id = R.string.feature_invoices_status),
|
||||
modifier = Modifier.padding(top = 8.dp)
|
||||
)
|
||||
|
||||
Text(
|
||||
text = Constants.DONE,
|
||||
modifier = Modifier.padding(top = 8.dp)
|
||||
)
|
||||
}
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Text(
|
||||
text = stringResource(id = R.string.feature_invoices_transaction_id),
|
||||
color = primaryDarkBlue,
|
||||
modifier = Modifier
|
||||
.padding(top = 10.dp)
|
||||
)
|
||||
Text(
|
||||
text = invoice.transactionId ?: "",
|
||||
color = primaryDarkBlue,
|
||||
modifier = Modifier
|
||||
.padding(top = 10.dp)
|
||||
.then(Modifier.height(0.dp))
|
||||
)
|
||||
}
|
||||
Divider()
|
||||
Text(
|
||||
text = stringResource(id = R.string.feature_invoices_unique_receipt_link),
|
||||
fontWeight = FontWeight.Normal,
|
||||
modifier = Modifier.padding(bottom = 10.dp)
|
||||
)
|
||||
Text(
|
||||
text = invoice.transactionId ?: "",
|
||||
color = primaryDarkBlue,
|
||||
modifier = Modifier
|
||||
.padding(top = 10.dp)
|
||||
.pointerInput(Unit) {
|
||||
detectTapGestures(
|
||||
onPress = {
|
||||
val intent = Intent(context, ReceiptActivity::class.java)
|
||||
intent.data = Uri.parse(
|
||||
Constants.RECEIPT_DOMAIN + invoice.transactionId
|
||||
)
|
||||
context.startActivity(intent)
|
||||
},
|
||||
onLongPress = {
|
||||
clipboardManager.setText(AnnotatedString(Constants.RECEIPT_DOMAIN + invoice.transactionId))
|
||||
})
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Text(
|
||||
text = stringResource(id = R.string.feature_invoices_date),
|
||||
modifier = Modifier.padding(top = 10.dp)
|
||||
)
|
||||
Text(
|
||||
text = DateHelper.getDateAsString(invoice!!.date),
|
||||
modifier = Modifier.padding(top = 10.dp)
|
||||
)
|
||||
}
|
||||
|
||||
Divider()
|
||||
Text(
|
||||
text = stringResource(id = R.string.feature_invoices_payment_options_will_be_fetched_from_upi),
|
||||
fontWeight = FontWeight.Normal,
|
||||
modifier = Modifier.padding(vertical = 10.dp)
|
||||
)
|
||||
Divider()
|
||||
Text(
|
||||
text = stringResource(id = R.string.feature_invoices_unique_payment_link),
|
||||
fontWeight = FontWeight.Normal,
|
||||
modifier = Modifier.padding(bottom = 10.dp)
|
||||
)
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Text(
|
||||
text = paymentLink.toString(),
|
||||
color = primaryDarkBlue,
|
||||
modifier = Modifier
|
||||
.padding(top = 10.dp)
|
||||
.pointerInput(Unit) {
|
||||
detectTapGestures(
|
||||
onLongPress = {
|
||||
clipboardManager.setText(AnnotatedString(paymentLink.toString()))
|
||||
})
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun Divider(modifier: Modifier = Modifier) {
|
||||
Box(
|
||||
modifier = modifier
|
||||
.fillMaxWidth()
|
||||
.height(1.dp)
|
||||
.background(Color(0x44000000))
|
||||
)
|
||||
}
|
||||
|
||||
class InvoiceDetailScreenProvider : PreviewParameterProvider<InvoiceDetailUiState> {
|
||||
override val values: Sequence<InvoiceDetailUiState>
|
||||
get() = sequenceOf(
|
||||
InvoiceDetailUiState.Loading,
|
||||
InvoiceDetailUiState.Error("Some Error Occurred"),
|
||||
InvoiceDetailUiState.Success(Invoice(), "", "")
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
@Preview(showBackground = true, showSystemUi = true)
|
||||
@Composable
|
||||
fun InvoiceDetailScreenPreview(
|
||||
@PreviewParameter(InvoiceDetailScreenProvider::class) invoiceDetailUiState: InvoiceDetailUiState
|
||||
) {
|
||||
MifosTheme {
|
||||
InvoiceDetailScreen(invoiceDetailUiState = invoiceDetailUiState) {}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,53 @@
|
||||
package org.mifospay.feature.invoices
|
||||
|
||||
import android.net.Uri
|
||||
import androidx.lifecycle.ViewModel
|
||||
import com.mifospay.core.model.entity.Invoice
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import org.mifospay.core.data.base.UseCase
|
||||
import org.mifospay.core.data.base.UseCaseHandler
|
||||
import org.mifospay.core.data.domain.usecase.invoice.FetchInvoice
|
||||
import org.mifospay.core.datastore.PreferencesHelper
|
||||
import javax.inject.Inject
|
||||
|
||||
@HiltViewModel
|
||||
class InvoiceDetailViewModel @Inject constructor(
|
||||
private val mUseCaseHandler: UseCaseHandler,
|
||||
private val mPreferencesHelper: PreferencesHelper,
|
||||
private val fetchInvoiceUseCase: FetchInvoice
|
||||
) : ViewModel() {
|
||||
|
||||
private val _invoiceDetailUiState =
|
||||
MutableStateFlow<InvoiceDetailUiState>(InvoiceDetailUiState.Loading)
|
||||
val invoiceDetailUiState: StateFlow<InvoiceDetailUiState> = _invoiceDetailUiState
|
||||
|
||||
fun getInvoiceDetails(data: Uri?) {
|
||||
mUseCaseHandler.execute(fetchInvoiceUseCase, FetchInvoice.RequestValues(data),
|
||||
object : UseCase.UseCaseCallback<FetchInvoice.ResponseValue> {
|
||||
override fun onSuccess(response: FetchInvoice.ResponseValue) {
|
||||
_invoiceDetailUiState.value = InvoiceDetailUiState.Success(
|
||||
response.invoices[0],
|
||||
mPreferencesHelper.fullName + " "
|
||||
+ mPreferencesHelper.clientId, data.toString()
|
||||
)
|
||||
}
|
||||
|
||||
override fun onError(message: String) {
|
||||
_invoiceDetailUiState.value = InvoiceDetailUiState.Error(message)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
sealed interface InvoiceDetailUiState {
|
||||
data object Loading : InvoiceDetailUiState
|
||||
data class Success(
|
||||
val invoice: Invoice?,
|
||||
val merchantId: String?,
|
||||
val paymentLink: String?
|
||||
) : InvoiceDetailUiState
|
||||
|
||||
data class Error(val message: String) : InvoiceDetailUiState
|
||||
}
|
||||
@ -0,0 +1,121 @@
|
||||
package org.mifospay.feature.invoices
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
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.foundation.layout.size
|
||||
import androidx.compose.material3.Card
|
||||
import androidx.compose.material3.CardDefaults
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import org.mifospay.R
|
||||
import org.mifospay.core.designsystem.theme.grey
|
||||
|
||||
@Composable
|
||||
fun InvoiceItem(
|
||||
invoiceTitle: String,
|
||||
invoiceAmount: String,
|
||||
invoiceStatus: String,
|
||||
invoiceDate: String,
|
||||
invoiceId: String,
|
||||
invoiceStatusIcon: Long,
|
||||
onClick: (String) -> Unit
|
||||
) {
|
||||
Card(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(4.dp)
|
||||
.clickable { onClick(invoiceId) },
|
||||
elevation = CardDefaults.cardElevation(4.dp),
|
||||
colors = CardDefaults.cardColors(Color.White)
|
||||
) {
|
||||
Column {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(10.dp),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Icon(
|
||||
painter = painterResource(
|
||||
id = if (invoiceStatusIcon == 0L) R.drawable.ic_remove_circle_outline_black_24dp
|
||||
else R.drawable.ic_check_round_black_24dp
|
||||
),
|
||||
contentDescription = "Invoice Status",
|
||||
modifier = Modifier
|
||||
.size(64.dp)
|
||||
.padding(5.dp),
|
||||
tint = if (invoiceStatusIcon == 0L) Color.Yellow else Color.Blue
|
||||
)
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(end = 10.dp)
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Text(
|
||||
text = invoiceTitle,
|
||||
color = Color.Black,
|
||||
modifier = Modifier.weight(1f)
|
||||
)
|
||||
Text(
|
||||
text = invoiceAmount,
|
||||
color = Color.Black,
|
||||
textAlign = TextAlign.End,
|
||||
modifier = Modifier.weight(1f)
|
||||
)
|
||||
}
|
||||
Text(
|
||||
text = invoiceStatus,
|
||||
color = grey,
|
||||
modifier = Modifier.padding(top = 1.dp)
|
||||
)
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
) {
|
||||
Text(
|
||||
text = invoiceDate,
|
||||
color = grey,
|
||||
modifier = Modifier.weight(1f)
|
||||
)
|
||||
Text(
|
||||
text = invoiceId,
|
||||
color = grey,
|
||||
textAlign = TextAlign.End,
|
||||
modifier = Modifier.weight(1f)
|
||||
)
|
||||
}
|
||||
Spacer(
|
||||
modifier = Modifier
|
||||
.padding(top = 10.dp)
|
||||
.fillMaxWidth()
|
||||
.height(1.dp)
|
||||
.background(Color.Gray)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(showBackground = true)
|
||||
@Composable
|
||||
fun PreviewInvoiceItem() {
|
||||
InvoiceItem("Logo for Richard", "$3000", "Pending", "12/3/4", "Invoice id:12345", 0L) {}
|
||||
}
|
||||
@ -0,0 +1,128 @@
|
||||
package org.mifospay.feature.invoices
|
||||
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.mifospay.core.model.entity.Invoice
|
||||
import org.mifospay.R
|
||||
import org.mifospay.core.designsystem.component.MifosLoadingWheel
|
||||
import org.mifospay.core.designsystem.icon.MifosIcons.Info
|
||||
import org.mifospay.core.designsystem.theme.MifosTheme
|
||||
import org.mifospay.core.ui.EmptyContentScreen
|
||||
|
||||
@Composable
|
||||
fun InvoiceScreen(
|
||||
viewModel: InvoicesViewModel = hiltViewModel()
|
||||
) {
|
||||
val invoiceUiState by viewModel.invoiceUiState.collectAsStateWithLifecycle()
|
||||
InvoiceScreen(
|
||||
invoiceUiState = invoiceUiState,
|
||||
getUniqueInvoiceLink = { viewModel.getUniqueInvoiceLink(it) }
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun InvoiceScreen(
|
||||
invoiceUiState: InvoicesUiState,
|
||||
getUniqueInvoiceLink: (Long) -> Uri?
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
when (invoiceUiState) {
|
||||
is InvoicesUiState.Error -> {
|
||||
EmptyContentScreen(
|
||||
modifier = Modifier,
|
||||
title = stringResource(id = R.string.error_oops),
|
||||
subTitle = stringResource(id = R.string.unexpected_error_subtitle),
|
||||
iconTint = Color.Black,
|
||||
iconImageVector = Info
|
||||
)
|
||||
}
|
||||
|
||||
is InvoicesUiState.InvoiceList -> {
|
||||
Column(modifier = Modifier.fillMaxSize()) {
|
||||
LazyColumn(modifier = Modifier.fillMaxSize()) {
|
||||
items(invoiceUiState.list) {
|
||||
InvoiceItem(
|
||||
invoiceTitle = it?.title.toString(),
|
||||
invoiceAmount = it?.amount.toString(),
|
||||
invoiceStatus = it?.status.toString(),
|
||||
invoiceDate = it?.date.toString(),
|
||||
invoiceId = it?.id.toString(),
|
||||
invoiceStatusIcon = it?.status!!,
|
||||
onClick = { invoiceId ->
|
||||
val intent = Intent(context, InvoiceActivity::class.java)
|
||||
intent.data = getUniqueInvoiceLink(invoiceId.toLong())
|
||||
context.startActivity(intent)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
InvoicesUiState.Empty -> {
|
||||
EmptyContentScreen(
|
||||
modifier = Modifier,
|
||||
title = stringResource(id = R.string.error_oops),
|
||||
subTitle = stringResource(id = R.string.error_no_invoices_found),
|
||||
iconTint = Color.Black,
|
||||
)
|
||||
}
|
||||
|
||||
InvoicesUiState.Loading -> {
|
||||
MifosLoadingWheel(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
contentDesc = stringResource(R.string.loading)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class InvoicesUiStateProvider : PreviewParameterProvider<InvoicesUiState> {
|
||||
override val values: Sequence<InvoicesUiState>
|
||||
get() = sequenceOf(
|
||||
InvoicesUiState.Loading,
|
||||
InvoicesUiState.Empty,
|
||||
InvoicesUiState.InvoiceList(sampleInvoiceList),
|
||||
InvoicesUiState.Error("Some Error Occurred")
|
||||
)
|
||||
}
|
||||
|
||||
@Preview(showBackground = true, showSystemUi = true)
|
||||
@Composable
|
||||
private fun InvoiceScreenPreview(
|
||||
@PreviewParameter(InvoicesUiStateProvider::class) invoiceUiState: InvoicesUiState
|
||||
) {
|
||||
MifosTheme {
|
||||
InvoiceScreen(invoiceUiState = invoiceUiState, getUniqueInvoiceLink = { Uri.EMPTY })
|
||||
}
|
||||
}
|
||||
|
||||
val sampleInvoiceList = List(10) { index ->
|
||||
Invoice(
|
||||
consumerId = "123456",
|
||||
consumerName = "John Doe",
|
||||
amount = 250.75,
|
||||
itemsBought = "2x Notebook, 1x Pen",
|
||||
status = 1L,
|
||||
transactionId = "txn_78910",
|
||||
id = index.toLong(),
|
||||
title = "Stationery Purchase",
|
||||
date = mutableListOf(2024, 3, 23)
|
||||
)
|
||||
}
|
||||
@ -0,0 +1,60 @@
|
||||
package org.mifospay.feature.invoices
|
||||
|
||||
import android.net.Uri
|
||||
import androidx.lifecycle.ViewModel
|
||||
import com.mifospay.core.model.entity.Invoice
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import org.mifospay.core.data.base.UseCase
|
||||
import org.mifospay.core.data.base.UseCaseHandler
|
||||
import org.mifospay.core.data.domain.usecase.invoice.FetchInvoices
|
||||
import org.mifospay.common.Constants.INVOICE_DOMAIN
|
||||
import org.mifospay.core.datastore.PreferencesHelper
|
||||
import javax.inject.Inject
|
||||
|
||||
@HiltViewModel
|
||||
class InvoicesViewModel @Inject constructor(
|
||||
private val mUseCaseHandler: UseCaseHandler,
|
||||
private val mPreferencesHelper: PreferencesHelper,
|
||||
private val fetchInvoicesUseCase: FetchInvoices
|
||||
) : ViewModel() {
|
||||
|
||||
|
||||
private val _invoiceUiState = MutableStateFlow<InvoicesUiState>(InvoicesUiState.Loading)
|
||||
val invoiceUiState: StateFlow<InvoicesUiState> = _invoiceUiState
|
||||
|
||||
private fun fetchInvoices() {
|
||||
_invoiceUiState.value = InvoicesUiState.Loading
|
||||
mUseCaseHandler.execute(fetchInvoicesUseCase,
|
||||
FetchInvoices.RequestValues(mPreferencesHelper.clientId.toString() + ""),
|
||||
object : UseCase.UseCaseCallback<FetchInvoices.ResponseValue> {
|
||||
override fun onSuccess(response: FetchInvoices.ResponseValue) {
|
||||
if (response.invoiceList.isNotEmpty())
|
||||
_invoiceUiState.value = InvoicesUiState.InvoiceList(response.invoiceList)
|
||||
else _invoiceUiState.value = InvoicesUiState.Empty
|
||||
}
|
||||
|
||||
override fun onError(message: String) {
|
||||
_invoiceUiState.value = InvoicesUiState.Error(message)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fun getUniqueInvoiceLink(id: Long): Uri? {
|
||||
return Uri.parse(
|
||||
INVOICE_DOMAIN + mPreferencesHelper.clientId + "/" + id
|
||||
)
|
||||
}
|
||||
|
||||
init {
|
||||
fetchInvoices()
|
||||
}
|
||||
}
|
||||
|
||||
sealed class InvoicesUiState {
|
||||
data object Loading : InvoicesUiState()
|
||||
data object Empty : InvoicesUiState()
|
||||
data class Error(val message: String) : InvoicesUiState()
|
||||
data class InvoiceList(val list: List<Invoice?>) : InvoicesUiState()
|
||||
}
|
||||
29
feature/invoices/src/main/res/values/strings.xml
Normal file
29
feature/invoices/src/main/res/values/strings.xml
Normal file
@ -0,0 +1,29 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="feature_invoices_invoice">Invoice</string>
|
||||
<string name="feature_invoices_loading">Loading</string>
|
||||
<string name="feature_invoices_invoice_details">Invoice details</string>
|
||||
<string name="feature_invoices_merchant_id">Merchant ID</string>
|
||||
<string name="feature_invoices_consumer_id">Consumer ID</string>
|
||||
<string name="feature_invoices_amount">Amount</string>
|
||||
<string name="feature_invoices_items_bought">items bought</string>
|
||||
<string name="feature_invoices_status">status</string>
|
||||
<string name="feature_invoices_transaction_id">Transaction ID : </string>
|
||||
<string name="feature_invoices_unique_receipt_link">Unique Receipt Link : </string>
|
||||
<string name="feature_invoices_date">date</string>
|
||||
<string name="feature_invoices_payment_options_will_be_fetched_from_upi">Payment Options (will be fetched from
|
||||
UPI)
|
||||
</string>
|
||||
<string name="feature_invoices_unique_payment_link">Unique Payment Link</string>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</resources>
|
||||
@ -0,0 +1,17 @@
|
||||
package org.mifospay.invoices
|
||||
|
||||
import org.junit.Test
|
||||
|
||||
import org.junit.Assert.*
|
||||
|
||||
/**
|
||||
* Example local unit test, which will execute on the development machine (host).
|
||||
*
|
||||
* See [testing documentation](http://d.android.com/tools/testing).
|
||||
*/
|
||||
class ExampleUnitTest {
|
||||
@Test
|
||||
fun addition_isCorrect() {
|
||||
assertEquals(4, 2 + 2)
|
||||
}
|
||||
}
|
||||
@ -44,3 +44,5 @@ include(":feature:editpassword")
|
||||
include(":feature:kyc")
|
||||
include(":feature:savedcards")
|
||||
|
||||
|
||||
include(":feature:invoices")
|
||||
|
||||
Loading…
Reference in New Issue
Block a user