Use a star to notify available updates to dictionaries

Julien LepillerSat Jun 06 15:20:49+0200 2020

6e03334

Use a star to notify available updates to dictionaries

CHANGELOG.md

2020
* Fix alignment in dictionary list.
2121
* Small alignment and size fixes in dictionary download screen.
2222
* Add back button to action bars to better navigate between screens.
23+
* Use a star to notify dictionary updates instead of background color.
2324
2425
### Features
2526

app/src/main/java/eu/lepiller/nani/DictionaryActivity.java

11
package eu.lepiller.nani;
22
33
import android.content.Intent;
4+
import android.graphics.drawable.Drawable;
45
import android.os.AsyncTask;
56
import android.os.Bundle;
67
import androidx.appcompat.app.AppCompatActivity;

2223
import java.net.MalformedURLException;
2324
import java.net.URL;
2425
import java.util.ArrayList;
26+
import java.util.HashMap;
2527
2628
import eu.lepiller.nani.dictionary.DictionariesAdapter;
2729
import eu.lepiller.nani.dictionary.DictionaryFactory;

app/src/main/java/eu/lepiller/nani/DictionaryDownloadActivity.java

8080
        setContentView(R.layout.activity_dictionary_download);
8181
        Bundle extras = getIntent().getExtras();
8282
83-
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
84-
8583
        // TODO: this will open the first dictionary on error, we probably want to display a proper
8684
        // error instead.
8785
        int position = 0;

app/src/main/java/eu/lepiller/nani/dictionary/DictionariesAdapter.java

11
package eu.lepiller.nani.dictionary;
22
33
import android.content.Context;
4+
import android.graphics.Typeface;
45
import android.graphics.drawable.Drawable;
56
import android.view.LayoutInflater;
67
import android.view.View;

1819
1920
public class DictionariesAdapter extends ArrayAdapter<Dictionary> {
2021
    private Context context;
22+
2123
    public DictionariesAdapter(Context context, ArrayList<Dictionary> dictionaries) {
2224
        super(context, 0, dictionaries);
2325
        this.context = context;

4547
        TextView entry_count_view = convertView.findViewById(R.id.entries_view);
4648
4749
        // 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+
        
4956
        if(icon != null) {
5057
            Drawable.ConstantState state = icon.getConstantState();
5158
            if(state != null) {

5966
        }
6067
6168
        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+
        }
6274
        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);
6775
6876
        int size = dictionary.getExpectedFileSize();
6977
        NumberFormat nf = NumberFormat.getInstance();

app/src/main/java/eu/lepiller/nani/dictionary/Dictionary.java

11
package eu.lepiller.nani.dictionary;
22
33
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;
48
import android.graphics.drawable.Drawable;
59
import android.os.Build;
10+
import android.util.Log;
611
import android.util.Pair;
712
813
import java.io.File;

1520
import java.security.NoSuchAlgorithmException;
1621
import java.util.Map;
1722
23+
import eu.lepiller.nani.R;
24+
1825
abstract public class Dictionary {
1926
    private String name;
2027
    private String description, fullDescription;

2330
    private String sha256;
2431
    private File file, temporaryFile;
2532
33+
    private static Drawable drawable=null, newDrawable=null;
34+
    private static final String TAG = "DICO";
35+
2636
    Dictionary(String n, String descr, String fullDescr, File cacheDir, int fileSize, int entries, String hash) {
2737
        name = n;
2838
        description = descr;

7181
    public abstract Map<String, Pair<File, File>> getDownloads();
7282
7383
    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+
            }
8091
        }
8192
        return drawable;
8293
    }
8394
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+
84131
    abstract int getDrawableId();
85132
86133
    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>