diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..94a25f7
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/assets/keyboard_themes/default/background.png b/app/src/main/assets/keyboard_themes/default/background.png
new file mode 100644
index 0000000..c2a690d
Binary files /dev/null and b/app/src/main/assets/keyboard_themes/default/background.png differ
diff --git a/app/src/main/assets/keyboard_themes/default/key_0.png b/app/src/main/assets/keyboard_themes/default/key_0.png
new file mode 100644
index 0000000..3f50ba7
Binary files /dev/null and b/app/src/main/assets/keyboard_themes/default/key_0.png differ
diff --git a/app/src/main/assets/keyboard_themes/default/key_1.png b/app/src/main/assets/keyboard_themes/default/key_1.png
new file mode 100644
index 0000000..a63ddbe
Binary files /dev/null and b/app/src/main/assets/keyboard_themes/default/key_1.png differ
diff --git a/app/src/main/assets/keyboard_themes/default/key_123.png b/app/src/main/assets/keyboard_themes/default/key_123.png
new file mode 100644
index 0000000..2742137
Binary files /dev/null and b/app/src/main/assets/keyboard_themes/default/key_123.png differ
diff --git a/app/src/main/assets/keyboard_themes/default/key_2.png b/app/src/main/assets/keyboard_themes/default/key_2.png
new file mode 100644
index 0000000..dbc74b9
Binary files /dev/null and b/app/src/main/assets/keyboard_themes/default/key_2.png differ
diff --git a/app/src/main/assets/keyboard_themes/default/key_3.png b/app/src/main/assets/keyboard_themes/default/key_3.png
new file mode 100644
index 0000000..f38b8a3
Binary files /dev/null and b/app/src/main/assets/keyboard_themes/default/key_3.png differ
diff --git a/app/src/main/assets/keyboard_themes/default/key_4.png b/app/src/main/assets/keyboard_themes/default/key_4.png
new file mode 100644
index 0000000..ce0566b
Binary files /dev/null and b/app/src/main/assets/keyboard_themes/default/key_4.png differ
diff --git a/app/src/main/assets/keyboard_themes/default/key_5.png b/app/src/main/assets/keyboard_themes/default/key_5.png
new file mode 100644
index 0000000..f1aecfe
Binary files /dev/null and b/app/src/main/assets/keyboard_themes/default/key_5.png differ
diff --git a/app/src/main/assets/keyboard_themes/default/key_6.png b/app/src/main/assets/keyboard_themes/default/key_6.png
new file mode 100644
index 0000000..c76f7ac
Binary files /dev/null and b/app/src/main/assets/keyboard_themes/default/key_6.png differ
diff --git a/app/src/main/assets/keyboard_themes/default/key_7.png b/app/src/main/assets/keyboard_themes/default/key_7.png
new file mode 100644
index 0000000..20be3d8
Binary files /dev/null and b/app/src/main/assets/keyboard_themes/default/key_7.png differ
diff --git a/app/src/main/assets/keyboard_themes/default/key_8.png b/app/src/main/assets/keyboard_themes/default/key_8.png
new file mode 100644
index 0000000..6ee3dfc
Binary files /dev/null and b/app/src/main/assets/keyboard_themes/default/key_8.png differ
diff --git a/app/src/main/assets/keyboard_themes/default/key_9.png b/app/src/main/assets/keyboard_themes/default/key_9.png
new file mode 100644
index 0000000..3459117
Binary files /dev/null and b/app/src/main/assets/keyboard_themes/default/key_9.png differ
diff --git a/app/src/main/assets/keyboard_themes/default/key_a.png b/app/src/main/assets/keyboard_themes/default/key_a.png
new file mode 100644
index 0000000..76687e3
Binary files /dev/null and b/app/src/main/assets/keyboard_themes/default/key_a.png differ
diff --git a/app/src/main/assets/keyboard_themes/default/key_a_up.png b/app/src/main/assets/keyboard_themes/default/key_a_up.png
new file mode 100644
index 0000000..2598472
Binary files /dev/null and b/app/src/main/assets/keyboard_themes/default/key_a_up.png differ
diff --git a/app/src/main/assets/keyboard_themes/default/key_abc.png b/app/src/main/assets/keyboard_themes/default/key_abc.png
new file mode 100644
index 0000000..a1923a6
Binary files /dev/null and b/app/src/main/assets/keyboard_themes/default/key_abc.png differ
diff --git a/app/src/main/assets/keyboard_themes/default/key_ai.png b/app/src/main/assets/keyboard_themes/default/key_ai.png
new file mode 100644
index 0000000..e3cf382
Binary files /dev/null and b/app/src/main/assets/keyboard_themes/default/key_ai.png differ
diff --git a/app/src/main/assets/keyboard_themes/default/key_amp.png b/app/src/main/assets/keyboard_themes/default/key_amp.png
new file mode 100644
index 0000000..03538fa
Binary files /dev/null and b/app/src/main/assets/keyboard_themes/default/key_amp.png differ
diff --git a/app/src/main/assets/keyboard_themes/default/key_asterisk.png b/app/src/main/assets/keyboard_themes/default/key_asterisk.png
new file mode 100644
index 0000000..620ce9f
Binary files /dev/null and b/app/src/main/assets/keyboard_themes/default/key_asterisk.png differ
diff --git a/app/src/main/assets/keyboard_themes/default/key_at.png b/app/src/main/assets/keyboard_themes/default/key_at.png
new file mode 100644
index 0000000..00ca5ed
Binary files /dev/null and b/app/src/main/assets/keyboard_themes/default/key_at.png differ
diff --git a/app/src/main/assets/keyboard_themes/default/key_b.png b/app/src/main/assets/keyboard_themes/default/key_b.png
new file mode 100644
index 0000000..ef6e890
Binary files /dev/null and b/app/src/main/assets/keyboard_themes/default/key_b.png differ
diff --git a/app/src/main/assets/keyboard_themes/default/key_b_up.png b/app/src/main/assets/keyboard_themes/default/key_b_up.png
new file mode 100644
index 0000000..bd5a787
Binary files /dev/null and b/app/src/main/assets/keyboard_themes/default/key_b_up.png differ
diff --git a/app/src/main/assets/keyboard_themes/default/key_backslash.png b/app/src/main/assets/keyboard_themes/default/key_backslash.png
new file mode 100644
index 0000000..aa8563c
Binary files /dev/null and b/app/src/main/assets/keyboard_themes/default/key_backslash.png differ
diff --git a/app/src/main/assets/keyboard_themes/default/key_backspace.png b/app/src/main/assets/keyboard_themes/default/key_backspace.png
new file mode 100644
index 0000000..129f1af
Binary files /dev/null and b/app/src/main/assets/keyboard_themes/default/key_backspace.png differ
diff --git a/app/src/main/assets/keyboard_themes/default/key_brace_l.png b/app/src/main/assets/keyboard_themes/default/key_brace_l.png
new file mode 100644
index 0000000..5c28b8a
Binary files /dev/null and b/app/src/main/assets/keyboard_themes/default/key_brace_l.png differ
diff --git a/app/src/main/assets/keyboard_themes/default/key_brace_r.png b/app/src/main/assets/keyboard_themes/default/key_brace_r.png
new file mode 100644
index 0000000..b1b2eb1
Binary files /dev/null and b/app/src/main/assets/keyboard_themes/default/key_brace_r.png differ
diff --git a/app/src/main/assets/keyboard_themes/default/key_bracket_l.png b/app/src/main/assets/keyboard_themes/default/key_bracket_l.png
new file mode 100644
index 0000000..1ec5367
Binary files /dev/null and b/app/src/main/assets/keyboard_themes/default/key_bracket_l.png differ
diff --git a/app/src/main/assets/keyboard_themes/default/key_bracket_r.png b/app/src/main/assets/keyboard_themes/default/key_bracket_r.png
new file mode 100644
index 0000000..300523d
Binary files /dev/null and b/app/src/main/assets/keyboard_themes/default/key_bracket_r.png differ
diff --git a/app/src/main/assets/keyboard_themes/default/key_bullet.png b/app/src/main/assets/keyboard_themes/default/key_bullet.png
new file mode 100644
index 0000000..3ac5c87
Binary files /dev/null and b/app/src/main/assets/keyboard_themes/default/key_bullet.png differ
diff --git a/app/src/main/assets/keyboard_themes/default/key_c.png b/app/src/main/assets/keyboard_themes/default/key_c.png
new file mode 100644
index 0000000..63fe12c
Binary files /dev/null and b/app/src/main/assets/keyboard_themes/default/key_c.png differ
diff --git a/app/src/main/assets/keyboard_themes/default/key_c_up.png b/app/src/main/assets/keyboard_themes/default/key_c_up.png
new file mode 100644
index 0000000..d823d4f
Binary files /dev/null and b/app/src/main/assets/keyboard_themes/default/key_c_up.png differ
diff --git a/app/src/main/assets/keyboard_themes/default/key_caret.png b/app/src/main/assets/keyboard_themes/default/key_caret.png
new file mode 100644
index 0000000..073533a
Binary files /dev/null and b/app/src/main/assets/keyboard_themes/default/key_caret.png differ
diff --git a/app/src/main/assets/keyboard_themes/default/key_colon.png b/app/src/main/assets/keyboard_themes/default/key_colon.png
new file mode 100644
index 0000000..83069a9
Binary files /dev/null and b/app/src/main/assets/keyboard_themes/default/key_colon.png differ
diff --git a/app/src/main/assets/keyboard_themes/default/key_comma.png b/app/src/main/assets/keyboard_themes/default/key_comma.png
new file mode 100644
index 0000000..641c7d6
Binary files /dev/null and b/app/src/main/assets/keyboard_themes/default/key_comma.png differ
diff --git a/app/src/main/assets/keyboard_themes/default/key_d.png b/app/src/main/assets/keyboard_themes/default/key_d.png
new file mode 100644
index 0000000..ec4aac5
Binary files /dev/null and b/app/src/main/assets/keyboard_themes/default/key_d.png differ
diff --git a/app/src/main/assets/keyboard_themes/default/key_d_up.png b/app/src/main/assets/keyboard_themes/default/key_d_up.png
new file mode 100644
index 0000000..79188a0
Binary files /dev/null and b/app/src/main/assets/keyboard_themes/default/key_d_up.png differ
diff --git a/app/src/main/assets/keyboard_themes/default/key_del.png b/app/src/main/assets/keyboard_themes/default/key_del.png
new file mode 100644
index 0000000..129f1af
Binary files /dev/null and b/app/src/main/assets/keyboard_themes/default/key_del.png differ
diff --git a/app/src/main/assets/keyboard_themes/default/key_dollar.png b/app/src/main/assets/keyboard_themes/default/key_dollar.png
new file mode 100644
index 0000000..f1ae8b9
Binary files /dev/null and b/app/src/main/assets/keyboard_themes/default/key_dollar.png differ
diff --git a/app/src/main/assets/keyboard_themes/default/key_dot.png b/app/src/main/assets/keyboard_themes/default/key_dot.png
new file mode 100644
index 0000000..adb7bd2
Binary files /dev/null and b/app/src/main/assets/keyboard_themes/default/key_dot.png differ
diff --git a/app/src/main/assets/keyboard_themes/default/key_e.png b/app/src/main/assets/keyboard_themes/default/key_e.png
new file mode 100644
index 0000000..1266671
Binary files /dev/null and b/app/src/main/assets/keyboard_themes/default/key_e.png differ
diff --git a/app/src/main/assets/keyboard_themes/default/key_e_up.png b/app/src/main/assets/keyboard_themes/default/key_e_up.png
new file mode 100644
index 0000000..b7ea305
Binary files /dev/null and b/app/src/main/assets/keyboard_themes/default/key_e_up.png differ
diff --git a/app/src/main/assets/keyboard_themes/default/key_equal.png b/app/src/main/assets/keyboard_themes/default/key_equal.png
new file mode 100644
index 0000000..a6df242
Binary files /dev/null and b/app/src/main/assets/keyboard_themes/default/key_equal.png differ
diff --git a/app/src/main/assets/keyboard_themes/default/key_euro.png b/app/src/main/assets/keyboard_themes/default/key_euro.png
new file mode 100644
index 0000000..dd2a727
Binary files /dev/null and b/app/src/main/assets/keyboard_themes/default/key_euro.png differ
diff --git a/app/src/main/assets/keyboard_themes/default/key_exclam.png b/app/src/main/assets/keyboard_themes/default/key_exclam.png
new file mode 100644
index 0000000..9b13fe9
Binary files /dev/null and b/app/src/main/assets/keyboard_themes/default/key_exclam.png differ
diff --git a/app/src/main/assets/keyboard_themes/default/key_f.png b/app/src/main/assets/keyboard_themes/default/key_f.png
new file mode 100644
index 0000000..bb41a4b
Binary files /dev/null and b/app/src/main/assets/keyboard_themes/default/key_f.png differ
diff --git a/app/src/main/assets/keyboard_themes/default/key_f_up.png b/app/src/main/assets/keyboard_themes/default/key_f_up.png
new file mode 100644
index 0000000..613b05c
Binary files /dev/null and b/app/src/main/assets/keyboard_themes/default/key_f_up.png differ
diff --git a/app/src/main/assets/keyboard_themes/default/key_g.png b/app/src/main/assets/keyboard_themes/default/key_g.png
new file mode 100644
index 0000000..1e2023b
Binary files /dev/null and b/app/src/main/assets/keyboard_themes/default/key_g.png differ
diff --git a/app/src/main/assets/keyboard_themes/default/key_g_up.png b/app/src/main/assets/keyboard_themes/default/key_g_up.png
new file mode 100644
index 0000000..3885062
Binary files /dev/null and b/app/src/main/assets/keyboard_themes/default/key_g_up.png differ
diff --git a/app/src/main/assets/keyboard_themes/default/key_gt.png b/app/src/main/assets/keyboard_themes/default/key_gt.png
new file mode 100644
index 0000000..6aab0fb
Binary files /dev/null and b/app/src/main/assets/keyboard_themes/default/key_gt.png differ
diff --git a/app/src/main/assets/keyboard_themes/default/key_h.png b/app/src/main/assets/keyboard_themes/default/key_h.png
new file mode 100644
index 0000000..97cc234
Binary files /dev/null and b/app/src/main/assets/keyboard_themes/default/key_h.png differ
diff --git a/app/src/main/assets/keyboard_themes/default/key_h_up.png b/app/src/main/assets/keyboard_themes/default/key_h_up.png
new file mode 100644
index 0000000..169b11c
Binary files /dev/null and b/app/src/main/assets/keyboard_themes/default/key_h_up.png differ
diff --git a/app/src/main/assets/keyboard_themes/default/key_hash.png b/app/src/main/assets/keyboard_themes/default/key_hash.png
new file mode 100644
index 0000000..2dc2f72
Binary files /dev/null and b/app/src/main/assets/keyboard_themes/default/key_hash.png differ
diff --git a/app/src/main/assets/keyboard_themes/default/key_i.png b/app/src/main/assets/keyboard_themes/default/key_i.png
new file mode 100644
index 0000000..77cded8
Binary files /dev/null and b/app/src/main/assets/keyboard_themes/default/key_i.png differ
diff --git a/app/src/main/assets/keyboard_themes/default/key_i_up.png b/app/src/main/assets/keyboard_themes/default/key_i_up.png
new file mode 100644
index 0000000..c44dd63
Binary files /dev/null and b/app/src/main/assets/keyboard_themes/default/key_i_up.png differ
diff --git a/app/src/main/assets/keyboard_themes/default/key_j.png b/app/src/main/assets/keyboard_themes/default/key_j.png
new file mode 100644
index 0000000..cf66ae5
Binary files /dev/null and b/app/src/main/assets/keyboard_themes/default/key_j.png differ
diff --git a/app/src/main/assets/keyboard_themes/default/key_j_up.png b/app/src/main/assets/keyboard_themes/default/key_j_up.png
new file mode 100644
index 0000000..15221e9
Binary files /dev/null and b/app/src/main/assets/keyboard_themes/default/key_j_up.png differ
diff --git a/app/src/main/assets/keyboard_themes/default/key_k.png b/app/src/main/assets/keyboard_themes/default/key_k.png
new file mode 100644
index 0000000..4c802e8
Binary files /dev/null and b/app/src/main/assets/keyboard_themes/default/key_k.png differ
diff --git a/app/src/main/assets/keyboard_themes/default/key_k_up.png b/app/src/main/assets/keyboard_themes/default/key_k_up.png
new file mode 100644
index 0000000..18b5ef2
Binary files /dev/null and b/app/src/main/assets/keyboard_themes/default/key_k_up.png differ
diff --git a/app/src/main/assets/keyboard_themes/default/key_l.png b/app/src/main/assets/keyboard_themes/default/key_l.png
new file mode 100644
index 0000000..3da5812
Binary files /dev/null and b/app/src/main/assets/keyboard_themes/default/key_l.png differ
diff --git a/app/src/main/assets/keyboard_themes/default/key_l_up.png b/app/src/main/assets/keyboard_themes/default/key_l_up.png
new file mode 100644
index 0000000..48d11fe
Binary files /dev/null and b/app/src/main/assets/keyboard_themes/default/key_l_up.png differ
diff --git a/app/src/main/assets/keyboard_themes/default/key_lt.png b/app/src/main/assets/keyboard_themes/default/key_lt.png
new file mode 100644
index 0000000..8094090
Binary files /dev/null and b/app/src/main/assets/keyboard_themes/default/key_lt.png differ
diff --git a/app/src/main/assets/keyboard_themes/default/key_m.png b/app/src/main/assets/keyboard_themes/default/key_m.png
new file mode 100644
index 0000000..6b5af2c
Binary files /dev/null and b/app/src/main/assets/keyboard_themes/default/key_m.png differ
diff --git a/app/src/main/assets/keyboard_themes/default/key_m_up.png b/app/src/main/assets/keyboard_themes/default/key_m_up.png
new file mode 100644
index 0000000..b84d37c
Binary files /dev/null and b/app/src/main/assets/keyboard_themes/default/key_m_up.png differ
diff --git a/app/src/main/assets/keyboard_themes/default/key_minus.png b/app/src/main/assets/keyboard_themes/default/key_minus.png
new file mode 100644
index 0000000..c1912a3
Binary files /dev/null and b/app/src/main/assets/keyboard_themes/default/key_minus.png differ
diff --git a/app/src/main/assets/keyboard_themes/default/key_money.png b/app/src/main/assets/keyboard_themes/default/key_money.png
new file mode 100644
index 0000000..42220fe
Binary files /dev/null and b/app/src/main/assets/keyboard_themes/default/key_money.png differ
diff --git a/app/src/main/assets/keyboard_themes/default/key_n.png b/app/src/main/assets/keyboard_themes/default/key_n.png
new file mode 100644
index 0000000..dab1f87
Binary files /dev/null and b/app/src/main/assets/keyboard_themes/default/key_n.png differ
diff --git a/app/src/main/assets/keyboard_themes/default/key_n_up.png b/app/src/main/assets/keyboard_themes/default/key_n_up.png
new file mode 100644
index 0000000..1d88286
Binary files /dev/null and b/app/src/main/assets/keyboard_themes/default/key_n_up.png differ
diff --git a/app/src/main/assets/keyboard_themes/default/key_o.png b/app/src/main/assets/keyboard_themes/default/key_o.png
new file mode 100644
index 0000000..23cf2b9
Binary files /dev/null and b/app/src/main/assets/keyboard_themes/default/key_o.png differ
diff --git a/app/src/main/assets/keyboard_themes/default/key_o_up.png b/app/src/main/assets/keyboard_themes/default/key_o_up.png
new file mode 100644
index 0000000..c3231f9
Binary files /dev/null and b/app/src/main/assets/keyboard_themes/default/key_o_up.png differ
diff --git a/app/src/main/assets/keyboard_themes/default/key_p.png b/app/src/main/assets/keyboard_themes/default/key_p.png
new file mode 100644
index 0000000..e93161b
Binary files /dev/null and b/app/src/main/assets/keyboard_themes/default/key_p.png differ
diff --git a/app/src/main/assets/keyboard_themes/default/key_p_up.png b/app/src/main/assets/keyboard_themes/default/key_p_up.png
new file mode 100644
index 0000000..70194e2
Binary files /dev/null and b/app/src/main/assets/keyboard_themes/default/key_p_up.png differ
diff --git a/app/src/main/assets/keyboard_themes/default/key_paren_l.png b/app/src/main/assets/keyboard_themes/default/key_paren_l.png
new file mode 100644
index 0000000..36f3555
Binary files /dev/null and b/app/src/main/assets/keyboard_themes/default/key_paren_l.png differ
diff --git a/app/src/main/assets/keyboard_themes/default/key_paren_r.png b/app/src/main/assets/keyboard_themes/default/key_paren_r.png
new file mode 100644
index 0000000..6ce9365
Binary files /dev/null and b/app/src/main/assets/keyboard_themes/default/key_paren_r.png differ
diff --git a/app/src/main/assets/keyboard_themes/default/key_percent.png b/app/src/main/assets/keyboard_themes/default/key_percent.png
new file mode 100644
index 0000000..a7943e2
Binary files /dev/null and b/app/src/main/assets/keyboard_themes/default/key_percent.png differ
diff --git a/app/src/main/assets/keyboard_themes/default/key_pipe.png b/app/src/main/assets/keyboard_themes/default/key_pipe.png
new file mode 100644
index 0000000..7025885
Binary files /dev/null and b/app/src/main/assets/keyboard_themes/default/key_pipe.png differ
diff --git a/app/src/main/assets/keyboard_themes/default/key_plus.png b/app/src/main/assets/keyboard_themes/default/key_plus.png
new file mode 100644
index 0000000..4257687
Binary files /dev/null and b/app/src/main/assets/keyboard_themes/default/key_plus.png differ
diff --git a/app/src/main/assets/keyboard_themes/default/key_pound.png b/app/src/main/assets/keyboard_themes/default/key_pound.png
new file mode 100644
index 0000000..9218ec7
Binary files /dev/null and b/app/src/main/assets/keyboard_themes/default/key_pound.png differ
diff --git a/app/src/main/assets/keyboard_themes/default/key_q.png b/app/src/main/assets/keyboard_themes/default/key_q.png
new file mode 100644
index 0000000..f19cf50
Binary files /dev/null and b/app/src/main/assets/keyboard_themes/default/key_q.png differ
diff --git a/app/src/main/assets/keyboard_themes/default/key_q_up.png b/app/src/main/assets/keyboard_themes/default/key_q_up.png
new file mode 100644
index 0000000..5d4df5a
Binary files /dev/null and b/app/src/main/assets/keyboard_themes/default/key_q_up.png differ
diff --git a/app/src/main/assets/keyboard_themes/default/key_question.png b/app/src/main/assets/keyboard_themes/default/key_question.png
new file mode 100644
index 0000000..bd2de25
Binary files /dev/null and b/app/src/main/assets/keyboard_themes/default/key_question.png differ
diff --git a/app/src/main/assets/keyboard_themes/default/key_quote.png b/app/src/main/assets/keyboard_themes/default/key_quote.png
new file mode 100644
index 0000000..9812639
Binary files /dev/null and b/app/src/main/assets/keyboard_themes/default/key_quote.png differ
diff --git a/app/src/main/assets/keyboard_themes/default/key_quote_d.png b/app/src/main/assets/keyboard_themes/default/key_quote_d.png
new file mode 100644
index 0000000..ad314c5
Binary files /dev/null and b/app/src/main/assets/keyboard_themes/default/key_quote_d.png differ
diff --git a/app/src/main/assets/keyboard_themes/default/key_r.png b/app/src/main/assets/keyboard_themes/default/key_r.png
new file mode 100644
index 0000000..17eabf6
Binary files /dev/null and b/app/src/main/assets/keyboard_themes/default/key_r.png differ
diff --git a/app/src/main/assets/keyboard_themes/default/key_r_up.png b/app/src/main/assets/keyboard_themes/default/key_r_up.png
new file mode 100644
index 0000000..8566458
Binary files /dev/null and b/app/src/main/assets/keyboard_themes/default/key_r_up.png differ
diff --git a/app/src/main/assets/keyboard_themes/default/key_s.png b/app/src/main/assets/keyboard_themes/default/key_s.png
new file mode 100644
index 0000000..d585210
Binary files /dev/null and b/app/src/main/assets/keyboard_themes/default/key_s.png differ
diff --git a/app/src/main/assets/keyboard_themes/default/key_s_up.png b/app/src/main/assets/keyboard_themes/default/key_s_up.png
new file mode 100644
index 0000000..96f8e59
Binary files /dev/null and b/app/src/main/assets/keyboard_themes/default/key_s_up.png differ
diff --git a/app/src/main/assets/keyboard_themes/default/key_semicolon.png b/app/src/main/assets/keyboard_themes/default/key_semicolon.png
new file mode 100644
index 0000000..d154544
Binary files /dev/null and b/app/src/main/assets/keyboard_themes/default/key_semicolon.png differ
diff --git a/app/src/main/assets/keyboard_themes/default/key_send.png b/app/src/main/assets/keyboard_themes/default/key_send.png
new file mode 100644
index 0000000..f15aae1
Binary files /dev/null and b/app/src/main/assets/keyboard_themes/default/key_send.png differ
diff --git a/app/src/main/assets/keyboard_themes/default/key_slash.png b/app/src/main/assets/keyboard_themes/default/key_slash.png
new file mode 100644
index 0000000..8f28257
Binary files /dev/null and b/app/src/main/assets/keyboard_themes/default/key_slash.png differ
diff --git a/app/src/main/assets/keyboard_themes/default/key_space.png b/app/src/main/assets/keyboard_themes/default/key_space.png
new file mode 100644
index 0000000..4db597c
Binary files /dev/null and b/app/src/main/assets/keyboard_themes/default/key_space.png differ
diff --git a/app/src/main/assets/keyboard_themes/default/key_symbols_123.png b/app/src/main/assets/keyboard_themes/default/key_symbols_123.png
new file mode 100644
index 0000000..e2e9a5b
Binary files /dev/null and b/app/src/main/assets/keyboard_themes/default/key_symbols_123.png differ
diff --git a/app/src/main/assets/keyboard_themes/default/key_symbols_more.png b/app/src/main/assets/keyboard_themes/default/key_symbols_more.png
new file mode 100644
index 0000000..a5b40cd
Binary files /dev/null and b/app/src/main/assets/keyboard_themes/default/key_symbols_more.png differ
diff --git a/app/src/main/assets/keyboard_themes/default/key_t.png b/app/src/main/assets/keyboard_themes/default/key_t.png
new file mode 100644
index 0000000..f94a079
Binary files /dev/null and b/app/src/main/assets/keyboard_themes/default/key_t.png differ
diff --git a/app/src/main/assets/keyboard_themes/default/key_t_up.png b/app/src/main/assets/keyboard_themes/default/key_t_up.png
new file mode 100644
index 0000000..1bfba2a
Binary files /dev/null and b/app/src/main/assets/keyboard_themes/default/key_t_up.png differ
diff --git a/app/src/main/assets/keyboard_themes/default/key_tilde.png b/app/src/main/assets/keyboard_themes/default/key_tilde.png
new file mode 100644
index 0000000..de61625
Binary files /dev/null and b/app/src/main/assets/keyboard_themes/default/key_tilde.png differ
diff --git a/app/src/main/assets/keyboard_themes/default/key_u.png b/app/src/main/assets/keyboard_themes/default/key_u.png
new file mode 100644
index 0000000..dc06718
Binary files /dev/null and b/app/src/main/assets/keyboard_themes/default/key_u.png differ
diff --git a/app/src/main/assets/keyboard_themes/default/key_u_up.png b/app/src/main/assets/keyboard_themes/default/key_u_up.png
new file mode 100644
index 0000000..1d2ba3c
Binary files /dev/null and b/app/src/main/assets/keyboard_themes/default/key_u_up.png differ
diff --git a/app/src/main/assets/keyboard_themes/default/key_underscore.png b/app/src/main/assets/keyboard_themes/default/key_underscore.png
new file mode 100644
index 0000000..b88b39d
Binary files /dev/null and b/app/src/main/assets/keyboard_themes/default/key_underscore.png differ
diff --git a/app/src/main/assets/keyboard_themes/default/key_up.png b/app/src/main/assets/keyboard_themes/default/key_up.png
new file mode 100644
index 0000000..9b825cd
Binary files /dev/null and b/app/src/main/assets/keyboard_themes/default/key_up.png differ
diff --git a/app/src/main/assets/keyboard_themes/default/key_up_upper.png b/app/src/main/assets/keyboard_themes/default/key_up_upper.png
new file mode 100644
index 0000000..52cd704
Binary files /dev/null and b/app/src/main/assets/keyboard_themes/default/key_up_upper.png differ
diff --git a/app/src/main/assets/keyboard_themes/default/key_v.png b/app/src/main/assets/keyboard_themes/default/key_v.png
new file mode 100644
index 0000000..b6dba48
Binary files /dev/null and b/app/src/main/assets/keyboard_themes/default/key_v.png differ
diff --git a/app/src/main/assets/keyboard_themes/default/key_v_up.png b/app/src/main/assets/keyboard_themes/default/key_v_up.png
new file mode 100644
index 0000000..a3026fa
Binary files /dev/null and b/app/src/main/assets/keyboard_themes/default/key_v_up.png differ
diff --git a/app/src/main/assets/keyboard_themes/default/key_w.png b/app/src/main/assets/keyboard_themes/default/key_w.png
new file mode 100644
index 0000000..ca77d4e
Binary files /dev/null and b/app/src/main/assets/keyboard_themes/default/key_w.png differ
diff --git a/app/src/main/assets/keyboard_themes/default/key_w_up.png b/app/src/main/assets/keyboard_themes/default/key_w_up.png
new file mode 100644
index 0000000..2f37d3b
Binary files /dev/null and b/app/src/main/assets/keyboard_themes/default/key_w_up.png differ
diff --git a/app/src/main/assets/keyboard_themes/default/key_x.png b/app/src/main/assets/keyboard_themes/default/key_x.png
new file mode 100644
index 0000000..baf8eec
Binary files /dev/null and b/app/src/main/assets/keyboard_themes/default/key_x.png differ
diff --git a/app/src/main/assets/keyboard_themes/default/key_x_up.png b/app/src/main/assets/keyboard_themes/default/key_x_up.png
new file mode 100644
index 0000000..72d9946
Binary files /dev/null and b/app/src/main/assets/keyboard_themes/default/key_x_up.png differ
diff --git a/app/src/main/assets/keyboard_themes/default/key_y.png b/app/src/main/assets/keyboard_themes/default/key_y.png
new file mode 100644
index 0000000..3033c75
Binary files /dev/null and b/app/src/main/assets/keyboard_themes/default/key_y.png differ
diff --git a/app/src/main/assets/keyboard_themes/default/key_y_up.png b/app/src/main/assets/keyboard_themes/default/key_y_up.png
new file mode 100644
index 0000000..09bd13c
Binary files /dev/null and b/app/src/main/assets/keyboard_themes/default/key_y_up.png differ
diff --git a/app/src/main/assets/keyboard_themes/default/key_z.png b/app/src/main/assets/keyboard_themes/default/key_z.png
new file mode 100644
index 0000000..e757c11
Binary files /dev/null and b/app/src/main/assets/keyboard_themes/default/key_z.png differ
diff --git a/app/src/main/assets/keyboard_themes/default/key_z_up.png b/app/src/main/assets/keyboard_themes/default/key_z_up.png
new file mode 100644
index 0000000..ae0b2b0
Binary files /dev/null and b/app/src/main/assets/keyboard_themes/default/key_z_up.png differ
diff --git a/app/src/main/java/com/example/myapplication/MyInputMethodService.kt b/app/src/main/java/com/example/myapplication/MyInputMethodService.kt
index 2a3bf59..1999beb 100644
--- a/app/src/main/java/com/example/myapplication/MyInputMethodService.kt
+++ b/app/src/main/java/com/example/myapplication/MyInputMethodService.kt
@@ -29,6 +29,10 @@ import com.example.myapplication.data.WordDictionary
import com.example.myapplication.data.LanguageModelLoader
import com.example.myapplication.SuggestionStats
import android.widget.HorizontalScrollView
+import com.example.myapplication.theme.ThemeManager
+import android.util.TypedValue
+import android.graphics.Bitmap
+import android.graphics.drawable.BitmapDrawable
class MyInputMethodService : InputMethodService() {
private var lastWordForLM: String? = null // 上一次输入的词
@@ -109,7 +113,7 @@ class MyInputMethodService : InputMethodService() {
private val keyStrokeWidthDp = 1 // 键的描边宽度
- private val keyMarginDp = 2 // 键的外边距
+ private val keyMarginDp = 1 // 键的外边距
private val keyPaddingHorizontalDp = 6 // 键的水平内边距
@@ -134,6 +138,9 @@ class MyInputMethodService : InputMethodService() {
override fun onCreate() {
super.onCreate()
+ ThemeManager.ensureBuiltInThemesInstalled(this) // 如果你用了内置 assets 方案
+ ThemeManager.init(this)
+
Thread {
// 1) Trie 词典
try {
@@ -227,11 +234,11 @@ class MyInputMethodService : InputMethodService() {
updateKeyLabels(view)
- // 默认应用:文字黑色 + 边框默认色 + 背景透明,并写入缓存
- setKeyTextColorInt(Color.BLACK)
-
- setKeyBorderColorInt(Color.parseColor("#1A000000"))
+ // // 默认应用:文字黑色 + 边框默认色 + 背景透明,并写入缓存
+ // setKeyTextColorInt(Color.BLACK)
+ // setKeyBorderColorInt(Color.parseColor("#1A000000"))
+ applyPerKeyBackgroundForMainKeyboard(view)
setKeyBackgroundColorInt(Color.TRANSPARENT) // 白底为 Color.WHITE
// 每次创建后立即把样式应用到所有键
@@ -242,6 +249,219 @@ class MyInputMethodService : InputMethodService() {
return view
}
+ /**
+ * 根据 viewIdName(例如 "key_w")给某个键设置背景图片。
+ * 默认情况:drawable 名 = viewIdName,例如 "key_w" -> R.drawable.key_w
+ * 如果传了 drawableName,比如 "key_w_up",就用那个。
+ */
+ private fun applyKeyBackground(
+ root: View,
+ viewIdName: String,
+ drawableName: String? = null
+ ) {
+ // 1. 找到这个 view
+ val viewId = resources.getIdentifier(viewIdName, "id", packageName)
+ if (viewId == 0) return
+
+ val v = root.findViewById(viewId) ?: return
+
+ // 2. 目标资源名(key_xxx)
+ val keyName = drawableName ?: viewIdName
+ val rawDrawable = ThemeManager.getDrawableForKey(this, keyName) ?: return
+
+ // ⚠️ 特殊:若是 background,就要等比缩放到高度=243dp
+ if (viewIdName == "background") {
+ val scaled = scaleDrawableToHeight(rawDrawable, 243f)
+ v.background = scaled
+ return
+ }
+
+ // 普通按键直接用
+ v.background = rawDrawable
+ }
+ // 缩放 Drawable 到指定高度
+ private fun scaleDrawableToHeight(src: Drawable, targetDp: Float): Drawable {
+ val dm = resources.displayMetrics
+ val targetHeightPx = TypedValue.applyDimension(
+ TypedValue.COMPLEX_UNIT_DIP,
+ targetDp,
+ dm
+ ).toInt()
+
+ // 尝试取 bitmap
+ val bitmap = (src as? BitmapDrawable)?.bitmap ?: return src
+
+ // 原图宽高
+ val w = bitmap.width
+ val h = bitmap.height
+
+ // 计算缩放比例(高度缩到 243dp)
+ val ratio = targetHeightPx.toFloat() / h
+
+ val targetWidthPx = (w * ratio).toInt()
+
+ // 缩放 bitmap
+ val scaledBitmap = Bitmap.createScaledBitmap(
+ bitmap,
+ targetWidthPx,
+ targetHeightPx,
+ true
+ )
+
+ // 返回新的 drawable
+ return BitmapDrawable(resources, scaledBitmap).apply {
+ setBounds(0, 0, targetWidthPx, targetHeightPx)
+ }
+ }
+
+
+ // 主键盘所有按键的背景图片
+ private fun applyPerKeyBackgroundForMainKeyboard(root: View) {
+ // a..z 小写默认背景:key_a, key_b, ...
+ for (c in 'a'..'z') {
+ val idName = "key_$c"
+ applyKeyBackground(root, idName) // 对应 drawable: key_a, key_b, ...
+ }
+
+ val idName = "background"
+ applyKeyBackground(root, idName)
+
+ // 键盘背景:drawable = "keyboard_root"
+ // 其他功能键/特殊键,直接用同名 drawable
+ val others = listOf(
+ "key_space",
+ "key_send",
+ "key_del",
+ "key_up", // 如果布局里是 key_up,就改成那个
+ "key_123", // 切到数字键盘
+ "key_ai" // AI 键盘
+ )
+
+ others.forEach { idName ->
+ applyKeyBackground(root, idName)
+ }
+ }
+ // 数字键盘所有按键的背景图片
+ private fun applyPerKeyBackgroundForNumberKeyboard(root: View) {
+ // 0..9
+ for (i in 0..9) {
+ val idName = "key_$i" // id: key_0 ... key_9
+ applyKeyBackground(root, idName) // drawable: key_0 ... key_9
+ }
+
+ val idName = "background"
+ applyKeyBackground(root, idName)
+
+ // 你在数字层定义的符号键
+ val symbolKeys = listOf(
+ "key_comma",
+ "key_dot",
+ "key_minus",
+ "key_slash",
+ "key_colon",
+ "key_semicolon",
+ "key_paren_l",
+ "key_paren_r",
+ "key_dollar",
+ "key_amp",
+ "key_at",
+ "key_question",
+ "key_exclam",
+ "key_quote",
+ "key_quote_d"
+ )
+
+ symbolKeys.forEach { idName ->
+ applyKeyBackground(root, idName)
+ }
+
+ // 功能键
+ val others = listOf(
+ "key_symbols_more", // 切符号层
+ "key_abc", // 回主键盘
+ "key_ai",
+ "key_space",
+ "key_send",
+ "key_del"
+ )
+
+ others.forEach { idName ->
+ applyKeyBackground(root, idName)
+ }
+ }
+ //符号键盘所有按键的背景图片
+ private fun applyPerKeyBackgroundForSymbolKeyboard(root: View) {
+ val symbolKeys = listOf(
+ // 第一行
+ "key_bracket_l",
+ "key_bracket_r",
+ "key_brace_l",
+ "key_brace_r",
+ "key_hash",
+ "key_percent",
+ "key_caret",
+ "key_asterisk",
+ "key_plus",
+ "key_equal",
+
+ // 第二行
+ "key_underscore",
+ "key_backslash",
+ "key_pipe",
+ "key_tilde",
+ "key_lt",
+ "key_gt",
+ "key_euro",
+ "key_pound",
+ "key_money",
+ "key_bullet",
+
+ // 第三行
+ "key_dot",
+ "key_comma",
+ "key_question",
+ "key_exclam",
+ "key_quote"
+ )
+
+ symbolKeys.forEach { idName ->
+ applyKeyBackground(root, idName)
+ }
+
+ val idName = "background"
+ applyKeyBackground(root, idName)
+
+ val others = listOf(
+ "key_symbols_123",
+ "key_backspace",
+ "key_abc",
+ "key_ai",
+ "key_space",
+ "key_send"
+ )
+
+ others.forEach { idName ->
+ applyKeyBackground(root, idName)
+ }
+ }
+ //大小写切换键的背景图片
+ private fun updateKeyBackgroundsForLetters(root: View) {
+ for (c in 'a'..'z') {
+ val idName = "key_$c"
+ // 小写:drawable = "key_a"
+ // 大写:drawable = "key_a_up"
+ val drawableName = if (isShiftOn) "${idName}_up" else idName
+ applyKeyBackground(root, idName, drawableName)
+ }
+ val upKeyIdName = "key_up"
+
+ // Shift 开:背景图 key_up_upper
+ // Shift 关:背景图 key_up
+ val upDrawableName = if (isShiftOn) "key_up_upper" else "key_up"
+
+ applyKeyBackground(root, upKeyIdName, upDrawableName)
+ }
+
// 确保了输入法在启动时能够正确显示主键盘
override fun onStartInputView(info: EditorInfo?, restarting: Boolean) {
@@ -294,9 +514,9 @@ class MyInputMethodService : InputMethodService() {
?.setOnClickListener { sendKey(' ') }
// shift
- var shiftId = resources.getIdentifier("key_shift","id",packageName)
+ var shiftId = resources.getIdentifier("key_up","id",packageName)
- if (shiftId==0) shiftId = resources.getIdentifier("key_Shift","id",packageName)
+ if (shiftId==0) shiftId = resources.getIdentifier("key_up","id",packageName)
keyboardView.findViewById(shiftId)?.setOnClickListener { v ->
toggleShift()
@@ -307,18 +527,18 @@ class MyInputMethodService : InputMethodService() {
}
//点击一次删除,长按连删
- keyboardView.findViewById(resources.getIdentifier("key_backspace","id",packageName))?.let { v ->
+ keyboardView.findViewById(resources.getIdentifier("key_del","id",packageName))?.let { v ->
v.setOnClickListener { handleBackspace() }
attachRepeatDelete(v)
}
//跳数字键盘
- keyboardView.findViewById(resources.getIdentifier("key_number","id",packageName))
+ keyboardView.findViewById(resources.getIdentifier("key_123","id",packageName))
?.setOnClickListener { showNumberKeyboard() }
//跳AI 键盘
- keyboardView.findViewById(resources.getIdentifier("key_Ai","id",packageName))
+ keyboardView.findViewById(resources.getIdentifier("key_ai","id",packageName))
?.setOnClickListener { showAiKeyboard() }
// 发送
@@ -332,21 +552,21 @@ class MyInputMethodService : InputMethodService() {
val resId = resources.getIdentifier("number_keyboard","layout",packageName)
if (resId != 0) {
numberKeyboardView = layoutInflater.inflate(resId,null)
-
- // 首次创建:立即应用当前文字色、边框色与背景色
- applyTextColorToAllTextViews(numberKeyboardView, currentTextColor)
-
- applyBorderColorToAllKeys(numberKeyboardView, currentBorderColor)
+
+ numberKeyboardView?.let {
+ applyPerKeyBackgroundForNumberKeyboard(it)
+ applyTextColorToAllTextViews(it, currentTextColor)
+ applyBorderColorToAllKeys(it, currentBorderColor)
+ }
}
}
numberKeyboardView?.let {
currentKeyboardView = it
-
setupListenersForNumberView(it)
-
setInputView(it)
}
}
+
//数字键盘事件
private fun setupListenersForNumberView(numView: View) {
@@ -360,20 +580,20 @@ class MyInputMethodService : InputMethodService() {
// 符号键
val symbolMap: List> = listOf(
"key_comma" to ',',
- "key_period" to '.',
- "key_tilde" to '~',
+ "key_dot" to '.',
+ "key_minus" to '-',
"key_slash" to '/',
"key_colon" to ':',
"key_semicolon" to ';',
- "key_left_paren" to '(',
- "key_right_paren" to ')',
+ "key_paren_l" to '(',
+ "key_paren_r" to ')',
"key_dollar" to '$',
"key_amp" to '&',
"key_at" to '@',
"key_question" to '?',
- "key_exclaim" to '!',
- "key_quote_single" to '\'',
- "key_quote" to '”'
+ "key_exclam" to '!',
+ "key_quote" to '\'',
+ "key_quote_d" to '”'
)
symbolMap.forEach { (name, ch) ->
val id = resources.getIdentifier(name, "id", packageName)
@@ -382,13 +602,17 @@ class MyInputMethodService : InputMethodService() {
}
// 切换:符号层
- numView.findViewById(resources.getIdentifier("key_symbol_switch","id",packageName))
+ numView.findViewById(resources.getIdentifier("key_symbols_more","id",packageName))
?.setOnClickListener { showSymbolKeyboard() }
// 切回字母
- numView.findViewById(resources.getIdentifier("key_abc_switch","id",packageName))
+ numView.findViewById(resources.getIdentifier("key_abc","id",packageName))
?.setOnClickListener { switchToMainKeyboard() }
+ //跳AI 键盘
+ numView.findViewById(resources.getIdentifier("key_ai","id",packageName))
+ ?.setOnClickListener { showAiKeyboard() }
+
// 空格
numView.findViewById(resources.getIdentifier("key_space","id",packageName))
?.setOnClickListener { sendKey(' ') }
@@ -398,41 +622,41 @@ class MyInputMethodService : InputMethodService() {
?.setOnClickListener { performSendAction() }
//点击一次删除,长按连删
- numView.findViewById(resources.getIdentifier("key_backspace","id",packageName))?.let { v ->
+ numView.findViewById(resources.getIdentifier("key_del","id",packageName))?.let { v ->
v.setOnClickListener { handleBackspace() }
attachRepeatDelete(v)
}
}
//显示符号键盘
- private fun showSymbolKeyboard() {
+ private fun showSymbolKeyboard() {
if (symbolKeyboardView == null) {
val resId = resources.getIdentifier("symbol_keyboard","layout",packageName)
if (resId != 0) {
symbolKeyboardView = layoutInflater.inflate(resId,null)
- // 首次创建:立即应用当前文字色、边框色与背景色
- applyTextColorToAllTextViews(symbolKeyboardView, currentTextColor)
-
- applyBorderColorToAllKeys(symbolKeyboardView, currentBorderColor)
+ symbolKeyboardView?.let {
+ applyPerKeyBackgroundForSymbolKeyboard(it)
+ applyTextColorToAllTextViews(it, currentTextColor)
+ applyBorderColorToAllKeys(it, currentBorderColor)
+ }
}
}
symbolKeyboardView?.let {
currentKeyboardView = it
-
setupListenersForSymbolView(it)
-
setInputView(it)
}
}
+
//符号键盘事件
private fun setupListenersForSymbolView(symView: View) {
val pairs = listOf(
// 第一行
- "key_lbracket" to '[',
- "key_rbracket" to ']',
- "key_lbrace" to '{',
- "key_rbrace" to '}',
+ "key_bracket_l" to '[',
+ "key_bracket_r" to ']',
+ "key_brace_l" to '{',
+ "key_brace_r" to '}',
"key_hash" to '#',
"key_percent" to '%',
"key_caret" to '^',
@@ -449,15 +673,15 @@ class MyInputMethodService : InputMethodService() {
"key_gt" to '>',
"key_euro" to '€',
"key_pound" to '£',
- "key_yen" to '¥',
- "key_middot" to '·',
+ "key_money" to '¥',
+ "key_bullet" to '•',
// 第三行
- "key_period" to '.',
+ "key_dot" to '.',
"key_comma" to ',',
"key_question" to '?',
- "key_exclaim" to '!',
- "key_quote_single" to '\''
+ "key_exclam" to '!',
+ "key_quote" to '\''
)
pairs.forEach { (name, ch) ->
val id = resources.getIdentifier(name, "id", packageName)
@@ -466,11 +690,11 @@ class MyInputMethodService : InputMethodService() {
}
// 切换回数字
- symView.findViewById(resources.getIdentifier("key_123_switch","id",packageName))
+ symView.findViewById(resources.getIdentifier("key_symbols_123","id",packageName))
?.setOnClickListener { showNumberKeyboard() }
// 切回字母
- symView.findViewById(resources.getIdentifier("key_abc_switch","id",packageName))
+ symView.findViewById(resources.getIdentifier("key_abc","id",packageName))
?.setOnClickListener { switchToMainKeyboard() }
// 空格
@@ -486,6 +710,9 @@ class MyInputMethodService : InputMethodService() {
v.setOnClickListener { handleBackspace() }
attachRepeatDelete(v)
}
+ //跳AI 键盘
+ symView.findViewById(resources.getIdentifier("key_ai","id",packageName))
+ ?.setOnClickListener { showAiKeyboard() }
}
//显示AI 键盘
@@ -711,18 +938,19 @@ private fun insertCompletion(word: String) {
// 字母键大小写转换
private fun updateKeyLabels(view: View) {
- var shiftId = resources.getIdentifier("key_shift","id",packageName)
-
- if (shiftId==0) shiftId = resources.getIdentifier("key_Shift","id",packageName)
-
+ var shiftId = resources.getIdentifier("key_up","id",packageName)
+ if (shiftId==0) shiftId = resources.getIdentifier("key_up","id",packageName)
view.findViewById(shiftId)?.isActivated = isShiftOn
-
+
for (c in 'a'..'z') {
val id = resources.getIdentifier("key_$c","id",packageName)
-
- findTextViewSafe(view,id)?.text = if (isShiftOn) c.uppercaseChar().toString() else c.toString()
+ findTextViewSafe(view,id)?.text = ""
}
+
+ //同步切换字母键背景
+ updateKeyBackgroundsForLetters(view)
}
+
//简单的音效播放器
private fun playKeyClick() {
@@ -772,13 +1000,13 @@ private fun insertCompletion(word: String) {
//键盘背景图更换
fun setKeyboardBackground(@DrawableRes resId: Int) {
mainHandler.post {
- mainKeyboardView?.findViewById(R.id.keyboard_root)?.setBackgroundResource(resId)
+ mainKeyboardView?.findViewById(R.id.background)?.setBackgroundResource(resId)
- numberKeyboardView?.findViewById(R.id.keyboard_root)?.setBackgroundResource(resId)
+ numberKeyboardView?.findViewById(R.id.background)?.setBackgroundResource(resId)
- symbolKeyboardView?.findViewById(R.id.keyboard_root)?.setBackgroundResource(resId)
+ symbolKeyboardView?.findViewById(R.id.background)?.setBackgroundResource(resId)
- aiKeyboardView?.findViewById(R.id.keyboard_root)?.setBackgroundResource(resId)
+ aiKeyboardView?.findViewById(R.id.background)?.setBackgroundResource(resId)
}
}
@@ -854,113 +1082,54 @@ private fun insertCompletion(word: String) {
}
}
- //动态设置按键背景色
+ fun setKeyBackgroundColor(colorStateList: ColorStateList) {
+ currentBackgroundColor = colorStateList
+ }
+
fun setKeyBackgroundColorInt(@ColorInt colorInt: Int) {
setKeyBackgroundColor(ColorStateList.valueOf(colorInt))
}
- //动态设置按键背景色
- fun setKeyBackgroundColor(colorStateList: ColorStateList) {
- currentBackgroundColor = colorStateList
- mainHandler.post {
- // 复用同一个应用函数(会读取 currentBackgroundColor 一起生成背景)
- applyBorderColorToAllKeys(mainKeyboardView, currentBorderColor)
-
- applyBorderColorToAllKeys(numberKeyboardView, currentBorderColor)
-
- applyBorderColorToAllKeys(symbolKeyboardView, currentBorderColor)
-
- applyBorderColorToAllKeys(aiKeyboardView, currentBorderColor)
- }
- }
-
- //为根视图内所有 TextView 应用:圆角描边 + 背景色 + ripple + 统一外边距/内边距
+ // 为所有 TextView 只设置 margin/padding,不再统一设置背景
private fun applyBorderColorToAllKeys(root: View?, borderColor: ColorStateList) {
if (root == null) return
- val strokeWidthPx = keyStrokeWidthDp.dpToPx()
-
- val cornerRadiusPx = keyCornerRadiusDp.dpToPx().toFloat()
-
val marginPx = keyMarginDp.dpToPx()
-
val paddingH = keyPaddingHorizontalDp.dpToPx()
-
- // 忽略的按键 id(suggestion_1到suggestion_20)
- val ignoredIds = (0..20).map {
- resources.getIdentifier("suggestion_$it", "id", packageName)
+
+ // 忽略的按键 id(suggestion_1...)
+ val ignoredIds = (0..20).map {
+ resources.getIdentifier("suggestion_$it", "id", packageName)
}.toSet()
-
+
fun dfs(v: View?) {
when (v) {
is TextView -> {
- if (v.id in ignoredIds) {
- v.background = null // 或者 v.setBackgroundColor(Color.TRANSPARENT)
+ if (v.id in ignoredIds) {
+ v.background = null
return
}
-
- v.background = buildKeyBackground(
- borderColor = borderColor,
- fillColor = currentBackgroundColor,
- strokeWidthPx = strokeWidthPx,
- cornerRadiusPx = cornerRadiusPx
- )
-
+
+ // 只更新 margin
(v.layoutParams as? LinearLayout.LayoutParams)?.let { lp ->
- if (lp.leftMargin != marginPx || lp.topMargin != marginPx ||
- lp.rightMargin != marginPx || lp.bottomMargin != marginPx
- ) {
- lp.setMargins(marginPx, marginPx, marginPx, marginPx)
- v.layoutParams = lp
- }
- }
-
- if (v.paddingLeft < paddingH || v.paddingRight < paddingH) {
- v.setPadding(paddingH, v.paddingTop, paddingH, v.paddingBottom)
+ lp.setMargins(marginPx, marginPx, marginPx, marginPx)
+ v.layoutParams = lp
}
+
+ // 只更新 padding
+ v.setPadding(paddingH, v.paddingTop, paddingH, v.paddingBottom)
}
+
is ViewGroup -> for (i in 0 until v.childCount) dfs(v.getChildAt(i))
}
}
-
+
dfs(root)
}
- // 构造“圆角 + 可变描边 + 可变背景色 + ripple”的背景
- private fun buildKeyBackground(
- borderColor: ColorStateList,
- fillColor: ColorStateList,
- strokeWidthPx: Int,
- cornerRadiusPx: Float
- ): Drawable {
- val content = GradientDrawable().apply {
- shape = GradientDrawable.RECTANGLE
- cornerRadius = cornerRadiusPx
-
- setStroke(strokeWidthPx, borderColor)
-
- color = fillColor // 动态背景色
- }
-
- return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
- val rippleColor = ColorStateList.valueOf(Color.parseColor("#22000000")) // 涟漪色
-
- val mask = GradientDrawable().apply {
- shape = GradientDrawable.RECTANGLE
-
- cornerRadius = cornerRadiusPx
-
- setColor(Color.WHITE)
- }
-
- RippleDrawable(rippleColor, content, mask)
- } else {
- content
- }
- }
//工具:dp -> px
private fun Int.dpToPx(): Int {
diff --git a/app/src/main/java/com/example/myapplication/theme/ThemeManager.kt b/app/src/main/java/com/example/myapplication/theme/ThemeManager.kt
new file mode 100644
index 0000000..815c0f4
--- /dev/null
+++ b/app/src/main/java/com/example/myapplication/theme/ThemeManager.kt
@@ -0,0 +1,240 @@
+package com.example.myapplication.theme
+
+import android.content.Context
+import android.content.res.AssetManager
+import android.graphics.BitmapFactory
+import android.graphics.drawable.BitmapDrawable
+import android.graphics.drawable.Drawable
+import java.io.File
+object ThemeManager {
+
+ // SharedPreferences 保存当前主题名
+ private const val PREF_NAME = "ime_theme_prefs"
+ private const val KEY_CURRENT_THEME = "current_theme"
+
+ // 当前主题名(如 "default")
+ @Volatile
+ private var currentThemeName: String? = null
+
+ // 缓存:规范化后的 keyName(lowercase) -> Drawable
+ @Volatile
+ private var drawableCache: MutableMap = mutableMapOf()
+
+ // ==================== 外部目录相关 ====================
+
+ /** 主题根目录:/Android/data//files/keyboard_themes */
+ private fun getThemeRootDir(context: Context): File =
+ File(context.getExternalFilesDir(null), "keyboard_themes")
+
+ /** 某个具体主题目录:/Android/.../keyboard_themes/ */
+ private fun getThemeDir(context: Context, themeName: String): File =
+ File(getThemeRootDir(context), themeName)
+
+ // ==================== 内置主题拷贝(assets -> 外部目录) ====================
+
+ /**
+ * 确保 APK 自带的主题(assets/keyboard_themes/...) 已经复制到
+ * /Android/data/.../files/keyboard_themes 目录下。
+ *
+ * 行为:
+ * - 如果主题目录不存在:整套拷贝过去。
+ * - 如果主题目录已经存在:只复制“新增文件”,不会覆盖已有文件。
+ *
+ * 建议在 IME 的 onCreate() 里调用一次。
+ */
+ fun ensureBuiltInThemesInstalled(context: Context) {
+ val am = context.assets
+ val rootName = "keyboard_themes"
+ val themeRootDir = getThemeRootDir(context)
+ if (!themeRootDir.exists()) themeRootDir.mkdirs()
+
+ // 列出 assets/keyboard_themes 下的所有子目录,比如 default、dark...
+ val themeNames = am.list(rootName) ?: return
+
+ for (themeName in themeNames) {
+ val assetThemePath = "$rootName/$themeName" // 如 keyboard_themes/default
+ val targetThemeDir = getThemeDir(context, themeName)
+ copyAssetsDirToDir(am, assetThemePath, targetThemeDir)
+ }
+ }
+
+ /**
+ * 递归地将 assets 中的某个目录合并复制到目标 File 目录下。
+ *
+ * 规则:
+ * - 如果目标目录不存在,则创建。
+ * - 如果目标文件已存在,则跳过(不覆盖用户改过的图)。
+ * - 如果是新文件,则复制过去(补充新图)。
+ */
+ private fun copyAssetsDirToDir(
+ assetManager: AssetManager,
+ assetDir: String,
+ targetDir: File
+ ) {
+ if (!targetDir.exists()) targetDir.mkdirs()
+
+ val children = assetManager.list(assetDir) ?: return
+ for (child in children) {
+ val childAssetPath = "$assetDir/$child"
+ val outFile = File(targetDir, child)
+
+ val grandChildren = assetManager.list(childAssetPath)
+ if (grandChildren?.isNotEmpty() == true) {
+ // 子目录,递归
+ copyAssetsDirToDir(assetManager, childAssetPath, outFile)
+ } else {
+ // 文件:如果已经存在就不覆盖;不存在才复制(补充新图)
+ if (outFile.exists()) continue
+
+ assetManager.open(childAssetPath).use { input ->
+ outFile.outputStream().use { output ->
+ input.copyTo(output)
+ }
+ }
+ }
+ }
+ }
+
+ // ==================== 主题初始化 / 切换 ====================
+
+ /**
+ * 初始化主题系统:
+ * - 读取 SharedPreferences 中上次使用的主题名
+ * - 默认使用 "default"
+ * - 加载该主题的所有图片到缓存
+ */
+ fun init(context: Context) {
+ if (currentThemeName != null) return
+
+ val prefs = context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE)
+ val name = prefs.getString(KEY_CURRENT_THEME, "default") ?: "default"
+ setCurrentTheme(context, name)
+ }
+
+ /**
+ * 切换当前主题:
+ * - 更新 currentThemeName
+ * - 写 SharedPreferences
+ * - 重新加载该主题的全部图片到缓存
+ */
+ fun setCurrentTheme(context: Context, themeName: String) {
+ currentThemeName = themeName
+
+ context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE)
+ .edit()
+ .putString(KEY_CURRENT_THEME, themeName)
+ .apply()
+
+ drawableCache = loadThemeDrawables(context, themeName)
+ }
+
+ fun getCurrentThemeName(): String? = currentThemeName
+
+ /**
+ * 扫描某个主题目录下的所有 png/jpg/webp 文件,
+ * 用“文件名(去掉扩展名,小写)”作为 keyName,构造缓存。
+ *
+ * 例如:
+ * /.../keyboard_themes/default/key_a.png -> "key_a"
+ * /.../keyboard_themes/default/key_a_up.PNG -> "key_a_up"
+ */
+ private fun loadThemeDrawables(
+ context: Context,
+ themeName: String
+ ): MutableMap {
+ val map = mutableMapOf()
+ val dir = getThemeDir(context, themeName)
+
+ if (!dir.exists() || !dir.isDirectory) return map
+
+ dir.listFiles()?.forEach { file ->
+ if (!file.isFile) return@forEach
+
+ val lowerName = file.name.lowercase()
+ if (
+ !(lowerName.endsWith(".png") ||
+ lowerName.endsWith(".jpg") ||
+ lowerName.endsWith(".jpeg") ||
+ lowerName.endsWith(".webp"))
+ ) return@forEach
+
+ // 统一小写作为 key,比如 key_a_up.png -> "key_a_up"
+ val key = lowerName.substringBeforeLast(".")
+ val bmp = BitmapFactory.decodeFile(file.absolutePath) ?: return@forEach
+ val d = BitmapDrawable(context.resources, bmp)
+ map[key] = d
+ }
+
+ return map
+ }
+
+ // ==================== 对外:按 keyName 取 Drawable ====================
+
+ /**
+ * 根据 keyName 获取对应的 Drawable。
+ *
+ * keyName 一般就是 view 的 idName:
+ * - "key_a"
+ * - "key_a_up"
+ * - "key_1"
+ * - "key_space"
+ * - "key_send"
+ * ...
+ *
+ * 对应文件:
+ * /Android/data/.../files/keyboard_themes/<当前主题>/key_a.png
+ *
+ * 内部统一用 keyName.lowercase() 做匹配,不区分大小写。
+ */
+ fun getDrawableForKey(context: Context, keyName: String): Drawable? {
+ if (currentThemeName == null) {
+ init(context)
+ }
+
+ // 统一小写,避免大小写差异
+ val norm = keyName.lowercase()
+
+ // 1) 缓存里有就直接返回
+ drawableCache[norm]?.let { return it }
+
+ // 2) 缓存里没有:尝试从当前主题目录里单独加载一遍(兼容运行时新增图片)
+ val theme = currentThemeName ?: return null
+ val dir = getThemeDir(context, theme)
+
+ val candidates = listOf(
+ File(dir, "$norm.png"),
+ File(dir, "$norm.webp"),
+ File(dir, "$norm.jpg"),
+ File(dir, "$norm.jpeg")
+ )
+
+ for (f in candidates) {
+ if (f.exists() && f.isFile) {
+ val bmp = BitmapFactory.decodeFile(f.absolutePath) ?: continue
+ val d = BitmapDrawable(context.resources, bmp)
+ drawableCache[norm] = d
+ return d
+ }
+ }
+
+ // 3) 找不到就返回 null(调用方自己决定是否兜底)
+ return null
+ }
+
+ // ==================== 可选:列出所有已安装主题 ====================
+
+ /**
+ * 返回当前外部目录下所有已经存在的主题名列表,
+ * 例如 ["default", "dark", "cute_pink"]。
+ */
+ fun listAvailableThemes(context: Context): List {
+ val root = getThemeRootDir(context)
+ if (!root.exists() || !root.isDirectory) return emptyList()
+
+ return root.listFiles()
+ ?.filter { it.isDirectory }
+ ?.map { it.name }
+ ?.sorted()
+ ?: emptyList()
+ }
+}
diff --git a/app/src/main/java/com/example/myapplication/utils/unzipToDir.kt b/app/src/main/java/com/example/myapplication/utils/unzipToDir.kt
new file mode 100644
index 0000000..53ca7b1
--- /dev/null
+++ b/app/src/main/java/com/example/myapplication/utils/unzipToDir.kt
@@ -0,0 +1,31 @@
+package com.example.myapplication.utils
+
+import java.io.*
+import java.util.zip.ZipEntry
+import java.util.zip.ZipInputStream
+
+fun unzipToDir(zipInputStream: InputStream, targetDir: File) {
+ ZipInputStream(BufferedInputStream(zipInputStream)).use { zis ->
+ var entry: ZipEntry? = zis.nextEntry
+ val buffer = ByteArray(4096)
+
+ while (entry != null) {
+ val file = File(targetDir, entry.name)
+
+ if (entry.isDirectory) {
+ file.mkdirs()
+ } else {
+ file.parentFile?.mkdirs()
+ FileOutputStream(file).use { fos ->
+ var count: Int
+ while (zis.read(buffer).also { count = it } != -1) {
+ fos.write(buffer, 0, count)
+ }
+ }
+ }
+
+ zis.closeEntry()
+ entry = zis.nextEntry
+ }
+ }
+}
diff --git a/app/src/main/res/layout/ai_keyboard.xml b/app/src/main/res/layout/ai_keyboard.xml
index 0daae57..4c91e4c 100644
--- a/app/src/main/res/layout/ai_keyboard.xml
+++ b/app/src/main/res/layout/ai_keyboard.xml
@@ -4,7 +4,7 @@
android:layout_height="wrap_content"
android:orientation="vertical"
android:background="@drawable/keyboard_background"
- android:id="@+id/keyboard_root"
+ android:id="@+id/background"
android:gravity="center"
android:padding="16dp">
diff --git a/app/src/main/res/layout/fragment_mine.xml b/app/src/main/res/layout/fragment_mine.xml
index 864ef77..3d068bc 100644
--- a/app/src/main/res/layout/fragment_mine.xml
+++ b/app/src/main/res/layout/fragment_mine.xml
@@ -220,7 +220,6 @@
@@ -12,10 +11,8 @@
android:layout_height="40dp"
android:scrollbars="none"
android:overScrollMode="never"
- android:background="@drawable/keyboard_background"
android:id="@+id/completion_scroll">
-
@@ -381,112 +350,87 @@
@@ -496,112 +440,89 @@
@@ -612,52 +533,42 @@
diff --git a/app/src/main/res/layout/number_keyboard.xml b/app/src/main/res/layout/number_keyboard.xml
index c67a5c0..0a5073c 100644
--- a/app/src/main/res/layout/number_keyboard.xml
+++ b/app/src/main/res/layout/number_keyboard.xml
@@ -3,20 +3,268 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/keyboard_background"
- android:id="@+id/keyboard_root"
+ android:id="@+id/background"
android:orientation="vertical">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
+
+
+
+
+
+
+
-
-
-
+
+
+
+