Compare commits

...

126 Commits

Author SHA1 Message Date
45a5810de1 Import library lists 2025-07-07 15:21:26 +02:00
923f5e48f6 screens/settings: allow resetting database despite broken condition 2025-06-26 23:56:09 +02:00
353d5c4c39 services/data_export_import: fix async import bug 2025-06-26 14:48:58 +02:00
a280c9e77a lib/database: verify mugiten tables 2025-06-26 13:43:45 +02:00
1af5b9bd83 library_list/table_names: fix table name 2025-06-26 00:04:59 +02:00
1eb077abff pubspec.lock: update jadb 2025-06-25 23:48:03 +02:00
1bc9e6a398 Data export/import 2025-06-25 23:39:38 +02:00
e83799df55 treewide: remaining fixes for history/library 2025-06-24 20:49:46 +02:00
fc7e2ca7ce components/drawing_board: use MLkit 2025-06-24 20:48:30 +02:00
d3d7fbc505 screens/debug: update with different component 2025-06-24 20:48:16 +02:00
3f55ae1413 treewide: implement most of library logic 2025-06-24 20:48:06 +02:00
b404267728 treewide: reimplement most of history logic 2025-06-24 20:47:45 +02:00
c11b87e2a5 lib/components: add kanji_box (to be used in history/library) 2025-06-20 23:41:17 +02:00
83a512adfe search: add quick button for drawing kanji 2025-06-20 23:41:06 +02:00
adaf7a4644 Update jadb, use extension on Database 2025-05-27 21:02:22 +02:00
65304f1cc3 treewide: remove leftover crust from overhaul 2025-05-22 22:28:51 +02:00
103f01c99f treewide: use jadb kanji filtering instead of regex 2025-05-22 22:01:03 +02:00
7bc17281a7 word_search/sense: render POS description + notes 2025-05-20 00:32:11 +02:00
a5b60a0f4e treewide: remove more unused stuff 2025-05-19 23:54:44 +02:00
dca2e37aef treewide: overhaul, upgrade to flutter 3, jisho api -> jadb 2025-05-19 23:15:03 +02:00
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
2ca9988018 Merge history entries (#41) 2022-01-25 20:44:00 +01:00
241ff1cab6 Move service logic out of main 2022-01-25 20:15:35 +01:00
76f8cc6c86 Add licenses and update docs (#39)
* Add info sections to application

* Update README

* Make screenshots bigger

* A little less big

* Fix heading sizes
2022-01-25 00:54:21 +01:00
f6134c07a1 Add fonts (#35) 2022-01-23 23:56:26 +01:00
a577af2667 Connect multiple kanji parts with search (#33) 2022-01-23 21:29:54 +01:00
3d30a81205 Add search buttons and explanations (#32)
* Add search button

* Add search tip to kanji search
2022-01-23 21:00:45 +01:00
28f900c02e Add more content to search results (#31)
* Add lots of new functionality to search results

* Fix jlpt level

* Make antonyms clickable

* Add kanji list

* Replace Blocof with BlocBuilder

* Make kanji widgets squared

* Add missing colons to headers

* add romaji under sentences

* Fix extensive search not showing

* Miscellaneous refactoring
2022-01-23 18:27:00 +01:00
25a58d6f59 Convert most bloc usage to listeners and builders 2022-01-23 04:52:28 +01:00
7e8442881a Small refactoring 2022-01-23 03:18:05 +01:00
b4a6b52e89 Merge pull request #23 from h7x4ABk3g/add-automatically-determine-theme-feature
Add automatically determine theme feature
2022-01-19 16:06:46 +01:00
71fccb237f Add automatically determine theme feature 2022-01-19 16:06:03 +01:00
fd384a2ac9 Merge pull request #19 from h7x4ABk3g/add-romaji-feature
Connect romaji transliteration to new setting
2022-01-19 13:48:54 +01:00
988d5c043c Connect romaji transliteration to new setting 2022-01-19 13:47:54 +01:00
17d6f862a2 Refactoring and cleaning 2022-01-19 02:10:05 +01:00
859b7753af Add romaji transliteration service 2022-01-19 02:02:59 +01:00
1c766d9ad1 Make theme colors constant 2022-01-17 14:50:01 +01:00
f0c6aaa69a Move radical data to data dir 2022-01-17 14:44:02 +01:00
e66e33b9ed Add grade based search 2022-01-17 14:43:10 +01:00
32740dd7dd Add radical kanji search feature 2022-01-16 13:30:00 +01:00
37ee031693 Add kanji handdrawing feature 2022-01-14 16:10:35 +01:00
24601a300d Update dependencies 2022-01-14 09:01:52 +01:00
4bf863c16b Merge pull request #8 from h7x4ABk3g/adapt-navigator
Adapt navigator
2021-12-06 20:31:42 +01:00
067ae564ce Upgrade dependencies 2021-12-06 20:26:52 +01:00
4e60f528cb Update history loading screen 2021-12-04 05:31:27 +01:00
37f2358411 Update gradle 2021-12-04 05:23:20 +01:00
cfe5a65380 Fix some more code style 2021-12-04 05:22:58 +01:00
fe5c5a4cce Replace objectbox with sembast 2021-12-04 05:13:13 +01:00
a0c608ccca Add storage entities 2021-12-01 23:10:07 +01:00
8811cef864 Update code style 2021-12-01 23:09:53 +01:00
9d8c7b8ebb Move all navigation from bloc to Navigator 2021-09-07 00:05:33 +02:00
feee76c2b6 Add theming functionality 2021-08-08 23:16:54 +02:00
0a7b71037b Add icon and splashscreen 2021-08-04 22:48:44 +02:00
d3f76f0b22 Fix small bugs, formatting and file structure 2021-08-03 22:13:50 +02:00
ff6f6ef868 Add temporary settings screen 2021-08-03 22:04:29 +02:00
e8f42860af Add lots of history functionality 2021-08-03 22:02:42 +02:00
d82fcbe427 Update to null safety 2021-07-26 21:41:38 +02:00
b86e0ae2f2 Separate history entries 2021-07-19 01:49:18 +02:00
99912333ac Animate kanji search UI 2021-07-19 01:47:12 +02:00
25e270ec1d Add database for search history 2021-07-17 16:11:17 +02:00
1aebc38954 Organize files better 2021-07-17 12:19:03 +02:00
b8f69bfaaf Add level badges to search results 2021-04-11 01:48:43 +02:00
38e099798a Update dependencies 2021-04-11 01:48:20 +02:00
be071affae Merge pull request #7 from h7x4ABk3g/circleci-project-setup
Add CircleCI
2021-03-06 01:59:39 +01:00
1f0b717e7e Add circleci badge 2021-03-06 01:56:11 +01:00
3fbc9f0693 Add folder generation steps 2021-03-06 01:02:39 +01:00
33b7ad0058 Store analysis data as an artifact 2021-03-06 00:57:31 +01:00
72ca8bce59 Fix test result directory structure 2021-03-06 00:48:57 +01:00
23056c8a95 Add command to ignore exit code 1 on tests 2021-03-06 00:42:50 +01:00
39dc0fdc72 Add needed flag to run unittests 2021-03-06 00:33:45 +01:00
8e040d6778 Run tojunit from homefolder 2021-03-06 00:24:23 +01:00
44ecad4f28 Add no-fatal-infos to analyze step 2021-03-06 00:22:26 +01:00
df4d02dab2 Add step to install test report converter 2021-03-06 00:16:59 +01:00
acd2246c38 Add pubspec.lock 2021-03-06 00:06:02 +01:00
3e3871fe7e Save dependencies to cache 2021-03-06 00:01:51 +01:00
8524c2ee56 turn requirements into lists 2021-03-05 23:41:43 +01:00
8432306edb Move 'requires' keyword to workflows 2021-03-05 23:40:05 +01:00
6eab955075 Add build job 2021-03-05 23:32:02 +01:00
3820517afd Add workflow definition 2021-03-05 23:20:50 +01:00
539b64b8ba Try new config 2021-03-05 23:19:29 +01:00
8e11db856d Merge pull request #6 from h7x4ABk3g/refactor-1
Refactor, update bits and pieces, and clean up the code
2021-03-05 22:44:35 +01:00
a179efc710 Fix search bug where header would be null 2021-03-05 22:40:20 +01:00
4dfb42f4b6 Move theme files to models 2021-03-05 22:39:43 +01:00
f89724906b Correct a formatting error 2021-03-05 22:39:28 +01:00
f76f0011ad Split search bar into component 2021-03-05 22:12:04 +01:00
4f6793c959 Split kanji search bar into component 2021-03-05 22:08:34 +01:00
2476d2958d Make LanguageSelector choice persistent 2021-03-05 00:38:35 +01:00
ef41b50f0d Add shared_preferences 2021-03-05 00:38:19 +01:00
0e54e73bb5 Add .circleci/config.yml 2021-03-03 21:15:03 +01:00
16d636b459 Update README 2021-03-03 12:47:59 +01:00
f1ab914ce3 Fix kanji icon 2021-03-03 12:47:35 +01:00
ac8572da9b Clean up variable naming 2021-03-03 00:24:25 +01:00
16ca1d2a69 Fix language selector design 2021-03-02 23:35:47 +01:00
68357e7328 Move search result page into folder 2021-03-02 23:09:56 +01:00
d280f62c9f move files around 2021-03-02 22:26:59 +01:00
1a3acf80f1 Update bloc 2021-03-02 22:26:33 +01:00
5eaf220683 Merge pull request #5 from h7x4ABk3g/development
Make project base
2020-08-24 23:51:22 +02:00
c583ef00d9 Update readme (#4)
* Make readme template

* Add search and kanji section
2020-08-24 23:50:23 +02:00
afe9243607 Add willpopscope to search page 2020-08-24 23:46:04 +02:00
c7f6f8c4b2 Update search card layout 2020-08-24 23:45:47 +02:00
7c4d03e87b Add parts of kanji_search_page to subfolder 2020-08-23 00:39:03 +02:00
c4e5fdd9ff Modularize search_card parts 2020-08-23 00:38:42 +02:00
5681b9708c Update search to use expansiontiles 2020-08-23 00:06:09 +02:00
e50a712893 Implement search bloc to search bar 2020-08-19 18:25:45 +02:00
7fd21d974b Merge branch 'development' of github.com:h7x4ABk3g/jisho_study_tool into development 2020-08-19 16:28:08 +02:00
b5f983d377 Add text to search card 2020-08-19 16:27:00 +02:00
42a6f5e412 Add search bloc 2020-08-19 16:26:25 +02:00
738676c414 Update bloc 2020-08-18 10:52:18 +02:00
725586399e Merge branch 'development' of github.com:h7x4ABk3g/jisho_study_tool into development 2020-08-18 09:16:15 +02:00
879bbf0581 Update bloc 2020-08-17 21:54:34 +02:00
3d0cef86ca Misc 2020-08-17 11:15:32 +02:00
b00ad31141 Remove pubspec.lock 2020-07-25 14:55:49 +02:00
50812c93ab Add paste button 2020-07-22 16:24:00 +02:00
ccd38eac2a Separate text field logic 2020-07-22 15:22:21 +02:00
689983b848 Placed keyboard logic inside bloc listener 2020-07-22 14:13:53 +02:00
195 changed files with 7984 additions and 2423 deletions

1
.envrc Normal file
View File

@@ -0,0 +1 @@
use flake

39
.gitignore vendored
View File

@@ -1,27 +1,6 @@
# Miscellaneous
*.class
*.log
*.pyc
*.swp
.DS_Store
.atom/
.buildlog/
.history
.svn/
# IntelliJ related
*.iml
*.ipr
*.iws
.idea/
# The .vscode folder contains launch configuration and tasks you configure in
# VS Code which you may wish to be included in version control, so this line
# is commented out by default.
#.vscode/
# Flutter/Dart/Pub related
**/doc/api/
**/ios/Flutter/.last_build_id
.dart_tool/
.flutter-plugins
.flutter-plugins-dependencies
@@ -30,8 +9,16 @@
.pub/
/build/
# Web related
lib/generated_plugin_registrant.dart
# Android Studio will place build artifacts here
/android/app/debug
/android/app/profile
/android/app/release
# Exceptions to above rules.
!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages
# -----------------------------
# Nix build results
result
result-*
# Database files
*.sqlite

View File

@@ -1,10 +0,0 @@
# This file tracks properties of this Flutter project.
# Used by Flutter tool to assess capabilities and perform upgrades etc.
#
# This file should be version controlled and should not be manually edited.
version:
revision: 0b8abb4724aa590dd0f429683339b1e045a1594d
channel: stable
project_type: app

View File

@@ -1,16 +1,25 @@
# jisho_study_tool
<h1>
<ruby>
<rp></rp><rt>むぎ</rt><rp></rp>
<rp></rp><rt>てん</rt><rp></rp>
</ruby>
/ Mugiten
</h1>
A new Flutter project.
A japanese dictionary as a study tool.
## Getting Started
## Screenshots
This project is a starting point for a Flutter application.
<p align="center">
<img src="docs/images/search.png" width="250"/>
<img src="docs/images/kanji_search.png" width="250"/>
<img src="docs/images/radical_search.png" width="250"/>
</p>
A few resources to get you started if this is your first Flutter project:
- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab)
- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook)
For help getting started with Flutter, view our
[online documentation](https://flutter.dev/docs), which offers tutorials,
samples, guidance on mobile development, and a full API reference.
<p align="center">
<img src="docs/images/search_result.png" width="250"/>
<img src="docs/images/kanji_result.png" width="250"/>
<img src="docs/images/draw_search.png" width="250"/>
</p>

28
analysis_options.yaml Normal file
View File

@@ -0,0 +1,28 @@
# This file configures the analyzer, which statically analyzes Dart code to
# check for errors, warnings, and lints.
#
# The issues identified by the analyzer are surfaced in the UI of Dart-enabled
# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
# invoked from the command line by running `flutter analyze`.
# The following line activates a set of recommended lints for Flutter apps,
# packages, and plugins designed to encourage good coding practices.
include: package:flutter_lints/flutter.yaml
linter:
# The lint rules applied to this project can be customized in the
# section below to disable rules from the `package:flutter_lints/flutter.yaml`
# included above or to enable additional rules. A list of all available lints
# and their documentation is published at https://dart.dev/lints.
#
# Instead of disabling a lint rule for the entire project in the
# section below, it can also be suppressed for a single line of code
# or a specific dart file by using the `// ignore: name_of_lint` and
# `// ignore_for_file: name_of_lint` syntax on the line or in the file
# producing the lint.
rules:
# avoid_print: false # Uncomment to disable the `avoid_print` rule
# prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
# Additional information about this file can be found at
# https://dart.dev/guides/language/analysis-options

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/to/reference-keystore
key.properties
**/*.keystore
**/*.jks

View File

@@ -1,67 +1,44 @@
def localProperties = new Properties()
def localPropertiesFile = rootProject.file('local.properties')
if (localPropertiesFile.exists()) {
localPropertiesFile.withReader('UTF-8') { reader ->
localProperties.load(reader)
}
plugins {
id "com.android.application"
id "kotlin-android"
// The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins.
id "dev.flutter.flutter-gradle-plugin"
}
def flutterRoot = localProperties.getProperty('flutter.sdk')
if (flutterRoot == null) {
throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
}
def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
if (flutterVersionCode == null) {
flutterVersionCode = '1'
}
def flutterVersionName = localProperties.getProperty('flutter.versionName')
if (flutterVersionName == null) {
flutterVersionName = '1.0'
}
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
android {
compileSdkVersion 28
namespace = "wtf.nani.mugiten"
compileSdk = flutter.compileSdkVersion
ndkVersion = flutter.ndkVersion
sourceSets {
main.java.srcDirs += 'src/main/kotlin'
compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
lintOptions {
disable 'InvalidPackage'
kotlinOptions {
jvmTarget = JavaVersion.VERSION_1_8
}
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
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
applicationId = "wtf.nani.mugiten"
// You can update the following values to match your application needs.
// For more information, see: https://flutter.dev/to/review-gradle-config.
minSdk = flutter.minSdkVersion
targetSdk = flutter.targetSdkVersion
versionCode = flutter.versionCode
versionName = flutter.versionName
}
buildTypes {
release {
// TODO: Add your own signing config for the release build.
// Signing with the debug keys for now, so `flutter run --release` works.
signingConfig signingConfigs.debug
signingConfig = signingConfigs.debug
}
}
}
flutter {
source '../..'
}
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'
source = "../.."
}

View File

@@ -1,7 +1,13 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.jisho_study_tool">
<!-- Flutter needs it to communicate with the running application
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!-- The INTERNET permission is required for development. Specifically,
the Flutter tool 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.READ_INTERNAL_STORAGE" />
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_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. -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application
android:name="io.flutter.app.FlutterApplication"
android:label="jisho_study_tool"
android:label="mugiten"
android:name="${applicationName}"
android:icon="@mipmap/ic_launcher">
<activity
android:name=".MainActivity"
android:exported="true"
android:launchMode="singleTop"
android:taskAffinity=""
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"/>
@@ -27,4 +31,23 @@
android:name="flutterEmbedding"
android:value="2" />
</application>
<!-- Required to query activities that can process text, see:
https://developer.android.com/training/package-visibility and
https://developer.android.com/reference/android/content/Intent#ACTION_PROCESS_TEXT.
In particular, this is used by the Flutter engine in io.flutter.plugin.text.ProcessTextPlugin. -->
<queries>
<intent>
<action android:name="android.intent.action.PROCESS_TEXT"/>
<data android:mimeType="text/plain"/>
</intent>
</queries>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.READ_INTERNAL_STORAGE" />
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
</manifest>

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);
}
}

View File

@@ -0,0 +1,5 @@
package wtf.nani.mugiten
import io.flutter.embedding.android.FlutterActivity
class MainActivity: FlutterActivity()

View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Modify this file to customize your launch splash screen -->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="?android:colorBackground" />
<!-- You can insert your own image assets here -->
<!-- <item>
<bitmap
android:gravity="center"
android:src="@mipmap/launch_image" />
</item> -->
</layer-list>

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 on -->
<style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
<!-- Show a splash screen on the activity. Automatically removed when
the Flutter engine draws its first frame -->
<item name="android:windowBackground">@drawable/launch_background</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

@@ -1,8 +1,18 @@
<?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 -->
the Flutter engine draws its first frame -->
<item name="android:windowBackground">@drawable/launch_background</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,6 +1,6 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.jisho_study_tool">
<!-- Flutter needs it to communicate with the running application
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!-- The INTERNET permission is required for development. Specifically,
the Flutter tool needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.
-->
<uses-permission android:name="android.permission.INTERNET"/>

View File

@@ -1,31 +1,18 @@
buildscript {
ext.kotlin_version = '1.3.50'
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.5.0'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
allprojects {
repositories {
google()
jcenter()
mavenCentral()
}
}
rootProject.buildDir = '../build'
rootProject.buildDir = "../build"
subprojects {
project.buildDir = "${rootProject.buildDir}/${project.name}"
}
subprojects {
project.evaluationDependsOn(':app')
project.evaluationDependsOn(":app")
}
task clean(type: Delete) {
tasks.register("clean", Delete) {
delete rootProject.buildDir
}

View File

@@ -1,4 +1,3 @@
org.gradle.jvmargs=-Xmx1536M
android.enableR8=true
org.gradle.jvmargs=-Xmx4G -XX:MaxMetaspaceSize=2G -XX:+HeapDumpOnOutOfMemoryError
android.useAndroidX=true
android.enableJetifier=true

View File

@@ -1,6 +1,5 @@
#Fri Jun 23 08:50:38 CEST 2017
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-all.zip

View File

@@ -1,15 +1,25 @@
include ':app'
pluginManagement {
def flutterSdkPath = {
def properties = new Properties()
file("local.properties").withInputStream { properties.load(it) }
def flutterSdkPath = properties.getProperty("flutter.sdk")
assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
return flutterSdkPath
}()
def flutterProjectRoot = rootProject.projectDir.parentFile.toPath()
includeBuild("$flutterSdkPath/packages/flutter_tools/gradle")
def plugins = new Properties()
def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins')
if (pluginsFile.exists()) {
pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) }
repositories {
google()
mavenCentral()
gradlePluginPortal()
}
}
plugins.each { name, path ->
def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile()
include ":$name"
project(":$name").projectDir = pluginDirectory
plugins {
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
id "com.android.application" version "8.1.0" apply false
id "org.jetbrains.kotlin.android" version "1.8.22" apply false
}
include ":app"

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

View File

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

BIN
assets/images/logo/mugi.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

View File

@@ -0,0 +1,49 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="83.959915mm"
height="86.423279mm"
viewBox="0 0 83.959915 86.423279"
version="1.1"
id="svg1"
xml:space="preserve"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"><defs
id="defs1"><filter
style="color-interpolation-filters:sRGB"
id="filter29"
x="-0.030891813"
y="-0.026372997"
width="1.0806977"
height="1.0800704"><feFlood
result="flood"
in="SourceGraphic"
flood-opacity="0.635294"
flood-color="rgb(0,0,0)"
id="feFlood28" /><feGaussianBlur
result="blur"
in="SourceGraphic"
stdDeviation="1.000000"
id="feGaussianBlur28" /><feOffset
result="offset"
in="blur"
dx="1.469442"
dy="2.486583"
id="feOffset28" /><feComposite
result="comp1"
operator="in"
in="flood"
in2="offset"
id="feComposite28" /><feComposite
result="comp2"
operator="over"
in="SourceGraphic"
in2="comp1"
id="feComposite29" /></filter></defs><g
id="layer1"
transform="translate(-71.699268,-4.8907089)"><path
style="display:inline;fill:#ffe680;fill-opacity:1;filter:url(#filter29)"
d="m 80.301184,97.702012 c -1.457273,-1.69689 -1.470163,-4.799934 -0.0613,-14.750524 2.0346,-14.36976 5.18519,-16.68294 23.493586,-17.24914 l 5.25734,-0.16258 -0.19015,-3.72956 c -0.10459,-2.051256 -0.21993,-3.761127 -0.25631,-3.799714 -0.0364,-0.03859 -2.91194,0.105653 -6.39011,0.320533 -20.741826,1.281422 -22.842716,1.230936 -23.292149,-0.559727 -0.62337,-2.483711 1.412843,-2.848206 21.982719,-3.935052 4.21319,-0.222611 7.67734,-0.430251 7.69813,-0.461422 0.0208,-0.03117 0.17532,-1.059928 0.34343,-2.286127 0.68266,-4.979403 4.27414,-4.306652 4.27414,0.800627 0,1.509867 0.0985,1.561057 3.00487,1.561843 3.53017,9.54e-4 12.71449,0.43988 19.45876,0.929948 2.9689,0.215734 5.79663,0.392243 6.28385,0.392243 h 0.88586 l 4.1e-4,-1.124479 c 0.002,-5.978047 3.73823,-3.517883 3.92216,2.582715 0.40785,13.528362 -2.72438,15.371842 -23.61434,13.898282 -4.20928,-0.29692 -8.12641,-0.53985 -8.70473,-0.53985 h -1.05149 l 0.16538,2.3151 c 0.79769,11.16612 10.39165,17.81656 30.07636,20.84861 6.81496,1.04972 8.54881,1.87478 7.72756,3.677224 -1.18331,2.59708 -18.91832,-0.551852 -28.24427,-5.014904 -9.0616,-4.33655 -13.85887,-11.03693 -13.87453,-19.37863 l -0.005,-2.4474 h -3.66574 c -18.236756,0 -20.562146,2.21241 -21.972106,20.90462 -0.48968,6.491834 -1.65321,9.069924 -3.25277,7.207364 z M 138.9884,65.779458 c 2.32051,-1.08049 4.99323,-6.500502 3.21018,-6.50993 -0.1819,-9.62e-4 -2.53339,-0.171799 -5.22552,-0.379639 -4.81465,-0.371702 -13.93777,-0.83476 -20.30678,-1.030702 l -3.24114,-0.09971 v 3.888641 3.88864 l 7.34219,0.20052 c 4.0382,0.11029 8.29468,0.28993 9.45885,0.39921 4.63418,0.43499 7.294,0.32661 8.76222,-0.35703 z M 75.380944,46.556657 c -1.93629,-0.601761 -1.63421,-2.185774 0.605647,-3.175849 2.18913,-0.967649 12.772843,-1.813816 28.045839,-2.242263 3.05594,-0.08573 5.82414,-0.210389 6.15156,-0.277026 l 0.59531,-0.121158 v -3.169959 -3.169959 l -3.24114,4.44e-4 c -1.78263,2.44e-4 -6.43426,0.182727 -10.336936,0.405517 -14.97356,0.854784 -18.436503,0.65495 -18.436503,-1.063907 0,-2.432958 5.024433,-3.246868 23.698869,-3.838992 4.35536,-0.138098 8.00814,-0.254345 8.11728,-0.258325 0.10914,-0.004 0.19843,-1.614581 0.19843,-3.579112 v -3.571875 l -0.85989,8.84e-4 c -0.47294,4.87e-4 -3.5388,0.180758 -6.81302,0.400604 -23.780816,1.59675 -27.548879,0.21034 -26.586179,-9.782034 0.57959,-6.0157858 3.264683,-6.0233028 4.126933,-0.01155 1.00363,6.997427 1.18108,7.030798 27.949346,5.25599 l 2.18281,-0.144727 v -3.270517 c 0,-9.6315092 3.9781,-10.4501792 4.1883,-0.861928 l 0.0911,4.154428 1.10146,0.131831 c 1.79603,0.214961 16.38858,0.693602 20.68063,0.678332 6.63735,-0.02361 7.53448,-0.681412 8.06683,-5.914803 0.6592,-6.4805388 3.77768,-6.5060208 4.1638,-0.03402 0.60286,10.104706 -1.72403,10.832533 -30.55302,9.556679 l -3.50573,-0.15515 v 3.569869 c 0,1.963428 0.0893,3.571681 0.19844,3.573895 23.61498,0.479191 31.81614,1.538388 31.81614,4.10912 0,1.709173 -3.4866,1.908749 -18.4365,1.055315 -3.90268,-0.22279 -8.55431,-0.405273 -10.33694,-0.405517 l -3.24114,-4.44e-4 v 3.169959 3.169959 l 0.59531,0.121252 c 0.32742,0.06669 2.61938,0.191877 5.09323,0.278196 5.74154,0.200336 23.05139,1.135917 25.13542,1.358545 3.63489,0.388301 5.95312,1.41232 5.95312,2.629631 0,1.670016 -2.03662,1.918068 -10.9802,1.33734 -18.72887,-1.21611 -36.40928,-1.265022 -53.313546,-0.14749 -6.68717,0.442086 -11.176253,0.530578 -12.11503,0.238822 z"
id="path2"
transform="matrix(1,0,0,0.87927938,0,0.59040935)" /></g></svg>

After

Width:  |  Height:  |  Size: 4.7 KiB

4
assets/licenses.json Normal file
View File

@@ -0,0 +1,4 @@
{
"droid-fonts": "assets/licenses/droid-fonts.txt",
"noto-fonts": "assets/licenses/noto-fonts.txt"
}

View File

@@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@@ -0,0 +1,94 @@
Copyright 2018 The Noto Project Authors (github.com/googlei18n/noto-fonts)
This Font Software is licensed under the SIL Open Font License,
Version 1.1.
This license is copied below, and is also available with a FAQ at:
http://scripts.sil.org/OFL
-----------------------------------------------------------
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
-----------------------------------------------------------
PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide
development of collaborative font projects, to support the font
creation efforts of academic and linguistic communities, and to
provide a free and open framework in which fonts may be shared and
improved in partnership with others.
The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded,
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply to
any document created using the fonts or their derivatives.
DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such. This may
include source files, build scripts and documentation.
"Reserved Font Name" refers to any names specified as such after the
copyright statement(s).
"Original Version" refers to the collection of Font Software
components as distributed by the Copyright Holder(s).
"Modified Version" refers to any derivative made by adding to,
deleting, or substituting -- in part or in whole -- any of the
components of the Original Version, by changing formats or by porting
the Font Software to a new environment.
"Author" refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.
PERMISSION & CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Font Software, to use, study, copy, merge, embed,
modify, redistribute, and sell modified and unmodified copies of the
Font Software, subject to the following conditions:
1) Neither the Font Software nor any of its individual components, in
Original or Modified Versions, may be sold by itself.
2) Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.
3) No Modified Version of the Font Software may use the Reserved Font
Name(s) unless explicit written permission is granted by the
corresponding Copyright Holder. This restriction only applies to the
primary font name as presented to the users.
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
Software shall not be used to promote, endorse or advertise any
Modified Version, except to acknowledge the contribution(s) of the
Copyright Holder(s) and the Author(s) or with their explicit written
permission.
5) The Font Software, modified or unmodified, in part or in whole,
must be distributed entirely under this license, and must not be
distributed under any other license. The requirement for fonts to
remain under this license does not apply to any document created using
the Font Software.
TERMINATION
This license becomes null and void if any of the above conditions are
not met.
DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.

3
devtools_options.yaml Normal file
View File

@@ -0,0 +1,3 @@
description: This file stores settings for Dart & Flutter DevTools.
documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states
extensions:

BIN
docs/images/draw_search.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

BIN
docs/images/history.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 212 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 145 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 125 KiB

BIN
docs/images/search.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 134 KiB

26
flake.lock generated Normal file
View File

@@ -0,0 +1,26 @@
{
"nodes": {
"nixpkgs": {
"locked": {
"lastModified": 1744463964,
"narHash": "sha256-LWqduOgLHCFxiTNYi3Uj5Lgz0SR+Xhw3kr/3Xd0GPTM=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "2631b0b7abcea6e640ce31cd78ea58910d31e650",
"type": "github"
},
"original": {
"id": "nixpkgs",
"ref": "nixos-unstable",
"type": "indirect"
}
},
"root": {
"inputs": {
"nixpkgs": "nixpkgs"
}
}
},
"root": "root",
"version": 7
}

49
flake.nix Normal file
View File

@@ -0,0 +1,49 @@
{
inputs.nixpkgs.url = "nixpkgs/nixos-unstable";
outputs = { self, nixpkgs }: let
inherit (nixpkgs) lib;
systems = [
"x86_64-linux"
"aarch64-linux"
"x86_64-darwin"
"aarch64-darwin"
];
forAllSystems = f: lib.genAttrs systems (system: let
pkgs = import nixpkgs {
inherit system;
config = {
android_sdk.accept_license = true;
allowUnfree = true;
};
};
androidSdk = (pkgs.androidenv.composeAndroidPackages {
buildToolsVersions = [ "33.0.1" "34.0.0" ];
platformVersions = [ "35" "34" ];
abiVersions = [ "armeabi-v7a" "arm64-v8a" ];
}).androidsdk;
in f system pkgs androidSdk);
in {
devShells = forAllSystems (_: pkgs: androidSdk: {
default = let
flutter' = pkgs.flutter327;
jdk' = pkgs.jdk17;
in pkgs.mkShell {
packages = [
flutter'
pkgs.sqlite-interactive
androidSdk
jdk'
];
env = {
ANDROID_SDK_ROOT = "${androidSdk}/libexec/android-sdk";
GRADLE_OPTS = "-Dorg.gradle.project.android.aapt2FromMavenOverride=${androidSdk}/libexec/android-sdk/build-tools/34.0.0/aapt2";
FLUTTER_SDK = "${flutter'}";
JAVA_HOME = "${jdk'}/lib/openjdk";
LIBSQLITE_PATH = "${pkgs.sqlite.out}/lib/libsqlite3.so";
JADB_PATH = "./assets/jadb.sqlite";
};
};
});
};
}

32
ios/.gitignore vendored
View File

@@ -1,32 +0,0 @@
*.mode1v3
*.mode2v3
*.moved-aside
*.pbxuser
*.perspectivev3
**/*sync/
.sconsign.dblite
.tags*
**/.vagrant/
**/DerivedData/
Icon?
**/Pods/
**/.symlinks/
profile
xcuserdata
**/.generated/
Flutter/App.framework
Flutter/Flutter.framework
Flutter/Flutter.podspec
Flutter/Generated.xcconfig
Flutter/app.flx
Flutter/app.zip
Flutter/flutter_assets/
Flutter/flutter_export_environment.sh
ServiceDefinitions.json
Runner/GeneratedPluginRegistrant.*
# Exceptions to above rules.
!default.mode1v3
!default.mode2v3
!default.pbxuser
!default.perspectivev3

View File

@@ -1,26 +0,0 @@
<?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>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>App</string>
<key>CFBundleIdentifier</key>
<string>io.flutter.flutter.app</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>App</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1.0</string>
<key>MinimumOSVersion</key>
<string>8.0</string>
</dict>
</plist>

View File

@@ -1 +0,0 @@
#include "Generated.xcconfig"

View File

@@ -1 +0,0 @@
#include "Generated.xcconfig"

View File

@@ -1,518 +0,0 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 46;
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 */; };
/* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */
9705A1C41CF9048500538489 /* Embed Frameworks */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "";
dstSubfolderSpec = 10;
files = (
3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */,
9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */,
);
name = "Embed Frameworks";
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
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>"; };
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
97C146EB1CF9000F007C117D /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */,
3B80C3941E831B6300D905FE /* App.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
9740EEB11CF90186004384FC /* Flutter */ = {
isa = PBXGroup;
children = (
3B80C3931E831B6300D905FE /* App.framework */,
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
9740EEBA1CF902C7004384FC /* Flutter.framework */,
9740EEB21CF90195004384FC /* Debug.xcconfig */,
7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
9740EEB31CF90195004384FC /* Generated.xcconfig */,
);
name = Flutter;
sourceTree = "<group>";
};
97C146E51CF9000F007C117D = {
isa = PBXGroup;
children = (
9740EEB11CF90186004384FC /* Flutter */,
97C146F01CF9000F007C117D /* Runner */,
97C146EF1CF9000F007C117D /* Products */,
);
sourceTree = "<group>";
};
97C146EF1CF9000F007C117D /* Products */ = {
isa = PBXGroup;
children = (
97C146EE1CF9000F007C117D /* Runner.app */,
);
name = Products;
sourceTree = "<group>";
};
97C146F01CF9000F007C117D /* Runner */ = {
isa = PBXGroup;
children = (
97C146FA1CF9000F007C117D /* Main.storyboard */,
97C146FD1CF9000F007C117D /* Assets.xcassets */,
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
97C147021CF9000F007C117D /* Info.plist */,
97C146F11CF9000F007C117D /* Supporting Files */,
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */,
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
74858FAE1ED2DC5600515810 /* AppDelegate.swift */,
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */,
);
path = Runner;
sourceTree = "<group>";
};
97C146F11CF9000F007C117D /* Supporting Files */ = {
isa = PBXGroup;
children = (
);
name = "Supporting Files";
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
97C146ED1CF9000F007C117D /* Runner */ = {
isa = PBXNativeTarget;
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
buildPhases = (
9740EEB61CF901F6004384FC /* Run Script */,
97C146EA1CF9000F007C117D /* Sources */,
97C146EB1CF9000F007C117D /* Frameworks */,
97C146EC1CF9000F007C117D /* Resources */,
9705A1C41CF9048500538489 /* Embed Frameworks */,
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
);
buildRules = (
);
dependencies = (
);
name = Runner;
productName = Runner;
productReference = 97C146EE1CF9000F007C117D /* Runner.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
97C146E61CF9000F007C117D /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 1020;
ORGANIZATIONNAME = "The Chromium Authors";
TargetAttributes = {
97C146ED1CF9000F007C117D = {
CreatedOnToolsVersion = 7.3.1;
LastSwiftMigration = 1100;
};
};
};
buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = 97C146E51CF9000F007C117D;
productRefGroup = 97C146EF1CF9000F007C117D /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
97C146ED1CF9000F007C117D /* Runner */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
97C146EC1CF9000F007C117D /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "Thin Binary";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin";
};
9740EEB61CF901F6004384FC /* Run Script */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "Run Script";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
97C146EA1CF9000F007C117D /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */,
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXVariantGroup section */
97C146FA1CF9000F007C117D /* Main.storyboard */ = {
isa = PBXVariantGroup;
children = (
97C146FB1CF9000F007C117D /* Base */,
);
name = Main.storyboard;
sourceTree = "<group>";
};
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = {
isa = PBXVariantGroup;
children = (
97C147001CF9000F007C117D /* Base */,
);
name = LaunchScreen.storyboard;
sourceTree = "<group>";
};
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
249021D3217E4FDB00AE95B9 /* Profile */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
};
name = Profile;
};
249021D4217E4FDB00AE95B9 /* Profile */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
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 = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
PRODUCT_BUNDLE_IDENTIFIER = com.example.jishoStudyTool;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;
VERSIONING_SYSTEM = "apple-generic";
};
name = Profile;
};
97C147031CF9000F007C117D /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
97C147041CF9000F007C117D /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos;
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
};
name = Release;
};
97C147061CF9000F007C117D /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
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 = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
PRODUCT_BUNDLE_IDENTIFIER = com.example.jishoStudyTool;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
VERSIONING_SYSTEM = "apple-generic";
};
name = Debug;
};
97C147071CF9000F007C117D /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
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 = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
PRODUCT_BUNDLE_IDENTIFIER = com.example.jishoStudyTool;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;
VERSIONING_SYSTEM = "apple-generic";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = {
isa = XCConfigurationList;
buildConfigurations = (
97C147031CF9000F007C117D /* Debug */,
97C147041CF9000F007C117D /* Release */,
249021D3217E4FDB00AE95B9 /* Profile */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = {
isa = XCConfigurationList;
buildConfigurations = (
97C147061CF9000F007C117D /* Debug */,
97C147071CF9000F007C117D /* Release */,
249021D4217E4FDB00AE95B9 /* Profile */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 97C146E61CF9000F007C117D /* Project object */;
}

View File

@@ -1,7 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "group:Runner.xcodeproj">
</FileRef>
</Workspace>

View File

@@ -1,91 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1020"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Profile"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@@ -1,7 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "group:Runner.xcodeproj">
</FileRef>
</Workspace>

View File

@@ -1,13 +0,0 @@
import UIKit
import Flutter
@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
}

View File

@@ -1,122 +0,0 @@
{
"images" : [
{
"size" : "20x20",
"idiom" : "iphone",
"filename" : "Icon-App-20x20@2x.png",
"scale" : "2x"
},
{
"size" : "20x20",
"idiom" : "iphone",
"filename" : "Icon-App-20x20@3x.png",
"scale" : "3x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-App-29x29@1x.png",
"scale" : "1x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-App-29x29@2x.png",
"scale" : "2x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-App-29x29@3x.png",
"scale" : "3x"
},
{
"size" : "40x40",
"idiom" : "iphone",
"filename" : "Icon-App-40x40@2x.png",
"scale" : "2x"
},
{
"size" : "40x40",
"idiom" : "iphone",
"filename" : "Icon-App-40x40@3x.png",
"scale" : "3x"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "Icon-App-60x60@2x.png",
"scale" : "2x"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "Icon-App-60x60@3x.png",
"scale" : "3x"
},
{
"size" : "20x20",
"idiom" : "ipad",
"filename" : "Icon-App-20x20@1x.png",
"scale" : "1x"
},
{
"size" : "20x20",
"idiom" : "ipad",
"filename" : "Icon-App-20x20@2x.png",
"scale" : "2x"
},
{
"size" : "29x29",
"idiom" : "ipad",
"filename" : "Icon-App-29x29@1x.png",
"scale" : "1x"
},
{
"size" : "29x29",
"idiom" : "ipad",
"filename" : "Icon-App-29x29@2x.png",
"scale" : "2x"
},
{
"size" : "40x40",
"idiom" : "ipad",
"filename" : "Icon-App-40x40@1x.png",
"scale" : "1x"
},
{
"size" : "40x40",
"idiom" : "ipad",
"filename" : "Icon-App-40x40@2x.png",
"scale" : "2x"
},
{
"size" : "76x76",
"idiom" : "ipad",
"filename" : "Icon-App-76x76@1x.png",
"scale" : "1x"
},
{
"size" : "76x76",
"idiom" : "ipad",
"filename" : "Icon-App-76x76@2x.png",
"scale" : "2x"
},
{
"size" : "83.5x83.5",
"idiom" : "ipad",
"filename" : "Icon-App-83.5x83.5@2x.png",
"scale" : "2x"
},
{
"size" : "1024x1024",
"idiom" : "ios-marketing",
"filename" : "Icon-App-1024x1024@1x.png",
"scale" : "1x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 564 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

View File

@@ -1,23 +0,0 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "LaunchImage.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "LaunchImage@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "LaunchImage@3x.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 B

View File

@@ -1,5 +0,0 @@
# Launch Screen Assets
You can customize the launch screen with your own desired assets by replacing the image files in this directory.
You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images.

View File

@@ -1,37 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="12121" systemVersion="16G29" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12089"/>
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="EHf-IW-A2E">
<objects>
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="Ydg-fD-yQy"/>
<viewControllerLayoutGuide type="bottom" id="xbc-2k-c8Z"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<imageView opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" image="LaunchImage" translatesAutoresizingMaskIntoConstraints="NO" id="YRO-k0-Ey4">
</imageView>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="YRO-k0-Ey4" firstAttribute="centerX" secondItem="Ze5-6b-2t3" secondAttribute="centerX" id="1a2-6s-vTC"/>
<constraint firstItem="YRO-k0-Ey4" firstAttribute="centerY" secondItem="Ze5-6b-2t3" secondAttribute="centerY" id="4X2-HB-R7a"/>
</constraints>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="53" y="375"/>
</scene>
</scenes>
<resources>
<image name="LaunchImage" width="168" height="185"/>
</resources>
</document>

View File

@@ -1,26 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="10117" systemVersion="15F34" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="BYZ-38-t0r">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10085"/>
</dependencies>
<scenes>
<!--Flutter View Controller-->
<scene sceneID="tne-QT-ifu">
<objects>
<viewController id="BYZ-38-t0r" customClass="FlutterViewController" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/>
<viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
</objects>
</scene>
</scenes>
</document>

View File

@@ -1,45 +0,0 @@
<?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>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>jisho_study_tool</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>$(FLUTTER_BUILD_NAME)</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>$(FLUTTER_BUILD_NUMBER)</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>
<string>Main</string>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
</dict>
</plist>

View File

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

View File

@@ -1,18 +0,0 @@
import 'dart:async';
import 'package:bloc/bloc.dart';
import 'package:meta/meta.dart';
part 'history_event.dart';
part 'history_state.dart';
class HistoryBloc extends Bloc<HistoryEvent, HistoryState> {
HistoryBloc() : super(HistoryInitial());
@override
Stream<HistoryState> mapEventToState(
HistoryEvent event,
) async* {
// TODO: implement mapEventToState
}
}

View File

@@ -1,4 +0,0 @@
part of 'history_bloc.dart';
@immutable
abstract class HistoryEvent {}

View File

@@ -1,6 +0,0 @@
part of 'history_bloc.dart';
@immutable
abstract class HistoryState {}
class HistoryInitial extends HistoryState {}

View File

@@ -1,41 +0,0 @@
import 'dart:async';
import './kanji_event.dart';
import './kanji_state.dart';
import 'package:bloc/bloc.dart';
import 'package:jisho_study_tool/services/kanji_search.dart';
import 'package:jisho_study_tool/services/kanji_suggestions.dart';
export './kanji_event.dart';
export './kanji_state.dart';
class KanjiBloc extends Bloc<KanjiEvent, KanjiState> {
KanjiBloc() : super(KanjiSearchInitial());
@override
Stream<KanjiState> mapEventToState(
KanjiEvent event,
) async* {
if (event is GetKanji) {
yield KanjiSearchLoading();
try {
final _kanji = await fetchKanji(event.kanjiSearchString);
if (_kanji.found) yield KanjiSearchFinished(kanji: _kanji);
else yield KanjiSearchError('Something went wrong');
} on Exception {
yield KanjiSearchError('Something went wrong');
}
} else if (event is GetKanjiSuggestions) {
final suggestions = kanjiSuggestions(event.searchString);
yield KanjiSearchInput(suggestions);
} else if (event is ReturnToInitialState) {
yield KanjiSearchInitial();
}
}
}

View File

@@ -1,17 +0,0 @@
abstract class KanjiEvent {
const KanjiEvent();
}
class GetKanjiSuggestions extends KanjiEvent {
final String searchString;
const GetKanjiSuggestions(this.searchString);
}
class GetKanji extends KanjiEvent {
final String kanjiSearchString;
const GetKanji(this.kanjiSearchString);
}
class ReturnToInitialState extends KanjiEvent {
const ReturnToInitialState();
}

View File

@@ -1,34 +0,0 @@
import 'package:unofficial_jisho_api/api.dart';
abstract class KanjiState {
const KanjiState();
}
class KanjiSearchInitial extends KanjiState {
const KanjiSearchInitial();
}
class KanjiSearchInput extends KanjiState {
final List<String> kanjiSuggestions;
const KanjiSearchInput(this.kanjiSuggestions);
}
class KanjiSearchLoading extends KanjiState {
const KanjiSearchLoading();
}
class KanjiSearchFinished extends KanjiState {
final KanjiResult kanji;
final bool starred;
const KanjiSearchFinished({
this.kanji,
this.starred = false,
});
}
class KanjiSearchError extends KanjiState {
final String message;
const KanjiSearchError(this.message);
}

View File

@@ -1,18 +0,0 @@
import 'dart:async';
import 'package:bloc/bloc.dart';
import 'package:meta/meta.dart';
part 'search_event.dart';
part 'search_state.dart';
class SearchBloc extends Bloc<SearchEvent, SearchState> {
SearchBloc() : super(SearchInitial());
@override
Stream<SearchState> mapEventToState(
SearchEvent event,
) async* {
// TODO: implement mapEventToState
}
}

View File

@@ -1,4 +0,0 @@
part of 'search_bloc.dart';
@immutable
abstract class SearchEvent {}

View File

@@ -1,14 +0,0 @@
part of 'search_bloc.dart';
@immutable
abstract class SearchState {}
class SearchInitial extends SearchState {}
class SearchLoading extends SearchState {}
class SearchFinished extends SearchState {}
class SearchError extends SearchState {}
class ReSearch extends SearchState {}

View File

@@ -0,0 +1,31 @@
import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import '../../models/themes/theme.dart';
import '../../settings.dart';
export 'package:flutter_bloc/flutter_bloc.dart';
export 'package:mugiten/models/themes/theme.dart';
part 'theme_event.dart';
part 'theme_state.dart';
class ThemeBloc extends Bloc<ThemeEvent, ThemeState> {
ThemeBloc() : super(const LightThemeState()) {
on<SetTheme>(
(event, emit) => emit(
event.themeIsDark ? const DarkThemeState() : const LightThemeState(),
),
);
final bool autoThemeIsDark =
SchedulerBinding.instance.window.platformBrightness == Brightness.dark;
add(
SetTheme(
themeIsDark: autoThemeEnabled ? autoThemeIsDark : darkThemeEnabled,
),
);
}
}

View File

@@ -0,0 +1,12 @@
part of 'theme_bloc.dart';
@immutable
abstract class ThemeEvent {
const ThemeEvent();
}
class SetTheme extends ThemeEvent {
final bool themeIsDark;
const SetTheme({required this.themeIsDark});
}

View File

@@ -0,0 +1,22 @@
part of 'theme_bloc.dart';
@immutable
abstract class ThemeState {
const ThemeState();
AppTheme get theme;
}
class LightThemeState extends ThemeState {
const LightThemeState();
@override
AppTheme get theme => const LightTheme();
}
class DarkThemeState extends ThemeState {
const DarkThemeState();
@override
AppTheme get theme => const DarkTheme();
}

View File

@@ -0,0 +1,27 @@
import 'package:flutter/material.dart';
class DenshiJishoBackground extends StatelessWidget {
final Widget child;
const DenshiJishoBackground({
super.key,
required this.child,
});
@override
Widget build(BuildContext context) {
return Stack(
children: [
Positioned(
right: 30,
left: 100,
bottom: 30,
child: Image.asset(
'assets/images/components/denshi_jisho_background_overlay.png',
),
),
child,
],
);
}
}

View File

@@ -0,0 +1,180 @@
import 'dart:math';
import 'package:flutter/material.dart';
import '../../bloc/theme/theme_bloc.dart';
import '../../settings.dart';
/// The ratio is defined as 'the amount of space the text should take'
/// divided by 'the amount of space the padding should take'.
///
/// So if the KanjiBox should span 50 pixels, and you wanted 10 of those pixels
/// to be used for padding (5 on each side), and 40 to be used for the text,
/// you could write:
///
/// ```dart
/// KanjiBox.withRatioAndFontSize({
/// kanji: '例',
/// ratio: 4 / 1,
/// fontSize: 40,
/// })
/// ```
///
class KanjiBox extends StatelessWidget {
final String kanji;
final double? fontSize;
final double? padding;
final Color? foreground;
final Color? background;
final double? contentPaddingRatio;
final double borderRadius;
static const double defaultRatio = 3 / 1;
static const double defaultBorderRadius = 10;
double get ratio => contentPaddingRatio ?? fontSize! / padding!;
double get fontSizeFactor => ratio / (ratio + 1);
double get paddingSizeFactor => 1 / (ratio + 1);
bool get isExpanded => contentPaddingRatio != null;
double? get size => isExpanded ? null : fontSize! + (2 * padding!);
double? get oneSidePadding => padding != null ? padding! / 2 : null;
const KanjiBox._({
super.key,
required this.kanji,
this.fontSize,
this.padding,
this.contentPaddingRatio,
this.foreground,
this.background,
this.borderRadius = defaultBorderRadius,
}) : assert(
kanji.length == 1,
'KanjiBox can not show more than one character at a time',
),
assert(
contentPaddingRatio != null || (fontSize != null && padding != null),
'Either contentPaddingRatio or both the fontSize and padding need to be '
'explicitly defined in order for the box to be able to render correctly',
);
const factory KanjiBox.withFontSizeAndPadding({
required String kanji,
required double fontSize,
required double padding,
Color? foreground,
Color? background,
double borderRadius,
}) = KanjiBox._;
factory KanjiBox.withFontSize({
required String kanji,
required double fontSize,
double ratio = defaultRatio,
Color? foreground,
Color? background,
double borderRadius = defaultBorderRadius,
}) =>
KanjiBox._(
kanji: kanji,
fontSize: fontSize,
padding: pow(ratio * (1 / fontSize), -1).toDouble(),
foreground: foreground,
background: background,
borderRadius: borderRadius,
);
factory KanjiBox.withPadding({
required String kanji,
double ratio = defaultRatio,
required double padding,
Color? foreground,
Color? background,
double borderRadius = defaultBorderRadius,
}) =>
KanjiBox._(
kanji: kanji,
fontSize: ratio * padding,
padding: padding,
foreground: foreground,
background: background,
borderRadius: borderRadius,
);
factory KanjiBox.expanded({
required String kanji,
double ratio = defaultRatio,
Color? foreground,
Color? background,
double borderRadius = defaultBorderRadius,
}) =>
KanjiBox._(
kanji: kanji,
contentPaddingRatio: ratio,
foreground: foreground,
background: background,
borderRadius: borderRadius,
);
/// A shortcut
factory KanjiBox.headline4({
required BuildContext context,
required String kanji,
double ratio = defaultRatio,
Color? foreground,
Color? background,
double borderRadius = defaultBorderRadius,
}) =>
KanjiBox.withFontSize(
kanji: kanji,
fontSize: Theme.of(context).textTheme.displaySmall!.fontSize!,
ratio: ratio,
foreground: foreground,
background: background,
borderRadius: borderRadius,
);
@override
Widget build(BuildContext context) {
return BlocBuilder<ThemeBloc, ThemeState>(
builder: (context, state) {
final calculatedForeground =
foreground ?? state.theme.menuGreyLight.foreground;
final calculatedBackground =
background ?? state.theme.menuGreyLight.background;
return LayoutBuilder(
builder: (context, constraints) {
final sizeConstraint =
min(constraints.maxHeight, constraints.maxWidth);
final calculatedFontSize =
fontSize ?? sizeConstraint * fontSizeFactor;
final calculatedPadding =
oneSidePadding ?? (sizeConstraint * paddingSizeFactor) / 2;
return Container(
padding: EdgeInsets.all(calculatedPadding),
alignment: Alignment.center,
width: size,
height: size,
decoration: BoxDecoration(
color: calculatedBackground,
borderRadius: BorderRadius.circular(borderRadius),
),
child: FittedBox(
child: Text(
kanji,
textScaler: TextScaler.linear(1),
style: TextStyle(
color: calculatedForeground,
fontSize: calculatedFontSize,
).merge(japaneseFont.textStyle),
),
),
);
},
);
},
);
}
}

View File

@@ -1,12 +1,12 @@
import 'package:flutter/material.dart';
class LoadingScreen extends StatelessWidget {
const LoadingScreen({super.key});
@override
Widget build(BuildContext context) {
return Container(
child: Center(
child: CircularProgressIndicator(),
),
return const Center(
child: CircularProgressIndicator(),
);
}
}

View File

@@ -0,0 +1,19 @@
import 'package:flutter/material.dart';
class OpaqueBox extends StatelessWidget {
final Widget child;
const OpaqueBox({
required this.child,
super.key,
});
@override
Widget build(BuildContext context) {
return Container(
decoration:
BoxDecoration(color: Theme.of(context).scaffoldBackgroundColor),
child: child,
);
}
}

View File

@@ -0,0 +1,19 @@
import 'package:flutter/material.dart';
import '../../models/themes/theme.dart';
class SplashScreen extends StatelessWidget {
const SplashScreen({super.key});
@override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(color: AppTheme.mugitenWheat.background),
child: const Center(
child: Image(
image: AssetImage('assets/images/logo/mugi.png'),
),
),
);
}
}

View File

@@ -0,0 +1,272 @@
import 'package:flutter/material.dart' hide Ink;
import 'package:get_it/get_it.dart';
import 'package:google_mlkit_digital_ink_recognition/google_mlkit_digital_ink_recognition.dart';
import 'package:jadb/search.dart';
import 'package:signature/signature.dart';
import 'package:sqflite/sqflite.dart';
import '../../bloc/theme/theme_bloc.dart';
import '../../settings.dart';
class DrawingBoard extends StatefulWidget {
final Function(String)? onSuggestionChosen;
final bool onlyOneCharacterSuggestions;
final bool allowKanji;
final bool allowHiragana;
final bool allowKatakana;
final bool allowOther;
const DrawingBoard({
this.onSuggestionChosen,
this.onlyOneCharacterSuggestions = false,
this.allowKanji = true,
this.allowHiragana = false,
this.allowKatakana = false,
this.allowOther = false,
super.key,
});
@override
State<DrawingBoard> createState() => _DrawingBoardState();
}
class _DrawingBoardState extends State<DrawingBoard> {
List<String> suggestions = [];
final List<List<StrokePoint>> strokes = [];
final List<List<StrokePoint>> undoQueue = [];
GlobalKey signatureW = GlobalKey();
GlobalKey suggestionBarW = GlobalKey();
static const double fontSize = 30;
static const double suggestionCirclePadding = 13;
late ColorSet panelColor =
BlocProvider.of<ThemeBloc>(context).state.theme.menuGreyLight;
late ColorSet barColor =
BlocProvider.of<ThemeBloc>(context).state.theme.menuGreyNormal;
late final SignatureController controller = SignatureController(
penColor: panelColor.foreground,
onDrawStart: () {
strokes.add([]);
undoQueue.clear();
},
onDrawMove: () => strokes.last.add(StrokePoint(
t: DateTime.now().millisecondsSinceEpoch,
x: controller.points.last.offset.dx,
y: controller.points.last.offset.dy,
)),
onDrawEnd: () => updateSuggestions(),
);
Future<void> updateSuggestions() async {
if (strokes.isEmpty) return setState(() => suggestions.clear());
final digitalInkRecognizer = DigitalInkRecognizer(languageCode: 'ja');
final context = DigitalInkRecognitionContext(
writingArea: WritingArea(
height: signatureW.currentContext!.size!.height,
width: signatureW.currentContext!.size!.width,
),
);
final ink = Ink()
..strokes = strokes.map((s) => Stroke()..points = s).toList();
final newSuggestions = await digitalInkRecognizer.recognize(
ink,
context: context,
);
setState(() {
suggestions = newSuggestions.map((rc) => rc.text).toList();
});
}
Future<List<String>> filterSuggestions() async {
const hiraganaR = r'\p{Script=Hiragana}';
const katakanaR = r'\p{Script=Katakana}';
final kanjiSuggestions = await GetIt.instance.get<Database>().filterKanji(
suggestions,
deduplicate: true,
);
final hiraganaSuggestions = suggestions
.where((s) => RegExp(hiraganaR).hasMatch(s))
.toSet()
.toList();
final katakanaSuggestions = suggestions
.where((s) => RegExp(katakanaR).hasMatch(s))
.toSet()
.toList();
return {
if (widget.allowKanji) ...kanjiSuggestions,
if (widget.allowHiragana) ...hiraganaSuggestions,
if (widget.allowKatakana) ...katakanaSuggestions,
}
.where((s) => !widget.onlyOneCharacterSuggestions || s.length == 1)
.toList();
}
Widget kanjiChip(String kanji) => InkWell(
onTap: () => widget.onSuggestionChosen?.call(kanji),
child: BlocBuilder<ThemeBloc, ThemeState>(
builder: (context, state) {
final colors = state.theme.menuGreyLight;
return Container(
height: fontSize + 2 * suggestionCirclePadding,
width: fontSize + 2 * suggestionCirclePadding,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: colors.background,
),
child: Center(
child: Text(
kanji,
style: TextStyle(
fontSize: fontSize,
color: colors.foreground,
).merge(japaneseFont.textStyle),
),
),
);
},
),
);
Widget suggestionBar() {
const padding = EdgeInsets.symmetric(horizontal: 10, vertical: 5);
return FutureBuilder<List<String>>(
future: filterSuggestions(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting ||
(!snapshot.hasError && (snapshot.data?.isEmpty ?? false))) {
return Container(
key: suggestionBarW,
color: barColor.background,
alignment: Alignment.center,
padding: padding,
child: const Text('No suggestions'),
);
}
if (snapshot.hasError) {
return Center(
child: Text(
'Error: ${snapshot.error}',
style: const TextStyle(color: Colors.red),
),
);
}
final filteredSuggestions = snapshot.data!;
return Container(
key: suggestionBarW,
color: barColor.background,
alignment: Alignment.center,
padding: padding,
// TODO: calculate dynamically
constraints: BoxConstraints(
minHeight: 8 +
suggestionCirclePadding * 2 +
fontSize +
(2 * 4) +
padding.vertical,
),
child: Wrap(
spacing: 20,
runSpacing: 5,
children: filteredSuggestions.map((s) => kanjiChip(s)).toList(),
),
);
},
);
}
Widget buttonRow() => Container(
color: panelColor.background,
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
IconButton(
onPressed: () => setState(() {
controller.clear();
strokes.clear();
suggestions.clear();
}),
icon: const Icon(Icons.delete),
),
IconButton(
onPressed: () {
if (strokes.isNotEmpty) {
undoQueue.add(strokes.removeLast());
controller.undo();
updateSuggestions();
}
},
icon: const Icon(Icons.undo),
),
IconButton(
onPressed: () {
if (undoQueue.isNotEmpty) {
strokes.add(undoQueue.removeLast());
controller.redo();
updateSuggestions();
}
},
icon: const Icon(Icons.redo),
),
if (!widget.onlyOneCharacterSuggestions)
IconButton(
onPressed: () => ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('TODO: implement scrolling page feature!'),
),
),
icon: const Icon(Icons.arrow_forward),
),
],
),
);
Widget drawingPanel() => AspectRatio(
aspectRatio: 1.2,
child: Stack(
alignment: Alignment.bottomRight,
children: [
ClipRect(
child: Signature(
key: signatureW,
controller: controller,
backgroundColor: panelColor.background,
),
),
buttonRow(),
],
),
);
@override
Widget build(BuildContext context) {
return BlocListener<ThemeBloc, ThemeState>(
listener: (context, state) => setState(() {
panelColor = state.theme.menuGreyLight;
barColor = state.theme.menuGreyDark;
}),
child: Column(
children: [
suggestionBar(),
drawingPanel(),
],
),
);
}
}

