feat:初步完成发红包弹窗UI

This commit is contained in:
Max
2023-10-23 20:15:02 +08:00
parent ad5a769f25
commit 5163c2dc9d
31 changed files with 1670 additions and 7 deletions

View File

@@ -35,6 +35,7 @@ android {
'src/module_luban/java',
'src/module_easyphoto/java',
'src/module_common/java',
'src/module_utils/java',
]
@@ -43,6 +44,7 @@ android {
'src/module_easypermission/res',
'src/module_easyphoto/res',
'src/module_common/res',
'src/module_utils/res',
]
@@ -144,6 +146,9 @@ dependencies {
api 'com.facebook.android:facebook-android-sdk:16.2.0'
api 'com.facebook.android:facebook-login:16.2.0'
// 网络请求chrome数据调试
implementation 'com.facebook.stetho:stetho:1.5.1'
implementation 'com.facebook.stetho:stetho-okhttp3:1.5.1'
}
repositories {
mavenCentral()

View File

@@ -4,6 +4,7 @@ import android.content.Context;
import android.os.Build;
import android.util.Log;
import com.facebook.stetho.okhttp3.StethoInterceptor;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.yizhuan.xchat_android_library.BuildConfig;
@@ -70,6 +71,8 @@ public final class RxNetManager {
});
loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
mBuilder.addInterceptor(loggingInterceptor);
mBuilder.addNetworkInterceptor(new StethoInterceptor());
}
for (Interceptor interceptor : interceptors) {

View File

@@ -26,6 +26,7 @@ public abstract class BaseApp extends Application{
public static void init(Application application) {
gContext = application;
com.chuhai.utils.AppUtils.init(application);
}
/**

View File

@@ -0,0 +1,403 @@
package com.chuhai.utils;
import android.annotation.SuppressLint;
import android.app.ActivityManager;
import android.app.Application;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.location.LocationManager;
import android.os.Handler;
import android.os.Looper;
import android.provider.Settings;
import android.text.TextUtils;
import android.view.View;
import android.view.Window;
import android.view.inputmethod.InputMethodManager;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* <pre>
* author:
* ___ ___ ___ ___
* _____ / /\ /__/\ /__/| / /\
* / /::\ / /::\ \ \:\ | |:| / /:/
* / /:/\:\ ___ ___ / /:/\:\ \ \:\ | |:| /__/::\
* / /:/~/::\ /__/\ / /\ / /:/~/::\ _____\__\:\ __| |:| \__\/\:\
* /__/:/ /:/\:| \ \:\ / /:/ /__/:/ /:/\:\ /__/::::::::\ /__/\_|:|____ \ \:\
* \ \:\/:/~/:/ \ \:\ /:/ \ \:\/:/__\/ \ \:\~~\~~\/ \ \:\/:::::/ \__\:\
* \ \::/ /:/ \ \:\/:/ \ \::/ \ \:\ ~~~ \ \::/~~~~ / /:/
* \ \:\/:/ \ \::/ \ \:\ \ \:\ \ \:\ /__/:/
* \ \::/ \__\/ \ \:\ \ \:\ \ \:\ \__\/
* \__\/ \__\/ \__\/ \__\/
* blog : http://blankj.com
* time : 16/12/08
* desc : utils about initialization
* </pre>
*/
public final class AppUtils {
private static final ExecutorService UTIL_POOL = Executors.newFixedThreadPool(3);
private static final Handler UTIL_HANDLER = new Handler(Looper.getMainLooper());
@SuppressLint("StaticFieldLeak")
private static Application sApplication;
private AppUtils() {
throw new UnsupportedOperationException("u can't instantiate me...");
}
/**
* Init utils.
* <p>Init it in the class of Application.</p>
*
* @param context context
*/
public static void init(final Context context) {
if (context == null) {
init(getApplicationByReflect());
return;
}
init((Application) context.getApplicationContext());
}
/**
* Init utils.
* <p>Init it in the class of Application.</p>
*
* @param app application
*/
public static void init(final Application app) {
if (sApplication == null) {
if (app == null) {
sApplication = getApplicationByReflect();
} else {
sApplication = app;
}
} else {
sApplication = app;
}
}
/**
* Return the context of Application object.
*
* @return the context of Application object
*/
public static Application getApp() {
if (sApplication != null) return sApplication;
Application app = getApplicationByReflect();
init(app);
return app;
}
public static String getPackageName(Context context) {
return context.getPackageName();
}
/**
* 获取版本名
*
* @param noSuffix 是否去掉后缀 (如:-debug、-test
*/
public static String getVersionName(boolean noSuffix) {
PackageInfo packageInfo = getPackageInfo(getApp());
if (packageInfo != null) {
String versionName = packageInfo.versionName;
if (noSuffix && versionName != null) {
int index = versionName.indexOf("-");
if (index >= 0) {
return versionName.substring(0, index);
}
}
return versionName;
}
return "";
}
//版本号
public static int getVersionCode() {
PackageInfo packageInfo = getPackageInfo(getApp());
if (packageInfo != null) {
return packageInfo.versionCode;
}
return 0;
}
/**
* 比较版本
* 1 = 大于当前版本
* 0 = 版本一样
* -1 = 当前版本大于更新版本
*/
public static int compareVersionNames(String newVersionName) {
try {
if (TextUtils.isEmpty(newVersionName)) {
return -1;
}
int res = 0;
String currentVersionName = getVersionName(true);
if (currentVersionName.equals(newVersionName)) {
return 0;
}
String[] oldNumbers = currentVersionName.split("\\.");
String[] newNumbers = newVersionName.split("\\.");
// To avoid IndexOutOfBounds
int minIndex = Math.min(oldNumbers.length, newNumbers.length);
for (int i = 0; i < minIndex; i++) {
int oldVersionPart = Integer.parseInt(oldNumbers[i]);
int newVersionPart = Integer.parseInt(newNumbers[i]);
if (oldVersionPart < newVersionPart) {
res = 1;
break;
} else if (oldVersionPart > newVersionPart) {
res = -1;
break;
}
}
// If versions are the same so far, but they have different length...
if (res == 0 && oldNumbers.length != newNumbers.length) {
res = (oldNumbers.length > newNumbers.length) ? -1 : 1;
}
return res;
} catch (Exception e) {
return -1;
}
}
private static PackageInfo getPackageInfo(Context context) {
PackageInfo packageInfo;
try {
PackageManager pm = context.getPackageManager();
packageInfo = pm.getPackageInfo(context.getPackageName(), PackageManager.GET_CONFIGURATIONS);
return packageInfo;
} catch (Exception e) {
return null;
}
}
static <T> Task<T> doAsync(final Task<T> task) {
UTIL_POOL.execute(task);
return task;
}
public static void runOnUiThread(final Runnable runnable) {
if (Looper.myLooper() == Looper.getMainLooper()) {
runnable.run();
} else {
AppUtils.UTIL_HANDLER.post(runnable);
}
}
public static void runOnUiThreadDelayed(final Runnable runnable, long delayMillis) {
AppUtils.UTIL_HANDLER.postDelayed(runnable, delayMillis);
}
static String getCurrentProcessName() {
String name = getCurrentProcessNameByFile();
if (!TextUtils.isEmpty(name)) return name;
name = getCurrentProcessNameByAms();
if (!TextUtils.isEmpty(name)) return name;
name = getCurrentProcessNameByReflect();
return name;
}
static void fixSoftInputLeaks(final Window window) {
InputMethodManager imm =
(InputMethodManager) AppUtils.getApp().getSystemService(Context.INPUT_METHOD_SERVICE);
if (imm == null) return;
String[] leakViews = new String[]{"mLastSrvView", "mCurRootView", "mServedView", "mNextServedView"};
for (String leakView : leakViews) {
try {
Field leakViewField = InputMethodManager.class.getDeclaredField(leakView);
if (leakViewField == null) continue;
if (!leakViewField.isAccessible()) {
leakViewField.setAccessible(true);
}
Object obj = leakViewField.get(imm);
if (!(obj instanceof View)) continue;
View view = (View) obj;
if (view.getRootView() == window.getDecorView().getRootView()) {
leakViewField.set(imm, null);
}
} catch (Throwable ignore) {/**/}
}
}
///////////////////////////////////////////////////////////////////////////
// private method
///////////////////////////////////////////////////////////////////////////
private static String getCurrentProcessNameByFile() {
try {
File file = new File("/proc/" + android.os.Process.myPid() + "/" + "cmdline");
BufferedReader mBufferedReader = new BufferedReader(new FileReader(file));
String processName = mBufferedReader.readLine().trim();
mBufferedReader.close();
return processName;
} catch (Exception e) {
e.printStackTrace();
return "";
}
}
private static String getCurrentProcessNameByAms() {
ActivityManager am = (ActivityManager) AppUtils.getApp().getSystemService(Context.ACTIVITY_SERVICE);
if (am == null) return "";
List<ActivityManager.RunningAppProcessInfo> info = am.getRunningAppProcesses();
if (info == null || info.size() == 0) return "";
int pid = android.os.Process.myPid();
for (ActivityManager.RunningAppProcessInfo aInfo : info) {
if (aInfo.pid == pid) {
if (aInfo.processName != null) {
return aInfo.processName;
}
}
}
return "";
}
private static String getCurrentProcessNameByReflect() {
String processName = "";
try {
Application app = AppUtils.getApp();
Field loadedApkField = app.getClass().getField("mLoadedApk");
loadedApkField.setAccessible(true);
Object loadedApk = loadedApkField.get(app);
Field activityThreadField = loadedApk.getClass().getDeclaredField("mActivityThread");
activityThreadField.setAccessible(true);
Object activityThread = activityThreadField.get(loadedApk);
Method getProcessName = activityThread.getClass().getDeclaredMethod("getProcessName");
processName = (String) getProcessName.invoke(activityThread);
} catch (Exception e) {
e.printStackTrace();
}
return processName;
}
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 e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
throw new NullPointerException("u should init first");
}
///////////////////////////////////////////////////////////////////////////
// interface
///////////////////////////////////////////////////////////////////////////
public abstract static class Task<Result> implements Runnable {
private static final int NEW = 0;
private static final int COMPLETING = 1;
private static final int CANCELLED = 2;
private static final int EXCEPTIONAL = 3;
private volatile int state = NEW;
abstract Result doInBackground();
private final Callback<Result> mCallback;
public Task(final Callback<Result> callback) {
mCallback = callback;
}
@Override
public void run() {
try {
final Result t = doInBackground();
if (state != NEW) return;
state = COMPLETING;
UTIL_HANDLER.post(new Runnable() {
@Override
public void run() {
mCallback.onCall(t);
}
});
} catch (Throwable th) {
if (state != NEW) return;
state = EXCEPTIONAL;
}
}
public void cancel() {
state = CANCELLED;
}
public boolean isDone() {
return state != NEW;
}
public boolean isCanceled() {
return state == CANCELLED;
}
}
public interface Callback<T> {
void onCall(T data);
}
/**
* 判断是否打开定位
*/
public static boolean getGpsStatus(Context ctx) {
//从系统服务中获取定位管理器
LocationManager locationManager
= (LocationManager) ctx.getSystemService(Context.LOCATION_SERVICE);
// 通过GPS卫星定位定位级别可以精确到街通过24颗卫星定位在室外和空旷的地方定位准确、速度快
boolean gps = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
// 通过WLAN或移动网络(3G/2G)确定的位置也称作AGPS辅助GPS定位。主要用于在室内或遮盖物建筑群或茂密的深林等密集的地方定位
boolean network = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
if (gps || network) {
return true;
}
return false;
}
/**
* 打开系统定位界面
*/
public static void goToOpenGps(Context ctx) {
Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
ctx.startActivity(intent);
}
}

View File

@@ -0,0 +1,195 @@
package com.chuhai.utils.ktx
import android.app.Activity
import android.content.Context
import android.content.res.TypedArray
import android.graphics.drawable.Drawable
import android.util.TypedValue
import androidx.annotation.*
import androidx.core.content.ContextCompat
import androidx.core.content.res.ResourcesCompat
import androidx.fragment.app.Fragment
import com.chuhai.utils.AppUtils
/**
* 资源工具类
* @author Max
* @date 2019-11-26.
*/
/**
* 获取颜色
*/
fun Fragment.getColorById(@ColorRes colorResId: Int): Int {
return ContextCompat.getColor(context!!, colorResId)
}
/**
* 获取图片
*/
fun Fragment.getDrawableById(@DrawableRes drawableRedId: Int): Drawable? {
return ContextCompat.getDrawable(context!!, drawableRedId)
}
/**
* 获取颜色
*/
fun Activity.getColorById(@ColorRes colorResId: Int): Int {
return ContextCompat.getColor(this, colorResId)
}
/**
* 获取图片
*/
fun Activity.getDrawableById(@DrawableRes drawableRedId: Int): Drawable? {
return ContextCompat.getDrawable(this, drawableRedId)
}
/**
* 获取颜色
*/
fun Context.getColorById(@ColorRes colorResId: Int): Int {
return ContextCompat.getColor(this, colorResId)
}
/**
* 获取图片
*/
fun Context.getDrawableById(@DrawableRes drawableRedId: Int): Drawable? {
return ContextCompat.getDrawable(this, drawableRedId)
}
/**
* 获取字符串资源
*/
fun Any.getStringById(@StringRes stringResId: Int): String {
return AppUtils.getApp().getString(stringResId)
}
/**
* 获取字符串资源
*/
fun Int.toStringRes(): String {
return AppUtils.getApp().getString(this)
}
/**
* 获取资源drawable
* */
fun Int.toDrawableRes(): Drawable? {
return ContextCompat.getDrawable(AppUtils.getApp(), this)
}
/**
* 获取资源color
* */
fun Int.toColorRes(): Int {
return ContextCompat.getColor(AppUtils.getApp(), this)
}
/**
* 通过自定义属性-获取DrawableRes
*/
@DrawableRes
fun Context.getDrawableResFromAttr(
@AttrRes attrResId: Int,
typedValue: TypedValue = TypedValue(),
resolveRefs: Boolean = true
): Int? {
return try {
theme.resolveAttribute(attrResId, typedValue, resolveRefs)
return typedValue.resourceId
} catch (e: Exception) {
e.printStackTrace()
null
}
}
/**
* 通过自定义属性-获取Drawable
*/
fun Context.getDrawableFromAttr(@AttrRes attrId: Int): Drawable? {
return try {
val drawableRes = getDrawableResFromAttr(attrId) ?: return null
ResourcesCompat.getDrawable(resources, drawableRes, null)
} catch (e: Exception) {
e.printStackTrace()
null
}
}
/**
* 通过自定义属性-获取ColorRes
*/
@ColorRes
fun Context.getColorResFromAttr(
@AttrRes attrResId: Int,
typedValue: TypedValue = TypedValue(),
resolveRefs: Boolean = true
): Int? {
return try {
theme.resolveAttribute(attrResId, typedValue, resolveRefs)
return typedValue.resourceId
} catch (e: Exception) {
e.printStackTrace()
null
}
}
/**
* 通过自定义属性-获取Color
*/
@ColorRes
fun Context.getColorFromAttr(
@AttrRes attrResId: Int
): Int? {
return try {
val colorRes = getColorFromAttr(attrResId) ?: return null
ResourcesCompat.getColor(resources, colorRes, null)
} catch (e: Exception) {
e.printStackTrace()
null
}
}
/**
* 通过自定义属性-获取LayoutRes
*/
@LayoutRes
fun Context.getLayoutResFromAttr(
@AttrRes attrResId: Int,
typedValue: TypedValue = TypedValue(),
resolveRefs: Boolean = true
): Int? {
return try {
theme.resolveAttribute(attrResId, typedValue, resolveRefs)
return typedValue.resourceId
} catch (e: Exception) {
e.printStackTrace()
null
}
}
/**
* 通过自定义属性-获取Boolean
*/
fun Context.getBooleanResFromAttr(
@AttrRes attrResId: Int,
defValue: Boolean = false
): Boolean {
var attrs: TypedArray? = null
try {
attrs = obtainStyledAttributes(null, intArrayOf(attrResId))
return attrs.getBoolean(0, defValue)
} catch (e: Exception) {
e.printStackTrace()
} finally {
attrs?.recycle()
}
return defValue
}

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
</resources>

View File

@@ -0,0 +1,3 @@
<resources>
</resources>