temp remove Pay any bill from nav menu, added ui for add, delete, edit subs

This commit is contained in:
2025-07-26 18:09:56 +05:00
parent 7499793ff8
commit 86b51fa99b
14 changed files with 1110 additions and 101 deletions

View File

@@ -77,6 +77,11 @@
android:exported="false"
android:label="Payment Review"
android:theme="@style/Theme.GridFlow.NoActionBar" />
<activity
android:name=".AddSubscriptionActivity"
android:exported="false"
android:label="Add Subscription"
android:theme="@style/Theme.GridFlow.NoActionBar" />
<provider
android:name="androidx.core.content.FileProvider"

View File

@@ -0,0 +1,130 @@
package sh.sar.gridflow
import android.content.Intent
import android.os.Bundle
import android.view.MenuItem
import android.widget.Toast
import androidx.appcompat.app.ActionBarDrawerToggle
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.GravityCompat
import androidx.drawerlayout.widget.DrawerLayout
import com.google.android.material.navigation.NavigationView
import sh.sar.gridflow.R
import sh.sar.gridflow.databinding.ActivityAddSubscriptionBinding
class AddSubscriptionActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelectedListener {
private lateinit var binding: ActivityAddSubscriptionBinding
private lateinit var drawerToggle: ActionBarDrawerToggle
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityAddSubscriptionBinding.inflate(layoutInflater)
setContentView(binding.root)
setupViews()
}
private fun setupViews() {
// Setup toolbar with hamburger menu
setSupportActionBar(binding.toolbar)
supportActionBar?.apply {
title = "Add Subscription"
}
// Setup drawer toggle
drawerToggle = ActionBarDrawerToggle(
this, binding.drawerLayout, binding.toolbar,
R.string.navigation_drawer_open, R.string.navigation_drawer_close
)
binding.drawerLayout.addDrawerListener(drawerToggle)
drawerToggle.syncState()
// Setup navigation
binding.navView.setNavigationItemSelectedListener(this)
// Handle continue button click
binding.btnContinue.setOnClickListener {
val subscriptionNumber = binding.editSubscriptionNumber.text.toString().trim()
val billNumber = binding.editBillNumber.text.toString().trim()
val alias = binding.editAlias.text.toString().trim()
if (validateInputs(subscriptionNumber, billNumber, alias)) {
Toast.makeText(this, "Continue action not implemented yet", Toast.LENGTH_SHORT).show()
}
}
}
private fun validateInputs(subscriptionNumber: String, billNumber: String, alias: String): Boolean {
var isValid = true
if (subscriptionNumber.isEmpty()) {
binding.editSubscriptionNumber.error = "Subscription number is required"
isValid = false
}
if (billNumber.isEmpty()) {
binding.editBillNumber.error = "Bill number is required"
isValid = false
}
if (alias.isEmpty()) {
binding.editAlias.error = "Alias/Description is required"
isValid = false
}
return isValid
}
override fun onNavigationItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
R.id.nav_dashboard -> {
val intent = Intent(this, MainActivity::class.java)
intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP
intent.putExtra("navigate_to", "dashboard")
startActivity(intent)
finish()
}
R.id.nav_bill_history -> {
val intent = Intent(this, MainActivity::class.java)
intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP
intent.putExtra("navigate_to", "bill_history")
startActivity(intent)
finish()
}
R.id.nav_subscriptions -> {
val intent = Intent(this, MainActivity::class.java)
intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP
intent.putExtra("navigate_to", "subscriptions")
startActivity(intent)
finish()
}
R.id.nav_band_rates -> {
val intent = Intent(this, MainActivity::class.java)
intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP
intent.putExtra("navigate_to", "band_rates")
startActivity(intent)
finish()
}
R.id.nav_pay_any_bill -> {
val intent = Intent(this, MainActivity::class.java)
intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP
intent.putExtra("navigate_to", "pay_any_bill")
startActivity(intent)
finish()
}
}
binding.drawerLayout.closeDrawer(GravityCompat.START)
return true
}
@Deprecated("Deprecated in Java")
override fun onBackPressed() {
if (binding.drawerLayout.isDrawerOpen(GravityCompat.START)) {
binding.drawerLayout.closeDrawer(GravityCompat.START)
} else {
super.onBackPressed()
}
}
}

View File

