diff --git a/README.md b/README.md
index ad0f279..e595b24 100644
--- a/README.md
+++ b/README.md
@@ -7,5 +7,4 @@
或者采用 `Nginx` 等Web服务器进行反向代理
-## TODO (新版本适配中)
-* SQL历史记录
\ No newline at end of file
+![](https://raw.githubusercontent.com/YuS1aN/zhenxun_bot_android_ui/master/docs/main.png)
![](https://raw.githubusercontent.com/YuS1aN/zhenxun_bot_android_ui/master/docs/plugin.png)
![](https://raw.githubusercontent.com/YuS1aN/zhenxun_bot_android_ui/master/docs/db.png)
![](https://raw.githubusercontent.com/YuS1aN/zhenxun_bot_android_ui/master/docs/edit.png)
![](https://raw.githubusercontent.com/YuS1aN/zhenxun_bot_android_ui/master/docs/conversation.png)
\ No newline at end of file
diff --git a/app/src/main/java/me/kbai/zhenxunui/api/ApiService.kt b/app/src/main/java/me/kbai/zhenxunui/api/ApiService.kt
index 8736550..2eb9e06 100644
--- a/app/src/main/java/me/kbai/zhenxunui/api/ApiService.kt
+++ b/app/src/main/java/me/kbai/zhenxunui/api/ApiService.kt
@@ -6,6 +6,7 @@ import me.kbai.zhenxunui.model.DeleteRemoteFile
import me.kbai.zhenxunui.model.EditRemoteFile
import me.kbai.zhenxunui.model.ExecuteSql
import me.kbai.zhenxunui.model.FriendListItem
+import me.kbai.zhenxunui.model.GetSqlLog
import me.kbai.zhenxunui.model.GroupInfo
import me.kbai.zhenxunui.model.GroupListItem
import me.kbai.zhenxunui.model.HandleRequest
@@ -18,6 +19,7 @@ import me.kbai.zhenxunui.model.RenameRemoteFile
import me.kbai.zhenxunui.model.RequestListResult
import me.kbai.zhenxunui.model.SendMessage
import me.kbai.zhenxunui.model.SqlLog
+import me.kbai.zhenxunui.model.SqlLogPage
import me.kbai.zhenxunui.model.TableColumn
import me.kbai.zhenxunui.model.TableListItem
import me.kbai.zhenxunui.model.UpdateGroup
@@ -118,8 +120,8 @@ interface ApiService {
@GET("database/get_table_column")
suspend fun getTableColumn(@Query("table_name") table: String): ApiResponse>
- @GET("database/get_sql_log")
- suspend fun getSqlLog(): ApiResponse>
+ @POST("database/get_sql_log")
+ suspend fun getSqlLog(@Body getSqlLog: GetSqlLog): ApiResponse
@POST("database/exec_sql")
suspend fun executeSql(@Body sql: ExecuteSql): ApiResponse>>
diff --git a/app/src/main/java/me/kbai/zhenxunui/extends/ApiExtends.kt b/app/src/main/java/me/kbai/zhenxunui/extends/ApiExtends.kt
index 6d9c907..46919bd 100644
--- a/app/src/main/java/me/kbai/zhenxunui/extends/ApiExtends.kt
+++ b/app/src/main/java/me/kbai/zhenxunui/extends/ApiExtends.kt
@@ -2,10 +2,8 @@ package me.kbai.zhenxunui.extends
import android.app.Application
import android.view.View
-import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.lifecycleScope
-import androidx.lifecycle.repeatOnLifecycle
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.launch
import me.kbai.zhenxunui.repository.Resource
@@ -40,18 +38,12 @@ suspend fun > Flow.apiCollect(
action.invoke(value)
}
-/**
- * 要记得在 active state 恢复 button 状态
- */
fun > Flow.launchAndApiCollectIn(
owner: LifecycleOwner,
button: View? = null,
- activeState: Lifecycle.State = Lifecycle.State.STARTED,
action: suspend (value: T) -> Unit
) = owner.lifecycleScope.launch {
- owner.repeatOnLifecycle(activeState) {
- apiCollect(button = button, action = action)
- }
+ apiCollect(button = button, action = action)
}
//fun > Flow.checkToken(
diff --git a/app/src/main/java/me/kbai/zhenxunui/model/GetSqlLog.kt b/app/src/main/java/me/kbai/zhenxunui/model/GetSqlLog.kt
new file mode 100644
index 0000000..6badfc4
--- /dev/null
+++ b/app/src/main/java/me/kbai/zhenxunui/model/GetSqlLog.kt
@@ -0,0 +1,10 @@
+package me.kbai.zhenxunui.model
+
+data class GetSqlLog(
+ val index: Int = 1,
+ val size: Int = 5
+) {
+ companion object {
+ val DEFAULT = GetSqlLog()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/me/kbai/zhenxunui/model/SqlLogPage.kt b/app/src/main/java/me/kbai/zhenxunui/model/SqlLogPage.kt
new file mode 100644
index 0000000..b0f4630
--- /dev/null
+++ b/app/src/main/java/me/kbai/zhenxunui/model/SqlLogPage.kt
@@ -0,0 +1,6 @@
+package me.kbai.zhenxunui.model
+
+data class SqlLogPage(
+ val total: Int,
+ val data: List
+)
\ No newline at end of file
diff --git a/app/src/main/java/me/kbai/zhenxunui/repository/ApiRepository.kt b/app/src/main/java/me/kbai/zhenxunui/repository/ApiRepository.kt
index fd522ce..9e57305 100644
--- a/app/src/main/java/me/kbai/zhenxunui/repository/ApiRepository.kt
+++ b/app/src/main/java/me/kbai/zhenxunui/repository/ApiRepository.kt
@@ -13,6 +13,7 @@ import me.kbai.zhenxunui.model.ChatMessage
import me.kbai.zhenxunui.model.DeleteRemoteFile
import me.kbai.zhenxunui.model.EditRemoteFile
import me.kbai.zhenxunui.model.ExecuteSql
+import me.kbai.zhenxunui.model.GetSqlLog
import me.kbai.zhenxunui.model.HandleRequest
import me.kbai.zhenxunui.model.PluginDetail
import me.kbai.zhenxunui.model.PluginInfo
@@ -125,6 +126,8 @@ object ApiRepository {
fun executeSql(sql: ExecuteSql) = networkFlow { BotApi.service.executeSql(sql) }
+ fun getSqlLog() = networkFlow { BotApi.service.getSqlLog(GetSqlLog.DEFAULT) }
+
fun readDir(path: String) = networkFlow { BotApi.service.readDir(path) }
fun renameFile(file: RemoteFile, newName: String) = networkFlow {
diff --git a/app/src/main/java/me/kbai/zhenxunui/ui/db/DbManageFragment.kt b/app/src/main/java/me/kbai/zhenxunui/ui/db/DbManageFragment.kt
index 8c4e8e2..cb21ef2 100644
--- a/app/src/main/java/me/kbai/zhenxunui/ui/db/DbManageFragment.kt
+++ b/app/src/main/java/me/kbai/zhenxunui/ui/db/DbManageFragment.kt
@@ -1,7 +1,12 @@
package me.kbai.zhenxunui.ui.db
+import android.annotation.SuppressLint
+import android.util.LayoutDirection
+import android.view.Gravity
import android.view.LayoutInflater
+import android.view.MotionEvent
import android.view.ViewGroup
+import android.widget.TextView
import androidx.fragment.app.viewModels
import me.kbai.zhenxunui.base.BaseFragment
import me.kbai.zhenxunui.databinding.FragmentDbManageBinding
@@ -11,6 +16,7 @@ import me.kbai.zhenxunui.extends.viewLifecycleScope
import me.kbai.zhenxunui.repository.Resource
import me.kbai.zhenxunui.tool.GlobalToast
import me.kbai.zhenxunui.viewmodel.DbManageViewModel
+import me.kbai.zhenxunui.viewmodel.SqlLogViewModel
/**
* @author Sean on 2023/5/30
@@ -18,12 +24,15 @@ import me.kbai.zhenxunui.viewmodel.DbManageViewModel
class DbManageFragment : BaseFragment() {
private val mViewModel by viewModels()
+ private val mSqlLogViewModel by viewModels()
override fun getViewBinding(
inflater: LayoutInflater,
container: ViewGroup?
): FragmentDbManageBinding = FragmentDbManageBinding.inflate(inflater, container, false)
+
+ @SuppressLint("ClickableViewAccessibility")
override fun initView() = viewBinding.run {
srlRefresh.setOnRefreshListener {
mViewModel.requestTableList()
@@ -38,13 +47,37 @@ class DbManageFragment : BaseFragment() {
if (it.data != null) {
SqlResultDialogFragment().show(childFragmentManager)
}
+
+ mSqlLogViewModel.requestSqlLog()
}
}
- }
- override fun onStart() {
- super.onStart()
- viewBinding.btnSql.isEnabled = true
+ etSql.setOnTouchListener touch@{ v, event ->
+ if (event.action != MotionEvent.ACTION_UP) return@touch false
+ val drawableEnd = (v as TextView).compoundDrawables[2] ?: return@touch false
+ val drawableLeft: Int
+ val drawableRight: Int
+
+ if (v.layoutDirection == LayoutDirection.LTR) {
+ drawableLeft = v.right - v.paddingEnd - drawableEnd.bounds.width()
+ drawableRight = v.right
+ } else {
+ drawableLeft = 0
+ drawableRight = v.paddingEnd + drawableEnd.bounds.width()
+ }
+
+ if (event.x >= drawableLeft && event.x <= drawableRight) {
+ SqlLogPopupWindow(this@DbManageFragment)
+ .setOnItemSelectedListener { popup, sqlLog ->
+ etSql.setText(sqlLog.sql)
+ etSql.setSelection(sqlLog.sql.length)
+ popup.dismiss()
+ }
+ .show(v)
+ return@touch true
+ }
+ return@touch false
+ }
}
override fun initData() {
diff --git a/app/src/main/java/me/kbai/zhenxunui/ui/db/SqlLogPopupWindow.kt b/app/src/main/java/me/kbai/zhenxunui/ui/db/SqlLogPopupWindow.kt
new file mode 100644
index 0000000..6fc543d
--- /dev/null
+++ b/app/src/main/java/me/kbai/zhenxunui/ui/db/SqlLogPopupWindow.kt
@@ -0,0 +1,88 @@
+package me.kbai.zhenxunui.ui.db
+
+import android.view.Gravity
+import android.view.View
+import android.view.ViewGroup.LayoutParams
+import android.view.WindowManager
+import android.view.inputmethod.InputMethodManager
+import android.widget.ArrayAdapter
+import android.widget.PopupWindow
+import androidx.core.view.isVisible
+import androidx.fragment.app.Fragment
+import androidx.fragment.app.viewModels
+import androidx.lifecycle.Observer
+import me.kbai.zhenxunui.R
+import me.kbai.zhenxunui.databinding.PopupSqlLogBinding
+import me.kbai.zhenxunui.model.SqlLog
+import me.kbai.zhenxunui.viewmodel.SqlLogViewModel
+
+
+class SqlLogPopupWindow(host: Fragment) : PopupWindow(
+ View.inflate(host.requireContext(), R.layout.popup_sql_log, null)
+) {
+ private val mBinding = PopupSqlLogBinding.bind(contentView)
+ private val mViewModel by host.viewModels()
+
+ private val mObserver: Observer>
+
+ private val mWindowManager = host.requireActivity().windowManager
+
+ private var mOnItemSelectedListener: ((SqlLogPopupWindow, SqlLog) -> Unit)? = null
+
+ init {
+ isFocusable = true
+ isOutsideTouchable = true
+ animationStyle = R.style.PopupAnim
+
+ mObserver = Observer { list ->
+ mBinding.lvSql.apply {
+ adapter = ArrayAdapter(
+ mBinding.root.context, R.layout.item_sql_log, 0, list.map { it.sql }
+ )
+ setOnItemClickListener { _, _, position, _ ->
+ mOnItemSelectedListener?.invoke(this@SqlLogPopupWindow, list[position])
+ }
+ }
+ mBinding.pbWaiting.isVisible = false
+ }
+ mViewModel.logs.observeForever(mObserver)
+ }
+
+ fun setOnItemSelectedListener(listener: (popup: SqlLogPopupWindow, sqlLog: SqlLog) -> Unit): SqlLogPopupWindow {
+ mOnItemSelectedListener = listener
+ return this
+ }
+
+ fun show(anchor: View) {
+ anchor.context.getSystemService(InputMethodManager::class.java)
+ .hideSoftInputFromWindow(anchor.windowToken, 0)
+
+ width = anchor.width
+ height = LayoutParams.WRAP_CONTENT
+ showAsDropDown(anchor, 0, 0, Gravity.BOTTOM)
+
+ val container: View = contentView.parent.let {
+ if (it is View) it else contentView
+ }
+ val params = (container.layoutParams as WindowManager.LayoutParams).apply {
+ flags = flags or WindowManager.LayoutParams.FLAG_DIM_BEHIND
+ dimAmount = 0.1f
+ }
+ mWindowManager.updateViewLayout(container, params)
+ }
+
+ override fun dismiss() {
+ mViewModel.logs.removeObserver(mObserver)
+
+ val container: View = contentView.parent.let {
+ if (it is View) it else contentView
+ }
+ val params = (container.layoutParams as WindowManager.LayoutParams).apply {
+ flags = flags and WindowManager.LayoutParams.FLAG_DIM_BEHIND.inv()
+ dimAmount = 0f
+ }
+ mWindowManager.updateViewLayout(container, params)
+
+ super.dismiss()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/me/kbai/zhenxunui/ui/group/ConversationFragment.kt b/app/src/main/java/me/kbai/zhenxunui/ui/group/ConversationFragment.kt
index 06d739d..d3e2078 100644
--- a/app/src/main/java/me/kbai/zhenxunui/ui/group/ConversationFragment.kt
+++ b/app/src/main/java/me/kbai/zhenxunui/ui/group/ConversationFragment.kt
@@ -46,7 +46,7 @@ class ConversationFragment : BaseFragment() {
btnSend.isEnabled = !it.isNullOrEmpty()
}
- btnSend.setOnDebounceClickListener {
+ btnSend.setOnDebounceClickListener { btn ->
val message = etText.text?.toString()
if (message.isNullOrEmpty()) {
return@setOnDebounceClickListener
@@ -54,7 +54,7 @@ class ConversationFragment : BaseFragment() {
etText.setText("")
mViewModel.sendMessage(mUserId, mGroupId, message)
- .launchAndApiCollectIn(this@ConversationFragment) {
+ .launchAndApiCollectIn(this@ConversationFragment, btn) {
if (it.success()) {
mMessageAdapter.addData(
mViewModel.insertSentMessage(mGroupId, mUserId, message)
@@ -66,11 +66,6 @@ class ConversationFragment : BaseFragment() {
}
}
- override fun onStart() {
- super.onStart()
- viewBinding.btnSend.isEnabled = true
- }
-
override fun initData() {
mGroupId = arguments?.getString(ARGS_GROUP_ID)
mUserId = arguments?.getString(ARGS_USER_ID)
diff --git a/app/src/main/java/me/kbai/zhenxunui/viewmodel/PluginTypeViewModel.kt b/app/src/main/java/me/kbai/zhenxunui/viewmodel/PluginTypeViewModel.kt
index 3aa245b..f726475 100644
--- a/app/src/main/java/me/kbai/zhenxunui/viewmodel/PluginTypeViewModel.kt
+++ b/app/src/main/java/me/kbai/zhenxunui/viewmodel/PluginTypeViewModel.kt
@@ -27,7 +27,8 @@ class PluginTypeViewModel : ViewModel() {
fun modifyPluginData(position: Int, data: PluginInfo, notify: Boolean = true) {
val list = _plugins.value
- list[position] = data
+ //后台接口 getPluginDetail version 错误, 固定为 0
+ list[position] = data.copy(version = list[position].version)
if (notify) _plugins.value = list
}
}
\ No newline at end of file
diff --git a/app/src/main/java/me/kbai/zhenxunui/viewmodel/SqlLogViewModel.kt b/app/src/main/java/me/kbai/zhenxunui/viewmodel/SqlLogViewModel.kt
new file mode 100644
index 0000000..3c96bd2
--- /dev/null
+++ b/app/src/main/java/me/kbai/zhenxunui/viewmodel/SqlLogViewModel.kt
@@ -0,0 +1,30 @@
+package me.kbai.zhenxunui.viewmodel
+
+import androidx.lifecycle.LiveData
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.viewModelScope
+import kotlinx.coroutines.launch
+import me.kbai.zhenxunui.extends.apiCollect
+import me.kbai.zhenxunui.model.SqlLog
+import me.kbai.zhenxunui.repository.ApiRepository
+import me.kbai.zhenxunui.tool.GlobalToast
+
+class SqlLogViewModel : ViewModel() {
+ private val _logs: MutableLiveData> = MutableLiveData()
+ val logs: LiveData> = _logs
+
+ init {
+ requestSqlLog()
+ }
+
+ fun requestSqlLog() = viewModelScope.launch {
+ ApiRepository.getSqlLog().apiCollect {
+ if (it.success() && it.data != null) {
+ _logs.value = it.data.data
+ } else {
+ GlobalToast.showToast(it.message)
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/res/anim/anim_top_enter.xml b/app/src/main/res/anim/anim_top_enter.xml
new file mode 100644
index 0000000..78c52d3
--- /dev/null
+++ b/app/src/main/res/anim/anim_top_enter.xml
@@ -0,0 +1,9 @@
+
+
\ No newline at end of file
diff --git a/app/src/main/res/anim/anim_top_exit.xml b/app/src/main/res/anim/anim_top_exit.xml
new file mode 100644
index 0000000..5ea3168
--- /dev/null
+++ b/app/src/main/res/anim/anim_top_exit.xml
@@ -0,0 +1,9 @@
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/bg_list_item_round_bottom.xml b/app/src/main/res/drawable/bg_list_item_round_bottom.xml
new file mode 100644
index 0000000..c9301f1
--- /dev/null
+++ b/app/src/main/res/drawable/bg_list_item_round_bottom.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_db_manage.xml b/app/src/main/res/layout/fragment_db_manage.xml
index 40b4345..fad4f6f 100644
--- a/app/src/main/res/layout/fragment_db_manage.xml
+++ b/app/src/main/res/layout/fragment_db_manage.xml
@@ -41,6 +41,7 @@
android:id="@+id/et_sql"
android:layout_width="match_parent"
android:layout_height="match_parent"
+ android:drawableEnd="@drawable/ic_arrow_drop_down_16"
android:inputType="text"
android:padding="0dp"
android:textSize="@dimen/et_text_size"
diff --git a/app/src/main/res/layout/fragment_request.xml b/app/src/main/res/layout/fragment_request.xml
index 44b9d86..cff66a2 100644
--- a/app/src/main/res/layout/fragment_request.xml
+++ b/app/src/main/res/layout/fragment_request.xml
@@ -5,9 +5,11 @@
android:layout_height="match_parent">
@@ -15,25 +17,33 @@
-
+ app:layout_constraintTop_toTopOf="parent">
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/popup_sql_log.xml b/app/src/main/res/layout/popup_sql_log.xml
new file mode 100644
index 0000000..408ecb3
--- /dev/null
+++ b/app/src/main/res/layout/popup_sql_log.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml
index ec51f01..dd78af1 100644
--- a/app/src/main/res/values/dimens.xml
+++ b/app/src/main/res/values/dimens.xml
@@ -28,5 +28,5 @@
18dp
20dp
28dp
- 48dp
+ 58dp
\ No newline at end of file
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
index c3a4d0b..463d436 100644
--- a/app/src/main/res/values/styles.xml
+++ b/app/src/main/res/values/styles.xml
@@ -35,7 +35,7 @@
- @color/dn_white
-
+
+
\ No newline at end of file
diff --git a/docs/conversation.jpg b/docs/conversation.jpg
new file mode 100644
index 0000000..cbfe478
Binary files /dev/null and b/docs/conversation.jpg differ
diff --git a/docs/db.jpg b/docs/db.jpg
new file mode 100644
index 0000000..78ef9ac
Binary files /dev/null and b/docs/db.jpg differ
diff --git a/docs/edit.jpg b/docs/edit.jpg
new file mode 100644
index 0000000..0804190
Binary files /dev/null and b/docs/edit.jpg differ
diff --git a/docs/main.jpg b/docs/main.jpg
new file mode 100644
index 0000000..dc4b0ef
Binary files /dev/null and b/docs/main.jpg differ
diff --git a/docs/menu.jpg b/docs/menu.jpg
new file mode 100644
index 0000000..d79c5d6
Binary files /dev/null and b/docs/menu.jpg differ
diff --git a/docs/plugin.jpg b/docs/plugin.jpg
new file mode 100644
index 0000000..be336fc
Binary files /dev/null and b/docs/plugin.jpg differ