Compare commits

...

18 Commits

Author SHA1 Message Date
edca7f92ec implement history 2025-06-06 05:29:37 +07:00
3f189f5975 implement menu settlement 2025-06-05 16:19:46 +07:00
5a03fc3aec UI Cetak ulang struk 2025-06-05 13:03:44 +07:00
a30e767adc update UI QRIS Result 2025-06-03 17:17:46 +07:00
74f95e0374 update UI QRIS 2025-06-02 13:16:46 +07:00
1799e7eb0e adjustment 2025-05-30 20:17:43 +07:00
2a24016637 implement menu debit dan qris 2025-05-30 19:27:43 +07:00
459d9ab0f1 improve page struct 2025-05-30 16:13:51 +07:00
191966a2e4 improve payment success UI 2025-05-30 14:59:46 +07:00
46fb81b6a7 initialize success sreen dan receipt screen 2025-05-30 11:47:53 +07:00
290f3015d9 Improve UI Pin Page 2025-05-28 21:31:57 +07:00
f1228db89a UI PIN 2025-05-28 14:33:26 +07:00
810964b4be menambahkan modal 2025-05-28 12:06:20 +07:00
a7fa40d60a UI Kartu Kredit 2025-05-27 15:46:20 +07:00
a07e7a99ac improve button lainnya 2025-05-23 01:04:54 +07:00
c55af6141f improve menu home page 2025-05-22 23:33:20 +07:00
6d681f5e41 Implement PaymentActivity dan TransactionActivity 2025-05-22 17:14:08 +07:00
1ca26371a1 Menu Home dan Icon 2025-05-22 17:03:58 +07:00
71 changed files with 7035 additions and 1012 deletions

3
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,3 @@
{
"java.configuration.updateBuildConfiguration": "interactive"
}

View File

@ -35,6 +35,7 @@ dependencies {
implementation libs.activity
implementation libs.constraintlayout
implementation libs.cardview
implementation 'androidx.recyclerview:recyclerview:1.3.0'
testImplementation libs.junit
androidTestImplementation libs.ext.junit
androidTestImplementation libs.espresso.core

View File

@ -17,6 +17,7 @@
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.BDKIPOC"
android:usesCleartextTraffic="true"
tools:targetApi="31">
<activity
android:name=".MainActivity"
@ -33,7 +34,27 @@
<activity
android:name=".PaymentActivity"
android:exported="false" />
<activity
android:name=".PinActivity"
android:screenOrientation="portrait"
android:theme="@style/Theme.AppCompat.Light.NoActionBar"
android:exported="false" />
<activity
android:name=".ReceiptActivity"
android:exported="false" />
<activity
android:name=".QrisActivity"
android:exported="false" />
<activity android:name=".QrisResultActivity" />
<activity
android:name=".SettlementActivity"
android:exported="false" />
<activity
android:name=".HistoryActivity"
android:exported="false" />
<activity
android:name=".HistoryDetailActivity"
android:exported="false" />
</application>
</manifest>

View File

@ -0,0 +1,415 @@
package com.example.bdkipoc;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.text.NumberFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Locale;
public class HistoryActivity extends AppCompatActivity {
private TextView tvTotalAmount;
private TextView tvTotalTransactions;
private TextView btnLihatDetailTop;
private Button btnLihatDetailBottom;
private RecyclerView recyclerView;
private HistoryAdapter adapter;
private List<HistoryItem> historyList;
private ImageView btnBack;
// Store full data for detail view
private static List<HistoryItem> fullHistoryData = new ArrayList<>();
private String API_URL = "https://be-edc.msvc.app/transactions?page=0&limit=50&sortOrder=DESC&from_date=2025-05-10&to_date=2025-05-21&location_id=0&merchant_id=0&sortColumn=id";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_history);
initViews();
setupRecyclerView();
fetchApiData();
setupClickListeners();
}
private void initViews() {
tvTotalAmount = findViewById(R.id.tv_total_amount);
tvTotalTransactions = findViewById(R.id.tv_total_transactions);
btnLihatDetailTop = findViewById(R.id.btn_lihat_detail);
btnLihatDetailBottom = findViewById(R.id.btn_lihat_detail_bottom);
recyclerView = findViewById(R.id.recycler_view);
btnBack = findViewById(R.id.btn_back);
historyList = new ArrayList<>();
}
private void setupRecyclerView() {
adapter = new HistoryAdapter(historyList);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.setAdapter(adapter);
}
private void setupClickListeners() {
btnBack.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
finish();
}
});
View.OnClickListener detailClickListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
try {
Intent intent = new Intent(HistoryActivity.this, HistoryDetailActivity.class);
startActivity(intent);
} catch (Exception e) {
e.printStackTrace();
Toast.makeText(HistoryActivity.this, "Error opening detail", Toast.LENGTH_SHORT).show();
}
}
};
btnLihatDetailTop.setOnClickListener(detailClickListener);
btnLihatDetailBottom.setOnClickListener(detailClickListener);
}
private void fetchApiData() {
new ApiTask().execute(API_URL);
}
private void processApiData(JSONArray dataArray) {
try {
historyList.clear();
fullHistoryData.clear(); // Clear static data
final long[] totalAmountArray = {0};
final int[] totalTransactionsArray = {0};
for (int i = 0; i < dataArray.length(); i++) {
JSONObject item = dataArray.getJSONObject(i);
String channelCode = item.getString("channel_code");
String amount = item.getString("amount");
String status = item.getString("status");
String transactionDate = item.getString("transaction_date");
String referenceId = item.getString("reference_id");
// Parse amount safely
double amountValue = 0;
try {
amountValue = Double.parseDouble(amount);
} catch (NumberFormatException e) {
amountValue = 0;
}
// Create history item
HistoryItem historyItem = new HistoryItem();
historyItem.setTime(formatTime(transactionDate));
historyItem.setDate(formatDate(transactionDate));
historyItem.setAmount((long) amountValue);
historyItem.setChannelName(formatChannelName(channelCode));
historyItem.setStatus(status);
historyItem.setReferenceId(referenceId);
historyItem.setFullDate(transactionDate);
historyItem.setChannelCode(channelCode);
// Add to full data
fullHistoryData.add(historyItem);
// Add first 10 to display list
if (i < 10) {
historyList.add(historyItem);
}
totalAmountArray[0] += (long) amountValue;
totalTransactionsArray[0]++;
}
runOnUiThread(new Runnable() {
@Override
public void run() {
updateSummary(totalAmountArray[0], totalTransactionsArray[0]);
adapter.notifyDataSetChanged();
}
});
} catch (JSONException e) {
e.printStackTrace();
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(HistoryActivity.this, "Error parsing data", Toast.LENGTH_SHORT).show();
loadSampleData();
}
});
}
}
private void updateSummary(long totalAmount, int totalTransactions) {
tvTotalAmount.setText("RP " + formatCurrency(totalAmount));
tvTotalTransactions.setText(String.valueOf(totalTransactions));
}
private void loadSampleData() {
historyList.clear();
fullHistoryData.clear();
// Create sample data
HistoryItem[] sampleData = {
new HistoryItem("03:44", "11-05-2025", 2018619, "Kredit", "FAILED", "197870"),
new HistoryItem("03:10", "12-05-2025", 3974866, "QRIS", "SUCCESS", "053059"),
new HistoryItem("15:17", "13-05-2025", 2418167, "QRIS", "FAILED", "668320"),
new HistoryItem("12:09", "11-05-2025", 3429230, "Debit", "FAILED", "454790"),
new HistoryItem("08:39", "10-05-2025", 4656447, "QRIS", "FAILED", "454248"),
new HistoryItem("00:35", "12-05-2025", 3507704, "QRIS", "FAILED", "301644"),
new HistoryItem("22:43", "13-05-2025", 4277904, "Debit", "SUCCESS", "388709"),
new HistoryItem("18:16", "11-05-2025", 4456904, "Debit", "FAILED", "986861")
};
for (HistoryItem item : sampleData) {
historyList.add(item);
fullHistoryData.add(item);
}
tvTotalAmount.setText("RP 36.166.829");
tvTotalTransactions.setText("10");
adapter.notifyDataSetChanged();
}
private String formatChannelName(String channelCode) {
switch (channelCode) {
case "DEBIT":
return "Debit";
case "QRIS":
return "QRIS";
case "OTHER":
return "Kredit";
default:
return channelCode.substring(0, 1).toUpperCase() +
channelCode.substring(1).toLowerCase();
}
}
private String formatTime(String isoDate) {
try {
SimpleDateFormat inputFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.getDefault());
SimpleDateFormat outputFormat = new SimpleDateFormat("HH:mm", Locale.getDefault());
Date date = inputFormat.parse(isoDate);
return outputFormat.format(date);
} catch (ParseException e) {
return "00:00";
}
}
private String formatDate(String isoDate) {
try {
SimpleDateFormat inputFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.getDefault());
SimpleDateFormat outputFormat = new SimpleDateFormat("dd-MM-yyyy", Locale.getDefault());
Date date = inputFormat.parse(isoDate);
return outputFormat.format(date);
} catch (ParseException e) {
return "01-01-2025";
}
}
private String formatCurrency(long amount) {
NumberFormat formatter = NumberFormat.getNumberInstance(new Locale("id", "ID"));
return formatter.format(amount);
}
// Public static method to get full data for detail activity
public static List<HistoryItem> getFullHistoryData() {
return new ArrayList<>(fullHistoryData);
}
// AsyncTask for API call
private class ApiTask extends AsyncTask<String, Void, String> {
@Override
protected String doInBackground(String... urls) {
try {
URL url = new URL(urls[0]);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.setConnectTimeout(10000);
connection.setReadTimeout(10000);
int responseCode = connection.getResponseCode();
if (responseCode == HttpURLConnection.HTTP_OK) {
BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
StringBuilder response = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
response.append(line);
}
reader.close();
return response.toString();
}
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
@Override
protected void onPostExecute(String result) {
if (result != null) {
try {
JSONObject jsonResponse = new JSONObject(result);
if (jsonResponse.getInt("status") == 200) {
JSONObject results = jsonResponse.getJSONObject("results");
JSONArray dataArray = results.getJSONArray("data");
processApiData(dataArray);
} else {
Toast.makeText(HistoryActivity.this, "API Error", Toast.LENGTH_SHORT).show();
loadSampleData();
}
} catch (JSONException e) {
e.printStackTrace();
Toast.makeText(HistoryActivity.this, "JSON Parse Error", Toast.LENGTH_SHORT).show();
loadSampleData();
}
} else {
Toast.makeText(HistoryActivity.this, "Network Error", Toast.LENGTH_SHORT).show();
loadSampleData();
}
}
}
}
// HistoryItem class - enhanced with more fields
class HistoryItem {
private String time;
private String date;
private long amount;
private String channelName;
private String status;
private String referenceId;
private String fullDate;
private String channelCode;
public HistoryItem() {}
public HistoryItem(String time, String date, long amount, String channelName, String status, String referenceId) {
this.time = time;
this.date = date;
this.amount = amount;
this.channelName = channelName;
this.status = status;
this.referenceId = referenceId;
}
// Getters and Setters
public String getTime() { return time; }
public void setTime(String time) { this.time = time; }
public String getDate() { return date; }
public void setDate(String date) { this.date = date; }
public long getAmount() { return amount; }
public void setAmount(long amount) { this.amount = amount; }
public String getChannelName() { return channelName; }
public void setChannelName(String channelName) { this.channelName = channelName; }
public String getStatus() { return status; }
public void setStatus(String status) { this.status = status; }
public String getReferenceId() { return referenceId; }
public void setReferenceId(String referenceId) { this.referenceId = referenceId; }
public String getFullDate() { return fullDate; }
public void setFullDate(String fullDate) { this.fullDate = fullDate; }
public String getChannelCode() { return channelCode; }
public void setChannelCode(String channelCode) { this.channelCode = channelCode; }
}
// HistoryAdapter class - simplified and stable
class HistoryAdapter extends RecyclerView.Adapter<HistoryAdapter.HistoryViewHolder> {
private List<HistoryItem> historyList;
public HistoryAdapter(List<HistoryItem> historyList) {
this.historyList = historyList;
}
@NonNull
@Override
public HistoryViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_history, parent, false);
return new HistoryViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull HistoryViewHolder holder, int position) {
HistoryItem item = historyList.get(position);
holder.tvTime.setText(item.getTime() + ", " + item.getDate());
holder.tvAmount.setText("Rp. " + formatCurrency(item.getAmount()));
holder.tvChannel.setText(item.getChannelName());
// Set status color
String status = item.getStatus();
if ("SUCCESS".equals(status)) {
holder.tvStatus.setText("Berhasil");
holder.tvStatus.setTextColor(0xFF4CAF50); // Green
} else if ("FAILED".equals(status)) {
holder.tvStatus.setText("Gagal");
holder.tvStatus.setTextColor(0xFFF44336); // Red
} else {
holder.tvStatus.setText("Tertunda");
holder.tvStatus.setTextColor(0xFFFF9800); // Orange
}
}
@Override
public int getItemCount() {
return historyList != null ? historyList.size() : 0;
}
private String formatCurrency(long amount) {
try {
NumberFormat formatter = NumberFormat.getNumberInstance(new Locale("id", "ID"));
return formatter.format(amount);
} catch (Exception e) {
return String.valueOf(amount);
}
}
static class HistoryViewHolder extends RecyclerView.ViewHolder {
TextView tvTime;
TextView tvAmount;
TextView tvChannel;
TextView tvStatus;
public HistoryViewHolder(@NonNull View itemView) {
super(itemView);
tvTime = itemView.findViewById(R.id.tv_time);
tvAmount = itemView.findViewById(R.id.tv_amount);
tvChannel = itemView.findViewById(R.id.tv_channel);
tvStatus = itemView.findViewById(R.id.tv_status);
}
}
}

View File

