From 5ed4df2cce5b3ca44ccbfd1a64d327fd4f7b1899 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=98=8E=E6=9C=88=E4=BE=9D=E5=B8=8C?= <1093286982@qq.com> Date: Fri, 16 Feb 2024 20:24:04 +0800 Subject: [PATCH 01/13] =?UTF-8?q?[add]=202.0=E6=96=B0=E7=89=88ui?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/build.gradle | 4 +- app/src/main/java/com/lu/wxmask/MainHook.java | 72 +- app/src/main/java/com/lu/wxmask/SelfHook.java | 31 +- .../java/com/lu/wxmask/plugin/CommonPlugin.kt | 12 + .../com/lu/wxmask/plugin/WXConfigPlugin.java | 2 +- .../java/com/lu/wxmask/plugin/WXMaskPlugin.kt | 3 + .../plugin/part/MaskUIManagerPluginPart.kt | 41 + .../com/lu/wxmask/plugin/ui/AddMaskItemUI.kt | 3 - .../lu/wxmask/plugin/ui/ConfigManagerUI.kt | 179 ++--- .../com/lu/wxmask/plugin/ui/EditMaskItemUI.kt | 4 - .../wxmask/plugin/ui/MaskItemUIController.kt | 96 +-- .../wxmask/plugin/ui/MaskManagerCenterUI.kt | 216 ++++++ .../java/com/lu/wxmask/plugin/ui/Theme.kt | 38 + .../com/lu/wxmask/plugin/ui/view/AttachUI.kt | 130 ++++ .../lu/wxmask/plugin/ui/view/BottomPopUI.kt | 132 ++++ .../wxmask/ui/adapter/SpinnerListAdapter.kt | 26 + .../com/lu/wxmask/util/ActivityUtils.java | 84 +++ .../java/com/lu/wxmask/util/BarUtils.java | 707 ++++++++++++++++++ .../java/com/lu/wxmask/util/KeyBoxUtil.java | 74 ++ app/src/main/java/com/lu/wxmask/util/Rm.java | 5 + .../main/java/com/lu/wxmask/util/ext/AnyX.kt | 44 +- .../java/com/lu/wxmask/util/ext/ResUtilX.kt | 2 + 22 files changed, 1667 insertions(+), 238 deletions(-) create mode 100644 app/src/main/java/com/lu/wxmask/plugin/part/MaskUIManagerPluginPart.kt create mode 100644 app/src/main/java/com/lu/wxmask/plugin/ui/MaskManagerCenterUI.kt create mode 100644 app/src/main/java/com/lu/wxmask/plugin/ui/Theme.kt create mode 100644 app/src/main/java/com/lu/wxmask/plugin/ui/view/AttachUI.kt create mode 100644 app/src/main/java/com/lu/wxmask/plugin/ui/view/BottomPopUI.kt create mode 100644 app/src/main/java/com/lu/wxmask/ui/adapter/SpinnerListAdapter.kt create mode 100644 app/src/main/java/com/lu/wxmask/util/ActivityUtils.java create mode 100644 app/src/main/java/com/lu/wxmask/util/BarUtils.java create mode 100644 app/src/main/java/com/lu/wxmask/util/KeyBoxUtil.java create mode 100644 app/src/main/java/com/lu/wxmask/util/Rm.java diff --git a/app/build.gradle b/app/build.gradle index a3dd881..526b34c 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -67,8 +67,8 @@ android { applicationId "com.lu.wxmask" minSdk 24 targetSdk 34 - versionCode 24 - versionName "1.23-bug" + versionCode 1000 + versionName "2.0-test" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" diff --git a/app/src/main/java/com/lu/wxmask/MainHook.java b/app/src/main/java/com/lu/wxmask/MainHook.java index 18b12d3..51c6526 100644 --- a/app/src/main/java/com/lu/wxmask/MainHook.java +++ b/app/src/main/java/com/lu/wxmask/MainHook.java @@ -3,6 +3,9 @@ import android.app.Application; import android.app.Instrumentation; import android.content.Context; +import android.content.res.Resources; +import android.content.res.XModuleResources; +import android.nfc.Tag; import androidx.annotation.Keep; import androidx.annotation.NonNull; @@ -16,30 +19,43 @@ import com.lu.wxmask.plugin.CommonPlugin; import com.lu.wxmask.plugin.WXConfigPlugin; import com.lu.wxmask.plugin.WXMaskPlugin; +import com.lu.wxmask.util.Rm; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; import java.util.concurrent.CopyOnWriteArraySet; +import de.robv.android.xposed.IXposedHookInitPackageResources; import de.robv.android.xposed.IXposedHookLoadPackage; +import de.robv.android.xposed.IXposedHookZygoteInit; import de.robv.android.xposed.XC_MethodHook; +import de.robv.android.xposed.callbacks.XC_InitPackageResources; import de.robv.android.xposed.callbacks.XC_LoadPackage; @Keep -public class MainHook implements IXposedHookLoadPackage { +public class MainHook implements IXposedHookLoadPackage, IXposedHookZygoteInit, IXposedHookInitPackageResources { + private static final String TARGET_PACKAGE = "com.tencent.mm"; public static CopyOnWriteArraySet uniqueMetaStore = new CopyOnWriteArraySet<>(); private boolean hasInit = false; private List initUnHookList = new ArrayList<>(); + private static String MODULE_PATH = null; @Override public void handleLoadPackage(XC_LoadPackage.LoadPackageParam lpparam) throws Throwable { - if (BuildConfig.APPLICATION_ID.equals(lpparam.packageName)) { - SelfHook.getInstance().handleLoadPackage(lpparam); - return; - } - if (!"com.tencent.mm".equals(lpparam.processName)) { +// if (BuildConfig.APPLICATION_ID.equals(lpparam.packageName)) { +// SelfHook.getInstance().handleLoadPackage(lpparam); +// return; +// } + + HashSet allowList = new HashSet<>(); + allowList.add(BuildConfig.APPLICATION_ID); + allowList.add(TARGET_PACKAGE); + + if (!allowList.contains(lpparam.processName)) { return; } + LogUtil.setLogger(new SimpleLogger() { @Override public void onLog(int level, @NonNull Object[] objects) { @@ -81,7 +97,7 @@ public void onLog(int level, @NonNull Object[] objects) { return new byte[]{}; } if (Short.TYPE.equals(returnType) || Short.class.equals(returnType)) { - return (short)0; + return (short) 0; } if (BuildConfig.DEBUG) { LogUtil.w("setOnErrorReturnFallback", throwable); @@ -163,6 +179,7 @@ protected void afterHookedMethod(MethodHookParam param) throws Throwable { private void initPlugin(Context context, XC_LoadPackage.LoadPackageParam lpparam) { if (context == null) { + LogUtil.w("context is null"); return; } if (hasInit) { @@ -171,18 +188,49 @@ private void initPlugin(Context context, XC_LoadPackage.LoadPackageParam lpparam LogUtil.i("start init Plugin"); hasInit = true; AppUtil.attachContext(context); + + if (BuildConfig.APPLICATION_ID.equals(lpparam.packageName)) { + initSelfPlugins(context, lpparam); + } else { + initTargetPlugins(context, lpparam); + } + + for (XC_MethodHook.Unhook unhook : initUnHookList) { + if (unhook != null) { + unhook.unhook(); + } + } + LogUtil.i("init plugin finish"); + } + + private void initSelfPlugins(Context context, XC_LoadPackage.LoadPackageParam lpparam) { + SelfHook.getInstance().handleHook(context, lpparam); + } + + private void initTargetPlugins(Context context, XC_LoadPackage.LoadPackageParam lpparam) { //目前生成的plugin都是单例的 PluginRegistry.register( CommonPlugin.class, WXConfigPlugin.class, WXMaskPlugin.class ).handleHooks(context, lpparam); - for (XC_MethodHook.Unhook unhook : initUnHookList) { - if (unhook != null) { - unhook.unhook(); - } + + } + + @Override + public void initZygote(StartupParam startupParam) throws Throwable { + MODULE_PATH = startupParam.modulePath; + } + + @Override + public void handleInitPackageResources(XC_InitPackageResources.InitPackageResourcesParam resparam) throws Throwable { + if (BuildConfig.APPLICATION_ID.equals(resparam.packageName)) { + return; + } + if (TARGET_PACKAGE.equals(resparam.packageName)) { +// XModuleResources xRes = XModuleResources.createInstance(MODULE_PATH, resparam.res); +// Rm.mask_layout_plugin_manager = resparam.res.addResource(xRes, R.layout.mask_layout_plugin_manager); } - LogUtil.i("init plugin finish"); } } \ No newline at end of file diff --git a/app/src/main/java/com/lu/wxmask/SelfHook.java b/app/src/main/java/com/lu/wxmask/SelfHook.java index 0a5299d..fb9e0b4 100644 --- a/app/src/main/java/com/lu/wxmask/SelfHook.java +++ b/app/src/main/java/com/lu/wxmask/SelfHook.java @@ -1,16 +1,29 @@ package com.lu.wxmask; +import android.app.Activity; +import android.app.Application; +import android.content.Context; + import androidx.annotation.Keep; +import com.lu.lposed.api2.XC_MethodHook2; +import com.lu.lposed.api2.XposedHelpers2; +import com.lu.lposed.plugin.IPlugin; +import com.lu.magic.util.AppUtil; +import com.lu.magic.util.ResUtil; import com.lu.magic.util.log.LogUtil; +import com.lu.wxmask.plugin.ui.MaskManagerCenterUI; +import com.lu.wxmask.util.ext.ResUtilXKt; import de.robv.android.xposed.XC_MethodHook; import de.robv.android.xposed.XposedHelpers; import de.robv.android.xposed.callbacks.XC_LoadPackage; @Keep -public class SelfHook { - private static class Holder { +public class SelfHook implements IPlugin { + + + private final static class Holder { private static final SelfHook INSTANCE = new SelfHook(); } @@ -23,7 +36,8 @@ public boolean isModuleEnable() { return false; } - public void handleLoadPackage(XC_LoadPackage.LoadPackageParam lpparam) { + @Override + public void handleHook(Context context, XC_LoadPackage.LoadPackageParam lpparam) { XposedHelpers.findAndHookMethod( SelfHook.class.getName(), lpparam.classLoader, @@ -36,5 +50,16 @@ protected void beforeHookedMethod(MethodHookParam param) throws Throwable { } ); + XposedHelpers.findAndHookMethod( + ClazzN.from("android.app.Activity"), + "onResume", + new XC_MethodHook() { + @Override + protected void afterHookedMethod(MethodHookParam param) throws Throwable { + Activity act = (Activity) param.thisObject; + act.findViewById(ResUtilXKt.getViewId(ResUtil.INSTANCE, "action_bar")).setOnClickListener(v -> new MaskManagerCenterUI(act).show()); + } + }); + } } \ No newline at end of file diff --git a/app/src/main/java/com/lu/wxmask/plugin/CommonPlugin.kt b/app/src/main/java/com/lu/wxmask/plugin/CommonPlugin.kt index 4921c40..caad477 100644 --- a/app/src/main/java/com/lu/wxmask/plugin/CommonPlugin.kt +++ b/app/src/main/java/com/lu/wxmask/plugin/CommonPlugin.kt @@ -1,8 +1,20 @@ package com.lu.wxmask.plugin import android.content.Context +import android.content.res.XModuleResources +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import com.lu.lposed.api2.XC_MethodHook2 +import com.lu.lposed.api2.XposedHelpers2 import com.lu.lposed.plugin.IPlugin +import com.lu.magic.util.ResUtil +import com.lu.wxmask.ClazzN +import com.lu.wxmask.plugin.ui.MaskManagerCenterUI import com.lu.wxmask.util.HookPointManager +import com.lu.wxmask.util.ext.getViewId import de.robv.android.xposed.callbacks.XC_LoadPackage class CommonPlugin : IPlugin { diff --git a/app/src/main/java/com/lu/wxmask/plugin/WXConfigPlugin.java b/app/src/main/java/com/lu/wxmask/plugin/WXConfigPlugin.java index 457c281..715002b 100644 --- a/app/src/main/java/com/lu/wxmask/plugin/WXConfigPlugin.java +++ b/app/src/main/java/com/lu/wxmask/plugin/WXConfigPlugin.java @@ -114,7 +114,7 @@ private void onEnterConfigUI(Activity activity, Intent intent) { } private void showManagerConfigUI(Activity activity, Intent intent) { - new ConfigManagerUI(activity).initUI().show(); + new ConfigManagerUI(activity).show(); } private void showAddTipDialog(Activity activity) { diff --git a/app/src/main/java/com/lu/wxmask/plugin/WXMaskPlugin.kt b/app/src/main/java/com/lu/wxmask/plugin/WXMaskPlugin.kt index cc9d401..9f5b80c 100644 --- a/app/src/main/java/com/lu/wxmask/plugin/WXMaskPlugin.kt +++ b/app/src/main/java/com/lu/wxmask/plugin/WXMaskPlugin.kt @@ -8,6 +8,7 @@ import com.lu.wxmask.plugin.part.EmptySingChatHistoryGalleryPluginPart import com.lu.wxmask.plugin.part.EnterChattingUIPluginPart import com.lu.wxmask.plugin.part.HideMainUIListPluginPart import com.lu.wxmask.plugin.part.HideSearchListUIPluginPart +import com.lu.wxmask.plugin.part.MaskUIManagerPluginPart import com.lu.wxmask.util.ConfigUtil import com.lu.wxmask.util.ConfigUtil.ConfigSetObserver import de.robv.android.xposed.callbacks.XC_LoadPackage.LoadPackageParam @@ -19,6 +20,7 @@ class WXMaskPlugin : IPlugin, ConfigSetObserver { private val enterChattingUIPluginPart = EnterChattingUIPluginPart() private val hideMainUIListPluginPart = HideMainUIListPluginPart() private val emptySingChatHistoryGalleryPluginPart = EmptySingChatHistoryGalleryPluginPart() + private val maskUIManagerPluginPart = MaskUIManagerPluginPart() companion object { fun containChatUser(chatUser: String?): Boolean { @@ -57,6 +59,7 @@ class WXMaskPlugin : IPlugin, ConfigSetObserver { enterChattingUIPluginPart.handleHook(context, lpparam) // hideSearchListPluginPart.handleHook(context, lpparam) emptySingChatHistoryGalleryPluginPart.handleHook(context, lpparam) + maskUIManagerPluginPart.handleHook(context, lpparam) } diff --git a/app/src/main/java/com/lu/wxmask/plugin/part/MaskUIManagerPluginPart.kt b/app/src/main/java/com/lu/wxmask/plugin/part/MaskUIManagerPluginPart.kt new file mode 100644 index 0000000..68624ac --- /dev/null +++ b/app/src/main/java/com/lu/wxmask/plugin/part/MaskUIManagerPluginPart.kt @@ -0,0 +1,41 @@ +package com.lu.wxmask.plugin.part + +import android.app.Activity +import android.content.Context +import android.view.ViewGroup +import android.widget.Button +import com.lu.lposed.api2.XC_MethodHook2 +import com.lu.lposed.api2.XposedHelpers2 +import com.lu.lposed.plugin.IPlugin +import com.lu.magic.util.view.ChildDeepCheck +import com.lu.wxmask.ClazzN +import com.lu.wxmask.plugin.ui.MaskManagerCenterUI +import de.robv.android.xposed.callbacks.XC_LoadPackage + +/** + * 糊脸ui管理页面 + */ +class MaskUIManagerPluginPart : IPlugin { + override fun handleHook(context: Context?, lpparam: XC_LoadPackage.LoadPackageParam?) { + XposedHelpers2.findAndHookMethod( + ClazzN.from("com.tencent.mm.plugin.setting.ui.setting.SettingsCareModeIntro"), + "initView", + object : XC_MethodHook2() { + override fun afterHookedMethod(param: MethodHookParam) { + val act: Activity = param.thisObject as Activity + val contentView = act.findViewById(android.R.id.content) + ChildDeepCheck().filter(contentView) { + return@filter it is Button && it.id > 0 + }.forEach { + it.setOnLongClickListener { v -> + MaskManagerCenterUI(act).show() + return@setOnLongClickListener true + } + } + } + } + ) + } + + +} \ No newline at end of file diff --git a/app/src/main/java/com/lu/wxmask/plugin/ui/AddMaskItemUI.kt b/app/src/main/java/com/lu/wxmask/plugin/ui/AddMaskItemUI.kt index a88cb82..b0115fa 100644 --- a/app/src/main/java/com/lu/wxmask/plugin/ui/AddMaskItemUI.kt +++ b/app/src/main/java/com/lu/wxmask/plugin/ui/AddMaskItemUI.kt @@ -81,12 +81,9 @@ class AddMaskItemUI( val tipMode = ui.tipSpinnerSelectedItem.first val tipData = GsonUtil.toJsonTree(MaskItemBean.TipData(tipMess)).asJsonObject - val clickCount = ui.etClickCount.text.toElseString("5").toInt() - val duration = ui.etDuration.text.toElseString("150").toInt() MaskItemBean(maskId, maskName, tipMode, tipData).let { ConfigUtil.addMaskList(it) - ConfigUtil.setTemporary(QuickTemporaryBean(duration, clickCount)) configListener?.invoke(dialog, it) } dialog.dismiss() diff --git a/app/src/main/java/com/lu/wxmask/plugin/ui/ConfigManagerUI.kt b/app/src/main/java/com/lu/wxmask/plugin/ui/ConfigManagerUI.kt index 8c8d836..342d10a 100644 --- a/app/src/main/java/com/lu/wxmask/plugin/ui/ConfigManagerUI.kt +++ b/app/src/main/java/com/lu/wxmask/plugin/ui/ConfigManagerUI.kt @@ -2,18 +2,17 @@ package com.lu.wxmask.plugin.ui import android.app.Activity import android.app.AlertDialog -import android.content.Context import android.graphics.Color import android.graphics.drawable.ColorDrawable +import android.graphics.drawable.GradientDrawable import android.view.Gravity -import android.view.KeyEvent import android.view.View import android.view.ViewGroup +import android.view.ViewGroup.LayoutParams.MATCH_PARENT import android.view.ViewGroup.MarginLayoutParams import android.widget.FrameLayout import android.widget.LinearLayout import android.widget.ListView -import android.widget.PopupWindow import android.widget.TextView import androidx.core.view.setPadding import com.lu.magic.util.ResUtil @@ -23,7 +22,10 @@ import com.lu.magic.util.ripple.RippleApplyUtil import com.lu.wxmask.adapter.AbsListAdapter import com.lu.wxmask.adapter.CommonListAdapter import com.lu.wxmask.bean.MaskItemBean +import com.lu.wxmask.plugin.ui.view.BottomPopUI import com.lu.wxmask.util.ConfigUtil +import com.lu.wxmask.util.ext.dp + interface IConfigManagerUI { fun onCreateView(): View @@ -32,118 +34,63 @@ interface IConfigManagerUI { } // PopWindow全屏+返回键监听弹窗,暂不需要,没有那么多配置 -internal class ConfigManagerUI(private val activity: Activity) : IConfigManagerUI { - private val popwindow = PopupWindow(activity) - private val controller = ConfigManagerUIController(activity) - - fun initUI(): ConfigManagerUI { - popwindow.apply { -// setBackgroundDrawable(ColorDrawable(ResUtil.getAttrColor(activity, android.R.attr.windowBackground))) - if (ResUtil.isAppNightMode(activity)) { - setBackgroundDrawable(ColorDrawable(0xFF303030.toInt())) - } else { - setBackgroundDrawable(ColorDrawable(Color.WHITE)) - } - // 强制适配夜间模式,系统底层直接修改的颜色 - // contentView.isForceDarkAllowed = true - // setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) - - isOutsideTouchable = true - //contentView监听返回键keylistener,需要焦点 - isFocusable = true - - activity.applicationContext.resources.displayMetrics.let { - width = it.widthPixels - height = MarginLayoutParams.WRAP_CONTENT - } - contentView = onCreateView() - - setOnDismissListener { - activity.window.attributes.let { - it.alpha = 1f - activity.window.attributes = it - } - } - //不剪切 - isClippingEnabled = false - } +internal class ConfigManagerUI(private val context: Activity) : IConfigManagerUI { + private lateinit var listAdapter: CommonListAdapter + private val popwindow: BottomPopUI +// private val mContentLayout = FrameLayout(context) - return this + init { + popwindow = BottomPopUI(onCreateView(), topDragBoundHeight = 44.dp) } - override fun onCreateView(): View { - val root = controller.onCreateView() - root.layoutParams.let { - if (it is LinearLayout.LayoutParams) { - it.marginStart = controller.dp24 - it.marginEnd = controller.dp24 - } - } - - root.setOnKeyListener { _, keyCode, _ -> - if (keyCode == KeyEvent.KEYCODE_BACK) { - dismiss() - return@setOnKeyListener true - } - return@setOnKeyListener false - } - return root - } override fun dismiss() { popwindow.dismiss() } override fun show() { - val anchor = activity.findViewById(android.R.id.content) - //避免首次,未创建完成,无法显示 - anchor.post { - activity.window.attributes.let { - it.alpha = 0.3f - activity.window.attributes = it - } - popwindow.showAtLocation(anchor, Gravity.CENTER, 0, 0) - } + popwindow.show() } -} - -private class ConfigManagerUIController(private val context: Context) { - private lateinit var listAdapter: CommonListAdapter - private lateinit var contentView: LinearLayout - val dp24 = SizeUtil.dp2px(context.resources, 24f).toInt() - - fun onCreateView(): View { - contentView = LinearLayout(context).apply { - layoutParams = LinearLayout.LayoutParams( - LinearLayout.LayoutParams.MATCH_PARENT, - LinearLayout.LayoutParams.MATCH_PARENT - ) - setPadding(dp24) + override fun onCreateView(): View { + return LinearLayout(context).apply { + layoutParams = MarginLayoutParams(MATCH_PARENT, 480.dp) + setPadding(24.dp) orientation = LinearLayout.VERTICAL - } - initTopLayout() - initMaskListView() + // 强制适配夜间模式,系统底层直接修改的颜色,不一定生效 + // isForceDarkAllowed = true + background = GradientDrawable().apply { + shape = GradientDrawable.RECTANGLE + if (ResUtil.isAppNightMode(context)) { + setColor(Theme.Color.bgColorDark) + } else { + setColor(Theme.Color.bgColor) + } + cornerRadii = floatArrayOf(16f.dp, 16f.dp, 16f.dp, 16f.dp, 0f, 0f, 0f, 0f) + } - return contentView + addView(initTopLayout()) + addView(initMaskListView()) + } } - private fun initTopLayout() { - FrameLayout(context).apply { - TextView(context).apply { + private fun initTopLayout(): FrameLayout { + + return FrameLayout(context).apply { + + layoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT).apply { + gravity = Gravity.CENTER_VERTICAL + } + addView(TextView(context).apply { + layoutParams = FrameLayout.LayoutParams(FrameLayout.LayoutParams.WRAP_CONTENT, FrameLayout.LayoutParams.WRAP_CONTENT).apply { + gravity = Gravity.CENTER + } setTextColor(context.getColor(android.R.color.tab_indicator_text)) + textSize = 16f text = "配置管理" - }.apply { - layoutParams = FrameLayout.LayoutParams( - FrameLayout.LayoutParams.WRAP_CONTENT, - FrameLayout.LayoutParams.WRAP_CONTENT - ) - addView(this) - } - }.apply { - - TextView(context).apply { + }) + addView(TextView(context).apply { text = "+" textSize = SizeUtil.sp2px(context.resources, 8f) setTextColor(context.getColor(android.R.color.tab_indicator_text)) @@ -151,37 +98,30 @@ private class ConfigManagerUIController(private val context: Context) { showAddMaskItemDialog() } RippleApplyUtil.apply(this, RectangleRippleBuilder(Color.TRANSPARENT, 0x33333333, 4)) - }.apply { val size = (textSize * 1.5).toInt() - layoutParams = FrameLayout.LayoutParams(size, size).also { - it.gravity = Gravity.END + layoutParams = FrameLayout.LayoutParams(size, size).apply { + gravity = Gravity.END } this.gravity = Gravity.CENTER - addView(this) - } - }.apply { - layoutParams = LinearLayout.LayoutParams( - LinearLayout.LayoutParams.MATCH_PARENT, - LinearLayout.LayoutParams.WRAP_CONTENT - ).also { - it.gravity = Gravity.CENTER_VERTICAL - } - contentView.addView(this) + }) } } - private fun initMaskListView() { - val listView = ListView(context).apply { - layoutParams = LinearLayout.LayoutParams( - MarginLayoutParams.MATCH_PARENT, - MarginLayoutParams.WRAP_CONTENT - ).also { + private fun initMaskListView(): ListView { + initListAdapter() + return ListView(context).apply { + layoutParams = LinearLayout.LayoutParams(MarginLayoutParams.MATCH_PARENT, MarginLayoutParams.WRAP_CONTENT).apply { + topMargin = 16.dp } divider = null selector = ColorDrawable(Color.TRANSPARENT) + adapter = listAdapter } - listAdapter = object : CommonListAdapter() { + } + + private fun initListAdapter() { + listAdapter = object : CommonListAdapter() { init { //去重 val dataListTemp = ConfigUtil.getMaskList().let { @@ -201,8 +141,7 @@ private class ConfigManagerUIController(private val context: Context) { MarginLayoutParams.MATCH_PARENT, MarginLayoutParams.WRAP_CONTENT ) - val dp6 = SizeUtil.dp2px(context.resources, 6f).toInt() - it.setPadding(dp6) + it.setPadding(6.dp) RippleApplyUtil.apply(it, RectangleRippleBuilder(Color.TRANSPARENT, 0x33333333)) } @@ -235,8 +174,6 @@ private class ConfigManagerUIController(private val context: Context) { } - listView.adapter = listAdapter - contentView.addView(listView) } private fun showDeleteMaskItemDialog(position: Int) { diff --git a/app/src/main/java/com/lu/wxmask/plugin/ui/EditMaskItemUI.kt b/app/src/main/java/com/lu/wxmask/plugin/ui/EditMaskItemUI.kt index 1a3838d..d07482a 100644 --- a/app/src/main/java/com/lu/wxmask/plugin/ui/EditMaskItemUI.kt +++ b/app/src/main/java/com/lu/wxmask/plugin/ui/EditMaskItemUI.kt @@ -97,10 +97,6 @@ class EditMaskItemUI( maskItemBean.tipData = it } - val clickCount = ui.etClickCount.text.toElseString("5").toInt() - val duration = ui.etDuration.text.toElseString("150").toInt() - ConfigUtil.setTemporary(QuickTemporaryBean(duration, clickCount)) - ConfigUtil.setMaskList(lst) ToastUtil.show("已更新!") onConfigChangeListener?.invoke(dialog, maskItemBean, MODE_CONFIG_UPDATE) diff --git a/app/src/main/java/com/lu/wxmask/plugin/ui/MaskItemUIController.kt b/app/src/main/java/com/lu/wxmask/plugin/ui/MaskItemUIController.kt index 72f14b2..91faff8 100644 --- a/app/src/main/java/com/lu/wxmask/plugin/ui/MaskItemUIController.kt +++ b/app/src/main/java/com/lu/wxmask/plugin/ui/MaskItemUIController.kt @@ -1,7 +1,6 @@ package com.lu.wxmask.plugin.ui import android.content.Context -import android.text.InputType import android.view.Gravity import android.view.View import android.view.ViewGroup @@ -13,13 +12,14 @@ import android.widget.TextView import androidx.core.view.setPadding import com.google.gson.JsonObject import com.lu.magic.util.SizeUtil -import com.lu.magic.util.kxt.toElseString import com.lu.wxmask.Constrant import com.lu.wxmask.adapter.AbsListAdapter import com.lu.wxmask.adapter.CommonListAdapter import com.lu.wxmask.bean.MaskItemBean import com.lu.wxmask.bean.QuickTemporaryBean +import com.lu.wxmask.ui.adapter.SpinnerListAdapter import com.lu.wxmask.util.ConfigUtil +import com.lu.wxmask.util.ext.dp internal class MaskItemUIController(private val context: Context, private val mask: MaskItemBean) { private val viewId: MutableMap = mutableMapOf() @@ -87,105 +87,19 @@ internal class MaskItemUIController(private val context: Context, private val ma get() = spinnerTipDataList[tipSpinner.selectedItemPosition] - val blockTemporary = LinearLayout(context).also { block -> - block.orientation = LinearLayout.VERTICAL - - val quick = QuickTemporaryBean(ConfigUtil.getTemporaryJson()?: JsonObject()) - block.addView(LinearLayout(context).also { row -> - row.orientation = LinearLayout.HORIZONTAL - row.gravity = Gravity.CENTER_VERTICAL - - row.addView(TextView(context).also { - it.text = "聊天页临时解除(全局配置)" - }) - row.addView( - Spinner(context).also { - viewId["spTemporaryMode"] = it - it.gravity = Gravity.RIGHT - val dataList = arrayListOf( - Constrant.CONFIG_TEMPORARY_MODE_QUICK_CLICK to "快速点击", - Constrant.CONFIG_TEMPORARY_MODE_LONG_PRESS to "长按解除", - Constrant.CONFIG_TEMPORARY_MODE_CIPHER to "长按解除" - - ) - it.adapter = SpinnerListAdapter(dataList) - it.visibility = View.GONE - }, - LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT - ) - }) - - block.addView(LinearLayout(context).also { row -> - row.orientation = LinearLayout.HORIZONTAL - row.gravity = Gravity.CENTER_VERTICAL - row.addView( - TextView(context).also { - it.text = "间隔时长/毫秒:" - }, - LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT - ) - row.addView( - EditText(context).also { - viewId["etDuration"] = it - it.inputType = InputType.TYPE_CLASS_NUMBER - it.setText(quick.duration.toElseString("150")) - }, - LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT - ) - }, LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT) - - block.addView(LinearLayout(context).also { row -> - row.orientation = LinearLayout.HORIZONTAL - row.gravity = Gravity.CENTER_VERTICAL - row.addView( - TextView(context).also { - it.text = "点击次数/次:" - }, - LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT - ) - row.addView(EditText(context).also { - viewId["etClickCount"] = it - it.inputType = InputType.TYPE_CLASS_NUMBER - it.setText(quick.clickCount.toElseString("5")) - }, LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT) - }, LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT) - } - - val etClickCount: EditText = viewId["etClickCount"] as EditText - val etDuration: EditText = viewId["etDuration"] as EditText - init { - val lp = LinearLayout.LayoutParams( + LinearLayout.LayoutParams( LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT - ).also { - it.topMargin = dp24 / 6 + ).apply { + topMargin = 4.dp } root.addView(etMaskId, LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT) root.addView(etTagName, LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT) root.addView(tipSpinner, LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT) root.addView(etTipMess, LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT) - root.addView(blockTemporary, lp) } - inner class SpinnerListAdapter(spinnerDataList: ArrayList>) : - CommonListAdapter, AbsListAdapter.ViewHolder>() { - init { - setData(spinnerDataList) - } - - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { - return ViewHolder(TextView(context).also { it.setPadding(dp24 / 6) }) - } - - override fun onBindViewHolder(vh: ViewHolder, position: Int, parent: ViewGroup) { - val itemView = vh.itemView - if (itemView is TextView) { - itemView.text = getItem(position)?.second - } - } - } - } diff --git a/app/src/main/java/com/lu/wxmask/plugin/ui/MaskManagerCenterUI.kt b/app/src/main/java/com/lu/wxmask/plugin/ui/MaskManagerCenterUI.kt new file mode 100644 index 0000000..68ad139 --- /dev/null +++ b/app/src/main/java/com/lu/wxmask/plugin/ui/MaskManagerCenterUI.kt @@ -0,0 +1,216 @@ +package com.lu.wxmask.plugin.ui + +import android.app.AlertDialog +import android.content.Context +import android.graphics.Color +import android.text.InputType +import android.util.AttributeSet +import android.util.TypedValue +import android.view.Gravity +import android.view.View +import android.view.ViewGroup +import android.view.ViewGroup.LayoutParams.MATCH_PARENT +import android.view.ViewGroup.LayoutParams.WRAP_CONTENT +import android.widget.EditText +import android.widget.FrameLayout +import android.widget.LinearLayout +import android.widget.Spinner +import android.widget.TextView +import com.google.gson.JsonObject +import com.lu.magic.util.ToastUtil +import com.lu.magic.util.kxt.toElseString +import com.lu.wxmask.Constrant +import com.lu.wxmask.bean.QuickTemporaryBean +import com.lu.wxmask.plugin.ui.view.AttachUI +import com.lu.wxmask.ui.adapter.SpinnerListAdapter +import com.lu.wxmask.util.ConfigUtil +import com.lu.wxmask.util.ext.dp +import com.lu.wxmask.util.ext.toIntElse +import com.lu.wxmask.util.ext.toJson + + +class MaskManagerCenterUI @JvmOverloads constructor( + context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0, defStyleRes: Int = 0 +) : AttachUI(context, attrs, defStyleAttr, defStyleRes) { + + var mQuickClickCountEdit: EditText? = null + var mQuickClickDurationEdit: EditText? = null + + override fun onCreateView(container: ViewGroup): View { + container.setBackgroundColor(Theme.Color.bgColor) + return LinearLayout(context).apply { + layoutParams = LinearLayout.LayoutParams(MATCH_PARENT, WRAP_CONTENT).apply { + orientation = LinearLayout.VERTICAL + } + addView(getTitleBar()) + addView(getContent()) + } + } + + private fun getTitleBar(): View { + return FrameLayout(context).apply { + layoutParams = MarginLayoutParams(MATCH_PARENT, WRAP_CONTENT).apply { + } + + addView(TextView(context).apply { + layoutParams = FrameLayout.LayoutParams(44.dp, 44.dp).apply { + gravity = Gravity.START + marginStart = 24.dp + marginEnd = 24.dp + } + setTextColor(Color.BLACK) + setTextSize(TypedValue.COMPLEX_UNIT_SP, 24f) + text = "×" + + setOnClickListener { + dismiss() + } + }) + addView(TextView(context).apply { + layoutParams = FrameLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT).apply { + gravity = Gravity.CENTER + } + setTextColor(Color.BLACK) + setTextSize(TypedValue.COMPLEX_UNIT_SP, 18f) + text = "老年人配置中心" + }) + } + } + + override fun dismiss() { + if (mQuickClickCountEdit?.text.isNullOrBlank() || mQuickClickDurationEdit?.text.isNullOrBlank()) { + ToastUtil.show("不能为空") + return + } + + val quickTempLocal = QuickTemporaryBean(ConfigUtil.getTemporaryJson() ?: JsonObject()) + val uiQuickTemp = QuickTemporaryBean().apply { + duration = mQuickClickDurationEdit?.text.toIntElse(duration) + clickCount = mQuickClickCountEdit?.text.toIntElse(clickCount) + } + + if (quickTempLocal.toJson() != (uiQuickTemp.toJson())) { + //数据发生了变更 + AlertDialog.Builder(context) + .setTitle("提示") + .setIcon(context.applicationInfo.icon) + .setMessage("是否保存修改?") + .setNegativeButton("取消", null) + .setPositiveButton("确定") { _, _ -> + ConfigUtil.setTemporary(uiQuickTemp) + super.dismiss() + }.show() + } else { + super.dismiss() + } + + } + + private fun getContent(): View { + val quickTemp = QuickTemporaryBean(ConfigUtil.getTemporaryJson() ?: JsonObject()) + + return LinearLayout(context).apply { + layoutParams = LinearLayout.LayoutParams(MATCH_PARENT, WRAP_CONTENT).apply { + orientation = LinearLayout.VERTICAL + } + setPadding(24.dp, 12.dp, 24.dp, 12.dp) + addView(FrameLayout(context).apply { + layoutParams = FrameLayout.LayoutParams(MATCH_PARENT, WRAP_CONTENT) + addView( + ItemTitle("小黑屋名单管理") + ) + addView(TextView(context).apply { + layoutParams = FrameLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT).apply { + gravity = Gravity.END or Gravity.CENTER_VERTICAL + } + text = ">" + textSize = 18f + scaleX = 0.6f + setTextColor(Color.GRAY) + }) + setOnClickListener { + ConfigManagerUI(getActivity()!!).show() + } + }) + addView(Divider()) + addView(ItemTitle("临时解除", onClick = { + + })) + addView(Spinner(context).apply { + gravity = Gravity.RIGHT + val dataList = arrayListOf( + Constrant.CONFIG_TEMPORARY_MODE_QUICK_CLICK to "快速点击", + Constrant.CONFIG_TEMPORARY_MODE_LONG_PRESS to "长按解除", + Constrant.CONFIG_TEMPORARY_MODE_CIPHER to "长按解除" + + ) + adapter = SpinnerListAdapter(dataList) + visibility = View.GONE + }) + + addView(LinearLayout(context).apply { + layoutParams = LinearLayout.LayoutParams(MATCH_PARENT, WRAP_CONTENT).apply { + orientation = LinearLayout.HORIZONTAL + } + addView(ItemSubTitle("间隔时长/毫秒:")) + addView(ItemSubEdit(quickTemp.duration.toElseString("150")).apply { + inputType = InputType.TYPE_CLASS_NUMBER + mQuickClickDurationEdit = this + }) + }) + + addView(LinearLayout(context).apply { + layoutParams = LinearLayout.LayoutParams(MATCH_PARENT, WRAP_CONTENT).apply { + orientation = LinearLayout.HORIZONTAL + topMargin = 4.dp + } + addView(ItemSubTitle("点击次数/次:")) + addView(ItemSubEdit(quickTemp.clickCount.toElseString("5")).apply { + mQuickClickCountEdit = this + inputType = InputType.TYPE_CLASS_NUMBER + }) + }) + } + } + + private fun Divider() = View(context).apply { + layoutParams = MarginLayoutParams(MATCH_PARENT, 1.dp).apply { + + } + setBackgroundColor(Theme.Color.divider) + } + + private fun ItemSubEdit(text: String) = EditText(context).apply { + layoutParams = LinearLayout.LayoutParams(0, WRAP_CONTENT).apply { + weight = 1f + gravity = Gravity.CENTER_VERTICAL + } + Theme.Style.itemSubTitleStyle(this) + setText(text) + } + + private fun ItemSubTitle(text: String, onClick: View.OnClickListener? = null) = TextView(context).apply { + layoutParams = LinearLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT).apply { + gravity = Gravity.CENTER_VERTICAL + } + gravity = Gravity.CENTER_VERTICAL + Theme.Style.itemSubTitleStyle(this) + this.text = text + this.setOnClickListener(onClick) + } + + private fun ItemTitle(text: String, onClick: View.OnClickListener? = null) = TextView(context).apply { + layoutParams = LinearLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT).apply { + topMargin = 12.dp + bottomMargin = 12.dp + } + gravity = Gravity.CENTER_VERTICAL + Theme.Style.itemTitleStyle(this) + this.text = text + if (onClick != null) { + this.setOnClickListener(onClick) + } + } + +} + diff --git a/app/src/main/java/com/lu/wxmask/plugin/ui/Theme.kt b/app/src/main/java/com/lu/wxmask/plugin/ui/Theme.kt new file mode 100644 index 0000000..851b965 --- /dev/null +++ b/app/src/main/java/com/lu/wxmask/plugin/ui/Theme.kt @@ -0,0 +1,38 @@ +package com.lu.wxmask.plugin.ui + +import android.view.View +import android.widget.TextView +import androidx.core.util.Consumer + +interface Theme { + companion object { + @JvmStatic + val Color = Theme.Colors() + val Style = Theme.Styles() + + } + + class Colors { + val bgColor = 0xFFF9F6F6.toInt() + val bgColorDark = 0xFF303030.toInt() + val divider = 0XFFCCCCCC.toInt() + } + + class Styles { + val itemTitleStyle = fun(value: TextView) { + value.apply { + textSize = 16f + setTextColor(android.graphics.Color.BLACK) + } + } + val itemSubTitleStyle: (v: TextView) -> Unit = { + it.apply { + textSize = 14f + setTextColor(android.graphics.Color.BLACK) + } + } + + + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/lu/wxmask/plugin/ui/view/AttachUI.kt b/app/src/main/java/com/lu/wxmask/plugin/ui/view/AttachUI.kt new file mode 100644 index 0000000..e1178ab --- /dev/null +++ b/app/src/main/java/com/lu/wxmask/plugin/ui/view/AttachUI.kt @@ -0,0 +1,130 @@ +package com.lu.wxmask.plugin.ui.view + +import android.app.Activity +import android.content.Context +import android.content.ContextWrapper +import android.os.Build +import android.util.AttributeSet +import android.view.KeyEvent +import android.view.View +import android.view.ViewGroup +import android.widget.FrameLayout +import androidx.core.view.ViewCompat +import com.lu.wxmask.util.BarUtils +import com.lu.wxmask.util.KeyBoxUtil +import com.lu.wxmask.util.ext.dp + + +open class AttachUI @JvmOverloads constructor( + context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0, defStyleRes: Int = 0 +) : FrameLayout(context, attrs, defStyleAttr, defStyleRes), ViewCompat.OnUnhandledKeyEventListenerCompat { + protected var isViewCreated = false + open fun onCreateView(container: ViewGroup): View { + return View(context) + } + + open fun dismiss() { + if (!isShowing()) { + return + } + KeyBoxUtil.hideSoftInput(this) + val container = parent as ViewGroup? + container?.removeView(this) + } + + override fun onKeyUp(keyCode: Int, event: KeyEvent?): Boolean { + if (keyCode == KeyEvent.KEYCODE_BACK && event?.action == KeyEvent.ACTION_UP) { + dismiss() + return true + } + return super.onKeyUp(keyCode, event) + } + + + override fun onUnhandledKeyEvent(v: View, event: KeyEvent): Boolean { + if (event.keyCode == KeyEvent.KEYCODE_BACK && event.action == KeyEvent.ACTION_UP) { + //处理未处理的按键事件,避免多个AttachUI实例,无法一一dismiss掉 + dismiss() + return true + } + return false + } + + override fun dispatchWindowFocusChanged(hasFocus: Boolean) { + super.dispatchWindowFocusChanged(hasFocus) + } + + override fun onAttachedToWindow() { + super.onAttachedToWindow() + init() + } + + override fun onDetachedFromWindow() { + super.onDetachedFromWindow() +// clearFocus() + } + + open fun show() { + if (isShowing()) { + return + } + KeyBoxUtil.hideSoftInput(this) + + getRootContainer()?.removeView(this) + var lp = layoutParams + if (lp == null) { + lp = MarginLayoutParams(MarginLayoutParams.MATCH_PARENT, MarginLayoutParams.MATCH_PARENT) + } else { + lp.width = MarginLayoutParams.MATCH_PARENT + lp.height = MarginLayoutParams.MATCH_PARENT + } + BarUtils.setStatusBarLightMode(getActivity()!!, true) + getRootContainer()?.addView(this, lp) + } + + open fun isShowing(): Boolean { + return parent != null && visibility == View.VISIBLE + } + + private fun init() { + //防止点击穿透 + isClickable = true + + //获取焦点,以便处理返回事件 + isFocusableInTouchMode = true + requestFocus() + + if (Build.VERSION.SDK_INT >= 28) { + //监听处理未处理的按键事件,避免多个AttachUI实例,无法一一dismiss掉 + ViewCompat.removeOnUnhandledKeyEventListener(this, this) + ViewCompat.addOnUnhandledKeyEventListener(this, this) + } + + setPadding(paddingLeft, 44.dp, paddingRight, paddingBottom) + if (!isViewCreated) { + addView(onCreateView(this)) + } + isViewCreated = true + + } + + protected fun getActivity(): Activity? { + var ctx = context + while (ctx is ContextWrapper) { + ctx = if (context is Activity) { + return context as Activity? + } else { + (context as ContextWrapper).baseContext + } + } + return null + } + + + protected fun getRootContainer(): ViewGroup? { + return (getActivity()?.window?.decorView) as ViewGroup? + + } + + +} \ No newline at end of file diff --git a/app/src/main/java/com/lu/wxmask/plugin/ui/view/BottomPopUI.kt b/app/src/main/java/com/lu/wxmask/plugin/ui/view/BottomPopUI.kt new file mode 100644 index 0000000..91d7b92 --- /dev/null +++ b/app/src/main/java/com/lu/wxmask/plugin/ui/view/BottomPopUI.kt @@ -0,0 +1,132 @@ +package com.lu.wxmask.plugin.ui.view + +import android.animation.ValueAnimator +import android.view.Gravity +import android.view.MotionEvent +import android.view.View +import android.view.ViewGroup +import android.view.ViewGroup.LayoutParams.WRAP_CONTENT +import android.widget.FrameLayout +import androidx.core.animation.addListener + +class BottomPopUI( + val content: View, + /** + * 顶部可拖动区域高度 + */ + var topDragBoundHeight: Int = 0 +) : AttachUI(content.context) { + private var downY: Float = 0f + private var isCanMove = false + private val mContentView = FrameLayout(context) + + init { + mContentView.layoutParams = FrameLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT).apply { + gravity = Gravity.BOTTOM + } + mContentView.isClickable = true + mContentView.setOnTouchListener(DragMoveListener()) + } + + override fun onCreateView(container: ViewGroup): View { + container.setBackgroundColor(0x66666666) + container.setOnClickListener { + dismiss() + } + mContentView.addView(content) + return mContentView + } + + override fun dismiss() { + if (!isShowing()) { + return + } + val startValue = if (mContentView.translationY > 0) { + mContentView.translationY + } else { + 0f + } + ValueAnimator.ofFloat(startValue, mContentView.height.toFloat()).apply { + duration = 300 + addUpdateListener { + mContentView.translationY = it.animatedValue as Float + } + addListener(onEnd = { + mContentView.translationY = 0f + super.dismiss() + }) + }.start() + } + + override fun show() { + if (isShowing() && mContentView.translationY <= 0f) { + return + } + post { + val startValue = if (mContentView.translationY > 0f) { + mContentView.translationY + } else if (mContentView.height > 0f) { + mContentView.height.toFloat() + } else { + mContentView.layoutParams.height.toFloat() + } + ValueAnimator.ofFloat(startValue, 0f).apply { + duration = 200 + addUpdateListener { + mContentView.translationY = it.animatedValue as Float + } + addListener( + onStart = { + mContentView.visibility = View.VISIBLE + }, + onEnd = { + mContentView.translationY = 0f + }) + }.start() + } + mContentView.visibility = View.INVISIBLE + super.show() + } + + + private inner class DragMoveListener : OnTouchListener { + override fun onTouch(v: View?, event: MotionEvent?): Boolean { + if (event == null) { + return false + } + if (topDragBoundHeight <= 0) { + return false + } + when (event.action) { + MotionEvent.ACTION_DOWN -> { + downY = event.y + isCanMove = downY < topDragBoundHeight + return isCanMove + } + + MotionEvent.ACTION_MOVE -> { + val distance = event.y - downY + if (isCanMove && distance > 0) { + mContentView.translationY = distance + return true + } + } + + MotionEvent.ACTION_UP -> { + if (mContentView.translationY == 0f) { + v?.performClick() + return false + } else if (mContentView.translationY > mContentView.height / 5f) { + dismiss() + } else { + show() + } + return true + } + + } + return false + } + + } +} \ No newline at end of file diff --git a/app/src/main/java/com/lu/wxmask/ui/adapter/SpinnerListAdapter.kt b/app/src/main/java/com/lu/wxmask/ui/adapter/SpinnerListAdapter.kt new file mode 100644 index 0000000..fd4d4bb --- /dev/null +++ b/app/src/main/java/com/lu/wxmask/ui/adapter/SpinnerListAdapter.kt @@ -0,0 +1,26 @@ +package com.lu.wxmask.ui.adapter + +import android.view.ViewGroup +import android.widget.TextView +import androidx.core.view.setPadding +import com.lu.wxmask.adapter.AbsListAdapter +import com.lu.wxmask.adapter.CommonListAdapter +import com.lu.wxmask.util.ext.dp + +class SpinnerListAdapter(spinnerDataList: ArrayList>) : + CommonListAdapter, AbsListAdapter.ViewHolder>() { + init { + setData(spinnerDataList) + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { + return ViewHolder(TextView(parent.context).also { it.setPadding(4.dp) }) + } + + override fun onBindViewHolder(vh: ViewHolder, position: Int, parent: ViewGroup) { + val itemView = vh.itemView + if (itemView is TextView) { + itemView.text = getItem(position)?.second + } + } +} diff --git a/app/src/main/java/com/lu/wxmask/util/ActivityUtils.java b/app/src/main/java/com/lu/wxmask/util/ActivityUtils.java new file mode 100644 index 0000000..7f93cf3 --- /dev/null +++ b/app/src/main/java/com/lu/wxmask/util/ActivityUtils.java @@ -0,0 +1,84 @@ +package com.lu.wxmask.util; + +import android.app.Activity; +import android.content.Context; +import android.content.ContextWrapper; +import android.os.Build; + +import java.lang.ref.WeakReference; +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.List; + +public class ActivityUtils { + + /** + * Return the activity by context. + * + * @param context The context. + * @return the activity by context. + */ + public static Activity getActivityByContext(Context context) { + Activity activity = getActivityByContextInner(context); + if (!isActivityAlive(activity)) return null; + return activity; + } + + private static Activity getActivityByContextInner(Context context) { + if (context == null) return null; + List list = new ArrayList<>(); + while (context instanceof ContextWrapper) { + if (context instanceof Activity) { + return (Activity) context; + } + Activity activity = getActivityFromDecorContext(context); + if (activity != null) return activity; + list.add(context); + context = ((ContextWrapper) context).getBaseContext(); + if (context == null) { + return null; + } + if (list.contains(context)) { + // loop context + return null; + } + } + return null; + } + + private static Activity getActivityFromDecorContext(Context context) { + if (context == null) return null; + if (context.getClass().getName().equals("com.android.internal.policy.DecorContext")) { + try { + Field mActivityContextField = context.getClass().getDeclaredField("mActivityContext"); + mActivityContextField.setAccessible(true); + //noinspection ConstantConditions,unchecked + return ((WeakReference) mActivityContextField.get(context)).get(); + } catch (Exception ignore) { + } + } + return null; + } + + /** + * Return whether the activity is alive. + * + * @param context The context. + * @return {@code true}: yes
{@code false}: no + */ + public static boolean isActivityAlive(final Context context) { + return isActivityAlive(getActivityByContext(context)); + } + + /** + * Return whether the activity is alive. + * + * @param activity The activity. + * @return {@code true}: yes
{@code false}: no + */ + public static boolean isActivityAlive(final Activity activity) { + return activity != null && !activity.isFinishing() + && (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1 || !activity.isDestroyed()); + } + +} diff --git a/app/src/main/java/com/lu/wxmask/util/BarUtils.java b/app/src/main/java/com/lu/wxmask/util/BarUtils.java new file mode 100644 index 0000000..e341b2e --- /dev/null +++ b/app/src/main/java/com/lu/wxmask/util/BarUtils.java @@ -0,0 +1,707 @@ +package com.lu.wxmask.util; + + +import static android.Manifest.permission.EXPAND_STATUS_BAR; + +import android.annotation.SuppressLint; +import android.app.Activity; +import android.content.Context; +import android.content.res.Resources; +import android.graphics.Color; +import android.graphics.Point; +import android.os.Build; +import android.util.TypedValue; +import android.view.Display; +import android.view.KeyCharacterMap; +import android.view.KeyEvent; +import android.view.View; +import android.view.ViewConfiguration; +import android.view.ViewGroup; +import android.view.ViewGroup.MarginLayoutParams; +import android.view.Window; +import android.view.WindowManager; + +import androidx.annotation.ColorInt; +import androidx.annotation.NonNull; +import androidx.annotation.RequiresApi; +import androidx.annotation.RequiresPermission; +import androidx.drawerlayout.widget.DrawerLayout; + +import com.lu.magic.util.AppUtil; + +import java.lang.reflect.Method; + +/** + *
+ *     author: Blankj
+ *     blog  : http://blankj.com
+ *     time  : 2016/09/23
+ *     desc  : utils about bar
+ * 
+ */ +public final class BarUtils { + + /////////////////////////////////////////////////////////////////////////// + // status bar + /////////////////////////////////////////////////////////////////////////// + + private static final String TAG_STATUS_BAR = "TAG_STATUS_BAR"; + private static final String TAG_OFFSET = "TAG_OFFSET"; + private static final int KEY_OFFSET = -123; + + private BarUtils() { + throw new UnsupportedOperationException("u can't instantiate me..."); + } + + /** + * Return the status bar's height. + * + * @return the status bar's height + */ + public static int getStatusBarHeight() { + Resources resources = Resources.getSystem(); + int resourceId = resources.getIdentifier("status_bar_height", "dimen", "android"); + return resources.getDimensionPixelSize(resourceId); + } + + /** + * Set the status bar's visibility. + * + * @param activity The activity. + * @param isVisible True to set status bar visible, false otherwise. + */ + public static void setStatusBarVisibility(@NonNull final Activity activity, + final boolean isVisible) { + setStatusBarVisibility(activity.getWindow(), isVisible); + } + + /** + * Set the status bar's visibility. + * + * @param window The window. + * @param isVisible True to set status bar visible, false otherwise. + */ + public static void setStatusBarVisibility(@NonNull final Window window, + final boolean isVisible) { + if (isVisible) { + window.clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); + showStatusBarView(window); + addMarginTopEqualStatusBarHeight(window); + } else { + window.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); + hideStatusBarView(window); + subtractMarginTopEqualStatusBarHeight(window); + } + } + + /** + * Return whether the status bar is visible. + * + * @param activity The activity. + * @return {@code true}: yes
{@code false}: no + */ + public static boolean isStatusBarVisible(@NonNull final Activity activity) { + int flags = activity.getWindow().getAttributes().flags; + return (flags & WindowManager.LayoutParams.FLAG_FULLSCREEN) == 0; + } + + /** + * Set the status bar's light mode. + * + * @param activity The activity. + * @param isLightMode True to set status bar light mode, false otherwise. + */ + public static void setStatusBarLightMode(@NonNull final Activity activity, + final boolean isLightMode) { + setStatusBarLightMode(activity.getWindow(), isLightMode); + } + + /** + * Set the status bar's light mode. + * + * @param window The window. + * @param isLightMode True to set status bar light mode, false otherwise. + */ + public static void setStatusBarLightMode(@NonNull final Window window, + final boolean isLightMode) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + View decorView = window.getDecorView(); + int vis = decorView.getSystemUiVisibility(); + if (isLightMode) { + vis |= View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR; + } else { + vis &= ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR; + } + decorView.setSystemUiVisibility(vis); + } + } + + /** + * Is the status bar light mode. + * + * @param activity The activity. + * @return {@code true}: yes
{@code false}: no + */ + public static boolean isStatusBarLightMode(@NonNull final Activity activity) { + return isStatusBarLightMode(activity.getWindow()); + } + + /** + * Is the status bar light mode. + * + * @param window The window. + * @return {@code true}: yes
{@code false}: no + */ + public static boolean isStatusBarLightMode(@NonNull final Window window) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + View decorView = window.getDecorView(); + int vis = decorView.getSystemUiVisibility(); + return (vis & View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR) != 0; + } + return false; + } + + /** + * Add the top margin size equals status bar's height for view. + * + * @param view The view. + */ + public static void addMarginTopEqualStatusBarHeight(@NonNull View view) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) return; + view.setTag(TAG_OFFSET); + Object haveSetOffset = view.getTag(KEY_OFFSET); + if (haveSetOffset != null && (Boolean) haveSetOffset) return; + MarginLayoutParams layoutParams = (MarginLayoutParams) view.getLayoutParams(); + layoutParams.setMargins(layoutParams.leftMargin, + layoutParams.topMargin + getStatusBarHeight(), + layoutParams.rightMargin, + layoutParams.bottomMargin); + view.setTag(KEY_OFFSET, true); + } + + /** + * Subtract the top margin size equals status bar's height for view. + * + * @param view The view. + */ + public static void subtractMarginTopEqualStatusBarHeight(@NonNull View view) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) return; + Object haveSetOffset = view.getTag(KEY_OFFSET); + if (haveSetOffset == null || !(Boolean) haveSetOffset) return; + MarginLayoutParams layoutParams = (MarginLayoutParams) view.getLayoutParams(); + layoutParams.setMargins(layoutParams.leftMargin, + layoutParams.topMargin - getStatusBarHeight(), + layoutParams.rightMargin, + layoutParams.bottomMargin); + view.setTag(KEY_OFFSET, false); + } + + private static void addMarginTopEqualStatusBarHeight(final Window window) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) return; + View withTag = window.getDecorView().findViewWithTag(TAG_OFFSET); + if (withTag == null) return; + addMarginTopEqualStatusBarHeight(withTag); + } + + private static void subtractMarginTopEqualStatusBarHeight(final Window window) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) return; + View withTag = window.getDecorView().findViewWithTag(TAG_OFFSET); + if (withTag == null) return; + subtractMarginTopEqualStatusBarHeight(withTag); + } + + /** + * Set the status bar's color. + * + * @param activity The activity. + * @param color The status bar's color. + */ + public static View setStatusBarColor(@NonNull final Activity activity, + @ColorInt final int color) { + return setStatusBarColor(activity, color, false); + } + + /** + * Set the status bar's color. + * + * @param activity The activity. + * @param color The status bar's color. + * @param isDecor True to add fake status bar in DecorView, + * false to add fake status bar in ContentView. + */ + public static View setStatusBarColor(@NonNull final Activity activity, + @ColorInt final int color, + final boolean isDecor) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) return null; + transparentStatusBar(activity); + return applyStatusBarColor(activity, color, isDecor); + } + + + /** + * Set the status bar's color. + * + * @param window The window. + * @param color The status bar's color. + */ + public static View setStatusBarColor(@NonNull final Window window, + @ColorInt final int color) { + return setStatusBarColor(window, color, false); + } + + /** + * Set the status bar's color. + * + * @param window The window. + * @param color The status bar's color. + * @param isDecor True to add fake status bar in DecorView, + * false to add fake status bar in ContentView. + */ + public static View setStatusBarColor(@NonNull final Window window, + @ColorInt final int color, + final boolean isDecor) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) return null; + transparentStatusBar(window); + return applyStatusBarColor(window, color, isDecor); + } + + /** + * Set the status bar's color. + * + * @param fakeStatusBar The fake status bar view. + * @param color The status bar's color. + */ + public static void setStatusBarColor(@NonNull final View fakeStatusBar, + @ColorInt final int color) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) return; + Activity activity = ActivityUtils.getActivityByContext(fakeStatusBar.getContext()); + if (activity == null) return; + transparentStatusBar(activity); + fakeStatusBar.setVisibility(View.VISIBLE); + ViewGroup.LayoutParams layoutParams = fakeStatusBar.getLayoutParams(); + layoutParams.width = ViewGroup.LayoutParams.MATCH_PARENT; + layoutParams.height = getStatusBarHeight(); + fakeStatusBar.setBackgroundColor(color); + } + + /** + * Set the custom status bar. + * + * @param fakeStatusBar The fake status bar view. + */ + public static void setStatusBarCustom(@NonNull final View fakeStatusBar) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) return; + Activity activity = ActivityUtils.getActivityByContext(fakeStatusBar.getContext()); + if (activity == null) return; + transparentStatusBar(activity); + fakeStatusBar.setVisibility(View.VISIBLE); + ViewGroup.LayoutParams layoutParams = fakeStatusBar.getLayoutParams(); + if (layoutParams == null) { + layoutParams = new ViewGroup.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + getStatusBarHeight() + ); + fakeStatusBar.setLayoutParams(layoutParams); + } else { + layoutParams.width = ViewGroup.LayoutParams.MATCH_PARENT; + layoutParams.height = getStatusBarHeight(); + } + } + + /** + * Set the status bar's color for DrawerLayout. + *

DrawLayout must add {@code android:fitsSystemWindows="true"}

+ * + * @param drawer The DrawLayout. + * @param fakeStatusBar The fake status bar view. + * @param color The status bar's color. + */ + public static void setStatusBarColor4Drawer(@NonNull final DrawerLayout drawer, + @NonNull final View fakeStatusBar, + @ColorInt final int color) { + setStatusBarColor4Drawer(drawer, fakeStatusBar, color, false); + } + + /** + * Set the status bar's color for DrawerLayout. + *

DrawLayout must add {@code android:fitsSystemWindows="true"}

+ * + * @param drawer The DrawLayout. + * @param fakeStatusBar The fake status bar view. + * @param color The status bar's color. + * @param isTop True to set DrawerLayout at the top layer, false otherwise. + */ + public static void setStatusBarColor4Drawer(@NonNull final DrawerLayout drawer, + @NonNull final View fakeStatusBar, + @ColorInt final int color, + final boolean isTop) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) return; + Activity activity = ActivityUtils.getActivityByContext(fakeStatusBar.getContext()); + if (activity == null) return; + transparentStatusBar(activity); + drawer.setFitsSystemWindows(false); + setStatusBarColor(fakeStatusBar, color); + for (int i = 0, count = drawer.getChildCount(); i < count; i++) { + drawer.getChildAt(i).setFitsSystemWindows(false); + } + if (isTop) { + hideStatusBarView(activity); + } else { + setStatusBarColor(activity, color, false); + } + } + + private static View applyStatusBarColor(final Activity activity, + final int color, + boolean isDecor) { + return applyStatusBarColor(activity.getWindow(), color, isDecor); + } + + private static View applyStatusBarColor(final Window window, + final int color, + boolean isDecor) { + ViewGroup parent = isDecor ? + (ViewGroup) window.getDecorView() : + (ViewGroup) window.findViewById(android.R.id.content); + View fakeStatusBarView = parent.findViewWithTag(TAG_STATUS_BAR); + if (fakeStatusBarView != null) { + if (fakeStatusBarView.getVisibility() == View.GONE) { + fakeStatusBarView.setVisibility(View.VISIBLE); + } + fakeStatusBarView.setBackgroundColor(color); + } else { + fakeStatusBarView = createStatusBarView(window.getContext(), color); + parent.addView(fakeStatusBarView); + } + return fakeStatusBarView; + } + + private static void hideStatusBarView(final Activity activity) { + hideStatusBarView(activity.getWindow()); + } + + private static void hideStatusBarView(final Window window) { + ViewGroup decorView = (ViewGroup) window.getDecorView(); + View fakeStatusBarView = decorView.findViewWithTag(TAG_STATUS_BAR); + if (fakeStatusBarView == null) return; + fakeStatusBarView.setVisibility(View.GONE); + } + + private static void showStatusBarView(final Window window) { + ViewGroup decorView = (ViewGroup) window.getDecorView(); + View fakeStatusBarView = decorView.findViewWithTag(TAG_STATUS_BAR); + if (fakeStatusBarView == null) return; + fakeStatusBarView.setVisibility(View.VISIBLE); + } + + private static View createStatusBarView(final Context context, + final int color) { + View statusBarView = new View(context); + statusBarView.setLayoutParams(new ViewGroup.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, getStatusBarHeight())); + statusBarView.setBackgroundColor(color); + statusBarView.setTag(TAG_STATUS_BAR); + return statusBarView; + } + + public static void transparentStatusBar(final Activity activity) { + transparentStatusBar(activity.getWindow()); + } + + public static void transparentStatusBar(final Window window) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) return; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); + window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); + int option = View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN; + int vis = window.getDecorView().getSystemUiVisibility(); + window.getDecorView().setSystemUiVisibility(option | vis); + window.setStatusBarColor(Color.TRANSPARENT); + } else { + window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); + } + } + + /////////////////////////////////////////////////////////////////////////// + // action bar + /////////////////////////////////////////////////////////////////////////// + + /** + * Return the action bar's height. + * + * @return the action bar's height + */ + public static int getActionBarHeight() { + TypedValue tv = new TypedValue(); + if (AppUtil.getContext().getTheme().resolveAttribute(android.R.attr.actionBarSize, tv, true)) { + return TypedValue.complexToDimensionPixelSize( + tv.data, Resources.getSystem().getDisplayMetrics() + ); + } + return 0; + } + + /////////////////////////////////////////////////////////////////////////// + // notification bar + /////////////////////////////////////////////////////////////////////////// + + /** + * Set the notification bar's visibility. + *

