ResultActivity.java
package com.secuso.privacyfriendlycodescanner.qrscanner.ui.activities;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.DrawableRes;
import androidx.annotation.NonNull;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.content.res.AppCompatResources;
import androidx.fragment.app.FragmentTransaction;
import androidx.lifecycle.ViewModelProvider;
import com.bumptech.glide.Glide;
import com.google.zxing.client.result.ParsedResult;
import com.journeyapps.barcodescanner.BarcodeResult;
import com.secuso.privacyfriendlycodescanner.qrscanner.R;
import com.secuso.privacyfriendlycodescanner.qrscanner.database.HistoryItem;
import com.secuso.privacyfriendlycodescanner.qrscanner.generator.Contents;
import com.secuso.privacyfriendlycodescanner.qrscanner.helpers.Utils;
import com.secuso.privacyfriendlycodescanner.qrscanner.ui.dialogfragments.QRCodeImageDialogFragment;
import com.secuso.privacyfriendlycodescanner.qrscanner.ui.dialogfragments.RawDataDialogFragment;
import com.secuso.privacyfriendlycodescanner.qrscanner.ui.resultfragments.CalendarResultFragment;
import com.secuso.privacyfriendlycodescanner.qrscanner.ui.resultfragments.ContactResultFragment;
import com.secuso.privacyfriendlycodescanner.qrscanner.ui.resultfragments.EmailResultFragment;
import com.secuso.privacyfriendlycodescanner.qrscanner.ui.resultfragments.GeoResultFragment;
import com.secuso.privacyfriendlycodescanner.qrscanner.ui.resultfragments.ProductResultFragment;
import com.secuso.privacyfriendlycodescanner.qrscanner.ui.resultfragments.ResultFragment;
import com.secuso.privacyfriendlycodescanner.qrscanner.ui.resultfragments.SMSResultFragment;
import com.secuso.privacyfriendlycodescanner.qrscanner.ui.resultfragments.TelResultFragment;
import com.secuso.privacyfriendlycodescanner.qrscanner.ui.resultfragments.TextResultFragment;
import com.secuso.privacyfriendlycodescanner.qrscanner.ui.resultfragments.URLResultFragment;
import com.secuso.privacyfriendlycodescanner.qrscanner.ui.resultfragments.WifiResultFragment;
import com.secuso.privacyfriendlycodescanner.qrscanner.ui.viewmodel.ResultViewModel;
import java.text.DateFormat;
import java.util.Date;
import android.os.Environment;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Map;
/**
* This activity displays the results of scan. Either from the history or from a scan directly.
*/
public class ResultActivity extends AppCompatActivity {
private static final String HISTORY_DATA = "ResultActivity.HISTORY_DATA";
private static BarcodeResult barcodeResult = null;
private static HistoryItem historyItem = null;
private Button chooseActionButton = null;
private ResultViewModel viewModel;
private ResultFragment currentResultFragment;
private Map<String, Double> productPrices; // 产品价格映射
public static void startResultActivity(@NonNull Context context, @NonNull BarcodeResult barcodeResult) {
ResultActivity.barcodeResult = barcodeResult;
ResultActivity.historyItem = null;
Intent resultIntent = new Intent(context, ResultActivity.class);
context.startActivity(resultIntent);
}
public static void startResultActivity(@NonNull Context context, @NonNull HistoryItem historyItem) {
ResultActivity.barcodeResult = null;
ResultActivity.historyItem = historyItem;
Intent resultIntent = new Intent(context, ResultActivity.class);
resultIntent.putExtra(HISTORY_DATA, true);
context.startActivity(resultIntent);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_result);
chooseActionButton = findViewById(R.id.btnChooseAction);
viewModel = new ViewModelProvider(this).get(ResultViewModel.class);
// 加载产品价格数据
productPrices = loadProductPrices();
initStateIfNecessary(savedInstanceState);
ActionBar ab = getSupportActionBar();
if (ab != null) {
ab.setDisplayHomeAsUpEnabled(true);
}
if (isFinishing()) {
return;
}
loadFragment(viewModel.mParsedResult);
if (isFinishing()) {
return;
}
displayGeneralData();
displayProductPrice(); // 显示价格
findViewById(R.id.btnChooseAction).setOnClickListener(this::onChooseActionButtonClick);
findViewById(R.id.btnRawData).setOnClickListener(this::onRawDataButtonClick);
findViewById(R.id.activity_result_qr_image).setOnClickListener(this::onQRImageClick);
}
private Map<String, Double> loadProductPrices() {
Map<String, Double> productPrices = new HashMap<>();
File downloadsDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
File csvFile = new File(downloadsDir, "product_prices.csv");
try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(csvFile)))) {
String line;
while ((line = reader.readLine()) != null) {
String[] parts = line.split(",");
if (parts.length == 2) {
String barcode = parts[0].trim();
Double price = Double.parseDouble(parts[1].trim());
productPrices.put(barcode, price);
}
}
} catch (IOException e) {
e.printStackTrace();
}
return productPrices;
}
private void displayGeneralData() {
ImageView qrImageView = findViewById(R.id.activity_result_qr_image);
TextView qrTypeText = findViewById(R.id.textView);
TextView timestampTextView = findViewById(R.id.textViewTimestamp);
TextView codeTypeText = findViewById(R.id.textViewCodeType);
ImageView codeTypeImageView = findViewById(R.id.item_history_type_image);
@DrawableRes int codeTypeDrawableRes = Utils.getBarcodeFormatIcon(viewModel.currentHistoryItem.getFormat());
Glide.with(this).load(AppCompatResources.getDrawable(this, codeTypeDrawableRes))
.placeholder(AppCompatResources.getDrawable(this, R.drawable.ic_no_image_accent_24dp))
.into(codeTypeImageView);
codeTypeText.setText(viewModel.currentHistoryItem.getFormat().toString());
Glide.with(this).load(viewModel.mCodeImage).into(qrImageView);
qrTypeText.setText(Contents.Type.parseParsedResultType(viewModel.mParsedResult.getType()).toLocalizedString(getApplicationContext()));
long timestamp = viewModel.currentHistoryItem.getTimestamp();
if (timestamp != 0) {
DateFormat df = DateFormat.getDateTimeInstance();
timestampTextView.setText(df.format(new Date(timestamp)));
}
}
private void displayProductPrice() {
TextView priceTextView = findViewById(R.id.textViewPrice); // 确保在布局中有这个TextView
String barcode = viewModel.currentHistoryItem.getText(); // 获取条形码文本
if (productPrices.containsKey(barcode)) {
double price = productPrices.get(barcode);
priceTextView.setText("价格: $" + price);
} else {
priceTextView.setText("未找到价格");
}
}
private void onQRImageClick(View view) {
QRCodeImageDialogFragment fragment = new QRCodeImageDialogFragment();
fragment.show(getSupportFragmentManager(), QRCodeImageDialogFragment.TAG);
}
private void onChooseActionButtonClick(View view) {
if (currentResultFragment != null) {
currentResultFragment.onProceedPressed(this);
}
}
private void onRawDataButtonClick(View view) {
RawDataDialogFragment fragment = RawDataDialogFragment.Companion.newInstance(viewModel.currentHistoryItem.getText());
fragment.show(getSupportFragmentManager(), RawDataDialogFragment.TAG);
}
private void initStateIfNecessary(Bundle savedInstanceState) {
boolean hasHistoryItem = getIntent().getBooleanExtra(HISTORY_DATA, false);
if (savedInstanceState == null) {
if (hasHistoryItem && historyItem != null) {
viewModel.initFromHistoryItem(historyItem);
} else if (barcodeResult != null) {
viewModel.initFromScan(barcodeResult);
} else {
// no data to display -> exit
Toast.makeText(this, R.string.activity_result_toast_error_cant_load, Toast.LENGTH_SHORT).show();
finish();
}
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.share, menu);
getMenuInflater().inflate(R.menu.copy, menu);
getMenuInflater().inflate(R.menu.save, menu);
return true;
}
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
if (menu != null) {
MenuItem saveMi = menu.findItem(R.id.save);
if (saveMi != null) {
saveMi.setVisible(!viewModel.mSavedToHistory);
}
}
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int itemId = item.getItemId();
if (itemId == R.id.share) {
Intent sharingIntent = new Intent(Intent.ACTION_SEND);
sharingIntent.setType("text/plain");
sharingIntent.putExtra(Intent.EXTRA_TEXT, viewModel.mParsedResult.getDisplayResult());
startActivity(Intent.createChooser(sharingIntent, getString(R.string.share_via)));
return true;
} else if (itemId == R.id.save) {
viewModel.saveHistoryItem(viewModel.currentHistoryItem);
invalidateOptionsMenu();
Toast.makeText(this, R.string.activity_result_toast_saved, Toast.LENGTH_SHORT).show();
return true;
} else if (itemId == R.id.copy) {
ClipboardManager clipboardManager = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE);
ClipData clipData = ClipData.newPlainText("Text", viewModel.mParsedResult.getDisplayResult());
clipboardManager.setPrimaryClip(clipData);
Toast.makeText(getApplicationContext(), R.string.content_copied, Toast.LENGTH_SHORT).show();
return true;
} else if (itemId == android.R.id.home) {
onBackPressed();
return true;
} else {
return super.onOptionsItemSelected(item);
}
}
private void loadFragment(ParsedResult parsedResult) {
if (parsedResult == null) {
Toast.makeText(this.getBaseContext(), R.string.activity_result_toast_error_cant_load, Toast.LENGTH_LONG).show();
finish();
return;
}
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ResultFragment resultFragment;
switch (parsedResult.getType()) {
case ADDRESSBOOK:
resultFragment = new ContactResultFragment();
break;
case CALENDAR:
resultFragment = new CalendarResultFragment();
break;
case EMAIL_ADDRESS:
resultFragment = new EmailResultFragment();
break;
case PRODUCT:
resultFragment = new ProductResultFragment();
break;
case URI:
resultFragment = new URLResultFragment();
break;
case GEO:
resultFragment = new GeoResultFragment();
break;
case TEL:
resultFragment = new TelResultFragment();
break;
case SMS:
resultFragment = new SMSResultFragment();
break;
case WIFI:
resultFragment = new WifiResultFragment();
break;
case ISBN:
// TODO: add isbn fragment
case VIN:
// TODO: add vin fragment
case TEXT:
default:
resultFragment = new TextResultFragment();
// hide "search" button if search engines are disabled
if (!PreferenceManager.getDefaultSharedPreferences(this).getBoolean("pref_search_engine_enabled", true)) {
chooseActionButton.setVisibility(View.GONE);
}
break;
}
currentResultFragment = resultFragment;
resultFragment.putQRCode(parsedResult);
ft.replace(R.id.activity_result_frame_layout, resultFragment);
ft.commit();
chooseActionButton.setText(resultFragment.getProceedButtonTitle(this));
}
}
xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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">
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/colorSurface"
android:fillViewport="true"
tools:context="com.secuso.privacyfriendlycodescanner.qrscanner.ui.activities.ResultActivity">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="80dp">
<androidx.cardview.widget.CardView
android:id="@+id/activity_result_qr_type_card"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_margin="16dp"
android:padding="8dp"
app:cardCornerRadius="4dp"
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="wrap_content">
<ImageView
android:id="@+id/activity_result_qr_image"
android:layout_width="80dp"
android:layout_height="0dp"
android:layout_margin="8dp"
android:scaleType="centerCrop"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/qqr" />
<ImageView
android:id="@+id/item_history_type_image"
android:layout_width="12dp"
android:layout_height="wrap_content"
android:layout_marginStart="32dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="2dp"
android:text="QR-Code"
android:textAppearance="@style/TextAppearance.AppCompat.Small"
app:layout_constraintBottom_toTopOf="@+id/textView"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toEndOf="@id/activity_result_qr_image"
app:layout_constraintTop_toTopOf="@id/activity_result_qr_image"
app:srcCompat="@drawable/ic_no_image_accent_24dp"
app:tint="?attr/colorHistoryIcons" />
<TextView
android:id="@+id/textViewCodeType"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="2dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="2dp"
android:text="QR-Code"
android:textAppearance="@style/TextAppearance.AppCompat.Small"
app:layout_constraintBottom_toTopOf="@+id/textView"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toEndOf="@id/item_history_type_image"
app:layout_constraintTop_toTopOf="@id/activity_result_qr_image" />
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="32dp"
android:layout_marginEnd="8dp"
android:text="Error"
android:textAppearance="@style/TextAppearance.AppCompat.Large"
app:layout_constraintBottom_toBottomOf="@id/activity_result_qr_image"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toEndOf="@id/activity_result_qr_image"
app:layout_constraintTop_toTopOf="@id/activity_result_qr_image" />
<TextView
android:id="@+id/textViewTimestamp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:text="TextView"
android:textAlignment="textEnd"
android:textSize="12sp"
app:layout_constrainedWidth="true"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toEndOf="@+id/textViewCodeType"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/btnRawData"
style="@style/Widget.MaterialComponents.Button.TextButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:layout_marginBottom="2dp"
android:text="@string/raw_data"
android:textColor="?attr/colorAccent"
app:layout_constrainedWidth="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toEndOf="@+id/textView"
app:layout_constraintTop_toBottomOf="@+id/textViewTimestamp"
app:layout_constraintVertical_bias="1.0" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.cardview.widget.CardView>
<FrameLayout
android:id="@+id/activity_result_frame_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/activity_result_qr_type_card"
app:layout_constraintVertical_bias="0.0" />
</androidx.constraintlayout.widget.ConstraintLayout>
</ScrollView>
<TextView
android:id="@+id/textViewPrice"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="200dp"
android:layout_marginLeft="15dp"
android:text="价格: "
android:textSize="16sp"/>
<com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
android:id="@+id/btnChooseAction"
style="@style/AppTheme.Button.ExtendedFloatingActionButton.Base"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginBottom="16dp"
android:clickable="true"
android:text="@string/choose_action"
android:textAlignment="center"
app:icon="@drawable/ic_baseline_next_plan_24dp" />
</RelativeLayout>
参考github
SecUSo//privacy-friendly-qr-scanner