#1044 - Automatic Balance Update (#1073)

This commit is contained in:
polarhun
2022-10-16 13:25:26 +01:00
committed by GitHub
parent c34e2fdd70
commit ccf12bf028
6 changed files with 146 additions and 0 deletions

View File

@@ -494,6 +494,15 @@ public class DBHelper extends SQLiteOpenHelper {
return (rowsUpdated == 1);
}
public static boolean updateLoyaltyCardBalance(SQLiteDatabase database, final int id, final BigDecimal newBalance) {
ContentValues contentValues = new ContentValues();
contentValues.put(LoyaltyCardDbIds.BALANCE, newBalance.toString());
int rowsUpdated = database.update(LoyaltyCardDbIds.TABLE, contentValues,
whereAttrs(LoyaltyCardDbIds.ID),
withArgs(id));
return (rowsUpdated == 1);
}
public static LoyaltyCard getLoyaltyCard(SQLiteDatabase database, final int id) {
Cursor data = database.query(LoyaltyCardDbIds.TABLE, null, whereAttrs(LoyaltyCardDbIds.ID), withArgs(id), null, null, null);

View File

@@ -1,6 +1,8 @@
package protect.card_locker;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.res.ColorStateList;
@@ -13,6 +15,8 @@ import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Bundle;
import android.text.Editable;
import android.text.InputType;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.TextUtils;
@@ -25,12 +29,15 @@ import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewOutlineProvider;
import android.view.ViewTreeObserver;
import android.view.Window;
import android.view.WindowInsets;
import android.view.WindowInsetsController;
import android.view.WindowManager;
import android.widget.EditText;
import android.widget.FrameLayout;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
@@ -64,8 +71,10 @@ import java.io.File;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.text.DateFormat;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Currency;
import java.util.List;
import protect.card_locker.async.TaskHandler;
@@ -85,6 +94,7 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
ImageButton bottomAppBarInfoButton;
ImageButton bottomAppBarPreviousButton;
ImageButton bottomAppBarNextButton;
ImageButton bottomAppBarUpdateBalanceButton;
AppCompatTextView storeName;
ImageButton maximizeButton;
ImageView mainImage;
@@ -363,6 +373,7 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
bottomAppBarInfoButton = binding.buttonShowInfo;
bottomAppBarPreviousButton = binding.buttonPrevious;
bottomAppBarNextButton = binding.buttonNext;
bottomAppBarUpdateBalanceButton = binding.buttonUpdateBalance;
barcodeImageGenerationFinishedCallback = () -> {
if (!(boolean) mainImage.getTag()) {
@@ -439,6 +450,7 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
bottomAppBarInfoButton.setOnClickListener(view -> showInfoDialog());
bottomAppBarPreviousButton.setOnClickListener(view -> prevNextCard(false));
bottomAppBarNextButton.setOnClickListener(view -> prevNextCard(true));
bottomAppBarUpdateBalanceButton.setOnClickListener(view -> showBalanceUpdateDialog());
mGestureDetector = new GestureDetector(this, this);
View.OnTouchListener gestureTouchListener = (v, event) -> mGestureDetector.onTouchEvent(event);
@@ -453,6 +465,7 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
iconImage.setClipBounds(new Rect(left, top, right, bottom));
}
});
this.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
}
private SpannableStringBuilder padSpannableString(SpannableStringBuilder spannableStringBuilder) {
@@ -523,6 +536,78 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
infoDialog.create().show();
}
private void showBalanceUpdateDialog() {
AlertDialog.Builder builder = new MaterialAlertDialogBuilder(this);
builder.setTitle(R.string.updateBalanceTitle);
FrameLayout container = new FrameLayout(this);
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT
);
params.leftMargin = 60;
params.rightMargin = 60;
LinearLayout layout = new LinearLayout(this);
layout.setOrientation(LinearLayout.VERTICAL);
TextView currentTextview = new TextView(this);
currentTextview.setText(getString(R.string.currentBalanceSentence, Utils.formatBalance(this, loyaltyCard.balance, loyaltyCard.balanceType)));
layout.addView(currentTextview);
TextView updateTextView = new TextView(this);
updateTextView.setText(getString(R.string.newBalanceSentence, Utils.formatBalance(this, loyaltyCard.balance, loyaltyCard.balanceType)));
layout.addView(updateTextView);
final EditText input = new EditText(this);
Context dialogContext = this;
input.setInputType(InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_FLAG_DECIMAL);
input.setHint(R.string.updateBalanceHint);
input.addTextChangedListener(new SimpleTextWatcher() {
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
BigDecimal newBalance;
try {
newBalance = calculateNewBalance(loyaltyCard.balance, loyaltyCard.balanceType, s.toString());
} catch (ParseException e) {
input.setTag(null);
updateTextView.setText(getString(R.string.newBalanceSentence, Utils.formatBalance(dialogContext, loyaltyCard.balance, loyaltyCard.balanceType)));
return;
}
// Save new balance into this element
input.setTag(newBalance);
updateTextView.setText(getString(R.string.newBalanceSentence, Utils.formatBalance(dialogContext, newBalance, loyaltyCard.balanceType)));
}
});
layout.addView(input);
layout.setLayoutParams(params);
container.addView(layout);
builder.setView(container);
builder.setPositiveButton(R.string.ok, (dialogInterface, i) -> {
// Grab calculated balance from input field
BigDecimal newBalance = (BigDecimal) input.getTag();
if (newBalance == null) {
return;
}
// Actually update balance
DBHelper.updateLoyaltyCardBalance(database, loyaltyCardId, newBalance);
// Reload UI
this.onResume();
});
builder.setNegativeButton(getString(R.string.cancel), (dialog, which) -> dialog.cancel());
AlertDialog dialog = builder.create();
dialog.show();
dialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
input.requestFocus();
}
private BigDecimal calculateNewBalance(BigDecimal currentBalance, Currency currency, String unparsedSubtraction) throws ParseException {
BigDecimal subtraction = Utils.parseBalance(unparsedSubtraction, currency);
return currentBalance.subtract(subtraction).max(new BigDecimal(0));
}
private void setBottomAppBarButtonState() {
if (!loyaltyCard.note.isEmpty() || !loyaltyCardGroups.isEmpty() || hasBalance(loyaltyCard) || loyaltyCard.expiry != null) {
bottomAppBarInfoButton.setVisibility(View.VISIBLE);
@@ -537,6 +622,8 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
bottomAppBarPreviousButton.setVisibility(View.VISIBLE);
bottomAppBarNextButton.setVisibility(View.VISIBLE);
}
bottomAppBarUpdateBalanceButton.setVisibility(hasBalance(loyaltyCard) ? View.VISIBLE : View.GONE);
}
private void prevNextCard(boolean next) {
@@ -709,6 +796,7 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
fixImageButtonColor(bottomAppBarInfoButton);
fixImageButtonColor(bottomAppBarPreviousButton);
fixImageButtonColor(bottomAppBarNextButton);
fixImageButtonColor(bottomAppBarUpdateBalanceButton);
setBottomAppBarButtonState();
// Make notification area light if dark icons are needed

View File

@@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="?attr/colorControlNormal"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M7,18c-1.1,0 -1.99,0.9 -1.99,2S5.9,22 7,22s2,-0.9 2,-2 -0.9,-2 -2,-2zM1,2v2h2l3.6,7.59 -1.35,2.45c-0.16,0.28 -0.25,0.61 -0.25,0.96 0,1.1 0.9,2 2,2h12v-2L7.42,15c-0.14,0 -0.25,-0.11 -0.25,-0.25l0.03,-0.12 0.9,-1.63h7.45c0.75,0 1.41,-0.41 1.75,-1.03l3.58,-6.49c0.08,-0.14 0.12,-0.31 0.12,-0.48 0,-0.55 -0.45,-1 -1,-1L5.21,4l-0.94,-2L1,2zM17,18c-1.1,0 -1.99,0.9 -1.99,2s0.89,2 1.99,2 2,-0.9 2,-2 -0.9,-2 -2,-2z"/>
</vector>

View File

@@ -8,6 +8,7 @@
android:layout_height="fill_parent"
android:fitsSystemWindows="true">
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/app_bar_layout"
android:layout_width="fill_parent"
@@ -264,6 +265,18 @@
android:tooltipText="@string/nextCard"
android:visibility="gone" />
<ImageButton
android:id="@+id/button_update_balance"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="end"
android:background="@android:color/transparent"
android:paddingStart="12dp"
android:paddingEnd="12dp"
android:src="@drawable/ic_baseline_shopping_cart_24"
android:tooltipText="@string/updateBalance"
android:visibility="gone" />
</com.google.android.material.bottomappbar.BottomAppBar>
<com.google.android.material.floatingactionbutton.FloatingActionButton

View File

@@ -250,6 +250,7 @@
<string name="sort">Sort</string>
<string name="showMoreInfo">Show info</string>
<string name="hideMoreInfo">Hide info</string>
<string name="updateBalance">Update balance</string>
<string name="swipeToSwitchImages">Swipe to switch images, hold to open image in the gallery app</string>
<string name="failedToRetrieveImageFile">Failed to retrieve image file</string>
<string name="barcodeLongPressMessage">Only images can be opened in the gallery app</string>
@@ -300,4 +301,8 @@
<item quantity="other">View archive (<xliff:g>%1$d</xliff:g> cards)</item>
</plurals>
<string name="welcome">Welcome to Catima</string>
<string name="updateBalanceTitle">How much did you spend?</string>
<string name="updateBalanceHint">Enter amount</string>
<string name="currentBalanceSentence">Current balance: <xliff:g>%s</xliff:g></string>
<string name="newBalanceSentence">New balance: <xliff:g>%s</xliff:g></string>
</resources>

View File

@@ -504,4 +504,30 @@ public class DatabaseTest {
assertEquals(0, card2.lastUsed);
assertEquals(100, card2.zoomLevel);
}
@Test
public void updateGiftCardOnlyBalance() {
long id = DBHelper.insertLoyaltyCard(mDatabase, "store", "note", null, new BigDecimal("100"), null, "cardId", null, CatimaBarcode.fromBarcode(BarcodeFormat.UPC_A), DEFAULT_HEADER_COLOR, 0, null,0);
boolean result = (id != -1);
assertTrue(result);
assertEquals(1, DBHelper.getLoyaltyCardCount(mDatabase));
result = DBHelper.updateLoyaltyCardBalance(mDatabase, 1, new BigDecimal(60));
assertTrue(result);
assertEquals(1, DBHelper.getLoyaltyCardCount(mDatabase));
LoyaltyCard loyaltyCard = DBHelper.getLoyaltyCard(mDatabase, 1);
assertNotNull(loyaltyCard);
assertEquals("store", loyaltyCard.store);
assertEquals("note", loyaltyCard.note);
assertEquals(null, loyaltyCard.expiry);
assertEquals(new BigDecimal(60), loyaltyCard.balance);
assertEquals(null, loyaltyCard.balanceType);
assertEquals("cardId", loyaltyCard.cardId);
assertEquals(null, loyaltyCard.barcodeId);
assertEquals(BarcodeFormat.UPC_A, loyaltyCard.barcodeType.format());
assertEquals(DEFAULT_HEADER_COLOR, loyaltyCard.headerColor);
assertEquals(0, loyaltyCard.starStatus);
assertEquals(0, loyaltyCard.archiveStatus);
}
}