@ -0,0 +1,204 @@
package com.example.bdkipoc;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import java.text.NumberFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Locale;
public class HistoryDetailActivity extends AppCompatActivity {
private RecyclerView recyclerView;
private HistoryDetailAdapter adapter;
private List<HistoryItem> detailList;
private ImageView btnBack;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_history_detail);
initViews();
setupRecyclerView();
loadData();
setupClickListeners();
}
private void initViews() {
recyclerView = findViewById(R.id.recycler_view);
btnBack = findViewById(R.id.btn_back);
detailList = new ArrayList<>();
}
private void setupRecyclerView() {
adapter = new HistoryDetailAdapter(detailList);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.setAdapter(adapter);
}
private void setupClickListeners() {
btnBack.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
finish();
}
});
}
private void loadData() {
try {
// Get data from HistoryActivity
List<HistoryItem> fullData = HistoryActivity.getFullHistoryData();
if (fullData != null && !fullData.isEmpty()) {
detailList.clear();
detailList.addAll(fullData);
adapter.notifyDataSetChanged();
} else {
loadSampleDetailData();
}
} catch (Exception e) {
e.printStackTrace();
loadSampleDetailData();
}
}
private void loadSampleDetailData() {
detailList.clear();
// Create sample detail data
HistoryItem[] sampleData = {
new HistoryItem("03:44", "11-05-2025", 2018619, "Kredit", "FAILED", "197870"),
new HistoryItem("03:10", "12-05-2025", 3974866, "QRIS", "SUCCESS", "053059"),
new HistoryItem("15:17", "13-05-2025", 2418167, "QRIS", "FAILED", "668320"),
new HistoryItem("12:09", "11-05-2025", 3429230, "Debit", "FAILED", "454790"),
new HistoryItem("08:39", "10-05-2025", 4656447, "QRIS", "FAILED", "454248"),
new HistoryItem("00:35", "12-05-2025", 3507704, "QRIS", "FAILED", "301644"),
new HistoryItem("22:43", "13-05-2025", 4277904, "Debit", "SUCCESS", "388709"),
new HistoryItem("18:16", "11-05-2025", 4456904, "Debit", "FAILED", "986861"),
new HistoryItem("12:51", "10-05-2025", 3027953, "Kredit", "SUCCESS", "771339"),
new HistoryItem("19:50", "14-05-2025", 4399035, "QRIS", "FAILED", "103478")
};
for (HistoryItem item : sampleData) {
detailList.add(item);
}
adapter.notifyDataSetChanged();
}
}
// HistoryDetailAdapter class - simplified for stability
class HistoryDetailAdapter extends RecyclerView.Adapter<HistoryDetailAdapter.DetailViewHolder> {
private List<HistoryItem> detailList;
public HistoryDetailAdapter(List<HistoryItem> detailList) {
this.detailList = detailList;
}
@NonNull
@Override
public DetailViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_history_detail, parent, false);
return new DetailViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull DetailViewHolder holder, int position) {
HistoryItem item = detailList.get(position);
try {
holder.tvReferenceId.setText("Ref: " + item.getReferenceId());
holder.tvAmount.setText("Rp. " + formatCurrency(item.getAmount()));
holder.tvChannel.setText(item.getChannelName());
holder.tvMerchant.setText("TEST MERCHANT");
holder.tvTime.setText(formatDateTime(item.getTime(), item.getDate()));
holder.tvIssuer.setText("BANK MANDIRI");
// Set status color
String status = item.getStatus();
if ("SUCCESS".equals(status)) {
holder.tvStatus.setText("Berhasil");
holder.tvStatus.setTextColor(0xFF4CAF50); // Green
} else if ("FAILED".equals(status)) {
holder.tvStatus.setText("Gagal");
holder.tvStatus.setTextColor(0xFFF44336); // Red
} else {
holder.tvStatus.setText("Tertunda");
holder.tvStatus.setTextColor(0xFFFF9800); // Orange
}
} catch (Exception e) {
e.printStackTrace();
// Set default values if error occurs
holder.tvReferenceId.setText("Ref: " + position);
holder.tvAmount.setText("Rp. 0");
holder.tvChannel.setText("Unknown");
holder.tvMerchant.setText("TEST MERCHANT");
holder.tvTime.setText("00:00, 01-01-2025");
holder.tvIssuer.setText("UNKNOWN");
holder.tvStatus.setText("Tidak Diketahui");
holder.tvStatus.setTextColor(0xFF666666);
}
}
@Override
public int getItemCount() {
return detailList != null ? detailList.size() : 0;
}
private String formatCurrency(long amount) {
try {
NumberFormat formatter = NumberFormat.getNumberInstance(new Locale("id", "ID"));
return formatter.format(amount);
} catch (Exception e) {
return String.valueOf(amount);
}
}
private String formatDateTime(String time, String date) {
try {
return time + ", " + date;
} catch (Exception e) {
return "00:00, 01-01-2025";
}
}
static class DetailViewHolder extends RecyclerView.ViewHolder {
TextView tvReferenceId;
TextView tvAmount;
TextView tvChannel;
TextView tvMerchant;
TextView tvTime;
TextView tvIssuer;
TextView tvStatus;
public DetailViewHolder(@NonNull View itemView) {
super(itemView);
try {
tvReferenceId = itemView.findViewById(R.id.tv_reference_id);
tvAmount = itemView.findViewById(R.id.tv_amount);
tvChannel = itemView.findViewById(R.id.tv_channel);
tvMerchant = itemView.findViewById(R.id.tv_merchant);
tvTime = itemView.findViewById(R.id.tv_time);
tvIssuer = itemView.findViewById(R.id.tv_issuer);
tvStatus = itemView.findViewById(R.id.tv_status);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}

View File

@ -1,41 +1,267 @@
package com.example.bdkipoc;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.view.WindowManager;
import androidx.activity.EdgeToEdge;
import androidx.appcompat.app.AppCompatActivity;
import androidx.cardview.widget.CardView;
import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;
import com.google.android.material.button.MaterialButton;
public class MainActivity extends AppCompatActivity {
private boolean isExpanded = false; // False = showing only 9 main menus, True = showing all 15 menus
private MaterialButton btnLainnya;
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if (hasFocus) {
getWindow().getDecorView().setSystemUiVisibility(
View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_FULLSCREEN
| View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
// Enable hardware acceleration for smoother scrolling
getWindow().setFlags(
WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED,
WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED
);
super.onCreate(savedInstanceState);
EdgeToEdge.enable(this);
setContentView(R.layout.activity_main);
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {
ViewCompat.setOnApplyWindowInsetsListener(findViewById(android.R.id.content), (v, insets) -> {
Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
return insets;
});
// Set up click listeners for the cards
CardView paymentCard = findViewById(R.id.card_payment);
CardView transactionsCard = findViewById(R.id.card_transactions);
// Initialize views
btnLainnya = findViewById(R.id.btn_lainnya);
paymentCard.setOnClickListener(v -> {
// Launch payment activity
startActivity(new android.content.Intent(MainActivity.this, PaymentActivity.class));
// Check if we're returning from a completed transaction
checkTransactionCompletion();
// Setup initial state - 9 main menus visible, 6 dummy menus hidden
setupInitialMenuState();
// Setup menu listeners
setupMenuListeners();
}
private void setupInitialMenuState() {
// 9 main menus should always be visible
CardView cardBantuan = findViewById(R.id.card_bantuan);
CardView cardInfoToko = findViewById(R.id.card_info_toko);
if (cardBantuan != null) {
cardBantuan.setVisibility(View.VISIBLE);
}
if (cardInfoToko != null) {
cardInfoToko.setVisibility(View.VISIBLE);
}
// 6 dummy menus should be hidden initially
CardView[] dummyCards = {
findViewById(R.id.card_dummy_menu_1),
findViewById(R.id.card_dummy_menu_2),
findViewById(R.id.card_dummy_menu_3),
findViewById(R.id.card_dummy_menu_4),
findViewById(R.id.card_dummy_menu_5),
findViewById(R.id.card_dummy_menu_6)
};
for (CardView card : dummyCards) {
if (card != null) {
card.setVisibility(View.GONE);
}
}
// Set initial button text
isExpanded = false;
btnLainnya.setText("Lainnya");
}
private void checkTransactionCompletion() {
Intent intent = getIntent();
if (intent != null) {
boolean transactionCompleted = intent.getBooleanExtra("transaction_completed", false);
String transactionAmount = intent.getStringExtra("transaction_amount");
if (transactionCompleted) {
if (transactionAmount != null) {
Toast.makeText(this, "Transaksi berhasil! Jumlah: Rp " + formatCurrency(transactionAmount), Toast.LENGTH_LONG).show();
} else {
Toast.makeText(this, "Transaksi berhasil diselesaikan!", Toast.LENGTH_LONG).show();
}
}
}
}
private String formatCurrency(String amount) {
try {
long amountValue = Long.parseLong(amount);
return String.format("%,d", amountValue).replace(',', '.');
} catch (NumberFormatException e) {
return amount;
}
}
private void setupMenuListeners() {
// Card IDs to set up listeners - Total 15 menu items
int[] cardIds = {
// Row 1 (Always visible - 3 items)
R.id.card_kartu_kredit,
R.id.card_kartu_debit,
R.id.card_qris,
// Row 2 (Always visible - 3 items)
R.id.card_uang_elektronik,
R.id.card_cetak_ulang,
R.id.card_settlement,
// Row 3 (Always visible - 3 items)
R.id.card_histori,
R.id.card_bantuan,
R.id.card_info_toko,
// Row 4 (Hidden initially - 3 items)
R.id.card_dummy_menu_1,
R.id.card_dummy_menu_2,
R.id.card_dummy_menu_3,
// Row 5 (Hidden initially - 3 items)
R.id.card_dummy_menu_4,
R.id.card_dummy_menu_5,
R.id.card_dummy_menu_6
};
// Set up click listeners for all cards
for (int cardId : cardIds) {
CardView cardView = findViewById(cardId);
if (cardView != null) {
cardView.setOnClickListener(v -> {
if (cardId == R.id.card_kartu_kredit) {
startActivity(new Intent(MainActivity.this, PaymentActivity.class));
} else if (cardId == R.id.card_kartu_debit) {
startActivity(new Intent(MainActivity.this, PaymentActivity.class));
} else if (cardId == R.id.card_qris) {
startActivity(new Intent(MainActivity.this, QrisActivity.class));
} else if (cardId == R.id.card_uang_elektronik) {
startActivity(new Intent(MainActivity.this, PaymentActivity.class));
} else if (cardId == R.id.card_cetak_ulang) {
startActivity(new Intent(MainActivity.this, TransactionActivity.class));
} else if (cardId == R.id.card_settlement) {
startActivity(new Intent(MainActivity.this, SettlementActivity.class));
} else if (cardId == R.id.card_histori) {
startActivity(new Intent(MainActivity.this, HistoryActivity.class));
} else if (cardId == R.id.card_bantuan) {
Toast.makeText(this, "Bantuan - Coming Soon", Toast.LENGTH_SHORT).show();
} else if (cardId == R.id.card_info_toko) {
Toast.makeText(this, "Info Toko - Coming Soon", Toast.LENGTH_SHORT).show();
} else if (cardId == R.id.card_dummy_menu_1) {
Toast.makeText(this, "Dummy Menu 1 - Coming Soon", Toast.LENGTH_SHORT).show();
} else if (cardId == R.id.card_dummy_menu_2) {
Toast.makeText(this, "Dummy Menu 2 - Coming Soon", Toast.LENGTH_SHORT).show();
} else if (cardId == R.id.card_dummy_menu_3) {
Toast.makeText(this, "Dummy Menu 3 - Coming Soon", Toast.LENGTH_SHORT).show();
} else if (cardId == R.id.card_dummy_menu_4) {
Toast.makeText(this, "Dummy Menu 4 - Coming Soon", Toast.LENGTH_SHORT).show();
} else if (cardId == R.id.card_dummy_menu_5) {
Toast.makeText(this, "Dummy Menu 5 - Coming Soon", Toast.LENGTH_SHORT).show();
} else if (cardId == R.id.card_dummy_menu_6) {
Toast.makeText(this, "Dummy Menu 6 - Coming Soon", Toast.LENGTH_SHORT).show();
} else {
// Fallback for any other cards
Toast.makeText(this, "Menu Diklik: " + getResources().getResourceEntryName(cardId), Toast.LENGTH_SHORT).show();
}
});
}
}
// Get references to ONLY the dummy cards that need to be toggled
CardView[] toggleableCards = {
findViewById(R.id.card_dummy_menu_1),
findViewById(R.id.card_dummy_menu_2),
findViewById(R.id.card_dummy_menu_3),
findViewById(R.id.card_dummy_menu_4),
findViewById(R.id.card_dummy_menu_5),
findViewById(R.id.card_dummy_menu_6)
};
// Set up "Lainnya" button click listener
btnLainnya.setOnClickListener(v -> {
isExpanded = !isExpanded;
if (isExpanded) {
// Show the 6 dummy menus with animation
for (CardView card : toggleableCards) {
if (card != null) {
card.setVisibility(View.VISIBLE);
card.setAlpha(0f);
card.animate()
.alpha(1f)
.setDuration(300)
.setInterpolator(new AccelerateDecelerateInterpolator())
.start();
}
}
btnLainnya.setText("Tampilkan Lebih Sedikit");
} else {
// Hide the 6 dummy menus with animation
for (CardView card : toggleableCards) {
if (card != null) {
card.animate()
.alpha(0f)
.setDuration(300)
.setInterpolator(new AccelerateDecelerateInterpolator())
.withEndAction(() -> card.setVisibility(View.GONE))
.start();
}
}
btnLainnya.setText("Lainnya");
}
});
transactionsCard.setOnClickListener(v -> {
// Launch transactions activity
startActivity(new android.content.Intent(MainActivity.this, TransactionActivity.class));
});
// Set up scan dan bayar card click listener
LinearLayout scanBayarContent = findViewById(R.id.scan_bayar_content);
if (scanBayarContent != null) {
scanBayarContent.setOnClickListener(v -> {
// Navigate to QRIS payment activity
startActivity(new Intent(MainActivity.this, QrisActivity.class));
});
}
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
setIntent(intent);
// Check for transaction completion when returning to MainActivity
checkTransactionCompletion();
}
@Override
protected void onResume() {
super.onResume();
// Clear any transaction completion flags to avoid repeated messages
getIntent().removeExtra("transaction_completed");
getIntent().removeExtra("transaction_amount");
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,557 @@
package com.example.bdkipoc;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.content.Intent;
import android.graphics.Color;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.text.TextUtils;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
public class PinActivity extends AppCompatActivity {
// Intent Extra Keys
public static final String EXTRA_TITLE = "extra_title";
public static final String EXTRA_SUBTITLE = "extra_subtitle";
public static final String EXTRA_AMOUNT = "extra_amount";
public static final String EXTRA_SOURCE_ACTIVITY = "extra_source_activity";
// Views
private EditText editTextPin;
private Button confirmButton;
private LinearLayout backNavigation;
private ImageView backArrow;
private TextView toolbarTitle;
// Success screen views
private View successScreen;
private ImageView successIcon;
private TextView successMessage;
// Numpad buttons
private TextView btn1, btn2, btn3, btn4, btn5, btn6, btn7, btn8, btn9, btn0, btn000;
private ImageView btnDelete;
// Data
private StringBuilder currentPin = new StringBuilder();
private static final int MAX_PIN_LENGTH = 6;
private static final int MIN_PIN_LENGTH = 4;
// Extra data from intent
private String sourceActivity;
private String amount;
// Animation
private Handler animationHandler = new Handler(Looper.getMainLooper());
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Set status bar color programmatically
setStatusBarColor();
setContentView(R.layout.activity_pin);
// Get intent extras
getIntentExtras();
initializeViews();
setupClickListeners();
setupInitialStates();
setupSuccessScreen();
}
private void setStatusBarColor() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
Window window = getWindow();
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
window.setStatusBarColor(Color.parseColor("#E31937")); // Red color
// Make status bar icons white (for dark red background)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
View decorView = window.getDecorView();
decorView.setSystemUiVisibility(0); // Clear light status bar flag
}
}
}
private void getIntentExtras() {
Intent intent = getIntent();
if (intent != null) {
sourceActivity = intent.getStringExtra(EXTRA_SOURCE_ACTIVITY);
amount = intent.getStringExtra(EXTRA_AMOUNT);
}
}
private void initializeViews() {
// Main views
editTextPin = findViewById(R.id.editTextPin);
confirmButton = findViewById(R.id.confirmButton);
backNavigation = findViewById(R.id.back_navigation);
backArrow = findViewById(R.id.backArrow);
toolbarTitle = findViewById(R.id.toolbarTitle);
// Success screen views
successScreen = findViewById(R.id.success_screen);
successIcon = findViewById(R.id.success_icon);
successMessage = findViewById(R.id.success_message);
// Numpad buttons
btn1 = findViewById(R.id.btn1);
btn2 = findViewById(R.id.btn2);
btn3 = findViewById(R.id.btn3);
btn4 = findViewById(R.id.btn4);
btn5 = findViewById(R.id.btn5);
btn6 = findViewById(R.id.btn6);
btn7 = findViewById(R.id.btn7);
btn8 = findViewById(R.id.btn8);
btn9 = findViewById(R.id.btn9);
btn0 = findViewById(R.id.btn0);
btn000 = findViewById(R.id.btn000);
btnDelete = findViewById(R.id.btnDelete);
}
private void setupSuccessScreen() {
// Initially hide success screen
if (successScreen != null) {
successScreen.setVisibility(View.GONE);
}
}
private void setupClickListeners() {
// Back navigation - entire LinearLayout is clickable
backNavigation.setOnClickListener(v -> {
addClickAnimation(v);
navigateBack();
});
// Individual back arrow (for additional touch area)
backArrow.setOnClickListener(v -> {
addClickAnimation(v);
navigateBack();
});
// Toolbar title (also clickable for back navigation)
toolbarTitle.setOnClickListener(v -> {
addClickAnimation(v);
navigateBack();
});
// Numpad listeners
btn1.setOnClickListener(v -> handleNumpadClick(v, "1"));
btn2.setOnClickListener(v -> handleNumpadClick(v, "2"));
btn3.setOnClickListener(v -> handleNumpadClick(v, "3"));
btn4.setOnClickListener(v -> handleNumpadClick(v, "4"));
btn5.setOnClickListener(v -> handleNumpadClick(v, "5"));
btn6.setOnClickListener(v -> handleNumpadClick(v, "6"));
btn7.setOnClickListener(v -> handleNumpadClick(v, "7"));
btn8.setOnClickListener(v -> handleNumpadClick(v, "8"));
btn9.setOnClickListener(v -> handleNumpadClick(v, "9"));
btn0.setOnClickListener(v -> handleNumpadClick(v, "0"));
btn000.setOnClickListener(v -> handleNumpadClick(v, "000"));
// Delete button
btnDelete.setOnClickListener(v -> {
addClickAnimation(v);
deleteLastDigit();
});
// Confirm button
confirmButton.setOnClickListener(v -> {
if (confirmButton.isEnabled()) {
addButtonClickAnimation(v);
handleConfirmPin();
}
});
}
private void navigateBack() {
finish();
}
private void handleNumpadClick(View view, String digit) {
addClickAnimation(view);
addDigit(digit);
}
private void setupInitialStates() {
// Set initial PIN display
editTextPin.setText("");
// Set initial button state
updateButtonState();
// Disable EditText input (only numpad input allowed)
editTextPin.setFocusable(false);
editTextPin.setClickable(false);
editTextPin.setCursorVisible(false);
}
private void addDigit(String digit) {
// Validate input length
if (currentPin.length() >= MAX_PIN_LENGTH) {
showToast("Maksimal " + MAX_PIN_LENGTH + " digit");
return;
}
// Handle special case for 000
if (digit.equals("000")) {
if (currentPin.length() + 3 <= MAX_PIN_LENGTH) {
currentPin.append("000");
} else {
int remainingLength = MAX_PIN_LENGTH - currentPin.length();
if (remainingLength > 0) {
currentPin.append("0".repeat(remainingLength));
}
}
} else {
currentPin.append(digit);
}
updatePinDisplay();
updateButtonState();
addInputFeedback();
}
private void deleteLastDigit() {
if (currentPin.length() > 0) {
String current = currentPin.toString();
// If current ends with 000, remove all three digits
if (current.endsWith("000") && current.length() >= 3) {
currentPin.delete(currentPin.length() - 3, currentPin.length());
} else {
currentPin.deleteCharAt(currentPin.length() - 1);
}
updatePinDisplay();
updateButtonState();
addDeleteFeedback();
}
}
private void updatePinDisplay() {
String pin = currentPin.toString();
if (pin.isEmpty()) {
editTextPin.setText("");
} else {
// Convert digits to asterisks for security
String maskedPin = "*".repeat(pin.length());
editTextPin.setText(maskedPin);
}
}
private void updateButtonState() {
boolean hasValidPin = currentPin.length() >= MIN_PIN_LENGTH;
confirmButton.setEnabled(hasValidPin);
if (hasValidPin) {
// Active state
confirmButton.setBackgroundResource(R.drawable.button_active_background);
confirmButton.setTextColor(Color.WHITE);
confirmButton.setAlpha(1.0f);
} else {
// Inactive state
confirmButton.setBackgroundResource(R.drawable.button_inactive_background);
confirmButton.setTextColor(Color.parseColor("#999999"));
confirmButton.setAlpha(0.6f);
}
}
private void handleConfirmPin() {
String pin = currentPin.toString();
if (TextUtils.isEmpty(pin)) {
showToast("Masukkan PIN");
return;
}
if (pin.length() < MIN_PIN_LENGTH) {
showToast("PIN minimal " + MIN_PIN_LENGTH + " digit");
return;
}
// Process PIN verification
verifyPin(pin);
}
private void verifyPin(String pin) {
// Show loading state
confirmButton.setText("Memverifikasi...");
confirmButton.setEnabled(false);
// Simulate PIN verification
animationHandler.postDelayed(() -> {
// For demo purposes, accept any PIN with length >= 4
// In real implementation, this would call backend API
if (isValidPin(pin)) {
// Show success screen instead of toast
handleSuccessfulVerification();
} else {
showToast("PIN tidak valid. Silakan coba lagi.");
resetPinState();
}
}, 2000);
}
private boolean isValidPin(String pin) {
// Demo validation - in real app, this would validate against backend
// For now, reject simple patterns like "1111", "1234", etc.
return !pin.equals("1111") &&
!pin.equals("1234") &&
!pin.equals("0000") &&
pin.length() >= MIN_PIN_LENGTH;
}
private void handleSuccessfulVerification() {
// Show full screen success message
showSuccessScreen();
// Navigate to receipt page after 2.5 seconds
animationHandler.postDelayed(() -> {
navigateToReceiptPage();
}, 2500);
}
private void showSuccessScreen() {
if (successScreen != null) {
// Hide all other UI components first
hideMainUIComponents();
// Set success message
if (successMessage != null) {
successMessage.setText("Pembayaran Berhasil");
}
// Show success screen with fade in animation
successScreen.setVisibility(View.VISIBLE);
successScreen.setAlpha(0f);
// Fade in the background
ObjectAnimator backgroundFadeIn = ObjectAnimator.ofFloat(successScreen, "alpha", 0f, 1f);
backgroundFadeIn.setDuration(500);
backgroundFadeIn.start();
// Add scale and bounce animation to success icon
if (successIcon != null) {
// Start with invisible icon
successIcon.setScaleX(0f);
successIcon.setScaleY(0f);
successIcon.setAlpha(0f);
// Scale animation with bounce effect
ObjectAnimator scaleX = ObjectAnimator.ofFloat(successIcon, "scaleX", 0f, 1.2f, 1f);
ObjectAnimator scaleY = ObjectAnimator.ofFloat(successIcon, "scaleY", 0f, 1.2f, 1f);
ObjectAnimator iconFadeIn = ObjectAnimator.ofFloat(successIcon, "alpha", 0f, 1f);
AnimatorSet iconAnimation = new AnimatorSet();
iconAnimation.playTogether(scaleX, scaleY, iconFadeIn);
iconAnimation.setDuration(800);
iconAnimation.setStartDelay(300);
iconAnimation.setInterpolator(new android.view.animation.OvershootInterpolator(1.2f));
iconAnimation.start();
}
// Add slide up animation to success message
if (successMessage != null) {
successMessage.setAlpha(0f);
successMessage.setTranslationY(50f);
ObjectAnimator messageSlideUp = ObjectAnimator.ofFloat(successMessage, "translationY", 50f, 0f);
ObjectAnimator messageFadeIn = ObjectAnimator.ofFloat(successMessage, "alpha", 0f, 1f);
AnimatorSet messageAnimation = new AnimatorSet();
messageAnimation.playTogether(messageSlideUp, messageFadeIn);
messageAnimation.setDuration(600);
messageAnimation.setStartDelay(600);
messageAnimation.setInterpolator(new android.view.animation.DecelerateInterpolator());
messageAnimation.start();
}
}
}
private void hideMainUIComponents() {
// Hide all main UI components to create clean full screen success
if (backNavigation != null) {
backNavigation.setVisibility(View.GONE);
}
// Hide the red header backgrounds
View redStatusBar = findViewById(R.id.red_status_bar);
View redHeaderBackground = findViewById(R.id.red_header_background);
if (redStatusBar != null) {
redStatusBar.setVisibility(View.GONE);
}
if (redHeaderBackground != null) {
redHeaderBackground.setVisibility(View.GONE);
}
// Hide PIN card
View pinCard = findViewById(R.id.pin_card);
if (pinCard != null) {
pinCard.setVisibility(View.GONE);
}
// Hide numpad
View numpadGrid = findViewById(R.id.numpad_grid);
if (numpadGrid != null) {
numpadGrid.setVisibility(View.GONE);
}
// Hide confirm button
if (confirmButton != null) {
confirmButton.setVisibility(View.GONE);
}
}
private void navigateToReceiptPage() {
// Create intent to navigate to receipt/struk page
Intent intent = new Intent(this, ReceiptActivity.class);
// Pass transaction data
intent.putExtra("transaction_amount", amount);
intent.putExtra("pin_verified", true);
intent.putExtra("source_activity", sourceActivity);
// Add transaction details (you can customize these)
intent.putExtra("merchant_name", "TOKO KLONTONG PAK EKO");
intent.putExtra("merchant_location", "Ciputat Baru, Tangsel");
intent.putExtra("transaction_id", generateTransactionId());
intent.putExtra("transaction_date", getCurrentDateTime());
intent.putExtra("payment_method", "Kartu Kredit");
intent.putExtra("card_type", "BCA");
intent.putExtra("tax_percentage", "11%");
intent.putExtra("service_fee", "500");
startActivity(intent);
// Set result for calling activity
Intent resultIntent = new Intent();
resultIntent.putExtra("pin_verified", true);
resultIntent.putExtra("pin_length", currentPin.length());
if (!TextUtils.isEmpty(amount)) {
resultIntent.putExtra(EXTRA_AMOUNT, amount);
}
setResult(RESULT_OK, resultIntent);
// Finish this activity
finish();
}
private String generateTransactionId() {
// Generate a simple transaction ID (in real app, this would come from backend)
return String.valueOf(System.currentTimeMillis() % 1000000000L);
}
private String getCurrentDateTime() {
// Get current date and time (in real app, use proper date formatting)
java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat("dd MMMM yyyy HH:mm", java.util.Locale.getDefault());
return sdf.format(new java.util.Date());
}
private void resetPinState() {
currentPin = new StringBuilder();
updatePinDisplay();
updateButtonState();
confirmButton.setText("Konfirmasi");
confirmButton.setEnabled(false);
}
// Animation methods
private void addClickAnimation(View view) {
ObjectAnimator scaleX = ObjectAnimator.ofFloat(view, "scaleX", 1f, 0.95f, 1f);
ObjectAnimator scaleY = ObjectAnimator.ofFloat(view, "scaleY", 1f, 0.95f, 1f);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.playTogether(scaleX, scaleY);
animatorSet.setDuration(150);
animatorSet.start();
}
private void addButtonClickAnimation(View view) {
ObjectAnimator scaleX = ObjectAnimator.ofFloat(view, "scaleX", 1f, 0.98f, 1f);
ObjectAnimator scaleY = ObjectAnimator.ofFloat(view, "scaleY", 1f, 0.98f, 1f);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.playTogether(scaleX, scaleY);
animatorSet.setDuration(200);
animatorSet.start();
}
private void addInputFeedback() {
ObjectAnimator fadeIn = ObjectAnimator.ofFloat(editTextPin, "alpha", 0.7f, 1f);
fadeIn.setDuration(200);
fadeIn.start();
}
private void addDeleteFeedback() {
ObjectAnimator shake = ObjectAnimator.ofFloat(editTextPin, "translationX", 0f, -10f, 10f, 0f);
shake.setDuration(300);
shake.start();
}
// Utility methods
private void showToast(String message) {
Toast.makeText(this, message, Toast.LENGTH_SHORT).show();
}
@Override
public void onBackPressed() {
// Prevent back press when success screen is showing
if (successScreen != null && successScreen.getVisibility() == View.VISIBLE) {
return;
}
navigateBack();
}
@Override
protected void onDestroy() {
super.onDestroy();
if (animationHandler != null) {
animationHandler.removeCallbacksAndMessages(null);
}
}
// Public methods for testing
public String getCurrentPin() {
return currentPin.toString();
}
public boolean isConfirmButtonEnabled() {
return confirmButton.isEnabled();
}
// Static helper method to launch PinActivity
public static void launch(android.content.Context context, String sourceActivity, String amount) {
Intent intent = new Intent(context, PinActivity.class);
intent.putExtra(EXTRA_SOURCE_ACTIVITY, sourceActivity);
if (!TextUtils.isEmpty(amount)) {
intent.putExtra(EXTRA_AMOUNT, amount);
}
// Launch for result if context is an Activity
if (context instanceof AppCompatActivity) {
((AppCompatActivity) context).startActivityForResult(intent, 100);
} else {
context.startActivity(intent);
}
}
}

View File

@ -0,0 +1,690 @@
package com.example.bdkipoc;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.view.inputmethod.InputMethodManager;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.Random;
import java.util.UUID;
public class QrisActivity extends AppCompatActivity {
// Views
private EditText editTextAmount;
private Button initiatePaymentButton;
private LinearLayout backNavigation;
private TextView toolbarTitle;
private TextView descriptionText;
// Numpad buttons
private TextView btn1, btn2, btn3, btn4, btn5, btn6, btn7, btn8, btn9, btn0, btn000;
private TextView btnDelete; // Changed from ImageView to TextView
// Only needed views for loading state
private ProgressBar progressBar;
private TextView statusTextView;
private TextView referenceIdTextView;
private LinearLayout initialPaymentLayout;
// Data
private StringBuilder currentAmount = new StringBuilder();
private static final int MAX_AMOUNT_LENGTH = 12;
private String transactionId;
private String transactionUuid;
private String referenceId;
private int amount;
private JSONObject midtransResponse;
// Animation
private Handler animationHandler = new Handler(Looper.getMainLooper());
private static final String BACKEND_BASE = "https://be-edc.msvc.app";
private static final String MIDTRANS_CHARGE_URL = "https://api.sandbox.midtrans.com/v2/charge";
private static final String MIDTRANS_AUTH = "Basic U0ItTWlkLXNlcnZlci1JM2RJWXdIRzVuamVMeHJCMVZ5endWMUM="; // Replace with your actual key
private static final String WEBHOOK_URL = "https://be-edc.msvc.app/webhooks/midtrans";
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Set status bar color programmatically
setStatusBarColor();
setContentView(R.layout.activity_qris);
initializeViews();
setupClickListeners();
setupInitialStates();
// Generate reference ID
referenceId = "ref-" + generateRandomString(8);
referenceIdTextView.setText(referenceId);
// Initially hide the progress and status views
progressBar.setVisibility(View.GONE);
statusTextView.setVisibility(View.GONE);
initialPaymentLayout.setVisibility(View.VISIBLE);
}
private void setStatusBarColor() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
Window window = getWindow();
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
window.setStatusBarColor(Color.parseColor("#E31937")); // Red color
// Make status bar icons white (for dark red background)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
View decorView = window.getDecorView();
decorView.setSystemUiVisibility(0); // Clear light status bar flag
}
}
}
private void initializeViews() {
// New UI components (similar to PaymentActivity)
editTextAmount = findViewById(R.id.editTextAmount);
initiatePaymentButton = findViewById(R.id.initiatePaymentButton);
backNavigation = findViewById(R.id.back_navigation);
toolbarTitle = findViewById(R.id.toolbarTitle);
descriptionText = findViewById(R.id.descriptionText);
// Numpad buttons
btn1 = findViewById(R.id.btn1);
btn2 = findViewById(R.id.btn2);
btn3 = findViewById(R.id.btn3);
btn4 = findViewById(R.id.btn4);
btn5 = findViewById(R.id.btn5);
btn6 = findViewById(R.id.btn6);
btn7 = findViewById(R.id.btn7);
btn8 = findViewById(R.id.btn8);
btn9 = findViewById(R.id.btn9);
btn0 = findViewById(R.id.btn0);
btn000 = findViewById(R.id.btn000);
btnDelete = findViewById(R.id.btnDelete); // Now TextView
// Only needed views for loading state
progressBar = findViewById(R.id.progressBar);
statusTextView = findViewById(R.id.statusTextView);
referenceIdTextView = findViewById(R.id.referenceIdTextView);
// Main content layout (replaces initialPaymentLayout)
initialPaymentLayout = findViewById(R.id.mainContentLayout);
}
private void setupClickListeners() {
// Back navigation
backNavigation.setOnClickListener(v -> {
addClickAnimation(v);
navigateBack();
});
toolbarTitle.setOnClickListener(v -> {
addClickAnimation(v);
navigateBack();
});
// Numpad listeners
btn1.setOnClickListener(v -> handleNumpadClick(v, "1"));
btn2.setOnClickListener(v -> handleNumpadClick(v, "2"));
btn3.setOnClickListener(v -> handleNumpadClick(v, "3"));
btn4.setOnClickListener(v -> handleNumpadClick(v, "4"));
btn5.setOnClickListener(v -> handleNumpadClick(v, "5"));
btn6.setOnClickListener(v -> handleNumpadClick(v, "6"));
btn7.setOnClickListener(v -> handleNumpadClick(v, "7"));
btn8.setOnClickListener(v -> handleNumpadClick(v, "8"));
btn9.setOnClickListener(v -> handleNumpadClick(v, "9"));
btn0.setOnClickListener(v -> handleNumpadClick(v, "0"));
btn000.setOnClickListener(v -> handleNumpadClick(v, "000"));
// Delete button
btnDelete.setOnClickListener(v -> {
addClickAnimation(v);
deleteLastDigit();
});
// Original QRIS buttons - only initiate payment needed
initiatePaymentButton.setOnClickListener(v -> {
if (initiatePaymentButton.isEnabled()) {
addButtonClickAnimation(v);
createTransaction();
}
});
}
private void setupInitialStates() {
// Initially hide amount input and show description
editTextAmount.setVisibility(View.GONE);
descriptionText.setVisibility(View.VISIBLE);
// Set initial button state
updateButtonState();
// Disable EditText input (only numpad input allowed)
editTextAmount.setFocusable(false);
editTextAmount.setClickable(false);
editTextAmount.setCursorVisible(false);
}
private void navigateBack() {
finish();
}
private void handleNumpadClick(View view, String digit) {
addClickAnimation(view);
addDigit(digit);
}
private void addDigit(String digit) {
// Validate input length
if (currentAmount.length() >= MAX_AMOUNT_LENGTH) {
showToast("Maksimal " + MAX_AMOUNT_LENGTH + " digit");
return;
}
// Handle leading zeros
if (currentAmount.length() == 0) {
if (digit.equals("000")) {
// Don't allow 000 as first input
return;
}
currentAmount.append(digit);
} else if (currentAmount.length() == 1 && currentAmount.toString().equals("0")) {
if (!digit.equals("000")) {
// Replace single 0 with new digit
currentAmount = new StringBuilder(digit);
} else {
return;
}
} else {
currentAmount.append(digit);
}
updateAmountDisplay();
updateButtonState();
addInputFeedback();
}
private void deleteLastDigit() {
if (currentAmount.length() > 0) {
String current = currentAmount.toString();
// If current ends with 000, remove all three digits
if (current.endsWith("000") && current.length() >= 3) {
currentAmount.delete(currentAmount.length() - 3, currentAmount.length());
} else {
currentAmount.deleteCharAt(currentAmount.length() - 1);
}
updateAmountDisplay();
updateButtonState();
addDeleteFeedback();
}
}
private void updateAmountDisplay() {
String amount = currentAmount.toString();
if (amount.isEmpty() || amount.equals("0")) {
// Show description text, hide amount input
editTextAmount.setVisibility(View.GONE);
descriptionText.setVisibility(View.VISIBLE);
} else {
// Show amount input, hide description text
String formattedAmount = formatCurrency(amount);
editTextAmount.setText(formattedAmount);
editTextAmount.setVisibility(View.VISIBLE);
descriptionText.setVisibility(View.GONE);
}
}
private String formatCurrency(String amount) {
if (TextUtils.isEmpty(amount) || amount.equals("0")) {
return "";
}
try {
long number = Long.parseLong(amount);
return String.format("%,d", number).replace(',', '.');
} catch (NumberFormatException e) {
return amount;
}
}
private void updateButtonState() {
boolean hasValidAmount = currentAmount.length() > 0 &&
!currentAmount.toString().equals("0") &&
!currentAmount.toString().isEmpty();
initiatePaymentButton.setEnabled(hasValidAmount);
// Use MaterialButton's backgroundTint property
com.google.android.material.button.MaterialButton materialButton =
(com.google.android.material.button.MaterialButton) initiatePaymentButton;
if (hasValidAmount) {
// Active state - red background like in the XML
materialButton.setBackgroundTintList(android.content.res.ColorStateList.valueOf(Color.parseColor("#DE0701")));
materialButton.setTextColor(Color.WHITE);
materialButton.setAlpha(1.0f);
} else {
// Inactive state - gray background
materialButton.setBackgroundTintList(android.content.res.ColorStateList.valueOf(Color.parseColor("#E8E8E8")));
materialButton.setTextColor(Color.parseColor("#999999"));
materialButton.setAlpha(0.6f);
}
}
private void createTransaction() {
String amountText = currentAmount.toString();
if (TextUtils.isEmpty(amountText) || amountText.equals("0")) {
showToast("Masukkan jumlah pembayaran");
return;
}
try {
long amountValue = Long.parseLong(amountText);
// Validate minimum amount
if (amountValue < 1000) {
showToast("Minimal pembayaran Rp 1.000");
return;
}
// Validate maximum amount
if (amountValue > 999999999L) {
showToast("Maksimal pembayaran Rp 999.999.999");
return;
}
// Set amount for transaction
amount = (int) amountValue;
// Show loading state
progressBar.setVisibility(View.VISIBLE);
statusTextView.setText("Creating transaction...");
statusTextView.setVisibility(View.VISIBLE);
initiatePaymentButton.setEnabled(false);
new CreateTransactionTask().execute();
} catch (NumberFormatException e) {
showToast("Format jumlah tidak valid");
}
}
private void displayQrCode(String qrImageUrl) {
// This method is no longer needed since we navigate to QrisResultActivity
// Keeping it for compatibility but it won't be called
}
private void simulateWebhook() {
// This method is no longer needed since we navigate to QrisResultActivity
// QrisResultActivity handles webhook simulation
}
private void showSuccessScreen() {
// This method is no longer needed since we navigate to QrisResultActivity
// QrisResultActivity handles success display
}
private String generateRandomString(int length) {
String chars = "abcdefghijklmnopqrstuvwxyz0123456789";
StringBuilder sb = new StringBuilder();
Random random = new Random();
for (int i = 0; i < length; i++) {
int index = random.nextInt(chars.length());
sb.append(chars.charAt(index));
}
return sb.toString();
}
private String getServerKey() {
// MIDTRANS_AUTH = 'Basic base64string'
String base64 = MIDTRANS_AUTH.replace("Basic ", "");
String decoded = android.util.Base64.decode(base64, android.util.Base64.DEFAULT).toString();
// Format is usually 'SB-Mid-server-xxxx:'. Remove trailing colon if present.
return decoded.replace(":\n", "");
}
private String generateSignature(String orderId, String statusCode, String grossAmount, String serverKey) {
String input = orderId + statusCode + grossAmount + serverKey;
try {
java.security.MessageDigest md = java.security.MessageDigest.getInstance("SHA-512");
byte[] messageDigest = md.digest(input.getBytes());
StringBuilder hexString = new StringBuilder();
for (byte b : messageDigest) {
String hex = Integer.toHexString(0xff & b);
if (hex.length() == 1) hexString.append('0');
hexString.append(hex);
}
return hexString.toString();
} catch (java.security.NoSuchAlgorithmException e) {
return "";
}
}
// Animation methods
private void addClickAnimation(View view) {
ObjectAnimator scaleX = ObjectAnimator.ofFloat(view, "scaleX", 1f, 0.95f, 1f);
ObjectAnimator scaleY = ObjectAnimator.ofFloat(view, "scaleY", 1f, 0.95f, 1f);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.playTogether(scaleX, scaleY);
animatorSet.setDuration(150);
animatorSet.start();
}
private void addButtonClickAnimation(View view) {
ObjectAnimator scaleX = ObjectAnimator.ofFloat(view, "scaleX", 1f, 0.98f, 1f);
ObjectAnimator scaleY = ObjectAnimator.ofFloat(view, "scaleY", 1f, 0.98f, 1f);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.playTogether(scaleX, scaleY);
animatorSet.setDuration(200);
animatorSet.start();
}
private void addInputFeedback() {
ObjectAnimator fadeIn = ObjectAnimator.ofFloat(editTextAmount, "alpha", 0.7f, 1f);
fadeIn.setDuration(200);
fadeIn.start();
}
private void addDeleteFeedback() {
ObjectAnimator shake = ObjectAnimator.ofFloat(editTextAmount, "translationX", 0f, -10f, 10f, 0f);
shake.setDuration(300);
shake.start();
}
// Utility methods
private void showToast(String message) {
Toast.makeText(this, message, Toast.LENGTH_SHORT).show();
}
@Override
public void onBackPressed() {
// Simple back navigation
navigateBack();
}
private class CreateTransactionTask extends AsyncTask<Void, Void, Boolean> {
private String errorMessage;
@Override
protected Boolean doInBackground(Void... voids) {
try {
// Generate a UUID for the transaction
transactionUuid = UUID.randomUUID().toString();
// Create transaction JSON payload
JSONObject payload = new JSONObject();
payload.put("type", "PAYMENT");
payload.put("channel_category", "RETAIL_OUTLET");
payload.put("channel_code", "QRIS");
payload.put("reference_id", referenceId);
Log.d("MidtransCharge", "Amount for transaction: " + amount);
payload.put("amount", amount);
payload.put("cashflow", "MONEY_IN");
payload.put("status", "INIT");
payload.put("device_id", 1);
payload.put("transaction_uuid", transactionUuid);
payload.put("transaction_time_seconds", 0.0);
payload.put("device_code", "PB4K252T00021");
payload.put("merchant_name", "Marcel Panjaitan");
payload.put("mid", "71000026521");
payload.put("tid", "73001500");
// Make the API call
URL url = new URI(BACKEND_BASE + "/transactions").toURL();
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type", "application/json");
conn.setRequestProperty("Accept", "application/json");
conn.setDoOutput(true);
try (OutputStream os = conn.getOutputStream()) {
byte[] input = payload.toString().getBytes("utf-8");
os.write(input, 0, input.length);
}
int responseCode = conn.getResponseCode();
if (responseCode == 200 || responseCode == 201) {
// Read the response
BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream(), "utf-8"));
StringBuilder response = new StringBuilder();
String responseLine;
while ((responseLine = br.readLine()) != null) {
response.append(responseLine.trim());
}
// Parse the response to get transaction ID
JSONObject jsonResponse = new JSONObject(response.toString());
JSONObject data = jsonResponse.getJSONObject("data");
transactionId = String.valueOf(data.getInt("id"));
// Now generate QRIS via Midtrans
return generateQris(amount);
} else {
// Read error response
BufferedReader br = new BufferedReader(new InputStreamReader(conn.getErrorStream(), "utf-8"));
StringBuilder response = new StringBuilder();
String responseLine;
while ((responseLine = br.readLine()) != null) {
response.append(responseLine.trim());
}
errorMessage = "Error creating transaction: " + response.toString();
return false;
}
} catch (Exception e) {
Log.e("MidtransCharge", "Exception: " + e.getMessage(), e);
errorMessage = "Unexpected error: " + e.getMessage();
return false;
}
}
private boolean generateQris(int amount) {
try {
// Create QRIS charge JSON payload
JSONObject payload = new JSONObject();
payload.put("payment_type", "qris");
JSONObject transactionDetails = new JSONObject();
transactionDetails.put("order_id", transactionUuid);
transactionDetails.put("gross_amount", amount);
payload.put("transaction_details", transactionDetails);
// Log the request details
Log.d("MidtransCharge", "URL: " + MIDTRANS_CHARGE_URL);
Log.d("MidtransCharge", "Authorization: " + MIDTRANS_AUTH);
Log.d("MidtransCharge", "Accept: application/json");
Log.d("MidtransCharge", "Content-Type: application/json");
Log.d("MidtransCharge", "X-Override-Notification: " + WEBHOOK_URL);
Log.d("MidtransCharge", "Payload: " + payload.toString());
// Make the API call to Midtrans
URL url = new URI(MIDTRANS_CHARGE_URL).toURL();
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("POST");
conn.setRequestProperty("Accept", "application/json");
conn.setRequestProperty("Content-Type", "application/json");
conn.setRequestProperty("Authorization", MIDTRANS_AUTH);
conn.setRequestProperty("X-Override-Notification", WEBHOOK_URL);
conn.setDoOutput(true);
try (OutputStream os = conn.getOutputStream()) {
byte[] input = payload.toString().getBytes("utf-8");
os.write(input, 0, input.length);
}
int responseCode = conn.getResponseCode();
if (responseCode == 200 || responseCode == 201) {
InputStream inputStream = conn.getInputStream();
if (inputStream != null) {
BufferedReader br = new BufferedReader(new InputStreamReader(inputStream, "utf-8"));
StringBuilder response = new StringBuilder();
String responseLine;
while ((responseLine = br.readLine()) != null) {
response.append(responseLine.trim());
}
// Parse the response
midtransResponse = new JSONObject(response.toString());
return true;
} else {
Log.e("MidtransCharge", "HTTP " + responseCode + ": No input stream available");
errorMessage = "Error generating QRIS: HTTP " + responseCode + ": No input stream available";
return false;
}
} else {
InputStream errorStream = conn.getErrorStream();
if (errorStream != null) {
BufferedReader br = new BufferedReader(new InputStreamReader(errorStream, "utf-8"));
StringBuilder errorResponse = new StringBuilder();
String responseLine;
while ((responseLine = br.readLine()) != null) {
errorResponse.append(responseLine.trim());
}
Log.e("MidtransCharge", "HTTP " + responseCode + ": " + errorResponse.toString());
errorMessage = "Error generating QRIS: HTTP " + responseCode + ": " + errorResponse.toString();
} else {
Log.e("MidtransCharge", "HTTP " + responseCode + ": No error stream available");
errorMessage = "Error generating QRIS: HTTP " + responseCode + ": No error stream available";
}
return false;
}
} catch (Exception e) {
Log.e("MidtransCharge", "Exception: " + e.getMessage(), e);
errorMessage = "Unexpected error: " + e.getMessage();
return false;
}
}
@Override
protected void onPostExecute(Boolean success) {
if (success && midtransResponse != null) {
try {
// Extract needed values from midtransResponse
JSONObject actions = midtransResponse.getJSONArray("actions").getJSONObject(0);
String qrImageUrl = actions.getString("url");
// Extract transaction_id
String transactionId = midtransResponse.getString("transaction_id");
String transactionTime = midtransResponse.getString("transaction_time");
String acquirer = midtransResponse.getString("acquirer");
String merchantId = midtransResponse.getString("merchant_id");
String exactGrossAmount = midtransResponse.getString("gross_amount");
// Log everything before launching activity
Log.d("MidtransCharge", "Creating QrisResultActivity intent with:");
Log.d("MidtransCharge", "qrImageUrl: " + qrImageUrl);
Log.d("MidtransCharge", "amount: " + amount);
Log.d("MidtransCharge", "referenceId: " + referenceId);
Log.d("MidtransCharge", "transactionUuid (orderId): " + transactionUuid);
Log.d("MidtransCharge", "transaction_id: " + transactionId);
Log.d("MidtransCharge", "exactGrossAmount: " + exactGrossAmount);
// Launch QrisResultActivity instead of showing QR inline
Intent intent = new Intent(QrisActivity.this, QrisResultActivity.class);
intent.putExtra("qrImageUrl", qrImageUrl);
intent.putExtra("amount", amount);
intent.putExtra("referenceId", referenceId);
intent.putExtra("orderId", transactionUuid); // Order ID
intent.putExtra("transactionId", transactionId); // Actual Midtrans transaction_id
intent.putExtra("grossAmount", exactGrossAmount); // Exact gross amount from response
intent.putExtra("transactionTime", transactionTime); // For timestamp
intent.putExtra("acquirer", acquirer);
intent.putExtra("merchantId", merchantId);
try {
startActivity(intent);
// Finish this activity so user can't go back to input form
finish();
} catch (Exception e) {
Log.e("MidtransCharge", "Failed to start QrisResultActivity: " + e.getMessage(), e);
Toast.makeText(QrisActivity.this, "Error launching QR display: " + e.getMessage(), Toast.LENGTH_LONG).show();
resetToInitialState();
}
} catch (JSONException e) {
Log.e("MidtransCharge", "QRIS response JSON error: " + e.getMessage(), e);
Toast.makeText(QrisActivity.this, "Error processing QRIS response", Toast.LENGTH_LONG).show();
resetToInitialState();
}
} else {
String message = (errorMessage != null && !errorMessage.isEmpty()) ? errorMessage : "Unknown error occurred. Please check Logcat for details.";
Toast.makeText(QrisActivity.this, message, Toast.LENGTH_LONG).show();
resetToInitialState();
}
progressBar.setVisibility(View.GONE);
}
}
private void resetToInitialState() {
// Reset to show the input form again
progressBar.setVisibility(View.GONE);
statusTextView.setVisibility(View.GONE);
initiatePaymentButton.setEnabled(true);
updateButtonState();
}
// Remove DownloadImageTask - no longer needed
// Remove SimulateWebhookTask - no longer needed
@Override
protected void onDestroy() {
super.onDestroy();
if (animationHandler != null) {
animationHandler.removeCallbacksAndMessages(null);
}
}
// Public methods for testing
public String getCurrentAmount() {
return currentAmount.toString();
}
public boolean isInitiateButtonEnabled() {
return initiatePaymentButton.isEnabled();
}
}