Must hold {@code }

+ * + * @param isVisible True to set notification bar visible, false otherwise. + */ + @RequiresPermission(EXPAND_STATUS_BAR) + public static void setNotificationBarVisibility(final boolean isVisible) { + String methodName; + if (isVisible) { + methodName = (Build.VERSION.SDK_INT <= 16) ? "expand" : "expandNotificationsPanel"; + } else { + methodName = (Build.VERSION.SDK_INT <= 16) ? "collapse" : "collapsePanels"; + } + invokePanels(methodName); + } + + private static void invokePanels(final String methodName) { + try { + @SuppressLint("WrongConstant") + Object service = AppUtil.getContext().getSystemService("statusbar"); + @SuppressLint("PrivateApi") + Class statusBarManager = Class.forName("android.app.StatusBarManager"); + Method expand = statusBarManager.getMethod(methodName); + expand.invoke(service); + } catch (Exception e) { + e.printStackTrace(); + } + } + + /////////////////////////////////////////////////////////////////////////// + // navigation bar + /////////////////////////////////////////////////////////////////////////// + + /** + * Return the navigation bar's height. + * + * @return the navigation bar's height + */ + public static int getNavBarHeight() { + Resources res = Resources.getSystem(); + int resourceId = res.getIdentifier("navigation_bar_height", "dimen", "android"); + if (resourceId != 0) { + return res.getDimensionPixelSize(resourceId); + } else { + return 0; + } + } + + /** + * Set the navigation bar's visibility. + * + * @param activity The activity. + * @param isVisible True to set navigation bar visible, false otherwise. + */ + public static void setNavBarVisibility(@NonNull final Activity activity, boolean isVisible) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) return; + setNavBarVisibility(activity.getWindow(), isVisible); + + } + + /** + * Set the navigation bar's visibility. + * + * @param window The window. + * @param isVisible True to set navigation bar visible, false otherwise. + */ + public static void setNavBarVisibility(@NonNull final Window window, boolean isVisible) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) return; + final ViewGroup decorView = (ViewGroup) window.getDecorView(); + for (int i = 0, count = decorView.getChildCount(); i < count; i++) { + final View child = decorView.getChildAt(i); + final int id = child.getId(); + if (id != View.NO_ID) { + String resourceEntryName = getResNameById(id); + if ("navigationBarBackground".equals(resourceEntryName)) { + child.setVisibility(isVisible ? View.VISIBLE : View.INVISIBLE); + } + } + } + final int uiOptions = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION + | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION + | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY; + if (isVisible) { + decorView.setSystemUiVisibility(decorView.getSystemUiVisibility() & ~uiOptions); + } else { + decorView.setSystemUiVisibility(decorView.getSystemUiVisibility() | uiOptions); + } + } + + /** + * Return whether the navigation bar visible. + *

