Add dictionary download

Julien LepillerSat Apr 06 18:57:04+0200 2019

a5317fa

Add dictionary download

.idea/misc.xml

11
<?xml version="1.0" encoding="UTF-8"?>
22
<project version="4">
3-
  <component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" project-jdk-name="JDK" project-jdk-type="JavaSDK">
3+
  <component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" project-jdk-name="1.8" project-jdk-type="JavaSDK">
44
    <output url="file://$PROJECT_DIR$/build/classes" />
55
  </component>
66
  <component name="ProjectType">

app/src/main/AndroidManifest.xml

99
        android:roundIcon="@mipmap/ic_launcher_round"
1010
        android:supportsRtl="true"
1111
        android:theme="@style/AppTheme">
12-
        <activity android:name=".AboutActivity"></activity>
12+
        <activity android:name=".DictionaryDownloadActivity"></activity>
13+
        <activity android:name=".AboutActivity" />
1314
        <activity
1415
            android:name=".DictionaryActivity"
1516
            android:label="@string/title_activity_dictionary"

2627
        </activity>
2728
    </application>
2829
30+
    <uses-permission android:name="android.permission.INTERNET" />
31+
2932
</manifest>
2932=
3033=
\ No newline at end of file

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

11
package eu.lepiller.nani;
22
3+
import android.content.Intent;
34
import android.os.Bundle;
4-
import android.support.design.widget.FloatingActionButton;
5-
import android.support.design.widget.Snackbar;
65
import android.support.v7.app.AppCompatActivity;
76
import android.support.v7.widget.Toolbar;
87
import android.view.View;
8+
import android.widget.AdapterView;
99
import android.widget.ListView;
1010
11+
import java.util.ArrayList;
12+
1113
import eu.lepiller.nani.dictionary.DictionariesAdapter;
1214
import eu.lepiller.nani.dictionary.DictionaryFactory;
15+
import eu.lepiller.nani.dictionary.Dictionary;
1316
1417
public class DictionaryActivity extends AppCompatActivity {
1518

1821
        super.onCreate(savedInstanceState);
1922
        setContentView(R.layout.activity_dictionary);
2023
        Toolbar toolbar = findViewById(R.id.toolbar);
24+
        toolbar.setTitle(R.string.title_activity_dictionary);
2125
        setSupportActionBar(toolbar);
2226
2327
        ListView list_view = findViewById(R.id.dictionary_view);
24-
        list_view.setAdapter(new DictionariesAdapter(getApplicationContext(), DictionaryFactory.getDictionnaries(getApplicationContext())));
28+
        final ArrayList<Dictionary> dictionaries = DictionaryFactory.getDictionnaries(getApplicationContext());
29+
        list_view.setAdapter(new DictionariesAdapter(getApplicationContext(), dictionaries));
30+
31+
        list_view.setOnItemClickListener(new AdapterView.OnItemClickListener() {
32+
            @Override
33+
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
34+
                Intent intent = new Intent(DictionaryActivity.this, DictionaryDownloadActivity.class);
35+
                intent.putExtra("dico", position);
36+
                startActivity(intent);
37+
            }
38+
        });
2539
    }
2640
2741
}

app/src/main/java/eu/lepiller/nani/DictionaryDownloadActivity.java unknown status 1

