Showing preview only (766K chars total). Download the full file or copy to clipboard to get everything.
Repository: 0xbad1d3a5/Kaku
Branch: master
Commit: 02ee8842fc18
Files: 175
Total size: 704.4 KB
Directory structure:
gitextract_arnt_e7c/
├── .gitattributes
├── .gitignore
├── .idea/
│ ├── encodings.xml
│ ├── misc.xml
│ ├── modules.xml
│ └── vcs.xml
├── LICENSE
├── README.md
├── app/
│ ├── .gitignore
│ ├── build.gradle
│ ├── proguard-rules.pro
│ └── src/
│ ├── main/
│ │ ├── AndroidManifest.xml
│ │ ├── java/
│ │ │ └── ca/
│ │ │ └── fuwafuwa/
│ │ │ └── kaku/
│ │ │ ├── BetaActivity.kt
│ │ │ ├── Constants.kt
│ │ │ ├── Database/
│ │ │ │ ├── DatabaseHelper.java
│ │ │ │ ├── DbHelperFactory.java
│ │ │ │ ├── IDatabaseHelper.java
│ │ │ │ ├── JmDictDatabase/
│ │ │ │ │ ├── JmDatabaseHelper.java
│ │ │ │ │ └── Models/
│ │ │ │ │ ├── Entry.java
│ │ │ │ │ ├── EntryOptimized.java
│ │ │ │ │ ├── Kanji.java
│ │ │ │ │ ├── KanjiIrregularity.java
│ │ │ │ │ ├── KanjiPriority.java
│ │ │ │ │ ├── Meaning.java
│ │ │ │ │ ├── MeaningAdditionalInfo.java
│ │ │ │ │ ├── MeaningAntonym.java
│ │ │ │ │ ├── MeaningCrossReference.java
│ │ │ │ │ ├── MeaningDialect.java
│ │ │ │ │ ├── MeaningField.java
│ │ │ │ │ ├── MeaningGloss.java
│ │ │ │ │ ├── MeaningKanjiRestriction.java
│ │ │ │ │ ├── MeaningLoanSource.java
│ │ │ │ │ ├── MeaningMisc.java
│ │ │ │ │ ├── MeaningPartOfSpeech.java
│ │ │ │ │ ├── MeaningReadingRestriction.java
│ │ │ │ │ ├── Reading.java
│ │ │ │ │ ├── ReadingIrregularity.java
│ │ │ │ │ ├── ReadingPriority.java
│ │ │ │ │ └── ReadingRestriction.java
│ │ │ │ └── KanjiDict2Database/
│ │ │ │ ├── Kd2DatabaseHelper.java
│ │ │ │ └── Models/
│ │ │ │ └── CharacterOptimized.java
│ │ │ ├── Deinflictor/
│ │ │ │ ├── DeinflectionDTOs.kt
│ │ │ │ ├── Deinflector.kt
│ │ │ │ └── PosMap.kt
│ │ │ ├── Dialogs/
│ │ │ │ ├── FeedbackDialogFragment.kt
│ │ │ │ ├── GrantPermissionDialogFragment.kt
│ │ │ │ ├── PlayStoreRatingDialogFragment.kt
│ │ │ │ ├── StarRatingDialogFragment.kt
│ │ │ │ └── TutorialExplainDialogFragment.kt
│ │ │ ├── Exceptions/
│ │ │ │ └── NotImplementedException.java
│ │ │ ├── Interfaces/
│ │ │ │ └── Stoppable.java
│ │ │ ├── KakuTools.kt
│ │ │ ├── LangUtils.kt
│ │ │ ├── MainActivity.kt
│ │ │ ├── MainService.java
│ │ │ ├── MainServiceHandler.java
│ │ │ ├── MainStartFragment.kt
│ │ │ ├── Ocr/
│ │ │ │ ├── BoxParams.java
│ │ │ │ ├── OcrCorrection.kt
│ │ │ │ ├── OcrParams.kt
│ │ │ │ ├── OcrResult.kt
│ │ │ │ └── OcrRunnable.kt
│ │ │ ├── PassthroughActivity.kt
│ │ │ ├── Search/
│ │ │ │ ├── JmSearchResult.kt
│ │ │ │ ├── JmTask.kt
│ │ │ │ ├── Kd2Task.kt
│ │ │ │ ├── SearchInfo.kt
│ │ │ │ └── Searcher.java
│ │ │ ├── TutorialActivity.kt
│ │ │ ├── TutorialEndFragment.kt
│ │ │ ├── TutorialFragment.kt
│ │ │ ├── TutorialWelcomeFragment.kt
│ │ │ ├── Windows/
│ │ │ │ ├── CaptureWindow.kt
│ │ │ │ ├── Data/
│ │ │ │ │ ├── DisplayData.kt
│ │ │ │ │ └── SquareChar.kt
│ │ │ │ ├── EditWindow.kt
│ │ │ │ ├── Enums/
│ │ │ │ │ ├── ChoiceType.java
│ │ │ │ │ └── LayoutPosition.kt
│ │ │ │ ├── HistoryWindow.kt
│ │ │ │ ├── InformationWindow.java
│ │ │ │ ├── InstantInfoWindow.kt
│ │ │ │ ├── InstantKanjiWindow.kt
│ │ │ │ ├── Interfaces/
│ │ │ │ │ ├── ICopyText.kt
│ │ │ │ │ ├── IRecalculateKanjiViews.kt
│ │ │ │ │ ├── ISearchPerformer.kt
│ │ │ │ │ └── WindowListener.java
│ │ │ │ ├── KanjiChoiceWindow.kt
│ │ │ │ ├── Views/
│ │ │ │ │ ├── ChoiceEditText.java
│ │ │ │ │ ├── ChoiceGridView.java
│ │ │ │ │ ├── ChoiceIconView.java
│ │ │ │ │ ├── KanjiCharacterView.kt
│ │ │ │ │ ├── KanjiGridView.kt
│ │ │ │ │ ├── KanjiImageView.kt
│ │ │ │ │ ├── ResizeView.java
│ │ │ │ │ ├── SquareGridView.kt
│ │ │ │ │ └── WindowView.java
│ │ │ │ ├── Window.java
│ │ │ │ └── WindowCoordinator.kt
│ │ │ └── XmlParsers/
│ │ │ ├── CommonParser.java
│ │ │ ├── Interfaces/
│ │ │ │ └── DictParser.java
│ │ │ ├── JmDict/
│ │ │ │ ├── JmConsts.java
│ │ │ │ ├── JmDTO/
│ │ │ │ │ ├── JmEntry.java
│ │ │ │ │ ├── JmGloss.java
│ │ │ │ │ ├── JmKEle.java
│ │ │ │ │ ├── JmLsource.java
│ │ │ │ │ ├── JmREle.java
│ │ │ │ │ └── JmSense.java
│ │ │ │ └── JmParser.java
│ │ │ ├── KanjiDict2/
│ │ │ │ ├── Kd2Consts.java
│ │ │ │ ├── Kd2DTO/
│ │ │ │ │ ├── Kd2Character.java
│ │ │ │ │ ├── Kd2Codepoint.java
│ │ │ │ │ ├── Kd2CpValue.java
│ │ │ │ │ ├── Kd2DicNumber.java
│ │ │ │ │ ├── Kd2DicRef.java
│ │ │ │ │ ├── Kd2Meaning.java
│ │ │ │ │ ├── Kd2Misc.java
│ │ │ │ │ ├── Kd2QCode.java
│ │ │ │ │ ├── Kd2QueryCode.java
│ │ │ │ │ ├── Kd2RadValue.java
│ │ │ │ │ ├── Kd2Radical.java
│ │ │ │ │ ├── Kd2Reading.java
│ │ │ │ │ ├── Kd2ReadingMeaning.java
│ │ │ │ │ ├── Kd2RmGroup.java
│ │ │ │ │ └── Kd2Variant.java
│ │ │ │ └── Kd2Parser.java
│ │ │ └── ParserRunnable.java
│ │ └── res/
│ │ ├── anim/
│ │ │ ├── fade_repeat.xml
│ │ │ └── slide_in.xml
│ │ ├── drawable/
│ │ │ ├── bg_solid_border_0_blue_black.xml
│ │ │ ├── bg_solid_border_0_white_black.xml
│ │ │ ├── bg_solid_border_corners_0_white_black_round.xml
│ │ │ ├── bg_translucent_border_0_black_black.xml
│ │ │ ├── bg_translucent_border_0_blue_blue.xml
│ │ │ ├── bg_transparent_border_0_nil_black.xml
│ │ │ ├── bg_transparent_border_0_nil_default.xml
│ │ │ └── bg_transparent_border_0_nil_ready.xml
│ │ ├── drawable-anydpi/
│ │ │ ├── icon_delete.xml
│ │ │ ├── icon_edit.xml
│ │ │ └── icon_swap.xml
│ │ ├── layout/
│ │ │ ├── activity_beta.xml
│ │ │ ├── activity_main.xml
│ │ │ ├── activity_passthrough.xml
│ │ │ ├── activity_tutorial.xml
│ │ │ ├── dialog_rating_stars.xml
│ │ │ ├── fragment_end.xml
│ │ │ ├── fragment_start.xml
│ │ │ ├── fragment_tutorial.xml
│ │ │ ├── fragment_welcome.xml
│ │ │ ├── window.xml
│ │ │ ├── window_capture.xml
│ │ │ ├── window_edit.xml
│ │ │ ├── window_history.xml
│ │ │ ├── window_info.xml
│ │ │ ├── window_instant_info.xml
│ │ │ ├── window_instant_kanji.xml
│ │ │ └── window_kanji_choice.xml
│ │ ├── mipmap-anydpi-v26/
│ │ │ ├── ic_launcher.xml
│ │ │ └── ic_launcher_round.xml
│ │ ├── values/
│ │ │ ├── colors.xml
│ │ │ ├── dimens.xml
│ │ │ ├── strings.xml
│ │ │ └── styles.xml
│ │ └── values-w820dp/
│ │ └── dimens.xml
│ └── test/
│ └── java/
│ └── ca/
│ └── fuwafuwa/
│ └── kaku/
│ ├── ExampleUnitTest.java
│ └── GenerateDictionary.java
├── build.gradle
├── fastlane/
│ └── metadata/
│ └── android/
│ └── en-US/
│ ├── full_description.txt
│ └── short_description.txt
├── gradle/
│ └── wrapper/
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradle.properties
├── gradlew
├── gradlew.bat
├── projectFilesBackup/
│ └── .idea/
│ └── workspace.xml
└── settings.gradle
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitattributes
================================================
# Auto detect text files and perform LF normalization
* text=auto
# Custom for Visual Studio
*.cs diff=csharp
*.sln merge=union
*.csproj merge=union
*.vbproj merge=union
*.fsproj merge=union
*.dbproj merge=union
# Standard to msysgit
*.doc diff=astextplain
*.DOC diff=astextplain
*.docx diff=astextplain
*.DOCX diff=astextplain
*.dot diff=astextplain
*.DOT diff=astextplain
*.pdf diff=astextplain
*.PDF diff=astextplain
*.rtf diff=astextplain
*.RTF diff=astextplain
================================================
FILE: .gitignore
================================================
# Ignore data files for Kaku - these shouldn't be checked in
app/src/main/assets/*
app/src/main/res/raw/*
# Ignore private and sensitive configuration files for Kaku
# If you pull the repo, you will need to create and populate these files yourself
# !!!! DO NOT EVER COMMIT THESE FILES AS THEY CONTAIN EXTREMELY SENSITIVE INFORMATION !!!!
app/src/main/res/values/private_strings.xml
keystore.properties
service_account.json
# Created by https://www.gitignore.io/api/android
# Edit at https://www.gitignore.io/?templates=android
### Android ###
# Built application files
*.apk
*.ap_
*.aab
# Release files
app/release/*
app/debug/*
# Files for the ART/Dalvik VM
*.dex
# Java class files
*.class
# Generated files
bin/
gen/
out/
# Gradle files
.gradle/
build/
# Local configuration file (sdk path, etc)
local.properties
# Proguard folder generated by Eclipse
proguard/
# Log Files
*.log
# Android Studio Navigation editor temp files
.navigation/
# Android Studio captures folder
captures/
# IntelliJ
*.iml
.idea/workspace.xml
.idea/tasks.xml
.idea/gradle.xml
.idea/assetWizardSettings.xml
.idea/dictionaries
.idea/libraries
.idea/caches
# Keystore files
# Uncomment the following lines if you do not want to check your keystore files in.
#*.jks
#*.keystore
# External native build folder generated in Android Studio 2.2 and later
.externalNativeBuild
# Google Services (e.g. APIs or Firebase)
google-services.json
# Freeline
freeline.py
freeline/
freeline_project_description.json
# fastlane
fastlane/report.xml
fastlane/Preview.html
fastlane/screenshots
fastlane/test_output
fastlane/readme.md
### Android Patch ###
gen-external-apklibs
# End of https://www.gitignore.io/api/android
================================================
FILE: .idea/encodings.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding" addBOMForNewFiles="with NO BOM" />
</project>
================================================
FILE: .idea/misc.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CMakeSettings">
<configurations>
<configuration PROFILE_NAME="Debug" CONFIG_NAME="Debug" />
</configurations>
</component>
<component name="DesignSurface">
<option name="filePathToZoomLevelMap">
<map>
<entry key="..\:/Dev/Kaku/app/src/main/res/drawable-anydpi/icon_delete.xml" value="0.8484375" />
<entry key="..\:/Dev/Kaku/app/src/main/res/drawable/bg_solid_border_0_blue_black.xml" value="0.590625" />
<entry key="..\:/Dev/Kaku/app/src/main/res/drawable/bg_solid_border_0_white_black.xml" value="0.8484375" />
<entry key="..\:/Dev/Kaku/app/src/main/res/drawable/bg_solid_border_corners_0_white_black_round.xml" value="0.8484375" />
<entry key="..\:/Dev/Kaku/app/src/main/res/drawable/bg_translucent_border_0_blue_blue.xml" value="0.8484375" />
<entry key="..\:/Dev/Kaku/app/src/main/res/drawable/bg_transparent_border_0_nil_default.xml" value="0.8484375" />
<entry key="..\:/Dev/Kaku/app/src/main/res/drawable/bg_transparent_border_0_nil_ready.xml" value="0.8484375" />
<entry key="..\:/Dev/Kaku/app/src/main/res/drawable/ic_baseline_arrow_right_alt_24.xml" value="0.8484375" />
<entry key="..\:/Dev/Kaku/app/src/main/res/drawable/icon_capture.xml" value="1.0" />
<entry key="..\:/Dev/Kaku/app/src/main/res/drawable/kakucaptureicon.xml" value="0.8053435114503816" />
<entry key="..\:/Dev/Kaku/app/src/main/res/layout/activity_beta.xml" value="0.3638948116560057" />
<entry key="..\:/Dev/Kaku/app/src/main/res/layout/activity_tutorial.xml" value="0.77265625" />
<entry key="..\:/Dev/Kaku/app/src/main/res/layout/fragment_end.xml" value="0.9079301075268817" />
<entry key="..\:/Dev/Kaku/app/src/main/res/layout/fragment_start.xml" value="0.67" />
<entry key="..\:/Dev/Kaku/app/src/main/res/layout/fragment_tutorial.xml" value="0.9079301075268817" />
<entry key="..\:/Dev/Kaku/app/src/main/res/layout/fragment_welcome.xml" value="0.9079301075268817" />
<entry key="..\:/Dev/Kaku/app/src/main/res/layout/window.xml" value="0.8" />
<entry key="..\:/Dev/Kaku/app/src/main/res/layout/window_capture.xml" value="0.4943778110944528" />
<entry key="..\:/Dev/Kaku/app/src/main/res/layout/window_edit.xml" value="0.56640625" />
<entry key="..\:/Dev/Kaku/app/src/main/res/layout/window_info.xml" value="0.8" />
</map>
</option>
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" default="true" project-jdk-name="JDK" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" />
</component>
<component name="ProjectType">
<option name="id" value="Android" />
</component>
</project>
================================================
FILE: .idea/modules.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/Kaku.iml" filepath="$PROJECT_DIR$/Kaku.iml" />
<module fileurl="file://$PROJECT_DIR$/.idea/modules/app/Kaku.app.iml" filepath="$PROJECT_DIR$/.idea/modules/app/Kaku.app.iml" />
</modules>
</component>
</project>
================================================
FILE: .idea/vcs.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>
================================================
FILE: LICENSE
================================================
BSD 3-Clause License
Copyright (c) 2016, 0xbad1d3a5
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
================================================
FILE: README.md
================================================
Kaku: 画 (かく) - stroke (of a kanji, etc.), picture, drawing
https://kaku.fuwafuwa.ca/
Kaku is a fast, powerful Japanese dictionary that stays on top of all your apps. It uses optical character recognition (OCR) technology to recognize kanji on the device screen for you (rather than the slowww tedious process of looking up individual characters manually), making it perfect for Japanese learners who want to study by reading raw manga, play untranslated games, and so on without the hassle of switching apps.
[<img src="https://fdroid.gitlab.io/artwork/badge/get-it-on.png"
alt="Get it on F-Droid"
height="80">](https://f-droid.org/packages/ca.fuwafuwa.kaku/)
[<img src="https://play.google.com/intl/en_us/badges/images/generic/en-play-badge.png"
alt="Get it on Google Play"
height="80">](https://play.google.com/store/apps/details?id=ca.fuwafuwa.kaku)
================================================
FILE: app/.gitignore
================================================
/build
================================================
FILE: app/build.gradle
================================================
plugins {
id 'com.android.application'
}
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
android {
compileSdkVersion 31
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
def versionPrefix = "1.3"
defaultConfig {
applicationId "ca.fuwafuwa.kaku"
minSdkVersion 21
targetSdkVersion 31
versionCode 78
versionName "$versionPrefix.$versionCode"
}
buildFeatures {
viewBinding true
}
buildTypes {
release {
debuggable false
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
debug {
debuggable true
}
}
packagingOptions {
resources {
excludes += ['META-INF/DEPENDENCIES', 'META-INF/LICENSE', 'META-INF/LICENSE.txt', 'META-INF/license.txt', 'META-INF/NOTICE', 'META-INF/NOTICE.txt', 'META-INF/notice.txt', 'META-INF/ASL2.0', 'META-INF/CONTRIBUTORS.md', 'META-INF/LICENSE.md']
}
}
testOptions {
unitTests.returnDefaultValues = true
}
}
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation 'com.rmtheis:tess-two:9.0.0'
implementation 'com.google.guava:guava:31.0.1-android'
implementation 'com.google.code.gson:gson:2.8.9'
implementation 'androidx.appcompat:appcompat:1.4.1'
implementation 'com.google.android.material:material:1.6.0'
implementation 'com.j256.ormlite:ormlite-android:5.1'
implementation 'com.google.android.gms:play-services-ads:20.6.0'
implementation 'com.atilika.kuromoji:kuromoji-core:0.9.0'
implementation 'com.atilika.kuromoji:kuromoji-ipadic:0.9.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
testImplementation 'junit:junit:4.13.2'
// Probably just delete all these was trying to get GenerateDictionary to work as a Unit Test
testImplementation 'com.j256.ormlite:ormlite-core:5.1'
testImplementation 'com.j256.ormlite:ormlite-jdbc:5.1'
testImplementation 'org.xerial:sqlite-jdbc:3.25.2'
testImplementation 'xmlpull:xmlpull:1.1.3.1'
testImplementation 'kxml2:kxml2:2.3.0'
}
================================================
FILE: app/proguard-rules.pro
================================================
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in D:\Android\AndroidSDK/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
================================================
FILE: app/src/main/AndroidManifest.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="ca.fuwafuwa.kaku">
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:largeHeap="true"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<meta-data
android:name="com.google.android.gms.ads.APPLICATION_ID"
android:value="@string/ads_app_id" />
<receiver android:name=".MainService$CloseMainService" />
<receiver android:name=".MainService$TogglePageModeMainService" />
<receiver android:name=".MainService$ToggleInstantModeMainService" />
<receiver android:name=".MainService$ToggleImagePreviewMainService" />
<receiver android:name=".MainService$ToggleShowHideMainService" />
<activity
android:name=".MainActivity"
android:label="Kaku"
android:noHistory="false"
android:launchMode="standard"
android:screenOrientation="portrait"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".BetaActivity"
android:label="Kaku Beta"
android:noHistory="false"
android:launchMode="standard"
android:screenOrientation="portrait">
</activity>
<activity
android:name=".TutorialActivity"
android:label="Kaku Tutorial"
android:noHistory="false"
android:launchMode="standard"
android:screenOrientation="portrait">
</activity>
<activity
android:name=".PassthroughActivity"
android:label="Kaku"
android:launchMode="singleInstance"
android:noHistory="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.PROCESS_TEXT" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="text/plain" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="text/plain" />
</intent-filter>
</activity>
<service
android:name=".MainService"
android:foregroundServiceType="mediaProjection"
android:exported="true" />
</application>
</manifest>
================================================
FILE: app/src/main/java/ca/fuwafuwa/kaku/BetaActivity.kt
================================================
package ca.fuwafuwa.kaku
import android.content.Intent
import android.net.Uri
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Button
class BetaActivity : AppCompatActivity()
{
override fun onCreate(savedInstanceState: Bundle?)
{
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_beta)
findViewById<Button>(R.id.beta_button_start).setOnClickListener {
finish()
}
val emailIntent = Intent(android.content.Intent.ACTION_SENDTO)
emailIntent.type = "text/plain"
emailIntent.data = Uri.parse("mailto:")
emailIntent.putExtra(android.content.Intent.EXTRA_EMAIL, arrayOf("0xbad1d3a5@gmail.com"))
emailIntent.putExtra(android.content.Intent.EXTRA_SUBJECT, "Kaku Beta User - ${android.os.Build.BRAND + " " + android.os.Build.MODEL}")
findViewById<Button>(R.id.beta_button_email).setOnClickListener {
startActivity(Intent.createChooser(emailIntent, "Send e-mail using..."))
}
}
}
================================================
FILE: app/src/main/java/ca/fuwafuwa/kaku/Constants.kt
================================================
@file:JvmName("Constants")
package ca.fuwafuwa.kaku
// Thanks to the fact that SqliteOpenHelper.onUpgrade() doesn't work (due to multi-threading and getDao() being called before onUpgrade()),
// we version/upgrade the DBs by changing the name. Lol. Should probably fix this if this becomes an issue in the future.
const val JMDICT_DATABASE_NAME = "DB_KakuDict-02-16-2019.db"
const val TESS_FOLDER_NAME = "tessdata"
const val TESS_DATA_NAME = "jpn.traineddata"
const val SCREENSHOT_FOLDER_NAME = "screenshots"
const val DB_SPLIT_CHAR = "\ufffc"
const val DB_JMDICT_NAME = "JMDICT"
const val DB_KANJIDICT_NAME = "KANJIDICT"
const val DB_ENAMEDICT_NAME = "ENAMEDICT"
const val KAKU_PREF_FILE = "ca.fuwafuwa.kaku"
const val KAKU_PREF_SHOW_HIDE = "ShowHide"
const val KAKU_PREF_IMAGE_FILTER = "ImageFilter"
const val KAKU_PREF_TEXT_DIRECTION = "TextDirection"
const val KAKU_PREF_INSTANT_MODE = "InstantMode"
const val KAKU_PREF_FIRST_LAUNCH = "FirstLaunch"
const val KAKU_PREF_TIMES_LAUNCHED = "TimesLaunched"
const val KAKU_PREF_PLAY_STORE_RATED = "PlayStoreRated"
const val EXTRA_PROJECTION_RESULT_CODE = "ca.fuwafuwa.kaku.PROJECTION_RESULT_CODE"
const val EXTRA_PROJECTION_RESULT_INTENT = "ca.fuwafuwa.kaku.PROJECTION_RESULT_INTENT"
const val WINDOW_CAPTURE = "WINDOW_CAPTURE"
const val WINDOW_INFO = "WINDOW_INFO"
const val WINDOW_EDIT = "WINDOW_EDIT"
const val WINDOW_INSTANT_KANJI = "WINDOW_INSTANT_KANJI"
const val WINDOW_KANJI_CHOICE = "WINDOW_KANJI_CHOICE"
const val WINDOW_HISTORY = "WINDOW_HISTORY"
const val KAKU_CHANNEL_ID = "kaku_notification_channel_id"
const val KAKU_CHANNEL_NAME = "Show Kaku Notification"
const val REQUEST_SCREENSHOT = 100
const val REQUEST_DRAW_ON_TOP = 200
const val REQUEST_SERVICE_TOGGLE_IMAGE_PREVIEW = 300
const val REQUEST_SERVICE_TOGGLE_PAGE_MODE = 400
const val REQUEST_SERVICE_TOGGLE_INSTANT_MODE = 500
const val REQUEST_SERVICE_SHUTDOWN = 600
const val REQUEST_SERVICE_TOGGLE_SHOW_HIDE = 700
================================================
FILE: app/src/main/java/ca/fuwafuwa/kaku/Database/DatabaseHelper.java
================================================
package ca.fuwafuwa.kaku.Database;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import com.j256.ormlite.android.apptools.OrmLiteSqliteOpenHelper;
import com.j256.ormlite.dao.Dao;
import java.sql.SQLException;
/**
* Created by 0xbad1d3a5 on 12/1/2016.
*/
public abstract class DatabaseHelper extends OrmLiteSqliteOpenHelper implements IDatabaseHelper {
public DatabaseHelper(Context context, String databaseName, SQLiteDatabase.CursorFactory factory, int databaseVersion) {
super(context, databaseName, factory, databaseVersion);
}
public abstract void deleteDatabase();
}
================================================
FILE: app/src/main/java/ca/fuwafuwa/kaku/Database/DbHelperFactory.java
================================================
package ca.fuwafuwa.kaku.Database;
import android.content.Context;
import ca.fuwafuwa.kaku.Database.JmDictDatabase.JmDatabaseHelper;
import ca.fuwafuwa.kaku.Database.KanjiDict2Database.Kd2DatabaseHelper;
/**
* Created by 0xbad1d3a5 on 12/1/2016.
*/
public class DbHelperFactory {
private static Context mContext;
public DbHelperFactory(Context context){
mContext = context;
}
public DatabaseHelper instance(Class clazz){
if (clazz == JmDatabaseHelper.class) {
return JmDatabaseHelper.instance(mContext);
}
else if (clazz == Kd2DatabaseHelper.class){
return Kd2DatabaseHelper.instance(mContext);
}
else {
return null;
}
}
}
================================================
FILE: app/src/main/java/ca/fuwafuwa/kaku/Database/IDatabaseHelper.java
================================================
package ca.fuwafuwa.kaku.Database;
import com.j256.ormlite.dao.Dao;
import java.sql.SQLException;
public interface IDatabaseHelper
{
<T> Dao<T, Integer> getDbDao(Class clazz) throws SQLException;
}
================================================
FILE: app/src/main/java/ca/fuwafuwa/kaku/Database/JmDictDatabase/JmDatabaseHelper.java
================================================
package ca.fuwafuwa.kaku.Database.JmDictDatabase;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.util.Log;
import com.j256.ormlite.dao.Dao;
import com.j256.ormlite.support.ConnectionSource;
import com.j256.ormlite.table.TableUtils;
import java.sql.SQLException;
import ca.fuwafuwa.kaku.Constants;
import ca.fuwafuwa.kaku.Database.DatabaseHelper;
import ca.fuwafuwa.kaku.Database.JmDictDatabase.Models.Entry;
import ca.fuwafuwa.kaku.Database.JmDictDatabase.Models.EntryOptimized;
import ca.fuwafuwa.kaku.Database.JmDictDatabase.Models.Kanji;
import ca.fuwafuwa.kaku.Database.JmDictDatabase.Models.KanjiIrregularity;
import ca.fuwafuwa.kaku.Database.JmDictDatabase.Models.KanjiPriority;
import ca.fuwafuwa.kaku.Database.JmDictDatabase.Models.Meaning;
import ca.fuwafuwa.kaku.Database.JmDictDatabase.Models.MeaningAdditionalInfo;
import ca.fuwafuwa.kaku.Database.JmDictDatabase.Models.MeaningAntonym;
import ca.fuwafuwa.kaku.Database.JmDictDatabase.Models.MeaningCrossReference;
import ca.fuwafuwa.kaku.Database.JmDictDatabase.Models.MeaningDialect;
import ca.fuwafuwa.kaku.Database.JmDictDatabase.Models.MeaningField;
import ca.fuwafuwa.kaku.Database.JmDictDatabase.Models.MeaningGloss;
import ca.fuwafuwa.kaku.Database.JmDictDatabase.Models.MeaningKanjiRestriction;
import ca.fuwafuwa.kaku.Database.JmDictDatabase.Models.MeaningLoanSource;
import ca.fuwafuwa.kaku.Database.JmDictDatabase.Models.MeaningMisc;
import ca.fuwafuwa.kaku.Database.JmDictDatabase.Models.MeaningPartOfSpeech;
import ca.fuwafuwa.kaku.Database.JmDictDatabase.Models.MeaningReadingRestriction;
import ca.fuwafuwa.kaku.Database.JmDictDatabase.Models.Reading;
import ca.fuwafuwa.kaku.Database.JmDictDatabase.Models.ReadingIrregularity;
import ca.fuwafuwa.kaku.Database.JmDictDatabase.Models.ReadingPriority;
import ca.fuwafuwa.kaku.Database.JmDictDatabase.Models.ReadingRestriction;
import ca.fuwafuwa.kaku.Exceptions.NotImplementedException;
import ca.fuwafuwa.kaku.KakuTools;
/**
* Created by 0xbad1d3a5 on 7/26/2016.
*/
public class JmDatabaseHelper extends DatabaseHelper {
private static final String TAG = JmDatabaseHelper.class.getName();
private static final String DATABASE_NAME = Constants.JMDICT_DATABASE_NAME;
private static final int DATABASE_VERSION = 1;
private static JmDatabaseHelper instance;
private Context mContext;
private JmDatabaseHelper(Context context){
super(context, String.format("%s/%s", context.getFilesDir().getAbsolutePath(), DATABASE_NAME), null, DATABASE_VERSION);
Log.d(TAG, "JmDatabaseHelper Constructor");
mContext = context;
}
public static synchronized JmDatabaseHelper instance(Context context){
if (instance == null){
instance = new JmDatabaseHelper(context);
}
return instance;
}
@Override
public void onCreate(SQLiteDatabase database, ConnectionSource connectionSource) {
Log.d(TAG, "JmDatabaseHelper onCreate");
try {
TableUtils.createTable(connectionSource, EntryOptimized.class);
} catch (SQLException e) {
e.printStackTrace();
}
}
@Override
public void onUpgrade(SQLiteDatabase database, ConnectionSource connectionSource, int oldVersion, int newVersion) {
// Can't use onUpgrade, because getDbDao() will sometimes run first due to being on another thread, opening a DB connection and causing issues when we try to delete the DB
throw new NotImplementedException();
}
public void deleteDatabase(){
mContext.deleteDatabase(String.format("%s/%s", mContext.getFilesDir().getAbsolutePath(), DATABASE_NAME));
}
public <T> Dao<T, Integer> getDbDao(Class clazz) throws SQLException {
return getDao(clazz);
}
}
================================================
FILE: app/src/main/java/ca/fuwafuwa/kaku/Database/JmDictDatabase/Models/Entry.java
================================================
package ca.fuwafuwa.kaku.Database.JmDictDatabase.Models;
import com.google.gson.annotations.Expose;
import com.j256.ormlite.dao.ForeignCollection;
import com.j256.ormlite.field.DatabaseField;
import com.j256.ormlite.field.ForeignCollectionField;
import com.j256.ormlite.table.DatabaseTable;
import ca.fuwafuwa.kaku.KakuTools;
/**
* Created by 0xbad1d3a5 on 5/2/2016.
*/
@DatabaseTable
public class Entry {
@Expose
@DatabaseField(id = true)
private Integer id;
@Expose
@ForeignCollectionField()
private ForeignCollection<Kanji> kanjis;
@Expose
@ForeignCollectionField()
private ForeignCollection<Reading> readings;
@Expose
@ForeignCollectionField()
private ForeignCollection<Meaning> meanings;
public Entry(){
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public ForeignCollection<Kanji> getKanjis() {
return kanjis;
}
public void setKanjis(ForeignCollection<Kanji> kanjis) {
this.kanjis = kanjis;
}
public ForeignCollection<Reading> getReadings() {
return readings;
}
public void setReadings(ForeignCollection<Reading> readings) {
this.readings = readings;
}
public ForeignCollection<Meaning> getMeanings() {
return meanings;
}
public void setMeanings(ForeignCollection<Meaning> meanings) {
this.meanings = meanings;
}
@Override
public String toString() {
return KakuTools.toJson(this);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Entry entry1 = (Entry) o;
return id.equals(entry1.id);
}
@Override
public int hashCode() {
return id.hashCode();
}
}
================================================
FILE: app/src/main/java/ca/fuwafuwa/kaku/Database/JmDictDatabase/Models/EntryOptimized.java
================================================
package ca.fuwafuwa.kaku.Database.JmDictDatabase.Models;
import com.google.gson.annotations.Expose;
import com.j256.ormlite.field.DataType;
import com.j256.ormlite.field.DatabaseField;
/**
* Created by 0xbad1d3a5 on 12/1/2016.
*/
public class EntryOptimized implements Comparable<EntryOptimized> {
@Expose(serialize = false)
@DatabaseField(generatedId = true)
private Integer id;
@Expose
@DatabaseField
private String kanji;
@Expose
@DatabaseField(dataType = DataType.LONG_STRING)
private String readings;
@Expose
@DatabaseField(dataType = DataType.LONG_STRING)
private String meanings;
@Expose
@DatabaseField(dataType = DataType.LONG_STRING)
private String pos;
@Expose
@DatabaseField(dataType = DataType.LONG_STRING)
private String priorities;
@Expose
@DatabaseField(dataType = DataType.LONG_STRING)
private String dictionary;
@Expose
@DatabaseField(dataType = DataType.BOOLEAN)
private boolean primaryEntry = false;
private boolean onlyKana = false;
public EntryOptimized(){
}
public String getKanji() {
return kanji;
}
public void setKanji(String kanji) {
this.kanji = kanji;
}
public String getReadings()
{
if (readings == null)
{
return "";
}
return readings;
}
public void setReadings(String readings) {
this.readings = readings;
}
public String getMeanings() {
return meanings;
}
public void setMeanings(String meanings) {
this.meanings = meanings;
}
public String getPos()
{
if (pos == null)
{
return "";
}
return pos;
}
public void setPos(String pos)
{
this.pos = pos;
}
public boolean isOnlyKana() {
return onlyKana;
}
public void setOnlyKana(boolean onlyKana) {
this.onlyKana = onlyKana;
}
public boolean isPrimaryEntry()
{
return primaryEntry;
}
public void setPrimaryEntry(boolean altForm)
{
primaryEntry = altForm;
}
public String getPriorities()
{
if (priorities == null)
{
return "";
}
return priorities;
}
public void setPriorities(String priorities)
{
this.priorities = priorities;
}
public String getDictionary()
{
return dictionary;
}
public void setDictionary(String dictionary)
{
this.dictionary = dictionary;
}
// Sort by kanji length for results
@Override
public int compareTo(EntryOptimized another) {
if (this.kanji.length() > another.getKanji().length()){
return -1;
}
else if (this.kanji.length() == another.getKanji().length()){
return 0;
}
else {
return 1;
}
}
}
================================================
FILE: app/src/main/java/ca/fuwafuwa/kaku/Database/JmDictDatabase/Models/Kanji.java
================================================
package ca.fuwafuwa.kaku.Database.JmDictDatabase.Models;
import com.google.gson.annotations.Expose;
import com.j256.ormlite.dao.ForeignCollection;
import com.j256.ormlite.field.DatabaseField;
import com.j256.ormlite.field.ForeignCollectionField;
import com.j256.ormlite.table.DatabaseTable;
import ca.fuwafuwa.kaku.KakuTools;
/**
* Created by 0xbad1d3a5 on 7/25/2016.
*/
@DatabaseTable
public class Kanji {
@Expose(serialize = false)
public static final String KANJI_FIELD = "kanji";
@Expose(serialize = false)
@DatabaseField(generatedId = true)
private Integer id;
@Expose(serialize = false)
@DatabaseField(foreign = true)
private Entry fkEntry;
@Expose
@DatabaseField
private String kanji;
@Expose
@ForeignCollectionField()
private ForeignCollection<KanjiIrregularity> kanjiIrregularities;
@Expose
@ForeignCollectionField()
private ForeignCollection<KanjiPriority> kanjiPriorities;
public String getKanji() {
return kanji;
}
public void setKanji(String kanji) {
this.kanji = kanji;
}
public Entry getFkEntry() {
return fkEntry;
}
public void setFkEntry(Entry fkEntry) {
this.fkEntry = fkEntry;
}
public ForeignCollection<KanjiIrregularity> getKanjiIrregularities() {
return kanjiIrregularities;
}
public ForeignCollection<KanjiPriority> getKanjiPriorities() {
return kanjiPriorities;
}
@Override
public String toString() {
return KakuTools.toJson(this);
}
}
================================================
FILE: app/src/main/java/ca/fuwafuwa/kaku/Database/JmDictDatabase/Models/KanjiIrregularity.java
================================================
package ca.fuwafuwa.kaku.Database.JmDictDatabase.Models;
import com.google.gson.annotations.Expose;
import com.j256.ormlite.field.DatabaseField;
import com.j256.ormlite.table.DatabaseTable;
import ca.fuwafuwa.kaku.KakuTools;
/**
* Created by 0xbad1d3a5 on 7/25/2016.
*/
@DatabaseTable
public class KanjiIrregularity {
@Expose(serialize = false)
@DatabaseField(generatedId = true)
private Integer id;
@Expose(serialize = false)
@DatabaseField(foreign = true)
private Kanji fkKanji;
@Expose
@DatabaseField
private String kanjiIrregularity;
public String getKanjiIrregularity() {
return kanjiIrregularity;
}
public void setKanjiIrregularity(String kanjiIrregularity) {
this.kanjiIrregularity = kanjiIrregularity;
}
public Kanji getFkKanji() {
return fkKanji;
}
public void setFkKanji(Kanji fkKanji) {
this.fkKanji = fkKanji;
}
@Override
public String toString() {
return KakuTools.toJson(this);
}
}
================================================
FILE: app/src/main/java/ca/fuwafuwa/kaku/Database/JmDictDatabase/Models/KanjiPriority.java
================================================
package ca.fuwafuwa.kaku.Database.JmDictDatabase.Models;
import com.google.gson.annotations.Expose;
import com.j256.ormlite.field.DatabaseField;
import com.j256.ormlite.table.DatabaseTable;
import ca.fuwafuwa.kaku.KakuTools;
/**
* Created by 0xbad1d3a5 on 7/25/2016.
*/
@DatabaseTable
public class KanjiPriority {
@Expose(serialize = false)
@DatabaseField(generatedId = true)
private Integer id;
@Expose(serialize = false)
@DatabaseField(foreign = true)
private Kanji fkKanji;
@Expose
@DatabaseField
private String kanjiPriority;
public String getKanjiPriority() {
return kanjiPriority;
}
public void setKanjiPriority(String kanjiPriority) {
this.kanjiPriority = kanjiPriority;
}
public Kanji getFkKanji() {
return fkKanji;
}
public void setFkKanji(Kanji fkKanji) {
this.fkKanji = fkKanji;
}
@Override
public String toString() {
return KakuTools.toJson(this);
}
}
================================================
FILE: app/src/main/java/ca/fuwafuwa/kaku/Database/JmDictDatabase/Models/Meaning.java
================================================
package ca.fuwafuwa.kaku.Database.JmDictDatabase.Models;
import com.google.gson.annotations.Expose;
import com.j256.ormlite.dao.ForeignCollection;
import com.j256.ormlite.field.DatabaseField;
import com.j256.ormlite.field.ForeignCollectionField;
import com.j256.ormlite.table.DatabaseTable;
import ca.fuwafuwa.kaku.KakuTools;
/**
* Created by 0xbad1d3a5 on 7/25/2016.
*/
@DatabaseTable
public class Meaning {
@Expose(serialize = false)
@DatabaseField(generatedId = true)
private Integer id;
@Expose(serialize = false)
@DatabaseField(foreign = true)
private Entry fkEntry;
@Expose
@ForeignCollectionField()
private ForeignCollection<MeaningKanjiRestriction> kanjiRestrictions;
@Expose
@ForeignCollectionField()
private ForeignCollection<MeaningReadingRestriction> readingRestrictions;
@Expose
@ForeignCollectionField()
private ForeignCollection<MeaningPartOfSpeech> partsOfSpeech;
@Expose
@ForeignCollectionField()
private ForeignCollection<MeaningCrossReference> crossReferences;
@Expose
@ForeignCollectionField()
private ForeignCollection<MeaningAntonym> antonyms;
@Expose
@ForeignCollectionField()
private ForeignCollection<MeaningField> fields;
@Expose
@ForeignCollectionField()
private ForeignCollection<MeaningMisc> miscs;
@Expose
@ForeignCollectionField()
private ForeignCollection<MeaningAdditionalInfo> additionalInfos;
@Expose
@ForeignCollectionField()
private ForeignCollection<MeaningLoanSource> loanSources;
@Expose
@ForeignCollectionField()
private ForeignCollection<MeaningDialect> dialects;
@Expose
@ForeignCollectionField()
private ForeignCollection<MeaningGloss> glosses;
public Entry getFkEntry() {
return fkEntry;
}
public void setFkEntry(Entry fkEntry) {
this.fkEntry = fkEntry;
}
public ForeignCollection<MeaningKanjiRestriction> getKanjiRestrictions() {
return kanjiRestrictions;
}
public ForeignCollection<MeaningReadingRestriction> getReadingRestrictions() {
return readingRestrictions;
}
public ForeignCollection<MeaningPartOfSpeech> getPartsOfSpeech() {
return partsOfSpeech;
}
public ForeignCollection<MeaningCrossReference> getCrossReferences() {
return crossReferences;
}
public ForeignCollection<MeaningAntonym> getAntonyms() {
return antonyms;
}
public ForeignCollection<MeaningField> getFields() {
return fields;
}
public ForeignCollection<MeaningMisc> getMiscs() {
return miscs;
}
public ForeignCollection<MeaningAdditionalInfo> getAdditionalInfos() {
return additionalInfos;
}
public ForeignCollection<MeaningLoanSource> getLoanSources() {
return loanSources;
}
public ForeignCollection<MeaningDialect> getDialects() {
return dialects;
}
public ForeignCollection<MeaningGloss> getGlosses() {
return glosses;
}
@Override
public String toString() {
return KakuTools.toJson(this);
}
}
================================================
FILE: app/src/main/java/ca/fuwafuwa/kaku/Database/JmDictDatabase/Models/MeaningAdditionalInfo.java
================================================
package ca.fuwafuwa.kaku.Database.JmDictDatabase.Models;
import com.google.gson.annotations.Expose;
import com.j256.ormlite.field.DatabaseField;
import com.j256.ormlite.table.DatabaseTable;
import ca.fuwafuwa.kaku.KakuTools;
/**
* Created by 0xbad1d3a5 on 7/25/2016.
*/
@DatabaseTable
public class MeaningAdditionalInfo {
@Expose(serialize = false)
@DatabaseField(generatedId = true)
private Integer id;
@Expose(serialize = false)
@DatabaseField(foreign = true)
private Meaning fkMeaning;
@Expose
@DatabaseField
private String additionalInfo;
public String getAdditionalInfo() {
return additionalInfo;
}
public void setAdditionalInfo(String additionalInfo) {
this.additionalInfo = additionalInfo;
}
public Meaning getFkMeaning() {
return fkMeaning;
}
public void setFkMeaning(Meaning fkMeaning) {
this.fkMeaning = fkMeaning;
}
@Override
public String toString() {
return KakuTools.toJson(this);
}
}
================================================
FILE: app/src/main/java/ca/fuwafuwa/kaku/Database/JmDictDatabase/Models/MeaningAntonym.java
================================================
package ca.fuwafuwa.kaku.Database.JmDictDatabase.Models;
import com.google.gson.annotations.Expose;
import com.j256.ormlite.field.DatabaseField;
import com.j256.ormlite.table.DatabaseTable;
import ca.fuwafuwa.kaku.KakuTools;
/**
* Created by 0xbad1d3a5 on 7/25/2016.
*/
@DatabaseTable
public class MeaningAntonym {
@Expose(serialize = false)
@DatabaseField(generatedId = true)
private Integer id;
@Expose(serialize = false)
@DatabaseField(foreign = true)
private Meaning fkMeaning;
@Expose
@DatabaseField
private String antonym;
public String getAntonym() {
return antonym;
}
public void setAntonym(String antonym) {
this.antonym = antonym;
}
public Meaning getFkMeaning() {
return fkMeaning;
}
public void setFkMeaning(Meaning fkMeaning) {
this.fkMeaning = fkMeaning;
}
@Override
public String toString() {
return KakuTools.toJson(this);
}
}
================================================
FILE: app/src/main/java/ca/fuwafuwa/kaku/Database/JmDictDatabase/Models/MeaningCrossReference.java
================================================
package ca.fuwafuwa.kaku.Database.JmDictDatabase.Models;
import com.google.gson.annotations.Expose;
import com.j256.ormlite.field.DatabaseField;
import com.j256.ormlite.table.DatabaseTable;
import ca.fuwafuwa.kaku.KakuTools;
/**
* Created by 0xbad1d3a5 on 7/25/2016.
*/
@DatabaseTable
public class MeaningCrossReference {
@Expose(serialize = false)
@DatabaseField(generatedId = true)
private Integer id;
@Expose(serialize = false)
@DatabaseField(foreign = true)
private Meaning fkMeaning;
@Expose
@DatabaseField
private String crossReference;
public String getCrossReference() {
return crossReference;
}
public void setCrossReference(String crossReference) {
this.crossReference = crossReference;
}
public Meaning getFkMeaning() {
return fkMeaning;
}
public void setFkMeaning(Meaning fkMeaning) {
this.fkMeaning = fkMeaning;
}
@Override
public String toString() {
return KakuTools.toJson(this);
}
}
================================================
FILE: app/src/main/java/ca/fuwafuwa/kaku/Database/JmDictDatabase/Models/MeaningDialect.java
================================================
package ca.fuwafuwa.kaku.Database.JmDictDatabase.Models;
import com.google.gson.annotations.Expose;
import com.j256.ormlite.field.DatabaseField;
import com.j256.ormlite.table.DatabaseTable;
import ca.fuwafuwa.kaku.KakuTools;
/**
* Created by 0xbad1d3a5 on 7/25/2016.
*/
@DatabaseTable
public class MeaningDialect {
@Expose(serialize = false)
@DatabaseField(generatedId = true)
private Integer id;
@Expose(serialize = false)
@DatabaseField(foreign = true)
private Meaning fkMeaning;
@Expose
@DatabaseField
private String dialect;
public String getDialect() {
return dialect;
}
public void setDialect(String dialect) {
this.dialect = dialect;
}
public Meaning getFkMeaning() {
return fkMeaning;
}
public void setFkMeaning(Meaning fkMeaning) {
this.fkMeaning = fkMeaning;
}
@Override
public String toString() {
return KakuTools.toJson(this);
}
}
================================================
FILE: app/src/main/java/ca/fuwafuwa/kaku/Database/JmDictDatabase/Models/MeaningField.java
================================================
package ca.fuwafuwa.kaku.Database.JmDictDatabase.Models;
import com.google.gson.annotations.Expose;
import com.j256.ormlite.field.DatabaseField;
import com.j256.ormlite.table.DatabaseTable;
import ca.fuwafuwa.kaku.KakuTools;
/**
* Created by 0xbad1d3a5 on 7/25/2016.
*/
@DatabaseTable
public class MeaningField {
@Expose(serialize = false)
@DatabaseField(generatedId = true)
private Integer id;
@Expose(serialize = false)
@DatabaseField(foreign = true)
private Meaning fkMeaning;
@Expose
@DatabaseField
private String field;
public String getField() {
return field;
}
public void setField(String field) {
this.field = field;
}
public Meaning getFkMeaning() {
return fkMeaning;
}
public void setFkMeaning(Meaning fkMeaning) {
this.fkMeaning = fkMeaning;
}
@Override
public String toString() {
return KakuTools.toJson(this);
}
}
================================================
FILE: app/src/main/java/ca/fuwafuwa/kaku/Database/JmDictDatabase/Models/MeaningGloss.java
================================================
package ca.fuwafuwa.kaku.Database.JmDictDatabase.Models;
import com.google.gson.annotations.Expose;
import com.j256.ormlite.field.DatabaseField;
import com.j256.ormlite.table.DatabaseTable;
import ca.fuwafuwa.kaku.KakuTools;
/**
* Created by 0xbad1d3a5 on 7/25/2016.
*/
@DatabaseTable
public class MeaningGloss {
@Expose(serialize = false)
@DatabaseField(generatedId = true)
private Integer id;
@Expose(serialize = false)
@DatabaseField(foreign = true)
private Meaning fkMeaning;
@Expose
@DatabaseField
private String gloss;
@Expose
@DatabaseField
private String lang;
@Expose
@DatabaseField
private String gender;
public String getGloss() {
return gloss;
}
public void setGloss(String gloss) {
this.gloss = gloss;
}
public String getLang() {
return lang;
}
public void setLang(String lang) {
this.lang = lang;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public Meaning getFkMeaning() {
return fkMeaning;
}
public void setFkMeaning(Meaning fkMeaning) {
this.fkMeaning = fkMeaning;
}
@Override
public String toString() {
return KakuTools.toJson(this);
}
}
================================================
FILE: app/src/main/java/ca/fuwafuwa/kaku/Database/JmDictDatabase/Models/MeaningKanjiRestriction.java
================================================
package ca.fuwafuwa.kaku.Database.JmDictDatabase.Models;
import com.google.gson.annotations.Expose;
import com.j256.ormlite.field.DatabaseField;
import com.j256.ormlite.table.DatabaseTable;
import ca.fuwafuwa.kaku.KakuTools;
/**
* Created by 0xbad1d3a5 on 7/25/2016.
*/
@DatabaseTable
public class MeaningKanjiRestriction {
@Expose(serialize = false)
@DatabaseField(generatedId = true)
private Integer id;
@Expose(serialize = false)
@DatabaseField(foreign = true)
private Meaning fkMeaning;
@Expose
@DatabaseField
private String kanjiRestriction;
public String getKanjiRestriction() {
return kanjiRestriction;
}
public void setKanjiRestriction(String kanjiRestriction) {
this.kanjiRestriction = kanjiRestriction;
}
public Meaning getFkMeaning() {
return fkMeaning;
}
public void setFkMeaning(Meaning fkMeaning) {
this.fkMeaning = fkMeaning;
}
@Override
public String toString() {
return KakuTools.toJson(this);
}
}
================================================
FILE: app/src/main/java/ca/fuwafuwa/kaku/Database/JmDictDatabase/Models/MeaningLoanSource.java
================================================
package ca.fuwafuwa.kaku.Database.JmDictDatabase.Models;
import com.google.gson.annotations.Expose;
import com.j256.ormlite.field.DatabaseField;
import com.j256.ormlite.table.DatabaseTable;
import ca.fuwafuwa.kaku.KakuTools;
/**
* Created by 0xbad1d3a5 on 7/25/2016.
*/
@DatabaseTable
public class MeaningLoanSource {
@Expose(serialize = false)
@DatabaseField(generatedId = true)
private Integer id;
@Expose(serialize = false)
@DatabaseField(foreign = true)
private Meaning fkMeaning;
@Expose
@DatabaseField
private String loanSource;
@Expose
@DatabaseField
private String lang;
@Expose
@DatabaseField
private String type;
@Expose
@DatabaseField
private String waseieigo;
public String getLoanSource() {
return loanSource;
}
public void setLoanSource(String loanSource) {
this.loanSource = loanSource;
}
public String getLang() {
return lang;
}
public void setLang(String lang) {
this.lang = lang;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getWaseieigo() {
return waseieigo;
}
public void setWaseieigo(String waseieigo) {
this.waseieigo = waseieigo;
}
public Meaning getFkMeaning() {
return fkMeaning;
}
public void setFkMeaning(Meaning fkMeaning) {
this.fkMeaning = fkMeaning;
}
@Override
public String toString() {
return KakuTools.toJson(this);
}
}
================================================
FILE: app/src/main/java/ca/fuwafuwa/kaku/Database/JmDictDatabase/Models/MeaningMisc.java
================================================
package ca.fuwafuwa.kaku.Database.JmDictDatabase.Models;
import com.google.gson.annotations.Expose;
import com.j256.ormlite.field.DatabaseField;
import com.j256.ormlite.table.DatabaseTable;
import ca.fuwafuwa.kaku.KakuTools;
/**
* Created by 0xbad1d3a5 on 7/25/2016.
*/
@DatabaseTable
public class MeaningMisc {
@Expose(serialize = false)
@DatabaseField(generatedId = true)
private Integer id;
@Expose(serialize = false)
@DatabaseField(foreign = true)
private Meaning fkMeaning;
@Expose
@DatabaseField
private String misc;
public String getMisc() {
return misc;
}
public void setMisc(String misc) {
this.misc = misc;
}
public Meaning getFkMeaning() {
return fkMeaning;
}
public void setFkMeaning(Meaning fkMeaning) {
this.fkMeaning = fkMeaning;
}
@Override
public String toString() {
return KakuTools.toJson(this);
}
}
================================================
FILE: app/src/main/java/ca/fuwafuwa/kaku/Database/JmDictDatabase/Models/MeaningPartOfSpeech.java
================================================
package ca.fuwafuwa.kaku.Database.JmDictDatabase.Models;
import com.google.gson.annotations.Expose;
import com.j256.ormlite.field.DatabaseField;
import com.j256.ormlite.table.DatabaseTable;
import ca.fuwafuwa.kaku.KakuTools;
/**
* Created by 0xbad1d3a5 on 7/25/2016.
*/
@DatabaseTable
public class MeaningPartOfSpeech {
@Expose(serialize = false)
@DatabaseField(generatedId = true)
private Integer id;
@Expose(serialize = false)
@DatabaseField(foreign = true)
private Meaning fkMeaning;
@Expose
@DatabaseField
private String partOfSpeech;
public String getPartOfSpeech() {
return partOfSpeech;
}
public void setPartOfSpeech(String partOfSpeech) {
this.partOfSpeech = partOfSpeech;
}
public Meaning getFkMeaning() {
return fkMeaning;
}
public void setFkMeaning(Meaning fkMeaning) {
this.fkMeaning = fkMeaning;
}
@Override
public String toString() {
return KakuTools.toJson(this);
}
}
================================================
FILE: app/src/main/java/ca/fuwafuwa/kaku/Database/JmDictDatabase/Models/MeaningReadingRestriction.java
================================================
package ca.fuwafuwa.kaku.Database.JmDictDatabase.Models;
import com.google.gson.annotations.Expose;
import com.j256.ormlite.field.DatabaseField;
import com.j256.ormlite.table.DatabaseTable;
import ca.fuwafuwa.kaku.KakuTools;
/**
* Created by 0xbad1d3a5 on 7/25/2016.
*/
@DatabaseTable
public class MeaningReadingRestriction {
@Expose(serialize = false)
@DatabaseField(generatedId = true)
private Integer id;
@Expose(serialize = false)
@DatabaseField(foreign = true)
private Meaning fkMeaning;
@Expose
@DatabaseField
private String readingRestriction;
public String getReadingRestriction() {
return readingRestriction;
}
public void setReadingRestriction(String readingRestriction) {
this.readingRestriction = readingRestriction;
}
public Meaning getFkMeaning() {
return fkMeaning;
}
public void setFkMeaning(Meaning fkMeaning) {
this.fkMeaning = fkMeaning;
}
@Override
public String toString() {
return KakuTools.toJson(this);
}
}
================================================
FILE: app/src/main/java/ca/fuwafuwa/kaku/Database/JmDictDatabase/Models/Reading.java
================================================
package ca.fuwafuwa.kaku.Database.JmDictDatabase.Models;
import com.google.gson.annotations.Expose;
import com.j256.ormlite.dao.ForeignCollection;
import com.j256.ormlite.field.DatabaseField;
import com.j256.ormlite.field.ForeignCollectionField;
import com.j256.ormlite.table.DatabaseTable;
import ca.fuwafuwa.kaku.KakuTools;
/**
* Created by 0xbad1d3a5 on 7/25/2016.
*/
@DatabaseTable
public class Reading {
@Expose(serialize = false)
@DatabaseField(generatedId = true)
private Integer id;
@Expose(serialize = false)
@DatabaseField(foreign = true)
private Entry fkEntry;
@Expose
@DatabaseField
private String reading;
@Expose
@DatabaseField
private String falseReading;
@Expose
@ForeignCollectionField()
private ForeignCollection<ReadingRestriction> readingRestrictions;
@Expose
@ForeignCollectionField()
private ForeignCollection<ReadingIrregularity> readingIrregularities;
@Expose
@ForeignCollectionField()
private ForeignCollection<ReadingPriority> readingPriorities;
public String getReading() {
return reading;
}
public void setReading(String reading) {
this.reading = reading;
}
public String getFalseReading() {
return falseReading;
}
public void setFalseReading(String falseReading) {
this.falseReading = falseReading;
}
public Entry getFkEntry() {
return fkEntry;
}
public void setFkEntry(Entry fkEntry) {
this.fkEntry = fkEntry;
}
public ForeignCollection<ReadingRestriction> getReadingRestrictions() {
return readingRestrictions;
}
public ForeignCollection<ReadingIrregularity> getReadingIrregularities() {
return readingIrregularities;
}
public ForeignCollection<ReadingPriority> getReadingPriorities() {
return readingPriorities;
}
@Override
public String toString() {
return KakuTools.toJson(this);
}
}
================================================
FILE: app/src/main/java/ca/fuwafuwa/kaku/Database/JmDictDatabase/Models/ReadingIrregularity.java
================================================
package ca.fuwafuwa.kaku.Database.JmDictDatabase.Models;
import com.google.gson.annotations.Expose;
import com.j256.ormlite.field.DatabaseField;
import com.j256.ormlite.table.DatabaseTable;
import ca.fuwafuwa.kaku.KakuTools;
/**
* Created by 0xbad1d3a5 on 7/25/2016.
*/
@DatabaseTable
public class ReadingIrregularity {
@Expose(serialize = false)
@DatabaseField(generatedId = true)
private Integer id;
@Expose(serialize = false)
@DatabaseField(foreign = true)
private Reading fkReading;
@Expose
@DatabaseField
private String readingIrregularity;
public String getReadingIrregularity() {
return readingIrregularity;
}
public void setReadingIrregularity(String readingIrregularity) {
this.readingIrregularity = readingIrregularity;
}
public Reading getFkReading() {
return fkReading;
}
public void setFkReading(Reading fkReading) {
this.fkReading = fkReading;
}
@Override
public String toString() {
return KakuTools.toJson(this);
}
}
================================================
FILE: app/src/main/java/ca/fuwafuwa/kaku/Database/JmDictDatabase/Models/ReadingPriority.java
================================================
package ca.fuwafuwa.kaku.Database.JmDictDatabase.Models;
import com.google.gson.annotations.Expose;
import com.j256.ormlite.field.DatabaseField;
import com.j256.ormlite.table.DatabaseTable;
import ca.fuwafuwa.kaku.KakuTools;
/**
* Created by 0xbad1d3a5 on 7/25/2016.
*/
@DatabaseTable
public class ReadingPriority {
@Expose(serialize = false)
@DatabaseField(generatedId = true)
private Integer id;
@Expose(serialize = false)
@DatabaseField(foreign = true)
private Reading fkReading;
@Expose
@DatabaseField
private String readingPriority;
public String getReadingPriority() {
return readingPriority;
}
public void setReadingPriority(String readingPriority) {
this.readingPriority = readingPriority;
}
public Reading getFkReading() {
return fkReading;
}
public void setFkReading(Reading fkReading) {
this.fkReading = fkReading;
}
@Override
public String toString() {
return KakuTools.toJson(this);
}
}
================================================
FILE: app/src/main/java/ca/fuwafuwa/kaku/Database/JmDictDatabase/Models/ReadingRestriction.java
================================================
package ca.fuwafuwa.kaku.Database.JmDictDatabase.Models;
import com.google.gson.annotations.Expose;
import com.j256.ormlite.field.DatabaseField;
import com.j256.ormlite.table.DatabaseTable;
import ca.fuwafuwa.kaku.KakuTools;
/**
* Created by 0xbad1d3a5 on 7/25/2016.
*/
@DatabaseTable
public class ReadingRestriction {
@Expose(serialize = false)
@DatabaseField(generatedId = true)
private Integer id;
@Expose(serialize = false)
@DatabaseField(foreign = true)
private Reading fkReading;
@Expose
@DatabaseField
private String readingRestriction;
public String getReadingRestriction() {
return readingRestriction;
}
public void setReadingRestriction(String readingRestriction) {
this.readingRestriction = readingRestriction;
}
public Reading getFkReading() {
return fkReading;
}
public void setFkReading(Reading fkReading) {
this.fkReading = fkReading;
}
@Override
public String toString() {
return KakuTools.toJson(this);
}
}
================================================
FILE: app/src/main/java/ca/fuwafuwa/kaku/Database/KanjiDict2Database/Kd2DatabaseHelper.java
================================================
package ca.fuwafuwa.kaku.Database.KanjiDict2Database;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import com.j256.ormlite.dao.Dao;
import com.j256.ormlite.support.ConnectionSource;
import com.j256.ormlite.table.TableUtils;
import java.sql.SQLException;
import ca.fuwafuwa.kaku.Constants;
import ca.fuwafuwa.kaku.Database.DatabaseHelper;
import ca.fuwafuwa.kaku.Database.JmDictDatabase.Models.EntryOptimized;
import ca.fuwafuwa.kaku.Database.KanjiDict2Database.Models.CharacterOptimized;
import ca.fuwafuwa.kaku.Exceptions.NotImplementedException;
/**
* Created by 0xbad1d3a5 on 12/1/2016.
*/
public class Kd2DatabaseHelper extends DatabaseHelper {
private static final String DATABASE_NAME = Constants.JMDICT_DATABASE_NAME;
private static final int DATABASE_VERSION = 1;
private static Kd2DatabaseHelper instance;
private Context mContext;
public Kd2DatabaseHelper(Context context){
super(context, String.format("%s/%s", context.getFilesDir().getAbsolutePath(), DATABASE_NAME), null, DATABASE_VERSION);
mContext = context;
}
public static synchronized Kd2DatabaseHelper instance(Context context){
if (instance == null){
instance = new Kd2DatabaseHelper(context);
}
return instance;
}
@Override
public void onCreate(SQLiteDatabase database, ConnectionSource connectionSource) {
try {
TableUtils.createTable(connectionSource, EntryOptimized.class);
}
catch (SQLException e){
e.printStackTrace();
}
}
@Override
public void onUpgrade(SQLiteDatabase database, ConnectionSource connectionSource, int oldVersion, int newVersion) {
throw new NotImplementedException();
}
@Override
public void deleteDatabase() {
//mContext.deleteDatabase(String.format("%s/%s", mContext.getFilesDir().getAbsolutePath(), DATABASE_NAME));
}
@Override
public <T> Dao<T, Integer> getDbDao(Class clazz) throws SQLException {
return getDao(clazz);
}
}
================================================
FILE: app/src/main/java/ca/fuwafuwa/kaku/Database/KanjiDict2Database/Models/CharacterOptimized.java
================================================
package ca.fuwafuwa.kaku.Database.KanjiDict2Database.Models;
import com.google.gson.annotations.Expose;
import com.j256.ormlite.field.DataType;
import com.j256.ormlite.field.DatabaseField;
/**
* Created by 0xbad1d3a5 on 12/3/2016.
*/
public class CharacterOptimized {
@Expose(serialize = false)
@DatabaseField(generatedId = true)
private Integer id;
@Expose
@DatabaseField
private String kanji;
@Expose
@DatabaseField(dataType = DataType.LONG_STRING)
private String onyomi;
@Expose
@DatabaseField(dataType = DataType.LONG_STRING)
private String kunyomi;
@Expose
@DatabaseField(dataType = DataType.LONG_STRING)
private String meaning;
public String getKanji() {
return kanji;
}
public void setKanji(String kanji) {
this.kanji = kanji;
}
public String getOnyomi() {
return onyomi;
}
public void setOnyomi(String onyomi) {
this.onyomi = onyomi;
}
public String getKunyomi() {
return kunyomi;
}
public void setKunyomi(String kunyomi) {
this.kunyomi = kunyomi;
}
public String getMeaning() {
return meaning;
}
public void setMeaning(String meaning) {
this.meaning = meaning;
}
}
================================================
FILE: app/src/main/java/ca/fuwafuwa/kaku/Deinflictor/DeinflectionDTOs.kt
================================================
package ca.fuwafuwa.kaku.Deinflictor
/**
* A RuleGroup is composed of multiple rules that share the same [DeinflectionRule.from] length
*
* @property rules List containing the rules in the RuleGroup
* @property fromLength The [DeinflectionRule.from] length of the RuleGroup
*/
class DeinflectionRuleGroup
{
val rules: ArrayList<DeinflectionRule> = ArrayList()
var fromLength: Int = 0
}
/**
* Data class to represent each rule in deinflect.dat
*
* @property from The inflected form
* @property to The deinflected form
* @property type Bitmask for determining whether to continue processing deinflection.
* This is kinda Japanese black magic and I don't really understand it that well either.
* @property reason Deinflection reason
*/
data class DeinflectionRule(
val from: String,
val to: String,
val type: Int,
val reason: String)
/**
* Class to represent a deinflected word
*
* @property word The deinflected word
* @property type Bitmask for determining whether to continue processing deinflection
* @property reason Deinflection reason
*/
class DeinflectionInfo(
var word: String,
var type: Int,
var reason: String)
================================================
FILE: app/src/main/java/ca/fuwafuwa/kaku/Deinflictor/Deinflector.kt
================================================
package ca.fuwafuwa.kaku.Deinflictor
import android.content.Context
import ca.fuwafuwa.kaku.LangUtils
import java.io.BufferedReader
class Deinflector(context: Context) {
private val _ruleGroups: ArrayList<DeinflectionRuleGroup> = ArrayList()
init
{
loadRules(context.assets.open("deinflect.dat").bufferedReader(Charsets.UTF_8))
}
private fun loadRules(reader: BufferedReader)
{
// Skip header
reader.readLine()
var ruleGroup = DeinflectionRuleGroup()
ruleGroup.fromLength = -1
var ruleReasons: ArrayList<String> = ArrayList()
reader.forEachLine {
var fields: List<String> = it.split("\t")
// Parse reason from file
if (fields.size == 1)
{
ruleReasons.add(fields[0].trim())
}
// Parse rule from file
else if (fields.size == 4)
{
var rule = DeinflectionRule(fields[0].trim(),
fields[1].trim(),
fields[2].trim().toInt(),
ruleReasons.get(fields[3].trim().toInt()))
// Group inflections of the same length together into the same RuleGroup
if (ruleGroup.fromLength != rule.from.length){
ruleGroup = DeinflectionRuleGroup()
ruleGroup.fromLength = rule.from.length
_ruleGroups.add(ruleGroup)
}
ruleGroup.rules.add(rule)
}
}
}
/**
* Gets potential deinflections of an inflected word.
* Does not guarantee that each deinflection is a real word.
*
* Example:
* かった い 1152 (00000000 00000000 00000100 10000000) 14 (past)
* ない る 2308 (00000000 00000000 00001001 00000100) 15 (negative)
*
* Starting word: 食べなかった
*
* 食べなかった
* - 食べない
* - 00000000 00000000 00000000 00000100
* - "< past"
*
* 食べない
* - 食べる
* - 00000000 00000000 00000000 00001001
* - "< negative"
*
* Chain is: ["食べない", "食べる"]
*/
fun getPotentialDeinflections(word: String): List<DeinflectionInfo> {
var text: String = word //LangUtils.ConvertKanatanaToHiragana(word)
// Chain of inflections encountered
var deinfWordChain = ArrayList<DeinflectionInfo>()
deinfWordChain.add(DeinflectionInfo(text, 0xFF, ""))
// Map of possible deinflections to its deinfWordList index
var prevSeenDeinfWords = HashMap<String, Int>()
prevSeenDeinfWords[text] = 0
var currWordChainIndex = 0
do
{
var currDeinflectionInfo: DeinflectionInfo = deinfWordChain.get(currWordChainIndex)
var currWord: String = currDeinflectionInfo.word
for (ruleGroup in _ruleGroups)
{
// Only process RuleGroup if inflected word is longer than the group
if (ruleGroup.fromLength > currWord.length) continue
// Get the last X characters of word so that wordTail is the same length as the RuleGroup
var wordTail: String = currWord.substring(currWord.length - ruleGroup.fromLength)
for (rule in ruleGroup.rules)
{
// Only process rule if wordTail matches a valid inflection rule
// Only process rule if previous word in deinflection chain allows for such a transformation (type does not mask out)
var shouldProcessRule = (currDeinflectionInfo.type and rule.type != 0) && (wordTail == rule.from)
if (!shouldProcessRule) continue
// Inflected words must be at least 2 characters in length
var newWord: String = currWord.substring(0, currWord.length - rule.from.length) + rule.to
if (newWord.length <= 1) continue
// We've seen this deinflection before under a different rule, update type
var prevSeenWordIndex: Int? = prevSeenDeinfWords.get(newWord)
if (prevSeenWordIndex != null)
{
var prevSeenWordType: Int = deinfWordChain[prevSeenWordIndex].type
deinfWordChain[prevSeenWordIndex].type = prevSeenWordType or (rule.type shr 8)
continue
}
// Add new deinflection to the deinflection chain
var newDeinflectedWord = DeinflectionInfo(
newWord,
rule.type shr 8,
if (currDeinflectionInfo.reason.isNotEmpty()) "< ${rule.reason} ${currDeinflectionInfo.reason}" else "< ${rule.reason}"
)
prevSeenDeinfWords[newWord] = deinfWordChain.size
deinfWordChain.add(newDeinflectedWord)
}
}
} while (++currWordChainIndex < deinfWordChain.size)
return deinfWordChain
}
}
================================================
FILE: app/src/main/java/ca/fuwafuwa/kaku/Deinflictor/PosMap.kt
================================================
package ca.fuwafuwa.kaku.Deinflictor
class PosMap {
companion object {
fun GetPosMapVal(pos: String) : String {
return when(pos){
"*" -> "*"
"一般" -> "general"
"形容詞" -> "adjective"
"形容詞・アウオ段" -> "adjective auo-end"
"形容詞・イ段" -> "adjective i-end"
"形容詞・イイ" -> "adjective ii"
"副詞" -> "adverb"
"助動詞" -> "auxiliary verb"
"接続詞" -> "conjunction"
"接続助詞" -> "conjunction particle"
"連体詞" -> "pre-noun adjectival"
"感動詞" -> "interjection"
"名詞" -> "noun"
"助詞" -> "particle"
"格助詞" -> "case-marking particle"
"終助詞" -> "sentence-ending particle"
"副助詞" -> "adverbial particle"
"並立助詞" -> "parallel marker"
"係助詞 " -> "binding particle"
"副助詞/並立助詞/終助詞" -> "adverbial particle/parallel marker/binding particle"
"接頭詞" -> "prefix"
"助数詞" -> "counter suffix"
"動詞" -> "verb"
"代名詞" -> "pronoun"
"固有名詞" -> "proper noun"
"動詞非自立的" -> pos
"形容動詞語幹" -> pos
"副詞可能" -> pos
"ナイ形容詞語幹" -> pos
"助動詞語幹" -> pos
"接続詞的" -> "conjunction-like"
"自立" -> "independent"
"非自立" -> "not independent"
"基本形" -> "basic form"
"文語基本形" -> "classical basic form"
"仮定形" -> "hypothetical form"
"未然形" -> "imperfective form (nai stem)"
"連用形" -> "conjunctive form (masu stem)"
"音便基本形" -> "euphonic change basic form"
"現代基本形" -> "modern basic form"
"基本形-促音便" -> "basic form - nasal sound change"
"未然ヌ接続" -> "before -ta link"
"未然ウ接続" -> "before -u link"
"未然レル接続" -> "before -reru link"
"連用タ接続" -> "continuous -ta link"
"連用テ接続" -> "continuous -te link"
"連用ニ接続" -> "continuous -ni link"
"連用デ接続" -> "continuous -de link"
"連用ゴザイ接続" -> "continuous -gozai link"
"体言接続" -> "uninflected word link"
"ガル接続" -> "-garu link"
"助詞類接続" -> "particle link"
"サ変接続" -> "irregular link"
"名詞接続" -> "noun link"
"形容詞接続" -> "adjective link"
"数接続" -> "number link"
"動詞接続" -> "verb link"
"体言接続特殊" -> "special uninflected word link"
"体言接続特殊2" -> "special uninflected word link 2"
"仮定縮約1" -> "assumed contraction 1"
"仮定縮約2" -> "assumed contraction 2"
"接尾" -> "suffix"
"不変化型" -> "Invariant type"
"未然特殊" -> "before special"
"連語" -> "compound word"
"フィラー" -> pos
"連体化" -> pos
"副詞化" -> pos
"特殊" -> "special"
"特殊・マス" -> "masu"
"特殊・デス" -> "desu"
"特殊・ジャ" -> "jya"
"特殊・タ" -> "ta"
"特殊・タイ" -> "tai"
"特殊・ヌ" -> "nu"
"特殊・ヤ" -> "ya"
"特殊・ナイ" -> "nai"
"特殊・ダ" -> "da"
"命令e" -> "e-command"
"命令i" -> "i-command"
"命令yo" -> "yo-command"
"命令ro" -> "ro-command"
"文語・ベシ" -> "classical beshi"
"文語・マジ" -> "classical maji"
"文語・キ" -> "classical ki"
"文語・ナリ" -> "classical nari"
"文語・ル" -> "classical ru"
"文語・リ" -> "classical ri"
"文語・ケリ" -> "classical keri"
"文語・ゴトシ" -> "classical gotoshi"
"一段" -> "ichidan verb"
"一段・クレル" -> "ichidan verb kureru"
"一段・得ル" -> "ichidan verb eru"
"四段・ハ行" -> "yodan verb ha"
"四段・タ行" -> "yodan verb ta"
"四段・サ行" -> "yodan verb sa"
"四段・バ行" -> "yodan verb ba"
"五段・ラ行特殊" -> pos
"五段・ラ行アル" -> pos
"五段・マ行" -> pos
"五段・サ行" -> pos
"五段・ラ行" -> pos
"五段・ワ行促音便" -> pos
"五段・カ行イ音便" -> pos
"五段・ガ行" -> pos
"五段・バ行" -> pos
"五段・タ行" -> pos
"五段・ナ行" -> pos
"五段・ワ行ウ音便" -> pos
"五段・カ行促音便ユク" -> pos
"五段・カ行促音便" -> pos
"上二・ハ行" -> pos
"上二・ダ行" -> pos
"下二・タ行" -> pos
"下二・ハ行" -> pos
"下二・ガ行" -> pos
"下二・カ行" -> pos
"下二・得" -> pos
"下二・マ行" -> pos
"下二・ダ行" -> pos
"サ変・−ズル" -> pos
"サ変・−スル" -> pos
"カ変・来ル" -> pos
"ラ変" -> pos
"サ変・スル" -> pos
"カ変・クル" -> pos
"縮約" -> pos
"人名" -> pos
"名" -> pos
"姓" -> pos
"数" -> pos
"組織" -> pos
"引用文字列" -> pos
"地域" -> pos
"国" -> pos
"引用" -> pos
"その他" -> pos
"間投" -> pos
"記号" -> pos
"アルファベット" -> pos
"括弧閉" -> pos
"括弧開" -> pos
"読点" -> pos
"句点" -> pos
"空白" -> pos
else -> "UNMAPPED"
};
}
}
}
================================================
FILE: app/src/main/java/ca/fuwafuwa/kaku/Dialogs/FeedbackDialogFragment.kt
================================================
package ca.fuwafuwa.kaku.Dialogs
import android.app.AlertDialog
import android.app.Dialog
import android.content.ActivityNotFoundException
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.widget.Toast
import androidx.fragment.app.DialogFragment
import ca.fuwafuwa.kaku.KAKU_PREF_FILE
import ca.fuwafuwa.kaku.KAKU_PREF_PLAY_STORE_RATED
class FeedbackDialogFragment : DialogFragment()
{
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog
{
return activity?.let {
val builder = AlertDialog.Builder(it)
builder.setTitle("Thanks for your feedback!")
.setMessage("Do you have anything you wish to say to the developer about Kaku? Bugs, feature requests, annoyances, anything goes!")
.setPositiveButton("SEND EMAIL")
{
_, _ ->
run {
val emailIntent = Intent(android.content.Intent.ACTION_SENDTO)
emailIntent.type = "text/plain"
emailIntent.data = Uri.parse("mailto:")
emailIntent.putExtra(android.content.Intent.EXTRA_EMAIL, arrayOf("0xbad1d3a5@gmail.com"))
emailIntent.putExtra(android.content.Intent.EXTRA_SUBJECT, "Kaku Feedback - ${android.os.Build.BRAND + " " + android.os.Build.MODEL}")
startActivity(Intent.createChooser(emailIntent, "Send e-mail using..."))
}
}
.setNegativeButton("CANCEL")
{
_, _ ->
run {
}
}
builder.create()
} ?: throw IllegalStateException("Activity cannot be null")
}
}
================================================
FILE: app/src/main/java/ca/fuwafuwa/kaku/Dialogs/GrantPermissionDialogFragment.kt
================================================
package ca.fuwafuwa.kaku.Dialogs
import android.app.AlertDialog
import android.app.Dialog
import android.content.Context
import android.content.Intent
import android.os.Bundle
import androidx.fragment.app.DialogFragment
import androidx.fragment.app.FragmentActivity
import ca.fuwafuwa.kaku.KAKU_PREF_FILE
import ca.fuwafuwa.kaku.KAKU_PREF_FIRST_LAUNCH
import ca.fuwafuwa.kaku.MainActivity
class GrantPermissionDialogFragment : DialogFragment()
{
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog
{
return activity?.let {
val builder = AlertDialog.Builder(it)
builder.setTitle("Grant Kaku Permissions")
.setMessage("Kaku uses optical character recognition (OCR) to detect text from images and works by automatically taking screenshots of your screen when active. After granting permissions, please restart Kaku.\n\nKaku works completely offline and WILL NEVER transmit ANY user data encountered during usage.")
.setPositiveButton("GRANT")
{
_, _ ->
run {
val prefs = context!!.getSharedPreferences(KAKU_PREF_FILE, Context.MODE_PRIVATE)
prefs.edit().putBoolean(KAKU_PREF_FIRST_LAUNCH, false).apply()
startActivity(Intent(activity, MainActivity::class.java))
(activity as FragmentActivity).finish()
}
}
.setNegativeButton("CANCEL")
{
_, _ ->
run {
}
}
builder.create()
} ?: throw IllegalStateException("Activity cannot be null")
}
}
================================================
FILE: app/src/main/java/ca/fuwafuwa/kaku/Dialogs/PlayStoreRatingDialogFragment.kt
================================================
package ca.fuwafuwa.kaku.Dialogs
import android.app.AlertDialog
import android.app.Dialog
import android.os.Bundle
import androidx.fragment.app.DialogFragment
import android.widget.Toast
import android.content.ActivityNotFoundException
import android.content.Context
import android.content.Intent
import android.net.Uri
import ca.fuwafuwa.kaku.KAKU_PREF_FILE
import ca.fuwafuwa.kaku.KAKU_PREF_PLAY_STORE_RATED
class PlayStoreRatingDialogFragment : DialogFragment()
{
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog
{
return activity?.let {
val builder = AlertDialog.Builder(it)
val prefs = requireContext().getSharedPreferences(KAKU_PREF_FILE, Context.MODE_PRIVATE)
builder.setTitle("Thanks for your feedback!")
.setMessage("Would you like to rate the app in the Play Store? It would mean a lot to me and helps support the app!")
.setPositiveButton("OK")
{
_, _ ->
run {
launchMarket()
prefs.edit().putBoolean(KAKU_PREF_PLAY_STORE_RATED, true).apply()
}
}
.setNegativeButton("NO")
{
_, _ ->
run {
}
}
.setNeutralButton("NEVER ASK AGAIN")
{
_, _ ->
run {
prefs.edit().putBoolean(KAKU_PREF_PLAY_STORE_RATED, true).apply()
}
}
builder.create()
} ?: throw IllegalStateException("Activity cannot be null")
}
private fun launchMarket()
{
val uri = Uri.parse("market://details?id=" + requireActivity().packageName)
val linkToMarket = Intent(Intent.ACTION_VIEW, uri)
try
{
startActivity(linkToMarket)
} catch (e: ActivityNotFoundException)
{
Toast.makeText(requireContext(), "Unable to launch Play Store", Toast.LENGTH_LONG).show()
}
}
}
================================================
FILE: app/src/main/java/ca/fuwafuwa/kaku/Dialogs/StarRatingDialogFragment.kt
================================================
package ca.fuwafuwa.kaku.Dialogs
import android.app.AlertDialog
import android.app.Dialog
import android.content.Context
import android.os.Bundle
import android.widget.TextView
import androidx.fragment.app.DialogFragment
import ca.fuwafuwa.kaku.KAKU_PREF_FILE
import ca.fuwafuwa.kaku.KAKU_PREF_PLAY_STORE_RATED
import ca.fuwafuwa.kaku.R
class StarRatingDialogFragment : DialogFragment()
{
private var rating = 0
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog
{
return activity?.let {
val builder = AlertDialog.Builder(it)
val inflater = requireActivity().layoutInflater;
val view = inflater.inflate(R.layout.dialog_rating_stars, null)
val star1 = view.findViewById<TextView>(R.id.dialog_rating_star1)
val star2 = view.findViewById<TextView>(R.id.dialog_rating_star2)
val star3 = view.findViewById<TextView>(R.id.dialog_rating_star3)
val star4 = view.findViewById<TextView>(R.id.dialog_rating_star4)
val star5 = view.findViewById<TextView>(R.id.dialog_rating_star5)
star1.setOnClickListener {
star1.text = "★"
star2.text = "☆"
star3.text = "☆"
star4.text = "☆"
star5.text = "☆"
rating = 1
}
star2.setOnClickListener {
star1.text = "★"
star2.text = "★"
star3.text = "☆"
star4.text = "☆"
star5.text = "☆"
rating = 2
}
star3.setOnClickListener {
star1.text = "★"
star2.text = "★"
star3.text = "★"
star4.text = "☆"
star5.text = "☆"
rating = 3
}
star4.setOnClickListener {
star1.text = "★"
star2.text = "★"
star3.text = "★"
star4.text = "★"
star5.text = "☆"
rating = 4
}
star5.setOnClickListener {
star1.text = "★"
star2.text = "★"
star3.text = "★"
star4.text = "★"
star5.text = "★"
rating = 5
}
builder.setTitle("What do you think of Kaku?")
.setView(view)
.setPositiveButton("Ok")
{
_, _ ->
run {
if (rating == 5)
{
PlayStoreRatingDialogFragment().show(requireActivity().supportFragmentManager, "PlayStoreRating")
} else
{
val prefs = requireContext().getSharedPreferences(KAKU_PREF_FILE, Context.MODE_PRIVATE)
prefs.edit().putBoolean(KAKU_PREF_PLAY_STORE_RATED, true).apply()
FeedbackDialogFragment().show(requireActivity().supportFragmentManager, "Feedback")
}
}
}
.setNegativeButton("Cancel")
{
_, _ ->
run {
}
}
builder.create()
} ?: throw IllegalStateException("Activity cannot be null")
}
}
================================================
FILE: app/src/main/java/ca/fuwafuwa/kaku/Dialogs/TutorialExplainDialogFragment.kt
================================================
package ca.fuwafuwa.kaku.Dialogs
import android.app.AlertDialog
import android.app.Dialog
import android.os.Bundle
import androidx.fragment.app.DialogFragment
class TutorialExplainDialogFragment : DialogFragment()
{
private lateinit var mTitle : String
private lateinit var mMessage : String
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog
{
mTitle = arguments?.getString(ARG_TITLE)!!
mMessage = arguments?.getString(ARG_MESSAGE)!!
return activity?.let {
val builder = AlertDialog.Builder(it)
builder.setTitle(mTitle)
.setMessage(mMessage)
.setPositiveButton("OK")
{
_, _ ->
run {
}
}
builder.create()
} ?: throw IllegalStateException("Activity cannot be null")
}
companion object
{
private val ARG_TITLE = "arg_title"
private val ARG_MESSAGE = "arg_message"
fun newInstance(title: String, message: String) : TutorialExplainDialogFragment
{
val dialog = TutorialExplainDialogFragment()
val args = Bundle()
args.putString(ARG_TITLE, title)
args.putString(ARG_MESSAGE, message)
dialog.arguments = args
return dialog
}
}
}
================================================
FILE: app/src/main/java/ca/fuwafuwa/kaku/Exceptions/NotImplementedException.java
================================================
package ca.fuwafuwa.kaku.Exceptions;
/**
* Created by 0xbad1d3a5 on 12/1/2016.
*/
public class NotImplementedException extends RuntimeException {
}
================================================
FILE: app/src/main/java/ca/fuwafuwa/kaku/Interfaces/Stoppable.java
================================================
package ca.fuwafuwa.kaku.Interfaces;
/**
* Created by 0xbad1d3a5 on 4/13/2016.
*/
public interface Stoppable {
void stop();
}
================================================
FILE: app/src/main/java/ca/fuwafuwa/kaku/KakuTools.kt
================================================
@file:JvmName("KakuTools")
package ca.fuwafuwa.kaku
import android.content.Context
import android.content.Intent
import android.os.Build
import android.util.DisplayMetrics
import android.util.Log
import android.widget.Toast
import com.google.gson.GsonBuilder
import java.io.File
import java.io.FileOutputStream
import java.lang.Exception
import java.util.ArrayList
private const val TAG = "KakuTools"
private val gson = GsonBuilder().setPrettyPrinting().disableHtmlEscaping().excludeFieldsWithoutExposeAnnotation().create()
enum class TextDirection(val value: Int) {
AUTO(0),
HORIZONTAL(1),
VERTICAL(2);
companion object {
private val values = values();
fun getByValue(value: Int) = values.firstOrNull { it.value == value }
}
}
data class Prefs(val textDirectionSetting: TextDirection,
val imageFilterSetting: Boolean,
val instantModeSetting: Boolean,
val showHideSetting: Boolean);
// NOTE: The defValue here should match the defValue of the BroadcastReceivers, otherwise
// they will be out of sync the first time.
fun getPrefs(context: Context): Prefs
{
val prefs = context.getSharedPreferences(KAKU_PREF_FILE, Context.MODE_PRIVATE)
return Prefs(
TextDirection.valueOf(prefs.getString(KAKU_PREF_TEXT_DIRECTION, TextDirection.AUTO.toString()).toString()),
prefs.getBoolean(KAKU_PREF_IMAGE_FILTER, true),
prefs.getBoolean(KAKU_PREF_INSTANT_MODE, true),
prefs.getBoolean(KAKU_PREF_SHOW_HIDE, true))
}
fun toJson(obj: Any): String
{
return gson.toJson(obj)
}
fun dpToPx(context: Context, dp: Int): Int
{
val displayMetrics = context.resources.displayMetrics
return Math.round(dp * (displayMetrics.xdpi / DisplayMetrics.DENSITY_DEFAULT))
}
fun pxToDp(context: Context, px: Int): Int
{
val displayMetrics = context.resources.displayMetrics
return Math.round(px / (displayMetrics.xdpi / DisplayMetrics.DENSITY_DEFAULT))
}
/**
* Splits `text` into individual unicode characters as a list of strings
* @param text Text to split
* @return List of strings with each string representing one unicode character
*/
fun splitTextByChar(text: String): List<String>
{
val charList = ArrayList<String>()
val length = text.length
var offset = 0
while (offset < length)
{
val curr = text.codePointAt(offset)
val charz = String(intArrayOf(curr), 0, 1)
charList.add(charz)
offset += Character.charCount(curr)
}
return charList
}
fun startKakuService(context: Context, i: Intent)
{
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
{
context.startForegroundService(i)
}
else
{
context.startService(i)
}
}
fun setupKakuDatabasesAndFiles(context: Context)
{
try {
val filesAndPaths = hashMapOf(
JMDICT_DATABASE_NAME to context.filesDir.absolutePath,
TESS_DATA_NAME to "${context.filesDir.absolutePath}/$TESS_FOLDER_NAME")
if (shouldResetData(filesAndPaths))
{
Log.d(TAG, "Resetting Data")
for (fileAndPath in filesAndPaths){
File("${fileAndPath.value}/${fileAndPath.key}").delete()
}
}
copyFilesIfNotExists(context, filesAndPaths)
var screenshotPath: String = context.filesDir.absolutePath + "/$SCREENSHOT_FOLDER_NAME"
createDirIfNotExists(screenshotPath)
deleteScreenshotsOlderThanOneDay(screenshotPath)
}
catch (e: Exception)
{
Toast.makeText(context, "Unable to setup Kaku database", Toast.LENGTH_LONG).show()
return
}
}
fun shouldResetData(filesAndPaths: Map<String, String>) : Boolean
{
for (fileAndPath in filesAndPaths){
if (!File("${fileAndPath.value}/${fileAndPath.key}").exists()) return true
}
return false
}
fun createDirIfNotExists(path: String)
{
val dir = File(path)
if (!dir.exists())
{
dir.mkdirs()
}
}
fun copyFilesIfNotExists(context: Context, filesAndPaths: Map<String, String>)
{
for (fileAndPath in filesAndPaths)
{
val path = fileAndPath.value
val fileName = fileAndPath.key
val filePath = "$path/$fileName"
if (File(filePath).exists())
{
return
}
createDirIfNotExists(path)
val input = context.assets.open(fileName)
val output = FileOutputStream(filePath)
input.copyTo(output);
output.close()
Log.d(TAG, "Copied $filePath")
}
}
fun deleteScreenshotsOlderThanOneDay(path: String)
{
try {
var dir = File(path)
if (dir.exists())
{
Log.d(TAG, dir.absolutePath)
var listFileNames = dir.list()
var purgeTime = System.currentTimeMillis() - 1 * 24 * 60 * 60 * 1000
for (fileName in listFileNames)
{
val file = File(fileName)
if (file.isFile && file.lastModified() < purgeTime)
{
file.delete()
}
}
}
}
catch (e: Exception)
{
Log.d(TAG, e.toString())
}
}
================================================
FILE: app/src/main/java/ca/fuwafuwa/kaku/LangUtils.kt
================================================
package ca.fuwafuwa.kaku
class LangUtils {
companion object {
private val KanaHalf: IntArray = intArrayOf(
0x3092, 0x3041, 0x3043, 0x3045, 0x3047, 0x3049, 0x3083, 0x3085,
0x3087, 0x3063, 0x30FC, 0x3042, 0x3044, 0x3046, 0x3048, 0x304A,
0x304B, 0x304D, 0x304F, 0x3051, 0x3053, 0x3055, 0x3057, 0x3059,
0x305B, 0x305D, 0x305F, 0x3061, 0x3064, 0x3066, 0x3068, 0x306A,
0x306B, 0x306C, 0x306D, 0x306E, 0x306F, 0x3072, 0x3075, 0x3078,
0x307B, 0x307E, 0x307F, 0x3080, 0x3081, 0x3082, 0x3084, 0x3086,
0x3088, 0x3089, 0x308A, 0x308B, 0x308C, 0x308D, 0x308F, 0x3093
)
private val KanaVoiced: IntArray = intArrayOf(
0x30F4, 0xFF74, 0xFF75, 0x304C, 0x304E, 0x3050, 0x3052, 0x3054,
0x3056, 0x3058, 0x305A, 0x305C, 0x305E, 0x3060, 0x3062, 0x3065,
0x3067, 0x3069, 0xFF85, 0xFF86, 0xFF87, 0xFF88, 0xFF89, 0x3070,
0x3073, 0x3076, 0x3079, 0x307C
)
private val KanaSemiVoiced: IntArray = intArrayOf(
0x3071, 0x3074, 0x3077, 0x307A, 0x307D
)
fun IsHiragana(char: Char) : Boolean
{
return Character.UnicodeBlock.of(char) == Character.UnicodeBlock.HIRAGANA
}
fun IsKatakana(char: Char) : Boolean
{
return Character.UnicodeBlock.of(char) == Character.UnicodeBlock.KATAKANA
}
fun IsKanji(char: Char) : Boolean
{
val block = Character.UnicodeBlock.of(char)
return block == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS ||
block == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A ||
block == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_B ||
block == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_C ||
block == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_D
}
fun IsJapaneseChar(char: Char) : Boolean
{
return IsHiragana(char) || IsKatakana(char) || IsKanji(char)
}
fun ConvertKanatanaToHiragana(text: String): String
{
var result: StringBuilder = StringBuilder()
var ordPrev: Int = 0;
for (i in text){
var ordCurr: Int = i.code
// Full-width katakana to hiragana
if ((ordCurr >= 0x30A1) && (ordCurr <= 0x30F3))
{
ordCurr -= 0x60
}
// Half-width katakana to hiragana
else if ((ordCurr >= 0xFF66) && (ordCurr <= 0xFF9D))
{
ordCurr = KanaHalf[ordCurr - 0xFF66]
}
// Voiced (used in half-width katakana) to hiragana
else if (ordCurr == 0xFF9E)
{
if (ordPrev >= 0xFF73 && ordPrev <= 0xFF8E)
{
result.setLength(result.length - 1)
ordCurr = KanaVoiced[ordPrev - 0xFF73]
}
}
// Semi-voiced (used in half-width katakana) to hiragana
else if (ordCurr == 0xFF9F)
{
if (ordPrev >= 0xFF8A && ordPrev <= 0xFF8E)
{
result.setLength(result.length - 1)
ordCurr = KanaSemiVoiced[ordPrev - 0xFF8A]
}
}
// Ignore Japanese ~
else if (ordCurr == 0xFF5E)
{
ordPrev = 0
continue
}
result.append(ordCurr.toChar())
ordPrev = ordCurr
}
return result.toString()
}
fun ConvertIntToCircledNum(num: Int): String
{
var circledNum: String = "($num)"
if (num == 0)
{
circledNum = "⓪"
} else if ((num >= 1) && (num <= 20))
{
circledNum = (('①' - 1) + num).toString()
}
// Note: Numbers over 20 may depend on font
else if ((num >= 21) && (num <= 35))
{
circledNum = (('㉑' - 21) + num).toString()
}
else if ((num >= 36) && (num <= 50))
{
circledNum = (('㊱' - 36) + num).toString()
}
return circledNum
}
}
}
================================================
FILE: app/src/main/java/ca/fuwafuwa/kaku/MainActivity.kt
================================================
package ca.fuwafuwa.kaku
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.content.SharedPreferences
import android.media.projection.MediaProjectionManager
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.os.CountDownTimer
import android.provider.Settings
import android.util.Log
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import ca.fuwafuwa.kaku.Dialogs.StarRatingDialogFragment
class MainActivity : AppCompatActivity()
{
private var mIsActivityVisible = false
private var mShownRating = false
private lateinit var mPrefs : SharedPreferences
private lateinit var mStartKakuIntent: Intent
override fun onCreate(savedInstanceState: Bundle?)
{
super.onCreate(savedInstanceState)
if (isBeta())
{
startActivity(Intent(this, BetaActivity::class.java))
}
mPrefs = getSharedPreferences(KAKU_PREF_FILE, Context.MODE_PRIVATE)
if (isFirstLaunch())
{
startActivity(Intent(this, TutorialActivity::class.java))
finish()
}
else {
supportActionBar?.hide()
setContentView(R.layout.activity_main)
setupKakuDatabasesAndFiles(this)
}
}
override fun onStart()
{
super.onStart()
checkDrawOnTopPermissions()
checkScreenRecordPermissions()
showRatingDialog()
}
override fun onPause()
{
super.onPause()
Log.d(TAG, "ACTIVITY INVISIBLE")
mIsActivityVisible = false
}
override fun onResume()
{
super.onResume()
Log.d(TAG, "ACTIVITY VISIBLE")
mIsActivityVisible = true
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?)
{
Log.d(TAG, "onActivityResult")
val relaunchAppText = "Relaunch Kaku after verifying permission"
if (requestCode == REQUEST_DRAW_ON_TOP)
{
Log.d(TAG, "Recieved ACTION_MANAGE_OVERLAY_PERMISSION Intent")
if (resultCode != Activity.RESULT_OK)
{
Toast.makeText(this, "Check Permission: Draw on Other Apps\n$relaunchAppText", Toast.LENGTH_LONG).show()
finish()
}
return
}
if (requestCode == REQUEST_SCREENSHOT)
{
Log.d(TAG, "Recieved REQUEST_SCREENSHOT Intent")
if (resultCode != Activity.RESULT_OK)
{
Toast.makeText(this, "Check Permission: Record Screen\n$relaunchAppText", Toast.LENGTH_LONG).show()
finish()
}
mStartKakuIntent = Intent(this, MainService::class.java)
.putExtra(EXTRA_PROJECTION_RESULT_CODE, resultCode)
.putExtra(EXTRA_PROJECTION_RESULT_INTENT, data)
return
}
}
fun startKaku(startFragment: MainStartFragment)
{
if (MainService.IsRunning())
{
return
}
if (!mIsActivityVisible)
{
return
}
if (::mStartKakuIntent.isInitialized)
{
startFragment.onKakuLoadStart()
val totalDuration = 2000
object : CountDownTimer(totalDuration.toLong(), 10)
{
override fun onFinish()
{
startFragment.onKakuLoaded()
startKakuService(this@MainActivity, mStartKakuIntent)
}
override fun onTick(millisUntilFinished: Long)
{
}
}.start()
}
else {
Toast.makeText(this, "Unable to start Kaku service", Toast.LENGTH_LONG).show()
}
}
private fun checkDrawOnTopPermissions()
{
var checkPermissions = "Check \"Draw on Top of Other Apps\" permission"
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
{
if (!Settings.canDrawOverlays(this))
{
Log.d(TAG, "Sending ACTION_MANAGE_OVERLAY_PERMISSION Intent")
startActivityForResult(Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:$packageName")), REQUEST_DRAW_ON_TOP)
}
}
else
{
Toast.makeText(this, "Manually $checkPermissions\nKaku might not work on this device", Toast.LENGTH_LONG).show()
}
}
private fun checkScreenRecordPermissions()
{
Log.d(TAG, "Sending REQUEST_SCREENSHOT Intent")
val mediaProjectionManager: MediaProjectionManager? = getSystemService(Context.MEDIA_PROJECTION_SERVICE) as MediaProjectionManager
startActivityForResult(mediaProjectionManager!!.createScreenCaptureIntent(), REQUEST_SCREENSHOT)
}
private fun showRatingDialog()
{
if (mShownRating)
{
return
}
mShownRating = true
val timesLaunched = mPrefs.getInt(KAKU_PREF_TIMES_LAUNCHED, 1)
val rated = mPrefs.getBoolean(KAKU_PREF_PLAY_STORE_RATED, false)
if (timesLaunched % 20 == 0 && !rated)
{
StarRatingDialogFragment().show(supportFragmentManager, "StarRating")
}
}
private fun isFirstLaunch() : Boolean
{
return mPrefs.getBoolean(KAKU_PREF_FIRST_LAUNCH, true)
}
private fun isBeta() : Boolean
{
val CURRENT_PROD_VERSION = 73 // just hardcoded, change when a build is ready to be rolled out to prod
return BuildConfig.VERSION_CODE > CURRENT_PROD_VERSION
}
companion object
{
private val TAG = MainActivity::class.java.name
}
}
================================================
FILE: app/src/main/java/ca/fuwafuwa/kaku/MainService.java
================================================
package ca.fuwafuwa.kaku;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.graphics.PixelFormat;
import android.graphics.Point;
import android.hardware.display.DisplayManager;
import android.hardware.display.VirtualDisplay;
import android.media.Image;
import android.media.ImageReader;
import android.media.projection.MediaProjection;
import android.media.projection.MediaProjectionManager;
import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
import androidx.annotation.RequiresApi;
import androidx.core.app.NotificationCompat;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.Display;
import android.view.WindowManager;
import android.widget.Toast;
import ca.fuwafuwa.kaku.Interfaces.Stoppable;
import ca.fuwafuwa.kaku.Windows.Window;
import ca.fuwafuwa.kaku.Windows.WindowCoordinator;
import static androidx.core.app.NotificationCompat.FLAG_FOREGROUND_SERVICE;
import static androidx.core.app.NotificationCompat.FLAG_ONGOING_EVENT;
/**
* Created by 0xbad1d3a5 on 4/9/2016.
*/
public class MainService extends Service implements Stoppable {
private static final String TAG = MainService.class.getName();
public static class CloseMainService extends BroadcastReceiver
{
@Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "GOT CLOSE");
context.stopService(new Intent(context, MainService.class));
}
}
public static class ToggleImagePreviewMainService extends BroadcastReceiver
{
@Override
public void onReceive(Context context, Intent intent)
{
SharedPreferences prefs = context.getSharedPreferences(Constants.KAKU_PREF_FILE, Context.MODE_PRIVATE);
boolean imagePreview = prefs.getBoolean(Constants.KAKU_PREF_IMAGE_FILTER, true);
prefs.edit().putBoolean(Constants.KAKU_PREF_IMAGE_FILTER, !imagePreview).apply();
KakuTools.startKakuService(context, new Intent(context, MainService.class));
}
}
public static class ToggleShowHideMainService extends BroadcastReceiver
{
@Override
public void onReceive(Context context, Intent intent)
{
SharedPreferences prefs = context.getSharedPreferences(Constants.KAKU_PREF_FILE, Context.MODE_PRIVATE);
boolean shown = prefs.getBoolean(Constants.KAKU_PREF_SHOW_HIDE, true);
prefs.edit().putBoolean(Constants.KAKU_PREF_SHOW_HIDE, !shown).apply();
KakuTools.startKakuService(context, new Intent(context, MainService.class));
}
}
public static class TogglePageModeMainService extends BroadcastReceiver
{
@Override
public void onReceive(Context context, Intent intent)
{
SharedPreferences prefs = context.getSharedPreferences(Constants.KAKU_PREF_FILE, Context.MODE_PRIVATE);
TextDirection textDirection = TextDirection.valueOf(prefs.getString(Constants.KAKU_PREF_TEXT_DIRECTION, TextDirection.AUTO.toString()));
textDirection = TextDirection.Companion.getByValue((textDirection.ordinal() + 1) % 3);
prefs.edit().putString(Constants.KAKU_PREF_TEXT_DIRECTION, textDirection.toString()).apply();
KakuTools.startKakuService(context, new Intent(context, MainService.class));
}
}
public static class ToggleInstantModeMainService extends BroadcastReceiver
{
@Override
public void onReceive(Context context, Intent intent)
{
SharedPreferences prefs = context.getSharedPreferences(Constants.KAKU_PREF_FILE, Context.MODE_PRIVATE);
boolean pageMode = prefs.getBoolean(Constants.KAKU_PREF_INSTANT_MODE, true);
prefs.edit().putBoolean(Constants.KAKU_PREF_INSTANT_MODE, !pageMode).apply();
KakuTools.startKakuService(context, new Intent(context, MainService.class));
}
}
public static class ScreenOffReceiver extends BroadcastReceiver
{
@Override
public void onReceive(Context context, Intent intent)
{
SharedPreferences prefs = context.getSharedPreferences(Constants.KAKU_PREF_FILE, Context.MODE_PRIVATE);
prefs.edit().putBoolean(Constants.KAKU_PREF_SHOW_HIDE, false).apply();
KakuTools.startKakuService(context, new Intent(context, MainService.class));
}
}
private class MediaProjectionStopCallback extends MediaProjection.Callback{
@Override
public void onStop(){
Log.d(TAG, "Stopping projection");
mHandler.post(new Runnable() {
@Override
public void run() {
if (MediaProjectionStopCallback.this == mMediaProjectionStopCallback){
if (mVirtualDisplay != null){
mVirtualDisplay.release();
}
mMediaProjection.unregisterCallback(MediaProjectionStopCallback.this);
mMediaProjection = null;
mImageReader.close();
}
}
});
}
}
private static boolean isKakuRunning = false;
private static final int VIRTUAL_DISPLAY_FLAGS = DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY | DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC;
private static final int NOTIFICATION_ID = 1;
private IntentFilter mIntentFilter = new IntentFilter(Intent.ACTION_SCREEN_OFF);
private ScreenOffReceiver mScreenOffReceiver = new ScreenOffReceiver();
private Intent mProjectionResultIntent;
private int mProjectionResultCode;
private WindowManager mWindowManager;
private MediaProjectionManager mMediaProjectionManager;
private MediaProjection mMediaProjection;
private ImageReader mImageReader;
private Display mDisplay;
private VirtualDisplay mVirtualDisplay;
private MainServiceHandler mHandler;
private int mRotation;
private Point mRealDisplaySize = new Point();
private MediaProjectionStopCallback mMediaProjectionStopCallback;
private WindowCoordinator mWindowCoordinator = new WindowCoordinator(this);
@Override
public IBinder onBind(Intent intent)
{
// Not used
return null;
}
@Override
public void onCreate()
{
super.onCreate();
if (!isKakuRunning)
{
SharedPreferences prefs = getSharedPreferences(Constants.KAKU_PREF_FILE, Context.MODE_PRIVATE);
prefs.edit().putBoolean(Constants.KAKU_PREF_SHOW_HIDE, true).apply();
}
Log.d(TAG, "CREATING MAINSERVICE: " + System.identityHashCode(this));
Toast.makeText(this, "Starting capture window...", Toast.LENGTH_LONG).show();
mMediaProjectionManager = (MediaProjectionManager) getSystemService(MEDIA_PROJECTION_SERVICE);
mHandler = new MainServiceHandler(this, mWindowCoordinator);
// Set preferences for ratings
SharedPreferences prefs = getSharedPreferences(Constants.KAKU_PREF_FILE, Context.MODE_PRIVATE);
int timesLaunched = prefs.getInt(Constants.KAKU_PREF_TIMES_LAUNCHED, 1);
prefs.edit().putInt(Constants.KAKU_PREF_TIMES_LAUNCHED, timesLaunched + 1).apply();
registerReceiver(mScreenOffReceiver, mIntentFilter);
startForeground(NOTIFICATION_ID, getNotification());
isKakuRunning = true;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId)
{
Log.d(TAG, "onStartCommand");
if (intent.getExtras() != null &&
intent.getExtras().containsKey(Constants.EXTRA_PROJECTION_RESULT_CODE) &&
intent.getExtras().containsKey(Constants.EXTRA_PROJECTION_RESULT_INTENT))
{
mProjectionResultIntent = (Intent) intent.getExtras().get(Constants.EXTRA_PROJECTION_RESULT_INTENT);
mProjectionResultCode = intent.getExtras().getInt(Constants.EXTRA_PROJECTION_RESULT_CODE);
}
// Determine if we need to start/stop the capture service
SharedPreferences prefs = getSharedPreferences(Constants.KAKU_PREF_FILE, Context.MODE_PRIVATE);
Boolean shown = prefs.getBoolean(Constants.KAKU_PREF_SHOW_HIDE, true);
if (shown)
{
// Re-init CaptureWindow as well as prefs may have changed (BroadcastReceiver go to onStartCommand())
mWindowCoordinator.getWindow(Constants.WINDOW_CAPTURE).reInit(new Window.ReinitOptions());
}
else
{
mWindowCoordinator.stopAllWindows();
stop();
}
// Set notification text
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(NOTIFICATION_ID, getNotification());
return START_NOT_STICKY;
}
@Override
public void onConfigurationChanged(Configuration newConfig)
{
super.onConfigurationChanged(newConfig);
if (mWindowCoordinator.hasWindow(Constants.WINDOW_CAPTURE))
{
final int rotation = mDisplay.getRotation();
if (rotation != mRotation)
{
Log.d(TAG, "Orientation changed");
mRotation = rotation;
createVirtualDisplay();
mWindowCoordinator.reinitAllWindows();
}
}
}
@Override
public void onDestroy()
{
unregisterReceiver(mScreenOffReceiver);
stopForeground(true);
Log.d(TAG, "DESTORYING MAINSERVICE: " + System.identityHashCode(this));
stop();
mWindowCoordinator.stopAllWindows();
mWindowCoordinator = null;
isKakuRunning = false;
Log.d(TAG, String.format("MAINSERVICE: %s DESTROYED", System.identityHashCode(this)));
super.onDestroy();
}
@Override
public void stop()
{
if (mMediaProjection != null)
{
mMediaProjection.stop();
}
}
public static boolean IsRunning()
{
return isKakuRunning;
}
/**
* This function is here as a bug fix against {@link #onConfigurationChanged(Configuration)} not
* triggering when the app is first started and immediately switches to another orientation. In
* such a case onConfigurationChanged will not trigger and {@link Window#reInit(ca.fuwafuwa.kaku.Windows.Window.ReinitOptions)} will not
* update the LayoutParams.
*/
public void onCaptureWindowFinishedInitializing()
{
if (mMediaProjection == null){
Log.d(TAG, "mMediaProjection is null");
mMediaProjection = mMediaProjectionManager.getMediaProjection(mProjectionResultCode, mProjectionResultIntent);
mMediaProjectionStopCallback = new MediaProjectionStopCallback();
mMediaProjection.registerCallback(mMediaProjectionStopCallback, mHandler);
}
createVirtualDisplay();
}
public Handler getHandler()
{
return mHandler;
}
public Image getScreenshot() throws InterruptedException
{
long startTime = System.nanoTime();
Image image = mImageReader.acquireLatestImage();
while (image == null && System.nanoTime() < startTime + 2000000000){
Thread.sleep(20);
image = mImageReader.acquireLatestImage();
}
return image;
}
private Notification getNotification()
{
String channelId;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
channelId = createNotificationChannel();
}
else {
channelId = "";
}
PendingIntent toggleShowHide = PendingIntent.getBroadcast(this, Constants.REQUEST_SERVICE_TOGGLE_SHOW_HIDE, new Intent(this, ToggleShowHideMainService.class), PendingIntent.FLAG_IMMUTABLE);
PendingIntent toggleImagePreview = PendingIntent.getBroadcast(this, Constants.REQUEST_SERVICE_TOGGLE_IMAGE_PREVIEW, new Intent(this, ToggleImagePreviewMainService.class), PendingIntent.FLAG_IMMUTABLE);
PendingIntent togglePageMode = PendingIntent.getBroadcast(this, Constants.REQUEST_SERVICE_TOGGLE_PAGE_MODE, new Intent(this, TogglePageModeMainService.class), PendingIntent.FLAG_IMMUTABLE);
PendingIntent toggleInstantMode = PendingIntent.getBroadcast(this, Constants.REQUEST_SERVICE_TOGGLE_INSTANT_MODE, new Intent(this, ToggleInstantModeMainService.class), PendingIntent.FLAG_IMMUTABLE);
PendingIntent closeMainService = PendingIntent.getBroadcast(this, Constants.REQUEST_SERVICE_SHUTDOWN, new Intent(this, CloseMainService.class), PendingIntent.FLAG_IMMUTABLE);
Prefs prefs = KakuTools.getPrefs(this);
String contentTitle = "Kaku";
switch (prefs.getTextDirectionSetting())
{
case AUTO:
contentTitle = "Kaku is determining text direction automatically";
break;
case VERTICAL:
contentTitle = "Kaku is reading text vertically";
break;
case HORIZONTAL:
contentTitle = "Kaku is reading text horizontally";
break;
}
Notification n;
if (prefs.getShowHideSetting())
{
n = new NotificationCompat.Builder(this, channelId)
.setSmallIcon(R.drawable.kaku_notification_icon)
.setContentTitle(contentTitle)
.setContentText(String.format("Instant mode %s, black and white filter %s", prefs.getInstantModeSetting() ? "on" : "off", prefs.getImageFilterSetting() ? "on" : "off"))
.setContentIntent(toggleShowHide)
.addAction(0, "Instant Mode", toggleInstantMode)
.addAction(0, "Image Filter", toggleImagePreview)
.addAction(0, "Shutdown", closeMainService)
.build();
}
else {
n = new NotificationCompat.Builder(this, channelId)
.setSmallIcon(R.drawable.kaku_notification_icon)
.setContentTitle("Kaku is hidden and in power-saving mode")
.setContentIntent(toggleShowHide)
.build();
}
n.flags = FLAG_ONGOING_EVENT | FLAG_FOREGROUND_SERVICE;
return n;
}
private void createVirtualDisplay()
{
// display metrics
mWindowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
DisplayMetrics metrics = getResources().getDisplayMetrics();
int mDensity = metrics.densityDpi;
mDisplay = mWindowManager.getDefaultDisplay();
// get width and height
mDisplay.getRealSize(mRealDisplaySize);
// start capture reader
Log.d(TAG, String.format("Starting Projection: %dx%d", mRealDisplaySize.x, mRealDisplaySize.y));
if (mVirtualDisplay != null){
mVirtualDisplay.release();
}
mImageReader = ImageReader.newInstance(mRealDisplaySize.x, mRealDisplaySize.y, PixelFormat.RGBA_8888, 2); // TODO: Something causing a NRE here
mVirtualDisplay = mMediaProjection.createVirtualDisplay(getClass().getName(), mRealDisplaySize.x, mRealDisplaySize.y, mDensity, VIRTUAL_DISPLAY_FLAGS, mImageReader.getSurface(), null, mHandler);
}
@RequiresApi(Build.VERSION_CODES.O)
private String createNotificationChannel()
{
String channelId = Constants.KAKU_CHANNEL_ID;
String channelName = Constants.KAKU_CHANNEL_NAME;
NotificationChannel channel = new NotificationChannel(channelId, channelName, NotificationManager.IMPORTANCE_LOW);
NotificationManager service = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
service.createNotificationChannel(channel);
return channelId;
}
}
================================================
FILE: app/src/main/java/ca/fuwafuwa/kaku/MainServiceHandler.java
================================================
package ca.fuwafuwa.kaku;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.widget.Toast;
import ca.fuwafuwa.kaku.Ocr.OcrResult;
import ca.fuwafuwa.kaku.Windows.InformationWindow;
import ca.fuwafuwa.kaku.Windows.InstantKanjiWindow;
import ca.fuwafuwa.kaku.Windows.WindowCoordinator;
/**
* Created by 0xbad1d3a5 on 4/15/2016.
*/
public class MainServiceHandler extends Handler {
private static final String TAG = MainServiceHandler.class.getName();
private MainService mKakuService;
private WindowCoordinator mWindowCoordinator;
public MainServiceHandler(MainService mainService, WindowCoordinator windowCoordinator)
{
mKakuService = mainService;
mWindowCoordinator = windowCoordinator;
}
@Override
public void handleMessage(Message message)
{
if (message.obj instanceof String){
Toast.makeText(mKakuService, message.obj.toString(), Toast.LENGTH_SHORT).show();
}
else if (message.obj instanceof OcrResult)
{
OcrResult result = (OcrResult) message.obj;
Log.d(TAG, result.toString());
if (result.getDisplayData().getInstantMode())
{
InstantKanjiWindow instantKanjiWindow = mWindowCoordinator.getWindowOfType(Constants.WINDOW_INSTANT_KANJI);
instantKanjiWindow.setResult(result.getDisplayData());
instantKanjiWindow.show();
}
else {
InformationWindow infoWindow = mWindowCoordinator.getWindowOfType(Constants.WINDOW_INFO);
infoWindow.setResult(result.getDisplayData());
infoWindow.show();
}
}
else {
Toast.makeText(mKakuService, String.format("Unable to handle type: %s", message.obj.getClass().getName()), Toast.LENGTH_SHORT).show();
}
}
}
================================================
FILE: app/src/main/java/ca/fuwafuwa/kaku/MainStartFragment.kt
================================================
package ca.fuwafuwa.kaku
import android.content.Context
import android.content.Intent
import android.graphics.BitmapFactory
import android.net.ConnectivityManager
import android.net.NetworkInfo
import android.net.Uri
import android.os.Bundle
import android.text.SpannableStringBuilder
import android.text.Spanned
import android.text.TextPaint
import android.text.method.LinkMovementMethod
import android.text.style.ClickableSpan
import android.util.TypedValue
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.ProgressBar
import android.widget.TextView
import androidx.core.content.ContextCompat
import androidx.fragment.app.Fragment
import com.google.android.gms.ads.*
import java.util.*
data class ImgData(val res: Int, val name: String, val nameLink: String, val imgLink: String, val hasImg: Boolean = true)
class MainStartFragment : Fragment()
{
private lateinit var mainActivity : MainActivity
private lateinit var rootView : View
private lateinit var kakuLogo : TextView
private lateinit var kakuTitle : TextView
private lateinit var tutorialText : TextView
private lateinit var githubText : TextView
private lateinit var supportText : TextView
private lateinit var progressBar : ProgressBar
private lateinit var promoView : ViewGroup
private lateinit var adView : AdView
private lateinit var saeView : ImageView
private lateinit var imgData : ImgData
private var showAds = false
override fun onCreate(savedInstanceState: Bundle?)
{
super.onCreate(savedInstanceState)
// Switch off deprecated network API
val cm = requireActivity().getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
val activeNetwork: NetworkInfo? = cm.activeNetworkInfo
val adsEnabled = false
val internetEnabled = activeNetwork?.isConnectedOrConnecting == true
showAds = adsEnabled && internetEnabled
if (showAds)
{
MobileAds.initialize(requireActivity())
}
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View?
{
mainActivity = activity as MainActivity
rootView = inflater.inflate(R.layout.fragment_start, container, false)
kakuLogo = rootView.findViewById(R.id.kaku_logo)
kakuTitle = rootView.findViewById(R.id.kaku_title)
tutorialText = rootView.findViewById(R.id.kaku_tutorial)
githubText = rootView.findViewById(R.id.kaku_github)
supportText = rootView.findViewById(R.id.support_text)
progressBar = rootView.findViewById(R.id.progress_bar)
promoView = rootView.findViewById(R.id.promoView)
adView = rootView.findViewById(R.id.adView)
saeView = rootView.findViewById(R.id.saeView)
configureBottomPromo(showAds)
tutorialText.setOnClickListener {
startActivity(Intent(mainActivity, TutorialActivity::class.java))
}
githubText.setOnClickListener {
val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse("https://github.com/0xbad1d3a5/Kaku"))
startActivity(browserIntent)
}
return rootView
}
override fun onStart()
{
super.onStart()
supportText.viewTreeObserver.addOnGlobalLayoutListener {
var pos = IntArray(2)
supportText.getLocationInWindow(pos)
val drawableHeight = rootView.height - pos[1] - dpToPx(mainActivity, 30)
val logoSize = drawableHeight.toFloat() / 2
val titleSize = logoSize / 5
val textSize = titleSize / 2
kakuLogo.setTextSize(TypedValue.COMPLEX_UNIT_PX, logoSize)
kakuTitle.setTextSize(TypedValue.COMPLEX_UNIT_PX, titleSize)
tutorialText.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize)
supportText.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize)
}
}
override fun onResume()
{
super.onResume()
if (showAds)
{
val adRequest = AdRequest.Builder().build()
adView.loadAd(adRequest)
}
if (!MainService.IsRunning())
{
onKakuLoadStart()
}
Timer().schedule(object : TimerTask()
{
override fun run()
{
mainActivity.runOnUiThread {
mainActivity.startKaku(this@MainStartFragment)
}
}
}, 3000)
}
fun onKakuLoadStart()
{
progressBar.isIndeterminate = true
progressBar.progress = 0
supportText.text = getString(R.string.kaku_loading)
}
fun onKakuLoaded()
{
progressBar.isIndeterminate = false
progressBar.progress = 100
writeSupportText()
}
private fun configureBottomPromo(adsEnabled: Boolean)
{
if (adsEnabled)
{
promoView.removeView(saeView)
setupAds()
}
else
{
promoView.removeView(adView)
setupImage()
}
if (MainService.IsRunning())
{
onKakuLoaded()
}
}
private fun setupAds()
{
adView.adListener = object: AdListener()
{
override fun onAdLoaded()
{
super.onAdLoaded()
mainActivity.startKaku(this@MainStartFragment)
}
override fun onAdFailedToLoad(p0: LoadAdError) {
super.onAdFailedToLoad(p0)
mainActivity.startKaku(this@MainStartFragment)
}
}
}
private fun setupImage()
{
imgData = getImageResources()
if (imgData.hasImg)
{
saeView.setImageBitmap(BitmapFactory.decodeStream(resources.openRawResource(imgData.res)))
saeView.setOnClickListener {
val i = Intent(Intent.ACTION_VIEW)
i.data = Uri.parse(imgData.imgLink)
startActivity(i)
}
}
}
private fun getImageResources(): ImgData
{
val imgs = listOf(
ImgData(R.raw.sae0001, "@ultonesan", "https://twitter.com/ultonesan", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=62885659"),
ImgData(R.raw.sae0002, "@ultonesan", "https://twitter.com/ultonesan", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=68641857"),
ImgData(R.raw.sae0003, "@ultonesan", "https://twitter.com/ultonesan", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=71950613"),
ImgData(R.raw.sae0021, "@ultonesan", "https://twitter.com/ultonesan", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=73297155"),
ImgData(R.raw.sae0044, "@ultonesan", "https://twitter.com/ultonesan", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=60987977"),
ImgData(R.raw.sae0004, "@yamoyamo18", "https://twitter.com/yamoyamo18", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=73628894"),
ImgData(R.raw.sae0005, "@yamoyamo18", "https://twitter.com/yamoyamo18", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=72424727"),
ImgData(R.raw.sae0009, "@yamoyamo18", "https://twitter.com/yamoyamo18", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=72008999"),
ImgData(R.raw.sae0016, "@yamoyamo18", "https://twitter.com/yamoyamo18", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=66871255"),
ImgData(R.raw.sae0022, "@yamoyamo18", "https://twitter.com/yamoyamo18", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=72822939"),
ImgData(R.raw.sae0023, "@yamoyamo18", "https://twitter.com/yamoyamo18", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=71623460"),
ImgData(R.raw.sae0024, "@yamoyamo18", "https://twitter.com/yamoyamo18", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=71994817"),
ImgData(R.raw.sae0025, "@yamoyamo18", "https://twitter.com/yamoyamo18", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=73311041"),
ImgData(R.raw.sae0026, "@yamoyamo18", "https://twitter.com/yamoyamo18", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=73166793"),
ImgData(R.raw.sae0027, "@yamoyamo18", "https://twitter.com/yamoyamo18", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=73056502"),
ImgData(R.raw.sae0028, "@yamoyamo18", "https://twitter.com/yamoyamo18", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=71894148"),
ImgData(R.raw.sae0029, "@yamoyamo18", "https://twitter.com/yamoyamo18", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=71741734"),
ImgData(R.raw.sae0030, "@yamoyamo18", "https://twitter.com/yamoyamo18", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=71550295"),
ImgData(R.raw.sae0006, "@Sutoroa_", "https://twitter.com/Sutoroa_", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=72284325"),
ImgData(R.raw.sae0098, "@Sutoroa_", "https://twitter.com/Sutoroa_", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=73191911"),
ImgData(R.raw.sae0007, "栗羊", "https://www.pixiv.net/member.php?id=7231087", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=70943811"),
ImgData(R.raw.sae0008, "fevri", "https://www.pixiv.net/member.php?id=23625153", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=71230492"),
ImgData(R.raw.sae0010, "@ultimate_force6", "https://twitter.com/ultimate_force6", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=68200934"),
ImgData(R.raw.sae0019, "@ultimate_force6", "https://twitter.com/ultimate_force6", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=65491060"),
ImgData(R.raw.sae0020, "@ultimate_force6", "https://twitter.com/ultimate_force6", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=71977064"),
ImgData(R.raw.sae0057, "@ultimate_force6", "https://twitter.com/ultimate_force6", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=74363079"),
ImgData(R.raw.sae0011, "@RomanticGACHA", "https://twitter.com/RomanticGACHA", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=71885557"),
ImgData(R.raw.sae0013, "ちゅんこ", "https://www.pixiv.net/member.php?id=15933874", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=70193706"),
ImgData(R.raw.sae0014, "ちゅんこ", "https://www.pixiv.net/member.php?id=15933874", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=69105225"),
ImgData(R.raw.sae0015, "ちゅんこ", "https://www.pixiv.net/member.php?id=15933874", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=64939768"),
ImgData(R.raw.sae0065, "ちゅんこ", "https://www.pixiv.net/member.php?id=15933874", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=57615504"),
ImgData(R.raw.sae0066, "ちゅんこ", "https://www.pixiv.net/member.php?id=15933874", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=57126244"),
ImgData(R.raw.sae0067, "ちゅんこ", "https://www.pixiv.net/member.php?id=15933874", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=57126244"),
ImgData(R.raw.sae0068, "ちゅんこ", "https://www.pixiv.net/member.php?id=15933874", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=62991879"),
ImgData(R.raw.sae0075, "ちゅんこ", "https://www.pixiv.net/member.php?id=15933874", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=59695678"),
ImgData(R.raw.sae0076, "ちゅんこ", "https://www.pixiv.net/member.php?id=15933874", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=59695678"),
ImgData(R.raw.sae0096, "ちゅんこ", "https://www.pixiv.net/member.php?id=15933874", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=73671294"),
ImgData(R.raw.sae0097, "ちゅんこ", "https://www.pixiv.net/member.php?id=15933874", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=73262536"),
ImgData(R.raw.sae0103, "ちゅんこ", "https://www.pixiv.net/member.php?id=15933874", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=59882410"),
ImgData(R.raw.sae0017, "@kusanosinta", "https://twitter.com/kusanosinta", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=66630846"),
ImgData(R.raw.sae0018, "@jksh5056", "https://twitter.com/jksh5056", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=66503611"),
ImgData(R.raw.sae0012, "@syounenkross", "https://twitter.com/syounenkross", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=64177621"),
ImgData(R.raw.sae0031, "@Nb_mk2", "https://twitter.com/Nb_mk2", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=63674704"),
ImgData(R.raw.sae0032, "@Hachita888", "https://twitter.com/Hachita888", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=68277697"),
ImgData(R.raw.sae0033, "@Hachita888", "https://twitter.com/Hachita888", "https://twitter.com/Hachita888/status/1101056129159749632"),
ImgData(R.raw.sae0034, "Toffee", "https://www.pixiv.net/member.php?id=13274275", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=62893744"),
ImgData(R.raw.sae0035, "@N1__03", "https://twitter.com/N1__03", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=63248104"),
ImgData(R.raw.sae0036, "@yu_hi0420", "https://twitter.com/yu_hi0420", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=60998374"),
ImgData(R.raw.sae0037, "@nike_abc", "https://twitter.com/nike_abc", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=63199962"),
ImgData(R.raw.sae0038, "iwawo", "https://www.pixiv.net/member.php?id=1926865", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=62945449"),
ImgData(R.raw.sae0039, "tamamooon", "https://www.pixiv.net/member.php?id=3796056", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=62176436"),
ImgData(R.raw.sae0040, "Ametama", "https://www.pixiv.net/member.php?id=10122880", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=61738328"),
ImgData(R.raw.sae0041, "@2cFirefly", "https://twitter.com/2cFirefly", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=61109132"),
ImgData(R.raw.sae0042, "LP", "https://www.pixiv.net/member.php?id=9774145", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=60911262"),
ImgData(R.raw.sae0043, "@haikimono", "https://twitter.com/haikimono", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=60871513"),
ImgData(R.raw.sae0045, "@xx__lotus", "https://twitter.com/xx__lotus", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=60860221"),
ImgData(R.raw.sae0046, "@kamonabe_44", "https://twitter.com/kamonabe_44", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=60254903"),
ImgData(R.raw.sae0047, "@Yunagi_Amane", "https://twitter.com/Yunagi_Amane", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=60128230"),
ImgData(R.raw.sae0048, "@Azmo_dan", "https://twitter.com/Azmo_dan", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=59980990"),
ImgData(R.raw.sae0049, "@takeashiro", "https://twitter.com/takeashiro", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=59770209"),
ImgData(R.raw.sae0050, "@watanseru", "https://twitter.com/watanseru", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=59521673"),
ImgData(R.raw.sae0051, "@gin_no_te", "https://twitter.com/gin_no_te", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=59907147"),
ImgData(R.raw.sae0052, "miazi", "https://www.pixiv.net/member.php?id=2551745", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=59536025"),
ImgData(R.raw.sae0053, "ちゅんこ", "https://www.pixiv.net/member.php?id=15933874", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=59420528"),
ImgData(R.raw.sae0054, "@shiredo326", "https://twitter.com/shiredo326", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=59213920"),
ImgData(R.raw.sae0055, "@kashinoshishi", "https://twitter.com/kashinoshishi", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=59283209"),
ImgData(R.raw.sae0056, "@xxSuite_Peexx", "https://twitter.com/xxSuite_Peexx", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=74367771"),
ImgData(R.raw.sae0058, "@minami_nyan", "https://twitter.com/minami_nyan", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=59145679"),
ImgData(R.raw.sae0059, "@magchomp8", "https://twitter.com/magchomp8", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=58950389"),
ImgData(R.raw.sae0060, "みなみ茶哂", "https://www.pixiv.net/member.php?id=4939449", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=58574011"),
ImgData(R.raw.sae0061, "@k_nishiwaki", "https://twitter.com/k_nishiwaki", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=58034287"),
ImgData(R.raw.sae0062, "Koji", "https://www.pixiv.net/member.php?id=19228899", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=57976156"),
ImgData(R.raw.sae0063, "@P_KiGiSi", "https://twitter.com/P_KiGiSi", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=57758102"),
ImgData(R.raw.sae0064, "@TakahashiMitama", "https://twitter.com/Takahashimitama", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=63206782"),
ImgData(R.raw.sae0069, "有河サトル", "https://www.pixiv.net/member.php?id=28781", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=53882354"),
ImgData(R.raw.sae0072, "有河サトル", "https://www.pixiv.net/member.php?id=28781", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=54029940"),
ImgData(R.raw.sae0070, "@25irohaxx", "https://twitter.com/25irohaxx", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=59642129"),
ImgData(R.raw.sae0071, "@pizzasi7", "https://twitter.com/pizzasi7", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=59989777"),
ImgData(R.raw.sae0073, "@frenchmaid_", "https://twitter.com/frenchmaid_", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=53105182"),
ImgData(R.raw.sae0074, "P-", "https://www.pixiv.net/member.php?id=1032188", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=51178608"),
ImgData(R.raw.sae0077, "P-", "https://www.pixiv.net/member.php?id=1032188", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=51344144"),
ImgData(R.raw.sae0106, "P-", "https://www.pixiv.net/member.php?id=1032188", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=57042341"),
ImgData(R.raw.sae0078, "@__KFR", "https://twitter.com/__KFR", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=49375938"),
ImgData(R.raw.sae0079, "AGG", "https://www.pixiv.net/member.php?id=12310765", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=49664984"),
ImgData(R.raw.sae0080, "みじんこうか", "https://www.pixiv.net/member.php?id=770137", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=47906259"),
ImgData(R.raw.sae0081, "@mazakaaaan", "https://twitter.com/mazakaaaan", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=47913066"),
ImgData(R.raw.sae0083, "@mazakaaaan", "https://twitter.com/mazakaaaan", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=46008331"),
ImgData(R.raw.sae0086, "@mazakaaaan", "https://twitter.com/mazakaaaan", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=41998732"),
ImgData(R.raw.sae0082, "H2O", "https://www.pixiv.net/member.php?id=18180240", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=59537085"),
ImgData(R.raw.sae0084, "@natuya777", "https://twitter.com/natuya777", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=43285880"),
ImgData(R.raw.sae0085, "@natuya777", "https://twitter.com/natuya777", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=46606608"),
ImgData(R.raw.sae0087, "しの", "https://www.pixiv.net/member.php?id=35037", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=36906360"),
ImgData(R.raw.sae0088, "美月めいあ", "https://www.pixiv.net/member.php?id=383657", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=33659173"),
ImgData(R.raw.sae0089, "@mckeeeeelog", "https://twitter.com/mckeeeeelog", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=29860757"),
ImgData(R.raw.sae0090, "@miyakoazu", "https://twitter.com/miyakoazu", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=32349060"),
ImgData(R.raw.sae0091, "@WzK7VHEGkO0J4E4", "https://twitter.com/WzK7VHEGkO0J4E4", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=59587222"),
ImgData(R.raw.sae0092, "@yuntayu", "https://twitter.com/yuntayu", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=32728220"),
ImgData(R.raw.sae0093, "@jackallllllllll", "https://twitter.com/jackallllllllll", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=42247716"),
ImgData(R.raw.sae0094, "@akihiko_05", "https://twitter.com/akihiko_05", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=68160948"),
ImgData(R.raw.sae0095, "Manyo", "https://www.pixiv.net/member.php?id=5940914", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=73269188"),
ImgData(R.raw.sae0099, "@migi_mawashi", "https://twitter.com/migi_mawashi", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=73112698"),
ImgData(R.raw.sae0100, "@syatly", "https://twitter.com/syatly", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=56959669"),
ImgData(R.raw.sae0101, "@syatly", "https://twitter.com/syatly", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=56959669"),
ImgData(R.raw.sae0102, "@ponyui0728", "https://twitter.com/ponyui0728", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=56880664"),
ImgData(R.raw.sae0104, "縞七", "https://www.pixiv.net/member.php?id=6454840", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=72524370"),
ImgData(R.raw.sae0105, "@elesake", "https://twitter.com/elesake", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=44565332")
//ImgData(R.raw.sae, "", "", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=72574413"),
//ImgData(R.raw.sae, "", "", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=72300606"),
//ImgData(R.raw.sae, "", "", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=72319649"),
//ImgData(R.raw.sae, "", "", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=72091546"),
//ImgData(R.raw.sae, "", "", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=72010515"),
//ImgData(R.raw.sae, "", "", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=71846364"),
//ImgData(R.raw.sae, "", "", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=71576086"),
//ImgData(R.raw.sae, "", "", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=71445592"),
//ImgData(R.raw.sae, "", "", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=61286524"),
//ImgData(R.raw.sae, "", "", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=71264363"),
//ImgData(R.raw.sae, "", "", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=71223663"),
//ImgData(R.raw.sae, "", "", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=68815242"),
//ImgData(R.raw.sae, "", "", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=72880878"),
//ImgData(R.raw.sae, "", "", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=69776652"),
//ImgData(R.raw.sae, "", "", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=70563899"),
//ImgData(R.raw.sae, "", "", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=69883575"),
//ImgData(R.raw.sae, "", "", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=61621521"),
//ImgData(R.raw.sae, "", "", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=69759435"),
//ImgData(R.raw.sae, "", "", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=69644506"),
//ImgData(R.raw.sae, "", "", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=69541575"),
//ImgData(R.raw.sae, "", "", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=67888363"),
//ImgData(R.raw.sae, "", "", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=69598154"),
//ImgData(R.raw.sae, "", "", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=69176611"),
//ImgData(R.raw.sae, "", "", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=69297967"),
//ImgData(R.raw.sae, "", "", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=68515979"),
//ImgData(R.raw.sae, "", "", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=55885699"),
//ImgData(R.raw.sae, "", "", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=66886065"),
//ImgData(R.raw.sae, "", "", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=67197908"),
//ImgData(R.raw.sae, "", "", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=67050561"),
//ImgData(R.raw.sae, "", "", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=61808784"),
//ImgData(R.raw.sae, "", "", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=62053790"),
//ImgData(R.raw.sae, "", "", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=55045464"),
//ImgData(R.raw.sae, "", "", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=68054335"),
//ImgData(R.raw.sae, "", "", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=61583824"),
//ImgData(R.raw.sae, "", "", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=66970564"),
//ImgData(R.raw.sae, "", "", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=66662471"),
//ImgData(R.raw.sae, "", "", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=61854663"),
//ImgData(R.raw.sae, "", "", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=61246834"),
//ImgData(R.raw.sae, "", "", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=66365255"),
//ImgData(R.raw.sae, "", "", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=66254674"),
//ImgData(R.raw.sae, "", "", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=66285209"),
//ImgData(R.raw.sae, "", "", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=46928698"),
//ImgData(R.raw.sae, "", "", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=66066299"),
//ImgData(R.raw.sae, "", "", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=65987865"),
//ImgData(R.raw.sae, "", "", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=65879293"),
//ImgData(R.raw.sae, "", "", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=62559423"),
//ImgData(R.raw.sae, "", "", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=65712553"),
//ImgData(R.raw.sae, "", "", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=61596965"),
//ImgData(R.raw.sae, "", "", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=46623623"),
//ImgData(R.raw.sae, "", "", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=63860848"),
//ImgData(R.raw.sae, "", "", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=61191380"),
//ImgData(R.raw.sae, "", "", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=65481843"),
//ImgData(R.raw.sae, "", "", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=60867649"),
//ImgData(R.raw.sae, "", "", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=63856945"),
//ImgData(R.raw.sae, "", "", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=65490674"),
//ImgData(R.raw.sae, "", "", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=63372013"),
//ImgData(R.raw.sae, "", "", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=63350634"),
//ImgData(R.raw.sae, "", "", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=64114259"),
//ImgData(R.raw.sae, "", "", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=61097071"),
//ImgData(R.raw.sae, "", "", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=41853425"),
//ImgData(R.raw.sae, "", "", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=27614826"),
//ImgData(R.raw.sae, "", "", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=61628173"),
//ImgData(R.raw.sae, "", "", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=63524058"),
//ImgData(R.raw.sae, "", "", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=61897582"),
//ImgData(R.raw.sae, "", "", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=62103143"),
//ImgData(R.raw.sae, "", "", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=65479372"),
//ImgData(R.raw.sae, "", "", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=25326404"),
//ImgData(R.raw.sae, "", "", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=65479726"),
//ImgData(R.raw.sae, "", "", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=26138046"),
//ImgData(R.raw.sae, "", "", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=60727676"),
//ImgData(R.raw.sae, "", "", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=61046820"),
//ImgData(R.raw.sae, "", "", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=65479738"),
//ImgData(R.raw.sae, "", "", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=63951102"),
//ImgData(R.raw.sae, "", "", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=65028532"),
//ImgData(R.raw.sae, "", "", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=24908091"),
//ImgData(R.raw.sae, "", "", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=64290897"),
//ImgData(R.raw.sae, "", "", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=58546816"),
//ImgData(R.raw.sae, "", "", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=62556140"),
//ImgData(R.raw.sae, "", "", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=59703065"),
//ImgData(R.raw.sae, "", "", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=64076559"),
//ImgData(R.raw.sae, "", "", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=36896429"),
//ImgData(R.raw.sae, "", "", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=31847612"),
//ImgData(R.raw.sae, "", "", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=52125154"),
//ImgData(R.raw.sae, "", "", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=32441611"),
//ImgData(R.raw.sae, "", "", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=57866673"),
//ImgData(R.raw.sae, "", "", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=54074753"),
//ImgData(R.raw.sae, "", "", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=56498215"),
//ImgData(R.raw.sae, "", "", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=57458361"),
//ImgData(R.raw.sae, "", "", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=60134647"),
//ImgData(R.raw.sae, "", "", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=58973257"),
//ImgData(R.raw.sae, "", "", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=52640454"),
//ImgData(R.raw.sae, "", "", "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=51140952"),
//ImgData(R.raw.sae, "", "", "https://twitter.com/_citrusmikan/status/1084315711516770305"),
//ImgData(R.raw.sae, "", "", "https://twitter.com/frenchmaid_/status/794449492128825344"),
//https://www.pixiv.net/member_illust.php?mode=medium&illust_id=46620217
//https://www.pixiv.net/member_illust.php?mode=medium&illust_id=60477054
//https://www.pixiv.net/member_illust.php?mode=medium&illust_id=63879982
//https://www.pixiv.net/member_illust.php?mode=medium&illust_id=60685026
//https://www.pixiv.net/member_illust.php?mode=medium&illust_id=54111389
//https://www.pixiv.net/member_illust.php?mode=medium&illust_id=60556417
//https://www.pixiv.net/member_illust.php?mode=medium&illust_id=61999933
//https://www.pixiv.net/member_illust.php?mode=medium&illust_id=61127239
//https://www.pixiv.net/member_illust.php?mode=medium&illust_id=59531868
//https://www.pixiv.net/member_illust.php?mode=medium&illust_id=60211876
//https://www.pixiv.net/member_illust.php?mode=medium&illust_id=62135077
//https://www.pixiv.net/member_illust.php?mode=medium&illust_id=59731482
//https://www.pixiv.net/member_illust.php?mode=medium&illust_id=58925725
//https://www.pixiv.net/member_illust.php?mode=medium&illust_id=53024162
//https://www.pixiv.net/member_illust.php?mode=medium&illust_id=66740209
//https://www.pixiv.net/member_illust.php?mode=medium&illust_id=68011261
//https://www.pixiv.net/member_illust.php?mode=medium&illust_id=43284648
//https://www.pixiv.net/member_illust.php?mode=medium&illust_id=59848031
//https://www.pixiv.net/member_illust.php?mode=medium&illust_id=73629542
//https://www.pixiv.net/member_illust.php?mode=medium&illust_id=56041501
//https://www.pixiv.net/member_illust.php?mode=medium&illust_id=70976755
//https://www.pixiv.net/member_illust.php?mode=medium&illust_id=67062837
//https://www.pixiv.net/member_illust.php?mode=medium&illust_id=42178521
//https://www.pixiv.net/member_illust.php?mode=medium&illust_id=70270394
//https://www.pixiv.net/member_illust.php?mode=medium&illust_id=62495444
//https://www.pixiv.net/member_illust.php?mode=medium&illust_id=68958428
//https://www.pixiv.net/member_illust.php?mode=medium&illust_id=68433759
//https://www.pixiv.net/member_illust.php?mode=medium&illust_id=57793633
)
return imgs.random()
}
private fun writeSupportText()
{
if (!showAds && imgData.hasImg)
{
val saeName = "小早川紗枝"
val artText = "\uD83C\uDF38 $saeName by ${imgData.name} \uD83C\uDF38"
val spannableStringBuilder = SpannableStringBuilder(artText)
val clickableSae = object : ClickableSpan()
{
override fun onClick(view: View)
{
val i = Intent(Intent.ACTION_VIEW)
i.data = Uri.parse("https://twitter.com/hashtag/%E5%B0%8F%E6%97%A9%E5%B7%9D%E7%B4%97%E6%9E%9D")
startActivity(i)
}
override fun updateDrawState(ds: TextPaint)
{
ds.color = ContextCompat.getColor(activity!!, R.color.blue_dark)
ds.isUnderlineText = false;
}
}
spannableStringBuilder.setSpan(clickableSae, artText.indexOf(saeName), artText.indexOf(saeName) + saeName.length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
val clickableLink = object : ClickableSpan()
{
override fun onClick(view: View)
{
val i = Intent(Intent.ACTION_VIEW)
i.data = Uri.parse(imgData.nameLink)
startActivity(i)
}
override fun updateDrawState(ds: TextPaint)
{
ds.color = ContextCompat.getColor(activity!!, R.color.blue_dark)
ds.isUnderlineText = false;
}
}
spannableStringBuilder.setSpan(clickableLink, artText.indexOf(imgData.name), artText.indexOf(imgData.name) + imgData.name.length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
supportText.text = spannableStringBuilder
supportText.movementMethod = LinkMovementMethod.getInstance()
}
else
{
supportText.text = getString(R.string.support_text)
}
}
}
================================================
FILE: app/src/main/java/ca/fuwafuwa/kaku/Ocr/BoxParams.java
================================================
package ca.fuwafuwa.kaku.Ocr;
/**
* Created by 0xbad1d3a5 on 4/16/2016.
*/
public final class BoxParams {
public int x;
public int y;
public int width;
public int height;
public BoxParams(int x, int y, int width, int height){
this.x = x;
this.y = y;
this.width = width;
this.height = height;
}
public String toString(){
return String.format("X:%d Y:%d (%dx%d)", x, y, width, height);
}
}
================================================
FILE: app/src/main/java/ca/fuwafuwa/kaku/Ocr/OcrCorrection.kt
================================================
package ca.fuwafuwa.kaku.Ocr
class OcrCorrection
{
companion object
{
val CommonLookalikes: List<List<String>> = listOf(
// Hiragana
listOf("あ", "ぁ", "お", "ぉ"),
listOf("い", "ぃ"),
listOf("う", "ぅ"),
listOf("え", "ぇ", "z", "Z"),
listOf("お", "ぉ", "あ", "ぁ"),
listOf("か", "が", "カ", "ガ", "ヵ", "力"),
listOf("き", "ぎ", "さ", "ざ"),
listOf("く", "ぐ", "〈", "<", "<", "("),
listOf("け", "げ"),
listOf("こ", "ご"),
listOf("さ", "ざ", "き", "ぎ"),
listOf("し", "じ", "L", "L", "U"),
listOf("す", "ず"),
listOf("せ", "ぜ"),
listOf("そ", "ぞ"),
listOf("た", "だ"),
listOf("ち", "ぢ"),
listOf("つ", "づ", "っ", "ウ", "ゥ", "ワ", "ヮ"),
listOf("て", "で"),
listOf("と", "ど"),
listOf("な"),
listOf("に"),
listOf("ぬ"),
listOf("ね"),
listOf("の"),
listOf("は", "ば", "ぱ"),
listOf("ひ", "び", "ぴ"),
listOf("ふ", "ぶ", "ぷ"),
listOf("へ", "べ", "ぺ"),
listOf("ほ", "ぼ", "ぽ"),
listOf("ま"),
listOf("み"),
listOf("む"),
listOf("め"),
listOf("も"),
listOf("や", "ゃ"),
listOf("ゆ", "ゅ"),
listOf("よ", "ょ"),
listOf("ら"),
listOf("り", "リ", "ㇼ"),
listOf("る"),
listOf("れ"),
listOf("ろ"),
listOf("わ", "ゎ"),
listOf("を"),
listOf("ん"),
// Katakana
listOf("ア", "ァ"),
listOf("イ", "ィ"),
listOf("ウ", "ゥ", "つ", "づ", "っ", "ワ", "ヮ"),
listOf("エ", "ェ"),
listOf("オ", "ォ"),
listOf("カ", "ガ", "ヵ", "か", "が", "力"),
listOf("キ", "ギ"),
listOf("ク", "グ", "ㇰ"),
listOf("ケ", "ゲ", "ヶ"),
listOf("コ", "ゴ"),
listOf("サ", "ザ"),
listOf("シ", "ジ", "ㇱ"),
listOf("ス", "ズ", "ㇲ"),
listOf("セ", "ゼ"),
listOf("ソ", "ゾ"),
listOf("タ", "ダ", "夕"),
listOf("チ", "ヂ"),
listOf("ツ", "ヅ", "ッ"),
listOf("テ", "デ"),
listOf("ト", "ド", "ㇳ"),
listOf("ナ"),
listOf("ニ"),
listOf("ヌ", "ㇴ"),
listOf("ネ"),
listOf("ノ"),
listOf("ハ", "バ", "パ", "ㇵ"),
listOf("ヒ", "ビ", "ピ", "ㇶ"),
listOf("フ", "ブ", "プ", "ㇷ", "ン"), //, "\u31f7\u309a"),
listOf("ヘ", "ベ", "ペ", "ㇸ"),
listOf("ホ", "ボ", "ポ", "ㇹ"),
listOf("マ"),
listOf("ミ"),
listOf("ム", "ㇺ"),
listOf("メ"),
listOf("モ"),
listOf("ヤ", "ャ"),
listOf("ユ", "ュ"),
listOf("ヨ", "ョ"),
listOf("ラ", "ㇻ"),
listOf("リ", "ㇼ", "り"),
listOf("ル", "ㇽ"),
listOf("レ", "ㇾ"),
listOf("ロ", "ㇿ", "口"),
listOf("ワ", "ヮ", "ウ", "ゥ", "つ", "づ", "っ"),
listOf("ヲ"),
listOf("ン"),
// Other
listOf("ー", "一", "―", "‐", "—", "-", "-", "_", "|"),
listOf("、", "`", "ヽ"),
listOf("。", "o")
)
val CommonMistakes : List<Pair<List<String>, String>> = listOf(
Pair(listOf("〈", "<", "<"), "く"),
Pair(listOf("L", "L"), "し"),
Pair(listOf("z", "Z"), "え"),
Pair(listOf("U"), "じ"),
Pair(listOf("`", "ヽ"), "、"),
Pair(listOf("o"), "。"),
// Special cases for multiple mappings
Pair(listOf("ー", "一", "―", "‐", "—", "-", "-", "_", "|"), "")
)
}
}
================================================
FILE: app/src/main/java/ca/fuwafuwa/kaku/Ocr/OcrParams.kt
================================================
package ca.fuwafuwa.kaku.Ocr
import android.graphics.Bitmap
import ca.fuwafuwa.kaku.TextDirection
data class OcrParams(val bitmap: Bitmap,
val originalBitmap: Bitmap,
val box: BoxParams,
val textDirection: TextDirection,
val instantMode: Boolean)
{
override fun toString() : String {
return "Box: $box InstantOCR: $instantMode TextDirection: $textDirection"
}
}
================================================
FILE: app/src/main/java/ca/fuwafuwa/kaku/Ocr/OcrResult.kt
================================================
package ca.fuwafuwa.kaku.Ocr
import ca.fuwafuwa.kaku.Windows.Data.DisplayDataOcr
/**
* Created by 0xbad1d3a5 on 5/2/2016.
*/
class OcrResult(val displayData: DisplayDataOcr,
private val mOcrTime: Long)
{
val text: String get() = displayData.text
val message: String get() = String.format("OCR Time: %.2fs", mOcrTime / 1000.0)
override fun toString(): String
{
return String.format("%s\nOcrTime: %d\nInstant: %b", text, mOcrTime, displayData.instantMode)
}
}
================================================
FILE: app/src/main/java/ca/fuwafuwa/kaku/Ocr/OcrRunnable.kt
================================================
package ca.fuwafuwa.kaku.Ocr
import android.content.Context
import android.graphics.Bitmap
import android.os.Message
import android.util.Log
import com.googlecode.tesseract.android.ResultIterator
import com.googlecode.tesseract.android.TessBaseAPI
import java.io.FileNotFoundException
import java.io.FileOutputStream
import java.util.ArrayList
import java.util.HashMap
import ca.fuwafuwa.kaku.*
import ca.fuwafuwa.kaku.Interfaces.Stoppable
import ca.fuwafuwa.kaku.MainService
import ca.fuwafuwa.kaku.Windows.CaptureWindow
import ca.fuwafuwa.kaku.Windows.Data.ChoiceCertainty
import ca.fuwafuwa.kaku.Windows.Data.DisplayDataOcr
import ca.fuwafuwa.kaku.Windows.Data.ISquareChar
import ca.fuwafuwa.kaku.Windows.Data.SquareCharOcr
/**
* Created by 0xbad1d3a5 on 4/16/2016.
*/
class OcrRunnable(context: Context, private var mCaptureWindow: CaptureWindow?) : Runnable, Stoppable
{
private val mContext: MainService = context as MainService
private val mOcrLock = java.lang.Object()
private val mSimilarChars = loadSimilarChars()
private val mCommonMistakes = loadCommonMistakes()
private var mTessBaseAPI: TessBaseAPI? = null
private var mThreadRunning = true
private var mTessReady = false
private var mOcrParams: OcrParams? = null
val isReadyForOcr: Boolean
get() = mOcrParams == null
init
{
mOcrParams = null
}
override fun run()
{
mTessBaseAPI = TessBaseAPI()
val storagePath = mContext.filesDir.absolutePath
mTessBaseAPI!!.init(storagePath, "jpn")
mTessReady = true
while (mThreadRunning)
{
Log.d(TAG, "THREAD STARTING NEW LOOP")
try
{
synchronized(mOcrLock)
{
if (!mThreadRunning)
{
return@synchronized
}
Log.d(TAG, "WAITING")
mOcrLock.wait()
Log.d(TAG, "THREAD STOPPED WAITING")
if (mOcrParams == null)
{
Log.d(TAG, "OcrRunnable - OcrParams null")
return@synchronized
}
Log.d(TAG, "Processing OCR with params " + mOcrParams!!.toString())
val startTime = System.currentTimeMillis()
when (mOcrParams!!.textDirection)
{
TextDirection.HORIZONTAL -> mTessBaseAPI!!.pageSegMode = TessBaseAPI.PageSegMode.PSM_SINGLE_BLOCK
TextDirection.VERTICAL -> mTessBaseAPI!!.pageSegMode = TessBaseAPI.PageSegMode.PSM_SINGLE_BLOCK_VERT_TEXT
}
saveBitmap(mOcrParams!!.bitmap)
mCaptureWindow!!.showLoadingAnimation()
mTessBaseAPI!!.setImage(mOcrParams!!.bitmap)
mTessBaseAPI!!.getHOCRText(0)
val displayData = getDisplayData(mOcrParams!!, mTessBaseAPI!!.resultIterator)
processDisplayData(displayData)
mTessBaseAPI!!.clear()
if (displayData.text.length > 0)
{
val ocrTime = System.currentTimeMillis() - startTime
sendOcrResultToContext(OcrResult(displayData, ocrTime))
} else
{
sendToastToContext("No Characters Recognized.")
}
mCaptureWindow!!.stopLoadingAnimation(mOcrParams!!.instantMode)
mOcrParams = null
}
} catch (e: Exception)
{
e.printStackTrace()
}
}
Log.d(TAG, "THREAD STOPPED")
}
/**
* Unblocks the thread and starts OCR
*/
fun runTess(ocrParams: OcrParams)
{
synchronized(mOcrLock)
{
if (!mThreadRunning || !mTessReady)
{
return
}
mOcrParams = ocrParams
mTessBaseAPI!!.stop()
mOcrLock.notify()
Log.d(TAG, "NOTIFIED")
}
}
/**
* Cancels OCR recognition in progress if Tesseract has been started
*/
fun cancel()
{
mTessBaseAPI!!.stop()
Log.d(TAG, "CANCELED")
}
/**
* Cancels any OCR recognition in progress and stops any further OCR attempts
*/
override fun stop()
{
synchronized(mOcrLock)
{
mThreadRunning = false
mOcrParams = null
mCaptureWindow = null
if (mTessBaseAPI != null)
{
mTessBaseAPI!!.stop()
}
mOcrLock.notify()
}
}
private fun processDisplayData(displayData: DisplayDataOcr)
{
for (squareChar in displayData.squareChars as List<SquareCharOcr>)
{
val similarChars = mSimilarChars[squareChar.char]
if (similarChars != null)
{
for (c in similarChars)
{
squareChar.addChoice(c, ChoiceCertainty.UNCERTAIN)
}
}
}
for (squareChar in displayData.squareChars as List<SquareCharOcr>)
{
correctCommonMistake(squareChar, "く")
correctCommonMistake(squareChar, "し")
correctCommonMistake(squareChar, "じ")
correctCommonMistake(squareChar, "え")
correctCommonMistake(squareChar, "、")
correctCommonMistake(squareChar, "。")
correctKanjiOne(squareChar)
correctKatakanaDash(squareChar)
}
}
private fun correctCommonMistake(squareChar: SquareCharOcr, char: String)
{
if (mCommonMistakes[squareChar.char] == char)
{
val prev = squareChar.prev
val next = squareChar.next
if (prev?.char != null && LangUtils.IsJapaneseChar(prev.char[0]) ||
next?.char != null && LangUtils.IsJapaneseChar(next.char[0]))
{
squareChar.addChoice(char, ChoiceCertainty.CERTAIN)
}
}
}
private fun correctKatakanaDash(squareChar: SquareCharOcr)
{
if (mCommonMistakes[squareChar.char] != null)
{
val prev = squareChar.prev
if (prev?.char != null && LangUtils.IsKatakana(prev.char[0]))
{
squareChar.addChoice("ー", ChoiceCertainty.CERTAIN)
}
}
}
private fun correctKanjiOne(squareChar: SquareCharOcr)
{
if (mCommonMistakes[squareChar.char] != null)
{
val next = squareChar.next
if (next?.char != null && (LangUtils.IsKanji(next.char[0]) || LangUtils.IsHiragana(next.char[0])))
{
squareChar.addChoice("一", ChoiceCertainty.CERTAIN)
}
}
}
private fun getDisplayData(ocrParams: OcrParams, iterator: ResultIterator): DisplayDataOcr
{
val bitmap = mOcrParams!!.originalBitmap
val boxParams = mOcrParams!!.box
val ocrChars = ArrayList<SquareCharOcr>()
val displayData = DisplayDataOcr(bitmap, boxParams, ocrParams.instantMode, ocrChars)
if (iterator.next(TessBaseAPI.PageIteratorLevel.RIL_SYMBOL))
{
iterator.begin()
} else
{
return displayData
}
do
{
val c = iterator.symbolChoicesAndConfidence
val choices = ArrayList<kotlin.Pair<String, Double>>()
for (p in c) choices.add(kotlin.Pair(p.first as String, p.second as Double))
val pos = iterator.getBoundingBox(TessBaseAPI.PageIteratorLevel.RIL_SYMBOL)
ocrChars.add(SquareCharOcr(displayData, choices, pos))
} while (iterator.next(TessBaseAPI.PageIteratorLevel.RIL_SYMBOL))
iterator.delete()
displayData.assignIndicies()
return displayData
}
private fun loadSimilarChars(): HashMap<String, List<String>>
{
val similarChars = HashMap<String, List<String>>()
for (list in OcrCorrection.CommonLookalikes)
{
for ((index, kana) in list.withIndex())
{
if (list.size == 1)
{
continue
}
val kanaList: List<String> = when (index)
{
0 -> list.takeLast(list.size - 1)
list.size - 1 -> list.take(list.size - 1)
else -> list.subList(0, index) + list.subList(index + 1, list.size)
}
if (similarChars.containsKey(kana))
{
for (k in kanaList)
{
if (!similarChars[kana]!!.contains(k))
{
similarChars[kana] = kanaList + listOf(k)
}
}
}
else
{
similarChars[kana] = kanaList
}
}
}
return similarChars
}
private fun loadCommonMistakes(): HashMap<String, String>
{
val commonMistakes = HashMap<String, String>()
for (pair in OcrCorrection.CommonMistakes)
{
for (c in pair.first)
{
commonMistakes[c] = pair.second
}
}
return commonMistakes
}
private fun sendOcrResultToContext(result: OcrResult)
{
Message.obtain(mContext.handler, 0, result).sendToTarget()
}
private fun sendToastToContext(message: String)
{
Message.obtain(mContext.handler, 0, message).sendToTarget()
}
@Throws(FileNotFoundException::class)
private fun saveBitmap(bitmap: Bitmap, name: String = "screen")
{
val fs = String.format("%s/%s/%s_%d.png", mContext.filesDir.absolutePath, SCREENSHOT_FOLDER_NAME, name, System.nanoTime())
Log.d(TAG, fs)
val fos = FileOutputStream(fs)
bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos)
}
companion object
{
private val TAG = OcrRunnable::class.java.name
}
}
================================================
FILE: app/src/main/java/ca/fuwafuwa/kaku/PassthroughActivity.kt
================================================
package ca.fuwafuwa.kaku
import android.content.Intent
import android.os.Bundle
import android.view.Window
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.NotificationCompat
import ca.fuwafuwa.kaku.Windows.InformationWindow
import ca.fuwafuwa.kaku.Windows.WindowCoordinator
class PassthroughActivity : AppCompatActivity()
{
override fun onCreate(savedInstanceState: Bundle?)
{
super.onCreate(savedInstanceState)
requestWindowFeature(Window.FEATURE_NO_TITLE);
setupKakuDatabasesAndFiles(this)
var processText : String? = null
when {
intent?.action == Intent.ACTION_PROCESS_TEXT ->
{
processText = intent.getStringExtra(Intent.EXTRA_PROCESS_TEXT)
}
intent?.action == Intent.ACTION_SEND ->
{
if ("text/plain" == intent.type)
{
processText = intent.getStringExtra(Intent.EXTRA_TEXT)
}
}
}
if (processText != null)
{
val windowCoordinator = WindowCoordinator(applicationContext)
val infoWindow = windowCoordinator.getWindow(WINDOW_INFO) as InformationWindow
infoWindow.setResult(processText)
infoWindow.show()
finish()
}
}
}
================================================
FILE: app/src/main/java/ca/fuwafuwa/kaku/Search/JmSearchResult.kt
================================================
package ca.fuwafuwa.kaku.Search
import ca.fuwafuwa.kaku.Database.JmDictDatabase.Models.EntryOptimized
import ca.fuwafuwa.kaku.Deinflictor.DeinflectionInfo
data class JmSearchResult(
val entry: EntryOptimized,
val deinfInfo: DeinflectionInfo,
val word: String
)
================================================
FILE: app/src/main/java/ca/fuwafuwa/kaku/Search/JmTask.kt
================================================
package ca.fuwafuwa.kaku.Search
import android.content.Context
import android.os.AsyncTask
import android.util.Log
import ca.fuwafuwa.kaku.DB_JMDICT_NAME
import ca.fuwafuwa.kaku.DB_KANJIDICT_NAME
import ca.fuwafuwa.kaku.Database.JmDictDatabase.JmDatabaseHelper
import ca.fuwafuwa.kaku.Database.JmDictDatabase.Models.EntryOptimized
import ca.fuwafuwa.kaku.Deinflictor.DeinflectionInfo
import ca.fuwafuwa.kaku.Deinflictor.Deinflector
import java.sql.SQLException
import java.util.ArrayList
import kotlin.collections.HashSet
import kotlin.collections.List
import kotlin.collections.filter
import kotlin.collections.sortedWith
/**
* Created by 0xbad1d3a5 on 12/16/2016.
*/
class JmTask @Throws(SQLException::class)
constructor(private val mSearchInfo: SearchInfo, private val mSearchJmTaskDone: SearchJmTaskDone, context: Context) : AsyncTask<Void, Void, List<JmSearchResult>>()
{
companion object
{
private val TAG = JmTask::class.java.getName()
}
private val mJmDbHelper: JmDatabaseHelper = JmDatabaseHelper.instance(context)
private val mDeinflector: Deinflector = Deinflector(context)
interface SearchJmTaskDone
{
fun jmTaskCallback(results: List<JmSearchResult>, searchInfo: SearchInfo)
}
override fun doInBackground(vararg params: Void): List<JmSearchResult>
{
val text = mSearchInfo.text
val textOffset = mSearchInfo.textOffset
val entryOptimizedDao = mJmDbHelper.getDbDao<EntryOptimized>(EntryOptimized::class.java)
val startDictTime = System.currentTimeMillis()
var character = String(intArrayOf(text.codePointAt(textOffset)), 0, 1)
// What the flying fuck? Wasn't the entire point of using an ORM is so shit would be escaped for me?
character = character.replace("%", "\\%")
character = character.replace("_", "\\_")
character = character.replace("'", "''")
val entries: List<EntryOptimized> = entryOptimizedDao.queryBuilder().where().like("kanji", "$character%").query()
val matchedEntries = rankResults(getMatchedEntries(text, textOffset, entries))
Log.d(TAG, "Dict lookup time: ${System.currentTimeMillis() - startDictTime}")
return matchedEntries
}
override fun onPostExecute(result: List<JmSearchResult>)
{
mSearchJmTaskDone.jmTaskCallback(result, mSearchInfo)
}
@Throws(SQLException::class)
private fun getMatchedEntries(text: String, textOffset: Int, entries: List<EntryOptimized>): List<JmSearchResult>
{
val end = if (textOffset + 80 >= text.length) text.length else textOffset + 80
var word = text.substring(textOffset, end)
val seenEntries = HashSet<EntryOptimized>()
val results = ArrayList<JmSearchResult>()
while (word.isNotEmpty())
{
// Find deinflections and add them
val deinfResultsList: List<DeinflectionInfo> = mDeinflector.getPotentialDeinflections(word)
var count = 0
for (deinfInfo in deinfResultsList)
{
val filteredEntry: List<EntryOptimized> = entries.filter { entry -> entry.kanji == deinfInfo.word }
if (filteredEntry.isEmpty())
{
continue
}
for (entry in filteredEntry){
if (seenEntries.contains(entry)){
continue
}
var valid = true
if (count > 0)
{
valid = (deinfInfo.type and 1 != 0) && (entry.pos.contains("v1")) ||
(deinfInfo.type and 2 != 0) && (entry.pos.contains("v5")) ||
(deinfInfo.type and 4 != 0) && (entry.pos.contains("adj-i")) ||
(deinfInfo.type and 8 != 0) && (entry.pos.contains("vk")) ||
(deinfInfo.type and 16 != 0) && (entry.pos.contains("vs-"))
}
if (valid){
results.add(JmSearchResult(entry, deinfInfo, word))
seenEntries.add(entry)
}
count++
}
}
// Add all exact matches as well
val filteredEntry: List<EntryOptimized> = entries.filter { entry -> entry.kanji == word }
for (entry in filteredEntry)
{
if (seenEntries.contains(entry))
{
continue
}
results.add(JmSearchResult(entry, DeinflectionInfo(word, 0, ""), word))
seenEntries.add(entry)
}
word = word.substring(0, word.length - 1)
}
return results
}
private fun rankResults(results: List<JmSearchResult>) : List<JmSearchResult>
{
return results.sortedWith(compareBy(
{ getDictPriority(it) },
{ 0 - it.entry.kanji.length },
{ getEntryPriority(it) },
{ getPriority(it) }))
}
private fun getDictPriority(result: JmSearchResult) : Int
{
return when
{
result.entry.dictionary == DB_JMDICT_NAME -> Int.MAX_VALUE - 2
result.entry.dictionary == DB_KANJIDICT_NAME -> Int.MAX_VALUE - 1
else -> Int.MAX_VALUE
}
}
private fun getEntryPriority(result: JmSearchResult) : Int
{
return if (result.entry.isPrimaryEntry) 0 else 1
}
private fun getPriority(result: JmSearchResult) : Int
{
val priorities = result.entry.priorities.split(",")
var lowestPriority = Int.MAX_VALUE
for (priority in priorities){
var pri = Int.MAX_VALUE
if (priority.contains("nf")){ // looks like the range is nf01-nf48
pri = priority.substring(2).toInt()
}
else if (priority == "news1"){
pri = 60
}
else if (priority == "news2"){
pri = 70
}
else if (priority == "ichi1"){
pri = 80
}
else if (priority == "ichi2"){
pri = 90
}
else if (priority == "spec1"){
pri = 100
}
else if (priority == "spec2"){
pri = 110
}
else if (priority == "gai1"){
pri = 120
}
else if (priority == "gai2"){
pri = 130
}
lowestPriority = if (pri < lowestPriority) pri else lowestPriority
}
return lowestPriority
}
}
================================================
FILE: app/src/main/java/ca/fuwafuwa/kaku/Search/Kd2Task.kt
================================================
package ca.fuwafuwa.kaku.Search
import android.content.Context
import android.os.AsyncTask
import com.j256.ormlite.dao.Dao
import java.sql.SQLException
import ca.fuwafuwa.kaku.Database.KanjiDict2Database.Kd2DatabaseHelper
import ca.fuwafuwa.kaku.Database.KanjiDict2Database.Models.CharacterOptimized
/**
* Created by 0xbad1d3a5 on 12/16/2016.
*/
class Kd2Task @Throws(SQLException::class)
constructor(private val mSearchInfo: SearchInfo, private val mSearchKd2TaskDone: SearchKd2TaskDone, context: Context) : AsyncTask<Void, Void, List<CharacterOptimized>>()
{
companion object
{
private val TAG = Kd2Task::class.java.name
}
private val mKd2DbHelper: Kd2DatabaseHelper
private val mCharacterOptimizedDao: Dao<CharacterOptimized, Int>
interface SearchKd2TaskDone
{
fun kd2TaskCallback(results: List<CharacterOptimized>, searchInfo: SearchInfo)
}
init
{
this.mKd2DbHelper = Kd2DatabaseHelper.instance(context)
this.mCharacterOptimizedDao = mKd2DbHelper.getDbDao(CharacterOptimized::class.java)
}
override fun doInBackground(vararg params: Void): List<CharacterOptimized>
{
val character = String(intArrayOf(mSearchInfo.text.codePointAt(mSearchInfo.textOffset)), 0, 1).replace("%", "\\%")
return mCharacterOptimizedDao.queryBuilder().where().like("kanji", "$character%").query().toList()
}
override fun onPostExecute(result: List<CharacterOptimized>)
{
mSearchKd2TaskDone.kd2TaskCallback(result, mSearchInfo)
}
}
================================================
FILE: app/src/main/java/ca/fuwafuwa/kaku/Search/SearchInfo.kt
================================================
package ca.fuwafuwa.kaku.Search
import ca.fuwafuwa.kaku.Windows.Data.DisplayData
import ca.fuwafuwa.kaku.Windows.Data.ISquareChar
import ca.fuwafuwa.kaku.Windows.Views.KanjiCharacterView
/**
* Created by 0xbad1d3a5 on 12/16/2016.
*/
class SearchInfo(val squareChar: ISquareChar)
{
val text: String get() = squareChar.displayData.text
val textOffset: Int
get() {
var index = 0
for (char in squareChar.displayData.squareChars)
{
if (char === squareChar)
{
break
}
index += char.char.length
}
return index
}
val index: Int get() = squareChar.index
}
================================================
FILE: app/src/main/java/ca/fuwafuwa/kaku/Search/Searcher.java
================================================
package ca.fuwafuwa.kaku.Search;
import android.content.Context;
import android.os.AsyncTask;
import android.util.Log;
import org.jetbrains.annotations.NotNull;
import java.sql.SQLException;
import java.util.List;
import ca.fuwafuwa.kaku.Database.JmDictDatabase.Models.EntryOptimized;
import ca.fuwafuwa.kaku.Database.KanjiDict2Database.Models.CharacterOptimized;
/**
* Created by 0xbad1d3a5 on 8/28/2016.
*/
public class Searcher implements JmTask.SearchJmTaskDone {
public interface SearchDictDone
{
void jmResultsCallback(List<JmSearchResult> results, SearchInfo search);
}
private static final String TAG = Searcher.class.getName();
private SearchDictDone mSearchDictDone;
private Context mContext;
public Searcher(Context context) throws SQLException
{
mContext = context;
}
public void registerCallback(SearchDictDone dictDone)
{
this.mSearchDictDone = dictDone;
}
public void unregisterCallback()
{
this.mSearchDictDone = null;
}
public void search(SearchInfo searchInfo)
{
try {
new JmTask(searchInfo, this, mContext).executeOnExecutor(AsyncTask.SERIAL_EXECUTOR);
} catch (SQLException e) {
e.printStackTrace();
}
}
@Override
public void jmTaskCallback(@NotNull List<JmSearchResult> results, @NotNull SearchInfo searchInfo)
{
mSearchDictDone.jmResultsCallback(results, searchInfo);
}
}
================================================
FILE: app/src/main/java/ca/fuwafuwa/kaku/TutorialActivity.kt
================================================
package ca.fuwafuwa.kaku
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager
import androidx.fragment.app.FragmentStatePagerAdapter
import ca.fuwafuwa.kaku.databinding.ActivityTutorialBinding
class TutorialActivity : AppCompatActivity()
{
inner class SectionsPagerAdapter(fm: FragmentManager) : FragmentStatePagerAdapter(fm)
{
override fun getItem(position: Int): Fragment
{
if (position == 0){
return TutorialWelcomeFragment.newInstance()
}
if (position in 1..9)
{
return TutorialFragment.newInstance(position)
}
return TutorialEndFragment.newInstance()
}
override fun getCount(): Int
{
return 11
}
}
private lateinit var mSectionsPagerAdapter: FragmentStatePagerAdapter
private lateinit var mBinding: ActivityTutorialBinding
override fun onCreate(savedInstanceState: Bundle?)
{
super.onCreate(savedInstanceState)
mBinding = ActivityTutorialBinding.inflate(layoutInflater)
supportActionBar?.hide()
setContentView(mBinding.root)
mSectionsPagerAdapter = SectionsPagerAdapter(supportFragmentManager)
mBinding.container.adapter = mSectionsPagerAdapter
mBinding.container.offscreenPageLimit = 1
mBinding.tabIndicator.setupWithViewPager(mBinding.container)
}
companion object
{
private val TAG = TutorialActivity::class.java.name
}
}
================================================
FILE: app/src/main/java/ca/fuwafuwa/kaku/TutorialEndFragment.kt
================================================
package ca.fuwafuwa.kaku
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import androidx.fragment.app.Fragment
import ca.fuwafuwa.kaku.Dialogs.GrantPermissionDialogFragment
class TutorialEndFragment : Fragment()
{
private lateinit var rootView : View
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View?
{
rootView = inflater.inflate(R.layout.fragment_end, container, false)
val button = rootView.findViewById<Button>(R.id.tutorial_end_start_kaku)
button.setOnClickListener {
GrantPermissionDialogFragment().show(fragmentManager!!, "GrantPermission")
}
return rootView
}
companion object
{
fun newInstance() : TutorialEndFragment {
return TutorialEndFragment()
}
}
}
================================================
FILE: app/src/main/java/ca/fuwafuwa/kaku/TutorialFragment.kt
================================================
package ca.fuwafuwa.kaku
import android.net.Uri
import android.os.Bundle
import android.util.Log
import android.view.*
import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
import android.widget.Button
import android.widget.LinearLayout
import android.widget.VideoView
import androidx.fragment.app.DialogFragment
import androidx.fragment.app.Fragment
import ca.fuwafuwa.kaku.Dialogs.TutorialExplainDialogFragment
class TutorialFragment : Fragment()
{
private lateinit var mRootView : View
private lateinit var mVideoView : VideoView
private lateinit var mButtonLayout : LinearLayout
private lateinit var mExplainButton: Button
private var mPos : Int = -1
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View?
{
mRootView = inflater.inflate(R.layout.fragment_tutorial, container, false)
mVideoView = mRootView.findViewById(R.id.instruction_video_view) as VideoView
mButtonLayout = mRootView.findViewById(R.id.tutorial_buttons) as LinearLayout
mExplainButton = mRootView.findViewById(R.id.tutorial_button_explain)
mPos = arguments?.getInt(ARG_SECTION_NUMBER)!!
mExplainButton.setOnClickListener {
getExplainDialogForFragment(mPos).show(fragmentManager!!, "ExplainDialog$mPos")
}
Log.d(TAG, "onCreateView $mPos")
return mRootView
}
override fun onStart()
{
super.onStart()
mButtonLayout.viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener
{
override fun onGlobalLayout()
{
val drawableHeight = mButtonLayout.y.toInt()
val params = LinearLayout.LayoutParams(WRAP_CONTENT, drawableHeight - dpToPx(context!!, 20))
params.gravity = Gravity.CENTER_HORIZONTAL
params.setMargins(0, dpToPx(context!!, 20), 0, 0)
mVideoView.layoutParams = params
mVideoView.requestLayout()
mButtonLayout.viewTreeObserver.removeOnGlobalLayoutListener(this)
}
})
}
override fun onResume()
{
super.onResume()
mVideoView.setVideoURI(Uri.parse("android.resource://ca.fuwafuwa.kaku/${getVideoForSectionNumber(mPos)}"))
mVideoView.setOnPreparedListener { it.isLooping = true }
mVideoView.start()
}
private fun getExplainDialogForFragment(num: Int) : DialogFragment
{
return TutorialExplainDialogFragment.newInstance(getTitleTextForSectionNumber(num), getTextForSectionNumber(num))
}
private fun getVideoForSectionNumber(num: Int): Int
{
when (num){
1 -> return R.raw.tut1
2 -> return R.raw.tut2
3 -> return R.raw.tut3
4 -> return R.raw.tut4
5 -> return R.raw.tut5
6 -> return R.raw.tut6
7 -> return R.raw.tut7
8 -> return R.raw.tut8
9 -> return R.raw.tut9
}
return 0
}
private fun getTitleTextForSectionNumber(num: Int): String
{
when (num){
1 -> return "BASIC USAGE"
2 -> return "INSTANT MODE"
3 -> return "QUICK IMAGE ACTION - FILTER"
4 -> return "QUICK TEXT ACTION - SWAP"
5 -> return "QUICK TEXT ACTION - EDIT"
6 -> return "QUICK TEXT ACTION - DELETE"
7 -> return "SEND TO GOOGLE TRANSLATE"
8 -> return "NOTIFICATION CONTROLS"
9 -> return "SELECT TO LOOKUP"
}
return ""
}
private fun getTextForSectionNumber(num: Int): String
{
when (num){
1 -> return "Drag the capture window to move the window. Drag the bottom right corner to resize. Double tap to start OCR and recognize text. Tip: resize area is inside the capture window."
2 -> return "If instant mode is turned on in the settings and the capture window is fairly small, OCR will start immediately. This mode was intended to recognize words, not sentences."
3 -> return "If the background of the text you want to recognize is translucent, you can try adjusting the image filter settings by doing a long press, then dragging left or right. Note: image filter setting must be turned on."
4 -> return "Sometimes Kaku misrecognizes the kanji but can be easily corrected. Perform a quick swipe downward on the kanji for possible alternate recognitions."
5 -> return "In the case that the correct kanji was not present in the swap quick action, perform a quick swipe to the upper-left to manually input the kanji. For manual correction, you must have a handwriting keyboard installed - for example, Gboard w/ Japanese Handwriting by Google."
6 -> return "If you need to delete any extraneous characters, swipe to the upper right. For all text quick actions, the swipe direction may be reversed in instant mode when there is not enough screen space."
7 -> return "Tap and hold on any kanji to copy recognized text to the clipboard. If you have \"Tap to Translate\" enabled in the Google Translate app, that will also be brought up."
8 -> return "Quickly show/hide Kaku or change Kaku's settings through the notification."
9 -> return "In the case that you can select the text and don't need OCR, simply select the text and send it to Kaku to bring up the dictionary."
}
return ""
}
companion object
{
private val TAG = TutorialFragment::class.java.name
private val ARG_SECTION_NUMBER = "section_number"
fun newInstance(sectionNumber: Int): TutorialFragment
{
val fragment = TutorialFragment()
val args = Bundle()
args.putInt(ARG_SECTION_NUMBER, sectionNumber)
fragment.arguments = args
return fragment
}
}
}
================================================
FILE: app/src/main/java/ca/fuwafuwa/kaku/TutorialWelcomeFragment.kt
================================================
package ca.fuwafuwa.kaku
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import an
gitextract_arnt_e7c/ ├── .gitattributes ├── .gitignore ├── .idea/ │ ├── encodings.xml │ ├── misc.xml │ ├── modules.xml │ └── vcs.xml ├── LICENSE ├── README.md ├── app/ │ ├── .gitignore │ ├── build.gradle │ ├── proguard-rules.pro │ └── src/ │ ├── main/ │ │ ├── AndroidManifest.xml │ │ ├── java/ │ │ │ └── ca/ │ │ │ └── fuwafuwa/ │ │ │ └── kaku/ │ │ │ ├── BetaActivity.kt │ │ │ ├── Constants.kt │ │ │ ├── Database/ │ │ │ │ ├── DatabaseHelper.java │ │ │ │ ├── DbHelperFactory.java │ │ │ │ ├── IDatabaseHelper.java │ │ │ │ ├── JmDictDatabase/ │ │ │ │ │ ├── JmDatabaseHelper.java │ │ │ │ │ └── Models/ │ │ │ │ │ ├── Entry.java │ │ │ │ │ ├── EntryOptimized.java │ │ │ │ │ ├── Kanji.java │ │ │ │ │ ├── KanjiIrregularity.java │ │ │ │ │ ├── KanjiPriority.java │ │ │ │ │ ├── Meaning.java │ │ │ │ │ ├── MeaningAdditionalInfo.java │ │ │ │ │ ├── MeaningAntonym.java │ │ │ │ │ ├── MeaningCrossReference.java │ │ │ │ │ ├── MeaningDialect.java │ │ │ │ │ ├── MeaningField.java │ │ │ │ │ ├── MeaningGloss.java │ │ │ │ │ ├── MeaningKanjiRestriction.java │ │ │ │ │ ├── MeaningLoanSource.java │ │ │ │ │ ├── MeaningMisc.java │ │ │ │ │ ├── MeaningPartOfSpeech.java │ │ │ │ │ ├── MeaningReadingRestriction.java │ │ │ │ │ ├── Reading.java │ │ │ │ │ ├── ReadingIrregularity.java │ │ │ │ │ ├── ReadingPriority.java │ │ │ │ │ └── ReadingRestriction.java │ │ │ │ └── KanjiDict2Database/ │ │ │ │ ├── Kd2DatabaseHelper.java │ │ │ │ └── Models/ │ │ │ │ └── CharacterOptimized.java │ │ │ ├── Deinflictor/ │ │ │ │ ├── DeinflectionDTOs.kt │ │ │ │ ├── Deinflector.kt │ │ │ │ └── PosMap.kt │ │ │ ├── Dialogs/ │ │ │ │ ├── FeedbackDialogFragment.kt │ │ │ │ ├── GrantPermissionDialogFragment.kt │ │ │ │ ├── PlayStoreRatingDialogFragment.kt │ │ │ │ ├── StarRatingDialogFragment.kt │ │ │ │ └── TutorialExplainDialogFragment.kt │ │ │ ├── Exceptions/ │ │ │ │ └── NotImplementedException.java │ │ │ ├── Interfaces/ │ │ │ │ └── Stoppable.java │ │ │ ├── KakuTools.kt │ │ │ ├── LangUtils.kt │ │ │ ├── MainActivity.kt │ │ │ ├── MainService.java │ │ │ ├── MainServiceHandler.java │ │ │ ├── MainStartFragment.kt │ │ │ ├── Ocr/ │ │ │ │ ├── BoxParams.java │ │ │ │ ├── OcrCorrection.kt │ │ │ │ ├── OcrParams.kt │ │ │ │ ├── OcrResult.kt │ │ │ │ └── OcrRunnable.kt │ │ │ ├── PassthroughActivity.kt │ │ │ ├── Search/ │ │ │ │ ├── JmSearchResult.kt │ │ │ │ ├── JmTask.kt │ │ │ │ ├── Kd2Task.kt │ │ │ │ ├── SearchInfo.kt │ │ │ │ └── Searcher.java │ │ │ ├── TutorialActivity.kt │ │ │ ├── TutorialEndFragment.kt │ │ │ ├── TutorialFragment.kt │ │ │ ├── TutorialWelcomeFragment.kt │ │ │ ├── Windows/ │ │ │ │ ├── CaptureWindow.kt │ │ │ │ ├── Data/ │ │ │ │ │ ├── DisplayData.kt │ │ │ │ │ └── SquareChar.kt │ │ │ │ ├── EditWindow.kt │ │ │ │ ├── Enums/ │ │ │ │ │ ├── ChoiceType.java │ │ │ │ │ └── LayoutPosition.kt │ │ │ │ ├── HistoryWindow.kt │ │ │ │ ├── InformationWindow.java │ │ │ │ ├── InstantInfoWindow.kt │ │ │ │ ├── InstantKanjiWindow.kt │ │ │ │ ├── Interfaces/ │ │ │ │ │ ├── ICopyText.kt │ │ │ │ │ ├── IRecalculateKanjiViews.kt │ │ │ │ │ ├── ISearchPerformer.kt │ │ │ │ │ └── WindowListener.java │ │ │ │ ├── KanjiChoiceWindow.kt │ │ │ │ ├── Views/ │ │ │ │ │ ├── ChoiceEditText.java │ │ │ │ │ ├── ChoiceGridView.java │ │ │ │ │ ├── ChoiceIconView.java │ │ │ │ │ ├── KanjiCharacterView.kt │ │ │ │ │ ├── KanjiGridView.kt │ │ │ │ │ ├── KanjiImageView.kt │ │ │ │ │ ├── ResizeView.java │ │ │ │ │ ├── SquareGridView.kt │ │ │ │ │ └── WindowView.java │ │ │ │ ├── Window.java │ │ │ │ └── WindowCoordinator.kt │ │ │ └── XmlParsers/ │ │ │ ├── CommonParser.java │ │ │ ├── Interfaces/ │ │ │ │ └── DictParser.java │ │ │ ├── JmDict/ │ │ │ │ ├── JmConsts.java │ │ │ │ ├── JmDTO/ │ │ │ │ │ ├── JmEntry.java │ │ │ │ │ ├── JmGloss.java │ │ │ │ │ ├── JmKEle.java │ │ │ │ │ ├── JmLsource.java │ │ │ │ │ ├── JmREle.java │ │ │ │ │ └── JmSense.java │ │ │ │ └── JmParser.java │ │ │ ├── KanjiDict2/ │ │ │ │ ├── Kd2Consts.java │ │ │ │ ├── Kd2DTO/ │ │ │ │ │ ├── Kd2Character.java │ │ │ │ │ ├── Kd2Codepoint.java │ │ │ │ │ ├── Kd2CpValue.java │ │ │ │ │ ├── Kd2DicNumber.java │ │ │ │ │ ├── Kd2DicRef.java │ │ │ │ │ ├── Kd2Meaning.java │ │ │ │ │ ├── Kd2Misc.java │ │ │ │ │ ├── Kd2QCode.java │ │ │ │ │ ├── Kd2QueryCode.java │ │ │ │ │ ├── Kd2RadValue.java │ │ │ │ │ ├── Kd2Radical.java │ │ │ │ │ ├── Kd2Reading.java │ │ │ │ │ ├── Kd2ReadingMeaning.java │ │ │ │ │ ├── Kd2RmGroup.java │ │ │ │ │ └── Kd2Variant.java │ │ │ │ └── Kd2Parser.java │ │ │ └── ParserRunnable.java │ │ └── res/ │ │ ├── anim/ │ │ │ ├── fade_repeat.xml │ │ │ └── slide_in.xml │ │ ├── drawable/ │ │ │ ├── bg_solid_border_0_blue_black.xml │ │ │ ├── bg_solid_border_0_white_black.xml │ │ │ ├── bg_solid_border_corners_0_white_black_round.xml │ │ │ ├── bg_translucent_border_0_black_black.xml │ │ │ ├── bg_translucent_border_0_blue_blue.xml │ │ │ ├── bg_transparent_border_0_nil_black.xml │ │ │ ├── bg_transparent_border_0_nil_default.xml │ │ │ └── bg_transparent_border_0_nil_ready.xml │ │ ├── drawable-anydpi/ │ │ │ ├── icon_delete.xml │ │ │ ├── icon_edit.xml │ │ │ └── icon_swap.xml │ │ ├── layout/ │ │ │ ├── activity_beta.xml │ │ │ ├── activity_main.xml │ │ │ ├── activity_passthrough.xml │ │ │ ├── activity_tutorial.xml │ │ │ ├── dialog_rating_stars.xml │ │ │ ├── fragment_end.xml │ │ │ ├── fragment_start.xml │ │ │ ├── fragment_tutorial.xml │ │ │ ├── fragment_welcome.xml │ │ │ ├── window.xml │ │ │ ├── window_capture.xml │ │ │ ├── window_edit.xml │ │ │ ├── window_history.xml │ │ │ ├── window_info.xml │ │ │ ├── window_instant_info.xml │ │ │ ├── window_instant_kanji.xml │ │ │ └── window_kanji_choice.xml │ │ ├── mipmap-anydpi-v26/ │ │ │ ├── ic_launcher.xml │ │ │ └── ic_launcher_round.xml │ │ ├── values/ │ │ │ ├── colors.xml │ │ │ ├── dimens.xml │ │ │ ├── strings.xml │ │ │ └── styles.xml │ │ └── values-w820dp/ │ │ └── dimens.xml │ └── test/ │ └── java/ │ └── ca/ │ └── fuwafuwa/ │ └── kaku/ │ ├── ExampleUnitTest.java │ └── GenerateDictionary.java ├── build.gradle ├── fastlane/ │ └── metadata/ │ └── android/ │ └── en-US/ │ ├── full_description.txt │ └── short_description.txt ├── gradle/ │ └── wrapper/ │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradle.properties ├── gradlew ├── gradlew.bat ├── projectFilesBackup/ │ └── .idea/ │ └── workspace.xml └── settings.gradle
SYMBOL INDEX (507 symbols across 72 files)
FILE: app/src/main/java/ca/fuwafuwa/kaku/Database/DatabaseHelper.java
class DatabaseHelper (line 15) | public abstract class DatabaseHelper extends OrmLiteSqliteOpenHelper imp...
method DatabaseHelper (line 17) | public DatabaseHelper(Context context, String databaseName, SQLiteData...
method deleteDatabase (line 21) | public abstract void deleteDatabase();
FILE: app/src/main/java/ca/fuwafuwa/kaku/Database/DbHelperFactory.java
class DbHelperFactory (line 12) | public class DbHelperFactory {
method DbHelperFactory (line 16) | public DbHelperFactory(Context context){
method instance (line 20) | public DatabaseHelper instance(Class clazz){
FILE: app/src/main/java/ca/fuwafuwa/kaku/Database/IDatabaseHelper.java
type IDatabaseHelper (line 7) | public interface IDatabaseHelper
method getDbDao (line 9) | <T> Dao<T, Integer> getDbDao(Class clazz) throws SQLException;
FILE: app/src/main/java/ca/fuwafuwa/kaku/Database/JmDictDatabase/JmDatabaseHelper.java
class JmDatabaseHelper (line 42) | public class JmDatabaseHelper extends DatabaseHelper {
method JmDatabaseHelper (line 53) | private JmDatabaseHelper(Context context){
method instance (line 59) | public static synchronized JmDatabaseHelper instance(Context context){
method onCreate (line 66) | @Override
method onUpgrade (line 76) | @Override
method deleteDatabase (line 82) | public void deleteDatabase(){
method getDbDao (line 86) | public <T> Dao<T, Integer> getDbDao(Class clazz) throws SQLException {
FILE: app/src/main/java/ca/fuwafuwa/kaku/Database/JmDictDatabase/Models/Entry.java
class Entry (line 14) | @DatabaseTable
method Entry (line 33) | public Entry(){
method getId (line 36) | public Integer getId() {
method setId (line 40) | public void setId(Integer id) {
method getKanjis (line 44) | public ForeignCollection<Kanji> getKanjis() {
method setKanjis (line 48) | public void setKanjis(ForeignCollection<Kanji> kanjis) {
method getReadings (line 52) | public ForeignCollection<Reading> getReadings() {
method setReadings (line 56) | public void setReadings(ForeignCollection<Reading> readings) {
method getMeanings (line 60) | public ForeignCollection<Meaning> getMeanings() {
method setMeanings (line 64) | public void setMeanings(ForeignCollection<Meaning> meanings) {
method toString (line 68) | @Override
method equals (line 73) | @Override
method hashCode (line 83) | @Override
FILE: app/src/main/java/ca/fuwafuwa/kaku/Database/JmDictDatabase/Models/EntryOptimized.java
class EntryOptimized (line 11) | public class EntryOptimized implements Comparable<EntryOptimized> {
method EntryOptimized (line 47) | public EntryOptimized(){
method getKanji (line 50) | public String getKanji() {
method setKanji (line 54) | public void setKanji(String kanji) {
method getReadings (line 58) | public String getReadings()
method setReadings (line 67) | public void setReadings(String readings) {
method getMeanings (line 71) | public String getMeanings() {
method setMeanings (line 75) | public void setMeanings(String meanings) {
method getPos (line 79) | public String getPos()
method setPos (line 88) | public void setPos(String pos)
method isOnlyKana (line 93) | public boolean isOnlyKana() {
method setOnlyKana (line 97) | public void setOnlyKana(boolean onlyKana) {
method isPrimaryEntry (line 101) | public boolean isPrimaryEntry()
method setPrimaryEntry (line 106) | public void setPrimaryEntry(boolean altForm)
method getPriorities (line 111) | public String getPriorities()
method setPriorities (line 120) | public void setPriorities(String priorities)
method getDictionary (line 125) | public String getDictionary()
method setDictionary (line 130) | public void setDictionary(String dictionary)
method compareTo (line 136) | @Override
FILE: app/src/main/java/ca/fuwafuwa/kaku/Database/JmDictDatabase/Models/Kanji.java
class Kanji (line 14) | @DatabaseTable
method getKanji (line 40) | public String getKanji() {
method setKanji (line 44) | public void setKanji(String kanji) {
method getFkEntry (line 48) | public Entry getFkEntry() {
method setFkEntry (line 52) | public void setFkEntry(Entry fkEntry) {
method getKanjiIrregularities (line 56) | public ForeignCollection<KanjiIrregularity> getKanjiIrregularities() {
method getKanjiPriorities (line 60) | public ForeignCollection<KanjiPriority> getKanjiPriorities() {
method toString (line 64) | @Override
FILE: app/src/main/java/ca/fuwafuwa/kaku/Database/JmDictDatabase/Models/KanjiIrregularity.java
class KanjiIrregularity (line 12) | @DatabaseTable
method getKanjiIrregularity (line 27) | public String getKanjiIrregularity() {
method setKanjiIrregularity (line 31) | public void setKanjiIrregularity(String kanjiIrregularity) {
method getFkKanji (line 35) | public Kanji getFkKanji() {
method setFkKanji (line 39) | public void setFkKanji(Kanji fkKanji) {
method toString (line 43) | @Override
FILE: app/src/main/java/ca/fuwafuwa/kaku/Database/JmDictDatabase/Models/KanjiPriority.java
class KanjiPriority (line 12) | @DatabaseTable
method getKanjiPriority (line 27) | public String getKanjiPriority() {
method setKanjiPriority (line 31) | public void setKanjiPriority(String kanjiPriority) {
method getFkKanji (line 35) | public Kanji getFkKanji() {
method setFkKanji (line 39) | public void setFkKanji(Kanji fkKanji) {
method toString (line 43) | @Override
FILE: app/src/main/java/ca/fuwafuwa/kaku/Database/JmDictDatabase/Models/Meaning.java
class Meaning (line 14) | @DatabaseTable
method getFkEntry (line 69) | public Entry getFkEntry() {
method setFkEntry (line 73) | public void setFkEntry(Entry fkEntry) {
method getKanjiRestrictions (line 76) | public ForeignCollection<MeaningKanjiRestriction> getKanjiRestrictions...
method getReadingRestrictions (line 80) | public ForeignCollection<MeaningReadingRestriction> getReadingRestrict...
method getPartsOfSpeech (line 84) | public ForeignCollection<MeaningPartOfSpeech> getPartsOfSpeech() {
method getCrossReferences (line 88) | public ForeignCollection<MeaningCrossReference> getCrossReferences() {
method getAntonyms (line 92) | public ForeignCollection<MeaningAntonym> getAntonyms() {
method getFields (line 96) | public ForeignCollection<MeaningField> getFields() {
method getMiscs (line 100) | public ForeignCollection<MeaningMisc> getMiscs() {
method getAdditionalInfos (line 104) | public ForeignCollection<MeaningAdditionalInfo> getAdditionalInfos() {
method getLoanSources (line 108) | public ForeignCollection<MeaningLoanSource> getLoanSources() {
method getDialects (line 112) | public ForeignCollection<MeaningDialect> getDialects() {
method getGlosses (line 116) | public ForeignCollection<MeaningGloss> getGlosses() {
method toString (line 120) | @Override
FILE: app/src/main/java/ca/fuwafuwa/kaku/Database/JmDictDatabase/Models/MeaningAdditionalInfo.java
class MeaningAdditionalInfo (line 12) | @DatabaseTable
method getAdditionalInfo (line 27) | public String getAdditionalInfo() {
method setAdditionalInfo (line 31) | public void setAdditionalInfo(String additionalInfo) {
method getFkMeaning (line 35) | public Meaning getFkMeaning() {
method setFkMeaning (line 39) | public void setFkMeaning(Meaning fkMeaning) {
method toString (line 43) | @Override
FILE: app/src/main/java/ca/fuwafuwa/kaku/Database/JmDictDatabase/Models/MeaningAntonym.java
class MeaningAntonym (line 12) | @DatabaseTable
method getAntonym (line 27) | public String getAntonym() {
method setAntonym (line 31) | public void setAntonym(String antonym) {
method getFkMeaning (line 35) | public Meaning getFkMeaning() {
method setFkMeaning (line 39) | public void setFkMeaning(Meaning fkMeaning) {
method toString (line 43) | @Override
FILE: app/src/main/java/ca/fuwafuwa/kaku/Database/JmDictDatabase/Models/MeaningCrossReference.java
class MeaningCrossReference (line 12) | @DatabaseTable
method getCrossReference (line 27) | public String getCrossReference() {
method setCrossReference (line 31) | public void setCrossReference(String crossReference) {
method getFkMeaning (line 35) | public Meaning getFkMeaning() {
method setFkMeaning (line 39) | public void setFkMeaning(Meaning fkMeaning) {
method toString (line 43) | @Override
FILE: app/src/main/java/ca/fuwafuwa/kaku/Database/JmDictDatabase/Models/MeaningDialect.java
class MeaningDialect (line 12) | @DatabaseTable
method getDialect (line 27) | public String getDialect() {
method setDialect (line 31) | public void setDialect(String dialect) {
method getFkMeaning (line 35) | public Meaning getFkMeaning() {
method setFkMeaning (line 39) | public void setFkMeaning(Meaning fkMeaning) {
method toString (line 43) | @Override
FILE: app/src/main/java/ca/fuwafuwa/kaku/Database/JmDictDatabase/Models/MeaningField.java
class MeaningField (line 12) | @DatabaseTable
method getField (line 27) | public String getField() {
method setField (line 31) | public void setField(String field) {
method getFkMeaning (line 35) | public Meaning getFkMeaning() {
method setFkMeaning (line 39) | public void setFkMeaning(Meaning fkMeaning) {
method toString (line 43) | @Override
FILE: app/src/main/java/ca/fuwafuwa/kaku/Database/JmDictDatabase/Models/MeaningGloss.java
class MeaningGloss (line 12) | @DatabaseTable
method getGloss (line 35) | public String getGloss() {
method setGloss (line 39) | public void setGloss(String gloss) {
method getLang (line 43) | public String getLang() {
method setLang (line 47) | public void setLang(String lang) {
method getGender (line 51) | public String getGender() {
method setGender (line 55) | public void setGender(String gender) {
method getFkMeaning (line 59) | public Meaning getFkMeaning() {
method setFkMeaning (line 63) | public void setFkMeaning(Meaning fkMeaning) {
method toString (line 67) | @Override
FILE: app/src/main/java/ca/fuwafuwa/kaku/Database/JmDictDatabase/Models/MeaningKanjiRestriction.java
class MeaningKanjiRestriction (line 12) | @DatabaseTable
method getKanjiRestriction (line 27) | public String getKanjiRestriction() {
method setKanjiRestriction (line 31) | public void setKanjiRestriction(String kanjiRestriction) {
method getFkMeaning (line 35) | public Meaning getFkMeaning() {
method setFkMeaning (line 39) | public void setFkMeaning(Meaning fkMeaning) {
method toString (line 43) | @Override
FILE: app/src/main/java/ca/fuwafuwa/kaku/Database/JmDictDatabase/Models/MeaningLoanSource.java
class MeaningLoanSource (line 12) | @DatabaseTable
method getLoanSource (line 39) | public String getLoanSource() {
method setLoanSource (line 43) | public void setLoanSource(String loanSource) {
method getLang (line 47) | public String getLang() {
method setLang (line 51) | public void setLang(String lang) {
method getType (line 55) | public String getType() {
method setType (line 59) | public void setType(String type) {
method getWaseieigo (line 63) | public String getWaseieigo() {
method setWaseieigo (line 67) | public void setWaseieigo(String waseieigo) {
method getFkMeaning (line 71) | public Meaning getFkMeaning() {
method setFkMeaning (line 75) | public void setFkMeaning(Meaning fkMeaning) {
method toString (line 79) | @Override
FILE: app/src/main/java/ca/fuwafuwa/kaku/Database/JmDictDatabase/Models/MeaningMisc.java
class MeaningMisc (line 12) | @DatabaseTable
method getMisc (line 27) | public String getMisc() {
method setMisc (line 31) | public void setMisc(String misc) {
method getFkMeaning (line 35) | public Meaning getFkMeaning() {
method setFkMeaning (line 39) | public void setFkMeaning(Meaning fkMeaning) {
method toString (line 43) | @Override
FILE: app/src/main/java/ca/fuwafuwa/kaku/Database/JmDictDatabase/Models/MeaningPartOfSpeech.java
class MeaningPartOfSpeech (line 12) | @DatabaseTable
method getPartOfSpeech (line 27) | public String getPartOfSpeech() {
method setPartOfSpeech (line 31) | public void setPartOfSpeech(String partOfSpeech) {
method getFkMeaning (line 35) | public Meaning getFkMeaning() {
method setFkMeaning (line 39) | public void setFkMeaning(Meaning fkMeaning) {
method toString (line 43) | @Override
FILE: app/src/main/java/ca/fuwafuwa/kaku/Database/JmDictDatabase/Models/MeaningReadingRestriction.java
class MeaningReadingRestriction (line 12) | @DatabaseTable
method getReadingRestriction (line 27) | public String getReadingRestriction() {
method setReadingRestriction (line 31) | public void setReadingRestriction(String readingRestriction) {
method getFkMeaning (line 35) | public Meaning getFkMeaning() {
method setFkMeaning (line 39) | public void setFkMeaning(Meaning fkMeaning) {
method toString (line 43) | @Override
FILE: app/src/main/java/ca/fuwafuwa/kaku/Database/JmDictDatabase/Models/Reading.java
class Reading (line 14) | @DatabaseTable
method getReading (line 45) | public String getReading() {
method setReading (line 49) | public void setReading(String reading) {
method getFalseReading (line 53) | public String getFalseReading() {
method setFalseReading (line 57) | public void setFalseReading(String falseReading) {
method getFkEntry (line 61) | public Entry getFkEntry() {
method setFkEntry (line 65) | public void setFkEntry(Entry fkEntry) {
method getReadingRestrictions (line 69) | public ForeignCollection<ReadingRestriction> getReadingRestrictions() {
method getReadingIrregularities (line 73) | public ForeignCollection<ReadingIrregularity> getReadingIrregularities...
method getReadingPriorities (line 77) | public ForeignCollection<ReadingPriority> getReadingPriorities() {
method toString (line 81) | @Override
FILE: app/src/main/java/ca/fuwafuwa/kaku/Database/JmDictDatabase/Models/ReadingIrregularity.java
class ReadingIrregularity (line 12) | @DatabaseTable
method getReadingIrregularity (line 27) | public String getReadingIrregularity() {
method setReadingIrregularity (line 31) | public void setReadingIrregularity(String readingIrregularity) {
method getFkReading (line 35) | public Reading getFkReading() {
method setFkReading (line 39) | public void setFkReading(Reading fkReading) {
method toString (line 43) | @Override
FILE: app/src/main/java/ca/fuwafuwa/kaku/Database/JmDictDatabase/Models/ReadingPriority.java
class ReadingPriority (line 12) | @DatabaseTable
method getReadingPriority (line 27) | public String getReadingPriority() {
method setReadingPriority (line 31) | public void setReadingPriority(String readingPriority) {
method getFkReading (line 35) | public Reading getFkReading() {
method setFkReading (line 39) | public void setFkReading(Reading fkReading) {
method toString (line 43) | @Override
FILE: app/src/main/java/ca/fuwafuwa/kaku/Database/JmDictDatabase/Models/ReadingRestriction.java
class ReadingRestriction (line 12) | @DatabaseTable
method getReadingRestriction (line 27) | public String getReadingRestriction() {
method setReadingRestriction (line 31) | public void setReadingRestriction(String readingRestriction) {
method getFkReading (line 35) | public Reading getFkReading() {
method setFkReading (line 39) | public void setFkReading(Reading fkReading) {
method toString (line 43) | @Override
FILE: app/src/main/java/ca/fuwafuwa/kaku/Database/KanjiDict2Database/Kd2DatabaseHelper.java
class Kd2DatabaseHelper (line 22) | public class Kd2DatabaseHelper extends DatabaseHelper {
method Kd2DatabaseHelper (line 31) | public Kd2DatabaseHelper(Context context){
method instance (line 36) | public static synchronized Kd2DatabaseHelper instance(Context context){
method onCreate (line 43) | @Override
method onUpgrade (line 53) | @Override
method deleteDatabase (line 58) | @Override
method getDbDao (line 63) | @Override
FILE: app/src/main/java/ca/fuwafuwa/kaku/Database/KanjiDict2Database/Models/CharacterOptimized.java
class CharacterOptimized (line 11) | public class CharacterOptimized {
method getKanji (line 33) | public String getKanji() {
method setKanji (line 37) | public void setKanji(String kanji) {
method getOnyomi (line 41) | public String getOnyomi() {
method setOnyomi (line 45) | public void setOnyomi(String onyomi) {
method getKunyomi (line 49) | public String getKunyomi() {
method setKunyomi (line 53) | public void setKunyomi(String kunyomi) {
method getMeaning (line 57) | public String getMeaning() {
method setMeaning (line 61) | public void setMeaning(String meaning) {
FILE: app/src/main/java/ca/fuwafuwa/kaku/Exceptions/NotImplementedException.java
class NotImplementedException (line 7) | public class NotImplementedException extends RuntimeException {
FILE: app/src/main/java/ca/fuwafuwa/kaku/Interfaces/Stoppable.java
type Stoppable (line 7) | public interface Stoppable {
method stop (line 8) | void stop();
FILE: app/src/main/java/ca/fuwafuwa/kaku/MainService.java
class MainService (line 43) | public class MainService extends Service implements Stoppable {
class CloseMainService (line 47) | public static class CloseMainService extends BroadcastReceiver
method onReceive (line 49) | @Override
class ToggleImagePreviewMainService (line 56) | public static class ToggleImagePreviewMainService extends BroadcastRec...
method onReceive (line 58) | @Override
class ToggleShowHideMainService (line 69) | public static class ToggleShowHideMainService extends BroadcastReceiver
method onReceive (line 71) | @Override
class TogglePageModeMainService (line 82) | public static class TogglePageModeMainService extends BroadcastReceiver
method onReceive (line 84) | @Override
class ToggleInstantModeMainService (line 96) | public static class ToggleInstantModeMainService extends BroadcastRece...
method onReceive (line 98) | @Override
class ScreenOffReceiver (line 109) | public static class ScreenOffReceiver extends BroadcastReceiver
method onReceive (line 111) | @Override
class MediaProjectionStopCallback (line 121) | private class MediaProjectionStopCallback extends MediaProjection.Call...
method onStop (line 122) | @Override
method onBind (line 166) | @Override
method onCreate (line 173) | @Override
method onStartCommand (line 201) | @Override
method onConfigurationChanged (line 235) | @Override
method onDestroy (line 254) | @Override
method stop (line 270) | @Override
method IsRunning (line 279) | public static boolean IsRunning()
method onCaptureWindowFinishedInitializing (line 290) | public void onCaptureWindowFinishedInitializing()
method getHandler (line 301) | public Handler getHandler()
method getScreenshot (line 306) | public Image getScreenshot() throws InterruptedException
method getNotification (line 317) | private Notification getNotification()
method createVirtualDisplay (line 375) | private void createVirtualDisplay()
method createNotificationChannel (line 395) | @RequiresApi(Build.VERSION_CODES.O)
FILE: app/src/main/java/ca/fuwafuwa/kaku/MainServiceHandler.java
class MainServiceHandler (line 16) | public class MainServiceHandler extends Handler {
method MainServiceHandler (line 23) | public MainServiceHandler(MainService mainService, WindowCoordinator w...
method handleMessage (line 29) | @Override
FILE: app/src/main/java/ca/fuwafuwa/kaku/Ocr/BoxParams.java
class BoxParams (line 6) | public final class BoxParams {
method BoxParams (line 13) | public BoxParams(int x, int y, int width, int height){
method toString (line 20) | public String toString(){
FILE: app/src/main/java/ca/fuwafuwa/kaku/Search/Searcher.java
class Searcher (line 18) | public class Searcher implements JmTask.SearchJmTaskDone {
type SearchDictDone (line 20) | public interface SearchDictDone
method jmResultsCallback (line 22) | void jmResultsCallback(List<JmSearchResult> results, SearchInfo sear...
method Searcher (line 30) | public Searcher(Context context) throws SQLException
method registerCallback (line 35) | public void registerCallback(SearchDictDone dictDone)
method unregisterCallback (line 40) | public void unregisterCallback()
method search (line 45) | public void search(SearchInfo searchInfo)
method jmTaskCallback (line 54) | @Override
FILE: app/src/main/java/ca/fuwafuwa/kaku/Windows/Enums/ChoiceType.java
type ChoiceType (line 6) | public enum ChoiceType {
FILE: app/src/main/java/ca/fuwafuwa/kaku/Windows/InformationWindow.java
class InformationWindow (line 45) | public class InformationWindow extends Window implements Searcher.Search...
method InformationWindow (line 60) | public InformationWindow(Context context, WindowCoordinator windowCoor...
method setResult (line 82) | public void setResult(DisplayData displayData)
method setResult (line 90) | public void setResult(String textResult)
method copyText (line 104) | public void copyText()
method performSearch (line 113) | @Override
method reInit (line 125) | @Override
method getDefaultParams (line 132) | @Override
method onTouch (line 148) | @Override
method show (line 162) | @Override
method hide (line 173) | @Override
method stop (line 198) | @Override
method onResize (line 205) | @Override
method onDown (line 211) | @Override
method onDoubleTap (line 217) | @Override
method onSingleTapUp (line 233) | @Override
method onScroll (line 261) | @Override
method onFling (line 277) | @Override
method jmResultsCallback (line 298) | @Override
method recalculateKanjiViews (line 330) | @Override
method displayResults (line 336) | private void displayResults(List<JmSearchResult> jmResults)
method getMeaning (line 374) | private String getMeaning(EntryOptimized entry)
FILE: app/src/main/java/ca/fuwafuwa/kaku/Windows/Interfaces/WindowListener.java
type WindowListener (line 9) | public interface WindowListener extends GestureDetector.OnGestureListene...
method onTouch (line 10) | boolean onTouch(MotionEvent e);
method onResize (line 11) | boolean onResize(MotionEvent e);
FILE: app/src/main/java/ca/fuwafuwa/kaku/Windows/Views/ChoiceEditText.java
class ChoiceEditText (line 16) | @SuppressLint("AppCompatCustomView")
type InputDoneListener (line 19) | public interface InputDoneListener
method onEditTextInputDone (line 21) | void onEditTextInputDone(String input);
method ChoiceEditText (line 29) | public ChoiceEditText(Context context)
method ChoiceEditText (line 35) | public ChoiceEditText(Context context, AttributeSet attrs)
method ChoiceEditText (line 41) | public ChoiceEditText(Context context, AttributeSet attrs, int defStyl...
method ChoiceEditText (line 47) | public ChoiceEditText(Context context, AttributeSet attrs, int defStyl...
method Init (line 53) | private void Init(Context context)
method showKeyboard (line 59) | public void showKeyboard()
method setInputDoneCallback (line 70) | public void setInputDoneCallback(InputDoneListener callback)
method onEditorAction (line 75) | @Override
method onKeyPreIme (line 87) | @Override
FILE: app/src/main/java/ca/fuwafuwa/kaku/Windows/Views/ChoiceGridView.java
class ChoiceGridView (line 21) | public class ChoiceGridView extends SquareGridView {
method ChoiceGridView (line 28) | public ChoiceGridView(Context context) {
method ChoiceGridView (line 33) | public ChoiceGridView(Context context, AttributeSet attrs) {
method ChoiceGridView (line 38) | public ChoiceGridView(Context context, AttributeSet attrs, int defStyl...
method ChoiceGridView (line 43) | public ChoiceGridView(Context context, AttributeSet attrs, int defStyl...
method Init (line 48) | private void Init(Context context){
method onKanjiViewScrollStart (line 53) | public void onKanjiViewScrollStart(SquareCharOcr squareChar, MotionEve...
method onKanjiViewScroll (line 92) | public void onKanjiViewScroll(MotionEvent e1, MotionEvent e2)
method onKanjiViewScrollEnd (line 108) | public void onKanjiViewScrollEnd(SquareCharOcr squareChar, MotionEvent...
method checkForSelection (line 124) | private boolean checkForSelection(TextView kanjiView, MotionEvent e){
FILE: app/src/main/java/ca/fuwafuwa/kaku/Windows/Views/ChoiceIconView.java
class ChoiceIconView (line 19) | @SuppressLint("AppCompatCustomView")
method ChoiceIconView (line 25) | public ChoiceIconView(Context context) {
method ChoiceIconView (line 30) | public ChoiceIconView(Context context, AttributeSet attrs) {
method ChoiceIconView (line 35) | public ChoiceIconView(Context context, AttributeSet attrs, int defStyl...
method ChoiceIconView (line 40) | public ChoiceIconView(Context context, AttributeSet attrs, int defStyl...
method Init (line 45) | private void Init(Context context){
method onKanjiViewScrollStart (line 49) | public void onKanjiViewScrollStart(int statusBarHeight, KanjiCharacter...
method onKanjiViewScroll (line 55) | public void onKanjiViewScroll(MotionEvent e1, MotionEvent e2)
method onKanjiViewScrollEnd (line 70) | public ChoiceType onKanjiViewScrollEnd(MotionEvent e){
method getChoiceType (line 76) | private ChoiceType getChoiceType(MotionEvent e){
FILE: app/src/main/java/ca/fuwafuwa/kaku/Windows/Views/ResizeView.java
class ResizeView (line 15) | public class ResizeView extends LinearLayout implements GestureDetector....
method ResizeView (line 20) | public ResizeView(Context context)
method ResizeView (line 26) | public ResizeView(Context context, AttributeSet attrs)
method ResizeView (line 32) | public ResizeView(Context context, AttributeSet attrs, int defStyleAttr)
method init (line 38) | private void init(Context context)
method setWindowListener (line 44) | public void setWindowListener(WindowListener windowListener)
method onTouchEvent (line 49) | @Override
method onSingleTapConfirmed (line 57) | @Override
method onDoubleTap (line 63) | @Override
method onDoubleTapEvent (line 69) | @Override
method onDown (line 75) | @Override
method onShowPress (line 81) | @Override
method onSingleTapUp (line 86) | @Override
method onScroll (line 92) | @Override
method onLongPress (line 98) | @Override
method onFling (line 103) | @Override
FILE: app/src/main/java/ca/fuwafuwa/kaku/Windows/Views/WindowView.java
class WindowView (line 14) | public class WindowView extends RelativeLayout
method WindowView (line 19) | public WindowView(Context context)
method WindowView (line 24) | public WindowView(Context context, AttributeSet attrs)
method WindowView (line 29) | public WindowView(Context context, AttributeSet attrs, int defStyleAttr)
method setWindowListener (line 34) | public void setWindowListener(WindowListener windowListener)
method setDetector (line 39) | public void setDetector(GestureDetectorCompat detector)
method onTouchEvent (line 44) | @Override
FILE: app/src/main/java/ca/fuwafuwa/kaku/Windows/Window.java
class Window (line 30) | public abstract class Window implements Stoppable, WindowListener {
type OnHeightKnown (line 34) | public interface OnHeightKnown {
method performAction (line 35) | void performAction();
class ReinitOptions (line 38) | public static class ReinitOptions
method Window (line 63) | public Window(Context context, WindowCoordinator windowCoordinator, in...
method reInit (line 112) | public void reInit(ReinitOptions options)
method getRealDisplaySizeFromContext (line 131) | private Point getRealDisplaySizeFromContext()
method stop (line 147) | @Override
method show (line 171) | public void show()
method hide (line 187) | public void hide()
method onTouch (line 207) | public boolean onTouch(MotionEvent e){
method onScroll (line 225) | @Override
method onSingleTapConfirmed (line 242) | @Override
method onDoubleTap (line 250) | @Override
method onDoubleTapEvent (line 258) | @Override
method onUp (line 266) | public boolean onUp(MotionEvent e){ return false; }
method onDown (line 271) | @Override
method onShowPress (line 279) | @Override
method onSingleTapUp (line 286) | @Override
method onLongPress (line 294) | @Override
method onFling (line 301) | @Override
method onResize (line 315) | public boolean onResize(MotionEvent e){
method setOnHeightKnownAction (line 344) | public void setOnHeightKnownAction(final OnHeightKnown onHeightKnown)
method getDefaultParams (line 362) | protected WindowManager.LayoutParams getDefaultParams(){
method getRealDisplaySize (line 379) | protected Point getRealDisplaySize()
method getStatusBarHeight (line 387) | protected int getStatusBarHeight()
method getViewHeight (line 409) | protected int getViewHeight(){
method getViewWidth (line 416) | protected int getViewWidth(){
method fixBoxBounds (line 424) | private void fixBoxBounds(){
FILE: app/src/main/java/ca/fuwafuwa/kaku/XmlParsers/CommonParser.java
class CommonParser (line 20) | public class CommonParser {
method CommonParser (line 26) | public CommonParser(Context mContext) {
method parseJmDict (line 30) | public void parseJmDict() throws Exception {
method parseString (line 38) | public static String parseString(XmlPullParser parser) throws IOExcept...
method parseOnlyEntityRef (line 66) | public static String parseOnlyEntityRef(XmlPullParser parser) throws I...
method parseAttributes (line 91) | public static HashMap<String, String> parseAttributes(XmlPullParser pa...
FILE: app/src/main/java/ca/fuwafuwa/kaku/XmlParsers/Interfaces/DictParser.java
type DictParser (line 13) | public interface DictParser {
method parseDict (line 15) | void parseDict(XmlPullParser parser) throws IOException, XmlPullParser...
FILE: app/src/main/java/ca/fuwafuwa/kaku/XmlParsers/JmDict/JmConsts.java
class JmConsts (line 6) | public class JmConsts {
FILE: app/src/main/java/ca/fuwafuwa/kaku/XmlParsers/JmDict/JmDTO/JmEntry.java
class JmEntry (line 13) | public class JmEntry {
method JmEntry (line 23) | public JmEntry(XmlPullParser parser) throws IOException, XmlPullParser...
method getEntSeq (line 52) | public Integer getEntSeq(){
method getKEle (line 56) | public List<JmKEle> getKEle(){
method getREle (line 60) | public List<JmREle> getREle(){
method getSense (line 64) | public List<JmSense> getSense(){
FILE: app/src/main/java/ca/fuwafuwa/kaku/XmlParsers/JmDict/JmDTO/JmGloss.java
class JmGloss (line 15) | public class JmGloss {
method JmGloss (line 25) | public JmGloss(XmlPullParser parser) throws IOException, XmlPullParser...
method toString (line 42) | public String toString(){
method getText (line 49) | public String getText(){
method getLang (line 53) | public String getLang(){
method getGender (line 57) | public String getGender(){
method isEnglish (line 61) | public boolean isEnglish() {
FILE: app/src/main/java/ca/fuwafuwa/kaku/XmlParsers/JmDict/JmDTO/JmKEle.java
class JmKEle (line 29) | public class JmKEle {
method JmKEle (line 37) | public JmKEle(XmlPullParser parser) throws IOException, XmlPullParserE...
method getKeb (line 67) | public String getKeb(){
method getKeInf (line 76) | public List<String> getKeInf(){
method getKePri (line 111) | public List<String> getKePri(){
FILE: app/src/main/java/ca/fuwafuwa/kaku/XmlParsers/JmDict/JmDTO/JmLsource.java
class JmLsource (line 15) | public class JmLsource {
method JmLsource (line 24) | public JmLsource(XmlPullParser parser) throws IOException, XmlPullPars...
method getText (line 34) | public String getText(){
method getLang (line 38) | public String getLang(){
method getLsType (line 42) | public String getLsType(){
method getLsWasei (line 46) | public String getLsWasei(){
FILE: app/src/main/java/ca/fuwafuwa/kaku/XmlParsers/JmDict/JmDTO/JmREle.java
class JmREle (line 23) | public class JmREle {
method JmREle (line 33) | public JmREle(XmlPullParser parser) throws IOException, XmlPullParserE...
method toString (line 65) | public String toString(){
method getReb (line 81) | public String getReb(){
method getReNoKanji (line 92) | public String getReNoKanji(){
method getReRestr (line 102) | public List<String> getReRestr(){
method getReInf (line 111) | public List<String> getReInf(){
method getRePri (line 118) | public List<String> getRePri(){
FILE: app/src/main/java/ca/fuwafuwa/kaku/XmlParsers/JmDict/JmDTO/JmSense.java
class JmSense (line 23) | public class JmSense {
method JmSense (line 40) | public JmSense(XmlPullParser parser) throws IOException, XmlPullParser...
method toString (line 90) | public String toString(){
method getStagk (line 100) | public List<String> getStagk(){
method getStagr (line 103) | public List<String> getStagr(){
method getPos (line 113) | public HashSet<String> getPos(){
method getXRef (line 126) | public List<String> getXRef() {
method getAnt (line 135) | public List<String> getAnt(){
method getField (line 144) | public List<String> getField(){
method getMisc (line 153) | public List<String> getMisc(){
method getSInf (line 163) | public List<String> getSInf(){
method getLSource (line 173) | public List<JmLsource> getLSource(){
method getDial (line 181) | public List<String> getDial(){
method getGloss (line 198) | public List<JmGloss> getGloss(){
method getExample (line 208) | public List<String> getExample(){
FILE: app/src/main/java/ca/fuwafuwa/kaku/XmlParsers/JmDict/JmParser.java
class JmParser (line 54) | public class JmParser implements DictParser {
method JmParser (line 61) | public JmParser(IDatabaseHelper dbHelper){
method parseDict (line 65) | @Override
method parseJmEntryOptimized (line 88) | public void parseJmEntryOptimized(JmEntry jmEntry) throws SQLException {
method parseJmEntry (line 205) | private void parseJmEntry(XmlPullParser parser) throws IOException, Xm...
method parseJmKanji (line 227) | private void parseJmKanji(JmEntry jmEntry, Entry entry) throws SQLExce...
method parseJmKanjiIrregularity (line 239) | private void parseJmKanjiIrregularity(JmKEle jmKEle, Kanji kanji) thro...
method parseJmKanjiPriority (line 248) | private void parseJmKanjiPriority(JmKEle jmKEle, Kanji kanji) throws S...
method parseJmMeaning (line 257) | private void parseJmMeaning(JmEntry jmEntry, Entry entry) throws SQLEx...
method parseJmMeaningAdditionalInfo (line 277) | private void parseJmMeaningAdditionalInfo(JmSense jmSense, Meaning mea...
method parseJmMeaningAntonym (line 286) | private void parseJmMeaningAntonym(JmSense jmSense, Meaning meaning) t...
method parseJmMeaningCrossReference (line 295) | private void parseJmMeaningCrossReference(JmSense jmSense, Meaning mea...
method parseJmMeaningDialect (line 304) | private void parseJmMeaningDialect(JmSense jmSense, Meaning meaning) t...
method parseJmMeaningField (line 313) | private void parseJmMeaningField(JmSense jmSense, Meaning meaning) thr...
method parseJmMeaningGloss (line 322) | private void parseJmMeaningGloss(JmSense jmSense, Meaning meaning) thr...
method parseJmMeaningKanjiRestriction (line 335) | private void parseJmMeaningKanjiRestriction(JmSense jmSense, Meaning m...
method parseJmMeaningLoanSource (line 344) | private void parseJmMeaningLoanSource(JmSense jmSense, Meaning meaning...
method parseJmMeaningMisc (line 356) | private void parseJmMeaningMisc(JmSense jmSense, Meaning meaning) thro...
method parseJmMeaningPartOfSpeech (line 365) | private void parseJmMeaningPartOfSpeech(JmSense jmSense, Meaning meani...
method parseJmMeaningReadingRestriction (line 374) | private void parseJmMeaningReadingRestriction(JmSense jmSense, Meaning...
method parseJmReading (line 383) | private void parseJmReading(JmEntry jmEntry, Entry entry) throws SQLEx...
method parseJmReadingIrregularity (line 397) | private void parseJmReadingIrregularity(JmREle jmREle, Reading reading...
method parseJmReadingPriority (line 406) | private void parseJmReadingPriority(JmREle jmREle, Reading reading) th...
method parseJmReadingRestriction (line 414) | private void parseJmReadingRestriction(JmREle jmREle, Reading reading)...
FILE: app/src/main/java/ca/fuwafuwa/kaku/XmlParsers/KanjiDict2/Kd2Consts.java
class Kd2Consts (line 7) | public class Kd2Consts {
FILE: app/src/main/java/ca/fuwafuwa/kaku/XmlParsers/KanjiDict2/Kd2DTO/Kd2Character.java
class Kd2Character (line 15) | public class Kd2Character {
method Kd2Character (line 27) | public Kd2Character(XmlPullParser parser) throws IOException, XmlPullP...
method getLiteral (line 62) | public String getLiteral() {
method getCodepoint (line 66) | public Kd2Codepoint getCodepoint() {
method getRadical (line 70) | public Kd2Radical getRadical() {
method getMisc (line 74) | public Kd2Misc getMisc() {
method getDic_number (line 78) | public Kd2DicNumber getDic_number() {
method getQuery_code (line 82) | public Kd2QueryCode getQuery_code() {
method getReading_meaning (line 86) | public Kd2ReadingMeaning getReading_meaning() {
FILE: app/src/main/java/ca/fuwafuwa/kaku/XmlParsers/KanjiDict2/Kd2DTO/Kd2Codepoint.java
class Kd2Codepoint (line 15) | public class Kd2Codepoint {
method Kd2Codepoint (line 21) | public Kd2Codepoint(XmlPullParser parser) throws IOException, XmlPullP...
FILE: app/src/main/java/ca/fuwafuwa/kaku/XmlParsers/KanjiDict2/Kd2DTO/Kd2CpValue.java
class Kd2CpValue (line 15) | public class Kd2CpValue {
method Kd2CpValue (line 22) | public Kd2CpValue(XmlPullParser parser) throws IOException, XmlPullPar...
FILE: app/src/main/java/ca/fuwafuwa/kaku/XmlParsers/KanjiDict2/Kd2DTO/Kd2DicNumber.java
class Kd2DicNumber (line 15) | public class Kd2DicNumber {
method Kd2DicNumber (line 21) | public Kd2DicNumber(XmlPullParser parser) throws IOException, XmlPullP...
FILE: app/src/main/java/ca/fuwafuwa/kaku/XmlParsers/KanjiDict2/Kd2DTO/Kd2DicRef.java
class Kd2DicRef (line 15) | public class Kd2DicRef {
method Kd2DicRef (line 24) | public Kd2DicRef(XmlPullParser parser) throws IOException, XmlPullPars...
FILE: app/src/main/java/ca/fuwafuwa/kaku/XmlParsers/KanjiDict2/Kd2DTO/Kd2Meaning.java
class Kd2Meaning (line 15) | public class Kd2Meaning {
method Kd2Meaning (line 22) | public Kd2Meaning(XmlPullParser parser) throws IOException, XmlPullPar...
method getM_lang (line 30) | public String getM_lang() {
method getText (line 34) | public String getText() {
FILE: app/src/main/java/ca/fuwafuwa/kaku/XmlParsers/KanjiDict2/Kd2DTO/Kd2Misc.java
class Kd2Misc (line 16) | public class Kd2Misc {
method Kd2Misc (line 27) | public Kd2Misc(XmlPullParser parser) throws IOException, XmlPullParser...
FILE: app/src/main/java/ca/fuwafuwa/kaku/XmlParsers/KanjiDict2/Kd2DTO/Kd2QCode.java
class Kd2QCode (line 15) | public class Kd2QCode {
method Kd2QCode (line 23) | public Kd2QCode(XmlPullParser parser) throws IOException, XmlPullParse...
FILE: app/src/main/java/ca/fuwafuwa/kaku/XmlParsers/KanjiDict2/Kd2DTO/Kd2QueryCode.java
class Kd2QueryCode (line 15) | public class Kd2QueryCode {
method Kd2QueryCode (line 21) | public Kd2QueryCode(XmlPullParser parser) throws IOException, XmlPullP...
FILE: app/src/main/java/ca/fuwafuwa/kaku/XmlParsers/KanjiDict2/Kd2DTO/Kd2RadValue.java
class Kd2RadValue (line 16) | public class Kd2RadValue {
method Kd2RadValue (line 23) | public Kd2RadValue(XmlPullParser parser) throws IOException, XmlPullPa...
FILE: app/src/main/java/ca/fuwafuwa/kaku/XmlParsers/KanjiDict2/Kd2DTO/Kd2Radical.java
class Kd2Radical (line 15) | public class Kd2Radical {
method Kd2Radical (line 21) | public Kd2Radical(XmlPullParser parser) throws IOException, XmlPullPar...
FILE: app/src/main/java/ca/fuwafuwa/kaku/XmlParsers/KanjiDict2/Kd2DTO/Kd2Reading.java
class Kd2Reading (line 17) | public class Kd2Reading {
method Kd2Reading (line 26) | public Kd2Reading(XmlPullParser parser) throws IOException, XmlPullPar...
method getR_type (line 39) | public String getR_type() {
method getOn_type (line 43) | public String getOn_type() {
method getR_status (line 47) | public String getR_status() {
method getText (line 51) | public String getText() {
FILE: app/src/main/java/ca/fuwafuwa/kaku/XmlParsers/KanjiDict2/Kd2DTO/Kd2ReadingMeaning.java
class Kd2ReadingMeaning (line 16) | public class Kd2ReadingMeaning {
method Kd2ReadingMeaning (line 23) | public Kd2ReadingMeaning(XmlPullParser parser) throws IOException, Xml...
method getRmGroups (line 43) | public List<Kd2RmGroup> getRmGroups(){
FILE: app/src/main/java/ca/fuwafuwa/kaku/XmlParsers/KanjiDict2/Kd2DTO/Kd2RmGroup.java
class Kd2RmGroup (line 15) | public class Kd2RmGroup {
method Kd2RmGroup (line 22) | public Kd2RmGroup(XmlPullParser parser) throws IOException, XmlPullPar...
method getReadings (line 42) | public List<Kd2Reading> getReadings() {
method getMeanings (line 46) | public List<Kd2Meaning> getMeanings() {
FILE: app/src/main/java/ca/fuwafuwa/kaku/XmlParsers/KanjiDict2/Kd2DTO/Kd2Variant.java
class Kd2Variant (line 15) | public class Kd2Variant {
method Kd2Variant (line 22) | public Kd2Variant(XmlPullParser parser) throws IOException, XmlPullPar...
FILE: app/src/main/java/ca/fuwafuwa/kaku/XmlParsers/KanjiDict2/Kd2Parser.java
class Kd2Parser (line 33) | public class Kd2Parser implements DictParser {
method Kd2Parser (line 40) | Kd2Parser(IDatabaseHelper dbHelper){
method parseDict (line 44) | @Override
method parseHeader (line 69) | private void parseHeader(XmlPullParser parser) throws IOException, Xml...
method parseKd2Character (line 85) | private void parseKd2Character(XmlPullParser parser) throws IOExceptio...
method parseKd2CharacterOptimized (line 96) | private void parseKd2CharacterOptimized(Kd2Character character) throws...
method parseKd2CharacterOptimizedOnyomi (line 117) | private String parseKd2CharacterOptimizedOnyomi(Kd2RmGroup rmGroup){
method parseKd2CharacterOptimizedKunyomi (line 136) | private String parseKd2CharacterOptimizedKunyomi(Kd2RmGroup rmGroup){
method parseKd2CharacterOptimizedMeaning (line 155) | private String parseKd2CharacterOptimizedMeaning(Kd2RmGroup rmGroup){
FILE: app/src/main/java/ca/fuwafuwa/kaku/XmlParsers/ParserRunnable.java
class ParserRunnable (line 32) | public class ParserRunnable implements Runnable {
method ParserRunnable (line 39) | public ParserRunnable(Context context) throws NoSuchMethodException, I...
method run (line 45) | @Override
method parseDictionary (line 58) | private void parseDictionary(Class dbHelperClass, Class dictParserClas...
FILE: app/src/test/java/ca/fuwafuwa/kaku/ExampleUnitTest.java
class ExampleUnitTest (line 16) | public class ExampleUnitTest {
method GetTokenString (line 18) | private String GetTokenString(Token token){
method test (line 31) | @Test
method TestCircledNum (line 40) | @Test
FILE: app/src/test/java/ca/fuwafuwa/kaku/GenerateDictionary.java
class GenerateDictionary (line 25) | public class GenerateDictionary
class DatabaseHelperImpl (line 27) | class DatabaseHelperImpl implements IDatabaseHelper {
method DatabaseHelperImpl (line 31) | DatabaseHelperImpl(ConnectionSource connectionSource){
method getDbDao (line 35) | @Override
method generateDic (line 51) | @Test
Condensed preview — 175 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (771K chars).
[
{
"path": ".gitattributes",
"chars": 483,
"preview": "# Auto detect text files and perform LF normalization\n* text=auto\n\n# Custom for Visual Studio\n*.cs diff=csharp\n*.sln"
},
{
"path": ".gitignore",
"chars": 1701,
"preview": "# Ignore data files for Kaku - these shouldn't be checked in\napp/src/main/assets/*\napp/src/main/res/raw/*\n\n# Ignore priv"
},
{
"path": ".idea/encodings.xml",
"chars": 135,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n <component name=\"Encoding\" addBOMForNewFiles=\"with NO BOM"
},
{
"path": ".idea/misc.xml",
"chars": 2820,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n <component name=\"CMakeSettings\">\n <configurations>\n "
},
{
"path": ".idea/modules.xml",
"chars": 383,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n <component name=\"ProjectModuleManager\">\n <modules>\n "
},
{
"path": ".idea/vcs.xml",
"chars": 167,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n <component name=\"VcsDirectoryMappings\">\n <mapping dire"
},
{
"path": "LICENSE",
"chars": 1510,
"preview": "BSD 3-Clause License\n\nCopyright (c) 2016, 0xbad1d3a5\nAll rights reserved.\n\nRedistribution and use in source and binary f"
},
{
"path": "README.md",
"chars": 876,
"preview": "Kaku: 画 (かく) - stroke (of a kanji, etc.), picture, drawing\n\nhttps://kaku.fuwafuwa.ca/\n\nKaku is a fast, powerful Japanese"
},
{
"path": "app/.gitignore",
"chars": 7,
"preview": "/build\n"
},
{
"path": "app/build.gradle",
"chars": 2374,
"preview": "plugins {\n id 'com.android.application'\n}\n\napply plugin: 'com.android.application'\napply plugin: 'kotlin-android'\n\nan"
},
{
"path": "app/proguard-rules.pro",
"chars": 652,
"preview": "# Add project specific ProGuard rules here.\n# By default, the flags in this file are appended to flags specified\n# in D:"
},
{
"path": "app/src/main/AndroidManifest.xml",
"chars": 3127,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n package="
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/BetaActivity.kt",
"chars": 1062,
"preview": "package ca.fuwafuwa.kaku\n\nimport android.content.Intent\nimport android.net.Uri\nimport androidx.appcompat.app.AppCompatAc"
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/Constants.kt",
"chars": 1942,
"preview": "@file:JvmName(\"Constants\")\n\npackage ca.fuwafuwa.kaku\n\n// Thanks to the fact that SqliteOpenHelper.onUpgrade() doesn't wo"
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/Database/DatabaseHelper.java",
"chars": 634,
"preview": "package ca.fuwafuwa.kaku.Database;\n\nimport android.content.Context;\nimport android.database.sqlite.SQLiteDatabase;\n\nimpo"
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/Database/DbHelperFactory.java",
"chars": 744,
"preview": "package ca.fuwafuwa.kaku.Database;\n\nimport android.content.Context;\n\nimport ca.fuwafuwa.kaku.Database.JmDictDatabase.JmD"
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/Database/IDatabaseHelper.java",
"chars": 205,
"preview": "package ca.fuwafuwa.kaku.Database;\n\nimport com.j256.ormlite.dao.Dao;\n\nimport java.sql.SQLException;\n\npublic interface ID"
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/Database/JmDictDatabase/JmDatabaseHelper.java",
"chars": 3808,
"preview": "package ca.fuwafuwa.kaku.Database.JmDictDatabase;\n\nimport android.content.Context;\nimport android.database.sqlite.SQLite"
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/Database/JmDictDatabase/Models/Entry.java",
"chars": 1870,
"preview": "package ca.fuwafuwa.kaku.Database.JmDictDatabase.Models;\n\nimport com.google.gson.annotations.Expose;\nimport com.j256.orm"
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/Database/JmDictDatabase/Models/EntryOptimized.java",
"chars": 2934,
"preview": "package ca.fuwafuwa.kaku.Database.JmDictDatabase.Models;\n\nimport com.google.gson.annotations.Expose;\nimport com.j256.orm"
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/Database/JmDictDatabase/Models/Kanji.java",
"chars": 1562,
"preview": "package ca.fuwafuwa.kaku.Database.JmDictDatabase.Models;\n\nimport com.google.gson.annotations.Expose;\nimport com.j256.orm"
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/Database/JmDictDatabase/Models/KanjiIrregularity.java",
"chars": 1029,
"preview": "package ca.fuwafuwa.kaku.Database.JmDictDatabase.Models;\n\nimport com.google.gson.annotations.Expose;\nimport com.j256.orm"
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/Database/JmDictDatabase/Models/KanjiPriority.java",
"chars": 997,
"preview": "package ca.fuwafuwa.kaku.Database.JmDictDatabase.Models;\n\nimport com.google.gson.annotations.Expose;\nimport com.j256.orm"
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/Database/JmDictDatabase/Models/Meaning.java",
"chars": 3131,
"preview": "package ca.fuwafuwa.kaku.Database.JmDictDatabase.Models;\n\nimport com.google.gson.annotations.Expose;\nimport com.j256.orm"
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/Database/JmDictDatabase/Models/MeaningAdditionalInfo.java",
"chars": 1032,
"preview": "package ca.fuwafuwa.kaku.Database.JmDictDatabase.Models;\n\nimport com.google.gson.annotations.Expose;\nimport com.j256.orm"
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/Database/JmDictDatabase/Models/MeaningAntonym.java",
"chars": 976,
"preview": "package ca.fuwafuwa.kaku.Database.JmDictDatabase.Models;\n\nimport com.google.gson.annotations.Expose;\nimport com.j256.orm"
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/Database/JmDictDatabase/Models/MeaningCrossReference.java",
"chars": 1032,
"preview": "package ca.fuwafuwa.kaku.Database.JmDictDatabase.Models;\n\nimport com.google.gson.annotations.Expose;\nimport com.j256.orm"
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/Database/JmDictDatabase/Models/MeaningDialect.java",
"chars": 976,
"preview": "package ca.fuwafuwa.kaku.Database.JmDictDatabase.Models;\n\nimport com.google.gson.annotations.Expose;\nimport com.j256.orm"
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/Database/JmDictDatabase/Models/MeaningField.java",
"chars": 960,
"preview": "package ca.fuwafuwa.kaku.Database.JmDictDatabase.Models;\n\nimport com.google.gson.annotations.Expose;\nimport com.j256.orm"
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/Database/JmDictDatabase/Models/MeaningGloss.java",
"chars": 1348,
"preview": "package ca.fuwafuwa.kaku.Database.JmDictDatabase.Models;\n\nimport com.google.gson.annotations.Expose;\nimport com.j256.orm"
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/Database/JmDictDatabase/Models/MeaningKanjiRestriction.java",
"chars": 1048,
"preview": "package ca.fuwafuwa.kaku.Database.JmDictDatabase.Models;\n\nimport com.google.gson.annotations.Expose;\nimport com.j256.orm"
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/Database/JmDictDatabase/Models/MeaningLoanSource.java",
"chars": 1596,
"preview": "package ca.fuwafuwa.kaku.Database.JmDictDatabase.Models;\n\nimport com.google.gson.annotations.Expose;\nimport com.j256.orm"
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/Database/JmDictDatabase/Models/MeaningMisc.java",
"chars": 952,
"preview": "package ca.fuwafuwa.kaku.Database.JmDictDatabase.Models;\n\nimport com.google.gson.annotations.Expose;\nimport com.j256.orm"
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/Database/JmDictDatabase/Models/MeaningPartOfSpeech.java",
"chars": 1016,
"preview": "package ca.fuwafuwa.kaku.Database.JmDictDatabase.Models;\n\nimport com.google.gson.annotations.Expose;\nimport com.j256.orm"
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/Database/JmDictDatabase/Models/MeaningReadingRestriction.java",
"chars": 1064,
"preview": "package ca.fuwafuwa.kaku.Database.JmDictDatabase.Models;\n\nimport com.google.gson.annotations.Expose;\nimport com.j256.orm"
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/Database/JmDictDatabase/Models/Reading.java",
"chars": 1988,
"preview": "package ca.fuwafuwa.kaku.Database.JmDictDatabase.Models;\n\nimport com.google.gson.annotations.Expose;\nimport com.j256.orm"
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/Database/JmDictDatabase/Models/ReadingIrregularity.java",
"chars": 1065,
"preview": "package ca.fuwafuwa.kaku.Database.JmDictDatabase.Models;\n\nimport com.google.gson.annotations.Expose;\nimport com.j256.orm"
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/Database/JmDictDatabase/Models/ReadingPriority.java",
"chars": 1033,
"preview": "package ca.fuwafuwa.kaku.Database.JmDictDatabase.Models;\n\nimport com.google.gson.annotations.Expose;\nimport com.j256.orm"
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/Database/JmDictDatabase/Models/ReadingRestriction.java",
"chars": 1057,
"preview": "package ca.fuwafuwa.kaku.Database.JmDictDatabase.Models;\n\nimport com.google.gson.annotations.Expose;\nimport com.j256.orm"
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/Database/KanjiDict2Database/Kd2DatabaseHelper.java",
"chars": 2085,
"preview": "package ca.fuwafuwa.kaku.Database.KanjiDict2Database;\n\nimport android.content.Context;\nimport android.database.sqlite.SQ"
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/Database/KanjiDict2Database/Models/CharacterOptimized.java",
"chars": 1280,
"preview": "package ca.fuwafuwa.kaku.Database.KanjiDict2Database.Models;\n\nimport com.google.gson.annotations.Expose;\nimport com.j256"
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/Deinflictor/DeinflectionDTOs.kt",
"chars": 1204,
"preview": "package ca.fuwafuwa.kaku.Deinflictor\n\n/**\n * A RuleGroup is composed of multiple rules that share the same [Deinflection"
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/Deinflictor/Deinflector.kt",
"chars": 5088,
"preview": "package ca.fuwafuwa.kaku.Deinflictor\n\nimport android.content.Context\nimport ca.fuwafuwa.kaku.LangUtils\nimport java.io.Bu"
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/Deinflictor/PosMap.kt",
"chars": 5783,
"preview": "package ca.fuwafuwa.kaku.Deinflictor\n\nclass PosMap {\n\n companion object {\n\n fun GetPosMapVal(pos: String) : St"
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/Dialogs/FeedbackDialogFragment.kt",
"chars": 1904,
"preview": "package ca.fuwafuwa.kaku.Dialogs\n\nimport android.app.AlertDialog\nimport android.app.Dialog\nimport android.content.Activi"
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/Dialogs/GrantPermissionDialogFragment.kt",
"chars": 1811,
"preview": "package ca.fuwafuwa.kaku.Dialogs\n\nimport android.app.AlertDialog\nimport android.app.Dialog\nimport android.content.Contex"
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/Dialogs/PlayStoreRatingDialogFragment.kt",
"chars": 2223,
"preview": "package ca.fuwafuwa.kaku.Dialogs\n\nimport android.app.AlertDialog\nimport android.app.Dialog\nimport android.os.Bundle\nimpo"
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/Dialogs/StarRatingDialogFragment.kt",
"chars": 3529,
"preview": "package ca.fuwafuwa.kaku.Dialogs\n\nimport android.app.AlertDialog\nimport android.app.Dialog\nimport android.content.Contex"
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/Dialogs/TutorialExplainDialogFragment.kt",
"chars": 1411,
"preview": "package ca.fuwafuwa.kaku.Dialogs\n\nimport android.app.AlertDialog\nimport android.app.Dialog\nimport android.os.Bundle\nimpo"
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/Exceptions/NotImplementedException.java",
"chars": 152,
"preview": "package ca.fuwafuwa.kaku.Exceptions;\n\n/**\n * Created by 0xbad1d3a5 on 12/1/2016.\n */\n\npublic class NotImplementedExcepti"
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/Interfaces/Stoppable.java",
"chars": 134,
"preview": "package ca.fuwafuwa.kaku.Interfaces;\n\n/**\n * Created by 0xbad1d3a5 on 4/13/2016.\n */\n\npublic interface Stoppable {\n v"
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/KakuTools.kt",
"chars": 5208,
"preview": "@file:JvmName(\"KakuTools\")\n\npackage ca.fuwafuwa.kaku\n\nimport android.content.Context\nimport android.content.Intent\nimpor"
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/LangUtils.kt",
"chars": 4586,
"preview": "package ca.fuwafuwa.kaku\n\nclass LangUtils {\n\n companion object {\n\n private val KanaHalf: IntArray = intArrayOf"
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/MainActivity.kt",
"chars": 5738,
"preview": "package ca.fuwafuwa.kaku\n\nimport android.app.Activity\nimport android.content.Context\nimport android.content.Intent\nimpor"
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/MainService.java",
"chars": 16240,
"preview": "package ca.fuwafuwa.kaku;\n\nimport android.app.Notification;\nimport android.app.NotificationChannel;\nimport android.app.N"
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/MainServiceHandler.java",
"chars": 1907,
"preview": "package ca.fuwafuwa.kaku;\n\nimport android.os.Handler;\nimport android.os.Message;\nimport android.util.Log;\nimport android"
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/MainStartFragment.kt",
"chars": 39567,
"preview": "package ca.fuwafuwa.kaku\n\nimport android.content.Context\nimport android.content.Intent\nimport android.graphics.BitmapFac"
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/Ocr/BoxParams.java",
"chars": 466,
"preview": "package ca.fuwafuwa.kaku.Ocr;\n\n/**\n * Created by 0xbad1d3a5 on 4/16/2016.\n */\npublic final class BoxParams {\n\n public"
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/Ocr/OcrCorrection.kt",
"chars": 4230,
"preview": "package ca.fuwafuwa.kaku.Ocr\n\nclass OcrCorrection\n{\n companion object\n {\n val CommonLookalikes: List<List<S"
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/Ocr/OcrParams.kt",
"chars": 465,
"preview": "package ca.fuwafuwa.kaku.Ocr\n\nimport android.graphics.Bitmap\nimport ca.fuwafuwa.kaku.TextDirection\n\ndata class OcrParams"
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/Ocr/OcrResult.kt",
"chars": 507,
"preview": "package ca.fuwafuwa.kaku.Ocr\n\nimport ca.fuwafuwa.kaku.Windows.Data.DisplayDataOcr\n\n/**\n * Created by 0xbad1d3a5 on 5/2/2"
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/Ocr/OcrRunnable.kt",
"chars": 10345,
"preview": "package ca.fuwafuwa.kaku.Ocr\n\nimport android.content.Context\nimport android.graphics.Bitmap\nimport android.os.Message\nim"
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/PassthroughActivity.kt",
"chars": 1352,
"preview": "package ca.fuwafuwa.kaku\n\nimport android.content.Intent\nimport android.os.Bundle\nimport android.view.Window\nimport andro"
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/Search/JmSearchResult.kt",
"chars": 286,
"preview": "package ca.fuwafuwa.kaku.Search\n\nimport ca.fuwafuwa.kaku.Database.JmDictDatabase.Models.EntryOptimized\nimport ca.fuwafuw"
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/Search/JmTask.kt",
"chars": 6735,
"preview": "package ca.fuwafuwa.kaku.Search\n\nimport android.content.Context\nimport android.os.AsyncTask\nimport android.util.Log\nimpo"
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/Search/Kd2Task.kt",
"chars": 1547,
"preview": "package ca.fuwafuwa.kaku.Search\n\nimport android.content.Context\nimport android.os.AsyncTask\n\nimport com.j256.ormlite.dao"
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/Search/SearchInfo.kt",
"chars": 727,
"preview": "package ca.fuwafuwa.kaku.Search\n\nimport ca.fuwafuwa.kaku.Windows.Data.DisplayData\nimport ca.fuwafuwa.kaku.Windows.Data.I"
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/Search/Searcher.java",
"chars": 1485,
"preview": "package ca.fuwafuwa.kaku.Search;\n\nimport android.content.Context;\nimport android.os.AsyncTask;\nimport android.util.Log;\n"
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/TutorialActivity.kt",
"chars": 1621,
"preview": "package ca.fuwafuwa.kaku\n\nimport android.os.Bundle\nimport androidx.appcompat.app.AppCompatActivity\nimport androidx.fragm"
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/TutorialEndFragment.kt",
"chars": 935,
"preview": "package ca.fuwafuwa.kaku\n\nimport android.os.Bundle\nimport android.view.LayoutInflater\nimport android.view.View\nimport an"
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/TutorialFragment.kt",
"chars": 5962,
"preview": "package ca.fuwafuwa.kaku\n\nimport android.net.Uri\nimport android.os.Bundle\nimport android.util.Log\nimport android.view.*\n"
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/TutorialWelcomeFragment.kt",
"chars": 644,
"preview": "package ca.fuwafuwa.kaku\n\nimport android.os.Bundle\nimport android.view.LayoutInflater\nimport android.view.View\nimport an"
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/Windows/CaptureWindow.kt",
"chars": 21559,
"preview": "package ca.fuwafuwa.kaku.Windows\n\nimport android.content.Context\nimport android.graphics.Bitmap\nimport android.graphics."
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/Windows/Data/DisplayData.kt",
"chars": 2453,
"preview": "package ca.fuwafuwa.kaku.Windows.Data\n\nimport android.graphics.Bitmap\nimport ca.fuwafuwa.kaku.Ocr.BoxParams\nimport ca.fu"
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/Windows/Data/SquareChar.kt",
"chars": 2293,
"preview": "package ca.fuwafuwa.kaku.Windows.Data\n\ninterface ISquareChar\n{\n var index: Int\n\n var char: String\n\n var text: S"
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/Windows/EditWindow.kt",
"chars": 6184,
"preview": "package ca.fuwafuwa.kaku.Windows\n\nimport android.content.Context\nimport android.graphics.Bitmap\nimport android.graphics."
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/Windows/Enums/ChoiceType.java",
"chars": 145,
"preview": "package ca.fuwafuwa.kaku.Windows.Enums;\n\n/**\n * Created by 0xbad1d3a5 on 1/9/2017.\n */\npublic enum ChoiceType {\n EDIT"
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/Windows/Enums/LayoutPosition.kt",
"chars": 110,
"preview": "package ca.fuwafuwa.kaku.Windows.Enums\n\nenum class LayoutPosition {\n TOP,\n BOTTOM,\n LEFT,\n RIGHT\n}"
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/Windows/HistoryWindow.kt",
"chars": 8634,
"preview": "package ca.fuwafuwa.kaku.Windows\n\nimport android.content.Context\nimport android.graphics.Color\nimport android.opengl.Vis"
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/Windows/InformationWindow.java",
"chars": 12357,
"preview": "package ca.fuwafuwa.kaku.Windows;\n\nimport android.animation.Animator;\nimport android.animation.AnimatorListenerAdapter;\n"
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/Windows/InstantInfoWindow.kt",
"chars": 12569,
"preview": "package ca.fuwafuwa.kaku.Windows\n\nimport android.content.Context\nimport android.graphics.Color\nimport android.util.Log\ni"
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/Windows/InstantKanjiWindow.kt",
"chars": 8980,
"preview": "package ca.fuwafuwa.kaku.Windows\n\nimport android.content.ClipData\nimport android.content.ClipboardManager\nimport android"
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/Windows/Interfaces/ICopyText.kt",
"chars": 87,
"preview": "package ca.fuwafuwa.kaku.Windows.Interfaces\n\ninterface ICopyText\n{\n fun copyText()\n}"
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/Windows/Interfaces/IRecalculateKanjiViews.kt",
"chars": 113,
"preview": "package ca.fuwafuwa.kaku.Windows.Interfaces\n\ninterface IRecalculateKanjiViews\n{\n fun recalculateKanjiViews()\n}"
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/Windows/Interfaces/ISearchPerformer.kt",
"chars": 221,
"preview": "package ca.fuwafuwa.kaku.Windows.Interfaces\n\nimport ca.fuwafuwa.kaku.Windows.Data.DisplayData\nimport ca.fuwafuwa.kaku.Wi"
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/Windows/Interfaces/WindowListener.java",
"chars": 351,
"preview": "package ca.fuwafuwa.kaku.Windows.Interfaces;\n\nimport android.view.GestureDetector;\nimport android.view.MotionEvent;\n\n/**"
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/Windows/KanjiChoiceWindow.kt",
"chars": 12511,
"preview": "package ca.fuwafuwa.kaku.Windows\n\nimport android.content.Context\nimport android.graphics.Bitmap\nimport android.graphics."
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/Windows/Views/ChoiceEditText.java",
"chars": 2654,
"preview": "package ca.fuwafuwa.kaku.Windows.Views;\n\nimport android.annotation.SuppressLint;\nimport android.content.Context;\nimport "
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/Windows/Views/ChoiceGridView.java",
"chars": 4179,
"preview": "package ca.fuwafuwa.kaku.Windows.Views;\n\nimport android.content.Context;\nimport android.graphics.Bitmap;\nimport android."
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/Windows/Views/ChoiceIconView.java",
"chars": 2534,
"preview": "package ca.fuwafuwa.kaku.Windows.Views;\n\nimport android.annotation.SuppressLint;\nimport android.content.Context;\nimport "
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/Windows/Views/KanjiCharacterView.kt",
"chars": 7928,
"preview": "package ca.fuwafuwa.kaku.Windows.Views\n\nimport android.content.Context\nimport android.graphics.Color\nimport android.util"
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/Windows/Views/KanjiGridView.kt",
"chars": 4277,
"preview": "package ca.fuwafuwa.kaku.Windows.Views\n\nimport android.content.Context\nimport android.util.AttributeSet\nimport ca.fuwafu"
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/Windows/Views/KanjiImageView.kt",
"chars": 1563,
"preview": "package ca.fuwafuwa.kaku.Windows.Views\n\nimport android.content.Context\nimport android.graphics.drawable.Drawable\nimport "
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/Windows/Views/ResizeView.java",
"chars": 2350,
"preview": "package ca.fuwafuwa.kaku.Windows.Views;\n\nimport android.content.Context;\nimport androidx.core.view.GestureDetectorCompat"
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/Windows/Views/SquareGridView.kt",
"chars": 3643,
"preview": "package ca.fuwafuwa.kaku.Windows.Views\n\nimport android.content.Context\nimport android.util.AttributeSet\nimport android.v"
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/Windows/Views/WindowView.java",
"chars": 1214,
"preview": "package ca.fuwafuwa.kaku.Windows.Views;\n\nimport android.content.Context;\nimport androidx.core.view.GestureDetectorCompat"
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/Windows/Window.java",
"chars": 15076,
"preview": "package ca.fuwafuwa.kaku.Windows;\n\nimport android.content.Context;\nimport android.graphics.PixelFormat;\nimport android.g"
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/Windows/WindowCoordinator.kt",
"chars": 2283,
"preview": "package ca.fuwafuwa.kaku.Windows\n\nimport android.content.Context\nimport ca.fuwafuwa.kaku.*\n\n/**\n * It seems like opening"
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/XmlParsers/CommonParser.java",
"chars": 3060,
"preview": "package ca.fuwafuwa.kaku.XmlParsers;\n\nimport android.content.Context;\nimport android.util.Log;\n\nimport org.xmlpull.v1.Xm"
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/XmlParsers/Interfaces/DictParser.java",
"chars": 372,
"preview": "package ca.fuwafuwa.kaku.XmlParsers.Interfaces;\n\nimport org.xmlpull.v1.XmlPullParser;\nimport org.xmlpull.v1.XmlPullParse"
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/XmlParsers/JmDict/JmConsts.java",
"chars": 2277,
"preview": "package ca.fuwafuwa.kaku.XmlParsers.JmDict;\n\n/**\n * Created by 0xbad1d3a5 on 4/25/2016.\n */\npublic class JmConsts {\n\n "
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/XmlParsers/JmDict/JmDTO/JmEntry.java",
"chars": 1956,
"preview": "package ca.fuwafuwa.kaku.XmlParsers.JmDict.JmDTO;\n\nimport org.xmlpull.v1.XmlPullParser;\nimport org.xmlpull.v1.XmlPullPar"
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/XmlParsers/JmDict/JmDTO/JmGloss.java",
"chars": 1491,
"preview": "package ca.fuwafuwa.kaku.XmlParsers.JmDict.JmDTO;\n\nimport org.xmlpull.v1.XmlPullParser;\nimport org.xmlpull.v1.XmlPullPar"
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/XmlParsers/JmDict/JmDTO/JmKEle.java",
"chars": 4664,
"preview": "package ca.fuwafuwa.kaku.XmlParsers.JmDict.JmDTO;\n\nimport org.xmlpull.v1.XmlPullParser;\nimport org.xmlpull.v1.XmlPullPar"
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/XmlParsers/JmDict/JmDTO/JmLsource.java",
"chars": 1286,
"preview": "package ca.fuwafuwa.kaku.XmlParsers.JmDict.JmDTO;\n\nimport org.xmlpull.v1.XmlPullParser;\nimport org.xmlpull.v1.XmlPullPar"
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/XmlParsers/JmDict/JmDTO/JmREle.java",
"chars": 4173,
"preview": "package ca.fuwafuwa.kaku.XmlParsers.JmDict.JmDTO;\n\nimport com.google.common.base.Joiner;\n\nimport org.xmlpull.v1.XmlPullP"
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/XmlParsers/JmDict/JmDTO/JmSense.java",
"chars": 7619,
"preview": "package ca.fuwafuwa.kaku.XmlParsers.JmDict.JmDTO;\n\nimport com.google.common.base.Joiner;\n\nimport org.xmlpull.v1.XmlPullP"
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/XmlParsers/JmDict/JmParser.java",
"chars": 18084,
"preview": "package ca.fuwafuwa.kaku.XmlParsers.JmDict;\n\nimport android.util.Log;\n\nimport com.google.common.base.Joiner;\n\nimport org"
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/XmlParsers/KanjiDict2/Kd2Consts.java",
"chars": 2649,
"preview": "package ca.fuwafuwa.kaku.XmlParsers.KanjiDict2;\n\n/**\n * Created by 0xbad1d3a5 on 11/30/2016.\n */\n\npublic class Kd2Consts"
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/XmlParsers/KanjiDict2/Kd2DTO/Kd2Character.java",
"chars": 2572,
"preview": "package ca.fuwafuwa.kaku.XmlParsers.KanjiDict2.Kd2DTO;\n\nimport org.xmlpull.v1.XmlPullParser;\nimport org.xmlpull.v1.XmlPu"
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/XmlParsers/KanjiDict2/Kd2DTO/Kd2Codepoint.java",
"chars": 1064,
"preview": "package ca.fuwafuwa.kaku.XmlParsers.KanjiDict2.Kd2DTO;\n\nimport org.xmlpull.v1.XmlPullParser;\nimport org.xmlpull.v1.XmlPu"
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/XmlParsers/KanjiDict2/Kd2DTO/Kd2CpValue.java",
"chars": 846,
"preview": "package ca.fuwafuwa.kaku.XmlParsers.KanjiDict2.Kd2DTO;\n\nimport org.xmlpull.v1.XmlPullParser;\nimport org.xmlpull.v1.XmlPu"
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/XmlParsers/KanjiDict2/Kd2DTO/Kd2DicNumber.java",
"chars": 1060,
"preview": "package ca.fuwafuwa.kaku.XmlParsers.KanjiDict2.Kd2DTO;\n\nimport org.xmlpull.v1.XmlPullParser;\nimport org.xmlpull.v1.XmlPu"
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/XmlParsers/KanjiDict2/Kd2DTO/Kd2DicRef.java",
"chars": 1004,
"preview": "package ca.fuwafuwa.kaku.XmlParsers.KanjiDict2.Kd2DTO;\n\nimport org.xmlpull.v1.XmlPullParser;\nimport org.xmlpull.v1.XmlPu"
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/XmlParsers/KanjiDict2/Kd2DTO/Kd2Meaning.java",
"chars": 962,
"preview": "package ca.fuwafuwa.kaku.XmlParsers.KanjiDict2.Kd2DTO;\n\nimport org.xmlpull.v1.XmlPullParser;\nimport org.xmlpull.v1.XmlPu"
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/XmlParsers/KanjiDict2/Kd2DTO/Kd2Misc.java",
"chars": 1963,
"preview": "package ca.fuwafuwa.kaku.XmlParsers.KanjiDict2.Kd2DTO;\n\nimport org.xmlpull.v1.XmlPullParser;\nimport org.xmlpull.v1.XmlPu"
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/XmlParsers/KanjiDict2/Kd2DTO/Kd2QCode.java",
"chars": 943,
"preview": "package ca.fuwafuwa.kaku.XmlParsers.KanjiDict2.Kd2DTO;\n\nimport org.xmlpull.v1.XmlPullParser;\nimport org.xmlpull.v1.XmlPu"
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/XmlParsers/KanjiDict2/Kd2DTO/Kd2QueryCode.java",
"chars": 1047,
"preview": "package ca.fuwafuwa.kaku.XmlParsers.KanjiDict2.Kd2DTO;\n\nimport org.xmlpull.v1.XmlPullParser;\nimport org.xmlpull.v1.XmlPu"
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/XmlParsers/KanjiDict2/Kd2DTO/Kd2RadValue.java",
"chars": 853,
"preview": "package ca.fuwafuwa.kaku.XmlParsers.KanjiDict2.Kd2DTO;\n\nimport org.xmlpull.v1.XmlPullParser;\nimport org.xmlpull.v1.XmlPu"
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/XmlParsers/KanjiDict2/Kd2DTO/Kd2Radical.java",
"chars": 1036,
"preview": "package ca.fuwafuwa.kaku.XmlParsers.KanjiDict2.Kd2DTO;\n\nimport org.xmlpull.v1.XmlPullParser;\nimport org.xmlpull.v1.XmlPu"
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/XmlParsers/KanjiDict2/Kd2DTO/Kd2Reading.java",
"chars": 1407,
"preview": "package ca.fuwafuwa.kaku.XmlParsers.KanjiDict2.Kd2DTO;\n\n//import junit.framework.Assert;\n\nimport org.xmlpull.v1.XmlPullP"
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/XmlParsers/KanjiDict2/Kd2DTO/Kd2ReadingMeaning.java",
"chars": 1387,
"preview": "package ca.fuwafuwa.kaku.XmlParsers.KanjiDict2.Kd2DTO;\n\nimport org.xmlpull.v1.XmlPullParser;\nimport org.xmlpull.v1.XmlPu"
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/XmlParsers/KanjiDict2/Kd2DTO/Kd2RmGroup.java",
"chars": 1393,
"preview": "package ca.fuwafuwa.kaku.XmlParsers.KanjiDict2.Kd2DTO;\n\nimport org.xmlpull.v1.XmlPullParser;\nimport org.xmlpull.v1.XmlPu"
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/XmlParsers/KanjiDict2/Kd2DTO/Kd2Variant.java",
"chars": 847,
"preview": "package ca.fuwafuwa.kaku.XmlParsers.KanjiDict2.Kd2DTO;\n\nimport org.xmlpull.v1.XmlPullParser;\nimport org.xmlpull.v1.XmlPu"
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/XmlParsers/KanjiDict2/Kd2Parser.java",
"chars": 5886,
"preview": "package ca.fuwafuwa.kaku.XmlParsers.KanjiDict2;\n\nimport android.util.Log;\n\nimport com.google.common.base.Function;\nimpor"
},
{
"path": "app/src/main/java/ca/fuwafuwa/kaku/XmlParsers/ParserRunnable.java",
"chars": 2898,
"preview": "package ca.fuwafuwa.kaku.XmlParsers;\n\nimport android.content.Context;\nimport android.util.Log;\nimport android.util.Xml;\n"
},
{
"path": "app/src/main/res/anim/fade_repeat.xml",
"chars": 260,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<alpha xmlns:android=\"http://schemas.android.com/apk/res/android\"\n android:fro"
},
{
"path": "app/src/main/res/anim/slide_in.xml",
"chars": 200,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<translate xmlns:android=\"http://schemas.android.com/apk/res/android\"\n android"
},
{
"path": "app/src/main/res/drawable/bg_solid_border_0_blue_black.xml",
"chars": 289,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\"\n android:"
},
{
"path": "app/src/main/res/drawable/bg_solid_border_0_white_black.xml",
"chars": 282,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\"\n android:"
},
{
"path": "app/src/main/res/drawable/bg_solid_border_corners_0_white_black_round.xml",
"chars": 594,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<layer-list xmlns:android=\"http://schemas.android.com/apk/res/android\">\n <item"
},
{
"path": "app/src/main/res/drawable/bg_translucent_border_0_black_black.xml",
"chars": 278,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\"\n android:"
},
{
"path": "app/src/main/res/drawable/bg_translucent_border_0_blue_blue.xml",
"chars": 329,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\"\n android:sha"
},
{
"path": "app/src/main/res/drawable/bg_transparent_border_0_nil_black.xml",
"chars": 286,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\"\n android:"
},
{
"path": "app/src/main/res/drawable/bg_transparent_border_0_nil_default.xml",
"chars": 330,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\"\n android:"
},
{
"path": "app/src/main/res/drawable/bg_transparent_border_0_nil_ready.xml",
"chars": 792,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<layer-list xmlns:android=\"http://schemas.android.com/apk/res/android\">\n <item"
},
{
"path": "app/src/main/res/drawable-anydpi/icon_delete.xml",
"chars": 467,
"preview": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n android:width=\"24dp\"\n android:height=\"24dp\"\n "
},
{
"path": "app/src/main/res/drawable-anydpi/icon_edit.xml",
"chars": 550,
"preview": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n android:width=\"24dp\"\n android:height=\"24dp\"\n "
},
{
"path": "app/src/main/res/drawable-anydpi/icon_swap.xml",
"chars": 456,
"preview": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n android:width=\"24dp\"\n android:height=\"24dp\"\n "
},
{
"path": "app/src/main/res/layout/activity_beta.xml",
"chars": 2244,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout\n xmlns:android=\"http://schemas.android.com/apk/res/android\"\n "
},
{
"path": "app/src/main/res/layout/activity_main.xml",
"chars": 434,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout\n xmlns:android=\"http://schemas.android.com/apk/res/android\"\n "
},
{
"path": "app/src/main/res/layout/activity_passthrough.xml",
"chars": 198,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n an"
},
{
"path": "app/src/main/res/layout/activity_tutorial.xml",
"chars": 962,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout\n xmlns:android=\"http://schemas.android.com/apk/res/android\"\n "
},
{
"path": "app/src/main/res/layout/dialog_rating_stars.xml",
"chars": 1920,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout\n xmlns:android=\"http://schemas.android.com/apk/res/android\"\n "
},
{
"path": "app/src/main/res/layout/fragment_end.xml",
"chars": 2190,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.constraintlayout.widget.ConstraintLayout\n xmlns:android=\"http://sche"
},
{
"path": "app/src/main/res/layout/fragment_start.xml",
"chars": 5382,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.constraintlayout.widget.ConstraintLayout\n xmlns:android=\"http://sche"
},
{
"path": "app/src/main/res/layout/fragment_tutorial.xml",
"chars": 2081,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout\n xmlns:android=\"http://schemas.android.com/apk/res/android\"\n "
},
{
"path": "app/src/main/res/layout/fragment_welcome.xml",
"chars": 1895,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.constraintlayout.widget.ConstraintLayout\n xmlns:android=\"http://sche"
},
{
"path": "app/src/main/res/layout/window.xml",
"chars": 712,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<ca.fuwafuwa.kaku.Windows.Views.WindowView\n xmlns:android=\"http://schemas.andr"
},
{
"path": "app/src/main/res/layout/window_capture.xml",
"chars": 794,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<FrameLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n andro"
},
{
"path": "app/src/main/res/layout/window_edit.xml",
"chars": 1115,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n an"
},
{
"path": "app/src/main/res/layout/window_history.xml",
"chars": 2283,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout\n xmlns:android=\"http://schemas.android.com/apk/res/android\"\n "
},
{
"path": "app/src/main/res/layout/window_info.xml",
"chars": 3206,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<FrameLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n andro"
},
{
"path": "app/src/main/res/layout/window_instant_info.xml",
"chars": 944,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<FrameLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n andro"
},
{
"path": "app/src/main/res/layout/window_instant_kanji.xml",
"chars": 765,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<FrameLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n andro"
},
{
"path": "app/src/main/res/layout/window_kanji_choice.xml",
"chars": 256,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n an"
},
{
"path": "app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml",
"chars": 265,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<adaptive-icon xmlns:android=\"http://schemas.android.com/apk/res/android\">\n <b"
},
{
"path": "app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml",
"chars": 265,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<adaptive-icon xmlns:android=\"http://schemas.android.com/apk/res/android\">\n <b"
},
{
"path": "app/src/main/res/values/colors.xml",
"chars": 797,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n <color name=\"Primary\">#FFFFFF</color>\n <color name=\"Accent\">#F"
},
{
"path": "app/src/main/res/values/dimens.xml",
"chars": 211,
"preview": "<resources>\n <!-- Default screen margins, per the Android Design guidelines. -->\n <dimen name=\"activity_horizontal"
},
{
"path": "app/src/main/res/values/strings.xml",
"chars": 3356,
"preview": "<resources>\n <string name=\"app_name\">Kaku</string>\n <string name=\"support_text\">\"Like Kaku? Rate the app!\"</string"
},
{
"path": "app/src/main/res/values/styles.xml",
"chars": 382,
"preview": "<resources>\n\n <!-- Base application theme. -->\n <style name=\"AppTheme\" parent=\"Theme.AppCompat.NoActionBar\">\n "
},
{
"path": "app/src/main/res/values-w820dp/dimens.xml",
"chars": 358,
"preview": "<resources>\n <!-- Example customization of dimensions originally defined in res/values/dimens.xml\n (such as s"
},
{
"path": "app/src/test/java/ca/fuwafuwa/kaku/ExampleUnitTest.java",
"chars": 1512,
"preview": "package ca.fuwafuwa.kaku;\n\nimport android.util.Xml;\n\nimport com.atilika.kuromoji.ipadic.Token;\nimport com.atilika.kuromo"
},
{
"path": "app/src/test/java/ca/fuwafuwa/kaku/GenerateDictionary.java",
"chars": 2434,
"preview": "package ca.fuwafuwa.kaku;\n\nimport android.util.Xml;\n\nimport com.j256.ormlite.dao.Dao;\nimport com.j256.ormlite.dao.DaoMan"
},
{
"path": "build.gradle",
"chars": 697,
"preview": "// Top-level build file where you can add configuration options common to all sub-projects/modules.\n\nbuildscript {\n e"
},
{
"path": "fastlane/metadata/android/en-US/full_description.txt",
"chars": 423,
"preview": "Kaku is a fast, powerful Japanese dictionary that stays on top of all your apps. It uses optical character recognition ("
},
{
"path": "fastlane/metadata/android/en-US/short_description.txt",
"chars": 23,
"preview": "Japanese OCR Dictionary"
},
{
"path": "gradle/wrapper/gradle-wrapper.properties",
"chars": 230,
"preview": "#Sat Mar 20 03:53:32 PDT 2021\ndistributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\nzipStoreBase=GRADLE_USER_"
},
{
"path": "gradle.properties",
"chars": 908,
"preview": "# Project-wide Gradle settings.\n\n# IDE (e.g. Android Studio) users:\n# Gradle settings configured through the IDE *will o"
},
{
"path": "gradlew",
"chars": 4971,
"preview": "#!/usr/bin/env bash\n\n##############################################################################\n##\n## Gradle start "
},
{
"path": "gradlew.bat",
"chars": 2314,
"preview": "@if \"%DEBUG%\" == \"\" @echo off\n@rem ##########################################################################\n@rem\n@rem "
},
{
"path": "projectFilesBackup/.idea/workspace.xml",
"chars": 270142,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n <component name=\"AndroidLayouts\">\n <shared>\n <con"
},
{
"path": "settings.gradle",
"chars": 15,
"preview": "include ':app'\n"
}
]
// ... and 1 more files (download for full content)
About this extraction
This page contains the full source code of the 0xbad1d3a5/Kaku GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 175 files (704.4 KB), approximately 180.1k tokens, and a symbol index with 507 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.