Compare commits
	
		
			2 Commits
		
	
	
		
			86b51fa99b
			...
			43477f9d47
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						
						
							
						
						43477f9d47
	
				 | 
					
					
						|||
| 
						
						
							
						
						26c3b7418c
	
				 | 
					
					
						
@@ -1,130 +0,0 @@
 | 
				
			|||||||
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()
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -640,6 +640,110 @@ class FenakaApiService {
 | 
				
			|||||||
        val matchResult = regex.find(html)
 | 
					        val matchResult = regex.find(html)
 | 
				
			||||||
        return matchResult?.groupValues?.get(1)
 | 
					        return matchResult?.groupValues?.get(1)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    suspend fun deleteCustomerSubscription(subscriptionId: Long, cookie: String): ApiResult<Unit> = withContext(Dispatchers.IO) {
 | 
				
			||||||
 | 
					        Log.d(TAG, "Deleting customer subscription: $subscriptionId")
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        val cookieHeader = "connect.sid=$cookie"
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        val request = Request.Builder()
 | 
				
			||||||
 | 
					            .url("$BASE_URL/api/customer-subscriptions/$subscriptionId")
 | 
				
			||||||
 | 
					            .delete()
 | 
				
			||||||
 | 
					            .header("Authorization", "Bearer $BEARER_TOKEN")
 | 
				
			||||||
 | 
					            .header("Content-Type", "application/json")
 | 
				
			||||||
 | 
					            .header("Cookie", cookieHeader)
 | 
				
			||||||
 | 
					            .header("Host", "api.fenaka.mv")
 | 
				
			||||||
 | 
					            .header("User-Agent", "Dart/3.5 (dart:io)")
 | 
				
			||||||
 | 
					            .build()
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            val response = client.newCall(request).execute()
 | 
				
			||||||
 | 
					            Log.d(TAG, "Delete subscription response code: ${response.code}")
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            when (response.code) {
 | 
				
			||||||
 | 
					                200, 204 -> {
 | 
				
			||||||
 | 
					                    Log.d(TAG, "Subscription deleted successfully")
 | 
				
			||||||
 | 
					                    ApiResult.Success(Unit, null)
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                404 -> {
 | 
				
			||||||
 | 
					                    Log.d(TAG, "Subscription not found: ${response.code}")
 | 
				
			||||||
 | 
					                    ApiResult.Error("Subscription not found", response.code)
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                403 -> {
 | 
				
			||||||
 | 
					                    Log.d(TAG, "Access denied: ${response.code}")
 | 
				
			||||||
 | 
					                    ApiResult.Error("Access denied", response.code)
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                else -> {
 | 
				
			||||||
 | 
					                    Log.d(TAG, "Failed to delete subscription: ${response.code}")
 | 
				
			||||||
 | 
					                    ApiResult.Error("Failed to delete subscription", response.code)
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        } catch (e: IOException) {
 | 
				
			||||||
 | 
					            Log.e(TAG, "Network error during subscription deletion", e)
 | 
				
			||||||
 | 
					            ApiResult.Error("Network error: ${e.message}", -1)
 | 
				
			||||||
 | 
					        } catch (e: Exception) {
 | 
				
			||||||
 | 
					            Log.e(TAG, "Unexpected error during subscription deletion", e)
 | 
				
			||||||
 | 
					            ApiResult.Error("Unexpected error: ${e.message}", -1)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    suspend fun addCustomerSubscription(name: String, subscriptionNumber: String, billNumber: String, cookie: String): ApiResult<Unit> = withContext(Dispatchers.IO) {
 | 
				
			||||||
 | 
					        Log.d(TAG, "Adding customer subscription: $subscriptionNumber with name: $name")
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        val cookieHeader = "connect.sid=$cookie"
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        // Create request body
 | 
				
			||||||
 | 
					        val requestBody = mapOf(
 | 
				
			||||||
 | 
					            "name" to name,
 | 
				
			||||||
 | 
					            "subscriptionNumber" to subscriptionNumber,
 | 
				
			||||||
 | 
					            "billNumber" to billNumber
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        val jsonBody = gson.toJson(requestBody).toRequestBody(JSON_MEDIA_TYPE.toMediaType())
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        val request = Request.Builder()
 | 
				
			||||||
 | 
					            .url("$BASE_URL/api/customer-subscriptions")
 | 
				
			||||||
 | 
					            .post(jsonBody)
 | 
				
			||||||
 | 
					            .header("Authorization", "Bearer $BEARER_TOKEN")
 | 
				
			||||||
 | 
					            .header("Content-Type", "application/json")
 | 
				
			||||||
 | 
					            .header("Cookie", cookieHeader)
 | 
				
			||||||
 | 
					            .header("Host", "api.fenaka.mv")
 | 
				
			||||||
 | 
					            .header("User-Agent", "Dart/3.5 (dart:io)")
 | 
				
			||||||
 | 
					            .build()
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            val response = client.newCall(request).execute()
 | 
				
			||||||
 | 
					            Log.d(TAG, "Add subscription response code: ${response.code}")
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            when (response.code) {
 | 
				
			||||||
 | 
					                200, 201 -> {
 | 
				
			||||||
 | 
					                    Log.d(TAG, "Subscription added successfully")
 | 
				
			||||||
 | 
					                    ApiResult.Success(Unit, null)
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                400 -> {
 | 
				
			||||||
 | 
					                    Log.d(TAG, "Bad request: ${response.code}")
 | 
				
			||||||
 | 
					                    ApiResult.Error("Invalid subscription data", response.code)
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                409 -> {
 | 
				
			||||||
 | 
					                    Log.d(TAG, "Subscription already exists: ${response.code}")
 | 
				
			||||||
 | 
					                    ApiResult.Error("Subscription already exists", response.code)
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                403 -> {
 | 
				
			||||||
 | 
					                    Log.d(TAG, "Access denied: ${response.code}")
 | 
				
			||||||
 | 
					                    ApiResult.Error("Access denied", response.code)
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                else -> {
 | 
				
			||||||
 | 
					                    Log.d(TAG, "Failed to add subscription: ${response.code}")
 | 
				
			||||||
 | 
					                    ApiResult.Error("Failed to add subscription", response.code)
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        } catch (e: IOException) {
 | 
				
			||||||
 | 
					            Log.e(TAG, "Network error during subscription addition", e)
 | 
				
			||||||
 | 
					            ApiResult.Error("Network error: ${e.message}", -1)
 | 
				
			||||||
 | 
					        } catch (e: Exception) {
 | 
				
			||||||
 | 
					            Log.e(TAG, "Unexpected error during subscription addition", e)
 | 
				
			||||||
 | 
					            ApiResult.Error("Unexpected error: ${e.message}", -1)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
sealed class ApiResult<T> {
 | 
					sealed class ApiResult<T> {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,16 +1,19 @@
 | 
				
			|||||||
package sh.sar.gridflow.ui.subscriptions
 | 
					package sh.sar.gridflow.ui.subscriptions
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import android.app.AlertDialog
 | 
					import android.app.AlertDialog
 | 
				
			||||||
import android.content.Intent
 | 
					import android.content.Context
 | 
				
			||||||
import android.os.Bundle
 | 
					import android.os.Bundle
 | 
				
			||||||
 | 
					import android.text.Editable
 | 
				
			||||||
 | 
					import android.text.TextWatcher
 | 
				
			||||||
import android.view.LayoutInflater
 | 
					import android.view.LayoutInflater
 | 
				
			||||||
import android.view.View
 | 
					import android.view.View
 | 
				
			||||||
import android.view.ViewGroup
 | 
					import android.view.ViewGroup
 | 
				
			||||||
 | 
					import android.view.inputmethod.InputMethodManager
 | 
				
			||||||
import android.widget.Toast
 | 
					import android.widget.Toast
 | 
				
			||||||
import androidx.fragment.app.Fragment
 | 
					import androidx.fragment.app.Fragment
 | 
				
			||||||
import androidx.lifecycle.ViewModelProvider
 | 
					import androidx.lifecycle.ViewModelProvider
 | 
				
			||||||
import androidx.recyclerview.widget.LinearLayoutManager
 | 
					import androidx.recyclerview.widget.LinearLayoutManager
 | 
				
			||||||
import sh.sar.gridflow.AddSubscriptionActivity
 | 
					import sh.sar.gridflow.data.BillLookupResponse
 | 
				
			||||||
import sh.sar.gridflow.data.CustomerSubscription
 | 
					import sh.sar.gridflow.data.CustomerSubscription
 | 
				
			||||||
import sh.sar.gridflow.databinding.DialogDeleteSubscriptionBinding
 | 
					import sh.sar.gridflow.databinding.DialogDeleteSubscriptionBinding
 | 
				
			||||||
import sh.sar.gridflow.databinding.DialogEditSubscriptionBinding
 | 
					import sh.sar.gridflow.databinding.DialogEditSubscriptionBinding
 | 
				
			||||||
@@ -55,8 +58,51 @@ class SubscriptionsFragment : Fragment() {
 | 
				
			|||||||
        
 | 
					        
 | 
				
			||||||
        // Handle FAB click
 | 
					        // Handle FAB click
 | 
				
			||||||
        binding.fabAddSubscription.setOnClickListener {
 | 
					        binding.fabAddSubscription.setOnClickListener {
 | 
				
			||||||
            val intent = Intent(requireContext(), AddSubscriptionActivity::class.java)
 | 
					            showAddSubscriptionForm()
 | 
				
			||||||
            startActivity(intent)
 | 
					        }
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        // Handle cancel button click
 | 
				
			||||||
 | 
					        binding.btnCancelAdd.setOnClickListener {
 | 
				
			||||||
 | 
					            hideAddSubscriptionForm()
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        // Handle continue button click
 | 
				
			||||||
 | 
					        binding.btnContinue.setOnClickListener {
 | 
				
			||||||
 | 
					            if (binding.btnContinue.text == "Add Subscription") {
 | 
				
			||||||
 | 
					                // Card is showing, add the subscription
 | 
				
			||||||
 | 
					                val alias = binding.editAlias.text.toString().trim()
 | 
				
			||||||
 | 
					                val subscriptionNumber = binding.editSubscriptionNumber.text.toString().trim()
 | 
				
			||||||
 | 
					                val billNumber = binding.editBillNumber.text.toString().trim()
 | 
				
			||||||
 | 
					                
 | 
				
			||||||
 | 
					                if (alias.isNotEmpty()) {
 | 
				
			||||||
 | 
					                    subscriptionsViewModel.addSubscription(
 | 
				
			||||||
 | 
					                        name = alias,
 | 
				
			||||||
 | 
					                        subscriptionNumber = subscriptionNumber,
 | 
				
			||||||
 | 
					                        billNumber = billNumber,
 | 
				
			||||||
 | 
					                        onSuccess = {
 | 
				
			||||||
 | 
					                            Toast.makeText(requireContext(), "Subscription added successfully", Toast.LENGTH_SHORT).show()
 | 
				
			||||||
 | 
					                            hideAddSubscriptionForm()
 | 
				
			||||||
 | 
					                        },
 | 
				
			||||||
 | 
					                        onError = { errorMessage ->
 | 
				
			||||||
 | 
					                            Toast.makeText(requireContext(), "Failed to add subscription: $errorMessage", Toast.LENGTH_SHORT).show()
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    )
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    binding.editAlias.error = "Alias/Description is required"
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                // Input fields are showing, do lookup
 | 
				
			||||||
 | 
					                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)) {
 | 
				
			||||||
 | 
					                    // First, lookup the bill to get customer info
 | 
				
			||||||
 | 
					                    subscriptionsViewModel.lookupBill(billNumber, subscriptionNumber) { errorMessage ->
 | 
				
			||||||
 | 
					                        Toast.makeText(requireContext(), "Failed to find subscription: $errorMessage", Toast.LENGTH_SHORT).show()
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        // Handle retry button
 | 
					        // Handle retry button
 | 
				
			||||||
@@ -91,6 +137,24 @@ class SubscriptionsFragment : Fragment() {
 | 
				
			|||||||
                showErrorState(error)
 | 
					                showErrorState(error)
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        // Bill lookup result
 | 
				
			||||||
 | 
					        subscriptionsViewModel.billLookupResult.observe(viewLifecycleOwner) { billLookup ->
 | 
				
			||||||
 | 
					            if (billLookup != null) {
 | 
				
			||||||
 | 
					                showCustomerInfo(billLookup)
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                hideCustomerInfo()
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        // Lookup loading state
 | 
				
			||||||
 | 
					        subscriptionsViewModel.isLookingUp.observe(viewLifecycleOwner) { isLookingUp ->
 | 
				
			||||||
 | 
					            if (isLookingUp) {
 | 
				
			||||||
 | 
					                showLookupLoading()
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                hideLookupLoading()
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    private fun showLoadingState() {
 | 
					    private fun showLoadingState() {
 | 
				
			||||||
@@ -131,14 +195,48 @@ class SubscriptionsFragment : Fragment() {
 | 
				
			|||||||
            .create()
 | 
					            .create()
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        dialogBinding.btnCancel.setOnClickListener {
 | 
					        dialogBinding.btnCancel.setOnClickListener {
 | 
				
			||||||
 | 
					            hideKeyboard()
 | 
				
			||||||
            dialog.dismiss()
 | 
					            dialog.dismiss()
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        dialogBinding.btnSubmit.setOnClickListener {
 | 
					        dialogBinding.btnSubmit.setOnClickListener {
 | 
				
			||||||
            val newName = dialogBinding.editSubscriptionName.text.toString().trim()
 | 
					            val newName = dialogBinding.editSubscriptionName.text.toString().trim()
 | 
				
			||||||
            if (newName.isNotEmpty()) {
 | 
					            if (newName.isNotEmpty()) {
 | 
				
			||||||
                Toast.makeText(context, "Edit API call needed for: $newName", Toast.LENGTH_SHORT).show()
 | 
					                hideKeyboard()
 | 
				
			||||||
                dialog.dismiss()
 | 
					                
 | 
				
			||||||
 | 
					                // Get bill number from subscription data - try lastBill first, then fallback
 | 
				
			||||||
 | 
					                val billNumber = subscription.subscription.lastBill?.billNumber ?: ""
 | 
				
			||||||
 | 
					                val subscriptionNumber = subscription.subscription.subscriptionNumber
 | 
				
			||||||
 | 
					                
 | 
				
			||||||
 | 
					                if (billNumber.isEmpty()) {
 | 
				
			||||||
 | 
					                    Toast.makeText(context, "Cannot edit: Bill number not available", Toast.LENGTH_SHORT).show()
 | 
				
			||||||
 | 
					                    return@setOnClickListener
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                
 | 
				
			||||||
 | 
					                // Edit = Delete + Add (since there's no edit API)
 | 
				
			||||||
 | 
					                subscriptionsViewModel.deleteSubscription(
 | 
				
			||||||
 | 
					                    subscriptionId = subscription.id,
 | 
				
			||||||
 | 
					                    onSuccess = {
 | 
				
			||||||
 | 
					                        // After successful delete, add the subscription with new name
 | 
				
			||||||
 | 
					                        subscriptionsViewModel.addSubscription(
 | 
				
			||||||
 | 
					                            name = newName,
 | 
				
			||||||
 | 
					                            subscriptionNumber = subscriptionNumber,
 | 
				
			||||||
 | 
					                            billNumber = billNumber,
 | 
				
			||||||
 | 
					                            onSuccess = {
 | 
				
			||||||
 | 
					                                Toast.makeText(requireContext(), "Subscription updated successfully", Toast.LENGTH_SHORT).show()
 | 
				
			||||||
 | 
					                                dialog.dismiss()
 | 
				
			||||||
 | 
					                            },
 | 
				
			||||||
 | 
					                            onError = { errorMessage ->
 | 
				
			||||||
 | 
					                                Toast.makeText(requireContext(), "Failed to update subscription: $errorMessage", Toast.LENGTH_SHORT).show()
 | 
				
			||||||
 | 
					                                dialog.dismiss()
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                        )
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    onError = { errorMessage ->
 | 
				
			||||||
 | 
					                        Toast.makeText(requireContext(), "Failed to update subscription: $errorMessage", Toast.LENGTH_SHORT).show()
 | 
				
			||||||
 | 
					                        dialog.dismiss()
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                )
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
                dialogBinding.editSubscriptionName.error = "Name cannot be empty"
 | 
					                dialogBinding.editSubscriptionName.error = "Name cannot be empty"
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
@@ -159,12 +257,138 @@ class SubscriptionsFragment : Fragment() {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        dialogBinding.btnYes.setOnClickListener {
 | 
					        dialogBinding.btnYes.setOnClickListener {
 | 
				
			||||||
            Toast.makeText(context, "Delete API call needed for: ${subscription.name}", Toast.LENGTH_SHORT).show()
 | 
					            subscriptionsViewModel.deleteSubscription(
 | 
				
			||||||
            dialog.dismiss()
 | 
					                subscriptionId = subscription.id,
 | 
				
			||||||
 | 
					                onSuccess = {
 | 
				
			||||||
 | 
					                    Toast.makeText(context, "Subscription deleted successfully", Toast.LENGTH_SHORT).show()
 | 
				
			||||||
 | 
					                    dialog.dismiss()
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                onError = { errorMessage ->
 | 
				
			||||||
 | 
					                    Toast.makeText(context, "Failed to delete subscription: $errorMessage", Toast.LENGTH_SHORT).show()
 | 
				
			||||||
 | 
					                    dialog.dismiss()
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        dialog.show()
 | 
					        dialog.show()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    private fun showAddSubscriptionForm() {
 | 
				
			||||||
 | 
					        binding.scrollAddForm.visibility = View.VISIBLE
 | 
				
			||||||
 | 
					        binding.recyclerSubscriptions.visibility = View.GONE
 | 
				
			||||||
 | 
					        binding.layoutError.visibility = View.GONE
 | 
				
			||||||
 | 
					        binding.layoutEmpty.visibility = View.GONE
 | 
				
			||||||
 | 
					        binding.progressLoading.visibility = View.GONE
 | 
				
			||||||
 | 
					        binding.fabAddSubscription.visibility = View.GONE
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        // Clear form fields and customer info
 | 
				
			||||||
 | 
					        binding.editSubscriptionNumber.text?.clear()
 | 
				
			||||||
 | 
					        binding.editBillNumber.text?.clear()
 | 
				
			||||||
 | 
					        binding.editAlias.text?.clear()
 | 
				
			||||||
 | 
					        subscriptionsViewModel.clearBillLookup()
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        // Ensure initial state is correct
 | 
				
			||||||
 | 
					        binding.inputFieldsLayout.visibility = View.VISIBLE
 | 
				
			||||||
 | 
					        binding.cardCustomerInfo.visibility = View.GONE
 | 
				
			||||||
 | 
					        binding.btnContinue.text = "Continue"
 | 
				
			||||||
 | 
					        binding.btnContinue.visibility = View.VISIBLE
 | 
				
			||||||
 | 
					        binding.btnCancelAdd.visibility = View.VISIBLE
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    private fun hideAddSubscriptionForm() {
 | 
				
			||||||
 | 
					        hideKeyboard()
 | 
				
			||||||
 | 
					        binding.scrollAddForm.visibility = View.GONE
 | 
				
			||||||
 | 
					        binding.fabAddSubscription.visibility = View.VISIBLE
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        // Show appropriate state based on subscriptions
 | 
				
			||||||
 | 
					        subscriptionsViewModel.subscriptions.value?.let { subscriptions ->
 | 
				
			||||||
 | 
					            if (subscriptions.isEmpty()) {
 | 
				
			||||||
 | 
					                showEmptyState()
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                showSubscriptionsList()
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        } ?: showEmptyState()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    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
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    private fun showCustomerInfo(billLookup: BillLookupResponse) {
 | 
				
			||||||
 | 
					        // Hide keyboard when showing customer info
 | 
				
			||||||
 | 
					        hideKeyboard()
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        // Hide input fields and show card
 | 
				
			||||||
 | 
					        binding.inputFieldsLayout.visibility = View.GONE
 | 
				
			||||||
 | 
					        binding.cardCustomerInfo.visibility = View.VISIBLE
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        // Change button text to "Add Subscription"
 | 
				
			||||||
 | 
					        binding.btnContinue.text = "Add Subscription"
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        // Service type
 | 
				
			||||||
 | 
					        val serviceType = when (billLookup.subscription.serviceId) {
 | 
				
			||||||
 | 
					            1 -> "Electricity"
 | 
				
			||||||
 | 
					            2 -> "Water"
 | 
				
			||||||
 | 
					            else -> "Unknown Service"
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        // Customer information
 | 
				
			||||||
 | 
					        binding.tvCustomerName.text = billLookup.customer.name
 | 
				
			||||||
 | 
					        binding.tvPhoneNumber.text = billLookup.customer.phone
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        // Address information
 | 
				
			||||||
 | 
					        val propertyName = billLookup.subscriptionAddress?.property?.name ?: "Unknown Property"
 | 
				
			||||||
 | 
					        val streetName = billLookup.subscriptionAddress?.property?.street?.name ?: "Unknown Street"
 | 
				
			||||||
 | 
					        binding.tvAddress.text = "$propertyName, $streetName"
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        // Service details
 | 
				
			||||||
 | 
					        binding.tvSubscriptionNumber.text = billLookup.subscription.subscriptionNumber
 | 
				
			||||||
 | 
					        binding.tvServiceType.text = serviceType
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    private fun hideCustomerInfo() {
 | 
				
			||||||
 | 
					        binding.cardCustomerInfo.visibility = View.GONE
 | 
				
			||||||
 | 
					        binding.inputFieldsLayout.visibility = View.VISIBLE
 | 
				
			||||||
 | 
					        binding.btnContinue.text = "Continue"
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        // Ensure buttons are visible
 | 
				
			||||||
 | 
					        binding.btnContinue.visibility = View.VISIBLE
 | 
				
			||||||
 | 
					        binding.btnCancelAdd.visibility = View.VISIBLE
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    private fun showLookupLoading() {
 | 
				
			||||||
 | 
					        binding.layoutLookupLoading.visibility = View.VISIBLE
 | 
				
			||||||
 | 
					        binding.cardCustomerInfo.visibility = View.GONE
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    private fun hideLookupLoading() {
 | 
				
			||||||
 | 
					        binding.layoutLookupLoading.visibility = View.GONE
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    private fun hideKeyboard() {
 | 
				
			||||||
 | 
					        val inputMethodManager = requireContext().getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
 | 
				
			||||||
 | 
					        val currentFocusView = activity?.currentFocus
 | 
				
			||||||
 | 
					        if (currentFocusView != null) {
 | 
				
			||||||
 | 
					            inputMethodManager.hideSoftInputFromWindow(currentFocusView.windowToken, 0)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override fun onDestroyView() {
 | 
					    override fun onDestroyView() {
 | 
				
			||||||
        super.onDestroyView()
 | 
					        super.onDestroyView()
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,6 +7,7 @@ import androidx.lifecycle.LiveData
 | 
				
			|||||||
import androidx.lifecycle.MutableLiveData
 | 
					import androidx.lifecycle.MutableLiveData
 | 
				
			||||||
import androidx.lifecycle.viewModelScope
 | 
					import androidx.lifecycle.viewModelScope
 | 
				
			||||||
import kotlinx.coroutines.launch
 | 
					import kotlinx.coroutines.launch
 | 
				
			||||||
 | 
					import sh.sar.gridflow.data.BillLookupResponse
 | 
				
			||||||
import sh.sar.gridflow.data.CustomerSubscription
 | 
					import sh.sar.gridflow.data.CustomerSubscription
 | 
				
			||||||
import sh.sar.gridflow.network.ApiResult
 | 
					import sh.sar.gridflow.network.ApiResult
 | 
				
			||||||
import sh.sar.gridflow.network.FenakaApiService
 | 
					import sh.sar.gridflow.network.FenakaApiService
 | 
				
			||||||
@@ -30,6 +31,12 @@ class SubscriptionsViewModel(application: Application) : AndroidViewModel(applic
 | 
				
			|||||||
    private val _error = MutableLiveData<String?>()
 | 
					    private val _error = MutableLiveData<String?>()
 | 
				
			||||||
    val error: LiveData<String?> = _error
 | 
					    val error: LiveData<String?> = _error
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
 | 
					    private val _billLookupResult = MutableLiveData<BillLookupResponse?>()
 | 
				
			||||||
 | 
					    val billLookupResult: LiveData<BillLookupResponse?> = _billLookupResult
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    private val _isLookingUp = MutableLiveData<Boolean>()
 | 
				
			||||||
 | 
					    val isLookingUp: LiveData<Boolean> = _isLookingUp
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
    init {
 | 
					    init {
 | 
				
			||||||
        loadSubscriptions()
 | 
					        loadSubscriptions()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -66,4 +73,95 @@ class SubscriptionsViewModel(application: Application) : AndroidViewModel(applic
 | 
				
			|||||||
        Log.d(TAG, "Refreshing subscriptions")
 | 
					        Log.d(TAG, "Refreshing subscriptions")
 | 
				
			||||||
        loadSubscriptions()
 | 
					        loadSubscriptions()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    fun deleteSubscription(subscriptionId: Long, onSuccess: () -> Unit, onError: (String) -> Unit) {
 | 
				
			||||||
 | 
					        val cookie = secureStorage.getCookie()
 | 
				
			||||||
 | 
					        if (cookie == null) {
 | 
				
			||||||
 | 
					            Log.d(TAG, "No cookie found, cannot delete subscription")
 | 
				
			||||||
 | 
					            onError("Authentication required")
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        viewModelScope.launch {
 | 
				
			||||||
 | 
					            Log.d(TAG, "Deleting subscription: $subscriptionId")
 | 
				
			||||||
 | 
					            when (val result = apiService.deleteCustomerSubscription(subscriptionId, cookie)) {
 | 
				
			||||||
 | 
					                is ApiResult.Success -> {
 | 
				
			||||||
 | 
					                    Log.d(TAG, "Subscription deleted successfully")
 | 
				
			||||||
 | 
					                    loadSubscriptions() // Refresh the list
 | 
				
			||||||
 | 
					                    onSuccess()
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                is ApiResult.Error -> {
 | 
				
			||||||
 | 
					                    Log.d(TAG, "Failed to delete subscription: ${result.message}")
 | 
				
			||||||
 | 
					                    onError(result.message)
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    fun lookupBill(billNumber: String, subscriptionNumber: String, onError: (String) -> Unit) {
 | 
				
			||||||
 | 
					        _isLookingUp.value = true
 | 
				
			||||||
 | 
					        _billLookupResult.value = null
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        viewModelScope.launch {
 | 
				
			||||||
 | 
					            Log.d(TAG, "Looking up bill: $billNumber, subscription: $subscriptionNumber")
 | 
				
			||||||
 | 
					            when (val result = apiService.findBill(billNumber, subscriptionNumber)) {
 | 
				
			||||||
 | 
					                is ApiResult.Success -> {
 | 
				
			||||||
 | 
					                    Log.d(TAG, "Bill lookup successful: ${result.data.customer.name}")
 | 
				
			||||||
 | 
					                    _isLookingUp.value = false
 | 
				
			||||||
 | 
					                    _billLookupResult.value = result.data
 | 
				
			||||||
 | 
					                    Log.d(TAG, "BillLookupResult LiveData updated")
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                is ApiResult.Error -> {
 | 
				
			||||||
 | 
					                    if (result.code == 404) {
 | 
				
			||||||
 | 
					                        Log.d(TAG, "404 received, trying with swapped parameters")
 | 
				
			||||||
 | 
					                        // Try again with swapped parameters
 | 
				
			||||||
 | 
					                        when (val retryResult = apiService.findBill(subscriptionNumber, billNumber)) {
 | 
				
			||||||
 | 
					                            is ApiResult.Success -> {
 | 
				
			||||||
 | 
					                                Log.d(TAG, "Retry successful with swapped parameters")
 | 
				
			||||||
 | 
					                                _isLookingUp.value = false
 | 
				
			||||||
 | 
					                                _billLookupResult.value = retryResult.data
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                            is ApiResult.Error -> {
 | 
				
			||||||
 | 
					                                Log.d(TAG, "Retry also failed: ${retryResult.message}")
 | 
				
			||||||
 | 
					                                _isLookingUp.value = false
 | 
				
			||||||
 | 
					                                onError(retryResult.message)
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    } else {
 | 
				
			||||||
 | 
					                        Log.d(TAG, "Bill lookup failed: ${result.message}")
 | 
				
			||||||
 | 
					                        _isLookingUp.value = false
 | 
				
			||||||
 | 
					                        onError(result.message)
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    fun clearBillLookup() {
 | 
				
			||||||
 | 
					        _billLookupResult.value = null
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    fun addSubscription(name: String, subscriptionNumber: String, billNumber: String, onSuccess: () -> Unit, onError: (String) -> Unit) {
 | 
				
			||||||
 | 
					        val cookie = secureStorage.getCookie()
 | 
				
			||||||
 | 
					        if (cookie == null) {
 | 
				
			||||||
 | 
					            Log.d(TAG, "No cookie found, cannot add subscription")
 | 
				
			||||||
 | 
					            onError("Authentication required")
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        viewModelScope.launch {
 | 
				
			||||||
 | 
					            Log.d(TAG, "Adding subscription: $subscriptionNumber with name: $name")
 | 
				
			||||||
 | 
					            when (val result = apiService.addCustomerSubscription(name, subscriptionNumber, billNumber, cookie)) {
 | 
				
			||||||
 | 
					                is ApiResult.Success -> {
 | 
				
			||||||
 | 
					                    Log.d(TAG, "Subscription added successfully")
 | 
				
			||||||
 | 
					                    loadSubscriptions() // Refresh the list
 | 
				
			||||||
 | 
					                    onSuccess()
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                is ApiResult.Error -> {
 | 
				
			||||||
 | 
					                    Log.d(TAG, "Failed to add subscription: ${result.message}")
 | 
				
			||||||
 | 
					                    onError(result.message)
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,178 +0,0 @@
 | 
				
			|||||||
<?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>
 | 
					 | 
				
			||||||
@@ -82,6 +82,319 @@
 | 
				
			|||||||
        android:paddingBottom="80dp"
 | 
					        android:paddingBottom="80dp"
 | 
				
			||||||
        tools:listitem="@layout/item_subscription_detailed" />
 | 
					        tools:listitem="@layout/item_subscription_detailed" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <!-- Add subscription form -->
 | 
				
			||||||
 | 
					    <ScrollView
 | 
				
			||||||
 | 
					        android:id="@+id/scroll_add_form"
 | 
				
			||||||
 | 
					        android:layout_width="match_parent"
 | 
				
			||||||
 | 
					        android:layout_height="match_parent"
 | 
				
			||||||
 | 
					        android:fillViewport="true"
 | 
				
			||||||
 | 
					        android:visibility="gone"
 | 
				
			||||||
 | 
					        android:background="?android:attr/colorBackground">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <LinearLayout
 | 
				
			||||||
 | 
					            android:layout_width="match_parent"
 | 
				
			||||||
 | 
					            android:layout_height="wrap_content"
 | 
				
			||||||
 | 
					            android:orientation="vertical"
 | 
				
			||||||
 | 
					            android:padding="32dp"
 | 
				
			||||||
 | 
					            android:gravity="center">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            <!-- Header Section -->
 | 
				
			||||||
 | 
					            <LinearLayout
 | 
				
			||||||
 | 
					                android:layout_width="match_parent"
 | 
				
			||||||
 | 
					                android:layout_height="wrap_content"
 | 
				
			||||||
 | 
					                android:orientation="vertical"
 | 
				
			||||||
 | 
					                android:gravity="center"
 | 
				
			||||||
 | 
					                android:layout_marginBottom="32dp">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                <TextView
 | 
				
			||||||
 | 
					                    android:layout_width="wrap_content"
 | 
				
			||||||
 | 
					                    android:layout_height="wrap_content"
 | 
				
			||||||
 | 
					                    android:text="Add New Subscription"
 | 
				
			||||||
 | 
					                    android:textSize="24sp"
 | 
				
			||||||
 | 
					                    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" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            </LinearLayout>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            <!-- Form Fields -->
 | 
				
			||||||
 | 
					            <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>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            <!-- Subscription Details Card -->
 | 
				
			||||||
 | 
					            <LinearLayout
 | 
				
			||||||
 | 
					                android:id="@+id/card_customer_info"
 | 
				
			||||||
 | 
					                android:layout_width="match_parent"
 | 
				
			||||||
 | 
					                android:layout_height="wrap_content"
 | 
				
			||||||
 | 
					                android:layout_marginBottom="24dp"
 | 
				
			||||||
 | 
					                android:visibility="gone"
 | 
				
			||||||
 | 
					                android:orientation="vertical"
 | 
				
			||||||
 | 
					                android:background="?android:attr/colorBackground"
 | 
				
			||||||
 | 
					                android:elevation="4dp"
 | 
				
			||||||
 | 
					                android:padding="20dp">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                <!-- Customer Details -->
 | 
				
			||||||
 | 
					                <TextView
 | 
				
			||||||
 | 
					                    android:layout_width="wrap_content"
 | 
				
			||||||
 | 
					                    android:layout_height="wrap_content"
 | 
				
			||||||
 | 
					                    android:text="Customer Details"
 | 
				
			||||||
 | 
					                    android:textSize="14sp"
 | 
				
			||||||
 | 
					                    android:textStyle="bold"
 | 
				
			||||||
 | 
					                    android:textColor="?android:attr/textColorPrimary"
 | 
				
			||||||
 | 
					                    android:layout_marginBottom="8dp" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                <LinearLayout
 | 
				
			||||||
 | 
					                    android:layout_width="match_parent"
 | 
				
			||||||
 | 
					                    android:layout_height="wrap_content"
 | 
				
			||||||
 | 
					                    android:orientation="horizontal"
 | 
				
			||||||
 | 
					                    android:layout_marginBottom="4dp">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    <TextView
 | 
				
			||||||
 | 
					                        android:layout_width="0dp"
 | 
				
			||||||
 | 
					                        android:layout_height="wrap_content"
 | 
				
			||||||
 | 
					                        android:layout_weight="1"
 | 
				
			||||||
 | 
					                        android:text="Name:"
 | 
				
			||||||
 | 
					                        android:textSize="12sp"
 | 
				
			||||||
 | 
					                        android:textColor="?android:attr/textColorSecondary" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    <TextView
 | 
				
			||||||
 | 
					                        android:id="@+id/tv_customer_name"
 | 
				
			||||||
 | 
					                        android:layout_width="0dp"
 | 
				
			||||||
 | 
					                        android:layout_height="wrap_content"
 | 
				
			||||||
 | 
					                        android:layout_weight="2"
 | 
				
			||||||
 | 
					                        android:textSize="12sp"
 | 
				
			||||||
 | 
					                        android:textColor="?android:attr/textColorPrimary" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                </LinearLayout>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                <LinearLayout
 | 
				
			||||||
 | 
					                    android:layout_width="match_parent"
 | 
				
			||||||
 | 
					                    android:layout_height="wrap_content"
 | 
				
			||||||
 | 
					                    android:orientation="horizontal"
 | 
				
			||||||
 | 
					                    android:layout_marginBottom="4dp">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    <TextView
 | 
				
			||||||
 | 
					                        android:layout_width="0dp"
 | 
				
			||||||
 | 
					                        android:layout_height="wrap_content"
 | 
				
			||||||
 | 
					                        android:layout_weight="1"
 | 
				
			||||||
 | 
					                        android:text="Phone:"
 | 
				
			||||||
 | 
					                        android:textSize="12sp"
 | 
				
			||||||
 | 
					                        android:textColor="?android:attr/textColorSecondary" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    <TextView
 | 
				
			||||||
 | 
					                        android:id="@+id/tv_phone_number"
 | 
				
			||||||
 | 
					                        android:layout_width="0dp"
 | 
				
			||||||
 | 
					                        android:layout_height="wrap_content"
 | 
				
			||||||
 | 
					                        android:layout_weight="2"
 | 
				
			||||||
 | 
					                        android:textSize="12sp"
 | 
				
			||||||
 | 
					                        android:textColor="?android:attr/textColorPrimary" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                </LinearLayout>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                <LinearLayout
 | 
				
			||||||
 | 
					                        android:layout_width="match_parent"
 | 
				
			||||||
 | 
					                        android:layout_height="wrap_content"
 | 
				
			||||||
 | 
					                        android:orientation="horizontal"
 | 
				
			||||||
 | 
					                        android:layout_marginBottom="12dp">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    <TextView
 | 
				
			||||||
 | 
					                            android:layout_width="0dp"
 | 
				
			||||||
 | 
					                            android:layout_height="wrap_content"
 | 
				
			||||||
 | 
					                            android:layout_weight="1"
 | 
				
			||||||
 | 
					                            android:text="Address:"
 | 
				
			||||||
 | 
					                            android:textSize="12sp"
 | 
				
			||||||
 | 
					                            android:textColor="?android:attr/textColorSecondary" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    <TextView
 | 
				
			||||||
 | 
					                            android:id="@+id/tv_address"
 | 
				
			||||||
 | 
					                            android:layout_width="0dp"
 | 
				
			||||||
 | 
					                            android:layout_height="wrap_content"
 | 
				
			||||||
 | 
					                            android:layout_weight="2"
 | 
				
			||||||
 | 
					                            android:textSize="12sp"
 | 
				
			||||||
 | 
					                            android:textColor="?android:attr/textColorPrimary" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                </LinearLayout>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    <!-- Service Details -->
 | 
				
			||||||
 | 
					                    <TextView
 | 
				
			||||||
 | 
					                        android:layout_width="wrap_content"
 | 
				
			||||||
 | 
					                        android:layout_height="wrap_content"
 | 
				
			||||||
 | 
					                        android:text="Service Details"
 | 
				
			||||||
 | 
					                        android:textSize="14sp"
 | 
				
			||||||
 | 
					                        android:textStyle="bold"
 | 
				
			||||||
 | 
					                        android:textColor="?android:attr/textColorPrimary"
 | 
				
			||||||
 | 
					                        android:layout_marginBottom="8dp" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                <LinearLayout
 | 
				
			||||||
 | 
					                        android:layout_width="match_parent"
 | 
				
			||||||
 | 
					                        android:layout_height="wrap_content"
 | 
				
			||||||
 | 
					                        android:orientation="horizontal"
 | 
				
			||||||
 | 
					                        android:layout_marginBottom="4dp">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    <TextView
 | 
				
			||||||
 | 
					                            android:layout_width="0dp"
 | 
				
			||||||
 | 
					                            android:layout_height="wrap_content"
 | 
				
			||||||
 | 
					                            android:layout_weight="1"
 | 
				
			||||||
 | 
					                            android:text="Subscription:"
 | 
				
			||||||
 | 
					                            android:textSize="12sp"
 | 
				
			||||||
 | 
					                            android:textColor="?android:attr/textColorSecondary" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    <TextView
 | 
				
			||||||
 | 
					                            android:id="@+id/tv_subscription_number"
 | 
				
			||||||
 | 
					                            android:layout_width="0dp"
 | 
				
			||||||
 | 
					                            android:layout_height="wrap_content"
 | 
				
			||||||
 | 
					                            android:layout_weight="2"
 | 
				
			||||||
 | 
					                            android:textSize="12sp"
 | 
				
			||||||
 | 
					                            android:textColor="?android:attr/textColorPrimary" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                </LinearLayout>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                <LinearLayout
 | 
				
			||||||
 | 
					                        android:layout_width="match_parent"
 | 
				
			||||||
 | 
					                        android:layout_height="wrap_content"
 | 
				
			||||||
 | 
					                        android:orientation="horizontal"
 | 
				
			||||||
 | 
					                        android:layout_marginBottom="16dp">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    <TextView
 | 
				
			||||||
 | 
					                            android:layout_width="0dp"
 | 
				
			||||||
 | 
					                            android:layout_height="wrap_content"
 | 
				
			||||||
 | 
					                            android:layout_weight="1"
 | 
				
			||||||
 | 
					                            android:text="Service:"
 | 
				
			||||||
 | 
					                            android:textSize="12sp"
 | 
				
			||||||
 | 
					                            android:textColor="?android:attr/textColorSecondary" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    <TextView
 | 
				
			||||||
 | 
					                            android:id="@+id/tv_service_type"
 | 
				
			||||||
 | 
					                            android:layout_width="0dp"
 | 
				
			||||||
 | 
					                            android:layout_height="wrap_content"
 | 
				
			||||||
 | 
					                            android:layout_weight="2"
 | 
				
			||||||
 | 
					                            android:textSize="12sp"
 | 
				
			||||||
 | 
					                            android:textColor="?android:attr/textColorPrimary" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                </LinearLayout>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            </LinearLayout>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                <!-- Loading indicator for lookup -->
 | 
				
			||||||
 | 
					                <LinearLayout
 | 
				
			||||||
 | 
					                    android:id="@+id/layout_lookup_loading"
 | 
				
			||||||
 | 
					                    android:layout_width="match_parent"
 | 
				
			||||||
 | 
					                    android:layout_height="wrap_content"
 | 
				
			||||||
 | 
					                    android:orientation="horizontal"
 | 
				
			||||||
 | 
					                    android:gravity="center"
 | 
				
			||||||
 | 
					                    android:layout_marginBottom="24dp"
 | 
				
			||||||
 | 
					                    android:visibility="gone">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    <ProgressBar
 | 
				
			||||||
 | 
					                        android:layout_width="24dp"
 | 
				
			||||||
 | 
					                        android:layout_height="24dp"
 | 
				
			||||||
 | 
					                        android:layout_marginEnd="8dp" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    <TextView
 | 
				
			||||||
 | 
					                        android:layout_width="wrap_content"
 | 
				
			||||||
 | 
					                        android:layout_height="wrap_content"
 | 
				
			||||||
 | 
					                        android:text="Looking up subscription details..."
 | 
				
			||||||
 | 
					                        android:textSize="14sp"
 | 
				
			||||||
 | 
					                        android:textColor="?android:attr/textColorSecondary" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                </LinearLayout>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                <!-- Buttons -->
 | 
				
			||||||
 | 
					                <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_add"
 | 
				
			||||||
 | 
					                        android:layout_width="wrap_content"
 | 
				
			||||||
 | 
					                        android:layout_height="56dp"
 | 
				
			||||||
 | 
					                        android:text="Cancel"
 | 
				
			||||||
 | 
					                        android:textSize="16sp"
 | 
				
			||||||
 | 
					                        android:textAllCaps="false"
 | 
				
			||||||
 | 
					                        android:layout_marginEnd="8dp"
 | 
				
			||||||
 | 
					                        style="@style/Widget.MaterialComponents.Button.TextButton" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    <com.google.android.material.button.MaterialButton
 | 
				
			||||||
 | 
					                        android:id="@+id/btn_continue"
 | 
				
			||||||
 | 
					                        android:layout_width="wrap_content"
 | 
				
			||||||
 | 
					                        android:layout_height="56dp"
 | 
				
			||||||
 | 
					                        android:text="Continue"
 | 
				
			||||||
 | 
					                        android:textSize="16sp"
 | 
				
			||||||
 | 
					                        android:textAllCaps="false"
 | 
				
			||||||
 | 
					                        android:paddingHorizontal="24dp" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                </LinearLayout>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        </LinearLayout>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    </ScrollView>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <com.google.android.material.floatingactionbutton.FloatingActionButton
 | 
					    <com.google.android.material.floatingactionbutton.FloatingActionButton
 | 
				
			||||||
        android:id="@+id/fab_add_subscription"
 | 
					        android:id="@+id/fab_add_subscription"
 | 
				
			||||||
        android:layout_width="wrap_content"
 | 
					        android:layout_width="wrap_content"
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user