1+
package eu.lepiller.nani;
2+
3+
import android.content.Context;
4+
import android.graphics.drawable.Drawable;
5+
import android.os.AsyncTask;
6+
import android.os.Build;
7+
import android.support.graphics.drawable.VectorDrawableCompat;
8+
import android.support.v7.app.AppCompatActivity;
9+
import android.os.Bundle;
10+
import android.util.Log;
11+
import android.view.View;
12+
import android.widget.ImageView;
13+
import android.widget.LinearLayout;
14+
import android.widget.ProgressBar;
15+
import android.widget.TextView;
16+
17+
import java.io.File;
18+
import java.io.FileOutputStream;
19+
import java.io.IOException;
20+
import java.io.InputStream;
21+
import java.io.OutputStream;
22+
import java.net.HttpURLConnection;
23+
import java.net.URL;
24+
import java.util.Map;
25+
26+
import eu.lepiller.nani.dictionary.Dictionary;
27+
import eu.lepiller.nani.dictionary.DictionaryFactory;
28+
29+
public class DictionaryDownloadActivity extends AppCompatActivity {
30+
    final static String TAG = "DWN";
31+
32+
    ProgressBar download_bar;
33+
34+
    @Override
35+
    protected void onCreate(Bundle savedInstanceState) {
36+
        super.onCreate(savedInstanceState);
37+
        setContentView(R.layout.activity_dictionary_download);
38+
39+
        int position = getIntent().getExtras().getInt("dico");
40+
41+
        final Dictionary d = DictionaryFactory.get(position);
42+
        updateLayout(d);
43+
    }
44+
45+
    private void updateLayout(final Dictionary d) {
46+
        TextView name_view = findViewById(R.id.name_view);
47+
        name_view.setText(d.getName());
48+
49+
        TextView description_view = findViewById(R.id.description_view);
50+
        description_view.setText(d.getDescription());
51+
52+
        download_bar = findViewById(R.id.download_progress);
53+
        download_bar.setProgress(0);
54+
55+
        ImageView icon_view = findViewById(R.id.icon_view);
56+
        Drawable icon = d.getDrawable(getApplicationContext());
57+
        if (icon != null) {
58+
            icon_view.setImageDrawable(icon);
59+
        }
60+
61+
        Drawable drawable;
62+
        int drawableResId = d.isDownloaded() ? R.drawable.ic_nani_refresh : R.drawable.ic_nani_download;
63+
        if (android.os.Build.VERSION.SDK_INT > Build.VERSION_CODES.M) {
64+
            drawable = getResources().getDrawable(drawableResId, getTheme());
65+
        } else {
66+
            drawable = VectorDrawableCompat.create(getResources(), drawableResId, getTheme());
67+
        }
68+
        final ImageView download_button = findViewById(R.id.download_button);
69+
        download_button.setImageDrawable(drawable);
70+
        download_button.setEnabled(true);
71+
72+
        drawableResId = R.drawable.ic_nani_trash;
73+
        if (android.os.Build.VERSION.SDK_INT > Build.VERSION_CODES.M) {
74+
            drawable = getResources().getDrawable(drawableResId, getTheme());
75+
        } else {
76+
            drawable = VectorDrawableCompat.create(getResources(), drawableResId, getTheme());
77+
        }
78+
        ImageView trash_button = findViewById(R.id.remove_button);
79+
        trash_button.setImageDrawable(drawable);
80+
81+
        LinearLayout remove_layout = findViewById(R.id.remove_layout);
82+
        remove_layout.setVisibility(d.isDownloaded()? View.VISIBLE: View.INVISIBLE);
83+
84+
        download_button.setOnClickListener(new View.OnClickListener() {
85+
            @Override
86+
            public void onClick(View v) {
87+
                download_button.setEnabled(false);
88+
                final DownloadTask downloadTask = new DownloadTask(DictionaryDownloadActivity.this);
89+
                downloadTask.execute(d);
90+
            }
91+
        });
92+
93+
        trash_button.setOnClickListener(new View.OnClickListener() {
94+
            @Override
95+
            public void onClick(View v) {
96+
                d.remove();
97+
                updateLayout(d);
98+
            }
99+
        });
100+
    }
101+
102+
    private class DownloadTask extends AsyncTask<Dictionary, Integer, String> {
103+
        private Dictionary d;
104+
        private Context context;
105+
106+
        public DownloadTask(Context context) {
107+
            this.context = context;
108+
        }
109+
110+
        @Override
111+
        protected String doInBackground(Dictionary... sDicos) {
112+
            InputStream input = null;
113+
            OutputStream output = null;
114+
            HttpURLConnection connection = null;
115+
            d = sDicos[0];
116+
117+
            Log.d(TAG, "Start downloading");
118+
119+
            for (Map.Entry<URL, File> e : d.getDownloads().entrySet()) {
120+
                try {
121+
                    URL url = e.getKey();
122+
                    Log.d(TAG, "URL: " + url.toString());
123+
                    connection = (HttpURLConnection) url.openConnection();
124+
                    connection.connect();
125+
126+
                    // expect HTTP 200 OK, so we don't mistakenly save error report
127+
                    // instead of the file
128+
                    if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) {
129+
                        Log.e(TAG, "Server returned HTTP " + connection.getResponseCode()
130+
                                + " " + connection.getResponseMessage());
131+
                        return "Server returned HTTP " + connection.getResponseCode()
132+
                                + " " + connection.getResponseMessage();
133+
                    }
134+
135+
                    // this will be useful to display download percentage
136+
                    // might be -1: server did not report the length
137+
                    int fileLength = connection.getContentLength();
138+
139+
                    // download the file
140+
                    input = connection.getInputStream();
141+
                    File file = e.getValue();
142+
                    file.getParentFile().mkdirs();
143+
                    output = new FileOutputStream(file);
144+
145+
                    byte data[] = new byte[4096];
146+
                    long total = 0;
147+
                    int count;
148+
                    while ((count = input.read(data)) != -1) {
149+
                        // allow canceling with back button
150+
                        if (isCancelled()) {
151+
                            input.close();
152+
                            return null;
153+
                        }
154+
                        total += count;
155+
                        // publishing the progress....
156+
                        if (fileLength > 0) // only if total length is known
157+
                            publishProgress((int) (total * 100 / fileLength));
158+
                        output.write(data, 0, count);
159+
                    }
160+
                } catch (Exception ex) {
161+
                    Log.e(TAG, ex.toString());
162+
                    return ex.toString();
163+
                } finally {
164+
                    try {
165+
                        if (output != null)
166+
                            output.close();
167+
                        if (input != null)
168+
                            input.close();
169+
                    } catch (IOException ignored) {
170+
                    }
171+
172+
                    if (connection != null)
173+
                        connection.disconnect();
174+
                }
175+
            }
176+
            return null;
177+
        }
178+
179+
        @Override
180+
        protected void onPreExecute() {
181+
            super.onPreExecute();
182+
            download_bar.setIndeterminate(true);
183+
        }
184+
185+
        @Override
186+
        protected void onProgressUpdate(Integer... progress) {
187+
            super.onProgressUpdate(progress);
188+
            // if we get here, length is known, now set indeterminate to false
189+
            download_bar.setIndeterminate(false);
190+
            download_bar.setMax(100);
191+
            download_bar.setProgress(progress[0]);
192+
        }
193+
194+
195+
        @Override
196+
        protected void onPostExecute(String result) {
197+
            download_bar.setProgress(100);
198+
            updateLayout(d);
199+
        }
200+
    }
