├── .gitignore ├── .idea ├── .gitignore ├── assetWizardSettings.xml ├── caches │ ├── build_file_checksums.ser │ └── gradle_models.ser ├── codeStyles │ └── Project.xml ├── compiler.xml ├── encodings.xml ├── gradle.xml ├── jarRepositories.xml ├── kotlinc.xml ├── misc.xml ├── modules.xml ├── runConfigurations.xml └── vcs.xml ├── DEBUG.md ├── LICENSE ├── README ├── README.md ├── SCREENSHOTS.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro ├── release │ └── output.json ├── schemas │ └── org.happypeng.sumatora.android.sumatoradictionary.db.PersistentDatabase │ │ ├── 2.json │ │ ├── 3.json │ │ ├── 4.json │ │ ├── 5.json │ │ ├── 6.json │ │ ├── 7.json │ │ └── 8.json └── src │ ├── androidTest │ └── java │ │ └── org │ │ └── happypeng │ │ └── sumatora │ │ └── android │ │ └── sumatoradictionary │ │ └── activity │ │ └── BasicSearchTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── assets │ │ ├── Apache-2.0.txt │ │ ├── BSD-python-romkan.txt │ │ ├── CC-by-4.0.txt │ │ ├── CC-by-SA-3.0.txt │ │ ├── GPLv3.txt │ │ ├── MIT.txt │ │ ├── Unsplash.txt │ │ ├── dictionaries.xml │ │ ├── dictionaries │ │ │ ├── dut.db.gz │ │ │ ├── eng.db.gz │ │ │ ├── examples_eng.db.gz │ │ │ ├── fre.db.gz │ │ │ ├── ger.db.gz │ │ │ ├── hun.db.gz │ │ │ ├── jmdict.db.gz │ │ │ ├── rus.db.gz │ │ │ ├── slv.db.gz │ │ │ ├── spa.db.gz │ │ │ └── swe.db.gz │ │ └── logback.xml │ ├── java │ │ └── org │ │ │ └── happypeng │ │ │ └── sumatora │ │ │ ├── android │ │ │ └── sumatoradictionary │ │ │ │ ├── DictionaryApplication.java │ │ │ │ ├── activity │ │ │ │ ├── AboutActivity.java │ │ │ │ ├── DictionaryBookmarksImportActivity.java │ │ │ │ ├── DictionaryLaunchActivity.java │ │ │ │ ├── LicenseActivity.java │ │ │ │ └── MainActivity.kt │ │ │ │ ├── adapter │ │ │ │ ├── DictionaryObjectAdapter.java │ │ │ │ └── DictionaryPagedListAdapter.kt │ │ │ │ ├── component │ │ │ │ ├── BookmarkComponent.java │ │ │ │ ├── BookmarkImportComponent.java │ │ │ │ ├── BookmarkShareComponent.java │ │ │ │ ├── LanguageSettingsComponent.java │ │ │ │ └── PersistentDatabaseComponent.java │ │ │ │ ├── db │ │ │ │ ├── AssetDictionaryObject.java │ │ │ │ ├── AssetDictionaryObjectDao.java │ │ │ │ ├── DictionaryBookmark.java │ │ │ │ ├── DictionaryBookmarkDao.java │ │ │ │ ├── DictionaryBookmarkImport.java │ │ │ │ ├── DictionaryBookmarkImportDao.java │ │ │ │ ├── DictionaryElement.java │ │ │ │ ├── DictionaryElementDao.java │ │ │ │ ├── DictionarySearchElement.java │ │ │ │ ├── DictionarySearchElementDao.java │ │ │ │ ├── DictionarySearchElementDiffUtil.java │ │ │ │ ├── InstalledDictionary.java │ │ │ │ ├── InstalledDictionaryDao.java │ │ │ │ ├── LocalDictionaryObject.java │ │ │ │ ├── LocalDictionaryObjectDao.java │ │ │ │ ├── PersistentDatabase.java │ │ │ │ ├── PersistentDatabaseInitialization.java │ │ │ │ ├── PersistentDatabaseParameters.java │ │ │ │ ├── PersistentLanguageSettings.java │ │ │ │ ├── PersistentLanguageSettingsDao.java │ │ │ │ ├── PersistentSetting.java │ │ │ │ ├── PersistentSettingsDao.java │ │ │ │ ├── RemoteDictionaryObject.java │ │ │ │ ├── RemoteDictionaryObjectDao.java │ │ │ │ └── tools │ │ │ │ │ ├── AttachedDatabases.java │ │ │ │ │ ├── BaseDictionaryObject.java │ │ │ │ │ ├── BasicQueryStatement.java │ │ │ │ │ ├── BookmarkImportQueryTool.java │ │ │ │ │ ├── DictionarySearchQueryTool.java │ │ │ │ │ ├── JmdictEntities.kt │ │ │ │ │ ├── QueryStatement.java │ │ │ │ │ ├── ReverseQueryStatement.java │ │ │ │ │ ├── Settings.java │ │ │ │ │ ├── SumatoraSQLiteOpenHelperFactory.java │ │ │ │ │ └── ValueHolder.java │ │ │ │ ├── fragment │ │ │ │ ├── BaseFragment.java │ │ │ │ ├── BookmarkFragment.kt │ │ │ │ ├── DebugFragment.java │ │ │ │ ├── QueryFragment.kt │ │ │ │ └── SettingsFragment.java │ │ │ │ ├── model │ │ │ │ ├── BaseFragmentModel.kt │ │ │ │ ├── BaseQueryFragmentModel.kt │ │ │ │ ├── BookmarkFragmentModel.kt │ │ │ │ ├── BookmarkImportModel.kt │ │ │ │ ├── DebugFragmentModel.java │ │ │ │ ├── MainActivityModel.kt │ │ │ │ ├── QueryFragmentModel.kt │ │ │ │ ├── action │ │ │ │ │ ├── ImportAction.kt │ │ │ │ │ └── QueryAction.kt │ │ │ │ ├── intent │ │ │ │ │ ├── DictionaryPagedListAdapterIntent.kt │ │ │ │ │ ├── ImportIntent.kt │ │ │ │ │ ├── LanguageSettingIntent.kt │ │ │ │ │ ├── MainActivityIntent.kt │ │ │ │ │ └── QueryIntent.kt │ │ │ │ ├── processor │ │ │ │ │ ├── ImportActionProcessorHolder.kt │ │ │ │ │ └── QueryActionProcessorHolder.kt │ │ │ │ ├── result │ │ │ │ │ ├── ImportResult.kt │ │ │ │ │ └── QueryResult.kt │ │ │ │ ├── state │ │ │ │ │ ├── ImportState.kt │ │ │ │ │ ├── MainActivityState.kt │ │ │ │ │ └── QueryState.kt │ │ │ │ ├── transformer │ │ │ │ │ ├── ImportIntentTransformer.kt │ │ │ │ │ └── QueryIntentTransformer.kt │ │ │ │ └── viewbinding │ │ │ │ │ ├── FragmentDictionaryQueryBindingUtil.java │ │ │ │ │ └── QueryMenu.java │ │ │ │ ├── mvibase │ │ │ │ ├── MviAction.kt │ │ │ │ ├── MviIntent.kt │ │ │ │ ├── MviResult.kt │ │ │ │ ├── MviView.kt │ │ │ │ ├── MviViewModel.kt │ │ │ │ └── MviViewState.kt │ │ │ │ ├── operator │ │ │ │ └── LiveDataWrapper.kt │ │ │ │ ├── viewholder │ │ │ │ ├── DictionaryObjectViewHolder.java │ │ │ │ ├── DictionarySearchElementViewHolder.kt │ │ │ │ └── rendering │ │ │ │ │ └── SearchElementRenderer.kt │ │ │ │ └── xml │ │ │ │ └── DictionaryBookmarkXML.java │ │ │ └── jromkan │ │ │ ├── Romkan.java │ │ │ └── RomkanData.java │ └── res │ │ ├── drawable │ │ ├── blake_meyer_423494_unsplash_lowres.jpg │ │ ├── ic_account_circle_white_64dp.xml │ │ ├── ic_add_24px.xml │ │ ├── ic_baseline_star_24px.xml │ │ ├── ic_delete_24px.xml │ │ ├── ic_edit_24px.xml │ │ ├── ic_explore_white_24dp.xml │ │ ├── ic_filter_alt_24px.xml │ │ ├── ic_info_white_24dp.xml │ │ ├── ic_launcher_background.xml │ │ ├── ic_menu_white_24dp.xml │ │ ├── ic_outline_bookmark_24px.xml │ │ ├── ic_outline_bookmark_border_24px.xml │ │ ├── ic_outline_bookmarks_24px.xml │ │ ├── ic_outline_cached_24px.xml │ │ ├── ic_outline_cancel_24px.xml │ │ ├── ic_outline_check_24px.xml │ │ ├── ic_outline_class_24px.xml │ │ ├── ic_outline_close_24px.xml │ │ ├── ic_outline_copyright_24px.xml │ │ ├── ic_outline_info_24px.xml │ │ ├── ic_outline_language_24px.xml │ │ ├── ic_outline_menu_24px.xml │ │ ├── ic_outline_public_24px.xml │ │ ├── ic_outline_search_24px.xml │ │ ├── ic_outline_search_24px_white.xml │ │ ├── ic_outline_settings_24px.xml │ │ ├── ic_outline_share_24px.xml │ │ ├── ic_outline_star_border_24px.xml │ │ ├── ic_outline_stop_24px.xml │ │ ├── ic_remove_24px.xml │ │ ├── ic_sumatora_icon.xml │ │ └── nav_drawer_header_foreground.xml │ │ ├── layout │ │ ├── activity_dictionaries_management.xml │ │ ├── activity_dictionary.xml │ │ ├── activity_dictionary_bookmarks_import.xml │ │ ├── activity_license.xml │ │ ├── dictionary_card.xml │ │ ├── fragment_debug.xml │ │ ├── fragment_dictionary_query.xml │ │ ├── fragment_settings.xml │ │ ├── menuitem_language.xml │ │ ├── navigation_drawer_header.xml │ │ └── word_card.xml │ │ ├── menu │ │ ├── bookmark_import_toolbar_menu.xml │ │ ├── debug_toolbar_menu.xml │ │ ├── navigation_menu.xml │ │ └── search_query_menu.xml │ │ ├── values-night │ │ └── colors.xml │ │ ├── values │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── integers.xml │ │ ├── strings.xml │ │ └── styles.xml │ │ └── xml │ │ ├── provider_paths.xml │ │ └── searchable.xml │ └── test │ └── java │ └── org │ └── happypeng │ └── sumatora │ └── android │ └── sumatoradictionary │ └── ExampleUnitTest.java ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── screenshots ├── Screenshot_1551520549.png ├── Screenshot_1551520596.png ├── Screenshot_1551520604.png ├── Screenshot_1551520634.png ├── Screenshot_1551520652.png ├── Screenshot_1551599195.png ├── Screenshot_1553243720.png ├── Screenshot_1556779255.png ├── Screenshot_1556779259.png ├── Screenshot_1556779266.png ├── Screenshot_1556779271.png ├── Screenshot_1561880402.png ├── Screenshot_1581404254.png ├── Screenshot_1581404274.png ├── Screenshot_1606555631.png └── Screenshot_1606555939.png └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | .externalNativeBuild 10 | keystore.properties 11 | -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ -------------------------------------------------------------------------------- /.idea/assetWizardSettings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 36 | 37 | -------------------------------------------------------------------------------- /.idea/caches/build_file_checksums.ser: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HappyPeng2x/SumatoraDictionary/7cbc006992941af4171713900a45a854afa2af8f/.idea/caches/build_file_checksums.ser -------------------------------------------------------------------------------- /.idea/caches/gradle_models.ser: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HappyPeng2x/SumatoraDictionary/7cbc006992941af4171713900a45a854afa2af8f/.idea/caches/gradle_models.ser -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 21 | 22 | -------------------------------------------------------------------------------- /.idea/jarRepositories.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | 14 | 15 | 19 | 20 | 24 | 25 | 29 | 30 | 34 | 35 | 39 | 40 | -------------------------------------------------------------------------------- /.idea/kotlinc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 24 | 41 | 42 | 43 | 44 | 45 | 46 | 48 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /DEBUG.md: -------------------------------------------------------------------------------- 1 | # Sumatora Dictionary Debugging 2 | 3 | ## Logs 4 | 5 | It is possible to display and share logs by opening the Settings view from the side menu and clicking on the Display Log button. 6 | 7 | ![](/screenshots/Screenshot_1556779255.png) 8 | ![](/screenshots/Screenshot_1556779259.png) 9 | ![](/screenshots/Screenshot_1556779266.png) 10 | ![](/screenshots/Screenshot_1556779271.png) 11 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | Please refer to README.md for all information, including licensing and credits. 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Sumatora Dictionary 2 | 3 | An offline Japanese dictionary for Android. 4 | 5 | Please see the [screenshots](/SCREENSHOTS.md) and visit the [website](https://sumatora.happypeng.org/). 6 | 7 | [Get it on F-Droid](https://f-droid.org/packages/org.happypeng.sumatora.android.sumatoradictionary/) 10 | 11 | [Get it on Google Play](https://play.google.com/store/apps/details?id=org.happypeng.sumatora.android.sumatoradictionary) 14 | 15 | ## Features 16 | 17 | Sumatora has the following distinctive features: 18 | - multilingual search (supports English, German, Russian, Spanish, Dutch, Hungarian, Swedish, Slovenian and French) 19 | - very fast search and display of exact term/term at the beginning/term included 20 | - reverse search from the translation in any of the supported languages 21 | - search in romaji, hiragana and katakana 22 | - bookmarks and bookmark export/import 23 | - search selected text in applications using contextual menu (or sharing) 24 | - enables the user to add memos to dictionary entries 25 | - a dark mode. 26 | 27 | ## License 28 | 29 | This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. 30 | 31 | See the [LICENSE](LICENSE) file for details. 32 | 33 | ## Credits 34 | 35 | * [JMDict](https://www.edrdg.org/jmdict/j_jmdict.html), published under the [Creative Commons Attribution-ShareAlike License (V3.0)](https://creativecommons.org/licenses/by-sa/3.0/), by James William Breen and The Electronic Dictionary Research and Development Group 36 | * [Material About Library](https://github.com/daniel-stoneuk/material-about-library), published under the [Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.html), by Daniel Stone 37 | * [Material Design Icons](https://material.io/tools/icons/), published under the [Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.html), by Google 38 | * [Creative Tail - 40 Flat Animal Icons](https://www.creativetail.com/40-free-flat-animal-icons/), published under the [Creative Commons Attribution International License (V4.0)](https://creativecommons.org/licenses/by/4.0/), by Creative Tail 39 | * [Material Design Navigation Drawer](https://github.com/Sottti/Material-Design-Nav-Drawer/tree/using_design_support_library), published under the [MIT License](https://opensource.org/licenses/MIT), by Pablo Costa 40 | * [A nice tiger photo](https://unsplash.com/photos/5RBXc7R-YWs), published under the [Unsplash License](https://unsplash.com/license), by Blake Meyer 41 | * [logback-android](https://tony19.github.io/logback-android/index.html), published under the [Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.html), by Anthony Trinh and QOS.ch 42 | * [Python-romkan](https://www.soimort.org/python-romkan/), published under the [BSD license](https://raw.githubusercontent.com/soimort/python-romkan/master/LICENSE), by Mort Yao 43 | 44 | Google Play and the Google Play logo are trademarks of Google LLC. 45 | 46 | ## Debugging 47 | 48 | Please see the [debug page](/DEBUG.md). 49 | -------------------------------------------------------------------------------- /SCREENSHOTS.md: -------------------------------------------------------------------------------- 1 | # Sumatora Dictionary Screenshots 2 | 3 | ## Search screen 4 | 5 | ![](/screenshots/Screenshot_1551520549.png) 6 | 7 | ## Search from romaji 8 | 9 | ![](/screenshots/Screenshot_1581404254.png) 10 | 11 | ## Reverse search 12 | 13 | ![](/screenshots/Screenshot_1581404274.png) 14 | 15 | ## Multilingual search 16 | ![](/screenshots/Screenshot_1561880402.png) 17 | 18 | ## Search from other apps 19 | 20 | ![](/screenshots/Screenshot_1551599195.png) 21 | 22 | ## Search from other apps (using sharing) 23 | 24 | ![](/screenshots/Screenshot_1553243720.png) 25 | 26 | ## Navigation drawer 27 | 28 | ![](/screenshots/Screenshot_1551520634.png) 29 | 30 | ## Bookmarks 31 | 32 | ![](/screenshots/Screenshot_1551520596.png) 33 | 34 | ## Bookmarks export 35 | 36 | ![](/screenshots/Screenshot_1551520604.png) 37 | 38 | ## Bookmarks import 39 | 40 | ![](/screenshots/Screenshot_1551520652.png) 41 | 42 | ## Memos 43 | 44 | ![](/screenshots/Screenshot_1606555939.png) 45 | 46 | ## Dark mode 47 | 48 | ![](/screenshots/Screenshot_1606555631.png) -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | 23 | -keep class ch.qos.** { *; } 24 | -keep class org.slf4j.** { *; } 25 | -keepattributes *Annotation* 26 | -dontwarn ch.qos.logback.core.net.* 27 | -------------------------------------------------------------------------------- /app/release/output.json: -------------------------------------------------------------------------------- 1 | [{"outputType":{"type":"APK"},"apkInfo":{"type":"MAIN","splits":[],"versionCode":1,"versionName":"0.1.0","enabled":true,"outputFile":"SumatoraDictionary-0.1.0-release.apk","fullName":"release","baseName":"release"},"path":"SumatoraDictionary-0.1.0-release.apk","properties":{}}] -------------------------------------------------------------------------------- /app/src/main/assets/BSD-python-romkan.txt: -------------------------------------------------------------------------------- 1 | The BSD License 2 | 3 | Copyright (c) 2012, 2013 Mort Yao 4 | Copyright (c) 2010 Masato Hagiwara 5 | Copyright (c) 2001 Satoru Takabayashi 6 | All rights reserved. 7 | 8 | Redistribution and use in source and binary forms, with or without 9 | modification, are permitted provided that the following conditions are met: 10 | * Redistributions of source code must retain the above copyright 11 | notice, this list of conditions and the following disclaimer. 12 | * Redistributions in binary form must reproduce the above copyright 13 | notice, this list of conditions and the following disclaimer in the 14 | documentation and/or other materials provided with the distribution. 15 | * Neither the name of the nor the 16 | names of its contributors may be used to endorse or promote products 17 | derived from this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 20 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY 23 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 26 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | -------------------------------------------------------------------------------- /app/src/main/assets/MIT.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /app/src/main/assets/Unsplash.txt: -------------------------------------------------------------------------------- 1 | All photos published on Unsplash can be used for free. 2 | You can use them for commercial and noncommercial purposes. 3 | You do not need to ask permission from or provide credit to the photographer 4 | or Unsplash, although it is appreciated when possible. 5 | 6 | More precisely, Unsplash grants you an irrevocable, nonexclusive, 7 | worldwide copyright license to download, copy, modify, distribute, perform, 8 | and use photos from Unsplash for free, including for commercial purposes, 9 | without permission from or attributing the photographer or Unsplash. 10 | This license does not include the right to compile photos from Unsplash 11 | to replicate a similar or competing service. 12 | -------------------------------------------------------------------------------- /app/src/main/assets/dictionaries.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 9 | 12 | 15 | 18 | 21 | 24 | 27 | 30 | 33 | 34 | -------------------------------------------------------------------------------- /app/src/main/assets/dictionaries/dut.db.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HappyPeng2x/SumatoraDictionary/7cbc006992941af4171713900a45a854afa2af8f/app/src/main/assets/dictionaries/dut.db.gz -------------------------------------------------------------------------------- /app/src/main/assets/dictionaries/eng.db.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HappyPeng2x/SumatoraDictionary/7cbc006992941af4171713900a45a854afa2af8f/app/src/main/assets/dictionaries/eng.db.gz -------------------------------------------------------------------------------- /app/src/main/assets/dictionaries/examples_eng.db.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HappyPeng2x/SumatoraDictionary/7cbc006992941af4171713900a45a854afa2af8f/app/src/main/assets/dictionaries/examples_eng.db.gz -------------------------------------------------------------------------------- /app/src/main/assets/dictionaries/fre.db.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HappyPeng2x/SumatoraDictionary/7cbc006992941af4171713900a45a854afa2af8f/app/src/main/assets/dictionaries/fre.db.gz -------------------------------------------------------------------------------- /app/src/main/assets/dictionaries/ger.db.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HappyPeng2x/SumatoraDictionary/7cbc006992941af4171713900a45a854afa2af8f/app/src/main/assets/dictionaries/ger.db.gz -------------------------------------------------------------------------------- /app/src/main/assets/dictionaries/hun.db.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HappyPeng2x/SumatoraDictionary/7cbc006992941af4171713900a45a854afa2af8f/app/src/main/assets/dictionaries/hun.db.gz -------------------------------------------------------------------------------- /app/src/main/assets/dictionaries/jmdict.db.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HappyPeng2x/SumatoraDictionary/7cbc006992941af4171713900a45a854afa2af8f/app/src/main/assets/dictionaries/jmdict.db.gz -------------------------------------------------------------------------------- /app/src/main/assets/dictionaries/rus.db.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HappyPeng2x/SumatoraDictionary/7cbc006992941af4171713900a45a854afa2af8f/app/src/main/assets/dictionaries/rus.db.gz -------------------------------------------------------------------------------- /app/src/main/assets/dictionaries/slv.db.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HappyPeng2x/SumatoraDictionary/7cbc006992941af4171713900a45a854afa2af8f/app/src/main/assets/dictionaries/slv.db.gz -------------------------------------------------------------------------------- /app/src/main/assets/dictionaries/spa.db.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HappyPeng2x/SumatoraDictionary/7cbc006992941af4171713900a45a854afa2af8f/app/src/main/assets/dictionaries/spa.db.gz -------------------------------------------------------------------------------- /app/src/main/assets/dictionaries/swe.db.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HappyPeng2x/SumatoraDictionary/7cbc006992941af4171713900a45a854afa2af8f/app/src/main/assets/dictionaries/swe.db.gz -------------------------------------------------------------------------------- /app/src/main/assets/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | %logger{12} 5 | 6 | 7 | [%thread] %msg%n 8 | 9 | 10 | 11 | 12 | ${DATA_DIR}/logs/log.txt 13 | 14 | 15 | %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n 16 | 17 | 18 | 19 | ${DATA_DIR}/log.%d.txt 20 | 3 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /app/src/main/java/org/happypeng/sumatora/android/sumatoradictionary/DictionaryApplication.java: -------------------------------------------------------------------------------- 1 | /* Sumatora Dictionary 2 | Copyright (C) 2019 Nicolas Centa 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see .*/ 16 | 17 | package org.happypeng.sumatora.android.sumatoradictionary; 18 | 19 | import android.app.Application; 20 | import android.os.StrictMode; 21 | 22 | import androidx.multidex.MultiDexApplication; 23 | 24 | import dagger.hilt.android.HiltAndroidApp; 25 | 26 | @HiltAndroidApp 27 | public class DictionaryApplication extends MultiDexApplication { 28 | //private DownloadEventReceiver m_downloadEventReceiver; 29 | 30 | @Override 31 | public void onCreate() { 32 | super.onCreate(); 33 | 34 | if (BuildConfig.DEBUG) { 35 | StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder() 36 | .detectAll() 37 | .penaltyLog() 38 | .build()); 39 | StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder() 40 | .detectAll() 41 | .penaltyLog() 42 | .build()); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /app/src/main/java/org/happypeng/sumatora/android/sumatoradictionary/activity/DictionaryLaunchActivity.java: -------------------------------------------------------------------------------- 1 | /* Sumatora Dictionary 2 | Copyright (C) 2019 Nicolas Centa 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see .*/ 16 | 17 | package org.happypeng.sumatora.android.sumatoradictionary.activity; 18 | 19 | import androidx.appcompat.app.AppCompatActivity; 20 | 21 | import android.content.Intent; 22 | 23 | import android.os.Build; 24 | import android.os.Bundle; 25 | 26 | import org.happypeng.sumatora.android.sumatoradictionary.BuildConfig; 27 | import org.slf4j.Logger; 28 | import org.slf4j.LoggerFactory; 29 | 30 | // We use this class so that Dictionary is brought in the front. 31 | // It is as if the application had been manually launched and the search word typed inside. 32 | // This is not the behavior expected for PROCESS_TEXT. 33 | // The behavior expected is that a new activity will be created for each app where PROCESS_TEXT is invoked. 34 | // However it is not supported by our current database structure. 35 | 36 | public class DictionaryLaunchActivity extends AppCompatActivity { 37 | 38 | @Override 39 | protected void onCreate(Bundle savedInstanceState) { 40 | super.onCreate(savedInstanceState); 41 | 42 | Logger log = null; 43 | 44 | if (BuildConfig.DEBUG_LAUNCH_ACTIVITY) { 45 | log = LoggerFactory.getLogger(this.getClass()); 46 | 47 | log.info("onCreate started"); 48 | } 49 | 50 | Intent inboundIntent = getIntent(); 51 | String receivedAction = inboundIntent.getAction(); 52 | 53 | String searchTerm = null; 54 | 55 | if (BuildConfig.DEBUG_LAUNCH_ACTIVITY) { 56 | log.info("receivedAction = " + receivedAction); 57 | 58 | if (inboundIntent.getExtras() != null) { 59 | for (String key : inboundIntent.getExtras().keySet()) { 60 | log.info("inboundIntent has key " + key); 61 | 62 | Object val = inboundIntent.getExtras().get(key); 63 | 64 | if (val != null) { 65 | log.info("type " + val.getClass().getName() + " value " + val.toString()); 66 | } else { 67 | log.info("value is null"); 68 | } 69 | } 70 | } 71 | } 72 | 73 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && 74 | receivedAction != null && receivedAction.equals(Intent.ACTION_PROCESS_TEXT)) { 75 | searchTerm = inboundIntent.getCharSequenceExtra(Intent.EXTRA_PROCESS_TEXT).toString(); 76 | } else if (receivedAction != null && receivedAction.equals(Intent.ACTION_SEND)) { 77 | searchTerm = inboundIntent.getStringExtra(Intent.EXTRA_TEXT); 78 | } 79 | 80 | final Intent notificationIntent = new Intent(this, MainActivity.class); 81 | notificationIntent.setAction(Intent.ACTION_MAIN); 82 | notificationIntent.addCategory(Intent.CATEGORY_LAUNCHER); 83 | 84 | if (searchTerm != null) { 85 | notificationIntent.putExtra("SEARCH_TERM", searchTerm); 86 | notificationIntent.putExtra("SET_SEARCH_FRAGMENT", true); 87 | } 88 | 89 | startActivity(notificationIntent); 90 | 91 | finish(); 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /app/src/main/java/org/happypeng/sumatora/android/sumatoradictionary/activity/LicenseActivity.java: -------------------------------------------------------------------------------- 1 | /* Sumatora Dictionary 2 | Copyright (C) 2018 Nicolas Centa 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see .*/ 16 | 17 | package org.happypeng.sumatora.android.sumatoradictionary.activity; 18 | 19 | import androidx.appcompat.app.AppCompatActivity; 20 | import android.os.Bundle; 21 | 22 | import java.io.BufferedReader; 23 | import java.io.IOException; 24 | import java.io.InputStreamReader; 25 | 26 | import android.widget.TextView; 27 | 28 | import org.happypeng.sumatora.android.sumatoradictionary.R; 29 | 30 | public class LicenseActivity extends AppCompatActivity { 31 | 32 | @Override 33 | protected void onCreate(Bundle savedInstanceState) { 34 | super.onCreate(savedInstanceState); 35 | setContentView(R.layout.activity_license); 36 | 37 | TextView text_view = (TextView) findViewById(R.id.licence_text_view); 38 | StringBuilder sb = new StringBuilder(); 39 | String asset = getIntent().getCharSequenceExtra("asset").toString(); 40 | 41 | try { 42 | BufferedReader reader = new BufferedReader(new InputStreamReader(getAssets().open(asset))); 43 | 44 | String line; 45 | 46 | while ((line = reader.readLine()) != null) { 47 | sb.append(line); 48 | sb.append("\n"); 49 | } 50 | 51 | reader.close(); 52 | } catch (IOException e) { 53 | System.err.println(e.toString()); 54 | } 55 | 56 | text_view.setText(sb.toString()); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /app/src/main/java/org/happypeng/sumatora/android/sumatoradictionary/adapter/DictionaryObjectAdapter.java: -------------------------------------------------------------------------------- 1 | /* Sumatora Dictionary 2 | Copyright (C) 2019 Nicolas Centa 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see . */ 16 | 17 | package org.happypeng.sumatora.android.sumatoradictionary.adapter; 18 | 19 | import android.view.LayoutInflater; 20 | import android.view.View; 21 | import android.view.ViewGroup; 22 | 23 | import androidx.annotation.NonNull; 24 | import androidx.recyclerview.widget.ListAdapter; 25 | 26 | import org.happypeng.sumatora.android.sumatoradictionary.R; 27 | import org.happypeng.sumatora.android.sumatoradictionary.db.tools.BaseDictionaryObject; 28 | import org.happypeng.sumatora.android.sumatoradictionary.viewholder.DictionaryObjectViewHolder; 29 | 30 | public class DictionaryObjectAdapter extends ListAdapter> { 31 | private boolean mInstallButton; 32 | private boolean mDeleteButton; 33 | 34 | private final DictionaryObjectViewHolder.OnClickListener mInstallListener; 35 | private final DictionaryObjectViewHolder.OnClickListener mDeleteListener; 36 | 37 | public DictionaryObjectAdapter(boolean aInstallButton, 38 | boolean aDeleteButton, 39 | final DictionaryObjectViewHolder.OnClickListener aInstallListener, 40 | final DictionaryObjectViewHolder.OnClickListener aDeleteListener) { 41 | super(BaseDictionaryObject.getDiffUtil()); 42 | 43 | mInstallButton = aInstallButton; 44 | mDeleteButton = aDeleteButton; 45 | 46 | mInstallListener = aInstallListener; 47 | mDeleteListener = aDeleteListener; 48 | } 49 | 50 | @NonNull 51 | @Override 52 | public DictionaryObjectViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { 53 | LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext()); 54 | View view = layoutInflater.inflate(R.layout.dictionary_card, parent, false); 55 | 56 | return new DictionaryObjectViewHolder(view, mInstallButton, mDeleteButton, 57 | mInstallListener, mDeleteListener); 58 | } 59 | 60 | @Override 61 | public void onBindViewHolder(@NonNull DictionaryObjectViewHolder holder, int position) { 62 | holder.bindTo(getItem(position)); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /app/src/main/java/org/happypeng/sumatora/android/sumatoradictionary/adapter/DictionaryPagedListAdapter.kt: -------------------------------------------------------------------------------- 1 | /* Sumatora Dictionary 2 | Copyright (C) 2019 Nicolas Centa 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see .*/ 16 | package org.happypeng.sumatora.android.sumatoradictionary.adapter 17 | 18 | import android.view.LayoutInflater 19 | import android.view.ViewGroup 20 | import androidx.paging.PagedListAdapter 21 | import androidx.recyclerview.widget.RecyclerView 22 | import io.reactivex.rxjava3.subjects.PublishSubject 23 | import org.happypeng.sumatora.android.sumatoradictionary.databinding.WordCardBinding 24 | import org.happypeng.sumatora.android.sumatoradictionary.db.DictionarySearchElement 25 | import org.happypeng.sumatora.android.sumatoradictionary.db.DictionarySearchElementDiffUtil 26 | import org.happypeng.sumatora.android.sumatoradictionary.db.tools.JMDICT_ENTITIES 27 | import org.happypeng.sumatora.android.sumatoradictionary.model.intent.DictionaryPagedListAdapterCloseIntent 28 | import org.happypeng.sumatora.android.sumatoradictionary.model.intent.DictionaryPagedListAdapterIntent 29 | import org.happypeng.sumatora.android.sumatoradictionary.viewholder.DictionarySearchElementViewHolder 30 | import java.util.* 31 | 32 | class DictionaryPagedListAdapter(aDisableBookmarkButton: Boolean, 33 | aDisableMemoEdit: Boolean, 34 | commitConsumer: (Long, Long, String?) -> Unit, 35 | private val holderColors: DictionarySearchElementViewHolder.Colors) : 36 | PagedListAdapter(DictionarySearchElementDiffUtil.getDiffUtil()) { 37 | private val entities = JMDICT_ENTITIES 38 | private val disableBookmarkButton: Boolean 39 | private val disableMemoEdit: Boolean 40 | private val commitConsumer: (Long, Long, String?) -> Unit 41 | private val intentSubject: PublishSubject = PublishSubject.create() 42 | 43 | fun close() { 44 | intentSubject.onNext(DictionaryPagedListAdapterCloseIntent) 45 | } 46 | 47 | // No placeholders = no null values 48 | override fun getItemId(position: Int): Long { 49 | return getItem(position)!!.getSeq() 50 | } 51 | 52 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DictionarySearchElementViewHolder { 53 | val layoutInflater = LayoutInflater.from(parent.context) 54 | val wordCardBinding = WordCardBinding.inflate(layoutInflater) 55 | return DictionarySearchElementViewHolder(wordCardBinding, 56 | entities, disableBookmarkButton, disableMemoEdit, 57 | commitConsumer, intentSubject, holderColors) 58 | } 59 | 60 | override fun onBindViewHolder(holder: DictionarySearchElementViewHolder, position: Int) { 61 | val entry = getItem(position) 62 | if (entry != null) { 63 | holder.bindTo(entry) 64 | } 65 | } 66 | 67 | init { 68 | setHasStableIds(true) 69 | disableBookmarkButton = aDisableBookmarkButton 70 | disableMemoEdit = aDisableMemoEdit 71 | this.commitConsumer = commitConsumer 72 | } 73 | 74 | override fun onViewRecycled(holder: DictionarySearchElementViewHolder) { 75 | super.onViewRecycled(holder) 76 | 77 | holder.recycle() 78 | } 79 | } -------------------------------------------------------------------------------- /app/src/main/java/org/happypeng/sumatora/android/sumatoradictionary/component/BookmarkComponent.java: -------------------------------------------------------------------------------- 1 | /* Sumatora Dictionary 2 | Copyright (C) 2019 Nicolas Centa 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see .*/ 16 | 17 | package org.happypeng.sumatora.android.sumatoradictionary.component; 18 | 19 | import androidx.annotation.MainThread; 20 | import androidx.annotation.WorkerThread; 21 | 22 | import org.happypeng.sumatora.android.sumatoradictionary.db.DictionaryBookmark; 23 | import org.happypeng.sumatora.android.sumatoradictionary.db.DictionaryBookmarkDao; 24 | import org.happypeng.sumatora.android.sumatoradictionary.db.PersistentDatabase; 25 | 26 | import java.util.ArrayList; 27 | import java.util.List; 28 | 29 | import javax.inject.Inject; 30 | import javax.inject.Singleton; 31 | 32 | import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers; 33 | import io.reactivex.rxjava3.core.Observable; 34 | import io.reactivex.rxjava3.schedulers.Schedulers; 35 | import io.reactivex.rxjava3.subjects.PublishSubject; 36 | import io.reactivex.rxjava3.subjects.Subject; 37 | 38 | @Singleton 39 | public class BookmarkComponent { 40 | private final PersistentDatabaseComponent persistentDatabaseComponent; 41 | private final Subject> bookmarkChanges; 42 | private final Observable> bookmarkChangesObservable; 43 | 44 | @Inject 45 | BookmarkComponent(final PersistentDatabaseComponent persistentDatabaseComponent) { 46 | this.persistentDatabaseComponent = persistentDatabaseComponent; 47 | 48 | bookmarkChanges = PublishSubject.create(); 49 | bookmarkChangesObservable = 50 | bookmarkChanges.observeOn(Schedulers.io()).map(l -> { 51 | final PersistentDatabase persistentDatabase = persistentDatabaseComponent.getDatabase(); 52 | final DictionaryBookmarkDao dictionaryBookmarkDao = persistentDatabase.dictionaryBookmarkDao(); 53 | 54 | persistentDatabase.runInTransaction(() -> 55 | { 56 | for (DictionaryBookmark b : l) { 57 | if (b.bookmark > 0 || (b.memo != null && !"".equals(b.memo))) { 58 | dictionaryBookmarkDao.insert(b); 59 | } else { 60 | dictionaryBookmarkDao.delete(b); 61 | } 62 | } 63 | }); 64 | 65 | return l; 66 | }).observeOn(AndroidSchedulers.mainThread()).publish().autoConnect(); 67 | } 68 | 69 | public Observable> getBookmarkChanges() { 70 | return bookmarkChangesObservable; 71 | } 72 | 73 | @MainThread 74 | public void updateBookmarks(final List bookmarks) { 75 | bookmarkChanges.onNext(bookmarks); 76 | } 77 | 78 | @MainThread 79 | public void updateBookmark(final DictionaryBookmark bookmark) { 80 | final ArrayList list = new ArrayList<>(1); 81 | list.add(bookmark); 82 | 83 | bookmarkChanges.onNext(list); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /app/src/main/java/org/happypeng/sumatora/android/sumatoradictionary/component/BookmarkShareComponent.java: -------------------------------------------------------------------------------- 1 | /* Sumatora Dictionary 2 | Copyright (C) 2019 Nicolas Centa 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see .*/ 16 | 17 | package org.happypeng.sumatora.android.sumatoradictionary.component; 18 | 19 | import android.content.Context; 20 | import android.content.Intent; 21 | import android.net.Uri; 22 | import android.widget.Toast; 23 | 24 | import androidx.annotation.MainThread; 25 | import androidx.annotation.WorkerThread; 26 | import androidx.core.content.FileProvider; 27 | 28 | import com.fasterxml.jackson.databind.ObjectMapper; 29 | 30 | import org.happypeng.sumatora.android.sumatoradictionary.db.DictionaryBookmark; 31 | 32 | import java.io.File; 33 | import java.io.IOException; 34 | import java.util.List; 35 | 36 | import javax.inject.Inject; 37 | import javax.inject.Singleton; 38 | 39 | import dagger.hilt.android.qualifiers.ActivityContext; 40 | import dagger.hilt.android.qualifiers.ApplicationContext; 41 | import dagger.hilt.android.scopes.ActivityRetainedScoped; 42 | import dagger.hilt.android.scopes.ActivityScoped; 43 | import dagger.hilt.android.scopes.FragmentScoped; 44 | import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers; 45 | import io.reactivex.rxjava3.annotations.NonNull; 46 | import io.reactivex.rxjava3.core.Completable; 47 | import io.reactivex.rxjava3.disposables.Disposable; 48 | import io.reactivex.rxjava3.observers.DisposableCompletableObserver; 49 | import io.reactivex.rxjava3.schedulers.Schedulers; 50 | 51 | @ActivityScoped 52 | public class BookmarkShareComponent { 53 | private static final String AUTHORITY = "org.happypeng.sumatora.android.sumatoradictionary.fileprovider"; 54 | 55 | final Context context; 56 | final PersistentDatabaseComponent persistentDatabaseComponent; 57 | final BookmarkComponent bookmarkComponent; 58 | 59 | 60 | @Inject 61 | BookmarkShareComponent(@ActivityContext final Context context, 62 | final PersistentDatabaseComponent persistentDatabaseComponent, 63 | final BookmarkComponent bookmarkComponent) { 64 | this.context = context; 65 | this.persistentDatabaseComponent = persistentDatabaseComponent; 66 | this.bookmarkComponent = bookmarkComponent; 67 | } 68 | 69 | @WorkerThread 70 | public File writeBookmarks() throws IOException { 71 | File parentDir = new File(context.getFilesDir(), "bookmarks"); 72 | final File outputFile = new File(parentDir, "bookmarks.json"); 73 | 74 | parentDir.mkdirs(); 75 | 76 | List bookmarks = persistentDatabaseComponent.getDatabase() 77 | .dictionaryBookmarkDao().getAll(); 78 | 79 | ObjectMapper mapper = new ObjectMapper(); 80 | mapper.writeValue(outputFile, bookmarks); 81 | 82 | return outputFile; 83 | } 84 | 85 | @MainThread 86 | public void shareBookmarks(final File outputFile) { 87 | Uri contentUri = FileProvider.getUriForFile 88 | (context, AUTHORITY, outputFile); 89 | 90 | Intent sharingIntent = new Intent(Intent.ACTION_SEND); 91 | 92 | sharingIntent.setType("text/*"); 93 | sharingIntent.putExtra(Intent.EXTRA_STREAM, contentUri); 94 | sharingIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); 95 | 96 | context.startActivity(Intent.createChooser(sharingIntent, "Share bookmarks")); 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /app/src/main/java/org/happypeng/sumatora/android/sumatoradictionary/db/AssetDictionaryObject.java: -------------------------------------------------------------------------------- 1 | /* Sumatora Dictionary 2 | Copyright (C) 2019 Nicolas Centa 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see .*/ 16 | 17 | package org.happypeng.sumatora.android.sumatoradictionary.db; 18 | 19 | import android.content.res.AssetManager; 20 | import android.util.Log; 21 | 22 | import androidx.annotation.NonNull; 23 | import androidx.annotation.WorkerThread; 24 | import androidx.room.Entity; 25 | 26 | import org.happypeng.sumatora.android.sumatoradictionary.db.tools.BaseDictionaryObject; 27 | 28 | import java.io.File; 29 | import java.io.FileOutputStream; 30 | import java.io.IOException; 31 | import java.io.InputStream; 32 | import java.io.OutputStream; 33 | 34 | @Entity(primaryKeys = {"type", "lang"}) 35 | public class AssetDictionaryObject extends BaseDictionaryObject { 36 | public AssetDictionaryObject() { 37 | super(); 38 | } 39 | 40 | public AssetDictionaryObject(final @NonNull String aFile, 41 | final String aDescription, 42 | final @NonNull String aType, 43 | final @NonNull String aLang, 44 | int aVersion, 45 | int aDate) { 46 | file = aFile; 47 | description = aDescription; 48 | type = aType; 49 | lang = aLang; 50 | version = aVersion; 51 | date = aDate; 52 | } 53 | 54 | @WorkerThread 55 | private static boolean copyAsset(@NonNull final AssetManager aAssetManager, String aName, 56 | File aOutput) { 57 | try { 58 | InputStream in = aAssetManager.open(aName); 59 | OutputStream out = new FileOutputStream(aOutput); 60 | copyFile(in, out); 61 | in.close(); 62 | in = null; 63 | out.flush(); 64 | out.close(); 65 | out = null; 66 | 67 | return true; 68 | } catch(IOException e) { 69 | Log.e("tag", "Failed to copy asset file: " + aName, e); 70 | } 71 | 72 | return false; 73 | } 74 | 75 | @WorkerThread 76 | public boolean install(final AssetManager aAssetManager, 77 | final String aDatabaseDir, 78 | final InstalledDictionaryDao aDao) { 79 | if (aAssetManager == null) { 80 | return false; 81 | } 82 | 83 | File sourceFile = new File(file); 84 | String fileName = sourceFile.getName(); 85 | 86 | File destFile = new File(aDatabaseDir, fileName); 87 | 88 | if (copyAsset(aAssetManager, 89 | sourceFile.toString(), 90 | destFile)) { 91 | InstalledDictionary insertDir = new InstalledDictionary(destFile.toString(), 92 | description, type, lang, version, date); 93 | 94 | aDao.insert(insertDir); 95 | 96 | return true; 97 | } 98 | 99 | return false; 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /app/src/main/java/org/happypeng/sumatora/android/sumatoradictionary/db/AssetDictionaryObjectDao.java: -------------------------------------------------------------------------------- 1 | /* Sumatora Dictionary 2 | Copyright (C) 2019 Nicolas Centa 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see .*/ 16 | 17 | package org.happypeng.sumatora.android.sumatoradictionary.db; 18 | 19 | import androidx.lifecycle.LiveData; 20 | import androidx.room.Dao; 21 | import androidx.room.Delete; 22 | import androidx.room.Insert; 23 | import androidx.room.OnConflictStrategy; 24 | import androidx.room.Query; 25 | import androidx.room.Update; 26 | 27 | import java.util.List; 28 | 29 | @Dao 30 | public interface AssetDictionaryObjectDao { 31 | @Insert(onConflict = OnConflictStrategy.REPLACE) 32 | void insertMany(List aActions); 33 | 34 | @Query("SELECT * FROM AssetDictionaryObject") 35 | List getAll(); 36 | 37 | @Query("SELECT * FROM AssetDictionaryObject") 38 | LiveData> getAllLive(); 39 | 40 | @Delete 41 | void deleteMany(List aActions); 42 | 43 | @Update 44 | void update(AssetDictionaryObject aAction); 45 | 46 | // Only updates, and jmdict and english translation if not installed are to be installed 47 | @Query("SELECT AssetDictionaryObject.description, " + 48 | "AssetDictionaryObject.type, AssetDictionaryObject.lang, " + 49 | "AssetDictionaryObject.version, AssetDictionaryObject.date, " + 50 | "AssetDictionaryObject.file " + 51 | "FROM AssetDictionaryObject INNER JOIN InstalledDictionary " + 52 | "ON AssetDictionaryObject.type == InstalledDictionary.type " + 53 | "AND AssetDictionaryObject.lang == InstalledDictionary.lang " + 54 | // "AND AssetDictionaryObject.date > InstalledDictionary.date " + 55 | "AND AssetDictionaryObject.version > InstalledDictionary.version") 56 | List getInstallObjects(); 57 | 58 | @Query("SELECT * FROM AssetDictionaryObject WHERE AssetDictionaryObject.type == :aType AND AssetDictionaryObject.lang == :aLang LIMIT 1") 59 | AssetDictionaryObject getForTypeLang(String aType, String aLang); 60 | } 61 | -------------------------------------------------------------------------------- /app/src/main/java/org/happypeng/sumatora/android/sumatoradictionary/db/DictionaryBookmark.java: -------------------------------------------------------------------------------- 1 | /* Sumatora Dictionary 2 | Copyright (C) 2019 Nicolas Centa 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see .*/ 16 | 17 | package org.happypeng.sumatora.android.sumatoradictionary.db; 18 | 19 | import androidx.room.Entity; 20 | 21 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 22 | import com.fasterxml.jackson.annotation.JsonInclude; 23 | import com.fasterxml.jackson.annotation.JsonProperty; 24 | 25 | @JsonInclude(JsonInclude.Include.NON_NULL) 26 | @JsonIgnoreProperties(ignoreUnknown = true) 27 | @Entity(primaryKeys = {"seq"}) 28 | public class DictionaryBookmark { 29 | @JsonProperty("seq") 30 | public long seq; 31 | 32 | @JsonProperty("bookmark") 33 | public long bookmark; 34 | 35 | @JsonProperty("memo") 36 | public String memo; 37 | 38 | public DictionaryBookmark() {} 39 | 40 | public DictionaryBookmark(long aSeq, long aBookmark, String aMemo) { 41 | seq = aSeq; 42 | bookmark = aBookmark; 43 | memo = aMemo; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /app/src/main/java/org/happypeng/sumatora/android/sumatoradictionary/db/DictionaryBookmarkDao.java: -------------------------------------------------------------------------------- 1 | /* Sumatora Dictionary 2 | Copyright (C) 2019 Nicolas Centa 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see .*/ 16 | 17 | package org.happypeng.sumatora.android.sumatoradictionary.db; 18 | 19 | import androidx.lifecycle.LiveData; 20 | import androidx.room.Dao; 21 | import androidx.room.Delete; 22 | import androidx.room.Insert; 23 | import androidx.room.OnConflictStrategy; 24 | import androidx.room.Query; 25 | 26 | import java.util.List; 27 | 28 | @Dao 29 | public interface DictionaryBookmarkDao { 30 | @Query("SELECT * FROM DictionaryBookmark") 31 | List getAll(); 32 | 33 | @Insert(onConflict = OnConflictStrategy.REPLACE) 34 | void insert(DictionaryBookmark aBookmark); 35 | 36 | @Insert(onConflict = OnConflictStrategy.REPLACE) 37 | void insertMany(List aBookmark); 38 | 39 | @Delete 40 | void delete(DictionaryBookmark aBookmark); 41 | 42 | @Query("DELETE FROM DictionaryBookmark WHERE seq = :seq") 43 | void delete(long seq); 44 | 45 | // This query is used to get a LiveData updated when the table is modified 46 | @Query("SELECT seq FROM DictionaryBookmark LIMIT 1") 47 | LiveData getFirstLive(); 48 | } 49 | -------------------------------------------------------------------------------- /app/src/main/java/org/happypeng/sumatora/android/sumatoradictionary/db/DictionaryBookmarkImport.java: -------------------------------------------------------------------------------- 1 | /* Sumatora Dictionary 2 | Copyright (C) 2019 Nicolas Centa 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see .*/ 16 | 17 | package org.happypeng.sumatora.android.sumatoradictionary.db; 18 | 19 | import androidx.room.Entity; 20 | 21 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 22 | import com.fasterxml.jackson.annotation.JsonInclude; 23 | import com.fasterxml.jackson.annotation.JsonProperty; 24 | 25 | @JsonInclude(JsonInclude.Include.NON_NULL) 26 | @JsonIgnoreProperties(ignoreUnknown = true) 27 | @Entity(primaryKeys = {"ref", "seq"}) 28 | public class DictionaryBookmarkImport { 29 | public int ref; 30 | 31 | @JsonProperty("seq") 32 | public long seq; 33 | 34 | @JsonProperty("bookmark") 35 | public long bookmark; 36 | 37 | @JsonProperty("memo") 38 | public String memo; 39 | 40 | public DictionaryBookmarkImport() { super(); } 41 | 42 | public DictionaryBookmarkImport(int aRef, long aSeq, long aBookmark, String aMemo) { 43 | super(); 44 | 45 | ref = aRef; 46 | seq = aSeq; 47 | memo = aMemo; 48 | bookmark = aBookmark; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /app/src/main/java/org/happypeng/sumatora/android/sumatoradictionary/db/DictionaryBookmarkImportDao.java: -------------------------------------------------------------------------------- 1 | /* Sumatora Dictionary 2 | Copyright (C) 2019 Nicolas Centa 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see .*/ 16 | 17 | package org.happypeng.sumatora.android.sumatoradictionary.db; 18 | 19 | import java.util.List; 20 | 21 | import androidx.lifecycle.LiveData; 22 | import androidx.room.Dao; 23 | import androidx.room.Delete; 24 | import androidx.room.Insert; 25 | import androidx.room.OnConflictStrategy; 26 | import androidx.room.Query; 27 | 28 | @Dao 29 | public interface DictionaryBookmarkImportDao { 30 | @Query("DELETE FROM DictionaryBookmarkImport WHERE ref=:ref") 31 | void delete(int ref); 32 | 33 | @Insert(onConflict = OnConflictStrategy.REPLACE) 34 | void insert(DictionaryBookmarkImport aBookmark); 35 | 36 | @Insert(onConflict = OnConflictStrategy.REPLACE) 37 | void insertMany(List aBookmark); 38 | } 39 | -------------------------------------------------------------------------------- /app/src/main/java/org/happypeng/sumatora/android/sumatoradictionary/db/DictionaryElement.java: -------------------------------------------------------------------------------- 1 | /* Sumatora Dictionary 2 | Copyright (C) 2019 Nicolas Centa 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see .*/ 16 | 17 | package org.happypeng.sumatora.android.sumatoradictionary.db; 18 | 19 | import androidx.room.Entity; 20 | 21 | @Entity(primaryKeys = {"ref", "seq"}) 22 | public class DictionaryElement { 23 | public int ref; 24 | public int entryOrder; 25 | public long seq; 26 | 27 | public DictionaryElement() { super(); } 28 | } 29 | -------------------------------------------------------------------------------- /app/src/main/java/org/happypeng/sumatora/android/sumatoradictionary/db/DictionaryElementDao.java: -------------------------------------------------------------------------------- 1 | /* Sumatora Dictionary 2 | Copyright (C) 2019 Nicolas Centa 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see .*/ 16 | 17 | package org.happypeng.sumatora.android.sumatoradictionary.db; 18 | 19 | import androidx.lifecycle.LiveData; 20 | import androidx.room.Dao; 21 | import androidx.room.Query; 22 | 23 | import java.util.List; 24 | 25 | @Dao 26 | public interface DictionaryElementDao { 27 | @Query("DELETE FROM DictionaryElement") 28 | void deleteAll(); 29 | 30 | // This query is used to get a LiveData updated when the table is modified 31 | @Query("SELECT seq FROM DictionaryElement LIMIT 1") 32 | LiveData getFirstLive(); 33 | } 34 | -------------------------------------------------------------------------------- /app/src/main/java/org/happypeng/sumatora/android/sumatoradictionary/db/DictionarySearchElement.java: -------------------------------------------------------------------------------- 1 | /* Sumatora Dictionary 2 | Copyright (C) 2019 Nicolas Centa 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see .*/ 16 | 17 | package org.happypeng.sumatora.android.sumatoradictionary.db; 18 | 19 | import androidx.room.Entity; 20 | 21 | @Entity(primaryKeys = {"ref", "seq"}) 22 | public class DictionarySearchElement { 23 | public int ref; 24 | public int entryOrder; 25 | public long seq; 26 | public String readingsPrio; 27 | public String readings; 28 | public String writingsPrio; 29 | public String writings; 30 | public String pos; 31 | public String xref; 32 | public String ant; 33 | public String misc; 34 | public String lsource; 35 | public String dial; 36 | public String s_inf; 37 | public String field; 38 | public String lang; 39 | public String lang_setting; 40 | public String gloss; 41 | public String example_sentences; 42 | public String example_translations; 43 | public long bookmark; 44 | public String memo; 45 | 46 | public DictionarySearchElement() { } 47 | 48 | public int getEntryOrder() { 49 | return entryOrder; 50 | } 51 | 52 | public long getSeq() { 53 | return seq; 54 | } 55 | 56 | public String getReadingsPrio() { 57 | return readingsPrio; 58 | } 59 | 60 | public String getReadings() { 61 | return readings; 62 | } 63 | 64 | public String getWritingsPrio() { 65 | return writingsPrio; 66 | } 67 | 68 | public String getWritings() { 69 | return writings; 70 | } 71 | 72 | public String getLang() { 73 | return lang; 74 | } 75 | 76 | public String getLangSetting() { return lang_setting; } 77 | 78 | public String getGloss() { 79 | return gloss; 80 | } 81 | 82 | public long getBookmark() { return bookmark; } 83 | public String getMemo() { return memo; } 84 | 85 | public String getPos() { return pos; } 86 | public String getXref() { return xref; } 87 | public String getAnt() { return ant; } 88 | public String getMisc() { return misc; } 89 | public String getLsource() { return lsource; } 90 | public String getDial() { return dial; } 91 | public String getS_inf() { return s_inf; } 92 | public String getField() { return field; } 93 | 94 | public String getExampleSentences() { return example_sentences; } 95 | public String getExampleTranslations() { return example_translations; } 96 | } 97 | -------------------------------------------------------------------------------- /app/src/main/java/org/happypeng/sumatora/android/sumatoradictionary/db/DictionarySearchElementDao.java: -------------------------------------------------------------------------------- 1 | package org.happypeng.sumatora.android.sumatoradictionary.db; 2 | 3 | import androidx.paging.DataSource; 4 | import androidx.room.Dao; 5 | import androidx.room.Query; 6 | 7 | @Dao 8 | public interface DictionarySearchElementDao { 9 | @Query("SELECT * FROM DictionarySearchElement " 10 | + "WHERE ref=:ref " 11 | + "ORDER BY entryOrder, seq") 12 | DataSource.Factory getAllDetailsLivePaged(int ref); 13 | 14 | @Query("DELETE FROM DictionarySearchElement") 15 | void deleteAll(); 16 | } 17 | -------------------------------------------------------------------------------- /app/src/main/java/org/happypeng/sumatora/android/sumatoradictionary/db/DictionarySearchElementDiffUtil.java: -------------------------------------------------------------------------------- 1 | /* Sumatora Dictionary 2 | Copyright (C) 2019 Nicolas Centa 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see .*/ 16 | 17 | package org.happypeng.sumatora.android.sumatoradictionary.db; 18 | 19 | import androidx.annotation.NonNull; 20 | import androidx.recyclerview.widget.DiffUtil; 21 | 22 | public class DictionarySearchElementDiffUtil { 23 | private static boolean compareStrings(final String str1, final String str2) { 24 | if ((str1 == null && str2 != null) || (str1 != null && str2 == null)) { 25 | return false; 26 | } 27 | 28 | if (str1 == null && str2 == null) { 29 | return true; 30 | } 31 | 32 | return str1.equals(str2); 33 | } 34 | 35 | private final static DiffUtil.ItemCallback DIFF_UTIL = 36 | new DiffUtil.ItemCallback() { 37 | @Override 38 | public boolean areItemsTheSame(@NonNull DictionarySearchElement oldItem, @NonNull DictionarySearchElement newItem) { 39 | return oldItem.getSeq() == newItem.getSeq(); 40 | } 41 | 42 | @Override 43 | public boolean areContentsTheSame(@NonNull DictionarySearchElement oldItem, @NonNull DictionarySearchElement newItem) { 44 | return oldItem.getSeq() == newItem.getSeq() && oldItem.getLang().equals(newItem.getLang()) && 45 | oldItem.getLangSetting().equals(newItem.getLangSetting()) && 46 | oldItem.getBookmark() == newItem.getBookmark() && 47 | compareStrings(oldItem.memo, newItem.memo); 48 | } 49 | }; 50 | 51 | public static DiffUtil.ItemCallback getDiffUtil() { 52 | return DIFF_UTIL; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /app/src/main/java/org/happypeng/sumatora/android/sumatoradictionary/db/InstalledDictionaryDao.java: -------------------------------------------------------------------------------- 1 | package org.happypeng.sumatora.android.sumatoradictionary.db; 2 | 3 | import androidx.lifecycle.LiveData; 4 | import androidx.room.Dao; 5 | import androidx.room.Delete; 6 | import androidx.room.Insert; 7 | import androidx.room.OnConflictStrategy; 8 | import androidx.room.Query; 9 | 10 | import java.util.List; 11 | 12 | @Dao 13 | public interface InstalledDictionaryDao { 14 | @Query("SELECT * FROM InstalledDictionary") 15 | List getAll(); 16 | 17 | @Query("SELECT * FROM InstalledDictionary") 18 | LiveData> getAllLive(); 19 | 20 | @Query("SELECT * FROM InstalledDictionary " + 21 | "WHERE InstalledDictionary.type = 'jmdict_translation' " + 22 | "AND InstalledDictionary.lang != 'eng'") 23 | LiveData> getRemovableLive(); 24 | 25 | @Delete 26 | void delete(InstalledDictionary aAction); 27 | 28 | @Insert(onConflict = OnConflictStrategy.REPLACE) 29 | void insert(InstalledDictionary aSetting); 30 | 31 | @Query("SELECT * FROM InstalledDictionary WHERE InstalledDictionary.type == :aType AND InstalledDictionary.lang == :aLang LIMIT 1") 32 | InstalledDictionary getForTypeLang(String aType, String aLang); 33 | } 34 | -------------------------------------------------------------------------------- /app/src/main/java/org/happypeng/sumatora/android/sumatoradictionary/db/LocalDictionaryObject.java: -------------------------------------------------------------------------------- 1 | /* Sumatora Dictionary 2 | Copyright (C) 2019 Nicolas Centa 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see .*/ 16 | 17 | package org.happypeng.sumatora.android.sumatoradictionary.db; 18 | 19 | import android.util.Log; 20 | 21 | import androidx.annotation.NonNull; 22 | import androidx.room.Entity; 23 | 24 | import org.happypeng.sumatora.android.sumatoradictionary.db.tools.BaseDictionaryObject; 25 | 26 | import java.io.File; 27 | import java.io.FileInputStream; 28 | import java.io.FileOutputStream; 29 | import java.io.OutputStream; 30 | import java.util.zip.GZIPInputStream; 31 | 32 | @Entity(primaryKeys = {"type", "lang"}) 33 | public class LocalDictionaryObject extends BaseDictionaryObject { 34 | public LocalDictionaryObject() { 35 | super(); 36 | } 37 | 38 | public LocalDictionaryObject(final RemoteDictionaryObject aRemoteDictionaryObject) { 39 | description = aRemoteDictionaryObject.description; 40 | type = aRemoteDictionaryObject.type; 41 | lang = aRemoteDictionaryObject.lang; 42 | version = aRemoteDictionaryObject.version; 43 | date = aRemoteDictionaryObject.date; 44 | file = aRemoteDictionaryObject.localFile; 45 | } 46 | 47 | private static boolean copyGZipFile(File aInput, File aOutput) { 48 | try { 49 | GZIPInputStream in = new GZIPInputStream(new FileInputStream(aInput)); 50 | OutputStream out = new FileOutputStream(aOutput); 51 | 52 | copyFile(in, out); 53 | 54 | in.close(); 55 | in = null; 56 | 57 | out.flush(); 58 | out.close(); 59 | out = null; 60 | 61 | return true; 62 | } catch (Exception e) { 63 | Log.e("tag", "Failed to copy downloaded file: " + aInput.getPath(), e); 64 | } 65 | 66 | return false; 67 | } 68 | 69 | public InstalledDictionary install(final File aDatabaseDir) { 70 | File sourceFile = new File(file); 71 | File destFile = new File(aDatabaseDir, type + "-" + lang + ".db"); 72 | 73 | if (copyGZipFile(sourceFile, destFile)) { 74 | return new InstalledDictionary(destFile.toString(), 75 | description, type, lang, version, date); 76 | 77 | } 78 | 79 | return null; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /app/src/main/java/org/happypeng/sumatora/android/sumatoradictionary/db/LocalDictionaryObjectDao.java: -------------------------------------------------------------------------------- 1 | /* Sumatora Dictionary 2 | Copyright (C) 2019 Nicolas Centa 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see .*/ 16 | 17 | package org.happypeng.sumatora.android.sumatoradictionary.db; 18 | 19 | import androidx.lifecycle.LiveData; 20 | import androidx.room.Dao; 21 | import androidx.room.Delete; 22 | import androidx.room.Insert; 23 | import androidx.room.OnConflictStrategy; 24 | import androidx.room.Query; 25 | import androidx.room.Update; 26 | 27 | import java.util.List; 28 | 29 | @Dao 30 | public interface LocalDictionaryObjectDao { 31 | @Insert(onConflict = OnConflictStrategy.REPLACE) 32 | void insertMany(List aActions); 33 | 34 | @Query("SELECT * FROM LocalDictionaryObject") 35 | List getAll(); 36 | 37 | @Query("SELECT * FROM LocalDictionaryObject") 38 | LiveData> getAllLive(); 39 | 40 | @Delete 41 | void deleteMany(List aActions); 42 | 43 | @Update 44 | void update(LocalDictionaryObject aAction); 45 | 46 | // All are to be installed 47 | @Query("SELECT * FROM LocalDictionaryObject") 48 | LiveData> getInstallObjects(); 49 | } 50 | -------------------------------------------------------------------------------- /app/src/main/java/org/happypeng/sumatora/android/sumatoradictionary/db/PersistentDatabase.java: -------------------------------------------------------------------------------- 1 | /* Sumatora Dictionary 2 | Copyright (C) 2019 Nicolas Centa 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see . */ 16 | 17 | package org.happypeng.sumatora.android.sumatoradictionary.db; 18 | 19 | import androidx.room.Database; 20 | import androidx.room.RoomDatabase; 21 | 22 | @Database(entities = {PersistentSetting.class, 23 | DictionaryBookmark.class, DictionaryBookmarkImport.class, 24 | DictionaryElement.class, 25 | DictionarySearchElement.class, 26 | InstalledDictionary.class, 27 | RemoteDictionaryObject.class, 28 | LocalDictionaryObject.class, 29 | AssetDictionaryObject.class, 30 | PersistentLanguageSettings.class}, version = 8) 31 | abstract public class PersistentDatabase extends RoomDatabase { 32 | public abstract PersistentSettingsDao persistentSettingsDao(); 33 | public abstract DictionaryBookmarkDao dictionaryBookmarkDao(); 34 | public abstract DictionaryBookmarkImportDao dictionaryBookmarkImportDao(); 35 | public abstract DictionaryElementDao dictionaryElementDao(); 36 | public abstract InstalledDictionaryDao installedDictionaryDao(); 37 | public abstract RemoteDictionaryObjectDao remoteDictionaryObjectDao(); 38 | public abstract LocalDictionaryObjectDao localDictionaryObjectDao(); 39 | public abstract AssetDictionaryObjectDao assetDictionaryObjectDao(); 40 | public abstract PersistentLanguageSettingsDao persistentLanguageSettingsDao(); 41 | public abstract DictionarySearchElementDao dictionarySearchElementDao(); 42 | } 43 | -------------------------------------------------------------------------------- /app/src/main/java/org/happypeng/sumatora/android/sumatoradictionary/db/PersistentLanguageSettings.java: -------------------------------------------------------------------------------- 1 | /* Sumatora Dictionary 2 | Copyright (C) 2020 Nicolas Centa 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see . */ 16 | 17 | package org.happypeng.sumatora.android.sumatoradictionary.db; 18 | 19 | import androidx.annotation.NonNull; 20 | import androidx.room.Entity; 21 | 22 | @Entity(primaryKeys = {"ref"}) 23 | public class PersistentLanguageSettings { 24 | public static final String LANG_DEFAULT = "eng"; 25 | public static final String BACKUP_LANG_DEFAULT = "eng"; 26 | 27 | public int ref; 28 | public @NonNull String lang; 29 | public String backupLang; 30 | 31 | public PersistentLanguageSettings() { 32 | lang = ""; 33 | ref = 0; 34 | } 35 | 36 | public PersistentLanguageSettings(int aRef, final @NonNull String aLang, final String aBackupLang) { 37 | ref = aRef; 38 | lang = aLang; 39 | backupLang = aBackupLang; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /app/src/main/java/org/happypeng/sumatora/android/sumatoradictionary/db/PersistentLanguageSettingsDao.java: -------------------------------------------------------------------------------- 1 | /* Sumatora Dictionary 2 | Copyright (C) 2020 Nicolas Centa 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see . */ 16 | 17 | package org.happypeng.sumatora.android.sumatoradictionary.db; 18 | 19 | import androidx.lifecycle.LiveData; 20 | import androidx.room.Dao; 21 | import androidx.room.Insert; 22 | import androidx.room.OnConflictStrategy; 23 | import androidx.room.Query; 24 | 25 | @Dao 26 | public interface PersistentLanguageSettingsDao { 27 | @Query("SELECT * FROM PersistentLanguageSettings WHERE ref = :ref") 28 | PersistentLanguageSettings getLanguageSettingsDirect(int ref); 29 | 30 | @Insert(onConflict = OnConflictStrategy.REPLACE) 31 | void update(PersistentLanguageSettings aLanguageSettings); 32 | } 33 | -------------------------------------------------------------------------------- /app/src/main/java/org/happypeng/sumatora/android/sumatoradictionary/db/PersistentSetting.java: -------------------------------------------------------------------------------- 1 | /* Sumatora Dictionary 2 | Copyright (C) 2019 Nicolas Centa 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see . */ 16 | 17 | package org.happypeng.sumatora.android.sumatoradictionary.db; 18 | 19 | import androidx.annotation.NonNull; 20 | import androidx.room.Entity; 21 | 22 | @Entity(primaryKeys = {"name"}) 23 | public class PersistentSetting { 24 | @NonNull public String name; 25 | @NonNull public String value; 26 | 27 | public PersistentSetting() {} 28 | 29 | public PersistentSetting(@NonNull final String aName, @NonNull final String aValue) { 30 | name = aName; 31 | value = aValue; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /app/src/main/java/org/happypeng/sumatora/android/sumatoradictionary/db/PersistentSettingsDao.java: -------------------------------------------------------------------------------- 1 | /* Sumatora Dictionary 2 | Copyright (C) 2019 Nicolas Centa 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see . */ 16 | 17 | package org.happypeng.sumatora.android.sumatoradictionary.db; 18 | 19 | import androidx.lifecycle.LiveData; 20 | import androidx.room.Dao; 21 | import androidx.room.Insert; 22 | import androidx.room.OnConflictStrategy; 23 | import androidx.room.Query; 24 | 25 | @Dao 26 | public interface PersistentSettingsDao { 27 | @Query("SELECT value FROM PersistentSetting WHERE name=:aName") 28 | LiveData getValue(String aName); 29 | 30 | @Query("SELECT value FROM PersistentSetting WHERE name=:aName") 31 | String getValueDirect(String aName); 32 | 33 | @Insert(onConflict = OnConflictStrategy.REPLACE) 34 | void insert(PersistentSetting aSetting); 35 | 36 | @Insert(onConflict = OnConflictStrategy.IGNORE) 37 | void insertDefault(PersistentSetting aSetting); 38 | } 39 | -------------------------------------------------------------------------------- /app/src/main/java/org/happypeng/sumatora/android/sumatoradictionary/db/tools/AttachedDatabases.java: -------------------------------------------------------------------------------- 1 | /* Sumatora Dictionary 2 | Copyright (C) 2020 Nicolas Centa 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see .*/ 16 | 17 | package org.happypeng.sumatora.android.sumatoradictionary.db.tools; 18 | 19 | import android.database.Cursor; 20 | 21 | import androidx.room.RoomDatabase; 22 | 23 | import java.util.LinkedList; 24 | import java.util.List; 25 | 26 | public class AttachedDatabases { 27 | public static List getAttachedDatabases(final RoomDatabase aDB) { 28 | LinkedList databases = new LinkedList<>(); 29 | Cursor cur = aDB.getOpenHelper().getReadableDatabase().query("PRAGMA database_list"); 30 | 31 | while (cur.moveToNext()) { 32 | databases.add(cur.getString(1)); 33 | } 34 | 35 | return databases; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /app/src/main/java/org/happypeng/sumatora/android/sumatoradictionary/db/tools/BasicQueryStatement.java: -------------------------------------------------------------------------------- 1 | /* Sumatora Dictionary 2 | Copyright (C) 2019 Nicolas Centa 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see .*/ 16 | 17 | package org.happypeng.sumatora.android.sumatoradictionary.db.tools; 18 | 19 | import androidx.annotation.WorkerThread; 20 | import androidx.sqlite.db.SupportSQLiteStatement; 21 | 22 | import org.happypeng.sumatora.android.sumatoradictionary.db.PersistentDatabase; 23 | import org.happypeng.sumatora.android.sumatoradictionary.db.PersistentLanguageSettings; 24 | import org.happypeng.sumatora.jromkan.Romkan; 25 | 26 | import java.util.Iterator; 27 | import java.util.List; 28 | 29 | public class BasicQueryStatement extends QueryStatement { 30 | private final boolean kana; 31 | private final Romkan romkan; 32 | final int order; 33 | 34 | BasicQueryStatement(final PersistentDatabase aDB, 35 | int aRef, int aOrder, 36 | final PersistentLanguageSettings aLanguageSettings, 37 | final SupportSQLiteStatement aStatement, 38 | final SupportSQLiteStatement aBackupStatement, 39 | boolean aKana, final Romkan aRomkan) { 40 | super(aDB, aRef, aLanguageSettings, aStatement, aBackupStatement); 41 | 42 | kana = aKana; 43 | romkan = aRomkan; 44 | order = aOrder; 45 | } 46 | 47 | @WorkerThread 48 | @Override 49 | long execute(final String term, final List parameters) { 50 | final ValueHolder returnValue = new ValueHolder<>(Long.valueOf(-1)); 51 | 52 | String bindTerm = escapeTerm(term); 53 | long insert = -1; 54 | long backupInsert = -1; 55 | 56 | if (kana) { 57 | bindTerm = romkan.to_katakana(romkan.to_hepburn(bindTerm)); 58 | } 59 | 60 | statement.bindLong(1, ref); 61 | statement.bindLong(2, order); 62 | statement.bindString(3, languageSettings.lang); 63 | statement.bindString(4, languageSettings.lang); 64 | statement.bindString(5, bindTerm); 65 | 66 | bind(statement, parameters, 6); 67 | 68 | insert = statement.executeInsert(); 69 | 70 | if (backupStatement != null) { 71 | backupStatement.bindLong(1, ref); 72 | backupStatement.bindLong(2, order); 73 | backupStatement.bindString(3, languageSettings.backupLang); 74 | backupStatement.bindString(4, languageSettings.lang); 75 | backupStatement.bindString(5, bindTerm); 76 | 77 | bind(backupStatement, parameters, 6); 78 | 79 | backupInsert = backupStatement.executeInsert(); 80 | 81 | returnValue.setValue(Math.max(backupInsert, insert)); 82 | } else { 83 | returnValue.setValue(insert); 84 | } 85 | 86 | return returnValue.getValue(); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /app/src/main/java/org/happypeng/sumatora/android/sumatoradictionary/db/tools/QueryStatement.java: -------------------------------------------------------------------------------- 1 | /* Sumatora Dictionary 2 | Copyright (C) 2019 Nicolas Centa 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see .*/ 16 | 17 | package org.happypeng.sumatora.android.sumatoradictionary.db.tools; 18 | 19 | import androidx.annotation.WorkerThread; 20 | import androidx.sqlite.db.SupportSQLiteStatement; 21 | 22 | import org.happypeng.sumatora.android.sumatoradictionary.db.PersistentDatabase; 23 | import org.happypeng.sumatora.android.sumatoradictionary.db.PersistentLanguageSettings; 24 | 25 | import java.io.IOException; 26 | import java.util.List; 27 | 28 | public abstract class QueryStatement { 29 | final int ref; 30 | final PersistentLanguageSettings languageSettings; 31 | final PersistentDatabase database; 32 | final SupportSQLiteStatement statement; 33 | final SupportSQLiteStatement backupStatement; 34 | 35 | QueryStatement(final PersistentDatabase aDB, 36 | int aRef, 37 | final PersistentLanguageSettings aLanguageSettings, 38 | final SupportSQLiteStatement aStatement, 39 | final SupportSQLiteStatement aBackupStatement) { 40 | ref = aRef; 41 | statement = aStatement; 42 | backupStatement = aBackupStatement; 43 | languageSettings = aLanguageSettings; 44 | database = aDB; 45 | } 46 | 47 | @WorkerThread 48 | abstract long execute(String term, List parameters); 49 | 50 | @WorkerThread 51 | public void close() throws IOException { 52 | statement.close(); 53 | 54 | if (backupStatement != null) { 55 | backupStatement.close(); 56 | } 57 | } 58 | 59 | protected static void bind(final SupportSQLiteStatement statement, 60 | final List parameters, 61 | final int start) { 62 | if (parameters == null) { 63 | return; 64 | } 65 | 66 | int i = start; 67 | 68 | for (Object parameter : parameters) { 69 | if (parameter == null) { 70 | statement.bindNull(i); 71 | } else if (parameter instanceof Long) { 72 | statement.bindLong(i, (Long) parameter); 73 | } else if (parameter instanceof Integer) { 74 | statement.bindLong(i, (Integer) parameter); 75 | } else if (parameter instanceof String) { 76 | statement.bindString(i, (String) parameter); 77 | } else if (parameter instanceof Boolean) { 78 | statement.bindLong(i, (Boolean) parameter ? 1 : 0); 79 | } 80 | 81 | i++; 82 | } 83 | } 84 | 85 | protected static String escapeTerm(final String term) { 86 | return term.replaceAll("[\"()]", ""); 87 | } 88 | } -------------------------------------------------------------------------------- /app/src/main/java/org/happypeng/sumatora/android/sumatoradictionary/db/tools/ReverseQueryStatement.java: -------------------------------------------------------------------------------- 1 | /* Sumatora Dictionary 2 | Copyright (C) 2019 Nicolas Centa 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see .*/ 16 | 17 | package org.happypeng.sumatora.android.sumatoradictionary.db.tools; 18 | 19 | import androidx.annotation.WorkerThread; 20 | import androidx.sqlite.db.SupportSQLiteStatement; 21 | 22 | import org.happypeng.sumatora.android.sumatoradictionary.db.PersistentDatabase; 23 | import org.happypeng.sumatora.android.sumatoradictionary.db.PersistentLanguageSettings; 24 | 25 | import java.util.List; 26 | 27 | public class ReverseQueryStatement extends QueryStatement { 28 | final SupportSQLiteStatement displayStatement; 29 | final SupportSQLiteStatement displayBackupStatement; 30 | final SupportSQLiteStatement deleteElementsStatement; 31 | 32 | ReverseQueryStatement(final PersistentDatabase aDB, 33 | int aRef, 34 | final PersistentLanguageSettings aLanguageSettings, 35 | final SupportSQLiteStatement aStatement, 36 | final SupportSQLiteStatement aBackupStatement, 37 | final SupportSQLiteStatement aDisplayStatement, 38 | final SupportSQLiteStatement aDisplayBackupStatement, 39 | final SupportSQLiteStatement aDeleteElementStatement) { 40 | super(aDB, aRef, aLanguageSettings, aStatement, aBackupStatement); 41 | 42 | displayStatement = aDisplayStatement; 43 | displayBackupStatement = aDisplayBackupStatement; 44 | deleteElementsStatement = aDeleteElementStatement; 45 | } 46 | 47 | @WorkerThread 48 | @Override 49 | long execute(final String term, final List parameters) { 50 | long returnValue = -1; 51 | 52 | long insert = -1; 53 | long backupInsert = -1; 54 | 55 | final String bindTerm = escapeTerm(term); 56 | 57 | statement.bindLong(1, ref); 58 | statement.bindString(2, bindTerm); 59 | 60 | statement.executeInsert(); 61 | 62 | if (backupStatement != null) { 63 | backupStatement.bindLong(1, ref); 64 | backupStatement.bindString(2, bindTerm); 65 | 66 | backupStatement.executeInsert(); 67 | } 68 | 69 | displayStatement.bindString(1, languageSettings.lang); 70 | displayStatement.bindString(2, languageSettings.lang); 71 | displayStatement.bindLong(3, ref); 72 | 73 | bind(displayStatement, parameters, 4); 74 | 75 | insert = displayStatement.executeInsert(); 76 | 77 | if (displayBackupStatement != null) { 78 | displayBackupStatement.bindString(1, languageSettings.backupLang); 79 | displayBackupStatement.bindString(2, languageSettings.lang); 80 | displayBackupStatement.bindLong(3, ref); 81 | 82 | bind(displayBackupStatement, parameters, 4); 83 | 84 | backupInsert = displayBackupStatement.executeInsert(); 85 | 86 | returnValue = Math.max(backupInsert, insert); 87 | } else { 88 | returnValue = insert; 89 | } 90 | 91 | deleteElementsStatement.bindLong(1, ref); 92 | 93 | deleteElementsStatement.executeUpdateDelete(); 94 | 95 | return returnValue; 96 | } 97 | } -------------------------------------------------------------------------------- /app/src/main/java/org/happypeng/sumatora/android/sumatoradictionary/db/tools/Settings.java: -------------------------------------------------------------------------------- 1 | /* Sumatora Dictionary 2 | Copyright (C) 2019 Nicolas Centa 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see . */ 16 | 17 | package org.happypeng.sumatora.android.sumatoradictionary.db.tools; 18 | 19 | import android.os.AsyncTask; 20 | 21 | import androidx.annotation.MainThread; 22 | import androidx.annotation.WorkerThread; 23 | import androidx.arch.core.util.Function; 24 | import androidx.lifecycle.LiveData; 25 | import androidx.lifecycle.MutableLiveData; 26 | import androidx.lifecycle.Transformations; 27 | 28 | import org.happypeng.sumatora.android.sumatoradictionary.db.PersistentDatabase; 29 | import org.happypeng.sumatora.android.sumatoradictionary.db.PersistentSetting; 30 | 31 | public class Settings { 32 | public static final String REPOSITORY_URL = "repositoryURL"; 33 | 34 | private final MutableLiveData m_db; 35 | 36 | public Settings() { 37 | m_db = new MutableLiveData<>(); 38 | } 39 | 40 | @WorkerThread 41 | public void postDatabase(final PersistentDatabase aDB) { 42 | m_db.postValue(aDB); 43 | } 44 | 45 | public LiveData getValue(final String aName) { 46 | return Transformations.switchMap(m_db, 47 | new Function>() { 48 | @Override 49 | public LiveData apply(PersistentDatabase input) { 50 | return input.persistentSettingsDao().getValue(aName); 51 | } 52 | }); 53 | } 54 | 55 | @WorkerThread 56 | public String getValueDirect(final String aName) { 57 | PersistentDatabase db = m_db.getValue(); 58 | 59 | if (db != null) { 60 | return db.persistentSettingsDao().getValueDirect(aName); 61 | } 62 | 63 | return null; 64 | } 65 | 66 | @WorkerThread 67 | public void postValue(final String aName, final String aValue) { 68 | if (m_db.getValue() != null) { 69 | m_db.getValue().persistentSettingsDao().insert(new PersistentSetting(aName, aValue)); 70 | } 71 | } 72 | 73 | @MainThread 74 | public void setValue(final String aName, final String aValue) { 75 | new AsyncTask() { 76 | @Override 77 | protected Void doInBackground(Void... voids) { 78 | postValue(aName, aValue); 79 | 80 | return null; 81 | } 82 | }.execute(); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /app/src/main/java/org/happypeng/sumatora/android/sumatoradictionary/db/tools/ValueHolder.java: -------------------------------------------------------------------------------- 1 | /* Sumatora Dictionary 2 | Copyright (C) 2019 Nicolas Centa 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see .*/ 16 | 17 | package org.happypeng.sumatora.android.sumatoradictionary.db.tools; 18 | 19 | public class ValueHolder { 20 | private T mValue; 21 | 22 | public ValueHolder(T aValue) { 23 | mValue = aValue; 24 | } 25 | 26 | public T getValue() { 27 | return mValue; 28 | } 29 | 30 | public void setValue(T aValue) { 31 | mValue = aValue; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /app/src/main/java/org/happypeng/sumatora/android/sumatoradictionary/fragment/BookmarkFragment.kt: -------------------------------------------------------------------------------- 1 | /* Sumatora Dictionary 2 | Copyright (C) 2020 Nicolas Centa 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see .*/ 16 | package org.happypeng.sumatora.android.sumatoradictionary.fragment 17 | 18 | import androidx.fragment.app.viewModels 19 | import androidx.lifecycle.ViewModelProvider 20 | import org.happypeng.sumatora.android.sumatoradictionary.model.BaseQueryFragmentModel 21 | import org.happypeng.sumatora.android.sumatoradictionary.model.BookmarkFragmentModel 22 | import org.happypeng.sumatora.android.sumatoradictionary.model.QueryFragmentModel 23 | 24 | class BookmarkFragment : BaseFragment() { 25 | private val viewModel: BookmarkFragmentModel by viewModels() 26 | 27 | override fun getModel(): BaseQueryFragmentModel { 28 | return viewModel 29 | } 30 | } -------------------------------------------------------------------------------- /app/src/main/java/org/happypeng/sumatora/android/sumatoradictionary/fragment/QueryFragment.kt: -------------------------------------------------------------------------------- 1 | /* Sumatora Dictionary 2 | Copyright (C) 2020 Nicolas Centa 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see .*/ 16 | package org.happypeng.sumatora.android.sumatoradictionary.fragment 17 | 18 | import androidx.fragment.app.viewModels 19 | import org.happypeng.sumatora.android.sumatoradictionary.model.BaseQueryFragmentModel 20 | import org.happypeng.sumatora.android.sumatoradictionary.model.QueryFragmentModel 21 | 22 | class QueryFragment : BaseFragment() { 23 | private val viewModel: QueryFragmentModel by viewModels() 24 | 25 | override fun getModel(): BaseQueryFragmentModel { 26 | return viewModel 27 | } 28 | } -------------------------------------------------------------------------------- /app/src/main/java/org/happypeng/sumatora/android/sumatoradictionary/model/BookmarkFragmentModel.kt: -------------------------------------------------------------------------------- 1 | /* Sumatora Dictionary 2 | Copyright (C) 2019 Nicolas Centa 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see .*/ 16 | package org.happypeng.sumatora.android.sumatoradictionary.model 17 | 18 | import androidx.hilt.Assisted 19 | import androidx.hilt.lifecycle.ViewModelInject 20 | import androidx.lifecycle.SavedStateHandle 21 | import androidx.paging.PagedList.BoundaryCallback 22 | import org.happypeng.sumatora.android.sumatoradictionary.component.BookmarkComponent 23 | import org.happypeng.sumatora.android.sumatoradictionary.component.BookmarkShareComponent 24 | import org.happypeng.sumatora.android.sumatoradictionary.component.LanguageSettingsComponent 25 | import org.happypeng.sumatora.android.sumatoradictionary.component.PersistentDatabaseComponent 26 | import org.happypeng.sumatora.android.sumatoradictionary.db.DictionarySearchElement 27 | import org.happypeng.sumatora.android.sumatoradictionary.model.state.QueryState 28 | 29 | class BookmarkFragmentModel @ViewModelInject constructor(bookmarkComponent: BookmarkComponent, 30 | persistentDatabaseComponent: PersistentDatabaseComponent, 31 | languageSettingsComponent: LanguageSettingsComponent, 32 | bookmarkShareComponent: BookmarkShareComponent, 33 | @Assisted savedStateHandle: SavedStateHandle) : BaseQueryFragmentModel(bookmarkComponent, 34 | persistentDatabaseComponent, 35 | languageSettingsComponent, 36 | bookmarkShareComponent, 37 | { component: PersistentDatabaseComponent, callback: BoundaryCallback? -> component.getSearchElements(KEY, callback) }, 38 | KEY, 39 | true, 40 | true, 41 | TITLE, 42 | true, 43 | true, 44 | false, 45 | false, 46 | savedStateHandle.get(QueryFragmentModel.STATUS_KEY) 47 | ) { 48 | companion object { 49 | const val KEY = 2 50 | const val TITLE = "Bookmarks" 51 | const val STATUS_KEY = "STATUS" 52 | } 53 | 54 | init { 55 | states().subscribe { 56 | savedStateHandle.set(QueryFragmentModel.STATUS_KEY, it) 57 | } 58 | } 59 | } -------------------------------------------------------------------------------- /app/src/main/java/org/happypeng/sumatora/android/sumatoradictionary/model/BookmarkImportModel.kt: -------------------------------------------------------------------------------- 1 | package org.happypeng.sumatora.android.sumatoradictionary.model 2 | 3 | import android.net.Uri 4 | import androidx.hilt.Assisted 5 | import androidx.hilt.lifecycle.ViewModelInject 6 | import androidx.lifecycle.SavedStateHandle 7 | import androidx.paging.PagedList 8 | import io.reactivex.rxjava3.core.Observable 9 | import io.reactivex.rxjava3.disposables.CompositeDisposable 10 | import io.reactivex.rxjava3.subjects.PublishSubject 11 | import org.happypeng.sumatora.android.sumatoradictionary.component.* 12 | import org.happypeng.sumatora.android.sumatoradictionary.db.DictionarySearchElement 13 | import org.happypeng.sumatora.android.sumatoradictionary.model.intent.* 14 | import org.happypeng.sumatora.android.sumatoradictionary.model.processor.ImportActionProcessorHolder 15 | import org.happypeng.sumatora.android.sumatoradictionary.model.result.ImportResult 16 | import org.happypeng.sumatora.android.sumatoradictionary.model.state.ImportState 17 | import org.happypeng.sumatora.android.sumatoradictionary.mvibase.MviViewModel 18 | import org.happypeng.sumatora.android.sumatoradictionary.model.transformer.ImportIntentTransformer 19 | 20 | class BookmarkImportModel @ViewModelInject constructor(private val bookmarkImportComponent: BookmarkImportComponent, 21 | persistentDatabaseComponent: PersistentDatabaseComponent, 22 | languageSettingsComponent: LanguageSettingsComponent, 23 | bookmarkShareComponent: BookmarkShareComponent, 24 | @Assisted savedStateHandle: SavedStateHandle?) : 25 | BaseFragmentModel(persistentDatabaseComponent, languageSettingsComponent, 26 | { component: PersistentDatabaseComponent, callback: PagedList.BoundaryCallback? -> 27 | component.getSearchElements(KEY, callback) }, false, true), MviViewModel { 28 | companion object { 29 | const val KEY = 3 30 | } 31 | 32 | private val intentsSubject: PublishSubject = PublishSubject.create() 33 | private val statesObservable: Observable = compose() 34 | private val closedObservable = statesObservable.filter { it.closed }.map { Unit } 35 | 36 | private fun compose(): Observable { 37 | val actionProcessorHolder = ImportActionProcessorHolder(persistentDatabaseComponent, bookmarkImportComponent, KEY) 38 | 39 | return intentsSubject 40 | .compose(ImportIntentTransformer()) 41 | .compose(actionProcessorHolder.actionProcessor) 42 | .scan(ImportState(false, null, closed = false, processing = false), 43 | this::transformStatus) 44 | .distinctUntilChanged() 45 | .replay(1) 46 | .autoConnect(0) 47 | } 48 | 49 | private fun transformStatus(previousState: ImportState, result: ImportResult): ImportState { 50 | return ImportState(result.executed, result.persistentLanguageSettings, result.close, result.processing) 51 | } 52 | 53 | override fun processIntents(intents: Observable) { 54 | intents.takeUntil(closedObservable).subscribe(intentsSubject::onNext) 55 | } 56 | 57 | override fun states(): Observable = statesObservable 58 | 59 | fun bookmarkImportFileOpen(uri: Uri) { 60 | processIntents(Observable.just(ImportFileIntent(uri))) 61 | } 62 | 63 | fun bookmarkImportCommit() { 64 | processIntents(Observable.just(ImportCommitIntent)) 65 | } 66 | 67 | fun bookmarkImportCancel() { 68 | processIntents(Observable.just(ImportCancelIntent)) 69 | } 70 | 71 | init { 72 | processIntents(languageSettingsComponent.persistentLanguageSettings.map { 73 | when (it) { 74 | is LanguageSettingDetachedIntent -> ImportLanguageSettingDetachedIntent 75 | is LanguageSettingAttachedIntent -> ImportLanguageSettingAttachedIntent(it.languageSettings) 76 | } 77 | }) 78 | processIntents(clearedObservable.map { ImportCloseIntent }) 79 | } 80 | } 81 | 82 | -------------------------------------------------------------------------------- /app/src/main/java/org/happypeng/sumatora/android/sumatoradictionary/model/DebugFragmentModel.java: -------------------------------------------------------------------------------- 1 | /* Sumatora Dictionary 2 | Copyright (C) 2019 Nicolas Centa 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see . */ 16 | 17 | package org.happypeng.sumatora.android.sumatoradictionary.model; 18 | 19 | import android.app.Application; 20 | import android.os.AsyncTask; 21 | 22 | import androidx.annotation.NonNull; 23 | import androidx.annotation.Nullable; 24 | import androidx.lifecycle.AndroidViewModel; 25 | import androidx.lifecycle.LiveData; 26 | import androidx.lifecycle.MutableLiveData; 27 | 28 | import java.io.BufferedReader; 29 | import java.io.File; 30 | import java.io.FileInputStream; 31 | import java.io.FileNotFoundException; 32 | import java.io.InputStreamReader; 33 | 34 | public class DebugFragmentModel extends AndroidViewModel { 35 | final private MutableLiveData mLog; 36 | final private File mLogsFile; 37 | 38 | public DebugFragmentModel(@NonNull Application application) { 39 | super(application); 40 | 41 | mLog = new MutableLiveData<>(); 42 | 43 | File filesDir = getApplication().getFilesDir(); 44 | File logsDir = new File(filesDir, "logs"); 45 | 46 | mLogsFile = new File(logsDir, "log.txt"); 47 | } 48 | 49 | public void readLog() { 50 | new AsyncTask() { 51 | @Override 52 | protected Void doInBackground(Void... voids) { 53 | try { 54 | BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(mLogsFile))); 55 | 56 | String line; 57 | StringBuilder sb = new StringBuilder(); 58 | 59 | while ((line = br.readLine()) != null) { 60 | sb.append(line); 61 | sb.append("\n"); 62 | } 63 | 64 | br.close(); 65 | 66 | mLog.postValue(sb.toString()); 67 | } catch (FileNotFoundException e) { 68 | mLog.postValue("No log data available."); 69 | } catch (Exception e) { 70 | e.printStackTrace(); 71 | } 72 | 73 | return null; 74 | } 75 | }.execute(); 76 | } 77 | 78 | public LiveData getLog() { 79 | return mLog; 80 | } 81 | 82 | public File getLogsFile() { 83 | return mLogsFile; 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /app/src/main/java/org/happypeng/sumatora/android/sumatoradictionary/model/QueryFragmentModel.kt: -------------------------------------------------------------------------------- 1 | /* Sumatora Dictionary 2 | Copyright (C) 2019 Nicolas Centa 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see .*/ 16 | package org.happypeng.sumatora.android.sumatoradictionary.model 17 | 18 | import androidx.hilt.Assisted 19 | import androidx.hilt.lifecycle.ViewModelInject 20 | import androidx.lifecycle.SavedStateHandle 21 | import androidx.paging.PagedList.BoundaryCallback 22 | import org.happypeng.sumatora.android.sumatoradictionary.component.BookmarkComponent 23 | import org.happypeng.sumatora.android.sumatoradictionary.component.BookmarkShareComponent 24 | import org.happypeng.sumatora.android.sumatoradictionary.component.LanguageSettingsComponent 25 | import org.happypeng.sumatora.android.sumatoradictionary.component.PersistentDatabaseComponent 26 | import org.happypeng.sumatora.android.sumatoradictionary.db.DictionarySearchElement 27 | import org.happypeng.sumatora.android.sumatoradictionary.model.state.QueryState 28 | 29 | class QueryFragmentModel @ViewModelInject constructor(bookmarkComponent: BookmarkComponent, 30 | persistentDatabaseComponent: PersistentDatabaseComponent, 31 | languageSettingsComponent: LanguageSettingsComponent, 32 | bookmarkShareComponent: BookmarkShareComponent, 33 | @Assisted savedStateHandle: SavedStateHandle) : BaseQueryFragmentModel(bookmarkComponent, 34 | persistentDatabaseComponent, 35 | languageSettingsComponent, 36 | bookmarkShareComponent, 37 | { component: PersistentDatabaseComponent, callback: BoundaryCallback? -> component.getSearchElements(KEY, callback) }, 38 | KEY, false, false, TITLE, false, 39 | false, false, false, 40 | savedStateHandle.get(STATUS_KEY) 41 | ) { 42 | companion object { 43 | const val KEY = 1 44 | const val TITLE = "Sumatora" 45 | const val STATUS_KEY = "STATUS" 46 | } 47 | 48 | init { 49 | states().subscribe { 50 | savedStateHandle.set(STATUS_KEY, it) 51 | } 52 | } 53 | } -------------------------------------------------------------------------------- /app/src/main/java/org/happypeng/sumatora/android/sumatoradictionary/model/action/ImportAction.kt: -------------------------------------------------------------------------------- 1 | /* Sumatora Dictionary 2 | Copyright (C) 2020 Nicolas Centa 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see .*/ 16 | 17 | package org.happypeng.sumatora.android.sumatoradictionary.model.action 18 | 19 | import android.net.Uri 20 | import org.happypeng.sumatora.android.sumatoradictionary.db.PersistentLanguageSettings 21 | import org.happypeng.sumatora.android.sumatoradictionary.model.intent.ImportIntent 22 | import org.happypeng.sumatora.android.sumatoradictionary.mvibase.MviAction 23 | 24 | sealed class ImportAction : MviAction 25 | 26 | object ImportCommitAction : ImportAction() 27 | 28 | object ImportLanguageSettingDetachedAction : ImportAction() 29 | class ImportLanguageSettingAttachedAction(val persistentLanguageSettings: PersistentLanguageSettings) : ImportAction() 30 | 31 | object ImportSetProcessingAction : ImportAction() 32 | class ImportFileAction(val uri: Uri) : ImportAction() 33 | 34 | object ImportClearAction : ImportAction() 35 | -------------------------------------------------------------------------------- /app/src/main/java/org/happypeng/sumatora/android/sumatoradictionary/model/action/QueryAction.kt: -------------------------------------------------------------------------------- 1 | /* Sumatora Dictionary 2 | Copyright (C) 2020 Nicolas Centa 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see .*/ 16 | 17 | package org.happypeng.sumatora.android.sumatoradictionary.model.action 18 | 19 | import org.happypeng.sumatora.android.sumatoradictionary.db.PersistentLanguageSettings 20 | import org.happypeng.sumatora.android.sumatoradictionary.db.tools.DictionarySearchQueryTool 21 | import org.happypeng.sumatora.android.sumatoradictionary.mvibase.MviAction 22 | 23 | sealed class QueryAction : MviAction 24 | 25 | class SetTermAction(val term: String) : QueryAction() 26 | object SearchAction : QueryAction() 27 | 28 | class CloseSearchBoxAction(val input: String) : QueryAction() 29 | object ClosedSearchBoxAction : QueryAction() 30 | object OpenSearchBoxAction : QueryAction() 31 | 32 | object BookmarkAction : QueryAction() 33 | object ScrollAction : QueryAction() 34 | 35 | object QueryLanguageSettingDetachedAction : QueryAction() 36 | class QueryLanguageSettingAttachedAction(val persistentLanguageSettings: PersistentLanguageSettings) : QueryAction() 37 | 38 | object QueryClearAction : QueryAction() 39 | object QueryCloseAction : QueryAction() 40 | -------------------------------------------------------------------------------- /app/src/main/java/org/happypeng/sumatora/android/sumatoradictionary/model/intent/DictionaryPagedListAdapterIntent.kt: -------------------------------------------------------------------------------- 1 | package org.happypeng.sumatora.android.sumatoradictionary.model.intent 2 | 3 | sealed class DictionaryPagedListAdapterIntent 4 | 5 | object DictionaryPagedListAdapterCloseIntent : DictionaryPagedListAdapterIntent() 6 | -------------------------------------------------------------------------------- /app/src/main/java/org/happypeng/sumatora/android/sumatoradictionary/model/intent/ImportIntent.kt: -------------------------------------------------------------------------------- 1 | /* Sumatora Dictionary 2 | Copyright (C) 2020 Nicolas Centa 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see .*/ 16 | 17 | package org.happypeng.sumatora.android.sumatoradictionary.model.intent 18 | 19 | import android.net.Uri 20 | import org.happypeng.sumatora.android.sumatoradictionary.db.PersistentLanguageSettings 21 | import org.happypeng.sumatora.android.sumatoradictionary.model.action.ImportAction 22 | import org.happypeng.sumatora.android.sumatoradictionary.mvibase.MviIntent 23 | 24 | sealed class ImportIntent : MviIntent 25 | 26 | object ImportCommitIntent : ImportIntent() 27 | object ImportCancelIntent : ImportIntent() 28 | 29 | class ImportFileIntent(val uri: Uri) : ImportIntent() 30 | 31 | object ImportLanguageSettingDetachedIntent : ImportIntent() 32 | class ImportLanguageSettingAttachedIntent(val persistentLanguageSettings: PersistentLanguageSettings) : ImportIntent() 33 | 34 | object ImportCloseIntent : ImportIntent() -------------------------------------------------------------------------------- /app/src/main/java/org/happypeng/sumatora/android/sumatoradictionary/model/intent/LanguageSettingIntent.kt: -------------------------------------------------------------------------------- 1 | /* Sumatora Dictionary 2 | Copyright (C) 2020 Nicolas Centa 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see .*/ 16 | 17 | package org.happypeng.sumatora.android.sumatoradictionary.model.intent 18 | 19 | import org.happypeng.sumatora.android.sumatoradictionary.db.PersistentLanguageSettings 20 | 21 | sealed class LanguageSettingIntent(val languageSettings: PersistentLanguageSettings) 22 | 23 | class LanguageSettingDetachedIntent(languageSettings: PersistentLanguageSettings) : LanguageSettingIntent(languageSettings) 24 | class LanguageSettingAttachedIntent(languageSettings: PersistentLanguageSettings) : LanguageSettingIntent(languageSettings) -------------------------------------------------------------------------------- /app/src/main/java/org/happypeng/sumatora/android/sumatoradictionary/model/intent/MainActivityIntent.kt: -------------------------------------------------------------------------------- 1 | /* Sumatora Dictionary 2 | Copyright (C) 2020 Nicolas Centa 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see .*/ 16 | 17 | package org.happypeng.sumatora.android.sumatoradictionary.model.intent 18 | 19 | sealed class MainActivityIntent 20 | 21 | sealed class MainActivityNavigationIntent : MainActivityIntent() 22 | 23 | object MainActivityNavigateBookmarksIntent : MainActivityNavigationIntent() 24 | object MainActivityNavigateSearchIntent : MainActivityNavigationIntent() 25 | object MainActivityNavigateSettingsIntent : MainActivityNavigationIntent() 26 | object MainActivityNavigateAboutIntent : MainActivityNavigationIntent() 27 | 28 | object MainActivityBackPressedIntent : MainActivityIntent() 29 | object MainActivityHomePressedIntent : MainActivityIntent() 30 | 31 | object MainActivityDrawerClosedIntent : MainActivityIntent() 32 | 33 | object MainActivityCloseIntent : MainActivityIntent() 34 | 35 | class MainActivitySearchIntent(val term: String) : MainActivityIntent() 36 | class MainActivitySetSearchFragmentSearchIntent(val term: String): MainActivityIntent() -------------------------------------------------------------------------------- /app/src/main/java/org/happypeng/sumatora/android/sumatoradictionary/model/intent/QueryIntent.kt: -------------------------------------------------------------------------------- 1 | /* Sumatora Dictionary 2 | Copyright (C) 2020 Nicolas Centa 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see .*/ 16 | 17 | package org.happypeng.sumatora.android.sumatoradictionary.model.intent 18 | 19 | import android.net.Uri 20 | import org.happypeng.sumatora.android.sumatoradictionary.db.PersistentLanguageSettings 21 | import org.happypeng.sumatora.android.sumatoradictionary.mvibase.MviIntent 22 | 23 | sealed class QueryIntent : MviIntent 24 | 25 | class ScrollIntent(val entryOrder: Int) : QueryIntent() 26 | object QueryCloseIntent : QueryIntent() 27 | object BookmarkIntent : QueryIntent() 28 | 29 | class SearchIntent(val term: String) : QueryIntent() 30 | class CloseSearchBoxIntent(val input: String) : QueryIntent() 31 | object OpenSearchBoxIntent : QueryIntent() 32 | 33 | sealed class QueryLanguageSettingIntent(val languageSettings: PersistentLanguageSettings) : QueryIntent() 34 | 35 | class QueryLanguageSettingDetachedIntent(languageSettings: PersistentLanguageSettings) : QueryLanguageSettingIntent(languageSettings) 36 | class QueryLanguageSettingAttachedIntent(languageSettings: PersistentLanguageSettings) : QueryLanguageSettingIntent(languageSettings) -------------------------------------------------------------------------------- /app/src/main/java/org/happypeng/sumatora/android/sumatoradictionary/model/result/ImportResult.kt: -------------------------------------------------------------------------------- 1 | /* Sumatora Dictionary 2 | Copyright (C) 2020 Nicolas Centa 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see .*/ 16 | 17 | package org.happypeng.sumatora.android.sumatoradictionary.model.result 18 | 19 | import org.happypeng.sumatora.android.sumatoradictionary.db.PersistentLanguageSettings 20 | import org.happypeng.sumatora.android.sumatoradictionary.mvibase.MviResult 21 | 22 | class ImportResult(val executed: Boolean, 23 | val persistentLanguageSettings: PersistentLanguageSettings?, 24 | val close: Boolean, 25 | val processing: Boolean) : MviResult -------------------------------------------------------------------------------- /app/src/main/java/org/happypeng/sumatora/android/sumatoradictionary/model/result/QueryResult.kt: -------------------------------------------------------------------------------- 1 | /* Sumatora Dictionary 2 | Copyright (C) 2020 Nicolas Centa 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see .*/ 16 | 17 | package org.happypeng.sumatora.android.sumatoradictionary.model.result 18 | 19 | import org.happypeng.sumatora.android.sumatoradictionary.db.PersistentLanguageSettings 20 | import org.happypeng.sumatora.android.sumatoradictionary.mvibase.MviResult 21 | 22 | class QueryResult(val currentQuery: Int, 23 | val term: String, 24 | val found: Boolean, 25 | val ready: Boolean, 26 | val searching: Boolean, 27 | val languageSettings: PersistentLanguageSettings?, 28 | val closed: Boolean, 29 | val searchBoxClosed: Boolean, 30 | val setIntent: Boolean, 31 | val clearSearchBox: Boolean) : MviResult -------------------------------------------------------------------------------- /app/src/main/java/org/happypeng/sumatora/android/sumatoradictionary/model/state/ImportState.kt: -------------------------------------------------------------------------------- 1 | /* Sumatora Dictionary 2 | Copyright (C) 2020 Nicolas Centa 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see .*/ 16 | package org.happypeng.sumatora.android.sumatoradictionary.model.state 17 | 18 | import org.happypeng.sumatora.android.sumatoradictionary.db.PersistentLanguageSettings 19 | import org.happypeng.sumatora.android.sumatoradictionary.db.tools.BookmarkImportQueryTool 20 | import org.happypeng.sumatora.android.sumatoradictionary.mvibase.MviViewState 21 | 22 | data class ImportState(val executed: Boolean, 23 | val persistentLanguageSettings: PersistentLanguageSettings?, 24 | val closed: Boolean, 25 | val processing: Boolean) : MviViewState -------------------------------------------------------------------------------- /app/src/main/java/org/happypeng/sumatora/android/sumatoradictionary/model/state/MainActivityState.kt: -------------------------------------------------------------------------------- 1 | /* Sumatora Dictionary 2 | Copyright (C) 2020 Nicolas Centa 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see .*/ 16 | 17 | package org.happypeng.sumatora.android.sumatoradictionary.model.state 18 | 19 | import android.os.Parcelable 20 | import kotlinx.android.parcel.Parcelize 21 | import org.happypeng.sumatora.android.sumatoradictionary.mvibase.MviViewState 22 | 23 | enum class MainActivityNavigationStatus { 24 | SEARCH, BOOKMARKS, SETTINGS 25 | } 26 | 27 | @Parcelize 28 | data class MainActivityState(val closed: Boolean, 29 | val navigate: Boolean, 30 | val navigationStatus: MainActivityNavigationStatus, 31 | val changeTerm: Boolean, 32 | val searchTerm: String, 33 | val drawerOpen: Boolean, 34 | val finished: Boolean, 35 | val searchTerms: Map) : MviViewState, Parcelable -------------------------------------------------------------------------------- /app/src/main/java/org/happypeng/sumatora/android/sumatoradictionary/model/state/QueryState.kt: -------------------------------------------------------------------------------- 1 | /* Sumatora Dictionary 2 | Copyright (C) 2020 Nicolas Centa 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see .*/ 16 | package org.happypeng.sumatora.android.sumatoradictionary.model.state 17 | 18 | import android.os.Parcelable 19 | import kotlinx.android.parcel.Parcelize 20 | import org.happypeng.sumatora.android.sumatoradictionary.db.PersistentLanguageSettings 21 | import org.happypeng.sumatora.android.sumatoradictionary.db.tools.DictionarySearchQueryTool 22 | import org.happypeng.sumatora.android.sumatoradictionary.mvibase.MviViewState 23 | 24 | @Parcelize 25 | data class QueryState(val term: String, 26 | val found: Boolean, 27 | val language: String?, 28 | val backupLanguage: String?, 29 | val closed: Boolean, 30 | val searching: Boolean, 31 | val ready: Boolean, 32 | val searchBoxClosed: Boolean, 33 | val setIntent: Boolean, 34 | val clearSearchBox: Boolean): MviViewState, Parcelable -------------------------------------------------------------------------------- /app/src/main/java/org/happypeng/sumatora/android/sumatoradictionary/model/transformer/ImportIntentTransformer.kt: -------------------------------------------------------------------------------- 1 | /* Sumatora Dictionary 2 | Copyright (C) 2020 Nicolas Centa 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see .*/ 16 | 17 | package org.happypeng.sumatora.android.sumatoradictionary.model.transformer 18 | 19 | import io.reactivex.rxjava3.core.Observable 20 | import io.reactivex.rxjava3.core.ObservableEmitter 21 | import io.reactivex.rxjava3.core.ObservableSource 22 | import io.reactivex.rxjava3.core.ObservableTransformer 23 | import org.happypeng.sumatora.android.sumatoradictionary.model.action.* 24 | import org.happypeng.sumatora.android.sumatoradictionary.model.intent.* 25 | 26 | class ImportIntentTransformer: ObservableTransformer { 27 | override fun apply(upstream: Observable): ObservableSource { 28 | return upstream.publish { 29 | it.publish { shared -> 30 | Observable.merge( 31 | listOf( 32 | shared.filter { intent -> intent is ImportCommitIntent }.map { ImportCommitAction }, 33 | shared.filter { intent -> intent is ImportLanguageSettingDetachedIntent }.map { ImportLanguageSettingDetachedAction }, 34 | shared.ofType(ImportLanguageSettingAttachedIntent::class.java).map { intent -> 35 | ImportLanguageSettingAttachedAction(intent.persistentLanguageSettings) 36 | }, 37 | shared.ofType(ImportFileIntent::class.java).flatMap { intent -> 38 | Observable.create { emitter: ObservableEmitter -> 39 | emitter.onNext(ImportSetProcessingAction) 40 | emitter.onNext(ImportFileAction(intent.uri)) 41 | emitter.onComplete() 42 | } 43 | }, 44 | shared.filter { intent -> intent is ImportCancelIntent }.map { ImportClearAction }, 45 | shared.filter { intent -> intent is ImportCloseIntent }.map { ImportClearAction } 46 | )) 47 | } 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /app/src/main/java/org/happypeng/sumatora/android/sumatoradictionary/model/transformer/QueryIntentTransformer.kt: -------------------------------------------------------------------------------- 1 | /* Sumatora Dictionary 2 | Copyright (C) 2020 Nicolas Centa 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see .*/ 16 | 17 | package org.happypeng.sumatora.android.sumatoradictionary.model.transformer 18 | 19 | import io.reactivex.rxjava3.core.Observable 20 | import io.reactivex.rxjava3.core.ObservableEmitter 21 | import io.reactivex.rxjava3.core.ObservableSource 22 | import io.reactivex.rxjava3.core.ObservableTransformer 23 | import org.happypeng.sumatora.android.sumatoradictionary.model.action.* 24 | import org.happypeng.sumatora.android.sumatoradictionary.model.intent.* 25 | 26 | class QueryIntentTransformer: ObservableTransformer { 27 | override fun apply(upstream: Observable): ObservableSource { 28 | return upstream.publish { 29 | it.publish { shared -> 30 | Observable.merge( 31 | listOf( 32 | shared.ofType(SearchIntent::class.java).flatMap { intent -> 33 | Observable.create { emitter: ObservableEmitter -> 34 | emitter.onNext(SetTermAction(intent.term)) 35 | emitter.onNext(SearchAction) 36 | emitter.onComplete() 37 | } 38 | }, 39 | shared.ofType(CloseSearchBoxIntent::class.java).flatMap { intent -> 40 | Observable.create { emitter: ObservableEmitter -> 41 | emitter.onNext(CloseSearchBoxAction(intent.input)) 42 | emitter.onNext(ClosedSearchBoxAction) 43 | emitter.onComplete() 44 | } 45 | }, 46 | shared.filter { intent -> intent is OpenSearchBoxIntent }.map { OpenSearchBoxAction }, 47 | shared.filter { intent -> intent is QueryCloseIntent }.flatMap { _ -> 48 | Observable.create { emitter: ObservableEmitter -> 49 | emitter.onNext(QueryClearAction) 50 | emitter.onNext(QueryCloseAction) 51 | emitter.onComplete() 52 | } 53 | }, 54 | shared.filter { intent -> intent is ScrollIntent }.map { ScrollAction }, 55 | shared.filter { intent -> intent is BookmarkIntent }.map { BookmarkAction }, 56 | shared.ofType(QueryLanguageSettingAttachedIntent::class.java).map { intent -> 57 | QueryLanguageSettingAttachedAction(intent.languageSettings) 58 | }, 59 | shared.ofType(QueryLanguageSettingDetachedIntent::class.java).map { _ -> 60 | QueryLanguageSettingDetachedAction 61 | } 62 | ) 63 | ) 64 | } 65 | } 66 | } 67 | } -------------------------------------------------------------------------------- /app/src/main/java/org/happypeng/sumatora/android/sumatoradictionary/mvibase/MviAction.kt: -------------------------------------------------------------------------------- 1 | package org.happypeng.sumatora.android.sumatoradictionary.mvibase 2 | 3 | /** 4 | * Immutable object which contains all the required information for a business logic to process. 5 | */ 6 | interface MviAction -------------------------------------------------------------------------------- /app/src/main/java/org/happypeng/sumatora/android/sumatoradictionary/mvibase/MviIntent.kt: -------------------------------------------------------------------------------- 1 | package org.happypeng.sumatora.android.sumatoradictionary.mvibase 2 | 3 | /** 4 | * Immutable object which represent an view's intent. 5 | */ 6 | interface MviIntent -------------------------------------------------------------------------------- /app/src/main/java/org/happypeng/sumatora/android/sumatoradictionary/mvibase/MviResult.kt: -------------------------------------------------------------------------------- 1 | package org.happypeng.sumatora.android.sumatoradictionary.mvibase 2 | 3 | /** 4 | * Immutable object resulting of a processed business logic. 5 | */ 6 | interface MviResult -------------------------------------------------------------------------------- /app/src/main/java/org/happypeng/sumatora/android/sumatoradictionary/mvibase/MviView.kt: -------------------------------------------------------------------------------- 1 | package org.happypeng.sumatora.android.sumatoradictionary.mvibase 2 | 3 | import io.reactivex.rxjava3.core.Observable 4 | 5 | /** 6 | * Object representing a UI that will 7 | * a) emit its intents to a view model, 8 | * b) subscribes to a view model for rendering its UI. 9 | * 10 | * @param I Top class of the [MviIntent] that the [MviView] will be emitting. 11 | * @param S Top class of the [MviViewState] the [MviView] will be subscribing to. 12 | */ 13 | interface MviView { 14 | /** 15 | * Unique [Observable] used by the [MviViewModel] 16 | * to listen to the [MviView]. 17 | * All the [MviView]'s [MviIntent]s must go through this [Observable]. 18 | */ 19 | fun intents(): Observable 20 | 21 | /** 22 | * Entry point for the [MviView] to render itself based on a [MviViewState]. 23 | */ 24 | fun render(state: S) 25 | } -------------------------------------------------------------------------------- /app/src/main/java/org/happypeng/sumatora/android/sumatoradictionary/mvibase/MviViewModel.kt: -------------------------------------------------------------------------------- 1 | package org.happypeng.sumatora.android.sumatoradictionary.mvibase 2 | 3 | import io.reactivex.rxjava3.core.Observable 4 | 5 | /** 6 | * Object that will subscribes to a [MviView]'s [MviIntent]s, 7 | * process it and emit a [MviViewState] back. 8 | * 9 | * @param I Top class of the [MviIntent] that the [MviViewModel] will be subscribing 10 | * to. 11 | * @param S Top class of the [MviViewState] the [MviViewModel] will be emitting. 12 | */ 13 | interface MviViewModel { 14 | fun processIntents(intents: Observable) 15 | 16 | fun states(): Observable 17 | } -------------------------------------------------------------------------------- /app/src/main/java/org/happypeng/sumatora/android/sumatoradictionary/mvibase/MviViewState.kt: -------------------------------------------------------------------------------- 1 | package org.happypeng.sumatora.android.sumatoradictionary.mvibase 2 | 3 | /** 4 | * Immutable object which contains all the required information to render a [MviView]. 5 | */ 6 | interface MviViewState -------------------------------------------------------------------------------- /app/src/main/java/org/happypeng/sumatora/android/sumatoradictionary/operator/LiveDataWrapper.kt: -------------------------------------------------------------------------------- 1 | /* Sumatora Dictionary 2 | Copyright (C) 2020 Nicolas Centa 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see .*/ 16 | package org.happypeng.sumatora.android.sumatoradictionary.operator 17 | 18 | import androidx.lifecycle.LiveData 19 | import io.reactivex.rxjava3.core.Observable 20 | import io.reactivex.rxjava3.subjects.PublishSubject 21 | import io.reactivex.rxjava3.subjects.Subject 22 | 23 | object LiveDataWrapper { 24 | fun wrap(liveData: LiveData, 25 | close: Observable): Observable { 26 | val subject: Subject = PublishSubject.create() 27 | liveData.observeForever { t: T -> subject.onNext(t) } 28 | return subject.takeUntil(close).doOnComplete { liveData.removeObserver { t: T -> subject.onNext(t) } } 29 | } 30 | } -------------------------------------------------------------------------------- /app/src/main/java/org/happypeng/sumatora/android/sumatoradictionary/viewholder/DictionaryObjectViewHolder.java: -------------------------------------------------------------------------------- 1 | package org.happypeng.sumatora.android.sumatoradictionary.viewholder; 2 | 3 | import android.view.View; 4 | import android.widget.ImageButton; 5 | import android.widget.TextView; 6 | 7 | import androidx.annotation.NonNull; 8 | import androidx.recyclerview.widget.RecyclerView; 9 | 10 | import org.happypeng.sumatora.android.sumatoradictionary.R; 11 | import org.happypeng.sumatora.android.sumatoradictionary.db.RemoteDictionaryObject; 12 | import org.happypeng.sumatora.android.sumatoradictionary.db.tools.BaseDictionaryObject; 13 | 14 | public class DictionaryObjectViewHolder extends RecyclerView.ViewHolder { 15 | public interface OnClickListener { 16 | void onClick(U aEntry); 17 | } 18 | 19 | private final TextView mDescription; 20 | 21 | private final ImageButton mInstallButton; 22 | private final ImageButton mDeleteButton; 23 | 24 | private final OnClickListener mInstallListener; 25 | private final OnClickListener mDeleteListener; 26 | 27 | public DictionaryObjectViewHolder(@NonNull View itemView, 28 | boolean aInstallButton, 29 | boolean aDeleteButton, 30 | OnClickListener aInstallListener, 31 | OnClickListener aDeleteListener) { 32 | super(itemView); 33 | 34 | mDescription = (TextView) itemView.findViewById(R.id.dictionary_card_description); 35 | 36 | mInstallButton = 37 | (ImageButton) itemView.findViewById(R.id.dictionary_card_install); 38 | mDeleteButton = 39 | (ImageButton) itemView.findViewById(R.id.dictionary_card_delete); 40 | 41 | if (!aInstallButton) { 42 | mInstallButton.setVisibility(View.GONE); 43 | } 44 | 45 | if (!aDeleteButton) { 46 | mDeleteButton.setVisibility(View.GONE); 47 | } 48 | 49 | mInstallListener = aInstallListener; 50 | mDeleteListener = aDeleteListener; 51 | } 52 | 53 | public void bindTo(final T aEntry) { 54 | if (aEntry == null) { return; } 55 | 56 | mDescription.setText(aEntry.description); 57 | 58 | if (mInstallListener != null) { 59 | mInstallButton.setOnClickListener(new View.OnClickListener() { 60 | @Override 61 | public void onClick(View v) { 62 | mInstallListener.onClick(aEntry); 63 | } 64 | }); 65 | } 66 | 67 | if (mDeleteListener != null) { 68 | mDeleteButton.setOnClickListener(new View.OnClickListener() { 69 | @Override 70 | public void onClick(View v) { 71 | mDeleteListener.onClick(aEntry); 72 | } 73 | }); 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/blake_meyer_423494_unsplash_lowres.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HappyPeng2x/SumatoraDictionary/7cbc006992941af4171713900a45a854afa2af8f/app/src/main/res/drawable/blake_meyer_423494_unsplash_lowres.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_account_circle_white_64dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_add_24px.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_baseline_star_24px.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_delete_24px.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_edit_24px.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_explore_white_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_filter_alt_24px.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_info_white_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_menu_white_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_outline_bookmark_24px.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_outline_bookmark_border_24px.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_outline_bookmarks_24px.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_outline_cached_24px.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_outline_cancel_24px.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_outline_check_24px.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_outline_class_24px.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_outline_close_24px.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_outline_copyright_24px.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_outline_info_24px.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_outline_language_24px.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_outline_menu_24px.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_outline_public_24px.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_outline_search_24px.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_outline_search_24px_white.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_outline_settings_24px.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_outline_share_24px.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_outline_star_border_24px.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_outline_stop_24px.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_remove_24px.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/nav_drawer_header_foreground.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_dictionary.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 11 | 12 | 16 | 17 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_dictionary_bookmarks_import.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_license.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 13 | 16 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /app/src/main/res/layout/dictionary_card.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 12 | 13 | 23 | 24 | 34 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_debug.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 18 | 19 | 22 | 25 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_dictionary_query.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 18 | 19 | 20 | 28 | 29 | 35 | 36 | 43 | 44 | 52 | 53 | 59 | 60 | 66 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 18 | 19 | 26 | 31 | 32 | 38 | 39 | 48 | 49 | 50 | 53 | 57 |