View File

@@ -0,0 +1,31 @@
import 'package:flutter/material.dart';
import '../../bloc/theme/theme_bloc.dart';
class TextDivider extends StatelessWidget {
final String text;
const TextDivider({
super.key,
required this.text,
});
@override
Widget build(BuildContext context) => BlocBuilder<ThemeBloc, ThemeState>(
builder: (context, state) {
final colors = state.theme.menuGreyNormal;
return Container(
decoration: BoxDecoration(color: colors.background),
padding: const EdgeInsets.symmetric(
vertical: 5,
horizontal: 10,
),
child: DefaultTextStyle.merge(
child: Text(text),
style: TextStyle(color: colors.foreground),
),
);
},
);
}

View File

@@ -0,0 +1,109 @@
import 'package:flutter/material.dart';
import 'package:flutter_slidable/flutter_slidable.dart';
import '../../models/history/history_entry.dart';
import '../../routing/routes.dart';
import '../../services/datetime.dart';
import '../../settings.dart';
import '../common/kanji_box.dart';
import '../common/loading.dart';
class HistoryEntryTile extends StatelessWidget {
final HistoryEntry entry;
final int objectKey;
final void Function()? onDelete;
final void Function()? onFavourite;
const HistoryEntryTile({
required this.entry,
required this.objectKey,
this.onDelete,
this.onFavourite,
super.key,
});
void Function() _onTap(context) => entry.isKanji
? () => Navigator.pushNamed(
context,
Routes.kanjiSearch,
arguments: entry.kanji,
)
: () => Navigator.pushNamed(
context,
Routes.search,
arguments: entry.word,
);
MaterialPageRoute get timestamps => MaterialPageRoute(
builder: (context) => Scaffold(
appBar: AppBar(title: const Text('Last searched')),
body: FutureBuilder<List<DateTime>>(
future: entry.timestamps,
builder: (context, snapshot) {
// TODO: provide proper error handling
if (snapshot.hasError) return ErrorWidget(snapshot.error!);
if (!snapshot.hasData) return const LoadingScreen();
return ListView(
children: snapshot.data!
.map(
(ts) => ListTile(
title: Text('${formatDate(ts)} ${formatTime(ts)}'),
),
)
.toList(),
);
},
),
),
);
List<SlidableAction> _actions(context) => [
SlidableAction(
backgroundColor: Colors.blue,
icon: Icons.access_time,
onPressed: (_) => Navigator.push(context, timestamps),
),
SlidableAction(
backgroundColor: Colors.red,
icon: Icons.delete,
onPressed: (_) async {
await entry.delete();
onDelete?.call();
},
),
];
@override
Widget build(BuildContext context) {
return Slidable(
endActionPane: ActionPane(
motion: const ScrollMotion(),
children: _actions(context),
),
child: Container(
padding: const EdgeInsets.symmetric(vertical: 10),
child: ListTile(
onTap: _onTap(context),
contentPadding: EdgeInsets.zero,
title: Row(
children: [
Padding(
padding: const EdgeInsets.symmetric(horizontal: 20),
child: Text(formatTime(entry.lastTimestamp)),
),
DefaultTextStyle.merge(
style: japaneseFont.textStyle,
child: entry.isKanji
? KanjiBox.headline4(
context: context,
kanji: entry.kanji!,
)
: Expanded(child: Text(entry.word!)),
),
],
),
),
),
);
}
}

