Compare commits

...

12 Commits

Author SHA1 Message Date
5ba64bbb46 Ignore android-data 2022-06-04 15:51:04 +02:00
67f46ccbc7 Add more functionality to sqlite database
- Automate and cache dart sql generators
- Add RADKFILE
- Add jouyou kanji data
2022-05-08 15:39:57 +02:00
d652fc0685 Update API 2022-05-08 15:33:03 +02:00
5d377aa668 Move images to subfolders 2022-05-07 19:46:33 +02:00
46fb93efe3 Start modelling a sqlite database 2022-05-07 18:35:50 +02:00
936c669118 Add nix flake 2022-05-07 00:01:31 +02:00
c242d56f41 Misc cleanup 2022-05-04 23:02:12 +02:00
edd3d7c9a9 Add import export functionality 2022-05-04 23:01:53 +02:00
7ad6540962 Update project files 2022-05-04 22:53:34 +02:00
76061a42f1 Add a failsafe for extraData searches 2022-05-01 23:34:11 +02:00
eaa5510942 Export reused kanji regex into own file 2022-05-01 23:33:45 +02:00
8c7253fd93 Update Jisho API version 2022-02-13 01:39:31 +01:00
86 changed files with 80013 additions and 230 deletions

22
.gitignore vendored
View File

@@ -22,6 +22,7 @@
# Flutter/Dart/Pub related
**/doc/api/
**/ios/Flutter/.last_build_id
.dart_tool/
.flutter-plugins
.flutter-plugins-dependencies
@@ -33,5 +34,22 @@
# Web related
lib/generated_plugin_registrant.dart
# Exceptions to above rules.
!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages
# Symbolication related
app.*.symbols
# Obfuscation related
app.*.map.json
# Android Studio will place build artifacts here
/android/app/debug
/android/app/profile
/android/app/release
# -----------------------------
# Nix build result
result
# The dev directory I'm using when moving files via adb
android-data

View File

@@ -4,7 +4,7 @@
# This file should be version controlled and should not be manually edited.
version:
revision: 0b8abb4724aa590dd0f429683339b1e045a1594d
revision: 7e9793dee1b85a243edd0e06cb1658e98b077561
channel: stable
project_type: app

6
android/.gitignore vendored
View File

@@ -5,3 +5,9 @@ gradle-wrapper.jar
/gradlew.bat
/local.properties
GeneratedPluginRegistrant.java
# Remember to never publicly share your keystore.
# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app
key.properties
**/*.keystore
**/*.jks

View File

@@ -26,24 +26,29 @@ apply plugin: 'kotlin-android'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
android {
compileSdkVersion 28
compileSdkVersion flutter.compileSdkVersion
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
sourceSets {
main.java.srcDirs += 'src/main/kotlin'
}
lintOptions {
disable 'InvalidPackage'
}
defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId "com.example.jisho_study_tool"
minSdkVersion 16
targetSdkVersion 28
applicationId "app.jishostudytool.jisho_study_tool"
// minSdkVersion flutter.minSdkVersion
minSdkVersion 19
targetSdkVersion flutter.targetSdkVersion
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
@@ -61,7 +66,4 @@ flutter {
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test:runner:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1'
}

View File

@@ -1,7 +1,10 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.jisho_study_tool">
package="app.jishostudytool.jisho_study_tool">
<!-- Flutter needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.
-->
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_INTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
</manifest>

View File

@@ -1,21 +1,25 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.jisho_study_tool">
<!-- io.flutter.app.FlutterApplication is an android.app.Application that
calls FlutterMain.startInitialization(this); in its onCreate method.
In most cases you can leave this as-is, but you if you want to provide
additional functionality it is fine to subclass or reimplement
FlutterApplication and put your custom class here. -->
<application
android:name="io.flutter.app.FlutterApplication"
android:label="jisho_study_tool"
package="app.jishostudytool.jisho_study_tool">
<application
android:label="Jisho Study Tool"
android:name="${applicationName}"
android:icon="@mipmap/launcher_icon">
<activity
android:name=".MainActivity"
android:exported="true"
android:launchMode="singleTop"
android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize">
<!-- Specifies an Android theme to apply to this Activity as soon as
the Android process has started. This theme is visible to the user
while the Flutter UI initializes. After that, this theme continues
to determine the Window background behind the Flutter UI. -->
<meta-data
android:name="io.flutter.embedding.android.NormalTheme"
android:resource="@style/NormalTheme"
/>
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
@@ -28,4 +32,7 @@
android:value="2" />
</application>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_INTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
</manifest>

View File

@@ -0,0 +1,20 @@
// Generated file.
// If you wish to remove Flutter's multidex support, delete this entire file.
package io.flutter.app;
import android.content.Context;
import androidx.annotation.CallSuper;
import androidx.multidex.MultiDex;
/**
* Extension of {@link io.flutter.app.FlutterApplication}, adding multidex support.
*/
public class FlutterMultiDexApplication extends FlutterApplication {
@Override
@CallSuper
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
MultiDex.install(this);
}
}

View File

@@ -0,0 +1,6 @@
package app.jishostudytool.jisho_study_tool
import io.flutter.embedding.android.FlutterActivity
class MainActivity: FlutterActivity() {
}

View File

@@ -1,12 +0,0 @@
package com.example.jisho_study_tool
import androidx.annotation.NonNull;
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugins.GeneratedPluginRegistrant
class MainActivity: FlutterActivity() {
override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
GeneratedPluginRegistrant.registerWith(flutterEngine);
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.8 KiB

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.8 KiB

After

Width:  |  Height:  |  Size: 7.7 KiB

View File

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is off -->
<style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
<item name="android:forceDarkAllowed">false</item>
<item name="android:windowFullscreen">false</item>
<item name="android:windowSplashScreenBackground">#202020</item>
</style>
<!-- Theme applied to the Android Window as soon as the process has started.
This theme determines the color of the Android Window while your
Flutter UI initializes, as well as behind your Flutter UI while its
running.
This Theme is only used starting with V2 of Flutter's Android embedding. -->
<style name="NormalTheme" parent="@android:style/Theme.Black.NoTitleBar">
<item name="android:windowBackground">?android:colorBackground</item>
</style>
</resources>

View File

@@ -5,13 +5,14 @@
<!-- Show a splash screen on the activity. Automatically removed when
Flutter draws its first frame -->
<item name="android:windowBackground">@drawable/launch_background</item>
<item name="android:forceDarkAllowed">false</item>
<item name="android:windowFullscreen">false</item>
</style>
<!-- Theme applied to the Android Window as soon as the process has started.
This theme determines the color of the Android Window while your
Flutter UI initializes, as well as behind your Flutter UI while its
running.
This Theme is only used starting with V2 of Flutter's Android embedding. -->
<style name="NormalTheme" parent="@android:style/Theme.Black.NoTitleBar">
<item name="android:windowBackground">?android:colorBackground</item>

View File

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is off -->
<style name="LaunchTheme" parent="@android:style/Theme.Light.NoTitleBar">
<item name="android:forceDarkAllowed">false</item>
<item name="android:windowFullscreen">false</item>
<item name="android:windowSplashScreenBackground">#3edd00</item>
</style>
<!-- Theme applied to the Android Window as soon as the process has started.
This theme determines the color of the Android Window while your
Flutter UI initializes, as well as behind your Flutter UI while its
running.
This Theme is only used starting with V2 of Flutter's Android embedding. -->
<style name="NormalTheme" parent="@android:style/Theme.Light.NoTitleBar">
<item name="android:windowBackground">?android:colorBackground</item>
</style>
</resources>

View File

@@ -1,8 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is off -->
<style name="LaunchTheme" parent="@android:style/Theme.Light.NoTitleBar">
<!-- Show a splash screen on the activity. Automatically removed when
Flutter draws its first frame -->
<item name="android:windowBackground">@drawable/launch_background</item>
<item name="android:forceDarkAllowed">false</item>
<item name="android:windowFullscreen">false</item>
</style>
</resources>
<!-- Theme applied to the Android Window as soon as the process has started.
This theme determines the color of the Android Window while your
Flutter UI initializes, as well as behind your Flutter UI while its
running.
This Theme is only used starting with V2 of Flutter's Android embedding. -->
<style name="NormalTheme" parent="@android:style/Theme.Light.NoTitleBar">
<item name="android:windowBackground">?android:colorBackground</item>
</style>
</resources>

View File

@@ -1,7 +1,10 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.jisho_study_tool">
package="app.jishostudytool.jisho_study_tool">
<!-- Flutter needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.
-->
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_INTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
</manifest>

View File

@@ -1,12 +1,12 @@
buildscript {
ext.kotlin_version = '1.5.0'
ext.kotlin_version = '1.6.10'
repositories {
google()
jcenter()
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:7.0.3'
classpath 'com.android.tools.build:gradle:4.1.0'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
@@ -14,7 +14,7 @@ buildscript {
allprojects {
repositories {
google()
jcenter()
mavenCentral()
}
}

View File

@@ -1,4 +1,3 @@
org.gradle.jvmargs=-Xmx1536M
android.enableR8=true
android.useAndroidX=true
android.enableJetifier=true

View File

@@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-all.zip

View File

@@ -1,15 +1,11 @@
include ':app'
def flutterProjectRoot = rootProject.projectDir.parentFile.toPath()
def localPropertiesFile = new File(rootProject.projectDir, "local.properties")
def properties = new Properties()
def plugins = new Properties()
def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins')
if (pluginsFile.exists()) {
pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) }
}
assert localPropertiesFile.exists()
localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) }
plugins.each { name, path ->
def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile()
include ":$name"
project(":$name").projectDir = pluginDirectory
}
def flutterSdkPath = properties.getProperty("flutter.sdk")
assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle"

View File

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 25 KiB

View File

@@ -0,0 +1,122 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
id="svg2443"
sodipodi:version="0.32"
inkscape:version="0.46"
width="228.14874"
height="60.237499"
xml:space="preserve"
sodipodi:docname="Compart Logo.svg"
version="1.0"
inkscape:output_extension="org.inkscape.output.svg.inkscape"><metadata
id="metadata2448"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
id="defs2446"><inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : 526.18109 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="744.09448 : 526.18109 : 1"
inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
id="perspective2450" /><clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath2458"><path
d="M 0,682.495 L 594.96,682.495 L 594.96,48.244 L 0,48.244 L 0,682.495 z"
id="path2460" /></clipPath><clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath2470"><path
d="M 0,841.945 L 594.96,841.945 L 594.96,0.055 L 0,0.055 L 0,841.945 z"
id="path2472" /></clipPath><clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath2496"><path
d="M 0,841.945 L 594.96,841.945 L 594.96,0.055 L 0,0.055 L 0,841.945 z"
id="path2498" /></clipPath><clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath2512"><path
d="M 0,841.945 L 594.96,841.945 L 594.96,0.055 L 0,0.055 L 0,841.945 z"
id="path2514" /></clipPath><clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath2532"><path
d="M 563.399,34.611 L 584.608,34.611 L 584.608,13.402 L 563.399,13.402 L 563.399,34.611 z"
id="path2534" /></clipPath><clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath2554"><path
d="M 0,841.945 L 594.96,841.945 L 594.96,0.055 L 0,0.055 L 0,841.945 z"
id="path2556" /></clipPath></defs><sodipodi:namedview
inkscape:window-height="974"
inkscape:window-width="1280"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
guidetolerance="10.0"
gridtolerance="10.0"
objecttolerance="10.0"
borderopacity="1.0"
bordercolor="#666666"
pagecolor="#ffffff"
id="base"
showgrid="false"
inkscape:zoom="4"
inkscape:cx="235.03328"
inkscape:cy="66.25"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:current-layer="g2510" /><g
id="g2452"
inkscape:groupmode="layer"
inkscape:label="Format-Nr-6-2006-03"
transform="matrix(1.25,0,0,-1.25,-226.22766,443.03353)"><g
id="g2508"
transform="translate(-231.45887,306.18182)"><g
id="g2510"
clip-path="url(#clipPath2512)"><path
d="M 574.003,46.057 L 603.942,46.057 L 603.942,2.245 L 574.003,2.245 L 574.003,46.057 z"
style="fill:#231f20;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path2520" /><path
d="M 552.796,48.245 L 603.942,48.245 L 603.942,45.215 L 552.796,45.215 L 552.796,48.245 z"
style="fill:#ed1c24;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path2522" /><path
d="M 552.796,2.798 L 603.942,2.798 L 603.942,-8.486 L 552.796,-8.486 L 552.796,2.798 z"
style="fill:#ed1c24;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path2524" /></g></g><path
d="M 331.94013,340.79282 L 353.14913,340.79282 L 353.14913,319.58382 L 331.94013,319.58382 L 331.94013,340.79282 z"
style="fill:#231f20;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path2526" /><g
id="g2528"
transform="translate(-231.45887,306.18182)"><g
id="g2530"
clip-path="url(#clipPath2532)"><path
d="M 574.003,35.651 L 586.674,35.651 L 586.674,11.401 L 574.003,11.401 L 574.003,35.651 z"
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path2536" /></g></g><path
d="M 202.82513,335.47782 C 201.67913,336.11382 200.34213,336.43182 199.00613,336.43182 C 193.88213,336.43182 189.87213,332.80382 189.87213,327.55282 C 189.87213,322.62082 193.91413,319.02482 198.75113,319.02482 C 200.15113,319.02482 201.55213,319.31082 202.82513,319.94782 L 202.82513,324.84782 C 202.06113,324.14782 200.94713,323.73482 199.92913,323.73482 C 197.54213,323.73482 195.85513,325.38882 195.85513,327.74382 C 195.85513,330.00382 197.60613,331.72182 199.83313,331.72182 C 200.94713,331.72182 201.96513,331.21282 202.82513,330.57682 L 202.82513,335.47782"
style="fill:#231f20;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path2538" /><path
d="M 213.68613,336.43182 C 208.43513,336.43182 203.85213,333.28182 203.85213,327.71282 C 203.85213,322.14282 208.46713,319.02482 213.68613,319.02482 C 218.93713,319.02482 223.51913,322.17482 223.51913,327.71282 C 223.51913,333.28182 218.93713,336.43182 213.68613,336.43182 z M 213.68613,331.40382 C 216.04113,331.40382 217.40913,329.71682 217.40913,327.71282 C 217.40913,325.64382 216.04113,324.05282 213.68613,324.05282 C 211.33113,324.05282 209.96313,325.64382 209.96313,327.71282 C 209.96313,329.71682 211.33113,331.40382 213.68613,331.40382"
style="fill:#231f20;fill-opacity:1;fill-rule:evenodd;stroke:none"
id="path2540" /><path
d="M 230.92713,335.89082 L 225.13513,335.89082 L 225.13513,319.56582 L 230.92713,319.56582 L 230.92713,327.36282 C 230.92713,329.17582 230.92713,331.94482 233.50513,331.94482 C 236.08213,331.94482 236.08213,329.17582 236.08213,327.36282 L 236.08213,319.56582 L 241.87413,319.56582 L 241.87413,327.36282 C 241.87413,329.30382 241.97013,331.81782 244.64313,331.81782 C 247.09313,331.81782 247.03013,329.04882 247.03013,327.36282 L 247.03013,319.56582 L 252.82213,319.56582 L 252.82213,329.97182 C 252.82213,333.72682 251.39013,336.43182 247.25313,336.43182 C 245.02513,336.43182 242.82913,335.34982 241.71513,333.31382 C 240.53813,335.47782 238.50113,336.43182 236.14613,336.43182 C 234.04613,336.43182 232.35913,335.66882 230.99113,333.85482 L 230.92713,333.85482 L 230.92713,335.89082"
style="fill:#231f20;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path2542" /><path
d="M 260.98013,335.89082 L 255.18813,335.89082 L 255.18813,311.41882 L 260.98013,311.41882 L 260.98013,321.12482 C 262.22113,319.69282 264.16213,319.02482 266.04013,319.02482 C 270.87713,319.02482 274.21913,322.97082 274.21913,327.68082 C 274.21913,332.35882 270.84513,336.43182 265.97613,336.43182 C 264.06713,336.43182 262.09413,335.66882 261.04413,334.04582 L 260.98013,334.04582 L 260.98013,335.89082 z M 264.51213,331.40382 C 266.86713,331.40382 268.23613,329.71682 268.23613,327.71282 C 268.23613,325.64382 266.86713,324.05282 264.51213,324.05282 C 262.15713,324.05282 260.78913,325.64382 260.78913,327.71282 C 260.78913,329.71682 262.15713,331.40382 264.51213,331.40382"
style="fill:#231f20;fill-opacity:1;fill-rule:evenodd;stroke:none"
id="path2544" /><path
d="M 285.26213,331.40382 C 287.61713,331.40382 288.98513,329.71682 288.98513,327.71282 C 288.98513,325.64382 287.61713,324.05282 285.26213,324.05282 C 282.90713,324.05282 281.53913,325.64382 281.53913,327.71282 C 281.53913,329.71682 282.90713,331.40382 285.26213,331.40382 z M 294.58613,335.89082 L 288.79413,335.89082 L 288.79413,334.29982 C 287.58513,335.73182 285.61213,336.43182 283.73413,336.43182 C 278.89713,336.43182 275.55613,332.42282 275.55613,327.74382 C 275.55613,323.06582 278.96113,319.02482 283.79813,319.02482 C 285.70713,319.02482 287.71213,319.75682 288.73113,321.37982 L 288.79413,321.37982 L 288.79413,319.56582 L 294.58613,319.56582 L 294.58613,335.89082"
style="fill:#231f20;fill-opacity:1;fill-rule:evenodd;stroke:none"
id="path2546" /><path
d="M 302.59613,335.89082 L 296.80413,335.89082 L 296.80413,319.56582 L 302.59613,319.56582 L 302.59613,326.15282 C 302.59613,328.95382 303.39213,331.08582 306.60613,331.08582 C 307.49713,331.08582 308.26113,330.98982 309.05613,330.54482 L 309.05613,336.11382 L 307.94313,336.11382 C 305.68313,336.11382 303.77313,335.22282 302.66013,333.21782 L 302.59613,333.21782 L 302.59613,335.89082"
style="fill:#231f20;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path2548" /><g
id="g2550"><g
id="g2552"
clip-path="url(#clipPath2554)"><path
d="M 318.04513,331.11782 L 321.32313,331.11782 L 321.32313,335.89082 L 318.04513,335.89082 L 318.04513,340.79182 L 312.25313,340.79182 L 312.25313,335.89082 L 310.37513,335.89082 L 310.37513,331.11782 L 312.25313,331.11782 L 312.25313,319.56582 L 318.04513,319.56582 L 318.04513,331.11782"
style="fill:#231f20;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path2558" /></g></g></g></svg>

