Refresh dictionary list on user action

Julien LepillerTue May 26 20:15:28+0200 2020

645a411

Refresh dictionary list on user action

app/build.gradle

2121
dependencies {
2222
    implementation fileTree(dir: 'libs', include: ['*.jar'])
2323
    implementation 'androidx.appcompat:appcompat:1.1.0'
24-
    implementation 'androidx.preference:preference:1.1.1'
2524
    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
26-
    implementation 'com.google.android.material:material:1.1.0'
25+
    implementation 'androidx.legacy:legacy-support-v4:1.0.0'
26+
    implementation 'androidx.preference:preference:1.1.1'
27+
    implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.0.0"
2728
    implementation 'com.andree-surya:moji4j:1.0.0'
2829
    implementation 'com.google.android:flexbox:2.0.1'
30+
    implementation 'com.google.android.material:material:1.1.0'
2931
    implementation project(path: ':furiganatextview')
30-
    implementation 'androidx.legacy:legacy-support-v4:1.0.0'
3132
    testImplementation 'junit:junit:4.12'
3233
    androidTestImplementation 'androidx.test.ext:junit:1.1.1'
3334
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'

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

11
package eu.lepiller.nani;
22
33
import android.content.Intent;
4+
import android.os.AsyncTask;
45
import android.os.Bundle;
56
import androidx.appcompat.app.AppCompatActivity;
67
import androidx.appcompat.widget.Toolbar;
8+
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
9+
710
import android.view.View;
811
import android.widget.AdapterView;
912
import android.widget.ListView;
1013
14+
import com.google.android.material.snackbar.Snackbar;
15+
16+
import java.io.File;
17+
import java.io.FileOutputStream;
18+
import java.io.IOException;
19+
import java.io.InputStream;
20+
import java.net.HttpURLConnection;
21+
import java.net.MalformedURLException;
22+
import java.net.URL;
1123
import java.util.ArrayList;
1224
1325
import eu.lepiller.nani.dictionary.DictionariesAdapter;

3951
                startActivityForResult(intent, DICO_REQUEST);
4052
            }
4153
        });
54+
55+
        final SwipeRefreshLayout refresher = findViewById(R.id.dictionary_refresh_layout);
56+
        refresher.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
57+
            @Override
58+
            public void onRefresh() {
59+
                new DownloadTask(refresher).execute();
60+
            }
61+
        });
62+
    }
63+
64+
    private class DownloadTask extends AsyncTask<String, Integer, Integer> {
65+
        private SwipeRefreshLayout refresher;
66+
67+
        DownloadTask(SwipeRefreshLayout r) {
68+
            refresher = r;
69+
        }
70+
71+
        @Override
72+
        protected Integer doInBackground(String... strings) {
73+
            try {
74+
                URL url = DictionaryFactory.getListUrl();
75+
                HttpURLConnection connection = (HttpURLConnection) url.openConnection();
76+
                connection.connect();
77+
                if(connection.getResponseCode() == HttpURLConnection.HTTP_OK) {
78+
                    InputStream input = connection.getInputStream();
79+
                    File file = DictionaryFactory.getListFile();
80+
                    file.getParentFile().mkdirs();
81+
                    int count = 0;
82+
                    byte[] data = new byte[4096];
83+
                    FileOutputStream output = new FileOutputStream(file);
84+
                    while((count = input.read(data)) != -1) {
85+
                        if (isCancelled()) {
86+
                            input.close();
87+
                            return null;
88+
                        }
89+
                        output.write(data, 0, count);
90+
                    }
91+
                } else {
92+
                    return R.string.error_dico_not_found;
93+
                }
94+
            } catch (MalformedURLException e) {
95+
                e.printStackTrace();
96+
                return R.string.error_dico_url;
97+
            } catch (IOException e) {
98+
                e.printStackTrace();
99+
                return R.string.error_dico_io;
100+
            }
101+
            return null;
102+
        }
103+
104+
        @Override
105+
        protected void onPostExecute(Integer i) {
106+
            super.onPostExecute(i);
107+
            refresher.setRefreshing(false);
108+
            adapter.notifyDataSetChanged();
109+
            if(i == null)
110+
                return;
111+
            Snackbar.make(findViewById(R.id.dictionary_view), getString(i),
112+
                    Snackbar.LENGTH_LONG).show();
113+
        }
42114
    }
43115
44116
    @Override
45117
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
46-
        if(requestCode == DICO_REQUEST) {
118+
        super.onActivityResult(requestCode, resultCode, data);
119+
        if (requestCode == DICO_REQUEST) {
47120
            adapter.notifyDataSetChanged();
48121
        }
49122
    }

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

22
33
import android.content.Context;
44
5+
import java.io.File;
6+
import java.net.MalformedURLException;
7+
import java.net.URL;
58
import java.util.ArrayList;
69
710
import eu.lepiller.nani.R;

