Did the same to inventory
This commit is contained in:
@@ -53,20 +53,15 @@ public class InventoryAdapter extends RecyclerView.Adapter<InventoryAdapter.Inve
|
||||
InventoryDTO inv = inventoryList.get(position);
|
||||
ItemInventoryBinding binding = holder.binding;
|
||||
|
||||
// Column: Inventory ID
|
||||
String invIdStr = inv.getInventoryId() != null ? String.valueOf(inv.getInventoryId()) : "—";
|
||||
binding.tvInventoryId.setText("Inv ID: " + invIdStr);
|
||||
|
||||
// Column: Product ID
|
||||
String prodIdStr = inv.getProdId() != null ? String.valueOf(inv.getProdId()) : "—";
|
||||
binding.tvProdId.setText("Prod ID: " + prodIdStr);
|
||||
|
||||
// Column: Product Name
|
||||
binding.tvProductName.setText(inv.getProductName() != null ? inv.getProductName() : "—");
|
||||
|
||||
// Column: Store Name
|
||||
binding.tvInventoryStore.setText("Store: " + (inv.getStoreName() != null ? inv.getStoreName() : "—"));
|
||||
|
||||
// Column: Quantity
|
||||
int qty = inv.getQuantity() != null ? inv.getQuantity() : 0;
|
||||
binding.tvQuantity.setText(String.valueOf(qty));
|
||||
binding.tvQuantity.setText("Stock: " + qty);
|
||||
|
||||
// Low stock = red, normal = green (like desktop reorder concept)
|
||||
if (qty <= 5) {
|
||||
|
||||
@@ -2,13 +2,13 @@ package com.example.petstoremobile.api;
|
||||
|
||||
import com.example.petstoremobile.dtos.BulkDeleteRequest;
|
||||
import com.example.petstoremobile.dtos.InventoryDTO;
|
||||
import com.example.petstoremobile.dtos.InventoryRequest;
|
||||
import com.example.petstoremobile.dtos.PageResponse;
|
||||
|
||||
import retrofit2.Call;
|
||||
import retrofit2.http.Body;
|
||||
import retrofit2.http.DELETE;
|
||||
import retrofit2.http.GET;
|
||||
import retrofit2.http.HTTP;
|
||||
import retrofit2.http.POST;
|
||||
import retrofit2.http.PUT;
|
||||
import retrofit2.http.Path;
|
||||
@@ -32,17 +32,17 @@ public interface InventoryApi {
|
||||
|
||||
// POST /api/v1/inventory
|
||||
@POST("api/v1/inventory")
|
||||
Call<InventoryDTO> createInventory(@Body InventoryRequest request);
|
||||
Call<InventoryDTO> createInventory(@Body InventoryDTO request);
|
||||
|
||||
// PUT /api/v1/inventory/{id}
|
||||
@PUT("api/v1/inventory/{id}")
|
||||
Call<InventoryDTO> updateInventory(@Path("id") Long id, @Body InventoryRequest request);
|
||||
Call<InventoryDTO> updateInventory(@Path("id") Long id, @Body InventoryDTO request);
|
||||
|
||||
// DELETE /api/v1/inventory/{id}
|
||||
@DELETE("api/v1/inventory/{id}")
|
||||
Call<Void> deleteInventory(@Path("id") Long id);
|
||||
|
||||
// DELETE /api/v1/inventory (bulk delete)
|
||||
@DELETE("api/v1/inventory")
|
||||
@HTTP(method = "DELETE", path = "api/v1/inventory", hasBody = true)
|
||||
Call<Void> bulkDeleteInventory(@Body BulkDeleteRequest request);
|
||||
}
|
||||
|
||||
@@ -6,6 +6,8 @@ public class InventoryDTO {
|
||||
private Long prodId;
|
||||
private String productName;
|
||||
private String categoryName;
|
||||
private Long storeId;
|
||||
private String storeName;
|
||||
private Integer quantity;
|
||||
private String createdAt;
|
||||
private String updatedAt;
|
||||
@@ -14,8 +16,9 @@ public class InventoryDTO {
|
||||
}
|
||||
|
||||
// Constructor for create/update requests (matches InventoryRequest)
|
||||
public InventoryDTO(Long prodId, Integer quantity) {
|
||||
public InventoryDTO(Long prodId, Long storeId, Integer quantity) {
|
||||
this.prodId = prodId;
|
||||
this.storeId = storeId;
|
||||
this.quantity = quantity;
|
||||
}
|
||||
|
||||
@@ -51,6 +54,22 @@ public class InventoryDTO {
|
||||
this.categoryName = categoryName;
|
||||
}
|
||||
|
||||
public Long getStoreId() {
|
||||
return storeId;
|
||||
}
|
||||
|
||||
public void setStoreId(Long storeId) {
|
||||
this.storeId = storeId;
|
||||
}
|
||||
|
||||
public String getStoreName() {
|
||||
return storeName;
|
||||
}
|
||||
|
||||
public void setStoreName(String storeName) {
|
||||
this.storeName = storeName;
|
||||
}
|
||||
|
||||
public Integer getQuantity() {
|
||||
return quantity;
|
||||
}
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
package com.example.petstoremobile.dtos;
|
||||
|
||||
public class InventoryRequest {
|
||||
private Long prodId;
|
||||
private Integer quantity;
|
||||
|
||||
public InventoryRequest() {
|
||||
}
|
||||
|
||||
public InventoryRequest(Long prodId, Integer quantity) {
|
||||
this.prodId = prodId;
|
||||
this.quantity = quantity;
|
||||
}
|
||||
|
||||
public Long getProdId() {
|
||||
return prodId;
|
||||
}
|
||||
|
||||
public void setProdId(Long prodId) {
|
||||
this.prodId = prodId;
|
||||
}
|
||||
|
||||
public Integer getQuantity() {
|
||||
return quantity;
|
||||
}
|
||||
|
||||
public void setQuantity(Integer quantity) {
|
||||
this.quantity = quantity;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,9 @@
|
||||
package com.example.petstoremobile.fragments.listfragments.detailfragments;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.text.Editable;
|
||||
import android.text.TextWatcher;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
@@ -18,15 +13,16 @@ import androidx.fragment.app.Fragment;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
import androidx.navigation.fragment.NavHostFragment;
|
||||
|
||||
import com.example.petstoremobile.adapters.BlackTextArrayAdapter;
|
||||
import com.example.petstoremobile.databinding.FragmentInventoryDetailBinding;
|
||||
import com.example.petstoremobile.dtos.InventoryDTO;
|
||||
import com.example.petstoremobile.dtos.InventoryRequest;
|
||||
import com.example.petstoremobile.dtos.ProductDTO;
|
||||
import com.example.petstoremobile.dtos.StoreDTO;
|
||||
import com.example.petstoremobile.utils.InputValidator;
|
||||
import com.example.petstoremobile.utils.Resource;
|
||||
import com.example.petstoremobile.utils.SpinnerUtils;
|
||||
import com.example.petstoremobile.viewmodels.InventoryViewModel;
|
||||
import com.example.petstoremobile.viewmodels.ProductViewModel;
|
||||
import com.example.petstoremobile.viewmodels.StoreViewModel;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -43,20 +39,15 @@ public class InventoryDetailFragment extends Fragment {
|
||||
|
||||
private InventoryViewModel inventoryViewModel;
|
||||
private ProductViewModel productViewModel;
|
||||
private StoreViewModel storeViewModel;
|
||||
|
||||
private boolean isEditing = false;
|
||||
private long inventoryId = -1;
|
||||
private long preselectedStoreId = -1;
|
||||
private long preselectedProductId = -1;
|
||||
|
||||
// The product selected from the dropdown
|
||||
private ProductDTO selectedProduct = null;
|
||||
|
||||
// For debouncing product search
|
||||
private final Handler searchHandler = new Handler(Looper.getMainLooper());
|
||||
private Runnable searchRunnable;
|
||||
|
||||
// Dropdown list
|
||||
private final List<ProductDTO> productSuggestions = new ArrayList<>();
|
||||
private ArrayAdapter<String> dropdownAdapter;
|
||||
private List<StoreDTO> storeList = new ArrayList<>();
|
||||
private List<ProductDTO> productList = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Initializes the view models.
|
||||
@@ -66,6 +57,7 @@ public class InventoryDetailFragment extends Fragment {
|
||||
super.onCreate(savedInstanceState);
|
||||
inventoryViewModel = new ViewModelProvider(this).get(InventoryViewModel.class);
|
||||
productViewModel = new ViewModelProvider(this).get(ProductViewModel.class);
|
||||
storeViewModel = new ViewModelProvider(this).get(StoreViewModel.class);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -85,94 +77,64 @@ public class InventoryDetailFragment extends Fragment {
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
|
||||
setupProductSearch();
|
||||
loadSpinnersData();
|
||||
handleArguments();
|
||||
|
||||
binding.btnInventoryBack.setOnClickListener(v -> navigateBack());
|
||||
binding.btnSaveInventory.setOnClickListener(v -> saveInventory());
|
||||
binding.btnDeleteInventory.setOnClickListener(v -> confirmDelete());
|
||||
|
||||
// Setup dropdown adapter
|
||||
dropdownAdapter = new BlackTextArrayAdapter<>(requireContext(),
|
||||
android.R.layout.simple_dropdown_item_1line, new ArrayList<>());
|
||||
binding.etProductSearch.setAdapter(dropdownAdapter);
|
||||
binding.etProductSearch.setThreshold(1); // start showing after 1 character
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyView() {
|
||||
super.onDestroyView();
|
||||
if (searchRunnable != null) {
|
||||
searchHandler.removeCallbacks(searchRunnable);
|
||||
}
|
||||
binding = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up the product search dropdown.
|
||||
* Fetches required data for spinners from the backend.
|
||||
*/
|
||||
private void setupProductSearch() {
|
||||
binding.etProductSearch.addTextChangedListener(new TextWatcher() {
|
||||
@Override public void beforeTextChanged(CharSequence s, int i, int i1, int i2) {
|
||||
}
|
||||
private void loadSpinnersData() {
|
||||
loadStores();
|
||||
loadProducts();
|
||||
}
|
||||
|
||||
@Override public void afterTextChanged(Editable s) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
||||
// Clear selected product when user is typing again
|
||||
selectedProduct = null;
|
||||
binding.tvProductInfo.setVisibility(View.GONE);
|
||||
|
||||
if (searchRunnable != null)
|
||||
searchHandler.removeCallbacks(searchRunnable);
|
||||
String query = s.toString().trim();
|
||||
if (query.isEmpty())
|
||||
return;
|
||||
|
||||
searchRunnable = () -> searchProducts(query);
|
||||
searchHandler.postDelayed(searchRunnable, 400);
|
||||
}
|
||||
});
|
||||
|
||||
// When user picks an item from the dropdown
|
||||
binding.etProductSearch.setOnItemClickListener((parent, view, position, id) -> {
|
||||
if (position < productSuggestions.size()) {
|
||||
selectedProduct = productSuggestions.get(position);
|
||||
// Show product details below the search box
|
||||
binding.tvProductInfo.setText(
|
||||
"ID: " + selectedProduct.getProdId()
|
||||
+ " • " + selectedProduct.getCategoryName());
|
||||
binding.tvProductInfo.setVisibility(View.VISIBLE);
|
||||
/**
|
||||
* Loads the list of stores for the spinner.
|
||||
*/
|
||||
private void loadStores() {
|
||||
storeViewModel.getAllStores(0, 100).observe(getViewLifecycleOwner(), resource -> {
|
||||
if (resource.status == Resource.Status.SUCCESS && resource.data != null) {
|
||||
storeList = resource.data.getContent();
|
||||
refreshStoreSpinner();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void refreshStoreSpinner() {
|
||||
SpinnerUtils.populateSpinner(requireContext(), binding.spinnerInventoryStore, storeList,
|
||||
StoreDTO::getStoreName, "-- Select Store --",
|
||||
preselectedStoreId, StoreDTO::getStoreId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches for products matching the query from the backend.
|
||||
* Loads the list of products for the spinner.
|
||||
*/
|
||||
private void searchProducts(String query) {
|
||||
if (getView() == null) return;
|
||||
productViewModel.getAllProducts(query, null, 0, 20, "prodName").observe(getViewLifecycleOwner(), resource -> {
|
||||
private void loadProducts() {
|
||||
productViewModel.getAllProducts(null, null, 0, 500, "prodName").observe(getViewLifecycleOwner(), resource -> {
|
||||
if (resource.status == Resource.Status.SUCCESS && resource.data != null) {
|
||||
productSuggestions.clear();
|
||||
productSuggestions.addAll(resource.data.getContent());
|
||||
|
||||
// Build display strings: "Product Name (ID: X)"
|
||||
List<String> names = new ArrayList<>();
|
||||
for (ProductDTO p : productSuggestions) {
|
||||
names.add(p.getProdName() + " (ID: " + p.getProdId() + ")");
|
||||
}
|
||||
|
||||
dropdownAdapter.clear();
|
||||
dropdownAdapter.addAll(names);
|
||||
dropdownAdapter.notifyDataSetChanged();
|
||||
binding.etProductSearch.showDropDown();
|
||||
productList = resource.data.getContent();
|
||||
refreshProductSpinner();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void refreshProductSpinner() {
|
||||
SpinnerUtils.populateSpinner(requireContext(), binding.spinnerInventoryProduct, productList,
|
||||
ProductDTO::getProdName, "-- Select Product --",
|
||||
preselectedProductId, ProductDTO::getProdId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles fragment arguments to determine if we are in edit or add mode.
|
||||
*/
|
||||
@@ -193,7 +155,6 @@ public class InventoryDetailFragment extends Fragment {
|
||||
isEditing = false;
|
||||
binding.tvInventoryMode.setText("Add Inventory");
|
||||
binding.tvInventoryId.setVisibility(View.GONE);
|
||||
binding.tvProductInfo.setVisibility(View.GONE);
|
||||
binding.btnDeleteInventory.setVisibility(View.GONE);
|
||||
binding.btnSaveInventory.setText("Add");
|
||||
}
|
||||
@@ -207,20 +168,12 @@ public class InventoryDetailFragment extends Fragment {
|
||||
if (resource == null) return;
|
||||
if (resource.status == Resource.Status.SUCCESS && resource.data != null) {
|
||||
InventoryDTO inv = resource.data;
|
||||
binding.etProductSearch.setText(inv.getProductName());
|
||||
binding.etQuantity.setText(String.valueOf(inv.getQuantity()));
|
||||
|
||||
if (inv.getProdId() != null) {
|
||||
binding.tvProductInfo.setText(
|
||||
"ID: " + inv.getProdId()
|
||||
+ " • " + inv.getCategoryName());
|
||||
binding.tvProductInfo.setVisibility(View.VISIBLE);
|
||||
|
||||
selectedProduct = new ProductDTO();
|
||||
selectedProduct.setProdId(inv.getProdId());
|
||||
selectedProduct.setProdName(inv.getProductName());
|
||||
selectedProduct.setCategoryName(inv.getCategoryName());
|
||||
}
|
||||
preselectedStoreId = inv.getStoreId() != null ? inv.getStoreId() : -1;
|
||||
preselectedProductId = inv.getProdId() != null ? inv.getProdId() : -1;
|
||||
|
||||
refreshStoreSpinner();
|
||||
refreshProductSpinner();
|
||||
} else if (resource.status == Resource.Status.ERROR) {
|
||||
Toast.makeText(getContext(), "Failed to load inventory: " + resource.message, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
@@ -231,9 +184,12 @@ public class InventoryDetailFragment extends Fragment {
|
||||
* Validates input and saves the current inventory item details to the backend.
|
||||
*/
|
||||
private void saveInventory() {
|
||||
if (selectedProduct == null) {
|
||||
binding.etProductSearch.setError("Please select a product from the list");
|
||||
binding.etProductSearch.requestFocus();
|
||||
if (binding.spinnerInventoryStore.getSelectedItemPosition() == 0) {
|
||||
Toast.makeText(getContext(), "Please select a store", Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
if (binding.spinnerInventoryProduct.getSelectedItemPosition() == 0) {
|
||||
Toast.makeText(getContext(), "Please select a product", Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -243,8 +199,10 @@ public class InventoryDetailFragment extends Fragment {
|
||||
}
|
||||
|
||||
int quantity = Integer.parseInt(binding.etQuantity.getText().toString().trim());
|
||||
StoreDTO store = storeList.get(binding.spinnerInventoryStore.getSelectedItemPosition() - 1);
|
||||
ProductDTO product = productList.get(binding.spinnerInventoryProduct.getSelectedItemPosition() - 1);
|
||||
|
||||
InventoryRequest request = new InventoryRequest(selectedProduct.getProdId(), quantity);
|
||||
InventoryDTO request = new InventoryDTO(product.getProdId(), store.getStoreId(), quantity);
|
||||
setButtonsEnabled(false);
|
||||
|
||||
if (isEditing) {
|
||||
|
||||
@@ -5,7 +5,6 @@ import androidx.lifecycle.LiveData;
|
||||
import com.example.petstoremobile.api.InventoryApi;
|
||||
import com.example.petstoremobile.dtos.BulkDeleteRequest;
|
||||
import com.example.petstoremobile.dtos.InventoryDTO;
|
||||
import com.example.petstoremobile.dtos.InventoryRequest;
|
||||
import com.example.petstoremobile.dtos.PageResponse;
|
||||
import com.example.petstoremobile.utils.Resource;
|
||||
|
||||
@@ -39,11 +38,11 @@ public class InventoryRepository extends BaseRepository {
|
||||
/**
|
||||
* Sends a request to the API to create a new inventory record.
|
||||
*/
|
||||
public LiveData<Resource<InventoryDTO>> createInventory(InventoryRequest request) {
|
||||
public LiveData<Resource<InventoryDTO>> createInventory(InventoryDTO request) {
|
||||
return executeCall(inventoryApi.createInventory(request));
|
||||
}
|
||||
|
||||
public LiveData<Resource<InventoryDTO>> updateInventory(Long id, InventoryRequest request) {
|
||||
public LiveData<Resource<InventoryDTO>> updateInventory(Long id, InventoryDTO request) {
|
||||
return executeCall(inventoryApi.updateInventory(id, request));
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@ import androidx.lifecycle.ViewModel;
|
||||
import com.example.petstoremobile.dtos.BulkDeleteRequest;
|
||||
import com.example.petstoremobile.dtos.CategoryDTO;
|
||||
import com.example.petstoremobile.dtos.InventoryDTO;
|
||||
import com.example.petstoremobile.dtos.InventoryRequest;
|
||||
import com.example.petstoremobile.dtos.PageResponse;
|
||||
import com.example.petstoremobile.dtos.StoreDTO;
|
||||
import com.example.petstoremobile.repositories.CategoryRepository;
|
||||
@@ -50,14 +49,14 @@ public class InventoryViewModel extends ViewModel {
|
||||
/**
|
||||
* Creates a new inventory record.
|
||||
*/
|
||||
public LiveData<Resource<InventoryDTO>> createInventory(InventoryRequest request) {
|
||||
public LiveData<Resource<InventoryDTO>> createInventory(InventoryDTO request) {
|
||||
return inventoryRepository.createInventory(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates an existing inventory record by ID.
|
||||
*/
|
||||
public LiveData<Resource<InventoryDTO>> updateInventory(Long id, InventoryRequest request) {
|
||||
public LiveData<Resource<InventoryDTO>> updateInventory(Long id, InventoryDTO request) {
|
||||
return inventoryRepository.updateInventory(id, request);
|
||||
}
|
||||
|
||||
|
||||
@@ -67,7 +67,23 @@
|
||||
android:layout_marginBottom="12dp"
|
||||
android:visibility="gone"/>
|
||||
|
||||
<!-- Product search label -->
|
||||
<!-- Store selection label -->
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Store"
|
||||
android:textColor="@color/text_dark"
|
||||
android:textSize="12sp"
|
||||
android:layout_marginBottom="4dp"/>
|
||||
|
||||
<!-- Store Spinner -->
|
||||
<Spinner
|
||||
android:id="@+id/spinnerInventoryStore"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp"/>
|
||||
|
||||
<!-- Product selection label -->
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
@@ -76,25 +92,12 @@
|
||||
android:textSize="12sp"
|
||||
android:layout_marginBottom="4dp"/>
|
||||
|
||||
<!-- AutoComplete search box -->
|
||||
<AutoCompleteTextView
|
||||
android:id="@+id/etProductSearch"
|
||||
<!-- Product Spinner -->
|
||||
<Spinner
|
||||
android:id="@+id/spinnerInventoryProduct"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="Search product name…"
|
||||
android:inputType="text"
|
||||
android:completionThreshold="1"
|
||||
android:layout_marginBottom="4dp"/>
|
||||
|
||||
<!-- Selected product info (ID + category) shown after picking -->
|
||||
<TextView
|
||||
android:id="@+id/tvProductInfo"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="#888888"
|
||||
android:textSize="12sp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:visibility="gone"/>
|
||||
android:layout_marginBottom="16dp"/>
|
||||
|
||||
<!-- Quantity label -->
|
||||
<TextView
|
||||
|
||||
@@ -47,7 +47,7 @@
|
||||
android:id="@+id/tvQuantity"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="0"
|
||||
android:text="Stock: 0"
|
||||
android:textColor="@color/text_dark"
|
||||
android:textSize="16sp"
|
||||
android:textStyle="bold" />
|
||||
@@ -55,31 +55,14 @@
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvInventoryId"
|
||||
android:id="@+id/tvInventoryStore"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:text="Inv ID: —"
|
||||
android:layout_marginTop="2dp"
|
||||
android:text="Store: —"
|
||||
android:textColor="#888888"
|
||||
android:textSize="14sp" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_vertical"
|
||||
android:layout_marginTop="8dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvProdId"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="Prod ID: —"
|
||||
android:textColor="#888888"
|
||||
android:textSize="13sp" />
|
||||
|
||||
</LinearLayout>
|
||||
android:textSize="14sp"
|
||||
android:textStyle="italic" />
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
|
||||
Reference in New Issue
Block a user