View File

@ -3,16 +3,23 @@ package com.example.bdkipoc;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.os.CountDownTimer;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
@ -33,11 +40,23 @@ public class QrisResultActivity extends AppCompatActivity {
private ImageView qrImageView;
private TextView amountTextView;
private TextView referenceTextView;
private TextView timerTextView;
private TextView qrStatusTextView;
private Button downloadQrisButton;
private Button checkStatusButton;
private Button cancelButton;
private TextView statusTextView;
private Button returnMainButton;
private ProgressBar progressBar;
private LinearLayout backNavigation;
// Timer and QR refresh
private CountDownTimer countDownTimer;
private long timeLeftInMillis = 60000; // 60 seconds
private int qrRefreshCount = 0;
private final int MAX_QR_REFRESH = 5; // Maximum 5 refreshes
// Data variables
private String orderId;
private String grossAmount;
private String referenceId;
@ -45,26 +64,102 @@ public class QrisResultActivity extends AppCompatActivity {
private String transactionTime;
private String acquirer;
private String merchantId;
private String originalQrImageUrl;
private int amount;
private String backendBase = "https://be-edc.msvc.app";
private String webhookUrl = "https://be-edc.msvc.app/webhooks/midtrans";
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Set status bar color programmatically
setStatusBarColor();
setContentView(R.layout.activity_qris_result);
initializeViews();
setupClickListeners();
setupData();
startTimer();
}
private void setStatusBarColor() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
Window window = getWindow();
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
window.setStatusBarColor(Color.parseColor("#E31937")); // Red color
// Make status bar icons white (for dark red background)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
View decorView = window.getDecorView();
decorView.setSystemUiVisibility(0); // Clear light status bar flag
}
}
}
private void initializeViews() {
qrImageView = findViewById(R.id.qrImageView);
amountTextView = findViewById(R.id.amountTextView);
referenceTextView = findViewById(R.id.referenceTextView);
timerTextView = findViewById(R.id.timerTextView);
qrStatusTextView = findViewById(R.id.qrStatusTextView);
downloadQrisButton = findViewById(R.id.downloadQrisButton);
checkStatusButton = findViewById(R.id.checkStatusButton);
cancelButton = findViewById(R.id.cancelButton);
statusTextView = findViewById(R.id.statusTextView);
returnMainButton = findViewById(R.id.returnMainButton);
progressBar = findViewById(R.id.progressBar);
backNavigation = findViewById(R.id.back_navigation);
}
private void setupClickListeners() {
// Back navigation
if (backNavigation != null) {
backNavigation.setOnClickListener(v -> finish());
}
// Cancel button
cancelButton.setOnClickListener(v -> {
if (countDownTimer != null) {
countDownTimer.cancel();
}
finish();
});
// Download QRIS button (now visible and functional)
downloadQrisButton.setOnClickListener(v -> {
qrImageView.setDrawingCacheEnabled(true);
Bitmap bitmap = qrImageView.getDrawingCache();
if (bitmap != null) {
saveImageToGallery(bitmap, "qris_code_" + System.currentTimeMillis());
}
qrImageView.setDrawingCacheEnabled(false);
});
// Check Payment Status button (now visible and functional)
checkStatusButton.setOnClickListener(v -> {
Toast.makeText(this, "Checking payment status...", Toast.LENGTH_SHORT).show();
simulateWebhook();
});
// Return to Main Screen button (now visible and functional)
returnMainButton.setOnClickListener(v -> {
if (countDownTimer != null) {
countDownTimer.cancel();
}
Intent intent = new Intent(QrisResultActivity.this, MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
finishAffinity();
});
}
private void setupData() {
Intent intent = getIntent();
String qrImageUrl = intent.getStringExtra("qrImageUrl");
int amount = intent.getIntExtra("amount", 0);
originalQrImageUrl = qrImageUrl; // Store original URL for refresh
amount = intent.getIntExtra("amount", 0);
referenceId = intent.getStringExtra("referenceId");
orderId = intent.getStringExtra("orderId");
grossAmount = intent.getStringExtra("grossAmount");
@ -75,60 +170,131 @@ public class QrisResultActivity extends AppCompatActivity {
if (orderId == null || transactionId == null) {
Log.e("QrisResultFlow", "orderId or transactionId is null! Intent extras: " + intent.getExtras());
android.widget.Toast.makeText(this, "Missing transaction details!", android.widget.Toast.LENGTH_LONG).show();
Toast.makeText(this, "Missing transaction details!", Toast.LENGTH_LONG).show();
}
// Get the exact amount from the grossAmount string value instead of the integer
String amountStr = "Amount: " + grossAmount;
amountTextView.setText(amountStr);
referenceTextView.setText("Reference ID: " + referenceId);
// Format and display amount
if (grossAmount != null) {
String formattedAmount = "RP." + formatCurrency(grossAmount);
amountTextView.setText(formattedAmount);
} else if (amount > 0) {
String formattedAmount = "RP." + formatCurrency(String.valueOf(amount));
amountTextView.setText(formattedAmount);
}
// Load QR image
new DownloadImageTask(qrImageView).execute(qrImageUrl);
// Set reference ID (hidden)
if (referenceId != null) {
referenceTextView.setText("Reference ID: " + referenceId);
}
// Load initial QR image
if (qrImageUrl != null) {
loadQrCode(qrImageUrl);
}
// Disable check status button initially
checkStatusButton.setEnabled(false);
// Start polling for pending payment log
pollPendingPaymentLog(orderId);
if (orderId != null) {
pollPendingPaymentLog(orderId);
}
}
// Download QRIS button
downloadQrisButton.setOnClickListener(new View.OnClickListener() {
private String formatCurrency(String amount) {
try {
long number = Long.parseLong(amount.replace(".00", ""));
return String.format("%,d", number).replace(',', '.');
} catch (NumberFormatException e) {
return amount;
}
}
private void startTimer() {
countDownTimer = new CountDownTimer(timeLeftInMillis, 1000) {
@Override
public void onClick(View v) {
qrImageView.setDrawingCacheEnabled(true);
Bitmap bitmap = qrImageView.getDrawingCache();
if (bitmap != null) {
saveImageToGallery(bitmap, "qris_code_" + System.currentTimeMillis());
public void onTick(long millisUntilFinished) {
timeLeftInMillis = millisUntilFinished;
int seconds = (int) (millisUntilFinished / 1000);
timerTextView.setText(String.valueOf(seconds));
// Update status text based on remaining time
if (seconds > 10) {
qrStatusTextView.setText("QR Code akan refresh dalam " + seconds + " detik");
qrStatusTextView.setTextColor(Color.parseColor("#666666"));
} else {
qrStatusTextView.setText("QR Code akan refresh dalam " + seconds + " detik");
qrStatusTextView.setTextColor(Color.parseColor("#E31937"));
}
qrImageView.setDrawingCacheEnabled(false);
}
});
// Check Payment Status button
checkStatusButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
simulateWebhook();
public void onFinish() {
timerTextView.setText("0");
qrStatusTextView.setText("Refreshing QR Code...");
qrStatusTextView.setTextColor(Color.parseColor("#E31937"));
// Auto refresh QR code
refreshQrCode();
}
});
}.start();
}
// Return to Main Screen button
returnMainButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(QrisResultActivity.this, com.example.bdkipoc.MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
finishAffinity();
private void refreshQrCode() {
qrRefreshCount++;
if (qrRefreshCount >= MAX_QR_REFRESH) {
// Max refresh reached, show expired message
timerTextView.setText("Expired");
qrStatusTextView.setText("QR Code telah expired. Silahkan generate ulang.");
qrStatusTextView.setTextColor(Color.parseColor("#E31937"));
Toast.makeText(this, "QR Code expired. Please generate new payment.", Toast.LENGTH_LONG).show();
return;
}
// Show loading state
progressBar.setVisibility(View.VISIBLE);
qrStatusTextView.setText("Generating new QR Code... (" + qrRefreshCount + "/" + MAX_QR_REFRESH + ")");
// Simulate generating new QR code
new Thread(() -> {
try {
// Simulate API call delay
Thread.sleep(2000);
// Generate new QR code (in real app, call Midtrans API again)
generateNewQrCode();
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
}
private void generateNewQrCode() {
new Handler(Looper.getMainLooper()).post(() -> {
progressBar.setVisibility(View.GONE);
// In real implementation, you would call Midtrans API again
// For demo, we'll reload the same QR with a timestamp to show refresh
String refreshedUrl = originalQrImageUrl + "?refresh=" + System.currentTimeMillis();
loadQrCode(refreshedUrl);
// Reset timer for new 60 seconds
timeLeftInMillis = 60000;
startTimer();
Toast.makeText(this, "QR Code refreshed! (" + qrRefreshCount + "/" + MAX_QR_REFRESH + ")", Toast.LENGTH_SHORT).show();
});
}
private void loadQrCode(String qrImageUrl) {
new DownloadImageTask(qrImageView).execute(qrImageUrl);
}
private static class DownloadImageTask extends AsyncTask<String, Void, Bitmap> {
ImageView bmImage;
DownloadImageTask(ImageView bmImage) {
this.bmImage = bmImage;
}
protected Bitmap doInBackground(String... urls) {
String urlDisplay = urls[0];
Bitmap bitmap = null;
@ -144,6 +310,7 @@ public class QrisResultActivity extends AppCompatActivity {
}
return bitmap;
}
protected void onPostExecute(Bitmap result) {
if (result != null) {
bmImage.setImageBitmap(result);
@ -157,12 +324,12 @@ public class QrisResultActivity extends AppCompatActivity {
String savedImageURL = android.provider.MediaStore.Images.Media.insertImage(
getContentResolver(), bitmap, fileName, "QRIS Payment QR Code");
if (savedImageURL != null) {
android.widget.Toast.makeText(this, "QRIS saved to gallery", android.widget.Toast.LENGTH_SHORT).show();
Toast.makeText(this, "QRIS saved to gallery", Toast.LENGTH_SHORT).show();
} else {
android.widget.Toast.makeText(this, "Failed to save QRIS", android.widget.Toast.LENGTH_SHORT).show();
Toast.makeText(this, "Failed to save QRIS", Toast.LENGTH_SHORT).show();
}
} catch (Exception e) {
android.widget.Toast.makeText(this, "Error saving QRIS: " + e.getMessage(), android.widget.Toast.LENGTH_LONG).show();
Toast.makeText(this, "Error saving QRIS: " + e.getMessage(), Toast.LENGTH_LONG).show();
}
}
@ -216,9 +383,9 @@ public class QrisResultActivity extends AppCompatActivity {
progressBar.setVisibility(View.GONE);
if (logFound) {
checkStatusButton.setEnabled(true);
android.widget.Toast.makeText(QrisResultActivity.this, "Pending payment log found!", android.widget.Toast.LENGTH_SHORT).show();
Toast.makeText(QrisResultActivity.this, "Pending payment log found!", Toast.LENGTH_SHORT).show();
} else {
android.widget.Toast.makeText(QrisResultActivity.this, "Pending payment log NOT found.", android.widget.Toast.LENGTH_LONG).show();
Toast.makeText(QrisResultActivity.this, "Pending payment log NOT found.", Toast.LENGTH_LONG).show();
}
});
}).start();
@ -273,15 +440,52 @@ public class QrisResultActivity extends AppCompatActivity {
}
new Handler(Looper.getMainLooper()).post(() -> {
progressBar.setVisibility(View.GONE);
// Proceed to show status/result
qrImageView.setVisibility(View.GONE);
amountTextView.setVisibility(View.GONE);
referenceTextView.setVisibility(View.GONE);
downloadQrisButton.setVisibility(View.GONE);
checkStatusButton.setVisibility(View.GONE);
statusTextView.setVisibility(View.VISIBLE);
returnMainButton.setVisibility(View.VISIBLE);
// Show success state
showSuccessState();
});
}).start();
}
}
private void showSuccessState() {
// Stop timer
if (countDownTimer != null) {
countDownTimer.cancel();
}
// Hide QR section and show success
qrImageView.setVisibility(View.GONE);
amountTextView.setVisibility(View.GONE);
timerTextView.setVisibility(View.GONE);
qrStatusTextView.setVisibility(View.GONE);
downloadQrisButton.setVisibility(View.GONE);
checkStatusButton.setVisibility(View.GONE);
cancelButton.setVisibility(View.GONE);
// Show success message
statusTextView.setText("Payment Successful!");
statusTextView.setTextColor(Color.parseColor("#4CAF50"));
statusTextView.setTextSize(24);
statusTextView.setVisibility(View.VISIBLE);
returnMainButton.setVisibility(View.VISIBLE);
returnMainButton.setText("Back to Main");
returnMainButton.setBackgroundColor(Color.parseColor("#4CAF50"));
Toast.makeText(this, "Payment completed successfully!", Toast.LENGTH_LONG).show();
}
@Override
protected void onDestroy() {
super.onDestroy();
if (countDownTimer != null) {
countDownTimer.cancel();
}
}
@Override
public void onBackPressed() {
if (countDownTimer != null) {
countDownTimer.cancel();
}
super.onBackPressed();
}
}