201+
}

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

5757
            Intent intent = new Intent(this, DictionaryActivity.class);
5858
            startActivity(intent);
5959
            return true;
60+
        } else if (id == R.id.action_about) {
61+
            Intent intent = new Intent(this, AboutActivity.class);
62+
            startActivity(intent);
63+
            return true;
6064
        }
6165
6266
        return super.onOptionsItemSelected(item);

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

3939
        }
4040
4141
        // Lookup view for data population
42-
        ImageButton download_button = (ImageButton) convertView.findViewById(R.id.download_button);
4342
        ImageView icon_view = (ImageView) convertView.findViewById(R.id.icon_view);
4443
        TextView name_view = (TextView) convertView.findViewById(R.id.name_view);
4544
        TextView description_view = (TextView) convertView.findViewById(R.id.description_view);
46-
        ProgressBar download_progress = (ProgressBar) convertView.findViewById(R.id.download_progress);
4745
4846
        // Populate the data into the template view using the data object
4947
        Drawable icon = dictionary.getDrawable(context);

5351
5452
        name_view.setText(dictionary.getName());
5553
        description_view.setText(dictionary.getDescription());
56-
        download_progress.setProgress(dictionary.currentSize() * 100 / dictionary.size());
57-
58-
        Drawable drawable;
59-
        int drawableResId = dictionary.isDownloaded()? R.drawable.ic_nani_trash: R.drawable.ic_nani_download;
60-
61-
        if (android.os.Build.VERSION.SDK_INT > Build.VERSION_CODES.M) {
62-
            drawable = context.getResources().getDrawable(drawableResId, context.getTheme());
63-
        } else {
64-
            drawable = VectorDrawableCompat.create(context.getResources(), drawableResId, context.getTheme());
65-
        }
66-
67-
        download_button.setImageDrawable(drawable);
6854
6955
        // Return the completed view to render on screen
7056
        return convertView;

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

