diff --git a/app/src/main/java/protect/card_locker/LetterBitmap.java b/app/src/main/java/protect/card_locker/LetterBitmap.java new file mode 100644 index 000000000..44c65d087 --- /dev/null +++ b/app/src/main/java/protect/card_locker/LetterBitmap.java @@ -0,0 +1,141 @@ +package protect.card_locker; + +import android.content.Context; +import android.content.res.Resources; +import android.content.res.TypedArray; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.Rect; +import android.graphics.Typeface; +import android.text.TextPaint; + +/** + * Original from https://github.com/andOTP/andOTP/blob/master/app/src/main/java/org/shadowice/flocke/andotp/Utilities/LetterBitmap.java + * which was originally from http://stackoverflow.com/questions/23122088/colored-boxed-with-letters-a-la-gmail + * Used to create a {@link Bitmap} that contains a letter used in the English + * alphabet or digit, if there is no letter or digit available, a default image + * is shown instead. + * + * Only English language supported. + */ +class LetterBitmap +{ + + /** + * The number of available tile colors + */ + private static final int NUM_OF_TILE_COLORS = 8; + + /** + * The {@link TextPaint} used to draw the letter onto the tile + */ + private final TextPaint mPaint = new TextPaint(); + /** + * The bounds that enclose the letter + */ + private final Rect mBounds = new Rect(); + /** + * The {@link Canvas} to draw on + */ + private final Canvas mCanvas = new Canvas(); + /** + * The first char of the name being displayed + */ + private final char[] mFirstChar = new char[1]; + + /** + * The background colors of the tile + */ + private final TypedArray mColors; + /** + * The font size used to display the letter + */ + private final int mTileLetterFontSize; + /** + * The default image to display + */ + private final Bitmap mDefaultBitmap; + + /** + * Constructor for LetterTileProvider + * + * @param context The {@link Context} to use + */ + public LetterBitmap(Context context) + { + final Resources res = context.getResources(); + + mPaint.setTypeface(Typeface.create("sans-serif-light", Typeface.BOLD)); + mPaint.setColor(Color.WHITE); + mPaint.setTextAlign(Paint.Align.CENTER); + mPaint.setAntiAlias(true); + + mColors = res.obtainTypedArray(R.array.letter_tile_colors); + mTileLetterFontSize = res.getDimensionPixelSize(R.dimen.tile_letter_font_size); + + mDefaultBitmap = BitmapFactory.decodeResource(res, android.R.drawable.sym_def_app_icon); + } + + /** + * @param displayName The name used to create the letter for the tile + * @param key The key used to generate the background color for the tile + * @param width The desired width of the tile + * @param height The desired height of the tile + * @return A {@link Bitmap} that contains a letter used in the English + * alphabet or digit, if there is no letter or digit available, a + * default image is shown instead + */ + public Bitmap getLetterTile(String displayName, String key, int width, int height) + { + final Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); + char firstChar = displayName.charAt(0); + + final Canvas c = mCanvas; + c.setBitmap(bitmap); + c.drawColor(pickColor(key)); + + if (!isEnglishLetterOrDigit(firstChar)) + { + firstChar = 'A'; + } + mFirstChar[0] = Character.toUpperCase(firstChar); + mPaint.setTextSize(mTileLetterFontSize); + mPaint.getTextBounds(mFirstChar, 0, 1, mBounds); + c.drawText(mFirstChar, 0, 1, width / 2, height / 2 + + (mBounds.bottom - mBounds.top) / 2, mPaint); + return bitmap; + } + + /** + * @param c The char to check + * @return True if c is in the English alphabet or is a digit, + * false otherwise + */ + private static boolean isEnglishLetterOrDigit(char c) + { + return 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' || '0' <= c && c <= '9'; + } + + /** + * @param key The key used to generate the tile color + * @return A new or previously chosen color for key used as the + * tile background color + */ + private int pickColor(String key) + { + // String.hashCode() is not supposed to change across java versions, so + // this should guarantee the same key always maps to the same color + final int color = Math.abs(key.hashCode()) % NUM_OF_TILE_COLORS; + try + { + return mColors.getColor(color, Color.BLACK); + } + finally + { + mColors.recycle(); + } + } +} \ No newline at end of file diff --git a/app/src/main/java/protect/card_locker/LoyaltyCardCursorAdapter.java b/app/src/main/java/protect/card_locker/LoyaltyCardCursorAdapter.java index 85110ac16..32e4f3797 100644 --- a/app/src/main/java/protect/card_locker/LoyaltyCardCursorAdapter.java +++ b/app/src/main/java/protect/card_locker/LoyaltyCardCursorAdapter.java @@ -6,6 +6,7 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.CursorAdapter; +import android.widget.ImageView; import android.widget.TextView; class LoyaltyCardCursorAdapter extends CursorAdapter @@ -29,6 +30,7 @@ class LoyaltyCardCursorAdapter extends CursorAdapter public void bindView(View view, Context context, Cursor cursor) { // Find fields to populate in inflated template + ImageView thumbnail = view.findViewById(R.id.thumbnail); TextView storeField = (TextView) view.findViewById(R.id.store); TextView cardIdField = (TextView) view.findViewById(R.id.cardId); @@ -49,5 +51,9 @@ class LoyaltyCardCursorAdapter extends CursorAdapter String cardIdLabel = view.getResources().getString(R.string.cardId); String cardIdText = String.format(cardIdFormat, cardIdLabel, loyaltyCard.cardId); cardIdField.setText(cardIdText); + + LetterBitmap letterBitmap = new LetterBitmap(context); + int pixelSize = context.getResources().getDimensionPixelSize(R.dimen.cardThumbnailSize); + thumbnail.setImageBitmap(letterBitmap.getLetterTile(loyaltyCard.store, loyaltyCard.store, pixelSize, pixelSize)); } } diff --git a/app/src/main/res/layout/loyalty_card_layout.xml b/app/src/main/res/layout/loyalty_card_layout.xml index ae6fc80dc..188297d66 100644 --- a/app/src/main/res/layout/loyalty_card_layout.xml +++ b/app/src/main/res/layout/loyalty_card_layout.xml @@ -8,6 +8,14 @@ android:baselineAligned="false" android:padding="@dimen/activity_margin"> + + 8dp 16dp + + + 33sp diff --git a/app/src/main/res/values/settings.xml b/app/src/main/res/values/settings.xml new file mode 100644 index 000000000..aa416bb2a --- /dev/null +++ b/app/src/main/res/values/settings.xml @@ -0,0 +1,13 @@ + + + + #f16364 + #f58559 + #f9a43e + #e4c62e + #67bf74 + #59a2be + #2093cd + #ad62a7 + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 41aa29c83..4b8072c7b 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -85,6 +85,8 @@ Card ID copied to clipboard + Thumbnail for card + Start Intro Welcome to Loyalty Card Keychain\n Manage your barcode-based store/loyalty cards on your phone!\n\n