├── .gitignore ├── .idea ├── .name ├── compiler.xml ├── copyright │ └── profiles_settings.xml ├── gradle.xml ├── misc.xml ├── modules.xml ├── runConfigurations.xml └── vcs.xml ├── README.md ├── app ├── .gitignore ├── app-release.apk ├── build.gradle ├── libs │ ├── armeabi-v7a │ │ ├── libiconv.so │ │ └── libzbarjni.so │ ├── armeabi │ │ ├── libiconv.so │ │ └── libzbarjni.so │ ├── jsoup-1.8.1.jar │ ├── x86 │ │ ├── libiconv.so │ │ └── libzbarjni.so │ └── zbar.jar ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── dict │ │ └── hm │ │ └── dictionary │ │ └── ApplicationTest.java │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── dict │ │ └── hm │ │ └── dictionary │ │ ├── async │ │ ├── HttpDownload.java │ │ ├── LoadDictionary.java │ │ ├── UnGzipThread.java │ │ ├── UserAsyncWorkerHandler.java │ │ └── WordAsyncQueryHandler.java │ │ ├── dict │ │ ├── DictContentProvider.java │ │ ├── DictFormat.java │ │ ├── DictItem.java │ │ ├── DictManager.java │ │ ├── DictSQLiteDatabase.java │ │ ├── DictSQLiteDefine.java │ │ ├── DictSQLiteHelper.java │ │ ├── UserDictSQLiteHelper.java │ │ └── parse │ │ │ ├── DictParser.java │ │ │ ├── IdxParser.java │ │ │ └── IfoFormat.java │ │ ├── lib │ │ ├── CustomGZIPInputStream.java │ │ ├── ScrimInsetsFrameLayout.java │ │ └── ZBarActivity.java │ │ ├── paper │ │ ├── JsonEntry.java │ │ ├── PaperErrorCode.java │ │ ├── PaperJsonReader.java │ │ ├── PaperJsonWriter.java │ │ ├── PaperParser.java │ │ └── PaperWorkerHandler.java │ │ └── ui │ │ ├── BaseManagerActivity.java │ │ ├── DialogExPreference.java │ │ ├── DictManagerActivity.java │ │ ├── FileListFragment.java │ │ ├── MainActivity.java │ │ ├── PaperArchiveFragment.java │ │ ├── PaperManagerActivity.java │ │ ├── PaperViewerFragment.java │ │ ├── SettingsFragment.java │ │ ├── UserDictFragment.java │ │ ├── adapter │ │ ├── NavigationDrawerAdapter.java │ │ ├── PaperJsonAdapter.java │ │ ├── PaperViewerAdapter.java │ │ └── UserDictAdapter.java │ │ └── dialog │ │ ├── AboutDialog.java │ │ ├── AlertDialogFragment.java │ │ ├── DefinitionDialog.java │ │ ├── EditDialog.java │ │ ├── NotificationDialog.java │ │ ├── ProgressDialog.java │ │ ├── SelectDialog.java │ │ └── SwitchDictDialog.java │ └── res │ ├── drawable-xxhdpi │ ├── ic_action_archive_white_24dp.png │ ├── ic_action_edit_white_24dp.png │ ├── ic_action_new_attachment.png │ ├── ic_action_next_item.png │ ├── ic_action_previous_item.png │ ├── ic_action_qrcode.png │ ├── ic_action_search.png │ ├── ic_add_black_24dp.png │ ├── ic_close_white_18dp.png │ ├── ic_favorite_black_48dp.png │ ├── ic_favorite_outline_black_48dp.png │ ├── ic_launcher.png │ ├── ic_sort_white_24dp.png │ └── ic_wallpaper.png │ ├── drawable │ ├── drawer_divider.xml │ ├── favorite_selector.xml │ ├── floating_button.xml │ └── list_selector.xml │ ├── layout │ ├── activity_camera.xml │ ├── activity_main.xml │ ├── activity_manager.xml │ ├── definition_item.xml │ ├── drawer_item.xml │ ├── edit_text.xml │ ├── fragment_file.xml │ ├── paper_json_item.xml │ ├── paper_viewer_item.xml │ ├── progress.xml │ ├── progress_circle.xml │ ├── snackbar.xml │ ├── textview_item.xml │ └── user_word_item.xml │ ├── menu │ ├── menu_archive.xml │ ├── menu_main.xml │ ├── menu_paper_manager.xml │ └── menu_user_dict.xml │ ├── values-v21 │ └── styles.xml │ ├── values-w820dp │ └── dimens.xml │ ├── values-zh │ └── strings.xml │ ├── values │ ├── attrs.xml │ ├── custom_color.xml │ ├── dimens.xml │ ├── strings.xml │ └── styles.xml │ └── xml │ ├── preferences.xml │ └── searchable.xml ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── screenshot └── dict.png └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | /local.properties 3 | /.idea/workspace.xml 4 | /.idea/libraries 5 | .DS_Store 6 | /build 7 | *.iml 8 | -------------------------------------------------------------------------------- /.idea/.name: -------------------------------------------------------------------------------- 1 | Dictionary -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 18 | 19 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 26 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 想法 2 | 问题: 3 | 4 | 在你英语阅读能力不足前,是时常需要查阅单词的,但当你中断阅读后,你又容易忘记之前看的内容了。 5 | 6 | 解决方案: 7 | 8 | **解析你所需要阅读的英文文章,基于你的单词词库过滤出文章内的生词,集中显示生词解释** 9 | 10 | *基础:* 个人单词库 11 | 12 | *难题:* 解析文章,Text性质的文档解析容易,其他的格式看OCR。对非 text 数据则通过云端提供的 OCR 服务解析。 13 | 14 | - 情景一:还记得当年做阅读理解的痛苦吗?如果拍照下阅读理解的内容进而解析过滤出生词,便可快速查阅生词意思。 15 | - 情景二:浏览器提供插件,解析当前网页内容,根据个人词库过滤出生词,也可快速查阅生词意思。 16 | 17 | 18 | *核心:* 个人词库(分通用与专业)。 19 | 20 | *终极形态:* 得到每个用户的专业性词库数据,提供用户可能感兴趣的单词。 21 | 22 | *云端同步个人词库* 23 | 24 | 以上是基于一个词典应用,你想得到生词的什么解释就看你拥有怎样的词典,不限于英英,英汉,英日,英韩等等,都是针对英语,英语容易分词。 25 | 26 | Android 通过 Intent 提供接口,接收 text 数据,解析内容过滤出生词。但这里面没统一格式,怎么实现? 27 | 28 | 下面是我的部分实现 (Android 应用) 29 | 30 | --------------- 31 | 32 | [下载](app/app-release.apk) 33 | ![screenshot](screenshot/dict.png) 34 | 35 | ## 基本功能 36 | 词典功能。 37 | 不包含词典,需自己添加。实现了 stardict 2.4.2 格式的字典, 还没增加音频图像的支持。后续增加字典格式。 38 | 一词典 = 一张FTS表一张索引表一项词典信息记录。(还是所有单词一张FTS表?) 39 | 40 | FTS 表提高搜索速度,会建立大量索引,空间使用量大增。不存放非搜索数据。 41 | 全文搜索表(FTS): 42 | 43 | | rowid | word | 44 | | :--------- | --------:| 45 | 46 | 根据不同词典格式建立不同的索引表。 47 | 单词索引表: 48 | 49 | | rowid | offset | size | 50 | | :-------- | :-------: | -------: | 51 | 52 | 记录词典信息表: 53 | 54 | | rowid | name | type | data | active | table_name | 55 | | :---- | :----:| :---: | :---: | :-------: | ----------: | 56 | 57 | 58 | name: 词典名 59 | type: 词典格式 60 | data: 词典相关信息,如相关文件路径等,自定义 61 | active: 激活词典。 62 | table_name: 词典对应的表名,目前是 table_name = name 63 | 64 | 通用个人词库表: 65 | 66 | | rowid | word | count | time | 67 | | :---- | :---:| :----:| ----:| 68 | 69 | 专业个人词库表: 70 | 71 | | rowid | word | count | time | explain | 72 | | :---- | :---: | :---: | :---: | -------: | 73 | 74 | 75 | word: 词 76 | count: 归档次数 77 | time: 初始归档时间 78 | explain: 说明 79 | 80 | ## 文章管理 81 | 你可以添加 text,html 格式的文章,解析器会分析出单词,统计各个单词的出现次数,按次数排序存储。提供三种方法归档文章单词,归档即是把单词存放到你的单词库里。 82 | - 全部归档,把全部单词归档。 83 | - 过滤归档,把已存在词库里面的单词归档(只是增加了归档次数),过滤出生词。 84 | - 手动归档,手动选择归档单词。 85 | 86 | 存储格式 JSON ,Key_Value 形式,单词为 key ,次数为 value 。 87 | 88 | ## 个人词库 89 | 分两种类型,通用词库和专业词库。专业词库可以添加解释。(未完全完成) 90 | - 词库记录初始归档时间,同时会记录单词的总统计次数。专业词库多一个个人解释项。 91 | - 根据统计次数、归档时间展示个人词库。 92 | 93 | ## TODO 94 | 单词变形纠正(如复数),去掉非单词,添加 OCR 云端解析支持,词库云端同步,浏览器插件支持... 95 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | -------------------------------------------------------------------------------- /app/app-release.apk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hm279/Dictionary/7525340d5833892993721243b9270079824a45ee/app/app-release.apk -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | signingConfigs { 5 | } 6 | compileSdkVersion 23 7 | buildToolsVersion '23.0.2' 8 | defaultConfig { 9 | applicationId "com.dict.hm.dictionary" 10 | minSdkVersion 16 11 | targetSdkVersion 23 12 | versionCode 1 13 | versionName "1.0" 14 | } 15 | buildTypes { 16 | release { 17 | minifyEnabled false 18 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 19 | } 20 | } 21 | productFlavors { 22 | } 23 | } 24 | 25 | dependencies { 26 | compile fileTree(dir: 'libs', include: ['*.jar']) 27 | compile files('libs/zbar.jar') 28 | compile 'com.android.support:support-v13:23.1.1' 29 | compile 'com.android.support:appcompat-v7:23.1.1' 30 | compile 'com.android.support:design:23.1.1' 31 | compile 'com.android.support:recyclerview-v7:23.1.1' 32 | } 33 | -------------------------------------------------------------------------------- /app/libs/armeabi-v7a/libiconv.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hm279/Dictionary/7525340d5833892993721243b9270079824a45ee/app/libs/armeabi-v7a/libiconv.so -------------------------------------------------------------------------------- /app/libs/armeabi-v7a/libzbarjni.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hm279/Dictionary/7525340d5833892993721243b9270079824a45ee/app/libs/armeabi-v7a/libzbarjni.so -------------------------------------------------------------------------------- /app/libs/armeabi/libiconv.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hm279/Dictionary/7525340d5833892993721243b9270079824a45ee/app/libs/armeabi/libiconv.so -------------------------------------------------------------------------------- /app/libs/armeabi/libzbarjni.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hm279/Dictionary/7525340d5833892993721243b9270079824a45ee/app/libs/armeabi/libzbarjni.so -------------------------------------------------------------------------------- /app/libs/jsoup-1.8.1.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hm279/Dictionary/7525340d5833892993721243b9270079824a45ee/app/libs/jsoup-1.8.1.jar -------------------------------------------------------------------------------- /app/libs/x86/libiconv.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hm279/Dictionary/7525340d5833892993721243b9270079824a45ee/app/libs/x86/libiconv.so -------------------------------------------------------------------------------- /app/libs/x86/libzbarjni.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hm279/Dictionary/7525340d5833892993721243b9270079824a45ee/app/libs/x86/libzbarjni.so -------------------------------------------------------------------------------- /app/libs/zbar.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hm279/Dictionary/7525340d5833892993721243b9270079824a45ee/app/libs/zbar.jar -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /home/hm/android-sdk-linux/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/dict/hm/dictionary/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package com.dict.hm.dictionary; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 14 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 30 | 31 | 32 | 36 | 37 | 40 | 41 | 44 | 45 | 49 | 50 | 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /app/src/main/java/com/dict/hm/dictionary/async/HttpDownload.java: -------------------------------------------------------------------------------- 1 | package com.dict.hm.dictionary.async; 2 | 3 | import android.os.AsyncTask; 4 | import android.util.Log; 5 | 6 | import com.dict.hm.dictionary.ui.BaseManagerActivity; 7 | 8 | import java.io.FileOutputStream; 9 | import java.io.IOException; 10 | import java.io.InputStream; 11 | import java.net.HttpURLConnection; 12 | import java.net.URL; 13 | 14 | /** 15 | * Created by hm on 15-4-28. 16 | */ 17 | public class HttpDownload extends AsyncTask { 18 | BaseManagerActivity activity; 19 | 20 | public HttpDownload(BaseManagerActivity activity) { 21 | super(); 22 | this.activity = activity; 23 | activity.initProgressDialog("Download dict file", 100); 24 | } 25 | 26 | @Override 27 | protected Long doInBackground(String... params) { 28 | HttpURLConnection connection = null; 29 | InputStream in = null; 30 | FileOutputStream out = null; 31 | long total = 0; 32 | if (params.length != 2) { 33 | return ((long) -1); 34 | } 35 | try { 36 | URL url = new URL(params[0]); 37 | connection = (HttpURLConnection) url.openConnection(); 38 | connection.connect(); 39 | if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) { 40 | return ((long) -1); 41 | } 42 | int fileLength = connection.getContentLength(); 43 | in = connection.getInputStream(); 44 | out = new FileOutputStream(params[1]); 45 | byte[] bytes = new byte[4096]; 46 | int read; 47 | while ((read = in.read(bytes)) != -1) { 48 | total += read; 49 | out.write(bytes, 0, read); 50 | if (fileLength > 0) { 51 | publishProgress((int) total *100 / fileLength); 52 | } 53 | } 54 | } catch (IOException e) { 55 | e.printStackTrace(); 56 | } finally { 57 | try { 58 | if (connection != null) { 59 | connection.disconnect(); 60 | } 61 | if (in != null) { 62 | in.close(); 63 | } 64 | if (out != null) { 65 | out.close(); 66 | } 67 | } catch (IOException e) { 68 | e.printStackTrace(); 69 | } 70 | } 71 | 72 | return total; 73 | } 74 | 75 | @Override 76 | protected void onProgressUpdate(Integer... values) { 77 | Log.d("Download process", values[0] + "%"); 78 | activity.setProgress(values[0]); 79 | // super.onProgressUpdate(values); 80 | } 81 | 82 | @Override 83 | protected void onPostExecute(Long aLong) { 84 | Log.d("Download success", "download size " + aLong); 85 | activity.dismissProgressDialog(); 86 | // super.onPostExecute(aLong); 87 | } 88 | 89 | } 90 | -------------------------------------------------------------------------------- /app/src/main/java/com/dict/hm/dictionary/async/LoadDictionary.java: -------------------------------------------------------------------------------- 1 | package com.dict.hm.dictionary.async; 2 | 3 | import android.os.Handler; 4 | import android.os.Message; 5 | 6 | import com.dict.hm.dictionary.ui.DictManagerActivity; 7 | import com.dict.hm.dictionary.dict.DictSQLiteHelper; 8 | import com.dict.hm.dictionary.dict.parse.IdxParser; 9 | 10 | import java.io.File; 11 | import java.io.IOException; 12 | import java.util.ArrayList; 13 | 14 | /** 15 | * Created by hm on 15-5-12. 16 | */ 17 | public class LoadDictionary extends Thread{ 18 | File idxFile; 19 | Handler handler; 20 | String bookName; 21 | DictSQLiteHelper helper; 22 | 23 | public LoadDictionary(String bookName, File idxFile, DictSQLiteHelper helper, Handler handler) { 24 | super(); 25 | this.idxFile = idxFile; 26 | this.handler = handler; 27 | this.bookName = bookName; 28 | this.helper = helper; 29 | } 30 | 31 | @Override 32 | public void run() { 33 | try { 34 | helper.createTable(bookName); 35 | loadWords(idxFile); 36 | } catch (IOException e) { 37 | throw new RuntimeException(e); 38 | } 39 | } 40 | 41 | private void loadWords(File idxFile) throws IOException { 42 | IdxParser parser = new IdxParser(idxFile); 43 | ArrayList list; 44 | int count = 0; 45 | 46 | while (true) { 47 | list = parser.getWordEntries(); 48 | if (list == null || list.size() == 0) { 49 | break; 50 | } 51 | helper.addWords(list); 52 | count += list.size(); 53 | Message message = handler.obtainMessage(DictManagerActivity.PROCESSING); 54 | message.arg1 = count; 55 | handler.sendMessage(message); 56 | } 57 | Message message = handler.obtainMessage(DictManagerActivity.OK); 58 | message.obj = bookName; 59 | handler.sendMessage(message); 60 | } 61 | 62 | } 63 | 64 | 65 | -------------------------------------------------------------------------------- /app/src/main/java/com/dict/hm/dictionary/async/UnGzipThread.java: -------------------------------------------------------------------------------- 1 | package com.dict.hm.dictionary.async; 2 | 3 | import android.os.Handler; 4 | import android.util.Log; 5 | 6 | import com.dict.hm.dictionary.lib.CustomGZIPInputStream; 7 | import com.dict.hm.dictionary.ui.DictManagerActivity; 8 | 9 | import java.io.BufferedInputStream; 10 | import java.io.BufferedOutputStream; 11 | import java.io.File; 12 | import java.io.FileInputStream; 13 | import java.io.FileOutputStream; 14 | import java.io.IOException; 15 | 16 | /** 17 | * Created by hm on 15-1-31. 18 | */ 19 | public class UnGzipThread extends Thread { 20 | File zip; 21 | File out; 22 | Handler handler; 23 | 24 | public UnGzipThread(File zip, File out, Handler handler) { 25 | this.zip = zip; 26 | this.out = out; 27 | this.handler = handler; 28 | } 29 | 30 | @Override 31 | public void run() { 32 | unzipFile(zip, out); 33 | } 34 | 35 | private boolean unzipFile(File gzipInputFile, File outputFile) { 36 | BufferedInputStream in = null; 37 | BufferedOutputStream out = null; 38 | CustomGZIPInputStream zin = null; 39 | int BUF_SIZE = 4096; 40 | try { 41 | in = new BufferedInputStream(new FileInputStream(gzipInputFile)); 42 | out = new BufferedOutputStream(new FileOutputStream(outputFile)); 43 | zin = new CustomGZIPInputStream(in); 44 | byte[] bytes = new byte[BUF_SIZE]; 45 | int read; 46 | // int count = 0; 47 | Log.d("in", "" + in.available()); 48 | while ((read = zin.read(bytes, 0, BUF_SIZE)) >= 0) { 49 | out.write(bytes, 0, read); 50 | // count += read; 51 | // Message message = handler.obtainMessage(BaseManagerActivity.PROCESSING); 52 | // message.arg1 = count; 53 | // handler.sendMessage(message); 54 | } 55 | handler.sendEmptyMessage(DictManagerActivity.DECOMPRESS); 56 | } catch (IOException e) { 57 | outputFile.delete(); 58 | handler.sendEmptyMessage(DictManagerActivity.DECOMPRESS_ERR); 59 | e.printStackTrace(); 60 | return false; 61 | } finally { 62 | try { 63 | if (in != null) { 64 | in.close(); 65 | } 66 | if (out != null) { 67 | out.close(); 68 | } 69 | if (zin != null) { 70 | zin .close(); 71 | } 72 | } catch (IOException e) { 73 | e.printStackTrace(); 74 | } 75 | } 76 | return true; 77 | } 78 | } 79 | 80 | -------------------------------------------------------------------------------- /app/src/main/java/com/dict/hm/dictionary/async/UserAsyncWorkerHandler.java: -------------------------------------------------------------------------------- 1 | package com.dict.hm.dictionary.async; 2 | 3 | import android.content.Context; 4 | import android.database.Cursor; 5 | import android.os.Handler; 6 | import android.os.HandlerThread; 7 | import android.os.Looper; 8 | import android.os.Message; 9 | 10 | import com.dict.hm.dictionary.dict.DictFormat; 11 | import com.dict.hm.dictionary.dict.UserDictSQLiteHelper; 12 | 13 | import java.io.File; 14 | import java.lang.ref.WeakReference; 15 | import java.util.ArrayList; 16 | 17 | /** 18 | * Created by hm on 15-5-6. 19 | */ 20 | public class UserAsyncWorkerHandler extends Handler { 21 | private static final int EVENT_ARG_QUERY = 1; 22 | private static final int EVENT_ARG_INSERT = 2; 23 | private static final int EVENT_ARG_UPDATE = 3; 24 | private static final int EVENT_ARG_DELETE = 4; 25 | private static final int EVENT_USER_QUERY = 5; 26 | private static final int EVENT_PAPER_LIST = 6; 27 | 28 | private static Looper sLooper = null; 29 | private Handler mWorkerThreadHandler; 30 | 31 | WeakReference listenerWeakReference; 32 | DictManagerCallback callback; 33 | UserDictSQLiteHelper helper; 34 | 35 | static UserAsyncWorkerHandler handler = null; 36 | 37 | protected static final class WorkerArgs { 38 | Handler handler; 39 | long rowid; 40 | Cursor result; 41 | DictFormat format; 42 | //paper list 43 | File dir; 44 | ArrayList files; 45 | } 46 | 47 | protected class WorkerHandler extends Handler { 48 | 49 | public WorkerHandler(Looper looper) { 50 | super(looper); 51 | } 52 | 53 | @Override 54 | public void handleMessage(Message msg) { 55 | if (helper == null) { 56 | return; 57 | } 58 | WorkerArgs args = (WorkerArgs) msg.obj; 59 | Message message = args.handler.obtainMessage(msg.what); 60 | switch (msg.what) { 61 | case EVENT_ARG_QUERY: 62 | args.result = helper.queryDictionaries(); 63 | break; 64 | case EVENT_ARG_INSERT: 65 | args.rowid = helper.insertDictionary(args.format); 66 | break; 67 | case EVENT_ARG_UPDATE: 68 | args.rowid = helper.updateDictionary(args.rowid, msg.arg1); 69 | break; 70 | case EVENT_ARG_DELETE: 71 | args.rowid = helper.deleteDictionary(args.rowid); 72 | break; 73 | case EVENT_USER_QUERY: 74 | args.result = helper.getWordsOrderBy(msg.arg1); 75 | break; 76 | case EVENT_PAPER_LIST: 77 | if (args.dir.isDirectory()) { 78 | String[] names = args.dir.list(); 79 | ArrayList list = new ArrayList<>(names.length); 80 | for (String name : args.dir.list()) { 81 | list.add(name); 82 | } 83 | args.files = list; 84 | } else { 85 | args.files = null; 86 | } 87 | break; 88 | default: 89 | return; 90 | } 91 | message.obj = args; 92 | message.sendToTarget(); 93 | } 94 | } 95 | 96 | public static UserAsyncWorkerHandler getInstance(Context context, DictManagerCallback mCallback) { 97 | if (handler == null) { 98 | handler = new UserAsyncWorkerHandler(context.getApplicationContext(), mCallback); 99 | } 100 | return handler; 101 | } 102 | 103 | public UserAsyncWorkerHandler(Context context, DictManagerCallback callback) { 104 | synchronized (UserAsyncWorkerHandler.class) { 105 | if (sLooper == null) { 106 | HandlerThread thread = new HandlerThread("AsyncQueryWorker"); 107 | thread.start(); 108 | 109 | sLooper = thread.getLooper(); 110 | } 111 | } 112 | mWorkerThreadHandler = new WorkerHandler(sLooper); 113 | helper = UserDictSQLiteHelper.getInstance(context); 114 | this.callback = callback; 115 | } 116 | 117 | public void setUserDictQueryListener(UserDictQueryListener listener) { 118 | listenerWeakReference = new WeakReference<>(listener); 119 | } 120 | 121 | @Override 122 | public void handleMessage(Message msg) { 123 | WorkerArgs args = (WorkerArgs) msg.obj; 124 | 125 | switch (msg.what) { 126 | case EVENT_ARG_QUERY: 127 | callback.onQueryComplete(args.result); 128 | break; 129 | case EVENT_ARG_INSERT: 130 | callback.onInsertComplete(args.rowid); 131 | break; 132 | case EVENT_ARG_UPDATE: 133 | callback.onUpdateComplete(args.rowid); 134 | break; 135 | case EVENT_ARG_DELETE: 136 | callback.onDeleteComplete(args.rowid); 137 | break; 138 | case EVENT_USER_QUERY: 139 | if (listenerWeakReference == null) { 140 | return; 141 | } 142 | UserDictQueryListener listener = listenerWeakReference.get(); 143 | if (listener == null) { 144 | return; 145 | } 146 | listener.onUserDictQueryComplete(args.result); 147 | break; 148 | case EVENT_PAPER_LIST: 149 | callback.onUserPaperListComplete(args.files); 150 | break; 151 | } 152 | } 153 | 154 | /** 155 | * start to get a list names of papers 156 | */ 157 | public void startList(File paperDir) { 158 | WorkerArgs args = new WorkerArgs(); 159 | args.handler = this; 160 | args.dir = paperDir; 161 | Message message = mWorkerThreadHandler.obtainMessage(EVENT_PAPER_LIST); 162 | message.obj = args; 163 | message.sendToTarget(); 164 | } 165 | 166 | 167 | public void startQuery() { 168 | WorkerArgs args = new WorkerArgs(); 169 | args.handler = this; 170 | Message message = mWorkerThreadHandler.obtainMessage(EVENT_ARG_QUERY); 171 | message.obj = args; 172 | message.sendToTarget(); 173 | } 174 | 175 | public void startInsert(DictFormat dictFormat) { 176 | WorkerArgs args = new WorkerArgs(); 177 | args.handler = this; 178 | args.format = dictFormat; 179 | Message message = mWorkerThreadHandler.obtainMessage(EVENT_ARG_INSERT); 180 | message.obj = args; 181 | message.sendToTarget(); 182 | } 183 | 184 | public void startUpdate(long rowid, int on) { 185 | WorkerArgs args = new WorkerArgs(); 186 | args.handler = this; 187 | args.rowid = rowid; 188 | Message message = mWorkerThreadHandler.obtainMessage(EVENT_ARG_UPDATE); 189 | message.obj = args; 190 | message.arg1 = on; 191 | message.sendToTarget(); 192 | } 193 | 194 | public void startDelete(long rowid) { 195 | WorkerArgs args = new WorkerArgs(); 196 | args.handler = this; 197 | args.rowid = rowid; 198 | Message message = mWorkerThreadHandler.obtainMessage(EVENT_ARG_DELETE); 199 | message.obj = args; 200 | message.sendToTarget(); 201 | } 202 | 203 | /** 204 | * get user dict's words 205 | * @param which 206 | */ 207 | public void startQuery(int which) { 208 | WorkerArgs args = new WorkerArgs(); 209 | args.handler = this; 210 | 211 | Message message = mWorkerThreadHandler.obtainMessage(EVENT_USER_QUERY); 212 | message .obj = args; 213 | message.arg1 = which; 214 | message.sendToTarget(); 215 | } 216 | 217 | public interface UserDictQueryListener { 218 | void onUserDictQueryComplete(Cursor result); 219 | } 220 | 221 | public interface DictManagerCallback { 222 | void onQueryComplete(Cursor result); 223 | void onInsertComplete(long id); 224 | void onUpdateComplete(long id); 225 | void onDeleteComplete(long id); 226 | void onUserPaperListComplete(ArrayList list); 227 | } 228 | } 229 | -------------------------------------------------------------------------------- /app/src/main/java/com/dict/hm/dictionary/async/WordAsyncQueryHandler.java: -------------------------------------------------------------------------------- 1 | package com.dict.hm.dictionary.async; 2 | 3 | import android.content.AsyncQueryHandler; 4 | import android.content.ContentResolver; 5 | import android.database.Cursor; 6 | import android.os.Handler; 7 | import android.os.Looper; 8 | import android.util.Log; 9 | 10 | import java.lang.ref.WeakReference; 11 | 12 | /** 13 | * Created by hm on 15-5-4. 14 | */ 15 | public class WordAsyncQueryHandler extends AsyncQueryHandler{ 16 | WeakReference listenerWeakReference; 17 | Handler worker = null; 18 | 19 | public interface AsyncQueryListener { 20 | void onQueryComplete(int token, Object cookie, Cursor cursor); 21 | } 22 | 23 | public WordAsyncQueryHandler(ContentResolver cr, AsyncQueryListener listener) { 24 | super(cr); 25 | listenerWeakReference = new WeakReference<>(listener); 26 | } 27 | 28 | @Override 29 | protected void onQueryComplete(int token, Object cookie, Cursor cursor) { 30 | final AsyncQueryListener listener = listenerWeakReference.get(); 31 | if (listener != null) { 32 | listener.onQueryComplete(token, cookie, cursor); 33 | } else if (cursor != null) { 34 | cursor.close(); 35 | } 36 | } 37 | 38 | @Override 39 | protected Handler createHandler(Looper looper) { 40 | worker = super.createHandler(looper); 41 | Log.d("thread id", "" + looper.getThread().getId()); 42 | return worker; 43 | } 44 | 45 | //TODO:does need to quit the worker thread? 46 | public void quit() { 47 | if (worker != null) { 48 | worker.getLooper().quit(); 49 | } 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /app/src/main/java/com/dict/hm/dictionary/dict/DictContentProvider.java: -------------------------------------------------------------------------------- 1 | package com.dict.hm.dictionary.dict; 2 | 3 | 4 | import android.app.SearchManager; 5 | import android.content.ContentProvider; 6 | import android.content.ContentResolver; 7 | import android.content.ContentValues; 8 | import android.content.UriMatcher; 9 | import android.database.Cursor; 10 | import android.net.Uri; 11 | import android.provider.BaseColumns; 12 | import android.text.TextUtils; 13 | import android.util.Log; 14 | 15 | /** 16 | * Created by hm on 15-1-7. 17 | */ 18 | public class DictContentProvider extends ContentProvider{ 19 | String TAG = "DictContentProvider"; 20 | public static String AUTHORITY = "com.dict.hm.dictionary.provider"; 21 | public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/dictionary"); 22 | public static final String WORDS_MIME_TYPE = ContentResolver.CURSOR_DIR_BASE_TYPE + 23 | "/vnd.com.dict.hm.provider"; 24 | public static final String DEFINITION_MIME_TYPE = ContentResolver.CURSOR_ITEM_BASE_TYPE + 25 | "/vnd.com.dict.hm.provider"; 26 | 27 | private String[] suggestionColumns = new String[] { 28 | BaseColumns._ID, 29 | DictSQLiteDefine.COLUMN_KEY_WORD, 30 | /** 31 | * alias of COLUMN_KEY_WORD 32 | * This column allows suggestions to provide additional data that is included 33 | * as an extra in the intent’s EXTRA_DATA_KEY key. 34 | */ 35 | SearchManager.SUGGEST_COLUMN_INTENT_EXTRA_DATA, 36 | /* SearchManager.SUGGEST_COLUMN_SHORTCUT_ID, 37 | (only if you want to refresh shortcuts) */ 38 | SearchManager.SUGGEST_COLUMN_INTENT_DATA_ID}; 39 | 40 | private String[] wordColumns = new String[] { 41 | BaseColumns._ID, 42 | DictSQLiteDefine.COLUMN_KEY_WORD}; 43 | 44 | //UriMatcher stuff 45 | private static final int SEARCH_WORDS = 0; 46 | private static final int GET_WORD = 1; 47 | private static final int SEARCH_SUGGEST = 2; 48 | private static final int REFRESH_SHORTCUT = 3; 49 | private static final int GET_INDEX_BY_WORD = 4; 50 | private static final UriMatcher uriMatcher = buildUriMatcher(); 51 | 52 | private DictSQLiteDatabase mDictionary; 53 | 54 | public boolean onCreate() { 55 | mDictionary = new DictSQLiteDatabase(getContext()); 56 | Log.d(TAG, "onCreate"); 57 | return true; 58 | } 59 | 60 | private static UriMatcher buildUriMatcher() { 61 | UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH); 62 | matcher.addURI(AUTHORITY, "dictionary", SEARCH_WORDS); 63 | matcher.addURI(AUTHORITY, "dictionary/#", GET_WORD); 64 | matcher.addURI(AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY, SEARCH_SUGGEST); 65 | matcher.addURI(AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY + "/*", SEARCH_SUGGEST); 66 | matcher.addURI(AUTHORITY, SearchManager.SUGGEST_URI_PATH_SHORTCUT, REFRESH_SHORTCUT); 67 | matcher.addURI(AUTHORITY, SearchManager.SUGGEST_URI_PATH_SHORTCUT + "/*", REFRESH_SHORTCUT); 68 | /** 69 | * this is for the PaperViewAdapter 70 | */ 71 | matcher.addURI(AUTHORITY, "dictionary/word", GET_INDEX_BY_WORD); 72 | return matcher; 73 | } 74 | 75 | @Override 76 | public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, 77 | String sortOrder) { 78 | switch (uriMatcher.match(uri)) { 79 | case SEARCH_SUGGEST: 80 | if (selectionArgs == null) { 81 | throw new IllegalArgumentException( 82 | "selectionArgs must be provided for the Uri: " + uri); 83 | } 84 | return getSuggestions(selectionArgs[0]); 85 | case SEARCH_WORDS: 86 | if (selectionArgs == null) { 87 | throw new IllegalArgumentException( 88 | "selectionArgs must be provided for the Uri: " + uri); 89 | } 90 | return search(selectionArgs[0]); 91 | case GET_INDEX_BY_WORD: 92 | if (selectionArgs == null) { 93 | throw new IllegalArgumentException( 94 | "selectionArgs must be provided for the Uri: " + uri); 95 | } 96 | return getWordIndex(selectionArgs[0]); 97 | case GET_WORD: 98 | return getWordIndex(uri); 99 | case REFRESH_SHORTCUT: 100 | return refreshShortcut(uri); 101 | default: 102 | throw new IllegalArgumentException("Unknown Uri: " + uri); 103 | } 104 | } 105 | 106 | /** 107 | * 108 | * @param query 109 | * @return 110 | * TODO: getSuggestions() can only get the suggest words without offset and size. 111 | */ 112 | private Cursor getSuggestions(String query) { 113 | Log.d(TAG, "getSuggestions:" + query); 114 | if (TextUtils.isEmpty(query)) { 115 | return null; 116 | } 117 | query = query.toLowerCase(); 118 | 119 | // return mDictionary.getWordMatches(query, columns); 120 | return mDictionary.getWordMatchesInLength(query, suggestionColumns); 121 | } 122 | 123 | private Cursor search(String query) { 124 | Log.d(TAG, "search:" + query); 125 | if (TextUtils.isEmpty(query)) { 126 | return null; 127 | } 128 | query = query.toLowerCase(); 129 | return mDictionary.getWordMatches(query, wordColumns); 130 | } 131 | 132 | /** 133 | * get the word's index by word 134 | * 135 | * @param word word to query 136 | * @return word's index to return 137 | */ 138 | private Cursor getWordIndex(String word) { 139 | Log.d(TAG, "getWord:" + word); 140 | if (TextUtils.isEmpty(word)) { 141 | return null; 142 | } 143 | word = word.toLowerCase(); 144 | return mDictionary.getIndexByWord(word); 145 | } 146 | 147 | /** 148 | * get word's index by word's id 149 | * 150 | * @param uri 151 | * @return 152 | */ 153 | private Cursor getWordIndex(Uri uri) { 154 | Log.d(TAG, "getWord:" + uri.toString()); 155 | String rowId = uri.getLastPathSegment(); 156 | return mDictionary.getIndexByRowId(rowId); 157 | } 158 | 159 | private Cursor refreshShortcut(Uri uri) { 160 | Log.d(TAG, "refreshShortcut:" + uri.toString()); 161 | /* This won't be called with the current implementation, but if we include 162 | * {@link SearchManager#SUGGEST_COLUMN_SHORTCUT_ID} as a column in our suggestions table, we 163 | * could expect to receive refresh queries when a shortcutted suggestion is displayed in 164 | * Quick Search Box. In which case, this method will query the table for the specific 165 | * word, using the given item Uri and provide all the columns originally provided with the 166 | * suggestion query. 167 | */ 168 | String rowId = uri.getLastPathSegment(); 169 | String[] columns = new String[] { 170 | BaseColumns._ID, 171 | DictSQLiteDefine.COLUMN_KEY_WORD, 172 | SearchManager.SUGGEST_COLUMN_SHORTCUT_ID, 173 | SearchManager.SUGGEST_COLUMN_INTENT_DATA_ID}; 174 | 175 | return mDictionary.getWord(rowId, columns); 176 | } 177 | 178 | @Override 179 | public Uri insert(Uri uri, ContentValues values) { 180 | throw new UnsupportedOperationException(); 181 | } 182 | 183 | @Override 184 | public int delete(Uri uri, String selection, String[] selectionArgs) { 185 | throw new UnsupportedOperationException(); 186 | } 187 | 188 | @Override 189 | public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { 190 | throw new UnsupportedOperationException(); 191 | } 192 | 193 | @Override 194 | public String getType(Uri uri) { 195 | switch (uriMatcher.match(uri)) { 196 | case SEARCH_WORDS: 197 | return WORDS_MIME_TYPE; 198 | case GET_WORD: 199 | return DEFINITION_MIME_TYPE; 200 | case SEARCH_SUGGEST: 201 | return SearchManager.SUGGEST_MIME_TYPE; 202 | case REFRESH_SHORTCUT: 203 | return SearchManager.SHORTCUT_MIME_TYPE; 204 | default: 205 | throw new IllegalArgumentException("Unknown URI " + uri); 206 | } 207 | } 208 | } 209 | -------------------------------------------------------------------------------- /app/src/main/java/com/dict/hm/dictionary/dict/DictFormat.java: -------------------------------------------------------------------------------- 1 | package com.dict.hm.dictionary.dict; 2 | 3 | /** 4 | * Created by hm on 15-5-20. 5 | */ 6 | public class DictFormat { 7 | /** 8 | * dictionary type 9 | */ 10 | public static final int STAR_DICT = 0; 11 | 12 | String name; 13 | int type; 14 | int on; 15 | String data; 16 | String mTableName; 17 | 18 | public DictFormat(String name, int type, int on, String data, String mTableName) { 19 | this.name = name; 20 | this.type = type; 21 | this.on = on; 22 | this.data = data; 23 | this.mTableName = mTableName; 24 | } 25 | 26 | public void setOn(int on) { 27 | this.on = on; 28 | } 29 | 30 | public String getName() { 31 | return name; 32 | } 33 | 34 | public String getData() { 35 | return data; 36 | } 37 | 38 | public int getType() { 39 | return type; 40 | } 41 | 42 | @Override 43 | public String toString() { 44 | return name; 45 | } 46 | 47 | public int getOn() { 48 | return on; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /app/src/main/java/com/dict/hm/dictionary/dict/DictItem.java: -------------------------------------------------------------------------------- 1 | package com.dict.hm.dictionary.dict; 2 | 3 | /** 4 | * Created by hm on 15-6-16. 5 | */ 6 | public class DictItem { 7 | Long id; 8 | String text; 9 | 10 | public DictItem(Long id, String text) { 11 | this.id = id; 12 | this.text = text; 13 | } 14 | 15 | @Override 16 | public String toString() { 17 | return text; 18 | } 19 | 20 | public Long getId() { 21 | return id; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /app/src/main/java/com/dict/hm/dictionary/dict/DictSQLiteDatabase.java: -------------------------------------------------------------------------------- 1 | package com.dict.hm.dictionary.dict; 2 | 3 | import android.app.SearchManager; 4 | import android.content.Context; 5 | import android.database.Cursor; 6 | import android.database.sqlite.SQLiteDatabase; 7 | import android.database.sqlite.SQLiteQueryBuilder; 8 | import android.provider.BaseColumns; 9 | 10 | import java.util.HashMap; 11 | 12 | /** 13 | * Created by hm on 15-1-8. 14 | */ 15 | public class DictSQLiteDatabase { 16 | private final SQLiteDatabase database; 17 | private static final HashMap columnMap = buildColumnMap(); 18 | DictManager manager; 19 | 20 | public DictSQLiteDatabase(Context context) { 21 | DictSQLiteHelper helper = DictSQLiteHelper.getInstance(context); 22 | database = helper.getReadableDatabase(); 23 | manager = DictManager.getInstance(context); 24 | } 25 | 26 | public Cursor getWord(String rowId, String[] columns){ 27 | String selection = "rowid = ?"; 28 | String[] selectionArgs = new String[] {rowId}; 29 | return getWord(selection, selectionArgs, columns); 30 | } 31 | 32 | public Cursor getIndexByRowId(String rowId) { 33 | String mTableName = getActiveTableName(); 34 | if (mTableName == null) { 35 | return null; 36 | } 37 | String selection = "rowid = ?"; 38 | String[] selectionArgs = new String[] {rowId}; 39 | String mIndexTable = "[" + mTableName + "]"; 40 | return database.query(mIndexTable, null, selection, selectionArgs, null, null, null); 41 | } 42 | 43 | /** 44 | * PageViewerAdapter will this function 45 | * need inner join 46 | * 47 | * @param word 48 | * @return 49 | */ 50 | public Cursor getIndexByWord(String word) { 51 | String mTableName = getActiveTableName(); 52 | if (mTableName == null) { 53 | return null; 54 | } 55 | String mIndexTable = "[" + mTableName + "]"; 56 | String mWordTable = DictSQLiteDefine.getWordFtsTable(mTableName); 57 | int len = word.length(); 58 | String sql = DictSQLiteDefine.getInnerJoinSql(mIndexTable, mWordTable, len); 59 | return database.rawQuery(sql, new String[]{word}); 60 | } 61 | 62 | public Cursor getWordMatches(String query, String[] columns) { 63 | String selection = DictSQLiteDefine.COLUMN_KEY_WORD + " MATCH ?"; 64 | String[] selectionArgs = new String[] {"^"+query+"*"}; 65 | return query(selection, selectionArgs, columns); 66 | } 67 | 68 | public Cursor getWordMatchesInLength(String word, String[] columns) { 69 | int length = word.length(); 70 | String selection = DictSQLiteDefine.COLUMN_KEY_WORD + " MATCH ? AND length(" 71 | + DictSQLiteDefine.COLUMN_KEY_WORD + ")=" + length; 72 | String[] selectionArgs = new String[] {"^"+word}; 73 | return query(selection, selectionArgs, columns); 74 | } 75 | 76 | private Cursor query(String selection, String[] selectionArgs, String[] columns) { 77 | String mTableName = getActiveTableName(); 78 | if (mTableName == null) { 79 | return null; 80 | } 81 | String table = DictSQLiteDefine.getWordFtsTable(mTableName); 82 | SQLiteQueryBuilder builder = new SQLiteQueryBuilder(); 83 | builder.setTables(table); 84 | builder.setProjectionMap(columnMap); 85 | 86 | Cursor cursor = builder.query(database, 87 | columns, selection, selectionArgs, null, null, DictSQLiteDefine.sortOrder); 88 | if (cursor == null) { 89 | return null; 90 | } else if (!cursor.moveToFirst()) { 91 | cursor.close(); 92 | return null; 93 | } 94 | return cursor; 95 | } 96 | 97 | private Cursor getWord(String selection, String[] selectionArgs, String[] columns) { 98 | String mTableName = getActiveTableName(); 99 | if (mTableName == null) { 100 | return null; 101 | } 102 | String table = "[" + mTableName + "]"; 103 | SQLiteQueryBuilder builder = new SQLiteQueryBuilder(); 104 | builder.setTables(table); 105 | builder.setProjectionMap(columnMap); 106 | 107 | Cursor cursor = builder.query(database, 108 | columns, selection, selectionArgs, null, null, null); 109 | if (cursor == null) { 110 | return null; 111 | } else if (!cursor.moveToFirst()) { 112 | cursor.close(); 113 | return null; 114 | } 115 | return cursor; 116 | } 117 | 118 | private String getActiveTableName() { 119 | int i = manager.getActiveDict(); 120 | if (i < 0) { 121 | return null; 122 | } else { 123 | DictFormat format = manager.getDictFormat(i); 124 | return format.mTableName; 125 | } 126 | } 127 | 128 | private static HashMap buildColumnMap() { 129 | HashMap map = new HashMap<>(); 130 | map.put(DictSQLiteDefine.COLUMN_KEY_WORD, DictSQLiteDefine.COLUMN_KEY_WORD); 131 | map.put(BaseColumns._ID, "rowid AS " + BaseColumns._ID); 132 | map.put(SearchManager.SUGGEST_COLUMN_INTENT_DATA_ID, "rowid AS " + 133 | SearchManager.SUGGEST_COLUMN_INTENT_DATA_ID); 134 | map.put(SearchManager.SUGGEST_COLUMN_INTENT_EXTRA_DATA, DictSQLiteDefine.COLUMN_KEY_WORD + " AS " + 135 | SearchManager.SUGGEST_COLUMN_INTENT_EXTRA_DATA); 136 | return map; 137 | } 138 | 139 | } 140 | -------------------------------------------------------------------------------- /app/src/main/java/com/dict/hm/dictionary/dict/DictSQLiteDefine.java: -------------------------------------------------------------------------------- 1 | package com.dict.hm.dictionary.dict; 2 | 3 | import android.app.SearchManager; 4 | 5 | /** 6 | * Created by hm on 15-5-4. 7 | */ 8 | public class DictSQLiteDefine { 9 | /** ------------------------------------------------------------------------------------------* 10 | * ------------------------ FTS3 table defined for word -------------------------------------* 11 | * 12 | * define dictionary's word table. 13 | * this table will be created as FTS3 table in SQLiteDatabase. 14 | */ 15 | public static final String COLUMN_KEY_WORD = SearchManager.SUGGEST_COLUMN_TEXT_1; 16 | 17 | /** 18 | * define word table 19 | */ 20 | public static final String WORD_FTS_TABLE = 21 | "CREATE VIRTUAL TABLE %s USING fts3 (" + COLUMN_KEY_WORD + " TEXT)"; 22 | 23 | public static final String sortOrder = COLUMN_KEY_WORD + " ASC"; //"ASC" 24 | 25 | public static final String FTS_PREFIX = "fts3-"; 26 | 27 | /**-------------------------------------------------------------------------------------------* 28 | * ------------------------- normal table defined for word index -----------------------------* 29 | * 30 | * define dictionary's word indexing. 31 | * this table will be created as normal table in SQLiteDatabase. 32 | */ 33 | public static final String COLUMN_OFFSET = "offset"; 34 | public static final String COLUMN_SIZE = "size"; 35 | 36 | /** 37 | * define index table 38 | */ 39 | public static final String WORD_INDEX_TABLE = "CREATE TABLE %s (" + 40 | COLUMN_OFFSET + " INTEGER, " + COLUMN_SIZE + " INTEGER)"; 41 | 42 | /** ------------------------------------------------------------------------------------------* 43 | * define SQLiteDatabase name and version 44 | */ 45 | public static final String DATABASE_NAME = "dictionary.db"; 46 | public static final int VERSION = 3; 47 | 48 | /** ------------------------------------------------------------------------------------------* 49 | * define a inner join sql 50 | */ 51 | private static final String inner_join_sql = "select * from %s a inner join %s b" + 52 | " ON a.rowid = b.rowid WHERE b." + COLUMN_KEY_WORD + " MATCH ? AND length(" + COLUMN_KEY_WORD + ")=%d"; 53 | 54 | 55 | public static String getCreateFTSTable(String name) { 56 | return String.format(WORD_FTS_TABLE, name); 57 | } 58 | 59 | public static String getCreateTable(String name) { 60 | return String.format(WORD_INDEX_TABLE, name); 61 | } 62 | 63 | public static String getInnerJoinSql(String mIndexTable, String mWordTable, int wordLength) { 64 | return String.format(inner_join_sql, mIndexTable, mWordTable, wordLength); 65 | } 66 | 67 | public static String getWordFtsTable(String mTableName) { 68 | return "[" + FTS_PREFIX + mTableName + "]"; 69 | } 70 | 71 | } 72 | -------------------------------------------------------------------------------- /app/src/main/java/com/dict/hm/dictionary/dict/DictSQLiteHelper.java: -------------------------------------------------------------------------------- 1 | package com.dict.hm.dictionary.dict; 2 | 3 | import android.content.ContentValues; 4 | import android.content.Context; 5 | import android.database.Cursor; 6 | import android.database.sqlite.SQLiteDatabase; 7 | import android.database.sqlite.SQLiteOpenHelper; 8 | import android.util.Log; 9 | 10 | import com.dict.hm.dictionary.dict.parse.IdxParser; 11 | 12 | import java.io.File; 13 | import java.util.ArrayList; 14 | 15 | /** 16 | * Created by hm on 15-5-12. 17 | * Every normal table has a corresponding fts3 table. 18 | * Define the fts3 table name to "fts3- + 'normal table name'", like: table1 ---> fts3-table1 19 | */ 20 | public class DictSQLiteHelper extends SQLiteOpenHelper{ 21 | private static final String TAG = "DictSQLiteHelper"; 22 | private SQLiteDatabase database = null; 23 | private String wordTableName; 24 | private String indexTableName; 25 | private static DictSQLiteHelper helper; 26 | 27 | public static DictSQLiteHelper getInstance(Context context) { 28 | if (helper == null) { 29 | File externalDir = context.getExternalFilesDir(null); 30 | String databaseName; 31 | if (externalDir != null) { 32 | databaseName = externalDir.getAbsolutePath() + File.separator + DictSQLiteDefine.DATABASE_NAME; 33 | } else { 34 | databaseName = DictSQLiteDefine.DATABASE_NAME; 35 | } 36 | helper = new DictSQLiteHelper(context.getApplicationContext(), databaseName); 37 | } 38 | return helper; 39 | } 40 | 41 | public DictSQLiteHelper(Context context, String mDatabaseName) { 42 | super(context, mDatabaseName, null, DictSQLiteDefine.VERSION); 43 | } 44 | 45 | @Override 46 | public void onCreate(SQLiteDatabase db) { 47 | database = db; 48 | } 49 | 50 | @Override 51 | public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { 52 | database = db; 53 | } 54 | 55 | public void dropTable(String table) { 56 | if (table != null) { 57 | database = getWritableDatabase(); 58 | database.execSQL("DROP TABLE IF EXISTS [" + table + "]"); 59 | database.execSQL("DROP TABLE IF EXISTS [" + DictSQLiteDefine.FTS_PREFIX + table + "]"); 60 | } 61 | } 62 | 63 | public Cursor getTables() { 64 | database = getWritableDatabase(); 65 | return database.rawQuery("SELECT * FROM sqlite_master WHERE TYPE='table'", null); 66 | } 67 | 68 | private long addWord(String word) { 69 | ContentValues values = new ContentValues(); 70 | values.put(DictSQLiteDefine.COLUMN_KEY_WORD, word); 71 | return database.insert(wordTableName, null, values); 72 | } 73 | 74 | private long addWord(int offset, int size) { 75 | ContentValues values = new ContentValues(); 76 | values.put(DictSQLiteDefine.COLUMN_OFFSET, offset); 77 | values.put(DictSQLiteDefine.COLUMN_SIZE, size); 78 | return database.insert(indexTableName, null, values); 79 | } 80 | 81 | private void deleteWord(String mTableName, long id) { 82 | database.delete(mTableName, "rowid = ?", new String[]{Long.toString(id)}); 83 | } 84 | 85 | public void addWords(ArrayList list) { 86 | if (database == null) { 87 | return; 88 | } 89 | database.beginTransaction(); 90 | long id0, id1; 91 | 92 | for (IdxParser.WordEntry entry : list) { 93 | id0 = addWord(new String(entry.word)); 94 | id1 = addWord(entry.offset, entry.size); 95 | if (id0 < 0 || id1 < 0 || id0 != id1) { 96 | Log.e(TAG, "unable to add word:" + new String(entry.word).trim()); 97 | if (id0 >= 0) { 98 | deleteWord(wordTableName, id0); 99 | } 100 | if (id1 >= 0) { 101 | deleteWord(indexTableName, id1); 102 | } 103 | } 104 | } 105 | database.setTransactionSuccessful(); 106 | database.endTransaction(); 107 | } 108 | 109 | public void createTable(String bookName) { 110 | wordTableName = "[" + DictSQLiteDefine.FTS_PREFIX + bookName + "]"; 111 | indexTableName = "[" + bookName + "]"; 112 | String createWordTableSQL = DictSQLiteDefine.getCreateFTSTable(wordTableName); 113 | String createIndexTableSQL = DictSQLiteDefine.getCreateTable(indexTableName); 114 | database = getWritableDatabase(); 115 | database.execSQL(createWordTableSQL); 116 | database.execSQL(createIndexTableSQL); 117 | } 118 | 119 | } 120 | -------------------------------------------------------------------------------- /app/src/main/java/com/dict/hm/dictionary/dict/parse/DictParser.java: -------------------------------------------------------------------------------- 1 | package com.dict.hm.dictionary.dict.parse; 2 | 3 | import android.util.Log; 4 | 5 | import java.io.File; 6 | import java.io.FileNotFoundException; 7 | import java.io.IOException; 8 | import java.io.RandomAccessFile; 9 | 10 | /** 11 | * Created by hm on 15-1-17. 12 | */ 13 | public class DictParser { 14 | File dictFile; 15 | RandomAccessFile randomAccessFile; 16 | 17 | public DictParser(File dictFile) { 18 | this.dictFile = dictFile; 19 | try { 20 | randomAccessFile = new RandomAccessFile(dictFile, "r"); 21 | } catch (FileNotFoundException e) { 22 | randomAccessFile = null; 23 | e.printStackTrace(); 24 | } 25 | } 26 | 27 | public String getWordDefinition(int offset, int size) { 28 | try { 29 | if (randomAccessFile != null && offset <= randomAccessFile.length()) { 30 | randomAccessFile.seek(offset); 31 | byte[] bytes = new byte[size]; 32 | int actuallySize = randomAccessFile.read(bytes); 33 | if (actuallySize != size) { 34 | return null; 35 | } 36 | return new String(bytes); 37 | } 38 | } catch (IOException e) { 39 | e.printStackTrace(); 40 | } 41 | return null; 42 | } 43 | 44 | public void closeFile() { 45 | Log.d("RandomAccessFile", "closed"); 46 | try { 47 | if (randomAccessFile != null) { 48 | randomAccessFile.close(); 49 | } 50 | } catch (IOException e) { 51 | e.printStackTrace(); 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /app/src/main/java/com/dict/hm/dictionary/dict/parse/IdxParser.java: -------------------------------------------------------------------------------- 1 | package com.dict.hm.dictionary.dict.parse; 2 | 3 | import android.util.Log; 4 | 5 | import java.io.BufferedInputStream; 6 | import java.io.File; 7 | import java.io.FileInputStream; 8 | import java.io.IOException; 9 | import java.io.InputStream; 10 | import java.util.ArrayList; 11 | import java.util.zip.GZIPInputStream; 12 | 13 | /** 14 | * Created by hm on 15-1-11. 15 | */ 16 | public class IdxParser { 17 | InputStream in; 18 | byte[] bytes = new byte[256]; 19 | 20 | public IdxParser(File idxFile) { 21 | try { 22 | if (idxFile.getName().endsWith(".idx.gz")) { 23 | in = new GZIPInputStream(new BufferedInputStream(new FileInputStream(idxFile))); 24 | } else { 25 | in = new BufferedInputStream(new FileInputStream(idxFile)); 26 | } 27 | 28 | } catch (IOException e) { 29 | e.printStackTrace(); 30 | } 31 | } 32 | 33 | /** 34 | * @return 10000 WordEntries 35 | * 36 | */ 37 | public ArrayList getWordEntries() { 38 | ArrayList list = new ArrayList<>(10000); 39 | WordEntry entry; 40 | int i = 0; 41 | try { 42 | if (in == null) { 43 | return null; 44 | } 45 | if (in.available() <= 0) { 46 | in.close(); 47 | return null; 48 | } 49 | Log.d("loading dictionary", "" + in.available()); 50 | } catch (IOException e) { 51 | e.printStackTrace(); 52 | } 53 | while ((entry = getNextWordEntry()) != null && i < 10000) { 54 | list.add(entry); 55 | i++; 56 | } 57 | return list; 58 | } 59 | 60 | private WordEntry getNextWordEntry() { 61 | WordEntry entry = new WordEntry(); 62 | int i = 0; 63 | int[] tmp = new int[4]; 64 | 65 | try { 66 | if (in.available() <= 0) { 67 | return null; 68 | } 69 | while ((bytes[i] = (byte)in.read()) != '\0') { 70 | i++; 71 | } 72 | byte[] word = new byte[i]; 73 | for (int j = 0; j < i; j++) { 74 | word[j] = bytes[j]; 75 | } 76 | entry.word = word; 77 | for (i = 0; i < 4; i++) { 78 | tmp[i] = in.read(); 79 | } 80 | entry.offset = (tmp[0] << 24) + (tmp[1] << 16) + (tmp[2] << 8) + tmp[3]; 81 | for (i = 0; i < 4; i++) { 82 | tmp[i] = in.read(); 83 | } 84 | entry.size = (tmp[0] << 24) + (tmp[1] << 16) + (tmp[2] << 8) + tmp[3]; 85 | } catch (IOException e) { 86 | e.printStackTrace(); 87 | } 88 | return entry; 89 | } 90 | 91 | public class WordEntry { 92 | public byte[] word; 93 | public int offset; 94 | public int size; 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /app/src/main/java/com/dict/hm/dictionary/dict/parse/IfoFormat.java: -------------------------------------------------------------------------------- 1 | package com.dict.hm.dictionary.dict.parse; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.File; 5 | import java.io.FileReader; 6 | import java.io.IOException; 7 | 8 | /** 9 | * Created by hm on 15-1-22. 10 | */ 11 | public class IfoFormat { 12 | String version; 13 | String bookName; 14 | int wordCount; 15 | int idxFileSize; 16 | int sameTypeSequence; 17 | 18 | public IfoFormat(File ifo) { 19 | if (ifo.isFile()) { 20 | getIfoFormat(ifo); 21 | } else { 22 | bookName = "The file " + ifo.getName() + " not found"; 23 | } 24 | } 25 | 26 | private void getIfoFormat(File ifo) { 27 | BufferedReader reader = null; 28 | try { 29 | reader = new BufferedReader(new FileReader(ifo)); 30 | String line; 31 | String name; 32 | while ((line = reader.readLine()) != null) { 33 | int index = line.indexOf('='); 34 | if (index > 0) { 35 | name = line.substring(index + 1); 36 | name = name.trim(); 37 | 38 | if (line.contains("bookname")) { 39 | bookName = name; 40 | } else if (line.contains("wordcount")) { 41 | wordCount = Integer.parseInt(name); 42 | } else if (line.contains("idxfilesize")) { 43 | idxFileSize = Integer.parseInt(name); 44 | } else if (line.contains("version")) { 45 | version = name; 46 | } else if (line.contains("sametypesequence")) { 47 | setSameTypeSequence(name); 48 | } 49 | } 50 | } 51 | } catch (IOException e) { 52 | e.printStackTrace(); 53 | } finally { 54 | if (reader != null) { 55 | try { 56 | reader.close(); 57 | } catch (IOException e) { 58 | e.printStackTrace(); 59 | } 60 | } 61 | } 62 | } 63 | 64 | /** 65 | * sameTypeSequence meaning: 66 | * 0x1 : 'm' 67 | * 0x2 : 'l' 68 | * 0x4 : 'g' 69 | * 0x8 : 't' 70 | * 0x10: 'y' 71 | * 0x20: 'W' 72 | * 0x40: 'P' 73 | * 0x80: 'X' 74 | */ 75 | private void setSameTypeSequence(String name) { 76 | sameTypeSequence = 0; 77 | if (name.contains("m")) { 78 | sameTypeSequence |= 0x1; 79 | } else if (name.contains("l")) { 80 | sameTypeSequence |= 0x2; 81 | } else if (name.contains("g")) { 82 | sameTypeSequence |= 0x4; 83 | } else if (name.contains("t")) { 84 | sameTypeSequence |= 0x8; 85 | } else if (name.contains("y")) { 86 | sameTypeSequence |= 0x10; 87 | } else if (name.contains("W")) { 88 | sameTypeSequence |= 0x20; 89 | } else if (name.contains("P")) { 90 | sameTypeSequence |= 0x40; 91 | } else if (name.contains("X")) { 92 | sameTypeSequence |= 0x80; 93 | } 94 | } 95 | 96 | public String getVersion() { 97 | return version; 98 | } 99 | 100 | public String getBookName() { 101 | return bookName; 102 | } 103 | 104 | public int getWordCount() { 105 | return wordCount; 106 | } 107 | 108 | public int getIdxFileSize() { 109 | return idxFileSize; 110 | } 111 | 112 | public int getSameTypeSequence() { 113 | return sameTypeSequence; 114 | } 115 | 116 | } 117 | -------------------------------------------------------------------------------- /app/src/main/java/com/dict/hm/dictionary/lib/ScrimInsetsFrameLayout.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.dict.hm.dictionary.lib; 18 | 19 | import android.content.Context; 20 | import android.content.res.TypedArray; 21 | import android.graphics.Canvas; 22 | import android.graphics.Rect; 23 | import android.graphics.drawable.Drawable; 24 | import android.support.v4.view.ViewCompat; 25 | import android.util.AttributeSet; 26 | import android.widget.FrameLayout; 27 | 28 | import com.dict.hm.dictionary.R; 29 | 30 | 31 | /** 32 | * A layout that draws something in the insets passed to {@link #fitSystemWindows(Rect)}, i.e. the area above UI chrome 33 | * (status and navigation bars, overlay action bars). 34 | */ 35 | public class ScrimInsetsFrameLayout extends FrameLayout { 36 | private Drawable mInsetForeground; 37 | 38 | private Rect mInsets; 39 | private Rect mTempRect = new Rect(); 40 | private OnInsetsCallback mOnInsetsCallback; 41 | 42 | public ScrimInsetsFrameLayout(Context context) { 43 | super(context); 44 | init(context, null, 0); 45 | } 46 | 47 | public ScrimInsetsFrameLayout(Context context, AttributeSet attrs) { 48 | super(context, attrs); 49 | init(context, attrs, 0); 50 | } 51 | 52 | public ScrimInsetsFrameLayout(Context context, AttributeSet attrs, int defStyle) { 53 | super(context, attrs, defStyle); 54 | init(context, attrs, defStyle); 55 | } 56 | 57 | private void init(Context context, AttributeSet attrs, int defStyle) { 58 | final TypedArray a = context.obtainStyledAttributes(attrs, 59 | R.styleable.ScrimInsetsView, defStyle, 0); 60 | if (a == null) { 61 | return; 62 | } 63 | mInsetForeground = a.getDrawable(R.styleable.ScrimInsetsView_mInsetForeground); 64 | a.recycle(); 65 | 66 | setWillNotDraw(true); 67 | } 68 | 69 | @Override 70 | protected boolean fitSystemWindows(Rect insets) { 71 | mInsets = new Rect(insets); 72 | setWillNotDraw(mInsetForeground == null); 73 | ViewCompat.postInvalidateOnAnimation(this); 74 | if (mOnInsetsCallback != null) { 75 | mOnInsetsCallback.onInsetsChanged(insets); 76 | } 77 | return true; // consume insets 78 | } 79 | 80 | @Override 81 | public void draw(Canvas canvas) { 82 | super.draw(canvas); 83 | 84 | int width = getWidth(); 85 | int height = getHeight(); 86 | if (mInsets != null && mInsetForeground != null) { 87 | int sc = canvas.save(); 88 | canvas.translate(getScrollX(), getScrollY()); 89 | 90 | // Top 91 | mTempRect.set(0, 0, width, mInsets.top); 92 | mInsetForeground.setBounds(mTempRect); 93 | mInsetForeground.draw(canvas); 94 | 95 | // Bottom 96 | mTempRect.set(0, height - mInsets.bottom, width, height); 97 | mInsetForeground.setBounds(mTempRect); 98 | mInsetForeground.draw(canvas); 99 | 100 | // Left 101 | mTempRect.set(0, mInsets.top, mInsets.left, height - mInsets.bottom); 102 | mInsetForeground.setBounds(mTempRect); 103 | mInsetForeground.draw(canvas); 104 | 105 | // Right 106 | mTempRect.set(width - mInsets.right, mInsets.top, width, height - mInsets.bottom); 107 | mInsetForeground.setBounds(mTempRect); 108 | mInsetForeground.draw(canvas); 109 | 110 | canvas.restoreToCount(sc); 111 | } 112 | } 113 | 114 | @Override 115 | protected void onAttachedToWindow() { 116 | super.onAttachedToWindow(); 117 | if (mInsetForeground != null) { 118 | mInsetForeground.setCallback(this); 119 | } 120 | } 121 | 122 | @Override 123 | protected void onDetachedFromWindow() { 124 | super.onDetachedFromWindow(); 125 | if (mInsetForeground != null) { 126 | mInsetForeground.setCallback(null); 127 | } 128 | } 129 | 130 | /** 131 | * Allows the calling container to specify a callback for custom processing when insets change (i.e. when 132 | * {@link #fitSystemWindows(Rect)} is called. This is useful for setting padding on UI elements based on 133 | * UI chrome insets (e.g. a Google Map or a ListView). When using with ListView or GridView, remember to set 134 | * clipToPadding to false. 135 | */ 136 | public void setOnInsetsCallback(OnInsetsCallback onInsetsCallback) { 137 | mOnInsetsCallback = onInsetsCallback; 138 | } 139 | 140 | public static interface OnInsetsCallback { 141 | public void onInsetsChanged(Rect insets); 142 | } 143 | } -------------------------------------------------------------------------------- /app/src/main/java/com/dict/hm/dictionary/lib/ZBarActivity.java: -------------------------------------------------------------------------------- 1 | package com.dict.hm.dictionary.lib; 2 | 3 | import android.app.Activity; 4 | import android.content.Intent; 5 | import android.content.pm.ActivityInfo; 6 | import android.content.pm.PackageManager; 7 | import android.hardware.Camera; 8 | import android.os.Bundle; 9 | import android.os.Handler; 10 | import android.util.Log; 11 | import android.view.MotionEvent; 12 | import android.view.SurfaceHolder; 13 | import android.view.SurfaceView; 14 | import android.view.View; 15 | import android.widget.CheckBox; 16 | import android.widget.CompoundButton; 17 | import android.widget.Toast; 18 | 19 | import com.dict.hm.dictionary.R; 20 | 21 | import net.sourceforge.zbar.Config; 22 | import net.sourceforge.zbar.Image; 23 | import net.sourceforge.zbar.ImageScanner; 24 | import net.sourceforge.zbar.Symbol; 25 | import net.sourceforge.zbar.SymbolSet; 26 | 27 | import java.io.IOException; 28 | import java.util.ArrayList; 29 | import java.util.List; 30 | 31 | 32 | /** 33 | * Created by hm on 15-3-16. 34 | */ 35 | public class ZBarActivity extends Activity{ 36 | private static final String TAG = "ZBar"; 37 | public static final String RESULT = "result"; 38 | private Camera mCamera; 39 | private ImageScanner scanner; 40 | 41 | private SurfaceView mPreview; 42 | private Handler autoFocusHandler; 43 | // boolean scanned = false; 44 | boolean previewing = true; 45 | boolean isSurfaceViewDestroyed = true; 46 | boolean autoFocus; 47 | // boolean reverse; 48 | private int count = 0; 49 | 50 | static { 51 | System.loadLibrary("iconv"); 52 | } 53 | 54 | @Override 55 | protected void onCreate(Bundle savedInstanceState) { 56 | super.onCreate(savedInstanceState); 57 | setContentView(R.layout.activity_camera); 58 | 59 | if (checkCameraHardware() && safeCameraOpen(0)) { 60 | setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); 61 | 62 | autoFocus = checkCameraAutoFocus(); 63 | mPreview = (SurfaceView) findViewById(R.id.camera_preview); 64 | mPreview.getHolder().addCallback(holderCallback); 65 | autoFocusHandler = new Handler(); 66 | scanner = new ImageScanner(); 67 | scanner.setConfig(0, Config.X_DENSITY, 3); 68 | scanner.setConfig(0, Config.Y_DENSITY, 3); 69 | 70 | // CheckBox checkBox = (CheckBox) findViewById(R.id.camera_checkbox); 71 | // checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { 72 | // @Override 73 | // public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { 74 | // reverse = isChecked; 75 | // } 76 | // }); 77 | 78 | mPreview.setOnTouchListener(new View.OnTouchListener() { 79 | @Override 80 | public boolean onTouch(View v, MotionEvent event) { 81 | if (!previewing) { 82 | previewing = true; 83 | mCamera.setPreviewCallback(previewCallback); 84 | mCamera.startPreview(); 85 | } 86 | return true; 87 | } 88 | }); 89 | } else { 90 | Toast.makeText(this, "failed to open Camera", Toast.LENGTH_LONG).show(); 91 | finish(); 92 | } 93 | // Log.d(TAG, "onCreate"); 94 | } 95 | 96 | @Override 97 | protected void onDestroy() { 98 | super.onDestroy(); 99 | releaseCameraAndPreview(); 100 | // Log.d(TAG, "onDestroy"); 101 | } 102 | 103 | @Override 104 | protected void onStop() { 105 | super.onStop(); 106 | if (previewing) { 107 | mCamera.stopPreview(); 108 | } 109 | // Log.d(TAG, "onStop"); 110 | } 111 | 112 | @Override 113 | protected void onStart() { 114 | super.onStart(); 115 | if (previewing && !isSurfaceViewDestroyed) { 116 | mCamera.startPreview(); 117 | } 118 | // Log.d(TAG, "onStart"); 119 | } 120 | 121 | private boolean safeCameraOpen(int id) { 122 | boolean bOpened = false; 123 | try { 124 | releaseCameraAndPreview(); 125 | mCamera = Camera.open(id); 126 | bOpened = (mCamera != null); 127 | } catch (Exception e) { 128 | e.printStackTrace(); 129 | } 130 | if (!bOpened) { 131 | Log.e(TAG, "failed to open Camera"); 132 | // Log.d(TAG, "Numbers " + Camera.getNumberOfCameras()); 133 | } 134 | return bOpened; 135 | } 136 | 137 | private void releaseCameraAndPreview() { 138 | if (mCamera != null) { 139 | previewing = false; 140 | mCamera.setPreviewCallback(null); 141 | mCamera.release(); 142 | mCamera = null; 143 | } 144 | // Log.d(TAG, "releaseCameraAndPreview"); 145 | } 146 | 147 | Camera.PreviewCallback previewCallback = new Camera.PreviewCallback() { 148 | @Override 149 | public void onPreviewFrame(byte[] data, Camera camera) { 150 | //every three times reverse image data once 151 | count++; 152 | if (count > 3) { 153 | reverseImageData(data); 154 | count = 0; 155 | } 156 | Camera.Parameters parameters = camera.getParameters(); 157 | Camera.Size size = parameters.getPreviewSize(); 158 | Image image = new Image(size.width, size.height, "Y800"); 159 | image.setData(data); 160 | int result = scanner.scanImage(image); 161 | if (result != 0) { 162 | previewing = false; 163 | mCamera.setPreviewCallback(null); 164 | mCamera.stopPreview(); 165 | SymbolSet symbolSet = scanner.getResults(); 166 | ArrayList list = new ArrayList<>(); 167 | for (Symbol symbol : symbolSet) { 168 | list.add(symbol.getData()); 169 | // scanned = true; 170 | Log.v(TAG, symbol.getData()); 171 | } 172 | finishAndSetResult(list); 173 | } 174 | } 175 | }; 176 | 177 | Camera.AutoFocusCallback autoFocusCallback = new Camera.AutoFocusCallback() { 178 | @Override 179 | public void onAutoFocus(boolean success, Camera camera) { 180 | autoFocusHandler.post(doAutoFocus); 181 | // Log.d(TAG, "auto focus"); 182 | } 183 | }; 184 | 185 | private Runnable doAutoFocus = new Runnable() { 186 | @Override 187 | public void run() { 188 | if (previewing) { 189 | mCamera.autoFocus(autoFocusCallback); 190 | } 191 | } 192 | }; 193 | 194 | SurfaceHolder.Callback holderCallback = new SurfaceHolder.Callback() { 195 | @Override 196 | public void surfaceCreated(SurfaceHolder holder) { 197 | try { 198 | mCamera.setPreviewDisplay(holder); 199 | } catch (IOException e) { 200 | e.printStackTrace(); 201 | } 202 | isSurfaceViewDestroyed = false; 203 | // Log.d(TAG, "surfaceCreated"); 204 | } 205 | 206 | @Override 207 | public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { 208 | if (holder.getSurface() == null) { 209 | return; 210 | } 211 | mCamera.stopPreview(); 212 | mCamera.setDisplayOrientation(90); 213 | mCamera.setPreviewCallback(previewCallback); 214 | mCamera.startPreview(); 215 | if (autoFocus) { 216 | mCamera.autoFocus(autoFocusCallback); 217 | } 218 | // Log.d(TAG, "surfaceChanged"); 219 | } 220 | 221 | @Override 222 | public void surfaceDestroyed(SurfaceHolder holder) { 223 | isSurfaceViewDestroyed = true; 224 | // Log.d(TAG, "surfaceDestroy"); 225 | } 226 | }; 227 | 228 | private boolean checkCameraHardware() { 229 | PackageManager manager = getPackageManager(); 230 | if (manager.hasSystemFeature(PackageManager.FEATURE_CAMERA) 231 | || manager.hasSystemFeature(PackageManager.FEATURE_CAMERA_FRONT)) { 232 | return true; 233 | } 234 | // Log.d(TAG, "No Camera Found"); 235 | return false; 236 | } 237 | 238 | private boolean checkCameraAutoFocus() { 239 | Camera.Parameters parameters = mCamera.getParameters(); 240 | List modes = parameters.getSupportedFocusModes(); 241 | if (modes.contains(Camera.Parameters.FOCUS_MODE_AUTO) || 242 | modes.contains(Camera.Parameters.FOCUS_MODE_MACRO)) { 243 | return true; 244 | } 245 | return false; 246 | } 247 | 248 | private void finishAndSetResult(ArrayList resultList) { 249 | Intent intent = new Intent(); 250 | intent.putStringArrayListExtra(RESULT, resultList); 251 | setResult(Activity.RESULT_OK, intent); 252 | finish(); 253 | } 254 | 255 | private void reverseImageData(byte[] data) { 256 | for (int i = 0; i < data.length; i++) { 257 | // data[i] = (byte) (~data[i] & 0xff); 258 | data[i] = (byte) (255 - data[i]); 259 | } 260 | } 261 | 262 | } 263 | -------------------------------------------------------------------------------- /app/src/main/java/com/dict/hm/dictionary/paper/JsonEntry.java: -------------------------------------------------------------------------------- 1 | package com.dict.hm.dictionary.paper; 2 | 3 | /** 4 | * Created by hm on 15-5-24. 5 | */ 6 | public class JsonEntry { 7 | String word; 8 | long count; 9 | 10 | public JsonEntry(String word, int count) { 11 | this.word = word; 12 | this.count = count; 13 | } 14 | 15 | public String getWord() { 16 | return word; 17 | } 18 | 19 | public long getCount() { 20 | return count; 21 | } 22 | 23 | @Override 24 | public String toString() { 25 | return word; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /app/src/main/java/com/dict/hm/dictionary/paper/PaperErrorCode.java: -------------------------------------------------------------------------------- 1 | package com.dict.hm.dictionary.paper; 2 | 3 | /** 4 | * Created by hm on 15-6-3. 5 | */ 6 | public class PaperErrorCode { 7 | public static final int ERR_GEN = -1; 8 | public static final int ERR_NET = -2; 9 | } 10 | -------------------------------------------------------------------------------- /app/src/main/java/com/dict/hm/dictionary/paper/PaperJsonReader.java: -------------------------------------------------------------------------------- 1 | package com.dict.hm.dictionary.paper; 2 | 3 | import android.util.JsonReader; 4 | import android.util.JsonWriter; 5 | import android.util.Log; 6 | 7 | import java.io.File; 8 | import java.io.FileNotFoundException; 9 | import java.io.FileReader; 10 | import java.io.FileWriter; 11 | import java.io.IOException; 12 | import java.util.ArrayList; 13 | 14 | /** 15 | * Created by hm on 15-3-25. 16 | */ 17 | public class PaperJsonReader { 18 | JsonReader reader; 19 | 20 | public PaperJsonReader(File json) { 21 | try { 22 | reader = new JsonReader(new FileReader(json)); 23 | } catch (FileNotFoundException e) { 24 | reader = null; 25 | e.printStackTrace(); 26 | } 27 | } 28 | 29 | public void openJson() { 30 | try { 31 | reader.beginObject(); 32 | } catch (IOException e) { 33 | e.printStackTrace(); 34 | } 35 | } 36 | 37 | public JsonEntry getNextJsonEntry() { 38 | JsonEntry entry = null; 39 | if (reader != null) { 40 | try { 41 | if (reader.hasNext()) { 42 | entry = new JsonEntry(reader.nextName(), reader.nextInt()); 43 | } 44 | } catch (IOException e) { 45 | e.printStackTrace(); 46 | Log.d("PaperJsonReader", "read json error"); 47 | } 48 | } 49 | return entry; 50 | } 51 | 52 | public void closeJson() { 53 | try { 54 | reader.close(); 55 | reader = null; 56 | } catch (IOException e) { 57 | e.printStackTrace(); 58 | } 59 | } 60 | 61 | /** 62 | * when you call endObject() at last, and you call hasNext() again, it will return true, 63 | * mark down and test it if needed. 64 | */ 65 | public ArrayList readAll() { 66 | ArrayList list = new ArrayList<>(); 67 | if (reader != null) { 68 | try { 69 | reader.beginObject(); 70 | while (reader.hasNext()) { 71 | list.add(new JsonEntry(reader.nextName(), reader.nextInt())); 72 | } 73 | reader.endObject(); 74 | } catch (IOException e) { 75 | e.printStackTrace(); 76 | Log.d("PaperJsonReader", "read json error"); 77 | } finally { 78 | try { 79 | reader.close(); 80 | reader = null; 81 | } catch (IOException e) { 82 | e.printStackTrace(); 83 | } 84 | } 85 | } 86 | return list; 87 | } 88 | 89 | } 90 | 91 | -------------------------------------------------------------------------------- /app/src/main/java/com/dict/hm/dictionary/paper/PaperJsonWriter.java: -------------------------------------------------------------------------------- 1 | package com.dict.hm.dictionary.paper; 2 | 3 | import android.util.JsonWriter; 4 | import android.util.Log; 5 | 6 | import java.io.File; 7 | import java.io.FileWriter; 8 | import java.io.IOException; 9 | import java.util.ArrayList; 10 | 11 | /** 12 | * Created by hm on 15-6-3. 13 | */ 14 | public class PaperJsonWriter { 15 | File json; 16 | 17 | public PaperJsonWriter(File json) { 18 | this.json = json; 19 | } 20 | 21 | public boolean storePaper(ArrayList sortedList) { 22 | if (json == null || json.isDirectory() || sortedList == null) { 23 | return false; 24 | } 25 | JsonWriter jsonWriter = null; 26 | try { 27 | try { 28 | json.createNewFile(); 29 | } catch (IOException e) { 30 | Log.d("error", "failed to create new file"); 31 | return false; 32 | } 33 | jsonWriter = new JsonWriter(new FileWriter(json)); 34 | jsonWriter.beginObject(); 35 | for (int i = 0; i < sortedList.size(); i++) { 36 | JsonEntry entry = sortedList.get(i); 37 | jsonWriter.name(entry.getWord()) 38 | .value(entry.getCount()); 39 | } 40 | jsonWriter.endObject(); 41 | jsonWriter.flush(); 42 | } catch (IOException e) { 43 | e.printStackTrace(); 44 | } finally { 45 | try { 46 | if (jsonWriter != null) { 47 | jsonWriter.close(); 48 | } 49 | } catch (IOException e) { 50 | e.printStackTrace(); 51 | } 52 | } 53 | return true; 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /app/src/main/java/com/dict/hm/dictionary/paper/PaperParser.java: -------------------------------------------------------------------------------- 1 | package com.dict.hm.dictionary.paper; 2 | 3 | import android.util.Log; 4 | import org.jsoup.Jsoup; 5 | import org.jsoup.helper.StringUtil; 6 | import org.jsoup.nodes.Document; 7 | import org.jsoup.nodes.Node; 8 | import org.jsoup.nodes.TextNode; 9 | import org.jsoup.select.NodeTraversor; 10 | import org.jsoup.select.NodeVisitor; 11 | import java.io.File; 12 | import java.io.FileNotFoundException; 13 | import java.io.IOException; 14 | import java.util.ArrayList; 15 | import java.util.Collections; 16 | import java.util.Comparator; 17 | import java.util.HashMap; 18 | import java.util.Map; 19 | import java.util.Scanner; 20 | 21 | /** 22 | * Created by hm on 15-3-3. 23 | */ 24 | public class PaperParser{ 25 | public static final int TXT = 0; 26 | public static final int HTML = 1; 27 | public static final int URL = 2; 28 | 29 | HashMap hashMap; 30 | File in; 31 | String url; 32 | String charset; 33 | int type; 34 | int error; 35 | 36 | public PaperParser(File in, String charset, int type) { 37 | this.in = in; 38 | this.charset = charset; 39 | this.type = type; 40 | } 41 | 42 | public PaperParser(String url) { 43 | if (url.startsWith("http://") || url.startsWith("https://")) { 44 | this.url = url; 45 | } else { 46 | this.url = "http://" + url; 47 | } 48 | this.type = URL; 49 | } 50 | 51 | public ArrayList parse() { 52 | hashMap = new HashMap<>(); 53 | boolean success = false; 54 | String text; 55 | switch (type) { 56 | case TXT: 57 | success = parseText(in, charset); 58 | break; 59 | case HTML: 60 | text = parseHtml(in, charset); 61 | success = parseText(text); 62 | break; 63 | case URL: 64 | if (url == null) { 65 | success = false; 66 | } else { 67 | text = parseURL(url); 68 | success = parseText(text); 69 | } 70 | break; 71 | } 72 | 73 | if (success) { 74 | return sort(hashMap); 75 | } 76 | return null; 77 | } 78 | 79 | public int getError() { 80 | return error; 81 | } 82 | 83 | private boolean parseText(File txt, String charset) { 84 | Scanner scanner; 85 | try { 86 | scanner = new Scanner(txt, charset); 87 | scanner.useDelimiter("[^a-zA-Z]+"); 88 | } catch (FileNotFoundException e) { 89 | e.printStackTrace(); 90 | return false; 91 | } 92 | return parseText(scanner); 93 | } 94 | 95 | private boolean parseText(String txt) { 96 | if (txt == null) { 97 | return false; 98 | } 99 | Scanner scanner; 100 | scanner = new Scanner(txt); 101 | scanner.useDelimiter("[^a-zA-Z]+"); 102 | return parseText(scanner); 103 | } 104 | 105 | private boolean parseText(Scanner scanner) { 106 | while (scanner.hasNext()) { 107 | String s = scanner.next(); 108 | s = s.toLowerCase(); 109 | if (hashMap.containsKey(s)) { 110 | Integer integer = hashMap.get(s); 111 | hashMap.put(s, integer + 1); 112 | } else { 113 | hashMap.put(s, 1); 114 | } 115 | } 116 | scanner.close(); 117 | return true; 118 | } 119 | 120 | private String parseHtml(File html, String charset) { 121 | String text = null; 122 | try { 123 | Document doc = Jsoup.parse(html, charset); 124 | FormattingVisitor formattingVisitor = new FormattingVisitor(); 125 | NodeTraversor nodeTraversor = new NodeTraversor(formattingVisitor); 126 | nodeTraversor.traverse(doc); 127 | text = formattingVisitor.toString(); 128 | } catch (IOException e) { 129 | e.printStackTrace(); 130 | } 131 | return text; 132 | } 133 | 134 | private String parseURL(String url) { 135 | String text; 136 | try { 137 | Document doc = Jsoup.connect(url).timeout(5000).get(); 138 | Log.d("parseURL", "return parsed doc"); 139 | FormattingVisitor formattingVisitor = new FormattingVisitor(); 140 | NodeTraversor nodeTraversor = new NodeTraversor(formattingVisitor); 141 | nodeTraversor.traverse(doc); 142 | text = formattingVisitor.toString(); 143 | } catch (IOException e) { 144 | error = PaperErrorCode.ERR_NET; 145 | e.printStackTrace(); 146 | text = null; 147 | } 148 | return text; 149 | } 150 | 151 | private ArrayList sort(HashMap hashMap) { 152 | ArrayList arrayList = new ArrayList<>(); 153 | for (Map.Entry entry : hashMap.entrySet()) { 154 | arrayList.add(new JsonEntry(entry.getKey(), entry.getValue())); 155 | } 156 | Collections.sort(arrayList, new Comparator() { 157 | @Override 158 | public int compare(JsonEntry lhs, JsonEntry rhs) { 159 | if (lhs.getCount() > rhs.getCount()) { 160 | return -1; 161 | } else if (lhs.getCount() < rhs.getCount()) { 162 | return 1; 163 | } 164 | return 0; 165 | } 166 | }); 167 | return arrayList; 168 | } 169 | 170 | private class FormattingVisitor implements NodeVisitor { 171 | private static final int maxWidth = 80; 172 | private int width = 0; 173 | private StringBuilder builder = new StringBuilder(); 174 | @Override 175 | public void head(Node node, int i) { 176 | String name = node.nodeName(); 177 | if (node instanceof TextNode) { 178 | append(((TextNode) node).text()); 179 | } else if (name.equals("li")) { 180 | append("\n * "); 181 | } 182 | } 183 | 184 | @Override 185 | public void tail(Node node, int i) { 186 | String name = node.nodeName(); 187 | if (name.equals("br")) { 188 | append("\n"); 189 | } else if (StringUtil.in(name, "p")) { 190 | append("\n\n"); 191 | // } else if (name.equals("a")) { 192 | // append(String.format(" <%s>", node.absUrl("href"))); 193 | } 194 | } 195 | 196 | private void append(String text) { 197 | if (text.startsWith("\n")) { 198 | width = 0; 199 | } 200 | 201 | if (text.equals(" ") && (builder.length() ==0 || 202 | StringUtil.in(builder.substring(builder.length() -1), " ", "\n"))) { 203 | return; 204 | } 205 | if (text.length() + width > maxWidth) { 206 | String words[] = text.split("\\s+"); 207 | for (int i = 0; i < words.length; i++) { 208 | String word = words[i]; 209 | boolean last = i == words.length -1; 210 | if (!last) { 211 | word = word + " "; 212 | } 213 | if (word.length() + width > maxWidth) { 214 | builder.append("\n").append(word); 215 | width = word.length(); 216 | } else { 217 | builder.append(word); 218 | width = word.length(); 219 | } 220 | } 221 | } else { 222 | builder.append(text); 223 | width += text.length(); 224 | } 225 | } 226 | 227 | @Override 228 | public String toString() { 229 | return builder.toString(); 230 | } 231 | } 232 | } 233 | -------------------------------------------------------------------------------- /app/src/main/java/com/dict/hm/dictionary/ui/BaseManagerActivity.java: -------------------------------------------------------------------------------- 1 | package com.dict.hm.dictionary.ui; 2 | 3 | import android.app.Fragment; 4 | import android.app.FragmentTransaction; 5 | import android.os.Bundle; 6 | import android.support.design.widget.FloatingActionButton; 7 | import android.support.design.widget.Snackbar; 8 | import android.support.v7.app.ActionBar; 9 | import android.support.v7.app.AppCompatActivity; 10 | import android.support.v7.widget.Toolbar; 11 | import android.util.TypedValue; 12 | import android.view.MenuItem; 13 | import android.view.View; 14 | import android.widget.ImageView; 15 | import android.widget.ListView; 16 | import android.widget.TextView; 17 | 18 | import com.dict.hm.dictionary.R; 19 | import com.dict.hm.dictionary.ui.dialog.AlertDialogFragment; 20 | import com.dict.hm.dictionary.ui.dialog.EditDialog; 21 | import com.dict.hm.dictionary.ui.dialog.NotificationDialog; 22 | import com.dict.hm.dictionary.ui.dialog.ProgressDialog; 23 | 24 | import java.io.File; 25 | 26 | /** 27 | * Created by hm on 15-3-18. 28 | */ 29 | public abstract class BaseManagerActivity extends AppCompatActivity 30 | implements FileListFragment.FileSelectedListener, 31 | AlertDialogFragment.ConfirmDialogListener, 32 | EditDialog.EditDialogListener { 33 | 34 | public static final String FRAGMENT_TAG = "top"; 35 | ActionBar actionBar; 36 | Toolbar toolbar; 37 | ListView listView; 38 | TextView empty; 39 | FloatingActionButton fab; 40 | FileListFragment fileListFragment; 41 | 42 | File selectedFile; 43 | String title = null; 44 | 45 | int action = -1; 46 | static final int ADD = 0; 47 | static final int DEL = 1; 48 | 49 | String notification = null; 50 | boolean isStop; 51 | 52 | @Override 53 | protected void onCreate(Bundle savedInstanceState) { 54 | super.onCreate(savedInstanceState); 55 | 56 | setContentView(R.layout.activity_manager); 57 | toolbar = (Toolbar) findViewById(R.id.manager_toolbar); 58 | listView = (ListView) findViewById(R.id.manager_listView); 59 | empty = (TextView) findViewById(R.id.emptyView); 60 | fab = (FloatingActionButton) findViewById(R.id.manager_fab); 61 | setSupportActionBar(toolbar); 62 | listView.setEmptyView(empty); 63 | 64 | actionBar = getSupportActionBar(); 65 | if (actionBar != null) { 66 | actionBar.setHomeButtonEnabled(true); 67 | actionBar.setDisplayHomeAsUpEnabled(true); 68 | actionBar.setTitle(null); 69 | } 70 | } 71 | 72 | @Override 73 | public boolean onOptionsItemSelected(MenuItem item) { 74 | switch (item.getItemId()) { 75 | case android.R.id.home: 76 | if (!dismissFragment()) { 77 | finish(); 78 | } 79 | return true; 80 | default: 81 | return super.onOptionsItemSelected(item); 82 | } 83 | } 84 | 85 | @Override 86 | public void onBackPressed() { 87 | if (fileListFragment != null ) { 88 | if (fileListFragment.onBackPressed()) { 89 | return; 90 | } else { 91 | dismissFragment(); 92 | return; 93 | } 94 | } 95 | if (dismissFragment()) { 96 | return; 97 | } 98 | super.onBackPressed(); 99 | } 100 | 101 | @Override 102 | protected void onStop() { 103 | super.onStop(); 104 | isStop = true; 105 | } 106 | 107 | @Override 108 | protected void onStart() { 109 | super.onStart(); 110 | isStop = false; 111 | if (notification != null) { 112 | setNotification(notification); 113 | } 114 | } 115 | 116 | protected void showFragment(Fragment fragment) { 117 | getFragmentManager().beginTransaction() 118 | .add(R.id.manager_frame, fragment, FRAGMENT_TAG) 119 | .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN) 120 | .commit(); 121 | listView.setVisibility(View.INVISIBLE); 122 | empty.setVisibility(View.INVISIBLE); 123 | // if (actionBar != null) { 124 | // actionBar.setHomeButtonEnabled(true); 125 | // actionBar.setDisplayHomeAsUpEnabled(true); 126 | // } 127 | } 128 | 129 | protected boolean dismissFragment() { 130 | Fragment fragment = getFragmentManager().findFragmentByTag(FRAGMENT_TAG); 131 | if (fragment == null) { 132 | return false; 133 | } 134 | getFragmentManager().beginTransaction() 135 | .remove(fragment) 136 | .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_CLOSE) 137 | .commit(); 138 | listView.setVisibility(View.VISIBLE); 139 | if (listView.getAdapter().isEmpty()) { 140 | empty.setVisibility(View.VISIBLE); 141 | } 142 | // if (actionBar != null) { 143 | // actionBar.setHomeButtonEnabled(false); 144 | // actionBar.setDisplayHomeAsUpEnabled(false); 145 | // } 146 | // toolbar.setTitle(title); 147 | fileListFragment = null; 148 | return true; 149 | } 150 | 151 | /** 152 | * after onStop() call this method (fragment's commit() method) will cause IllegalStateException. 153 | * 154 | * @param text 155 | */ 156 | public void setNotification(String text) { 157 | if (isStop) { 158 | notification = text; 159 | return; 160 | } else { 161 | notification = null; 162 | } 163 | NotificationDialog dialog = NotificationDialog.newInstance(text); 164 | dialog.show(getFragmentManager(), null); 165 | 166 | if (fab.getVisibility() == View.VISIBLE) { 167 | final float y = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 72, 168 | getResources().getDisplayMetrics()); 169 | fab.animate().translationYBy(-y); 170 | dialog.setFab(fab, y); 171 | } 172 | } 173 | 174 | public void setProgressDialog(int progress) { 175 | if (dialog != null && dialog.isAdded()) { 176 | dialog.setProgressBar(progress); 177 | } 178 | } 179 | 180 | public void dismissProgressDialog() { 181 | if (dialog != null) { 182 | dialog.dismissAllowingStateLoss(); 183 | } 184 | } 185 | 186 | public void initProgressDialog(String msg, int max) { 187 | dialog = ProgressDialog.newInstance(msg, max); 188 | dialog.show(getFragmentManager(), null); 189 | } 190 | ProgressDialog dialog; 191 | 192 | } 193 | -------------------------------------------------------------------------------- /app/src/main/java/com/dict/hm/dictionary/ui/DialogExPreference.java: -------------------------------------------------------------------------------- 1 | package com.dict.hm.dictionary.ui; 2 | 3 | import android.content.Context; 4 | import android.preference.DialogPreference; 5 | import android.util.AttributeSet; 6 | 7 | import com.dict.hm.dictionary.R; 8 | import com.dict.hm.dictionary.dict.DictManager; 9 | 10 | /** 11 | * Created by hm on 15-6-5. 12 | */ 13 | public class DialogExPreference extends DialogPreference{ 14 | String key_paper; 15 | String key_dict; 16 | public DialogExPreference(Context context, AttributeSet attrs) { 17 | super(context, attrs); 18 | setDialogTitle(null); 19 | key_paper = context.getString(R.string.action_clear_paper); 20 | key_dict = context.getString(R.string.action_clear_user_dict); 21 | } 22 | 23 | @Override 24 | protected void onDialogClosed(boolean positiveResult) { 25 | if (positiveResult) { 26 | DictManager manager = DictManager.getInstance(getContext()); 27 | CharSequence key = getTitle(); 28 | if (key.equals(key_dict)) { 29 | manager.clearUserDict(); 30 | } else { 31 | manager.clearPaper(); 32 | } 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /app/src/main/java/com/dict/hm/dictionary/ui/DictManagerActivity.java: -------------------------------------------------------------------------------- 1 | package com.dict.hm.dictionary.ui; 2 | 3 | import android.content.Intent; 4 | import android.graphics.Bitmap; 5 | import android.graphics.Canvas; 6 | import android.graphics.drawable.BitmapDrawable; 7 | import android.graphics.drawable.Drawable; 8 | import android.net.Uri; 9 | import android.os.Build; 10 | import android.os.Bundle; 11 | import android.os.Environment; 12 | import android.os.Handler; 13 | import android.os.Message; 14 | import android.util.Log; 15 | import android.view.MenuItem; 16 | import android.view.View; 17 | import android.widget.AdapterView; 18 | import android.widget.ArrayAdapter; 19 | import android.widget.Toast; 20 | 21 | import com.dict.hm.dictionary.R; 22 | import com.dict.hm.dictionary.dict.DictFormat; 23 | import com.dict.hm.dictionary.dict.DictManager; 24 | import com.dict.hm.dictionary.async.HttpDownload; 25 | import com.dict.hm.dictionary.lib.ZBarActivity; 26 | import com.dict.hm.dictionary.dict.parse.IfoFormat; 27 | import com.dict.hm.dictionary.ui.dialog.AlertDialogFragment; 28 | import com.dict.hm.dictionary.ui.dialog.EditDialog; 29 | 30 | import java.io.File; 31 | import java.util.ArrayList; 32 | 33 | /** 34 | * Created by hm on 15-3-18. 35 | */ 36 | public class DictManagerActivity extends BaseManagerActivity { 37 | 38 | public static final int ERR = -1; 39 | public static final int OK = 0; 40 | public static final int PROCESSING = 1; 41 | public static final int DELETE = 2; 42 | 43 | public static final int DECOMPRESS = 10; 44 | public static final int DECOMPRESS_ERR = -10; 45 | 46 | private ArrayAdapter adapter; 47 | private int deleteItemPosition; 48 | private DictManager manager; 49 | private int wordCount; 50 | 51 | @Override 52 | protected void onCreate(Bundle savedInstanceState) { 53 | super.onCreate(savedInstanceState); 54 | 55 | //manage dictionary 56 | // title = getString(R.string.title_dict); 57 | empty.setText("No Dictionary"); 58 | // setTitle(title); 59 | listView.setOnItemClickListener(dictClickListener); 60 | fab.setVisibility(View.VISIBLE); 61 | fab.setOnClickListener(fabClickListener); 62 | 63 | manager = DictManager.getInstance(this); 64 | adapter = new ArrayAdapter<>(this, R.layout.textview_item, manager.getDictFormats()); 65 | listView.setAdapter(adapter); 66 | } 67 | 68 | // @Override 69 | // public boolean onCreateOptionsMenu(Menu menu) { 70 | // getMenuInflater().inflate(R.menu.menu_dict_manager, menu); 71 | // return true; 72 | // } 73 | 74 | @Override 75 | public boolean onOptionsItemSelected(MenuItem item) { 76 | if (item.getItemId() == R.id.action_add_url) { 77 | EditDialog editDialog = EditDialog.newInstance("Input Url", "http://"); 78 | editDialog.show(getFragmentManager(), null); 79 | return true; 80 | } else if (item.getItemId() == R.id.action_scan_qrcode) { 81 | Intent intent = new Intent(this, ZBarActivity.class); 82 | startActivityForResult(intent, 0); 83 | return true; 84 | } 85 | return super.onOptionsItemSelected(item); 86 | } 87 | 88 | @Override 89 | protected void onActivityResult(int requestCode, int resultCode, Intent data) { 90 | super.onActivityResult(requestCode, resultCode, data); 91 | if (resultCode == RESULT_OK) { 92 | ArrayList list = data.getStringArrayListExtra(ZBarActivity.RESULT); 93 | if (list.size() == 1) { 94 | onEditDialogPositiveClick(list.get(0)); 95 | Log.v("result", list.get(0)); 96 | } else if (list.size() > 1) { 97 | //TODO: handle more than one scanning result. 98 | onEditDialogPositiveClick(list.get(0)); 99 | } 100 | } 101 | } 102 | 103 | @Override 104 | public void onEditDialogPositiveClick(String url) { 105 | String filePath = Environment.getExternalStorageDirectory().getPath(); 106 | Uri uri = Uri.parse(url); 107 | new HttpDownload(this).execute(url, filePath + "/" + uri.getLastPathSegment()); 108 | } 109 | 110 | @Override 111 | public void onDialogPositiveClick() { 112 | switch (action) { 113 | case ADD: 114 | if (fileListFragment != null) { 115 | DictFormat format = manager.addDictionary(selectedFile, handler); 116 | if (format != null) { 117 | dismissFragment(); 118 | initProgressDialog("Loading...", wordCount); 119 | } 120 | } 121 | break; 122 | case DEL: 123 | manager.removeDictionary(deleteItemPosition, handler); 124 | break; 125 | } 126 | action = -1; 127 | adapter.notifyDataSetChanged(); 128 | } 129 | 130 | @Override 131 | public void onFileSelectedListener(File file) { 132 | String name = file.getName(); 133 | if (name.endsWith(".ifo")) { 134 | IfoFormat format = new IfoFormat(file); 135 | String msg = "Book Name: " + format.getBookName() + '\n' 136 | + "Version: " + format.getVersion() + '\n' 137 | + "Word Count: " + format.getWordCount(); 138 | AlertDialogFragment dialogFragment = AlertDialogFragment 139 | .newInstance("Add Dictionary", msg, "Add", "Cancel"); 140 | dialogFragment.show(getFragmentManager(), null); 141 | action = ADD; 142 | selectedFile = file; 143 | wordCount = format.getWordCount(); 144 | } else { 145 | Toast.makeText(this, "please select .ifo file", Toast.LENGTH_LONG).show(); 146 | } 147 | } 148 | 149 | @Override 150 | protected boolean dismissFragment() { 151 | fab.setVisibility(View.VISIBLE); 152 | return super.dismissFragment(); 153 | } 154 | 155 | private View.OnClickListener fabClickListener = new View.OnClickListener() { 156 | @Override 157 | public void onClick(View v) { 158 | fileListFragment = new FileListFragment(); 159 | showFragment(fileListFragment); 160 | fab.setVisibility(View.INVISIBLE); 161 | } 162 | }; 163 | 164 | private AdapterView.OnItemClickListener dictClickListener = new AdapterView.OnItemClickListener() { 165 | @Override 166 | public void onItemClick(AdapterView parent, View view, int position, long id) { 167 | DictFormat dictFormat = (DictFormat) parent.getItemAtPosition(position); 168 | String ifoPath = dictFormat.getData(); 169 | IfoFormat format = new IfoFormat(new File(ifoPath)); 170 | String msg = "Book Name: " + format.getBookName() + '\n' 171 | + "Version: " + format.getVersion() + '\n' 172 | + "Word Count: " + format.getWordCount(); 173 | 174 | AlertDialogFragment dialogFragment = AlertDialogFragment 175 | .newInstance("Remove Dictionary?", msg, "Remove", "Cancel"); 176 | dialogFragment.show(getFragmentManager(), null); 177 | deleteItemPosition = position; 178 | action = DEL; 179 | } 180 | }; 181 | 182 | Handler handler = new Handler(new Handler.Callback() { 183 | @Override 184 | public boolean handleMessage(Message msg) { 185 | switch (msg.what) { 186 | case ERR: // something wrong happened 187 | return true; 188 | case PROCESSING: //in inserting words to SQLiteDatabase 189 | setProgressDialog(msg.arg1); 190 | return true; 191 | case OK: //have done loading new dictionary words index to SQLiteDatabase 192 | dismissProgressDialog(); 193 | setNotification(msg.obj + " has been added"); 194 | return true; 195 | case DELETE: //delete SQLiteDatabase table 196 | setNotification(msg.obj + " has been removed"); 197 | return true; 198 | case DECOMPRESS: //have done decompressing 199 | return true; 200 | case DECOMPRESS_ERR: 201 | return true; 202 | default: 203 | return false; 204 | } 205 | } 206 | }); 207 | 208 | } 209 | -------------------------------------------------------------------------------- /app/src/main/java/com/dict/hm/dictionary/ui/FileListFragment.java: -------------------------------------------------------------------------------- 1 | package com.dict.hm.dictionary.ui; 2 | 3 | import android.app.Activity; 4 | import android.app.Fragment; 5 | import android.content.Context; 6 | import android.os.Bundle; 7 | import android.os.Environment; 8 | import android.util.Log; 9 | import android.view.LayoutInflater; 10 | import android.view.View; 11 | import android.view.ViewGroup; 12 | import android.widget.AdapterView; 13 | import android.widget.ArrayAdapter; 14 | import android.widget.ListView; 15 | import android.widget.TextView; 16 | 17 | import com.dict.hm.dictionary.R; 18 | 19 | import java.io.File; 20 | import java.util.ArrayList; 21 | import java.util.Collections; 22 | 23 | /** 24 | * Created by hm on 15-1-7. 25 | * 26 | * Help to load file like *.ifo, *.txt and so on. 27 | * load Dictionary *.ifo 28 | * load text file, which contains your own words, like top 5000 words. 29 | */ 30 | public class FileListFragment extends Fragment { 31 | public static final String FILEPATH = "FileListFragment"; 32 | private File curDir = null; 33 | private Context context; 34 | private ListView listView; 35 | private TextView emptyText; 36 | private FileSelectedListener listener; 37 | 38 | public interface FileSelectedListener { 39 | void onFileSelectedListener(File file); 40 | } 41 | @Override 42 | public void onAttach(Activity activity) { 43 | super.onAttach(activity); 44 | context = activity; 45 | try { 46 | listener = (FileSelectedListener) activity; 47 | } catch (ClassCastException e) { 48 | throw new ClassCastException(activity.toString() 49 | + " must implement interface FileSelectedListener"); 50 | } 51 | } 52 | 53 | @Override 54 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 55 | View view = inflater.inflate(R.layout.fragment_file, container, false); 56 | listView = (ListView) view.findViewById(R.id.file_listView); 57 | emptyText = (TextView) view.findViewById(R.id.file_emptyView); 58 | 59 | return view; 60 | } 61 | 62 | @Override 63 | public void onActivityCreated(Bundle savedInstanceState) { 64 | Log.d("FileListFragment", "onActivityCreated"); 65 | super.onCreate(savedInstanceState); 66 | emptyText.setText("No File"); 67 | listView.setOnItemClickListener(fileListViewListener); 68 | listView.setEmptyView(emptyText); 69 | 70 | Bundle bundle = getArguments(); 71 | File rootDir; 72 | if (bundle != null) { 73 | String path = bundle.getString(FILEPATH); 74 | rootDir = new File(path); 75 | } else { 76 | rootDir = Environment.getExternalStorageDirectory(); 77 | } 78 | 79 | if (rootDir.isDirectory()) { 80 | length = rootDir.getAbsolutePath().length(); 81 | onDictionarySelected(rootDir); 82 | } 83 | // getActivity().setTitle("Select File"); 84 | } 85 | 86 | int length; 87 | public boolean onBackPressed() { 88 | Log.d("FileListFragment", "onBackPressed"); 89 | if(curDir != null) { 90 | if (curDir.getAbsolutePath().length() > length) { 91 | onDictionarySelected(curDir.getParentFile()); 92 | return true; 93 | } 94 | } 95 | return false; 96 | } 97 | 98 | AdapterView.OnItemClickListener fileListViewListener = new AdapterView.OnItemClickListener(){ 99 | @Override 100 | public void onItemClick(AdapterView parent, View view, int position, long id) { 101 | String fileName = (String) parent.getItemAtPosition(position); 102 | File file = new File(curDir, fileName); 103 | onDictionarySelected(file); 104 | } 105 | }; 106 | 107 | private void onDictionarySelected(File file) { 108 | Log.d(FILEPATH, file.getPath()); 109 | if (file.isFile()) { 110 | listener.onFileSelectedListener(file); 111 | return; 112 | } 113 | String[] names = file.list(); 114 | if (names == null) { 115 | return; 116 | } 117 | 118 | ArrayList list = new ArrayList<>(); 119 | for (String name : names) { 120 | list.add(name); 121 | } 122 | Collections.sort(list); 123 | curDir = file; 124 | ArrayAdapter adapter = new ArrayAdapter<>(context, R.layout.textview_item, list); 125 | listView.setAdapter(adapter); 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /app/src/main/java/com/dict/hm/dictionary/ui/PaperArchiveFragment.java: -------------------------------------------------------------------------------- 1 | package com.dict.hm.dictionary.ui; 2 | 3 | import android.app.ListFragment; 4 | import android.os.Bundle; 5 | import android.support.v7.app.ActionBar; 6 | import android.view.Menu; 7 | import android.view.MenuInflater; 8 | import android.view.MenuItem; 9 | import android.view.View; 10 | import android.widget.ListView; 11 | 12 | import java.io.File; 13 | import java.util.ArrayList; 14 | 15 | import com.dict.hm.dictionary.paper.JsonEntry; 16 | import com.dict.hm.dictionary.paper.PaperWorkerHandler; 17 | import com.dict.hm.dictionary.ui.PaperManagerActivity; 18 | import com.dict.hm.dictionary.R; 19 | import com.dict.hm.dictionary.ui.adapter.PaperJsonAdapter; 20 | 21 | 22 | /** 23 | * Created by hm on 15-1-22. 24 | */ 25 | public class PaperArchiveFragment extends ListFragment { 26 | public static final String JSON_PATH = "path"; 27 | 28 | File jsonFile; 29 | boolean isManual; 30 | 31 | PaperJsonAdapter adapter = null; 32 | PaperWorkerHandler paperWorkerHandler = null; 33 | PaperManagerActivity activity = null; 34 | Menu menu; 35 | ActionBar actionBar; 36 | 37 | @Override 38 | public void onCreate(Bundle savedInstanceState) { 39 | super.onCreate(savedInstanceState); 40 | setHasOptionsMenu(true); 41 | } 42 | 43 | @Override 44 | public void onActivityCreated(Bundle savedInstanceState) { 45 | super.onCreate(savedInstanceState); 46 | setListShown(true); 47 | setListAdapter(null); 48 | // getListView().setChoiceMode(AbsListView.CHOICE_MODE_SINGLE); 49 | // drawable = getListView().getSelector(); 50 | 51 | isManual = false; 52 | activity = (PaperManagerActivity) getActivity(); 53 | // activity.setTitle(getActivity().getResources().getString(R.string.title_paper_archive)); 54 | actionBar = activity.getSupportActionBar(); 55 | 56 | Bundle bundle = getArguments(); 57 | String jsonPath = bundle.getString(JSON_PATH); 58 | if (jsonPath == null) { 59 | setEmptyText("missing paper"); 60 | } else { 61 | jsonFile = new File(jsonPath); 62 | paperWorkerHandler = activity.getPaperWorkerHandler(); 63 | paperWorkerHandler.startJsonRead(jsonFile); 64 | } 65 | } 66 | 67 | @Override 68 | public void onDestroy() { 69 | super.onDestroy(); 70 | actionBar.setHomeAsUpIndicator(null); 71 | } 72 | 73 | @Override 74 | public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { 75 | inflater.inflate(R.menu.menu_archive, menu); 76 | menu.findItem(R.id.action_save).setVisible(false); 77 | menu.findItem(R.id.action_attachment).setVisible(false); 78 | menu.findItem(R.id.action_add_url).setVisible(false); 79 | menu.findItem(R.id.action_scan_qrcode).setVisible(false); 80 | this.menu = menu; 81 | } 82 | 83 | @Override 84 | public boolean onOptionsItemSelected(MenuItem item) { 85 | if (adapter == null) { 86 | return false; 87 | } 88 | int id = item.getItemId(); 89 | switch (id) { 90 | case R.id.action_filter: 91 | /** 92 | * this will filter the word, that had been existed in UserDict. 93 | * And left the new words. 94 | */ 95 | archiveALL(true); 96 | return true; 97 | case R.id.action_archive: 98 | /** 99 | * this will archive all the words into MyDict. 100 | */ 101 | archiveALL(false); 102 | return true; 103 | case R.id.action_manual: 104 | startManual(); 105 | return true; 106 | case R.id.action_save: 107 | archiveManual(); 108 | finishManual(); 109 | return true; 110 | } 111 | return super.onOptionsItemSelected(item); 112 | } 113 | 114 | /** 115 | * record the click item's position 116 | */ 117 | @Override 118 | public void onListItemClick(ListView l, View v, int position, long id) { 119 | if (isManual) { 120 | adapter.removeItem(position); 121 | } 122 | } 123 | 124 | /** 125 | * start to manually select words 126 | */ 127 | private void startManual() { 128 | /** 129 | * show the archiving interface 130 | */ 131 | menu.findItem(R.id.action_archive).setVisible(false); 132 | menu.findItem(R.id.action_filter).setVisible(false); 133 | menu.findItem(R.id.action_manual).setVisible(false); 134 | menu.findItem(R.id.action_save).setVisible(true); 135 | isManual = true; 136 | actionBar.setHomeAsUpIndicator(R.drawable.ic_close_white_18dp); 137 | // getListView().setChoiceMode(AbsListView.CHOICE_MODE_MULTIPLE); 138 | // getListView().setSelector(android.R.color.transparent); 139 | adapter.clearRemovedList(); 140 | } 141 | 142 | private void finishManual() { 143 | menu.findItem(R.id.action_archive).setVisible(true); 144 | menu.findItem(R.id.action_filter).setVisible(true); 145 | menu.findItem(R.id.action_manual).setVisible(true); 146 | menu.findItem(R.id.action_save).setVisible(false); 147 | 148 | isManual = false; 149 | actionBar.setHomeAsUpIndicator(null); 150 | // getListView().setChoiceMode(AbsListView.CHOICE_MODE_SINGLE); 151 | // getListView().setSelector(drawable); 152 | } 153 | 154 | private void archiveALL(boolean filter) { 155 | ArrayList words = adapter.getList(); 156 | if (filter) { 157 | paperWorkerHandler.startArchive(words, jsonFile, PaperWorkerHandler.FILTER); 158 | activity.initProgressDialog("Filter words...", 0); 159 | } else { 160 | paperWorkerHandler.startArchive(words, jsonFile, PaperWorkerHandler.ALL); 161 | activity.initProgressDialog("Archive all words", 0); 162 | } 163 | } 164 | 165 | private void archiveManual() { 166 | ArrayList words = adapter.getRemovedList(); 167 | paperWorkerHandler.startArchive(words, jsonFile, PaperWorkerHandler.MANUAL); 168 | paperWorkerHandler.startJsonWrite(jsonFile, adapter.getList()); 169 | activity.initProgressDialog("Archive selected words", 0); 170 | } 171 | 172 | public void setAdapter(ArrayList arrayList) { 173 | if (arrayList != null) { 174 | adapter = new PaperJsonAdapter(getActivity(), arrayList); 175 | setListAdapter(adapter); 176 | } 177 | setEmptyText("No Word"); 178 | } 179 | 180 | public void onFilterComplete(ArrayList left) { 181 | adapter.setList(left); 182 | } 183 | 184 | } 185 | 186 | -------------------------------------------------------------------------------- /app/src/main/java/com/dict/hm/dictionary/ui/PaperViewerFragment.java: -------------------------------------------------------------------------------- 1 | package com.dict.hm.dictionary.ui; 2 | 3 | import android.app.Activity; 4 | import android.app.ListFragment; 5 | import android.os.Bundle; 6 | 7 | import com.dict.hm.dictionary.paper.PaperJsonReader; 8 | import com.dict.hm.dictionary.ui.MainActivity; 9 | import com.dict.hm.dictionary.dict.DictManager; 10 | import com.dict.hm.dictionary.dict.parse.DictParser; 11 | import com.dict.hm.dictionary.ui.adapter.PaperViewerAdapter; 12 | 13 | import java.io.File; 14 | 15 | /** 16 | * Created by hm on 15-5-28. 17 | */ 18 | public class PaperViewerFragment extends ListFragment{ 19 | public static final String PAPER_NAME = "paper_name"; 20 | DictParser dictParser; 21 | PaperJsonReader jsonReader; 22 | 23 | @Override 24 | public void onAttach(Activity activity) { 25 | super.onAttach(activity); 26 | dictParser = DictManager.getInstance(activity).getDictParser(); 27 | } 28 | 29 | @Override 30 | public void onActivityCreated(Bundle savedInstanceState) { 31 | super.onActivityCreated(savedInstanceState); 32 | Bundle bundle = getArguments(); 33 | String name = bundle.getString(PAPER_NAME); 34 | if (name != null) { 35 | File json = new File(DictManager.getInstance(getActivity()).getPaperDir(), name); 36 | jsonReader = new PaperJsonReader(json); 37 | jsonReader.openJson(); 38 | PaperViewerAdapter adapter = new PaperViewerAdapter(getActivity(), jsonReader, dictParser); 39 | setListAdapter(adapter); 40 | } else { 41 | setEmptyText("Missing Paper"); 42 | //setListShown to true will display empty text. Or it will display the ProgressBar. 43 | setListShown(true); 44 | } 45 | } 46 | 47 | @Override 48 | public void onDestroyView() { 49 | super.onDestroyView(); 50 | if (jsonReader != null) { 51 | jsonReader.closeJson(); 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /app/src/main/java/com/dict/hm/dictionary/ui/SettingsFragment.java: -------------------------------------------------------------------------------- 1 | package com.dict.hm.dictionary.ui; 2 | 3 | import android.os.Bundle; 4 | import android.preference.PreferenceFragment; 5 | 6 | import com.dict.hm.dictionary.R; 7 | 8 | /** 9 | * Created by hm on 15-6-1. 10 | */ 11 | public class SettingsFragment extends PreferenceFragment { 12 | 13 | @Override 14 | public void onCreate(Bundle savedInstanceState) { 15 | super.onCreate(savedInstanceState); 16 | addPreferencesFromResource(R.xml.preferences); 17 | getActivity().setTheme(R.style.SettingsPreferenceStyle); 18 | } 19 | 20 | 21 | } 22 | -------------------------------------------------------------------------------- /app/src/main/java/com/dict/hm/dictionary/ui/UserDictFragment.java: -------------------------------------------------------------------------------- 1 | package com.dict.hm.dictionary.ui; 2 | 3 | import android.app.ListFragment; 4 | import android.content.ContentResolver; 5 | import android.database.Cursor; 6 | import android.net.Uri; 7 | import android.os.Bundle; 8 | import android.view.Menu; 9 | import android.view.MenuInflater; 10 | import android.view.MenuItem; 11 | import android.view.View; 12 | import android.widget.ListView; 13 | 14 | import com.dict.hm.dictionary.R; 15 | import com.dict.hm.dictionary.async.UserAsyncWorkerHandler; 16 | import com.dict.hm.dictionary.dict.DictContentProvider; 17 | import com.dict.hm.dictionary.dict.DictManager; 18 | import com.dict.hm.dictionary.dict.DictSQLiteDefine; 19 | import com.dict.hm.dictionary.dict.UserDictSQLiteHelper; 20 | import com.dict.hm.dictionary.dict.parse.DictParser; 21 | import com.dict.hm.dictionary.ui.adapter.UserDictAdapter; 22 | import com.dict.hm.dictionary.ui.dialog.DefinitionDialog; 23 | import com.dict.hm.dictionary.ui.dialog.SelectDialog; 24 | 25 | import java.util.ArrayList; 26 | 27 | /** 28 | * Created by hm on 15-6-9. 29 | */ 30 | public class UserDictFragment extends ListFragment 31 | implements UserAsyncWorkerHandler.UserDictQueryListener, 32 | SelectDialog.OrderSelectListener { 33 | public static final int ORDER_COUNT = 0; 34 | public static final int ORDER_TIME = 1; 35 | public static final int ORDER_OTHER = 2; 36 | public static final int size = 100; 37 | private UserDictAdapter userDictAdapter = null; 38 | private UserAsyncWorkerHandler userHandler; 39 | private Uri uri; 40 | private DictManager manager; 41 | 42 | @Override 43 | public void onCreate(Bundle savedInstanceState) { 44 | super.onCreate(savedInstanceState); 45 | setHasOptionsMenu(true); 46 | } 47 | 48 | @Override 49 | public void onActivityCreated(Bundle savedInstanceState) { 50 | super.onActivityCreated(savedInstanceState); 51 | 52 | userHandler = UserAsyncWorkerHandler.getInstance(getActivity(), null); 53 | userHandler.setUserDictQueryListener(this); 54 | userHandler.startQuery(ORDER_OTHER); 55 | 56 | userDictAdapter = new UserDictAdapter(getActivity()); 57 | setEmptyText(getResources().getString(R.string.action_user_dict)); 58 | setListAdapter(userDictAdapter); 59 | setListShown(true); 60 | 61 | manager = DictManager.getInstance(getActivity()); 62 | uri = Uri.withAppendedPath(DictContentProvider.CONTENT_URI, "word"); 63 | } 64 | 65 | @Override 66 | public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { 67 | inflater.inflate(R.menu.menu_user_dict, menu); 68 | } 69 | 70 | @Override 71 | public boolean onOptionsItemSelected(MenuItem item) { 72 | if (item.getItemId() == R.id.order) { 73 | SelectDialog dialog = new SelectDialog(); 74 | dialog.setTargetFragment(this, 0); 75 | dialog.show(getFragmentManager(), null); 76 | return true; 77 | } else { 78 | return super.onOptionsItemSelected(item); 79 | } 80 | } 81 | 82 | @Override 83 | public void onListItemClick(ListView l, View v, int position, long id) { 84 | DictParser dictParser = manager.getDictParser(); 85 | if (dictParser == null) { 86 | return; 87 | } 88 | String word = (String) l.getItemAtPosition(position); 89 | ContentResolver contentResolver = getActivity().getContentResolver(); 90 | Cursor cursor = contentResolver.query(uri, null, null, new String[]{word}, null); 91 | if (cursor != null) { 92 | if (cursor.moveToFirst()) { 93 | int offset = cursor.getInt(cursor.getColumnIndex(DictSQLiteDefine.COLUMN_OFFSET)); 94 | int size = cursor.getInt(cursor.getColumnIndex(DictSQLiteDefine.COLUMN_SIZE)); 95 | String definition = dictParser.getWordDefinition(offset, size); 96 | DefinitionDialog.getDefinitionDialog(word, definition).show(getFragmentManager(), null); 97 | } 98 | cursor.close(); 99 | } 100 | } 101 | 102 | /** -----------------------------------------------------------------------------------------*/ 103 | //TODO: remove the lastID, sort the words by count or time. get all the words in one time. 104 | @Override 105 | public void onUserDictQueryComplete(Cursor cursor) { 106 | ArrayList words = new ArrayList<>(); 107 | ArrayList counts = new ArrayList<>(); 108 | ArrayList times = new ArrayList<>(); 109 | 110 | if (cursor != null) { 111 | if (cursor.moveToFirst()) { 112 | int wordIndex = cursor.getColumnIndex(UserDictSQLiteHelper.COLUMN_WORD); 113 | int countIndex = cursor.getColumnIndex(UserDictSQLiteHelper.COLUMN_COUNT); 114 | int timeIndex = cursor.getColumnIndex(UserDictSQLiteHelper.COLUMN_TIME); 115 | do { 116 | words.add(cursor.getString(wordIndex)); 117 | counts.add(cursor.getLong(countIndex)); 118 | times.add(cursor.getString(timeIndex)); 119 | } while (cursor.moveToNext()); 120 | cursor.moveToLast(); 121 | } 122 | cursor.close(); 123 | } 124 | userDictAdapter.updateAdapterData(words, counts, times); 125 | setListShown(true); 126 | } 127 | 128 | @Override 129 | public void onOrderSelectListener(int which) { 130 | userDictAdapter.clearAdapterData(); 131 | userHandler.startQuery(which); 132 | setListShown(false); 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /app/src/main/java/com/dict/hm/dictionary/ui/adapter/NavigationDrawerAdapter.java: -------------------------------------------------------------------------------- 1 | package com.dict.hm.dictionary.ui.adapter; 2 | 3 | import android.content.Context; 4 | import android.content.res.Resources; 5 | import android.graphics.drawable.ClipDrawable; 6 | import android.util.TypedValue; 7 | import android.view.LayoutInflater; 8 | import android.view.View; 9 | import android.view.ViewGroup; 10 | import android.widget.BaseAdapter; 11 | import android.widget.TextView; 12 | 13 | import com.dict.hm.dictionary.R; 14 | 15 | /** 16 | * Created by hm on 15-5-28. 17 | */ 18 | public class NavigationDrawerAdapter extends BaseAdapter{ 19 | public static final int PERSONAL_DICT = 1; 20 | public static final int SWITCH_DICT = 2; 21 | public static final int LIST_PAPER = 3; 22 | public static final int MANAGE_DICT = 4; 23 | public static final int MANAGE_PAPER = 5; 24 | public static final int SETTINGS = 6; 25 | public static final int ABOUT = 7; 26 | 27 | private Context context; 28 | private LayoutInflater inflater; 29 | private Resources resources; 30 | private final int count = 12; 31 | 32 | public NavigationDrawerAdapter(Context context) { 33 | this.context = context; 34 | inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 35 | resources = context.getResources(); 36 | } 37 | 38 | @Override 39 | public View getView(int position, View convertView, ViewGroup parent) { 40 | View view; 41 | if (convertView == null) { 42 | view = inflater.inflate(R.layout.drawer_item, parent, false); 43 | } else { 44 | view = convertView; 45 | } 46 | String string; 47 | switch (position) { 48 | case 2: //personal dict 49 | string = context.getString(R.string.drawer_personal_dict); 50 | break; 51 | case 3: //switch dict 52 | string = context.getString(R.string.drawer_dict_switch); 53 | break; 54 | case 4: //list paper 55 | string = context.getString(R.string.drawer_paper_list); 56 | break; 57 | case 6: //manage dict 58 | string = context.getString(R.string.drawer_dict_manager); 59 | break; 60 | case 7: //manage paper 61 | string = context.getString(R.string.drawer_paper_manager); 62 | break; 63 | case 9: //settings 64 | string = context.getString(R.string.drawer_settings); 65 | break; 66 | case 10: //about 67 | string = context.getString(R.string.drawer_about); 68 | break; 69 | case 0: //image 70 | case 1: //space 71 | case 5: //divider 72 | case 8: //divider 73 | case 11: //space 74 | string = null; 75 | break; 76 | default: 77 | string = ""; 78 | } 79 | TextView textView = (TextView) view.findViewById(R.id.drawer_text); 80 | textView.setText(string); 81 | 82 | view.setBackground(null); 83 | if (string == null) { 84 | if (position == 0) { 85 | view.getLayoutParams().height = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 86 | 152, resources.getDisplayMetrics()); 87 | view.setBackgroundResource(R.drawable.ic_wallpaper); 88 | } else if (position == 1 || position == 11){ 89 | view.getLayoutParams().height = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 90 | 16, resources.getDisplayMetrics()); 91 | } else { 92 | view.getLayoutParams().height = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 93 | 16, resources.getDisplayMetrics()); 94 | ClipDrawable drawable = (ClipDrawable) resources.getDrawable(R.drawable.drawer_divider); 95 | if (drawable != null) { 96 | //set title divider height to 1dp, view's height is 16dp 97 | int level = 10000 / 16; 98 | drawable.setLevel(level); 99 | } 100 | view.setBackground(drawable); 101 | } 102 | } 103 | return view; 104 | } 105 | 106 | @Override 107 | public int getItemViewType(int position) { 108 | int type; 109 | switch (position) { 110 | case 2: //personal dict 111 | type = PERSONAL_DICT; 112 | break; 113 | case 3: //switch dict 114 | type = SWITCH_DICT; 115 | break; 116 | case 4: //list paper 117 | type = LIST_PAPER; 118 | break; 119 | case 6: //manage dict 120 | type = MANAGE_DICT; 121 | break; 122 | case 7: //manage paper 123 | type = MANAGE_PAPER; 124 | break; 125 | case 9: //settings 126 | type = SETTINGS; 127 | break; 128 | case 10: //about 129 | type = ABOUT; 130 | break; 131 | // case 0: //image 132 | // case 1: //space 133 | // case 5: //divider 134 | // case 8: //divider 135 | // case 11: //space 136 | default: 137 | type = 0; 138 | } 139 | return type; 140 | } 141 | 142 | @Override 143 | public boolean isEnabled(int position) { 144 | return getItemViewType(position) > 0; 145 | } 146 | 147 | @Override 148 | public int getCount() { 149 | return count; 150 | } 151 | 152 | @Override 153 | public Object getItem(int position) { 154 | return null; 155 | } 156 | 157 | @Override 158 | public long getItemId(int position) { 159 | return position; 160 | } 161 | 162 | } 163 | -------------------------------------------------------------------------------- /app/src/main/java/com/dict/hm/dictionary/ui/adapter/PaperJsonAdapter.java: -------------------------------------------------------------------------------- 1 | package com.dict.hm.dictionary.ui.adapter; 2 | 3 | import android.content.Context; 4 | import android.view.LayoutInflater; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | import android.widget.BaseAdapter; 8 | import android.widget.TextView; 9 | 10 | import com.dict.hm.dictionary.R; 11 | import com.dict.hm.dictionary.paper.JsonEntry; 12 | 13 | import java.util.ArrayList; 14 | 15 | 16 | /** 17 | * Created by hm on 15-3-20. 18 | */ 19 | public class PaperJsonAdapter extends BaseAdapter{ 20 | LayoutInflater inflater; 21 | ArrayList list; 22 | ArrayList removedList; 23 | 24 | public PaperJsonAdapter(Context context, ArrayList list) { 25 | inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 26 | this.list= list; 27 | removedList = new ArrayList<>(); 28 | } 29 | 30 | @Override 31 | public int getCount() { 32 | return list.size(); 33 | } 34 | 35 | @Override 36 | public Object getItem(int position) { 37 | if (list.size() > position) { 38 | return list.get(position).getWord(); 39 | } else { 40 | return null; 41 | } 42 | } 43 | 44 | @Override 45 | public long getItemId(int position) { 46 | return position; 47 | } 48 | 49 | @Override 50 | public View getView(int position, View convertView, ViewGroup parent) { 51 | View view; 52 | if (convertView != null) { 53 | view = convertView; 54 | } else { 55 | view = inflater.inflate(R.layout.paper_json_item, parent, false); 56 | // view.setBackgroundResource(R.drawable.list_selector); 57 | } 58 | TextView wordView = (TextView) view.findViewById(R.id.paper_json_word); 59 | TextView countView = (TextView) view.findViewById(R.id.paper_json_count); 60 | JsonEntry entry = list.get(position); 61 | wordView.setText(entry.getWord()); 62 | countView.setText(Long.toString(entry.getCount())); 63 | return view; 64 | } 65 | 66 | public void removeItem(int position) { 67 | removedList.add(list.get(position)); 68 | list.remove(position); 69 | notifyDataSetChanged(); 70 | } 71 | 72 | public void setList(ArrayList list) { 73 | if (list == null) { 74 | return; 75 | } 76 | this.list = list; 77 | notifyDataSetChanged(); 78 | } 79 | 80 | public ArrayList getList() { 81 | return list; 82 | } 83 | 84 | public ArrayList getRemovedList() { 85 | return removedList; 86 | } 87 | 88 | public void clearRemovedList() { 89 | removedList.clear(); 90 | } 91 | 92 | } 93 | -------------------------------------------------------------------------------- /app/src/main/java/com/dict/hm/dictionary/ui/adapter/PaperViewerAdapter.java: -------------------------------------------------------------------------------- 1 | package com.dict.hm.dictionary.ui.adapter; 2 | 3 | import android.content.Context; 4 | import android.database.Cursor; 5 | import android.net.Uri; 6 | import android.view.LayoutInflater; 7 | import android.view.View; 8 | import android.view.ViewGroup; 9 | import android.widget.BaseAdapter; 10 | import android.widget.TextView; 11 | 12 | import com.dict.hm.dictionary.async.WordAsyncQueryHandler; 13 | import com.dict.hm.dictionary.dict.DictContentProvider; 14 | import com.dict.hm.dictionary.dict.DictSQLiteDefine; 15 | import com.dict.hm.dictionary.R; 16 | import com.dict.hm.dictionary.dict.parse.DictParser; 17 | import com.dict.hm.dictionary.paper.JsonEntry; 18 | import com.dict.hm.dictionary.paper.PaperJsonReader; 19 | 20 | import java.util.ArrayList; 21 | 22 | /** 23 | * Created by hm on 15-2-12. 24 | */ 25 | public class PaperViewerAdapter extends BaseAdapter 26 | implements WordAsyncQueryHandler.AsyncQueryListener{ 27 | private LayoutInflater inflater; 28 | private WordAsyncQueryHandler queryWord; 29 | private DictParser parser; 30 | private PaperJsonReader reader; 31 | private ArrayList definitions; 32 | private ArrayList entries; 33 | private Uri uri; 34 | 35 | private static final String error = "can't find word in the dictionary"; 36 | private static final String error1 = "occur error while reading text from .dict file"; 37 | 38 | private int count = 0; 39 | private int queryPosition = 0; 40 | private static final int preloadSize = 5; 41 | private boolean hasNext = true; 42 | 43 | 44 | public PaperViewerAdapter(Context context, PaperJsonReader reader, DictParser parser) { 45 | this.parser = parser; 46 | this.reader = reader; 47 | inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 48 | definitions = new ArrayList<>(); 49 | entries = new ArrayList<>(); 50 | queryWord = new WordAsyncQueryHandler(context.getContentResolver(), this); 51 | uri = Uri.parse(DictContentProvider.CONTENT_URI + "/" + "word"); 52 | /** 53 | * This can't set to Integer.MAX_VALUE, because the ListView which will setAdapter() to 54 | * this Adapter has a HeadView. The HeadView will be counted as one view. And I think the 55 | * max views is up to MAX_VALUE. So while I set 'size = Integer.MAX_VALUE - 1', the ListView 56 | * would show nothing. 57 | */ 58 | // size = Integer.MAX_VALUE - 1; 59 | preload(); 60 | } 61 | 62 | @Override 63 | public View getView(int position, View convertView, ViewGroup parent) { 64 | // long start, end; 65 | // start = SystemClock.currentThreadTimeMillis(); 66 | 67 | View view; 68 | if (convertView != null) { 69 | view = convertView; 70 | } else { 71 | view = inflater.inflate(R.layout.paper_viewer_item, parent, false); 72 | } 73 | String word_text = entries.get(position).getWord(); 74 | String definition_text = definitions.get(position); 75 | 76 | TextView word_TextView = (TextView) view.findViewById(R.id.paper_word); 77 | TextView definition_TextView = (TextView) view.findViewById(R.id.paper_definition); 78 | word_TextView.setText(word_text); 79 | definition_TextView.setText(definition_text); 80 | 81 | if (hasNext && (queryPosition < position + preloadSize)) { 82 | preload(); 83 | } 84 | // if (position == mark) { 85 | // Animation animation = AnimationUtils 86 | // .loadAnimation(context, R.anim.abc_slide_in_bottom); 87 | // view.startAnimation(animation); 88 | // } 89 | 90 | // end = SystemClock.currentThreadTimeMillis(); 91 | // Log.d("preload", "time-" + (end - start)); 92 | 93 | return view; 94 | } 95 | 96 | @Override 97 | public int getCount() { 98 | return count; 99 | } 100 | 101 | @Override 102 | public Object getItem(int position) { 103 | if (position < entries.size()) { 104 | return entries.get(position).getWord(); 105 | } 106 | return null; 107 | } 108 | 109 | @Override 110 | public long getItemId(int position) { 111 | return position; 112 | } 113 | 114 | @Override 115 | public void onQueryComplete(int token, Object cookie, Cursor cursor) { 116 | updateWordDefinition(token, cookie, cursor); 117 | } 118 | 119 | private void preload() { 120 | int i = 0; 121 | while (i < preloadSize) { 122 | JsonEntry entry = reader.getNextJsonEntry(); 123 | if (entry != null) { 124 | queryWord.startQuery(queryPosition, null, uri, null, null, 125 | new String[]{entry.getWord()}, null); 126 | entries.add(entry); 127 | } else { 128 | hasNext = false; 129 | break; 130 | } 131 | i++; 132 | queryPosition++; 133 | } 134 | } 135 | 136 | //TODO: need to be changed 137 | private void updateWordDefinition(int token, Object cookie, Cursor cursor) { 138 | int offset = -1; 139 | int size = -1; 140 | if (cursor != null) { 141 | try { 142 | cursor.moveToFirst(); 143 | if (cursor.moveToFirst()) { 144 | int i0 = cursor.getColumnIndex(DictSQLiteDefine.COLUMN_OFFSET); 145 | int i1 = cursor.getColumnIndex(DictSQLiteDefine.COLUMN_SIZE); 146 | offset = cursor.getInt(i0); 147 | size = cursor.getInt(i1); 148 | } 149 | } finally { 150 | cursor.close(); 151 | } 152 | } 153 | count++; 154 | definitions.add(getDefinition(offset, size)); 155 | //done preload 156 | if (token + 1 == queryPosition) { 157 | notifyDataSetChanged(); 158 | } 159 | if (token < preloadSize) { 160 | notifyDataSetChanged(); 161 | } 162 | } 163 | 164 | private String getDefinition(int offset, int size) { 165 | if (offset < 0 || size < 0) { 166 | return error; 167 | } 168 | String definition = null; 169 | if (parser != null) { 170 | definition = parser.getWordDefinition(offset, size); 171 | } 172 | if (definition != null) { 173 | return definition; 174 | } 175 | return error1; 176 | } 177 | 178 | } 179 | -------------------------------------------------------------------------------- /app/src/main/java/com/dict/hm/dictionary/ui/adapter/UserDictAdapter.java: -------------------------------------------------------------------------------- 1 | package com.dict.hm.dictionary.ui.adapter; 2 | 3 | import android.content.Context; 4 | import android.view.LayoutInflater; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | import android.widget.BaseAdapter; 8 | import android.widget.TextView; 9 | 10 | import com.dict.hm.dictionary.R; 11 | 12 | import java.util.ArrayList; 13 | 14 | /** 15 | * Created by hm on 15-5-6. 16 | */ 17 | public class UserDictAdapter extends BaseAdapter { 18 | private LayoutInflater layoutInflater; 19 | private int count; 20 | ArrayList words; 21 | ArrayList counts; 22 | ArrayList times; 23 | 24 | public UserDictAdapter(Context context) { 25 | layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 26 | words = new ArrayList<>(); 27 | counts = new ArrayList<>(); 28 | times = new ArrayList<>(); 29 | count = 0; 30 | } 31 | 32 | public void updateAdapterData(ArrayList words, ArrayList counts, 33 | ArrayList times) { 34 | this.words.addAll(words); 35 | this.counts.addAll(counts); 36 | this.times.addAll(times); 37 | count = this.words.size(); 38 | notifyDataSetChanged(); 39 | } 40 | 41 | public void clearAdapterData () { 42 | words.clear(); 43 | counts.clear(); 44 | times.clear(); 45 | count = 0; 46 | } 47 | 48 | @Override 49 | public int getCount() { 50 | return count; 51 | } 52 | 53 | @Override 54 | public Object getItem(int position) { 55 | if (position < words.size()) { 56 | return words.get(position); 57 | } 58 | return null; 59 | } 60 | 61 | @Override 62 | public long getItemId(int position) { 63 | if (position < words.size()) { 64 | return position; 65 | } 66 | return 0; 67 | } 68 | 69 | @Override 70 | public View getView(int position, View convertView, ViewGroup parent) { 71 | View view; 72 | if (convertView != null) { 73 | view = convertView; 74 | } else { 75 | view = layoutInflater.inflate(R.layout.user_word_item, parent, false); 76 | } 77 | TextView word = (TextView) view.findViewById(R.id.user_word); 78 | TextView count = (TextView) view.findViewById(R.id.user_count); 79 | TextView time = (TextView) view.findViewById(R.id.user_time); 80 | word.setText(words.get(position)); 81 | count.setText(counts.get(position).toString()); 82 | time.setText(times.get(position)); 83 | 84 | return view; 85 | } 86 | 87 | } 88 | -------------------------------------------------------------------------------- /app/src/main/java/com/dict/hm/dictionary/ui/dialog/AboutDialog.java: -------------------------------------------------------------------------------- 1 | package com.dict.hm.dictionary.ui.dialog; 2 | 3 | import android.app.Dialog; 4 | import android.app.DialogFragment; 5 | import android.os.Bundle; 6 | import android.support.v7.app.AlertDialog; 7 | 8 | import com.dict.hm.dictionary.R; 9 | 10 | /** 11 | * Created by hm on 15-6-1. 12 | */ 13 | public class AboutDialog extends DialogFragment { 14 | 15 | @Override 16 | public Dialog onCreateDialog(Bundle savedInstanceState) { 17 | AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); 18 | builder.setTitle(getString(R.string.about_title)); 19 | builder.setMessage(getString(R.string.about_message)); 20 | builder.setPositiveButton("OK", null); 21 | 22 | return builder.create(); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /app/src/main/java/com/dict/hm/dictionary/ui/dialog/AlertDialogFragment.java: -------------------------------------------------------------------------------- 1 | package com.dict.hm.dictionary.ui.dialog; 2 | 3 | import android.app.Activity; 4 | import android.app.Dialog; 5 | import android.app.DialogFragment; 6 | import android.content.DialogInterface; 7 | import android.os.Bundle; 8 | import android.support.v7.app.AlertDialog; 9 | 10 | /** 11 | * Created by hm on 15-1-20. 12 | */ 13 | public class AlertDialogFragment extends DialogFragment { 14 | private static final String TITLE = "title"; 15 | private static final String POSITIVE = "positive"; 16 | private static final String NEGATIVE = "negative"; 17 | private static final String MSG = "msg"; 18 | ConfirmDialogListener listener; 19 | 20 | public static AlertDialogFragment newInstance(String title, String msg, 21 | String positive , String negative) { 22 | Bundle bundle = new Bundle(); 23 | bundle.putString(TITLE, title); 24 | bundle.putString(MSG, msg); 25 | bundle.putString(POSITIVE, positive); 26 | bundle.putString(NEGATIVE, negative); 27 | AlertDialogFragment dialogFragment = new AlertDialogFragment(); 28 | dialogFragment.setArguments(bundle); 29 | return dialogFragment; 30 | } 31 | 32 | public interface ConfirmDialogListener { 33 | void onDialogPositiveClick(); 34 | } 35 | 36 | @Override 37 | public void onAttach(Activity activity) { 38 | super.onAttach(activity); 39 | try { 40 | listener = (ConfirmDialogListener) activity; 41 | } catch (ClassCastException e) { 42 | throw new ClassCastException(activity.toString() 43 | + " must implement ConfirmDialogListener"); 44 | } 45 | } 46 | 47 | @Override 48 | public Dialog onCreateDialog(Bundle savedInstanceState) { 49 | Bundle bundle = getArguments(); 50 | String title = bundle.getString(TITLE); 51 | String message= bundle.getString(MSG); 52 | String positive = bundle.getString(POSITIVE); 53 | String negative = bundle.getString(NEGATIVE); 54 | 55 | AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); 56 | builder.setTitle(title); 57 | builder.setMessage(message); 58 | builder.setPositiveButton(positive, new DialogInterface.OnClickListener() { 59 | @Override 60 | public void onClick(DialogInterface dialog, int which) { 61 | listener.onDialogPositiveClick(); 62 | } 63 | }); 64 | builder.setNegativeButton(negative, new DialogInterface.OnClickListener() { 65 | @Override 66 | public void onClick(DialogInterface dialog, int which) { 67 | dismiss(); 68 | } 69 | }); 70 | 71 | return builder.create(); 72 | } 73 | 74 | } 75 | -------------------------------------------------------------------------------- /app/src/main/java/com/dict/hm/dictionary/ui/dialog/DefinitionDialog.java: -------------------------------------------------------------------------------- 1 | package com.dict.hm.dictionary.ui.dialog; 2 | 3 | import android.app.Dialog; 4 | import android.app.DialogFragment; 5 | import android.graphics.drawable.Drawable; 6 | import android.os.Bundle; 7 | import android.support.v7.app.AlertDialog; 8 | import android.view.LayoutInflater; 9 | import android.view.View; 10 | import android.widget.ImageView; 11 | import android.widget.TextView; 12 | 13 | import com.dict.hm.dictionary.R; 14 | import com.dict.hm.dictionary.dict.UserDictSQLiteHelper; 15 | import com.dict.hm.dictionary.paper.JsonEntry; 16 | 17 | import java.util.ArrayList; 18 | 19 | /** 20 | * Created by hm on 15-6-10. 21 | */ 22 | public class DefinitionDialog extends DialogFragment{ 23 | private static final String WORD = "word"; 24 | private static final String DEF = "def"; 25 | 26 | public static DefinitionDialog getDefinitionDialog(String word, String def) { 27 | Bundle bundle = new Bundle(); 28 | bundle.putString(WORD, word); 29 | bundle.putString(DEF, def); 30 | DefinitionDialog dialog = new DefinitionDialog(); 31 | dialog.setArguments(bundle); 32 | return dialog; 33 | } 34 | 35 | @Override 36 | public Dialog onCreateDialog(Bundle savedInstanceState) { 37 | Bundle bundle = getArguments(); 38 | String definition = bundle.getString(DEF); 39 | String word = bundle.getString(WORD); 40 | AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); 41 | // builder.setTitle(word); 42 | builder.setMessage(definition); 43 | builder.setCustomTitle(createCustomTitleView(word)); 44 | return builder.create(); 45 | } 46 | 47 | private View createCustomTitleView(final String word) { 48 | View view = LayoutInflater.from(getActivity()).inflate(R.layout.definition_item, null); 49 | TextView textView = (TextView) view.findViewById(R.id.word); 50 | textView.setText(word); 51 | final ImageView favorite= (ImageView) view.findViewById(R.id.favorite); 52 | favorite.setOnClickListener(new View.OnClickListener() { 53 | @Override 54 | public void onClick(View v) { 55 | Drawable drawable = getResources().getDrawable(R.drawable.ic_favorite_black_48dp); 56 | favorite.setImageDrawable(drawable); 57 | //TODO: store the word to my dictionary. 58 | UserDictSQLiteHelper helper = UserDictSQLiteHelper.getInstance(getActivity()); 59 | ArrayList words = new ArrayList<>(); 60 | JsonEntry entry = new JsonEntry(word, 1); 61 | words.add(entry); 62 | helper.insertWords(words); 63 | } 64 | }); 65 | return view; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /app/src/main/java/com/dict/hm/dictionary/ui/dialog/EditDialog.java: -------------------------------------------------------------------------------- 1 | package com.dict.hm.dictionary.ui.dialog; 2 | 3 | import android.app.Activity; 4 | import android.app.Dialog; 5 | import android.app.DialogFragment; 6 | import android.content.DialogInterface; 7 | import android.os.Bundle; 8 | import android.support.v7.app.AlertDialog; 9 | import android.view.View; 10 | import android.widget.EditText; 11 | 12 | import com.dict.hm.dictionary.R; 13 | 14 | /** 15 | * Created by hm on 14-12-21. 16 | */ 17 | public class EditDialog extends DialogFragment { 18 | private static final String TEXT = "text"; 19 | private static final String HINT = "hint"; 20 | private static final String TITLE = "title"; 21 | private static final String POSITIVE = "positive"; 22 | EditDialogListener listener; 23 | 24 | public static EditDialog newInstance(String title, String hint) { 25 | EditDialog dialogFragment = new EditDialog(); 26 | Bundle bundle = new Bundle(); 27 | bundle.putString(HINT, hint); 28 | bundle.putString(TITLE, title); 29 | dialogFragment.setArguments(bundle); 30 | 31 | return dialogFragment; 32 | } 33 | 34 | public static EditDialog newInstance(String title, String editText, String positive) { 35 | EditDialog dialogFragment = new EditDialog(); 36 | Bundle bundle = new Bundle(); 37 | bundle.putString(TEXT, editText); 38 | bundle.putString(TITLE, title); 39 | bundle.putString(POSITIVE, positive); 40 | dialogFragment.setArguments(bundle); 41 | 42 | return dialogFragment; 43 | } 44 | 45 | public interface EditDialogListener{ 46 | void onEditDialogPositiveClick(String url); 47 | } 48 | 49 | @Override 50 | public void onAttach(Activity activity) { 51 | super.onAttach(activity); 52 | try { 53 | listener = (EditDialogListener) activity; 54 | } catch (ClassCastException e) { 55 | throw new ClassCastException(getTargetFragment().toString() 56 | + " must implement WarningDialogListener"); 57 | } 58 | } 59 | 60 | @Override 61 | public Dialog onCreateDialog(Bundle savedInstanceState) { 62 | Bundle bundle = getArguments(); 63 | String editText = bundle.getString(TEXT); 64 | String title = bundle.getString(TITLE); 65 | String hint = bundle.getString(HINT); 66 | String positive = bundle.getString(POSITIVE); 67 | if (positive == null) { 68 | positive = "Ok"; 69 | } 70 | 71 | AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); 72 | builder.setTitle(title); 73 | View view = getActivity().getLayoutInflater().inflate(R.layout.edit_text, null); 74 | builder.setView(view); 75 | EditText edit = (EditText)view.findViewById(R.id.editText); 76 | edit.setHint(hint); 77 | edit.setText(editText); 78 | 79 | builder.setPositiveButton(positive, new DialogInterface.OnClickListener() { 80 | @Override 81 | public void onClick(DialogInterface dialogInterface, int i) { 82 | EditText edit = (EditText)getDialog().findViewById(R.id.editText); 83 | listener.onEditDialogPositiveClick(edit.getText().toString()); 84 | } 85 | }); 86 | builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() { 87 | @Override 88 | public void onClick(DialogInterface dialogInterface, int i) { 89 | dismiss(); 90 | } 91 | }); 92 | 93 | return builder.create(); 94 | } 95 | 96 | } 97 | -------------------------------------------------------------------------------- /app/src/main/java/com/dict/hm/dictionary/ui/dialog/NotificationDialog.java: -------------------------------------------------------------------------------- 1 | package com.dict.hm.dictionary.ui.dialog; 2 | 3 | import android.app.Dialog; 4 | import android.app.DialogFragment; 5 | import android.content.DialogInterface; 6 | import android.os.Bundle; 7 | import android.support.v7.app.AlertDialog; 8 | import android.view.Gravity; 9 | import android.view.View; 10 | import android.view.ViewGroup; 11 | import android.view.Window; 12 | import android.view.WindowManager; 13 | import android.widget.ImageView; 14 | import android.widget.TextView; 15 | 16 | import com.dict.hm.dictionary.R; 17 | 18 | /** 19 | * Created by hm on 15-4-7. 20 | */ 21 | public class NotificationDialog extends DialogFragment{ 22 | private static String TXT = "text"; 23 | 24 | public static NotificationDialog newInstance(String text) { 25 | NotificationDialog dialogFragment = new NotificationDialog(); 26 | Bundle bundle = new Bundle(); 27 | bundle.putString(TXT, text); 28 | dialogFragment.setArguments(bundle); 29 | 30 | return dialogFragment; 31 | } 32 | 33 | @Override 34 | public Dialog onCreateDialog(Bundle savedInstanceState) { 35 | Bundle bundle = getArguments(); 36 | String text = bundle.getString(TXT); 37 | if (text == null || text.equals("")) { 38 | text = "HAVE A GOOD DAY!"; 39 | } 40 | AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); 41 | // builder.setMessage(text); 42 | View view = getActivity().getLayoutInflater().inflate(R.layout.snackbar, null); 43 | TextView textView =(TextView) view.findViewById(R.id.snackbar_text); 44 | textView.setText(text); 45 | builder.setView(view); 46 | 47 | Dialog dialog = builder.create(); 48 | //set dialog's style 49 | Window window = dialog.getWindow(); 50 | window.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); 51 | WindowManager.LayoutParams layoutParams = window.getAttributes(); 52 | layoutParams.gravity = Gravity.BOTTOM; 53 | layoutParams.dimAmount = 0.0f; 54 | layoutParams.flags |= WindowManager.LayoutParams.FLAG_DIM_BEHIND; 55 | window.setAttributes(layoutParams); 56 | return dialog; 57 | } 58 | 59 | @Override 60 | public void onDismiss(DialogInterface dialog) { 61 | if (fab != null) { 62 | fab.animate().translationYBy(y); 63 | } 64 | super.onDismiss(dialog); 65 | } 66 | 67 | public void setFab(ImageView fab, float y) { 68 | this.fab = fab; 69 | this.y = y; 70 | } 71 | ImageView fab = null; 72 | float y = 0; 73 | 74 | } 75 | -------------------------------------------------------------------------------- /app/src/main/java/com/dict/hm/dictionary/ui/dialog/ProgressDialog.java: -------------------------------------------------------------------------------- 1 | package com.dict.hm.dictionary.ui.dialog; 2 | 3 | import android.app.AlertDialog; 4 | import android.app.Dialog; 5 | import android.app.DialogFragment; 6 | import android.os.Bundle; 7 | import android.view.LayoutInflater; 8 | import android.view.View; 9 | import android.view.Window; 10 | import android.view.WindowManager; 11 | import android.widget.ProgressBar; 12 | 13 | import com.dict.hm.dictionary.R; 14 | 15 | 16 | /** 17 | * Created by hm on 15-4-8. 18 | */ 19 | public class ProgressDialog extends DialogFragment{ 20 | private static final String MAX = "max"; 21 | private static final String MSG = "msg"; 22 | ProgressBar progressBar; 23 | 24 | 25 | public static ProgressDialog newInstance(String msg, int max) { 26 | ProgressDialog dialogFragment = new ProgressDialog(); 27 | Bundle bundle = new Bundle(); 28 | bundle.putString(MSG, msg); 29 | bundle.putInt(MAX, max); 30 | dialogFragment.setArguments(bundle); 31 | 32 | return dialogFragment; 33 | } 34 | 35 | @Override 36 | public Dialog onCreateDialog(Bundle savedInstanceState) { 37 | Bundle bundle = getArguments(); 38 | int max = bundle.getInt(MAX); 39 | String msg = bundle.getString(MSG); 40 | 41 | LayoutInflater inflater = getActivity().getLayoutInflater(); 42 | View view; 43 | if (max > 0) { 44 | view = inflater.inflate(R.layout.progress, null); 45 | progressBar = (ProgressBar) view.findViewById(R.id.progressBar); 46 | progressBar.setMax(max); 47 | } else { 48 | view = inflater.inflate(R.layout.progress_circle, null); 49 | progressBar = (ProgressBar) view.findViewById(R.id.progressBar_circle); 50 | } 51 | 52 | AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); 53 | builder.setView(view); 54 | builder.setMessage(msg); 55 | Dialog dialog = builder.create(); 56 | 57 | dialog.getWindow().requestFeature(Window.FEATURE_NO_TITLE); 58 | dialog.setCanceledOnTouchOutside(false); 59 | // setCancelable(false); 60 | 61 | return dialog; 62 | } 63 | 64 | @Override 65 | public void onStart() { 66 | super.onStart(); 67 | //set dialog's style 68 | Window window = getDialog().getWindow(); 69 | WindowManager.LayoutParams layoutParams = window.getAttributes(); 70 | layoutParams.dimAmount = 0.0f; 71 | layoutParams.flags |= WindowManager.LayoutParams.FLAG_DIM_BEHIND; 72 | window.setAttributes(layoutParams); 73 | } 74 | 75 | public void setProgressBar(int value) { 76 | progressBar.setProgress(value); 77 | if (value >= progressBar.getMax()) { 78 | dismiss(); 79 | } 80 | } 81 | 82 | } 83 | -------------------------------------------------------------------------------- /app/src/main/java/com/dict/hm/dictionary/ui/dialog/SelectDialog.java: -------------------------------------------------------------------------------- 1 | package com.dict.hm.dictionary.ui.dialog; 2 | 3 | import android.app.Activity; 4 | import android.app.Dialog; 5 | import android.app.DialogFragment; 6 | import android.content.DialogInterface; 7 | import android.os.Bundle; 8 | import android.support.v7.app.AlertDialog; 9 | 10 | import com.dict.hm.dictionary.R; 11 | 12 | /** 13 | * Created by hm on 15-6-9. 14 | */ 15 | public class SelectDialog extends DialogFragment { 16 | OrderSelectListener listener; 17 | 18 | @Override 19 | public void onAttach(Activity activity) { 20 | try { 21 | listener = (OrderSelectListener) getTargetFragment(); 22 | } catch (ClassCastException e) { 23 | throw new ClassCastException(getTargetFragment().toString() 24 | + " must implement OrderSelectListener"); 25 | } 26 | super.onAttach(activity); 27 | } 28 | 29 | @Override 30 | public Dialog onCreateDialog(Bundle savedInstanceState) { 31 | AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); 32 | builder.setItems(R.array.order, new DialogInterface.OnClickListener() { 33 | @Override 34 | public void onClick(DialogInterface dialog, int which) { 35 | listener.onOrderSelectListener(which); 36 | } 37 | }); 38 | return builder.create(); 39 | } 40 | 41 | public interface OrderSelectListener { 42 | void onOrderSelectListener(int which); 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /app/src/main/java/com/dict/hm/dictionary/ui/dialog/SwitchDictDialog.java: -------------------------------------------------------------------------------- 1 | package com.dict.hm.dictionary.ui.dialog; 2 | 3 | import android.app.Activity; 4 | import android.app.Dialog; 5 | import android.app.DialogFragment; 6 | import android.content.DialogInterface; 7 | import android.os.Bundle; 8 | import android.support.v7.app.AlertDialog; 9 | 10 | import com.dict.hm.dictionary.R; 11 | 12 | /** 13 | * Created by hm on 15-5-28. 14 | */ 15 | public class SwitchDictDialog extends DialogFragment { 16 | private SwitchDictDialogListener listener; 17 | 18 | public static final String ARRAY_DATA = "data"; 19 | public static final String CHECKED = "checked"; 20 | 21 | public interface SwitchDictDialogListener { 22 | void onSwitchDictClick(int which); 23 | } 24 | 25 | @Override 26 | public void onAttach(Activity activity) { 27 | super.onAttach(activity); 28 | try { 29 | listener = (SwitchDictDialogListener) activity; 30 | } catch (ClassCastException e) { 31 | throw new ClassCastException(activity.toString() 32 | + " must implement SwitchDictDialogListener"); 33 | } 34 | } 35 | 36 | @Override 37 | public Dialog onCreateDialog(Bundle savedInstanceState) { 38 | Bundle bundle = getArguments(); 39 | CharSequence[] items = bundle.getCharSequenceArray(ARRAY_DATA); 40 | int position = bundle.getInt(CHECKED); 41 | 42 | AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); 43 | builder.setTitle(R.string.drawer_dict_switch); 44 | builder.setSingleChoiceItems(items, position, new DialogInterface.OnClickListener() { 45 | @Override 46 | public void onClick(DialogInterface dialog, int which) { 47 | listener.onSwitchDictClick(which); 48 | dismiss(); 49 | } 50 | }); 51 | return builder.create(); 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_action_archive_white_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hm279/Dictionary/7525340d5833892993721243b9270079824a45ee/app/src/main/res/drawable-xxhdpi/ic_action_archive_white_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_action_edit_white_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hm279/Dictionary/7525340d5833892993721243b9270079824a45ee/app/src/main/res/drawable-xxhdpi/ic_action_edit_white_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_action_new_attachment.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hm279/Dictionary/7525340d5833892993721243b9270079824a45ee/app/src/main/res/drawable-xxhdpi/ic_action_new_attachment.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_action_next_item.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hm279/Dictionary/7525340d5833892993721243b9270079824a45ee/app/src/main/res/drawable-xxhdpi/ic_action_next_item.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_action_previous_item.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hm279/Dictionary/7525340d5833892993721243b9270079824a45ee/app/src/main/res/drawable-xxhdpi/ic_action_previous_item.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_action_qrcode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hm279/Dictionary/7525340d5833892993721243b9270079824a45ee/app/src/main/res/drawable-xxhdpi/ic_action_qrcode.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_action_search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hm279/Dictionary/7525340d5833892993721243b9270079824a45ee/app/src/main/res/drawable-xxhdpi/ic_action_search.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_add_black_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hm279/Dictionary/7525340d5833892993721243b9270079824a45ee/app/src/main/res/drawable-xxhdpi/ic_add_black_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_close_white_18dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hm279/Dictionary/7525340d5833892993721243b9270079824a45ee/app/src/main/res/drawable-xxhdpi/ic_close_white_18dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_favorite_black_48dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hm279/Dictionary/7525340d5833892993721243b9270079824a45ee/app/src/main/res/drawable-xxhdpi/ic_favorite_black_48dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_favorite_outline_black_48dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hm279/Dictionary/7525340d5833892993721243b9270079824a45ee/app/src/main/res/drawable-xxhdpi/ic_favorite_outline_black_48dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hm279/Dictionary/7525340d5833892993721243b9270079824a45ee/app/src/main/res/drawable-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_sort_white_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hm279/Dictionary/7525340d5833892993721243b9270079824a45ee/app/src/main/res/drawable-xxhdpi/ic_sort_white_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_wallpaper.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hm279/Dictionary/7525340d5833892993721243b9270079824a45ee/app/src/main/res/drawable-xxhdpi/ic_wallpaper.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/drawer_divider.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/favorite_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/floating_button.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 38 | 39 | 40 | 41 | 42 | 43 | 49 | 50 | 51 | 52 | 53 | 54 | 60 | 61 | 62 | 63 | 64 | 65 | 71 | 72 | 73 | 74 | 75 | 76 | 82 | 83 | 84 | 85 | 86 | 87 | 93 | 94 | 95 | 96 | 97 | 98 | 104 | 105 | 106 | 107 | 108 | 109 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/list_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_camera.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | 13 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 13 | 18 | 19 | 25 | 26 | 31 | 36 | 37 | 38 | 39 | 40 | 49 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_manager.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 16 | 17 | 22 | 29 | 30 | 37 | 38 | 39 | 58 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /app/src/main/res/layout/definition_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 19 | 29 | 30 | -------------------------------------------------------------------------------- /app/src/main/res/layout/drawer_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 19 | 20 | -------------------------------------------------------------------------------- /app/src/main/res/layout/edit_text.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_file.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 13 | 14 | 19 | -------------------------------------------------------------------------------- /app/src/main/res/layout/paper_json_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 19 | 25 | -------------------------------------------------------------------------------- /app/src/main/res/layout/paper_viewer_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 19 | 20 | 27 | 28 | -------------------------------------------------------------------------------- /app/src/main/res/layout/progress.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 15 | 16 | -------------------------------------------------------------------------------- /app/src/main/res/layout/progress_circle.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 14 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/layout/snackbar.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /app/src/main/res/layout/textview_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 16 | 17 | -------------------------------------------------------------------------------- /app/src/main/res/layout/user_word_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 17 | 18 | 25 | 31 | 32 | 33 | 34 | 35 | 42 | 43 | -------------------------------------------------------------------------------- /app/src/main/res/menu/menu_archive.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 10 | 11 | 16 | 17 | 22 | 23 | 28 | 29 | -------------------------------------------------------------------------------- /app/src/main/res/menu/menu_main.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /app/src/main/res/menu/menu_paper_manager.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 11 | 16 | 22 | 23 | -------------------------------------------------------------------------------- /app/src/main/res/menu/menu_user_dict.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/values-v21/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/values-w820dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 64dp 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/values-zh/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 词典 4 | 清空用户词典 5 | 词典 6 | 文章 7 | 搜索 8 | 设置 9 | 个人词典 10 | 关闭 11 | 打开 12 | 查询不到 \"%s\" 13 | 设置 14 | 词典 15 | 文章 16 | 归档 17 | 输入 18 | 关于 19 | 词典管理 20 | 切换词典 21 | 文章列表 22 | 文章管理 23 | 个人词典 24 | 设置 25 | 关于 26 | 感谢开源项目 Jsoup 和 ZBar。\n邮件支持: kenhm808@gmail.com 27 | 清空用户文章 28 | 自动过滤 29 | 新增文章时,自动过滤认识的单词 30 | 清空 31 | 取消 32 | -------------------------------------------------------------------------------- /app/src/main/res/values/attrs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/values/custom_color.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #4db6ac 4 | #26a69a 5 | #00897b 6 | #00796b 7 | #00695c 8 | #F44336 9 | #1E000000 10 | #1E000000 11 | 12 | #8BC34A 13 | -------------------------------------------------------------------------------- /app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16dp 4 | 16dp 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Dictionary 5 | 6 | Settings 7 | Search 8 | Dictionary 9 | Paper 10 | Personal dictionary 11 | Clear user dictionary 12 | 13 | 14 | %1$d result for \"%2$s\": 15 | %1$d results for \"%2$s\": 16 | 17 | 18 | 19 | No results found for \"%s\" 20 | 21 | Enter Word 22 | setting 23 | 24 | Dictionary 25 | Paper 26 | Archive 27 | 28 | Open 29 | Close 30 | 31 | Personal dictionary 32 | Switch dictionary 33 | Paper list 34 | Manage dictionary 35 | Manage paper 36 | Settings 37 | About 38 | About 39 | Thanks to open source project Jsoup and ZBar.\nEmail support: kenhm808@gmail.com 40 | Clear user papers 41 | Auto-filter 42 | when add new paper, auto filter known words 43 | Clear 44 | Cancel 45 | auto_filter 46 | 47 | 48 | order by count 49 | order by time 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 38 | 39 | 42 | 45 | 46 | 50 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /app/src/main/res/xml/preferences.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 11 | 12 | 13 | 14 | 19 | 20 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /app/src/main/res/xml/searchable.xml: -------------------------------------------------------------------------------- 1 | 2 | 19 | 20 | 25 | 40 | 41 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | jcenter() 6 | } 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:1.2.3' 9 | 10 | // NOTE: Do not place your application dependencies here; they belong 11 | // in the individual module build.gradle files 12 | } 13 | } 14 | 15 | allprojects { 16 | repositories { 17 | jcenter() 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | ## Project-wide Gradle settings. 2 | # 3 | # For more details on how to configure your build environment visit 4 | # http://www.gradle.org/docs/current/userguide/build_environment.html 5 | # 6 | # Specifies the JVM arguments used for the daemon process. 7 | # The setting is particularly useful for tweaking memory settings. 8 | # Default value: -Xmx10248m -XX:MaxPermSize=256m 9 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 10 | # 11 | # When configured, Gradle will run in incubating parallel mode. 12 | # This option should only be used with decoupled projects. More details, visit 13 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 14 | # org.gradle.parallel=true 15 | #Sat Nov 21 15:38:42 CST 2015 16 | systemProp.https.proxyPort=8123 17 | systemProp.http.proxyHost=127.0.0.1 18 | systemProp.https.proxyHost=127.0.0.1 19 | systemProp.http.proxyPort=8123 20 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hm279/Dictionary/7525340d5833892993721243b9270079824a45ee/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Wed Apr 10 15:27:10 PDT 2013 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-all.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # For Cygwin, ensure paths are in UNIX format before anything is touched. 46 | if $cygwin ; then 47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 48 | fi 49 | 50 | # Attempt to set APP_HOME 51 | # Resolve links: $0 may be a link 52 | PRG="$0" 53 | # Need this for relative symlinks. 54 | while [ -h "$PRG" ] ; do 55 | ls=`ls -ld "$PRG"` 56 | link=`expr "$ls" : '.*-> \(.*\)$'` 57 | if expr "$link" : '/.*' > /dev/null; then 58 | PRG="$link" 59 | else 60 | PRG=`dirname "$PRG"`"/$link" 61 | fi 62 | done 63 | SAVED="`pwd`" 64 | cd "`dirname \"$PRG\"`/" >&- 65 | APP_HOME="`pwd -P`" 66 | cd "$SAVED" >&- 67 | 68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 69 | 70 | # Determine the Java command to use to start the JVM. 71 | if [ -n "$JAVA_HOME" ] ; then 72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 73 | # IBM's JDK on AIX uses strange locations for the executables 74 | JAVACMD="$JAVA_HOME/jre/sh/java" 75 | else 76 | JAVACMD="$JAVA_HOME/bin/java" 77 | fi 78 | if [ ! -x "$JAVACMD" ] ; then 79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 80 | 81 | Please set the JAVA_HOME variable in your environment to match the 82 | location of your Java installation." 83 | fi 84 | else 85 | JAVACMD="java" 86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 87 | 88 | Please set the JAVA_HOME variable in your environment to match the 89 | location of your Java installation." 90 | fi 91 | 92 | # Increase the maximum file descriptors if we can. 93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 94 | MAX_FD_LIMIT=`ulimit -H -n` 95 | if [ $? -eq 0 ] ; then 96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 97 | MAX_FD="$MAX_FD_LIMIT" 98 | fi 99 | ulimit -n $MAX_FD 100 | if [ $? -ne 0 ] ; then 101 | warn "Could not set maximum file descriptor limit: $MAX_FD" 102 | fi 103 | else 104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 105 | fi 106 | fi 107 | 108 | # For Darwin, add options to specify how the application appears in the dock 109 | if $darwin; then 110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 111 | fi 112 | 113 | # For Cygwin, switch paths to Windows format before running java 114 | if $cygwin ; then 115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 158 | function splitJvmOpts() { 159 | JVM_OPTS=("$@") 160 | } 161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 163 | 164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 165 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /screenshot/dict.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hm279/Dictionary/7525340d5833892993721243b9270079824a45ee/screenshot/dict.png -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | --------------------------------------------------------------------------------