66
import android.support.graphics.drawable.VectorDrawableCompat;
77
88
import java.io.File;
9+
import java.net.MalformedURLException;
10+
import java.net.URL;
11+
import java.util.Map;
912
10-
abstract class Dictionary {
13+
abstract public class Dictionary {
1114
    private String name;
1215
    private String description;
1316
    File file;

1821
        this.file = new File(cacheDir, "/dico/" + name);
1922
    }
2023
21-
    String getName() {
24+
    public String getName() {
2225
        return name;
2326
    }
2427
25-
    String getDescription() {
28+
    public String getDescription() {
2629
        return description;
2730
    }
2831
29-
    abstract boolean isDownloaded();
32+
    protected File getFile() {
33+
        return file;
34+
    }
35+
36+
    abstract public boolean isDownloaded();
3037
31-
    abstract int size();
38+
    abstract public int size();
3239
3340
    // Used for downloads: tells what siwe we currently have downloaded
3441
    abstract int currentSize();
3542
36-
    abstract void download();
43+
    public abstract Map<URL, File> getDownloads();
3744
38-
    Drawable getDrawable(Context context) {
45+
    public Drawable getDrawable(Context context) {
3946
        Drawable drawable;
4047
        int drawableResId = getDrawableId();
4148
        if (android.os.Build.VERSION.SDK_INT > Build.VERSION_CODES.M) {

4855
4956
    abstract int getDrawableId();
5057
51-
    abstract void remove();
58+
    abstract public void remove();
5259
}

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

1111
    private static ArrayList<Dictionary> dictionaries;
1212
1313
    private DictionaryFactory(Context context) {
14-
        dictionaries.add(new JMDict("edict_sub",
15-
                context.getString(R.string.dico_edict_sub),
14+
        dictionaries = new ArrayList<>();
15+
        dictionaries.add(new JMDict("example_jmdict",
16+
                context.getString(R.string.dico_example),
1617
                context.getCacheDir(),
17-
                "https://xana.lepiller.eu/nani/dico/edict_sub.gz"));
18+
                "https://xana.lepiller.eu/nani/dico/example_jmdict"));
19+
20+
        dictionaries.add(new JMDict("example_jmdict",
21+
                context.getString(R.string.dico_example),
22+
                context.getCacheDir(),
23+
                "https://xana.lepiller.eu/nani/dico/example_jmdict"));
24+
25+
        dictionaries.add(new JMDict("example_jmdict",
26+
                context.getString(R.string.dico_example),
27+
                context.getCacheDir(),
28+
                "https://xana.lepiller.eu/nani/dico/example_jmdict"));
29+
    }
30+
31+
    public static Dictionary get(int position) {
32+
        return dictionaries.get(position);
1833
    }
1934
2035
    public static ArrayList<Dictionary> getDictionnaries(Context context) {

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

11
package eu.lepiller.nani.dictionary;
22
33
import java.io.File;
4+
import java.net.MalformedURLException;
5+
import java.net.URL;
6+
import java.util.HashMap;
7+
import java.util.Map;
48
59
import eu.lepiller.nani.R;
610
711
public class JMDict extends Dictionary {
812
    private String mUrl;
913
10-
    public JMDict(String name, String description, File cacheDir, String url) {
14+
    JMDict(String name, String description, File cacheDir, String url) {
1115
        super(name, description, cacheDir);
1216
        mUrl = url;
1317
    }
1418
1519
    @Override
16-
    boolean isDownloaded() {
17-
        return false;
20+
    public boolean isDownloaded() {
21+
        File f = getFile();
22+
        return f.exists();
1823
    }
1924
2025
    @Override
21-
    int size() {
26+
    public int size() {
2227
        return 1;
2328
    }
2429

2833
    }
2934
3035
    @Override
31-
    void download() {
32-
36+
    public Map<URL, File> getDownloads() {
37+
        HashMap<URL, File> result = new HashMap<>();
38+
        try {
39+
            result.put(new URL(mUrl), getFile());
40+
        } catch (MalformedURLException e) {
41+
            e.printStackTrace();
42+
        }
43+
        return result;
3344
    }
3445
3546
    @Override

3849
    }
3950
4051
    @Override
41-
    void remove() {
42-
52+
    public void remove() {
53+
        File file = getFile();
54+
        file.delete();
4355
    }
4456
}

app/src/main/res/drawable/ic_nani_refresh.xml unknown status 1

1+
<vector android:height="24dp" android:viewportHeight="115"
2+
    android:viewportWidth="115" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
3+
    <path android:fillColor="#00000000"
4+
        android:pathData="M26.44,95.149A40,40 0,0 1,7.47 47.684,40 40,0 0,1 50.649,20.326a40,40 0,0 1,34.816 37.426"
5+
        android:strokeColor="#000000" android:strokeLineCap="round" android:strokeWidth="10"/>
6+
    <path android:fillColor="#00000000"
7+
        android:pathData="m50.819,51.492 l34.645,6.259 23.941,-25.914"
8+
        android:strokeAlpha="1" android:strokeColor="#000000"
9+
        android:strokeLineCap="round" android:strokeLineJoin="round" android:strokeWidth="10"/>
10+
</vector>

app/src/main/res/layout/activity_about.xml

11
<?xml version="1.0" encoding="utf-8"?>
2-
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
2+
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
33
    xmlns:app="http://schemas.android.com/apk/res-auto"
44
    xmlns:tools="http://schemas.android.com/tools"
55
    android:layout_width="match_parent"
66
    android:layout_height="match_parent"
77
    tools:context=".AboutActivity">
88
9-
    <TextView
10-
        android:id="@+id/textView"
11-
        android:layout_width="wrap_content"
12-
        android:layout_height="wrap_content"
13-
        android:layout_marginStart="8dp"
14-
        android:layout_marginLeft="8dp"
15-
        android:layout_marginEnd="8dp"
16-
        android:layout_marginRight="8dp"
17-
        android:text="@string/nani_about"
18-
        android:textColor="@color/colorPrimary"
19-
        app:layout_constraintEnd_toEndOf="parent"
20-
        app:layout_constraintStart_toStartOf="parent"
21-
        app:layout_constraintTop_toBottomOf="@+id/textView5" />
22-
23-
    <TextView
24-
        android:id="@+id/textView2"
25-
        android:layout_width="wrap_content"
9+
    <android.support.constraint.ConstraintLayout
10+
        android:layout_width="match_parent"
2611
        android:layout_height="wrap_content"
27-
        android:layout_marginStart="8dp"
28-
        android:layout_marginLeft="8dp"
29-
        android:layout_marginTop="16dp"
30-
        android:layout_marginEnd="8dp"
31-
        android:layout_marginRight="8dp"
32-
        android:text="@string/license"
33-
        android:textColor="@color/colorPrimaryDark"
34-
        android:textSize="@dimen/title_size"
35-
        app:layout_constraintEnd_toEndOf="parent"
36-
        app:layout_constraintStart_toStartOf="parent"
37-
        app:layout_constraintTop_toBottomOf="@+id/textView" />
12+
        android:layout_margin="8dp">
3813
39-
    <TextView
40-
        android:id="@+id/textView3"
41-
        android:layout_width="wrap_content"
42-
        android:layout_height="wrap_content"
43-
        android:layout_marginStart="8dp"
44-
        android:layout_marginLeft="8dp"
45-
        android:layout_marginTop="8dp"
46-
        android:layout_marginEnd="8dp"
47-
        android:layout_marginRight="8dp"
48-
        android:text="@string/license_text"
49-
        android:textColor="@color/colorPrimary"
50-
        app:layout_constraintEnd_toEndOf="parent"
51-
        app:layout_constraintStart_toStartOf="parent"
52-
        app:layout_constraintTop_toBottomOf="@+id/textView2" />
14+
        <TextView
15+
            android:id="@+id/textView6"
16+
            android:layout_width="wrap_content"
17+
            android:layout_height="wrap_content"
18+
            android:layout_marginStart="8dp"
19+
            android:layout_marginLeft="8dp"
20+
            android:layout_marginTop="8dp"
21+
            android:layout_marginEnd="8dp"
22+
            android:layout_marginRight="8dp"
23+
            android:text="@string/data_licenses"
24+
            android:textColor="@color/colorPrimaryDark"
25+
            android:textSize="@dimen/title_size"
26+
            app:layout_constraintEnd_toEndOf="parent"
27+
            app:layout_constraintStart_toStartOf="parent"
28+
            app:layout_constraintTop_toBottomOf="@+id/linearLayout" />
5329
54-
    <LinearLayout
55-
        android:id="@+id/linearLayout"
56-
        android:layout_width="match_parent"
57-
        android:layout_height="wrap_content"
58-
        android:layout_marginStart="8dp"
59-
        android:layout_marginLeft="8dp"
60-
        android:layout_marginTop="16dp"
61-
        android:layout_marginEnd="8dp"
62-
        android:layout_marginRight="8dp"
63-
        android:orientation="horizontal"
64-
        app:layout_constraintEnd_toEndOf="parent"
65-
        app:layout_constraintStart_toStartOf="parent"
66-
        app:layout_constraintTop_toBottomOf="@+id/textView3">
30+
        <TextView
31+
            android:id="@+id/textView5"
32+
            android:layout_width="wrap_content"
33+
            android:layout_height="wrap_content"
34+
            android:layout_marginStart="8dp"
35+
            android:layout_marginLeft="8dp"
36+
            android:layout_marginTop="8dp"
37+
            android:layout_marginEnd="8dp"
38+
            android:layout_marginRight="8dp"
39+
            android:text="@string/action_about"
40+
            android:textColor="@color/colorPrimaryDark"
41+
            android:textSize="@dimen/title_size"
42+
            app:layout_constraintEnd_toEndOf="parent"
43+
            app:layout_constraintStart_toStartOf="parent"
44+
            app:layout_constraintTop_toTopOf="parent" />
6745
68-
        <Button
69-
            android:id="@+id/report_button"
46+
        <TextView
47+
            android:id="@+id/textView4"
7048
            android:layout_width="wrap_content"
7149
            android:layout_height="wrap_content"
50+
            android:layout_marginStart="8dp"
51+
            android:layout_marginLeft="8dp"
52+
            android:layout_marginTop="8dp"
53+
            android:layout_marginEnd="8dp"
7254
            android:layout_marginRight="8dp"
73-
            android:layout_weight="1"
74-
            android:background="@color/colorAccent"
75-
            android:text="@string/report"
76-
            android:textColor="@color/colorGrey" />
55+
            android:text="@string/data_intro"
56+
            android:textColor="@color/colorPrimary"
57+
            app:layout_constraintEnd_toEndOf="parent"
58+
            app:layout_constraintStart_toStartOf="parent"
59+
            app:layout_constraintTop_toBottomOf="@+id/textView6" />
7760
78-
        <Button
79-
            android:id="@+id/sources_button"
61+
        <LinearLayout
62+
            android:id="@+id/linearLayout"
63+
            android:layout_width="match_parent"
64+
            android:layout_height="wrap_content"
65+
            android:layout_marginStart="8dp"
66+
            android:layout_marginLeft="8dp"
67+
            android:layout_marginTop="16dp"
68+
            android:layout_marginEnd="8dp"
69+
            android:layout_marginRight="8dp"
70+
            android:orientation="horizontal"
71+
            app:layout_constraintEnd_toEndOf="parent"
72+
            app:layout_constraintStart_toStartOf="parent"
73+
            app:layout_constraintTop_toBottomOf="@+id/textView3">
74+
75+
            <Button
76+
                android:id="@+id/report_button"
77+
                android:layout_width="wrap_content"
78+
                android:layout_height="wrap_content"
79+
                android:layout_marginRight="8dp"
80+
                android:layout_weight="1"
81+
                android:background="@color/colorAccent"
82+
                android:text="@string/report"
83+
                android:textColor="@color/colorGrey" />
84+
85+
            <Button
86+
                android:id="@+id/sources_button"
87+
                android:layout_width="wrap_content"
88+
                android:layout_height="wrap_content"
89+
                android:layout_marginLeft="8dp"
90+
                android:layout_weight="1"
91+
                android:background="@color/colorAccent"
92+
                android:text="@string/view_source"
93+
                android:textColor="@color/colorGrey" />
94+
        </LinearLayout>
95+
96+
        <TextView
97+
            android:id="@+id/textView3"
8098
            android:layout_width="wrap_content"
8199
            android:layout_height="wrap_content"
100+
            android:layout_marginStart="8dp"
82101
            android:layout_marginLeft="8dp"
83-
            android:layout_weight="1"
84-
            android:background="@color/colorAccent"
85-
            android:text="@string/view_source"
86-
            android:textColor="@color/colorGrey" />
87-
    </LinearLayout>
102+
            android:layout_marginTop="8dp"
103+
            android:layout_marginEnd="8dp"
104+
            android:layout_marginRight="8dp"
105+
            android:text="@string/license_text"
106+
            android:textColor="@color/colorPrimary"
107+
            app:layout_constraintEnd_toEndOf="parent"
108+
            app:layout_constraintStart_toStartOf="parent"
109+
            app:layout_constraintTop_toBottomOf="@+id/textView2" />
88110
89-
    <TextView
90-
        android:id="@+id/textView4"
91-
        android:layout_width="wrap_content"
92-
        android:layout_height="wrap_content"
93-
        android:layout_marginStart="8dp"
94-
        android:layout_marginLeft="8dp"
95-
        android:layout_marginTop="8dp"
96-
        android:layout_marginEnd="8dp"
97-
        android:layout_marginRight="8dp"
98-
        android:text="TextView"
99-
        android:textColor="@color/colorPrimary"
100-
        app:layout_constraintEnd_toEndOf="parent"
101-
        app:layout_constraintStart_toStartOf="parent"
102-
        app:layout_constraintTop_toBottomOf="@+id/textView6"
103-
        tools:text="@string/data_intro" />
111+
        <TextView
112+
            android:id="@+id/textView2"
113+
            android:layout_width="wrap_content"
114+
            android:layout_height="wrap_content"
115+
            android:layout_marginStart="8dp"
116+
            android:layout_marginLeft="8dp"
117+
            android:layout_marginTop="16dp"
118+
            android:layout_marginEnd="8dp"
119+
            android:layout_marginRight="8dp"
120+
            android:text="@string/license"
121+
            android:textColor="@color/colorPrimaryDark"
122+
            android:textSize="@dimen/title_size"
123+
            app:layout_constraintEnd_toEndOf="parent"
124+
            app:layout_constraintStart_toStartOf="parent"
125+
            app:layout_constraintTop_toBottomOf="@+id/textView" />
104126
105-
    <TextView
106-
        android:id="@+id/textView5"
107-
        android:layout_width="wrap_content"
108-
        android:layout_height="wrap_content"
109-
        android:layout_marginStart="8dp"
110-
        android:layout_marginLeft="8dp"
111-
        android:layout_marginTop="8dp"
112-
        android:layout_marginEnd="8dp"
113-
        android:layout_marginRight="8dp"
114-
        android:text="TextView"
115-
        android:textColor="@color/colorPrimaryDark"
116-
        android:textSize="@dimen/title_size"
117-
        app:layout_constraintEnd_toEndOf="parent"
118-
        app:layout_constraintStart_toStartOf="parent"
119-
        app:layout_constraintTop_toTopOf="parent"
120-
        tools:text="@string/action_about" />
127+
        <TextView
128+
            android:id="@+id/textView"
129+
            android:layout_width="wrap_content"
130+
            android:layout_height="wrap_content"
131+
            android:layout_marginStart="8dp"
132+
            android:layout_marginLeft="8dp"
133+
            android:layout_marginEnd="8dp"
134+
            android:layout_marginRight="8dp"
135+
            android:text="@string/nani_about"
136+
            android:textColor="@color/colorPrimary"
137+
            app:layout_constraintEnd_toEndOf="parent"
138+
            app:layout_constraintStart_toStartOf="parent"
139+
            app:layout_constraintTop_toBottomOf="@+id/textView5" />
140+
    </android.support.constraint.ConstraintLayout>
121141
122-
    <TextView
123-
        android:id="@+id/textView6"
124-
        android:layout_width="wrap_content"
125-
        android:layout_height="wrap_content"
126-
        android:layout_marginStart="8dp"
127-
        android:layout_marginLeft="8dp"
128-
        android:layout_marginTop="8dp"
129-
        android:layout_marginEnd="8dp"
130-
        android:layout_marginRight="8dp"
131-
        android:text="TextView"
132-
        android:textColor="@color/colorPrimaryDark"
133-
        android:textSize="@dimen/title_size"
134-
        app:layout_constraintEnd_toEndOf="parent"
135-
        app:layout_constraintStart_toStartOf="parent"
136-
        app:layout_constraintTop_toBottomOf="@+id/linearLayout"
137-
        tools:text="@string/data_licenses" />
138-
</android.support.constraint.ConstraintLayout>
138>
1390>
\ No newline at end of file
142+
</ScrollView>
142<
0143<
\ No newline at end of file

app/src/main/res/layout/activity_dictionary_download.xml unknown status 1

1+
<?xml version="1.0" encoding="utf-8"?>
2+
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
3+
    xmlns:app="http://schemas.android.com/apk/res-auto"
4+
    xmlns:tools="http://schemas.android.com/tools"
5+
    android:layout_width="match_parent"
6+
    android:layout_height="match_parent"
7+
    tools:context=".DictionaryDownloadActivity">
8+
9+
    <LinearLayout
10+
        android:id="@+id/linearLayout2"
11+
        android:layout_width="match_parent"
12+
        android:layout_height="wrap_content"
13+
        android:layout_marginStart="8dp"
14+
        android:layout_marginLeft="8dp"
15+
        android:layout_marginTop="8dp"
16+
        android:layout_marginEnd="8dp"
17+
        android:layout_marginRight="8dp"
18+
        android:orientation="horizontal"
19+
        app:layout_constraintEnd_toEndOf="parent"
20+
        app:layout_constraintStart_toStartOf="parent"
21+
        app:layout_constraintTop_toTopOf="parent">
22+
23+
        <ImageView
24+
            android:id="@+id/icon_view"
25+
            android:layout_width="wrap_content"
26+
            android:layout_height="wrap_content"
27+
            android:layout_weight="0"
28+
            app:srcCompat="@android:drawable/ic_menu_close_clear_cancel" />
29+
30+
        <TextView
31+
            android:id="@+id/name_view"
32+
            android:layout_width="wrap_content"
33+
            android:layout_height="wrap_content"
34+
            android:layout_margin="8dp"
35+
            android:layout_weight="1"
36+
            android:text="Name" />
37+
38+
    </LinearLayout>
39+
40+
    <TextView
41+
        android:id="@+id/description_view"
42+
        android:layout_width="wrap_content"
43+
        android:layout_height="wrap_content"
44+
        android:layout_margin="8dp"
45+
        android:layout_marginStart="8dp"
46+
        android:layout_marginLeft="8dp"
47+
        android:layout_marginTop="8dp"
48+
        android:layout_marginEnd="8dp"
49+
        android:layout_marginRight="8dp"
50+
        android:text="Description"
51+
        app:layout_constraintEnd_toEndOf="parent"
52+
        app:layout_constraintStart_toStartOf="parent"
53+
        app:layout_constraintTop_toBottomOf="@+id/linearLayout2" />
54+
55+
    <LinearLayout
56+
        android:id="@+id/linearLayout3"
57+
        android:layout_width="match_parent"
58+
        android:layout_height="wrap_content"
59+
        android:layout_marginStart="8dp"
60+
        android:layout_marginLeft="8dp"
61+
        android:layout_marginTop="8dp"
62+
        android:layout_marginEnd="8dp"
63+
        android:layout_marginRight="8dp"
64+
        android:orientation="horizontal"
65+
        app:layout_constraintEnd_toEndOf="parent"
66+
        app:layout_constraintStart_toStartOf="parent"
67+
        app:layout_constraintTop_toBottomOf="@+id/description_view">
68+
69+
        <ProgressBar
70+
            android:id="@+id/download_progress"
71+
            style="?android:attr/progressBarStyleHorizontal"
72+
            android:layout_width="wrap_content"
73+
            android:layout_height="wrap_content"
74+
            android:layout_gravity="center"
75+
            android:layout_margin="8dp"
76+
            android:layout_weight="1" />
77+
78+
        <ImageButton
79+
            android:id="@+id/download_button"
80+
            android:layout_width="wrap_content"
81+
            android:layout_height="wrap_content"
82+
            android:layout_gravity="center"
83+
            android:layout_margin="8dp"
84+
            android:layout_weight="0"
85+
            android:background="#00ffffff"
86+
            app:srcCompat="@android:drawable/arrow_down_float" />
87+
    </LinearLayout>
88+
89+
    <LinearLayout
90+
        android:id="@+id/remove_layout"
91+
        android:layout_width="match_parent"
92+
        android:layout_height="wrap_content"
93+
        android:orientation="horizontal"
94+
        app:layout_constraintTop_toBottomOf="@+id/linearLayout3"
95+
        tools:layout_editor_absoluteX="8dp">
96+
97+
        <TextView
98+
            android:id="@+id/size_view"
99+
            android:layout_width="wrap_content"
100+
            android:layout_height="wrap_content"
101+
            android:layout_margin="8dp"
102+
            android:layout_marginTop="8dp"
103+
            android:layout_marginBottom="8dp"
104+
            android:layout_weight="1"
105+
            android:text="TextView" />
106+
107+
        <ImageButton
108+
            android:id="@+id/remove_button"
109+
            android:layout_width="wrap_content"
110+
            android:layout_height="wrap_content"
111+
            android:layout_margin="8dp"
112+
            android:layout_weight="0"
113+
            app:srcCompat="@android:drawable/arrow_down_float" />
114+
    </LinearLayout>
115+
116+
</android.support.constraint.ConstraintLayout>
116<
0117<
\ No newline at end of file

app/src/main/res/layout/content_dictionary.xml

1414
        android:layout_height="659dp"
1515
        android:layout_marginStart="8dp"
1616
        android:layout_marginLeft="8dp"
17-
        android:layout_marginTop="8dp"
17+
        android:layout_marginTop="32dp"
1818
        android:layout_marginEnd="8dp"
1919
        android:layout_marginRight="8dp"
2020
        android:layout_marginBottom="8dp"

app/src/main/res/layout/layout_dictionary.xml

11
<?xml version="1.0" encoding="utf-8"?>
2-
<android.support.constraint.ConstraintLayout
2+
<LinearLayout
33
    xmlns:android="http://schemas.android.com/apk/res/android"
44
    xmlns:app="http://schemas.android.com/apk/res-auto"
55
    xmlns:tools="http://schemas.android.com/tools"
66
    android:layout_width="match_parent"
7-
    android:layout_height="match_parent">
7+
    android:layout_height="wrap_content">
88
9-
    <LinearLayout
10-
        android:layout_width="match_parent"
11-
        android:layout_height="match_parent"
12-
        android:layout_marginTop="8dp"
13-
        android:orientation="horizontal"
14-
        app:layout_constraintTop_toTopOf="parent">
9+
    <ImageView
10+
        android:id="@+id/icon_view"
11+
        android:layout_width="64dp"
12+
        android:layout_height="64dp"
13+
        android:layout_gravity="center"
14+
        android:contentDescription="@string/icon_description"
15+
        android:layout_weight="0"
16+
        app:srcCompat="@android:drawable/ic_menu_close_clear_cancel" />
1517
16-
        <ImageView
17-
            android:id="@+id/icon_view"
18-
            android:layout_width="64dp"
19-
            android:layout_height="64dp"
18+
    <LinearLayout
19+
        android:layout_width="wrap_content"
20+
        android:layout_height="wrap_content"
21+
        android:layout_gravity="center"
22+
        android:layout_weight="100"
23+
        android:orientation="vertical">
24+
25+
        <TextView
26+
            android:id="@+id/name_view"
27+
            android:layout_width="match_parent"
28+
            android:layout_height="wrap_content"
2029
            android:layout_marginStart="8dp"
21-
            android:contentDescription="@string/icon_description"
22-
            app:layout_constraintStart_toStartOf="parent"
23-
            app:layout_constraintTop_toTopOf="parent"
24-
            app:srcCompat="@android:drawable/ic_menu_close_clear_cancel" />
25-
26-
        <LinearLayout
30+
            android:layout_marginLeft="8dp"
31+
            android:layout_marginTop="8dp"
32+
            android:layout_marginEnd="8dp"
33+
            android:layout_marginRight="8dp"
34+
            android:text="Name" />
35+
36+
        <TextView
37+
            android:id="@+id/description_view"
2738
            android:layout_width="match_parent"
2839
            android:layout_height="wrap_content"
29-
            android:layout_marginStart="78dp"
30-
            android:layout_marginEnd="78dp"
31-
            android:orientation="vertical"
32-
            app:layout_constraintEnd_toStartOf="@+id/download_button"
33-
            app:layout_constraintStart_toEndOf="@+id/icon_view"
34-
            app:layout_constraintTop_toTopOf="parent">
35-
36-
            <TextView
37-
                android:id="@+id/name_view"
38-
                android:layout_width="match_parent"
39-
                android:layout_height="wrap_content"
40-
                android:layout_marginStart="8dp"
41-
                android:layout_marginLeft="8dp"
42-
                android:layout_marginTop="8dp"
43-
                android:layout_marginEnd="8dp"
44-
                android:layout_marginRight="8dp"
45-
                android:text="Name"
46-
                app:layout_constraintTop_toTopOf="parent" />
47-
48-
            <TextView
49-
                android:id="@+id/description_view"
50-
                android:layout_width="match_parent"
51-
                android:layout_height="wrap_content"
52-
                android:layout_marginStart="8dp"
53-
                android:layout_marginLeft="8dp"
54-
                android:layout_marginTop="8dp"
55-
                android:layout_marginEnd="8dp"
56-
                android:layout_marginRight="8dp"
57-
                android:text="Description" />
58-
59-
            <ProgressBar
60-
                android:id="@+id/download_progress"
61-
                style="?android:attr/progressBarStyleHorizontal"
62-
                android:layout_width="match_parent"
63-
                android:layout_height="wrap_content"
64-
                android:layout_marginStart="8dp"
65-
                android:layout_marginLeft="8dp"
66-
                android:layout_marginTop="8dp"
67-
                android:layout_marginEnd="8dp"
68-
                android:layout_marginRight="8dp"
69-
                android:progress="0"
70-
                app:layout_constraintEnd_toStartOf="@+id/download_button"
71-
                app:layout_constraintStart_toEndOf="@+id/icon_view"
72-
                app:layout_constraintTop_toBottomOf="@+id/name_view" />
73-
74-
        </LinearLayout>
75-
76-
        <ImageButton
77-
            android:id="@+id/download_button"
78-
            android:layout_width="64dp"
79-
            android:layout_height="64dp"
80-
            android:contentDescription="@string/download"
81-
            app:layout_constraintEnd_toEndOf="parent"
82-
            app:layout_constraintTop_toTopOf="parent"
83-
            app:srcCompat="@android:drawable/ic_menu_close_clear_cancel" />
84-
40+
            android:layout_marginStart="8dp"
41+
            android:layout_marginLeft="8dp"
42+
            android:layout_marginTop="8dp"
43+
            android:layout_marginEnd="8dp"
44+
            android:layout_marginRight="8dp"
45+
            android:text="Description" />
8546
    </LinearLayout>
8647
87-
</android.support.constraint.ConstraintLayout>
87>
880>
\ No newline at end of file
48+
</LinearLayout>
48<
049<
\ No newline at end of file

app/src/main/res/values/dimens.xml

11
<resources>
22
    <dimen name="fab_margin">16dp</dimen>
3-
    <dimen name="title_size">32dp</dimen>
3+
    <dimen name="title_size">32sp</dimen>
44
</resources>

app/src/main/res/values/strings.xml

66
77
    <string name="search_hint">Search japanese word, kanji, meaning, ???</string>
88
    <string name="search_button">Search</string>
9-
    <string name="title_activity_dictionary">DictionaryActivity</string>
9+
    <string name="title_activity_dictionary">Dictionaries</string>
1010
1111
    <string name="download">Download</string>
1212
    <string name="remove">Remove</string>
1313
    <string name="icon_description">Icon</string>
1414
1515
    <!-- Dictionnary descriptions -->
16-
    <string name="dico_edict_sub">The Japanese-English reduced dictionnary from the
17-
        Electronic Dictionary Research and Development Group</string>
16+
    <string name="dico_example">An example dictionary with only an entry for ?????? (gathering up). Used in development.</string>
1817
1918
    <!-- About activity -->
2019
    <string name="nani_about">Hi, tyreunom here!\n