diff --git a/.github/workflows/android-smoke.yml b/.github/workflows/android-smoke.yml index d359543..2237956 100644 --- a/.github/workflows/android-smoke.yml +++ b/.github/workflows/android-smoke.yml @@ -34,4 +34,6 @@ jobs: api-level: 34 target: google_apis arch: x86_64 - script: pwsh -NoProfile -File platforms/android/smoke.ps1 -Serial emulator-5554 + script: | + pwsh -NoProfile -File platforms/android/smoke.ps1 -Serial emulator-5554 + pwsh -NoProfile -File platforms/android/ui-smoke.ps1 -Serial emulator-5554 diff --git a/CHANGELOG.en.md b/CHANGELOG.en.md index 2fe8ed4..1f7072d 100644 --- a/CHANGELOG.en.md +++ b/CHANGELOG.en.md @@ -9,21 +9,23 @@ Korean version: [CHANGELOG.md](CHANGELOG.md). ## [Unreleased] -### Fixed +## [0.10.9] - 2026-10-23 -- Windows release updates and removal no longer fail before the administrator prompt because the encoded installer exceeds the Windows command-line limit. The elevated script is encoded once, preserving release verification and the existing local installation path. +### Added + +- Android keyboard tools for pasting the current clipboard, moving the cursor, choosing an input mode, and controlling haptics and key previews. Clipboard history is not stored, and sensitive content is hidden from previews. ### Changed +- Refined Android keyboard light/dark surfaces and press feedback with the Tacit logo and Lucide icons. The selected reading appears first with a clear highlight; double-tapping Shift locks capitals, and Enter displays its current confirmation, search, send, or other action. - Plain confirmation now keeps unfinished readings in the language already shown, including Enter, shortcuts and session flushes. Standalone letters are classified before display, so English suffixes no longer depend on confirmation to fix a Korean preview. Japanese confirmation keeps the displayed segmentation and live candidate, completing only a pending Japanese `n` to `ん`; explicit language changes, Space conversion, Tab completion and newly typed digit context remain separate actions. -## [0.10.9] - 2026-10-23 - ### Fixed +- Windows release updates and removal no longer fail before the administrator prompt because the encoded installer exceeds the Windows command-line limit. The elevated script is encoded once, preserving release verification and the existing local installation path. +- Overlapping Shift input such as `akfgkfRK` now stays Korean (`말할까`) when supported by existing vocabulary or inflections; otherwise, case-sensitive Latin identifiers are preserved. The Korean exception no longer admits Japanese candidates. Unlisted Korean spellings with an overlapping Shift key now keep their Latin keys until explicitly corrected; normal Korean key spelling remains available. - Generalized correction preferences now apply only to the actual runner-up language. This prevents a Korean preference from turning English into Japanese or broken Hangul when Japanese is enabled, while preserving explicitly learned words. - Confirmation with Space or Enter keeps the language of a completed composition. This fixes `연습햇` becoming `연습got` and Japanese previews becoming English or Korean, while preserving explicit language cycling and Japanese candidate conversion. -- A vowel typed while Shift overlaps a preceding Korean doubled consonant is scored normally instead of being categorically classified as English. This fixes `말할까` becoming `akfgkfRK`, while preserving the original keys and English capitalization. ## [0.10.8] - 2026-10-22 diff --git a/CHANGELOG.md b/CHANGELOG.md index 9d0fdf7..a1907a7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,21 +9,23 @@ GitHub 릴리스 노트가 되고 대시보드의 업데이트 탭에도 그대 ## [Unreleased] -### 수정 +## [0.10.9] - 2026-10-23 -- Windows 릴리스 업데이트·제거 시 인코딩된 설치 명령이 Windows 명령줄 길이 제한을 넘어 관리자 권한 창도 뜨지 않던 문제를 고쳤습니다. 관리자 스크립트는 한 번만 인코딩하며, 릴리스 검증과 기존 로컬 설치 경로는 유지합니다. +### 추가 + +- Android 키보드에 현재 클립보드 붙여넣기, 커서 이동, 입력 모드 메뉴와 진동·키 미리보기 설정을 추가했습니다. 클립보드 기록은 저장하지 않으며 민감한 내용은 미리 표시하지 않습니다. ### 변경 +- Android 키보드에 Tacit 로고와 Lucide 아이콘을 적용하고 밝은·어두운 키 배경과 눌림 표시를 다듬었습니다. 선택된 읽기는 앞쪽에서 강조하며, Shift 두 번으로 대문자를 고정하고 Enter는 확정·검색·전송 등 현재 동작을 표시합니다. - Enter·단축키·세션 종료 등 단순 확정은 미완성 입력도 화면에 보인 언어로 유지합니다. 한 글자는 표시 전에 독립된 입력으로 판별해 영어 접미사의 한글 미리보기를 확정 때 고치는 동작을 없앴습니다. 일본어는 표시된 분절과 실시간 후보를 유지하고, 미완성 일본어 `n`만 `ん`으로 마무리합니다. 명시적인 언어 변경·Space 변환·Tab 자동완성과 새로 입력한 숫자 문맥은 별도 동작으로 유지합니다. -## [0.10.9] - 2026-10-23 - ### 수정 +- Windows 릴리스 업데이트·제거 시 인코딩된 설치 명령이 Windows 명령줄 길이 제한을 넘어 관리자 권한 창도 뜨지 않던 문제를 고쳤습니다. 관리자 스크립트는 한 번만 인코딩하며, 릴리스 검증과 기존 로컬 설치 경로는 유지합니다. +- `akfgkfRK` (`말할까`)처럼 Shift가 겹친 입력은 기존 한국어 어휘·활용형 근거가 있을 때만 대문자 보호를 완화해, 그 외에는 라틴 식별자의 대소문자를 보존합니다. 한국어 예외로 일본어 후보까지 허용하던 경로도 제한합니다. 사전에 없는 한국어에 Shift가 겹치면 라틴 키를 유지하며, 명시적 언어 교정이나 정상 한국어 키 입력으로 입력할 수 있습니다. - 일반 선호 학습은 실제 2순위 언어에만 적용합니다. 일본어가 켜져 있을 때 한국어 선호 때문에 영어가 일본어나 깨진 한글로 바뀌는 문제를 고쳤으며, 명시적으로 학습한 단어는 유지합니다. - Space·Enter로 확정할 때 완성된 조합의 언어를 유지합니다. `연습햇`이 `연습got`으로, 일본어 미리보기가 영어나 한국어로 바뀌던 문제를 고쳤으며, 명시적인 언어 전환과 일본어 후보 변환은 유지합니다. -- 한국어 된소리를 입력한 뒤 모음까지 Shift가 겹쳐도 자동으로 영문으로 단정하지 않습니다. `말할까`가 `akfgkfRK`로 바뀌던 문제를 고쳤으며, 원래 키 입력과 영문 대소문자는 보존합니다. ## [0.10.8] - 2026-10-22 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 19cf34f..8c179dc 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -31,6 +31,11 @@ Android APK를 빌드한 뒤 실행 중인 에뮬레이터·기기에서 JNI를 `./platforms/android/smoke.ps1 -Serial emulator-5554`를 실행합니다. 생성·활성화, 영·한 입력, 일시 정지·재개와 해제를 검사하며 시스템 입력기 선택은 바꾸지 않습니다. +키보드 UI는 격리된 에뮬레이터에서 `./platforms/android/ui-smoke.ps1 -Serial emulator-5560`으로 +검사합니다. 테스트 APK를 설치하고 Tacit을 잠시 선택한 뒤 기존 입력기를 복원하며, 실제 +조합·클립보드·선택 영역·대문자 고정·Enter·커서 전달을 검증합니다. 테스트용 편집 화면은 +`io.github.iamallyouneed.tacit.tests/io.github.iamallyouneed.tacit.KeyboardTestActivity`입니다. + ```sh cargo fmt --all -- --check cargo clippy --workspace --all-targets -- -D warnings @@ -137,6 +142,11 @@ After building the Android APK, run `./platforms/android/smoke.ps1 -Serial emula against a running emulator/device to check JNI creation, activation, English/Korean input, pause/resume, reset and destruction. This does not change the system's selected input method. +Run `./platforms/android/ui-smoke.ps1 -Serial emulator-5560` on an isolated emulator for keyboard UI +checks. It installs the test APKs, temporarily selects Tacit, restores the previous IME, and checks +real composition, clipboard/selection behavior, caps lock, Enter and cursor events. The separate +test editor is `io.github.iamallyouneed.tacit.tests/io.github.iamallyouneed.tacit.KeyboardTestActivity`. + ```sh cargo fmt --all -- --check cargo clippy --workspace --all-targets -- -D warnings diff --git a/crates/core/src/decide/engine.rs b/crates/core/src/decide/engine.rs index badb6ca..d0189b7 100644 --- a/crates/core/src/decide/engine.rs +++ b/crates/core/src/decide/engine.rs @@ -374,27 +374,46 @@ impl DecisionEngine for HeuristicEngine { fn decide(&self, keys: &str, context: &DecisionContext) -> Decision { let mut previous = '\0'; let mut has_lowercase = false; + let mut shift_overlap = false; let english_capital = self.english_on // Keep ordinary lowercase typing on the existing fast path. && keys .chars() .any(|c| c.is_uppercase() && !DubeolsikLayout::is_korean_shift_key(c)) && keys.chars().any(|c| { - // Shift may overlap the vowel after a doubled consonant; let the models judge it. + // Shift may overlap the vowel after a doubled consonant; verify its Korean evidence below. let overlap = self.korean_on && has_lowercase && matches!(previous, 'Q' | 'W' | 'E' | 'R' | 'T') && DubeolsikLayout::jamo(c).is_some_and(is_vowel); + shift_overlap |= c.is_uppercase() + && !DubeolsikLayout::is_korean_shift_key(c) + && overlap; previous = c; has_lowercase |= c.is_ascii_lowercase(); c.is_uppercase() && !DubeolsikLayout::is_korean_shift_key(c) && !overlap }); - if english_capital { + // Syllable likelihood alone also accepts identifiers; require existing Korean lexical evidence. + let korean_overlap = !shift_overlap + || HangulComposer::compose(keys).is_some_and(|composed| { + if composed.is_broken() { + return false; + } + let text = composed.text(); + self.korean.is_known_word_or_inflected(&text) + || self.korean.is_vocabulary_word(&text) + }); + if english_capital || !korean_overlap { return Decision { language: Language::English, confidence: CAPITALISED_ENGLISH_CONFIDENCE, output: keys.to_string(), - explanation: "uppercase outside QWERTOP".to_string(), + explanation: if english_capital { + "uppercase outside QWERTOP" + } else { + "Shift overlap without Korean lexical evidence" + } + .to_string(), runner_up: None, }; } @@ -438,6 +457,8 @@ impl DecisionEngine for HeuristicEngine { #[cfg(feature = "japanese")] let j = self .japanese + // Korean Shift evidence only admits a Korean reading, not unrelated Japanese candidates. + .filter(|_| !shift_overlap) .and_then(|model| model.score(keys, context.partial && !known)); // English words inside a Japanese phrase (googlede…) score as segmented Japanese, // not as kana with stray letters. diff --git a/crates/core/tests/engine.rs b/crates/core/tests/engine.rs index 230ee35..a39ae30 100644 --- a/crates/core/tests/engine.rs +++ b/crates/core/tests/engine.rs @@ -87,7 +87,7 @@ fn shift_overlap_uses_korean_scores_without_losing_english_case() { let e = heuristic(); for partial in [true, false] { let context = DecisionContext { partial, ..ctx() }; - for keys in ["akfgkfRk", "akfgkfRK", "gkfRK", "dlfRK"] { + for keys in ["akfgkfRk", "akfgkfRK", "gkfRK", "dlfRk"] { let d = e.decide(keys, &context); assert_eq!(d.language, Language::Korean, "{keys}: {d:?}"); assert_eq!( @@ -108,6 +108,81 @@ fn shift_overlap_uses_korean_scores_without_losing_english_case() { } } +#[test] +fn shift_overlap_preserves_matching_latin_identifiers() { + let mut failures = Vec::new(); + for japanese in [false, true] { + let languages = Languages::legacy(japanese); + let e = HeuristicEngine::for_languages(&languages); + for partial in [true, false] { + let context = DecisionContext { partial, ..ctx() }; + // These intended identifiers enter the same Shift-overlap gate as Korean input. + for keys in [ + "cmdWL", "rmWL", "dmlWL", "turnsRI", "cmdWLr", "rmWLr", "dmlWLr", "cmdWLfoo", + ] { + let d = e.decide(keys, &context); + if d.language != Language::English || d.output != keys { + failures.push(format!( + "languages={:?}, partial={partial}, {keys}: {d:?}", + languages.ids() + )); + } + } + } + } + assert!(failures.is_empty(), "{}", failures.join("\n")); +} + +#[test] +fn shift_overlap_retains_korean_positive_cases() { + for japanese in [false, true] { + let e = HeuristicEngine::for_languages(&Languages::legacy(japanese)); + for partial in [true, false] { + let context = DecisionContext { partial, ..ctx() }; + for (keys, text) in [("akfgkfRK", "말할까"), ("smfWlr", "늘찍")] { + let d = e.decide(keys, &context); + assert_eq!(d.language, Language::Korean, "{keys}: {d:?}"); + assert_eq!(d.output, text, "{keys}: {d:?}"); + assert_eq!(e.render(keys, Language::English), keys); + } + } + } +} + +#[test] +fn shift_overlap_without_lexical_evidence_preserves_case() { + for japanese in [false, true] { + let e = HeuristicEngine::for_languages(&Languages::legacy(japanese)); + for partial in [true, false] { + // An unlisted Korean spelling is ambiguous too; it needs canonical keys or explicit correction. + for keys in ["smfWLr", "dlfRK", "yukiRI"] { + let d = e.decide(keys, &DecisionContext { partial, ..ctx() }); + assert_eq!(d.language, Language::English, "{keys}: {d:?}"); + assert_eq!(d.output, keys); + } + } + } +} + +#[cfg(feature = "japanese")] +#[test] +fn korean_shift_evidence_does_not_admit_japanese() { + let mut e = HeuristicEngine::for_languages(&Languages::legacy(true)); + // Even an overwhelming Japanese score cannot use a Korean-specific exception. + e.japanese_offset = 100.0; + for partial in [true, false] { + let d = e.decide("akfgkfRK", &DecisionContext { partial, ..ctx() }); + assert_eq!(d.language, Language::Korean, "{d:?}"); + assert_eq!(d.output, "말할까"); + } + let e = HeuristicEngine::for_languages(&Languages::from_ids(&["en", "ja"]).unwrap()); + for keys in ["cmdWL", "rmWL", "dmlWL", "turnsRI", "yukiRI"] { + let d = e.decide(keys, &ctx()); + assert_eq!(d.language, Language::English, "{keys}: {d:?}"); + assert_eq!(d.output, keys); + } +} + #[test] fn mixed_sentence() { let e = heuristic(); diff --git a/crates/core/tests/session.rs b/crates/core/tests/session.rs index 124dc90..3716f40 100644 --- a/crates/core/tests/session.rs +++ b/crates/core/tests/session.rs @@ -319,6 +319,35 @@ fn confirmation_keeps_the_visible_korean_reading() { } } +#[test] +fn shift_overlap_identifiers_keep_case_and_allow_explicit_korean() { + for keys in ["cmdWL", "rmWL", "dmlWL", "turnsRI", "smfWLr", "dlfRK"] { + for correct in [false, true] { + let mut r = Rig::new("shift-overlap-identifiers"); + r.field.insert_text("앞😀 뒤", None); + r.field.cursor = "앞😀 ".encode_utf16().count(); + r.type_(keys); + assert_eq!(r.text(), format!("앞😀 {keys} 뒤")); + let expected = if correct { + r.key(Key::Escape); + tacit_core::lang::hangul::HangulComposer::compose(keys) + .unwrap() + .text() + } else { + keys.to_string() + }; + assert_eq!(r.text(), format!("앞😀 {expected} 뒤")); + assert!(r.key(Key::Enter)); + assert_eq!(r.text(), format!("앞😀 {expected} 뒤")); + assert!(!r.composing()); + assert_eq!( + r.field.selected_range().location, + format!("앞😀 {expected}").encode_utf16().count() + ); + } + } +} + #[test] fn confirmation_keeps_incomplete_previews() { let mut changes = Vec::new(); diff --git a/docs/report/performance-enkoja.md b/docs/report/performance-enkoja.md index 399c60e..7ecf34e 100644 --- a/docs/report/performance-enkoja.md +++ b/docs/report/performance-enkoja.md @@ -24,17 +24,17 @@ cargo run --release --manifest-path lab/Cargo.toml -- --profile enkoja --save 직전 버전과 비교합니다. 기준선은 `lab/baseline-enkoja.tsv`이며, 영·한 기준선을 대신 사용하지 않습니다. 아래 수치는 동일 프로필 5회 실행의 중앙값입니다. -## 한눈에: 0.10.2 → 0.10.3 +## 한눈에: 0.10.3 → 0.10.9 ▲ 좋아짐 · ▼ 나빠짐 · = 동점/잡음(정확도 0.05%p, 지연 25% 안은 잡음으로 봄). 정확도는 높을수록, 크기·지연·메모리는 낮을수록 좋음. -이전 열의 정확도·지연·메모리는 0.10.2 태그를 같은 lab·데이터로 0.10.3과 번갈아 5바퀴 돌린 중앙값입니다. 크기는 각 버전의 빌드 기록이며, 0.10.2는 일본어를 항상 포함한 단일 패키지(`tacit-windows.zip`), 0.10.3은 일본어 포함판(`tacit-windows-ja.zip`)입니다. 지연은 이 컴퓨터의 상대 비교만 의미가 있습니다. +이전 열은 같은 프로필의 과거 보고서 기록입니다. 같은 lab·데이터로 교차 재측정하지 않은 지연 차이는 코드 개선의 증거로 해석하지 않습니다. ### 정확도 핵심 (%) 막대 범위: 영·한 80~100%, 일본어(ja.*) 0~100%. -| 지표 | 0.10.2 | 0.10.3 | 변화 | +| 지표 | 0.10.3 | 0.10.9 | 변화 | | --- | ---: | ---: | ---: | | `acc.ALL` | 99.52 `████████████` | 99.52 `████████████` | +0.00 = | | `acc.en.freq/none` | 98.85 `███████████░` | 98.85 `███████████░` | +0.00 = | @@ -63,7 +63,7 @@ cargo run --release --manifest-path lab/Cargo.toml -- --profile enkoja --save ### 유형별 시나리오 문장 정답률 (%, 높을수록 좋음, 막대 80~100 구간) -| 유형 | 0.10.2 | 0.10.3 | 변화 | +| 유형 | 0.10.3 | 0.10.9 | 변화 | | --- | ---: | ---: | ---: | | chat | 96.51 `██████████░░` | 96.51 `██████████░░` | +0.00 = | | dev | 98.98 `███████████░` | 98.98 `███████████░` | +0.00 = | @@ -72,43 +72,150 @@ cargo run --release --manifest-path lab/Cargo.toml -- --profile enkoja --save ### 크기 비교 (KiB, 낮을수록 좋음, 막대 표 안 최대 기준) -| 항목 | 0.10.2 | 0.10.3 | 변화 | +| 항목 | 0.10.3 | 0.10.9 | 변화 | | --- | ---: | ---: | ---: | -| `tacit_tip.dll` (x64) | 957 `█░░░░░░░░░░░` | 962 `█░░░░░░░░░░░` | +5 (+0.5%) ▼ | -| `tacit_tip.dll` (x86) | 771 `█░░░░░░░░░░░` | 773 `█░░░░░░░░░░░` | +2 (+0.3%) ▼ | -| `tacit-config.exe` | 3277 `███░░░░░░░░░` | 3285 `███░░░░░░░░░` | +8 (+0.2%) ▼ | -| `tacit-windows-ja.zip` | - | 2389 `██░░░░░░░░░░` | 신규 | -| `tacit-pack-en-0.10.3.zip` | 446 `█░░░░░░░░░░░` | 446 `█░░░░░░░░░░░` | 0 = | -| `tacit-pack-ko-0.10.3.zip` | 450 `█░░░░░░░░░░░` | 450 `█░░░░░░░░░░░` | 0 = | -| `tacit-pack-ja-0.10.3.zip` | 14628 `████████████` | 14628 `████████████` | 0 = | +| `tacit_tip.dll` (x64) | 962 `█░░░░░░░░░░░` | 968 `█░░░░░░░░░░░` | +6 (+0.6%) ▼ | +| `tacit_tip.dll` (x86) | 773 `█░░░░░░░░░░░` | 778 `█░░░░░░░░░░░` | +5 (+0.6%) ▼ | +| `tacit-config.exe` | 3285 `███░░░░░░░░░` | 3339 `███░░░░░░░░░` | +54 (+1.6%) ▼ | +| `tacit-windows-ja.zip` | 2389 `██░░░░░░░░░░` | 2418 `██░░░░░░░░░░` | +29 (+1.2%) ▼ | +| `tacit-pack-en-0.10.9.zip` | 446 `█░░░░░░░░░░░` | 446 `█░░░░░░░░░░░` | 0 = | +| `tacit-pack-ko-0.10.9.zip` | 450 `█░░░░░░░░░░░` | 451 `█░░░░░░░░░░░` | +1 (+0.2%) ▼ | +| `tacit-pack-ja-0.10.9.zip` | 14628 `████████████` | 14628 `████████████` | 0 = | ### 지연 비교 (µs 중앙값, 낮을수록 좋음, 막대 표 안 최대 기준) -| 항목 | 0.10.2 | 0.10.3 | 변화 | +| 항목 | 0.10.3 | 0.10.9 | 변화 | | --- | ---: | ---: | ---: | -| `commit.avg_us` | 84.15 `██░░░░░░░░░░` | 46.94 `█░░░░░░░░░░░` | -37.21 (-44.2%) ▲ | -| `commit.p50_us` | 54.30 `█░░░░░░░░░░░` | 42.50 `█░░░░░░░░░░░` | -11.80 (-21.7%) = | -| `commit.p95_us` | 257.30 `██████░░░░░░` | 99.90 `██░░░░░░░░░░` | -157.40 (-61.2%) ▲ | -| `commit.p99_us` | 387.30 `█████████░░░` | 143.50 `███░░░░░░░░░` | -243.80 (-62.9%) ▲ | -| `keystroke.avg_us` | 37.78 `█░░░░░░░░░░░` | 22.07 `█░░░░░░░░░░░` | -15.71 (-41.6%) ▲ | -| `keystroke.p50_us` | 22.10 `█░░░░░░░░░░░` | 14.00 `█░░░░░░░░░░░` | -8.10 (-36.7%) ▲ | -| `keystroke.p95_us` | 136.00 `███░░░░░░░░░` | 64.30 `██░░░░░░░░░░` | -71.70 (-52.7%) ▲ | -| `keystroke.p99_us` | 245.90 `██████░░░░░░` | 101.30 `██░░░░░░░░░░` | -144.60 (-58.8%) ▲ | -| `ja.convert.avg_us` | 246.87 `██████░░░░░░` | 191.27 `█████░░░░░░░` | -55.60 (-22.5%) = | -| `ja.convert.p50_us` | 222.70 `█████░░░░░░░` | 173.10 `████░░░░░░░░` | -49.60 (-22.3%) = | -| `ja.convert.p95_us` | 438.70 `██████████░░` | 320.90 `████████░░░░` | -117.80 (-26.9%) ▲ | -| `ja.convert.p99_us` | 509.50 `████████████` | 386.00 `█████████░░░` | -123.50 (-24.2%) = | +| `commit.avg_us` | 46.94 `█░░░░░░░░░░░` | 78.49 `█░░░░░░░░░░░` | +31.55 (+67.2%) ▼ | +| `commit.p50_us` | 42.50 `█░░░░░░░░░░░` | 68.40 `█░░░░░░░░░░░` | +25.90 (+60.9%) ▼ | +| `commit.p95_us` | 99.90 `█░░░░░░░░░░░` | 172.30 `██░░░░░░░░░░` | +72.40 (+72.5%) ▼ | +| `commit.p99_us` | 143.50 `██░░░░░░░░░░` | 257.60 `████░░░░░░░░` | +114.10 (+79.5%) ▼ | +| `keystroke.avg_us` | 22.07 `█░░░░░░░░░░░` | 37.14 `█░░░░░░░░░░░` | +15.07 (+68.3%) ▼ | +| `keystroke.p50_us` | 14.00 `█░░░░░░░░░░░` | 22.70 `█░░░░░░░░░░░` | +8.70 (+62.1%) ▼ | +| `keystroke.p95_us` | 64.30 `█░░░░░░░░░░░` | 111.00 `██░░░░░░░░░░` | +46.70 (+72.6%) ▼ | +| `keystroke.p99_us` | 101.30 `█░░░░░░░░░░░` | 181.80 `███░░░░░░░░░` | +80.50 (+79.5%) ▼ | +| `ja.convert.avg_us` | 191.27 `███░░░░░░░░░` | 360.45 `█████░░░░░░░` | +169.18 (+88.5%) ▼ | +| `ja.convert.p50_us` | 173.10 `██░░░░░░░░░░` | 317.00 `████░░░░░░░░` | +143.90 (+83.1%) ▼ | +| `ja.convert.p95_us` | 320.90 `████░░░░░░░░` | 592.00 `████████░░░░` | +271.10 (+84.5%) ▼ | +| `ja.convert.p99_us` | 386.00 `█████░░░░░░░` | 860.00 `████████████` | +474.00 (+122.8%) ▼ | ### 시작·메모리 비교 (낮을수록 좋음, 막대 행별 비교) -| 항목 | 0.10.2 | 0.10.3 | 변화 | +| 항목 | 0.10.3 | 0.10.9 | 변화 | | --- | ---: | ---: | ---: | -| `load.ms` | 16.89 `███████████░` | 18.74 `████████████` | +1.85 (+11.0%) = | -| `heap.loaded_kb` | 2468.13 `████████████` | 2468.14 `████████████` | +0.01 (+0.0%) = | -| `heap.peak_kb` | 14047.55 `████████████` | 14047.56 `████████████` | +0.01 (+0.0%) = | -| `ja.load.ms` | 3.22 `████████████` | 2.91 `███████████░` | -0.31 (-9.6%) = | +| `load.ms` | 18.74 `███████░░░░░` | 30.86 `████████████` | +12.12 (+64.7%) ▼ | +| `heap.loaded_kb` | 2468.14 `████████████` | 2468.14 `████████████` | +0.00 (+0.0%) = | +| `heap.peak_kb` | 14047.56 `████████████` | 14047.65 `████████████` | +0.09 (+0.0%) = | +| `ja.load.ms` | 2.91 `██████░░░░░░` | 5.60 `████████████` | +2.69 (+92.4%) ▼ | | `ja.heap.loaded_kb` | 2998.60 `████████████` | 2998.60 `████████████` | +0.00 (+0.0%) = | +## 0.10.9 + +commit b58cc6d, 2026-10-23, rustc 1.93.1 (01f6ddf75 2026-02-11) + +프로필: `enkoja` (영·한·일), lab 0.2.12. + +공통 정확도·시나리오는 해당 언어가 켜진 판별기로 측정합니다. acc.ALL은 영·한 공통 세트이며 일본어 정답률과 합산하지 않습니다. + +load.ms·heap.*는 판별기 시작/단어 평가 기준입니다. enkoja의 ja.load.ms·ja.heap.loaded_kb는 별도 가나→한자 변환기 초기화/힙 증가입니다. 영·한판(tacit-windows.zip)과 일본어 포함판(tacit-windows-ja.zip)은 프로그램과 설치 zip이 다르고, 팩 목록도 활성 언어에 따라 다릅니다. + +### 크기 (KiB) + +| 항목 | KiB | +| --- | ---: | +| `tacit_tip.dll` (x64) | 968 | +| `tacit_tip.dll` (x86) | 778 | +| `tacit-config.exe` | 3339 | +| `tacit-windows-ja.zip` | 2418 | +| `tacit-pack-en-0.10.9.zip` | 446 | +| `tacit-pack-ko-0.10.9.zip` | 451 | +| `tacit-pack-ja-0.10.9.zip` | 14628 | + +### 정확도 (%) + +| 세트 | 정확도 | +| --- | ---: | +| `acc.ALL` | 99.52 | +| `acc.en.freq/none` | 98.85 | +| `acc.en.freq/after-ko` | 98.80 | +| `acc.ko.words/none` | 100.00 | +| `acc.ko.vocab/none` | 100.00 | +| `big.ko.sent.sentence` | 99.03 | +| `big.ko.sent.token` | 99.81 | +| `big.ko.phrase.sentence` | 99.37 | +| `big.ko.long.sentence` | 97.70 | +| `big.en.sent.sentence` | 99.90 | +| `big.cs.particle.sentence` | 99.06 | +| `big.cs.particle.token` | 99.85 | +| `big.cs_heldout.particle.sentence` | 98.95 | +| `big.cs.bare.sentence` | 96.94 | +| `big.cs.number.sentence` | 99.05 | +| `big.ko.title.none` | 99.87 | +| `big.ko.title.after-en` | 99.37 | +| `big.learn.other_forms_before` | 100.00 | +| `big.learn.other_forms_after` | 100.00 | +| `ja.convert.ALL.top1` | 85.94 | +| `ja.convert.ALL.top5` | 96.88 | +| `ja.detect.none.top1` | 100.00 | +| `ja.detect.after-ja.top1` | 100.00 | +| `ja.guard.english.top1` | 100.00 | + +### 유형별 시나리오 (문장 정답률 %, token은 단어 단위, chain은 4문장 이어 입력) + +| 유형 | 문장 | token | chain.token | µs/글자 | +| --- | ---: | ---: | ---: | ---: | +| chat | 96.51 | 98.78 | 99.17 | 8.42 | +| dev | 98.98 | 99.69 | 99.37 | 9.05 | +| writing | 98.78 | 99.77 | 99.75 | 10.60 | +| 전체 | 98.12 | 99.50 | | | + +| 시나리오 | 문장 정답률 | +| --- | ---: | +| `chat.brand` | 100.00 | +| `chat.casual` | 100.00 | +| `chat.english` | 100.00 | +| `chat.loan` | 92.31 | +| `chat.number` | 100.00 | +| `chat.punct` | 100.00 | +| `chat.slang` | 88.24 | +| `dev.commit` | 100.00 | +| `dev.error` | 100.00 | +| `dev.identifier` | 100.00 | +| `dev.issue` | 100.00 | +| `dev.review` | 100.00 | +| `dev.terminal` | 96.00 | +| `dev.tool` | 100.00 | +| `writing.academic` | 92.86 | +| `writing.email` | 100.00 | +| `writing.english` | 100.00 | +| `writing.essay` | 100.00 | +| `writing.formal` | 100.00 | +| `writing.long` | 100.00 | +| `writing.numbers` | 100.00 | +| `writing.quote` | 100.00 | + +### 속도·메모리 (중앙값, 5회) + +| 항목 | 값 | +| --- | ---: | +| `commit.avg_us` | 78.49 | +| `commit.p50_us` | 68.40 | +| `commit.p95_us` | 172.30 | +| `commit.p99_us` | 257.60 | +| `keystroke.avg_us` | 37.14 | +| `keystroke.p50_us` | 22.70 | +| `keystroke.p95_us` | 111.00 | +| `keystroke.p99_us` | 181.80 | +| `ja.convert.avg_us` | 360.45 | +| `ja.convert.p50_us` | 317.00 | +| `ja.convert.p95_us` | 592.00 | +| `ja.convert.p99_us` | 860.00 | +| `load.ms` | 30.86 | +| `heap.loaded_kb` | 2468.14 | +| `heap.peak_kb` | 14047.65 | +| `ja.load.ms` | 5.60 | +| `ja.heap.loaded_kb` | 2998.60 | + ## 0.10.3 commit 5816b5d (작업 트리 변경 포함), 2026-10-19, rustc 1.93.1 (01f6ddf75 2026-02-11) diff --git a/docs/report/performance.md b/docs/report/performance.md index a765de7..04ffbb8 100644 --- a/docs/report/performance.md +++ b/docs/report/performance.md @@ -86,17 +86,17 @@ sh lab/report.sh --profile enkoja > section-enkoja.md # 별도 영·한·일 문 - 기준선 저장도 프로필별입니다: `cargo run --release --manifest-path lab/Cargo.toml -- --profile enko --save`는 `lab/baseline-enko.tsv`, `--profile enkoja --save`는 `lab/baseline-enkoja.tsv`만 갱신합니다. 기본값은 `enko`입니다. - **이전 버전과 비교할 때는 같은 lab으로 잽니다.** 세트와 데이터가 달라지면 같은 코드도 수치가 달라집니다. 새 worktree 둘을 만들어 한쪽에만 `git restore --source=<이전 태그> --worktree --staged crates/core`를 하고(코어에 없는 API를 쓰는 `lab/src/tune.rs` 같은 파일은 그 worktree에서만 비활성으로 바꿉니다), 각각 `lab/data`를 **복사**해 두고 5회씩 돌려 중앙값을 냅니다. `lab/data`를 junction이나 링크로 연결한 worktree를 `git worktree remove --force` 하면 링크 너머의 실제 데이터까지 지워집니다. -## 한눈에: 0.10.2 → 0.10.3 +## 한눈에: 0.10.3 → 0.10.9 ▲ 좋아짐 · ▼ 나빠짐 · = 동점/잡음(정확도 0.05%p, 지연 25% 안은 잡음으로 봄). 정확도는 높을수록, 크기·지연·메모리는 낮을수록 좋음. -0.10.3은 릴리즈 전(미출시) 작업 트리입니다. 이전 열의 정확도·지연·메모리는 0.10.2 태그를 같은 lab·데이터로 0.10.3과 번갈아 9바퀴 돌린 중앙값이고, 크기는 같은 컴퓨터에서 같은 빌드 설정으로 만든 0.10.2 로컬 빌드입니다. 그래서 앞 보고서의 0.10.2 값(지연이 약 1.8배 빠름)과 직접 이어 읽지 않습니다. 지연은 이 컴퓨터의 상대 비교만 의미가 있습니다. +이전 열은 같은 프로필의 과거 보고서 기록입니다. 같은 lab·데이터로 교차 재측정하지 않은 지연 차이는 코드 개선의 증거로 해석하지 않습니다. ### 정확도 핵심 (%) 막대 범위: 영·한 80~100%, 일본어(ja.*) 0~100%. -| 지표 | 0.10.2 | 0.10.3 | 변화 | +| 지표 | 0.10.3 | 0.10.9 | 변화 | | --- | ---: | ---: | ---: | | `acc.ALL` | 99.69 `████████████` | 99.69 `████████████` | +0.00 = | | `acc.en.freq/none` | 99.50 `████████████` | 99.50 `████████████` | +0.00 = | @@ -120,7 +120,7 @@ sh lab/report.sh --profile enkoja > section-enkoja.md # 별도 영·한·일 문 ### 유형별 시나리오 문장 정답률 (%, 높을수록 좋음, 막대 80~100 구간) -| 유형 | 0.10.2 | 0.10.3 | 변화 | +| 유형 | 0.10.3 | 0.10.9 | 변화 | | --- | ---: | ---: | ---: | | chat | 96.51 `██████████░░` | 96.51 `██████████░░` | +0.00 = | | dev | 98.98 `███████████░` | 98.98 `███████████░` | +0.00 = | @@ -129,35 +129,130 @@ sh lab/report.sh --profile enkoja > section-enkoja.md # 별도 영·한·일 문 ### 크기 비교 (KiB, 낮을수록 좋음, 막대 표 안 최대 기준) -| 항목 | 0.10.2 | 0.10.3 | 변화 | +| 항목 | 0.10.3 | 0.10.9 | 변화 | | --- | ---: | ---: | ---: | -| `tacit_tip.dll` (x64) | 951 `███░░░░░░░░░` | 747 `███░░░░░░░░░` | -204 (-21.5%) ▲ | -| `tacit_tip.dll` (x86) | 766 `███░░░░░░░░░` | 613 `██░░░░░░░░░░` | -153 (-20.0%) ▲ | -| `tacit-config.exe` | 3276 `████████████` | 3100 `███████████░` | -176 (-5.4%) ▲ | -| `tacit-windows.zip` | 2379 `█████████░░░` | 2150 `████████░░░░` | -229 (-9.6%) ▲ | -| `tacit-pack-en-0.10.3.zip` | 446 `██░░░░░░░░░░` | 446 `██░░░░░░░░░░` | 0 = | -| `tacit-pack-ko-0.10.3.zip` | 451 `██░░░░░░░░░░` | 451 `██░░░░░░░░░░` | 0 = | +| `tacit_tip.dll` (x64) | 747 `███░░░░░░░░░` | 756 `███░░░░░░░░░` | +9 (+1.2%) ▼ | +| `tacit_tip.dll` (x86) | 613 `██░░░░░░░░░░` | 620 `██░░░░░░░░░░` | +7 (+1.1%) ▼ | +| `tacit-config.exe` | 3100 `████████████` | 3158 `████████████` | +58 (+1.9%) ▼ | +| `tacit-windows.zip` | 2150 `████████░░░░` | 2182 `████████░░░░` | +32 (+1.5%) ▼ | +| `tacit-pack-en-0.10.9.zip` | 446 `██░░░░░░░░░░` | 446 `██░░░░░░░░░░` | 0 = | +| `tacit-pack-ko-0.10.9.zip` | 451 `██░░░░░░░░░░` | 451 `██░░░░░░░░░░` | 0 = | ### 지연 비교 (µs 중앙값, 낮을수록 좋음, 막대 표 안 최대 기준) -| 항목 | 0.10.2 | 0.10.3 | 변화 | +| 항목 | 0.10.3 | 0.10.9 | 변화 | | --- | ---: | ---: | ---: | -| `commit.avg_us` | 10.32 `██░░░░░░░░░░` | 10.48 `███░░░░░░░░░` | +0.16 (+1.6%) = | -| `commit.p50_us` | 9.20 `██░░░░░░░░░░` | 9.00 `██░░░░░░░░░░` | -0.20 (-2.2%) = | -| `commit.p95_us` | 18.20 `████░░░░░░░░` | 19.80 `█████░░░░░░░` | +1.60 (+8.8%) = | -| `commit.p99_us` | 31.30 `███████░░░░░` | 37.00 `█████████░░░` | +5.70 (+18.2%) = | -| `keystroke.avg_us` | 9.48 `██░░░░░░░░░░` | 9.70 `██░░░░░░░░░░` | +0.22 (+2.3%) = | -| `keystroke.p50_us` | 7.80 `██░░░░░░░░░░` | 7.60 `██░░░░░░░░░░` | -0.20 (-2.6%) = | -| `keystroke.p95_us` | 20.60 `█████░░░░░░░` | 22.80 `█████░░░░░░░` | +2.20 (+10.7%) = | -| `keystroke.p99_us` | 44.90 `███████████░` | 50.30 `████████████` | +5.40 (+12.0%) = | +| `commit.avg_us` | 10.48 `██░░░░░░░░░░` | 15.84 `██░░░░░░░░░░` | +5.36 (+51.1%) ▼ | +| `commit.p50_us` | 9.00 `█░░░░░░░░░░░` | 12.80 `██░░░░░░░░░░` | +3.80 (+42.2%) ▼ | +| `commit.p95_us` | 19.80 `███░░░░░░░░░` | 26.30 `████░░░░░░░░` | +6.50 (+32.8%) ▼ | +| `commit.p99_us` | 37.00 `█████░░░░░░░` | 56.50 `████████░░░░` | +19.50 (+52.7%) ▼ | +| `keystroke.avg_us` | 9.70 `█░░░░░░░░░░░` | 15.18 `██░░░░░░░░░░` | +5.48 (+56.5%) ▼ | +| `keystroke.p50_us` | 7.60 `█░░░░░░░░░░░` | 10.70 `██░░░░░░░░░░` | +3.10 (+40.8%) ▼ | +| `keystroke.p95_us` | 22.80 `███░░░░░░░░░` | 33.70 `█████░░░░░░░` | +10.90 (+47.8%) ▼ | +| `keystroke.p99_us` | 50.30 `███████░░░░░` | 83.60 `████████████` | +33.30 (+66.2%) ▼ | ### 시작·메모리 비교 (낮을수록 좋음, 막대 행별 비교) -| 항목 | 0.10.2 | 0.10.3 | 변화 | +| 항목 | 0.10.3 | 0.10.9 | 변화 | | --- | ---: | ---: | ---: | -| `load.ms` | 1.78 `████████████` | 1.57 `███████████░` | -0.21 (-11.8%) = | -| `heap.loaded_kb` | 52.66 `████████████` | 52.67 `████████████` | +0.01 (+0.0%) = | -| `heap.peak_kb` | 11628.71 `████████████` | 11628.73 `████████████` | +0.02 (+0.0%) = | +| `load.ms` | 1.57 `██████░░░░░░` | 3.19 `████████████` | +1.62 (+103.2%) ▼ | +| `heap.loaded_kb` | 52.67 `████████████` | 52.67 `████████████` | +0.00 (+0.0%) = | +| `heap.peak_kb` | 11628.73 `████████████` | 11628.82 `████████████` | +0.09 (+0.0%) = | + +## 0.10.9 + +commit b58cc6d, 2026-10-23, rustc 1.93.1 (01f6ddf75 2026-02-11) + +프로필: `enko` (영·한), lab 0.2.12. + +공통 정확도·시나리오는 해당 언어가 켜진 판별기로 측정합니다. acc.ALL은 영·한 공통 세트이며 일본어 정답률과 합산하지 않습니다. + +load.ms·heap.*는 판별기 시작/단어 평가 기준입니다. enkoja의 ja.load.ms·ja.heap.loaded_kb는 별도 가나→한자 변환기 초기화/힙 증가입니다. 영·한판(tacit-windows.zip)과 일본어 포함판(tacit-windows-ja.zip)은 프로그램과 설치 zip이 다르고, 팩 목록도 활성 언어에 따라 다릅니다. + +### 크기 (KiB) + +| 항목 | KiB | +| --- | ---: | +| `tacit_tip.dll` (x64) | 756 | +| `tacit_tip.dll` (x86) | 620 | +| `tacit-config.exe` | 3158 | +| `tacit-windows.zip` | 2182 | +| `tacit-pack-en-0.10.9.zip` | 446 | +| `tacit-pack-ko-0.10.9.zip` | 451 | + +### 정확도 (%) + +| 세트 | 정확도 | +| --- | ---: | +| `acc.ALL` | 99.69 | +| `acc.en.freq/none` | 99.50 | +| `acc.en.freq/after-ko` | 99.45 | +| `acc.ko.words/none` | 100.00 | +| `acc.ko.vocab/none` | 100.00 | +| `big.ko.sent.sentence` | 99.13 | +| `big.ko.sent.token` | 99.83 | +| `big.ko.phrase.sentence` | 99.37 | +| `big.ko.long.sentence` | 98.40 | +| `big.en.sent.sentence` | 99.93 | +| `big.cs.particle.sentence` | 99.06 | +| `big.cs.particle.token` | 99.85 | +| `big.cs_heldout.particle.sentence` | 98.95 | +| `big.cs.bare.sentence` | 97.77 | +| `big.cs.number.sentence` | 99.29 | +| `big.ko.title.none` | 99.87 | +| `big.ko.title.after-en` | 99.37 | +| `big.learn.other_forms_before` | 100.00 | +| `big.learn.other_forms_after` | 100.00 | + +### 유형별 시나리오 (문장 정답률 %, token은 단어 단위, chain은 4문장 이어 입력) + +| 유형 | 문장 | token | chain.token | µs/글자 | +| --- | ---: | ---: | ---: | ---: | +| chat | 96.51 | 98.78 | 99.17 | 3.04 | +| dev | 98.98 | 99.69 | 99.37 | 3.50 | +| writing | 98.78 | 99.77 | 99.75 | 2.23 | +| 전체 | 98.12 | 99.50 | | | + +| 시나리오 | 문장 정답률 | +| --- | ---: | +| `chat.brand` | 100.00 | +| `chat.casual` | 100.00 | +| `chat.english` | 100.00 | +| `chat.loan` | 92.31 | +| `chat.number` | 100.00 | +| `chat.punct` | 100.00 | +| `chat.slang` | 88.24 | +| `dev.commit` | 100.00 | +| `dev.error` | 100.00 | +| `dev.identifier` | 100.00 | +| `dev.issue` | 100.00 | +| `dev.review` | 100.00 | +| `dev.terminal` | 96.00 | +| `dev.tool` | 100.00 | +| `writing.academic` | 92.86 | +| `writing.email` | 100.00 | +| `writing.english` | 100.00 | +| `writing.essay` | 100.00 | +| `writing.formal` | 100.00 | +| `writing.long` | 100.00 | +| `writing.numbers` | 100.00 | +| `writing.quote` | 100.00 | + +### 속도·메모리 (중앙값, 5회) + +| 항목 | 값 | +| --- | ---: | +| `commit.avg_us` | 15.84 | +| `commit.p50_us` | 12.80 | +| `commit.p95_us` | 26.30 | +| `commit.p99_us` | 56.50 | +| `keystroke.avg_us` | 15.18 | +| `keystroke.p50_us` | 10.70 | +| `keystroke.p95_us` | 33.70 | +| `keystroke.p99_us` | 83.60 | +| `load.ms` | 3.19 | +| `heap.loaded_kb` | 52.67 | +| `heap.peak_kb` | 11628.82 | ## 0.10.3 diff --git a/platforms/android/THIRD_PARTY_NOTICES.md b/platforms/android/THIRD_PARTY_NOTICES.md index 32ac453..31b1015 100644 --- a/platforms/android/THIRD_PARTY_NOTICES.md +++ b/platforms/android/THIRD_PARTY_NOTICES.md @@ -14,3 +14,13 @@ Tacit's remaining code is covered by the repository's AGPL-3.0-only license. HeliBoard's input engine, dictionaries, settings, and gesture libraries are not included. The rounded key backgrounds and light/dark palettes are original Tacit resources. + +## Lucide icons + +The `app/res/drawable/ic_*.xml` vectors are adapted from +[Lucide](https://github.com/lucide-icons/lucide/tree/20aef31db93fe4d9f398dbb15b120d99c48eef95/icons) +at commit `20aef31db93fe4d9f398dbb15b120d99c48eef95`. +SVG geometry is preserved as Android vector paths with a 1.8-unit stroke. +Lucide uses ISC, with MIT attribution for icons derived from Feather. +The complete upstream [license](app/res/raw/lucide_license.txt) is bundled in the APK. +No Lucide runtime dependency is used. The toolbar logo is Tacit's existing `assets/icon.png`. diff --git a/platforms/android/app/res/drawable-nodpi/tacit_logo.png b/platforms/android/app/res/drawable-nodpi/tacit_logo.png new file mode 100644 index 0000000..5312ed0 Binary files /dev/null and b/platforms/android/app/res/drawable-nodpi/tacit_logo.png differ diff --git a/platforms/android/app/res/drawable/clipboard_action.xml b/platforms/android/app/res/drawable/clipboard_action.xml new file mode 100644 index 0000000..fc4ac50 --- /dev/null +++ b/platforms/android/app/res/drawable/clipboard_action.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/platforms/android/app/res/drawable/ic_arrow_big_up.xml b/platforms/android/app/res/drawable/ic_arrow_big_up.xml new file mode 100644 index 0000000..486c19d --- /dev/null +++ b/platforms/android/app/res/drawable/ic_arrow_big_up.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/platforms/android/app/res/drawable/ic_arrow_big_up_dash.xml b/platforms/android/app/res/drawable/ic_arrow_big_up_dash.xml new file mode 100644 index 0000000..cf6951c --- /dev/null +++ b/platforms/android/app/res/drawable/ic_arrow_big_up_dash.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/platforms/android/app/res/drawable/ic_arrow_left.xml b/platforms/android/app/res/drawable/ic_arrow_left.xml new file mode 100644 index 0000000..c9c9093 --- /dev/null +++ b/platforms/android/app/res/drawable/ic_arrow_left.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/platforms/android/app/res/drawable/ic_arrow_right.xml b/platforms/android/app/res/drawable/ic_arrow_right.xml new file mode 100644 index 0000000..526a4ff --- /dev/null +++ b/platforms/android/app/res/drawable/ic_arrow_right.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/platforms/android/app/res/drawable/ic_chevron_down.xml b/platforms/android/app/res/drawable/ic_chevron_down.xml new file mode 100644 index 0000000..a127e44 --- /dev/null +++ b/platforms/android/app/res/drawable/ic_chevron_down.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/platforms/android/app/res/drawable/ic_chevron_left.xml b/platforms/android/app/res/drawable/ic_chevron_left.xml new file mode 100644 index 0000000..34f8600 --- /dev/null +++ b/platforms/android/app/res/drawable/ic_chevron_left.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/platforms/android/app/res/drawable/ic_clipboard.xml b/platforms/android/app/res/drawable/ic_clipboard.xml new file mode 100644 index 0000000..384d5db --- /dev/null +++ b/platforms/android/app/res/drawable/ic_clipboard.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/platforms/android/app/res/drawable/ic_clipboard_paste.xml b/platforms/android/app/res/drawable/ic_clipboard_paste.xml new file mode 100644 index 0000000..b2b6dbb --- /dev/null +++ b/platforms/android/app/res/drawable/ic_clipboard_paste.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/platforms/android/app/res/drawable/ic_corner_down_left.xml b/platforms/android/app/res/drawable/ic_corner_down_left.xml new file mode 100644 index 0000000..12e0500 --- /dev/null +++ b/platforms/android/app/res/drawable/ic_corner_down_left.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/platforms/android/app/res/drawable/ic_delete.xml b/platforms/android/app/res/drawable/ic_delete.xml new file mode 100644 index 0000000..d9aaba1 --- /dev/null +++ b/platforms/android/app/res/drawable/ic_delete.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/platforms/android/app/res/drawable/ic_ellipsis.xml b/platforms/android/app/res/drawable/ic_ellipsis.xml new file mode 100644 index 0000000..319249e --- /dev/null +++ b/platforms/android/app/res/drawable/ic_ellipsis.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/platforms/android/app/res/drawable/ic_keyboard.xml b/platforms/android/app/res/drawable/ic_keyboard.xml new file mode 100644 index 0000000..5863ce2 --- /dev/null +++ b/platforms/android/app/res/drawable/ic_keyboard.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/platforms/android/app/res/drawable/ic_move_horizontal.xml b/platforms/android/app/res/drawable/ic_move_horizontal.xml new file mode 100644 index 0000000..61e1465 --- /dev/null +++ b/platforms/android/app/res/drawable/ic_move_horizontal.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/platforms/android/app/res/drawable/ic_settings_2.xml b/platforms/android/app/res/drawable/ic_settings_2.xml new file mode 100644 index 0000000..6509055 --- /dev/null +++ b/platforms/android/app/res/drawable/ic_settings_2.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/platforms/android/app/res/drawable/keyboard_key.xml b/platforms/android/app/res/drawable/keyboard_key.xml index b091fb6..86aa623 100644 --- a/platforms/android/app/res/drawable/keyboard_key.xml +++ b/platforms/android/app/res/drawable/keyboard_key.xml @@ -6,19 +6,20 @@ - + - + - + + diff --git a/platforms/android/app/res/drawable/reading_chip.xml b/platforms/android/app/res/drawable/reading_chip.xml index dd2401f..87b0dca 100644 --- a/platforms/android/app/res/drawable/reading_chip.xml +++ b/platforms/android/app/res/drawable/reading_chip.xml @@ -4,21 +4,28 @@ android:insetTop="4dp" android:insetBottom="4dp"> - - - - + + + + + + + + + + + - + - - + + diff --git a/platforms/android/app/res/layout/input.xml b/platforms/android/app/res/layout/input.xml index 70d0119..15a3d86 100644 --- a/platforms/android/app/res/layout/input.xml +++ b/platforms/android/app/res/layout/input.xml @@ -5,15 +5,125 @@ android:background="@color/keyboard_background" android:orientation="vertical"> - + android:paddingRight="4dp"> - + + + + + + + + + + + + + + + + + +