Use a star to notify available updates to dictionaries
CHANGELOG.md
| 20 | 20 | * Fix alignment in dictionary list. | |
| 21 | 21 | * Small alignment and size fixes in dictionary download screen. | |
| 22 | 22 | * Add back button to action bars to better navigate between screens. | |
| 23 | + | * Use a star to notify dictionary updates instead of background color. | |
| 23 | 24 | ||
| 24 | 25 | ### Features | |
| 25 | 26 |
app/src/main/java/eu/lepiller/nani/DictionaryActivity.java
| 1 | 1 | package eu.lepiller.nani; | |
| 2 | 2 | ||
| 3 | 3 | import android.content.Intent; | |
| 4 | + | import android.graphics.drawable.Drawable; | |
| 4 | 5 | import android.os.AsyncTask; | |
| 5 | 6 | import android.os.Bundle; | |
| 6 | 7 | import androidx.appcompat.app.AppCompatActivity; | |
… | |||
| 22 | 23 | import java.net.MalformedURLException; | |
| 23 | 24 | import java.net.URL; | |
| 24 | 25 | import java.util.ArrayList; | |
| 26 | + | import java.util.HashMap; | |
| 25 | 27 | ||
| 26 | 28 | import eu.lepiller.nani.dictionary.DictionariesAdapter; | |
| 27 | 29 | import eu.lepiller.nani.dictionary.DictionaryFactory; | |
app/src/main/java/eu/lepiller/nani/DictionaryDownloadActivity.java
| 80 | 80 | setContentView(R.layout.activity_dictionary_download); | |
| 81 | 81 | Bundle extras = getIntent().getExtras(); | |
| 82 | 82 | ||
| 83 | - | getSupportActionBar().setDisplayHomeAsUpEnabled(true); | |
| 84 | - | ||
| 85 | 83 | // TODO: this will open the first dictionary on error, we probably want to display a proper | |
| 86 | 84 | // error instead. | |
| 87 | 85 | int position = 0; |
app/src/main/java/eu/lepiller/nani/dictionary/DictionariesAdapter.java
| 1 | 1 | package eu.lepiller.nani.dictionary; | |
| 2 | 2 | ||
| 3 | 3 | import android.content.Context; | |
| 4 | + | import android.graphics.Typeface; | |
| 4 | 5 | import android.graphics.drawable.Drawable; | |
| 5 | 6 | import android.view.LayoutInflater; | |
| 6 | 7 | import android.view.View; | |
… | |||
| 18 | 19 | ||
| 19 | 20 | public class DictionariesAdapter extends ArrayAdapter<Dictionary> { | |
| 20 | 21 | private Context context; | |
| 22 | + | ||
| 21 | 23 | public DictionariesAdapter(Context context, ArrayList<Dictionary> dictionaries) { | |
| 22 | 24 | super(context, 0, dictionaries); | |
| 23 | 25 | this.context = context; | |
… | |||
| 45 | 47 | TextView entry_count_view = convertView.findViewById(R.id.entries_view); | |
| 46 | 48 | ||
| 47 | 49 | // Populate the data into the template view using the data object | |
| 48 | - | Drawable icon = dictionary.getDrawable(context); | |
| 50 | + | Drawable icon; | |
| 51 | + | if (dictionary.isDownloaded() && !dictionary.isUpToDate()) | |
| 52 | + | icon = dictionary.getNewDrawable(context); | |
| 53 | + | else | |
| 54 | + | icon = dictionary.getDrawable(context); | |
| 55 | + | ||
| 49 | 56 | if(icon != null) { | |
| 50 | 57 | Drawable.ConstantState state = icon.getConstantState(); | |
| 51 | 58 | if(state != null) { | |
… | |||
| 59 | 66 | } | |
| 60 | 67 | ||
| 61 | 68 | name_view.setText(dictionary.getName()); | |
| 69 | + | if(!dictionary.isUpToDate() && dictionary.isDownloaded()) { | |
| 70 | + | name_view.setTypeface(null, Typeface.BOLD); | |
| 71 | + | } else { | |
| 72 | + | name_view.setTypeface(null, Typeface.NORMAL); | |
| 73 | + | } | |
| 62 | 74 | description_view.setText(dictionary.getDescription()); | |
| 63 | - | if(!dictionary.isUpToDate() && dictionary.isDownloaded()) | |
| 64 | - | convertView.setBackgroundColor(context.getResources().getColor(R.color.colorUpdate)); | |
| 65 | - | else | |
| 66 | - | convertView.setBackgroundColor(0); | |
| 67 | 75 | ||
| 68 | 76 | int size = dictionary.getExpectedFileSize(); | |
| 69 | 77 | NumberFormat nf = NumberFormat.getInstance(); | |
app/src/main/java/eu/lepiller/nani/dictionary/Dictionary.java
| 1 | 1 | package eu.lepiller.nani.dictionary; | |
| 2 | 2 | ||
| 3 | 3 | import android.content.Context; | |
| 4 | + | import android.graphics.Bitmap; | |
| 5 | + | import android.graphics.BitmapFactory; | |
| 6 | + | import android.graphics.Canvas; | |
| 7 | + | import android.graphics.drawable.BitmapDrawable; | |
| 4 | 8 | import android.graphics.drawable.Drawable; | |
| 5 | 9 | import android.os.Build; | |
| 10 | + | import android.util.Log; | |
| 6 | 11 | import android.util.Pair; | |
| 7 | 12 | ||
| 8 | 13 | import java.io.File; | |
… | |||
| 15 | 20 | import java.security.NoSuchAlgorithmException; | |
| 16 | 21 | import java.util.Map; | |
| 17 | 22 | ||
| 23 | + | import eu.lepiller.nani.R; | |
| 24 | + | ||
| 18 | 25 | abstract public class Dictionary { | |
| 19 | 26 | private String name; | |
| 20 | 27 | private String description, fullDescription; | |
… | |||
| 23 | 30 | private String sha256; | |
| 24 | 31 | private File file, temporaryFile; | |
| 25 | 32 | ||
| 33 | + | private static Drawable drawable=null, newDrawable=null; | |
| 34 | + | private static final String TAG = "DICO"; | |
| 35 | + | ||
| 26 | 36 | Dictionary(String n, String descr, String fullDescr, File cacheDir, int fileSize, int entries, String hash) { | |
| 27 | 37 | name = n; | |
| 28 | 38 | description = descr; | |
… | |||
| 71 | 81 | public abstract Map<String, Pair<File, File>> getDownloads(); | |
| 72 | 82 | ||
| 73 | 83 | public Drawable getDrawable(Context context) { | |
| 74 | - | Drawable drawable; | |
| 75 | - | int drawableResId = getDrawableId(); | |
| 76 | - | if (android.os.Build.VERSION.SDK_INT > Build.VERSION_CODES.M) { | |
| 77 | - | drawable = context.getResources().getDrawable(drawableResId, context.getTheme()); | |
| 78 | - | } else { | |
| 79 | - | drawable = context.getResources().getDrawable(drawableResId); | |
| 84 | + | if(drawable == null) { | |
| 85 | + | int drawableResId = getDrawableId(); | |
| 86 | + | if (android.os.Build.VERSION.SDK_INT > Build.VERSION_CODES.M) { | |
| 87 | + | drawable = context.getResources().getDrawable(drawableResId, context.getTheme()); | |
| 88 | + | } else { | |
| 89 | + | drawable = context.getResources().getDrawable(drawableResId); | |
| 90 | + | } | |
| 80 | 91 | } | |
| 81 | 92 | return drawable; | |
| 82 | 93 | } | |
| 83 | 94 | ||
| 95 | + | private Bitmap drawableToBitmap(Drawable drawable) { | |
| 96 | + | Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), | |
| 97 | + | Bitmap.Config.ARGB_8888); | |
| 98 | + | Canvas canvas = new Canvas(bitmap); | |
| 99 | + | drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight()); | |
| 100 | + | drawable.draw(canvas); | |
| 101 | + | return bitmap; | |
| 102 | + | } | |
| 103 | + | ||
| 104 | + | private Bitmap drawableToBitmap(Drawable drawable, int width, int height) { | |
| 105 | + | Bitmap background = drawableToBitmap(drawable); | |
| 106 | + | return Bitmap.createScaledBitmap(background, width, height, false); | |
| 107 | + | } | |
| 108 | + | ||
| 109 | + | public Drawable getNewDrawable(Context context) { | |
| 110 | + | if(newDrawable == null) { | |
| 111 | + | Bitmap big = Bitmap.createBitmap(64, 64, Bitmap.Config.ARGB_8888); | |
| 112 | + | Canvas canvas = new Canvas(big); | |
| 113 | + | ||
| 114 | + | // Ensure we have the base icon | |
| 115 | + | getDrawable(context); | |
| 116 | + | ||
| 117 | + | Drawable star; | |
| 118 | + | if (android.os.Build.VERSION.SDK_INT > Build.VERSION_CODES.M) { | |
| 119 | + | star = context.getResources().getDrawable(R.drawable.ic_star, context.getTheme()); | |
| 120 | + | } else { | |
| 121 | + | star = context.getResources().getDrawable(R.drawable.ic_star); | |
| 122 | + | } | |
| 123 | + | ||
| 124 | + | canvas.drawBitmap(drawableToBitmap(drawable, 64, 64), 0, 0, null); | |
| 125 | + | canvas.drawBitmap(drawableToBitmap(star, 22, 22), 39, 39, null); | |
| 126 | + | newDrawable = new BitmapDrawable(context.getResources(), big); | |
| 127 | + | } | |
| 128 | + | return newDrawable; | |
| 129 | + | } | |
| 130 | + | ||
| 84 | 131 | abstract int getDrawableId(); | |
| 85 | 132 | ||
| 86 | 133 | abstract public void remove(); | |
app/src/main/res/drawable/ic_star.xml unknown status 1
| 1 | + | <vector xmlns:android="http://schemas.android.com/apk/res/android" | |
| 2 | + | android:width="16dp" | |
| 3 | + | android:height="16dp" | |
| 4 | + | android:viewportWidth="16" | |
| 5 | + | android:viewportHeight="16"> | |
| 6 | + | <path | |
| 7 | + | android:pathData="M16,12.7132 L10.2328,11.9042 6.2681,16 5.2885,10.4919 -0,8.1428 5.1618,5.5476l0.6962,-5.5476 4.1698,3.9042 5.7188,-1.0796 -2.5847,5.0081z" | |
| 8 | + | android:strokeWidth="0.26458332" | |
| 9 | + | android:fillColor="#ffdd55"/> | |
| 10 | + | </vector> |