diff --git a/app/build.gradle b/app/build.gradle
index 47f494c..c3c7941 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -8,8 +8,8 @@ android {
applicationId "jp.ddo.hotmist.unicodepad"
minSdkVersion 16
targetSdkVersion 32
- versionCode 52
- versionName "2.11.0"
+ versionCode 53
+ versionName "2.12.0"
}
compileOptions {
diff --git a/app/src/main/assets/namedb.zip b/app/src/main/assets/namedb.zip
deleted file mode 100644
index 1386cec..0000000
Binary files a/app/src/main/assets/namedb.zip and /dev/null differ
diff --git a/app/src/main/java/jp/ddo/hotmist/unicodepad/CompleteAdapter.kt b/app/src/main/java/jp/ddo/hotmist/unicodepad/CompleteAdapter.kt
index 2aea339..8b877fc 100644
--- a/app/src/main/java/jp/ddo/hotmist/unicodepad/CompleteAdapter.kt
+++ b/app/src/main/java/jp/ddo/hotmist/unicodepad/CompleteAdapter.kt
@@ -35,10 +35,10 @@ internal class CompleteAdapter(context: Context, pref: SharedPreferences) : Base
private var current = ""
fun update(str: String) {
synchronized(lock) {
- for (s in str.split(" ").toTypedArray()) if (s.isNotEmpty()) {
+ for (s in str.split(" ", "\n").toTypedArray()) if (s.isNotEmpty()) {
(temp ?: list).let {
it.remove(s)
- if (it.size == 255) it.removeAt(254)
+ while (it.size >= 255) it.removeAt(254)
it.add(0, s)
}
}
diff --git a/app/src/main/java/jp/ddo/hotmist/unicodepad/EmojiAdapter.kt b/app/src/main/java/jp/ddo/hotmist/unicodepad/EmojiAdapter.kt
index 82c56fd..787eb44 100644
--- a/app/src/main/java/jp/ddo/hotmist/unicodepad/EmojiAdapter.kt
+++ b/app/src/main/java/jp/ddo/hotmist/unicodepad/EmojiAdapter.kt
@@ -32,7 +32,7 @@ internal class EmojiAdapter(activity: Activity, pref: SharedPreferences, private
private lateinit var grp: MutableList
private lateinit var idx: MutableList
private var current = pref.getInt("emoji", 0)
- private var modifier = pref.getBoolean("modifier", true)
+ private var tone = pref.getInt("tone", 11034)
private var guard = 0
private val scrollListener = object : AbsListView.OnScrollListener {
override fun onScrollStateChanged(view: AbsListView, scrollState: Int) {}
@@ -78,14 +78,59 @@ internal class EmojiAdapter(activity: Activity, pref: SharedPreferences, private
val jump = Spinner(activity)
this.jump = jump
hl.addView(jump, LinearLayout.LayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT, 1f))
- val modc = CheckBox(activity)
- modc.setText(R.string.modifier)
- modc.setPadding(0, 0, (activity.resources.displayMetrics.density * 8f).toInt(), 0)
- hl.addView(modc, LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.MATCH_PARENT))
+ hl.addView(Spinner(activity).apply {
+ val adp = ArrayAdapter(activity, android.R.layout.simple_spinner_item, listOf("⬚", "\uD83C\uDFFB", "\uD83C\uDFFC", "\uD83C\uDFFD", "\uD83C\uDFFE", "\uD83C\uDFFF")).apply {
+ setDropDownViewResource(R.layout.spinner_drop_down_item)
+ }
+ adapter = adp
+ setSelection(adp.getPosition(Character.toChars(tone).concatToString()))
+ onItemSelectedListener = object : OnItemSelectedListener {
+ override fun onItemSelected(parent: AdapterView<*>?, v: View?, position: Int, id: Long) {
+ val item = adp.getItem(position)!!.codePointAt(0)
+ if (tone == item) return
+ tone = item
+ ++guard
+ view.setOnScrollListener(null)
+ jump.onItemSelectedListener = null
+ jump.adapter = null
+ cur?.close()
+ cur = db.emoji(UnicodeActivity.univer, item)
+ map = TreeMap()
+ grp = ArrayList()
+ idx = ArrayList()
+ var last2 = ""
+ cur?.let {
+ it.moveToFirst()
+ while (!it.isAfterLast) {
+ val curr = it.getString(1) + " / " + it.getString(2)
+ if (curr == last2) {
+ it.moveToNext()
+ continue
+ }
+ last2 = curr
+ map[it.position] = map.size
+ grp.add(curr)
+ idx.add(it.position)
+ it.moveToNext()
+ }
+ }
+ if (current >= grp.size) current = grp.size - 1
+ view.invalidateViews()
+ jump.adapter = ArrayAdapter(activity, android.R.layout.simple_spinner_item, grp).also {
+ it.setDropDownViewResource(R.layout.spinner_drop_down_item)
+ }
+ jump.setSelection(current)
+ view.setSelection(idx[current])
+ view.setOnScrollListener(scrollListener)
+ jump.onItemSelectedListener = selectListener
+ view.post { --guard }
+ }
+ override fun onNothingSelected(parent: AdapterView<*>?) {}
+ } }, LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.MATCH_PARENT))
if (Build.VERSION.SDK_INT >= 21) hl.setPadding(0, (activity.resources.displayMetrics.density * 8f).toInt(), 0, (activity.resources.displayMetrics.density * 8f).toInt())
layout.addView(hl, LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT))
layout.addView(this.view, LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT, 1f))
- cur = db.emoji(UnicodeActivity.univer, modifier)
+ cur = db.emoji(UnicodeActivity.univer, tone)
map = TreeMap()
grp = ArrayList()
idx = ArrayList()
@@ -113,46 +158,6 @@ internal class EmojiAdapter(activity: Activity, pref: SharedPreferences, private
jump.setSelection(current)
view.setOnScrollListener(scrollListener)
jump.onItemSelectedListener = selectListener
- modc.isChecked = modifier
- modc.setOnCheckedChangeListener { _: CompoundButton, isChecked: Boolean ->
- if (modifier == isChecked) return@setOnCheckedChangeListener
- modifier = isChecked
- ++guard
- view.setOnScrollListener(null)
- jump.onItemSelectedListener = null
- jump.adapter = null
- cur?.close()
- cur = db.emoji(UnicodeActivity.univer, modifier)
- map = TreeMap()
- grp = ArrayList()
- idx = ArrayList()
- var last2 = ""
- cur?.let {
- it.moveToFirst()
- while (!it.isAfterLast) {
- val curr = it.getString(1) + " / " + it.getString(2)
- if (curr == last2) {
- it.moveToNext()
- continue
- }
- last2 = curr
- map[it.position] = map.size
- grp.add(curr)
- idx.add(it.position)
- it.moveToNext()
- }
- }
- if (current >= grp.size) current = grp.size - 1
- view.invalidateViews()
- jump.adapter = ArrayAdapter(activity, android.R.layout.simple_spinner_item, grp).also {
- it.setDropDownViewResource(R.layout.spinner_drop_down_item)
- }
- jump.setSelection(current)
- view.setSelection(idx[current])
- view.setOnScrollListener(scrollListener)
- jump.onItemSelectedListener = selectListener
- view.post { --guard }
- }
return layout
}
@@ -172,7 +177,7 @@ internal class EmojiAdapter(activity: Activity, pref: SharedPreferences, private
override fun save(edit: SharedPreferences.Editor) {
edit.putInt("emoji", current)
- edit.putBoolean("modifier", modifier)
+ edit.putInt("tone", tone)
}
override fun getCount(): Int {
diff --git a/app/src/main/java/jp/ddo/hotmist/unicodepad/NameDatabase.kt b/app/src/main/java/jp/ddo/hotmist/unicodepad/NameDatabase.kt
index 240706c..373f916 100644
--- a/app/src/main/java/jp/ddo/hotmist/unicodepad/NameDatabase.kt
+++ b/app/src/main/java/jp/ddo/hotmist/unicodepad/NameDatabase.kt
@@ -31,7 +31,7 @@ class NameDatabase(context: Context) {
operator fun get(code: Int, column: String): String? {
if (column == "name") {
if (code in 0xE000..0xF8FF || code in 0xFFF80..0xFFFFD || code in 0x10FF80..0x10FFFD) return "Private Use"
- if (code in 0x3400..0x4DBF || code in 0x4E00..0x9FFF || code in 0x20000..0x2A6DF || code in 0x2A700..0x2B738 || code in 0x2B740..0x2B81D || code in 0x2B820..0x2CEA1 || code in 0x2CEB0..0x2EBE0 || code in 0x30000..0x3134A) return "CJK Unified Ideograph"
+ if (code in 0x3400..0x4DBF || code in 0x4E00..0x9FFF || code in 0x20000..0x2A6DF || code in 0x2A700..0x2B738 || code in 0x2B740..0x2B81D || code in 0x2B820..0x2CEA1 || code in 0x2CEB0..0x2EBE0 || code in 0x30000..0x3134A || code in 0x31350 .. 0x323AF) return "CJK Unified Ideograph"
if (code in 0xAC00..0xD7A3) return "Hangul Syllable"
if (code in 0x17000..0x187F7) return "Tangut Character"
}
@@ -39,7 +39,7 @@ class NameDatabase(context: Context) {
}
operator fun get(code: String, column: String): String? {
- return get("emoji_table", "'$code'", column)
+ return get("emoji_table2", "'$code'", column)
}
private operator fun get(table: String, code: String, column: String): String? {
@@ -73,7 +73,7 @@ class NameDatabase(context: Context) {
}
fun getInt(code: String, column: String): Int {
- return getInt("emoji_table", "'$code'", column)
+ return getInt("emoji_table2", "'$code'", column)
}
private fun getInt(table: String, code: String, column: String): Int {
@@ -100,14 +100,14 @@ class NameDatabase(context: Context) {
else -> version
}
return try {
- db.rawQuery("SELECT id FROM name_table WHERE " + list.joinToString(" ") { "words LIKE '%$it%' AND " } + "version <= $version UNION ALL SELECT id FROM emoji_table WHERE " + list.joinToString(" ") { "name LIKE '%$it%' AND " } + "version <= $emojiVersion;", null)
+ db.rawQuery("SELECT id FROM name_table WHERE " + list.joinToString(" ") { "words LIKE '%$it%' AND " } + "version <= $version UNION ALL SELECT id FROM emoji_table2 WHERE " + list.joinToString(" ") { "name LIKE '%$it%' AND " } + "version <= $emojiVersion;", null)
} catch (e: SQLiteException) {
null
}
}
@SuppressLint("Recycle")
- fun emoji(version: Int, mod: Boolean): Cursor? {
+ fun emoji(version: Int, tone: Int): Cursor? {
val emojiVersion = when (version) {
600, 610, 620, 630 -> 60
700 -> 70
@@ -115,7 +115,7 @@ class NameDatabase(context: Context) {
else -> version
}
return try {
- db.rawQuery("SELECT id, grp, subgrp FROM emoji_table WHERE version <= $emojiVersion" + if (mod) ";" else " AND mod = 0;", null)
+ db.rawQuery("SELECT id, grp, subgrp FROM emoji_table2 WHERE version <= $emojiVersion AND (tone = $tone OR tone = 0);", null)
} catch (e: SQLiteException) {
null
}
@@ -129,7 +129,7 @@ class NameDatabase(context: Context) {
return try {
val db = SQLiteDatabase.openDatabase(context.getFileStreamPath(dbpath).absolutePath, null, SQLiteDatabase.OPEN_READONLY or SQLiteDatabase.NO_LOCALIZED_COLLATORS)
try {
- db.rawQuery("SELECT COUNT(*) FROM sqlite_master WHERE type='table' AND name='name_table' OR name='emoji_table';", null).use { cur ->
+ db.rawQuery("SELECT COUNT(*) FROM sqlite_master WHERE type='table' AND name='name_table' OR name='emoji_table2';", null).use { cur ->
cur.moveToFirst()
if (cur.getInt(0) != 2) throw SQLiteException()
}
@@ -137,7 +137,7 @@ class NameDatabase(context: Context) {
cur.moveToFirst()
if (cur.getInt(0) != 34930) throw SQLiteException()
}
- db.rawQuery("SELECT COUNT(*) FROM 'emoji_table';", null).use { cur ->
+ db.rawQuery("SELECT COUNT(*) FROM 'emoji_table2';", null).use { cur ->
cur.moveToFirst()
if (cur.getInt(0) != 3655) throw SQLiteException()
}
diff --git a/app/src/main/java/jp/ddo/hotmist/unicodepad/UnicodeActivity.kt b/app/src/main/java/jp/ddo/hotmist/unicodepad/UnicodeActivity.kt
index 727940d..1507b54 100644
--- a/app/src/main/java/jp/ddo/hotmist/unicodepad/UnicodeActivity.kt
+++ b/app/src/main/java/jp/ddo/hotmist/unicodepad/UnicodeActivity.kt
@@ -16,12 +16,14 @@
package jp.ddo.hotmist.unicodepad
import android.annotation.SuppressLint
+import android.app.AlertDialog
import android.content.Intent
import android.content.SharedPreferences
import android.content.res.Configuration
import android.graphics.Typeface
import android.os.Build
import android.os.Bundle
+import android.os.Handler
import android.os.Process
import android.provider.OpenableColumns
import android.text.*
@@ -31,7 +33,6 @@ import android.view.inputmethod.InputMethodManager
import android.widget.*
import androidx.appcompat.app.AppCompatActivity
import androidx.core.provider.FontRequest
-import androidx.core.view.MenuItemCompat
import androidx.core.view.doOnLayout
import androidx.emoji2.text.EmojiCompat
import androidx.emoji2.text.EmojiCompat.InitCallback
@@ -43,6 +44,7 @@ import java.io.FileOutputStream
import java.io.IOException
import java.util.*
import java.util.zip.CRC32
+import kotlin.concurrent.thread
import kotlin.math.max
import kotlin.math.min
@@ -51,12 +53,14 @@ import kotlin.math.min
class UnicodeActivity : AppCompatActivity() {
private lateinit var editText: EditText
private lateinit var btnClear: ImageButton
- private lateinit var btnFinish: Button
+ private lateinit var btnFinish: MenuItem
private lateinit var chooser: FontChooser
private lateinit var locale: LocaleChooser
private lateinit var scroll: LockableScrollView
private lateinit var pager: ViewPager
internal lateinit var adpPage: PageAdapter
+ private lateinit var itemUndo: MenuItem
+ private lateinit var itemRedo: MenuItem
private val adCompat: AdCompat = AdCompatImpl()
private lateinit var cm: ClipboardManager
private lateinit var pref: SharedPreferences
@@ -65,6 +69,8 @@ class UnicodeActivity : AppCompatActivity() {
private var disableime = false
private var delay: Runnable? = null
private var timer = 500
+ private val history = mutableListOf(Triple("", 0, 0))
+ private var historyCursor = 0
@SuppressLint("ClickableViewAccessibility")
public override fun onCreate(savedInstanceState: Bundle?) {
pref = PreferenceManager.getDefaultSharedPreferences(this)
@@ -99,13 +105,40 @@ class UnicodeActivity : AppCompatActivity() {
true
}
it.textSize = fontsize
- it.setOnEditorActionListener { _, _, keyEvent ->
- if (keyEvent?.keyCode == KeyEvent.KEYCODE_ENTER) {
- if (keyEvent.action == KeyEvent.ACTION_DOWN) btnFinish.performClick()
+ it.setOnEditorActionListener { _, actionId, keyEvent ->
+ if (keyEvent?.keyCode == KeyEvent.KEYCODE_ENTER && keyEvent.action == KeyEvent.ACTION_DOWN || actionId == EditorInfo.IME_ACTION_DONE) {
+ onOptionsItemSelected(btnFinish)
true
} else
false
}
+ it.addTextChangedListener(object : TextWatcher {
+ override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
+ }
+
+ override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
+ }
+
+ override fun afterTextChanged(s: Editable?) {
+ if (!::itemUndo.isInitialized) {
+ history[0] = Triple(s.toString(), 0, 0)
+ return
+ }
+ if (s.toString() == history[historyCursor].first) {
+ return
+ }
+ while (history.size > historyCursor + 1) {
+ history.removeLast()
+ }
+ while (history.size >= MAX_HISTORY) {
+ history.removeFirst()
+ }
+ history.add(Triple(s.toString(), it.selectionStart, it.selectionEnd))
+ historyCursor = history.size - 1
+ itemUndo.isEnabled = historyCursor > 0
+ itemRedo.isEnabled = false
+ }
+ })
}
btnClear = findViewById(R.id.clear).also {
it.setOnClickListener {
@@ -124,7 +157,6 @@ class UnicodeActivity : AppCompatActivity() {
val start = editText.selectionStart
if (start < 1) return@Runnable
val end = editText.selectionEnd
- if (start < 1) return@Runnable
if (start != end) editText.editableText.delete(min(start, end), max(start, end)) else if (start > 1 && Character.isSurrogatePair(str[start - 2], str[start - 1])) editText.editableText.delete(start - 2, start) else editText.editableText.delete(start - 1, start)
if (delay != null) {
editText.postDelayed(delay, timer.toLong())
@@ -142,53 +174,6 @@ class UnicodeActivity : AppCompatActivity() {
true
}
}
- findViewById
- UnicodePad 2.11.0
+ UnicodePad 2.12.0
UnicodePad is licensed under the Apache License, Version2.0
https://github.com/Ryosuke839/UnicodePad
\ No newline at end of file
diff --git a/scripts/build_namedb.py b/scripts/build_namedb.py
index 8ea82b2..0cda1b3 100755
--- a/scripts/build_namedb.py
+++ b/scripts/build_namedb.py
@@ -104,9 +104,11 @@ def oneline(line):
print(ftp.cwd('/Public/emoji/15.0/'))
group = ''
subgroup = ''
+ pending = None
def emoji_line(line):
nonlocal group
nonlocal subgroup
+ nonlocal pending
if len(line) == 0:
return
if line[0] == '#':
@@ -121,17 +123,40 @@ def emoji_line(line):
return
if m.group(2) != 'fully-qualified':
return
- exp = 'INSERT INTO emoji_table (id, name, version, grp, subgrp, mod) values (\'{}\', \'{}\', {}, \'{}\', \'{}\', {});'.format(
- m.group(1).rstrip(' '), m.group(5), int(m.group(3) + m.group(4) + '0'), group, subgroup, 1 if re.search(' (1F3F[B-F]|1F9B[0-3]) ', m.group(1)) else 0)
+ exp = 'INSERT INTO emoji_table2 (id, name, version, grp, subgrp, tone) values (\'{}\', \'{}\', {}, \'{}\', \'{}\','.format(
+ m.group(1).rstrip(' '), m.group(5), int(m.group(3) + m.group(4) + '0'), group, subgroup)
+ m = re.search(' (1F3F[B-F]) ', m.group(1))
+ if m:
+ if pending is not None:
+ try:
+ cur.execute(pending + '11034);')
+ except:
+ print(pending + '11034);')
+ raise
+ pending = None
+ try:
+ cur.execute(exp + str(int(m.group(1), 16)) + ');')
+ except:
+ print(exp + str(int(m.group(1), 16)) + ');')
+ raise
+ else:
+ if pending is not None:
+ try:
+ cur.execute(pending + '0);')
+ except:
+ print(pending + '0);')
+ raise
+ pending = exp
+ cur.execute('CREATE TABLE emoji_table2 (id text NOT NULL PRIMARY KEY, name text NOT NULL, version integer NOT NULL, grp text NOT NULL, subgrp text NOT NULL, tone integer NOT NULL);')
+ print(ftp.retrlines(f'RETR emoji-test.txt', emoji_line))
+ if pending is not None:
try:
- cur.execute(exp)
+ cur.execute(pending + '0);')
except:
- print(exp)
+ print(pending + '0);')
raise
- cur.execute('CREATE TABLE emoji_table (id text NOT NULL PRIMARY KEY, name text NOT NULL, version integer NOT NULL, grp text NOT NULL, subgrp text NOT NULL, mod bit NOT NULL);')
- print(ftp.retrlines(f'RETR emoji-test.txt', emoji_line))
con.commit()
- for cmd in ['SELECT COUNT(*) FROM sqlite_master WHERE type=\'table\' AND name=\'name_table\' OR name=\'emoji_table\'', 'SELECT COUNT(*) FROM \'name_table\';', 'SELECT COUNT(*) FROM \'emoji_table\';']:
+ for cmd in ['SELECT COUNT(*) FROM sqlite_master WHERE type=\'table\' AND name=\'name_table\' OR name=\'emoji_table2\'', 'SELECT COUNT(*) FROM \'name_table\';', 'SELECT COUNT(*) FROM \'emoji_table2\';']:
print(cmd)
cur.execute(cmd)
r = cur.fetchone()