View File

@ -0,0 +1,208 @@
package com.example.bdkipoc;
import android.content.Intent;
import android.graphics.Color;
import android.os.Build;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
public class ReceiptActivity extends AppCompatActivity {
// Views
private LinearLayout backNavigation;
private ImageView backArrow;
private TextView toolbarTitle;
// Receipt details
private TextView merchantName;
private TextView merchantLocation;
private TextView midText;
private TextView tidText;
private TextView transactionNumber;
private TextView transactionDate;
private TextView paymentMethod;
private TextView cardType;
private TextView transactionTotal;
private TextView taxPercentage;
private TextView serviceFee;
private TextView finalTotal;
// Action buttons
private LinearLayout printButton;
private LinearLayout emailButton;
private Button finishButton;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Set status bar color
setStatusBarColor();
setContentView(R.layout.activity_receipt);
initializeViews();
setupClickListeners();
loadTransactionData();
}
private void setStatusBarColor() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
Window window = getWindow();
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
window.setStatusBarColor(Color.parseColor("#E31937")); // Red color
// Make status bar icons white (for dark red background)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
View decorView = window.getDecorView();
decorView.setSystemUiVisibility(0); // Clear light status bar flag
}
}
}
private void initializeViews() {
// Navigation
backNavigation = findViewById(R.id.back_navigation);
backArrow = findViewById(R.id.backArrow);
toolbarTitle = findViewById(R.id.toolbarTitle);
// Receipt details
merchantName = findViewById(R.id.merchant_name);
merchantLocation = findViewById(R.id.merchant_location);
midText = findViewById(R.id.mid_text);
tidText = findViewById(R.id.tid_text);
transactionNumber = findViewById(R.id.transaction_number);
transactionDate = findViewById(R.id.transaction_date);
paymentMethod = findViewById(R.id.payment_method);
cardType = findViewById(R.id.card_type);
transactionTotal = findViewById(R.id.transaction_total);
taxPercentage = findViewById(R.id.tax_percentage);
serviceFee = findViewById(R.id.service_fee);
finalTotal = findViewById(R.id.final_total);
// Action buttons - Updated to LinearLayout
printButton = findViewById(R.id.print_button);
emailButton = findViewById(R.id.email_button);
finishButton = findViewById(R.id.finish_button);
}
private void setupClickListeners() {
// Back navigation - Goes back to previous activity (PaymentActivity)
backNavigation.setOnClickListener(v -> navigateBackToPrevious());
backArrow.setOnClickListener(v -> navigateBackToPrevious());
toolbarTitle.setOnClickListener(v -> navigateBackToPrevious());
// Action buttons
printButton.setOnClickListener(v -> handlePrintReceipt());
emailButton.setOnClickListener(v -> handleEmailReceipt());
finishButton.setOnClickListener(v -> handleFinish());
}
private void loadTransactionData() {
Intent intent = getIntent();
if (intent != null) {
// Data dari TransactionActivity
String amount = intent.getStringExtra("transaction_amount");
String merchantNameStr = intent.getStringExtra("merchant_name");
String merchantLocationStr = intent.getStringExtra("merchant_location");
String transactionId = intent.getStringExtra("transaction_id");
String transactionDateStr = intent.getStringExtra("transaction_date");
String paymentMethodStr = intent.getStringExtra("payment_method");
String cardTypeStr = intent.getStringExtra("card_type");
// Set data ke view
merchantName.setText(merchantNameStr != null ? merchantNameStr : "TOKO KLONTONG PAK EKO");
merchantLocation.setText(merchantLocationStr != null ? merchantLocationStr : "Ciputat Baru, Tangsel");
transactionNumber.setText(transactionId != null ? transactionId : "3429483635");
transactionDate.setText(transactionDateStr != null ? transactionDateStr : "13 Januari 2025 13:46");
paymentMethod.setText(paymentMethodStr != null ? paymentMethodStr : "Kartu Kredit");
cardType.setText(cardTypeStr != null ? cardTypeStr : "BCA");
// Format nominal
if (amount != null) {
try {
long amountValue = Long.parseLong(amount);
transactionTotal.setText(formatCurrency(amountValue));
// Hitung total akhir (contoh: tambah pajak 11% dan biaya layanan 500)
long tax = (long) (amountValue * 0.11);
long serviceFeeValue = 500;
long total = amountValue + tax + serviceFeeValue;
taxPercentage.setText(formatCurrency(tax) + " (11%)");
serviceFee.setText(formatCurrency(serviceFeeValue));
finalTotal.setText(formatCurrency(total));
} catch (NumberFormatException e) {
transactionTotal.setText(amount);
finalTotal.setText(amount);
}
}
}
}
private String formatCurrency(long amount) {
return String.format("%,d", amount).replace(',', '.');
}
private void handlePrintReceipt() {
// Handle print receipt action
// In real app, this would integrate with printer
showToast("Mencetak struk...");
}
private void handleEmailReceipt() {
// Handle email receipt action
// In real app, this would open email intent
showToast("Mengirim email...");
}
private void handleFinish() {
// Navigate to MainActivity/Home Page when "Selesai" button is pressed
navigateToHomePage();
}
private void navigateBackToPrevious() {
// Navigate back to PaymentActivity (previous activity)
Intent intent = new Intent(this, PaymentActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
finish();
}
private void navigateToHomePage() {
// Navigate to MainActivity/Home Page when "Selesai" button is pressed
Intent intent = new Intent(this, MainActivity.class);
// Clear all previous activities from the stack and start fresh
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
// Optional: Add success message to show in MainActivity
intent.putExtra("transaction_completed", true);
intent.putExtra("transaction_amount", getIntent().getStringExtra("transaction_amount"));
startActivity(intent);
finish();
// Show success message
showToast("Transaksi berhasil diselesaikan!");
}
private void showToast(String message) {
android.widget.Toast.makeText(this, message, android.widget.Toast.LENGTH_SHORT).show();
}
@Override
public void onBackPressed() {
// Back button behavior - goes back to previous activity
navigateBackToPrevious();
}
}