View File

@@ -1,126 +0,0 @@
import 'package:flutter/material.dart';
import 'package:unofficial_jisho_api/api.dart';
class Examples extends StatelessWidget {
final List<YomiExample> _onyomiExamples;
final List<YomiExample> _kunyomiExamples;
const Examples(
this._onyomiExamples,
this._kunyomiExamples,
);
@override
Widget build(BuildContext context) {
return ExpansionTile(
title: Center(
child: Container(
padding: EdgeInsets.symmetric(vertical: 10.0, horizontal: 10.0),
decoration: BoxDecoration(
color: Colors.blue,
borderRadius: BorderRadius.circular(10.0),
),
child: Text(
'Examples',
style: TextStyle(
color: Colors.white,
fontSize: 20.0,
),
),
),
),
children: [
_onyomiExamples
.map((onyomiExample) => _Example(onyomiExample, _KanaType.onyomi))
.toList(),
_kunyomiExamples
.map((kunyomiExample) =>
_Example(kunyomiExample, _KanaType.kunyomi))
.toList(),
].expand((list) => list).toList());
}
}
enum _KanaType { kunyomi, onyomi }
class _Example extends StatelessWidget {
final _KanaType _kanaType;
final YomiExample _yomiExample;
const _Example(this._yomiExample, this._kanaType);
@override
Widget build(BuildContext context) {
return Container(
margin: EdgeInsets.symmetric(
vertical: 10.0,
horizontal: 10.0,
),
decoration: BoxDecoration(
color: Colors.grey, borderRadius: BorderRadius.circular(10.0)),
child: IntrinsicHeight(
child: Row(
children: [
Container(
padding: EdgeInsets.symmetric(
vertical: 10.0,
horizontal: 10.0,
),
decoration: BoxDecoration(
color: (_kanaType == _KanaType.kunyomi)
? Colors.lightBlue
: Colors.orange,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(10.0),
bottomLeft: Radius.circular(10.0),
),
),
child: Column(
children: [
Container(
child: Text(
_yomiExample.reading,
style: TextStyle(
color: Colors.white,
fontSize: 15.0,
),
),
),
SizedBox(
height: 5.0,
),
Container(
child: Text(
_yomiExample.example,
style: TextStyle(
color: Colors.white,
fontSize: 20.0,
),
),
),
],
),
),
SizedBox(
width: 15.0,
),
Expanded(
child: Wrap(
children: [
Container(
child: Text(
_yomiExample.meaning,
style: TextStyle(
color: Colors.white,
),
),
)
],
),
),
],
),
),
);
}
}