After

Width:  |  Height:  |  Size: 9.1 KiB

View File

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 28 KiB

View File

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

184
flake.lock generated Normal file
View File

@@ -0,0 +1,184 @@
{
"nodes": {
"android-nixpkgs": {
"inputs": {
"devshell": "devshell",
"flake-utils": "flake-utils_2",
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1651782096,
"narHash": "sha256-rrj0HPwmDf6Q14sljnVf2hkMvc97rndgi4PJkFtpFPk=",
"owner": "tadfisher",
"repo": "android-nixpkgs",
"rev": "ccd2a8f58709ea3413fcb72769b2f62a98332215",
"type": "github"
},
"original": {
"owner": "tadfisher",
"repo": "android-nixpkgs",
"type": "github"
}
},
"devshell": {
"inputs": {
"flake-utils": "flake-utils",
"nixpkgs": "nixpkgs"
},
"locked": {
"lastModified": 1650900878,
"narHash": "sha256-qhNncMBSa9STnhiLfELEQpYC1L4GrYHNIzyCZ/pilsI=",
"owner": "numtide",
"repo": "devshell",
"rev": "d97df53b5ddaa1cfbea7cddbd207eb2634304733",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "devshell",
"type": "github"
}
},
"flake-utils": {
"locked": {
"lastModified": 1642700792,
"narHash": "sha256-XqHrk7hFb+zBvRg6Ghl+AZDq03ov6OshJLiSWOoX5es=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "846b2ae0fc4cc943637d3d1def4454213e203cba",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"flake-utils_2": {
"locked": {
"lastModified": 1649676176,
"narHash": "sha256-OWKJratjt2RW151VUlJPRALb7OU2S5s+f0vLj4o1bHM=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "a4b154ebbdc88c8498a5c7b01589addc9e9cb678",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"flake-utils_3": {
"locked": {
"lastModified": 1649676176,
"narHash": "sha256-OWKJratjt2RW151VUlJPRALb7OU2S5s+f0vLj4o1bHM=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "a4b154ebbdc88c8498a5c7b01589addc9e9cb678",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"flake-utils_4": {
"locked": {
"lastModified": 1649676176,
"narHash": "sha256-OWKJratjt2RW151VUlJPRALb7OU2S5s+f0vLj4o1bHM=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "a4b154ebbdc88c8498a5c7b01589addc9e9cb678",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"nix-dart": {
"inputs": {
"flake-utils": "flake-utils_4",
"nixpkgs": [
"nixpkgs"
],
"pub2nix": "pub2nix"
},
"locked": {
"lastModified": 1651781526,
"narHash": "sha256-q01e+S69g4UDrMcEitaQOccr2aHeiJ+VEmPS94h/7WY=",
"owner": "tadfisher",
"repo": "nix-dart",
"rev": "71d2fda0f9590d5de917fb736dee312d9fef7e27",
"type": "github"
},
"original": {
"owner": "tadfisher",
"repo": "nix-dart",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1643381941,
"narHash": "sha256-pHTwvnN4tTsEKkWlXQ8JMY423epos8wUOhthpwJjtpc=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "5efc8ca954272c4376ac929f4c5ffefcc20551d5",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixpkgs-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs_2": {
"locked": {
"lastModified": 1651743098,
"narHash": "sha256-NuQNu6yHh54li0kZffM59FRC5bWCJusygL4Cy+3O0fY=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "d4191fe35cbe52f755ef73009d4d37b9e002efa2",
"type": "github"
},
"original": {
"id": "nixpkgs",
"ref": "nixos-21.11",
"type": "indirect"
}
},
"pub2nix": {
"flake": false,
"locked": {
"lastModified": 1594192744,
"narHash": "sha256-pDvcXSG1Mh2BpwkqAcNDJzcupV3pIAAtZJLfkiHMAz4=",
"owner": "paulyoung",
"repo": "pub2nix",
"rev": "0c7ecca590fcd1616db8c6468f799ffef36c85e9",
"type": "github"
},
"original": {
"owner": "paulyoung",
"repo": "pub2nix",
"type": "github"
}
},
"root": {
"inputs": {
"android-nixpkgs": "android-nixpkgs",
"flake-utils": "flake-utils_3",
"nix-dart": "nix-dart",
"nixpkgs": "nixpkgs_2"
}
}
},
"root": "root",
"version": 7
}

116
flake.nix Normal file
View File

@@ -0,0 +1,116 @@
{
description = "A dictionary app for studying japanese";
inputs = {
nixpkgs.url = "nixpkgs/nixos-21.11";
flake-utils = {
url = "github:numtide/flake-utils";
inputs.nixpkgs.follows = "nixpkgs";
};
android-nixpkgs = {
url = "github:tadfisher/android-nixpkgs";
inputs.nixpkgs.follows = "nixpkgs";
};
nix-dart = {
url = "github:tadfisher/nix-dart";
inputs.nixpkgs.follows = "nixpkgs";
};
# nix-flutter = {
# url = "path:/home/h7x4/git/flutter_linux_2.5.1-stable/flutter";
# inputs.nixpkgs.follows = "nixpkgs";
# };
};
outputs = { self, nixpkgs, flake-utils, android-nixpkgs, nix-dart }:
let
system = "x86_64-linux";
pkgs = import nixpkgs {
inherit system;
config = {
android_sdk.accept_license = true;
allowUnfree = true;
};
};
dartVersion = "2.14.2";
dartChannel = "stable";
flutterVersion = "2.5.1";
flutterChannel = "stable";
in {
packages.${system} = {
android-sdk = android-nixpkgs.sdk.${system} (sdkPkgs: with sdkPkgs; [
cmdline-tools-latest
build-tools-32-0-0
build-tools-31-0-0
build-tools-30-0-2
build-tools-29-0-2
platform-tools
platforms-android-32
platforms-android-31
platforms-android-30
platforms-android-29
emulator
]);
# dart = nix-dart.packages.${system}.dart;
dart = (pkgs.callPackage ./nix/dart.nix {});
inherit (pkgs.callPackage ./nix/flutter.nix { inherit (self.packages.${system}) dart; }) flutter;
# pub2nix-lock = nix-dart.packages.${system}.pub2nix-lock;
};
# apps.${system} = {
# web-debug = {
# type = "app";
# program = "";
# };
# web-release = {
# type = "app";
# program = "";
# };
# apk-debug = {
# type = "app";
# program = "";
# };
# apk-release = {
# type = "app";
# program = "${self.packages.${system}.flutter}/bin/flutter run --release";
# };
# default = self.apps.${system}.apk-debug;
# };
devShell.${system} = let
inherit (pkgs) lcov google-chrome sqlite sqlite-web;
inherit (self.packages.${system}) android-sdk flutter dart;
inherit (nix-dart.packages.${system}) pub2nix-lock;
java = pkgs.jdk8;
in pkgs.mkShell rec {
ANDROID_JAVA_HOME="${java.home}";
ANDROID_SDK_ROOT = "${android-sdk}/share/android-sdk";
CHROME_EXECUTABLE = "${google-chrome}/bin/google-chrome-stable";
FLUTTER_SDK="${flutter}";
GRADLE_OPTS = "-Dorg.gradle.project.android.aapt2FromMavenOverride=${ANDROID_SDK_ROOT}/build-tools/32.0.0/aapt2";
JAVA_HOME="${ANDROID_JAVA_HOME}";
USE_CCACHE=0;
buildInputs = [
android-sdk
dart
flutter
google-chrome
java
lcov
pub2nix-lock
sqlite
sqlite-web
];
};
};
}

2
ios/.gitignore vendored
View File

@@ -1,3 +1,4 @@
**/dgph
*.mode1v3
*.mode2v3
*.moved-aside
@@ -18,6 +19,7 @@ Flutter/App.framework
Flutter/Flutter.framework
Flutter/Flutter.podspec
Flutter/Generated.xcconfig
Flutter/ephemeral/
Flutter/app.flx
Flutter/app.zip
Flutter/flutter_assets/

View File

@@ -3,7 +3,7 @@
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<string>en</string>
<key>CFBundleExecutable</key>
<string>App</string>
<key>CFBundleIdentifier</key>
@@ -21,6 +21,6 @@
<key>CFBundleVersion</key>
<string>1.0</string>
<key>MinimumOSVersion</key>
<string>8.0</string>
<string>9.0</string>
</dict>
</plist>

View File

@@ -3,17 +3,13 @@
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objectVersion = 50;
objects = {
/* Begin PBXBuildFile section */
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; };
3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; };
9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
@@ -26,8 +22,6 @@
dstPath = "";
dstSubfolderSpec = 10;
files = (
3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */,
9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */,
);
name = "Embed Frameworks";
runOnlyForDeploymentPostprocessing = 0;
@@ -38,13 +32,11 @@
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = "<group>"; };
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; };
9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; sourceTree = "<group>"; };
97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
@@ -57,8 +49,6 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */,
3B80C3941E831B6300D905FE /* App.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -68,9 +58,7 @@
9740EEB11CF90186004384FC /* Flutter */ = {
isa = PBXGroup;
children = (
3B80C3931E831B6300D905FE /* App.framework */,
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
9740EEBA1CF902C7004384FC /* Flutter.framework */,
9740EEB21CF90195004384FC /* Debug.xcconfig */,
7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
9740EEB31CF90195004384FC /* Generated.xcconfig */,
@@ -102,7 +90,6 @@
97C146FD1CF9000F007C117D /* Assets.xcassets */,
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
97C147021CF9000F007C117D /* Info.plist */,
97C146F11CF9000F007C117D /* Supporting Files */,
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */,
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
74858FAE1ED2DC5600515810 /* AppDelegate.swift */,
@@ -111,13 +98,6 @@
path = Runner;
sourceTree = "<group>";
};
97C146F11CF9000F007C117D /* Supporting Files */ = {
isa = PBXGroup;
children = (
);
name = "Supporting Files";
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
@@ -147,8 +127,8 @@
97C146E61CF9000F007C117D /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 1020;
ORGANIZATIONNAME = "The Chromium Authors";
LastUpgradeCheck = 1300;
ORGANIZATIONNAME = "";
TargetAttributes = {
97C146ED1CF9000F007C117D = {
CreatedOnToolsVersion = 7.3.1;
@@ -157,7 +137,7 @@
};
};
buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
compatibilityVersion = "Xcode 3.2";
compatibilityVersion = "Xcode 9.3";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
@@ -201,7 +181,7 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin";
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
};
9740EEB61CF901F6004384FC /* Run Script */ = {
isa = PBXShellScriptBuildPhase;
@@ -253,7 +233,6 @@
/* Begin XCBuildConfiguration section */
249021D3217E4FDB00AE95B9 /* Profile */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
@@ -293,7 +272,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos;
@@ -310,17 +289,12 @@
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
LIBRARY_SEARCH_PATHS = (
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.example.jishoStudyTool;
PRODUCT_BUNDLE_IDENTIFIER = app.jishostudytool.jishoStudyTool;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;
@@ -330,7 +304,6 @@
};
97C147031CF9000F007C117D /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
@@ -376,7 +349,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
@@ -386,7 +359,6 @@
};
97C147041CF9000F007C117D /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
@@ -426,11 +398,12 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos;
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_OPTIMIZATION_LEVEL = "-O";
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
};
@@ -444,17 +417,12 @@
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
LIBRARY_SEARCH_PATHS = (
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.example.jishoStudyTool;
PRODUCT_BUNDLE_IDENTIFIER = app.jishostudytool.jishoStudyTool;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
@@ -471,17 +439,12 @@
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
LIBRARY_SEARCH_PATHS = (
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.example.jishoStudyTool;
PRODUCT_BUNDLE_IDENTIFIER = app.jishostudytool.jishoStudyTool;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;

View File

@@ -2,6 +2,6 @@
<Workspace
version = "1.0">
<FileRef
location = "group:Runner.xcodeproj">
location = "self:">
</FileRef>
</Workspace>

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>PreviewsEnabled</key>
<false/>
</dict>
</plist>

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1020"
LastUpgradeVersion = "1300"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
@@ -27,8 +27,6 @@
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
@@ -38,8 +36,8 @@
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
<Testables>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
@@ -61,8 +59,6 @@
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Profile"

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>PreviewsEnabled</key>
<false/>
</dict>
</plist>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.4 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.8 KiB

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.4 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.9 KiB

After

Width:  |  Height:  |  Size: 7.7 KiB

View File

@@ -4,6 +4,8 @@
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key>
<string>Jisho Study Tool</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>

View File

@@ -1 +1 @@
#import "GeneratedPluginRegistrant.h"
#import "GeneratedPluginRegistrant.h"

View File

@@ -17,7 +17,7 @@ class DenshiJishoBackground extends StatelessWidget {
left: 100,
bottom: 30,
child: Image.asset(
'assets/images/denshi_jisho_background_overlay.png',
'assets/images/components/denshi_jisho_background_overlay.png',
),
),
child,

View File

@@ -9,6 +9,7 @@ import './kanji_result_body/radical.dart';
import './kanji_result_body/rank.dart';
import './kanji_result_body/stroke_order_gif.dart';
import './kanji_result_body/yomi_chips.dart';
import '../../services/kanji_grade_conversion.dart';
class KanjiResultBody extends StatelessWidget {
late final String query;
@@ -24,6 +25,7 @@ class KanjiResultBody extends StatelessWidget {
resultData = result.data!;
}
// TODO: add compart link
Widget get headerRow => Container(
margin: const EdgeInsets.fromLTRB(20.0, 20.0, 20.0, 30.0),
child: Row(
@@ -62,7 +64,7 @@ class KanjiResultBody extends StatelessWidget {
Row(
children: [
const Text('Grade: ', style: TextStyle(fontSize: 20.0)),
Grade(grade: resultData.taughtIn),
Grade(grade: resultData.grade),
],
),
Row(

View File

@@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
import 'package:jisho_study_tool/services/kanji_regex.dart';
import 'package:unofficial_jisho_api/api.dart';
import '../../../../models/themes/theme.dart';
@@ -34,8 +35,8 @@ class KanjiKanaBox extends StatelessWidget {
bool get hasFurigana => word.reading != null;
String get kana => '${word.reading ?? ""}${word.word ?? ""}'
.replaceAll(RegExp(r'\p{Script=Hani}', unicode: true), '');
String get kana =>
'${word.reading ?? ""}${word.word ?? ""}'.replaceAll(kanjiRegex, '');
@override
Widget build(BuildContext context) {

View File

@@ -24,7 +24,7 @@ Widget _wiki({
margin: EdgeInsets.fromLTRB(0, 0, 10, isJapanese ? 12 : 10),
child: IconButton(
onPressed: () => open_webpage(link),
icon: SvgPicture.asset('assets/images/wikipedia.svg'),
icon: SvgPicture.asset('assets/images/links/wikipedia.svg'),
),
),
Container(
@@ -51,7 +51,7 @@ Widget _dbpedia(String link) => Container(
child: IconButton(
onPressed: () => open_webpage(link),
icon: Image.asset(
'assets/images/dbpedia.png',
'assets/images/links/dbpedia.png',
),
),
);

View File

@@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
import 'package:jisho_study_tool/services/kanji_regex.dart';
import 'package:unofficial_jisho_api/api.dart';
import './parts/common_badge.dart';
@@ -31,6 +32,7 @@ class SearchResultCard extends StatefulWidget {
class _SearchResultCardState extends State<SearchResultCard> {
PhrasePageScrapeResultData? extraData;
bool? extraDataSearchFailed;
Future<PhrasePageScrapeResult?> _scrape(JishoResult result) =>
(!(result.japanese[0].word == null && result.japanese[0].reading == null))
@@ -55,7 +57,7 @@ class _SearchResultCardState extends State<SearchResultCard> {
return jlpt.last;
}
List<String> get kanji => RegExp(r'(\p{Script=Hani})', unicode: true)
List<String> get kanji => kanjiRegex
.allMatches(
widget.result.japanese
.map((w) => '${w.word ?? ""}${w.reading ?? ""}')
@@ -132,18 +134,19 @@ class _SearchResultCardState extends State<SearchResultCard> {
if (extensiveSearchEnabled && extraData == null) {
final data = await _scrape(widget.result);
setState(() {
extraData = (data != null && data.found) ? data.data : null;
extraDataSearchFailed = !(data?.found ?? false);
extraData = !extraDataSearchFailed! ? data!.data : null;
});
}
},
title: _header,
children: [
if (extensiveSearchEnabled && extraData == null)
if (extensiveSearchEnabled && extraDataSearchFailed == null)
const Padding(
padding: EdgeInsets.symmetric(vertical: 10),
child: Center(child: CircularProgressIndicator()),
)
else if (extraData != null)
else if (!extraDataSearchFailed!)
_body(extendedData: extraData)
else
_body()

6
lib/migrations/.gitignore vendored Normal file
View File

@@ -0,0 +1,6 @@
test.db
data/jisho
data/radkfile
data/kradfile
data/0002_radicals.json
!data/jouyou

View File

@@ -0,0 +1,295 @@
-- KANJI
CREATE TABLE Kanji_YomiExample (
exampleID INTEGER PRIMARY KEY AUTOINCREMENT,
example TEXT NOT NULL,
reading TEXT NOT NULL,
meaning TEXT NOT NULL,
UNIQUE (example, reading, meaning)
);
CREATE TABLE Kanji_Radical (
id INTEGER NOT NULL UNIQUE,
symbol CHAR(1) NOT NULL PRIMARY KEY,
strokes INTEGER NOT NULL,
meaning TEXT NOT NULL,
searchSymbol CHAR(1)
);
CREATE TABLE Kanji_Radical_Forms (
form CHAR(1) NOT NULL PRIMARY KEY,
radical CHAR(1) NOT NULL,
FOREIGN KEY(radical) REFERENCES Kanji_Radical(symbol)
);
CREATE TABLE Kanji_Kunyomi (
yomi TEXT NOT NULL PRIMARY KEY
);
CREATE TABLE Kanji_Onyomi (
yomi TEXT NOT NULL PRIMARY KEY
);
CREATE TABLE Kanji_Part (
part CHAR(1) NOT NULL PRIMARY KEY
-- FOREIGN KEY(part) REFERENCES Kanji_Radical(symbol)
);
CREATE TABLE Kanji_Result (
kanji CHAR(1) PRIMARY KEY,
taughtIn INTEGER CHECK (taughtIn BETWEEN 1 AND 7),
jlptLevel INTEGER CHECK (jlptLevel BETWEEN 1 AND 5),
newspaperFrequencyRank INTEGER,
strokeCount INTEGER NOT NULL,
meaning INTEGER NOT NULL,
radical CHAR(1) NOT NULL,
isJouyou BOOLEAN NOT NULL DEFAULT false,
FOREIGN KEY (radical) REFERENCES Kanji_Radical(symbol)
);
CREATE TABLE Kanji_ResultKunyomiExample_XRef (
exampleID INTEGER NOT NULL,
kanji CHAR(1) NOT NULL,
FOREIGN KEY(exampleID) REFERENCES Kanji_YomiExample(exampleID),
FOREIGN KEY(kanji) REFERENCES Kanji_Result(kanji),
PRIMARY KEY(exampleID, kanji)
);
CREATE TABLE Kanji_ResultOnyomiExample_XRef (
exampleID INTEGER NOT NULL,
kanji CHAR(1) NOT NULL,
FOREIGN KEY(exampleID) REFERENCES Kanji_YomiExample(exampleID),
FOREIGN KEY(kanji) REFERENCES Kanji_Result(kanji),
PRIMARY KEY(exampleID, kanji)
);
CREATE TABLE Kanji_ResultKunyomi_XRef (
yomi TEXT NOT NULL,
kanji CHAR(1) NOT NULL,
FOREIGN KEY(yomi) REFERENCES Kanji_Kunyomi(yomi),
FOREIGN KEY(kanji) REFERENCES Kanji_Result(kanji),
PRIMARY KEY(yomi, kanji)
);
CREATE TABLE Kanji_ResultOnyomi_XRef (
yomi TEXT NOT NULL,
kanji CHAR(1) NOT NULL,
FOREIGN KEY(yomi) REFERENCES Kanji_Onyomi(yomi),
FOREIGN KEY(kanji) REFERENCES Kanji_Result(kanji),
PRIMARY KEY(yomi, kanji)
);
CREATE TABLE Kanji_ResultPart_XRef (
part CHAR(1) NOT NULL,
kanji CHAR(1) NOT NULL,
FOREIGN KEY(part) REFERENCES Kanji_Part(part),
FOREIGN KEY(kanji) REFERENCES Kanji_Result(kanji),
PRIMARY KEY(part, kanji)
);
-- RADKFILE
CREATE TABLE RADKFILE (
kanji CHAR(1) NOT NULL,
radical CHAR(1) NOT NULL,
FOREIGN KEY(radical) REFERENCES Kanji_Radical(symbol)
);
CREATE INDEX RADK ON RADKFILE (radical);
CREATE INDEX KRAD ON RADKFILE (kanji);
-- Example Sentence
CREATE TABLE ExampleSentence_Result (
resultID INTEGER PRIMARY KEY AUTOINCREMENT,
kanji TEXT NOT NULL,
kana TEXT NOT NULL,
english TEXT NOT NULL
);
CREATE TABLE ExampleSentence_Piece (
orderNum INTEGER NOT NULL,
lifted TEXT,
unlifted TEXT NOT NULL,
resultID INTEGER NOT NULL,
FOREIGN KEY(resultID) REFERENCES ExampleSentence_Result(resultID),
PRIMARY KEY(resultID, orderNum)
);
-- Words
CREATE TABLE PhraseScrape_Result (
uri TEXT NOT NULL PRIMARY KEY
);
CREATE TABLE PhraseScrape_Sentence (
english TEXT NOT NULL,
japanese TEXT NOT NULL,
PRIMARY KEY (english, japanese)
);
CREATE TABLE PhraseScrape_Sentence_Piece (
orderNum INTEGER NOT NULL,
lifted TEXT,
unlifted TEXT NOT NULL,
sentenceEnglish TEXT NOT NULL,
sentenceJapanese TEXT NOT NULL,
FOREIGN KEY(sentenceEnglish, sentenceJapanese) REFERENCES PhraseScrape_Sentence(english, japanese) ON DELETE CASCADE,
PRIMARY KEY (sentenceEnglish, sentenceJapanese, orderNum)
);
CREATE TABLE PhraseScrape_Meaning_SeeAlsoTerm (
seeAlsoTerm TEXT NOT NULL,
meaningDefinition TEXT NOT NULL,
resultUri TEXT NOT NULL,
FOREIGN KEY (meaningDefinition, resultUri) REFERENCES PhraseScrape_Meaning (definition, resultUri) ON DELETE CASCADE,
PRIMARY KEY (seeAlsoTerm, meaningDefinition, resultUri)
);
CREATE TABLE PhraseScrape_Meaning_Supplemental (
supplemental TEXT NOT NULL,
meaningDefinition TEXT NOT NULL,
resultUri TEXT NOT NULL,
FOREIGN KEY (meaningDefinition, resultUri) REFERENCES PhraseScrape_Meaning (definition, resultUri) ON DELETE CASCADE,
PRIMARY KEY (supplemental, meaningDefinition, resultUri)
);
CREATE TABLE PhraseScrape_Meaning_Tag (
tag TEXT NOT NULL,
meaningDefinition TEXT NOT NULL,
resultUri TEXT NOT NULL,
FOREIGN KEY (meaningDefinition, resultUri) REFERENCES PhraseScrape_Meaning (definition, resultUri) ON DELETE CASCADE,
PRIMARY KEY (tag, meaningDefinition, resultUri)
);
CREATE TABLE PhraseScrape_Meaning (
definition TEXT NOT NULL,
definitionAbstract TEXT,
resultUri TEXT NOT NULL,
FOREIGN KEY(resultUri) REFERENCES PhraseScrape_Result(uri) ON DELETE CASCADE,
PRIMARY KEY(definition,resultUri)
);
CREATE TABLE PhraseScrape_MeaningSentence_XRef (
sentenceEnglish TEXT NOT NULL,
sentenceJapanese TEXT NOT NULL,
resultUri TEXT NOT NULL,
FOREIGN KEY(resultUri) REFERENCES PhraseScrape_Result(uri) ON DELETE CASCADE,
FOREIGN KEY(sentenceEnglish, sentenceJapanese) REFERENCES PhraseScrape_Sentence(english, japanese) ON DELETE CASCADE
);
CREATE TABLE PhraseScrape_KanjiKanaPair (
kanji TEXT NOT NULL,
kana TEXT,
resultUri TEXT NOT NULL,
FOREIGN KEY(resultUri) REFERENCES PhraseScrape_Result(uri) ON DELETE CASCADE,
PRIMARY KEY (kanji, kana, resultUri)
);
CREATE TABLE PhraseScrape_AudioFile (
uri TEXT NOT NULL PRIMARY KEY,
mimetype TEXT NOT NULL,
resultUri TEXT NOT NULL,
FOREIGN KEY(resultUri) REFERENCES PhraseScrape_Result(uri) ON DELETE CASCADE
);
CREATE TABLE PhraseScrape_Note (
note TEXT NOT NULL,
resultUri TEXT NOT NULL,
FOREIGN KEY(resultUri) REFERENCES PhraseScrape_Result(uri) ON DELETE CASCADE,
PRIMARY KEY (note, resultUri)
);
-- API
CREATE TABLE PhraseSearch_JishoResult (
slug TEXT NOT NULL PRIMARY KEY,
isCommon BOOLEAN
);
CREATE TABLE PhraseScrape_JishoResult_Tag (
tag TEXT NOT NULL,
resultSlug TEXT NOT NULl,
FOREIGN KEY(resultSlug) REFERENCES PhraseSearch_JishoResult(slug) ON DELETE CASCADE,
PRIMARY KEY (tag, resultSlug)
);
CREATE TABLE PhraseScrape_JishoResult_Jlpt (
jlpt TEXT NOT NULL,
resultSlug TEXT NOT NULl,
FOREIGN KEY(resultSlug) REFERENCES PhraseSearch_JishoResult(slug) ON DELETE CASCADE,
PRIMARY KEY (jlpt, resultSlug)
);
CREATE TABLE PhraseSearch_JapaneseWord (
word TEXT,
reading TEXT,
resultSlug TEXT NOT NULl,
FOREIGN KEY(resultSlug) REFERENCES PhraseSearch_JishoResult(slug) ON DELETE CASCADE,
PRIMARY KEY (word, reading, resultSlug),
CHECK (word NOT NULL OR reading NOT NULL)
);
CREATE TABLE PhraseSearch_WordSense (
id INTEGER PRIMARY KEY AUTOINCREMENT
);
CREATE TABLE PhraseSearch_WordSense_Link (
text TEXT NOT NULL,
url TEXT NOT NULL,
senseID INTEGER NOT NULL,
FOREIGN KEY(senseID) REFERENCES PhraseSearch_WordSense(id) ON DELETE CASCADE,
PRIMARY KEY(url, senseID)
);
CREATE TABLE PhraseSearch_WordSense_Tag (
tag TEXT NOT NULL,
senseID INTEGER NOT NULL,
FOREIGN KEY(senseID) REFERENCES PhraseSearch_WordSense(id) ON DELETE CASCADE,
PRIMARY KEY (tag, senseID)
);
CREATE TABLE PhraseSearch_WordSense_SeeAlso (
seeAlso TEXT NOT NULL,
senseID INTEGER NOT NULL,
FOREIGN KEY(senseID) REFERENCES PhraseSearch_WordSense(id) ON DELETE CASCADE,
PRIMARY KEY (seeAlso, senseID)
);
CREATE TABLE PhraseSearch_WordSense_Antonym (
antonym TEXT NOT NULL,
senseID INTEGER NOT NULL,
FOREIGN KEY(senseID) REFERENCES PhraseSearch_WordSense(id) ON DELETE CASCADE,
PRIMARY KEY (antonym, senseID)
);
CREATE TABLE PhraseSearch_WordSense_Source (
language TEXT NOT NULL,
word TEXT,
senseID INTEGER NOT NULL,
FOREIGN KEY(senseID) REFERENCES PhraseSearch_WordSense(id) ON DELETE CASCADE,
PRIMARY KEY (language, senseID)
);
CREATE TABLE PhraseSearch_WordSense_Info (
info TEXT NOT NULL,
senseID INTEGER NOT NULL,
FOREIGN KEY(senseID) REFERENCES PhraseSearch_WordSense(id) ON DELETE CASCADE,
PRIMARY KEY (info, senseID)
);
CREATE TABLE PhraseSearch_WordSense_Restriction (
restriction TEXT NOT NULL,
senseID INTEGER NOT NULL,
FOREIGN KEY(senseID) REFERENCES PhraseSearch_WordSense(id) ON DELETE CASCADE,
PRIMARY KEY (restriction, senseID)
);
CREATE TABLE PhraseSearch_Attribution (
jmdict BOOLEAN NOT NULL,
jmnedict BOOLEAN NOT NULL,
dbpedia TEXT,
resultSlug TEXT NOT NULl PRIMARY KEY,
FOREIGN KEY(resultSlug) REFERENCES PhraseSearch_JishoResult(slug) ON DELETE CASCADE
);

View File

@@ -0,0 +1,254 @@
INSERT INTO Kanji_Radical(id, symbol, strokes, meaning, searchSymbol) VALUES
(1, '', 1, 'one', NULL),
(2, '', 1, 'line', NULL),
(3, '', 1, 'dot', NULL),
(4, '', 1, 'slash', NULL),
(5, '', 1, 'second', NULL),
(6, '', 1, 'hook', NULL),
(7, '', 2, 'two', NULL),
(8, '', 2, 'lid', NULL),
(9, '', 2, 'man, human', NULL),
(10, '', 2, 'man, human', ''),
(11, '𠆢', 2, 'man, human', ''),
(12, '', 2, 'legs', NULL),
(13, '', 2, 'enter', NULL),
(14, '', 2, 'eight', NULL),
(15, '', 2, 'eight', ''),
(16, '', 2, 'open country', NULL),
(17, '', 2, 'cover', NULL),
(18, '', 2, 'ice', NULL),
(19, '', 2, 'table', NULL),
(20, '', 2, 'container, open mouth', NULL),
(21, '', 2, 'knife, sword', NULL),
(22, '', 2, 'knife, sword', ''),
(23, '', 2, 'power, force', NULL),
(24, '', 2, 'wrap, embrace', NULL),
(25, '', 2, 'spoon', NULL),
(26, '', 2, 'box', NULL),
(27, '', 2, 'ten, complete', NULL),
(28, '', 2, 'divination', NULL),
(29, '', 2, 'kneel', NULL),
(30, '', 2, 'cliff', NULL),
(31, '', 2, 'private', NULL),
(32, '', 2, 'right hand', NULL),
(33, '', 2, 'katakana, jisho search radical', NULL),
(34, '', 2, 'second', NULL),
(35, '', 2, 'katakana, jisho search radical', NULL),
(36, '', 2, 'slash', NULL),
(360, '𠂉', 2, 'slash', ''),
(37, '', 3, 'walk', ''),
(38, '', 3, 'mouth, opening', NULL),
(39, '', 3, 'enclosure', NULL),
(40, '', 3, 'earth', NULL),
(41, '', 3, 'scholar, bachelor', NULL),
(42, '', 3, 'go', NULL),
(43, '', 3, 'evening, sunset', NULL),
(44, '', 3, 'big, very', NULL),
(45, '', 3, 'woman, female', NULL),
(46, '', 3, 'child, seed', NULL),
(47, '', 3, 'roof', NULL),
(48, '', 3, 'thumb, inch', NULL),
(49, '', 3, 'small, insignificant', NULL),
(50, '', 3, 'small, insignificant', ''),
(51, '', 3, 'lame', NULL),
(52, '', 3, 'corpse', NULL),
(53, '', 3, 'sprout', NULL),
(54, '', 3, 'mountain', NULL),
(55, '', 3, 'river', NULL),
(56, '', 3, 'river', NULL),
(57, '', 3, 'work', NULL),
(58, '', 3, 'oneself', NULL),
(59, '', 3, 'turban, scarf', NULL),
(60, '', 3, 'pestle', NULL),
(61, '', 3, 'short, tiny', NULL),
(62, '广', 3, 'house on cliff', NULL),
(63, '', 3, 'long stride', NULL),
(64, '', 3, 'two hands, twenty', NULL),
(65, '', 3, 'shoot, arrow', NULL),
(66, '', 3, 'bow', NULL),
(67, '', 3, 'pig snout', NULL),
(68, '', 3, 'pig snout', NULL),
(69, '', 3, 'bristle, beard', NULL),
(70, '', 3, 'step', NULL),
(71, '', 3, 'heart', ''),
(72, '', 3, 'hand', ''),
(73, '', 3, 'water', ''),
(74, '', 3, 'dog', ''),
(75, '', 3, 'grass', ''),
(76, '', 3, 'town (阝 right)', ''),
(77, '', 3, 'mound, dam (阝 left)', ''),
(78, '', 3, 'second', NULL),
(79, '', 3, 'lid', NULL),
(80, '', 3, 'right hand', NULL),
(81, '', 3, 'slash', NULL),
(82, '', 4, 'old', ''),
(83, '', 4, 'heart', NULL),
(84, '', 4, 'spear, halberd', NULL),
(85, '', 4, 'door, house', NULL),
(86, '', 4, 'hand', NULL),
(87, '', 4, 'branch', NULL),
(88, '', 4, 'rap', NULL),
(89, '', 4, 'script, literature', NULL),
(90, '', 4, 'dipper', NULL),
(91, '', 4, 'axe', NULL),
(92, '', 4, 'square', NULL),
(93, '', 4, 'perish', NULL),
(94, '', 4, 'sun, day', NULL),
(95, '', 4, 'say', NULL),
(96, '', 4, 'moon, month', NULL),
(97, '', 4, 'tree', NULL),
(98, '', 4, 'lack, yawn', NULL),
(99, '', 4, 'stop', NULL),
(100, '', 4, 'death, decay', NULL),
(101, '', 4, 'weapon, lance', NULL),
(102, '', 4, 'compare, compete', NULL),
(103, '', 4, 'fur, hair', NULL),
(104, '', 4, 'clan', NULL),
(105, '', 4, 'steam, breath', NULL),
(106, '', 4, 'water', NULL),
(107, '', 4, 'fire', NULL),
(108, '', 4, 'fire', ''),
(109, '', 4, 'claw', NULL),
(110, '', 4, 'father', NULL),
(111, '', 4, 'mix, twine, cross', NULL),
(112, '', 4, 'split wood', NULL),
(113, '', 4, 'slice', NULL),
(114, '', 4, 'cow', NULL),
(115, '', 4, 'dog', NULL),
(116, '', 4, 'sign', ''),
(117, '', 4, 'jade (king)', NULL),
(118, '', 4, 'legs', NULL),
(119, '', 4, 'two', NULL),
(120, '', 4, 'wrap, embrace', NULL),
(121, '', 4, 'lame', NULL),
(122, '', 4, 'two', NULL),
(123, '', 4, 'sprout', NULL),
(124, '', 4, 'oneself', NULL),
(125, '', 4, 'mother, do not', NULL),
(126, '', 5, 'dark, profound', NULL),
(127, '', 5, 'tile', NULL),
(128, '', 5, 'sweet', NULL),
(129, '', 5, 'life', NULL),
(130, '', 5, 'use', NULL),
(131, '', 5, 'field', NULL),
(132, '', 5, 'bolt of cloth', NULL),
(133, '', 5, 'sickness', ''),
(134, '', 5, 'footsteps', NULL),
(135, '', 5, 'white', NULL),
(136, '', 5, 'skin', NULL),
(137, '', 5, 'dish', NULL),
(138, '', 5, 'eye', NULL),
(139, '', 5, 'spear', NULL),
(140, '', 5, 'arrow', NULL),
(141, '', 5, 'stone', NULL),
(142, '', 5, 'sign', NULL),
(143, '', 5, 'track', ''),
(144, '', 5, 'grain', NULL),
(145, '', 5, 'cave', NULL),
(146, '', 5, 'stand, erect', NULL),
(147, '', 5, 'clothes', ''),
(148, '', 5, 'one', NULL),
(149, '', 5, 'work', NULL),
(150, '', 5, 'open country', NULL),
(151, '', 5, 'mother, do not', NULL),
(152, '', 5, 'net', ''),
(153, '', 5, 'fang', NULL),
(154, '', 6, 'melon', NULL),
(155, '', 6, 'bamboo', NULL),
(156, '', 6, 'rice', NULL),
(157, '', 6, 'silk', NULL),
(158, '', 6, 'jar', NULL),
(159, '', 6, 'sheep', NULL),
(160, '', 6, 'feather', NULL),
(161, '', 6, 'beard', NULL),
(162, '', 6, 'plow', NULL),
(163, '', 6, 'ear', NULL),
(164, '', 6, 'brush', NULL),
(165, '', 6, 'meat', NULL),
(166, '', 6, 'self', NULL),
(167, '', 6, 'arrive', NULL),
(168, '', 6, 'mortar', NULL),
(169, '', 6, 'tongue', NULL),
(170, '', 6, 'boat', NULL),
(171, '', 6, 'stopping', NULL),
(172, '', 6, 'colour, prettiness', NULL),
(173, '', 6, 'tiger stripes', NULL),
(174, '', 6, 'insect', NULL),
(175, '', 6, 'blood', NULL),
(176, '', 6, 'go, do', NULL),
(177, '', 6, 'clothes', NULL),
(178, '西', 6, 'west', NULL),
(179, '', 7, 'minster, official', NULL),
(180, '', 7, 'see', NULL),
(181, '', 7, 'horn', NULL),
(182, '', 7, 'speech', NULL),
(183, '', 7, 'valley', NULL),
(184, '', 7, 'bean', NULL),
(185, '', 7, 'pig', NULL),
(186, '', 7, 'cat, badger', NULL),
(187, '', 7, 'shell', NULL),
(188, '', 7, 'red, naked', NULL),
(189, '', 7, 'run', NULL),
(190, '', 7, 'foot', NULL),
(191, '', 7, 'body', NULL),
(192, '', 7, 'cart, car', NULL),
(193, '', 7, 'bitter', NULL),
(194, '', 7, 'morning', NULL),
(195, '', 7, 'wine, alcohol', NULL),
(196, '', 7, 'divide, distinguish, choose', NULL),
(197, '', 7, 'village, mile', NULL),
(198, '', 7, 'opposite', NULL),
(199, '', 7, 'wheat', NULL),
(200, '', 8, 'metal, gold', NULL),
(201, '', 8, 'long, grow', NULL),
(202, '', 8, 'gate', NULL),
(203, '', 8, 'slave, capture', NULL),
(204, '', 8, 'small bird', NULL),
(205, '', 8, 'rain', NULL),
(206, '', 8, 'blue', NULL),
(207, '', 8, 'wrong', NULL),
(208, '', 8, 'big, very', NULL),
(209, '', 8, 'mountain', NULL),
(210, '', 8, 'legs', NULL),
(211, '', 8, 'script, literature', NULL),
(212, '', 9, 'face', NULL),
(213, '', 9, 'leather, rawhide', NULL),
(214, '', 9, 'leek', NULL),
(215, '', 9, 'sound', NULL),
(216, '', 9, 'leaf', NULL),
(217, '', 9, 'wind', NULL),
(218, '', 9, 'fly', NULL),
(219, '', 9, 'eat, food', NULL),
(220, '', 9, 'head', NULL),
(221, '', 9, 'fragrance', NULL),
(222, '', 9, 'mouth, opening', NULL),
(223, '', 10, 'horse', NULL),
(224, '', 10, 'bone', NULL),
(225, '', 10, 'tall', NULL),
(226, '', 10, 'long hair', NULL),
(227, '', 10, 'fight', NULL),
(228, '', 10, 'herbs, sacrificial wine', NULL),
(229, '', 10, 'tripod, cauldron', NULL),
(230, '', 10, 'ghost, demon', NULL),
(231, '', 10, 'stand, erect', NULL),
(232, '', 10, 'tanned leather', NULL),
(233, '', 11, 'fish', NULL),
(234, '', 11, 'bird', NULL),
(235, '', 11, 'salt', NULL),
(236, '鹿', 11, 'deer', NULL),
(237, '', 11, 'hemp, flax', NULL),
(238, '', 11, 'second', NULL),
(239, '', 11, 'mouth, opening', ''),
(240, '', 11, 'yellow', NULL),
(241, '', 11, 'black', NULL),
(242, '', 12, 'millet', NULL),
(243, '', 12, 'embroidery, needlework', NULL),
(244, '', 12, 'fire', NULL),
(245, '', 12, 'stop', NULL),
(246, '', 13, 'frog, amphibian', NULL),
(247, '', 13, 'tripod', NULL),
(248, '', 13, 'drum', NULL),
(249, '', 13, 'rat, mouse', NULL),
(250, '', 14, 'nose', NULL),
(251, '', 14, 'even, uniformly', NULL),
(252, '', 17, 'flute', NULL);

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

18
lib/migrations/Makefile Normal file
View File

@@ -0,0 +1,18 @@
DB_NAME=test.db
all: clean dart
sqlite3 $(DB_NAME) < 0001_initial.sql
sqlite3 $(DB_NAME) < 0002_populate_radicals.sql
sqlite3 $(DB_NAME) < 0003_populate_radkfile.sql
sqlite3 $(DB_NAME) < 0004_populate_jouyou_kanji.sql
convert_kradk:
iconv -f EUC-JP -t UTF-8 -o data/radkfile_utf8 data/radkfile
dart:
dart run tools/update_0002.dart
dart run tools/update_0003.dart
dart run tools/update_0004.dart
clean:
rm test.db || true

View File

@@ -0,0 +1 @@
一右雨円王音下火花貝学気九休玉金空月犬見五口校左三山子四糸字耳七車手十出女小上森人水正生青夕石赤千川先早草足村大男竹中虫町天田土二日入年白八百文木本名目立力林六

View File

@@ -0,0 +1 @@
引羽雲園遠何科夏家歌画回会海絵外角楽活間丸岩顔汽記帰弓牛魚京強教近兄形計元言原戸古午後語工公広交光考行高黄合谷国黒今才細作算止市矢姉思紙寺自時室社弱首秋週春書少場色食心新親図数西声星晴切雪船線前組走多太体台地池知茶昼長鳥朝直通弟店点電刀冬当東答頭同道読内南肉馬売買麦半番父風分聞米歩母方北毎妹万明鳴毛門夜野友用曜来里理話

View File

@@ -0,0 +1 @@
悪安暗医委意育員院飲運泳駅央横屋温化荷界開階寒感漢館岸起期客究急級宮球去橋業曲局銀区苦具君係軽血決研県庫湖向幸港号根祭皿仕死使始指歯詩次事持式実写者主守取酒受州拾終習集住重宿所暑助昭消商章勝乗植申身神真深進世整昔全相送想息速族他打対待代第題炭短談着注柱丁帳調追定庭笛鉄転都度投豆島湯登等動童農波配倍箱畑発反坂板皮悲美鼻筆氷表秒病品負部服福物平返勉放味命面問役薬由油有遊予羊洋葉陽様落流旅両緑礼列練路和

View File

@@ -0,0 +1 @@
愛案以衣位茨印英栄媛塩岡億加果貨課芽賀改械害街各覚潟完官管関観願岐希季旗器機議求泣給挙漁共協鏡競極熊訓軍郡群径景芸欠結建健験固功好香候康佐差菜最埼材崎昨札刷察参産散残氏司試児治滋辞鹿失借種周祝順初松笑唱焼照城縄臣信井成省清静席積折節説浅戦選然争倉巣束側続卒孫帯隊達単置仲沖兆低底的典伝徒努灯働特徳栃奈梨熱念敗梅博阪飯飛必票標不夫付府阜富副兵別辺変便包法望牧末満未民無約勇要養浴利陸良料量輪類令冷例連老労録

View File

@@ -0,0 +1 @@
圧囲移因永営衛易益液演応往桜可仮価河過快解格確額刊幹慣眼紀基寄規喜技義逆久旧救居許境均禁句型経潔件険検限現減故個護効厚耕航鉱構興講告混査再災妻採際在財罪殺雑酸賛士支史志枝師資飼示似識質舎謝授修述術準序招証象賞条状常情織職制性政勢精製税責績接設絶祖素総造像増則測属率損貸態団断築貯張停提程適統堂銅導得毒独任燃能破犯判版比肥非費備評貧布婦武復複仏粉編弁保墓報豊防貿暴脈務夢迷綿輸余容略留領歴

View File

@@ -0,0 +1 @@
胃異遺域宇映延沿恩我灰拡革閣割株干巻看簡危机揮貴疑吸供胸郷勤筋系敬警劇激穴券絹権憲源厳己呼誤后孝皇紅降鋼刻穀骨困砂座済裁策冊蚕至私姿視詞誌磁射捨尺若樹収宗就衆従縦縮熟純処署諸除承将傷障蒸針仁垂推寸盛聖誠舌宣専泉洗染銭善奏窓創装層操蔵臓存尊退宅担探誕段暖値宙忠著庁頂腸潮賃痛敵展討党糖届難乳認納脳派拝背肺俳班晩否批秘俵腹奮並陛閉片補暮宝訪亡忘棒枚幕密盟模訳郵優預幼欲翌乱卵覧裏律臨朗論

View File

@@ -0,0 +1 @@
亜哀挨曖握扱宛嵐依威為畏尉萎偉椅彙違維慰緯壱逸芋咽姻淫陰隠韻唄鬱畝浦詠影鋭疫悦越謁閲炎怨宴援煙猿鉛縁艶汚凹押旺欧殴翁奥憶臆虞乙俺卸穏佳苛架華菓渦嫁暇禍靴寡箇稼蚊牙瓦雅餓介戒怪拐悔皆塊楷潰壊懐諧劾崖涯慨蓋該概骸垣柿核殻郭較隔獲嚇穫岳顎掛括喝渇葛滑褐轄且釜鎌刈甘汗缶肝冠陥乾勘患貫喚堪換敢棺款閑勧寛歓監緩憾還環韓艦鑑含玩頑企伎忌奇祈軌既飢鬼亀幾棋棄毀畿輝騎宜偽欺儀戯擬犠菊吉喫詰却脚虐及丘朽臼糾嗅窮巨拒拠虚距御凶叫狂享況峡挟狭恐恭脅矯響驚仰暁凝巾斤菌琴僅緊錦謹襟吟駆惧愚偶遇隅串屈掘窟繰勲薫刑茎契恵啓掲渓蛍傾携継詣慶憬稽憩鶏迎鯨隙撃桁傑肩倹兼剣拳軒圏堅嫌献遣賢謙鍵繭顕懸幻玄弦舷股虎孤弧枯雇誇鼓錮顧互呉娯悟碁勾孔巧甲江坑抗攻更拘肯侯恒洪荒郊貢控梗喉慌硬絞項溝綱酵稿衡購乞拷剛傲豪克酷獄駒込頃昆恨婚痕紺魂墾懇沙唆詐鎖挫采砕宰栽彩斎債催塞歳載剤削柵索酢搾錯咲刹拶撮擦桟惨傘斬暫旨伺刺祉肢施恣脂紫嗣雌摯賜諮侍慈餌璽軸𠮟疾執湿嫉漆芝赦斜煮遮邪蛇酌釈爵寂朱狩殊珠腫趣寿呪需儒囚舟秀臭袖羞愁酬醜蹴襲汁充柔渋銃獣叔淑粛塾俊瞬旬巡盾准殉循潤遵庶緒如叙徐升召匠床抄肖尚昇沼宵症祥称渉紹訟掌晶焦硝粧詔奨詳彰憧衝償礁鐘丈冗浄剰畳壌嬢錠譲醸拭殖飾触嘱辱尻伸芯辛侵津唇娠振浸紳診寝慎審震薪刃尽迅甚陣尋腎須吹炊帥粋衰酔遂睡穂随髄枢崇据杉裾瀬是姓征斉牲凄逝婿誓請醒斥析脊隻惜戚跡籍拙窃摂仙占扇栓旋煎羨腺詮践箋潜遷薦繊鮮禅漸膳繕狙阻租措粗疎訴塑遡礎双壮荘捜挿桑掃曹曽爽喪痩葬僧遭槽踪燥霜騒藻憎贈即促捉俗賊遜汰妥唾堕惰駄耐怠胎泰堆袋逮替滞戴滝択沢卓拓託濯諾濁但脱奪棚誰丹旦胆淡嘆端綻鍛弾壇恥致遅痴稚緻畜逐蓄秩窒嫡抽衷酎鋳駐弔挑彫眺釣貼超跳徴嘲澄聴懲勅捗沈珍朕陳鎮椎墜塚漬坪爪鶴呈廷抵邸亭貞帝訂逓偵堤艇締諦泥摘滴溺迭哲徹撤添塡殿斗吐妬途渡塗賭奴怒到逃倒凍唐桃透悼盗陶塔搭棟痘筒稲踏謄藤闘騰洞胴瞳峠匿督篤凸突屯豚頓貪鈍曇丼那謎鍋軟尼弐匂虹尿妊忍寧捻粘悩濃把覇婆罵杯排廃輩培陪媒賠伯拍泊迫剝舶薄漠縛爆箸肌鉢髪伐抜罰閥氾帆汎伴畔般販斑搬煩頒範繁藩蛮盤妃彼披卑疲被扉碑罷避尾眉微膝肘匹泌姫漂苗描猫浜賓頻敏瓶扶怖附訃赴浮符普腐敷膚賦譜侮舞封伏幅覆払沸紛雰噴墳憤丙併柄塀幣弊蔽餅壁璧癖蔑偏遍哺捕舗募慕簿芳邦奉抱泡胞俸倣峰砲崩蜂飽褒縫乏忙坊妨房肪某冒剖紡傍帽貌膨謀頰朴睦僕墨撲没勃堀奔翻凡盆麻摩磨魔昧埋膜枕又抹慢漫魅岬蜜妙眠矛霧娘冥銘滅免麺茂妄盲耗猛網黙紋冶弥厄躍闇喩愉諭癒唯幽悠湧猶裕雄誘憂融与誉妖庸揚揺溶腰瘍踊窯擁謡抑沃翼拉裸羅雷頼絡酪辣濫藍欄吏痢履璃離慄柳竜粒隆硫侶虜慮了涼猟陵僚寮療瞭糧厘倫隣瑠涙累塁励戻鈴零霊隷齢麗暦劣烈裂恋廉錬呂炉賂露弄郎浪廊楼漏籠麓賄脇惑枠湾腕

View File

@@ -0,0 +1 @@
氏統保第結派案策基価提挙応企検藤沢裁証援施井護展態鮮視条幹独宮率衛張監環審義訴株姿閣衆評影松撃佐核整融製票渉響推請器士討攻崎督授催及憲離激摘系批郎健盟従修隊織拡故振弁就異献厳維浜遺塁邦素遣抗模雄益緊標宣昭廃伊江僚吉盛皇臨踏壊債興源儀創障継筋闘葬避司康善逮迫惑崩紀聴脱級博締救執房撤削密措志載陣我為抑幕染奈傷択秀徴弾償功拠秘拒刑塚致繰尾描鈴盤項喪伴養懸街契掲躍棄邸縮還属慮枠恵露沖緩節需射購揮充貢鹿却端賃獲郡併徹貴衝焦奪災浦析譲称納樹挑誘紛至宗促慎控智握宙俊銭渋銃操携診託撮誕侵括謝駆透津壁稲仮裂敏是排裕堅訳芝綱典賀扱顧弘看訟戒祉誉歓奏勧騒閥甲縄郷揺免既薦隣華範隠徳哲杉釈己妥威豪熊滞微隆症暫忠倉彦肝喚沿妙唱阿索誠襲懇俳柄驚麻李浩剤瀬趣陥斎貫仙慰序旬兼聖旨即柳舎偽較覇詳抵脅茂犠旗距雅飾網竜詩繁翼潟敵魅嫌斉敷擁圏酸罰滅礎腐脚潮梅尽僕桜滑孤炎賠句鋼頑鎖彩摩励縦輝蓄軸巡稼瞬砲噴誇祥牲秩帝宏唆阻泰賄撲堀菊絞縁唯膨矢耐塾漏慶猛芳懲剣彰棋丁恒揚冒之倫陳憶潜梨仁克岳概拘墓黙須偏雰遇諮狭卓亀糧簿炉牧殊殖艦輩穴奇慢鶴謀暖昌拍朗寛覆胞泣隔浄没暇肺貞靖鑑飼陰銘随烈尋稿丹啓也丘棟壌漫玄粘悟舗妊熟旭恩騰往豆遂狂岐陛緯培衰艇屈径淡抽披廷錦准暑磯奨浸剰胆繊駒虚霊帳悔諭惨虐翻墜沼据肥徐糖搭盾脈滝軌俵妨擦鯨荘諾雷漂懐勘栽拐駄添冠斜鏡聡浪亜覧詐壇勲魔酬紫曙紋卸奮欄逸涯拓眼獄尚彫穏顕巧矛垣欺釣萩粛栗愚嘉遭架鬼庶稚滋幻煮姫誓把践呈疎仰剛疾征砕謡嫁謙后嘆菌鎌巣頻琴班棚潔酷宰廊寂辰霞伏碁俗漠邪晶墨鎮洞履劣那殴娠奉憂朴亭淳怪鳩酔惜穫佳潤悼乏該赴桑桂髄虎盆晋穂壮堤飢傍疫累痴搬晃癒桐寸郭尿凶吐宴鷹賓虜陶鐘憾猪紘磁弥昆粗訂芽庄傘敦騎寧循忍怠如寮祐鵬鉛珠凝苗獣哀跳匠垂蛇澄縫僧眺亘呉凡憩媛溝恭刈睡錯伯笹穀陵霧魂弊妃舶餓窮掌麗綾臭悦刃縛暦宜盲粋辱毅轄猿弦稔窒炊洪摂飽冗桃狩朱渦紳枢碑鍛刀鼓裸猶塊旋弓幣膜扇腸槽慈楊伐駿漬糾亮墳坪紺娯椿舌羅峡俸厘峰圭醸蓮弔乙汁尼遍衡薫猟羊款閲偵喝敢胎酵憤豚遮扉硫赦窃泡瑞又慨紡恨肪扶戯伍忌濁奔斗蘭迅肖鉢朽殻享秦茅藩沙輔媒鶏禅嘱胴迭挿嵐椎絹陪剖譜郁悠淑帆暁傑楠笛玲奴錠拳翔遷拙侍尺峠篤肇渇叔雌亨堪叙酢吟逓嶺甚喬崇漆岬癖愉寅礁乃洲屯樺槙姻巌擬塀唇睦閑胡幽峻曹詠卑侮鋳抹尉槻隷禍蝶酪茎帥逝汽琢匿襟蛍蕉寡琉痢庸朋坑藍賊搾畔遼唄孔橘漱呂拷嬢苑巽杜渓翁廉謹瞳湧欣窯褒醜升殉煩巴禎劾租堕桟稜婿倭斐慕矯罷囚某虹魁泌鴻赳於蚊漸厄葵禄藻嫡孟嚇尭凸巳韻暢硝霜芹勅棺杏鳳儒慧馨楼愁匡彬欽眉褐薪嵯賜繕綜翠栓榛鮎艶凹蔦惣隼錬衷渚斥逐芙稀皐詔惟雛耀佑渥黛宵憧惇妄甫脩蚕酌蒼嬉頒暉肢只凱檀謄彗丑梓叶嗣絢汐伽朔抄畝黎爽蛮惰旺冴偲萌瑠壱侯允鯉蒔遥弧瑛舜彪附但卯芋綺凌茜洸皓婆毬鯛緋邑怜碧倣穣啄悌酉柚倹亦繭采詢賦紗玖眸錘弐倖諄笙痘裟侃爾洵昴耗莞銑碩伶滉宥伎晏迪朕且綸晨竣燦吏頌麿楓箇梧琳澪哉晟匁凪衿丙梢茄颯恕勺瑚蕗瞭遵虞燎侑柊斤謁捺嵩茉蓉燿袈冶誼墾栞菖勁椋旦紬叡凜胤爵亥麟脹汰莉瑳瑶椰耶丞絃奎璃昂塑熙柾諒菫崚鞠捷濫

View File

@@ -0,0 +1 @@
党協総区領県設改府査委軍団各島革村勢減再税営比防補境導副算輸述線農州武象域額欧担準賞辺造被技低復移個門課脳極含蔵量型況針専谷史階管兵接細効丸湾録省旧橋岸周材戸央券編捜竹超並療採森競介根販歴将幅般貿講林装諸劇河航鉄児禁印逆換久短油暴輪占植清倍均億圧芸署伸停爆陸玉波帯延羽固則乱普測豊厚齢囲卒略承順岩練軽了庁城患層版令角絡損募裏仏績築貨混昇池血温季星永著誌庫刊像香坂底布寺宇巨震希触依籍汚枚複郵仲栄札板骨傾届巻燃跡包駐弱紹雇替預焼簡章臓律贈照薄群秒奥詰双刺純翌快片敬悩泉皮漁荒貯硬埋柱祭袋筆訓浴童宝封胸砂塩賢腕兆床毛緑尊祝柔殿濃液衣肩零幼荷泊黄甘臣浅掃雲掘捨軟沈凍乳恋紅郊腰炭踊冊勇械菜珍卵湖喫干虫刷湯溶鉱涙匹孫鋭枝塗軒毒叫拝氷乾棒祈拾粉糸綿汗銅湿瓶咲召缶隻脂蒸肌耕鈍泥隅灯辛磨麦姓筒鼻粒詞胃畳机膚濯塔沸灰菓帽枯涼舟貝符憎皿肯燥畜挟曇滴伺

View File

@@ -0,0 +1 @@
政議民連対部合市内相定回選米実関決全表戦経最現調化当約首法性要制治務成期取都和機平加受続進数記初指権支産点報済活原共得解交資予向際勝面告反判認参利組信在件側任引求所次昨論官増係感情投示変打直両式確果容必演歳争談能位置流格疑過局放常状球職与供役構割費付由説難優夫収断石違消神番規術備宅害配警育席訪乗残想声念助労例然限追商葉伝働形景落好退頭負渡失差末守若種美命福望非観察段横深申様財港識呼達良候程満敗値突光路科積他処太客否師登易速存飛殺号単座破除完降責捕危給苦迎園具辞因馬愛富彼未舞亡冷適婦寄込顔類余王返妻背熱宿薬険頼覚船途許抜便留罪努精散静婚喜浮絶幸押倒等老曲払庭徒勤遅居雑招困欠更刻賛抱犯恐息遠戻願絵越欲痛笑互束似列探逃遊迷夢君閉緒折草暮酒悲晴掛到寝暗盗吸陽御歯忘雪吹娘誤洗慣礼窓昔貧怒泳祖杯疲皆鳴腹煙眠怖耳頂箱晩寒髪忙才靴恥偶偉猫幾

View File

@@ -0,0 +1 @@
会同事自社発者地業方新場員立開手力問代明動京目通言理体田主題意不作用度強公持野以思家世多正安院心界教文元重近考画海売知道集別物使品計死特私始朝運終台広住真有口少町料工建空急止送切転研足究楽起着店病質待試族銀早映親験英医仕去味写字答夜音注帰古歌買悪図週室歩風紙黒花春赤青館屋色走秋夏習駅洋旅服夕借曜飲肉貸堂鳥飯勉冬昼茶弟牛魚兄犬妹姉漢

View File

@@ -0,0 +1 @@
日一国人年大十二本中長出三時行見月後前生五間上東四今金九入学高円子外八六下来気小七山話女北午百書先名川千水半男西電校語土木聞食車何南万毎白天母火右読友左休父雨

View File

@@ -0,0 +1,178 @@
import 'dart:convert';
import 'dart:io';
import 'package:html/parser.dart';
import 'package:http/http.dart' as http;
import 'package:unofficial_jisho_api/api.dart';
class Radical {
final int id;
final String symbol;
final String? search_symbol;
final String meaning;
final int strokes;
const Radical({
required this.id,
required this.symbol,
required this.strokes,
required this.meaning,
this.search_symbol,
});
@override
String toString() {
return '$id - ($symbol, $strokes${search_symbol != null ? ", $search_symbol" : ""})';
}
String get sql_tuple => ' ('
'$id, '
"'$symbol', "
'$strokes, '
"'$meaning', "
"${search_symbol != null ? "'$search_symbol'" : 'NULL'}"
')';
factory Radical.fromJson(Map<String, dynamic> json) {
return Radical(
id: json['id'] as int,
symbol: json['symbol'] as String,
strokes: json['strokes'] as int,
meaning: json['meaning'] as String,
search_symbol: json['search_symbol'] as String?,
);
}
Map<String, Object?> toJson() => {
'id': id,
'symbol': symbol,
'strokes': strokes,
'meaning': meaning,
'search_symbol': search_symbol,
};
}
String hexToUnicode(String code) =>
String.fromCharCode(int.parse(code, radix: 16));
/// Some of the radicals in jisho are written using katakana,
/// and some are written using either the symbols from the
/// Kangxi radical block (U+2F00-U+2FDF) or the
/// Unified CJK Character block (U+4E00-U+9FFF). These have been
/// used without care, and therefore some of the radicals are not
/// easily searchable. This conversion table helps solve this issue.
///
/// See:
/// https://en.wikipedia.org/wiki/List_of_radicals_in_Unicode
/// https://second.wiki/wiki/unicodeblock_kangxi-radikale
/// https://wiki.contextgarden.net/List_of_Unicode_blocks
Future<Map<String, String>> fetchEquivalentUCJKIdeographs() async {
final response = await http.get(
Uri.parse(
'https://www.unicode.org/Public/UNIDATA/EquivalentUnifiedIdeograph.txt',
),
);
final Map<String, String> result = {};
for (final line in response.body.split('\n')) {
if (line.startsWith('#') || RegExp(r'^\s*$').hasMatch(line)) continue;
final items = line.split(RegExp(r'\s+'));
if (items[0].contains('.')) {
final startEnd = items[0].split('..');
final start = int.parse(startEnd[0], radix: 16);
final end = int.parse(startEnd[1], radix: 16);
for (int i = 0; i <= (end - start); i++) {
result[String.fromCharCode(start + i)] = hexToUnicode(items[2]);
}
} else {
result[hexToUnicode(items[0])] = hexToUnicode(items[2]);
}
}
return result;
}
final cacheFile = File('data/0002_radicals.json');
Future<void> cacheRadicals() async {
final Map<String, String> equivalentSymbols =
await fetchEquivalentUCJKIdeographs();
equivalentSymbols[''] = '';
equivalentSymbols[''] = '丿';
equivalentSymbols[''] = '';
equivalentSymbols[''] = '';
equivalentSymbols[''] = '';
final Map<String, List<String>> inverseEquivalentSymbols = {};
for (final entry in equivalentSymbols.entries) {
if (inverseEquivalentSymbols.containsKey(entry.value)) {
inverseEquivalentSymbols[entry.value]!.add(entry.key);
continue;
}
inverseEquivalentSymbols[entry.value] = [entry.key];
}
final response = await http.get(Uri.parse('https://jisho.org/'));
final document = parse(response.body);
final table = document.querySelector('.radical_table')!;
final List<Radical> radicals = [];
int i = 0;
for (final node in table.children) {
if (node.className == 'reset_icon_list_item') continue;
if (node.className == 'number') {
i = int.parse(node.innerHtml);
continue;
}
final String radical = node.innerHtml;
print('Caching: $radical');
KanjiResult? result;
for (final item in [
radical,
equivalentSymbols[radical],
...inverseEquivalentSymbols[radical] ?? [],
]) {
if (item == null) continue;
result = await searchForKanji(item);
if (result.found) break;
}
final Radical radicalData = Radical(
id: int.parse(node.attributes['data-radical']!),
symbol: radical,
strokes: i,
search_symbol: node.attributes['data-radk'],
meaning: ['', ''].contains(radical)
? 'katakana, jisho search radical'
: result!.data!.radical!.meaning,
);
radicals.add(radicalData);
}
assert(radicals.length == 252, '[ERROR] Missing radicals!');
final encoder = JsonEncoder.withIndent(' ');
cacheFile.writeAsStringSync(encoder.convert(radicals));
}
Future<void> main(List<String> args) async {
if (!cacheFile.existsSync()) {
await cacheRadicals();
}
List<Radical> radicals = (jsonDecode(cacheFile.readAsStringSync()) as List).map((e) => Radical.fromJson(e)).toList();
File('0002_populate_radicals.sql').writeAsStringSync(
'''
INSERT INTO Kanji_Radical(id, symbol, strokes, meaning, searchSymbol) VALUES
${radicals.map((r) => r.sql_tuple).join(',\n')};
''',
);
}

View File

@@ -0,0 +1,28 @@
import 'dart:io';
// TODO: Automate download of radkfile
void main() {
final String content = File('data/radkfile_utf8').readAsStringSync();
final Iterable<String> blocks =
content.replaceAll(RegExp(r'^#.*$'), '').split(r'$').skip(2);
final List<String> tuples = [];
for (final block in blocks) {
final String radical = block[1];
final List<String> kanjiList = block
.replaceFirst(RegExp(r'.*\n'), '')
.split('')
..removeWhere((e) => e == '' || e == '\n');
for (final kanji in kanjiList) {
tuples.add(" ('$radical', '$kanji')");
}
}
File('0003_populate_radkfile.sql').writeAsStringSync(
'''
INSERT INTO RADKFILE(radical, kanji) VALUES
${tuples.join(',\n')};''',
);
}

View File

@@ -0,0 +1,213 @@
// ignore_for_file: avoid_print
import 'dart:convert';
import 'dart:io';
import 'package:unofficial_jisho_api/api.dart';
Future<void> cacheData(int i) async {
final File cacheFile = File('data/jisho/grade$i.json');
final File kanjiFile = File('data/jouyou/grade$i.txt');
final List<String> kanji = [
for (final k in kanjiFile.readAsStringSync().runes) String.fromCharCode(k)
];
final List<KanjiResultData> data = [];
await Future.wait([
for (int i = 0; i < kanji.length; i++)
Future.delayed(Duration(milliseconds: 300 * i), () async {
print('$i: ${kanji[i]}');
final result = await searchForKanji(kanji[i]);
data.add(result.data!);
})
]);
const JsonEncoder encoder = JsonEncoder.withIndent(' ');
cacheFile.writeAsStringSync(encoder.convert(data));
}
String quote(String input) => "'${input.replaceAll("'", "''")}'";
extension SQLInserts on KanjiResultData {
int? get jlptLevelNumber =>
jlptLevel != null ? int.parse(jlptLevel![1]) : null;
int? get taughtInNumber => taughtIn == null
? null
: taughtIn == 'junior high'
? 7
: int.parse(taughtIn![6]);
static String get kanjiResultCols =>
'(kanji, strokeCount, meaning, radical, jlptLevel, newspaperFrequencyRank, taughtIn, isJouyou)';
String get kanjiResultRow =>
// ignore: prefer_interpolation_to_compose_strings
'("$kanji", $strokeCount, "$meaning", "${radical!.symbol}", ' +
((jlptLevel != null) ? '$jlptLevelNumber, ' : 'NULL, ') +
((newspaperFrequencyRank != null)
? '$newspaperFrequencyRank, '
: 'NULL, ') +
((taughtIn != null) ? '$taughtInNumber, ' : 'NULL, ') +
'true'
')';
static String get yomiCols => '(yomi)';
static String get partCols => '(part)';
List<String> get onyomiRows => onyomi.map((y) => '("$y")').toList();
List<String> get kunyomiRows => kunyomi.map((y) => '("$y")').toList();
List<String> get partsRows => kunyomi.map((p) => '("$p")').toList();
static String get yomiXRefCols => '(kanji, yomi)';
static String get partXRefCols => '(kanji, part)';
List<String> get onyomiXRefRows =>
onyomi.map((y) => "('$kanji', '$y')").toList();
List<String> get kunyomiXRefRows =>
kunyomi.map((y) => "('$kanji', '$y')").toList();
List<String> get partsXRefRows =>
kunyomi.map((p) => "('$kanji', '$p')").toList();
static String get yomiExampleCols => '(example, reading, meaning)';
List<String> get onyomiExamplesRows => onyomiExamples
.map(
(y) =>
'(${quote(y.example)}, ${quote(y.reading)}, ${quote(y.meaning)})',
)
.toList();
List<String> get kunyomiExamplesRows => kunyomiExamples
.map(
(y) =>
'(${quote(y.example)}, ${quote(y.reading)}, ${quote(y.meaning)})',
)
.toList();
static String get yomiExampleXRefCols => '(exampleID, kanji)';
List<String> onyomiExamplesXRefRows(int exampleID) => [
for (int i = 0; i < onyomiExamples.length; i++)
"(${exampleID + i}, '$kanji')"
];
List<String> kunyomiExamplesXRefRows(int exampleID) => [
for (int i = 0; i < kunyomiExamples.length; i++)
"(${exampleID + i}, '$kanji')"
];
}
int exampleIDXRefCounter = 1;
List<String> generateStatements(List<KanjiResultData> kanji) {
final List<String> statements = [];
final List<String> tableKanjiResult = [];
final List<String> tableOnyomi = [];
final List<String> tableKunyomi = [];
final List<String> tablePart = [];
final List<String> tableOnyomiExamples = [];
final List<String> tableKunyomiExamples = [];
final List<String> tableOnyomiXRef = [];
final List<String> tableKunyomiXRef = [];
final List<String> tablePartXRef = [];
final List<String> tableOnyomiExamplesXRef = [];
final List<String> tableKunyomiExamplesXRef = [];
for (final k in kanji) {
tableKanjiResult.add(k.kanjiResultRow);
tableOnyomi.addAll(k.onyomiRows);
tableKunyomi.addAll(k.kunyomiRows);
tablePart.addAll(k.partsRows);
tableOnyomiExamples.addAll(k.onyomiExamplesRows);
tableKunyomiExamples.addAll(k.kunyomiExamplesRows);
tableOnyomiXRef.addAll(k.onyomiXRefRows);
tableKunyomiXRef.addAll(k.kunyomiXRefRows);
tablePartXRef.addAll(k.partsXRefRows);
}
for (final k in kanji) {
final oxr = k.onyomiExamplesXRefRows(exampleIDXRefCounter);
exampleIDXRefCounter += oxr.length;
tableOnyomiExamplesXRef.addAll(oxr);
}
for (final k in kanji) {
final kxr = k.kunyomiExamplesXRefRows(exampleIDXRefCounter);
exampleIDXRefCounter += kxr.length;
tableKunyomiExamplesXRef.addAll(kxr);
}
void insertStatement({
required String table,
required List<String> values,
orIgnore = false,
}) =>
statements.add(
'INSERT${orIgnore ? ' OR IGNORE' : ''} INTO $table VALUES\n'
'${values.join(',\n')};\n',
);
insertStatement(
table: 'Kanji_Result${SQLInserts.kanjiResultCols}',
values: tableKanjiResult,
);
for (final isOnyomi in [true, false]) {
final String name = isOnyomi ? 'Onyomi' : 'Kunyomi';
insertStatement(
table: 'Kanji_$name${SQLInserts.yomiCols}',
values: isOnyomi ? tableOnyomi : tableKunyomi,
orIgnore: true,
);
insertStatement(
table: 'Kanji_Result${name}_XRef${SQLInserts.yomiXRefCols}',
values: isOnyomi ? tableOnyomiXRef : tableKunyomiXRef,
);
insertStatement(
table: 'Kanji_YomiExample${SQLInserts.yomiExampleCols}',
values: isOnyomi ? tableOnyomiExamples : tableKunyomiExamples,
orIgnore: true,
);
insertStatement(
table: 'Kanji_Result${name}Example_XRef${SQLInserts.yomiExampleXRefCols}',
values: isOnyomi ? tableOnyomiExamplesXRef : tableKunyomiExamplesXRef,
);
}
insertStatement(
table: 'Kanji_Part${SQLInserts.partCols}',
values: tablePart,
orIgnore: true,
);
insertStatement(
table: 'Kanji_ResultPart_XRef${SQLInserts.partXRefCols}',
values: tablePartXRef,
);
return statements;
}
Future<void> main() async {
final dataDir = Directory('data/jisho');
dataDir.createSync();
final List<String> statements = [];
for (int i = 1; i <= 7; i++) {
final File cacheFile = File('data/jisho/grade$i.json');
if (!cacheFile.existsSync()) {
await cacheData(i);
}
final String content = cacheFile.readAsStringSync();
final List<KanjiResultData> kanji = (jsonDecode(content) as List)
.map((e) => KanjiResultData.fromJson(e))
.toList();
statements.addAll(generateStatements(kanji));
}
File('0004_populate_jouyou_kanji.sql')
.writeAsStringSync(statements.join('\n'));
}

View File

@@ -86,3 +86,35 @@ Future<void> addSearchToDatabase({
.toJson(),
);
}
List<Search> mergeSearches(List<Search> a, List<Search> b) {
final List<Search> result = [...a];
for (final Search search in b) {
late final Iterable<Search> matchingEntry;
if (search.isKanji) {
matchingEntry =
result.where((e) => e.kanjiQuery?.kanji == search.kanjiQuery!.kanji);
} else {
matchingEntry =
result.where((e) => e.wordQuery?.query == search.wordQuery!.query);
}
if (matchingEntry.isEmpty) {
result.add(search);
continue;
}
final timestamps = [...matchingEntry.first.timestamps];
matchingEntry.first.timestamps.clear();
matchingEntry.first.timestamps.addAll(
(timestamps
..addAll(search.timestamps)
..sort())
.toSet()
.toList(),
);
}
return result;
}

View File

View File

@@ -1,13 +1,22 @@
import 'dart:convert';
import 'dart:io';
import 'package:confirm_dialog/confirm_dialog.dart';
import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart';
import 'package:flutter_settings_ui/flutter_settings_ui.dart';
import 'package:mdi/mdi.dart';
import 'package:path_provider/path_provider.dart';
import 'package:sembast/sembast_io.dart';
import 'package:sembast/utils/sembast_import_export.dart';
import '../bloc/theme/theme_bloc.dart';
import '../components/common/denshi_jisho_background.dart';
import '../models/history/search.dart';
import '../routing/routes.dart';
import '../services/database.dart';
import '../services/open_webpage.dart';
import '../services/snackbar.dart';
import '../settings.dart';
class SettingsView extends StatefulWidget {
@@ -19,6 +28,8 @@ class SettingsView extends StatefulWidget {
class _SettingsViewState extends State<SettingsView> {
final Database db = GetIt.instance.get<Database>();
bool dataExportIsLoading = false;
bool dataImportIsLoading = false;
Future<void> clearHistory(context) async {
final bool userIsSure = await confirm(context);
@@ -40,6 +51,92 @@ class _SettingsViewState extends State<SettingsView> {
setState(() => autoThemeEnabled = b);
}
Future<void> changeFont(context) async {
final int? i = await _chooseFromList(
list: [for (final font in JapaneseFont.values) font.name],
chosen: japaneseFont.index,
)(context);
if (i != null)
setState(() {
japaneseFont = JapaneseFont.values[i];
});
}
/// Can assume Android for time being
Future<void> exportData(context) async {
setState(() => dataExportIsLoading = true);
final path = (await getExternalStorageDirectory())!;
final dbData = await exportDatabase(db);
final file = File('${path.path}/jisho_data.json');
file.createSync(recursive: true);
await file.writeAsString(jsonEncode(dbData));
setState(() => dataExportIsLoading = false);
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(content: Text('Data exported to ${file.path}')));
}
/// Can assume Android for time being
Future<void> importData(context) async {
setState(() => dataImportIsLoading = true);
final path = await FilePicker.platform.pickFiles(
type: FileType.custom,
allowedExtensions: ['json'],
);
final file = File(path!.files[0].path!);
final List<Search> prevSearches = (await Search.store.find(db))
.map((e) => Search.fromJson(e.value! as Map<String, Object?>))
.toList();
late final List<Search> importedSearches;
try {
importedSearches = ((((jsonDecode(await file.readAsString())
as Map<String, Object?>)['stores']! as List)
.map((e) => e as Map)
.where((e) => e['name'] == 'search')
.first)['values'] as List)
.map((item) => Search.fromJson(item))
.toList();
} catch (e) {
debugPrint(e.toString());
showSnackbar(
context,
"Couldn't read file. Did you choose the right one?",
);
return;
}
final List<Search> mergedSearches =
mergeSearches(prevSearches, importedSearches);
// print(mergedSearches);
await GetIt.instance.get<Database>().close();
GetIt.instance.unregister<Database>();
final importedDb = await importDatabase(
{
'sembast_export': 1,
'version': 1,
'stores': [
{
'name': 'search',
'keys': [for (var i = 1; i <= mergedSearches.length; i++) i],
'values': mergedSearches.map((e) => e.toJson()).toList(),
}
]
},
databaseFactoryIo,
await databasePath(),
);
GetIt.instance.registerSingleton<Database>(importedDb);
setState(() => dataImportIsLoading = false);
showSnackbar(context, 'Data imported successfully');
}
Future<int?> Function(BuildContext) _chooseFromList({
required List<String> list,
int? chosen,
@@ -89,9 +186,7 @@ class _SettingsViewState extends State<SettingsView> {
SettingsTile.switchTile(
title: 'Use romaji',
leading: const Icon(Mdi.alphabetical),
onToggle: (b) {
setState(() => romajiEnabled = b);
},
onToggle: (b) => setState(() => romajiEnabled = b),
switchValue: romajiEnabled,
theme: theme,
switchActiveColor: AppTheme.jishoGreen.background,
@@ -99,9 +194,7 @@ class _SettingsViewState extends State<SettingsView> {
SettingsTile.switchTile(
title: 'Extensive search',
leading: const Icon(Icons.downloading),
onToggle: (b) {
setState(() => extensiveSearchEnabled = b);
},
onToggle: (b) => setState(() => extensiveSearchEnabled = b),
switchValue: extensiveSearchEnabled,
theme: theme,
switchActiveColor: AppTheme.jishoGreen.background,
@@ -114,18 +207,7 @@ class _SettingsViewState extends State<SettingsView> {
SettingsTile(
title: 'Japanese font',
leading: const Icon(Icons.format_size),
onPressed: (context) async {
final int? i = await _chooseFromList(
list: [
for (final font in JapaneseFont.values) font.name
],
chosen: japaneseFont.index,
)(context);
if (i != null)
setState(() {
japaneseFont = JapaneseFont.values[i];
});
},
onPressed: changeFont,
theme: theme,
trailing: Text(japaneseFont.name),
// subtitle:
@@ -134,6 +216,7 @@ class _SettingsViewState extends State<SettingsView> {
),
],
),
SettingsSection(
title: 'Theme',
titleTextStyle: _titleTextStyle,
@@ -161,6 +244,7 @@ class _SettingsViewState extends State<SettingsView> {
),
],
),
// TODO: This will be left commented until caching is implemented
// SettingsSection(
// title: 'Cache',
@@ -196,14 +280,31 @@ class _SettingsViewState extends State<SettingsView> {
// ),
// ],
// ),
SettingsSection(
title: 'Data',
titleTextStyle: _titleTextStyle,
tiles: <SettingsTile>[
SettingsTile(
leading: const Icon(Icons.file_upload),
title: 'Import Data',
onPressed: importData,
enabled: Platform.isAndroid,
subtitle:
Platform.isAndroid ? null : 'Not available on iOS yet',
subtitleWidget: dataImportIsLoading
? const LinearProgressIndicator()
: null,
),
SettingsTile(
leading: const Icon(Icons.file_download),
title: 'Export Data',
enabled: false,
enabled: Platform.isAndroid,
subtitle:
Platform.isAndroid ? null : 'Not available on iOS yet',
subtitleWidget: dataExportIsLoading
? const LinearProgressIndicator()
: null,
),
SettingsTile(
leading: const Icon(Icons.delete),
@@ -220,6 +321,7 @@ class _SettingsViewState extends State<SettingsView> {
)
],
),
SettingsSection(
title: 'Info',
titleTextStyle: _titleTextStyle,

View File

@@ -6,10 +6,14 @@ import 'package:path_provider/path_provider.dart';
import 'package:sembast/sembast.dart';
import 'package:sembast/sembast_io.dart';
Future<void> setupDatabase() async {
Future<String> databasePath() async {
final Directory appDocDir = await getApplicationDocumentsDirectory();
if (!appDocDir.existsSync()) appDocDir.createSync(recursive: true);
return join(appDocDir.path, 'sembast.db');
}
Future<void> setupDatabase() async {
final Database database =
await databaseFactoryIo.openDatabase(join(appDocDir.path, 'sembast.db'));
await databaseFactoryIo.openDatabase(await databasePath());
GetIt.instance.registerSingleton<Database>(database);
}

View File

@@ -1,25 +1,5 @@
import 'package:unofficial_jisho_api/api.dart' as jisho;
export 'package:unofficial_jisho_api/api.dart' show KanjiResult;
String? _convertGrade(String grade) {
const conversionTable = {
'grade 1': '小1',
'grade 2': '小2',
'grade 3': '小3',
'grade 4': '小4',
'grade 5': '小5',
'grade 6': '小6',
'junior high': ''
};
return conversionTable[grade];
}
// TODO: fix this logic
Future<jisho.KanjiResult> fetchKanji(String kanji) async {
final result = await jisho.searchForKanji(kanji);
if (result.data != null && result.data?.taughtIn != null)
result.data!.taughtIn = _convertGrade(result.data!.taughtIn!);
return result;
}
Future<jisho.KanjiResult> fetchKanji(String kanji) =>
jisho.searchForKanji(kanji);

View File

@@ -0,0 +1,23 @@
import 'package:unofficial_jisho_api/api.dart';
extension GradeConversion on KanjiResultData {
String? get grade => {
'grade 1': '小1',
'grade 2': '小2',
'grade 3': '小3',
'grade 4': '小4',
'grade 5': '小5',
'grade 6': '小6',
'junior high': ''
}[taughtIn];
int? get gradeNum => {
'grade 1': 1,
'grade 2': 2,
'grade 3': 3,
'grade 4': 4,
'grade 5': 5,
'grade 6': 6,
'junior high': 7,
}[taughtIn];
}

View File

@@ -0,0 +1 @@
final kanjiRegex = RegExp(r'\p{Script=Hani}', unicode: true);

View File

@@ -0,0 +1,4 @@
import 'package:flutter/material.dart';
void showSnackbar(BuildContext context, String text) =>
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(text)));

74
nix/dart.nix Normal file
View File

@@ -0,0 +1,74 @@
{ stdenv
, lib
, fetchurl
, unzip
, version ? "2.16.2"
, sources ? let
base = "https://storage.googleapis.com/dart-archive/channels";
x86_64 = "x64";
i686 = "ia32";
aarch64 = "arm64";
# Make sure that if the user overrides version parameter they're
# also need to override sources, to avoid mistakes
version = "2.16.2";
in
{
"${version}-aarch64-darwin" = fetchurl {
url = "${base}/stable/release/${version}/sdk/dartsdk-macos-${aarch64}-release.zip";
sha256 = "sha256-DDE4DpA2m8wKkUZuQDn4NpXVvtaJ6sIHeKNjk3RbpYE=";
};
"${version}-x86_64-darwin" = fetchurl {
url = "${base}/stable/release/${version}/sdk/dartsdk-macos-${x86_64}-release.zip";
sha256 = "sha256-s6bkwh2m5KdRr/WxWXwItO9YaDpp/HI3xjnS2UHmN+I=";
};
"${version}-x86_64-linux" = lib.trace version fetchurl {
url = "${base}/stable/release/${version}/sdk/dartsdk-linux-${x86_64}-release.zip";
sha256 = "sha256-egrYd7B4XhkBiHPIFE2zopxKtQ58GqlogAKA/UeiXnI=";
};
"${version}-i686-linux" = fetchurl {
url = "${base}/stable/release/${version}/sdk/dartsdk-linux-${i686}-release.zip";
sha256 = "sha256-SRq5TtxS+bwCqVxa0U2Zhn8J1Wtm4Onq+3uQS+951sw=";
};
"${version}-aarch64-linux" = fetchurl {
url = "${base}/stable/release/${version}/sdk/dartsdk-linux-${aarch64}-release.zip";
sha256 = "sha256-iDbClCNDUsxT6K6koc4EQuu7dppTbOfzCVedpQIKI5U=";
};
}
}:
assert version != null && version != "";
assert sources != null && (builtins.isAttrs sources);
stdenv.mkDerivation {
pname = "dart";
inherit version;
nativeBuildInputs = [ unzip ];
src = sources."${version}-${stdenv.hostPlatform.system}" or (throw "unsupported version/system: ${version}/${stdenv.hostPlatform.system}");
installPhase = ''
mkdir -p $out
cp -R * $out/
echo $libPath
'' + lib.optionalString(stdenv.isLinux) ''
find $out/bin -executable -type f -exec patchelf --set-interpreter $(cat $NIX_CC/nix-support/dynamic-linker) {} \;
'';
libPath = lib.makeLibraryPath [ stdenv.cc.cc ];
dontStrip = true;
meta = with lib; {
homepage = "https://www.dartlang.org/";
maintainers = with maintainers; [ grburst flexagoon ];
description = "Scalable programming language, with robust libraries and runtimes, for building web, server, and mobile apps";
longDescription = ''
Dart is a class-based, single inheritance, object-oriented language
with C-style syntax. It offers compilation to JavaScript, interfaces,
mixins, abstract classes, reified generics, and optional typing.
'';
platforms = [ "x86_64-linux" "i686-linux" "aarch64-linux" "x86_64-darwin" "aarch64-darwin" ];
license = licenses.bsd3;
};
}

24
nix/flutter.nix Normal file
View File

@@ -0,0 +1,24 @@
{ flutterPackages, fetchurl, dart }:
let
dartVersion = "2.16.2";
flutterVersion = "2.10.5";
channel = "stable";
filename = "flutter_linux_${flutterVersion}-${channel}.tar.xz";
getPatches = dir:
let files = builtins.attrNames (builtins.readDir dir);
in map (f: dir + ("/" + f)) files;
in
{
flutter = flutterPackages.mkFlutter {
version = flutterVersion;
inherit dart;
pname = "flutter";
src = fetchurl {
url = "https://storage.googleapis.com/flutter_infra_release/releases/${channel}/linux/${filename}";
sha256 = "DTZwxlMUYk8NS1SaWUJolXjD+JnRW73Ps5CdRHDGnt0=";
};
patches = getPatches ./flutter_patches;
};
}

178
nix/flutter_builder.nix Normal file
View File

@@ -0,0 +1,178 @@
{ pname
, version
, patches
, dart
, src
}:
{ bash
, buildFHSUserEnv
, cacert
, git
, runCommand
, stdenv
, lib
, alsa-lib
, dbus
, expat
, libpulseaudio
, libuuid
, libX11
, libxcb
, libXcomposite
, libXcursor
, libXdamage
, libXfixes
, libXrender
, libXtst
, libXi
, libXext
, libGL
, nspr
, nss
, systemd
, which
, callPackage
}:
let
drvName = "flutter-${version}";
flutter = stdenv.mkDerivation {
name = "${drvName}-unwrapped";
buildInputs = [ git ];
inherit src patches version;
postPatch = ''
patchShebangs --build ./bin/
'';
buildPhase = ''
export FLUTTER_ROOT="$(pwd)"
export FLUTTER_TOOLS_DIR="$FLUTTER_ROOT/packages/flutter_tools"
export SCRIPT_PATH="$FLUTTER_TOOLS_DIR/bin/flutter_tools.dart"
export SNAPSHOT_PATH="$FLUTTER_ROOT/bin/cache/flutter_tools.snapshot"
export STAMP_PATH="$FLUTTER_ROOT/bin/cache/flutter_tools.stamp"
export DART_SDK_PATH="${dart}"
HOME=../.. # required for pub upgrade --offline, ~/.pub-cache
# path is relative otherwise it's replaced by /build/flutter
pushd "$FLUTTER_TOOLS_DIR"
${dart}/bin/pub get --offline
popd
local revision="$(cd "$FLUTTER_ROOT"; git rev-parse HEAD)"
${dart}/bin/dart --snapshot="$SNAPSHOT_PATH" --packages="$FLUTTER_TOOLS_DIR/.packages" "$SCRIPT_PATH"
echo "$revision" > "$STAMP_PATH"
echo -n "${version}" > version
rm -r bin/cache/{artifacts,dart-sdk,downloads}
rm bin/cache/*.stamp
'';
installPhase = ''
runHook preInstall
mkdir -p $out
cp -r . $out
mkdir -p $out/bin/cache/
ln -sf ${dart} $out/bin/cache/dart-sdk
runHook postInstall
'';
doInstallCheck = true;
installCheckInputs = [ which ];
installCheckPhase = ''
runHook preInstallCheck
export HOME="$(mktemp -d)"
$out/bin/flutter config --android-studio-dir $HOME
$out/bin/flutter config --android-sdk $HOME
$out/bin/flutter --version | fgrep -q '${version}'
runHook postInstallCheck
'';
};
# Wrap flutter inside an fhs user env to allow execution of binary,
# like adb from $ANDROID_HOME or java from android-studio.
fhsEnv = buildFHSUserEnv {
name = "${drvName}-fhs-env";
multiPkgs = pkgs: [
# Flutter only use these certificates
(runCommand "fedoracert" { } ''
mkdir -p $out/etc/pki/tls/
ln -s ${cacert}/etc/ssl/certs $out/etc/pki/tls/certs
'')
pkgs.zlib
];
targetPkgs = pkgs:
with pkgs; [
bash
curl
dart
git
unzip
which
xz
# flutter test requires this lib
libGLU
# for android emulator
alsa-lib
dbus
expat
libpulseaudio
libuuid
libX11
libxcb
libXcomposite
libXcursor
libXdamage
libXext
libXfixes
libXi
libXrender
libXtst
libGL
nspr
nss
systemd
];
};
in
let
self = (self:
runCommand drvName
{
startScript = ''
#!${bash}/bin/bash
export PUB_CACHE=''${PUB_CACHE:-"$HOME/.pub-cache"}
export ANDROID_EMULATOR_USE_SYSTEM_LIBS=1
${fhsEnv}/bin/${drvName}-fhs-env ${flutter}/bin/flutter --no-version-check "$@"
'';
preferLocalBuild = true;
allowSubstitutes = false;
passthru = {
unwrapped = flutter;
inherit dart;
mkFlutterApp = callPackage ../../../build-support/flutter {
flutter = self;
};
};
meta = with lib; {
description = "Flutter is Google's SDK for building mobile, web and desktop with Dart";
longDescription = ''
Flutter is Googles UI toolkit for building beautiful,
natively compiled applications for mobile, web, and desktop from a single codebase.
'';
homepage = "https://flutter.dev";
license = licenses.bsd3;
platforms = [ "x86_64-linux" ];
maintainers = with maintainers; [ babariviere ericdallo ];
};
} ''
mkdir -p $out/bin
mkdir -p $out/bin/cache/
ln -sf ${dart} $out/bin/cache/dart-sdk
echo -n "$startScript" > $out/bin/${pname}
chmod +x $out/bin/${pname}
'') self;
in
self

View File

@@ -0,0 +1,37 @@
diff --git i/bin/internal/shared.sh w/bin/internal/shared.sh
index 05cba4393b..2a775bf24f 100644
--- i/bin/internal/shared.sh
+++ w/bin/internal/shared.sh
@@ -217,8 +217,6 @@ function shared::execute() {
# FLUTTER_TOOL_ARGS="--enable-asserts $FLUTTER_TOOL_ARGS"
# FLUTTER_TOOL_ARGS="$FLUTTER_TOOL_ARGS --observe=65432"
- upgrade_flutter 7< "$PROG_NAME"
-
BIN_NAME="$(basename "$PROG_NAME")"
case "$BIN_NAME" in
flutter*)
diff --git i/packages/flutter_tools/lib/src/runner/flutter_command_runner.dart w/packages/flutter_tools/lib/src/runner/flutter_command_runner.dart
index 396756808e..4915f71f18 100644
--- i/packages/flutter_tools/lib/src/runner/flutter_command_runner.dart
+++ w/packages/flutter_tools/lib/src/runner/flutter_command_runner.dart
@@ -241,7 +241,6 @@ class FlutterCommandRunner extends CommandRunner<void> {
globals.flutterUsage.suppressAnalytics = true;
}
- globals.flutterVersion.ensureVersionFile();
final bool machineFlag = topLevelResults['machine'] as bool? ?? false;
final bool ci = await globals.botDetector.isRunningOnBot;
final bool redirectedCompletion = !globals.stdio.hasTerminal &&
@@ -250,11 +249,6 @@ class FlutterCommandRunner extends CommandRunner<void> {
final bool versionCheckFlag = topLevelResults['version-check'] as bool? ?? false;
final bool explicitVersionCheckPassed = topLevelResults.wasParsed('version-check') && versionCheckFlag;
- if (topLevelResults.command?.name != 'upgrade' &&
- (explicitVersionCheckPassed || (versionCheckFlag && !isMachine))) {
- await globals.flutterVersion.checkFlutterVersionFreshness();
- }
-
// See if the user specified a specific device.
globals.deviceManager?.specifiedDeviceId = topLevelResults['device-id'] as String?;

View File

@@ -0,0 +1,77 @@
diff --git i/packages/flutter_tools/lib/src/asset.dart w/packages/flutter_tools/lib/src/asset.dart
index ed42baea29..e7308372e7 100644
--- i/packages/flutter_tools/lib/src/asset.dart
+++ w/packages/flutter_tools/lib/src/asset.dart
@@ -5,6 +5,7 @@
import 'package:meta/meta.dart';
import 'package:package_config/package_config.dart';
+import 'base/common.dart';
import 'base/context.dart';
import 'base/deferred_component.dart';
import 'base/file_system.dart';
@@ -16,6 +17,7 @@ import 'convert.dart';
import 'dart/package_map.dart';
import 'devfs.dart';
import 'flutter_manifest.dart';
+import 'globals.dart' as globals;
import 'license_collector.dart';
import 'project.dart';
@@ -504,7 +506,7 @@ class ManifestAssetBundle implements AssetBundle {
}
final Uri entryUri = _fileSystem.path.toUri(asset);
result.add(_Asset(
- baseDir: _fileSystem.path.join(Cache.flutterRoot!, 'bin', 'cache', 'artifacts', 'material_fonts'),
+ baseDir: _fileSystem.path.join(globals.fsUtils.homeDirPath!, '.cache', 'flutter', 'artifacts', 'material_fonts'),
relativeUri: Uri(path: entryUri.pathSegments.last),
entryUri: entryUri,
package: null,
diff --git i/packages/flutter_tools/lib/src/cache.dart w/packages/flutter_tools/lib/src/cache.dart
index defc86cc20..5078375f02 100644
--- i/packages/flutter_tools/lib/src/cache.dart
+++ w/packages/flutter_tools/lib/src/cache.dart
@@ -22,6 +22,7 @@ import 'base/user_messages.dart';
import 'build_info.dart';
import 'convert.dart';
import 'features.dart';
+import 'globals.dart' as globals;
const String kFlutterRootEnvironmentVariableName = 'FLUTTER_ROOT'; // should point to //flutter/ (root of flutter/flutter repo)
const String kFlutterEngineEnvironmentVariableName = 'FLUTTER_ENGINE'; // should point to //engine/src/ (root of flutter/engine repo)
@@ -322,8 +323,15 @@ class Cache {
return;
}
assert(_lock == null);
+
+ final Directory dir = _fileSystem.directory(_fileSystem.path.join(globals.fsUtils.homeDirPath!, '.cache', 'flutter'));
+ if (!dir.existsSync()) {
+ dir.createSync(recursive: true);
+ globals.os.chmod(dir, '755');
+ }
+
final File lockFile =
- _fileSystem.file(_fileSystem.path.join(flutterRoot!, 'bin', 'cache', 'lockfile'));
+ _fileSystem.file(_fileSystem.path.join(globals.fsUtils.homeDirPath!, '.cache', 'flutter', 'lockfile'));
try {
_lock = lockFile.openSync(mode: FileMode.write);
} on FileSystemException catch (e) {
@@ -383,7 +391,8 @@ class Cache {
String get devToolsVersion {
if (_devToolsVersion == null) {
const String devToolsDirPath = 'dart-sdk/bin/resources/devtools';
- final Directory devToolsDir = getCacheDir(devToolsDirPath, shouldCreate: false);
+ final Directory devToolsDir =
+ _fileSystem.directory(_fileSystem.path.join(flutterRoot!, 'bin', 'cache', devToolsDirPath));
if (!devToolsDir.existsSync()) {
throw Exception('Could not find directory at ${devToolsDir.path}');
}
@@ -536,7 +545,7 @@ class Cache {
if (_rootOverride != null) {
return _fileSystem.directory(_fileSystem.path.join(_rootOverride!.path, 'bin', 'cache'));
} else {
- return _fileSystem.directory(_fileSystem.path.join(flutterRoot!, 'bin', 'cache'));
+ return _fileSystem.directory(_fileSystem.path.join(globals.fsUtils.homeDirPath!, '.cache', 'flutter'));
}
}

View File

@@ -7,14 +7,14 @@ packages:
name: _fe_analyzer_shared
url: "https://pub.dartlang.org"
source: hosted
version: "33.0.0"
version: "31.0.0"
analyzer:
dependency: transitive
description:
name: analyzer
url: "https://pub.dartlang.org"
source: hosted
version: "3.1.0"
version: "2.8.0"
animated_size_and_fade:
dependency: "direct main"
description:
@@ -28,7 +28,7 @@ packages:
name: archive
url: "https://pub.dartlang.org"
source: hosted
version: "3.1.8"
version: "3.3.0"
args:
dependency: transitive
description:
@@ -56,7 +56,7 @@ packages:
name: bloc
url: "https://pub.dartlang.org"
source: hosted
version: "8.0.2"
version: "8.0.3"
boolean_selector:
dependency: transitive
description:
@@ -70,7 +70,7 @@ packages:
name: build
url: "https://pub.dartlang.org"
source: hosted
version: "2.2.1"
version: "2.3.0"
build_config:
dependency: transitive
description:
@@ -84,7 +84,7 @@ packages:
name: build_daemon
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.1"
version: "3.1.0"
build_resolvers:
dependency: transitive
description:
@@ -98,7 +98,7 @@ packages:
name: build_runner
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.7"
version: "2.1.10"
build_runner_core:
dependency: transitive
description:
@@ -119,7 +119,7 @@ packages:
name: built_value
url: "https://pub.dartlang.org"
source: hosted
version: "8.1.3"
version: "8.2.3"
characters:
dependency: transitive
description:
@@ -175,7 +175,7 @@ packages:
name: confirm_dialog
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.0"
version: "1.0.1"
convert:
dependency: transitive
description:
@@ -183,13 +183,20 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.1"
coverage:
dependency: transitive
description:
name: coverage
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.3"
crypto:
dependency: transitive
description:
name: crypto
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.1"
version: "3.0.2"
csslib:
dependency: transitive
description:
@@ -232,6 +239,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "6.1.2"
file_picker:
dependency: "direct main"
description:
name: file_picker
url: "https://pub.dartlang.org"
source: hosted
version: "4.5.1"
fixnum:
dependency: transitive
description:
@@ -264,7 +278,14 @@ packages:
name: flutter_native_splash
url: "https://pub.dartlang.org"
source: hosted
version: "1.3.3"
version: "2.1.6"
flutter_plugin_android_lifecycle:
dependency: transitive
description:
name: flutter_plugin_android_lifecycle
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.5"
flutter_settings_ui:
dependency: "direct main"
description:
@@ -351,7 +372,7 @@ packages:
name: http_multi_server
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.1"
version: "3.2.0"
http_parser:
dependency: transitive
description:
@@ -365,7 +386,7 @@ packages:
name: image
url: "https://pub.dartlang.org"
source: hosted
version: "3.1.0"
version: "3.1.3"
io:
dependency: transitive
description:
@@ -386,28 +407,35 @@ packages:
name: json_annotation
url: "https://pub.dartlang.org"
source: hosted
version: "4.4.0"
version: "4.5.0"
just_audio:
dependency: "direct main"
description:
name: just_audio
url: "https://pub.dartlang.org"
source: hosted
version: "0.9.18"
version: "0.9.21"
just_audio_platform_interface:
dependency: transitive
description:
name: just_audio_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "4.0.0"
version: "4.1.0"
just_audio_web:
dependency: transitive
description:
name: just_audio_web
url: "https://pub.dartlang.org"
source: hosted
version: "0.4.3"
version: "0.4.7"
lint:
dependency: transitive
description:
name: lint
url: "https://pub.dartlang.org"
source: hosted
version: "1.8.2"
logging:
dependency: transitive
description:
@@ -422,6 +450,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "0.12.11"
material_color_utilities:
dependency: transitive
description:
name: material_color_utilities
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.3"
mdi:
dependency: "direct main"
description:
@@ -442,7 +477,7 @@ packages:
name: mime
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.1"
version: "1.0.2"
nested:
dependency: transitive
description:
@@ -450,6 +485,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.0"
node_preamble:
dependency: transitive
description:
name: node_preamble
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.1"
package_config:
dependency: transitive
description:
@@ -484,21 +526,21 @@ packages:
name: path_provider
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.8"
version: "2.0.9"
path_provider_android:
dependency: transitive
description:
name: path_provider_android
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.11"
version: "2.0.13"
path_provider_ios:
dependency: transitive
description:
name: path_provider_ios
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.7"
version: "2.0.8"
path_provider_linux:
dependency: transitive
description:
@@ -575,7 +617,7 @@ packages:
name: pub_semver
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.0"
version: "2.1.1"
pubspec_parse:
dependency: transitive
description:
@@ -596,42 +638,84 @@ packages:
name: sembast
url: "https://pub.dartlang.org"
source: hosted
version: "3.1.1+1"
version: "3.2.0"
share_plus:
dependency: "direct main"
description:
name: share_plus
url: "https://pub.dartlang.org"
source: hosted
version: "4.0.4"
share_plus_linux:
dependency: transitive
description:
name: share_plus_linux
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.0"
share_plus_macos:
dependency: transitive
description:
name: share_plus_macos
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.0"
share_plus_platform_interface:
dependency: transitive
description:
name: share_plus_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.2"
share_plus_web:
dependency: transitive
description:
name: share_plus_web
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.0"
share_plus_windows:
dependency: transitive
description:
name: share_plus_windows
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.0"
shared_preferences:
dependency: "direct main"
description:
name: shared_preferences
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.12"
version: "2.0.13"
shared_preferences_android:
dependency: transitive
description:
name: shared_preferences_android
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.10"
version: "2.0.11"
shared_preferences_ios:
dependency: transitive
description:
name: shared_preferences_ios
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.9"
version: "2.1.0"
shared_preferences_linux:
dependency: transitive
description:
name: shared_preferences_linux
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.4"
version: "2.1.0"
shared_preferences_macos:
dependency: transitive
description:
name: shared_preferences_macos
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.2"
version: "2.0.3"
shared_preferences_platform_interface:
dependency: transitive
description:
@@ -652,14 +736,28 @@ packages:
name: shared_preferences_windows
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.4"
version: "2.1.0"
shelf:
dependency: transitive
description:
name: shelf
url: "https://pub.dartlang.org"
source: hosted
version: "1.2.0"
version: "1.3.0"
shelf_packages_handler:
dependency: transitive
description:
name: shelf_packages_handler
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.0"
shelf_static:
dependency: transitive
description:
name: shelf_static
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.0"
shelf_web_socket:
dependency: transitive
description:
@@ -679,6 +777,20 @@ packages:
description: flutter
source: sdk
version: "0.0.99"
source_map_stack_trace:
dependency: transitive
description:
name: source_map_stack_trace
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.0"
source_maps:
dependency: transitive
description:
name: source_maps
url: "https://pub.dartlang.org"
source: hosted
version: "0.10.10"
source_span:
dependency: transitive
description:
@@ -720,7 +832,7 @@ packages:
name: synchronized
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.0"
version: "3.0.0+2"
term_glyph:
dependency: transitive
description:
@@ -728,13 +840,27 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.2.0"
test:
dependency: "direct main"
description:
name: test
url: "https://pub.dartlang.org"
source: hosted
version: "1.19.5"
test_api:
dependency: transitive
description:
name: test_api
url: "https://pub.dartlang.org"
source: hosted
version: "0.4.3"
version: "0.4.8"
test_core:
dependency: transitive
description:
name: test_core
url: "https://pub.dartlang.org"
source: hosted
version: "0.4.9"
timing:
dependency: transitive
description:
@@ -762,42 +888,42 @@ packages:
name: unofficial_jisho_api
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.3"
version: "2.0.4"
url_launcher:
dependency: "direct main"
description:
name: url_launcher
url: "https://pub.dartlang.org"
source: hosted
version: "6.0.18"
version: "6.1.0"
url_launcher_android:
dependency: transitive
description:
name: url_launcher_android
url: "https://pub.dartlang.org"
source: hosted
version: "6.0.14"
version: "6.0.16"
url_launcher_ios:
dependency: transitive
description:
name: url_launcher_ios
url: "https://pub.dartlang.org"
source: hosted
version: "6.0.14"
version: "6.0.15"
url_launcher_linux:
dependency: transitive
description:
name: url_launcher_linux
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.2"
version: "3.0.0"
url_launcher_macos:
dependency: transitive
description:
name: url_launcher_macos
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.2"
version: "3.0.0"
url_launcher_platform_interface:
dependency: transitive
description:
@@ -811,21 +937,21 @@ packages:
name: url_launcher_web
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.6"
version: "2.0.9"
url_launcher_windows:
dependency: transitive
description:
name: url_launcher_windows
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.2"
version: "3.0.0"
uuid:
dependency: transitive
description:
name: uuid
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.5"
version: "3.0.6"
vector_math:
dependency: transitive
description:
@@ -833,6 +959,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.1"
vm_service:
dependency: transitive
description:
name: vm_service
url: "https://pub.dartlang.org"
source: hosted
version: "7.5.0"
watcher:
dependency: transitive
description:
@@ -846,21 +979,28 @@ packages:
name: web_socket_channel
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.0"
version: "2.2.0"
webkit_inspection_protocol:
dependency: transitive
description:
name: webkit_inspection_protocol
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.0"
win32:
dependency: transitive
description:
name: win32
url: "https://pub.dartlang.org"
source: hosted
version: "2.3.3"
version: "2.5.2"
xdg_directories:
dependency: transitive
description:
name: xdg_directories
url: "https://pub.dartlang.org"
source: hosted
version: "0.2.0"
version: "0.2.0+1"
xml:
dependency: transitive
description:
@@ -876,5 +1016,5 @@ packages:
source: hosted
version: "3.1.0"
sdks:
dart: ">=2.15.1 <3.0.0"
flutter: ">=2.5.0"
dart: ">=2.16.0 <3.0.0"
flutter: ">=2.10.0"

View File

@@ -10,9 +10,11 @@ dependencies:
collection: ^1.15.0
confirm_dialog: ^1.0.0
division: ^0.9.0
file_picker: ^4.5.1
flutter:
sdk: flutter
flutter_bloc: ^8.0.0
flutter_settings_ui: ^2.0.1
flutter_slidable: ^1.1.0
flutter_svg: ^1.0.2
get_it: ^7.2.0
@@ -22,18 +24,19 @@ dependencies:
path: ^1.8.0
path_provider: ^2.0.2
sembast: ^3.1.1
flutter_settings_ui: ^2.0.1
share_plus: ^4.0.4
test: ^1.19.5
shared_preferences: ^2.0.6
signature: ^5.0.0
unofficial_jisho_api: ^2.0.2
unofficial_jisho_api: ^3.0.0
url_launcher: ^6.0.9
dev_dependencies:
build_runner: ^2.0.6
flutter_test:
sdk: flutter
flutter_native_splash: ^1.2.0
flutter_launcher_icons: "^0.9.1"
flutter_native_splash: ^2.1.6
flutter_launcher_icons: "^0.9.2"
flutter_icons:
android: "launcher_icon"
@@ -42,11 +45,13 @@ flutter_icons:
flutter:
uses-material-design: true
assets:
- assets/
- assets/fonts/
- assets/images/
- assets/images/components/
- assets/images/links/
- assets/images/logo/
- assets/licenses/
@@ -58,7 +63,7 @@ flutter:
- family: Noto Sans CJK
fonts:
- asset: assets/fonts/NotoSansCJK-Regular.ttc
- asset: assets/fonts/NotoSansCJK-Regular.ttc
- family: Noto Serif CJK
fonts:

View File

@@ -0,0 +1,34 @@
import 'package:jisho_study_tool/models/history/kanji_query.dart';
import 'package:jisho_study_tool/models/history/search.dart';
import 'package:jisho_study_tool/models/history/word_query.dart';
import 'package:test/test.dart';
void main() {
group('Search', () {
final List<Search> searches = [
Search.fromKanjiQuery(kanjiQuery: KanjiQuery(kanji: '')),
Search.fromWordQuery(wordQuery: WordQuery(query: 'テスト')),
Search.fromJson({'timestamps':[1648658269960],'lastTimestamp':1648658269960,'wordQuery':null,'kanjiQuery':{'kanji':''}}),
Search.fromJson({'timestamps':[1648674967535],'lastTimestamp':1648674967535,'wordQuery':{'query':'黙る'},'kanjiQuery':null}),
Search.fromJson({'timestamps':[1649079907766],'lastTimestamp':1649079907766,'wordQuery':{'query':'seal'},'kanjiQuery':null}),
Search.fromJson({'timestamps':[1649082072981],'lastTimestamp':1649082072981,'wordQuery':{'query':'感涙屋'},'kanjiQuery':null}),
Search.fromJson({'timestamps':[1644951726777,1644951732749],'lastTimestamp':1644951732749,'wordQuery':{'query':'呑める'},'kanjiQuery':null}),
];
test("mergeSearches with empty lists doesn't add data", () {
final List<Search> merged1 = mergeSearches(searches, []);
final List<Search> merged2 = mergeSearches([], searches);
for (int i = 0; i < searches.length; i++) {
expect(merged1[i], searches[i]);
expect(merged2[i], searches[i]);
}
});
test("mergeSearches with the same list doesn't add data", () {
final List<Search> merged = mergeSearches(searches, searches);
for (int i = 0; i < searches.length; i++) {
expect(merged[i], searches[i]);
}
expect(mergeSearches(searches, searches), searches);
});
});
}