View File

@ -0,0 +1,354 @@
package com.example.bdkipoc;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
public class SettlementActivity extends AppCompatActivity {
private TextView tvTotalAmount;
private TextView tvTotalTransactions;
private RecyclerView recyclerView;
private SettlementAdapter adapter;
private List<SettlementItem> settlementList;
private ImageView btnBack;
private String API_URL = "https://be-edc.msvc.app/transactions/performa-chanel-pembayaran?from_date=2025-01-01&to_date=2025-06-04&location_id=0&merchant_id=0";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_settlement);
initViews();
setupRecyclerView();
fetchApiData();
setupClickListeners();
}
private void fetchApiData() {
// Execute network call in background thread
new ApiTask().execute(API_URL);
}
private void processApiData(JSONArray dataArray) {
try {
settlementList.clear();
final long[] totalAmountArray = {0}; // Using array to make it effectively final
final int[] totalTransactionsArray = {0}; // Using array to make it effectively final
// Process each channel individually (no grouping)
for (int i = 0; i < dataArray.length(); i++) {
JSONObject item = dataArray.getJSONObject(i);
String channelCode = item.getString("channel_code");
int transactions = item.getInt("total_transactions");
long maxAmount = item.getLong("max_transastions");
// Use channel code directly as display name with some formatting
String displayName = formatChannelName(channelCode);
int iconResource = getChannelIcon(channelCode);
settlementList.add(new SettlementItem(
displayName,
maxAmount,
transactions,
iconResource
));
totalAmountArray[0] += maxAmount;
totalTransactionsArray[0] += transactions;
}
// Update UI on main thread
runOnUiThread(new Runnable() {
@Override
public void run() {
updateSummary(totalAmountArray[0], totalTransactionsArray[0]);
adapter.notifyDataSetChanged();
}
});
} catch (JSONException e) {
e.printStackTrace();
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(SettlementActivity.this, "Error parsing data", Toast.LENGTH_SHORT).show();
loadSampleData(); // Fallback to sample data
}
});
}
}
private void updateSummary(long totalAmount, int totalTransactions) {
tvTotalAmount.setText(formatCurrency(totalAmount));
tvTotalTransactions.setText(String.valueOf(totalTransactions));
}
private void initViews() {
tvTotalAmount = findViewById(R.id.tv_total_amount);
tvTotalTransactions = findViewById(R.id.tv_total_transactions);
recyclerView = findViewById(R.id.recycler_view);
btnBack = findViewById(R.id.btn_back);
settlementList = new ArrayList<>();
}
private void setupRecyclerView() {
adapter = new SettlementAdapter(settlementList);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.setAdapter(adapter);
}
private void setupClickListeners() {
btnBack.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
finish();
}
});
}
private void loadSampleData() {
// Sample data as fallback
settlementList.clear();
settlementList.add(new SettlementItem("Kartu Kredit", 200000, 13, android.R.drawable.ic_menu_recent_history));
settlementList.add(new SettlementItem("Kartu Debit", 200000, 13, android.R.drawable.ic_menu_manage));
settlementList.add(new SettlementItem("Transfer", 200000, 13, android.R.drawable.ic_menu_send));
settlementList.add(new SettlementItem("Uang Elektronik", 200000, 13, android.R.drawable.ic_menu_gallery));
settlementList.add(new SettlementItem("QRIS", 200000, 13, android.R.drawable.ic_menu_camera));
// Update summary
tvTotalAmount.setText(formatCurrency(3506500));
tvTotalTransactions.setText("65");
adapter.notifyDataSetChanged();
}
private String formatChannelName(String channelCode) {
// Format channel code to be more readable
switch (channelCode) {
case "GO-PAY":
return "GoPay";
case "SHOPEEPAY":
return "ShopeePay";
case "LINKAJA":
return "LinkAja";
case "MASTERCARD":
return "Mastercard";
case "VISA":
return "Visa";
case "QRIS":
return "QRIS";
case "DANA":
return "Dana";
case "OVO":
return "OVO";
case "DEBIT":
return "Kartu Debit";
case "GPN":
return "GPN";
case "OTHER":
return "Lainnya";
default:
// Capitalize first letter and make rest lowercase
return channelCode.substring(0, 1).toUpperCase() +
channelCode.substring(1).toLowerCase();
}
}
private String getChannelDisplayName(String channelCode) {
// Deprecated - keeping for backward compatibility
return formatChannelName(channelCode);
}
private int getChannelIcon(String channelCode) {
// Dynamic icon assignment based on channel type
switch (channelCode) {
case "DEBIT":
return android.R.drawable.ic_menu_manage;
case "VISA":
case "MASTERCARD":
return android.R.drawable.ic_menu_recent_history;
case "QRIS":
return android.R.drawable.ic_menu_camera;
case "DANA":
case "GO-PAY":
case "OVO":
case "SHOPEEPAY":
case "LINKAJA":
return android.R.drawable.ic_menu_gallery;
case "GPN":
return android.R.drawable.ic_menu_send;
case "OTHER":
return android.R.drawable.ic_menu_info_details;
default:
return android.R.drawable.ic_menu_help;
}
}
private String formatCurrency(long amount) {
NumberFormat formatter = NumberFormat.getNumberInstance(new Locale("id", "ID"));
return formatter.format(amount);
}
// Deprecated helper class - no longer needed
// private static class ChannelData { ... }
// AsyncTask for API call
private class ApiTask extends AsyncTask<String, Void, String> {
@Override
protected String doInBackground(String... urls) {
try {
URL url = new URL(urls[0]);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.setConnectTimeout(5000);
connection.setReadTimeout(5000);
int responseCode = connection.getResponseCode();
if (responseCode == HttpURLConnection.HTTP_OK) {
BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
StringBuilder response = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
response.append(line);
}
reader.close();
return response.toString();
}
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
@Override
protected void onPostExecute(String result) {
if (result != null) {
try {
JSONObject jsonResponse = new JSONObject(result);
if (jsonResponse.getInt("status") == 200) {
JSONArray dataArray = jsonResponse.getJSONArray("data");
processApiData(dataArray);
} else {
Toast.makeText(SettlementActivity.this, "API Error", Toast.LENGTH_SHORT).show();
loadSampleData();
}
} catch (JSONException e) {
e.printStackTrace();
Toast.makeText(SettlementActivity.this, "JSON Parse Error", Toast.LENGTH_SHORT).show();
loadSampleData();
}
} else {
Toast.makeText(SettlementActivity.this, "Network Error", Toast.LENGTH_SHORT).show();
loadSampleData();
}
}
}
}
// SettlementItem class - combined in same file
class SettlementItem {
private String channelName;
private long amount;
private int transactionCount;
private int iconResource;
public SettlementItem() {}
public SettlementItem(String channelName, long amount, int transactionCount, int iconResource) {
this.channelName = channelName;
this.amount = amount;
this.transactionCount = transactionCount;
this.iconResource = iconResource;
}
// Getters and Setters
public String getChannelName() { return channelName; }
public void setChannelName(String channelName) { this.channelName = channelName; }
public long getAmount() { return amount; }
public void setAmount(long amount) { this.amount = amount; }
public int getTransactionCount() { return transactionCount; }
public void setTransactionCount(int transactionCount) { this.transactionCount = transactionCount; }
public int getIconResource() { return iconResource; }
public void setIconResource(int iconResource) { this.iconResource = iconResource; }
}
// SettlementAdapter class - combined in same file
class SettlementAdapter extends RecyclerView.Adapter<SettlementAdapter.SettlementViewHolder> {
private List<SettlementItem> settlementList;
public SettlementAdapter(List<SettlementItem> settlementList) {
this.settlementList = settlementList;
}
@NonNull
@Override
public SettlementViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_settlement, parent, false);
return new SettlementViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull SettlementViewHolder holder, int position) {
SettlementItem item = settlementList.get(position);
holder.ivIcon.setImageResource(item.getIconResource());
holder.tvChannelName.setText(item.getChannelName());
holder.tvAmount.setText("Rp. " + formatCurrency(item.getAmount()));
holder.tvTransactionCount.setText(item.getTransactionCount() + " Transaksi");
}
@Override
public int getItemCount() {
return settlementList.size();
}
private String formatCurrency(long amount) {
NumberFormat formatter = NumberFormat.getNumberInstance(new Locale("id", "ID"));
return formatter.format(amount);
}
static class SettlementViewHolder extends RecyclerView.ViewHolder {
ImageView ivIcon;
TextView tvChannelName;
TextView tvAmount;
TextView tvTransactionCount;
public SettlementViewHolder(@NonNull View itemView) {
super(itemView);
ivIcon = itemView.findViewById(R.id.iv_icon);
tvChannelName = itemView.findViewById(R.id.tv_channel_name);
tvAmount = itemView.findViewById(R.id.tv_amount);
tvTransactionCount = itemView.findViewById(R.id.tv_transaction_count);
}
}
}

View File

@ -2,15 +2,21 @@ 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 android.content.Intent;
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;
@ -25,67 +31,173 @@ import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
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);
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 +261,73 @@ 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) {
// Buka ReceiptActivity dengan data transaksi
Intent intent = new Intent(this, ReceiptActivity.class);
// Format data sesuai kebutuhan ReceiptActivity
intent.putExtra("transaction_id", transaction.referenceId);
intent.putExtra("transaction_amount", transaction.amount.replace("Rp. ", "").replace(".", ""));
intent.putExtra("transaction_date", formatDate(transaction.createdAt)); // Format tanggal jika perlu
intent.putExtra("payment_method", "Kartu " + transaction.channelCode); // Contoh: "Kartu BCA"
intent.putExtra("card_type", transaction.channelCategory);
intent.putExtra("merchant_name", transaction.merchantName);
intent.putExtra("merchant_location", "Lokasi Merchant"); // Tambahkan jika ada di data
startActivity(intent);
}
private String formatDate(String rawDate) {
try {
SimpleDateFormat inputFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault());
SimpleDateFormat outputFormat = new SimpleDateFormat("dd MMMM yyyy HH:mm", new Locale("id", "ID"));
Date date = inputFormat.parse(rawDate);
return outputFormat.format(date);
} catch (Exception e) {
return rawDate; // Fallback ke format asli jika parsing gagal
}
}
@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 +353,4 @@ public class TransactionActivity extends AppCompatActivity {
this.merchantName = merchantName;
}
}
}
}

View File

@ -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,30 @@ 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));
holder.itemView.setOnClickListener(v -> {
if (printClickListener != null) {
printClickListener.onPrintClick(t);
}
});
// Set click listener for print button
holder.printSection.setOnClickListener(v -> {
if (printClickListener != null) {
printClickListener.onPrintClick(t);
}
});
}
@Override
@ -51,14 +72,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);
}
}
}
}

View File

@ -0,0 +1,4 @@
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="300"
android:fromAlpha="0.0"
android:toAlpha="1.0" />

View File

@ -0,0 +1,4 @@
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="300"
android:fromAlpha="1.0"
android:toAlpha="0.0" />

View File

@ -0,0 +1,14 @@
<set xmlns:android="http://schemas.android.com/apk/res/android">
<scale
android:duration="200"
android:fromXScale="0.8"
android:fromYScale="0.8"
android:pivotX="50%"
android:pivotY="50%"
android:toXScale="1.0"
android:toYScale="1.0" />
<alpha
android:duration="200"
android:fromAlpha="0.0"
android:toAlpha="1.0" />
</set>

View File

@ -0,0 +1,14 @@
<set xmlns:android="http://schemas.android.com/apk/res/android">
<scale
android:duration="200"
android:fromXScale="1.0"
android:fromYScale="1.0"
android:pivotX="50%"
android:pivotY="50%"
android:toXScale="0.8"
android:toYScale="0.8" />
<alpha
android:duration="200"
android:fromAlpha="1.0"
android:toAlpha="0.0" />
</set>

View File

@ -0,0 +1,10 @@
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:duration="300"
android:fromXDelta="-100%p"
android:toXDelta="0" />
<alpha
android:duration="300"
android:fromAlpha="0.0"
android:toAlpha="1.0" />
</set>

View File

@ -0,0 +1,10 @@
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:duration="300"
android:fromXDelta="100%p"
android:toXDelta="0" />
<alpha
android:duration="300"
android:fromAlpha="0.0"
android:toAlpha="1.0" />
</set>

View File

@ -0,0 +1,10 @@
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:duration="300"
android:fromXDelta="0"
android:toXDelta="-100%p" />
<alpha
android:duration="300"
android:fromAlpha="1.0"
android:toAlpha="0.0" />
</set>

View File

@ -0,0 +1,10 @@
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:duration="300"
android:fromXDelta="0"
android:toXDelta="100%p" />
<alpha
android:duration="300"
android:fromAlpha="1.0"
android:toAlpha="0.0" />
</set>

View 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="#DE0701" />
<corners android:radius="8dp" />
</shape>

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/button_active_background" android:state_enabled="true"/>
<item android:drawable="@drawable/button_inactive_background" android:state_enabled="false"/>
</selector>

View 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="#3498DB" />
<corners android:radius="8dp" />
</shape>

View 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="#ECEFF0" />
<corners android:radius="8dp" />
</shape>

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="#F5F5F5" />
<stroke
android:width="1dp"
android:color="#E0E0E0" />
<corners android:radius="8dp" />
</shape>

View File

@ -0,0 +1,6 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="#3498DB" />
<corners android:radius="12dp" />
<stroke android:width="0dp" />
</shape>

Binary file not shown.

After

Width:  |  Height:  |  Size: 220 B

View File

@ -0,0 +1,10 @@
<!-- res/drawable/icons/ic_backspace.xml -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#333333"
android:pathData="M22,3H7c-0.69,0 -1.23,0.35 -1.59,0.88L0,12l5.41,8.11c0.36,0.53 0.9,0.89 1.59,0.89h15c1.1,0 2,-0.9 2,-2V5c0,-1.1 -0.9,-2 -2,-2zM19,15.59L17.59,17 14,13.41 10.41,17 9,15.59 12.59,12 9,8.41 10.41,7 14,10.59 17.59,7 19,8.41 15.41,12 19,15.59z"/>
</vector>

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

View File

@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?attr/colorOnPrimary">
<path
android:fillColor="@android:color/white"
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM10,17l-5,-5 1.41,-1.41L10,14.17l7.59,-7.59L19,8l-9,9z"/>
</vector>

Binary file not shown.

After

Width:  |  Height:  |  Size: 606 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#000000"
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8zM11,16h2v-1h1c0.55,0 1,-0.45 1,-1v-3c0,-0.55 -0.45,-1 -1,-1h-3v-1h4V8h-2V7h-2v1h-1c-0.55,0 -1,0.45 -1,1v3c0,0.55 0.45,1 1,1h3v1H9v2h2v1z"/>
</vector>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FFFFFF"
android:pathData="M12,22c1.1,0 2,-0.9 2,-2h-4c0,1.1 0.9,2 2,2zM18,16v-5c0,-3.07 -1.64,-5.64 -4.5,-6.32L13.5,4c0,-0.83 -0.67,-1.5 -1.5,-1.5s-1.5,0.67 -1.5,1.5v0.68C7.63,5.36 6,7.92 6,11v5l-2,2v1h16v-1l-2,-2z"/>
</vector>

Binary file not shown.

After

Width:  |  Height:  |  Size: 586 B

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FFFFFF"
android:pathData="M3,11h8L11,3L3,3v8zM5,5h4v4L5,9L5,5zM13,3v8h8L21,3h-8zM19,9h-4L15,5h4v4zM3,21h8v-8L3,13v8zM5,15h4v4L5,19v-4zM13,13v8h8v-8h-8zM19,19h-4v-4h4v4z"/>
</vector>

Binary file not shown.

After

Width:  |  Height:  |  Size: 607 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#000000"
android:pathData="M19,3h-4.18C14.4,1.84 13.3,1 12,1c-1.3,0 -2.4,0.84 -2.82,2L5,3c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2L21,5c0,-1.1 -0.9,-2 -2,-2zM12,3c0.55,0 1,0.45 1,1s-0.45,1 -1,1 -1,-0.45 -1,-1 0.45,-1 1,-1zM12,7c1.66,0 3,1.34 3,3s-1.34,3 -3,3 -3,-1.34 -3,-3 1.34,-3 3,-3zM18,19L6,19v-1.4c0,-2 4,-3.1 6,-3.1s6,1.1 6,3.1L18,19z"/>
</vector>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#000000"
android:pathData="M16,17.01V10h-2v7.01h-3L15,20l4,-3h-3zM9,3L5,6h3v7.01h2V6h3L9,3z"/>
</vector>

View 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>

View File

@ -0,0 +1,4 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#666666" />
<corners android:radius="4dp" />
</shape>

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<font-family xmlns:app="http://schemas.android.com/apk/res-auto">
<font
app:font="@font/inter_regular"
app:fontWeight="400"
app:fontStyle="normal"/>
<font
app:font="@font/inter_medium"
app:fontWeight="500"
app:fontStyle="normal"/>
</font-family>

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,174 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#F5F5F5"
android:orientation="vertical">
<!-- Header with red background -->
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="200dp"
android:background="#E53E3E">
<!-- Back button -->
<ImageView
android:id="@+id/btn_back"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_alignParentStart="true"
android:layout_marginStart="16dp"
android:layout_marginTop="24dp"
android:background="?attr/selectableItemBackgroundBorderless"
android:clickable="true"
android:focusable="true"
android:padding="4dp"
android:src="@android:drawable/ic_menu_revert"
android:tint="@android:color/white" />
<!-- Title -->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:layout_toEndOf="@id/btn_back"
android:text="Kembali"
android:textColor="@android:color/white"
android:textSize="16sp" />
<!-- History Card -->
<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="120dp"
android:layout_marginStart="16dp"
android:layout_marginTop="64dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="16dp"
app:cardCornerRadius="12dp"
app:cardElevation="4dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#4299E1"
android:orientation="vertical"
android:padding="16dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<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="Transaksi Hari Ini"
android:textColor="@android:color/white"
android:textSize="14sp"
android:textStyle="bold" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="2dp"
android:text="Total Transaksi"
android:textColor="#E0FFFFFF"
android:textSize="12sp" />
<TextView
android:id="@+id/tv_total_amount"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:text="RP 4.500.000"
android:textColor="@android:color/white"
android:textSize="20sp"
android:textStyle="bold" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="2dp"
android:text="Jumlah Transaksi"
android:textColor="#E0FFFFFF"
android:textSize="12sp" />
<TextView
android:id="@+id/tv_total_transactions"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="30"
android:textColor="@android:color/white"
android:textSize="16sp"
android:textStyle="bold" />
</LinearLayout>
<TextView
android:id="@+id/btn_lihat_detail"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:background="?attr/selectableItemBackgroundBorderless"
android:clickable="true"
android:focusable="true"
android:padding="8dp"
android:text="Lihat Detail"
android:textColor="@android:color/white"
android:textSize="12sp"
android:textStyle="bold" />
</LinearLayout>
</LinearLayout>
</androidx.cardview.widget.CardView>
</RelativeLayout>
<!-- Content -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="vertical"
android:padding="16dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:text="Transaksi Terbaru"
android:textColor="#333333"
android:textSize="16sp"
android:textStyle="bold" />
<!-- Transaction List -->
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
</LinearLayout>
<!-- Bottom Button -->
<Button
android:id="@+id/btn_lihat_detail_bottom"
android:layout_width="match_parent"
android:layout_height="48dp"
android:layout_margin="16dp"
android:background="#6B46C1"
android:text="Lihat Detail"
android:textColor="@android:color/white"
android:textSize="16sp"
android:textStyle="bold" />
</LinearLayout>

View File

@ -0,0 +1,45 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#F5F5F5"
android:orientation="vertical">
<!-- Header -->
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="56dp"
android:background="#E53E3E"
android:padding="16dp">
<ImageView
android:id="@+id/btn_back"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_alignParentStart="true"
android:layout_centerVertical="true"
android:background="?attr/selectableItemBackgroundBorderless"
android:clickable="true"
android:focusable="true"
android:src="@android:drawable/ic_menu_revert"
android:tint="@android:color/white" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="Detail Transaksi"
android:textColor="@android:color/white"
android:textSize="18sp"
android:textStyle="bold" />
</RelativeLayout>
<!-- Content -->
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp" />
</LinearLayout>

