From 5a03fc3aec294656ac2ea099fb5ddec4f16c0352 Mon Sep 17 00:00:00 2001 From: riz081 Date: Thu, 5 Jun 2025 13:03:44 +0700 Subject: [PATCH] UI Cetak ulang struk --- .../example/bdkipoc/TransactionActivity.java | 177 +++++++++++++++--- .../example/bdkipoc/TransactionAdapter.java | 41 ++-- .../main/res/drawable/search_background.xml | 5 + .../res/drawable/search_button_background.xml | 4 + .../main/res/layout/activity_transaction.xml | 54 ++++-- app/src/main/res/layout/item_transaction.xml | 100 ++++++---- 6 files changed, 296 insertions(+), 85 deletions(-) create mode 100644 app/src/main/res/drawable/search_background.xml create mode 100644 app/src/main/res/drawable/search_button_background.xml diff --git a/app/src/main/java/com/example/bdkipoc/TransactionActivity.java b/app/src/main/java/com/example/bdkipoc/TransactionActivity.java index 51daef6..66678bc 100644 --- a/app/src/main/java/com/example/bdkipoc/TransactionActivity.java +++ b/app/src/main/java/com/example/bdkipoc/TransactionActivity.java @@ -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 transactionList; + private List 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 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); - - adapter = new TransactionAdapter(transactionList); - recyclerView.setLayoutManager(new LinearLayoutManager(this)); + private void setupRecyclerView() { + transactionList = new ArrayList<>(); + filteredList = new ArrayList<>(); + + 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; - progressBar.setVisibility(View.VISIBLE); + 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 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; @@ -201,4 +332,4 @@ public class TransactionActivity extends AppCompatActivity { this.merchantName = merchantName; } } -} +} \ No newline at end of file diff --git a/app/src/main/java/com/example/bdkipoc/TransactionAdapter.java b/app/src/main/java/com/example/bdkipoc/TransactionAdapter.java index e7e0703..39f93cc 100644 --- a/app/src/main/java/com/example/bdkipoc/TransactionAdapter.java +++ b/app/src/main/java/com/example/bdkipoc/TransactionAdapter.java @@ -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 { private List transactionList; + private OnPrintClickListener printClickListener; + + public interface OnPrintClickListener { + void onPrintClick(TransactionActivity.Transaction transaction); + } public TransactionAdapter(List 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 { + if (printClickListener != null) { + printClickListener.onPrintClick(t); + } + }); } @Override @@ -51,14 +66,14 @@ public class TransactionAdapter extends RecyclerView.Adapter + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/search_button_background.xml b/app/src/main/res/drawable/search_button_background.xml new file mode 100644 index 0000000..eb1015a --- /dev/null +++ b/app/src/main/res/drawable/search_button_background.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_transaction.xml b/app/src/main/res/layout/activity_transaction.xml index 866cebd..d91f155 100644 --- a/app/src/main/res/layout/activity_transaction.xml +++ b/app/src/main/res/layout/activity_transaction.xml @@ -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" /> @@ -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"> + + + + + + + + + + android:background="@android:color/white" /> + - - - + \ No newline at end of file diff --git a/app/src/main/res/layout/item_transaction.xml b/app/src/main/res/layout/item_transaction.xml index e26dcb6..09b7e16 100644 --- a/app/src/main/res/layout/item_transaction.xml +++ b/app/src/main/res/layout/item_transaction.xml @@ -1,44 +1,76 @@ + android:orientation="vertical" + android:background="@android:color/white"> - + android:orientation="horizontal" + android:padding="16dp" + android:gravity="center_vertical"> - + + - + + - + + - - + + + + + + + + + + + + \ No newline at end of file