View File

@@ -1,25 +0,0 @@
import 'package:flutter/material.dart';
class Grade extends StatelessWidget {
final String _grade;
@override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.all(10.0),
child: Text(
_grade,
style: TextStyle(
color: Colors.white,
fontSize: 20.0,
),
),
decoration: BoxDecoration(
color: Colors.blue,
shape: BoxShape.circle,
),
);
}
Grade(this._grade);
}

View File

@@ -1,22 +0,0 @@
import 'package:flutter/material.dart';
class Header extends StatelessWidget {
final String _kanji;
@override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10.0), color: Colors.blue),
child: Padding(
padding: const EdgeInsets.all(10.0),
child: Text(
_kanji,
style: TextStyle(fontSize: 80.0, color: Colors.white),
),
),
);
}
Header(this._kanji);
}

View File

@@ -1,26 +0,0 @@
import 'package:flutter/material.dart';
class JlptLevel extends StatelessWidget {
final String _jlptLevel;
@override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.all(10.0),
child: Text(
_jlptLevel,
style: TextStyle(
color: Colors.white,
fontSize: 20.0,
),
),
decoration: BoxDecoration(
shape: BoxShape.circle,
color: Colors.blue,
),
);
}
JlptLevel(this._jlptLevel);
}

View File

@@ -1,91 +0,0 @@
import 'package:flutter/material.dart';
import 'package:jisho_study_tool/components/kanji/kanji__search_page/examples.dart';
import 'package:unofficial_jisho_api/api.dart' as jisho;
import './grade.dart';
import './header.dart';
import './jlpt_level.dart';
import './meaning.dart';
import './radical.dart';
import './rank.dart';
import './stroke_order_gif.dart';
import './onyomi.dart';
import './kunyomi.dart';
class KanjiResultCard extends StatelessWidget {
final jisho.KanjiResult _result;
@override
Widget build(BuildContext context) {
return ListView(
children: [
Container(
margin: EdgeInsets.fromLTRB(20.0, 20.0, 20.0, 30.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Flexible(
flex: 1,
fit: FlexFit.tight,
child: Center(child: SizedBox()),
),
Flexible(
flex: 1,
fit: FlexFit.tight,
child: Center(child: Header(_result.query)),
),
Flexible(
flex: 1,
fit: FlexFit.tight,
child: Center(
child: Radical(_result.radical),
),
),
],
),
),
Meaning(_result.meaning),
_result.onyomi.length != 0 ? Onyomi(_result.onyomi) : SizedBox.shrink(),
_result.kunyomi.length != 0 ? Kunyomi(_result.kunyomi) : SizedBox.shrink(),
IntrinsicHeight(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
StrokeOrderGif(_result.strokeOrderGifUri),
Container(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Text("JLPT: ", style: TextStyle(fontSize: 20.0)),
JlptLevel(_result.jlptLevel ?? ""),
],
),
Row(
children: [
Text("Grade: ", style: TextStyle(fontSize: 20.0)),
Grade(_result.taughtIn ?? ""),
],
),
Row(
children: [
Text("Rank: ", style: TextStyle(fontSize: 20.0)),
Rank(_result.newspaperFrequencyRank ?? -1),
],
),
],
),
),
],
),
),
Examples(_result.onyomiExamples, _result.kunyomiExamples),
],
);
}
KanjiResultCard(this._result);
}

Some files were not shown because too many files have changed in this diff Show More