View File

@ -1,92 +1,701 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
<ScrollView
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/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
android:fillViewport="true"
android:overScrollMode="never"
android:scrollbars="none"
android:background="#FFFFFF">
<TextView
android:id="@+id/title_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/main_title"
android:textSize="24sp"
android:layout_marginTop="32dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#FFFFFF"
tools:context=".MainActivity">
<androidx.cardview.widget.CardView
android:id="@+id/card_payment"
android:layout_width="140dp"
android:layout_height="140dp"
android:layout_marginTop="64dp"
app:cardCornerRadius="8dp"
app:cardElevation="4dp"
app:cardBackgroundColor="@color/light_blue"
app:layout_constraintEnd_toStartOf="@+id/card_transactions"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/title_text">
<LinearLayout
<!-- Status Bar Area -->
<View
android:id="@+id/status_bar_background"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical"
android:padding="16dp">
android:layout_height="24dp"
android:background="#E31937"
app:layout_constraintTop_toTopOf="parent"/>
<ImageView
android:layout_width="64dp"
android:layout_height="64dp"
android:src="@android:drawable/ic_menu_send"
android:contentDescription="@string/payment"
app:tint="@color/primary_blue" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="@string/payment2"
android:textColor="@color/primary_blue"
android:textStyle="bold" />
</LinearLayout>
</androidx.cardview.widget.CardView>
<androidx.cardview.widget.CardView
android:id="@+id/card_transactions"
android:layout_width="140dp"
android:layout_height="140dp"
app:cardCornerRadius="8dp"
app:cardElevation="4dp"
app:cardBackgroundColor="@color/light_gray"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/card_payment"
app:layout_constraintTop_toTopOf="@+id/card_payment">
<LinearLayout
<!-- Red Background Header -->
<View
android:id="@+id/red_header_background"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical"
android:padding="16dp">
android:layout_height="100dp"
android:background="#E31937"
app:layout_constraintTop_toBottomOf="@id/status_bar_background"/>
<ImageView
android:layout_width="64dp"
android:layout_height="64dp"
android:src="@android:drawable/ic_menu_recent_history"
android:contentDescription="@string/transactions"
app:tint="@color/accent_teal" />
<!-- Merchant Card -->
<androidx.cardview.widget.CardView
android:id="@+id/merchant_card"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="16dp"
app:cardCornerRadius="12dp"
app:cardElevation="4dp"
app:layout_constraintTop_toBottomOf="@id/status_bar_background">
<TextView
android:layout_width="wrap_content"
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="@string/transactions2"
android:textColor="@color/accent_teal"
android:textStyle="bold" />
</LinearLayout>
</androidx.cardview.widget.CardView>
android:orientation="vertical"
android:padding="16dp">
</androidx.constraintlayout.widget.ConstraintLayout>
<ImageView
android:layout_width="144dp"
android:layout_height="36dp"
android:src="@drawable/ic_logo_icon"
android:scaleType="fitStart"
android:adjustViewBounds="true"
android:layout_marginBottom="8dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TOKO KLONTONG PAK EKO"
android:textColor="#061D28"
android:textSize="18sp"
android:textStyle="bold"
android:layout_gravity="center_horizontal"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:text="Ciputat Baru, Tangsel"
android:textColor="#9FA4A9"
android:textSize="14sp"
android:layout_gravity="center_horizontal"/>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginTop="12dp"
android:layout_marginBottom="12dp"
android:background="#EEEEEE"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="MID: 12345678901"
android:textColor="#9FA4A9"
android:textSize="14sp"
android:layout_marginEnd="16dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TID: 12345678901"
android:textColor="#9FA4A9"
android:textSize="14sp"/>
</LinearLayout>
</LinearLayout>
</androidx.cardview.widget.CardView>
<!-- Menu Grid -->
<GridLayout
android:id="@+id/menu_grid"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:columnCount="3"
android:rowCount="5"
android:background="@android:color/white"
android:padding="8dp"
app:layout_constraintTop_toBottomOf="@id/merchant_card">
<!-- Row 1: Kartu Kredit, Kartu Debit, QRIS -->
<androidx.cardview.widget.CardView
android:id="@+id/card_kartu_kredit"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_columnWeight="1"
android:layout_rowWeight="1"
android:layout_margin="8dp"
app:cardCornerRadius="12dp"
app:cardElevation="2dp"
app:cardBackgroundColor="#F3F4F3">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center"
android:padding="16dp">
<ImageView
android:layout_width="48dp"
android:layout_height="48dp"
android:src="@drawable/ic_credit_card"
android:tint="#E31937"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="Kartu Kredit"
style="@style/MenuCardTitle"/>
</LinearLayout>
</androidx.cardview.widget.CardView>
<androidx.cardview.widget.CardView
android:id="@+id/card_kartu_debit"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_columnWeight="1"
android:layout_rowWeight="1"
android:layout_margin="8dp"
app:cardCornerRadius="12dp"
app:cardElevation="2dp"
app:cardBackgroundColor="#F3F4F3">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center"
android:padding="16dp">
<ImageView
android:layout_width="48dp"
android:layout_height="48dp"
android:src="@drawable/ic_debit_card"
android:tint="#E31937"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="Kartu Debit"
style="@style/MenuCardTitle"/>
</LinearLayout>
</androidx.cardview.widget.CardView>
<androidx.cardview.widget.CardView
android:id="@+id/card_qris"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_columnWeight="1"
android:layout_rowWeight="1"
android:layout_margin="8dp"
app:cardCornerRadius="12dp"
app:cardElevation="2dp"
app:cardBackgroundColor="#F3F4F3">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center"
android:padding="16dp">
<ImageView
android:layout_width="48dp"
android:layout_height="48dp"
android:src="@drawable/ic_qris"
android:tint="#E31937"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="QRIS"
style="@style/MenuCardTitle"/>
</LinearLayout>
</androidx.cardview.widget.CardView>
<!-- Row 2: Uang Elektronik, Cetak Ulang, Settlement -->
<androidx.cardview.widget.CardView
android:id="@+id/card_uang_elektronik"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_columnWeight="1"
android:layout_rowWeight="1"
android:layout_margin="8dp"
app:cardCornerRadius="12dp"
app:cardElevation="2dp"
app:cardBackgroundColor="#F3F4F3">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center"
android:padding="16dp">
<ImageView
android:layout_width="48dp"
android:layout_height="48dp"
android:src="@drawable/ic_e_money"
android:tint="#E31937"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="Uang Elektronik"
style="@style/MenuCardTitle"/>
</LinearLayout>
</androidx.cardview.widget.CardView>
<androidx.cardview.widget.CardView
android:id="@+id/card_cetak_ulang"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_columnWeight="1"
android:layout_rowWeight="1"
android:layout_margin="8dp"
app:cardCornerRadius="12dp"
app:cardElevation="2dp"
app:cardBackgroundColor="#F3F4F3">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center"
android:padding="16dp">
<ImageView
android:layout_width="48dp"
android:layout_height="48dp"
android:src="@drawable/ic_reprint"
android:tint="#E31937"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="Cetak Ulang"
style="@style/MenuCardTitle"/>
</LinearLayout>
</androidx.cardview.widget.CardView>
<androidx.cardview.widget.CardView
android:id="@+id/card_settlement"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_columnWeight="1"
android:layout_rowWeight="1"
android:layout_margin="8dp"
app:cardCornerRadius="12dp"
app:cardElevation="2dp"
app:cardBackgroundColor="#F3F4F3">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center"
android:padding="16dp">
<ImageView
android:layout_width="48dp"
android:layout_height="48dp"
android:src="@drawable/ic_settlement"
android:tint="#E31937"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="Settlement"
style="@style/MenuCardTitle"/>
</LinearLayout>
</androidx.cardview.widget.CardView>
<!-- Row 3: Histori, Bantuan, Info Toko -->
<androidx.cardview.widget.CardView
android:id="@+id/card_histori"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_columnWeight="1"
android:layout_rowWeight="1"
android:layout_margin="8dp"
app:cardCornerRadius="12dp"
app:cardElevation="2dp"
app:cardBackgroundColor="#F3F4F3">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center"
android:padding="16dp">
<ImageView
android:layout_width="48dp"
android:layout_height="48dp"
android:src="@drawable/ic_history"
android:tint="#E31937"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="Histori"
style="@style/MenuCardTitle"/>
</LinearLayout>
</androidx.cardview.widget.CardView>
<androidx.cardview.widget.CardView
android:id="@+id/card_bantuan"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_columnWeight="1"
android:layout_rowWeight="1"
android:layout_margin="8dp"
android:visibility="visible"
app:cardCornerRadius="12dp"
app:cardElevation="2dp"
app:cardBackgroundColor="#F3F4F3">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center"
android:padding="16dp">
<ImageView
android:layout_width="48dp"
android:layout_height="48dp"
android:src="@drawable/ic_help"
android:tint="#E31937"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="Bantuan"
style="@style/MenuCardTitle"/>
</LinearLayout>
</androidx.cardview.widget.CardView>
<androidx.cardview.widget.CardView
android:id="@+id/card_info_toko"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_columnWeight="1"
android:layout_rowWeight="1"
android:layout_margin="8dp"
android:visibility="visible"
app:cardCornerRadius="12dp"
app:cardElevation="2dp"
app:cardBackgroundColor="#F3F4F3">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center"
android:padding="16dp">
<ImageView
android:layout_width="48dp"
android:layout_height="48dp"
android:src="@drawable/ic_store_info"
android:tint="#E31937"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="Info Toko"
style="@style/MenuCardTitle"/>
</LinearLayout>
</androidx.cardview.widget.CardView>
<!-- Row 4: Dummy Menu 1, 2, 3 (Hidden initially) -->
<androidx.cardview.widget.CardView
android:id="@+id/card_dummy_menu_1"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_columnWeight="1"
android:layout_rowWeight="1"
android:layout_margin="8dp"
android:visibility="gone"
app:cardCornerRadius="12dp"
app:cardElevation="2dp"
app:cardBackgroundColor="#F3F4F3">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center"
android:padding="16dp">
<ImageView
android:layout_width="48dp"
android:layout_height="48dp"
android:src="@drawable/ic_qr_code"
android:tint="#E31937"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="Dummy Menu 1"
style="@style/MenuCardTitle"/>
</LinearLayout>
</androidx.cardview.widget.CardView>
<androidx.cardview.widget.CardView
android:id="@+id/card_dummy_menu_2"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_columnWeight="1"
android:layout_rowWeight="1"
android:layout_margin="8dp"
android:visibility="gone"
app:cardCornerRadius="12dp"
app:cardElevation="2dp"
app:cardBackgroundColor="#F3F4F3">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center"
android:padding="16dp">
<ImageView
android:layout_width="48dp"
android:layout_height="48dp"
android:src="@drawable/ic_qr_code"
android:tint="#E31937"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="Dummy Menu 2"
style="@style/MenuCardTitle"/>
</LinearLayout>
</androidx.cardview.widget.CardView>
<androidx.cardview.widget.CardView
android:id="@+id/card_dummy_menu_3"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_columnWeight="1"
android:layout_rowWeight="1"
android:layout_margin="8dp"
android:visibility="gone"
app:cardCornerRadius="12dp"
app:cardElevation="2dp"
app:cardBackgroundColor="#F3F4F3">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center"
android:padding="16dp">
<ImageView
android:layout_width="48dp"
android:layout_height="48dp"
android:src="@drawable/ic_qr_code"
android:tint="#E31937"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="Dummy Menu 3"
style="@style/MenuCardTitle"/>
</LinearLayout>
</androidx.cardview.widget.CardView>
<!-- Row 5: Dummy Menu 4, 5, 6 (Hidden initially) -->
<androidx.cardview.widget.CardView
android:id="@+id/card_dummy_menu_4"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_columnWeight="1"
android:layout_rowWeight="1"
android:layout_margin="8dp"
android:visibility="gone"
app:cardCornerRadius="12dp"
app:cardElevation="2dp"
app:cardBackgroundColor="#F3F4F3">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center"
android:padding="16dp">
<ImageView
android:layout_width="48dp"
android:layout_height="48dp"
android:src="@drawable/ic_qr_code"
android:tint="#E31937"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="Dummy Menu 4"
style="@style/MenuCardTitle"/>
</LinearLayout>
</androidx.cardview.widget.CardView>
<androidx.cardview.widget.CardView
android:id="@+id/card_dummy_menu_5"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_columnWeight="1"
android:layout_rowWeight="1"
android:layout_margin="8dp"
android:visibility="gone"
app:cardCornerRadius="12dp"
app:cardElevation="2dp"
app:cardBackgroundColor="#F3F4F3">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center"
android:padding="16dp">
<ImageView
android:layout_width="48dp"
android:layout_height="48dp"
android:src="@drawable/ic_qr_code"
android:tint="#E31937"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="Dummy Menu 5"
style="@style/MenuCardTitle"/>
</LinearLayout>
</androidx.cardview.widget.CardView>
<androidx.cardview.widget.CardView
android:id="@+id/card_dummy_menu_6"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_columnWeight="1"
android:layout_rowWeight="1"
android:layout_margin="8dp"
android:visibility="gone"
app:cardCornerRadius="12dp"
app:cardElevation="2dp"
app:cardBackgroundColor="#F3F4F3">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center"
android:padding="16dp">
<ImageView
android:layout_width="48dp"
android:layout_height="48dp"
android:src="@drawable/ic_qr_code"
android:tint="#E31937"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="Dummy Menu 6"
style="@style/MenuCardTitle"/>
</LinearLayout>
</androidx.cardview.widget.CardView>
</GridLayout>
<!-- Lainnya Button -->
<com.google.android.material.button.MaterialButton
android:id="@+id/btn_lainnya"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Tampilkan Lebih Sedikit"
android:textColor="#DE0701"
android:backgroundTint="#FFFFFF"
android:textAllCaps="false"
app:strokeColor="#DE0701"
app:strokeWidth="1dp"
app:cornerRadius="8dp"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:layout_marginTop="8dp"
app:layout_constraintTop_toBottomOf="@id/menu_grid"/>
<!-- Scan dan Bayar Card -->
<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:layout_marginTop="24dp"
android:layout_marginBottom="24dp"
app:cardCornerRadius="12dp"
app:cardBackgroundColor="#E31937"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@id/btn_lainnya"
app:layout_constraintVertical_bias="0">
<LinearLayout
android:id="@+id/scan_bayar_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical"
android:padding="16dp">
<ImageView
android:layout_width="48dp"
android:layout_height="48dp"
android:src="@drawable/ic_qr_code"
android:tint="@android:color/white"/>
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_marginStart="16dp"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="SCAN DAN BAYAR"
android:textColor="@android:color/white"
android:textSize="16sp"
android:textStyle="bold"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Terima pembayaran dengan QRIS secara mudah"
android:textColor="@android:color/white"
android:textSize="12sp"/>
</LinearLayout>
</LinearLayout>
</androidx.cardview.widget.CardView>
</androidx.constraintlayout.widget.ConstraintLayout>
</ScrollView>

View File

@ -1,227 +1,268 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
<ScrollView
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:layout_width="match_parent"
android:layout_height="match_parent">
android:layout_height="match_parent"
android:fillViewport="true"
android:overScrollMode="never"
android:scrollbars="none"
android:background="#FFFFFF">
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
app:title="QRIS Payment" />
</com.google.android.material.appbar.AppBarLayout>
<androidx.core.widget.NestedScrollView
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
android:background="#FFFFFF"
tools:context=".PaymentActivity">
<LinearLayout
<!-- Red Status Bar (Override purple) -->
<View
android:id="@+id/red_status_bar"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="16dp">
android:layout_height="24dp"
android:background="#E31937"
app:layout_constraintTop_toTopOf="parent"/>
<ProgressBar
android:id="@+id/progressBar"
<!-- Red Background Header (Extended height untuk back navigation) -->
<View
android:id="@+id/red_header_background"
android:layout_width="match_parent"
android:layout_height="160dp"
android:background="#E31937"
app:layout_constraintTop_toBottomOf="@id/red_status_bar"/>
<!-- Back Navigation (Positioned closer to status bar/appbar) -->
<LinearLayout
android:id="@+id/back_navigation"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical"
android:layout_marginStart="16dp"
android:layout_marginBottom="5dp"
android:background="?attr/selectableItemBackgroundBorderless"
android:padding="8dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/red_status_bar">
<!-- Back Arrow -->
<ImageView
android:id="@+id/backArrow"
android:layout_width="16dp"
android:layout_height="16dp"
android:src="@drawable/ic_arrow_back"
android:contentDescription="Back" />
<!-- Title Text -->
<TextView
android:id="@+id/toolbarTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:visibility="gone" />
android:layout_marginStart="8dp"
android:text="Kembali"
android:textColor="@android:color/white"
android:textSize="12sp"
android:fontFamily="@font/inter"
android:textStyle="normal" />
</LinearLayout>
<!-- Payment Card -->
<androidx.cardview.widget.CardView
android:id="@+id/paymentCard"
android:layout_width="match_parent"
android:layout_height="191dp"
android:layout_margin="16dp"
android:layout_marginTop="5dp"
app:cardBackgroundColor="#3498DB"
app:cardCornerRadius="12dp"
app:cardElevation="8dp"
app:layout_constraintTop_toBottomOf="@id/back_navigation">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="20dp">
<!-- Title -->
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="TOTAL PEMBAYARAN"
android:textColor="@android:color/white"
android:textSize="18sp"
android:textStyle="bold"
android:fontFamily="@font/inter"
android:layout_marginBottom="24dp" />
<!-- Amount Input Section -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginBottom="8dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="RP"
android:textColor="@android:color/white"
android:textSize="20sp"
android:textStyle="bold"
android:fontFamily="@font/inter"
android:layout_marginEnd="8dp"
android:layout_gravity="bottom" />
<EditText
android:id="@+id/editTextAmount"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:background="@android:color/transparent"
android:textColor="@android:color/white"
android:textColorHint="#80FFFFFF"
android:textSize="20sp"
android:textStyle="bold"
android:fontFamily="@font/inter"
android:hint=""
android:inputType="none"
android:focusable="false"
android:clickable="false"
android:cursorVisible="false"
android:text=""
android:gravity="start"
android:paddingBottom="4dp" />
</LinearLayout>
<!-- White Underline -->
<View
android:layout_width="match_parent"
android:layout_height="2dp"
android:background="@android:color/white"
android:layout_marginBottom="16dp" />
<!-- Description -->
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Pastikan kembali nominal pembayaran pelanggan Anda"
android:textColor="@android:color/white"
android:textSize="12sp"
android:fontFamily="@font/inter"
android:alpha="0.9" />
</LinearLayout>
</androidx.cardview.widget.CardView>
<!-- Numpad -->
<GridLayout
android:id="@+id/numpad_grid"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:columnCount="3"
android:rowCount="4"
android:layout_marginTop="24dp"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
app:layout_constraintTop_toBottomOf="@id/paymentCard">
<!-- Row 1: 1, 2, 3 -->
<TextView
android:id="@+id/btn1"
style="@style/NumpadButton"
android:text="1" />
<TextView
android:id="@+id/statusTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:gravity="center"
android:text="Ready to make a payment"
android:textSize="18sp" />
android:id="@+id/btn2"
style="@style/NumpadButton"
android:text="2" />
<!-- Initial Payment Form -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/btn3"
style="@style/NumpadButton"
android:text="3" />
<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp"
app:cardBackgroundColor="@color/light_blue"
app:cardCornerRadius="8dp"
app:cardElevation="4dp">
<!-- Row 2: 4, 5, 6 -->
<TextView
android:id="@+id/btn4"
style="@style/NumpadButton"
android:text="4" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="16dp">
<TextView
android:id="@+id/btn5"
style="@style/NumpadButton"
android:text="5" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Amount"
android:textColor="@color/primary_blue"
android:textSize="16sp" />
<TextView
android:id="@+id/btn6"
style="@style/NumpadButton"
android:text="6" />
<EditText
android:id="@+id/editTextAmount"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:hint="Enter amount"
android:inputType="number"
android:maxLength="12"
android:importantForAutofill="no"
android:singleLine="true"
android:textColor="@color/primary_blue"
android:textSize="24sp"
android:textStyle="bold"
android:gravity="end" />
<!-- Row 3: 7, 8, 9 -->
<TextView
android:id="@+id/btn7"
style="@style/NumpadButton"
android:text="7" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="Reference ID"
android:textColor="@color/primary_blue"
android:textSize="16sp" />
<TextView
android:id="@+id/btn8"
style="@style/NumpadButton"
android:text="8" />
<TextView
android:id="@+id/referenceIdTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="ref-abcd1234"
android:textColor="@color/primary_blue"
android:textSize="16sp" />
</LinearLayout>
</androidx.cardview.widget.CardView>
<TextView
android:id="@+id/btn9"
style="@style/NumpadButton"
android:text="9" />
<Button
android:id="@+id/initiatePaymentButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:backgroundTint="@color/primary_blue"
android:text="Start Payment" />
</LinearLayout>
<!-- Row 4: 000, 0, Delete -->
<TextView
android:id="@+id/btn000"
style="@style/NumpadButton"
android:text="000" />
<!-- QR Code and Payment Details -->
<LinearLayout
android:id="@+id/paymentDetailsLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:visibility="gone">
<TextView
android:id="@+id/btn0"
style="@style/NumpadButton"
android:text="0" />
<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp"
app:cardCornerRadius="8dp"
app:cardElevation="4dp">
<ImageView
android:id="@+id/btnDelete"
android:layout_width="0dp"
android:layout_height="60dp"
android:layout_columnWeight="1"
android:layout_margin="8dp"
android:background="?attr/selectableItemBackgroundBorderless"
android:src="@drawable/ic_backspace"
android:scaleType="center"
android:contentDescription="Delete" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:orientation="vertical"
android:padding="16dp">
</GridLayout>
<ImageView
android:id="@+id/qrCodeImageView"
android:layout_width="250dp"
android:layout_height="250dp"
android:contentDescription="QRIS Code"
android:scaleType="fitCenter" />
<!-- Confirmation Button (UPDATED: Menggunakan MaterialButton) -->
<com.google.android.material.button.MaterialButton
android:id="@+id/confirmButton"
android:layout_width="match_parent"
android:layout_height="48dp"
android:text="Konfirmasi"
android:textColor="#FFFFFF"
android:textSize="16sp"
android:textStyle="bold"
android:fontFamily="@font/inter"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:layout_marginTop="24dp"
android:layout_marginBottom="24dp"
android:enabled="false"
app:backgroundTint="#DE0701"
app:cornerRadius="8dp"
app:rippleColor="#B3000000"
app:layout_constraintTop_toBottomOf="@id/numpad_grid"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintVertical_bias="1" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:gravity="center"
android:text="Scan with your banking app or e-wallet to pay"
android:textSize="14sp" />
</LinearLayout>
</androidx.cardview.widget.CardView>
<Button
android:id="@+id/simulatePaymentButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:backgroundTint="@color/accent_green"
android:text="Confirm Payment" />
</LinearLayout>
<!-- Payment Success -->
<LinearLayout
android:id="@+id/paymentSuccessLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:visibility="gone">
<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp"
app:cardBackgroundColor="@color/light_gray"
app:cardCornerRadius="8dp"
app:cardElevation="4dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:orientation="vertical"
android:padding="16dp">
<ImageView
android:layout_width="64dp"
android:layout_height="64dp"
android:contentDescription="Success Icon"
android:src="@android:drawable/ic_dialog_info"
android:tint="@color/accent_green" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:gravity="center"
android:text="Payment Successful!"
android:textColor="@color/accent_green"
android:textSize="20sp"
android:textStyle="bold" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:gravity="center"
android:text="Your transaction has been completed successfully."
android:textSize="14sp" />
</LinearLayout>
</androidx.cardview.widget.CardView>
<Button
android:id="@+id/returnToMainButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:backgroundTint="@color/primary_blue"
android:text="Return to Main" />
</LinearLayout>
</LinearLayout>
</androidx.core.widget.NestedScrollView>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</ScrollView>

