Show pitch accent in result when available

Julien LepillerThu Jun 11 04:21:52+0200 2020

39fd091

Show pitch accent in result when available

CHANGELOG.md

2424
* Add a Help screen and two topics: kanji input by component and romaji input.
2525
* Add a button for direct help access on radical input.
2626
* Application can now download dictionaries from Wadoku.
27+
* Application can now show pitch accent with proper dictionary.
2728
2829
### Translations
2930

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

99
import androidx.appcompat.widget.Toolbar;
1010
import androidx.preference.PreferenceManager;
1111
12+
import android.util.Log;
1213
import android.view.View;
1314
import android.view.Menu;
1415
import android.view.MenuItem;

3738
    private static ArrayList<Result> savedResults;
3839
    private RadicalSelectorView radical_selector;
3940
41+
    private static final String TAG = "MAIN";
42+
4043
    @Override
4144
    protected void onCreate(Bundle savedInstanceState) {
4245
        super.onCreate(savedInstanceState);

239242
            FuriganaTextView kanji_view = child_result.findViewById(R.id.kanji_view);
240243
            LinearLayout senses_view = child_result.findViewById(R.id.sense_view);
241244
            TextView additional_info = child_result.findViewById(R.id.additional_info_view);
245+
            TextView pitch_view = child_result.findViewById(R.id.pitch_view);
242246
243247
            // Populate the data into the template view using the data object
244248
            kanji_view.setFuriganaText(result.getKanjiFurigana());
245249
250+
            // If pitch information is available, make it visible
251+
            String pitch = result.getPitch();
252+
            if(pitch != null) {
253+
                Log.d(TAG, "pitch: "+pitch);
254+
                pitch_view.setVisibility(View.VISIBLE);
255+
                pitch_view.setText(pitch);
256+
            }
257+
246258
            StringBuilder additional = new StringBuilder();
247259
            boolean separator = false;
248260
            for (String s : result.getAlternatives()) {

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

232232
    private static void augment(Result r) throws IncompatibleFormatException {
233233
        for(Dictionary d: dictionaries) {
234234
            if(d instanceof ResultAugmenterDictionary && d.isDownloaded()) {
235+
                Log.d(TAG, "Augmenting " + r.getKanji());
235236
                ((ResultAugmenterDictionary) d).augment(r);
236237
            }
237238
        }

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

7575
                    String expected = readSha256FromFile(sha256);
7676
7777
                    // If the file has the expected hash, we have it
78-
                    Log.d(TAG, "expected: " + expected + "; actual: " + hash);
78+
                    Log.v(TAG, "expected: " + expected + "; actual: " + hash);
7979
                    return expected.compareTo(hash) == 0;
8080
                } catch (FileNotFoundException e) {
8181
                    e.printStackTrace();

179179
180180
            return new HuffmanTree(left, right);
181181
        } else if (b == 0) {
182-
            Log.d(TAG, "Skipping byte " + file.readByte());
182+
            Log.v(TAG, "Skipping byte " + file.readByte());
183183
            return new HuffmanValue("");
184184
        } else {
185185
            ArrayList<Byte> bs = new ArrayList<>();

203203
        while(c == null || !c.isEmpty()) {
204204
            if(h instanceof ResultDictionary.HuffmanValue) {
205205
                c = ((ResultDictionary.HuffmanValue) h).character;
206-
                Log.d(TAG, "Huffman read: " + c);
206+
                Log.v(TAG, "Huffman read: " + c);
207207
                b.append(c);
208208
                h = huffman;
209209
            } else if(h instanceof ResultDictionary.HuffmanTree) {
210210
                if(bits.isEmpty()) {
211211
                    byte by = file.readByte();
212-
                    Log.d(TAG, "Read byte for huffman: " + by);
212+
                    Log.v(TAG, "Read byte for huffman: " + by);
213213
                    for(int i = 7; i>-1; i--) {
214214
                        bits.add((by&(1<<i))!=0);
215215
                    }
216-
                    Log.d(TAG, "Read byte for huffman: " + bits);
216+
                    Log.v(TAG, "Read byte for huffman: " + bits);
217217
                }
218218
219219
                Boolean bo = bits.get(0);

226226
    }
227227
228228
    static void logHuffman(Huffman h, ArrayList<Boolean> address) {
229-
        if (h instanceof JMDict.HuffmanValue) {
230-
            Log.d(TAG, "HUFF: " + ((JMDict.HuffmanValue) h).character + " -> " + address.toString());
231-
        } else if(h instanceof JMDict.HuffmanTree) {
229+
        if (h instanceof ResultDictionary.HuffmanValue) {
230+
            Log.v(TAG, "HUFF: " + ((ResultDictionary.HuffmanValue) h).character + " -> " + address.toString());
231+
        } else if(h instanceof ResultDictionary.HuffmanTree) {
232232
            ArrayList<Boolean> address_l = new ArrayList<>(address);
233233
            address_l.add(false);
234234
            ArrayList<Boolean> address_r = new ArrayList<>(address);

241241
    static ArrayList<String> getHuffmanStringList(RandomAccessFile file, Huffman huffman) throws IOException {
242242
        ArrayList<String> results = new ArrayList<>();
243243
        int number = file.readShort();
244-
        Log.d(TAG, "huffmanStrings: " + number);
244+
        Log.v(TAG, "huffmanStrings: " + number);
245245
        for(int i=0; i<number; i++) {
246246
            results.add(getHuffmanString(file, huffman));
247247
        }

255255
        }
256256
257257
        int valuesLength = file.readShort();
258-
        Log.d(TAG, "number of values: " + valuesLength);
258+
        Log.v(TAG, "number of values: " + valuesLength);
259259
        file.skipBytes(valuesLength * 4);
260260
261261
        int transitionLength = file.readByte();
262-
        Log.d(TAG, "number of transitions: " + transitionLength);
262+
        Log.v(TAG, "number of transitions: " + transitionLength);
263263
264264
        for(int i = 0; i < transitionLength; i++) {
265265
            byte letter = file.readByte();
266-
            Log.d(TAG, "Possible transition " + letter + "; Expected transition: " + txt[0]);
266+
            Log.v(TAG, "Possible transition " + letter + "; Expected transition: " + txt[0]);
267267
            if(letter == txt[0]) {
268-
                Log.d(TAG, "Taking transition "+letter);
268+
                Log.v(TAG, "Taking transition "+letter);
269269
                byte[] ntxt = new byte[txt.length-1];
270270
                System.arraycopy(txt, 1, ntxt, 0, txt.length-1);
271271
                return searchTrie(file, file.readInt(), ntxt, decoder);

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

3030
3131
    private Result getValue(RandomAccessFile file, long pos) throws IOException {
3232
        file.seek(pos);
33-
        Log.d(TAG, "Getting value at " + pos);
33+
        Log.v(TAG, "Getting value at " + pos);
3434
        ArrayList<String> kanjis = getHuffmanStringList(file, kanjiHuffman);
3535
36-
        Log.d(TAG, "Getting readings");
36+
        Log.v(TAG, "Getting readings");
3737
        ArrayList<Result.Reading> readings = new ArrayList<>();
3838
        int reading_number = file.readShort();
39-
        Log.d(TAG, reading_number + " readings.");
39+
        Log.v(TAG, reading_number + " readings.");
4040
        for(int i=0; i<reading_number; i++) {
4141
            ArrayList<String> reading_kanjis = getStringList(file);
42-
            Log.d(TAG, "kanjis: " + reading_kanjis);
42+
            Log.v(TAG, "kanjis: " + reading_kanjis);
4343
            ArrayList<String> reading_infos = getStringList(file);
44-
            Log.d(TAG, "infos: " + reading_kanjis);
44+
            Log.v(TAG, "infos: " + reading_kanjis);
4545
            ArrayList<String> reading_readings = getHuffmanStringList(file, readingHuffman);
4646
            Result.Reading r = new Result.Reading(reading_kanjis, reading_infos, reading_readings);
4747
            readings.add(r);

4949
5050
        ArrayList<Result.Sense> senses = new ArrayList<>();
5151
        int meaning_number = file.readShort();
52-
        Log.d(TAG, meaning_number + " meanings.");
52+
        Log.v(TAG, meaning_number + " meanings.");
5353
        for(int i=0; i<meaning_number; i++) {
5454
            ArrayList<String> sense_references = getStringList(file);
5555
            ArrayList<String> sense_limits = getStringList(file);

7474
7575
    private ArrayList<Integer> getValues(RandomAccessFile file, long triePos) throws IOException {
7676
        file.seek(triePos);
77-
        Log.d(TAG, "Getting values");
77+
        Log.v(TAG, "Getting values");
7878
        int valuesLength = file.readShort();
7979
        ArrayList<Integer> results = new ArrayList<>();
8080
81-
        Log.d(TAG, "Number of values: " + valuesLength);
81+
        Log.v(TAG, "Number of values: " + valuesLength);
8282
        for(int i=0; i<valuesLength; i++) {
8383
            results.add(file.readInt());
8484
        }
8585
8686
        int transitionLength = file.readByte();
87-
        Log.d(TAG, "Number of transitions: " + transitionLength);
87+
        Log.v(TAG, "Number of transitions: " + transitionLength);
8888
        int[] others = new int[transitionLength];
8989
        for(int i=0; i<transitionLength; i++) {
9090
            file.skipBytes(1);

9595
            results.addAll(getValues(file, others[i]));
9696
        }
9797
98-
        Log.d(TAG, "result size: " + results.size());
98+
        Log.v(TAG, "result size: " + results.size());
9999
        return results;
100100
    }
101101

128128
                long meaningTriePos = file.readInt();
129129
130130
                Log.d(TAG, "Search in: " + getFile());
131-
                Log.d(TAG, "kanji: " + kanjiTriePos);
132-
                Log.d(TAG, "reading: " + readingTriePos);
133-
                Log.d(TAG, "meaning: " + meaningTriePos);
131+
                Log.v(TAG, "kanji: " + kanjiTriePos);
132+
                Log.v(TAG, "reading: " + readingTriePos);
133+
                Log.v(TAG, "meaning: " + meaningTriePos);
134134
135135
                kanjiHuffman = loadHuffman(file);
136136
                readingHuffman = loadHuffman(file);

166166
                }
167167
                Arrays.sort(uniqResultsArray);
168168
169-
                Log.d(TAG, uniqResults.toString());
169+
                Log.v(TAG, uniqResults.toString());
170170
171171
                int num = 0;
172172
                for(int i: uniqResultsArray) {

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

1515
1616
class WadokuPitchDictionary extends ResultAugmenterDictionary {
1717
    private static final String TAG = "PITCH";
18-
    private Huffman huffman;
18+
    private Huffman huffman = null;
1919
    private long triePos;
2020
2121
    WadokuPitchDictionary(String name, String description, String fullDescription, File cacheDir, String url, int fileSize, int entries, String hash) {

4141
    void augment(Result r) throws IncompatibleFormatException {
4242
        try {
4343
            RandomAccessFile file = new RandomAccessFile(getFile(), "r");
44-
            byte[] header = new byte[13];
45-
            int l = file.read(header);
46-
            if (l != header.length)
47-
                return;
4844
49-
            if(!Arrays.equals(header, "NANI_PITCH001".getBytes()))
50-
                throw new IncompatibleFormatException(getName());
45+
            if(huffman == null) {
46+
                byte[] header = new byte[13];
47+
                int l = file.read(header);
48+
                if (l != header.length)
49+
                    return;
5150
52-
            // number of entries
53-
            file.readInt();
51+
                if (!Arrays.equals(header, "NANI_PITCH001".getBytes()))
52+
                    throw new IncompatibleFormatException(getName());
5453
55-
            huffman = loadHuffman(file);
56-
            logHuffman(huffman, new ArrayList<Boolean>());
54+
                // number of entries
55+
                file.readInt();
5756
58-
            triePos = file.getFilePointer();
57+
                huffman = loadHuffman(file);
58+
                logHuffman(huffman, new ArrayList<Boolean>());
59+
60+
                triePos = file.getFilePointer();
61+
            }
5962
6063
            List<String> kanjis = r.getAlternatives();
6164
6265
            for(String k: kanjis) {
66+
                Log.d(TAG, "Searching pitch for " + k);
6367
                String pitch = findPitch(k, file);
6468
                if(pitch != null) {
69+
                    Log.d(TAG, "Found " + pitch);
6570
                    r.addPitch(k, pitch);
6671
                }
6772
            }

app/src/main/java/eu/lepiller/nani/result/Result.java

22
33
import android.util.Log;
44
5-
import java.io.IOException;
6-
import java.io.RandomAccessFile;
75
import java.util.ArrayList;
86
import java.util.regex.Matcher;
97
import java.util.regex.Pattern;

10199
        return reading;
102100
    }
103101
102+
    public String getPitch() {
103+
        if(readings.size() > 0) {
104+
            ArrayList<String> pitches = readings.get(0).pitches;
105+
            if(pitches.size() > 0)
106+
                return pitches.get(0);
107+
        }
108+
        return null;
109+
    }
110+
104111
    public String getKanjiFurigana() {
105112
        String txt = getKanji();
106113
        String reading = getReading();
107-
        Log.d("RESULT", "reading: " + reading);
114+
        Log.v("RESULT", "reading: " + reading);
108115
109116
        // split the text into kanji / not kanji portions
110117
        ArrayList<String> portions = new ArrayList<>();

142149
        }
143150
        current.append("$");
144151
145-
        Log.d("RESULT", "regex: " + current.toString());
152+
        Log.v("RESULT", "regex: " + current.toString());
146153
147154
        Pattern p = Pattern.compile(current.toString());
148155
        Matcher m = p.matcher(reading);
149156
150157
        if(!m.matches()) {
151-
            Log.d("RESULT", "Finaly: " + txt);
158+
            Log.v("RESULT", "Finaly: " + txt);
152159
            return txt;
153160
        }
154161
155162
        // We have a match!
156163
157-
        Log.d("RESULT", "matched");
164+
        Log.v("RESULT", "matched");
158165
159166
        current = new StringBuilder();
160167
        int group = 1;

171178
                current.append(s);
172179
            }
173180
        }
174-
        Log.d("RESULT", "Finaly: " + current.toString());
181+
        Log.v("RESULT", "Finaly: " + current.toString());
175182
        return current.toString();
176183
    }
177184

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

1818
        app:contains_ruby_tags="true"
1919
        android:textSize="@dimen/title_size" />
2020
21+
    <TextView
22+
        android:layout_width="wrap_content"
23+
        android:layout_height="wrap_content"
24+
        android:id="@+id/pitch_view"
25+
        android:visibility="gone"/>
26+
2127
    <LinearLayout
2228
        android:layout_width="wrap_content"
2329
        android:layout_height="wrap_content"