diff --git a/app/build.gradle b/app/build.gradle index 0c6f0cc..0420389 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -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 { diff --git a/app/src/main/java/io/neoterm/App.kt b/app/src/main/java/io/neoterm/App.kt index 465fe5c..7aa7095 100644 --- a/app/src/main/java/io/neoterm/App.kt +++ b/app/src/main/java/io/neoterm/App.kt @@ -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 { diff --git a/app/src/main/java/io/neoterm/customize/completion/AutoCompletionManager.kt b/app/src/main/java/io/neoterm/customize/completion/CompletionProviderManager.kt similarity index 89% rename from app/src/main/java/io/neoterm/customize/completion/AutoCompletionManager.kt rename to app/src/main/java/io/neoterm/customize/completion/CompletionProviderManager.kt index fcd2e9e..0718bb6 100644 --- a/app/src/main/java/io/neoterm/customize/completion/AutoCompletionManager.kt +++ b/app/src/main/java/io/neoterm/customize/completion/CompletionProviderManager.kt @@ -7,7 +7,7 @@ import io.neoterm.frontend.completion.CompletionManager /** * @author kiva */ -object AutoCompletionManager { +object CompletionProviderManager { fun init(context: Context) { CompletionManager.registerProvider(PathProvider()) } diff --git a/app/src/main/java/io/neoterm/frontend/client/TermCompleteListener.kt b/app/src/main/java/io/neoterm/frontend/client/TermCompleteListener.kt index 9ba8c05..e93a4bb 100644 --- a/app/src/main/java/io/neoterm/frontend/client/TermCompleteListener.kt +++ b/app/src/main/java/io/neoterm/frontend/client/TermCompleteListener.kt @@ -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() - 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 { diff --git a/app/src/main/java/io/neoterm/frontend/client/TermUiPresenter.kt b/app/src/main/java/io/neoterm/frontend/client/TermUiPresenter.kt index 234cf9a..0ff2ba2 100644 --- a/app/src/main/java/io/neoterm/frontend/client/TermUiPresenter.kt +++ b/app/src/main/java/io/neoterm/frontend/client/TermUiPresenter.kt @@ -9,4 +9,6 @@ interface TermUiPresenter { fun requirePaste() fun requireUpdateTitle(title: String?) fun requireOnSessionFinished() + fun requireHideIme() + fun requireFinishAutoCompletion(): Boolean } \ No newline at end of file diff --git a/app/src/main/java/io/neoterm/frontend/client/TermViewClient.kt b/app/src/main/java/io/neoterm/frontend/client/TermViewClient.kt index 764014e..d9b667b 100644 --- a/app/src/main/java/io/neoterm/frontend/client/TermViewClient.kt +++ b/app/src/main/java/io/neoterm/frontend/client/TermViewClient.kt @@ -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: diff --git a/app/src/main/java/io/neoterm/frontend/completion/listener/OnAutoCompleteListener.kt b/app/src/main/java/io/neoterm/frontend/completion/listener/OnAutoCompleteListener.kt index 575edc2..e002e4a 100755 --- a/app/src/main/java/io/neoterm/frontend/completion/listener/OnAutoCompleteListener.kt +++ b/app/src/main/java/io/neoterm/frontend/completion/listener/OnAutoCompleteListener.kt @@ -11,4 +11,6 @@ interface OnAutoCompleteListener { fun onKeyCode(keyCode: Int, keyMod: Int) fun onCleanUp() + + fun onFinishCompletion(): Boolean } diff --git a/app/src/main/java/io/neoterm/customize/completion/widget/CandidatePopupWindow.kt b/app/src/main/java/io/neoterm/frontend/completion/widget/CandidatePopupWindow.kt similarity index 86% rename from app/src/main/java/io/neoterm/customize/completion/widget/CandidatePopupWindow.kt rename to app/src/main/java/io/neoterm/frontend/completion/widget/CandidatePopupWindow.kt index 705a708..3af5eda 100644 --- a/app/src/main/java/io/neoterm/customize/completion/widget/CandidatePopupWindow.kt +++ b/app/src/main/java/io/neoterm/frontend/completion/widget/CandidatePopupWindow.kt @@ -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 diff --git a/app/src/main/java/io/neoterm/ui/term/NeoTermActivity.kt b/app/src/main/java/io/neoterm/ui/term/NeoTermActivity.kt index 85e089a..7eb20ee 100644 --- a/app/src/main/java/io/neoterm/ui/term/NeoTermActivity.kt +++ b/app/src/main/java/io/neoterm/ui/term/NeoTermActivity.kt @@ -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() } diff --git a/app/src/main/java/io/neoterm/ui/term/tab/TermTab.kt b/app/src/main/java/io/neoterm/ui/term/tab/TermTab.kt index 5847597..5f984c4 100644 --- a/app/src/main/java/io/neoterm/ui/term/tab/TermTab.kt +++ b/app/src/main/java/io/neoterm/ui/term/tab/TermTab.kt @@ -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()) } diff --git a/app/src/main/java/io/neoterm/view/MaxHeightView.kt b/app/src/main/java/io/neoterm/view/MaxHeightView.kt new file mode 100644 index 0000000..f456297 --- /dev/null +++ b/app/src/main/java/io/neoterm/view/MaxHeightView.kt @@ -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) + } +} \ No newline at end of file diff --git a/app/src/main/res/layout/popup_auto_complete.xml b/app/src/main/res/layout/popup_auto_complete.xml index 3b3cbaa..2cb9f83 100644 --- a/app/src/main/res/layout/popup_auto_complete.xml +++ b/app/src/main/res/layout/popup_auto_complete.xml @@ -1,5 +1,5 @@ - - \ No newline at end of file + \ No newline at end of file diff --git a/app/src/main/res/values-zh/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml similarity index 100% rename from app/src/main/res/values-zh/strings.xml rename to app/src/main/res/values-zh-rCN/strings.xml diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml new file mode 100644 index 0000000..f435a79 --- /dev/null +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -0,0 +1,95 @@ + + + NeoTerm + 關於 + 複製 + 一般設定 + 新增終端 + 軟件包 + 貼上 + 返回鍵發送ESC + 按下返回鍵時,發送ESC而不關閉 + 響鈴 + 收到 \'\\a\' 時響鈴 + 登入程式 + 登入時使用指定的程式 + 震動 + 收到 \'\\a\' 時震動 + 程式選擇模式 + 當 NeoTerm 和 系統 都有同一個程式時,選擇要被執行的程式模式 + 初始化指令 + 在新的創建新的終端時執行指令 + 軟體源 + 向下切換窗口 + 關閉目前視窗時切換到下一個而不是上一個 + 字體,主題,擴充鍵盤,自動填充 + 個人化 + 全螢幕 + 隱藏標題欄 + 在鍵盤顯示時隱藏標題欄 + 顯示建議 (需要 oh-my-zsh) + 使用一些程式時,在螢幕底部顯示快捷鍵 + 為寬字元設定權重 + 如果快捷輸入欄顯示錯誤,請勾選此項目 + 色彩主題 + 字體 + 設定 + 更多 + 切換輸入法 + 切換視窗 + 介面設定 + 找不到 Shell %s, 請先安裝. + 正在安装 + 將要安装 oh-my-zsh 並將登入程式切換到 zsh + 全螢幕模式已改變,請重新開啟 NeoTerm + NeoTerm 無法取得必需的權限,正在退出 + 還有這種操作? + 使用系统Shell + 重試 + APT 源已改變,可能需要執行 apt update 來更新 + 軟體包: %s\n版本: %s\n依賴: %s\n使用空間: %s\n描述: %s\n首頁: %s + 軟體包列表為空,請檢查你的軟體源 + 重新整理 + 更新並重新整理 + 懸浮視窗 + + + 只使用 NeoTerm + 優先使用 NeoTerm + 優先使用 System + + 完成 + 安裝 + + + 預設軟體源 (穩定,推薦) + 偵錯軟體源 (可能不穩定) + 手動輸入… + + 擴充鍵盤 + 響鈴,震動,Shell,初始化指令 + 全螢幕,標題欄,切換動畫 + 軟體源,更新,升級 + 安裝字體 + 安裝色彩主題 + 發現 + 你好,NeoTerm + 輕觸以選擇你的最愛 + 安裝 + 發現 + 裝置: %s + 程式: %s + 錯誤訊息 + 我們正在努力讓這個 Activity 永不見天日… + %d 個終端 + (永不休眠) + 開啟休眠鎖 + 關閉休眠鎖 + 離開 + 在此處打開終端 + 使用者腳本 + 没有找到可用的使用者腳本或是沒有檔案被選擇 + 處理的檔案 + 可用的使用者腳本 + 從操作列表中中移除檔案? + \ No newline at end of file