Improve: AutoComplete PopupWindow will not cover the IME.
This commit is contained in:
parent
57e5b99ed9
commit
89d4140a71
app
@ -17,14 +17,14 @@ android {
|
||||
applicationId "io.neoterm"
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 25
|
||||
versionCode 14
|
||||
versionName "1.2.0-rc3"
|
||||
versionCode 15
|
||||
versionName "1.2.0-rc4"
|
||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||
resConfigs "zh"
|
||||
resConfigs "zh-rCN", "zh-rTW"
|
||||
externalNativeBuild {
|
||||
cmake {
|
||||
cppFlags "-std=c++11"
|
||||
abiFilters 'x86', 'x86_64', 'armeabi-v7a', 'arm64-v8a'
|
||||
abiFilters 'x86', 'x86_64', 'arm64-v8a'
|
||||
}
|
||||
}
|
||||
sourceSets {
|
||||
|
@ -2,7 +2,7 @@ package io.neoterm
|
||||
|
||||
import android.app.Application
|
||||
import io.neoterm.customize.color.ColorSchemeManager
|
||||
import io.neoterm.customize.completion.AutoCompletionManager
|
||||
import io.neoterm.customize.completion.CompletionProviderManager
|
||||
import io.neoterm.customize.font.FontManager
|
||||
import io.neoterm.customize.script.UserScriptManager
|
||||
import io.neoterm.preference.NeoPreference
|
||||
@ -22,7 +22,7 @@ class App : Application() {
|
||||
ColorSchemeManager.init(this)
|
||||
FontManager.init(this)
|
||||
UserScriptManager.init(this)
|
||||
AutoCompletionManager.init(this)
|
||||
CompletionProviderManager.init(this)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
@ -7,7 +7,7 @@ import io.neoterm.frontend.completion.CompletionManager
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
object AutoCompletionManager {
|
||||
object CompletionProviderManager {
|
||||
fun init(context: Context) {
|
||||
CompletionManager.registerProvider(PathProvider())
|
||||
}
|
@ -1,12 +1,9 @@
|
||||
package io.neoterm.frontend.client
|
||||
|
||||
import android.util.Log
|
||||
import android.view.KeyEvent
|
||||
import io.neoterm.BuildConfig
|
||||
import io.neoterm.customize.completion.widget.CandidatePopupWindow
|
||||
import io.neoterm.frontend.completion.widget.CandidatePopupWindow
|
||||
import io.neoterm.frontend.completion.CompletionManager
|
||||
import io.neoterm.frontend.completion.listener.OnAutoCompleteListener
|
||||
import io.neoterm.frontend.completion.model.CompletionCandidate
|
||||
import io.neoterm.frontend.completion.model.CompletionResult
|
||||
import io.neoterm.view.TerminalView
|
||||
import java.util.*
|
||||
@ -17,20 +14,18 @@ import java.util.*
|
||||
class TermCompleteListener(var terminalView: TerminalView?) : OnAutoCompleteListener {
|
||||
|
||||
private val inputStack = Stack<Char>()
|
||||
private val popupWindow = CandidatePopupWindow(terminalView!!.context)
|
||||
private var popupWindow: CandidatePopupWindow? = null
|
||||
|
||||
override fun onKeyCode(keyCode: Int, keyMod: Int) {
|
||||
when (keyCode) {
|
||||
KeyEvent.KEYCODE_DEL -> {
|
||||
Log.e("NeoTerm-AC", "BackSpace")
|
||||
popChar()
|
||||
activateAutoCompletion()
|
||||
}
|
||||
|
||||
KeyEvent.KEYCODE_ENTER -> {
|
||||
Log.e("NeoTerm-AC", "Clear Chars")
|
||||
clearChars()
|
||||
popupWindow.dismiss()
|
||||
popupWindow?.dismiss()
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -44,10 +39,22 @@ class TermCompleteListener(var terminalView: TerminalView?) : OnAutoCompleteList
|
||||
}
|
||||
|
||||
override fun onCleanUp() {
|
||||
popupWindow.cleanup()
|
||||
popupWindow?.dismiss()
|
||||
popupWindow?.cleanup()
|
||||
popupWindow = null
|
||||
terminalView = null
|
||||
}
|
||||
|
||||
override fun onFinishCompletion(): Boolean {
|
||||
val popWindow = popupWindow ?: return false
|
||||
|
||||
if (popWindow.isShowing()) {
|
||||
popWindow.dismiss()
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
private fun activateAutoCompletion() {
|
||||
val text = getCurrentEditingText()
|
||||
if (text.isEmpty()) {
|
||||
@ -62,20 +69,24 @@ class TermCompleteListener(var terminalView: TerminalView?) : OnAutoCompleteList
|
||||
result.markScore(0)
|
||||
return
|
||||
}
|
||||
|
||||
if (BuildConfig.DEBUG) {
|
||||
val candidates = result.candidates
|
||||
Log.e("NeoTerm-AC", "Completing for $text")
|
||||
candidates.forEach {
|
||||
Log.e("NeoTerm-AC", " Candidate: ${it.completeString}")
|
||||
}
|
||||
}
|
||||
showAutoCompleteCandidates(result)
|
||||
}
|
||||
|
||||
private fun showAutoCompleteCandidates(result: CompletionResult) {
|
||||
popupWindow.candidates = result.candidates
|
||||
popupWindow.show(terminalView!!)
|
||||
val termView = terminalView
|
||||
var popWindow = popupWindow
|
||||
|
||||
if (termView == null) {
|
||||
return
|
||||
}
|
||||
|
||||
if (popWindow == null) {
|
||||
popWindow = CandidatePopupWindow(termView.context)
|
||||
this.popupWindow = popWindow
|
||||
}
|
||||
|
||||
popWindow.candidates = result.candidates
|
||||
popWindow.show(termView)
|
||||
}
|
||||
|
||||
private fun getCurrentEditingText(): String {
|
||||
|
@ -9,4 +9,6 @@ interface TermUiPresenter {
|
||||
fun requirePaste()
|
||||
fun requireUpdateTitle(title: String?)
|
||||
fun requireOnSessionFinished()
|
||||
fun requireHideIme()
|
||||
fun requireFinishAutoCompletion(): Boolean
|
||||
}
|
@ -2,6 +2,7 @@ package io.neoterm.frontend.client
|
||||
|
||||
import android.content.Context
|
||||
import android.media.AudioManager
|
||||
import android.util.Log
|
||||
import android.view.InputDevice
|
||||
import android.view.KeyEvent
|
||||
import android.view.MotionEvent
|
||||
@ -62,6 +63,12 @@ class TermViewClient(val context: Context) : TerminalViewClient {
|
||||
}
|
||||
return false
|
||||
}
|
||||
KeyEvent.KEYCODE_BACK -> {
|
||||
if (e?.action == KeyEvent.ACTION_DOWN) {
|
||||
return termUI?.requireFinishAutoCompletion() ?: false
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
if (e != null && e.isCtrlPressed && e.isAltPressed) {
|
||||
// Get the unmodified code point:
|
||||
|
@ -11,4 +11,6 @@ interface OnAutoCompleteListener {
|
||||
fun onKeyCode(keyCode: Int, keyMod: Int)
|
||||
|
||||
fun onCleanUp()
|
||||
|
||||
fun onFinishCompletion(): Boolean
|
||||
}
|
||||
|
@ -1,18 +1,17 @@
|
||||
package io.neoterm.customize.completion.widget
|
||||
package io.neoterm.frontend.completion.widget
|
||||
|
||||
import android.content.Context
|
||||
import android.util.Log
|
||||
import android.view.Gravity
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.BaseAdapter
|
||||
import android.widget.ListView
|
||||
import android.widget.PopupWindow
|
||||
import android.widget.TextView
|
||||
import android.widget.*
|
||||
import io.neoterm.R
|
||||
import io.neoterm.backend.TerminalColors
|
||||
import io.neoterm.customize.color.ColorSchemeManager
|
||||
import io.neoterm.frontend.completion.model.CompletionCandidate
|
||||
import io.neoterm.view.MaxHeightView
|
||||
import io.neoterm.view.TerminalView
|
||||
|
||||
/**
|
||||
@ -30,8 +29,17 @@ class CandidatePopupWindow(val context: Context) {
|
||||
}
|
||||
|
||||
candidateAdapter?.notifyDataSetChanged()
|
||||
if (!(popupWindow?.isShowing ?: false)) {
|
||||
popupWindow?.showAtLocation(terminalView, Gravity.BOTTOM.and(Gravity.START),
|
||||
|
||||
val popWindow = popupWindow
|
||||
if (popWindow != null) {
|
||||
// Ensure that the popup window will not cover the IME.
|
||||
val rootView = popWindow.contentView
|
||||
if (rootView is MaxHeightView) {
|
||||
val maxHeight = terminalView.height
|
||||
rootView.setMaxHeight(maxHeight)
|
||||
}
|
||||
|
||||
popWindow.showAtLocation(terminalView, Gravity.BOTTOM.and(Gravity.START),
|
||||
terminalView.cursorAbsX,
|
||||
terminalView.cursorAbsY)
|
||||
}
|
||||
@ -41,6 +49,10 @@ class CandidatePopupWindow(val context: Context) {
|
||||
popupWindow?.dismiss()
|
||||
}
|
||||
|
||||
fun isShowing(): Boolean {
|
||||
return popupWindow?.isShowing ?: false
|
||||
}
|
||||
|
||||
private fun createPopupWindow(): PopupWindow {
|
||||
val popupWindow = PopupWindow(context)
|
||||
popupWindow.isOutsideTouchable = true
|
@ -226,7 +226,7 @@ class NeoTermActivity : AppCompatActivity(), ServiceConnection, SharedPreference
|
||||
.takeWhile { it is TermTab }
|
||||
.forEach {
|
||||
val termTab = it as TermTab
|
||||
// After stopped, window locatinos may changed
|
||||
// After stopped, window locations may changed
|
||||
// Rebind it at next time.
|
||||
termTab.resetAutoCompleteStatus()
|
||||
}
|
||||
|
@ -37,7 +37,7 @@ class TermTab(title: CharSequence) : Tab(title), TermUiPresenter {
|
||||
resetAutoCompleteStatus()
|
||||
}
|
||||
|
||||
fun requireHideIme() {
|
||||
override fun requireHideIme() {
|
||||
val terminalView = termData.termView
|
||||
if (terminalView != null) {
|
||||
val imm = terminalView.context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
|
||||
@ -47,6 +47,10 @@ class TermTab(title: CharSequence) : Tab(title), TermUiPresenter {
|
||||
}
|
||||
}
|
||||
|
||||
override fun requireFinishAutoCompletion(): Boolean {
|
||||
return termData.onAutoCompleteListener?.onFinishCompletion() ?: false
|
||||
}
|
||||
|
||||
override fun requireToggleFullScreen() {
|
||||
EventBus.getDefault().post(ToggleFullScreenEvent())
|
||||
}
|
||||
|
54
app/src/main/java/io/neoterm/view/MaxHeightView.kt
Normal file
54
app/src/main/java/io/neoterm/view/MaxHeightView.kt
Normal file
@ -0,0 +1,54 @@
|
||||
package io.neoterm.view
|
||||
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import android.view.View
|
||||
import android.widget.LinearLayout
|
||||
|
||||
class MaxHeightView : LinearLayout {
|
||||
|
||||
private var maxHeight = -1
|
||||
|
||||
constructor(context: Context) : super(context) {}
|
||||
|
||||
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {}
|
||||
|
||||
constructor(context: Context, attrs: AttributeSet, defStyle: Int) : super(context, attrs, defStyle) {}
|
||||
|
||||
fun setMaxHeight(maxHeight: Int) {
|
||||
this.maxHeight = maxHeight
|
||||
}
|
||||
|
||||
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
|
||||
var finalHeightMeasureSpec = heightMeasureSpec
|
||||
|
||||
if (maxHeight > 0) {
|
||||
val heightMode = View.MeasureSpec.getMode(heightMeasureSpec)
|
||||
var heightSize = View.MeasureSpec.getSize(heightMeasureSpec)
|
||||
|
||||
if (heightMode == View.MeasureSpec.EXACTLY) {
|
||||
heightSize = if (heightSize <= maxHeight)
|
||||
heightSize
|
||||
else
|
||||
maxHeight
|
||||
}
|
||||
|
||||
if (heightMode == View.MeasureSpec.UNSPECIFIED) {
|
||||
heightSize = if (heightSize <= maxHeight)
|
||||
heightSize
|
||||
else
|
||||
maxHeight
|
||||
}
|
||||
if (heightMode == View.MeasureSpec.AT_MOST) {
|
||||
heightSize = if (heightSize <= maxHeight)
|
||||
heightSize
|
||||
else
|
||||
maxHeight
|
||||
}
|
||||
finalHeightMeasureSpec = View.MeasureSpec.makeMeasureSpec(heightSize,
|
||||
heightMode)
|
||||
}
|
||||
|
||||
super.onMeasure(widthMeasureSpec, finalHeightMeasureSpec)
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<io.neoterm.view.MaxHeightView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@color/popup_background"
|
||||
@ -10,4 +10,4 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
</LinearLayout>
|
||||
</io.neoterm.view.MaxHeightView>
|
95
app/src/main/res/values-zh-rTW/strings.xml
Normal file
95
app/src/main/res/values-zh-rTW/strings.xml
Normal file
@ -0,0 +1,95 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="app_name">NeoTerm</string>
|
||||
<string name="about">關於</string>
|
||||
<string name="copy_text">複製</string>
|
||||
<string name="general_settings">一般設定</string>
|
||||
<string name="new_session">新增終端</string>
|
||||
<string name="package_settings">軟件包</string>
|
||||
<string name="paste_text">貼上</string>
|
||||
<string name="pref_general_backspace_map_to_esc">返回鍵發送ESC</string>
|
||||
<string name="pref_general_backspace_map_to_esc_desc">按下返回鍵時,發送ESC而不關閉</string>
|
||||
<string name="pref_general_bell">響鈴</string>
|
||||
<string name="pref_general_bell_desc">收到 \'\\a\' 時響鈴</string>
|
||||
<string name="pref_general_shell">登入程式</string>
|
||||
<string name="pref_general_shell_desc">登入時使用指定的程式</string>
|
||||
<string name="pref_general_vibrate">震動</string>
|
||||
<string name="pref_general_vibrate_desc">收到 \'\\a\' 時震動</string>
|
||||
<string name="pref_general_program_selection">程式選擇模式</string>
|
||||
<string name="pref_general_program_selection_desc">當 NeoTerm 和 系統 都有同一個程式時,選擇要被執行的程式模式</string>
|
||||
<string name="pref_general_initial_command">初始化指令</string>
|
||||
<string name="pref_general_initial_command_desc">在新的創建新的終端時執行指令</string>
|
||||
<string name="pref_package_source">軟體源</string>
|
||||
<string name="pref_ui_close_tab_anim_next_tab">向下切換窗口</string>
|
||||
<string name="pref_ui_close_tab_anim_next_tab_desc">關閉目前視窗時切換到下一個而不是上一個</string>
|
||||
<string name="customization_settings_desc">字體,主題,擴充鍵盤,自動填充</string>
|
||||
<string name="customization_settings">個人化</string>
|
||||
<string name="pref_ui_fullscreen">全螢幕</string>
|
||||
<string name="pref_ui_hide_toolbar">隱藏標題欄</string>
|
||||
<string name="pref_ui_hide_toolbar_desc">在鍵盤顯示時隱藏標題欄</string>
|
||||
<string name="pref_ui_suggestions">顯示建議 (需要 oh-my-zsh)</string>
|
||||
<string name="pref_ui_suggestions_desc">使用一些程式時,在螢幕底部顯示快捷鍵</string>
|
||||
<string name="pref_ui_wide_char_weight_explicit">為寬字元設定權重</string>
|
||||
<string name="pref_ui_wide_char_weight_explicit_desc">如果快捷輸入欄顯示錯誤,請勾選此項目</string>
|
||||
<string name="pref_customization_color_scheme">色彩主題</string>
|
||||
<string name="pref_customization_font">字體</string>
|
||||
<string name="settings">設定</string>
|
||||
<string name="text_selection_more">更多</string>
|
||||
<string name="toggle_ime">切換輸入法</string>
|
||||
<string name="toggle_tab_switcher_menu_item">切換視窗</string>
|
||||
<string name="ui_settings">介面設定</string>
|
||||
<string name="shell_not_found">找不到 Shell %s, 請先安裝.</string>
|
||||
<string name="installer_message">正在安装</string>
|
||||
<string name="installer_install_zsh_required">將要安装 oh-my-zsh 並將登入程式切換到 zsh</string>
|
||||
<string name="fullscreen_mode_changed">全螢幕模式已改變,請重新開啟 NeoTerm</string>
|
||||
<string name="permission_denied">NeoTerm 無法取得必需的權限,正在退出</string>
|
||||
<string name="error">還有這種操作?</string>
|
||||
<string name="use_system_shell">使用系统Shell</string>
|
||||
<string name="retry">重試</string>
|
||||
<string name="source_changed">APT 源已改變,可能需要執行 apt update 來更新</string>
|
||||
<string name="package_details">軟體包: %s\n版本: %s\n依賴: %s\n使用空間: %s\n描述: %s\n首頁: %s</string>
|
||||
<string name="package_list_empty">軟體包列表為空,請檢查你的軟體源</string>
|
||||
<string name="menu_refresh_list">重新整理</string>
|
||||
<string name="menu_update">更新並重新整理</string>
|
||||
<string name="float_up">懸浮視窗</string>
|
||||
|
||||
<string-array name="pref_general_program_selection_entries">
|
||||
<item>只使用 NeoTerm</item>
|
||||
<item>優先使用 NeoTerm</item>
|
||||
<item>優先使用 System</item>
|
||||
</string-array>
|
||||
<string name="done">完成</string>
|
||||
<string name="install">安裝</string>
|
||||
|
||||
<string-array name="pref_package_source_entries">
|
||||
<item>預設軟體源 (穩定,推薦)</item>
|
||||
<item>偵錯軟體源 (可能不穩定)</item>
|
||||
<item>手動輸入…</item>
|
||||
</string-array>
|
||||
<string name="pref_customization_eks">擴充鍵盤</string>
|
||||
<string name="general_settings_desc">響鈴,震動,Shell,初始化指令</string>
|
||||
<string name="ui_settings_desc">全螢幕,標題欄,切換動畫</string>
|
||||
<string name="package_settings_desc">軟體源,更新,升級</string>
|
||||
<string name="install_font">安裝字體</string>
|
||||
<string name="install_color">安裝色彩主題</string>
|
||||
<string name="setup_hello">發現</string>
|
||||
<string name="setup_info">你好,NeoTerm</string>
|
||||
<string name="setup_info2">輕觸以選擇你的最愛</string>
|
||||
<string name="setup_next">安裝</string>
|
||||
<string name="discovery">發現</string>
|
||||
<string name="crash_model">裝置: %s</string>
|
||||
<string name="crash_app">程式: %s</string>
|
||||
<string name="crash_stack_trace">錯誤訊息</string>
|
||||
<string name="crash_tips">我們正在努力讓這個 Activity 永不見天日…</string>
|
||||
<string name="service_status_text">%d 個終端</string>
|
||||
<string name="service_lock_acquired"> (永不休眠)</string>
|
||||
<string name="service_acquire_lock">開啟休眠鎖</string>
|
||||
<string name="service_release_lock">關閉休眠鎖</string>
|
||||
<string name="exit">離開</string>
|
||||
<string name="term_here">在此處打開終端</string>
|
||||
<string name="user_script">使用者腳本</string>
|
||||
<string name="no_user_script_found_or_files_selected">没有找到可用的使用者腳本或是沒有檔案被選擇</string>
|
||||
<string name="files_to_handle">處理的檔案</string>
|
||||
<string name="available_user_scripts">可用的使用者腳本</string>
|
||||
<string name="confirm_remove_file_from_list">從操作列表中中移除檔案?</string>
|
||||
</resources>
|
Loading…
x
Reference in New Issue
Block a user