Kaynağa Gözat

[feat]键盘插件,增加Loading弹窗

hezihao 8 ay önce
ebeveyn
işleme
d41b105a67

+ 21 - 3
plugins/keyboard_android/android/src/main/kotlin/com/atmob/keyboard_android/component/child/impl/AiKeyboardCommonPanelComponent.kt

@@ -22,6 +22,7 @@ import com.atmob.keyboard_android.util.InputMethodUtil
 import com.atmob.keyboard_android.util.KeyboardHolder
 import com.atmob.keyboard_android.util.LogUtil
 import com.atmob.keyboard_android.util.UserInfoHelper
+import com.atmob.keyboard_android.util.loading.WaitLoadingController
 import com.atmob.keyboard_android.util.recyclerview.GridDivider
 import com.atmob.keyboard_android.widget.LongTouchContainer
 import com.blankj.utilcode.util.ConvertUtils
@@ -51,6 +52,8 @@ class AiKeyboardCommonPanelComponent @JvmOverloads constructor(
     private lateinit var mKeyListItems: Items
     private lateinit var mKeyListAdapter: MultiTypeAdapter
 
+    private lateinit var mWaitLoadingController: WaitLoadingController
+
     override fun onInflateViewId(): Int {
         return R.layout.component_ai_keyboard_common_panel
     }
@@ -67,6 +70,9 @@ class AiKeyboardCommonPanelComponent @JvmOverloads constructor(
     }
 
     override fun bindView(view: View) {
+        mWaitLoadingController =
+            WaitLoadingController(context, KeyboardHolder.getKeyboardService()?.getKeyboardWindow())
+
         setupKeyList()
         setupActionBtn()
         setupViewModel()
@@ -296,8 +302,12 @@ class AiKeyboardCommonPanelComponent @JvmOverloads constructor(
      * @param characterId 人设Id
      */
     private fun doChatSuperReply(characterId: String) {
+        mWaitLoadingController.showWait()
         val viewModel = KeyboardHolder.getKeyboardService()?.getKeyboardViewModel()
-        viewModel?.chatSuperReply(characterId, onFail = {
+        viewModel?.chatSuperReply(characterId, onSuccess = {
+            mWaitLoadingController.hideWait()
+        }, onFail = {
+            mWaitLoadingController.hideWait()
             ToastUtils.showShort(it)
         })
     }
@@ -306,8 +316,12 @@ class AiKeyboardCommonPanelComponent @JvmOverloads constructor(
      * 生成<教你说>的内容
      */
     private fun doChatSuperSpeak(characterId: String) {
+        mWaitLoadingController.showWait()
         val viewModel = KeyboardHolder.getKeyboardService()?.getKeyboardViewModel()
-        viewModel?.chatSuperSpeak(characterId, onFail = {
+        viewModel?.chatSuperSpeak(characterId, onSuccess = {
+            mWaitLoadingController.hideWait()
+        }, onFail = {
+            mWaitLoadingController.hideWait()
             ToastUtils.showShort(it)
         })
     }
@@ -316,8 +330,12 @@ class AiKeyboardCommonPanelComponent @JvmOverloads constructor(
      * 生成<开场白>的内容
      */
     private fun doChatPrologue(name: String) {
+        mWaitLoadingController.showWait()
         val viewModel = KeyboardHolder.getKeyboardService()?.getKeyboardViewModel()
-        viewModel?.chatPrologue(name, onFail = {
+        viewModel?.chatPrologue(name, onSuccess = {
+            mWaitLoadingController.hideWait()
+        }, onFail = {
+            mWaitLoadingController.hideWait()
             ToastUtils.showShort(it)
         })
     }

+ 21 - 3
plugins/keyboard_android/android/src/main/kotlin/com/atmob/keyboard_android/component/child/impl/AiKeyboardProloguePanelComponent.kt

@@ -22,6 +22,7 @@ import com.atmob.keyboard_android.util.InputMethodUtil
 import com.atmob.keyboard_android.util.KeyboardHolder
 import com.atmob.keyboard_android.util.LogUtil
 import com.atmob.keyboard_android.util.UserInfoHelper
+import com.atmob.keyboard_android.util.loading.WaitLoadingController
 import com.atmob.keyboard_android.util.recyclerview.GridDivider
 import com.atmob.keyboard_android.widget.LongTouchContainer
 import com.atmob.keyboard_android.widget.indicator.TabPagerTitleView
@@ -64,6 +65,8 @@ class AiKeyboardProloguePanelComponent @JvmOverloads constructor(
      */
     private lateinit var mTabList: MutableList<String>
 
+    private lateinit var mWaitLoadingController: WaitLoadingController
+
     override fun onInflateViewId(): Int {
         return R.layout.component_ai_keyboard_prologue_panel
     }
@@ -80,6 +83,9 @@ class AiKeyboardProloguePanelComponent @JvmOverloads constructor(
     }
 
     override fun bindView(view: View) {
+        mWaitLoadingController =
+            WaitLoadingController(context, KeyboardHolder.getKeyboardService()?.getKeyboardWindow())
+
         setupTabBar()
         setupKeyList()
         setupActionBtn()
@@ -375,8 +381,12 @@ class AiKeyboardProloguePanelComponent @JvmOverloads constructor(
      * @param characterId 人设Id
      */
     private fun doChatSuperReply(characterId: String) {
+        mWaitLoadingController.showWait()
         val viewModel = KeyboardHolder.getKeyboardService()?.getKeyboardViewModel()
-        viewModel?.chatSuperReply(characterId, onFail = {
+        viewModel?.chatSuperReply(characterId, onSuccess = {
+            mWaitLoadingController.hideWait()
+        }, onFail = {
+            mWaitLoadingController.hideWait()
             ToastUtils.showShort(it)
         })
     }
@@ -385,8 +395,12 @@ class AiKeyboardProloguePanelComponent @JvmOverloads constructor(
      * 生成<教你说>的内容
      */
     private fun doChatSuperSpeak(characterId: String) {
+        mWaitLoadingController.showWait()
         val viewModel = KeyboardHolder.getKeyboardService()?.getKeyboardViewModel()
-        viewModel?.chatSuperSpeak(characterId, onFail = {
+        viewModel?.chatSuperSpeak(characterId, onSuccess = {
+            mWaitLoadingController.hideWait()
+        }, onFail = {
+            mWaitLoadingController.hideWait()
             ToastUtils.showShort(it)
         })
     }
@@ -395,8 +409,12 @@ class AiKeyboardProloguePanelComponent @JvmOverloads constructor(
      * 生成<开场白>的内容
      */
     private fun doChatPrologue(name: String) {
+        mWaitLoadingController.showWait()
         val viewModel = KeyboardHolder.getKeyboardService()?.getKeyboardViewModel()
-        viewModel?.chatPrologue(name, onFail = {
+        viewModel?.chatPrologue(name, onSuccess = {
+            mWaitLoadingController.hideWait()
+        }, onFail = {
+            mWaitLoadingController.hideWait()
             ToastUtils.showShort(it)
         })
     }

+ 6 - 0
plugins/keyboard_android/android/src/main/kotlin/com/atmob/keyboard_android/mvvm/viewmodel/KeyboardViewModel.kt

@@ -287,6 +287,7 @@ class KeyboardViewModel : ViewModel() {
      */
     fun chatSuperReply(
         characterId: String,
+        onSuccess: () -> Unit,
         onFail: (String) -> Unit
     ) {
         val req = SuperReplyReq(
@@ -300,6 +301,7 @@ class KeyboardViewModel : ViewModel() {
         mKeyboardRepository.chatSuperReply(req, onSuccess = {
             // 只有一条数据,直接添加到输入框
             _chatSuperReplyResult.value = it.content
+            onSuccess.invoke()
         }, onFail)
     }
 
@@ -310,6 +312,7 @@ class KeyboardViewModel : ViewModel() {
      */
     fun chatSuperSpeak(
         characterId: String,
+        onSuccess: () -> Unit,
         onFail: (String) -> Unit
     ) {
         val req = SuperSpeakReq(
@@ -323,6 +326,7 @@ class KeyboardViewModel : ViewModel() {
         mKeyboardRepository.chatSuperSpeak(req, onSuccess = {
             // 有多条数据,需要跳转列表页面中显示
             _aiChatListResult.value = it.list
+            onSuccess.invoke()
         }, onFail)
     }
 
@@ -331,11 +335,13 @@ class KeyboardViewModel : ViewModel() {
      */
     fun chatPrologue(
         name: String,
+        onSuccess: () -> Unit,
         onFail: (String) -> Unit
     ) {
         mKeyboardRepository.chatPrologue(name, onSuccess = {
             // 有多条数据,需要跳转列表页面中显示
             _aiChatListResult.value = it.list
+            onSuccess.invoke()
         }, onFail)
     }
 }

+ 67 - 0
plugins/keyboard_android/android/src/main/kotlin/com/atmob/keyboard_android/util/loading/LoadingDialog.kt

@@ -0,0 +1,67 @@
+package com.atmob.keyboard_android.util.loading
+
+import android.content.Context
+import android.graphics.Color
+import android.graphics.drawable.ColorDrawable
+import android.view.Gravity
+import android.view.LayoutInflater
+import android.view.Window
+import android.view.WindowManager
+import android.widget.PopupWindow
+import com.atmob.keyboard_android.R
+
+/**
+ * Loading弹窗
+ */
+class LoadingDialog(private val context: Context, private val hostWindow: Window) {
+    private var mPopupWindow: PopupWindow? = null
+
+    /**
+     * 显示Loading
+     */
+    fun show() {
+        if (mPopupWindow?.isShowing == true) {
+            return
+        }
+
+        // 填充布局
+        val contentView = LayoutInflater.from(context).inflate(R.layout.dialog_loading, null, false)
+
+        // 配置 PopupWindow
+        mPopupWindow = PopupWindow(
+            contentView,
+            WindowManager.LayoutParams.WRAP_CONTENT,
+            WindowManager.LayoutParams.WRAP_CONTENT
+        ).apply {
+            // 获取焦点
+            isFocusable = true
+            // 禁止点击外部区域,关闭弹窗
+            isOutsideTouchable = false
+            // 设置背景,否则还是会关闭
+            setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
+        }
+
+        // 显示在屏幕中央
+        mPopupWindow?.showAtLocation(
+            hostWindow.decorView,
+            Gravity.CENTER,
+            0,
+            0
+        )
+    }
+
+    /**
+     * 是否正在显示
+     */
+    fun isShowing(): Boolean {
+        return mPopupWindow?.isShowing == true
+    }
+
+    /**
+     * 隐藏Loading
+     */
+    fun dismiss() {
+        mPopupWindow?.dismiss()
+        mPopupWindow = null
+    }
+}

+ 90 - 0
plugins/keyboard_android/android/src/main/kotlin/com/atmob/keyboard_android/util/loading/WaitLoadingController.java

@@ -0,0 +1,90 @@
+package com.atmob.keyboard_android.util.loading;
+
+import android.content.Context;
+import android.os.Handler;
+import android.os.Looper;
+import android.view.Window;
+
+/**
+ * Loading控制器
+ */
+public class WaitLoadingController {
+    /**
+     * 一定要显示够指定时间
+     */
+    private static final long LOAD_MIN_TIME = 100;
+
+    private LoadingDialog vLoadingDialog;
+
+    private final Handler mMainHandler;
+
+    /**
+     * 开始展示的时间
+     */
+    private long showTime;
+
+    public WaitLoadingController(Context context, Window hostWindow) {
+        mMainHandler = new Handler(Looper.getMainLooper());
+        setup(context, hostWindow);
+    }
+
+    private void setup(Context context, Window hostWindow) {
+        ensureMainThreadRun(() -> {
+            vLoadingDialog = new LoadingDialog(context, hostWindow);
+        });
+    }
+
+    public void showWait() {
+        ensureMainThreadRun(() -> {
+            if (vLoadingDialog != null && !vLoadingDialog.isShowing()) {
+                showTime = System.currentTimeMillis();
+                vLoadingDialog.show();
+            }
+        });
+    }
+
+    public void hideWait() {
+        long currentTime = System.currentTimeMillis();
+        Runnable runnable = () -> {
+            if (vLoadingDialog != null) {
+                vLoadingDialog.dismiss();
+            }
+        };
+        // 显示到调用结束,间隔的时间
+        long intervalTime = currentTime - showTime;
+        // 最少要显示够的时间
+        long leastTime = showTime + LOAD_MIN_TIME;
+        // 如果显示时间比最大时间大,则马上隐藏
+        if (intervalTime >= LOAD_MIN_TIME) {
+            ensureMainThreadRun(runnable);
+        } else {
+            // 否则,补够时间,再隐藏
+            ensureMainThreadRun(runnable, leastTime - currentTime);
+        }
+    }
+
+    private void destroy() {
+        ensureMainThreadRun(() -> {
+            hideWait();
+            vLoadingDialog = null;
+        });
+    }
+
+    /**
+     * 确保主线程执行
+     */
+    public void ensureMainThreadRun(Runnable runnable) {
+        if (Thread.currentThread() == Looper.getMainLooper().getThread()) {
+            runnable.run();
+        } else {
+            mMainHandler.post(runnable);
+        }
+    }
+
+    /**
+     * 延时执行,确保在主线程
+     */
+    public void ensureMainThreadRun(Runnable runnable, long delayMillis) {
+        mMainHandler.postDelayed(runnable, delayMillis);
+    }
+}

+ 20 - 0
plugins/keyboard_android/android/src/main/res/layout/dialog_loading.xml

@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    tools:background="@android:color/black">
+
+    <LinearLayout
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center"
+        android:gravity="center"
+        android:orientation="vertical">
+
+        <ProgressBar
+            android:layout_width="48dp"
+            android:layout_height="48dp"
+            android:indeterminate="true" />
+    </LinearLayout>
+</FrameLayout>

+ 1 - 0
plugins/keyboard_android/android/src/main/res/values/string.xml

@@ -29,4 +29,5 @@
     <string name="how_to_confess">如何告白</string>
     <string name="promotion_relationship">关系升温</string>
     <string name="no_clipboard_data_tip">还没有复制内容喔</string>
+    <string name="loading_tip">加载中…</string>
 </resources>