This commit is contained in:
pengxiaolong
2026-01-23 16:52:51 +08:00
parent affe08c8b4
commit 63415e1fde
13 changed files with 266 additions and 326 deletions

View File

@@ -209,7 +209,7 @@ class GuideActivity : AppCompatActivity() {
}, 1500)
scrollView.postDelayed({
titleTextView.text = "The other party is typing..."
titleTextView.text = getString(R.string.currently_inputting)
}, 500)
inputMessage.isFocusable = true
inputMessage.isFocusableInTouchMode = true

View File

@@ -69,6 +69,10 @@ class MyInputMethodService : InputMethodService(), KeyboardEnvironment {
private val wordDictionary = WordDictionary(this) // 词库
private var currentInput = StringBuilder() // 当前输入前缀
private var completionSuggestions = emptyList<String>() // 自动完成建议
private val suggestionViews = mutableListOf<TextView>() // 缓存动态创建的候选视图
private var suggestionSlotCount: Int = 21 // 包含前缀位,调这里可修改渲染数量
private val completionCapacity: Int
get() = (suggestionSlotCount - 1).coerceAtLeast(0)
@Volatile private var isSpecialToken: BooleanArray = BooleanArray(0)
@@ -866,76 +870,116 @@ class MyInputMethodService : InputMethodService(), KeyboardEnvironment {
// 统一处理补全/联想
override fun updateCompletionsAndRender(prefix: String) {
val ic = currentInputConnection
// 先判断整个编辑框是不是“真的空”
val beforeAll = ic?.getTextBeforeCursor(256, 0)?.toString().orEmpty()
val afterAll = ic?.getTextAfterCursor(256, 0)?.toString().orEmpty()
val editorReallyEmpty = beforeAll.isEmpty() && afterAll.isEmpty()
// 当前输入前缀
currentInput.clear()
currentInput.append(prefix)
// 如果整个编辑框都是空的:直接清空联想 & 刷新 UI什么都不算
if (editorReallyEmpty) {
clearEditorState()
return
}
// 否则再去算 lastWord
val lastWord = getPrevWordBeforeCursor()
val maxCompletions = completionCapacity
Thread {
val list = try {
if (prefix.isEmpty()) {
if (lastWord == null) {
// 这里也保持 emptyList防止空前缀 + 无上文时走全局高频随机词
emptyList()
} else {
suggestWithBigram("", lastWord, topK = 20)
}
} else {
val fromBi = suggestWithBigram(prefix, lastWord, topK = 20)
if (fromBi.isNotEmpty()) {
fromBi.filter { it != prefix }
} else {
wordDictionary.wordTrie.startsWith(prefix, 20)
.filter { it != prefix }
}
}
} catch (_: Throwable) {
if (prefix.isNotEmpty()) {
wordDictionary.wordTrie.startsWith(prefix, 20)
.filterNot { it == prefix }
} else {
val list =
if (maxCompletions <= 0) {
emptyList()
} else {
try {
if (prefix.isEmpty()) {
if (lastWord == null) {
emptyList()
} else {
suggestWithBigram("", lastWord, topK = maxCompletions)
}
} else {
val fromBi = suggestWithBigram(prefix, lastWord, topK = maxCompletions)
if (fromBi.isNotEmpty()) {
fromBi.filter { it != prefix }
} else {
wordDictionary.wordTrie.startsWith(prefix, maxCompletions)
.filter { it != prefix }
}
}
} catch (_: Throwable) {
if (prefix.isNotEmpty()) {
wordDictionary.wordTrie.startsWith(prefix, maxCompletions)
.filterNot { it == prefix }
} else {
emptyList()
}
}
}
}
mainHandler.post {
completionSuggestions = suggestionStats.sortByCount(list.distinct().take(20))
val limited = if (maxCompletions > 0) list.distinct().take(maxCompletions) else emptyList()
completionSuggestions = suggestionStats.sortByCount(limited)
showCompletionSuggestions()
}
}.start()
}
private fun ensureSuggestionViews(): List<TextView> {
val container = mainKeyboardView?.findViewById<LinearLayout>(R.id.completion_suggestions)
?: return emptyList()
val targetCount = maxOf(suggestionSlotCount, 1)
if (suggestionViews.size < targetCount) {
repeat(targetCount - suggestionViews.size) {
val view = buildSuggestionView(container)
suggestionViews.add(view)
container.addView(view)
}
} else if (suggestionViews.size > targetCount) {
val removeCount = suggestionViews.size - targetCount
repeat(removeCount) {
val view = suggestionViews.removeLast()
container.removeView(view)
}
}
suggestionViews.forEach { view ->
if (view.parent == null) container.addView(view)
}
return suggestionViews.take(targetCount)
}
private fun buildSuggestionView(parent: LinearLayout): TextView {
val dp = resources.displayMetrics.density
return TextView(parent.context).apply {
layoutParams = LinearLayout.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.MATCH_PARENT
)
textSize = 16f
setPadding((12 * dp).toInt(), 0, (12 * dp).toInt(), 0)
gravity = Gravity.CENTER
isClickable = true
setBackgroundResource(R.drawable.btn_keyboard)
setTextColor(Color.parseColor("#000000"))
}
}
// 显示自动完成建议(布局不变)
private fun showCompletionSuggestions() {
mainHandler.post {
val suggestionsView =
mainKeyboardView?.findViewById<LinearLayout>(R.id.completion_suggestions)
// 新增:联想滚动条 & 控制面板
val completionScroll =
mainKeyboardView?.findViewById<ConstraintLayout>(R.id.completion_scroll)
val controlLayout =
mainKeyboardView?.findViewById<LinearLayout>(R.id.control_layout)
val suggestions = (0..20).map { i ->
mainKeyboardView?.findViewById<TextView>(
resources.getIdentifier("suggestion_$i", "id", packageName)
)
val suggestions = ensureSuggestionViews()
if (suggestions.isEmpty()) {
completionScroll?.visibility = View.GONE
controlLayout?.visibility = View.VISIBLE
return@post
}
// 当前前缀
@@ -962,25 +1006,46 @@ class MyInputMethodService : InputMethodService(), KeyboardEnvironment {
controlLayout?.visibility = View.GONE
}
// suggestion_0 显示 prefix
suggestions[0]?.text = prefix
suggestions[0]?.visibility = if (prefix.isEmpty()) View.GONE else View.VISIBLE
suggestions[0]?.setOnClickListener {
insertCompletion(prefix)
val prefixView = suggestions.first()
prefixView.text = prefix
prefixView.visibility = if (prefix.isEmpty()) View.GONE else View.VISIBLE
if (prefix.isEmpty()) {
prefixView.setOnClickListener(null)
} else {
prefixView.setOnClickListener { insertCompletion(prefix) }
}
// suggestion_1.. 按 completionSuggestions 填充
// 按 completionSuggestions 填充
suggestions.drop(1).forEachIndexed { index, textView ->
textView?.text = completionSuggestions.getOrNull(index) ?: ""
if (index < completionSuggestions.size) {
textView?.visibility = View.VISIBLE
textView?.setOnClickListener {
suggestionStats.incClick(completionSuggestions[index])
insertCompletion(completionSuggestions[index])
val word = completionSuggestions.getOrNull(index)
if (word != null) {
textView.text = word
textView.visibility = View.VISIBLE
textView.setOnClickListener {
suggestionStats.incClick(word)
insertCompletion(word)
}
} else {
textView?.visibility = View.GONE
textView?.setOnClickListener(null)
textView.text = ""
textView.visibility = View.GONE
textView.setOnClickListener(null)
}
}
// 给最后一个可见候选留出右侧距离,避免被关闭按钮遮挡
val spacingEndPx = (44 * resources.displayMetrics.density).toInt()
suggestions.forEach { view ->
val lp = view.layoutParams
if (lp is LinearLayout.LayoutParams) {
lp.marginEnd = 0
view.layoutParams = lp
}
}
suggestions.lastOrNull { it.visibility == View.VISIBLE }?.let { lastView ->
val lp = lastView.layoutParams
if (lp is LinearLayout.LayoutParams) {
lp.marginEnd = spacingEndPx
lastView.layoutParams = lp
}
}
@@ -1251,6 +1316,8 @@ class MyInputMethodService : InputMethodService(), KeyboardEnvironment {
// ================== bigram & 联想实现 ==================
private fun suggestWithBigram(prefix: String, lastWord: String?, topK: Int = 20): List<String> {
if (topK <= 0) return emptyList()
val m = bigramModel
if (m == null || !bigramReady) {
return if (prefix.isNotEmpty()) {
@@ -1308,6 +1375,7 @@ class MyInputMethodService : InputMethodService(), KeyboardEnvironment {
}
private fun unigramTopKFiltered(topK: Int): List<String> {
if (topK <= 0) return emptyList()
val m = bigramModel ?: return emptyList()
if (!bigramReady) return emptyList()
@@ -1332,6 +1400,7 @@ class MyInputMethodService : InputMethodService(), KeyboardEnvironment {
}
private fun topKByScore(pairs: List<Pair<String, Float>>, k: Int): List<String> {
if (k <= 0) return emptyList()
val heap = java.util.PriorityQueue<Pair<String, Float>>(k.coerceAtLeast(1)) { a, b ->
a.second.compareTo(b.second)
}
@@ -1399,15 +1468,11 @@ class MyInputMethodService : InputMethodService(), KeyboardEnvironment {
controlLayout?.visibility = View.VISIBLE
// 再让联想区域里的文本都清空一下
val suggestions = (0..20).map { i ->
mainKeyboardView?.findViewById<TextView>(
resources.getIdentifier("suggestion_$i", "id", packageName)
)
}
val suggestions = ensureSuggestionViews()
suggestions.forEach { tv ->
tv?.text = ""
tv?.visibility = View.GONE
tv?.setOnClickListener(null)
tv.text = ""
tv.visibility = View.GONE
tv.setOnClickListener(null)
}
}
}

View File

@@ -77,11 +77,23 @@ abstract class BaseKeyboard(
if (id != 0) add(id)
}
}
val suggestionContainerId =
env.ctx.resources.getIdentifier("completion_suggestions", "id", env.ctx.packageName)
fun isInSuggestionContainer(view: View): Boolean {
if (suggestionContainerId == 0) return false
var parent = view.parent
while (parent is View) {
if (parent.id == suggestionContainerId) return true
parent = parent.parent
}
return false
}
fun dfs(v: View?) {
when (v) {
is TextView -> {
if (ignoredIds.contains(v.id)) return
if (ignoredIds.contains(v.id) || isInSuggestionContainer(v)) return
val lp = v.layoutParams
if (lp is LinearLayout.LayoutParams) {

View File

@@ -9,6 +9,7 @@ import okhttp3.Response
import okhttp3.ResponseBody.Companion.toResponseBody
import com.example.myapplication.utils.EncryptedSharedPreferencesUtil
import android.content.Context
import com.example.myapplication.AppContext
import com.example.myapplication.network.security.BodyParamsExtractor
import com.example.myapplication.network.security.NonceUtils
import com.example.myapplication.network.security.SignUtils
@@ -28,6 +29,9 @@ private val NO_LOGIN_REQUIRED_PATHS = setOf(
"/themes/listByStyle",
"/wallet/balance",
"/character/listByUser",
"/user/detail",
"/character/listByTag",
"/character/list",
)
private val NO_SIGN_REQUIRED_PATHS = setOf(
@@ -294,7 +298,7 @@ val responseInterceptor = Interceptor { chain ->
if (errorResponse.code == 40102|| errorResponse.code == 40103) {
val isNoLoginApi = noLoginRequired(request.url)
EncryptedSharedPreferencesUtil.remove(AppContext.context, "user")
Log.w(
"1314520-HTTP",
"40102 path=${request.url.encodedPath}, noLogin=$isNoLoginApi"

View File

@@ -129,6 +129,12 @@ class HomeFragment : Fragment() {
}
}
is AuthEvent.TokenExpired,
is AuthEvent.Logout -> {
// token 被清理或主动退出后,刷新首页为未登录态数据
refreshHomeAfterNetwork()
}
is AuthEvent.CharacterAdded -> {
viewLifecycleOwner.lifecycleScope.launch {
loadingOverlay.show()

View File

@@ -41,6 +41,7 @@ class ShopFragment : Fragment(R.layout.fragment_shop) {
private lateinit var tagContainer: LinearLayout
private lateinit var balance: TextView
private lateinit var swipeRefreshLayout: SwipeRefreshLayout
private lateinit var shopTitle: TextView
// ===== Data =====
private var tabTitles: List<Theme> = emptyList()
@@ -335,19 +336,34 @@ class ShopFragment : Fragment(R.layout.fragment_shop) {
private fun setupSwipeRefreshConflictFix() {
val appBar = requireView().findViewById<AppBarLayout>(R.id.appBar)
// 1) 监听 AppBar 是否完全展开
appBar.addOnOffsetChangedListener { _, verticalOffset ->
appBar.addOnOffsetChangedListener { appBarLayout, verticalOffset ->
// 你原来的逻辑:是否完全展开
appBarFullyExpanded = (verticalOffset == 0)
// ===== 1) 快吸顶才展开:最后 20% 才开始从 0 -> 50dp =====
val ratio = kotlin.math.abs(verticalOffset).toFloat() / appBarLayout.totalScrollRange
val start = 0.8f // 80% 之后开始出现
val range = 0.2f // 用最后 20% 展开到满
val progress = ((ratio - start) / range).coerceIn(0f, 1f)
val maxHeightPx = (50 * resources.displayMetrics.density).toInt()
val newHeight = (progress * maxHeightPx).toInt()
// ===== 2) 同步文字渐显 =====
shopTitle.alpha = progress
// ===== 3) 防止抖动:高度没变就不 setLayoutParams =====
val lp = shopTitle.layoutParams
if (lp.height != newHeight) {
lp.height = newHeight
shopTitle.layoutParams = lp
}
}
// 2) 核心:自定义"子 View 是否能向上滚"的判断
swipeRefreshLayout.setOnChildScrollUpCallback { _, _ ->
// AppBar 没完全展开:不要让刷新抢手势(优先展开/折叠头部)
if (!appBarFullyExpanded) return@setOnChildScrollUpCallback true
// 找到 ViewPager2 当前页的 RecyclerView
val rv = findCurrentPageRecyclerView()
// rv 能向上滚:说明列表不在顶部 -> 禁止触发刷新
rv?.canScrollVertically(-1) ?: false
}
}
@@ -405,6 +421,7 @@ class ShopFragment : Fragment(R.layout.fragment_shop) {
runCatching { RetrofitClient.apiService.themeList() }.getOrNull()
private fun bindViews(view: View) {
shopTitle = view.findViewById(R.id.shopTitle)
viewPager = view.findViewById(R.id.viewPager)
tagScroll = view.findViewById(R.id.tagScroll)
tagContainer = view.findViewById(R.id.tagContainer)
@@ -442,6 +459,17 @@ class ShopFragment : Fragment(R.layout.fragment_shop) {
"element_id" to "search_btn",
)
}
view.findViewById<View>(R.id.recordButton).setOnClickListener {
//消费记录
AuthEventBus.emit(AuthEvent.OpenGlobalPage(R.id.consumptionRecordFragment))
BehaviorReporter.report(
isNewUser = false,
"page_id" to "my",
"element_id" to "menu_item",
"item_title" to "消费记录"
)
}
}
}

View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<gradient
android:angle="90"
android:startColor="#F6F7FB"
android:endColor="#E9FFF1"
android:centerColor="#F6F7FB"
android:centerY="0.05" />
</shape>

View File

@@ -0,0 +1,5 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="#E8FFFD" /> <!-- 背景色 -->
<corners android:radius="8dp" /> <!-- 圆角半径,越大越圆 -->
</shape>

View File

@@ -9,12 +9,10 @@
tools:context=".ui.home.HomeFragment">
<!-- 背景-->
<ImageView
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="@drawable/bg"
android:scaleType="fitXY"
android:adjustViewBounds="true" />
android:background="#F6F7FB"/>
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"

View File

@@ -12,19 +12,21 @@
android:layout_height="match_parent">
<!-- 背景-->
<ImageView
<!-- <ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="@drawable/bg"
android:scaleType="fitXY"
android:adjustViewBounds="true" />
android:adjustViewBounds="true" /> -->
<!-- 头部 + 标签行,放进 AppBarLayout 里 -->
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appBar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@android:color/transparent">
android:background="@drawable/bg_shop_gradient"
android:elevation="0dp"
android:stateListAnimator="@null">
<!-- 这一块会跟着滚动,滑出屏幕 -->
<LinearLayout
@@ -35,14 +37,39 @@
android:orientation="vertical"
app:layout_scrollFlags="scroll|exitUntilCollapsed">
<!-- 搜索、皮肤栏 -->
<!--消费记录,搜索、皮肤栏 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="40dp"
android:layout_gravity="center_horizontal"
android:gravity="end|bottom"
android:orientation="horizontal">
<LinearLayout
android:id="@+id/recordButton"
android:layout_width="wrap_content"
android:layout_height="32dp"
android:gravity="center"
android:paddingStart="7dp"
android:paddingEnd="7dp"
android:background="@drawable/shop_record_bg"
android:orientation="horizontal">
<ImageView
android:layout_width="15dp"
android:layout_height="16dp"
android:layout_marginEnd="4dp"
android:src="@drawable/record" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/mine_consumption_record"
android:textColor="#02BEAC"/>
</LinearLayout>
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"/>
<ImageView
android:id="@+id/searchButton"
android:layout_width="24dp"
@@ -198,21 +225,34 @@
<HorizontalScrollView
android:id="@+id/tagScroll"
android:layout_width="match_parent"
android:layout_height="30dp"
android:layout_height="wrap_content"
android:paddingStart="16dp"
android:paddingEnd="16dp"
android:layout_marginTop="18dp"
android:layout_marginBottom="18dp"
android:fillViewport="true"
android:scrollbars="none"
android:overScrollMode="never">
<LinearLayout
android:id="@+id/tagContainer"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="horizontal"
android:gravity="center_vertical" />
android:layout_height="wrap_content"
android:orientation="vertical"
android:gravity="center_vertical">
<TextView
android:id="@+id/shopTitle"
android:layout_width="match_parent"
android:layout_height="0dp"
android:gravity="center"
android:text="@string/shop_title"
android:textColor="#1B1F1A"
android:textSize="20sp" />
<LinearLayout
android:id="@+id/tagContainer"
android:layout_width="wrap_content"
android:layout_height="30dp"
android:orientation="horizontal"
android:gravity="center_vertical" />
</LinearLayout>
</HorizontalScrollView>
</com.google.android.material.appbar.AppBarLayout>

View File

@@ -68,8 +68,9 @@ xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_marginTop="3dp"
android:background="@drawable/complete_bg">
<HorizontalScrollView
android:layout_width="match_parent"
android:layout_width="0dp"
android:layout_height="50dp"
android:layout_weight="1"
android:scrollbars="none"
android:overScrollMode="never"
app:layout_constraintStart_toStartOf="parent"
@@ -84,239 +85,7 @@ xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_height="match_parent"
android:orientation="horizontal"
android:paddingStart="4dp"
android:paddingEnd="4dp">
<TextView
android:id="@+id/suggestion_0"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:textSize="16sp"
android:paddingHorizontal="12dp"
android:gravity="center"
android:clickable="true"
android:background="@drawable/btn_keyboard"
android:textColor="#FFFFFF"/>
<TextView
android:id="@+id/suggestion_1"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:textSize="16sp"
android:paddingHorizontal="12dp"
android:gravity="center"
android:clickable="true"
android:background="@drawable/btn_keyboard"
android:textColor="#FFFFFF"/>
<TextView
android:id="@+id/suggestion_2"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:textSize="16sp"
android:paddingHorizontal="12dp"
android:gravity="center"
android:clickable="true"
android:background="@drawable/btn_keyboard"
android:textColor="#FFFFFF"/>
<TextView
android:id="@+id/suggestion_3"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:textSize="16sp"
android:paddingHorizontal="12dp"
android:gravity="center"
android:clickable="true"
android:background="@drawable/btn_keyboard"
android:textColor="#FFFFFF"/>
<TextView
android:id="@+id/suggestion_4"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:textSize="16sp"
android:paddingHorizontal="12dp"
android:gravity="center"
android:clickable="true"
android:background="@drawable/btn_keyboard"
android:textColor="#FFFFFF"/>
<TextView
android:id="@+id/suggestion_5"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:textSize="16sp"
android:paddingHorizontal="12dp"
android:gravity="center"
android:clickable="true"
android:background="@drawable/btn_keyboard"
android:textColor="#FFFFFF"/>
<TextView
android:id="@+id/suggestion_6"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:textSize="16sp"
android:paddingHorizontal="12dp"
android:gravity="center"
android:clickable="true"
android:background="@drawable/btn_keyboard"
android:textColor="#FFFFFF"/>
<TextView
android:id="@+id/suggestion_7"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:textSize="16sp"
android:paddingHorizontal="12dp"
android:gravity="center"
android:clickable="true"
android:background="@drawable/btn_keyboard"
android:textColor="#FFFFFF"/>
<TextView
android:id="@+id/suggestion_8"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:textSize="16sp"
android:paddingHorizontal="12dp"
android:gravity="center"
android:clickable="true"
android:background="@drawable/btn_keyboard"
android:textColor="#FFFFFF"/>
<TextView
android:id="@+id/suggestion_9"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:textSize="16sp"
android:paddingHorizontal="12dp"
android:gravity="center"
android:clickable="true"
android:background="@drawable/btn_keyboard"
android:textColor="#FFFFFF"/>
<TextView
android:id="@+id/suggestion_10"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:textSize="16sp"
android:paddingHorizontal="12dp"
android:gravity="center"
android:clickable="true"
android:background="@drawable/btn_keyboard"
android:textColor="#FFFFFF"/>
<TextView
android:id="@+id/suggestion_11"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:textSize="16sp"
android:paddingHorizontal="12dp"
android:gravity="center"
android:clickable="true"
android:background="@drawable/btn_keyboard"
android:textColor="#FFFFFF"/>
<TextView
android:id="@+id/suggestion_12"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:textSize="16sp"
android:paddingHorizontal="12dp"
android:gravity="center"
android:clickable="true"
android:background="@drawable/btn_keyboard"
android:textColor="#FFFFFF"/>
<TextView
android:id="@+id/suggestion_13"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:textSize="16sp"
android:paddingHorizontal="12dp"
android:gravity="center"
android:clickable="true"
android:background="@drawable/btn_keyboard"
android:textColor="#FFFFFF"/>
<TextView
android:id="@+id/suggestion_14"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:textSize="16sp"
android:paddingHorizontal="12dp"
android:gravity="center"
android:clickable="true"
android:background="@drawable/btn_keyboard"
android:textColor="#FFFFFF"/>
<TextView
android:id="@+id/suggestion_15"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:textSize="16sp"
android:paddingHorizontal="12dp"
android:gravity="center"
android:clickable="true"
android:background="@drawable/btn_keyboard"
android:textColor="#FFFFFF"/>
<TextView
android:id="@+id/suggestion_16"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:textSize="16sp"
android:paddingHorizontal="12dp"
android:gravity="center"
android:clickable="true"
android:background="@drawable/btn_keyboard"
android:textColor="#FFFFFF"/>
<TextView
android:id="@+id/suggestion_17"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:textSize="16sp"
android:paddingHorizontal="12dp"
android:gravity="center"
android:clickable="true"
android:background="@drawable/btn_keyboard"
android:textColor="#FFFFFF"/>
<TextView
android:id="@+id/suggestion_18"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:textSize="16sp"
android:paddingHorizontal="12dp"
android:gravity="center"
android:clickable="true"
android:background="@drawable/btn_keyboard"
android:textColor="#FFFFFF"/>
<TextView
android:id="@+id/suggestion_19"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:textSize="16sp"
android:paddingHorizontal="12dp"
android:gravity="center"
android:clickable="true"
android:background="@drawable/btn_keyboard"
android:textColor="#FFFFFF"/>
<TextView
android:id="@+id/suggestion_20"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:textSize="16sp"
android:paddingHorizontal="12dp"
android:gravity="center"
android:clickable="true"
android:background="@drawable/btn_keyboard"
android:textColor="#FFFFFF"/>
</LinearLayout>
android:paddingEnd="4dp" />
</HorizontalScrollView>
<LinearLayout

View File

@@ -99,6 +99,7 @@
<string name="add">添加</string>
<!-- 商城 -->
<string name="shop_title">商城</string>
<string name="shop_mall">积分商城</string>
<string name="shop_points">我的积分</string>
<string name="shop_recharge">充值</string>
@@ -140,7 +141,7 @@
<string name="imguide_btn_2">去切换</string>
<!-- ai键盘 -->
<string name="ai_keyboard_input_hint">点击粘贴您的内容</string>
<string name="ai_keyboard_input_hint">粘贴TA的话</string>
<string name="ai_keyboard_paste_btn">粘贴</string>
<string name="ai_keyboard_clear_btn">清空</string>
<string name="ai_keyboard_send_btn">发送</string>
@@ -156,6 +157,7 @@
<string name="skip">跳过</string>
<string name="delete">删除</string>
<string name="next">下一步</string>
<string name="currently_inputting">对方正在输入...</string>
<!-- 服务条款与隐私政策(小字提醒区) -->
<string name="terms_and_privacy_1">继续操作即表示您已经阅读并同意我们的</string>

View File

@@ -103,6 +103,7 @@
<!-- 商城 -->
<string name="shop_title">Shop</string>
<string name="shop_mall">Points Mall</string>
<string name="shop_points">My points</string>
<string name="shop_recharge">Recharge</string>
@@ -162,6 +163,7 @@
<string name="skip">Skip</string>
<string name="delete">Delete</string>
<string name="next">Next step</string>
<string name="currently_inputting">The other party is currently inputting...</string>
<!-- 服务条款与隐私政策(小字提醒区) -->
<string name="terms_and_privacy_1">By Continuing, You Agree To Our </string>