forked from LibreMV/GridFlow
fix dashboard bills display and add payment support
This commit is contained in:
250
app/src/main/java/sh/sar/gridflow/PaymentReviewActivity.kt
Normal file
250
app/src/main/java/sh/sar/gridflow/PaymentReviewActivity.kt
Normal file
@@ -0,0 +1,250 @@
|
||||
package sh.sar.gridflow
|
||||
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.view.View
|
||||
import android.widget.Toast
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.appcompat.app.AppCompatDelegate
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import kotlinx.coroutines.launch
|
||||
import sh.sar.gridflow.data.OutstandingBill
|
||||
import sh.sar.gridflow.data.PaymentDetails
|
||||
import sh.sar.gridflow.data.PaymentGateway
|
||||
import sh.sar.gridflow.data.PaymentItem
|
||||
import sh.sar.gridflow.data.PaymentRequest
|
||||
import sh.sar.gridflow.databinding.ActivityPaymentReviewBinding
|
||||
import sh.sar.gridflow.network.ApiResult
|
||||
import sh.sar.gridflow.network.FenakaApiService
|
||||
import sh.sar.gridflow.ui.payment.BillSummaryAdapter
|
||||
import sh.sar.gridflow.ui.payment.PaymentConfirmationDialog
|
||||
import sh.sar.gridflow.ui.payment.PaymentMethodAdapter
|
||||
import sh.sar.gridflow.utils.SecureStorage
|
||||
|
||||
class PaymentReviewActivity : AppCompatActivity() {
|
||||
|
||||
private lateinit var binding: ActivityPaymentReviewBinding
|
||||
private lateinit var secureStorage: SecureStorage
|
||||
private lateinit var apiService: FenakaApiService
|
||||
private lateinit var billSummaryAdapter: BillSummaryAdapter
|
||||
private lateinit var paymentMethodAdapter: PaymentMethodAdapter
|
||||
|
||||
private var outstandingBills: List<OutstandingBill> = emptyList()
|
||||
|
||||
companion object {
|
||||
private const val TAG = "PaymentReviewActivity"
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
// Force system theme (follows device dark mode setting)
|
||||
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM)
|
||||
|
||||
binding = ActivityPaymentReviewBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
|
||||
secureStorage = SecureStorage(this)
|
||||
apiService = FenakaApiService()
|
||||
|
||||
setupViews()
|
||||
loadData()
|
||||
}
|
||||
|
||||
private fun setupViews() {
|
||||
// Setup bills RecyclerView
|
||||
billSummaryAdapter = BillSummaryAdapter()
|
||||
binding.recyclerBills.apply {
|
||||
layoutManager = LinearLayoutManager(this@PaymentReviewActivity)
|
||||
adapter = billSummaryAdapter
|
||||
}
|
||||
|
||||
// Setup payment methods RecyclerView
|
||||
paymentMethodAdapter = PaymentMethodAdapter { paymentMethod ->
|
||||
onPaymentMethodSelected(paymentMethod)
|
||||
}
|
||||
binding.recyclerPaymentMethods.apply {
|
||||
layoutManager = LinearLayoutManager(this@PaymentReviewActivity)
|
||||
adapter = paymentMethodAdapter
|
||||
}
|
||||
}
|
||||
|
||||
private fun loadData() {
|
||||
val cookie = secureStorage.getCookie()
|
||||
if (cookie == null) {
|
||||
Toast.makeText(this, "Authentication required", Toast.LENGTH_SHORT).show()
|
||||
finish()
|
||||
return
|
||||
}
|
||||
|
||||
showLoading(true)
|
||||
|
||||
lifecycleScope.launch {
|
||||
// Load outstanding bills first
|
||||
when (val billsResult = apiService.getOutstandingBills("connect.sid=$cookie")) {
|
||||
is ApiResult.Success -> {
|
||||
outstandingBills = billsResult.data
|
||||
updateBillsUI()
|
||||
|
||||
// Then load payment methods
|
||||
when (val gatewaysResult = apiService.getPaymentGateways("connect.sid=$cookie")) {
|
||||
is ApiResult.Success -> {
|
||||
paymentMethodAdapter.updatePaymentMethods(gatewaysResult.data)
|
||||
showLoading(false)
|
||||
}
|
||||
is ApiResult.Error -> {
|
||||
Log.e(TAG, "Failed to load payment gateways: ${gatewaysResult.message}")
|
||||
showLoading(false)
|
||||
Toast.makeText(this@PaymentReviewActivity, "Failed to load payment methods", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
is ApiResult.Error -> {
|
||||
Log.e(TAG, "Failed to load outstanding bills: ${billsResult.message}")
|
||||
showLoading(false)
|
||||
Toast.makeText(this@PaymentReviewActivity, "Failed to load bills", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateBillsUI() {
|
||||
billSummaryAdapter.updateBills(outstandingBills)
|
||||
|
||||
// Calculate total bills count
|
||||
val totalBillCount = outstandingBills.sumOf { bill ->
|
||||
try {
|
||||
bill.outstandingBillCount.toInt()
|
||||
} catch (e: NumberFormatException) {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate total amount
|
||||
val totalAmount = outstandingBills.sumOf { bill ->
|
||||
try {
|
||||
bill.outstandingAmount.toDouble()
|
||||
} catch (e: NumberFormatException) {
|
||||
0.0
|
||||
}
|
||||
}
|
||||
|
||||
binding.textBillCount.text = "You are paying a total of $totalBillCount bills"
|
||||
binding.textTotalAmount.text = "MVR ${String.format("%.2f", totalAmount)}"
|
||||
}
|
||||
|
||||
private fun showLoading(show: Boolean) {
|
||||
binding.layoutLoading.visibility = if (show) View.VISIBLE else View.GONE
|
||||
binding.recyclerPaymentMethods.visibility = if (show) View.GONE else View.VISIBLE
|
||||
}
|
||||
|
||||
private fun onPaymentMethodSelected(paymentMethod: PaymentGateway) {
|
||||
Log.d(TAG, "Payment method selected: ${paymentMethod.name} (${paymentMethod.code})")
|
||||
|
||||
// Show payment confirmation dialog
|
||||
PaymentConfirmationDialog.show(
|
||||
context = this,
|
||||
paymentGateway = paymentMethod,
|
||||
onContinue = { dialog ->
|
||||
if (paymentMethod.code == "bml") {
|
||||
processBmlPayment(dialog)
|
||||
} else {
|
||||
Toast.makeText(this, "Not yet implemented.. use BML", Toast.LENGTH_SHORT).show()
|
||||
dialog.dismiss()
|
||||
}
|
||||
},
|
||||
onCancel = {
|
||||
Log.d(TAG, "Payment cancelled by user")
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
private fun processBmlPayment(dialog: PaymentConfirmationDialog) {
|
||||
val cookie = secureStorage.getCookie()
|
||||
if (cookie == null) {
|
||||
Toast.makeText(this, "Authentication required", Toast.LENGTH_SHORT).show()
|
||||
dialog.dismiss()
|
||||
return
|
||||
}
|
||||
|
||||
Log.d(TAG, "Processing BML payment...")
|
||||
dialog.showLoading(true)
|
||||
|
||||
lifecycleScope.launch {
|
||||
try {
|
||||
// Create payment items from outstanding bills
|
||||
val paymentItems = outstandingBills.map { bill ->
|
||||
PaymentItem(
|
||||
id = bill.subscriptionId,
|
||||
type = "subscription",
|
||||
amount = bill.outstandingAmount.toDoubleOrNull() ?: 0.0
|
||||
)
|
||||
}
|
||||
|
||||
val paymentRequest = PaymentRequest(
|
||||
gateway = "bml",
|
||||
details = PaymentDetails(items = paymentItems)
|
||||
)
|
||||
|
||||
// Step 1: Initiate payment
|
||||
when (val paymentResult = apiService.initiatePayment(paymentRequest, "connect.sid=$cookie")) {
|
||||
is ApiResult.Success -> {
|
||||
val paymentResponse = paymentResult.data
|
||||
Log.d(TAG, "Payment initiated successfully. ID: ${paymentResponse.id}")
|
||||
|
||||
// Calculate total amount
|
||||
val totalAmount = paymentItems.sumOf { it.amount }
|
||||
|
||||
// Step 2: Get redirect URL
|
||||
when (val redirectResult = apiService.getPaymentRedirectUrl(
|
||||
gateway = "bml",
|
||||
reference = paymentResponse.id,
|
||||
amount = totalAmount,
|
||||
cookie = "connect.sid=$cookie"
|
||||
)) {
|
||||
is ApiResult.Success -> {
|
||||
val redirectUrl = redirectResult.data
|
||||
Log.d(TAG, "Got redirect URL: $redirectUrl")
|
||||
|
||||
// Open browser with redirect URL
|
||||
openBrowser(redirectUrl)
|
||||
dialog.dismiss()
|
||||
|
||||
// Take user back (finish activity)
|
||||
finish()
|
||||
}
|
||||
is ApiResult.Error -> {
|
||||
Log.e(TAG, "Failed to get redirect URL: ${redirectResult.message}")
|
||||
dialog.showLoading(false)
|
||||
Toast.makeText(this@PaymentReviewActivity, "Failed to get payment URL", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
is ApiResult.Error -> {
|
||||
Log.e(TAG, "Failed to initiate payment: ${paymentResult.message}")
|
||||
dialog.showLoading(false)
|
||||
Toast.makeText(this@PaymentReviewActivity, "Failed to initiate payment", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Error processing BML payment", e)
|
||||
dialog.showLoading(false)
|
||||
Toast.makeText(this@PaymentReviewActivity, "Payment processing error", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun openBrowser(url: String) {
|
||||
try {
|
||||
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(url))
|
||||
startActivity(intent)
|
||||
Log.d(TAG, "Opened browser with URL: $url")
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Failed to open browser", e)
|
||||
Toast.makeText(this, "Failed to open browser", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user