View File

@ -0,0 +1,298 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView
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:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true"
android:overScrollMode="never"
android:scrollbars="none"
android:background="#F5F5F5">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#FFFFFF"
tools:context=".PinActivity">
<!-- Red Status Bar (Override purple) -->
<View
android:id="@+id/red_status_bar"
android:layout_width="match_parent"
android:layout_height="24dp"
android:background="#E31937"
app:layout_constraintTop_toTopOf="parent"/>
<!-- Red Background Header (Extended height untuk back navigation) -->
<View
android:id="@+id/red_header_background"
android:layout_width="match_parent"
android:layout_height="160dp"
android:background="#E31937"
app:layout_constraintTop_toBottomOf="@id/red_status_bar"/>
<!-- Header with Back Navigation -->
<LinearLayout
android:id="@+id/back_navigation"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical"
android:layout_marginStart="16dp"
android:layout_marginBottom="5dp"
android:background="?attr/selectableItemBackgroundBorderless"
android:padding="8dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/red_status_bar">
<!-- Back Arrow -->
<ImageView
android:id="@+id/backArrow"
android:layout_width="16dp"
android:layout_height="16dp"
android:src="@drawable/ic_arrow_back"
android:contentDescription="Back" />
<!-- Title Text -->
<TextView
android:id="@+id/toolbarTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:text="Kembali"
android:textColor="@android:color/white"
android:textSize="12sp"
android:fontFamily="@font/inter"/>
</LinearLayout>
<!-- PIN Card -->
<androidx.cardview.widget.CardView
android:id="@+id/pin_card"
android:layout_width="match_parent"
android:layout_height="191dp"
android:layout_margin="16dp"
android:layout_marginTop="5dp"
app:cardBackgroundColor="#3498DB"
app:cardCornerRadius="12dp"
app:cardElevation="8dp"
app:layout_constraintTop_toBottomOf="@id/back_navigation">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="20dp">
<!-- Title Text -->
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="SILAKAN MASUKAN PIN"
android:textColor="@android:color/white"
android:textSize="18sp"
android:textStyle="bold"
android:fontFamily="@font/inter"
android:layout_marginBottom="24dp"
android:gravity="center"
android:textAlignment="center"/>
<!-- PIN Input Display -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginBottom="8dp"
android:gravity="center">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@android:color/white"
android:textSize="20sp"
android:textStyle="bold"
android:fontFamily="@font/inter"
android:layout_marginEnd="8dp"
android:layout_gravity="center_vertical" />
<EditText
android:id="@+id/editTextPin"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:background="@android:color/transparent"
android:textColor="@android:color/white"
android:textColorHint="#80FFFFFF"
android:textSize="20sp"
android:textStyle="bold"
android:fontFamily="@font/inter"
android:hint=""
android:inputType="none"
android:focusable="false"
android:clickable="false"
android:cursorVisible="false"
android:text=""
android:gravity="center"
android:textAlignment="center"
android:paddingBottom="4dp" />
</LinearLayout>
<!-- White Underline -->
<View
android:layout_width="match_parent"
android:layout_height="2dp"
android:background="@android:color/white"
android:layout_marginBottom="16dp" />
</LinearLayout>
</androidx.cardview.widget.CardView>
<!-- Numpad Grid -->
<GridLayout
android:id="@+id/numpad_grid"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:columnCount="3"
android:rowCount="4"
android:layout_margin="16dp"
android:layout_marginTop="32dp"
app:layout_constraintTop_toBottomOf="@id/pin_card">
<!-- Row 1: 1, 2, 3 -->
<TextView
android:id="@+id/btn1"
style="@style/NumpadButton"
android:text="1"/>
<TextView
android:id="@+id/btn2"
style="@style/NumpadButton"
android:text="2"/>
<TextView
android:id="@+id/btn3"
style="@style/NumpadButton"
android:text="3"/>
<!-- Row 2: 4, 5, 6 -->
<TextView
android:id="@+id/btn4"
style="@style/NumpadButton"
android:text="4"/>
<TextView
android:id="@+id/btn5"
style="@style/NumpadButton"
android:text="5"/>
<TextView
android:id="@+id/btn6"
style="@style/NumpadButton"
android:text="6"/>
<!-- Row 3: 7, 8, 9 -->
<TextView
android:id="@+id/btn7"
style="@style/NumpadButton"
android:text="7"/>
<TextView
android:id="@+id/btn8"
style="@style/NumpadButton"
android:text="8"/>
<TextView
android:id="@+id/btn9"
style="@style/NumpadButton"
android:text="9"/>
<!-- Row 4: 000, 0, Delete -->
<TextView
android:id="@+id/btn000"
style="@style/NumpadButton"
android:text="000"/>
<TextView
android:id="@+id/btn0"
style="@style/NumpadButton"
android:text="0"/>
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_columnWeight="1"
android:layout_margin="8dp"
android:gravity="center">
<ImageView
android:id="@+id/btnDelete"
android:layout_width="48dp"
android:layout_height="48dp"
android:src="@drawable/ic_backspace"
android:background="?android:attr/selectableItemBackgroundBorderless"
android:padding="12dp"
android:tint="#666666"/>
</LinearLayout>
</GridLayout>
<!-- Confirmation Button -->
<Button
android:id="@+id/confirmButton"
android:layout_width="match_parent"
android:layout_height="48dp"
android:layout_margin="16dp"
android:layout_marginTop="32dp"
android:text="Konfirmasi"
android:textColor="#999999"
android:textSize="16sp"
android:textStyle="bold"
android:background="@drawable/button_inactive_background"
android:enabled="false"
android:alpha="0.6"
app:layout_constraintTop_toBottomOf="@id/numpad_grid"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintVertical_bias="0"/>
<!-- Success Screen (Full Screen Overlay) - IMPROVED VERSION -->
<LinearLayout
android:id="@+id/success_screen"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center"
android:background="#E31937"
android:visibility="gone"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent">
<!-- Success Icon -->
<ImageView
android:id="@+id/success_icon"
android:layout_width="120dp"
android:layout_height="120dp"
android:src="@drawable/ic_success_payment"
android:layout_marginBottom="32dp"
android:scaleType="centerInside"/>
<!-- Success Message -->
<TextView
android:id="@+id/success_message"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Pembayaran Berhasil"
android:textColor="@android:color/white"
android:textSize="24sp"
android:textStyle="bold"
android:fontFamily="@font/inter"
android:gravity="center"
android:letterSpacing="0.02"/>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</ScrollView>

View File

@ -0,0 +1,306 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView
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:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true"
android:overScrollMode="never"
android:scrollbars="none"
android:background="#FFFFFF">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#FFFFFF"
tools:context=".QrisActivity">
<!-- Red Status Bar -->
<View
android:id="@+id/red_status_bar"
android:layout_width="match_parent"
android:layout_height="24dp"
android:background="#E31937"
app:layout_constraintTop_toTopOf="parent"/>
<!-- Red Background Header -->
<View
android:id="@+id/red_header_background"
android:layout_width="match_parent"
android:layout_height="160dp"
android:background="#E31937"
app:layout_constraintTop_toBottomOf="@id/red_status_bar"/>
<!-- Back Navigation -->
<LinearLayout
android:id="@+id/back_navigation"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical"
android:layout_marginStart="16dp"
android:layout_marginBottom="5dp"
android:background="?attr/selectableItemBackgroundBorderless"
android:padding="8dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/red_status_bar">
<!-- Back Arrow -->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text=""
android:textColor="@android:color/white"
android:textSize="18sp"
android:textStyle="bold"
android:layout_marginEnd="8dp" />
<!-- Title Text -->
<TextView
android:id="@+id/toolbarTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Kembali"
android:textColor="@android:color/white"
android:textSize="12sp"
android:textStyle="normal" />
<!-- Hidden back arrow for Java compatibility -->
<ImageView
android:id="@+id/backArrow"
android:layout_width="0dp"
android:layout_height="0dp"
android:visibility="gone" />
</LinearLayout>
<!-- Payment Card -->
<androidx.cardview.widget.CardView
android:id="@+id/paymentCard"
android:layout_width="match_parent"
android:layout_height="191dp"
android:layout_margin="16dp"
android:layout_marginTop="5dp"
app:cardBackgroundColor="#3498DB"
app:cardCornerRadius="12dp"
app:cardElevation="8dp"
app:layout_constraintTop_toBottomOf="@id/back_navigation">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="20dp">
<!-- Title -->
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="TOTAL PEMBAYARAN"
android:textColor="@android:color/white"
android:textSize="18sp"
android:textStyle="bold"
android:layout_marginBottom="24dp"
android:gravity="center" />
<!-- RP Label -->
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="RP"
android:textColor="@android:color/white"
android:textSize="20sp"
android:textStyle="bold"
android:layout_marginBottom="8dp" />
<!-- Amount Input Field (initially hidden) -->
<EditText
android:id="@+id/editTextAmount"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@android:color/transparent"
android:textColor="@android:color/white"
android:textSize="20sp"
android:textStyle="bold"
android:inputType="none"
android:focusable="false"
android:clickable="false"
android:cursorVisible="false"
android:text=""
android:gravity="start"
android:paddingBottom="4dp"
android:visibility="gone" />
<!-- Description Text (always visible initially) -->
<TextView
android:id="@+id/descriptionText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Pastikan kembali nominal pembayaran pelanggan Anda"
android:textColor="@android:color/white"
android:textSize="12sp"
android:alpha="0.9"
android:layout_marginBottom="8dp" />
<!-- White Underline -->
<View
android:layout_width="match_parent"
android:layout_height="2dp"
android:background="@android:color/white" />
<!-- Hidden Reference ID for internal use -->
<TextView
android:id="@+id/referenceIdTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="ref-abcd1234"
android:textColor="@android:color/white"
android:textSize="12sp"
android:visibility="gone" />
</LinearLayout>
</androidx.cardview.widget.CardView>
<!-- Main Content Layout -->
<LinearLayout
android:id="@+id/mainContentLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintTop_toBottomOf="@id/paymentCard"
app:layout_constraintBottom_toTopOf="@id/initiatePaymentButton">
<!-- Numpad -->
<GridLayout
android:id="@+id/numpad_grid"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:columnCount="3"
android:rowCount="4"
android:layout_marginTop="8dp"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp">
<!-- Row 1: 1, 2, 3 -->
<TextView
android:id="@+id/btn1"
style="@style/NumpadButton"
android:text="1" />
<TextView
android:id="@+id/btn2"
style="@style/NumpadButton"
android:text="2" />
<TextView
android:id="@+id/btn3"
style="@style/NumpadButton"
android:text="3" />
<!-- Row 2: 4, 5, 6 -->
<TextView
android:id="@+id/btn4"
style="@style/NumpadButton"
android:text="4" />
<TextView
android:id="@+id/btn5"
style="@style/NumpadButton"
android:text="5" />
<TextView
android:id="@+id/btn6"
style="@style/NumpadButton"
android:text="6" />
<!-- Row 3: 7, 8, 9 -->
<TextView
android:id="@+id/btn7"
style="@style/NumpadButton"
android:text="7" />
<TextView
android:id="@+id/btn8"
style="@style/NumpadButton"
android:text="8" />
<TextView
android:id="@+id/btn9"
style="@style/NumpadButton"
android:text="9" />
<!-- Row 4: 000, 0, Delete -->
<TextView
android:id="@+id/btn000"
style="@style/NumpadButton"
android:text="000" />
<TextView
android:id="@+id/btn0"
style="@style/NumpadButton"
android:text="0" />
<TextView
android:id="@+id/btnDelete"
android:layout_width="0dp"
android:layout_height="60dp"
android:layout_columnWeight="1"
android:layout_margin="8dp"
android:background="?attr/selectableItemBackgroundBorderless"
android:gravity="center"
android:text="⌫"
android:textColor="@android:color/black"
android:textSize="28sp"
android:clickable="true"
android:focusable="true"
android:contentDescription="Delete" />
</GridLayout>
</LinearLayout>
<!-- Confirmation Button -->
<com.google.android.material.button.MaterialButton
android:id="@+id/initiatePaymentButton"
android:layout_width="match_parent"
android:layout_height="48dp"
android:text="Konfirmasi"
android:textColor="#FFFFFF"
android:textSize="16sp"
android:textStyle="bold"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:layout_marginTop="24dp"
android:layout_marginBottom="24dp"
android:enabled="false"
app:backgroundTint="#DE0701"
app:cornerRadius="8dp"
app:rippleColor="#B3000000"
app:layout_constraintBottom_toBottomOf="parent" />
<!-- Progress Bar (For create transaction loading) -->
<ProgressBar
android:id="@+id/progressBar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<!-- Status Text (For create transaction status) -->
<TextView
android:id="@+id/statusTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="16dp"
android:gravity="center"
android:text="Ready to make a payment"
android:textSize="18sp"
android:textColor="@android:color/black"
android:visibility="gone"
app:layout_constraintTop_toBottomOf="@id/progressBar"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</ScrollView>

View File

@ -1,82 +1,223 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="24dp"
android:background="#181824"
>
android:background="#FFFFFF">
<TextView
android:id="@+id/amountTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/amount"
android:textColor="#2D5DA1"
android:textSize="20sp"
android:layout_gravity="center_horizontal"
android:layout_marginTop="16dp"/>
<!-- Red Status Bar -->
<View
android:layout_width="match_parent"
android:layout_height="44dp"
android:background="#E31937" />
<TextView
android:id="@+id/referenceTextView"
android:layout_width="wrap_content"
<!-- Header with Back Navigation -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/reference_id"
android:textColor="#2D5DA1"
android:background="#E31937"
android:paddingBottom="16dp">
<LinearLayout
android:id="@+id/back_navigation"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical"
android:layout_marginStart="16dp"
android:background="?attr/selectableItemBackgroundBorderless"
android:padding="8dp"
android:clickable="true"
android:focusable="true">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text=""
android:textColor="@android:color/white"
android:textSize="18sp"
android:textStyle="bold"
android:layout_marginEnd="8dp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Kembali"
android:textColor="@android:color/white"
android:textSize="14sp" />
</LinearLayout>
</LinearLayout>
<!-- White Card Container -->
<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="16dp"
android:layout_marginTop="0dp"
app:cardCornerRadius="16dp"
app:cardElevation="8dp"
app:cardBackgroundColor="@android:color/white">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="24dp"
android:gravity="center_horizontal">
<!-- Generate QR Title -->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Generate QR"
android:textColor="@android:color/black"
android:textSize="18sp"
android:textStyle="bold"
android:layout_marginBottom="24dp" />
<!-- QRIS Logo Text -->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="QRIS"
android:textColor="@android:color/black"
android:textSize="32sp"
android:textStyle="bold"
android:fontFamily="monospace"
android:layout_marginBottom="24dp" />
<!-- QR Code -->
<ImageView
android:id="@+id/qrImageView"
android:layout_width="200dp"
android:layout_height="200dp"
android:layout_gravity="center_horizontal"
android:contentDescription="QRIS QR Code"
android:scaleType="fitCenter"
android:background="#F0F0F0"
android:layout_marginBottom="24dp" />
<!-- Amount Display -->
<TextView
android:id="@+id/amountTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="RP.200.000"
android:textColor="@android:color/black"
android:textSize="20sp"
android:textStyle="bold"
android:layout_marginBottom="16dp" />
<!-- Timer/Counter -->
<TextView
android:id="@+id/timerTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="60"
android:textColor="#E31937"
android:textSize="18sp"
android:textStyle="bold"
android:layout_marginBottom="24dp" />
<!-- QR Refresh Status -->
<TextView
android:id="@+id/qrStatusTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="QR Code akan refresh dalam"
android:textColor="#666666"
android:textSize="12sp"
android:layout_marginBottom="16dp"
android:visibility="visible" />
<!-- Action Buttons Section -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_marginTop="16dp">
<!-- Download QRIS Button -->
<Button
android:id="@+id/downloadQrisButton"
android:layout_width="match_parent"
android:layout_height="48dp"
android:layout_marginBottom="8dp"
android:text="Download QRIS"
android:textColor="@android:color/white"
android:textSize="14sp"
android:background="#4CAF50"
android:visibility="visible" />
<!-- Check Payment Status Button -->
<Button
android:id="@+id/checkStatusButton"
android:layout_width="match_parent"
android:layout_height="48dp"
android:layout_marginBottom="8dp"
android:text="Check Payment Status"
android:textColor="@android:color/white"
android:textSize="14sp"
android:background="#2196F3"
android:visibility="visible" />
<!-- Return to Main Button -->
<Button
android:id="@+id/returnMainButton"
android:layout_width="match_parent"
android:layout_height="48dp"
android:text="Return to Main"
android:textColor="@android:color/white"
android:textSize="14sp"
android:background="#FF9800"
android:visibility="visible" />
</LinearLayout>
<!-- Hidden views for compatibility -->
<TextView
android:id="@+id/referenceTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Reference ID: ref-12345"
android:textColor="@android:color/black"
android:textSize="14sp"
android:visibility="gone" />
<ProgressBar
android:id="@+id/progressBar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone" />
<TextView
android:id="@+id/statusTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Payment Status Success"
android:textColor="@android:color/black"
android:textSize="18sp"
android:visibility="gone" />
</LinearLayout>
</androidx.cardview.widget.CardView>
<!-- Spacer to push button to bottom -->
<View
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
<!-- Bottom Cancel Button -->
<Button
android:id="@+id/cancelButton"
android:layout_width="match_parent"
android:layout_height="48dp"
android:layout_margin="16dp"
android:text="Batalkan"
android:textColor="#E31937"
android:textSize="16sp"
android:layout_gravity="center_horizontal"
android:layout_marginBottom="16dp"
android:layout_marginTop="8dp"/>
android:textStyle="normal"
android:background="@android:color/transparent"
style="?android:attr/borderlessButtonStyle" />
<ImageView
android:id="@+id/qrImageView"
android:layout_width="280dp"
android:layout_height="280dp"
android:layout_gravity="center_horizontal"
android:layout_marginTop="16dp"
android:contentDescription="@string/qr_code"/>
<Button
android:id="@+id/downloadQrisButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/download_qris"
android:layout_gravity="center_horizontal"
android:layout_marginTop="16dp"/>
<Button
android:id="@+id/checkStatusButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/check_payment_status"
android:layout_gravity="center_horizontal"
android:layout_marginTop="16dp"/>
<ProgressBar
android:id="@+id/progressBar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:visibility="gone"/>
<TextView
android:id="@+id/statusTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/payment_status_success"
android:textColor="#2D5DA1"
android:textSize="20sp"
android:layout_gravity="center_horizontal"
android:layout_marginTop="24dp"
android:visibility="gone"/>
<Button
android:id="@+id/returnMainButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/return_main"
android:layout_gravity="center_horizontal"
android:layout_marginTop="24dp"
android:visibility="gone"/>
</LinearLayout>
</LinearLayout>

