浏览代码

[feat]键盘插件,实现模式切换弹窗UI

hezihao 8 月之前
父节点
当前提交
6c9236ed66
共有 25 个文件被更改,包括 483 次插入5 次删除
  1. 3 2
      android/build.gradle.kts
  2. 12 0
      plugins/keyboard_android/android/build.gradle
  3. 17 0
      plugins/keyboard_android/android/src/main/kotlin/com/atmob/keyboard_android/component/QuickSwitchComponent.kt
  4. 42 0
      plugins/keyboard_android/android/src/main/kotlin/com/atmob/keyboard_android/enums/Mode.kt
  5. 10 0
      plugins/keyboard_android/android/src/main/kotlin/com/atmob/keyboard_android/ext/ContextExt.kt
  6. 7 0
      plugins/keyboard_android/android/src/main/kotlin/com/atmob/keyboard_android/keyboard/CustomKeyboardService.kt
  7. 16 0
      plugins/keyboard_android/android/src/main/kotlin/com/atmob/keyboard_android/model/ModeItem.kt
  8. 132 0
      plugins/keyboard_android/android/src/main/kotlin/com/atmob/keyboard_android/popup/ModeSwitchPopupWindow.kt
  9. 50 0
      plugins/keyboard_android/android/src/main/kotlin/com/atmob/keyboard_android/popup/item/ModeListItemViewBinder.kt
  10. 48 0
      plugins/keyboard_android/android/src/main/kotlin/com/atmob/keyboard_android/util/ContextUtil.java
  11. 30 0
      plugins/keyboard_android/android/src/main/kotlin/com/atmob/keyboard_android/util/KeyboardHolder.kt
  12. 7 0
      plugins/keyboard_android/android/src/main/res/anim/popup_enter.xml
  13. 7 0
      plugins/keyboard_android/android/src/main/res/anim/popup_exit.xml
  14. 7 0
      plugins/keyboard_android/android/src/main/res/drawable/bg_mode_selected.xml
  15. 23 0
      plugins/keyboard_android/android/src/main/res/layout/item_mode.xml
  16. 1 1
      plugins/keyboard_android/android/src/main/res/layout/keyboard_layout.xml
  17. 44 0
      plugins/keyboard_android/android/src/main/res/layout/popup_mode_switch_attach.xml
  18. 3 2
      plugins/keyboard_android/android/src/main/res/layout/quick_switch_component.xml
  19. 二进制
      plugins/keyboard_android/android/src/main/res/mipmap-xxxhdpi/bg_popup.9.png
  20. 二进制
      plugins/keyboard_android/android/src/main/res/mipmap-xxxhdpi/ic_arrow.png
  21. 2 0
      plugins/keyboard_android/android/src/main/res/values/colors.xml
  22. 8 0
      plugins/keyboard_android/android/src/main/res/values/theme.xml
  23. 3 0
      plugins/keyboard_android/example/android/build.gradle.kts
  24. 3 0
      plugins/keyboard_android/example/android/settings.gradle.kts
  25. 8 0
      pubspec.lock

+ 3 - 2
android/build.gradle.kts

@@ -8,8 +8,9 @@ allprojects {
         set("ndkVersion", "27.0.12077973")
     }
     repositories {
-
-
+        maven {
+            url = uri("https://jitpack.io")
+        }
         google()
         mavenCentral()
     }

+ 12 - 0
plugins/keyboard_android/android/build.gradle

