Refresh dictionary list on user action
app/build.gradle
21 | 21 | dependencies { | |
22 | 22 | implementation fileTree(dir: 'libs', include: ['*.jar']) | |
23 | 23 | implementation 'androidx.appcompat:appcompat:1.1.0' | |
24 | - | implementation 'androidx.preference:preference:1.1.1' | |
25 | 24 | 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" | |
27 | 28 | implementation 'com.andree-surya:moji4j:1.0.0' | |
28 | 29 | implementation 'com.google.android:flexbox:2.0.1' | |
30 | + | implementation 'com.google.android.material:material:1.1.0' | |
29 | 31 | implementation project(path: ':furiganatextview') | |
30 | - | implementation 'androidx.legacy:legacy-support-v4:1.0.0' | |
31 | 32 | testImplementation 'junit:junit:4.12' | |
32 | 33 | androidTestImplementation 'androidx.test.ext:junit:1.1.1' | |
33 | 34 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' |
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.os.AsyncTask; | |
4 | 5 | import android.os.Bundle; | |
5 | 6 | import androidx.appcompat.app.AppCompatActivity; | |
6 | 7 | import androidx.appcompat.widget.Toolbar; | |
8 | + | import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; | |
9 | + | ||
7 | 10 | import android.view.View; | |
8 | 11 | import android.widget.AdapterView; | |
9 | 12 | import android.widget.ListView; | |
10 | 13 | ||
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; | |
11 | 23 | import java.util.ArrayList; | |
12 | 24 | ||
13 | 25 | import eu.lepiller.nani.dictionary.DictionariesAdapter; | |
… | |||
39 | 51 | startActivityForResult(intent, DICO_REQUEST); | |
40 | 52 | } | |
41 | 53 | }); | |
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 | + | } | |
42 | 114 | } | |
43 | 115 | ||
44 | 116 | @Override | |
45 | 117 | 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) { | |
47 | 120 | adapter.notifyDataSetChanged(); | |
48 | 121 | } | |
49 | 122 | } |
app/src/main/java/eu/lepiller/nani/dictionary/DictionaryFactory.java
2 | 2 | ||
3 | 3 | import android.content.Context; | |
4 | 4 | ||
5 | + | import java.io.File; | |
6 | + | import java.net.MalformedURLException; | |
7 | + | import java.net.URL; | |
5 | 8 | import java.util.ArrayList; | |
6 | 9 | ||
7 | 10 | import eu.lepiller.nani.R; | |
… | |||
10 | 13 | public class DictionaryFactory { | |
11 | 14 | private static DictionaryFactory instance; | |
12 | 15 | private static ArrayList<Dictionary> dictionaries; | |
16 | + | private static File cacheDir; | |
13 | 17 | ||
14 | 18 | private DictionaryFactory(Context context) { | |
19 | + | cacheDir = context.getCacheDir(); | |
15 | 20 | dictionaries = new ArrayList<>(); | |
16 | 21 | dictionaries.add(new RadicalDict("RadK", | |
17 | 22 | context.getString(R.string.dico_radk), | |
18 | 23 | context.getString(R.string.dico_radk_long), | |
19 | - | context.getCacheDir(), | |
24 | + | cacheDir, | |
20 | 25 | "https://nani.lepiller.eu/dicos/radicals.nani")); | |
21 | 26 | dictionaries.add(new JMDict("JMdict_e", | |
22 | 27 | context.getString(R.string.dico_jmdict_e), | |
23 | 28 | context.getString(R.string.dico_jmdict_long), | |
24 | - | context.getCacheDir(), | |
29 | + | cacheDir, | |
25 | 30 | "https://nani.lepiller.eu/dicos/JMdict_e.nani")); | |
26 | 31 | dictionaries.add(new JMDict("JMdict_dut", | |
27 | 32 | context.getString(R.string.dico_jmdict_dut), | |
28 | 33 | context.getString(R.string.dico_jmdict_long), | |
29 | - | context.getCacheDir(), | |
34 | + | cacheDir, | |
30 | 35 | "https://nani.lepiller.eu/dicos/JMdict_dut.nani")); | |
31 | 36 | dictionaries.add(new JMDict("JMdict_fre", | |
32 | 37 | context.getString(R.string.dico_jmdict_fre), | |
33 | 38 | context.getString(R.string.dico_jmdict_long), | |
34 | - | context.getCacheDir(), | |
39 | + | cacheDir, | |
35 | 40 | "https://nani.lepiller.eu/dicos/JMdict_fre.nani")); | |
36 | 41 | dictionaries.add(new JMDict("JMdict_ger", | |
37 | 42 | context.getString(R.string.dico_jmdict_ger), | |
38 | 43 | context.getString(R.string.dico_jmdict_long), | |
39 | - | context.getCacheDir(), | |
44 | + | cacheDir, | |
40 | 45 | "https://nani.lepiller.eu/dicos/JMdict_ger.nani")); | |
41 | 46 | dictionaries.add(new JMDict("JMdict_hun", | |
42 | 47 | context.getString(R.string.dico_jmdict_hun), | |
43 | 48 | context.getString(R.string.dico_jmdict_long), | |
44 | - | context.getCacheDir(), | |
49 | + | cacheDir, | |
45 | 50 | "https://nani.lepiller.eu/dicos/JMdict_hun.nani")); | |
46 | 51 | dictionaries.add(new JMDict("JMdict_rus", | |
47 | 52 | context.getString(R.string.dico_jmdict_rus), | |
48 | 53 | context.getString(R.string.dico_jmdict_long), | |
49 | - | context.getCacheDir(), | |
54 | + | cacheDir, | |
50 | 55 | "https://nani.lepiller.eu/dicos/JMdict_rus.nani")); | |
51 | 56 | dictionaries.add(new JMDict("JMdict_slv", | |
52 | 57 | context.getString(R.string.dico_jmdict_slv), | |
53 | 58 | context.getString(R.string.dico_jmdict_long), | |
54 | - | context.getCacheDir(), | |
59 | + | cacheDir, | |
55 | 60 | "https://nani.lepiller.eu/dicos/JMdict_slv.nani")); | |
56 | 61 | dictionaries.add(new JMDict("JMdict_spa", | |
57 | 62 | context.getString(R.string.dico_jmdict_spa), | |
58 | 63 | context.getString(R.string.dico_jmdict_long), | |
59 | - | context.getCacheDir(), | |
64 | + | cacheDir, | |
60 | 65 | "https://nani.lepiller.eu/dicos/JMdict_spa.nani")); | |
61 | 66 | dictionaries.add(new JMDict("JMdict_swe", | |
62 | 67 | context.getString(R.string.dico_jmdict_swe), | |
63 | 68 | context.getString(R.string.dico_jmdict_long), | |
64 | - | context.getCacheDir(), | |
69 | + | cacheDir, | |
65 | 70 | "https://nani.lepiller.eu/dicos/JMdict_swe.nani")); | |
66 | 71 | } | |
67 | 72 | ||
… | |||
114 | 119 | ||
115 | 120 | throw new NoDictionaryException(); | |
116 | 121 | } | |
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 | + | } | |
117 | 130 | } |
app/src/main/res/layout/content_dictionary.xml
8 | 8 | tools:context=".DictionaryActivity" | |
9 | 9 | tools:showIn="@layout/activity_dictionary"> | |
10 | 10 | ||
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> | |
21 | 27 | </LinearLayout> | |
21 | 27 | = | |
22 | 28 | = | \ No newline at end of file |
app/src/main/res/values/strings.xml
57 | 57 | <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 | |
58 | 58 | to access the kanji selection by component view.</string> | |
59 | 59 | ||
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 | + | ||
60 | 64 | <!-- Result view --> | |
61 | 65 | <string name="sense_number">%d.</string> | |
62 | 66 | <string name="sense_separator">"; "</string> |