Call it in onWindowFocusChanged will get right result.

+ * + * @param activity The activity. + * @return {@code true}: yes
{@code false}: no + */ + public static boolean isNavBarVisible(@NonNull final Activity activity) { + return isNavBarVisible(activity.getWindow()); + } + + /** + * Return whether the navigation bar visible. + *

Call it in onWindowFocusChanged will get right result.

+ * + * @param window The window. + * @return {@code true}: yes
{@code false}: no + */ + public static boolean isNavBarVisible(@NonNull final Window window) { + boolean isVisible = false; + ViewGroup decorView = (ViewGroup) window.getDecorView(); + for (int i = 0, count = decorView.getChildCount(); i < count; i++) { + final View child = decorView.getChildAt(i); + final int id = child.getId(); + if (id != View.NO_ID) { + String resourceEntryName = getResNameById(id); + if ("navigationBarBackground".equals(resourceEntryName) + && child.getVisibility() == View.VISIBLE) { + isVisible = true; + break; + } + } + } + if (isVisible) { + int visibility = decorView.getSystemUiVisibility(); + isVisible = (visibility & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0; + } + return isVisible; + } + + private static String getResNameById(int id) { + try { + return AppUtil.getContext().getResources().getResourceEntryName(id); + } catch (Exception ignore) { + return ""; + } + } + + /** + * Set the navigation bar's color. + * + * @param activity The activity. + * @param color The navigation bar's color. + */ + @RequiresApi(Build.VERSION_CODES.LOLLIPOP) + public static void setNavBarColor(@NonNull final Activity activity, @ColorInt final int color) { + setNavBarColor(activity.getWindow(), color); + } + + /** + * Set the navigation bar's color. + * + * @param window The window. + * @param color The navigation bar's color. + */ + @RequiresApi(Build.VERSION_CODES.LOLLIPOP) + public static void setNavBarColor(@NonNull final Window window, @ColorInt final int color) { + window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); + window.setNavigationBarColor(color); + } + + /** + * Return the color of navigation bar. + * + * @param activity The activity. + * @return the color of navigation bar + */ + @RequiresApi(Build.VERSION_CODES.LOLLIPOP) + public static int getNavBarColor(@NonNull final Activity activity) { + return getNavBarColor(activity.getWindow()); + } + + /** + * Return the color of navigation bar. + * + * @param window The window. + * @return the color of navigation bar + */ + @RequiresApi(Build.VERSION_CODES.LOLLIPOP) + public static int getNavBarColor(@NonNull final Window window) { + return window.getNavigationBarColor(); + } + + /** + * Return whether the navigation bar visible. + * + * @return {@code true}: yes
{@code false}: no + */ + public static boolean isSupportNavBar() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { + WindowManager wm = (WindowManager) AppUtil.getContext().getSystemService(Context.WINDOW_SERVICE); + if (wm == null) return false; + Display display = wm.getDefaultDisplay(); + Point size = new Point(); + Point realSize = new Point(); + display.getSize(size); + display.getRealSize(realSize); + return realSize.y != size.y || realSize.x != size.x; + } + boolean menu = ViewConfiguration.get(AppUtil.getContext()).hasPermanentMenuKey(); + boolean back = KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_BACK); + return !menu && !back; + } + + /** + * Set the nav bar's light mode. + * + * @param activity The activity. + * @param isLightMode True to set nav bar light mode, false otherwise. + */ + public static void setNavBarLightMode(@NonNull final Activity activity, + final boolean isLightMode) { + setNavBarLightMode(activity.getWindow(), isLightMode); + } + + /** + * Set the nav bar's light mode. + * + * @param window The window. + * @param isLightMode True to set nav bar light mode, false otherwise. + */ + public static void setNavBarLightMode(@NonNull final Window window, + final boolean isLightMode) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + View decorView = window.getDecorView(); + int vis = decorView.getSystemUiVisibility(); + if (isLightMode) { + vis |= View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR; + } else { + vis &= ~View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR; + } + decorView.setSystemUiVisibility(vis); + } + } + + /** + * Is the nav bar light mode. + * + * @param activity The activity. + * @return {@code true}: yes
{@code false}: no + */ + public static boolean isNavBarLightMode(@NonNull final Activity activity) { + return isNavBarLightMode(activity.getWindow()); + } + + /** + * Is the nav bar light mode. + * + * @param window The window. + * @return {@code true}: yes
{@code false}: no + */ + public static boolean isNavBarLightMode(@NonNull final Window window) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + View decorView = window.getDecorView(); + int vis = decorView.getSystemUiVisibility(); + return (vis & View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR) != 0; + } + return false; + } +} diff --git a/app/src/main/java/com/lu/wxmask/util/KeyBoxUtil.java b/app/src/main/java/com/lu/wxmask/util/KeyBoxUtil.java new file mode 100644 index 0000000..1adc85b --- /dev/null +++ b/app/src/main/java/com/lu/wxmask/util/KeyBoxUtil.java @@ -0,0 +1,74 @@ +package com.lu.wxmask.util; + +import android.content.Context; +import android.os.Bundle; +import android.os.Handler; +import android.os.ResultReceiver; +import android.view.View; +import android.view.inputmethod.InputMethodManager; + +import androidx.annotation.NonNull; + +public class KeyBoxUtil { + + + /** + * Hide the soft input. + * + * @param view The view. + */ + public static void hideSoftInput(@NonNull final View view) { + InputMethodManager imm = + (InputMethodManager) view.getContext().getSystemService(Context.INPUT_METHOD_SERVICE); + if (imm == null) return; + imm.hideSoftInputFromWindow(view.getWindowToken(), 0); + } + + + /** + * Show the soft input. + * + * @param view The view. + */ + public static void showSoftInput(@NonNull final View view) { + showSoftInput(view, 0); + } + + /** + * Show the soft input. + * + * @param view The view. + * @param flags Provides additional operating flags. Currently may be + * 0 or have the {@link InputMethodManager#SHOW_IMPLICIT} bit set. + */ + public static void showSoftInput(@NonNull final View view, final int flags) { + Context context = view.getContext().getApplicationContext(); + InputMethodManager imm = + (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE); + if (imm == null) return; + view.setFocusable(true); + view.setFocusableInTouchMode(true); + view.requestFocus(); + imm.showSoftInput(view, flags, new ResultReceiver(new Handler()) { + @Override + protected void onReceiveResult(int resultCode, Bundle resultData) { + if (resultCode == InputMethodManager.RESULT_UNCHANGED_HIDDEN + || resultCode == InputMethodManager.RESULT_HIDDEN) { + toggleSoftInput(context); + } + } + }); + imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, InputMethodManager.HIDE_IMPLICIT_ONLY); + } + + /** + * Toggle the soft input display or not. + */ + public static void toggleSoftInput(Context context) { + InputMethodManager imm = + (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE); + if (imm == null) return; + imm.toggleSoftInput(0, 0); + } + +} diff --git a/app/src/main/java/com/lu/wxmask/util/Rm.java b/app/src/main/java/com/lu/wxmask/util/Rm.java new file mode 100644 index 0000000..968f1c0 --- /dev/null +++ b/app/src/main/java/com/lu/wxmask/util/Rm.java @@ -0,0 +1,5 @@ +package com.lu.wxmask.util; + +public class Rm { +// public static int mask_layout_plugin_manager; +} diff --git a/app/src/main/java/com/lu/wxmask/util/ext/AnyX.kt b/app/src/main/java/com/lu/wxmask/util/ext/AnyX.kt index 6bafd86..da864ff 100644 --- a/app/src/main/java/com/lu/wxmask/util/ext/AnyX.kt +++ b/app/src/main/java/com/lu/wxmask/util/ext/AnyX.kt @@ -1,7 +1,17 @@ package com.lu.wxmask.util.ext +import android.view.TextureView +import android.view.View +import androidx.core.util.Consumer import com.google.gson.JsonObject +import com.lu.magic.util.AppUtil import com.lu.magic.util.GsonUtil +import com.lu.magic.util.SizeUtil +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract + +val sizeIntCache = HashMap() +val sizeFloatCache = HashMap() fun Any?.toJsonObject(): JsonObject { return GsonUtil.toJsonTree(this).asJsonObject @@ -9,4 +19,36 @@ fun Any?.toJsonObject(): JsonObject { fun Any?.toJson(): String { return GsonUtil.toJson(this) -} \ No newline at end of file +} + +val Int.dp: Int + get() = sizeIntCache[this.toString()].let { + if (it == null) { + val v = SizeUtil.dp2px(AppUtil.getContext().resources, this.toFloat()).toInt() + sizeIntCache[this.toString()] = v + return@let v + } + return it + } + +val Float.dp: Float + get() = sizeFloatCache[this.toString()].let { + if (it == null) { + val v = SizeUtil.dp2px(AppUtil.getContext().resources, this.toFloat()) + sizeFloatCache[this.toString()] = v + return@let v + } + return it + } + +val Double.dp: Float + get() = this.toFloat().dp + +fun CharSequence?.toIntElse(fallback: Int): Int = try { + if (this == null) { + fallback + } + Integer.parseInt(this.toString()) +} catch (e: Exception) { + fallback +} diff --git a/app/src/main/java/com/lu/wxmask/util/ext/ResUtilX.kt b/app/src/main/java/com/lu/wxmask/util/ext/ResUtilX.kt index d73ab74..934fd99 100644 --- a/app/src/main/java/com/lu/wxmask/util/ext/ResUtilX.kt +++ b/app/src/main/java/com/lu/wxmask/util/ext/ResUtilX.kt @@ -4,6 +4,8 @@ import com.lu.magic.util.AppUtil import com.lu.magic.util.ResUtil private val resMap = HashMap() + +@JvmOverloads fun ResUtil.getViewId(idName: String, packageName: String = AppUtil.getPackageName()): Int { val k = "@id/$idName" var id = resMap[k] From bffb29139ffb1839cce6b9974998f6e32fb99354 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=98=8E=E6=9C=88=E4=BE=9D=E5=B8=8C?= <1093286982@qq.com> Date: Fri, 16 Feb 2024 21:35:26 +0800 Subject: [PATCH 02/13] =?UTF-8?q?[add]=20=E6=8B=96=E5=8A=A8=E6=AE=8B?= =?UTF-8?q?=E5=BD=B1=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/lu/wxmask/plugin/WXConfigPlugin.java | 13 ++-- .../lu/wxmask/plugin/ui/ConfigManagerUI.kt | 6 +- .../com/lu/wxmask/plugin/ui/view/AttachUI.kt | 14 +++- .../lu/wxmask/plugin/ui/view/BottomPopUI.kt | 73 +++++++++++-------- 4 files changed, 63 insertions(+), 43 deletions(-) diff --git a/app/src/main/java/com/lu/wxmask/plugin/WXConfigPlugin.java b/app/src/main/java/com/lu/wxmask/plugin/WXConfigPlugin.java index 715002b..cc90cc5 100644 --- a/app/src/main/java/com/lu/wxmask/plugin/WXConfigPlugin.java +++ b/app/src/main/java/com/lu/wxmask/plugin/WXConfigPlugin.java @@ -5,14 +5,18 @@ import android.content.Context; import android.content.Intent; import android.os.Bundle; +import android.os.Looper; import android.view.View; +import androidx.core.os.HandlerCompat; + import com.lu.lposed.api2.XC_MethodHook2; import com.lu.lposed.api2.XposedHelpers2; import com.lu.lposed.plugin.IPlugin; import com.lu.magic.util.GsonUtil; import com.lu.magic.util.ToastUtil; import com.lu.magic.util.log.LogUtil; +import com.lu.magic.util.thread.AppExecutor; import com.lu.wxmask.ClazzN; import com.lu.wxmask.Constrant; import com.lu.wxmask.bean.MaskItemBean; @@ -233,12 +237,10 @@ private Object findChatUserObject(Object fragmentObj) { //8.0.34开始,数据库基类改变。包:com.tencent.mm.autogen.table 已经不存在,不再校验 Object v = XposedHelpers2.getObjectField(f, "h"); return v; - } - else if (AppVersionUtil.getVersionCode() <= Constrant.WX_CODE_8_0_40) { + } else if (AppVersionUtil.getVersionCode() <= Constrant.WX_CODE_8_0_40) { Object v = XposedHelpers2.getObjectField(f, "i"); return v; - } - else { + } else { //8.0.33与8.0.34共同的父类: com.tencent.mm.contact.d Field[] hitFields = XposedHelpers2.findFieldsByExactPredicate(f.getClass(), field -> ClazzN.from("com.tencent.mm.contact.d").isAssignableFrom(field.getType())); if (hitFields.length > 0) { @@ -246,8 +248,7 @@ else if (AppVersionUtil.getVersionCode() <= Constrant.WX_CODE_8_0_40) { Object result = field.get(f); LogUtil.w(AppVersionUtil.getSmartVersionName(), "guess user info object, ", "find field: ", field.getName(), "=", result); return result; - } - else { + } else { LogUtil.w(AppVersionUtil.getSmartVersionName(), "guess user info object fail!"); } } diff --git a/app/src/main/java/com/lu/wxmask/plugin/ui/ConfigManagerUI.kt b/app/src/main/java/com/lu/wxmask/plugin/ui/ConfigManagerUI.kt index 342d10a..3a4eb2c 100644 --- a/app/src/main/java/com/lu/wxmask/plugin/ui/ConfigManagerUI.kt +++ b/app/src/main/java/com/lu/wxmask/plugin/ui/ConfigManagerUI.kt @@ -23,6 +23,7 @@ import com.lu.wxmask.adapter.AbsListAdapter import com.lu.wxmask.adapter.CommonListAdapter import com.lu.wxmask.bean.MaskItemBean import com.lu.wxmask.plugin.ui.view.BottomPopUI +import com.lu.wxmask.util.BarUtils import com.lu.wxmask.util.ConfigUtil import com.lu.wxmask.util.ext.dp @@ -40,7 +41,10 @@ internal class ConfigManagerUI(private val context: Activity) : IConfigManagerUI // private val mContentLayout = FrameLayout(context) init { - popwindow = BottomPopUI(onCreateView(), topDragBoundHeight = 44.dp) + popwindow = BottomPopUI(onCreateView(), topDragBoundHeight = 48.dp) + popwindow.onShowListener = { + BarUtils.setStatusBarLightMode(context, true) + } } diff --git a/app/src/main/java/com/lu/wxmask/plugin/ui/view/AttachUI.kt b/app/src/main/java/com/lu/wxmask/plugin/ui/view/AttachUI.kt index e1178ab..eab68da 100644 --- a/app/src/main/java/com/lu/wxmask/plugin/ui/view/AttachUI.kt +++ b/app/src/main/java/com/lu/wxmask/plugin/ui/view/AttachUI.kt @@ -10,7 +10,6 @@ import android.view.View import android.view.ViewGroup import android.widget.FrameLayout import androidx.core.view.ViewCompat -import com.lu.wxmask.util.BarUtils import com.lu.wxmask.util.KeyBoxUtil import com.lu.wxmask.util.ext.dp @@ -19,6 +18,10 @@ open class AttachUI @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0, defStyleRes: Int = 0 ) : FrameLayout(context, attrs, defStyleAttr, defStyleRes), ViewCompat.OnUnhandledKeyEventListenerCompat { protected var isViewCreated = false + var onShowListener: ((v: AttachUI) -> Unit)? = null + var onDismissListener: ((v: AttachUI) -> Unit)? = null + + open fun onCreateView(container: ViewGroup): View { return View(context) } @@ -30,6 +33,8 @@ open class AttachUI @JvmOverloads constructor( KeyBoxUtil.hideSoftInput(this) val container = parent as ViewGroup? container?.removeView(this) + + onDismissListener?.invoke(this) } override fun onKeyUp(keyCode: Int, event: KeyEvent?): Boolean { @@ -68,7 +73,7 @@ open class AttachUI @JvmOverloads constructor( if (isShowing()) { return } - KeyBoxUtil.hideSoftInput(this) +// KeyBoxUtil.hideSoftInput(this) getRootContainer()?.removeView(this) var lp = layoutParams @@ -78,8 +83,9 @@ open class AttachUI @JvmOverloads constructor( lp.width = MarginLayoutParams.MATCH_PARENT lp.height = MarginLayoutParams.MATCH_PARENT } - BarUtils.setStatusBarLightMode(getActivity()!!, true) getRootContainer()?.addView(this, lp) + onShowListener?.invoke(this) + z = 99f } open fun isShowing(): Boolean { @@ -123,7 +129,7 @@ open class AttachUI @JvmOverloads constructor( protected fun getRootContainer(): ViewGroup? { return (getActivity()?.window?.decorView) as ViewGroup? - +// return getActivity()?.findViewById(android.R.id.content) } diff --git a/app/src/main/java/com/lu/wxmask/plugin/ui/view/BottomPopUI.kt b/app/src/main/java/com/lu/wxmask/plugin/ui/view/BottomPopUI.kt index 91d7b92..623df02 100644 --- a/app/src/main/java/com/lu/wxmask/plugin/ui/view/BottomPopUI.kt +++ b/app/src/main/java/com/lu/wxmask/plugin/ui/view/BottomPopUI.kt @@ -4,28 +4,29 @@ import android.animation.ValueAnimator import android.view.Gravity import android.view.MotionEvent import android.view.View +import android.view.ViewConfiguration import android.view.ViewGroup import android.view.ViewGroup.LayoutParams.WRAP_CONTENT import android.widget.FrameLayout import androidx.core.animation.addListener class BottomPopUI( - val content: View, + val contentView: View, /** * 顶部可拖动区域高度 */ var topDragBoundHeight: Int = 0 -) : AttachUI(content.context) { - private var downY: Float = 0f - private var isCanMove = false - private val mContentView = FrameLayout(context) - +) : AttachUI(contentView.context) { + private val mContentContainer = FrameLayout(context) + //需要进行动画平移的是contentView而不是容器,因为当前容器参数不定,transfer会引发大量layout残影 + private var mTransferView = contentView init { - mContentView.layoutParams = FrameLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT).apply { + mContentContainer.layoutParams = FrameLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT).apply { gravity = Gravity.BOTTOM } - mContentView.isClickable = true - mContentView.setOnTouchListener(DragMoveListener()) + mContentContainer.isClickable = true + //使用容器,而不是contentView自己来监听,因为contentView是外层传进来的,避免事件覆盖 + mContentContainer.setOnTouchListener(DragMoveListener()) } override fun onCreateView(container: ViewGroup): View { @@ -33,63 +34,67 @@ class BottomPopUI( container.setOnClickListener { dismiss() } - mContentView.addView(content) - return mContentView + mContentContainer.addView(contentView) + return mContentContainer } override fun dismiss() { if (!isShowing()) { return } - val startValue = if (mContentView.translationY > 0) { - mContentView.translationY + val startValue = if (mTransferView.translationY > 0) { + mTransferView.translationY } else { 0f } - ValueAnimator.ofFloat(startValue, mContentView.height.toFloat()).apply { + ValueAnimator.ofFloat(startValue, mTransferView.height.toFloat()).apply { duration = 300 addUpdateListener { - mContentView.translationY = it.animatedValue as Float + mTransferView.translationY = it.animatedValue as Float } addListener(onEnd = { - mContentView.translationY = 0f + mTransferView.translationY = 0f super.dismiss() }) }.start() } override fun show() { - if (isShowing() && mContentView.translationY <= 0f) { + if (isShowing() && mTransferView.translationY <= 0f) { return } post { - val startValue = if (mContentView.translationY > 0f) { - mContentView.translationY - } else if (mContentView.height > 0f) { - mContentView.height.toFloat() + val startValue = if (mTransferView.translationY > 0f) { + mTransferView.translationY + } else if (mTransferView.height > 0f) { + mTransferView.height.toFloat() } else { - mContentView.layoutParams.height.toFloat() + mTransferView.layoutParams.height.toFloat() } ValueAnimator.ofFloat(startValue, 0f).apply { duration = 200 addUpdateListener { - mContentView.translationY = it.animatedValue as Float + mTransferView.translationY = it.animatedValue as Float } addListener( onStart = { - mContentView.visibility = View.VISIBLE + mTransferView.visibility = View.VISIBLE }, onEnd = { - mContentView.translationY = 0f + mTransferView.translationY = 0f }) }.start() } - mContentView.visibility = View.INVISIBLE + mTransferView.visibility = View.INVISIBLE super.show() } private inner class DragMoveListener : OnTouchListener { + private var downY: Float = 0f + private var isOnBounds = false + private var moveY: Float = 0f + private var isCanDrag = false override fun onTouch(v: View?, event: MotionEvent?): Boolean { if (event == null) { return false @@ -100,23 +105,27 @@ class BottomPopUI( when (event.action) { MotionEvent.ACTION_DOWN -> { downY = event.y - isCanMove = downY < topDragBoundHeight - return isCanMove + isOnBounds = downY < topDragBoundHeight + return isOnBounds } MotionEvent.ACTION_MOVE -> { val distance = event.y - downY - if (isCanMove && distance > 0) { - mContentView.translationY = distance + if (Math.abs(event.y - moveY) > ViewConfiguration.get(context).scaledTouchSlop) { + isCanDrag = true + } + if (isOnBounds && distance > 0 && isCanDrag) { + mTransferView.translationY = distance + moveY = event.y return true } } MotionEvent.ACTION_UP -> { - if (mContentView.translationY == 0f) { + if (mTransferView.translationY == 0f) { v?.performClick() return false - } else if (mContentView.translationY > mContentView.height / 5f) { + } else if (mTransferView.translationY > mTransferView.height / 5f) { dismiss() } else { show() From c5a12e73dfcfb5d2752c475d1f82139c07fcdd86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=98=8E=E6=9C=88=E4=BE=9D=E5=B8=8C?= <1093286982@qq.com> Date: Fri, 16 Feb 2024 21:47:22 +0800 Subject: [PATCH 03/13] =?UTF-8?q?[fix]=20=E9=85=8D=E7=BD=AE=E7=AE=A1?= =?UTF-8?q?=E7=90=86=E9=9D=A2=E6=9D=BF=E6=8B=96=E5=8A=A8=E5=81=B6=E7=8E=B0?= =?UTF-8?q?=E5=BA=95=E9=83=A8=E8=83=8C=E6=99=AF=E5=B8=83=E5=B1=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/java/com/lu/wxmask/Constrant.kt | 2 ++ .../com/lu/wxmask/plugin/ui/view/AttachUI.kt | 22 ++++++++++--------- .../lu/wxmask/plugin/ui/view/BottomPopUI.kt | 4 +++- .../java/com/lu/wxmask/util/AppVersionUtil.kt | 5 ++++- 4 files changed, 21 insertions(+), 12 deletions(-) diff --git a/app/src/main/java/com/lu/wxmask/Constrant.kt b/app/src/main/java/com/lu/wxmask/Constrant.kt index eab8850..6adfa13 100644 --- a/app/src/main/java/com/lu/wxmask/Constrant.kt +++ b/app/src/main/java/com/lu/wxmask/Constrant.kt @@ -48,6 +48,8 @@ class Constrant { const val WX_CODE_8_0_43 = 2480 const val WX_CODE_8_0_44 = 2502 const val WX_CODE_8_0_45 = 2521 + const val WX_CODE_8_0_46 = 2540 + const val WX_CODE_8_0_47 = 2560 } } \ No newline at end of file diff --git a/app/src/main/java/com/lu/wxmask/plugin/ui/view/AttachUI.kt b/app/src/main/java/com/lu/wxmask/plugin/ui/view/AttachUI.kt index eab68da..fc84786 100644 --- a/app/src/main/java/com/lu/wxmask/plugin/ui/view/AttachUI.kt +++ b/app/src/main/java/com/lu/wxmask/plugin/ui/view/AttachUI.kt @@ -21,6 +21,15 @@ open class AttachUI @JvmOverloads constructor( var onShowListener: ((v: AttachUI) -> Unit)? = null var onDismissListener: ((v: AttachUI) -> Unit)? = null + var _rootContainer: ViewGroup? = null + var rootContainer: ViewGroup? = _rootContainer + get() { + if (_rootContainer == null) { + _rootContainer = (getActivity()?.window?.decorView) as ViewGroup? + } + return _rootContainer + } + open fun onCreateView(container: ViewGroup): View { return View(context) @@ -73,9 +82,6 @@ open class AttachUI @JvmOverloads constructor( if (isShowing()) { return } -// KeyBoxUtil.hideSoftInput(this) - - getRootContainer()?.removeView(this) var lp = layoutParams if (lp == null) { lp = MarginLayoutParams(MarginLayoutParams.MATCH_PARENT, MarginLayoutParams.MATCH_PARENT) @@ -83,7 +89,9 @@ open class AttachUI @JvmOverloads constructor( lp.width = MarginLayoutParams.MATCH_PARENT lp.height = MarginLayoutParams.MATCH_PARENT } - getRootContainer()?.addView(this, lp) + if (parent == null) { + rootContainer?.addView(this, lp) + } onShowListener?.invoke(this) z = 99f } @@ -127,10 +135,4 @@ open class AttachUI @JvmOverloads constructor( } - protected fun getRootContainer(): ViewGroup? { - return (getActivity()?.window?.decorView) as ViewGroup? -// return getActivity()?.findViewById(android.R.id.content) - } - - } \ No newline at end of file diff --git a/app/src/main/java/com/lu/wxmask/plugin/ui/view/BottomPopUI.kt b/app/src/main/java/com/lu/wxmask/plugin/ui/view/BottomPopUI.kt index 623df02..bd21cdd 100644 --- a/app/src/main/java/com/lu/wxmask/plugin/ui/view/BottomPopUI.kt +++ b/app/src/main/java/com/lu/wxmask/plugin/ui/view/BottomPopUI.kt @@ -85,7 +85,9 @@ class BottomPopUI( }) }.start() } - mTransferView.visibility = View.INVISIBLE + if (!isShowing()) { + mTransferView.visibility = View.INVISIBLE + } super.show() } diff --git a/app/src/main/java/com/lu/wxmask/util/AppVersionUtil.kt b/app/src/main/java/com/lu/wxmask/util/AppVersionUtil.kt index 30ab6d1..879e749 100644 --- a/app/src/main/java/com/lu/wxmask/util/AppVersionUtil.kt +++ b/app/src/main/java/com/lu/wxmask/util/AppVersionUtil.kt @@ -59,7 +59,10 @@ class AppVersionUtil { Constrant.WX_CODE_8_0_42, Constrant.WX_CODE_8_0_43, Constrant.WX_CODE_8_0_44, - Constrant.WX_CODE_8_0_45 -> true + Constrant.WX_CODE_8_0_45, + Constrant.WX_CODE_8_0_46, + Constrant.WX_CODE_8_0_47 + -> true else -> false } } From f23665396a17b9975a271e780c631ec8a95f811e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=98=8E=E6=9C=88=E4=BE=9D=E5=B8=8C?= <1093286982@qq.com> Date: Fri, 16 Feb 2024 22:02:28 +0800 Subject: [PATCH 04/13] =?UTF-8?q?[mod]=20=E4=B8=BB=E9=A2=98=E8=89=B2?= =?UTF-8?q?=E5=8F=98=E6=9B=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/java/com/lu/wxmask/ui/MainFragment.kt | 2 +- app/src/main/res/values-night/themes.xml | 4 ++-- app/src/main/res/values/colors.xml | 2 ++ app/src/main/res/values/themes.xml | 4 ++-- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/com/lu/wxmask/ui/MainFragment.kt b/app/src/main/java/com/lu/wxmask/ui/MainFragment.kt index e52df7d..b877823 100644 --- a/app/src/main/java/com/lu/wxmask/ui/MainFragment.kt +++ b/app/src/main/java/com/lu/wxmask/ui/MainFragment.kt @@ -144,7 +144,7 @@ class MainFragment : BaseFragment() { private fun applyModuleStateRipple(v: View, enable: Boolean) { val contentColor = if (enable) { - view.context.getColor(R.color.purple_200) + view.context.getColor(R.color.app_primary) } else { 0xFFFF6027.toInt() } diff --git a/app/src/main/res/values-night/themes.xml b/app/src/main/res/values-night/themes.xml index f5a6683..509f1a1 100644 --- a/app/src/main/res/values-night/themes.xml +++ b/app/src/main/res/values-night/themes.xml @@ -2,8 +2,8 @@