UI Cetak ulang struk
This commit is contained in:
parent
a30e767adc
commit
5a03fc3aec
@ -2,15 +2,20 @@ package com.example.bdkipoc;
|
||||
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.text.Editable;
|
||||
import android.text.TextWatcher;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.widget.EditText;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
@ -26,66 +31,169 @@ import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class TransactionActivity extends AppCompatActivity {
|
||||
public class TransactionActivity extends AppCompatActivity implements TransactionAdapter.OnPrintClickListener {
|
||||
private RecyclerView recyclerView;
|
||||
private TransactionAdapter adapter;
|
||||
private List<Transaction> transactionList;
|
||||
private List<Transaction> filteredList;
|
||||
private ProgressBar progressBar;
|
||||
private FloatingActionButton refreshButton;
|
||||
private EditText searchEditText;
|
||||
private ImageButton searchButton;
|
||||
|
||||
// Pagination variables
|
||||
private int page = 0;
|
||||
private final int limit = 10;
|
||||
private boolean isLoading = false;
|
||||
private boolean isLastPage = false;
|
||||
private List<Transaction> transactionList = new ArrayList<>();
|
||||
private String currentSearchQuery = "";
|
||||
private boolean isRefreshing = false;
|
||||
|
||||
@Override
|
||||
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_transaction);
|
||||
|
||||
// Set up the toolbar as the action bar
|
||||
androidx.appcompat.widget.Toolbar toolbar = findViewById(R.id.toolbar);
|
||||
setSupportActionBar(toolbar);
|
||||
// Initialize views
|
||||
initViews();
|
||||
|
||||
// Enable the back button in the action bar
|
||||
// Setup toolbar
|
||||
setupToolbar();
|
||||
|
||||
// Setup RecyclerView
|
||||
setupRecyclerView();
|
||||
|
||||
// Setup search functionality
|
||||
setupSearch();
|
||||
|
||||
// Load initial data
|
||||
loadTransactions(0);
|
||||
}
|
||||
|
||||
private void initViews() {
|
||||
recyclerView = findViewById(R.id.recyclerView);
|
||||
progressBar = findViewById(R.id.progressBar);
|
||||
searchEditText = findViewById(R.id.searchEditText);
|
||||
searchButton = findViewById(R.id.searchButton);
|
||||
}
|
||||
|
||||
private void setupToolbar() {
|
||||
Toolbar toolbar = findViewById(R.id.toolbar);
|
||||
setSupportActionBar(toolbar);
|
||||
if (getSupportActionBar() != null) {
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
getSupportActionBar().setDisplayShowHomeEnabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
recyclerView = findViewById(R.id.recyclerView);
|
||||
progressBar = findViewById(R.id.progressBar);
|
||||
refreshButton = findViewById(R.id.refreshButton);
|
||||
private void setupRecyclerView() {
|
||||
transactionList = new ArrayList<>();
|
||||
filteredList = new ArrayList<>();
|
||||
|
||||
adapter = new TransactionAdapter(transactionList);
|
||||
recyclerView.setLayoutManager(new LinearLayoutManager(this));
|
||||
adapter = new TransactionAdapter(filteredList);
|
||||
adapter.setPrintClickListener(this);
|
||||
|
||||
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
|
||||
recyclerView.setLayoutManager(layoutManager);
|
||||
recyclerView.setAdapter(adapter);
|
||||
|
||||
refreshButton.setOnClickListener(v -> refreshTransactions());
|
||||
|
||||
// Add scroll listener for pagination
|
||||
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
|
||||
@Override
|
||||
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
|
||||
super.onScrolled(recyclerView, dx, dy);
|
||||
if (!recyclerView.canScrollVertically(1) && !isLoading && !isLastPage) {
|
||||
|
||||
// Pagination: Load more when reaching the bottom
|
||||
if (!recyclerView.canScrollVertically(1) && !isLoading && !isLastPage && currentSearchQuery.isEmpty()) {
|
||||
loadTransactions(page + 1);
|
||||
}
|
||||
|
||||
// Detect scroll to top for refresh gesture (double tap on top)
|
||||
LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
|
||||
if (layoutManager != null && layoutManager.findFirstCompletelyVisibleItemPosition() == 0 && dy < 0) {
|
||||
// User is at top and scrolling up, enable refresh on search button long press
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
loadTransactions(0);
|
||||
private void setupSearch() {
|
||||
// Search button click listener
|
||||
searchButton.setOnClickListener(v -> performSearch());
|
||||
|
||||
// Search button long press for refresh
|
||||
searchButton.setOnLongClickListener(v -> {
|
||||
refreshTransactions();
|
||||
Toast.makeText(this, "Refreshing data...", Toast.LENGTH_SHORT).show();
|
||||
return true;
|
||||
});
|
||||
|
||||
// Search EditText listener
|
||||
searchEditText.addTextChangedListener(new TextWatcher() {
|
||||
@Override
|
||||
public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
|
||||
|
||||
@Override
|
||||
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
||||
currentSearchQuery = s.toString().trim();
|
||||
filterTransactions(currentSearchQuery);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterTextChanged(Editable s) {}
|
||||
});
|
||||
}
|
||||
|
||||
private void refreshTransactions() {
|
||||
if (isRefreshing) return;
|
||||
|
||||
isRefreshing = true;
|
||||
// Clear search when refreshing
|
||||
searchEditText.setText("");
|
||||
currentSearchQuery = "";
|
||||
page = 0;
|
||||
isLastPage = false;
|
||||
transactionList.clear();
|
||||
filteredList.clear();
|
||||
adapter.notifyDataSetChanged();
|
||||
loadTransactions(0);
|
||||
}
|
||||
|
||||
private void performSearch() {
|
||||
String query = searchEditText.getText().toString().trim();
|
||||
currentSearchQuery = query;
|
||||
filterTransactions(query);
|
||||
|
||||
// Hide keyboard
|
||||
searchEditText.clearFocus();
|
||||
}
|
||||
|
||||
private void filterTransactions(String query) {
|
||||
filteredList.clear();
|
||||
|
||||
if (query.isEmpty()) {
|
||||
filteredList.addAll(transactionList);
|
||||
} else {
|
||||
for (Transaction transaction : transactionList) {
|
||||
if (transaction.referenceId.toLowerCase().contains(query.toLowerCase()) ||
|
||||
transaction.amount.contains(query)) {
|
||||
filteredList.add(transaction);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
adapter.notifyDataSetChanged();
|
||||
|
||||
// Scroll to top after filtering
|
||||
if (!filteredList.isEmpty()) {
|
||||
recyclerView.scrollToPosition(0);
|
||||
}
|
||||
}
|
||||
|
||||
private void loadTransactions(int pageToLoad) {
|
||||
isLoading = true;
|
||||
if (pageToLoad == 0) {
|
||||
progressBar.setVisibility(View.VISIBLE);
|
||||
}
|
||||
new FetchTransactionsTask(pageToLoad).execute();
|
||||
}
|
||||
|
||||
@ -149,33 +257,56 @@ public class TransactionActivity extends AppCompatActivity {
|
||||
@Override
|
||||
protected void onPostExecute(List<Transaction> transactions) {
|
||||
isLoading = false;
|
||||
isRefreshing = false;
|
||||
progressBar.setVisibility(View.GONE);
|
||||
|
||||
if (error) {
|
||||
Toast.makeText(TransactionActivity.this, "Failed to fetch transactions", Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
|
||||
if (pageToLoad == 0) {
|
||||
transactionList.clear();
|
||||
}
|
||||
transactionList.addAll(transactions);
|
||||
adapter.notifyDataSetChanged();
|
||||
|
||||
// Update filtered list based on current search
|
||||
filterTransactions(currentSearchQuery);
|
||||
|
||||
page = pageToLoad;
|
||||
if (transactionList.size() >= total) {
|
||||
isLastPage = true;
|
||||
}
|
||||
|
||||
// Scroll to top if it's a refresh
|
||||
if (pageToLoad == 0 && !filteredList.isEmpty()) {
|
||||
recyclerView.scrollToPosition(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(android.view.MenuItem item) {
|
||||
public void onPrintClick(Transaction transaction) {
|
||||
// Handle print button click
|
||||
Toast.makeText(this, "Cetak Ulang: " + transaction.referenceId, Toast.LENGTH_SHORT).show();
|
||||
|
||||
// Implement your print logic here
|
||||
// For example, you might want to:
|
||||
// 1. Generate receipt
|
||||
// 2. Send to printer
|
||||
// 3. Show print preview
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
if (item.getItemId() == android.R.id.home) {
|
||||
// Handle the back button click
|
||||
finish();
|
||||
return true;
|
||||
}
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
// Transaction model class
|
||||
static class Transaction {
|
||||
int id;
|
||||
String type;
|
||||
|
@ -4,6 +4,7 @@ import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
@ -14,11 +15,20 @@ import java.util.Locale;
|
||||
|
||||
public class TransactionAdapter extends RecyclerView.Adapter<TransactionAdapter.TransactionViewHolder> {
|
||||
private List<TransactionActivity.Transaction> transactionList;
|
||||
private OnPrintClickListener printClickListener;
|
||||
|
||||
public interface OnPrintClickListener {
|
||||
void onPrintClick(TransactionActivity.Transaction transaction);
|
||||
}
|
||||
|
||||
public TransactionAdapter(List<TransactionActivity.Transaction> transactionList) {
|
||||
this.transactionList = transactionList;
|
||||
}
|
||||
|
||||
public void setPrintClickListener(OnPrintClickListener listener) {
|
||||
this.printClickListener = listener;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public TransactionViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
@ -30,19 +40,24 @@ public class TransactionAdapter extends RecyclerView.Adapter<TransactionAdapter.
|
||||
public void onBindViewHolder(@NonNull TransactionViewHolder holder, int position) {
|
||||
TransactionActivity.Transaction t = transactionList.get(position);
|
||||
|
||||
// Set reference ID
|
||||
holder.referenceId.setText(t.referenceId);
|
||||
|
||||
// Format the amount as Indonesian Rupiah
|
||||
try {
|
||||
double amountValue = Double.parseDouble(t.amount);
|
||||
NumberFormat rupiahFormat = NumberFormat.getCurrencyInstance(new Locale.Builder().setLanguage("id").setRegion("ID").build());
|
||||
holder.amount.setText(rupiahFormat.format(amountValue));
|
||||
NumberFormat rupiahFormat = NumberFormat.getInstance(new Locale("id", "ID"));
|
||||
holder.amount.setText("Rp. " + rupiahFormat.format(amountValue));
|
||||
} catch (NumberFormatException e) {
|
||||
holder.amount.setText("Rp " + t.amount);
|
||||
holder.amount.setText("Rp. " + t.amount);
|
||||
}
|
||||
|
||||
holder.status.setText(t.status);
|
||||
holder.referenceId.setText(t.referenceId);
|
||||
holder.merchantName.setText(t.merchantName);
|
||||
holder.createdAt.setText(t.createdAt.replace("T", " ").substring(0, 19));
|
||||
// Set click listener for print button
|
||||
holder.printSection.setOnClickListener(v -> {
|
||||
if (printClickListener != null) {
|
||||
printClickListener.onPrintClick(t);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -51,14 +66,14 @@ public class TransactionAdapter extends RecyclerView.Adapter<TransactionAdapter.
|
||||
}
|
||||
|
||||
static class TransactionViewHolder extends RecyclerView.ViewHolder {
|
||||
TextView amount, status, referenceId, merchantName, createdAt;
|
||||
TextView amount, referenceId;
|
||||
LinearLayout printSection;
|
||||
|
||||
public TransactionViewHolder(@NonNull View itemView) {
|
||||
super(itemView);
|
||||
amount = itemView.findViewById(R.id.textAmount);
|
||||
status = itemView.findViewById(R.id.textStatus);
|
||||
referenceId = itemView.findViewById(R.id.textReferenceId);
|
||||
merchantName = itemView.findViewById(R.id.textMerchantName);
|
||||
createdAt = itemView.findViewById(R.id.textCreatedAt);
|
||||
printSection = itemView.findViewById(R.id.printSection);
|
||||
}
|
||||
}
|
||||
}
|
5
app/src/main/res/drawable/search_background.xml
Normal file
5
app/src/main/res/drawable/search_background.xml
Normal file
@ -0,0 +1,5 @@
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<solid android:color="#f5f5f5" />
|
||||
<corners android:radius="4dp" />
|
||||
<stroke android:width="1dp" android:color="#e0e0e0" />
|
||||
</shape>
|
4
app/src/main/res/drawable/search_button_background.xml
Normal file
4
app/src/main/res/drawable/search_button_background.xml
Normal file
@ -0,0 +1,4 @@
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<solid android:color="#666666" />
|
||||
<corners android:radius="4dp" />
|
||||
</shape>
|
@ -12,10 +12,10 @@
|
||||
android:id="@+id/toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
android:background="?attr/colorPrimary"
|
||||
android:background="#F44336"
|
||||
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
|
||||
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
|
||||
app:title="Transactions History" />
|
||||
app:title="CETAK ULANG STRUK" />
|
||||
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
@ -23,9 +23,42 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp"
|
||||
android:background="#f5f5f5"
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior">
|
||||
|
||||
<!-- Search Section -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:padding="16dp"
|
||||
android:background="@android:color/white"
|
||||
android:gravity="center_vertical">
|
||||
|
||||
<EditText
|
||||
android:id="@+id/searchEditText"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="48dp"
|
||||
android:layout_weight="1"
|
||||
android:background="@drawable/search_background"
|
||||
android:hint="Cari dengan nomor struk..."
|
||||
android:paddingStart="16dp"
|
||||
android:paddingEnd="16dp"
|
||||
android:textSize="14sp"
|
||||
android:textColorHint="#999999" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/searchButton"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:layout_marginStart="8dp"
|
||||
android:background="@drawable/search_button_background"
|
||||
android:src="@android:drawable/ic_menu_search"
|
||||
android:contentDescription="Search"
|
||||
app:tint="@android:color/white" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/progressBar"
|
||||
android:layout_width="wrap_content"
|
||||
@ -38,17 +71,8 @@
|
||||
android:id="@+id/recyclerView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginTop="8dp" />
|
||||
android:background="@android:color/white" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
android:id="@+id/refreshButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom|end"
|
||||
android:layout_margin="16dp"
|
||||
android:contentDescription="Refresh"
|
||||
android:src="@android:drawable/ic_popup_sync"
|
||||
app:tint="@android:color/white" />
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
@ -1,44 +1,76 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="12dp"
|
||||
android:background="@android:color/white"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:elevation="2dp">
|
||||
android:orientation="vertical"
|
||||
android:background="@android:color/white">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/textAmount"
|
||||
android:layout_width="wrap_content"
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Amount"
|
||||
android:textStyle="bold"
|
||||
android:textSize="18sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/textStatus"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Status"
|
||||
android:textColor="#4CAF50"
|
||||
android:textStyle="bold" />
|
||||
android:orientation="horizontal"
|
||||
android:padding="16dp"
|
||||
android:gravity="center_vertical">
|
||||
|
||||
<!-- Kolom 1: Reference ID -->
|
||||
<TextView
|
||||
android:id="@+id/textReferenceId"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Reference ID" />
|
||||
android:layout_weight="1"
|
||||
android:text="ref-eowu3pin"
|
||||
android:textColor="#333333"
|
||||
android:textSize="16sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<!-- Kolom 2: Amount -->
|
||||
<TextView
|
||||
android:id="@+id/textAmount"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="Rp. 1.111"
|
||||
android:textColor="#666666"
|
||||
android:textSize="14sp"
|
||||
android:textAlignment="textEnd" />
|
||||
|
||||
<!-- Kolom 3: Print Button -->
|
||||
<LinearLayout
|
||||
android:id="@+id/printSection"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_vertical|end"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:padding="8dp"
|
||||
android:clickable="true"
|
||||
android:focusable="true">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="16dp"
|
||||
android:layout_height="16dp"
|
||||
android:src="@drawable/ic_print"
|
||||
android:layout_marginEnd="8dp"
|
||||
app:tint="#666666" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/textMerchantName"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Merchant Name" />
|
||||
android:text="Cetak Ulang"
|
||||
android:textColor="#666666"
|
||||
android:textSize="14sp" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<!-- Bottom Border -->
|
||||
<View
|
||||
android:id="@+id/bottomBorder"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:background="#e0e0e0" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/textCreatedAt"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Created At" />
|
||||
</LinearLayout>
|
Loading…
x
Reference in New Issue
Block a user