1013
public class DictionaryFactory {
1114
    private static DictionaryFactory instance;
1215
    private static ArrayList<Dictionary> dictionaries;
16+
    private static File cacheDir;
1317
1418
    private DictionaryFactory(Context context) {
19+
        cacheDir = context.getCacheDir();
1520
        dictionaries = new ArrayList<>();
1621
        dictionaries.add(new RadicalDict("RadK",
1722
                context.getString(R.string.dico_radk),
1823
                context.getString(R.string.dico_radk_long),
19-
                context.getCacheDir(),
24+
                cacheDir,
2025
                "https://nani.lepiller.eu/dicos/radicals.nani"));
2126
        dictionaries.add(new JMDict("JMdict_e",
2227
                context.getString(R.string.dico_jmdict_e),
2328
                context.getString(R.string.dico_jmdict_long),
24-
                context.getCacheDir(),
29+
                cacheDir,
2530
                "https://nani.lepiller.eu/dicos/JMdict_e.nani"));
2631
        dictionaries.add(new JMDict("JMdict_dut",
2732
                context.getString(R.string.dico_jmdict_dut),
2833
                context.getString(R.string.dico_jmdict_long),
29-
                context.getCacheDir(),
34+
                cacheDir,
3035
                "https://nani.lepiller.eu/dicos/JMdict_dut.nani"));
3136
        dictionaries.add(new JMDict("JMdict_fre",
3237
                context.getString(R.string.dico_jmdict_fre),
3338
                context.getString(R.string.dico_jmdict_long),
34-
                context.getCacheDir(),
39+
                cacheDir,
3540
                "https://nani.lepiller.eu/dicos/JMdict_fre.nani"));
3641
        dictionaries.add(new JMDict("JMdict_ger",
3742
                context.getString(R.string.dico_jmdict_ger),
3843
                context.getString(R.string.dico_jmdict_long),
39-
                context.getCacheDir(),
44+
                cacheDir,
4045
                "https://nani.lepiller.eu/dicos/JMdict_ger.nani"));
4146
        dictionaries.add(new JMDict("JMdict_hun",
4247
                context.getString(R.string.dico_jmdict_hun),
4348
                context.getString(R.string.dico_jmdict_long),
44-
                context.getCacheDir(),
49+
                cacheDir,
4550
                "https://nani.lepiller.eu/dicos/JMdict_hun.nani"));
4651
        dictionaries.add(new JMDict("JMdict_rus",
4752
                context.getString(R.string.dico_jmdict_rus),
4853
                context.getString(R.string.dico_jmdict_long),
49-
                context.getCacheDir(),
54+
                cacheDir,
5055
                "https://nani.lepiller.eu/dicos/JMdict_rus.nani"));
5156
        dictionaries.add(new JMDict("JMdict_slv",
5257
                context.getString(R.string.dico_jmdict_slv),
5358
                context.getString(R.string.dico_jmdict_long),
54-
                context.getCacheDir(),
59+
                cacheDir,
5560
                "https://nani.lepiller.eu/dicos/JMdict_slv.nani"));
5661
        dictionaries.add(new JMDict("JMdict_spa",
5762
                context.getString(R.string.dico_jmdict_spa),
5863
                context.getString(R.string.dico_jmdict_long),
59-
                context.getCacheDir(),
64+
                cacheDir,
6065
                "https://nani.lepiller.eu/dicos/JMdict_spa.nani"));
6166
        dictionaries.add(new JMDict("JMdict_swe",
6267
                context.getString(R.string.dico_jmdict_swe),
6368
                context.getString(R.string.dico_jmdict_long),
64-
                context.getCacheDir(),
69+
                cacheDir,
6570
                "https://nani.lepiller.eu/dicos/JMdict_swe.nani"));
6671
    }
6772

114119
115120
        throw new NoDictionaryException();
116121
    }
122+
123+
    public static URL getListUrl() throws MalformedURLException {
124+
        return new URL("https://nani.lepiller.eu/dicos/list");
125+
    }
126+
127+
    public static File getListFile() {
128+
        return new File(cacheDir + "/list");
129+
    }
117130
}

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

88
    tools:context=".DictionaryActivity"
99
    tools:showIn="@layout/activity_dictionary">
1010
11-
    <ListView
12-
        android:id="@+id/dictionary_view"
13-
        android:layout_width="395dp"
14-
        android:layout_height="659dp"
15-
        android:layout_marginStart="8dp"
16-
        android:layout_marginLeft="8dp"
17-
        android:layout_marginTop="32dp"
18-
        android:layout_marginEnd="8dp"
19-
        android:layout_marginRight="8dp"
20-
        android:layout_marginBottom="8dp" />
11+
    <androidx.swiperefreshlayout.widget.SwipeRefreshLayout
12+
        android:layout_width="match_parent"
13+
        android:layout_height="wrap_content"
14+
        android:id="@+id/dictionary_refresh_layout">
15+
16+
        <ListView
17+
            android:id="@+id/dictionary_view"
18+
            android:layout_width="395dp"
19+
            android:layout_height="659dp"
20+
            android:layout_marginStart="8dp"
21+
            android:layout_marginLeft="8dp"
22+
            android:layout_marginTop="32dp"
23+
            android:layout_marginEnd="8dp"
24+
            android:layout_marginRight="8dp"
25+
            android:layout_marginBottom="8dp" />
26+
    </androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
2127
</LinearLayout>
2127=
2228=
\ No newline at end of file

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

5757
    <string name="dico_radk_long">This dictionary allows you to enter kanji by selecting some of its components.  Tap the water component button on the bottom of the screen
5858
    to access the kanji selection by component view.</string>
5959
60+
    <string name="error_dico_url">Error fetching dictionary list: malformed URL.</string>
61+
    <string name="error_dico_io">Error fetching dictionary list: cannot write to cache file.</string>
62+
    <string name="error_dico_not_found">Error fetching dictionary list: cannot find it on server.</string>
63+
6064
    <!-- Result view -->
6165
    <string name="sense_number">%d.</string>
6266
    <string name="sense_separator">"; "</string>