@@ -203,6 +203,7 @@ class LoginActivity : AppCompatActivity() {
private fun handlePayWithoutAccount() {
Log.d(TAG, "Pay without account button clicked")
val intent = Intent(this, PayWithoutAccountActivity::class.java)
intent.putExtra("hide_toolbar", true)
startActivity(intent)
}

View File

@@ -10,6 +10,7 @@ import android.view.View
import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.TextView
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.app.AppCompatDelegate
import androidx.drawerlayout.widget.DrawerLayout
@@ -89,10 +90,15 @@ class MainActivity : AppCompatActivity() {
true
}
R.id.nav_pay_any_bill -> {
val intent = Intent(this, PayWithoutAccountActivity::class.java)
startActivity(intent)
drawerLayout.closeDrawers()
true
// Let default navigation handle it (will navigate to PayAnyBillFragment)
try {
navController.navigate(menuItem.itemId)
menuItem.isChecked = true
drawerLayout.closeDrawers()
true
} catch (e: Exception) {
false
}
}
else -> {
// Let the default navigation handle other items
@@ -107,6 +113,30 @@ class MainActivity : AppCompatActivity() {
}
}
}
// Handle navigation extras from other activities
handleNavigationIntent(intent)
}
override fun onNewIntent(intent: Intent?) {
super.onNewIntent(intent)
intent?.let { handleNavigationIntent(it) }
}
private fun handleNavigationIntent(intent: Intent) {
val navigateTo = intent.getStringExtra("navigate_to")
if (navigateTo != null) {
val navController = findNavController(R.id.nav_host_fragment_content_main)
when (navigateTo) {
"dashboard" -> navController.navigate(R.id.nav_dashboard)
"bill_history" -> navController.navigate(R.id.nav_bill_history)
"subscriptions" -> navController.navigate(R.id.nav_subscriptions)
"band_rates" -> navController.navigate(R.id.nav_band_rates)
"pay_any_bill" -> navController.navigate(R.id.nav_pay_any_bill)
}
// Close the drawer
binding.drawerLayout.closeDrawers()
}
}
private fun initializeNavigationHeader(navView: NavigationView) {

View File

@@ -1,13 +1,19 @@
package sh.sar.gridflow
import android.content.Intent
import android.os.Bundle
import android.util.Log
import android.view.MenuItem
import android.view.View
import android.widget.Toast
import androidx.appcompat.app.ActionBarDrawerToggle
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.app.AppCompatDelegate
import androidx.core.view.GravityCompat
import androidx.lifecycle.lifecycleScope
import com.google.android.material.navigation.NavigationView
import kotlinx.coroutines.launch
import sh.sar.gridflow.R
import sh.sar.gridflow.data.BillLookupResponse
import sh.sar.gridflow.databinding.ActivityPayWithoutAccountBinding
import sh.sar.gridflow.network.ApiResult
@@ -15,11 +21,12 @@ import sh.sar.gridflow.network.FenakaApiService
import java.text.SimpleDateFormat
import java.util.*
class PayWithoutAccountActivity : AppCompatActivity() {
class PayWithoutAccountActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelectedListener {
private lateinit var binding: ActivityPayWithoutAccountBinding
private var binding: ActivityPayWithoutAccountBinding? = null
private lateinit var apiService: FenakaApiService
private var currentBill: BillLookupResponse? = null
private var drawerToggle: ActionBarDrawerToggle? = null
companion object {
private const val TAG = "PayWithoutAccountActivity"
@@ -33,34 +40,161 @@ class PayWithoutAccountActivity : AppCompatActivity() {
Log.d(TAG, "PayWithoutAccountActivity onCreate")
binding = ActivityPayWithoutAccountBinding.inflate(layoutInflater)
setContentView(binding.root)
// Check if toolbar should be hidden
val hideToolbar = intent.getBooleanExtra("hide_toolbar", false)
if (hideToolbar) {
// Use original layout for login context
binding = ActivityPayWithoutAccountBinding.inflate(layoutInflater)
setContentView(binding!!.root)
binding!!.toolbar.visibility = View.GONE
// Remove margin since toolbar is hidden
val scrollView = findViewById<android.widget.ScrollView>(R.id.scroll_view)
scrollView?.let { view ->
val params = view.layoutParams as androidx.coordinatorlayout.widget.CoordinatorLayout.LayoutParams
params.topMargin = 0
view.layoutParams = params
}
} else {
// Use drawer layout for menu context
setContentView(R.layout.activity_pay_without_account_drawer)
// Don't use ViewBinding for drawer layout, access views manually
setupDrawer()
}
apiService = FenakaApiService()
setupClickListeners()
}
private fun setupClickListeners() {
binding.btnContinue.setOnClickListener {
handleContinue()
private fun setupDrawer() {
val toolbar = findViewById<androidx.appcompat.widget.Toolbar>(R.id.toolbar)
setSupportActionBar(toolbar)
supportActionBar?.apply {
title = "Pay Without Account"
}
binding.btnPay.setOnClickListener {
handlePayment()
val drawerLayout = findViewById<androidx.drawerlayout.widget.DrawerLayout>(R.id.drawer_layout)
drawerToggle = ActionBarDrawerToggle(
this, drawerLayout, toolbar,
R.string.navigation_drawer_open, R.string.navigation_drawer_close
)
drawerLayout.addDrawerListener(drawerToggle!!)
drawerToggle?.syncState()
val navView = findViewById<com.google.android.material.navigation.NavigationView>(R.id.nav_view)
navView.setNavigationItemSelectedListener(this)
}
// Helper methods to access views regardless of layout type
private fun getBillDetailsCard(): com.google.android.material.card.MaterialCardView {
val hideToolbar = intent.getBooleanExtra("hide_toolbar", false)
return if (hideToolbar) {
binding!!.billDetailsCard
} else {
findViewById(R.id.bill_details_card)
}
}
private fun getInputFieldsLayout(): android.widget.LinearLayout {
val hideToolbar = intent.getBooleanExtra("hide_toolbar", false)
return if (hideToolbar) {
binding!!.inputFieldsLayout
} else {
findViewById(R.id.input_fields_layout)
}
}
private fun getBillNumberInput(): com.google.android.material.textfield.TextInputEditText {
val hideToolbar = intent.getBooleanExtra("hide_toolbar", false)
return if (hideToolbar) {
binding!!.etBillNumber
} else {
findViewById(R.id.et_bill_number)
}
}
private fun getSubscriptionNumberInput(): com.google.android.material.textfield.TextInputEditText {
val hideToolbar = intent.getBooleanExtra("hide_toolbar", false)
return if (hideToolbar) {
binding!!.etSubscriptionNumber
} else {
findViewById(R.id.et_subscription_number)
}
}
private fun getContinueButton(): com.google.android.material.button.MaterialButton {
val hideToolbar = intent.getBooleanExtra("hide_toolbar", false)
return if (hideToolbar) {
binding!!.btnContinue
} else {
findViewById(R.id.btn_continue)
}
}
// Additional helper methods for views that exist only in the original layout
private fun getTvBillNumber(): android.widget.TextView? {
val hideToolbar = intent.getBooleanExtra("hide_toolbar", false)
return if (hideToolbar) {
binding!!.tvBillNumber
} else {
findViewById(R.id.tv_bill_number)
}
}
private fun getTvBillStatus(): android.widget.TextView? {
val hideToolbar = intent.getBooleanExtra("hide_toolbar", false)
return if (hideToolbar) {
binding!!.tvBillStatus
} else {
findViewById(R.id.tv_bill_status)
}
}
private fun getPayButton(): com.google.android.material.button.MaterialButton? {
val hideToolbar = intent.getBooleanExtra("hide_toolbar", false)
return if (hideToolbar) {
binding!!.btnPay
} else {
findViewById(R.id.btn_pay)
}
}
private fun setupClickListeners() {
val hideToolbar = intent.getBooleanExtra("hide_toolbar", false)
if (hideToolbar) {
// Use ViewBinding for original layout
binding!!.btnContinue.setOnClickListener {
handleContinue()
}
binding!!.btnPay.setOnClickListener {
handlePayment()
}
} else {
// Use findViewById for drawer layout
val btnContinue = findViewById<com.google.android.material.button.MaterialButton>(R.id.btn_continue)
val btnPay = findViewById<com.google.android.material.button.MaterialButton>(R.id.btn_pay)
btnContinue.setOnClickListener {
handleContinue()
}
btnPay.setOnClickListener {
handlePayment()
}
}
}
private fun handleContinue() {
// Check if we're showing the card - if so, hide it and show input fields
if (binding.billDetailsCard.visibility == View.VISIBLE) {
if (getBillDetailsCard().visibility == View.VISIBLE) {
Log.d(TAG, "Hiding bill details card and showing input fields")
showInputFields()
return
}
// Otherwise, perform bill search
val billNumber = binding.etBillNumber.text.toString().trim()
val subscriptionNumber = binding.etSubscriptionNumber.text.toString().trim()
val billNumber = getBillNumberInput().text.toString().trim()
val subscriptionNumber = getSubscriptionNumberInput().text.toString().trim()
Log.d(TAG, "handleContinue called with bill: $billNumber, subscription: $subscriptionNumber")
@@ -73,11 +207,11 @@ class PayWithoutAccountActivity : AppCompatActivity() {
}
private fun showInputFields() {
binding.inputFieldsLayout.visibility = View.VISIBLE
binding.billDetailsCard.visibility = View.GONE
getInputFieldsLayout().visibility = View.VISIBLE
getBillDetailsCard().visibility = View.GONE
currentBill = null
// Update button text to Continue when showing input fields
binding.btnContinue.text = "Continue"
getContinueButton().text = "Continue"
}
private fun fetchBillDetails(billNumber: String, subscriptionNumber: String) {
@@ -149,63 +283,69 @@ class PayWithoutAccountActivity : AppCompatActivity() {
private fun showBillDetails(bill: BillLookupResponse) {
// Hide input fields and show bill details
binding.inputFieldsLayout.visibility = View.GONE
binding.billDetailsCard.visibility = View.VISIBLE
getInputFieldsLayout().visibility = View.GONE
getBillDetailsCard().visibility = View.VISIBLE
// Update button text to Search Another Bill when showing card
binding.btnContinue.text = "Search Another Bill"
getContinueButton().text = "Search Another Bill"
// Set bill information
binding.tvBillNumber.text = bill.billNumber
binding.tvBillAmount.text = "MVR ${bill.billAmount}"
binding.tvBillStatus.text = bill.status.uppercase()
// Set customer information
binding.tvCustomerName.text = bill.customer.name
binding.tvAccountNumber.text = bill.customer.accountNumber
binding.tvPhoneNumber.text = bill.customer.phone
// Set address information
val address = "${bill.subscriptionAddress.property.name}, ${bill.subscriptionAddress.property.street.name}"
binding.tvAddress.text = address
// Set subscription information
binding.tvSubscriptionNumber.text = bill.subscription.subscriptionNumber
binding.tvServiceType.text = if (bill.subscription.serviceId == 1) "Electricity" else "Water"
// Format and set dates
val dueDateFormatted = formatDate(bill.dueDate)
val billDateFormatted = formatDate(bill.billDate)
binding.tvDueDate.text = dueDateFormatted
binding.tvBillDate.text = billDateFormatted
// Set bill information (only set views that exist in both layouts)
getTvBillNumber()?.text = bill.billNumber
getTvBillStatus()?.text = bill.status.uppercase()
// Set payment status and button
val isPaid = bill.status == "paid"
binding.btnPay.isEnabled = !isPaid
binding.btnPay.alpha = if (isPaid) 0.5f else 1.0f
binding.btnPay.text = if (isPaid) "Already Paid" else "Pay MVR ${bill.billAmount}"
getPayButton()?.let { payButton ->
payButton.isEnabled = !isPaid
payButton.alpha = if (isPaid) 0.5f else 1.0f
payButton.text = if (isPaid) "Already Paid" else "Pay MVR ${bill.billAmount}"
}
// Set status color
when (bill.status.lowercase()) {
"paid" -> {
binding.tvBillStatus.setTextColor(getColor(android.R.color.holo_green_dark))
}
"unpaid" -> {
binding.tvBillStatus.setTextColor(getColor(android.R.color.holo_red_dark))
}
else -> {
binding.tvBillStatus.setTextColor(getColor(android.R.color.holo_orange_dark))
// Set status color based on payment status
getTvBillStatus()?.let { statusView ->
when (bill.status.lowercase()) {
"paid" -> {
statusView.setTextColor(getColor(android.R.color.holo_green_dark))
}
"unpaid" -> {
statusView.setTextColor(getColor(android.R.color.holo_red_dark))
}
else -> {
statusView.setTextColor(getColor(android.R.color.holo_orange_dark))
}
}
}
// Show additional payment details if available
bill.billPaymentDetails?.let { paymentDetails ->
if (paymentDetails.paidAmount.toDoubleOrNull() ?: 0.0 > 0.0) {
binding.tvPaidAmount.visibility = View.VISIBLE
binding.tvPaidAmount.text = "Paid: MVR ${paymentDetails.paidAmount}"
if (paymentDetails.pendingAmount.toDoubleOrNull() ?: 0.0 > 0.0) {
binding.tvPendingAmount.visibility = View.VISIBLE
binding.tvPendingAmount.text = "Pending: MVR ${paymentDetails.pendingAmount}"
// Note: Detailed bill information (customer name, address, etc.)
// is only shown in the original layout from login screen
val hideToolbar = intent.getBooleanExtra("hide_toolbar", false)
if (hideToolbar) {
// Set detailed information only when using original layout
binding!!.tvBillAmount.text = "MVR ${bill.billAmount}"
binding!!.tvCustomerName.text = bill.customer.name
binding!!.tvAccountNumber.text = bill.customer.accountNumber
binding!!.tvPhoneNumber.text = bill.customer.phone
val address = "${bill.subscriptionAddress.property.name}, ${bill.subscriptionAddress.property.street.name}"
binding!!.tvAddress.text = address
binding!!.tvSubscriptionNumber.text = bill.subscription.subscriptionNumber
binding!!.tvServiceType.text = if (bill.subscription.serviceId == 1) "Electricity" else "Water"
val dueDateFormatted = formatDate(bill.dueDate)
val billDateFormatted = formatDate(bill.billDate)
binding!!.tvDueDate.text = dueDateFormatted
binding!!.tvBillDate.text = billDateFormatted
// Show payment details if available
bill.billPaymentDetails?.let { paymentDetails ->
if (paymentDetails.paidAmount.toDoubleOrNull() ?: 0.0 > 0.0) {
binding!!.tvPaidAmount.visibility = View.VISIBLE
binding!!.tvPaidAmount.text = "Paid: MVR ${paymentDetails.paidAmount}"
if (paymentDetails.pendingAmount.toDoubleOrNull() ?: 0.0 > 0.0) {
binding!!.tvPendingAmount.visibility = View.VISIBLE
binding!!.tvPendingAmount.text = "Pending: MVR ${paymentDetails.pendingAmount}"
}
}
}
}
@@ -225,23 +365,23 @@ class PayWithoutAccountActivity : AppCompatActivity() {
private fun validateInput(billNumber: String, subscriptionNumber: String): Boolean {
if (billNumber.isEmpty()) {
binding.etBillNumber.error = "Bill number is required"
getBillNumberInput().error = "Bill number is required"
return false
}
if (subscriptionNumber.isEmpty()) {
binding.etSubscriptionNumber.error = "Subscription number is required"
getSubscriptionNumberInput().error = "Subscription number is required"
return false
}
// Basic validation - you can add more specific validation rules here
if (billNumber.length < 3) {
binding.etBillNumber.error = "Bill number must be at least 3 characters"
getBillNumberInput().error = "Bill number must be at least 3 characters"
return false
}
if (subscriptionNumber.length < 3) {
binding.etSubscriptionNumber.error = "Subscription number must be at least 3 characters"
getSubscriptionNumberInput().error = "Subscription number must be at least 3 characters"
return false
}
@@ -249,15 +389,81 @@ class PayWithoutAccountActivity : AppCompatActivity() {
}
private fun setLoading(isLoading: Boolean) {
binding.btnContinue.isEnabled = !isLoading
binding.btnContinue.text = if (isLoading) "Searching Bill..." else "Continue"
getContinueButton().isEnabled = !isLoading
getContinueButton().text = if (isLoading) "Searching Bill..." else "Continue"
binding.etBillNumber.isEnabled = !isLoading
binding.etSubscriptionNumber.isEnabled = !isLoading
getBillNumberInput().isEnabled = !isLoading
getSubscriptionNumberInput().isEnabled = !isLoading
if (isLoading) {
binding.billDetailsCard.visibility = View.GONE
binding.inputFieldsLayout.visibility = View.VISIBLE
getBillDetailsCard().visibility = View.GONE
getInputFieldsLayout().visibility = View.VISIBLE
}
}
override fun onSupportNavigateUp(): Boolean {
onBackPressedDispatcher.onBackPressed()
return true
}
override fun onNavigationItemSelected(item: android.view.MenuItem): Boolean {
when (item.itemId) {
R.id.nav_dashboard -> {
val intent = Intent(this, MainActivity::class.java)
intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP
intent.putExtra("navigate_to", "dashboard")
startActivity(intent)
finish()
}
R.id.nav_bill_history -> {
val intent = Intent(this, MainActivity::class.java)
intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP
intent.putExtra("navigate_to", "bill_history")
startActivity(intent)
finish()
}
R.id.nav_subscriptions -> {
val intent = Intent(this, MainActivity::class.java)
intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP
intent.putExtra("navigate_to", "subscriptions")
startActivity(intent)
finish()
}
R.id.nav_band_rates -> {
val intent = Intent(this, MainActivity::class.java)
intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP
intent.putExtra("navigate_to", "band_rates")
startActivity(intent)
finish()
}
R.id.nav_pay_any_bill -> {
val intent = Intent(this, MainActivity::class.java)
intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP
intent.putExtra("navigate_to", "pay_any_bill")
startActivity(intent)
finish()
}
}
val drawerLayout = findViewById<androidx.drawerlayout.widget.DrawerLayout>(R.id.drawer_layout)
drawerLayout?.closeDrawer(androidx.core.view.GravityCompat.START)
return true
}
@Deprecated("Deprecated in Java")
override fun onBackPressed() {
// Check if toolbar is hidden (launched from login)
val hideToolbar = intent.getBooleanExtra("hide_toolbar", false)
if (hideToolbar) {
// If launched from login, go back to login
super.onBackPressed()
} else {
// If launched from main menu, check if drawer is open
val drawerLayout = findViewById<androidx.drawerlayout.widget.DrawerLayout>(R.id.drawer_layout)
if (drawerLayout?.isDrawerOpen(androidx.core.view.GravityCompat.START) == true) {
drawerLayout.closeDrawer(androidx.core.view.GravityCompat.START)
} else {
super.onBackPressed()
}
}
}
}

View File

@@ -7,7 +7,7 @@ import androidx.lifecycle.ViewModel
class PayAnyBillViewModel : ViewModel() {
private val _text = MutableLiveData<String>().apply {
value = "Pay Any Bill\n\nComing soon..."
value = "Coming Soon"
}
val text: LiveData<String> = _text
}

View File

@@ -9,7 +9,10 @@ import androidx.recyclerview.widget.RecyclerView
import sh.sar.gridflow.data.CustomerSubscription
import sh.sar.gridflow.databinding.ItemSubscriptionDetailedBinding
class DetailedSubscriptionsAdapter : ListAdapter<CustomerSubscription, DetailedSubscriptionsAdapter.SubscriptionViewHolder>(SubscriptionDiffCallback()) {
class DetailedSubscriptionsAdapter(
private val onEditClick: (CustomerSubscription) -> Unit,
private val onDeleteClick: (CustomerSubscription) -> Unit
) : ListAdapter<CustomerSubscription, DetailedSubscriptionsAdapter.SubscriptionViewHolder>(SubscriptionDiffCallback()) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SubscriptionViewHolder {
val binding = ItemSubscriptionDetailedBinding.inflate(
@@ -21,14 +24,18 @@ class DetailedSubscriptionsAdapter : ListAdapter<CustomerSubscription, DetailedS
}
override fun onBindViewHolder(holder: SubscriptionViewHolder, position: Int) {
holder.bind(getItem(position))
holder.bind(getItem(position), onEditClick, onDeleteClick)
}
class SubscriptionViewHolder(
private val binding: ItemSubscriptionDetailedBinding
) : RecyclerView.ViewHolder(binding.root) {
fun bind(subscription: CustomerSubscription) {
fun bind(
subscription: CustomerSubscription,
onEditClick: (CustomerSubscription) -> Unit,
onDeleteClick: (CustomerSubscription) -> Unit
) {
with(binding) {
// Service icon and category
val serviceIcon = when (subscription.subscription.serviceId) {
@@ -53,13 +60,13 @@ class DetailedSubscriptionsAdapter : ListAdapter<CustomerSubscription, DetailedS
textCustomerName.text = subscription.subscription.customer.name
textCustomerPhone.text = subscription.subscription.customer.phone
// Action buttons - show coming soon toasts
// Action buttons
btnEdit.setOnClickListener {
Toast.makeText(it.context, "Edit subscription coming soon", Toast.LENGTH_SHORT).show()
onEditClick(subscription)
}
btnDelete.setOnClickListener {
Toast.makeText(it.context, "Delete subscription coming soon", Toast.LENGTH_SHORT).show()
onDeleteClick(subscription)
}
}
}

View File

@@ -1,5 +1,7 @@
package sh.sar.gridflow.ui.subscriptions
import android.app.AlertDialog
import android.content.Intent
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
@@ -8,6 +10,10 @@ import android.widget.Toast
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProvider
import androidx.recyclerview.widget.LinearLayoutManager
import sh.sar.gridflow.AddSubscriptionActivity
import sh.sar.gridflow.data.CustomerSubscription
import sh.sar.gridflow.databinding.DialogDeleteSubscriptionBinding
import sh.sar.gridflow.databinding.DialogEditSubscriptionBinding
import sh.sar.gridflow.databinding.FragmentSubscriptionsBinding
class SubscriptionsFragment : Fragment() {
@@ -38,7 +44,10 @@ class SubscriptionsFragment : Fragment() {
private fun setupViews() {
// Setup RecyclerView
subscriptionsAdapter = DetailedSubscriptionsAdapter()
subscriptionsAdapter = DetailedSubscriptionsAdapter(
onEditClick = { subscription -> showEditDialog(subscription) },
onDeleteClick = { subscription -> showDeleteDialog(subscription) }
)
binding.recyclerSubscriptions.apply {
layoutManager = LinearLayoutManager(requireContext())
adapter = subscriptionsAdapter
@@ -46,7 +55,8 @@ class SubscriptionsFragment : Fragment() {
// Handle FAB click
binding.fabAddSubscription.setOnClickListener {
Toast.makeText(context, "Add subscription coming soon", Toast.LENGTH_SHORT).show()
val intent = Intent(requireContext(), AddSubscriptionActivity::class.java)
startActivity(intent)
}
// Handle retry button
@@ -112,6 +122,50 @@ class SubscriptionsFragment : Fragment() {
binding.textError.text = error
}
private fun showEditDialog(subscription: CustomerSubscription) {
val dialogBinding = DialogEditSubscriptionBinding.inflate(layoutInflater)
dialogBinding.editSubscriptionName.setText(subscription.name)
val dialog = AlertDialog.Builder(requireContext())
.setView(dialogBinding.root)
.create()
dialogBinding.btnCancel.setOnClickListener {
dialog.dismiss()
}
dialogBinding.btnSubmit.setOnClickListener {
val newName = dialogBinding.editSubscriptionName.text.toString().trim()
if (newName.isNotEmpty()) {
Toast.makeText(context, "Edit API call needed for: $newName", Toast.LENGTH_SHORT).show()
dialog.dismiss()
} else {
dialogBinding.editSubscriptionName.error = "Name cannot be empty"
}
}
dialog.show()
}
private fun showDeleteDialog(subscription: CustomerSubscription) {
val dialogBinding = DialogDeleteSubscriptionBinding.inflate(layoutInflater)
val dialog = AlertDialog.Builder(requireContext())
.setView(dialogBinding.root)
.create()
dialogBinding.btnCancel.setOnClickListener {
dialog.dismiss()
}
dialogBinding.btnYes.setOnClickListener {
Toast.makeText(context, "Delete API call needed for: ${subscription.name}", Toast.LENGTH_SHORT).show()
dialog.dismiss()
}
dialog.show()
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null

View File

@@ -0,0 +1,178 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.drawerlayout.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:context=".AddSubscriptionActivity">
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?android:attr/colorBackground">
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/Theme.GridFlow.AppBarOverlay">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary" />
</com.google.android.material.appbar.AppBarLayout>
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true"
android:layout_marginTop="?attr/actionBarSize">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="32dp"
android:gravity="center">
<!-- Logo and Title Section -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="vertical"
android:gravity="center">
<ImageView
android:id="@+id/iv_app_logo"
android:layout_width="120dp"
android:layout_height="120dp"
android:layout_marginBottom="24dp"
android:src="@mipmap/ic_launcher"
android:contentDescription="GridFlow Logo" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Add New Subscription"
android:textSize="28sp"
android:textStyle="bold"
android:textColor="?android:attr/textColorPrimary"
android:layout_marginBottom="8dp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Enter your subscription details below"
android:textSize="14sp"
android:textColor="?android:attr/textColorSecondary"
android:alpha="0.7"
android:layout_marginBottom="32dp" />
</LinearLayout>
<!-- Subscription Form -->
<LinearLayout
android:id="@+id/input_form_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_marginTop="32dp">
<!-- Input Fields Container -->
<LinearLayout
android:id="@+id/input_fields_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<!-- Subscription Number Input -->
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:hint="Subscription Number"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/edit_subscription_number"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="text"
android:textSize="16sp" />
</com.google.android.material.textfield.TextInputLayout>
<!-- Bill Number Input -->
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:hint="Bill Number"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/edit_bill_number"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="text"
android:textSize="16sp" />
</com.google.android.material.textfield.TextInputLayout>
<!-- Alias/Description Input -->
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="24dp"
android:hint="Alias/Description"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/edit_alias"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="text"
android:textSize="16sp" />
</com.google.android.material.textfield.TextInputLayout>
</LinearLayout>
<!-- Continue Button -->
<com.google.android.material.button.MaterialButton
android:id="@+id/btn_continue"
android:layout_width="match_parent"
android:layout_height="56dp"
android:text="Continue"
android:textSize="16sp"
android:textAllCaps="false"
android:layout_marginBottom="24dp" />
</LinearLayout>
<!-- Spacer for bottom -->
<View
android:layout_width="match_parent"
android:layout_height="32dp" />
</LinearLayout>
</ScrollView>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
<com.google.android.material.navigation.NavigationView
android:id="@+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:fitsSystemWindows="true"
app:headerLayout="@layout/nav_header_main"
app:menu="@menu/activity_main_drawer" />
</androidx.drawerlayout.widget.DrawerLayout>

View File

@@ -1,10 +1,31 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true"
android:background="?android:attr/colorBackground">
android:background="?android:attr/colorBackground"
tools:context=".PayWithoutAccountActivity">
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/Theme.GridFlow.AppBarOverlay">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary" />
</com.google.android.material.appbar.AppBarLayout>
<ScrollView
android:id="@+id/scroll_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true"
android:layout_marginTop="?attr/actionBarSize">
<LinearLayout
android:layout_width="match_parent"
@@ -474,4 +495,6 @@
</LinearLayout>
</ScrollView>
</ScrollView>
</androidx.coordinatorlayout.widget.CoordinatorLayout>

View File

@@ -0,0 +1,252 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.drawerlayout.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:context=".PayWithoutAccountActivity">
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:id="@+id/coordinator_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?android:attr/colorBackground">
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/Theme.GridFlow.AppBarOverlay">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary" />
</com.google.android.material.appbar.AppBarLayout>
<ScrollView
android:id="@+id/scroll_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true"
android:layout_marginTop="?attr/actionBarSize">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="32dp"
android:gravity="center">
<!-- Logo and Title Section -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="vertical"
android:gravity="center">
<ImageView
android:id="@+id/iv_app_logo"
android:layout_width="120dp"
android:layout_height="120dp"
android:layout_marginBottom="24dp"
android:src="@mipmap/ic_launcher"
android:contentDescription="GridFlow Logo" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Pay Without Account"
android:textSize="28sp"
android:textStyle="bold"
android:textColor="?android:attr/textColorPrimary"
android:layout_marginBottom="8dp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Enter your bill and subscription details"
android:textSize="14sp"
android:textColor="?android:attr/textColorSecondary"
android:alpha="0.7"
android:layout_marginBottom="32dp" />
</LinearLayout>
<!-- Payment Form -->
<LinearLayout
android:id="@+id/input_form_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_marginTop="32dp">
<!-- Input Fields Container -->
<LinearLayout
android:id="@+id/input_fields_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<!-- Bill Number Input -->
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:hint="Bill Number"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/et_bill_number"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="text"
android:textSize="16sp" />
</com.google.android.material.textfield.TextInputLayout>
<!-- Subscription Number Input -->
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="24dp"
android:hint="Subscription Number"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/et_subscription_number"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="text"
android:textSize="16sp" />
</com.google.android.material.textfield.TextInputLayout>
</LinearLayout>
<!-- Bill Details Card -->
<com.google.android.material.card.MaterialCardView
android:id="@+id/bill_details_card"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="24dp"
android:visibility="gone"
app:cardCornerRadius="12dp"
app:cardElevation="4dp"
app:strokeWidth="1dp"
app:strokeColor="?android:attr/textColorSecondary">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="20dp">
<!-- Bill Header -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginBottom="16dp">
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Bill Number"
android:textSize="12sp"
android:textColor="?android:attr/textColorSecondary"
android:alpha="0.7" />
<TextView
android:id="@+id/tv_bill_number"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="5-5879"
android:textSize="16sp"
android:textStyle="bold"
android:textColor="?android:attr/textColorPrimary" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:gravity="end">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Status"
android:textSize="12sp"
android:textColor="?android:attr/textColorSecondary"
android:alpha="0.7" />
<TextView
android:id="@+id/tv_bill_status"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="PAID"
android:textSize="14sp"
android:textStyle="bold" />
</LinearLayout>
</LinearLayout>
<!-- Continue/Search Another Bill Button -->
<com.google.android.material.button.MaterialButton
android:id="@+id/btn_pay"
android:layout_width="match_parent"
android:layout_height="56dp"
android:text="Pay MVR 1,176.23"
android:textSize="16sp"
android:textAllCaps="false" />
</LinearLayout>
</com.google.android.material.card.MaterialCardView>
<!-- Continue/Search Another Bill Button -->
<com.google.android.material.button.MaterialButton
android:id="@+id/btn_continue"
android:layout_width="match_parent"
android:layout_height="56dp"
android:text="Continue"
android:textSize="16sp"
android:textAllCaps="false"
android:layout_marginBottom="24dp" />
</LinearLayout>
<!-- Spacer for bottom -->
<View
android:layout_width="match_parent"
android:layout_height="32dp" />
</LinearLayout>
</ScrollView>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
<com.google.android.material.navigation.NavigationView
android:id="@+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:fitsSystemWindows="true"
app:headerLayout="@layout/nav_header_main"
app:menu="@menu/activity_main_drawer" />
</androidx.drawerlayout.widget.DrawerLayout>

View File

@@ -0,0 +1,48 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="24dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Delete Subscription"
android:textSize="20sp"
android:textStyle="bold"
android:textColor="?android:attr/textColorPrimary"
android:layout_marginBottom="16dp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Are you sure you want to remove this subscription?"
android:textSize="16sp"
android:textColor="?android:attr/textColorPrimary"
android:layout_marginBottom="24dp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="end">
<com.google.android.material.button.MaterialButton
android:id="@+id/btn_cancel"
style="@style/Widget.MaterialComponents.Button.TextButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Cancel"
android:layout_marginEnd="8dp" />
<com.google.android.material.button.MaterialButton
android:id="@+id/btn_yes"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Yes"
android:backgroundTint="?android:attr/colorError" />
</LinearLayout>
</LinearLayout>

View File

@@ -0,0 +1,56 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res/auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="24dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Edit Subscription"
android:textSize="20sp"
android:textStyle="bold"
android:textColor="?android:attr/textColorPrimary"
android:layout_marginBottom="16dp" />
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="24dp"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/edit_subscription_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Subscription Name"
android:inputType="text"
android:maxLines="1" />
</com.google.android.material.textfield.TextInputLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="end">
<com.google.android.material.button.MaterialButton
android:id="@+id/btn_cancel"
style="@style/Widget.MaterialComponents.Button.TextButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Cancel"
android:layout_marginEnd="8dp" />
<com.google.android.material.button.MaterialButton
android:id="@+id/btn_submit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Submit" />
</LinearLayout>
</LinearLayout>

View File

@@ -1,29 +1,48 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true"
android:background="?android:attr/colorBackground"
tools:context=".ui.payanybill.PayAnyBillFragment">
<LinearLayout
android:layout_width="match_parent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="20dp"
android:gravity="center">
android:gravity="center"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<ImageView
android:layout_width="120dp"
android:layout_height="120dp"
android:layout_marginBottom="24dp"
android:src="@drawable/ic_pay_any_bill_24"
android:contentDescription="Pay Any Bill Icon"
android:alpha="0.6" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Pay Any Bill"
android:textSize="28sp"
android:textStyle="bold"
android:textColor="?android:attr/textColorPrimary"
android:layout_marginBottom="8dp" />
<TextView
android:id="@+id/text_pay_any_bill"
android:layout_width="match_parent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Coming Soon"
android:textSize="18sp"
android:textColor="?android:attr/textColorPrimary"
android:gravity="center"
android:layout_marginTop="100dp"
tools:text="Pay Any Bill\n\nComing soon..." />
android:textColor="?android:attr/textColorSecondary"
android:alpha="0.7" />
</LinearLayout>
</ScrollView>
</androidx.constraintlayout.widget.ConstraintLayout>