1
0
mirror of https://github.com/fumiama/simple-dict-android.git synced 2026-06-27 07:20:29 +08:00
1. 增加查看更多
2. 优化查询延迟
This commit is contained in:
fumiama
2021-03-21 12:54:17 +08:00
parent 44c5d8b5ef
commit 32def630a3
9 changed files with 133 additions and 92 deletions

View File

@@ -12,8 +12,8 @@ android {
applicationId "top.fumiama.simpledict" applicationId "top.fumiama.simpledict"
minSdkVersion 26 minSdkVersion 26
targetSdkVersion 30 targetSdkVersion 30
versionCode 10 versionCode 11
versionName '1.8' versionName '1.9'
resConfigs "zh", "zh-rCN" resConfigs "zh", "zh-rCN"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"

Binary file not shown.

View File

@@ -1,18 +0,0 @@
{
"version": 2,
"artifactType": {
"type": "APK",
"kind": "Directory"
},
"applicationId": "top.fumiama.simpledict",
"variantName": "processReleaseResources",
"elements": [
{
"type": "SINGLE",
"filters": [],
"versionCode": 10,
"versionName": "1.8",
"outputFile": "app-release.apk"
}
]
}

View File

@@ -10,9 +10,11 @@ import android.text.Spanned
import android.text.style.StrikethroughSpan import android.text.style.StrikethroughSpan
import android.util.Log import android.util.Log
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.MotionEvent
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.EditText import android.view.inputmethod.InputMethodManager
import android.widget.ImageButton
import android.widget.Toast import android.widget.Toast
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
@@ -22,8 +24,12 @@ import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import com.lapism.search.internal.SearchLayout import com.lapism.search.internal.SearchLayout
import kotlinx.android.synthetic.main.activity_main.* import kotlinx.android.synthetic.main.activity_main.*
import kotlinx.android.synthetic.main.activity_main.ffsw
import kotlinx.android.synthetic.main.activity_main.view.*
import kotlinx.android.synthetic.main.dialog_input.view.* import kotlinx.android.synthetic.main.dialog_input.view.*
import kotlinx.android.synthetic.main.line_word.view.* import kotlinx.android.synthetic.main.line_word.view.*
import kotlinx.android.synthetic.main.line_word.view.tb
import kotlinx.android.synthetic.main.line_word.view.tn
import java.io.FileNotFoundException import java.io.FileNotFoundException
import java.lang.Exception import java.lang.Exception
@@ -35,10 +41,13 @@ class MainActivity : AppCompatActivity() {
private var hasLiked = false private var hasLiked = false
private var cm: ClipboardManager? = null private var cm: ClipboardManager? = null
private var ad: ListViewHolder.RecyclerViewAdapter? = null private var ad: ListViewHolder.RecyclerViewAdapter? = null
private var lastLikeLine: View? = null
@SuppressLint("ClickableViewAccessibility")
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main) setContentView(R.layout.activity_main)
val ime = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
getSharedPreferences("remote", MODE_PRIVATE)?.apply { getSharedPreferences("remote", MODE_PRIVATE)?.apply {
if(contains("host")) getString("host", host)?.apply { host = this } if(contains("host")) getString("host", host)?.apply { host = this }
if(contains("port")) getInt("port", port).apply { port = this } if(contains("port")) getInt("port", port).apply { port = this }
@@ -51,24 +60,31 @@ class MainActivity : AppCompatActivity() {
layoutManager = LinearLayoutManager(this@MainActivity) layoutManager = LinearLayoutManager(this@MainActivity)
adapter = ad adapter = ad
setOnScrollChangeListener { _, _, scrollY, _, _ -> setOnScrollChangeListener { _, _, scrollY, _, _ ->
ffsw.isEnabled = scrollY == 0 this@MainActivity.ffsw.isEnabled = scrollY == 0
} }
ffsw.apply { }
setOnRefreshListener {
fetchThread() ffsw.apply {
setOnRefreshListener {
fetchThread{
updateSize()
} }
isRefreshing = true }
fetchThread() isRefreshing = true
fetchThread {
updateSize()
} }
} }
ffms.apply { ffms.apply {
val recyclerView = findViewById<RecyclerView>(R.id.search_recycler_view) val recyclerView = findViewById<RecyclerView>(R.id.search_recycler_view)
setAdapterLayoutManager(LinearLayoutManager(this@MainActivity)) setAdapterLayoutManager(LinearLayoutManager(this@MainActivity))
val adapter = SearchViewHolder(recyclerView, findViewById(R.id.search_search_edit_text)).RecyclerViewAdapter() val adapter = SearchViewHolder(recyclerView).RecyclerViewAdapter()
setAdapter(adapter) setAdapter(adapter)
navigationIconSupport = SearchLayout.NavigationIconSupport.SEARCH navigationIconSupport = SearchLayout.NavigationIconSupport.SEARCH
setMicIconImageResource(R.drawable.ic_setting) setMicIconImageResource(R.drawable.ic_setting)
val micView = findViewById<ImageButton>(R.id.search_image_view_mic)
setClearFocusOnBackPressed(true)
setOnNavigationClickListener(object : SearchLayout.OnNavigationClickListener { setOnNavigationClickListener(object : SearchLayout.OnNavigationClickListener {
override fun onNavigationClick(hasFocus: Boolean) { override fun onNavigationClick(hasFocus: Boolean) {
if (hasFocus()) { if (hasFocus()) {
@@ -80,8 +96,15 @@ class MainActivity : AppCompatActivity() {
}) })
setTextHint(android.R.string.search_go) setTextHint(android.R.string.search_go)
setOnQueryTextListener(object : SearchLayout.OnQueryTextListener { setOnQueryTextListener(object : SearchLayout.OnQueryTextListener {
var lastChangeTime = 0L
override fun onQueryTextChange(newText: CharSequence): Boolean { override fun onQueryTextChange(newText: CharSequence): Boolean {
if (newText.isNotEmpty()) adapter.refresh() postDelayed({
val diff = System.currentTimeMillis() - lastChangeTime
if(diff > 500) {
if (newText.isNotEmpty()) adapter.refresh(newText)
}
}, 1024)
lastChangeTime = System.currentTimeMillis()
return true return true
} }
@@ -140,22 +163,29 @@ class MainActivity : AppCompatActivity() {
} }
}) })
setOnFocusChangeListener(object : SearchLayout.OnFocusChangeListener { setOnFocusChangeListener(object : SearchLayout.OnFocusChangeListener {
override fun onFocusChange(hasFocus: Boolean) { override fun onFocusChange(hasFocus: Boolean) {
navigationIconSupport = if (hasFocus) SearchLayout.NavigationIconSupport.ARROW navigationIconSupport = if (hasFocus) SearchLayout.NavigationIconSupport.ARROW
else SearchLayout.NavigationIconSupport.SEARCH else {
micView.postDelayed({ micView.visibility = View.VISIBLE }, 233)
SearchLayout.NavigationIconSupport.SEARCH
}
} }
}) })
this@MainActivity.ffc.setOnTouchListener { _, e ->
if (e.action == MotionEvent.ACTION_UP && mSearchEditText?.text?.isNotEmpty() == true) {
ime.hideSoftInputFromWindow(window.decorView.windowToken, 0)
}
false
}
} }
} }
override fun onBackPressed() { override fun onBackPressed() {
if(ffms.hasFocus()) { if(ffms.hasFocus()) {
if(hasLiked) ad?.refresh() if(hasLiked) ad?.refresh()
ffms.clearFocus() } else super.onBackPressed()
}
else super.onBackPressed()
} }
/*override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { /*override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
@@ -170,13 +200,18 @@ class MainActivity : AppCompatActivity() {
} }
}*/ }*/
private fun fetchThread() { private fun updateSize() {
lastLikeLine?.fftc?.text = dict?.size?.toString()?:"0"
}
private fun fetchThread(doWhenFinish: (()->Unit)? = null) {
Thread{ Thread{
dict?.fetchDict { dict?.fetchDict {
runOnUiThread { runOnUiThread {
Toast.makeText(this@MainActivity, "刷新成功", Toast.LENGTH_SHORT).show() Toast.makeText(this@MainActivity, "刷新成功", Toast.LENGTH_SHORT).show()
ffsw.isRefreshing = false ffsw.isRefreshing = false
ad?.refresh() ad?.refresh()
doWhenFinish?.apply { this() }
} }
} }
}.start() }.start()
@@ -200,6 +235,7 @@ class MainActivity : AppCompatActivity() {
if (t.diet.text.isNotEmpty() && newText != data) Thread { if (t.diet.text.isNotEmpty() && newText != data) Thread {
dict?.set(key, newText) dict?.set(key, newText)
line?.tb?.text = newText line?.tb?.text = newText
updateSize()
}.start() }.start()
else Toast.makeText(this, "未更改", Toast.LENGTH_SHORT).show() else Toast.makeText(this, "未更改", Toast.LENGTH_SHORT).show()
} }
@@ -217,6 +253,7 @@ class MainActivity : AppCompatActivity() {
ta.text = delKey ta.text = delKey
tn.text = delKey tn.text = delKey
tb.text = delData tb.text = delData
updateSize()
} }
}.start() }.start()
} }
@@ -224,9 +261,9 @@ class MainActivity : AppCompatActivity() {
.show() .show()
} }
inner class SearchViewHolder(itemView: View, private val editText: EditText) : ListViewHolder(itemView) { inner class SearchViewHolder(itemView: View) : ListViewHolder(itemView) {
inner class RecyclerViewAdapter : ListViewHolder.RecyclerViewAdapter() { inner class RecyclerViewAdapter : ListViewHolder.RecyclerViewAdapter() {
override fun getKeys() = filter(editText.text) override fun getKeys(filterText: CharSequence?) = filterText?.let { filter(it) }
override fun getValue(key: String) = dict?.get(key) override fun getValue(key: String) = dict?.get(key)
private fun filter(text: CharSequence): List<String> { private fun filter(text: CharSequence): List<String> {
val selectSet = dict?.keys?.filter { it.contains(text, true) }?.toSet()?.plus(dict?.filterValues { it?.contains(text, true) ?: false }.let { val selectSet = dict?.keys?.filter { it.contains(text, true) }?.toSet()?.plus(dict?.filterValues { it?.contains(text, true) ?: false }.let {
@@ -242,12 +279,17 @@ class MainActivity : AppCompatActivity() {
} }
inner class LikeViewHolder(itemView: View) : ListViewHolder(itemView) { inner class LikeViewHolder(itemView: View) : ListViewHolder(itemView) {
inner class RecyclerViewAdapter: ListViewHolder.RecyclerViewAdapter(){ inner class RecyclerViewAdapter: ListViewHolder.RecyclerViewAdapter(true){
override fun getKeys() = getSharedPreferences("dict", MODE_PRIVATE).all.keys.toTypedArray().let{ var capacity = 5
override fun loadMore() {
capacity += 5
refresh()
}
override fun getKeys(filterText: CharSequence?) = getSharedPreferences("dict", MODE_PRIVATE).all.keys.toTypedArray().let{
dict?.let { d -> dict?.let { d ->
val end = d.latestKeys.size val end = d.latestKeys.size
val start = if(end > 5) end - 5 else 0 val start = if(end > capacity) end - capacity else 0
(d.latestKeys.copyOfRange(start, end) + it).toList() (it + d.latestKeys.copyOfRange(start, end).reversedArray()).toList()
}?: emptyList() }?: emptyList()
} }
override fun getValue(key: String) = dict?.get(key)?:getSharedPreferences("dict", MODE_PRIVATE).getString(key, "null") override fun getValue(key: String) = dict?.get(key)?:getSharedPreferences("dict", MODE_PRIVATE).getString(key, "null")
@@ -255,11 +297,12 @@ class MainActivity : AppCompatActivity() {
} }
open inner class ListViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { open inner class ListViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
open inner class RecyclerViewAdapter : open inner class RecyclerViewAdapter(private val showLoadMore: Boolean = false) :
RecyclerView.Adapter<ListViewHolder>() { RecyclerView.Adapter<ListViewHolder>() {
private var listKeys: List<String>? = null private var listKeys: List<String>? = null
open fun getKeys(): List<String>? = null open fun getKeys(filterText: CharSequence? = null): List<String>? = null
open fun getValue(key: String): String? = null open fun getValue(key: String): String? = null
open fun loadMore() {}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ListViewHolder { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ListViewHolder {
return ListViewHolder( return ListViewHolder(
LayoutInflater.from(parent.context) LayoutInflater.from(parent.context)
@@ -279,6 +322,8 @@ class MainActivity : AppCompatActivity() {
Log.d("MyMain", "Like status of $key is $like") Log.d("MyMain", "Like status of $key is $like")
holder.itemView.apply { holder.itemView.apply {
runOnUiThread { runOnUiThread {
ta.visibility = View.VISIBLE
lwclast.visibility = View.GONE
tn.text = key tn.text = key
ta.text = key ta.text = key
tb.text = data tb.text = data
@@ -309,15 +354,27 @@ class MainActivity : AppCompatActivity() {
} }
} }
} }
} else if(showLoadMore && position == size) runOnUiThread{
holder.itemView.apply {
lastLikeLine = this
ta.visibility = View.GONE
lwclast.visibility = View.VISIBLE
tn.text = "motkyep..."
tb.text = "加载更多..."
updateSize()
setOnClickListener {
loadMore()
}
}
} }
} }
}.start() }.start()
} }
override fun getItemCount() = listKeys?.size?:0 override fun getItemCount() = (listKeys?.size?:0) + (if(showLoadMore) 1 else 0)
fun refresh() = Thread{ fun refresh(filterText: CharSequence? = null) = Thread{
listKeys = getKeys() listKeys = getKeys(filterText)
runOnUiThread { notifyDataSetChanged() } runOnUiThread { notifyDataSetChanged() }
}.start() }.start()
} }

View File

@@ -5,6 +5,7 @@ import java.lang.Thread.sleep
class SimpleDict(private val client: Client, private val pwd: String) { //must run in thread class SimpleDict(private val client: Client, private val pwd: String) { //must run in thread
private var dict = HashMap<String, String?>() private var dict = HashMap<String, String?>()
val size get() = dict.size
val keys get() = dict.keys val keys get() = dict.keys
//val values get() = dict.values //val values get() = dict.values
//val size get() = dict.size //val size get() = dict.size

View File

@@ -2,6 +2,7 @@
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" <androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/ffc"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent">
@@ -16,35 +17,10 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent">
<androidx.constraintlayout.widget.ConstraintLayout <androidx.recyclerview.widget.RecyclerView
android:id="@+id/ffr"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="wrap_content" />
<ImageView
android:id="@+id/imageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="32dp"
app:layout_constraintBottom_toBottomOf="@+id/ffr"
app:layout_constraintEnd_toEndOf="parent"
app:srcCompat="@drawable/bg_dere" />
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/nisi"
android:text="hv#st"
android:textSize="18sp"
app:layout_constraintBottom_toBottomOf="@+id/ffr"
app:layout_constraintEnd_toStartOf="@+id/imageView" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/ffr"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.core.widget.NestedScrollView> </androidx.core.widget.NestedScrollView>
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout> </androidx.swiperefreshlayout.widget.SwipeRefreshLayout>

View File

@@ -1,13 +1,56 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:clickable="true" android:clickable="true"
android:focusable="true" android:focusable="true"
android:foreground="?android:attr/selectableItemBackground"> android:foreground="?android:attr/selectableItemBackground">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/lwclast"
android:layout_width="match_parent"
android:layout_height="0dp"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:visibility="visible">
<TextView
android:id="@+id/fftc"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/nisi"
android:text="0"
android:textSize="18sp"
app:layout_constraintBottom_toTopOf="@+id/fftt"
app:layout_constraintEnd_toStartOf="@+id/imageView" />
<TextView
android:id="@+id/fftt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/nisi"
android:text="hv#st"
android:textSize="18sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/imageView" />
<ImageView
android:id="@+id/imageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:srcCompat="@drawable/bg_dere" />
</androidx.constraintlayout.widget.ConstraintLayout>
<LinearLayout <LinearLayout
android:id="@+id/linearLayout2"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:orientation="vertical"> android:orientation="vertical">

Binary file not shown.

View File

@@ -1,18 +0,0 @@
{
"version": 2,
"artifactType": {
"type": "APK",
"kind": "Directory"
},
"applicationId": "top.fumiama.simpledict",
"variantName": "processWinreleaseResources",
"elements": [
{
"type": "SINGLE",
"filters": [],
"versionCode": 8,
"versionName": "1.6",
"outputFile": "app-winrelease.apk"
}
]
}