@@ -17,6 +17,7 @@ def flutterSdk = localProperties.getProperty('flutter.sdk')
 buildscript {
     ext.kotlin_version = "1.8.22"
     repositories {
+        maven { url 'https://jitpack.io' }
         google()
         mavenCentral()
     }
@@ -29,6 +30,7 @@ buildscript {
 
 allprojects {
     repositories {
+        maven { url 'https://jitpack.io' }
         google()
         mavenCentral()
     }
@@ -65,6 +67,10 @@ android {
         testImplementation("org.mockito:mockito-core:5.0.0")
         compileOnly(files("$flutterSdk/bin/cache/artifacts/engine/android-arm/flutter.jar"))
 
+        // AppCompat
+        implementation 'androidx.appcompat:appcompat:1.3.1'
+        // Material
+        implementation 'com.google.android.material:material:1.4.0'
         // RecyclerView
         implementation 'androidx.recyclerview:recyclerview:1.3.0'
         // ConstraintLayout
@@ -73,6 +79,12 @@ android {
         implementation "com.google.code.gson:gson:2.10"
         // CircleImageView
         implementation 'de.hdodenhof:circleimageview:3.1.0'
+        // XPopup
+        // implementation 'com.github.li-xiaojun:XPopup:2.10.0'
+        // Android Util Code
+        implementation 'com.blankj:utilcodex:1.31.1'
+        // RecyclerView Adapter
+        implementation 'me.drakeet.multitype:multitype:3.5.0'
     }
 
     testOptions {

+ 17 - 0
plugins/keyboard_android/android/src/main/kotlin/com/atmob/keyboard_android/component/QuickSwitchComponent.kt

@@ -5,6 +5,7 @@ import android.util.AttributeSet
 import android.view.View
 import com.atmob.keyboard_android.R
 import com.atmob.keyboard_android.component.base.BaseUIComponent
+import com.atmob.keyboard_android.popup.ModeSwitchPopupWindow
 
 /**
  * 快速切换组件
@@ -12,13 +13,29 @@ import com.atmob.keyboard_android.component.base.BaseUIComponent
 class QuickSwitchComponent @JvmOverloads constructor(
     context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
 ) : BaseUIComponent(context, attrs, defStyleAttr) {
+    private lateinit var vModeSwitchLayout: View
+
+    /**
+     * 模式切换的弹窗
+     */
+    private val mModeSwitchPopupWindow = ModeSwitchPopupWindow(context)
+
     override fun onInflateViewId(): Int {
         return R.layout.quick_switch_component
     }
 
     override fun findView(view: View) {
+        vModeSwitchLayout = view.findViewById(R.id.mode_switch_layout)
     }
 
     override fun bindView(view: View) {
+        vModeSwitchLayout.setOnClickListener {
+            // 弹出模式切换弹窗
+            if (mModeSwitchPopupWindow.isShowing()) {
+                mModeSwitchPopupWindow.dismiss()
+            } else {
+                mModeSwitchPopupWindow.show(vModeSwitchLayout)
+            }
+        }
     }
 }

+ 42 - 0
plugins/keyboard_android/android/src/main/kotlin/com/atmob/keyboard_android/enums/Mode.kt

@@ -0,0 +1,42 @@
+package com.atmob.keyboard_android.enums
+
+import com.atmob.keyboard_android.R
+import com.atmob.keyboard_android.ext.getResString
+
+/**
+ * 模式枚举
+ */
+enum class Mode(val type: Int, val modeName: String) {
+    /**
+     * 帮聊
+     */
+    HELP_CHAT(1, getResString(R.string.mode_help_chat)),
+
+    /**
+     * 教你说
+     */
+    TEACH_YOU_SAY(1, getResString(R.string.mode_teach_you_say)),
+
+    /**
+     * 开场白
+     */
+    OPEN_REMARKS(2, getResString(R.string.mode_open_remarks));
+
+    companion object {
+        /**
+         * 通过类型,找到枚举实例
+         */
+        fun fromType(type: Int): Mode {
+            return values().firstOrNull {
+                it.type == type
+            } ?: HELP_CHAT
+        }
+
+        /**
+         * 获取所有模式
+         */
+        fun getAll(): List<Mode> {
+            return values().toList()
+        }
+    }
+}

+ 10 - 0
plugins/keyboard_android/android/src/main/kotlin/com/atmob/keyboard_android/ext/ContextExt.kt

@@ -0,0 +1,10 @@
+package com.atmob.keyboard_android.ext
+
+import com.atmob.keyboard_android.util.ContextUtil
+
+/**
+ * 获取资源字符串
+ */
+fun getResString(resId: Int): String {
+    return ContextUtil.getContext().resources.getString(resId)
+}

+ 7 - 0
plugins/keyboard_android/android/src/main/kotlin/com/atmob/keyboard_android/keyboard/CustomKeyboardService.kt

@@ -10,6 +10,7 @@ import android.widget.GridLayout
 import android.widget.Toast
 import com.atmob.keyboard_android.R
 import com.atmob.keyboard_android.util.InputMethodUtil
+import com.atmob.keyboard_android.util.KeyboardHolder
 import com.atmob.keyboard_android.util.LogUtil
 import io.flutter.embedding.engine.FlutterEngineCache
 import io.flutter.plugin.common.MethodCall
@@ -68,6 +69,7 @@ class CustomKeyboardService : InputMethodService() {
         LogUtil.d("onCreateInputView!")
         val keyboardView = layoutInflater.inflate(R.layout.keyboard_layout, null)
         vKeyboardView = keyboardView
+        KeyboardHolder.attachKeyboardRootView(keyboardView)
 
         // 获取按键映射
         fetchKeyMappings()
@@ -75,6 +77,11 @@ class CustomKeyboardService : InputMethodService() {
         return keyboardView
     }
 
+    override fun onDestroy() {
+        super.onDestroy()
+        KeyboardHolder.detachKeyboardRootView()
+    }
+
     override fun onStartInputView(info: EditorInfo?, restarting: Boolean) {
         super.onStartInputView(info, restarting)
         LogUtil.d("onStartInputView: 重新加载键盘数据")

+ 16 - 0
plugins/keyboard_android/android/src/main/kotlin/com/atmob/keyboard_android/model/ModeItem.kt

@@ -0,0 +1,16 @@
+package com.atmob.keyboard_android.model
+
+import com.atmob.keyboard_android.enums.Mode
+import java.io.Serializable
+
+/**
+ * 模式实体类
+ */
+data class ModeItem(
+    // 模式
+    val mode: Mode,
+    /**
+     * 是否选中
+     */
+    var selected: Boolean = false,
+) : Serializable

+ 132 - 0
plugins/keyboard_android/android/src/main/kotlin/com/atmob/keyboard_android/popup/ModeSwitchPopupWindow.kt

@@ -0,0 +1,132 @@
+package com.atmob.keyboard_android.popup
+
+import android.annotation.SuppressLint
+import android.content.Context
+import android.view.Gravity
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.PopupWindow
+import android.widget.TextView
+import androidx.recyclerview.widget.LinearLayoutManager
+import androidx.recyclerview.widget.RecyclerView
+import com.atmob.keyboard_android.R
+import com.atmob.keyboard_android.enums.Mode
+import com.atmob.keyboard_android.model.ModeItem
+import com.atmob.keyboard_android.popup.item.ModeListItemViewBinder
+import com.blankj.utilcode.util.ConvertUtils
+import me.drakeet.multitype.Items
+import me.drakeet.multitype.MultiTypeAdapter
+
+/**
+ * 模式切换PopupWindow弹窗
+ */
+class ModeSwitchPopupWindow(private val context: Context) {
+    private var popupWindow: PopupWindow? = null
+
+    /**
+     * 显示弹窗
+     *
+     * @param anchorView 锚点View
+     */
+    @SuppressLint("InflateParams", "NotifyDataSetChanged")
+    fun show(anchorView: View) {
+        if (isShowing()) {
+            return
+        }
+
+        val context = anchorView.context
+
+        if (popupWindow == null) {
+            val contentView =
+                LayoutInflater.from(context).inflate(R.layout.popup_mode_switch_attach, null, false)
+
+            val currentSelectModeLayout: View =
+                contentView.findViewById(R.id.current_select_mode_layout)
+            val currentSelectMode: TextView = contentView.findViewById(R.id.current_select_mode)
+            val list: RecyclerView = contentView.findViewById(R.id.list)
+
+            currentSelectModeLayout.setOnClickListener {
+                dismiss()
+            }
+
+            val listItems = Items().apply {
+                addAll(Mode.getAll().mapIndexed { index, item ->
+                    // TODO: 先写死选中第一个,后续根据flutter端传过来的模式,来决定选中哪个
+                    ModeItem(item, selected = index == 0)
+                })
+            }
+
+            list.apply {
+                layoutManager = LinearLayoutManager(context)
+                adapter = MultiTypeAdapter(listItems).apply {
+                    register(ModeItem::class.java, ModeListItemViewBinder { item ->
+                        // 先全部反选
+                        listItems.map {
+                            if (it is ModeItem) {
+                                it.selected = false
+                            }
+                            it
+                        }
+                        // 再选中当前选择的模式
+                        val targetPosition = listItems.indexOf(item)
+                        val targetItem = listItems[targetPosition] as ModeItem
+                        targetItem.selected = true
+                        notifyDataSetChanged()
+
+                        // 更新当前选择的模式
+                        currentSelectMode.text = targetItem.mode.modeName
+
+                        // 关闭弹窗
+                        dismiss()
+                    })
+                }
+            }
+
+            popupWindow = PopupWindow(
+                contentView,
+                ViewGroup.LayoutParams.WRAP_CONTENT,
+                ViewGroup.LayoutParams.WRAP_CONTENT,
+                true
+            ).apply {
+                // 不获取焦点,否则获取焦点会将软键盘关闭
+                isFocusable = false
+                // 点击外部关闭
+                isOutsideTouchable = true
+                // 保持输入法活跃
+                inputMethodMode = PopupWindow.INPUT_METHOD_NEEDED
+                // 设置弹出动画
+                animationStyle = R.style.PopupAnimation
+            }
+        }
+
+        // 获取相对于输入法窗口的坐标
+        val location = IntArray(2)
+        anchorView.getLocationInWindow(location)
+
+        // 计算弹窗显示位置
+        val popupX = location[0] - ConvertUtils.dp2px(5f)
+        val popupY = location[1] - ConvertUtils.dp2px(5f)
+
+        popupWindow?.showAtLocation(
+            anchorView,
+            Gravity.NO_GRAVITY,
+            popupX,
+            popupY
+        )
+    }
+
+    /**
+     * 弹窗是否显示中
+     */
+    fun isShowing(): Boolean {
+        return popupWindow?.isShowing == true
+    }
+
+    /**
+     * 关闭弹窗
+     */
+    fun dismiss() {
+        popupWindow?.dismiss()
+    }
+}

+ 50 - 0
plugins/keyboard_android/android/src/main/kotlin/com/atmob/keyboard_android/popup/item/ModeListItemViewBinder.kt

@@ -0,0 +1,50 @@
+package com.atmob.keyboard_android.popup.item
+
+import android.graphics.Typeface
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.TextView
+import androidx.recyclerview.widget.RecyclerView
+import com.atmob.keyboard_android.R
+import com.atmob.keyboard_android.model.ModeItem
+import me.drakeet.multitype.ItemViewBinder
+
+/**
+ * 模式列表
+ */
+class ModeListItemViewBinder(
+    private val onItemClick: (item: ModeItem) -> Unit
+) : ItemViewBinder<ModeItem, ModeListItemViewBinder.InnerViewHolder>() {
+    override fun onCreateViewHolder(
+        inflater: LayoutInflater,
+        parent: ViewGroup
+    ): InnerViewHolder {
+        return InnerViewHolder(inflater.inflate(R.layout.item_mode, parent, false))
+    }
+
+    override fun onBindViewHolder(
+        holder: InnerViewHolder,
+        item: ModeItem
+    ) {
+        holder.vMode.apply {
+            text = item.mode.modeName
+            // 选中
+            if (item.selected) {
+                setTypeface(typeface, Typeface.BOLD)
+                setBackgroundResource(R.drawable.bg_mode_selected)
+            } else {
+                // 未选中
+                setTypeface(typeface, Typeface.NORMAL)
+                setBackgroundDrawable(null)
+            }
+        }
+        holder.itemView.setOnClickListener {
+            onItemClick.invoke(item)
+        }
+    }
+
+    inner class InnerViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
+        val vMode: TextView = itemView.findViewById(R.id.mode)
+    }
+}

+ 48 - 0
plugins/keyboard_android/android/src/main/kotlin/com/atmob/keyboard_android/util/ContextUtil.java

@@ -0,0 +1,48 @@
+package com.atmob.keyboard_android.util;
+
+import android.annotation.SuppressLint;
+import android.app.Application;
+import android.content.Context;
+
+import java.lang.reflect.InvocationTargetException;
+
+/**
+ * Context工具类
+ */
+public class ContextUtil {
+    @SuppressLint("StaticFieldLeak")
+    private static Context sContext;
+
+    private ContextUtil() {
+    }
+
+    /**
+     * 获取上下文Context
+     */
+    public static Context getContext() {
+        if (sContext == null) {
+            sContext = getApplicationByReflect();
+        }
+        return sContext;
+    }
+
+    /**
+     * 反射ActivityThread获取Context
+     */
+    private static Application getApplicationByReflect() {
+        try {
+            @SuppressLint("PrivateApi")
+            Class<?> activityThread = Class.forName("android.app.ActivityThread");
+            Object thread = activityThread.getMethod("currentActivityThread").invoke(null);
+            Object app = activityThread.getMethod("getApplication").invoke(thread);
+            if (app == null) {
+                throw new NullPointerException("u should init first");
+            }
+            return (Application) app;
+        } catch (NoSuchMethodException | IllegalAccessException
+                 | InvocationTargetException | ClassNotFoundException e) {
+            e.printStackTrace();
+        }
+        throw new NullPointerException("u should init first");
+    }
+}

+ 30 - 0
plugins/keyboard_android/android/src/main/kotlin/com/atmob/keyboard_android/util/KeyboardHolder.kt

@@ -0,0 +1,30 @@
+package com.atmob.keyboard_android.util
+
+import android.annotation.SuppressLint
+import android.view.View
+
+@SuppressLint("StaticFieldLeak")
+object KeyboardHolder {
+    private var keyboardRootView: View? = null
+
+    /**
+     * 保存软键盘的根View
+     */
+    fun attachKeyboardRootView(view: View) {
+        this.keyboardRootView = view
+    }
+
+    /**
+     * 获取软键盘的根View
+     */
+    fun getKeyboardRootView(): View? {
+        return this.keyboardRootView
+    }
+
+    /**
+     * 移除软键盘的根View
+     */
+    fun detachKeyboardRootView() {
+        this.keyboardRootView = null
+    }
+}

+ 7 - 0
plugins/keyboard_android/android/src/main/res/anim/popup_enter.xml

@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<set xmlns:android="http://schemas.android.com/apk/res/android">
+    <alpha
+        android:duration="200"
+        android:fromAlpha="0.5"
+        android:toAlpha="1.0" />
+</set>

+ 7 - 0
plugins/keyboard_android/android/src/main/res/anim/popup_exit.xml

@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<set xmlns:android="http://schemas.android.com/apk/res/android">
+    <alpha
+        android:duration="200"
+        android:fromAlpha="1.0"
+        android:toAlpha="0.5" />
+</set>

+ 7 - 0
plugins/keyboard_android/android/src/main/res/drawable/bg_mode_selected.xml

@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="rectangle">
+
+    <solid android:color="@color/bg_quick_switch_checked" />
+    <corners android:radius="7dp" />
+</shape>

+ 23 - 0
plugins/keyboard_android/android/src/main/res/layout/item_mode.xml

@@ -0,0 +1,23 @@
+<?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="wrap_content">
+
+    <TextView
+        android:id="@+id/mode"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="2dp"
+        android:layout_marginTop="8dp"
+        android:layout_marginEnd="2dp"
+        android:background="@drawable/bg_mode_selected"
+        android:paddingStart="10dp"
+        android:paddingTop="9dp"
+        android:paddingEnd="10dp"
+        android:paddingBottom="9dp"
+        android:textColor="@color/text_color_primary"
+        android:textSize="12sp"
+        android:textStyle="bold"
+        tools:text="@string/mode_help_chat" />
+</FrameLayout>

+ 1 - 1
plugins/keyboard_android/android/src/main/res/layout/keyboard_layout.xml

@@ -29,7 +29,7 @@
         android:layout_height="wrap_content"
         android:orientation="vertical"
         android:padding="5dp"
-        android:visibility="visible">
+        android:visibility="gone">
 
         <!-- 输入框 -->
         <EditText

+ 44 - 0
plugins/keyboard_android/android/src/main/res/layout/popup_mode_switch_attach.xml

@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:background="@mipmap/bg_popup"
+    android:orientation="vertical">
+
+    <LinearLayout
+        android:id="@+id/current_select_mode_layout"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:gravity="center_vertical"
+        android:orientation="horizontal"
+        android:paddingStart="12dp"
+        android:paddingEnd="5dp">
+
+        <TextView
+            android:id="@+id/current_select_mode"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_marginEnd="16dp"
+            android:layout_weight="1"
+            android:text="帮聊"
+            android:textColor="@color/text_color_primary"
+            android:textSize="12sp"
+            android:textStyle="bold" />
+
+        <ImageView
+            android:layout_width="8dp"
+            android:layout_height="8dp"
+            android:layout_margin="8dp"
+            android:src="@mipmap/ic_arrow" />
+    </LinearLayout>
+
+    <Space
+        android:layout_width="match_parent"
+        android:layout_height="10dp" />
+
+    <androidx.recyclerview.widget.RecyclerView
+        android:id="@+id/list"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent" />
+</LinearLayout>

+ 3 - 2
plugins/keyboard_android/android/src/main/res/layout/quick_switch_component.xml

@@ -13,6 +13,7 @@
         android:orientation="horizontal">
 
         <LinearLayout
+            android:id="@+id/mode_switch_layout"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:layout_marginStart="1dp"
@@ -47,9 +48,9 @@
             android:layout_height="wrap_content"
             android:layout_gravity="center_vertical"
             android:layout_marginStart="9dp"
+            android:text="小蕊"
             android:textColor="@color/text_color_primary"
-            android:textSize="12sp"
-            android:text="小蕊" />
+            android:textSize="12sp" />
 
         <ImageView
             android:layout_width="wrap_content"

二进制
plugins/keyboard_android/android/src/main/res/mipmap-xxxhdpi/bg_popup.9.png


二进制
plugins/keyboard_android/android/src/main/res/mipmap-xxxhdpi/ic_arrow.png


+ 2 - 0
plugins/keyboard_android/android/src/main/res/values/colors.xml

@@ -20,6 +20,8 @@
     <color name="text_color_auxiliary2">#F95FAC</color>
     <color name="text_color_auxiliary3">#FD5E4D</color>
     <color name="text_color_auxiliary4">#FB8A3C</color>
+    <!-- 模式切换,选中颜色 -->
     <color name="bg_quick_switch_checked">#DDCFFD</color>
+    <!-- 模式切换,未选中颜色 -->
     <color name="bg_quick_switch_normal">#FFFFFF</color>
 </resources>

+ 8 - 0
plugins/keyboard_android/android/src/main/res/values/theme.xml

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <!-- 弹窗动画 -->
+    <style name="PopupAnimation">
+        <item name="android:windowEnterAnimation">@anim/popup_enter</item>
+        <item name="android:windowExitAnimation">@anim/popup_exit</item>
+    </style>
+</resources>

+ 3 - 0
plugins/keyboard_android/example/android/build.gradle.kts

@@ -1,5 +1,8 @@
 allprojects {
     repositories {
+        maven {
+            url = uri("https://jitpack.io")
+        }
         google()
         mavenCentral()
     }

+ 3 - 0
plugins/keyboard_android/example/android/settings.gradle.kts

@@ -10,6 +10,9 @@ pluginManagement {
     includeBuild("$flutterSdkPath/packages/flutter_tools/gradle")
 
     repositories {
+        maven {
+            url = uri("https://jitpack.io")
+        }
         google()
         mavenCentral()
         gradlePluginPortal()

+ 8 - 0
pubspec.lock

@@ -419,6 +419,14 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "5.9.3"
+  flutter_slidable:
+    dependency: "direct main"
+    description:
+      name: flutter_slidable
+      sha256: ab7dbb16f783307c9d7762ede2593ce32c220ba2ba0fd540a3db8e9a3acba71a
+      url: "https://pub.dev"
+    source: hosted
+    version: "4.0.0"
   flutter_smart_dialog:
     dependency: "direct main"
     description: