render subscriptions
This commit is contained in:
@@ -65,7 +65,8 @@ data class SubscriptionDetails(
|
|||||||
val hasSmartMeter: Boolean,
|
val hasSmartMeter: Boolean,
|
||||||
val category: ServiceCategory,
|
val category: ServiceCategory,
|
||||||
val customer: Customer,
|
val customer: Customer,
|
||||||
val lastBill: LastBill?
|
val lastBill: LastBill?,
|
||||||
|
val subscriptionAddress: SubscriptionAddress?
|
||||||
)
|
)
|
||||||
|
|
||||||
data class ServiceCategory(
|
data class ServiceCategory(
|
||||||
@@ -85,7 +86,25 @@ data class Customer(
|
|||||||
val id: Long,
|
val id: Long,
|
||||||
val name: String,
|
val name: String,
|
||||||
val accountNumber: String,
|
val accountNumber: String,
|
||||||
val phone: String
|
val phone: String,
|
||||||
|
val type: String
|
||||||
|
)
|
||||||
|
|
||||||
|
data class SubscriptionAddress(
|
||||||
|
val id: Long,
|
||||||
|
val type: String,
|
||||||
|
val property: Property?
|
||||||
|
)
|
||||||
|
|
||||||
|
data class Property(
|
||||||
|
val id: Long,
|
||||||
|
val name: String,
|
||||||
|
val street: Street?
|
||||||
|
)
|
||||||
|
|
||||||
|
data class Street(
|
||||||
|
val id: Long,
|
||||||
|
val name: String
|
||||||
)
|
)
|
||||||
|
|
||||||
data class LastBill(
|
data class LastBill(
|
||||||
|
@@ -0,0 +1,77 @@
|
|||||||
|
package sh.sar.gridflow.ui.subscriptions
|
||||||
|
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import android.widget.Toast
|
||||||
|
import androidx.recyclerview.widget.DiffUtil
|
||||||
|
import androidx.recyclerview.widget.ListAdapter
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import sh.sar.gridflow.data.CustomerSubscription
|
||||||
|
import sh.sar.gridflow.databinding.ItemSubscriptionDetailedBinding
|
||||||
|
|
||||||
|
class DetailedSubscriptionsAdapter : ListAdapter<CustomerSubscription, DetailedSubscriptionsAdapter.SubscriptionViewHolder>(SubscriptionDiffCallback()) {
|
||||||
|
|
||||||
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SubscriptionViewHolder {
|
||||||
|
val binding = ItemSubscriptionDetailedBinding.inflate(
|
||||||
|
LayoutInflater.from(parent.context),
|
||||||
|
parent,
|
||||||
|
false
|
||||||
|
)
|
||||||
|
return SubscriptionViewHolder(binding)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onBindViewHolder(holder: SubscriptionViewHolder, position: Int) {
|
||||||
|
holder.bind(getItem(position))
|
||||||
|
}
|
||||||
|
|
||||||
|
class SubscriptionViewHolder(
|
||||||
|
private val binding: ItemSubscriptionDetailedBinding
|
||||||
|
) : RecyclerView.ViewHolder(binding.root) {
|
||||||
|
|
||||||
|
fun bind(subscription: CustomerSubscription) {
|
||||||
|
with(binding) {
|
||||||
|
// Service icon and category
|
||||||
|
val serviceIcon = when (subscription.subscription.serviceId) {
|
||||||
|
1 -> "⚡" // Electrical
|
||||||
|
2 -> "💧" // Water
|
||||||
|
else -> "🔌" // Unknown
|
||||||
|
}
|
||||||
|
textServiceIcon.text = serviceIcon
|
||||||
|
|
||||||
|
// Subscription info
|
||||||
|
textSubscriptionName.text = subscription.name
|
||||||
|
textSubscriptionNumber.text = "Sub #${subscription.subscription.subscriptionNumber}"
|
||||||
|
textServiceCategory.text = subscription.subscription.category.name.uppercase()
|
||||||
|
|
||||||
|
// Property information
|
||||||
|
val propertyName = subscription.subscription.subscriptionAddress?.property?.name ?: "Unknown Property"
|
||||||
|
val streetName = subscription.subscription.subscriptionAddress?.property?.street?.name ?: "Unknown Street"
|
||||||
|
textPropertyName.text = propertyName
|
||||||
|
textPropertyStreet.text = streetName
|
||||||
|
|
||||||
|
// Customer information
|
||||||
|
textCustomerName.text = subscription.subscription.customer.name
|
||||||
|
textCustomerPhone.text = subscription.subscription.customer.phone
|
||||||
|
|
||||||
|
// Action buttons - show coming soon toasts
|
||||||
|
btnEdit.setOnClickListener {
|
||||||
|
Toast.makeText(it.context, "Edit subscription coming soon", Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
|
|
||||||
|
btnDelete.setOnClickListener {
|
||||||
|
Toast.makeText(it.context, "Delete subscription coming soon", Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class SubscriptionDiffCallback : DiffUtil.ItemCallback<CustomerSubscription>() {
|
||||||
|
override fun areItemsTheSame(oldItem: CustomerSubscription, newItem: CustomerSubscription): Boolean {
|
||||||
|
return oldItem.id == newItem.id
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun areContentsTheSame(oldItem: CustomerSubscription, newItem: CustomerSubscription): Boolean {
|
||||||
|
return oldItem == newItem
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -7,35 +7,109 @@ import android.view.ViewGroup
|
|||||||
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 sh.sar.gridflow.databinding.FragmentSubscriptionsBinding
|
import sh.sar.gridflow.databinding.FragmentSubscriptionsBinding
|
||||||
|
|
||||||
class SubscriptionsFragment : Fragment() {
|
class SubscriptionsFragment : Fragment() {
|
||||||
|
|
||||||
private var _binding: FragmentSubscriptionsBinding? = null
|
private var _binding: FragmentSubscriptionsBinding? = null
|
||||||
private val binding get() = _binding!!
|
private val binding get() = _binding!!
|
||||||
|
|
||||||
|
private lateinit var subscriptionsViewModel: SubscriptionsViewModel
|
||||||
|
private lateinit var subscriptionsAdapter: DetailedSubscriptionsAdapter
|
||||||
|
|
||||||
override fun onCreateView(
|
override fun onCreateView(
|
||||||
inflater: LayoutInflater,
|
inflater: LayoutInflater,
|
||||||
container: ViewGroup?,
|
container: ViewGroup?,
|
||||||
savedInstanceState: Bundle?
|
savedInstanceState: Bundle?
|
||||||
): View {
|
): View {
|
||||||
val subscriptionsViewModel =
|
subscriptionsViewModel = ViewModelProvider(
|
||||||
ViewModelProvider(this).get(SubscriptionsViewModel::class.java)
|
this,
|
||||||
|
ViewModelProvider.AndroidViewModelFactory.getInstance(requireActivity().application)
|
||||||
|
).get(SubscriptionsViewModel::class.java)
|
||||||
|
|
||||||
_binding = FragmentSubscriptionsBinding.inflate(inflater, container, false)
|
_binding = FragmentSubscriptionsBinding.inflate(inflater, container, false)
|
||||||
val root: View = binding.root
|
|
||||||
|
setupViews()
|
||||||
val textView = binding.textSubscriptions
|
setupObservers()
|
||||||
subscriptionsViewModel.text.observe(viewLifecycleOwner) {
|
|
||||||
textView.text = it
|
return binding.root
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setupViews() {
|
||||||
|
// Setup RecyclerView
|
||||||
|
subscriptionsAdapter = DetailedSubscriptionsAdapter()
|
||||||
|
binding.recyclerSubscriptions.apply {
|
||||||
|
layoutManager = LinearLayoutManager(requireContext())
|
||||||
|
adapter = subscriptionsAdapter
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle FAB click
|
// Handle FAB click
|
||||||
binding.fabAddSubscription.setOnClickListener {
|
binding.fabAddSubscription.setOnClickListener {
|
||||||
Toast.makeText(context, "Add subscription coming soon", Toast.LENGTH_SHORT).show()
|
Toast.makeText(context, "Add subscription coming soon", Toast.LENGTH_SHORT).show()
|
||||||
}
|
}
|
||||||
|
|
||||||
return root
|
// Handle retry button
|
||||||
|
binding.btnRetry.setOnClickListener {
|
||||||
|
subscriptionsViewModel.refreshSubscriptions()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setupObservers() {
|
||||||
|
// Subscriptions data
|
||||||
|
subscriptionsViewModel.subscriptions.observe(viewLifecycleOwner) { subscriptions ->
|
||||||
|
subscriptionsAdapter.submitList(subscriptions)
|
||||||
|
|
||||||
|
// Show appropriate state
|
||||||
|
if (subscriptions.isEmpty()) {
|
||||||
|
showEmptyState()
|
||||||
|
} else {
|
||||||
|
showSubscriptionsList()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Loading state
|
||||||
|
subscriptionsViewModel.isLoading.observe(viewLifecycleOwner) { isLoading ->
|
||||||
|
if (isLoading) {
|
||||||
|
showLoadingState()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error state
|
||||||
|
subscriptionsViewModel.error.observe(viewLifecycleOwner) { error ->
|
||||||
|
if (error != null) {
|
||||||
|
showErrorState(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun showLoadingState() {
|
||||||
|
binding.progressLoading.visibility = View.VISIBLE
|
||||||
|
binding.recyclerSubscriptions.visibility = View.GONE
|
||||||
|
binding.layoutError.visibility = View.GONE
|
||||||
|
binding.layoutEmpty.visibility = View.GONE
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun showSubscriptionsList() {
|
||||||
|
binding.progressLoading.visibility = View.GONE
|
||||||
|
binding.recyclerSubscriptions.visibility = View.VISIBLE
|
||||||
|
binding.layoutError.visibility = View.GONE
|
||||||
|
binding.layoutEmpty.visibility = View.GONE
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun showEmptyState() {
|
||||||
|
binding.progressLoading.visibility = View.GONE
|
||||||
|
binding.recyclerSubscriptions.visibility = View.GONE
|
||||||
|
binding.layoutError.visibility = View.GONE
|
||||||
|
binding.layoutEmpty.visibility = View.VISIBLE
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun showErrorState(error: String) {
|
||||||
|
binding.progressLoading.visibility = View.GONE
|
||||||
|
binding.recyclerSubscriptions.visibility = View.GONE
|
||||||
|
binding.layoutError.visibility = View.VISIBLE
|
||||||
|
binding.layoutEmpty.visibility = View.GONE
|
||||||
|
binding.textError.text = error
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroyView() {
|
override fun onDestroyView() {
|
||||||
|
@@ -1,13 +1,69 @@
|
|||||||
package sh.sar.gridflow.ui.subscriptions
|
package sh.sar.gridflow.ui.subscriptions
|
||||||
|
|
||||||
|
import android.app.Application
|
||||||
|
import android.util.Log
|
||||||
|
import androidx.lifecycle.AndroidViewModel
|
||||||
import androidx.lifecycle.LiveData
|
import androidx.lifecycle.LiveData
|
||||||
import androidx.lifecycle.MutableLiveData
|
import androidx.lifecycle.MutableLiveData
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.viewModelScope
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import sh.sar.gridflow.data.CustomerSubscription
|
||||||
|
import sh.sar.gridflow.network.ApiResult
|
||||||
|
import sh.sar.gridflow.network.FenakaApiService
|
||||||
|
import sh.sar.gridflow.utils.SecureStorage
|
||||||
|
|
||||||
class SubscriptionsViewModel : ViewModel() {
|
class SubscriptionsViewModel(application: Application) : AndroidViewModel(application) {
|
||||||
|
|
||||||
private val _text = MutableLiveData<String>().apply {
|
private val secureStorage = SecureStorage(application)
|
||||||
value = "Subscriptions\n\nComing soon..."
|
private val apiService = FenakaApiService()
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val TAG = "SubscriptionsViewModel"
|
||||||
|
}
|
||||||
|
|
||||||
|
private val _subscriptions = MutableLiveData<List<CustomerSubscription>>()
|
||||||
|
val subscriptions: LiveData<List<CustomerSubscription>> = _subscriptions
|
||||||
|
|
||||||
|
private val _isLoading = MutableLiveData<Boolean>()
|
||||||
|
val isLoading: LiveData<Boolean> = _isLoading
|
||||||
|
|
||||||
|
private val _error = MutableLiveData<String?>()
|
||||||
|
val error: LiveData<String?> = _error
|
||||||
|
|
||||||
|
init {
|
||||||
|
loadSubscriptions()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun loadSubscriptions() {
|
||||||
|
val cookie = secureStorage.getCookie()
|
||||||
|
if (cookie == null) {
|
||||||
|
Log.d(TAG, "No cookie found, cannot load subscriptions")
|
||||||
|
_error.value = "Authentication required"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
_isLoading.value = true
|
||||||
|
_error.value = null
|
||||||
|
|
||||||
|
viewModelScope.launch {
|
||||||
|
Log.d(TAG, "Loading customer subscriptions")
|
||||||
|
when (val result = apiService.getCustomerSubscriptions("connect.sid=$cookie")) {
|
||||||
|
is ApiResult.Success -> {
|
||||||
|
Log.d(TAG, "Subscriptions loaded successfully: ${result.data.size} found")
|
||||||
|
_isLoading.value = false
|
||||||
|
_subscriptions.value = result.data
|
||||||
|
|
||||||
|
} is ApiResult.Error -> {
|
||||||
|
Log.d(TAG, "Failed to load subscriptions: ${result.message}")
|
||||||
|
_isLoading.value = false
|
||||||
|
_error.value = result.message
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun refreshSubscriptions() {
|
||||||
|
Log.d(TAG, "Refreshing subscriptions")
|
||||||
|
loadSubscriptions()
|
||||||
}
|
}
|
||||||
val text: LiveData<String> = _text
|
|
||||||
}
|
}
|
||||||
|
9
app/src/main/res/drawable/card_background.xml
Normal file
9
app/src/main/res/drawable/card_background.xml
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:shape="rectangle">
|
||||||
|
<solid android:color="@color/card_background_color" />
|
||||||
|
<corners android:radius="12dp" />
|
||||||
|
<stroke
|
||||||
|
android:width="1dp"
|
||||||
|
android:color="@color/card_stroke_color" />
|
||||||
|
</shape>
|
6
app/src/main/res/drawable/category_tag_background.xml
Normal file
6
app/src/main/res/drawable/category_tag_background.xml
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:shape="rectangle">
|
||||||
|
<solid android:color="@color/category_tag_background" />
|
||||||
|
<corners android:radius="8dp" />
|
||||||
|
</shape>
|
@@ -1,37 +1,86 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<androidx.coordinatorlayout.widget.CoordinatorLayout 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:app="http://schemas.android.com/apk/res/auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:background="?android:attr/colorBackground"
|
android:background="?android:attr/colorBackground"
|
||||||
tools:context=".ui.subscriptions.SubscriptionsFragment">
|
tools:context=".ui.subscriptions.SubscriptionsFragment">
|
||||||
|
|
||||||
<ScrollView
|
<!-- Loading indicator -->
|
||||||
|
<ProgressBar
|
||||||
|
android:id="@+id/progress_loading"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:visibility="gone" />
|
||||||
|
|
||||||
|
<!-- Error message -->
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/layout_error"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:fillViewport="true">
|
android:orientation="vertical"
|
||||||
|
android:gravity="center"
|
||||||
|
android:padding="32dp"
|
||||||
|
android:visibility="gone">
|
||||||
|
|
||||||
<LinearLayout
|
<TextView
|
||||||
android:layout_width="match_parent"
|
android:id="@+id/text_error"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="vertical"
|
android:textSize="16sp"
|
||||||
android:padding="20dp"
|
android:textColor="?android:attr/textColorPrimary"
|
||||||
android:gravity="center">
|
android:gravity="center"
|
||||||
|
android:layout_marginBottom="16dp"
|
||||||
|
tools:text="Failed to load subscriptions" />
|
||||||
|
|
||||||
<TextView
|
<com.google.android.material.button.MaterialButton
|
||||||
android:id="@+id/text_subscriptions"
|
android:id="@+id/btn_retry"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:textSize="18sp"
|
android:text="Retry" />
|
||||||
android:textColor="?android:attr/textColorPrimary"
|
|
||||||
android:gravity="center"
|
|
||||||
android:layout_marginTop="100dp"
|
|
||||||
tools:text="Subscriptions\n\nComing soon..." />
|
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
</ScrollView>
|
<!-- Empty state -->
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/layout_empty"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:gravity="center"
|
||||||
|
android:padding="32dp"
|
||||||
|
android:visibility="gone">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="No subscriptions found"
|
||||||
|
android:textSize="18sp"
|
||||||
|
android:textColor="?android:attr/textColorPrimary"
|
||||||
|
android:gravity="center"
|
||||||
|
android:layout_marginBottom="8dp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Add a new subscription to get started"
|
||||||
|
android:textSize="14sp"
|
||||||
|
android:textColor="?android:attr/textColorSecondary"
|
||||||
|
android:gravity="center" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<!-- Subscriptions list -->
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/recycler_subscriptions"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:clipToPadding="false"
|
||||||
|
android:paddingTop="8dp"
|
||||||
|
android:paddingBottom="80dp"
|
||||||
|
tools:listitem="@layout/item_subscription_detailed" />
|
||||||
|
|
||||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||||
android:id="@+id/fab_add_subscription"
|
android:id="@+id/fab_add_subscription"
|
||||||
@@ -42,6 +91,6 @@
|
|||||||
android:layout_marginBottom="16dp"
|
android:layout_marginBottom="16dp"
|
||||||
android:src="@drawable/ic_add_24"
|
android:src="@drawable/ic_add_24"
|
||||||
android:contentDescription="Add subscription"
|
android:contentDescription="Add subscription"
|
||||||
app:tint="?android:attr/colorBackground" />
|
android:tint="?android:attr/colorBackground" />
|
||||||
|
|
||||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||||
|
182
app/src/main/res/layout/item_subscription_detailed.xml
Normal file
182
app/src/main/res/layout/item_subscription_detailed.xml
Normal file
@@ -0,0 +1,182 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginHorizontal="16dp"
|
||||||
|
android:layout_marginVertical="4dp"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="16dp"
|
||||||
|
android:background="@drawable/card_background"
|
||||||
|
android:elevation="2dp">
|
||||||
|
|
||||||
|
<!-- Header with service icon and name -->
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:layout_marginBottom="12dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/text_service_icon"
|
||||||
|
android:layout_width="32dp"
|
||||||
|
android:layout_height="32dp"
|
||||||
|
android:gravity="center"
|
||||||
|
android:textSize="16sp"
|
||||||
|
android:background="@drawable/circle_background"
|
||||||
|
android:layout_marginEnd="12dp"
|
||||||
|
tools:text="⚡" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/text_subscription_name"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textSize="16sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:textColor="?android:attr/textColorPrimary"
|
||||||
|
tools:text="Nalahiya" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/text_subscription_number"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textSize="12sp"
|
||||||
|
android:textColor="?android:attr/textColorSecondary"
|
||||||
|
tools:text="Sub #98738" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/text_service_category"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingHorizontal="8dp"
|
||||||
|
android:paddingVertical="4dp"
|
||||||
|
android:textSize="10sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:textColor="?android:attr/textColorPrimary"
|
||||||
|
android:background="@drawable/category_tag_background"
|
||||||
|
android:textAllCaps="true"
|
||||||
|
tools:text="DOMESTIC" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<!-- Property and Customer Information Side by Side -->
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:layout_marginBottom="12dp">
|
||||||
|
|
||||||
|
<!-- Property Information -->
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_marginEnd="16dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Property"
|
||||||
|
android:textSize="10sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:textColor="?android:attr/textColorSecondary"
|
||||||
|
android:textAllCaps="true"
|
||||||
|
android:layout_marginBottom="4dp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/text_property_name"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textSize="13sp"
|
||||||
|
android:textColor="?android:attr/textColorPrimary"
|
||||||
|
android:layout_marginBottom="2dp"
|
||||||
|
tools:text="NALAHIYA" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/text_property_street"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textSize="11sp"
|
||||||
|
android:textColor="?android:attr/textColorSecondary"
|
||||||
|
tools:text="EDHURU ALIBE HIN'GUN" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<!-- Customer Information -->
|
||||||
|
<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="Customer"
|
||||||
|
android:textSize="10sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:textColor="?android:attr/textColorSecondary"
|
||||||
|
android:textAllCaps="true"
|
||||||
|
android:layout_marginBottom="4dp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/text_customer_name"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textSize="13sp"
|
||||||
|
android:textColor="?android:attr/textColorPrimary"
|
||||||
|
android:layout_marginBottom="2dp"
|
||||||
|
tools:text="Muaaviyath Mohamed" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/text_customer_phone"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textSize="11sp"
|
||||||
|
android:textColor="?android:attr/textColorSecondary"
|
||||||
|
tools:text="9873221" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<!-- Action Buttons -->
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:gravity="end">
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/btn_edit"
|
||||||
|
style="?android:attr/buttonBarButtonStyle"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Edit"
|
||||||
|
android:textSize="11sp"
|
||||||
|
android:minHeight="36dp"
|
||||||
|
android:layout_marginEnd="8dp" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/btn_delete"
|
||||||
|
style="?android:attr/buttonBarButtonStyle"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Delete"
|
||||||
|
android:textSize="11sp"
|
||||||
|
android:minHeight="36dp"
|
||||||
|
android:textColor="?android:attr/colorError" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
@@ -14,4 +14,7 @@
|
|||||||
<color name="icon_circle_border">#555555</color>
|
<color name="icon_circle_border">#555555</color>
|
||||||
<color name="selected_subscription_background">#1E3A8A</color>
|
<color name="selected_subscription_background">#1E3A8A</color>
|
||||||
<color name="selected_subscription_border">#3B82F6</color>
|
<color name="selected_subscription_border">#3B82F6</color>
|
||||||
|
<color name="category_tag_background">#424242</color>
|
||||||
|
<color name="card_stroke_color">#222222</color>
|
||||||
|
<color name="card_background_color">#121212</color>
|
||||||
</resources>
|
</resources>
|
||||||
|
@@ -14,4 +14,7 @@
|
|||||||
<color name="icon_circle_border">#BBDEFB</color>
|
<color name="icon_circle_border">#BBDEFB</color>
|
||||||
<color name="selected_subscription_background">#E3F2FD</color>
|
<color name="selected_subscription_background">#E3F2FD</color>
|
||||||
<color name="selected_subscription_border">#90CAF9</color>
|
<color name="selected_subscription_border">#90CAF9</color>
|
||||||
|
<color name="category_tag_background">#E0E0E0</color>
|
||||||
|
<color name="card_stroke_color">#E0E0E0</color>
|
||||||
|
<color name="card_background_color">#FFFFFF</color>
|
||||||
</resources>
|
</resources>
|
||||||
|
Reference in New Issue
Block a user