View File

@ -0,0 +1,547 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView
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:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true"
android:overScrollMode="never"
android:scrollbars="none"
android:background="#F5F5F5">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#F5F5F5"
tools:context=".ReceiptActivity">
<!-- Red Status Bar (Override purple) -->
<View
android:id="@+id/red_status_bar"
android:layout_width="match_parent"
android:layout_height="24dp"
android:background="#E31937"
app:layout_constraintTop_toTopOf="parent"/>
<!-- Red Background Header -->
<View
android:id="@+id/red_header_background"
android:layout_width="match_parent"
android:layout_height="120dp"
android:background="#E31937"
app:layout_constraintTop_toBottomOf="@id/red_status_bar"/>
<!-- Header with Back Navigation -->
<LinearLayout
android:id="@+id/back_navigation"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:background="?attr/selectableItemBackgroundBorderless"
android:padding="8dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/red_status_bar">
<!-- Back Arrow -->
<ImageView
android:id="@+id/backArrow"
android:layout_width="20dp"
android:layout_height="20dp"
android:src="@drawable/ic_arrow_back"
android:tint="@android:color/white"
android:contentDescription="Kembali" />
<!-- Title Text -->
<TextView
android:id="@+id/toolbarTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:text="Kembali"
android:textColor="@android:color/white"
android:textSize="16sp"
android:fontFamily="@font/inter"/>
</LinearLayout>
<!-- Receipt Card - Positioned to overlap header by half -->
<androidx.cardview.widget.CardView
android:id="@+id/receipt_card"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:layout_marginTop="60dp"
app:cardBackgroundColor="@android:color/white"
app:cardCornerRadius="12dp"
app:cardElevation="8dp"
app:layout_constraintTop_toBottomOf="@id/red_status_bar">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="20dp">
<!-- Header Section -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:gravity="center"
android:layout_marginBottom="16dp">
<!-- EDC Merchant Logo/Text -->
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="EDC "
android:textColor="#E31937"
android:textSize="24sp"
android:textStyle="bold"
android:fontFamily="@font/inter"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Merchant"
android:textColor="#3F51B5"
android:textSize="24sp"
android:textStyle="bold"
android:fontFamily="@font/inter"/>
</LinearLayout>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="BANK BRI"
android:textColor="#333333"
android:textSize="12sp"
android:fontFamily="@font/inter"
android:layout_marginTop="2dp"/>
</LinearLayout>
<!-- Merchant Info -->
<TextView
android:id="@+id/merchant_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="TOKO KLONTONG PAK EKO"
android:textColor="#333333"
android:textSize="16sp"
android:textStyle="bold"
android:fontFamily="@font/inter"
android:gravity="center"
android:layout_marginBottom="4dp"/>
<TextView
android:id="@+id/merchant_location"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Ciputat Baru, Tangsel"
android:textColor="#666666"
android:textSize="14sp"
android:fontFamily="@font/inter"
android:gravity="center"
android:layout_marginBottom="16dp"/>
<!-- Separator Line -->
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#E0E0E0"
android:layout_marginBottom="16dp"/>
<!-- Transaction Details -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginBottom="8dp">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="MID: "
android:textColor="#666666"
android:textSize="12sp"
android:fontFamily="@font/inter"/>
<TextView
android:id="@+id/mid_text"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="1234567890"
android:textColor="#333333"
android:textSize="12sp"
android:fontFamily="@font/inter"/>
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="TID: "
android:textColor="#666666"
android:textSize="12sp"
android:fontFamily="@font/inter"/>
<TextView
android:id="@+id/tid_text"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="1234567890"
android:textColor="#333333"
android:textSize="12sp"
android:fontFamily="@font/inter"/>
</LinearLayout>
<!-- Separator Line -->
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#E0E0E0"
android:layout_marginVertical="12dp"/>
<!-- Transaction Number -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginBottom="8dp">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Nomor transaksi"
android:textColor="#666666"
android:textSize="14sp"
android:fontFamily="@font/inter"/>
<TextView
android:id="@+id/transaction_number"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="3429483635"
android:textColor="#333333"
android:textSize="14sp"
android:fontFamily="@font/inter"/>
</LinearLayout>
<!-- Transaction Date -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginBottom="8dp">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Tanggal transaksi"
android:textColor="#666666"
android:textSize="14sp"
android:fontFamily="@font/inter"/>
<TextView
android:id="@+id/transaction_date"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="13 Januari 2025 13:46"
android:textColor="#333333"
android:textSize="14sp"
android:fontFamily="@font/inter"/>
</LinearLayout>
<!-- Payment Method -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginBottom="8dp">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Metode pembayaran"
android:textColor="#666666"
android:textSize="14sp"
android:fontFamily="@font/inter"/>
<TextView
android:id="@+id/payment_method"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Kartu Kredit"
android:textColor="#333333"
android:textSize="14sp"
android:fontFamily="@font/inter"/>
</LinearLayout>
<!-- Card Type -->
<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="Jenis Kartu"
android:textColor="#666666"
android:textSize="14sp"
android:fontFamily="@font/inter"/>
<TextView
android:id="@+id/card_type"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="BCA"
android:textColor="#333333"
android:textSize="14sp"
android:fontFamily="@font/inter"/>
</LinearLayout>
<!-- Separator Line -->
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#E0E0E0"
android:layout_marginBottom="16dp"/>
<!-- Transaction Amount -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginBottom="8dp">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Total transaksi"
android:textColor="#666666"
android:textSize="14sp"
android:fontFamily="@font/inter"/>
<TextView
android:id="@+id/transaction_total"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="3.500.000"
android:textColor="#333333"
android:textSize="14sp"
android:fontFamily="@font/inter"/>
</LinearLayout>
<!-- Tax -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginBottom="8dp">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Pajak (%)"
android:textColor="#666666"
android:textSize="14sp"
android:fontFamily="@font/inter"/>
<TextView
android:id="@+id/tax_percentage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="11%"
android:textColor="#333333"
android:textSize="14sp"
android:fontFamily="@font/inter"/>
</LinearLayout>
<!-- Service Fee -->
<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="Biaya Layanan"
android:textColor="#666666"
android:textSize="14sp"
android:fontFamily="@font/inter"/>
<TextView
android:id="@+id/service_fee"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="500"
android:textColor="#333333"
android:textSize="14sp"
android:fontFamily="@font/inter"/>
</LinearLayout>
<!-- Separator Line -->
<View
android:layout_width="match_parent"
android:layout_height="2dp"
android:background="#E0E0E0"
android:layout_marginBottom="16dp"/>
<!-- Final Total -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginBottom="20dp">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="TOTAL"
android:textColor="#333333"
android:textSize="18sp"
android:textStyle="bold"
android:fontFamily="@font/inter"/>
<TextView
android:id="@+id/final_total"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="3.506.500"
android:textColor="#333333"
android:textSize="18sp"
android:textStyle="bold"
android:fontFamily="@font/inter"/>
</LinearLayout>
</LinearLayout>
</androidx.cardview.widget.CardView>
<!-- Action Buttons (Print & Email) -->
<LinearLayout
android:id="@+id/action_buttons_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginHorizontal="16dp"
android:layout_marginTop="24dp"
app:layout_constraintTop_toBottomOf="@id/receipt_card">
<!-- Print Button -->
<LinearLayout
android:id="@+id/print_button"
android:layout_width="0dp"
android:layout_height="56dp"
android:layout_weight="1"
android:layout_marginEnd="8dp"
android:orientation="horizontal"
android:gravity="center"
android:background="@drawable/button_secondary_background"
android:clickable="true"
android:focusable="true">
<ImageView
android:layout_width="20dp"
android:layout_height="20dp"
android:src="@drawable/ic_print"
android:tint="#666666"
android:layout_marginEnd="8dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Cetak Ulang"
android:textColor="#666666"
android:textSize="14sp"
android:fontFamily="@font/inter"/>
</LinearLayout>
<!-- Email Button -->
<LinearLayout
android:id="@+id/email_button"
android:layout_width="0dp"
android:layout_height="56dp"
android:layout_weight="1"
android:layout_marginStart="8dp"
android:orientation="horizontal"
android:gravity="center"
android:background="@drawable/button_secondary_background"
android:clickable="true"
android:focusable="true">
<ImageView
android:layout_width="20dp"
android:layout_height="20dp"
android:src="@drawable/ic_email"
android:tint="#666666"
android:layout_marginEnd="8dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Email"
android:textColor="#666666"
android:textSize="14sp"
android:fontFamily="@font/inter"/>
</LinearLayout>
</LinearLayout>
<!-- Finish Button -->
<Button
android:id="@+id/finish_button"
android:layout_width="match_parent"
android:layout_height="56dp"
android:layout_marginHorizontal="16dp"
android:layout_marginTop="16dp"
android:layout_marginBottom="24dp"
android:text="Selesai"
android:textColor="@android:color/white"
android:textSize="16sp"
android:textStyle="bold"
android:background="@drawable/button_finish_background"
android:fontFamily="@font/inter"
app:layout_constraintTop_toBottomOf="@id/action_buttons_container"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintVertical_bias="0"/>
</androidx.constraintlayout.widget.ConstraintLayout>
</ScrollView>

View File

@ -0,0 +1,160 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#F5F5F5"
android:orientation="vertical">
<!-- Header with solid red background -->
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="200dp"
android:background="#E53E3E">
<!-- Back button -->
<ImageView
android:id="@+id/btn_back"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_alignParentStart="true"
android:layout_marginStart="16dp"
android:layout_marginTop="24dp"
android:background="?attr/selectableItemBackgroundBorderless"
android:clickable="true"
android:focusable="true"
android:padding="4dp"
android:src="@android:drawable/ic_menu_revert"
android:tint="@android:color/white" />
<!-- Title -->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:layout_toEndOf="@id/btn_back"
android:text="Kembali"
android:textColor="@android:color/white"
android:textSize="16sp" />
<!-- Settlement Card -->
<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="120dp"
android:layout_marginStart="16dp"
android:layout_marginTop="64dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="16dp"
app:cardCornerRadius="12dp"
app:cardElevation="4dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#4299E1"
android:orientation="vertical"
android:padding="16dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="SETTLEMENT"
android:textColor="@android:color/white"
android:textSize="14sp"
android:textStyle="bold" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="2dp"
android:text="Rekap dan kirim transaksi hari ini"
android:textColor="#E0FFFFFF"
android:textSize="12sp" />
<TextView
android:id="@+id/tv_total_amount"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="3.506.500"
android:textColor="@android:color/white"
android:textSize="24sp"
android:textStyle="bold" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Jumlah Transaksi"
android:textColor="#E0FFFFFF"
android:textSize="12sp" />
</LinearLayout>
<TextView
android:id="@+id/tv_total_transactions"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="65"
android:textColor="@android:color/white"
android:textSize="20sp"
android:textStyle="bold" />
</LinearLayout>
</androidx.cardview.widget.CardView>
</RelativeLayout>
<!-- Content -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="vertical"
android:padding="16dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:text="Informasi Ringkasan Transaksi Hari Ini"
android:textColor="#333333"
android:textSize="16sp"
android:textStyle="bold" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:text="Pastikan Anda melakukan settlement untuk menyelesaikan transaksi harian."
android:textColor="#666666"
android:textSize="12sp" />
<!-- Transaction List -->
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
</LinearLayout>
<!-- Bottom Button -->
<Button
android:id="@+id/btn_continue"
android:layout_width="match_parent"
android:layout_height="48dp"
android:layout_margin="16dp"
android:background="#E53E3E"
android:text="Selanjutnya"
android:textColor="@android:color/white"
android:textSize="16sp"
android:textStyle="bold" />
</LinearLayout>

View File

@ -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>
</androidx.coordinatorlayout.widget.CoordinatorLayout>

View File

@ -0,0 +1,69 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@android:color/white"
android:clickable="true"
android:focusable="true"
android:orientation="horizontal"
android:padding="16dp">
<!-- Left Content -->
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical">
<TextView
android:id="@+id/tv_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="09:00, 07-05-2025"
android:textColor="#333333"
android:textSize="14sp" />
<TextView
android:id="@+id/tv_amount"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:text="Rp. 78.000"
android:textColor="#333333"
android:textSize="14sp"
android:textStyle="bold" />
</LinearLayout>
<!-- Center Content -->
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginStart="16dp"
android:orientation="vertical">
<TextView
android:id="@+id/tv_channel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Kredit"
android:textColor="#333333"
android:textSize="14sp"
android:textStyle="bold" />
</LinearLayout>
<!-- Right Content -->
<TextView
android:id="@+id/tv_status"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginStart="16dp"
android:text="Berhasil"
android:textColor="#4CAF50"
android:textSize="12sp"
android:textStyle="bold" />
</LinearLayout>

View File

@ -0,0 +1,178 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
app:cardCornerRadius="8dp"
app:cardElevation="2dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="16dp">
<!-- Header Row -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:id="@+id/tv_reference_id"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Ref: 197870"
android:textColor="#333333"
android:textSize="14sp"
android:textStyle="bold" />
<TextView
android:id="@+id/tv_status"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="SUCCESS"
android:textColor="#4CAF50"
android:textSize="12sp"
android:textStyle="bold" />
</LinearLayout>
<!-- Amount -->
<TextView
android:id="@+id/tv_amount"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="Rp. 2.018.619"
android:textColor="#333333"
android:textSize="18sp"
android:textStyle="bold" />
<!-- Details Grid -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:orientation="vertical">
<!-- Row 1 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<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="Channel"
android:textColor="#666666"
android:textSize="12sp" />
<TextView
android:id="@+id/tv_channel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Other Payment"
android:textColor="#333333"
android:textSize="14sp"
android:textStyle="bold" />
</LinearLayout>
<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="Waktu"
android:textColor="#666666"
android:textSize="12sp" />
<TextView
android:id="@+id/tv_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="16/05/2025 05:40"
android:textColor="#333333"
android:textSize="14sp"
android:textStyle="bold" />
</LinearLayout>
</LinearLayout>
<!-- Row 2 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:orientation="horizontal">
<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="Merchant"
android:textColor="#666666"
android:textSize="12sp" />
<TextView
android:id="@+id/tv_merchant"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TEST MERCHANT"
android:textColor="#333333"
android:textSize="14sp"
android:textStyle="bold" />
</LinearLayout>
<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="Issuer"
android:textColor="#666666"
android:textSize="12sp" />
<TextView
android:id="@+id/tv_issuer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="BANK MANDIRI"
android:textColor="#333333"
android:textSize="14sp"
android:textStyle="bold" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
</LinearLayout>
</androidx.cardview.widget.CardView>

View File

@ -0,0 +1,70 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@android:color/white"
android:clickable="true"
android:focusable="true"
android:orientation="horizontal"
android:padding="16dp">
<!-- Icon -->
<ImageView
android:id="@+id/iv_icon"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_gravity="center_vertical"
android:background="#F7FAFC"
android:padding="8dp"
android:src="@android:drawable/ic_menu_gallery"
android:tint="#E53E3E" />
<!-- Content -->
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_weight="1"
android:orientation="vertical">
<TextView
android:id="@+id/tv_channel_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Kartu Kredit"
android:textColor="#333333"
android:textSize="14sp"
android:textStyle="bold" />
</LinearLayout>
<!-- Amount and Count -->
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:orientation="vertical">
<TextView
android:id="@+id/tv_amount"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end"
android:text="Rp. 200.000"
android:textColor="#333333"
android:textSize="14sp"
android:textStyle="bold" />
<TextView
android:id="@+id/tv_transaction_count"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end"
android:layout_marginTop="2dp"
android:text="13 Transaksi"
android:textColor="#666666"
android:textSize="12sp" />
</LinearLayout>
</LinearLayout>

View File

@ -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" />
android:orientation="horizontal"
android:padding="16dp"
android:gravity="center_vertical">
<TextView
android:id="@+id/textStatus"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Status"
android:textColor="#4CAF50"
android:textStyle="bold" />
<!-- Kolom 1: Reference ID -->
<TextView
android:id="@+id/textReferenceId"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="ref-eowu3pin"
android:textColor="#333333"
android:textSize="16sp"
android:textStyle="bold" />
<TextView
android:id="@+id/textReferenceId"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Reference ID" />
<!-- 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" />
<TextView
android:id="@+id/textMerchantName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Merchant Name" />
<!-- 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">
<TextView
android:id="@+id/textCreatedAt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Created At" />
</LinearLayout>
<ImageView
android:layout_width="16dp"
android:layout_height="16dp"
android:src="@drawable/ic_print"
android:layout_marginEnd="8dp"
app:tint="#666666" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
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" />
</LinearLayout>

View File

@ -0,0 +1,43 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- res/layout/modal_layout.xml -->
<androidx.cardview.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="32dp"
app:cardCornerRadius="16dp"
app:cardElevation="8dp"
app:cardBackgroundColor="#FFFFFF">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="32dp"
android:gravity="center">
<!-- Card Icon -->
<ImageView
android:layout_width="80dp"
android:layout_height="80dp"
android:src="@drawable/ic_card_insert"
android:layout_marginBottom="24dp"
android:scaleType="fitCenter"
android:adjustViewBounds="true"/>
<!-- Main Text -->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Silakan Tempelkan / Gesekkan / Masukkan Kartu ke Perangkat"
android:textColor="#333333"
android:textSize="16sp"
android:textStyle="normal"
android:textAlignment="center"
android:gravity="center"
android:lineSpacingExtra="4dp"/>
</LinearLayout>
</androidx.cardview.widget.CardView>

View File

@ -0,0 +1,48 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Style yang sudah ada -->
<style name="MenuCardTitle">
<item name="fontFamily">@font/inter</item>
<item name="android:textSize">12sp</item>
<item name="android:textColor">#DD0701</item>
<item name="android:textAlignment">center</item>
<item name="android:lineSpacingExtra">0dp</item>
<item name="android:lineSpacingMultiplier">1.0</item>
<item name="android:letterSpacing">0</item>
<item name="android:textStyle">normal</item>
</style>
<!-- Style baru untuk Toolbar Title -->
<style name="ToolbarTitleStyle">
<item name="fontFamily">@font/inter</item>
<item name="android:textSize">18sp</item>
<item name="android:textStyle">bold</item>
<item name="android:lineSpacingExtra">6dp</item>
<item name="android:lineSpacingMultiplier">1.0</item>
<item name="android:letterSpacing">0</item>
<item name="android:textColor">@android:color/white</item>
</style>
<!-- Custom Toolbar Theme -->
<style name="CustomToolbarTheme" parent="ThemeOverlay.AppCompat.Dark.ActionBar">
<item name="android:textAppearance">@style/ToolbarTitleStyle</item>
<item name="titleTextAppearance">@style/ToolbarTitleStyle</item>
</style>
<!-- Numpad Button Style -->
<style name="NumpadButton">
<item name="android:layout_width">0dp</item>
<item name="android:layout_height">60dp</item>
<item name="android:layout_columnWeight">1</item>
<item name="android:layout_margin">8dp</item>
<item name="android:background">?attr/selectableItemBackgroundBorderless</item>
<item name="android:textSize">28sp</item>
<item name="android:textColor">#333333</item>
<item name="android:textStyle">normal</item>
<item name="android:fontFamily">@font/inter</item>
<item name="android:gravity">center</item>
<item name="android:clickable">true</item>
<item name="android:focusable">true</item>
</style>
</resources>

0
gradlew vendored Normal file → Executable file
View File