card edit activity: revised instance saving, revised temp image handling

This commit is contained in:
Katharine
2021-11-04 02:41:23 +08:00
parent 57cfac3172
commit 8940a8ea77
4 changed files with 136 additions and 75 deletions

View File

@@ -117,7 +117,6 @@
<activity
android:name="com.yalantis.ucrop.UCropActivity"
android:screenOrientation="portrait"
android:theme="@style/Theme.AppCompat.NoActionBar"/>
<provider

View File

@@ -16,9 +16,7 @@ import android.graphics.Color;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.os.LocaleList;
import android.provider.MediaStore;
import android.text.Editable;
import android.text.InputType;
import android.util.Log;
@@ -36,6 +34,15 @@ import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.annotation.NonNull;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.widget.Toolbar;
import androidx.core.content.FileProvider;
import androidx.fragment.app.DialogFragment;
import com.google.android.material.chip.Chip;
import com.google.android.material.chip.ChipGroup;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
@@ -44,7 +51,6 @@ import com.google.android.material.tabs.TabLayout;
import com.jaredrummler.android.colorpicker.ColorPickerDialog;
import com.jaredrummler.android.colorpicker.ColorPickerDialogListener;
import com.yalantis.ucrop.UCrop;
import com.yalantis.ucrop.UCropActivity;
import com.yalantis.ucrop.model.AspectRatio;
import java.io.File;
@@ -66,16 +72,6 @@ import java.util.Locale;
import java.util.NoSuchElementException;
import java.util.concurrent.Callable;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.annotation.NonNull;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.widget.Toolbar;
import androidx.core.content.FileProvider;
import androidx.exifinterface.media.ExifInterface;
import androidx.fragment.app.DialogFragment;
import protect.card_locker.async.TaskHandler;
public class LoyaltyCardEditActivity extends CatimaAppCompatActivity {
@@ -84,7 +80,18 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity {
private final String STATE_TAB_INDEX = "savedTab";
private final String STATE_TEMP_CARD = "tempLoyaltyCard";
private final String STATE_REQUESTED_IMAGE = "requestedImage";
private final String STATE_TEMP_CAMERA_PICTURE_PATH = "tempCameraPicturePath";
private final String STATE_FRONT_IMAGE_UNSAVED = "frontImageUnsaved";
private final String STATE_BACK_IMAGE_UNSAVED = "backImageUnsaved";
private final String STATE_UPDATE_LOYALTY_CARD = "updateLoyaltyCard";
private final String STATE_HAS_CHANGED = "hasChange";
private final String TEMP_CAMERA_IMAGE_NAME = LoyaltyCardEditActivity.class.getSimpleName() + "_camera_image.jpg";
private final String TEMP_CROP_IMAGE_NAME = LoyaltyCardEditActivity.class.getSimpleName() + "_crop_image.png";
private final Bitmap.CompressFormat TEMP_CROP_IMAGE_FORMAT = Bitmap.CompressFormat.PNG;
private final String TEMP_UNSAVED_FRONT_IMAGE_NAME = LoyaltyCardEditActivity.class.getSimpleName() + "_front_image.png";
private final String TEMP_UNSAVED_BACK_IMAGE_NAME= LoyaltyCardEditActivity.class.getSimpleName() + "_back_image.png";
private final Bitmap.CompressFormat TEMP_UNSAVED_IMAGE_FORMAT = Bitmap.CompressFormat.PNG;
private static final int ID_IMAGE_FRONT = 0;
private static final int ID_IMAGE_BACK = 1;
@@ -144,19 +151,19 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity {
HashMap<String, Currency> currencies = new HashMap<>();
String tempCameraPicturePath;
LoyaltyCard tempLoyaltyCard;
ActivityResultLauncher<Intent> mPhotoTakerLauncher;
ActivityResultLauncher<Uri> mPhotoTakerLauncher;
ActivityResultLauncher<Intent> mPhotoPickerLauncher;
ActivityResultLauncher<Intent> mCardIdAndBarCodeEditorLauncher;
ActivityResultLauncher<Intent> mCropperLauncher;
int mRequestedImage;
int mRequestedImage = 0;
int mCropperFinishedType = 0;
UCrop.Options mCropperOptions;
boolean mFrontImageUnsaved = false;
boolean mBackImageUnsaved = false;
final private TaskHandler mTasks = new TaskHandler();
@@ -199,6 +206,8 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity {
+ ", updateLoyaltyCard=" + updateLoyaltyCard);
}
@Override
public void onSaveInstanceState(@NonNull Bundle savedInstanceState) {
super.onSaveInstanceState(savedInstanceState);
@@ -206,7 +215,20 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity {
savedInstanceState.putInt(STATE_TAB_INDEX, tabs.getSelectedTabPosition());
savedInstanceState.putParcelable(STATE_TEMP_CARD, tempLoyaltyCard);
savedInstanceState.putInt(STATE_REQUESTED_IMAGE, mRequestedImage);
savedInstanceState.putString(STATE_TEMP_CAMERA_PICTURE_PATH, tempCameraPicturePath);
Object cardImageFrontObj = cardImageFront.getTag();
if (mFrontImageUnsaved && (cardImageFrontObj instanceof Bitmap) && Utils.saveTempImage(this, (Bitmap)cardImageFrontObj, TEMP_UNSAVED_FRONT_IMAGE_NAME, TEMP_UNSAVED_IMAGE_FORMAT) != null){
savedInstanceState.putInt(STATE_FRONT_IMAGE_UNSAVED, 1);
}else{
savedInstanceState.putInt(STATE_FRONT_IMAGE_UNSAVED, 0);
}
Object cardImageBackObj = cardImageBack.getTag();
if (mBackImageUnsaved && (cardImageBackObj instanceof Bitmap) && Utils.saveTempImage(this, (Bitmap)cardImageBackObj, TEMP_UNSAVED_BACK_IMAGE_NAME, TEMP_UNSAVED_IMAGE_FORMAT) != null){
savedInstanceState.putInt(STATE_BACK_IMAGE_UNSAVED, 1);
}else{
savedInstanceState.putInt(STATE_BACK_IMAGE_UNSAVED, 0);
}
savedInstanceState.putInt(STATE_UPDATE_LOYALTY_CARD, updateLoyaltyCard ? 1 : 0);
savedInstanceState.putInt(STATE_HAS_CHANGED, hasChanged? 1:0);
}
@Override
@@ -216,7 +238,10 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity {
tabs = findViewById(R.id.tabs);
tabs.selectTab(tabs.getTabAt(savedInstanceState.getInt(STATE_TAB_INDEX)));
mRequestedImage = savedInstanceState.getInt(STATE_REQUESTED_IMAGE);
tempCameraPicturePath = savedInstanceState.getString(STATE_TEMP_CAMERA_PICTURE_PATH);
mFrontImageUnsaved = savedInstanceState.getInt(STATE_FRONT_IMAGE_UNSAVED) == 1;
mBackImageUnsaved = savedInstanceState.getInt(STATE_BACK_IMAGE_UNSAVED) == 1;
updateLoyaltyCard = savedInstanceState.getInt(STATE_UPDATE_LOYALTY_CARD) == 1;
hasChanged = savedInstanceState.getInt(STATE_HAS_CHANGED) == 1;
}
@Override
@@ -438,7 +463,6 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity {
if (!lastValue.toString().equals(getString(R.string.setBarcodeId))) {
barcodeIdField.setText(lastValue);
}
;
AlertDialog.Builder builder = new AlertDialog.Builder(LoyaltyCardEditActivity.this);
builder.setTitle(R.string.setBarcodeId);
@@ -531,13 +555,14 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity {
tabs.selectTab(tabs.getTabAt(0));
mPhotoTakerLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), result -> {
if (result.getResultCode() == RESULT_OK) {
startCropper(tempCameraPicturePath);
}
mPhotoTakerLauncher = registerForActivityResult(new ActivityResultContracts.TakePicture(), result->{
if (result) {
startCropper(getCacheDir() + "/" + TEMP_CAMERA_IMAGE_NAME);
}
});
// android 11: wanted to swap it to ActivityResultContracts.GetContent but then it shows a file browsers that shows image mime types, offering gallery in the file browser
mPhotoPickerLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), result -> {
if (result.getResultCode() == RESULT_OK) {
Intent intent = result.getData();
@@ -548,7 +573,6 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity {
Uri uri = intent.getData();
startCropperUri(uri);
}
});
mCardIdAndBarCodeEditorLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), result -> {
@@ -577,25 +601,20 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity {
if (debugUri == null){
throw new RuntimeException("ucrop returned success but not destination uri!");
}
String cropOutputPath = debugUri.getPath();
Log.d("cropper", "cropper has produced image at " + debugUri.toString());
Bitmap bitmap = BitmapFactory.decodeFile(cropOutputPath);
Log.d("cropper", "ucrop produced image at " + debugUri);
Bitmap bitmap = BitmapFactory.decodeFile(getCacheDir() + "/" + TEMP_CROP_IMAGE_NAME);
if (bitmap != null) {
bitmap = Utils.resizeBitmap(bitmap);
try {
bitmap = Utils.rotateBitmap(bitmap, new ExifInterface(cropOutputPath));
} catch (IOException e) {
e.printStackTrace();
}
if (mRequestedImage == Utils.CARD_IMAGE_FROM_CAMERA_FRONT || mRequestedImage == Utils.CARD_IMAGE_FROM_FILE_FRONT) {
if (requestedFrontImage()) {
mFrontImageUnsaved = true;
setCardImage(cardImageFront, bitmap);
} else {
mBackImageUnsaved = true;
setCardImage(cardImageBack, bitmap);
}
Log.d("cropper", "mRequestedImage: " + mRequestedImage);
mCropperFinishedType = mRequestedImage;
hasChanged = true;
} else {
Toast.makeText(LoyaltyCardEditActivity.this, R.string.errorReadingImage, Toast.LENGTH_LONG).show();
@@ -615,7 +634,7 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity {
}
private void setCropperOptions(){
mCropperOptions.setCompressionFormat(Bitmap.CompressFormat.JPEG);
mCropperOptions.setCompressionFormat(TEMP_CROP_IMAGE_FORMAT);
mCropperOptions.setFreeStyleCropEnabled(true);
mCropperOptions.setHideBottomControls(false);
// needed when bottom controls are hidden
@@ -641,6 +660,18 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity {
extractIntentFields(intent);
}
private boolean requestedFrontImage(){
return mRequestedImage == Utils.CARD_IMAGE_FROM_CAMERA_FRONT || mRequestedImage == Utils.CARD_IMAGE_FROM_FILE_FRONT;
}
private boolean croppedFrontImage(){
return mCropperFinishedType == Utils.CARD_IMAGE_FROM_CAMERA_FRONT || mCropperFinishedType == Utils.CARD_IMAGE_FROM_FILE_FRONT;
}
private boolean croppedBackImage(){
return mCropperFinishedType == Utils.CARD_IMAGE_FROM_CAMERA_BACK || mCropperFinishedType == Utils.CARD_IMAGE_FROM_FILE_BACK;
}
@SuppressLint("DefaultLocale")
@Override
public void onResume() {
@@ -650,6 +681,7 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity {
onResuming = true;
if (tempLoyaltyCard == null) {
if (updateLoyaltyCard) {
tempLoyaltyCard = db.getLoyaltyCard(loyaltyCardId);
@@ -659,9 +691,6 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity {
finish();
return;
}
setTitle(R.string.editCardTitle);
setCardImage(cardImageFront, Utils.retrieveCardImage(this, tempLoyaltyCard.id, true));
setCardImage(cardImageBack, Utils.retrieveCardImage(this, tempLoyaltyCard.id, false));
} else if (importLoyaltyCardUri != null) {
try {
tempLoyaltyCard = importUriHelper.parse(importLoyaltyCardUri);
@@ -670,14 +699,37 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity {
finish();
return;
}
setTitle(R.string.addCardTitle);
} else {
// New card, use default values
tempLoyaltyCard = new LoyaltyCard(-1, "", "", null, new BigDecimal("0"), null, "", null, null, null, 0, Utils.getUnixTime(),100);
setTitle(R.string.addCardTitle);
}
}
if(!initDone) {
if (updateLoyaltyCard) {
setTitle(R.string.editCardTitle);
if (!mFrontImageUnsaved && !croppedFrontImage()) {
setCardImage(cardImageFront, Utils.retrieveCardImage(this, tempLoyaltyCard.id, true));
}
if (!mBackImageUnsaved && !croppedBackImage()) {
setCardImage(cardImageBack, Utils.retrieveCardImage(this, tempLoyaltyCard.id, false));
}
}else{
setTitle(R.string.addCardTitle);
}
if(mFrontImageUnsaved && !croppedFrontImage()){
setCardImage(cardImageFront, Utils.loadTempImage(this, TEMP_UNSAVED_FRONT_IMAGE_NAME));
}
if(mBackImageUnsaved && !croppedBackImage()){
setCardImage(cardImageBack, Utils.loadTempImage(this, TEMP_UNSAVED_BACK_IMAGE_NAME));
}
}
mCropperFinishedType = 0;
boolean hadChanges = hasChanged;
storeFieldEdit.setText(tempLoyaltyCard.store);
noteFieldEdit.setText(tempLoyaltyCard.note);
formatExpiryField(this, expiryField, tempLoyaltyCard.expiry);
@@ -767,8 +819,8 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity {
// Initialization has finished
if (!initDone) {
hasChanged = false;
initDone = true;
hasChanged = hadChanges;
}
generateOrHideBarcode();
@@ -908,26 +960,13 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity {
confirmExitDialog.show();
}
private File createTempFile(String prefix, String suffix) throws IOException{
String imageFileName = prefix + new Date().getTime();
return File.createTempFile(
imageFileName,
suffix,
getExternalFilesDir(Environment.DIRECTORY_PICTURES)
);
}
private void takePhotoForCard(int type) throws IOException {
Intent i = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
File image = createTempFile("CATIMA_", ".jpg");
tempCameraPicturePath = image.getAbsolutePath();
Uri photoURI = FileProvider.getUriForFile(LoyaltyCardEditActivity.this, BuildConfig.APPLICATION_ID, image);
i.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);
Uri photoURI = FileProvider.getUriForFile(LoyaltyCardEditActivity.this, BuildConfig.APPLICATION_ID, Utils.createTempFile(this, TEMP_CAMERA_IMAGE_NAME));
mRequestedImage = type;
mPhotoTakerLauncher.launch(i);
mPhotoTakerLauncher.launch(photoURI);
}
class EditCardIdAndBarcode implements View.OnClickListener {
@@ -1168,12 +1207,7 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity {
public void startCropperUri(Uri sourceUri){
Log.d("cropper", "launching cropper with image " + sourceUri.getPath());
File cropOutput;
try {
cropOutput = createTempFile("UCROP_", ".jpg");
}catch(java.io.IOException e){
Log.e("image cropping", "failed creating temporarily file");
return;
}
cropOutput = Utils.createTempFile(this, TEMP_CROP_IMAGE_NAME);
Uri destUri = Uri.parse("file://" + cropOutput.getAbsolutePath());
Log.d("cropper", "asking cropper to output to " + destUri.toString());

View File

@@ -25,6 +25,7 @@ import com.google.zxing.Result;
import com.google.zxing.common.HybridBinarizer;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
@@ -410,10 +411,37 @@ public class Utils {
Configuration config = inputContext.getResources().getConfiguration();
int currentNightMode = config.uiMode & Configuration.UI_MODE_NIGHT_MASK;
return (currentNightMode == Configuration.UI_MODE_NIGHT_YES);
}else if (nightModeSetting == AppCompatDelegate.MODE_NIGHT_YES){
return true;
}else{
return false;
}else {
return nightModeSetting == AppCompatDelegate.MODE_NIGHT_YES;
}
}
public static File createTempFile(Context context, String name){
return new File(context.getCacheDir() + "/" + name);
}
public static String saveTempImage(Context context, Bitmap in, String name, Bitmap.CompressFormat format){
File image = createTempFile(context, name);
try (FileOutputStream out = new FileOutputStream(image)){
in.compress(format, 100, out);
return image.getAbsolutePath();
}catch(IOException e){
Log.d("store temp image", "failed writing temp file for temporary image, name: " + name);
return null;
}
}
public static Bitmap loadImage(String path){
try{
return BitmapFactory.decodeStream(new FileInputStream(path));
}catch(IOException e){
Log.d("load image", "failed loading image from " + path);
return null;
}
}
public static Bitmap loadTempImage(Context context, String name){
return loadImage(context.getCacheDir() + "/" + name);
}
}

View File

@@ -1,3 +1,3 @@
<paths>
<external-path name="exportPath" path="/" />
<cache-path name="cachePath" path="/" />
</paths>