这个提交包含在:
xuqm 2023-06-26 10:58:04 +08:00
父节点 cef3f0e8f2
当前提交 00f97d1ed1
共有 220 个文件被更改,包括 13767 次插入0 次删除

85
.gitignore vendored 普通文件
查看文件

@ -0,0 +1,85 @@
# Built application files
*.apk
*.aar
*.ap_
*.aab
# Files for the ART/Dalvik VM
*.dex
# Java class files
*.class
# Generated files
bin/
gen/
out/
# Uncomment the following line in case you need and you don't have the release build type files in your app
# release/
# Gradle files
.gradle/
build/
# Local configuration file (sdk path, etc)
local.properties
# Proguard folder generated by Eclipse
proguard/
# Log Files
*.log
# Android Studio Navigation editor temp files
.navigation/
# Android Studio captures folder
captures/
# IntelliJ
*.iml
.idea/
# Android Studio 3 in .gitignore file.
.idea/caches
.idea/modules.xml
# Comment next line if keeping position of elements in Navigation Editor is relevant for you
.idea/navEditor.xml
# Keystore files
# Uncomment the following lines if you do not want to check your keystore files in.
#*.jks
#*.keystore
# External native build folder generated in Android Studio 2.2 and later
.externalNativeBuild
.cxx/
# Google Services (e.g. APIs or Firebase)
# google-services.json
# Freeline
freeline.py
freeline/
freeline_project_description.json
# fastlane
fastlane/report.xml
fastlane/Preview.html
fastlane/screenshots
fastlane/test_output
fastlane/readme.md
# Version control
vcs.xml
# lint
lint/intermediates/
lint/generated/
lint/outputs/
lint/tmp/
# lint/reports/
/app/key
output-metadata.json
# Android Profiling
*.hprof

查看文件

@ -0,0 +1 @@
# 摆药机

1
app/.gitignore vendored 普通文件
查看文件

@ -0,0 +1 @@
/build

85
app/build.gradle 普通文件
查看文件

@ -0,0 +1,85 @@
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt'
android {
compileSdkVersion versions.compileSdk
buildToolsVersion versions.buildTools
defaultConfig {
applicationId apps.applicationId
minSdkVersion versions.minSdk
targetSdkVersion versions.targetSdk
versionCode versions.versionCode
versionName versions.versionName
manifestPlaceholders = [
APP_NAME: apps.applicationName,
APP_ID : apps.applicationId,
]
buildConfigField("String", "APP_Name", "\"" + apps.applicationName + "\"")
flavorDimensions "versioncode"
}
buildTypes {
debug {
minifyEnabled false
signingConfig signingConfigs.debug
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
release {
minifyEnabled false
signingConfig signingConfigs.debug
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
applicationVariants.all { variant ->
variant.outputs.all { output ->
if ("debug" != variant.buildType.name) {
def now = new Date()
def path = "../../../../../apks/${variant.buildType.name}/v${defaultConfig.versionName}_" + now.format("yyyy.MM.dd_HH")
outputFileName = path + "/${applicationId}.apk"
}
}
}
signingConfigs {
debug {
keyAlias 'xuqm'
keyPassword 'xuqinmin1022'
storeFile file('key')
storePassword 'xuqinmin1022'
}
releaseConfig {}
}
sourceSets {
main {
jniLibs.srcDirs = ['libs']
}
}
androidExtensions {
experimental = true
}
namespace 'com.bjca.hp.acupuncture'
}
dependencies {
implementation fileTree(dir: "libs", include: ["*.jar","*.aar"])
implementation project(path: ':core')
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
implementation 'com.android.support:appcompat-v7:28.0.0'
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
implementation 'androidx.appcompat:appcompat:1.3.0'
implementation 'com.google.android.material:material:1.3.0'
implementation 'tp.xmaihh:serialport:2.1'
implementation 'com.rabbitmq:amqp-client:5.15.0'
}

21
app/proguard-rules.pro vendored 普通文件
查看文件

@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile

查看文件

@ -0,0 +1,76 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<!-- 网络权限 -->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" /> <!-- <uses-permission android:name="android.permission.READ_LOGS" /> -->
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />
<application
android:name=".MyApplication"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="${APP_NAME}"
android:supportsRtl="true"
android:theme="@style/AppTheme"
android:usesCleartextTraffic="true"
tools:replace="android:label">
<activity
android:name=".ui.TestActivity"
android:exported="false" />
<activity
android:name=".ui.SettingActivity"
android:exported="false" />
<receiver
android:name=".receiver.BootCompleteReceiver"
android:enabled="true"
android:exported="true">
<!-- 接收启动完成的广播 -->
<intent-filter android:priority="1000">
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
<activity
android:name=".ui.MainActivity"
android:exported="false" />
<activity
android:name=".ui.WelcomeActivity"
android:exported="true"
android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${APP_ID}.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/filepaths" />
</provider>
<meta-data
android:name="design_width_in_dp"
android:value="540" />
<meta-data
android:name="design_height_in_dp"
android:value="960" />
</application>
</manifest>

二进制文件未显示。

二进制文件未显示。

二进制文件未显示。

二进制文件未显示。

二进制文件未显示。

二进制文件未显示。

查看文件

@ -0,0 +1,33 @@
package com.bjca.hp.acupuncture;
import com.xuqm.base.App;
import com.xuqm.base.di.component.AppComponent;
import com.xuqm.base.di.manager.HttpManager;
import com.bjca.hp.acupuncture.common.CrashHandler;
import com.bjca.hp.acupuncture.repository.HeaderInterceptor;
/**
* @author xuqm
*/
public class MyApplication extends App {
public static String baseUrl = "http://10.10.203.120:31734";
public static AppComponent appComponent1;
public static AppComponent appComponent2;
@Override
public void onCreate() {
super.onCreate();
appComponent = HttpManager.getAppComponent(baseUrl, new HeaderInterceptor(getApplicationContext()));
appComponent1 = HttpManager.getAppComponent("http://10.10.203.120:35662", new HeaderInterceptor(getApplicationContext()));
appComponent2 = HttpManager.getAppComponent("http://10.10.203.120:31669", new HeaderInterceptor(getApplicationContext()));
CrashHandler.getInstance().init(this);
}
@Override
public boolean showLog() {
return super.showLog();
}
}

查看文件

@ -0,0 +1,166 @@
package com.bjca.hp.acupuncture.common;
import android.content.Context;
import android.os.Environment;
import android.os.SystemClock;
import android.util.Log;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
/*************************************************************************************************
* <pre>
* @包路径 cn.org.bjca.wcert.ywq.utils.crash
* @版权所有 北京数字认证股份有限公司 (C) 2017
*
* @类描述:
* @版本: V1.5.1
* @作者 daizhenhong
* @创建时间 2017/12/13 下午4:22
*
* @修改记录
-----------------------------------------------------------------------------------------------
----------- 时间 | 修改人 | 修改的方法 | 修改描述 ---------------
-----------------------------------------------------------------------------------------------
</pre>
************************************************************************************************/
public class CrashHandler implements Thread.UncaughtExceptionHandler {
private static String TAG = "CrashHandler";
// 系统默认的UncaughtException处理类
private Thread.UncaughtExceptionHandler mDefaultHandler;
// 用于格式化日期,作为日志文件名的一部分
private DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
private static CrashHandler mCrashHandler;
private Context mContext;
private CrashHandler() {
}
public static CrashHandler getInstance() {
if (mCrashHandler == null) {
synchronized (CrashHandler.class) {
mCrashHandler = new CrashHandler();
}
}
return mCrashHandler;
}
public void init(Context context) {
mContext = context;
mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
Thread.setDefaultUncaughtExceptionHandler(this);
}
@Override
public void uncaughtException(Thread thread, Throwable throwable) {
if (!handleException(throwable) && mDefaultHandler != null) {
// 如果用户没有处理则让系统默认的异常处理器来处理
mDefaultHandler.uncaughtException(thread, throwable);
} else {
SystemClock.sleep(2000);
// 退出程序
android.os.Process.killProcess(android.os.Process.myPid());
System.exit(1);
}
}
private boolean handleException(Throwable ex) {
if (ex == null) {
return false;
}
try {
saveCrashInfoFile(ex);
SystemClock.sleep(2000);
} catch (Exception e) {
e.printStackTrace();
}
return true;
}
private String saveCrashInfoFile(Throwable ex) {
StringBuffer sb = new StringBuffer();
if (hasSdcard())
try {
SimpleDateFormat sDateFormat = new SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss", Locale.CHINA);
String date = sDateFormat.format(new Date());
sb.append("\r\n" + date + "\n");
Writer writer = new StringWriter();
PrintWriter printWriter = new PrintWriter(writer);
ex.printStackTrace(printWriter);
Throwable cause = ex.getCause();
while (cause != null) {
cause.printStackTrace(printWriter);
cause = cause.getCause();
}
printWriter.flush();
printWriter.close();
String result = writer.toString();
sb.append(result);
String fileName = writeFile(sb.toString());
return fileName;
} catch (Exception e) {
Log.e(TAG, "an error occured while writing file...", e);
sb.append("an error occured while writing file...\r\n");
writeFile(sb.toString());
}
return null;
}
private String writeFile(String text) {
Log.e("writeFile", text);
String time = formatter.format(new Date());
String fileName = "crash-demo-" + time + ".log";
String path = getGlobalpath();
File dir = new File(path);
if (!dir.exists()) {
dir.mkdir();
}
FileOutputStream fos = null;
try {
fos = new FileOutputStream(path + fileName, true);
fos.write(text.getBytes());
fos.flush();
fos.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return fileName;
}
public String getGlobalpath() {
return Environment.getExternalStorageDirectory().getAbsolutePath()
+ File.separator + "crash" + File.separator;
}
public boolean hasSdcard(){
return Environment.getExternalStorageState()
.equals(Environment.MEDIA_MOUNTED);
}
}

查看文件

@ -0,0 +1,248 @@
package com.bjca.hp.acupuncture.common;
import android.text.TextUtils;
import android.util.Log;
import com.rabbitmq.client.AMQP;
import com.rabbitmq.client.AlreadyClosedException;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.DefaultConsumer;
import com.rabbitmq.client.Envelope;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeoutException;
/***************************************************************************
* <pre></pre>
* @文件名称 RabbitMQClient
* @包 com.bjca.hp.acupuncture.common
* @版权所有北京数字医信责任有限公司 (C) 2022
*
* @类描述:
* @版本: V1.0
* @创建人 xuqm
* @创建时间2022/6/15 下午 02:19
* @修改记录
*/
public class RabbitMQClient {
private final String TAG = "RabbitMQ";
private final String FLAG_SEND = "send";
private final String FLAG_RECEIVE = "receive";
private final ConnectionFactory factory;
private Connection connection;
private Map<String, Channel> channelMap = new HashMap<>();
public static final String EXCHANGETYPE_FANOUT = "fanout"; //不用匹配路由发送给所有绑定转换器的队列
public static final String EXCHANGETYPE_DIRECT = "direct"; //匹配路由一致才发送给绑定转换器队列
public static final String EXCHANGETYPE_TOPIC = "topic"; // 通配符* # 匹配路由一致才发送给绑定转换器队列
public RabbitMQClient(String hostIp, int port, String username, String password) {
factory = new ConnectionFactory();
factory.setUsername(username);
factory.setPassword(password);
factory.setHost(hostIp);
factory.setPort(port);
factory.setVirtualHost("/");//类似数据库的意思
factory.setConnectionTimeout(15 * 1000); //连接时间设置为10秒
factory.setAutomaticRecoveryEnabled(true); //恢复连接通道
factory.setTopologyRecoveryEnabled(true); //恢复通道中 转换器队列绑定关系等
factory.setNetworkRecoveryInterval(5 * 1000); //恢复连接间隔默认5秒
}
/**
* @param message 需要发送的消息
* @param queueName 管道名称
* @date 创建时间:2020/9/8 0008
* @auther gaoxiaoxiong
* @Descriptiion
**/
public void sendQueueMessage(String message, String queueName) throws IOException, TimeoutException, AlreadyClosedException {
if (connection == null || !connection.isOpen()) {
connection = factory.newConnection();
}
if (!channelMap.containsKey(FLAG_SEND + queueName)) {
Channel channel = connection.createChannel();
channel.queueDeclare(queueName, false, false, false, null);
channelMap.put(FLAG_SEND + queueName, channel);
}
//空名字的交换机需要设置routingKey此时会将routingKey 作为 队列名使用
channelMap.get(FLAG_SEND + queueName).basicPublish("", queueName, null, message.getBytes());
}
/**
* @param exchangeName 交换机名称
* @param message 需要发送的消息
* @param queueName 队列名称
* @param routingKey 路由规则
* @date 创建时间:2020/9/8 0008
* @auther gaoxiaoxiong
* @Descriptiion 发送 exchangeType direct 类型的信息
**/
public void sendDirectTypeMessage(String exchangeName, String message, String queueName, String routingKey) throws IOException, TimeoutException, AlreadyClosedException {
if (connection == null || !connection.isOpen()) {
connection = factory.newConnection();
}
if (!channelMap.containsKey(FLAG_SEND + exchangeName + EXCHANGETYPE_DIRECT + queueName)) {
Channel channel = connection.createChannel();
channel.queueDeclare(queueName, false, false, false, null);
channel.exchangeDeclare(exchangeName, EXCHANGETYPE_DIRECT);
channelMap.put(FLAG_SEND + exchangeName + EXCHANGETYPE_DIRECT + queueName, channel);
}
channelMap.get(FLAG_SEND + exchangeName + EXCHANGETYPE_DIRECT + queueName).basicPublish(exchangeName, routingKey, null, message.getBytes());
}
/**
* @param exchangeName 交换机名称
* @param queueName 队列名称
* @param message 发送的消息
* @date 创建时间:2020/9/8 0008
* @auther gaoxiaoxiong
* @Descriptiion 发送 exchangeType fanout 类型的信息
**/
public void sendFanoutTypeMessage(String exchangeName, String queueName, String message) throws IOException, TimeoutException, AlreadyClosedException {
if (connection == null || !connection.isOpen()) {
connection = factory.newConnection();
}
if (!channelMap.containsKey(FLAG_SEND + exchangeName + EXCHANGETYPE_FANOUT + queueName)) {
Channel channel = connection.createChannel();
channel.queueDeclare(queueName, false, false, false, null);
channel.exchangeDeclare(exchangeName, EXCHANGETYPE_FANOUT);
channelMap.put(FLAG_SEND + exchangeName + EXCHANGETYPE_FANOUT + queueName, channel);
}
channelMap.get(FLAG_SEND + exchangeName + EXCHANGETYPE_FANOUT + queueName).basicPublish(exchangeName, "", null, message.getBytes());
}
/**
* @param exchangeName 交换机名称
* @param exchangeType 模式
* @param queueName 队列名称
* @param message 需要发送的消息
* @param routingKey 路由规则
* @date 创建时间:2020/9/8 0008
* @auther gaoxiaoxiong
* @Descriptiion
**/
public void sendExchangeNameQueueMessage(String exchangeName, String exchangeType, String message, String queueName, String routingKey) throws IOException, TimeoutException, AlreadyClosedException {
if (connection == null || !connection.isOpen()) {
connection = factory.newConnection();
}
if (!channelMap.containsKey(FLAG_SEND + exchangeName + exchangeType + queueName)) {
Channel channel = connection.createChannel();
channel.queueDeclare(queueName, false, false, false, null);
channel.exchangeDeclare(exchangeName, exchangeType);
channelMap.put(FLAG_SEND + exchangeName + exchangeType + queueName, channel);
}
if (exchangeType.equals(EXCHANGETYPE_FANOUT)) {
channelMap.get(FLAG_SEND + exchangeName + exchangeType + queueName).basicPublish(exchangeName, "", null, message.getBytes());
} else if (exchangeType.equals(EXCHANGETYPE_DIRECT)) {
channelMap.get(FLAG_SEND + exchangeName + exchangeType + queueName).basicPublish(exchangeName, routingKey, null, message.getBytes());
} else if (exchangeType.equals(EXCHANGETYPE_TOPIC)) {
channelMap.get(FLAG_SEND + exchangeName + exchangeType + queueName).basicPublish(exchangeName, routingKey, null, message.getBytes());
}
}
/**
* @param queueName 队列名称
* @date 创建时间:2020/9/8 0008
* @auther gaoxiaoxiong
* @Descriptiion
**/
public void receiveQueueMessage(final String queueName, final ResponseListener listener)
throws IOException, TimeoutException, AlreadyClosedException {
receiveQueueRoutingKeyMessage(queueName, "", "", "", listener);
}
/**
* @param queueName 队列名称
* @param routingKey 路由规则
* @param exchangeName 交换机名称
* @param exchangeType 交换机类型
* @date 创建时间:2020/9/8 0008
* @auther gaoxiaoxiong
* @Descriptiion
**/
public void receiveQueueRoutingKeyMessage(String queueName, final String routingKey, String exchangeName, String exchangeType, final ResponseListener listener)
throws IOException, TimeoutException, AlreadyClosedException {
if (exchangeType.equals(EXCHANGETYPE_DIRECT) || exchangeType.equals(EXCHANGETYPE_TOPIC)) {
if (TextUtils.isEmpty(routingKey)) {
throw new NullPointerException("路由规则不能为空");
}
}
if (!TextUtils.isEmpty(routingKey)) {
if (TextUtils.isEmpty(exchangeName)) {
throw new NullPointerException("交换机名称不能为空");
}
}
if (!channelMap.containsKey(FLAG_RECEIVE + routingKey + queueName)) {
if (connection == null || !connection.isOpen()) {
connection = factory.newConnection();
}
final Channel channel = connection.createChannel();
channel.queueDeclare(queueName, true, false, false, null);
//绑定转换器使用路由筛选消息
if (!TextUtils.isEmpty(routingKey)) {
channel.exchangeDeclare(exchangeName, exchangeType);
channel.queueBind(queueName, exchangeName, routingKey); //设置绑定
}
//监听队列
channel.basicConsume(queueName, false, new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope,
AMQP.BasicProperties properties, byte[] body)
throws IOException {
String message = new String(body, "UTF-8");
if (listener != null) {
listener.receive(message);
}
channel.basicAck(envelope.getDeliveryTag(), false); //消息应答
}
});
channelMap.put(FLAG_RECEIVE + routingKey + queueName, channel);
Log.e(TAG,"已经连接上了,队列名称:" + queueName);
}
}
/**
* 关闭所有资源
*/
public void close() {
for (Channel next : channelMap.values()) {
if (next != null && next.isOpen()) {
try {
next.close();
} catch (IOException | TimeoutException e) {
e.printStackTrace();
}
}
}
channelMap.clear();
if (connection != null && connection.isOpen()) {
try {
connection.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public interface ResponseListener {
void receive(String message);
}
}

查看文件

@ -0,0 +1,239 @@
package com.bjca.hp.acupuncture.common;
import android.os.SystemClock;
import android.text.TextUtils;
import com.rabbitmq.client.AlreadyClosedException;
import java.io.IOException;
import java.util.UUID;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeoutException;
/***************************************************************************
* <pre></pre>
* @文件名称 RabbitMQUtil
* @包 com.bjca.hp.acupuncture.common
* @版权所有北京数字医信责任有限公司 (C) 2022
*
* @类描述:
* @版本: V1.0
* @创建人 xuqm
* @创建时间2022/6/15 下午 02:22
* @修改记录
*/
public class RabbitMQUtil {
private boolean isRunning = true;
private RabbitMQClient rabbitMQ;
private ExecutorService executor;
public RabbitMQUtil(String hostIp, int port, String username, String password) {
rabbitMQ = new RabbitMQClient(hostIp, port, username, password);
executor = Executors.newSingleThreadExecutor(); //根据项目需要设置常用线程个数
}
/**
* @param message 发送的消息
* @param queueName 队列名称
* @date 创建时间:2020/9/8 0008
* @auther gaoxiaoxiong
* @Descriptiion
**/
public void sendMessage(final String message, final String queueName, final SendMessageListener sendMessageListener,final ErrorMessageListener errorMessageListener) {
executor.execute(new Runnable() {
@Override
public void run() {
try {
rabbitMQ.sendQueueMessage(message, queueName);
if (sendMessageListener != null) sendMessageListener.sendMessage(true);
} catch (IOException | TimeoutException | AlreadyClosedException e) {
e.printStackTrace();
if (errorMessageListener!=null){
errorMessageListener.errorMessage(e);
}
if (sendMessageListener != null) sendMessageListener.sendMessage(false);
}
}
});
}
/**
* @param message 发送的消息
* @param exchangeName 交换机名称
* @param queueName 队列名称
* @date 创建时间:2020/9/8 0008
* @auther gaoxiaoxiong
* @Descriptiion
**/
public void sendMessage(final String message, final String exchangeName, final String exchangeType, final String queueName, final String routingKey, final SendMessageListener sendMessageListener,final ErrorMessageListener errorMessageListener) {
executor.execute(new Runnable() {
@Override
public void run() {
try {
rabbitMQ.sendExchangeNameQueueMessage(exchangeName, exchangeType, message, queueName, routingKey);
if (sendMessageListener != null) sendMessageListener.sendMessage(true);
} catch (IOException | TimeoutException | AlreadyClosedException e) {
e.printStackTrace();
if (errorMessageListener!=null){
errorMessageListener.errorMessage(e);
}
if (sendMessageListener != null) sendMessageListener.sendMessage(false);
}
}
});
}
/**
* @param exchangeName 交换机名称
* @param queueName 队列名称
* @param message 需要发送的消息
* @date 创建时间:2020/9/8 0008
* @auther gaoxiaoxiong
* @Descriptiion
**/
public void sendFanoutTypeMessage(final String exchangeName, final String message, final String queueName, final SendMessageListener sendMessageListener,final ErrorMessageListener errorMessageListener) {
executor.execute(new Runnable() {
@Override
public void run() {
try {
rabbitMQ.sendFanoutTypeMessage(exchangeName, queueName, message);
if (sendMessageListener != null) sendMessageListener.sendMessage(true);
} catch (IOException | TimeoutException | AlreadyClosedException e) {
e.printStackTrace();
if (errorMessageListener!=null){
errorMessageListener.errorMessage(e);
}
if (sendMessageListener != null) sendMessageListener.sendMessage(false);
}
}
});
}
/**
* @param exchangeName 交换机名称
* @param message 需要发送的消息
* @param queueName 队列名称
* @param routingKey 路由规则
* @date 创建时间:2020/9/8 0008
* @auther gaoxiaoxiong
* @Descriptiion 发送 exchangeType direct 类型的信息
**/
public void sendDirectTypeMessage(final String exchangeName, final String queueName, final String message, final String routingKey, final SendMessageListener sendMessageListener,final ErrorMessageListener errorMessageListener) {
executor.execute(new Runnable() {
@Override
public void run() {
try {
rabbitMQ.sendDirectTypeMessage(exchangeName, queueName, message, routingKey);
if (sendMessageListener != null) sendMessageListener.sendMessage(true);
} catch (IOException | TimeoutException | AlreadyClosedException e) {
e.printStackTrace();
if (errorMessageListener!=null){
errorMessageListener.errorMessage(e);
}
if (sendMessageListener != null) sendMessageListener.sendMessage(false);
}
}
});
}
/**
* @param queueName 队列名称
* @date 创建时间:2020/9/8 0008
* @auther gaoxiaoxiong
* @Descriptiion
**/
public void receiveQueueMessage(String queueName, final ReceiveMessageListener listener,final ErrorMessageListener errorMessageListener) {
String newQueueName = null;
if (TextUtils.isEmpty(queueName)){
newQueueName = createDefaultQueueName(queueName);
}else {
newQueueName = queueName;
}
final String finalNewQueueName = newQueueName;
executor.execute(() -> {
while (isRunning) {
try {
rabbitMQ.receiveQueueMessage(finalNewQueueName, message -> {
if (listener != null) listener.receiveMessage(message);
});
} catch (IOException | TimeoutException | AlreadyClosedException e) {
if (errorMessageListener!=null){
errorMessageListener.errorMessage(e);
}
e.printStackTrace();
SystemClock.sleep(5000);
}
}
});
}
public void receiveQueueRoutingKeyMessage(String queueName, final String routingKey, final String exchangeName, final String exchangeType, final ReceiveMessageListener listener,final ErrorMessageListener errorMessageListener) {
String newQueueName = null;
if (TextUtils.isEmpty(queueName)){
newQueueName = createDefaultQueueName(queueName);
}else {
newQueueName = queueName;
}
final String finalNewQueueName = newQueueName;
executor.execute(new Runnable() {
@Override
public void run() {
while (isRunning) {
try {
rabbitMQ.receiveQueueRoutingKeyMessage(finalNewQueueName, routingKey, exchangeName, exchangeType, new RabbitMQClient.ResponseListener() {
@Override
public void receive(String message) {
if (listener != null) listener.receiveMessage(message);
}
});
} catch (IOException | TimeoutException | AlreadyClosedException e) {
if (errorMessageListener!=null){
errorMessageListener.errorMessage(e);
}
e.printStackTrace();
SystemClock.sleep(5000); //等待五秒
}
}
}
});
}
public String createDefaultQueueName(String routingKey) {
if (TextUtils.isEmpty(routingKey)){
routingKey = "";
}
return routingKey + "@" + UUID.randomUUID();
}
/**
* 建议
* 在application中关闭或者在结束工作时关闭
*/
public void close() {
isRunning = false;
executor.execute(new Runnable() {
@Override
public void run() {
rabbitMQ.close();
executor.shutdownNow();
}
});
}
public interface ReceiveMessageListener {
void receiveMessage(String message);
}
public interface SendMessageListener {
void sendMessage(boolean isSuccess);
}
public interface ErrorMessageListener{
void errorMessage(Exception e);
}
}

查看文件

@ -0,0 +1,4 @@
package com.bjca.hp.acupuncture.common
const val SHARE_RISK_LOCATION = "share_risk_location"
const val SHARE_RISK_PURE = "share_risk_pure"

查看文件

@ -0,0 +1,72 @@
package com.bjca.hp.acupuncture.model
import com.google.gson.annotations.SerializedName
data class DrugUsage(
@field:SerializedName("total")
val total: Int,
@field:SerializedName("size")
val size: Int,
@field:SerializedName("nulls")
val nulls: Any,
@field:SerializedName("index")
val index: Int,
@field:SerializedName("items")
val items: List<ItemsItem5>
)
data class ItemsItem5(
@field:SerializedName("code")
val code: String,
@field:SerializedName("sysCodes")
val sysCodes: Any,
@field:SerializedName("seqNo")
val seqNo: Int,
@field:SerializedName("memo")
val memo: Any,
@field:SerializedName("global")
val global: Boolean,
@field:SerializedName("type")
val type: String,
@field:SerializedName("parentType")
val parentType: Any,
@field:SerializedName("parentCode")
val parentCode: Any,
@field:SerializedName("codeChain")
val codeChain: String,
@field:SerializedName("ifMaster")
val ifMaster: Boolean,
@field:SerializedName("extra")
val extra: Any,
@field:SerializedName("disabled")
val disabled: Boolean,
@field:SerializedName("lockKey")
val lockKey: String,
@field:SerializedName("id")
val id: Int,
@field:SerializedName("text")
val text: String,
@field:SerializedName("shortCode")
val shortCode: String
)

查看文件

@ -0,0 +1,71 @@
package com.bjca.hp.acupuncture.model
data class ItemsItems(
val assessorName: String,
val storehouseCode: String,
val sysCode: String,
val ifStateExpense: Boolean,
val patientId: Int,
val usage: String,
val medicalAdvice: String,
val dosagePerTime: String,
val frequency: String,
val approveUserId: Int,
val itemName: String,
val price: Double,
val paymentId: Int,
val patientAge: String,
val cashierId: String,
val lockKey: String,
val id: Int,
val ifInjury: Boolean,
val paymentState: String,
val invoiceNo: String,
val barcode: String,
val originalPaymentId: String,
val diagnosis: String,
val drugRpType: String,
val originalInvoiceNo: String,
val examineReason: String,
val opNo: String,
val name: String,
val executorDeptCode: String,
val assessorCode: String,
val refundDate: String,
val deptCode: String,
val makeMethod: String,
val distributeState: String,
val rpFeeType: String,
val no: String,
val settleId: String,
val approveDate: String,
val originalNo: String,
val patientGender: String,
val appNo: String,
val settleDate: String,
val adviceNo: String,
val doctorName: String,
val rpSettleType: String,
val doctorId: Int,
val offsetState: String,
val disabled: Boolean,
val drugRestrict: String,
val rpClass: String,
val groupNo: String,
val cashierName: String,
val ifInsurance: Boolean,
val examineResult: String,
val patientName: String,
val dosageUnit: String,
val cost: Int,
val quantity: String,
val ifDivide: String,
val excessDrugExplain: String,
val approveUserName: String,
val rpStatisticType: String,
val days: String,
val cashierCode: String,
val paymentDate: String,
val quantityPerDay: String
)

查看文件

@ -0,0 +1,15 @@
package com.bjca.hp.acupuncture.model
/***************************************************************************
* <pre></pre>
* @文件名称 MqMessage
* @包 com.bjca.hp.acupuncture.model
* @版权所有北京数字医信责任有限公司 (C) 2022
*
* @类描述:
* @版本: V1.0
* @创建人 xuqm
* @创建时间2022/6/20 下午 05:06
* @修改记录
*/
data class MqMessage(val no:String)

查看文件

@ -0,0 +1,168 @@
package com.bjca.hp.acupuncture.model
import com.google.gson.annotations.SerializedName
data class RegModel(
@field:SerializedName("total")
val total: Int,
@field:SerializedName("size")
val size: Int,
@field:SerializedName("nulls")
val nulls: String,
@field:SerializedName("index")
val index: Int,
@field:SerializedName("items")
val items: List<ItemsItem3>
)
data class ItemsItem3(
@field:SerializedName("date")
val date: String,
@field:SerializedName("additionUserId")
val additionUserId: String,
@field:SerializedName("deptName")
val deptName: String,
@field:SerializedName("seqNo")
val seqNo: Int,
@field:SerializedName("patientId")
val patientId: Int,
@field:SerializedName("signInDate")
val signInDate: String,
@field:SerializedName("patientGender")
val patientGender: String,
@field:SerializedName("opType")
val opType: String,
@field:SerializedName("ifSubsequent")
val ifSubsequent: Boolean,
@field:SerializedName("registrarName")
val registrarName: String,
@field:SerializedName("ifDoctorAdd")
val ifDoctorAdd: Boolean,
@field:SerializedName("cardNo")
val cardNo: String,
@field:SerializedName("additionUserName")
val additionUserName: String,
@field:SerializedName("treatDate")
val treatDate: String,
@field:SerializedName("takingDate")
val takingDate: String,
@field:SerializedName("ifDeleted")
val ifDeleted: Boolean,
@field:SerializedName("doctorName")
val doctorName: String,
@field:SerializedName("appointmentChannelCode")
val appointmentChannelCode: String,
@field:SerializedName("lineNo")
val lineNo: Double,
@field:SerializedName("doctorId")
val doctorId: Int,
@field:SerializedName("price")
val price: Double,
@field:SerializedName("ifAddition")
val ifAddition: Boolean,
@field:SerializedName("patientAge")
val patientAge: String,
@field:SerializedName("lockKey")
val lockKey: String,
@field:SerializedName("id")
val id: Int,
@field:SerializedName("state")
val state: String,
@field:SerializedName("paymentState")
val paymentState: String,
@field:SerializedName("regType")
val regType: String,
@field:SerializedName("periodEnd")
val periodEnd: String,
@field:SerializedName("registrarId")
val registrarId: Int,
@field:SerializedName("patientName")
val patientName: String,
@field:SerializedName("targetId")
val targetId: String,
@field:SerializedName("cardType")
val cardType: String,
@field:SerializedName("pay")
val pay: Double,
@field:SerializedName("lineId")
val lineId: Int,
@field:SerializedName("occupationalInjury")
val occupationalInjury: String,
@field:SerializedName("version")
val version: Int,
@field:SerializedName("patientPhone")
val patientPhone: String,
@field:SerializedName("ifEmergency")
val ifEmergency: Boolean,
@field:SerializedName("patientLevel")
val patientLevel: String,
@field:SerializedName("periodType")
val periodType: String,
@field:SerializedName("opNo")
val opNo: String,
@field:SerializedName("ifMaternityInsurance")
val ifMaternityInsurance: Boolean,
@field:SerializedName("periodStart")
val periodStart: String,
@field:SerializedName("appointmentDate")
val appointmentDate: String,
@field:SerializedName("appCardType")
val appCardType: String,
@field:SerializedName("deptCode")
val deptCode: String,
@field:SerializedName("appCardNo")
val appCardNo: String
)

查看文件

@ -0,0 +1,153 @@
package com.bjca.hp.acupuncture.model
import com.google.gson.annotations.SerializedName
data class RpDetailModel(
@field:SerializedName("total")
val total: Int,
@field:SerializedName("size")
val size: Int,
@field:SerializedName("nulls")
val nulls: String,
@field:SerializedName("index")
val index: Int,
@field:SerializedName("items")
val items: List<ItemsItem2>
)
data class ItemsItem2(
@field:SerializedName("shelfIndex")
val shelfIndex: String,
@field:SerializedName("shelfCommand")
val shelfCommand: String,
@field:SerializedName("standard")
val standard: String,
@field:SerializedName("no")
val no: String,
@field:SerializedName("storehouseCode")
val storehouseCode: String,
@field:SerializedName("code")
val code: String,
@field:SerializedName("usage")
val usage: String,
@field:SerializedName("appNo")
val appNo: String,
@field:SerializedName("memo")
val memo: String,
@field:SerializedName("herbalSpecialUsage")
val herbalSpecialUsage: String,
@field:SerializedName("restrict")
val restrict: String,
@field:SerializedName("type")
val type: String,
@field:SerializedName("dosagePerTime")
val dosagePerTime: String,
@field:SerializedName("frequency")
val frequency: String,
@field:SerializedName("insuranceCode")
val insuranceCode: String,
@field:SerializedName("totalDose")
val totalDose: String,
@field:SerializedName("times")
val times: String,
@field:SerializedName("price")
val price: Double,
@field:SerializedName("mnemonic")
val mnemonic: String,
@field:SerializedName("offsetState")
val offsetState: String,
@field:SerializedName("warning")
val warning: String,
@field:SerializedName("lockKey")
val lockKey: String,
@field:SerializedName("id")
val id: Int,
@field:SerializedName("rpClass")
val rpClass: String,
@field:SerializedName("groupNo")
val groupNo: String,
@field:SerializedName("key")
val key: String,
@field:SerializedName("dosageUnit")
val dosageUnit: String,
@field:SerializedName("quantity")
val quantity: Int,
@field:SerializedName("cost")
val cost: Double,
@field:SerializedName("rpNo")
val rpNo: String,
@field:SerializedName("lotNumber")
val lotNumber: String,
@field:SerializedName("manufacturerCode")
val manufacturerCode: String,
@field:SerializedName("approvalNumber")
val approvalNumber: String,
@field:SerializedName("feeType")
val feeType: String,
@field:SerializedName("unit")
val unit: String,
@field:SerializedName("symptom")
val symptom: String,
@field:SerializedName("form")
val form: String,
@field:SerializedName("opNo")
val opNo: String,
@field:SerializedName("name")
val name: String,
@field:SerializedName("parts")
val parts: String,
@field:SerializedName("days")
val days: Int,
@field:SerializedName("executorDeptCode")
val executorDeptCode: String,
@field:SerializedName("offsetId")
val offsetId: Any
)

查看文件

@ -0,0 +1,21 @@
package com.bjca.hp.acupuncture.model
import com.google.gson.annotations.SerializedName
data class RpModel(
@field:SerializedName("total")
val total: Int,
@field:SerializedName("size")
val size: Int,
@field:SerializedName("nulls")
val nulls: Any,
@field:SerializedName("index")
val index: Int,
@field:SerializedName("items")
val items: List<ItemsItems>
)

查看文件

@ -0,0 +1,113 @@
package com.bjca.hp.acupuncture.model
import com.google.gson.annotations.SerializedName
import com.xuqm.base.adapter.BaseItem
import java.util.ArrayList
data class WelcomeLIstModel(
@field:SerializedName("total")
val total: Int? = null,
@field:SerializedName("size")
val size: Int? = null,
@field:SerializedName("nulls")
val nulls: Any? = null,
@field:SerializedName("index")
val index: Int? = null,
@field:SerializedName("items")
val items: ArrayList<ItemsItem> = arrayListOf()
)
data class ItemsItem(
@field:SerializedName("standard")
val standard: String? = null,
@field:SerializedName("storehouseCode")
val storehouseCode: String? = null,
@field:SerializedName("shelfIndex")
val shelfIndex: Any? = null,
@field:SerializedName("code")
val code: String? = null,
@field:SerializedName("purpose")
val purpose: String? = null,
@field:SerializedName("supplierCode")
val supplierCode: String? = null,
@field:SerializedName("herbalSku")
val herbalSku: String? = null,
@field:SerializedName("type")
val type: String? = null,
@field:SerializedName("restrict")
val restrict: String? = null,
@field:SerializedName("rate")
val rate: Double? = null,
@field:SerializedName("price")
val price: Double? = null,
@field:SerializedName("srcId")
val srcId: Any? = null,
@field:SerializedName("disabled")
val disabled: Boolean? = null,
@field:SerializedName("lockKey")
val lockKey: Any? = null,
@field:SerializedName("id")
val id: Int? = null,
@field:SerializedName("applyQuantity")
val applyQuantity: Double? = null,
@field:SerializedName("shortCode")
val shortCode: String? = null,
@field:SerializedName("expirationDate")
val expirationDate: String? = null,
@field:SerializedName("brandName")
val brandName: String? = null,
@field:SerializedName("cost")
val cost: Double? = null,
@field:SerializedName("quantity")
val quantity: Double? = null,
@field:SerializedName("lotNumber")
val lotNumber: String? = null,
@field:SerializedName("manufacturerCode")
val manufacturerCode: String? = null,
@field:SerializedName("feeType")
val feeType: Any? = null,
@field:SerializedName("approvalNumber")
val approvalNumber: Any? = null,
@field:SerializedName("ceilType")
val ceilType: String? = null,
@field:SerializedName("unit")
val unit: String? = null,
@field:SerializedName("form")
val form: String? = null,
@field:SerializedName("name")
val name: String? = null
) : BaseItem()

查看文件

@ -0,0 +1,30 @@
package com.bjca.hp.acupuncture.receiver
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import com.bjca.hp.acupuncture.ui.MainActivity
/***************************************************************************
* <pre></pre>
* @文件名称 BootCompleteReceiver
* @包 com.bjca.hp.acupuncture.receiver
* @版权所有北京数字医信责任有限公司 (C) 2022
*
* @类描述:
* @版本: V1.0
* @创建人 xuqm
* @创建时间2022/6/24 下午 06:34
* @修改记录
*/
class BootCompleteReceiver : BroadcastReceiver(){
override fun onReceive(context: Context, intent: Intent) {
if(Intent.ACTION_BOOT_COMPLETED == intent.action){
val thisIntent = Intent(context, MainActivity::class.java)
thisIntent.action = "android.intent.action.MAIN";
thisIntent.addCategory("android.intent.category.LAUNCHER");
thisIntent.flags = Intent.FLAG_ACTIVITY_NEW_TASK;
context.startActivity(thisIntent);
}
}
}

查看文件

@ -0,0 +1,130 @@
package com.bjca.hp.acupuncture.repository
import android.content.Context
import com.xuqm.base.common.SHARE_UESR_TOKEN
import com.xuqm.base.extensions.getStringForPreferences
import com.xuqm.base.extensions.log
import com.xuqm.base.extensions.loge
import okhttp3.Headers
import okhttp3.Interceptor
import okhttp3.Response
import okhttp3.internal.http.HttpHeaders
import okhttp3.internal.http.StatusLine
import okio.Buffer
import okio.BufferedSource
import okio.GzipSource
import java.io.EOFException
import java.net.HttpURLConnection
import java.nio.charset.Charset
class HeaderInterceptor(val context: Context) : Interceptor {
val UTF8 = Charset.forName("UTF-8")
override fun intercept(chain: Interceptor.Chain): Response {
val original = chain.request()
//请求定制:添加请求头
val requestBuilder = original.newBuilder()
.header("Authentication", context.getStringForPreferences(SHARE_UESR_TOKEN))
.addHeader("Content-Type", "application/json;charset=UTF-8")
// context.getStringForPreferences(SHARE_UESR_TOKEN).loge()
val request = requestBuilder.build()
"${request.url()}(${request.method()})".loge()
val headers = request.headers()
// request.body()?.also {
//
// if (!bodyHasUnknownEncoding(headers)) {
// val buffer = Buffer()
// it.writeTo(buffer)
//
// var charset = Charset.forName("UTF-8")
// it.contentType()?.also { its -> charset = its.charset(Charset.forName("UTF-8"))!! }
//
//// if (isPlaintext(buffer)) {
//// buffer.readString(charset).loge()
//// }
// }
// }
val response = chain.proceed(request)
response.body()?.also {
if (!bodyHasUnknownEncoding(headers) && hasBody(response)) {
val source: BufferedSource = it.source()
source.request(Long.MAX_VALUE) // Buffer the entire body.
var buffer = source.buffer
if ("gzip".equals(headers.get("Content-Encoding"), ignoreCase = true)) {
var gzippedResponseBody: GzipSource? = null
try {
gzippedResponseBody = GzipSource(buffer.clone())
buffer = Buffer()
buffer.writeAll(gzippedResponseBody)
} finally {
gzippedResponseBody?.close()
}
}
var charset = UTF8
it.contentType()?.also { its -> charset = its.charset(Charset.forName("UTF-8"))!! }
if (isPlaintext(buffer)) {
buffer.clone().readString(charset).log()
}
}
}
return response
}
private fun bodyHasUnknownEncoding(headers: Headers): Boolean {
val contentEncoding = headers["Content-Encoding"]
return (contentEncoding != null && !contentEncoding.equals("identity", ignoreCase = true)
&& !contentEncoding.equals("gzip", ignoreCase = true))
}
private fun isPlaintext(buffer: Buffer): Boolean {
return try {
val prefix = Buffer()
val byteCount = if (buffer.size < 64) buffer.size else 64
buffer.copyTo(prefix, 0, byteCount)
for (i in 0..15) {
if (prefix.exhausted()) {
break
}
val codePoint = prefix.readUtf8CodePoint()
if (Character.isISOControl(codePoint) && !Character.isWhitespace(codePoint)) {
return false
}
}
true
} catch (e: EOFException) {
false // Truncated UTF-8 sequence.
}
}
fun hasBody(response: Response): Boolean {
// HEAD requests never yield a body regardless of the response headers.
if (response.request().method() == "HEAD") {
return false
}
val responseCode = response.code()
if ((responseCode < StatusLine.HTTP_CONTINUE || responseCode >= 200)
&& responseCode != HttpURLConnection.HTTP_NO_CONTENT && responseCode != HttpURLConnection.HTTP_NOT_MODIFIED
) {
return true
}
// If the Content-Length or Transfer-Encoding headers disagree with the response code, the
// response is malformed. For best compatibility, we honor the headers.
return HttpHeaders.contentLength(response) != -1L || "chunked".equals(
response.header("Transfer-Encoding"),
ignoreCase = true
)
}
}

查看文件

@ -0,0 +1,30 @@
package com.bjca.hp.acupuncture.repository
import com.bjca.hp.acupuncture.model.*
import com.xuqm.sdhbwfu.core.model.HttpResult
import io.reactivex.Observable
import retrofit2.http.GET
import retrofit2.http.Path
import retrofit2.http.Query
interface Service {
@GET("drug/stock/standard?storehouseCode=2&type=&form=&purpose=&restrict=&danger=&antibiotic=&keyword=&manufacturerCode=&supplierCode=&expirationDateMin=&expirationDateMax=&sort=id&asc=false&papeIndexOnView=2&pageSize=20&tenantId=101")
fun standard(@Query("pageIndex") pageIndex: Int): Observable<WelcomeLIstModel>
// op/rp?no=CF220609004247&rpClass=药品&tenantId=101
@GET("op/rp?rpClass=药品&tenantId=101")
fun rp(@Query("no") no: String): Observable<RpModel>
// op/rpDetail?opNo=MZ220321036030&rpNo=CF220323001947&tenantId=101
@GET("op/rpDetail?tenantId=101")
fun rpDetail(@Query("opNo") opNo: String, @Query("rpNo") rpNo: String): Observable<RpDetailModel>
// op/reg?opNo=MZ220321036030&tenantId=101
@GET("op/reg?tenantId=101")
fun reg(@Query("opNo") opNo: String): Observable<RegModel>
// dict/DrugUsage?sort=id&asc=false&pageIndexOnView=1&pageSize=100&dictType=DrugType&pageIndex=0
@GET("dict/DrugUsage?sort=id&asc=false&pageIndexOnView=1&pageSize=100&dictType=DrugType&pageIndex=0")
fun drugUsage(): Observable<DrugUsage>
}

查看文件

@ -0,0 +1,243 @@
package com.bjca.hp.acupuncture.ui
import android.graphics.Typeface
import android.os.Bundle
import androidx.activity.viewModels
import com.bigkoo.alertview.AlertView
import com.bjca.hp.acupuncture.MyApplication
import com.bjca.hp.acupuncture.R
import com.bjca.hp.acupuncture.databinding.ActivityMainBinding
import com.bjca.hp.acupuncture.model.ItemsItem2
import com.bjca.hp.acupuncture.model.ItemsItem3
import com.bjca.hp.acupuncture.model.ItemsItem5
import com.bjca.hp.acupuncture.model.ItemsItems
import com.bjca.hp.acupuncture.viewmodel.MainVM
import com.xuqm.base.adapter.CommonAdapter
import com.xuqm.base.adapter.ViewHolder
import com.xuqm.base.dialog.loading.LoadingDialog
import com.xuqm.base.extensions.loge
import com.xuqm.base.ui.BaseActivity
import com.xuqm.sdhbwfu.core.extensions.linearLayoutManager
import com.xuqm.sdhbwfu.core.extensions.showMessage
import tp.xmaihh.serialport.SerialHelper
import tp.xmaihh.serialport.bean.ComBean
class MainActivity : BaseActivity<ActivityMainBinding>() {
override fun fullscreen(): Boolean = true
override fun getLayoutId(): Int = R.layout.activity_main
private val vm: MainVM by viewModels()
override fun initView(savedInstanceState: Bundle?) {
super.initView(savedInstanceState)
sourceHanSansCNBold =
Typeface.createFromAsset(mContext?.assets, "fonts/SourceHanSansCN-Bold.ttf")
sourceHanSansCNMedium =
Typeface.createFromAsset(mContext?.assets, "fonts/SourceHanSansCN-Medium.ttf")
sourceHanSansCNNormal =
Typeface.createFromAsset(mContext?.assets, "fonts/SourceHanSansCN-Normal.ttf")
sourceHanSansCNRegular =
Typeface.createFromAsset(mContext?.assets, "fonts/SourceHanSansCN-Regular.ttf")
din =
Typeface.createFromAsset(mContext?.assets, "fonts/DIN-Alternate-Bold.ttf")
binding.title.typeface = sourceHanSansCNBold
binding.name.typeface = sourceHanSansCNBold
binding.tags.typeface = sourceHanSansCNMedium
binding.btn.typeface = sourceHanSansCNBold
binding.title1.typeface = sourceHanSansCNMedium
binding.title2.typeface = sourceHanSansCNMedium
binding.title3.typeface = sourceHanSansCNMedium
binding.title5.typeface = sourceHanSansCNMedium
binding.n1.typeface = sourceHanSansCNRegular
binding.v1.typeface = sourceHanSansCNRegular
binding.n2.typeface = sourceHanSansCNRegular
binding.v2.typeface = sourceHanSansCNRegular
binding.n3.typeface = sourceHanSansCNRegular
binding.v3.typeface = sourceHanSansCNRegular
binding.n4.typeface = sourceHanSansCNRegular
binding.v4.typeface = sourceHanSansCNRegular
binding.n5.typeface = sourceHanSansCNRegular
binding.v5.typeface = sourceHanSansCNRegular
binding.n6.typeface = sourceHanSansCNRegular
binding.v6.typeface = sourceHanSansCNRegular
binding.n7.typeface = sourceHanSansCNRegular
binding.v7.typeface = sourceHanSansCNRegular
binding.n8.typeface = sourceHanSansCNRegular
binding.v8.typeface = sourceHanSansCNRegular
binding.n9.typeface = sourceHanSansCNRegular
binding.v9.typeface = sourceHanSansCNRegular
binding.n10.typeface = sourceHanSansCNRegular
binding.v10.typeface = sourceHanSansCNRegular
binding.n11.typeface = sourceHanSansCNRegular
binding.v11.typeface = sourceHanSansCNRegular
binding.n12.typeface = sourceHanSansCNRegular
binding.v12.typeface = sourceHanSansCNRegular
binding.n13.typeface = sourceHanSansCNRegular
binding.v13.typeface = sourceHanSansCNRegular
binding.n14.typeface = sourceHanSansCNRegular
binding.v14.typeface = sourceHanSansCNRegular
binding.n15.typeface = sourceHanSansCNRegular
binding.v15.typeface = sourceHanSansCNRegular
binding.n16.typeface = sourceHanSansCNRegular
binding.v16.typeface = sourceHanSansCNRegular
binding.n17.typeface = sourceHanSansCNRegular
binding.v17.typeface = sourceHanSansCNRegular
binding.list.linearLayoutManager(mContext, 15)
binding.list.adapter = adapter
binding.btn.setOnClickListener {
LoadingDialog.showDialog("")
if (adapter.datas.size > 0)
sndMessage(0)
else {
// s.sendHex("0105002cff004DF3"); // 发送Hex
MyApplication.getInstance().runOnUiThreadDelay({
try {
s.sendHex("02050001ff00DDC9"); // 发送Hex
} catch (e: Exception) {
e.showMessage()
}
LoadingDialog.dismissDialog()
}, 500)
}
}
}
private fun sndMessage(i: Int) {
if (i >= adapter.datas.size) {
LoadingDialog.dismissDialog()
AlertView(
"取药完成", adapter.datas.map { it.shelfIndex}.joinToString(), null, arrayOf("确定"), null, mContext,
AlertView.Style.Alert
) { _, _ ->
mContext.finish()
}.show()
return
}
try {
s.sendHex(adapter.datas[i].shelfCommand); // 发送Hex
} catch (e: Exception) {
e.showMessage()
}
MyApplication.getInstance().runOnUiThreadDelay({
sndMessage(i + 1)
}, 2300)
}
lateinit var sourceHanSansCNBold: Typeface
lateinit var sourceHanSansCNMedium: Typeface
lateinit var sourceHanSansCNNormal: Typeface
lateinit var sourceHanSansCNRegular: Typeface
lateinit var din: Typeface
var rp: ItemsItems? = null
var regM: ItemsItem3? = null
var usages: List<ItemsItem5> = listOf()
lateinit var s: SerialHelper
override fun initData() {
super.initData()
s = object : SerialHelper("/dev/ttyS0", 38400) {
override fun onDataReceived(paramComBean: ComBean?) {
paramComBean?.bRec?.loge()
}
}
try {
s.open()
} catch (e: Exception) {
e.showMessage()
}
vm.status.observe(this) {
rp = it
rerresh()
}
vm.regM.observe(this) {
regM = it
rerresh()
}
vm.usages.observe(this) {
usages = it ?: listOf()
intent.getStringExtra("opNo")?.let { it1 -> vm.getRp(it1) }
}
vm.rpDetail.observe(this) {
adapter.setmDatas(it)
}
vm.drugUsage()
}
fun getUsage(code: String): String {
var text = "--"
usages.forEach {
if (it.code == code) {
text = it.text
}
}
return text
}
private fun rerresh() {
rp?.let {
binding.v8.text = it.diagnosis
binding.v14.text = it.doctorName
binding.v16.text = "${it.price}"
binding.v13.text = it.approveUserName
binding.v11.text = it.no
}
regM?.let {
binding.v1.text = it.patientName
binding.v2.text = it.patientGender
binding.v3.text = "${it.patientAge}"
binding.v4.text = it.patientPhone
binding.v5.text = ""
binding.v6.text = it.appCardNo
binding.v7.text = it.deptName
binding.v9.text = it.date
binding.v10.text = it.opType
}
}
private val adapter = object : CommonAdapter<ItemsItem2>(R.layout.item_main) {
override fun convert(holder: ViewHolder, item: ItemsItem2, position: Int) {
holder.setTypeface(R.id.index, sourceHanSansCNMedium)
.setText(R.id.index, "${position + 1}")
.setTypeface(R.id.n1, sourceHanSansCNRegular)
.setTypeface(R.id.v1, sourceHanSansCNRegular)
.setText(R.id.v1, item.name)//名称
.setTypeface(R.id.n2, sourceHanSansCNRegular)
.setTypeface(R.id.v1, sourceHanSansCNRegular)
.setText(R.id.v2, item.standard)//规格
.setTypeface(R.id.n3, sourceHanSansCNRegular)
.setTypeface(R.id.v3, sourceHanSansCNRegular)
.setText(R.id.v3, "${item.quantity}${item.unit}")//数量
.setTypeface(R.id.n4, sourceHanSansCNRegular)
.setTypeface(R.id.v4, sourceHanSansCNRegular)
.setText(R.id.v4, getUsage(item.usage))//使用方法---码表
.setTypeface(R.id.n5, sourceHanSansCNRegular)
.setTypeface(R.id.v5, sourceHanSansCNRegular)
.setText(R.id.v5, "${item.dosagePerTime}${item.dosageUnit}")//用量
.setTypeface(R.id.n6, sourceHanSansCNRegular)
.setTypeface(R.id.v6, sourceHanSansCNRegular)
.setText(R.id.v6, item.frequency)//频次---码表
.setTypeface(R.id.n7, sourceHanSansCNRegular)
.setTypeface(R.id.v7, sourceHanSansCNRegular)
.setText(R.id.v7, "${item.days}")//使用周期
}
}
}

查看文件

@ -0,0 +1,209 @@
package com.bjca.hp.acupuncture.ui
import android.os.Bundle
import com.bjca.hp.acupuncture.MyApplication
import com.bjca.hp.acupuncture.R
import com.bjca.hp.acupuncture.databinding.ActivitySettingBinding
import com.xuqm.base.extensions.loge
import com.xuqm.base.ui.BaseActivity
import com.xuqm.sdhbwfu.core.extensions.showMessage
import kotlinx.android.synthetic.main.activity_setting.*
import tp.xmaihh.serialport.SerialHelper
import tp.xmaihh.serialport.bean.ComBean
import java.util.*
class SettingActivity : BaseActivity<ActivitySettingBinding>() {
override fun getLayoutId(): Int = R.layout.activity_setting
override fun initView(savedInstanceState: Bundle?) {
super.initView(savedInstanceState)
binding.a13.setOnClickListener {
val a11 = binding.a11.text.toString().toInt()
if (a11 <= 0 || a11 > 9) {
"请输入正确的柜号,从1开始".showMessage()
return@setOnClickListener
}
val a12 = binding.a12.text.toString().toInt()
if (a12 <= 0) {
"请输入正确的柜门号,从1开始".showMessage()
return@setOnClickListener
}
val b1 = "0${a11}05${intToHex(a12, 4)}ff00"
val b2 = getCRC(b1)
try {
s.sendHex("${b1}${b2}"); // 发送Hex
} catch (e: Exception) {
e.showMessage()
}
}
binding.a24.setOnClickListener {
val a21 = binding.a21.text.toString().toInt()
if (a21 <= 0 || a21 > 9) {
"请输入正确的柜号,从1开始".showMessage()
return@setOnClickListener
}
val a22 = binding.a22.text.toString().toInt()
if (a22 <= 0) {
"请输入正确的柜门号,从1开始".showMessage()
return@setOnClickListener
}
val a23 = binding.a23.text.toString().toInt()
if (a23 <= 0) {
"请输入正确的柜门号,从1开始".showMessage()
return@setOnClickListener
}
sndMessage(a21, a22, a23)
}
binding.a31.setOnClickListener {
sndMessage(1, 1, 84)
}
binding.a32.setOnClickListener {
sndMessage(2, 1, 84)
}
binding.a33.setOnClickListener {
sndMessage(3, 1, 84)
}
}
private fun sndMessage(i: Int, ii: Int, iii: Int) {
if (ii > iii) return
val b1 = "0${i}05${intToHex(ii, 4)}ff00"
val b2 = getCRC(b1)
try {
s.sendHex("${b1}${b2}"); // 发送Hex
} catch (e: Exception) {
e.showMessage()
}
MyApplication.getInstance().runOnUiThreadDelay({
sndMessage(i, ii + 1, iii)
}, 2300)
}
lateinit var s: SerialHelper
override fun initData() {
super.initData()
s = object : SerialHelper("/dev/ttyS0", 38400) {
override fun onDataReceived(paramComBean: ComBean?) {
paramComBean?.bRec?.loge()
}
}
try {
s.open()
} catch (e: Exception) {
e.showMessage()
}
}
/**
* 10进制转16进制.
*
* @param n 10进制数
* @param size 转换后的16进制位数
* @return 转换结果
*/
private fun intToHex(n: Int, size: Int): String {
var n = n
var s = StringBuffer()
var a: String
val b = charArrayOf(
'0',
'1',
'2',
'3',
'4',
'5',
'6',
'7',
'8',
'9',
'A',
'B',
'C',
'D',
'E',
'F'
)
while (n != 0) {
s = s.append(b[n % 16])
n = n / 16
}
a = s.reverse().toString()
a = add_zero(a, size)
return a
}
fun add_zero(str: String, size: Int): String {
var str = str
if (str.length < size) {
str = "0$str"
str = add_zero(str, size)
}
return str
}
fun getCRC(data: String): String {
var data = data
data = data.replace(" ", "")
val len = data.length
if (len % 2 != 0) {
return "0000"
}
val num = len / 2
val para = ByteArray(num)
for (i in 0 until num) {
val value = Integer.valueOf(data.substring(i * 2, 2 * (i + 1)), 16)
para[i] = value.toByte()
}
return getCRC(para)
}
/**
* 计算CRC16校验码
*
* @param bytes
* 字节数组
* @return [String] 校验码
* @since 1.0
*/
fun getCRC(bytes: ByteArray): String {
// CRC寄存器全为1
var CRC = 0x0000ffff
// 多项式校验值
val POLYNOMIAL = 0x0000a001
var i: Int
var j: Int
i = 0
while (i < bytes.size) {
CRC = CRC xor (bytes[i].toInt() and 0x000000ff)
j = 0
while (j < 8) {
if (CRC and 0x00000001 != 0) {
CRC = CRC shr 1
CRC = CRC xor POLYNOMIAL
} else {
CRC = CRC shr 1
}
j++
}
i++
}
// 结果转换为16进制
var result = Integer.toHexString(CRC).uppercase(Locale.getDefault())
if (result.length != 4) {
val sb = StringBuffer("0000")
result = sb.replace(4 - result.length, 4, result).toString()
}
//高位在前地位在后
//return result.substring(2, 4) + " " + result.substring(0, 2);
// 交换高低位,低位在前高位在后
return result.substring(2, 4) + result.substring(0, 2)
}
}

查看文件

@ -0,0 +1,36 @@
package com.bjca.hp.acupuncture.ui
import android.os.Build.VERSION_CODES.R
import android.os.Bundle
import com.bjca.hp.acupuncture.R
import com.bjca.hp.acupuncture.databinding.ActivityTestBinding
import com.xuqm.base.common.ToolsHelper
import com.xuqm.base.extensions.getStringForPreferences
import com.xuqm.base.extensions.putString
import com.xuqm.base.ui.BaseActivity
import com.xuqm.base.web.XWebViewHelper
class TestActivity : BaseActivity<ActivityTestBinding>() {
override fun getLayoutId(): Int = R.layout.activity_test
override fun initView(savedInstanceState: Bundle?) {
super.initView(savedInstanceState)
val str = getStringForPreferences("wurl")
if (!ToolsHelper.isNull(str))
binding.editUrl.setText(str)
binding.btn.setOnClickListener {
val url =
if (ToolsHelper.isNull(binding.editUrl.text)) "https://web.sdk.qcloud.com/trtc/webrtc/demo/quick-demo-vue3-ts/index.html#/"
else binding.editUrl.text.toString()
putString("wurl", url)
XWebViewHelper.startWebNoTopBar(
mContext,
url
)
}
}
}

查看文件

@ -0,0 +1,166 @@
package com.bjca.hp.acupuncture.ui
import android.content.Intent
import android.graphics.Typeface
import android.os.Bundle
import com.bjca.hp.acupuncture.R
import com.bjca.hp.acupuncture.common.RabbitMQUtil
import com.bjca.hp.acupuncture.databinding.ActivityWelcomeBinding
import com.bjca.hp.acupuncture.model.ItemsItem
import com.bjca.hp.acupuncture.viewmodel.WelcomeVM
import com.xuqm.base.adapter.BasePagedAdapter
import com.xuqm.base.adapter.CommonPagedAdapter
import com.xuqm.base.adapter.ViewHolder
import com.xuqm.base.ui.BaseListFormLayoutActivity
import com.xuqm.sdhbwfu.core.extensions.gridLayoutManager
import com.xuqm.sdhbwfu.core.extensions.runWithPermission
import com.xuqm.sdhbwfu.core.extensions.toStrings
class WelcomeActivity : BaseListFormLayoutActivity<ItemsItem, WelcomeVM, ActivityWelcomeBinding>() {
override fun getLayoutId(): Int = R.layout.activity_welcome
override fun fullscreen(): Boolean = true
// lateinit var s: SerialHelper
lateinit var sourceHanSansCNBold: Typeface
lateinit var sourceHanSansCNMedium: Typeface
lateinit var sourceHanSansCNNormal: Typeface
lateinit var din: Typeface
lateinit var mq: RabbitMQUtil
private var oldTime = 0L
private var index = 0
override fun initView(savedInstanceState: Bundle?) {
super.initView(savedInstanceState)
sourceHanSansCNBold =
Typeface.createFromAsset(mContext?.assets, "fonts/SourceHanSansCN-Bold.ttf")
sourceHanSansCNMedium =
Typeface.createFromAsset(mContext?.assets, "fonts/SourceHanSansCN-Medium.ttf")
sourceHanSansCNNormal =
Typeface.createFromAsset(mContext?.assets, "fonts/SourceHanSansCN-Normal.ttf")
din =
Typeface.createFromAsset(mContext?.assets, "fonts/DIN-Alternate-Bold.ttf")
binding.title.typeface = sourceHanSansCNBold
binding.title.setOnClickListener {
val newTime = System.currentTimeMillis()
if (newTime - oldTime < 2500 && oldTime != 0L) {
if (index > 5) {
startActivity(Intent(mContext, SettingActivity::class.java))
index = 0
}
index++
} else {
oldTime = newTime
index = 0
}
}
// binding.list.gridLayoutManager(mContext, 6, 2)
// binding.list.adapter = adapter
// adapter.setmDatas(arrayListOf("空调", "水泵", "空气净化器", "阳台", "灯"))
recyclerView.gridLayoutManager(mContext, 21, 3)
adapter.setItemLongClickListener { _, _, _ ->
startActivity(Intent(mContext, MainActivity::class.java))
return@setItemLongClickListener true
}
}
override fun onDestroy() {
super.onDestroy()
mq.close()
}
override fun initData() {
super.initData()
runWithPermission(
"android.permission.MODIFY_AUDIO_SETTINGS",
"android.permission.RECORD_AUDIO",
"android.permission.CAMERA"
) {
startActivity(Intent(mContext, TestActivity::class.java))
}
// XWebViewHelper.startWebNoTopBar(mContext,"https://mdtdemo.51trust.com/")
// mq = RabbitMQUtil("10.10.202.11", 5672, "guest", "guest")
//
// mq.receiveQueueMessage("RpNoByMedicineCabinet",
// {
//
// startActivity(Intent(mContext, MainActivity::class.java)
// .apply {
// putExtra(
// "opNo",
// GsonImplHelp.get().toObject(it, MqMessage::class.java).no
// )
// })
// }
// ) {
// it.loge()
// }
// s = object : SerialHelper("/dev/ttyS0", 38400) {
// override fun onDataReceived(paramComBean: ComBean?) {
// paramComBean?.bRec?.loge()
// }
//
// }
// s.setStickPackageHelper {
// try {
// val available = it.available()
// if (available > 0) {
// val buffer = ByteArray(available)
// val size = it.read(buffer)
// if (size > 0) {
// return@setStickPackageHelper buffer;
// }
// } else {
// SystemClock.sleep(50);
// }
//
// } catch (e: IOException) {
// e.printStackTrace();
// }
// return@setStickPackageHelper null
// }
// s.sendHex("02050001ff00DDC9"); // 发送Hex
}
private val adapter = object : CommonPagedAdapter<ItemsItem>(R.layout.item_welcome) {
override fun convert(holder: ViewHolder, item: ItemsItem, position: Int) {
holder
.setTypeface(R.id.index, sourceHanSansCNMedium)
.setTypeface(R.id.name, sourceHanSansCNBold)
.setTypeface(R.id.hint, sourceHanSansCNNormal)
.setTypeface(R.id.number, din)
.setTypeface(R.id.unit, sourceHanSansCNNormal)
.setTypeface(R.id.balance, sourceHanSansCNNormal)
.setText(R.id.index, "${position + 1}")
.setText(R.id.name, item.name)
.setText(R.id.hint, item.supplierCode)
.setText(R.id.number, item.price?.toStrings())
.setText(R.id.unit, "元/${item.unit}")
.setText(R.id.balance, "剩余:${item.quantity}${item.unit}")
}
}
override fun adapter(): BasePagedAdapter<ItemsItem> = adapter
}

查看文件

@ -0,0 +1,104 @@
package com.bjca.hp.acupuncture.viewmodel
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import com.bjca.hp.acupuncture.MyApplication
import com.bjca.hp.acupuncture.model.ItemsItem2
import com.bjca.hp.acupuncture.model.ItemsItem3
import com.bjca.hp.acupuncture.model.ItemsItem5
import com.bjca.hp.acupuncture.model.ItemsItems
import com.bjca.hp.acupuncture.repository.Service
import com.xuqm.base.di.manager.HttpManager
import com.xuqm.base.extensions.showMessage
import com.xuqm.sdhbwfu.core.viewModel.BaseViewModel
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
/***************************************************************************
* <pre></pre>
* @文件名称 WelcomeVM
* @包 com.bjca.hp.acupuncture.viewmodel
* @版权所有北京数字医信责任有限公司 (C) 2022
*
* @类描述:
* @版本: V1.0
* @创建人 xuqm
* @创建时间2022/6/17 下午 02:33
* @修改记录
*/
class MainVM : BaseViewModel() {
private val _status = MutableLiveData<ItemsItems>()
val status: LiveData<ItemsItems> = _status
fun getRp(opNo:String = "CF220609004247" ) {
HttpManager.getApi(MyApplication.appComponent1, Service::class.java)
.rp(opNo)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
{
_status.postValue(it.items[0])
rpDetail(it.items[0].opNo, it.items[0].no)
reg(it.items[0].opNo)
}, {
_status.postValue(null)
showMessage(it.toString())
}
).adds()
}
private val _rpDetail = MutableLiveData<List<ItemsItem2>>()
val rpDetail: LiveData<List<ItemsItem2>> = _rpDetail
fun rpDetail(opNo: String, rpNo: String) {
HttpManager.getApi(MyApplication.appComponent1, Service::class.java)
.rpDetail(opNo, rpNo)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
{
_rpDetail.postValue(it.items)
}, {
_rpDetail.postValue(null)
showMessage(it.toString())
}
).adds()
}
private val _regM = MutableLiveData<ItemsItem3>()
val regM: LiveData<ItemsItem3> = _regM
fun reg(opNo: String) {
HttpManager.getApi(MyApplication.appComponent1, Service::class.java)
.reg(opNo)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
{
_regM.postValue(it?.items?.get(0))
}, {
_regM.postValue(null)
showMessage(it.toString())
}
).adds()
}
private val _usages = MutableLiveData<List<ItemsItem5>>()
val usages: LiveData<List<ItemsItem5>> = _usages
fun drugUsage() {
HttpManager.getApi(MyApplication.appComponent2, Service::class.java)
.drugUsage()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
{
_usages.postValue(it.items)
}, {
_usages.postValue(null)
showMessage(it.toString())
}
).adds()
}
}

查看文件

@ -0,0 +1,40 @@
package com.bjca.hp.acupuncture.viewmodel
import com.bjca.hp.acupuncture.model.ItemsItem
import com.bjca.hp.acupuncture.repository.Service
import com.xuqm.base.di.manager.HttpManager
import com.xuqm.base.extensions.showMessage
import com.xuqm.base.viewmodel.BaseListViewModel
import com.xuqm.base.viewmodel.callback.Response
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
/***************************************************************************
* <pre></pre>
* @文件名称 WelcomeVM
* @包 com.bjca.hp.acupuncture.viewmodel
* @版权所有北京数字医信责任有限公司 (C) 2022
*
* @类描述:
* @版本: V1.0
* @创建人 xuqm
* @创建时间2022/6/17 下午 02:33
* @修改记录
*/
class WelcomeVM : BaseListViewModel<ItemsItem>() {
override fun loadData(page: Int, onResponse: Response<ItemsItem>) {
add(
HttpManager.getApi(Service::class.java)
.standard(page)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
{
onResponse.onResponse(it.items)
}, {
onResponse.onResponse(null)
// showMessage(it)
}
))
}
}

查看文件

@ -0,0 +1,22 @@
package com.bjca.hp.acupuncture.widget;
import androidx.annotation.ColorInt;
/***************************************************************************
* <pre></pre>
* @文件名称 ColorUser
* @包 com.bjca.hp.acupuncture.widget
* @版权所有北京数字医信责任有限公司 (C) 2022
*
* @类描述:
* @版本: V1.0
* @创建人 xuqm
* @创建时间2022/1/19 上午 10:58
* @修改记录
*/
public class ColorUser {
@ColorInt
public static final int ce = 0xFF04E8EE;
@ColorInt
public static final int cs = 0x003A6FF2;
}

查看文件

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:tools="http://schemas.android.com/tools" xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape android:shape="rectangle">
<stroke android:width="0.5dp" android:color="#00000014" />
<corners android:radius="5dp" />
<solid android:color="@color/white"/>
</shape>
</item>
</selector>

查看文件

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

查看文件

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

查看文件

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape android:shape="rectangle">
<corners android:bottomRightRadius="1dp" android:topRightRadius="1dp" />
<solid android:color="#FFFFFF" />
</shape>
</item>
</selector>

查看文件

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape android:shape="rectangle">
<corners android:bottomLeftRadius="1dp" android:topLeftRadius="1dp" />
<solid android:color="#BA7D45" />
</shape>
</item>
</selector>

查看文件

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:tools="http://schemas.android.com/tools" xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape android:shape="rectangle">
<corners android:radius="1dp" />
<stroke android:width="1dp" android:color="#5EA564" />
</shape>
</item>
</selector>

查看文件

@ -0,0 +1,698 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:app="http://schemas.android.com/apk/res-auto">
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#BA7D45"
tools:context=".ui.MainActivity">
<TextView
android:id="@+id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:gravity="center"
android:text="联创明医医院智慧药柜"
android:textColor="@color/white"
android:textSize="16sp"
android:textStyle="bold"
app:layout_constraintTop_toTopOf="parent" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="15dp"
android:layout_marginTop="76dp"
android:background="@drawable/bg_main"
android:orientation="vertical"
app:layout_constraintTop_toTopOf="parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:background="@drawable/bg_main"
android:gravity="center"
android:orientation="horizontal"
app:layout_constraintTop_toTopOf="parent">
<TextView
android:id="@+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="广州黄埔区明医医院处方笺"
android:textColor="#202020"
android:textSize="14sp"
android:textStyle="bold" />
<TextView
android:id="@+id/tags"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="17.5dp"
android:background="@drawable/bg_main_tag"
android:paddingHorizontal="7.5dp"
android:paddingVertical="4.5dp"
android:text="普通"
android:textColor="#5EA564" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:orientation="horizontal"
android:paddingHorizontal="15dp">
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="3"
android:orientation="vertical">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<View
android:layout_width="0dp"
android:layout_height="4dp"
android:background="#BA7D45"
app:layout_constraintBottom_toBottomOf="@+id/title1"
app:layout_constraintEnd_toEndOf="@+id/title1"
app:layout_constraintStart_toStartOf="@+id/title1" />
<TextView
android:id="@+id/title1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="患者信息"
android:textColor="#ff202020"
android:textSize="13sp"
android:textStyle="bold"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
android:id="@+id/n1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="姓名:"
android:textColor="#ff848484"
android:textSize="11sp" />
<TextView
android:id="@+id/v1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="--"
android:textColor="#ff202020"
android:textSize="11sp" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
android:id="@+id/n2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="性别:"
android:textColor="#ff848484"
android:textSize="11sp" />
<TextView
android:id="@+id/v2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="--"
android:textColor="#ff202020"
android:textSize="11sp" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
android:id="@+id/n3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="年龄:"
android:textColor="#ff848484"
android:textSize="11sp" />
<TextView
android:id="@+id/v3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="--"
android:textColor="#ff202020"
android:textSize="11sp" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
android:id="@+id/n4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="电话:"
android:textColor="#ff848484"
android:textSize="11sp" />
<TextView
android:id="@+id/v4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="--"
android:textColor="#ff202020"
android:textSize="11sp" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
android:id="@+id/n5"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="地址:"
android:textColor="#ff848484"
android:textSize="11sp" />
<TextView
android:id="@+id/v5"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="--"
android:textColor="#ff202020"
android:textSize="11sp" />
</LinearLayout>
</LinearLayout>
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="4"
android:orientation="vertical">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<View
android:layout_width="0dp"
android:layout_height="4dp"
android:background="#BA7D45"
app:layout_constraintBottom_toBottomOf="@+id/title2"
app:layout_constraintEnd_toEndOf="@+id/title2"
app:layout_constraintStart_toStartOf="@+id/title2" />
<TextView
android:id="@+id/title2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="就诊信息"
android:textColor="#ff202020"
android:textSize="13sp"
android:textStyle="bold"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
android:id="@+id/n6"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="就诊卡号:"
android:textColor="#ff848484"
android:textSize="11sp" />
<TextView
android:id="@+id/v6"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="--"
android:textColor="#ff202020"
android:textSize="11sp" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
android:id="@+id/n7"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="就诊科别:"
android:textColor="#ff848484"
android:textSize="11sp" />
<TextView
android:id="@+id/v7"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="--"
android:textColor="#ff202020"
android:textSize="11sp" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
android:id="@+id/n8"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="诊断结果:"
android:textColor="#ff848484"
android:textSize="11sp" />
<TextView
android:id="@+id/v8"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="--"
android:textColor="#ff202020"
android:textSize="11sp" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
android:id="@+id/n9"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="就诊日期:"
android:textColor="#ff848484"
android:textSize="11sp" />
<TextView
android:id="@+id/v9"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="--"
android:textColor="#ff202020"
android:textSize="11sp" />
</LinearLayout>
</LinearLayout>
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="4"
android:orientation="vertical">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<View
android:layout_width="0dp"
android:layout_height="4dp"
android:background="#BA7D45"
app:layout_constraintBottom_toBottomOf="@+id/title3"
app:layout_constraintEnd_toEndOf="@+id/title3"
app:layout_constraintStart_toStartOf="@+id/title3" />
<TextView
android:id="@+id/title3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="医疗信息"
android:textColor="#ff202020"
android:textSize="13sp"
android:textStyle="bold"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
android:id="@+id/n10"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="医疗类别:"
android:textColor="#ff848484"
android:textSize="11sp" />
<TextView
android:id="@+id/v10"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="--"
android:textColor="#ff202020"
android:textSize="11sp" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
android:id="@+id/n11"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="医疗/医保卡:"
android:textColor="#ff848484"
android:textSize="11sp" />
<TextView
android:id="@+id/v11"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="--"
android:textColor="#ff202020"
android:textSize="11sp" />
</LinearLayout>
<ImageView
android:layout_width="129dp"
android:layout_height="50dp"
android:layout_marginTop="12dp"
android:scaleType="centerCrop"
android:src="@color/ic_launcher_background" />
</LinearLayout>
</LinearLayout>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginHorizontal="15dp"
android:layout_marginTop="20dp">
<View
android:layout_width="0dp"
android:layout_height="4dp"
android:background="#BA7D45"
app:layout_constraintBottom_toBottomOf="@+id/title4"
app:layout_constraintEnd_toEndOf="@+id/title4"
app:layout_constraintStart_toStartOf="@+id/title4" />
<TextView
android:id="@+id/title4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="药品及使用说明"
android:textColor="#ff202020"
android:textSize="13sp"
android:textStyle="bold"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
<com.xuqm.base.view.MaxLimitRecyclerView
android:id="@+id/list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:maxLength="6"
android:paddingHorizontal="15dp"
app:limit_maxHeight="350dp" />
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginHorizontal="15dp"
android:layout_marginTop="20dp">
<View
android:layout_width="0dp"
android:layout_height="4dp"
android:background="#BA7D45"
app:layout_constraintBottom_toBottomOf="@+id/title5"
app:layout_constraintEnd_toEndOf="@+id/title5"
app:layout_constraintStart_toStartOf="@+id/title5" />
<TextView
android:id="@+id/title5"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="药品及使用说明"
android:textColor="#ff202020"
android:textSize="13sp"
android:textStyle="bold"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:orientation="horizontal"
android:paddingHorizontal="15dp">
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
android:id="@+id/n12"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="药师:"
android:textColor="#ff848484"
android:textSize="11sp" />
<TextView
android:id="@+id/v12"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="--"
android:textColor="#ff202020"
android:textSize="11sp" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
android:id="@+id/n13"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="审方:"
android:textColor="#ff848484"
android:textSize="11sp" />
<TextView
android:id="@+id/v13"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="--"
android:textColor="#ff202020"
android:textSize="11sp" />
</LinearLayout>
</LinearLayout>
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
android:id="@+id/n14"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="医师:"
android:textColor="#ff848484"
android:textSize="11sp" />
<TextView
android:id="@+id/v14"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="--"
android:textColor="#ff202020"
android:textSize="11sp" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
android:id="@+id/n15"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="调配:"
android:textColor="#ff848484"
android:textSize="11sp" />
<TextView
android:id="@+id/v15"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="智慧药柜"
android:textColor="#ff202020"
android:textSize="11sp" />
</LinearLayout>
</LinearLayout>
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
android:id="@+id/n16"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="药品金额:"
android:textColor="#ff848484"
android:textSize="11sp" />
<TextView
android:id="@+id/v16"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="--"
android:textColor="#ff202020"
android:textSize="11sp" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
android:id="@+id/n17"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="核对发药:"
android:textColor="#ff848484"
android:textSize="11sp" />
<TextView
android:id="@+id/v17"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="--"
android:textColor="#ff202020"
android:textSize="11sp" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
<TextView
android:id="@+id/btn"
android:layout_width="170dp"
android:layout_height="50dp"
android:layout_gravity="center_horizontal"
android:layout_marginTop="45dp"
android:layout_marginBottom="45dp"
android:background="@drawable/bg_main_btn"
android:gravity="center"
android:text="确认发药"
android:textColor="@color/white"
android:textSize="14sp"
android:textStyle="bold" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

查看文件

@ -0,0 +1,167 @@
<?xml version="1.0" encoding="utf-8"?>
<layout>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".ui.SettingActivity">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="40dp"
android:gravity="center"
android:text="开指定柜门"
android:textColor="@color/black"
android:textSize="18sp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="68dp"
android:layout_marginTop="10dp"
android:background="@drawable/bg_button"
android:orientation="horizontal"
app:layout_constraintTop_toTopOf="parent">
<EditText
android:id="@+id/a11"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:hint="柜号(1.2.3)"
android:inputType="number" />
<EditText
android:id="@+id/a12"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:hint="窗口号"
android:inputType="number" />
<TextView
android:id="@+id/a13"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="@drawable/bg_button_red"
android:gravity="center"
android:text="开门"
android:textColor="@color/white"
android:textSize="18sp" />
</LinearLayout>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="40dp"
android:gravity="center"
android:text="开指定指定范围内柜门"
android:textColor="@color/black"
android:textSize="18sp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="68dp"
android:layout_marginTop="10dp"
android:background="@drawable/bg_button"
android:orientation="horizontal"
app:layout_constraintTop_toTopOf="parent">
<EditText
android:id="@+id/a21"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:hint="柜号(1.2.3)"
android:inputType="number" />
<EditText
android:id="@+id/a22"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:hint="开始窗口号"
android:inputType="number" />
<EditText
android:id="@+id/a23"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:hint="结束窗口号"
android:inputType="number" />
<TextView
android:id="@+id/a24"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="@drawable/bg_button_red"
android:gravity="center"
android:text="开门"
android:textColor="@color/white"
android:textSize="18sp" />
</LinearLayout>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="40dp"
android:gravity="center"
android:text="一键开门"
android:textColor="@color/black"
android:textSize="18sp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="68dp"
android:layout_marginTop="10dp"
android:background="@drawable/bg_button"
android:orientation="horizontal"
app:layout_constraintTop_toTopOf="parent">
<TextView
android:id="@+id/a31"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="@drawable/bg_button_red"
android:gravity="center"
android:text="一号柜"
android:textColor="@color/white"
android:textSize="18sp" />
<TextView
android:id="@+id/a32"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:layout_marginHorizontal="10dp"
android:background="@drawable/bg_button_red"
android:gravity="center"
android:text="二号柜"
android:textColor="@color/white"
android:textSize="18sp" />
<TextView
android:id="@+id/a33"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="@drawable/bg_button_red"
android:gravity="center"
android:text="三号柜"
android:textColor="@color/white"
android:textSize="18sp" />
</LinearLayout>
</LinearLayout>
</layout>

查看文件

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<layout>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ui.TestActivity">
<EditText
android:id="@+id/edit_url"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="150dp"
android:text="https://web.sdk.qcloud.com/trtc/webrtc/demo/quick-demo-vue3-ts/index.html#/"
android:textSize="21sp"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:text="进入页面"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/edit_url" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

查看文件

@ -0,0 +1,50 @@
<?xml version="1.0" encoding="utf-8"?>
<layout>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#BA7D45"
tools:context=".ui.WelcomeActivity">
<TextView
android:id="@+id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:gravity="center"
android:text="联创明医医院智慧药柜"
android:textColor="@color/white"
android:textSize="16sp"
android:textStyle="bold"
app:layout_constraintTop_toTopOf="parent" />
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:id="@+id/baseRefreshLayout"
android:layout_width="match_parent"
android:layout_marginTop="20dp"
android:layout_marginBottom="34dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@+id/title">
<com.xuqm.base.view.EmptyView
android:id="@+id/baseEmptyView"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/baseRecyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:overScrollMode="never" />
</com.xuqm.base.view.EmptyView>
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

查看文件

@ -0,0 +1,224 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="50dp">
<TextView
android:id="@+id/index"
android:layout_width="25dp"
android:layout_height="match_parent"
android:background="@drawable/bg_main_item_index"
android:gravity="center"
android:text="1"
android:textColor="@color/white"
android:textSize="12sp"
app:layout_constraintStart_toStartOf="parent" />
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:background="@drawable/bg_main_item_content"
android:orientation="horizontal"
android:paddingHorizontal="6dp"
android:gravity="center_vertical"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/index">
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="25"
android:orientation="vertical">
<TextView
android:id="@+id/n1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="药品名称"
android:textColor="#ffacabab"
android:textSize="10sp" />
<TextView
android:id="@+id/v1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:layout_marginTop="6dp"
android:lines="1"
android:text="药品名称药品名称药品名称药品名称药品名称药品名称药品名称"
android:textColor="#ff202020"
android:textSize="12sp" />
</LinearLayout>
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="18"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/n2"
android:text="规格"
android:textColor="#ffacabab"
android:textSize="10sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:layout_marginTop="6dp"
android:lines="1"
android:text="0.5g*10粒"
android:id="@+id/v2"
android:textColor="#ff202020"
android:textSize="12sp" />
</LinearLayout>
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="9"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:id="@+id/n3"
android:layout_height="wrap_content"
android:text="数量"
android:textColor="#ffacabab"
android:textSize="10sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:layout_marginTop="6dp"
android:lines="1"
android:id="@+id/v3"
android:text="1盒"
android:textColor="#ff202020"
android:textSize="12sp" />
</LinearLayout>
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="12"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/n4"
android:text="使用方法"
android:textColor="#ffacabab"
android:textSize="10sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:layout_marginTop="6dp"
android:lines="1"
android:text="口服"
android:id="@+id/v4"
android:textColor="#ff202020"
android:textSize="12sp" />
</LinearLayout>
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="12"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:id="@+id/n5"
android:layout_height="wrap_content"
android:text="用量"
android:textColor="#ffacabab"
android:textSize="10sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:layout_marginTop="6dp"
android:lines="1"
android:id="@+id/v5"
android:text="6g"
android:textColor="#ff202020"
android:textSize="12sp" />
</LinearLayout>
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="13"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="频次"
android:id="@+id/n6"
android:textColor="#ffacabab"
android:textSize="10sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:layout_marginTop="6dp"
android:lines="1"
android:id="@+id/v6"
android:text="每日1次"
android:textColor="#ff202020"
android:textSize="12sp" />
</LinearLayout>
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="10"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/n7"
android:text="使用周期"
android:textColor="#ffacabab"
android:textSize="10sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:layout_marginTop="6dp"
android:lines="1"
android:id="@+id/v7"
android:text="2天"
android:textColor="#ff202020"
android:textSize="12sp" />
</LinearLayout>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

查看文件

@ -0,0 +1,83 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="130dp"
android:background="@drawable/bg_item_welcome">
<TextView
android:id="@+id/index"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:layout_marginTop="10dp"
android:background="#BA7D45"
android:paddingHorizontal="7.5dp"
android:paddingVertical="3.5dp"
android:text="01"
android:textColor="@color/white"
android:textSize="13sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:text="活血止痛胶囊(10mg/盒)"
android:textColor="@color/black"
android:textSize="13sp"
android:textStyle="bold"
app:layout_constraintStart_toStartOf="@+id/index"
app:layout_constraintTop_toBottomOf="@+id/index" />
<TextView
android:id="@+id/hint"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:text="广东联合制药"
android:textColor="#A4ADBA"
android:textSize="10sp"
app:layout_constraintStart_toStartOf="@+id/index"
app:layout_constraintTop_toBottomOf="@+id/name" />
<TextView
android:id="@+id/number"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="15dp"
android:text="12.5"
android:textColor="#FF4600"
android:textStyle="bold"
android:textSize="18sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="@+id/index" />
<TextView
android:id="@+id/unit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="元/盒"
android:textColor="#FF4600"
android:layout_marginBottom="3dp"
app:layout_constraintBottom_toBottomOf="@+id/number"
android:textSize="10sp"
app:layout_constraintStart_toEndOf="@+id/number" />
<TextView
android:id="@+id/balance"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="剩余100盒"
android:textColor="#333333"
android:layout_marginBottom="3dp"
android:layout_marginEnd="10dp"
app:layout_constraintBottom_toBottomOf="@+id/number"
android:textSize="11sp"
app:layout_constraintEnd_toEndOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

二进制文件未显示。

之后

宽度:  |  高度:  |  大小: 286 KiB

二进制文件未显示。

之后

宽度:  |  高度:  |  大小: 286 KiB

二进制文件未显示。

之后

宽度:  |  高度:  |  大小: 7.3 KiB

二进制文件未显示。

之后

宽度:  |  高度:  |  大小: 286 KiB

二进制文件未显示。

之后

宽度:  |  高度:  |  大小: 4.4 KiB

二进制文件未显示。

之后

宽度:  |  高度:  |  大小: 79 KiB

二进制文件未显示。

之后

宽度:  |  高度:  |  大小: 286 KiB

二进制文件未显示。

之后

宽度:  |  高度:  |  大小: 1.5 KiB

二进制文件未显示。

之后

宽度:  |  高度:  |  大小: 136 KiB

二进制文件未显示。

之后

宽度:  |  高度:  |  大小: 28 KiB

二进制文件未显示。

之后

宽度:  |  高度:  |  大小: 286 KiB

查看文件

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

查看文件

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorPrimary">#33a6ff</color>
<color name="colorPrimaryDark">#00574B</color>
<color name="colorAccent">#7e53c5</color>
<color name="bg_lapss_line">#BBBBBB</color>
<color name="black_filter_10">#10000000</color>
<color name="textcolor">#797979</color>
<color name="textcolor_blue">#33a6ff</color>
<color name="backgroundColor">#10142B</color>
</resources>

查看文件

@ -0,0 +1,3 @@
<resources>
<string name="app_name">Test</string>
</resources>

查看文件

@ -0,0 +1,20 @@
<resources>
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
<item name="android:windowTranslucentStatus">true</item>
<item name="backgroundColor">#F1F4F7</item>
</style>
<style name="DialogTheme" parent="Theme.AppCompat.Light.Dialog">
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
<item name="android:windowLightStatusBar">false</item>
<item name="android:windowCloseOnTouchOutside">false</item>
</style>
</resources>

查看文件

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-path
name="external"
path="." />
</paths>

2
base/.gitattributes vendored 普通文件
查看文件

@ -0,0 +1,2 @@
# Auto detect text files and perform LF normalization
* text=auto

83
base/.gitignore vendored 普通文件
查看文件

@ -0,0 +1,83 @@
# Built application files
*.apk
*.ap_
*.aab
# Files for the ART/Dalvik VM
*.dex
# Java class files
*.class
# Generated files
bin/
gen/
out/
# Uncomment the following line in case you need and you don't have the release build type files in your app
# release/
# Gradle files
.gradle/
build/
# Local configuration file (sdk path, etc)
local.properties
# Proguard folder generated by Eclipse
proguard/
# Log Files
*.log
# Android Studio Navigation editor temp files
.navigation/
# Android Studio captures folder
captures/
# IntelliJ
*.iml
.idea/workspace.xml
.idea/tasks.xml
.idea/gradle.xml
.idea/assetWizardSettings.xml
.idea/dictionaries
.idea/libraries
# Android Studio 3 in .gitignore file.
.idea/caches
.idea/modules.xml
# Comment next line if keeping position of elements in Navigation Editor is relevant for you
.idea/navEditor.xml
# Keystore files
# Uncomment the following lines if you do not want to check your keystore files in.
#*.jks
#*.keystore
# External native build folder generated in Android Studio 2.2 and later
.externalNativeBuild
# Google Services (e.g. APIs or Firebase)
# google-services.json
# Freeline
freeline.py
freeline/
freeline_project_description.json
# fastlane
fastlane/report.xml
fastlane/Preview.html
fastlane/screenshots
fastlane/test_output
fastlane/readme.md
# Version control
vcs.xml
# lint
lint/intermediates/
lint/generated/
lint/outputs/
lint/tmp/
# lint/reports/

184
base/README.md 普通文件
查看文件

@ -0,0 +1,184 @@
[TOC]
# WebSocket
``````kotlin
WebSocketHandler.getInstance("ws://192.168.3.20:8765")
``````
# 线程
## UI线程执行
````kotlin
runOnUiThread { "提示信息".showMessage() }
````
````kotlin
App.getInstance().runOnUiThread() {}
````
## 延时执行
```kotlin
App.getInstance().runOnUiThreadDelay({},1100)
```
# 常用工具
## Toast
````kotlin
"连接完成".showMessage()
````
````kotlin
ToolsHelper.showMessage("")
````
## Log
````kotlin
"".loge()
````
````kotlin
"".log()
````
````kotlin
LogHelper.d("")
````
# 常用方法
## 双击退出
```kotlin
private var oldTime = 0L
override fun onBackPressed() {
val newTime = System.currentTimeMillis()
if (newTime - oldTime < 1500 && oldTime != 0L)
AppManager.getInstance().exit()
else {
oldTime = newTime
ToolsHelper.showMessage("双击退出")
}
}
```
# 界面
> 所有界面继承`BaseFragment`,`BaseActivity`,`BaseListActivity`等
>
> 页面`layout`跟节点必须为`layout`
```xml
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
</layout>
```
## 列表页面
### 纯列表
> `BaseListActivity`
### 自定义布局列表
> `BaseListFormLayoutActivity`
>
> 布局列表部分必须使用下面的方法和id
```xml
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:id="@+id/baseRefreshLayout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.xuqm.base.view.EmptyView
android:id="@+id/baseEmptyView"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/baseRecyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:overScrollMode="never" />
</com.xuqm.base.view.EmptyView>
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
```
## 界面控件使用
```kotlin
binding.btn1.setOnClickListener {
}
```
## 导航栏
> 使用base自带导航栏的情况下,可以操控对应控件
```kotlin
baseBinding.baseToolbar.backBtn.setOnClickListener {}
```

94
base/build.gradle 普通文件
查看文件

@ -0,0 +1,94 @@
apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'
apply plugin: 'maven-publish'
// aar包的版本号
def aarVersion = "0.0.1.101"
android {
compileSdkVersion versions.compileSdk
buildToolsVersion versions.buildTools
defaultConfig {
minSdkVersion versions.minSdk
targetSdkVersion versions.targetSdk
flavorDimensions "versioncode"
buildConfigField("String", "APP_ID", "\"" + apps.applicationId + "\"")
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
productFlavors productF
namespace 'com.xuqm.base'
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
api androidxDependencies
implementation 'androidx.appcompat:appcompat:1.3.0'
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
implementation 'org.jetbrains.anko:anko-commons:0.10.5'
annotationProcessor compilerDependencies
commonDependencies.each { k, v ->
api(v) {
//support库
exclude group: 'com.android.support'
}
}
//
api 'com.huawei.hms:scanplus:1.1.1.301'
}
// aar包中的任务
task sourceJar(type: Jar) {
archiveClassifier.set('sources')
from android.sourceSets.main.java.srcDirs
}
afterEvaluate {
publishing {
publications {
// debug名字是自己起的
release(MavenPublication) {
groupId = 'cn.org.bjca.trust.android'
artifactId = 'base'
version = aarVersion
// debug release
from components.release
//
artifact sourceJar
}
}
//
repositories {
//
// mavenLocal()
//
// maven {
// allowInsecureProtocol true
// url("http://nexus.51trust.net/repository/android-hosted/")
// credentials {
// username = "deployment"
// password = "deployment123"
// }
// }
maven {
allowInsecureProtocol true
url("http://xuqinmin.com.cn:8081/repository/android-releases/")
credentials {
username = "admin"
password = "xuqinmin1022"
}
}
}
}
}

0
base/consumer-rules.pro 普通文件
查看文件

21
base/proguard-rules.pro vendored 普通文件
查看文件

@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile

查看文件

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 7.0之后安装apk、需要权限 -->
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
<permission android:name="android.permission.INSTALL_PACKAGES" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.webkit.PermissionRequest" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.webkit.resource.VIDEO_CAPTURE" />
<application>
<activity android:name=".web.XWebViewActivity" />
</application>
</manifest>

查看文件

@ -0,0 +1,155 @@
package com.livinglifetechway.quickpermissions_kotlin
import android.content.Context
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment
import com.livinglifetechway.quickpermissions_kotlin.util.PermissionCheckerFragment
import com.livinglifetechway.quickpermissions_kotlin.util.PermissionsUtil
import com.livinglifetechway.quickpermissions_kotlin.util.QuickPermissionsRequest
import com.livinglifetechway.quickpermissions_kotlin.util.QuickPermissionsOptions
private const val TAG = "runWithPermissions"
/**
* Injects code to ask for permissions before executing any code that requires permissions
* defined in the annotation
*/
fun Context?.runWithPermissions(
vararg permissions: String,
options: QuickPermissionsOptions = QuickPermissionsOptions(),
callback: () -> Unit
): Any? {
return runWithPermissionsHandler(this, permissions, callback, options)
}
/**
* Injects code to ask for permissions before executing any code that requires permissions
* defined in the annotation
*/
fun Fragment?.runWithPermissions(
vararg permissions: String,
options: QuickPermissionsOptions = QuickPermissionsOptions(),
callback: () -> Unit
): Any? {
return runWithPermissionsHandler(this, permissions, callback, options)
}
private fun runWithPermissionsHandler(target: Any?, permissions: Array<out String>, callback: () -> Unit, options: QuickPermissionsOptions): Nothing? {
Log.d(TAG, "runWithPermissions: start")
// get the permissions defined in annotation
Log.d(TAG, "runWithPermissions: permissions to check: $permissions")
// get target
if (target is AppCompatActivity || target is Fragment) {
Log.d(TAG, "runWithPermissions: context found")
val context = when (target) {
is Context -> target
is Fragment -> target.context
else -> null
}
// check if we have the permissions
if (PermissionsUtil.hasSelfPermission(context, arrayOf(*permissions))) {
Log.d(TAG, "runWithPermissions: already has required permissions. Proceed with the execution.")
callback()
} else {
// we don't have required permissions
// begin the permission request flow
Log.d(TAG, "runWithPermissions: doesn't have required permissions")
// check if we have permission checker fragment already attached
// support for AppCompatActivity and Activity
var permissionCheckerFragment = when (context) {
// for app compat activity
is AppCompatActivity -> context.supportFragmentManager?.findFragmentByTag(PermissionCheckerFragment::class.java.canonicalName) as PermissionCheckerFragment?
// for support fragment
is Fragment -> context.childFragmentManager.findFragmentByTag(PermissionCheckerFragment::class.java.canonicalName) as PermissionCheckerFragment?
// else return null
else -> null
}
// check if permission check fragment is added or not
// if not, add that fragment
if (permissionCheckerFragment == null) {
Log.d(TAG, "runWithPermissions: adding headless fragment for asking permissions")
permissionCheckerFragment = PermissionCheckerFragment.newInstance()
when (context) {
is AppCompatActivity -> {
context.supportFragmentManager.beginTransaction().apply {
add(permissionCheckerFragment, PermissionCheckerFragment::class.java.canonicalName)
commit()
}
// make sure fragment is added before we do any context based operations
context.supportFragmentManager?.executePendingTransactions()
}
is Fragment -> {
// this does not work at the moment
context.childFragmentManager.beginTransaction().apply {
add(permissionCheckerFragment, PermissionCheckerFragment::class.java.canonicalName)
commit()
}
// make sure fragment is added before we do any context based operations
context.childFragmentManager.executePendingTransactions()
}
}
}
// set callback to permission checker fragment
permissionCheckerFragment.setListener(object : PermissionCheckerFragment.QuickPermissionsCallback {
override fun onPermissionsGranted(quickPermissionsRequest: QuickPermissionsRequest?) {
Log.d(TAG, "runWithPermissions: got permissions")
try {
callback()
} catch (throwable: Throwable) {
throwable.printStackTrace()
}
}
override fun onPermissionsDenied(quickPermissionsRequest: QuickPermissionsRequest?) {
quickPermissionsRequest?.permissionsDeniedMethod?.invoke(quickPermissionsRequest)
}
override fun shouldShowRequestPermissionsRationale(quickPermissionsRequest: QuickPermissionsRequest?) {
quickPermissionsRequest?.rationaleMethod?.invoke(quickPermissionsRequest)
}
override fun onPermissionsPermanentlyDenied(quickPermissionsRequest: QuickPermissionsRequest?) {
quickPermissionsRequest?.permanentDeniedMethod?.invoke(quickPermissionsRequest)
}
})
// create permission request instance
val permissionRequest = QuickPermissionsRequest(permissionCheckerFragment, arrayOf(*permissions))
permissionRequest.handleRationale = options.handleRationale
permissionRequest.handlePermanentlyDenied = options.handlePermanentlyDenied
permissionRequest.rationaleMessage = if (options.rationaleMessage.isBlank())
"These permissions are required to perform this feature. Please allow us to use this feature. "
else
options.rationaleMessage
permissionRequest.permanentlyDeniedMessage = if (options.permanentlyDeniedMessage.isBlank())
"Some permissions are permanently denied which are required to perform this operation. Please open app settings to grant these permissions."
else
options.permanentlyDeniedMessage
permissionRequest.rationaleMethod = options.rationaleMethod
permissionRequest.permanentDeniedMethod = options.permanentDeniedMethod
permissionRequest.permissionsDeniedMethod = options.permissionsDeniedMethod
// begin the flow by requesting permissions
permissionCheckerFragment.setRequestPermissionsRequest(permissionRequest)
// start requesting permissions for the first time
permissionCheckerFragment.requestPermissionsFromUser()
}
} else {
// context is null
// cannot handle the permission checking from the any class other than AppCompatActivity/Fragment
// crash the app RIGHT NOW!
throw IllegalStateException("Found " + target!!::class.java.canonicalName + " : No support from any classes other than AppCompatActivity/Fragment")
}
return null
}

查看文件

@ -0,0 +1,237 @@
package com.livinglifetechway.quickpermissions_kotlin.util
import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri.fromParts
import android.os.Bundle
import android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS
import android.util.Log
import androidx.core.app.ActivityCompat
import androidx.fragment.app.Fragment
import org.jetbrains.anko.alert
/**
* This fragment holds the single permission request and holds it until the flow is completed
*/
class PermissionCheckerFragment : Fragment() {
private var quickPermissionsRequest: QuickPermissionsRequest? = null
interface QuickPermissionsCallback {
fun shouldShowRequestPermissionsRationale(quickPermissionsRequest: QuickPermissionsRequest?)
fun onPermissionsGranted(quickPermissionsRequest: QuickPermissionsRequest?)
fun onPermissionsPermanentlyDenied(quickPermissionsRequest: QuickPermissionsRequest?)
fun onPermissionsDenied(quickPermissionsRequest: QuickPermissionsRequest?)
}
companion object {
private const val TAG = "QuickPermissionsKotlin"
private const val PERMISSIONS_REQUEST_CODE = 199
fun newInstance(): PermissionCheckerFragment = PermissionCheckerFragment()
}
private var mListener: QuickPermissionsCallback? = null
fun setListener(listener: QuickPermissionsCallback) {
mListener = listener
Log.d(TAG, "onCreate: listeners set")
}
private fun removeListener() {
mListener = null
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Log.d(TAG, "onCreate: permission fragment created")
}
fun setRequestPermissionsRequest(quickPermissionsRequest: QuickPermissionsRequest?) {
this.quickPermissionsRequest = quickPermissionsRequest
}
private fun removeRequestPermissionsRequest() {
quickPermissionsRequest = null
}
fun clean() {
if (quickPermissionsRequest != null) {
// permission request flow is finishing
// let the caller receive callback about it
if (quickPermissionsRequest?.deniedPermissions?.size ?: 0 > 0)
mListener?.onPermissionsDenied(quickPermissionsRequest)
removeRequestPermissionsRequest()
removeListener()
} else {
Log.w(
TAG, "clean: QuickPermissionsRequest has already completed its flow. " +
"No further callbacks will be called for the current flow."
)
}
}
fun requestPermissionsFromUser() {
if (quickPermissionsRequest != null) {
Log.d(TAG, "requestPermissionsFromUser: requesting permissions")
requestPermissions(
quickPermissionsRequest?.permissions.orEmpty(),
PERMISSIONS_REQUEST_CODE
)
} else {
Log.w(
TAG,
"requestPermissionsFromUser: QuickPermissionsRequest has already completed its flow. " +
"Cannot request permissions again from the request received from the callback. " +
"You can start the new flow by calling runWithPermissions() { } again."
)
}
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<String>,
grantResults: IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
Log.d(TAG, "passing callback")
// check if permissions granted
handlePermissionResult(permissions, grantResults)
}
/**
* Checks and takes the action based on permission results retrieved from onRequestPermissionsResult
* and from the settings activity
*
* @param permissions List of Permissions
* @param grantResults A list of permission result <b>Granted</b> or <b>Denied</b>
*/
private fun handlePermissionResult(permissions: Array<String>, grantResults: IntArray) {
// add a check with the permissions list
// if the permissions list is empty, that means system has told that permissions request
// is invalid somehow or discarded the previous request
// this can happen in case when the multiple permissions requests are sent
// simultaneously to the system
if (permissions.isEmpty()) {
Log.w(
TAG,
"handlePermissionResult: Permissions result discarded. You might have called multiple permissions request simultaneously"
)
return
}
if (PermissionsUtil.hasSelfPermission(context, permissions)) {
// set the denied permissions to empty as all the permissions are granted
// this is required as clean will be called which can invoke on permissions denied
// if it finds some permissions in the denied list
quickPermissionsRequest?.deniedPermissions = emptyArray()
// we are good to go!
mListener?.onPermissionsGranted(quickPermissionsRequest)
// flow complete
clean()
} else {
// we are still missing permissions
val deniedPermissions = PermissionsUtil.getDeniedPermissions(permissions, grantResults)
quickPermissionsRequest?.deniedPermissions = deniedPermissions
// check if rationale dialog should be shown or not
var shouldShowRationale = true
var isPermanentlyDenied = false
for (i in 0 until deniedPermissions.size) {
val deniedPermission = deniedPermissions[i]
val rationale = shouldShowRequestPermissionRationale(deniedPermission)
if (!rationale) {
shouldShowRationale = false
isPermanentlyDenied = true
break
}
}
if (quickPermissionsRequest?.handlePermanentlyDenied == true && isPermanentlyDenied) {
quickPermissionsRequest?.permanentDeniedMethod?.let {
// get list of permanently denied methods
quickPermissionsRequest?.permanentlyDeniedPermissions =
PermissionsUtil.getPermanentlyDeniedPermissions(
this,
permissions,
grantResults
)
mListener?.onPermissionsPermanentlyDenied(quickPermissionsRequest)
return
}
activity?.alert {
message = quickPermissionsRequest?.permanentlyDeniedMessage.orEmpty()
positiveButton("SETTINGS") {
openAppSettings()
}
negativeButton("CANCEL") {
clean()
}
}?.apply { isCancelable = false }?.show()
return
}
// if should show rationale dialog
if (quickPermissionsRequest?.handleRationale == true && shouldShowRationale) {
quickPermissionsRequest?.rationaleMethod?.let {
mListener?.shouldShowRequestPermissionsRationale(quickPermissionsRequest)
return
}
activity?.alert {
message = quickPermissionsRequest?.rationaleMessage.orEmpty()
positiveButton("TRY AGAIN") {
requestPermissionsFromUser()
}
negativeButton("CANCEL") {
clean()
}
}?.apply { isCancelable = false }?.show()
return
}
// if handlePermanentlyDenied = false and handleRationale = false
// This will call permissionsDenied method
clean()
}
}
fun openAppSettings() {
if (quickPermissionsRequest != null) {
val intent = Intent(
ACTION_APPLICATION_DETAILS_SETTINGS,
fromParts("package", activity?.packageName, null)
)
// intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivityForResult(intent, PERMISSIONS_REQUEST_CODE)
} else {
Log.w(
TAG,
"openAppSettings: QuickPermissionsRequest has already completed its flow. Cannot open app settings"
)
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == PERMISSIONS_REQUEST_CODE) {
val permissions = quickPermissionsRequest?.permissions ?: emptyArray()
val grantResults = IntArray(permissions.size)
permissions.forEachIndexed { index, s ->
grantResults[index] = context?.let { ActivityCompat.checkSelfPermission(it, s) }
?: PackageManager.PERMISSION_DENIED
}
handlePermissionResult(permissions, grantResults)
}
}
}

查看文件

@ -0,0 +1,54 @@
package com.livinglifetechway.quickpermissions_kotlin.util
import android.app.Activity
import android.content.Context
import android.content.pm.PackageManager
import androidx.core.app.ActivityCompat
import androidx.fragment.app.Fragment
/**
* Utility class that wraps access to the runtime permissions API in M and provides basic helper
* methods.
*/
object PermissionsUtil {
fun getDeniedPermissions(permissions: Array<String>, grantResults: IntArray): Array<String> =
permissions.filterIndexed { index, s ->
grantResults[index] == PackageManager.PERMISSION_DENIED
}.toTypedArray()
fun getPermanentlyDeniedPermissions(
fragment: Fragment,
permissions: Array<String>,
grantResults: IntArray
): Array<String> =
permissions.filterIndexed { index, s ->
grantResults[index] == PackageManager.PERMISSION_DENIED && !fragment.shouldShowRequestPermissionRationale(
s
)
}.toTypedArray()
/**
* Returns true if the Activity has access to all given permissions.
* Always returns true on platforms below M.
*
* @see Activity.checkSelfPermission
*/
fun hasSelfPermission(activity: Context?, permissions: Array<String>): Boolean {
// Verify that all required permissions have been granted
activity?.let {
for (permission in permissions) {
if (ActivityCompat.checkSelfPermission(
activity,
permission
) != PackageManager.PERMISSION_GRANTED
) {
return false
}
}
}
return true
}
}

查看文件

@ -0,0 +1,11 @@
package com.livinglifetechway.quickpermissions_kotlin.util
data class QuickPermissionsOptions(
var handleRationale: Boolean = true,
var rationaleMessage: String = "",
var handlePermanentlyDenied: Boolean = true,
var permanentlyDeniedMessage: String = "",
var rationaleMethod: ((QuickPermissionsRequest) -> Unit)? = null,
var permanentDeniedMethod: ((QuickPermissionsRequest) -> Unit)? = null,
var permissionsDeniedMethod: ((QuickPermissionsRequest) -> Unit)? = null
)

查看文件

@ -0,0 +1,30 @@
package com.livinglifetechway.quickpermissions_kotlin.util
data class QuickPermissionsRequest(
private var target: PermissionCheckerFragment,
var permissions: Array<String> = emptyArray(),
var handleRationale: Boolean = true,
var rationaleMessage: String = "",
var handlePermanentlyDenied: Boolean = true,
var permanentlyDeniedMessage: String = "",
internal var rationaleMethod: ((QuickPermissionsRequest) -> Unit)? = null,
internal var permanentDeniedMethod: ((QuickPermissionsRequest) -> Unit)? = null,
internal var permissionsDeniedMethod: ((QuickPermissionsRequest) -> Unit)? = null,
var deniedPermissions: Array<String> = emptyArray(),
var permanentlyDeniedPermissions: Array<String> = emptyArray()
) {
/**
* Proceed with requesting permissions again with user request
*/
fun proceed() = target.requestPermissionsFromUser()
/**
* Cancels the current permissions request flow
*/
fun cancel() = target.clean()
/**
* In case of permissions permanently denied, request user to enable from app settings
*/
fun openAppSettings() = target.openAppSettings()
}

查看文件

@ -0,0 +1,111 @@
package com.xuqm.base;
import android.app.Application;
import android.content.Context;
import android.os.Handler;
import android.util.DisplayMetrics;
import android.view.WindowManager;
import androidx.annotation.Nullable;
import com.orhanobut.logger.AndroidLogAdapter;
import com.orhanobut.logger.FormatStrategy;
import com.orhanobut.logger.Logger;
import com.orhanobut.logger.PrettyFormatStrategy;
import com.xuqm.base.di.component.AppComponent;
import com.xuqm.base.di.manager.HttpManager;
public class App extends Application {
public AppComponent appComponent;
// 宽高
private int width = 0, height = 0;
private static App instance;
public static App getInstance() {
if (null == instance) {
synchronized (App.class) {
if (null == instance)
instance = new App();
}
}
return instance;
}
public App() {
instance = this;
handler = new Handler();
appComponent = HttpManager.getAppComponent("");
}
//https://www.wanandroid.com/wxarticle/list/408/1/json
@Override
public void onCreate() {
super.onCreate();
DisplayMetrics dm = new DisplayMetrics();
WindowManager wm = (WindowManager) this.getSystemService(Context.WINDOW_SERVICE);
if (null != wm) {
wm.getDefaultDisplay().getMetrics(dm);
width = dm.widthPixels;// 屏幕宽度
height = dm.heightPixels;// 屏幕高度
}
FormatStrategy formatStrategy = PrettyFormatStrategy.newBuilder()
.showThreadInfo(false) // (Optional) Whether to show thread info or not. Default true
.methodCount(0) // (Optional) How many method line to show. Default 2
.methodOffset(2) // (Optional) Hides internal method calls up to offset. Default 5
//.logStrategy(customLog) // (Optional) Changes the log strategy to print out. Default LogCat
.tag("LogHttpInfo") // (Optional) Global tag for every log. Default PRETTY_LOGGER
.build();
Logger.addLogAdapter(new AndroidLogAdapter(formatStrategy) {
@Override
public boolean isLoggable(int priority, @Nullable String tag) {
return showLog();
}
});
}
/**
* 是否打印日志
*
* @return true-开启日志
*/
public boolean showLog() {
return true;
}
public int getHeight() {
return height;
}
public int getWidth() {
return width;
}
private final Handler handler;
/**
* 提交主线程处理
*
* @param runnable runnable
*/
public void runOnUiThread(final Runnable runnable) {
handler.post(runnable);
}
/**
* 提交主线程延时后处理
*
* @param runnable runnable
* @param delayMillis 延时时间
*/
public void runOnUiThreadDelay(final Runnable runnable, long delayMillis) {
handler.postDelayed(runnable, delayMillis);
}
}

查看文件

@ -0,0 +1,222 @@
package com.xuqm.base;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Build;
import android.os.Environment;
import android.os.Looper;
import android.util.Log;
import android.widget.Toast;
import com.xuqm.base.common.FileHelper;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;
import java.lang.Thread.UncaughtExceptionHandler;
import java.lang.reflect.Field;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
/**
* UncaughtException处理类,当程序发生Uncaught异常的时候,有该类来接管程序,并记录发送错误报告.
*
* @author user
*/
public class CrashHandler implements UncaughtExceptionHandler {
public static final String TAG = "CrashHandler";
// CrashHandler 实例
private static CrashHandler INSTANCE = new CrashHandler();
// 程序的 Context 对象
private Context mContext;
// 系统默认的 UncaughtException 处理类
private UncaughtExceptionHandler mDefaultHandler;
// 用来存储设备信息和异常信息
private Map<String, String> infos = new HashMap<String, String>();
// 用于格式化日期,作为日志文件名的一部分
private DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss", Locale.getDefault());
/**
* 保证只有一个 CrashHandler 实例
*/
private CrashHandler() {
}
/**
* 获取 CrashHandler 实例 ,单例模式
*/
public static CrashHandler getInstance() {
return INSTANCE;
}
/**
* 初始化
*
* @param context
*/
public void init(Context context) {
mContext = context;
// 获取系统默认的 UncaughtException 处理器
mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
// 设置该 CrashHandler 为程序的默认处理器
Thread.setDefaultUncaughtExceptionHandler(this);
}
/**
* UncaughtException 发生时会转入该函数来处理
*/
@Override
public void uncaughtException(Thread thread, Throwable ex) {
if (!handleException(ex) && mDefaultHandler != null) {
// 如果用户没有处理则让系统默认的异常处理器来处理
mDefaultHandler.uncaughtException(thread, ex);
} else {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
Log.e(TAG, "error : ", e);
Thread.currentThread().interrupt();
}
// Intent mIntent = new Intent(mContext, WelcomeActivity.class);
// mIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
// mContext.startActivity(mIntent);
android.os.Process.killProcess(android.os.Process.myPid());
}
}
/**
* 自定义错误处理收集错误信息发送错误报告等操作均在此完成
*
* @param ex
* @return true如果处理了该异常信息否则返回 false
*/
private boolean handleException(Throwable ex) {
if (ex == null) {
return false;
}
// 使用 Toast 来显示异常信息
new Thread() {
@Override
public void run() {
Looper.prepare();
Toast.makeText(mContext, "好像出了点问题~~~", Toast.LENGTH_LONG).show();
Looper.loop();
}
}.start();
// 收集设备参数信息
collectDeviceInfo(mContext);
// 保存日志文件
saveCrashInfo2File(ex);
return true;
}
/**
* 收集设备参数信息
*
* @param ctx
*/
public void collectDeviceInfo(Context ctx) {
try {
PackageManager pm = ctx.getPackageManager();
PackageInfo pi = pm.getPackageInfo(ctx.getPackageName(), PackageManager.GET_ACTIVITIES);
if (pi != null) {
String versionName = pi.versionName == null ? "null" : pi.versionName;
String versionCode = pi.versionCode + "";
infos.put("versionName", versionName);
infos.put("versionCode", versionCode);
}
} catch (NameNotFoundException e) {
Log.e(TAG, "an error occured when collect package info", e);
}
Field[] fields = Build.class.getDeclaredFields();
for (Field field : fields) {
try {
field.setAccessible(true);
infos.put(field.getName(), field.get(null).toString());
Log.d(TAG, field.getName() + " : " + field.get(null));
} catch (Exception e) {
Log.e(TAG, "an error occured when collect crash info", e);
}
}
}
/**
* 保存错误信息到文件中 *
*
* @param ex
* @return 返回文件名称, 便于将文件传送到服务器
*/
private String saveCrashInfo2File(Throwable ex) {
StringBuffer sb = new StringBuffer();
for (Map.Entry<String, String> entry : infos.entrySet()) {
String key = entry.getKey();
String value = entry.getValue();
sb.append(String.format("%s=%s\n", key, value));
}
Writer writer = new StringWriter();
PrintWriter printWriter = new PrintWriter(writer);
ex.printStackTrace(printWriter);
Throwable cause = ex.getCause();
while (cause != null) {
cause.printStackTrace(printWriter);
cause = cause.getCause();
}
printWriter.close();
String result = writer.toString();
sb.append(result);
long timestamp = System.currentTimeMillis();
String time = formatter.format(new Date());
String fileName = "crash-" + time + "-" + timestamp + ".log";
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
String path = String.format("%scrash/", FileHelper.getRootFilePath());
File dir = new File(path);
if (!dir.exists()) {
dir.mkdirs();
}
FileOutputStream fos = null;
try {
fos = new FileOutputStream(path + fileName);
fos.write(sb.toString().getBytes());
} catch (Exception e) {
Log.e(TAG, "an error occured while writing file...", e);
} finally {
try {
if (fos != null) {
fos.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
return fileName;
}
}

查看文件

@ -0,0 +1,17 @@
package com.xuqm.base.adapter;
/**
* 所有用到{@link com.xuqm.base.ui.BaseListActivity}来做的列表页
* 数据model都要继承BaseItem
*/
public class BaseItem {
private int s_id;
public int getS_id() {
return s_id;
}
public void setS_id(int s_id) {
this.s_id = s_id;
}
}

查看文件

@ -0,0 +1,186 @@
package com.xuqm.base.adapter;
import android.content.Context;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.xuqm.base.adapter.callback.AdapterItemClickListener;
import com.xuqm.base.adapter.callback.AdapterItemLongClickListener;
import java.util.ArrayList;
import java.util.List;
/**
* 不用{@link BasePagedAdapter}的时候可以用这个
* <p>
*
* @param <T> 数据各式
*/
public abstract class BaseNormalAdapter<T> extends RecyclerView.Adapter<ViewHolder> {
private Context context;
private AdapterItemClickListener<T> itemClickListener;//item的点击事件
private AdapterItemLongClickListener<T> itemLongClickListener;//item的长按事件
private ItemViewDelegateManager<T> mItemViewDelegateManager;//ItemViewDelegate的管理类
private List<T> list;
private AdapterItemClickListener<T> listener;
public BaseNormalAdapter() {
this.list = new ArrayList<>();
mItemViewDelegateManager = new ItemViewDelegateManager<>();
}
public BaseNormalAdapter(List<T> list) {
this.list = null == list ? new ArrayList<>() : list;
mItemViewDelegateManager = new ItemViewDelegateManager<>();
}
public void setmDatas(List<T> mDatas) {
this.list.clear();
this.addmDatas(null == mDatas ? new ArrayList<>() : mDatas);
}
public List<T> getDatas() {
return this.list;
}
public void addmDatas(List<T> mDatas) {
this.list.addAll(mDatas);
notifyDataSetChanged();
}
public void addItem(T item) {
this.list.add(item);
notifyDataSetChanged();
}
public void removeItem(T item) {
this.list.remove(item);
notifyDataSetChanged();
}
@Override
public int getItemViewType(int position) {
if (!useItemViewDelegateManager()) return super.getItemViewType(position);
return mItemViewDelegateManager.getItemViewType(list.get(position), position);
}
/**
* 判断是否有多种ItemViewType
* 根据mItemViewDelegateManager 里面存储的数量决定
*
* @return true 有多种ItemViewType
*/
private boolean useItemViewDelegateManager() {
return mItemViewDelegateManager.getItemViewDelegateCount() > 0;
}
/**
* 添加不同的item样式
*
* @param itemViewDelegate 自定义的item
* @return this
*/
public BaseNormalAdapter addItemViewDelegate(ItemViewDelegate<T> itemViewDelegate) {
mItemViewDelegateManager.addDelegate(itemViewDelegate);
return this;
}
/**
* 添加不同的item样式
*
* @param viewType 自定义的item type 不能重复
* @param itemViewDelegate 自定义的item
* @return this
*/
public BaseNormalAdapter addItemViewDelegate(int viewType, ItemViewDelegate<T> itemViewDelegate) {
mItemViewDelegateManager.addDelegate(viewType, itemViewDelegate);
return this;
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
ItemViewDelegate itemViewDelegate = mItemViewDelegateManager.getItemViewDelegate(viewType);
int layoutId = itemViewDelegate.getItemViewLayoutId();//这里拿到自定义的layoutId
context = parent.getContext();//context没用传递过来这里自己获取到
return new ViewHolder(context, parent, layoutId);
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
if (null != itemClickListener) {
holder.itemView.setOnClickListener(v -> itemClickListener.onClick(holder.itemView, list.get(position), position));
}
if (null != itemLongClickListener) {
holder.itemView.setOnLongClickListener(v -> itemLongClickListener.onClick(holder.itemView, list.get(position), position));
}
convert(holder, list.get(position));
}
@Override
public int getItemCount() {
return list.size();
}
/**
* 设置item点击监听
*
* @param itemClickListener item的点击事件
*/
public void setItemClickListener(AdapterItemClickListener<T> itemClickListener) {
this.itemClickListener = itemClickListener;
}
/**
* 设置item长按监听
*
* @param itemLongClickListener item的长按事件
*/
public void setItemLongClickListener(AdapterItemLongClickListener<T> itemLongClickListener) {
this.itemLongClickListener = itemLongClickListener;
}
/**
* 部分情况可以需要用到这个比如item里面元素想要和item使用同一个回调处理
*
* @return
*/
protected AdapterItemClickListener<T> getItemClickListener() {
return itemClickListener;
}
/**
* ui绘制的事件分发给ItemViewDelegate自己处理
* 比如settext() setOnClickListener()这些
*
* @param holder holder
* @param item item
*/
public void convert(ViewHolder holder, T item) {
mItemViewDelegateManager.convert(holder, item, holder.getAdapterPosition());
}
/**
* 刷新知道item
*
* @param position position
*/
public void changeItem(int position) {
if (0 <= position && position < getItemCount()) {
notifyItemChanged(position);
}
}
public void changeItem(int position, Object payload) {
if (0 <= position && position < getItemCount()) {
notifyItemChanged(position, payload);
}
}
}

查看文件

@ -0,0 +1,157 @@
package com.xuqm.base.adapter;
import android.content.Context;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.paging.PagedListAdapter;
import com.xuqm.base.adapter.callback.AdapterItemClickListener;
import com.xuqm.base.adapter.callback.AdapterItemLongClickListener;
import java.util.List;
/**
* 如果用到了{@link com.xuqm.base.ui.BaseListActivity}来展示列表页面的话需要adapter继承这个
* <p>
* 如果item只有一种类型可以使用{@link CommonPagedAdapter}来展示
* <p>
* 如果不用{@link CommonPagedAdapter}的话继承后需要使用{@link #addItemViewDelegate(ItemViewDelegate)}
* 来设置展示的页面
*
* @param <T>
*/
public class BasePagedAdapter<T extends BaseItem> extends PagedListAdapter<T, ViewHolder> {
private Context context;
private AdapterItemClickListener<T> itemClickListener;//item的点击事件
private AdapterItemLongClickListener<T> itemLongClickListener;//item的长按事件
private ItemViewDelegateManager<T> mItemViewDelegateManager;//ItemViewDelegate的管理类
public BasePagedAdapter() {
super(new Diff<>());
mItemViewDelegateManager = new ItemViewDelegateManager<>();
}
@Override
public int getItemViewType(int position) {
if (!useItemViewDelegateManager()) return super.getItemViewType(position);
return mItemViewDelegateManager.getItemViewType(getItem(position), position);
}
/**
* 判断是否有多种ItemViewType
* 根据mItemViewDelegateManager 里面存储的数量决定
*
* @return true 有多种ItemViewType
*/
private boolean useItemViewDelegateManager() {
return mItemViewDelegateManager.getItemViewDelegateCount() > 0;
}
/**
* 添加不同的item样式
*
* @param itemViewDelegate 自定义的item
* @return this
*/
public BasePagedAdapter addItemViewDelegate(ItemViewDelegate<T> itemViewDelegate) {
mItemViewDelegateManager.addDelegate(itemViewDelegate);
return this;
}
/**
* 添加不同的item样式
*
* @param viewType 自定义的item type 不能重复
* @param itemViewDelegate 自定义的item
* @return this
*/
public BasePagedAdapter addItemViewDelegate(int viewType, ItemViewDelegate<T> itemViewDelegate) {
mItemViewDelegateManager.addDelegate(viewType, itemViewDelegate);
return this;
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
ItemViewDelegate itemViewDelegate = mItemViewDelegateManager.getItemViewDelegate(viewType);
int layoutId = itemViewDelegate.getItemViewLayoutId();//这里拿到自定义的layoutId
context = parent.getContext();//context没用传递过来这里自己获取到
return new ViewHolder(context, parent, layoutId);
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
convert(holder, getItem(position));
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position, @NonNull List<Object> payloads) {
if (null != itemClickListener) {
holder.itemView.setOnClickListener(v -> itemClickListener.onClick(holder.itemView, getItem(position), position));
}
if (null != itemLongClickListener) {
holder.itemView.setOnLongClickListener(v -> itemLongClickListener.onClick(holder.itemView, getItem(position), position));
}
bindViewHolder(holder, getItem(position), position, payloads);
}
private void bindViewHolder(ViewHolder holder, T item, int position, List<Object> payloads) {
convert(holder, item);
}
/**
* 设置item点击监听
*
* @param itemClickListener item的点击事件
*/
public void setItemClickListener(AdapterItemClickListener<T> itemClickListener) {
this.itemClickListener = itemClickListener;
}
/**
* 设置item长按监听
*
* @param itemLongClickListener item的长按事件
*/
public void setItemLongClickListener(AdapterItemLongClickListener<T> itemLongClickListener) {
this.itemLongClickListener = itemLongClickListener;
}
/**
* 部分情况可以需要用到这个比如item里面元素想要和item使用同一个回调处理
* @return
*/
protected AdapterItemClickListener<T> getItemClickListener() {
return itemClickListener;
}
/**
* ui绘制的事件分发给ItemViewDelegate自己处理
* 比如settext() setOnClickListener()这些
* @param holder holder
* @param item item
*/
public void convert(ViewHolder holder, T item) {
mItemViewDelegateManager.convert(holder, item, holder.getAdapterPosition());
}
/**
* 刷新知道item
* @param position position
*/
public void changeItem(int position) {
if (0 <= position && position < getItemCount()) {
notifyItemChanged(position);
}
}
public void changeItem(int position, Object payload) {
if (0 <= position && position < getItemCount()) {
notifyItemChanged(position, payload);
}
}
}

查看文件

@ -0,0 +1,59 @@
package com.xuqm.base.adapter;
import java.util.List;
/**
* 这个adapter主要是用来简化通用adapter
* 如果item只有一种样式或者说不需要用到itemViewType可以直接使用这个
* <p>
* 构造函数直接传入对应的layoutId然后重写convert方法就可以了
* list不传的话后面使用{@link #setmDatas(List)} 添加就可以了
*
* @param <T> item用到的数据类型
*/
public abstract class CommonAdapter<T> extends BaseNormalAdapter<T> {
protected CommonAdapter(final int layoutId) {
super();
addItemViewDelegate(new ItemViewDelegate<T>() {
@Override
public int getItemViewLayoutId() {
return layoutId;
}
@Override
public boolean isForViewType(T item, int position) {
return true;
}
@Override
public void convert(ViewHolder holder, T t, int position) {
CommonAdapter.this.convert(holder, t, position);
}
});
}
protected CommonAdapter(final int layoutId, List<T> list) {
super(list);
addItemViewDelegate(new ItemViewDelegate<T>() {
@Override
public int getItemViewLayoutId() {
return layoutId;
}
@Override
public boolean isForViewType(T item, int position) {
return true;
}
@Override
public void convert(ViewHolder holder, T t, int position) {
CommonAdapter.this.convert(holder, t, position);
}
});
}
protected abstract void convert(ViewHolder holder, T item, int position);
}

查看文件

@ -0,0 +1,36 @@
package com.xuqm.base.adapter;
/**
* 这个adapter主要是用来简化通用列表页的绘制
* 如果item只有一种样式或者说不需要用到itemViewType可以直接使用这个
* <p>
* 构造函数直接传入对应的layoutId然后重写convert方法就可以了
*
* @param <T> item用到的数据类型
*/
public abstract class CommonPagedAdapter<T extends BaseItem> extends BasePagedAdapter<T> {
protected CommonPagedAdapter(final int layoutId) {
super();
addItemViewDelegate(new ItemViewDelegate<T>() {
@Override
public int getItemViewLayoutId() {
return layoutId;
}
@Override
public boolean isForViewType(T item, int position) {
return true;
}
@Override
public void convert(ViewHolder holder, T t, int position) {
CommonPagedAdapter.this.convert(holder, t, position);
}
});
}
protected abstract void convert(ViewHolder holder, T item, int position);
}

查看文件

@ -0,0 +1,16 @@
package com.xuqm.base.adapter;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.DiffUtil;
public class Diff<T extends BaseItem> extends DiffUtil.ItemCallback<T> {
@Override
public boolean areItemsTheSame(@NonNull T oldItem, @NonNull T newItem) {
return oldItem.getS_id() == newItem.getS_id();
}
@Override
public boolean areContentsTheSame(@NonNull T oldItem, @NonNull T newItem) {
return oldItem.getS_id() == newItem.getS_id();
}
}

查看文件

@ -0,0 +1,72 @@
package com.xuqm.base.adapter;
import android.content.Context;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.MotionEvent;
import android.widget.HorizontalScrollView;
public class ElasticHorizontalScrollView extends HorizontalScrollView {
private float x;
private DisplayMetrics metrics;
private int threshold = 0;
public ElasticHorizontalScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
metrics = getResources().getDisplayMetrics();
}
public ElasticHorizontalScrollView(Context context) {
this(context, null);
}
public void setThreshold(int threshold) {
this.threshold = threshold;
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
if (ev == null) {
return super.onTouchEvent(ev);
} else {
return commOnTouchEvent(ev);
}
}
public void reset() {
scrollTo(0, 0);
}
private boolean commOnTouchEvent(MotionEvent ev) {
int action = ev.getAction();
int length = threshold;
switch (action) {
case MotionEvent.ACTION_DOWN:
x = ev.getX();
break;
case MotionEvent.ACTION_UP:
//复原位置
if ((ev.getX() - x) > 0) {
if (getScrollX() > length / 2) {
smoothScrollTo(length, 0);
} else {
smoothScrollTo(0, 0);
}
} else {
if (getScrollX() > length / 2) {
smoothScrollTo(length, 0);
} else {
smoothScrollTo(0, 0);
}
}
return true;
case MotionEvent.ACTION_MOVE:
return super.onTouchEvent(ev);
default:
return true;
}
return true;
}
}

查看文件

@ -0,0 +1,30 @@
package com.xuqm.base.adapter;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.lifecycle.Lifecycle;
import androidx.viewpager2.adapter.FragmentStateAdapter;
import java.util.List;
public class FragmentAdapter extends FragmentStateAdapter {
private List<Fragment> fragments;
public FragmentAdapter(@NonNull FragmentManager fragmentManager, @NonNull Lifecycle lifecycle, List<Fragment> fragments) {
super(fragmentManager, lifecycle);
this.fragments = fragments;
}
@NonNull
@Override
public Fragment createFragment(int position) {
return fragments.get(position);
}
@Override
public int getItemCount() {
return fragments.size();
}
}

查看文件

@ -0,0 +1,15 @@
package com.xuqm.base.adapter;
/**
* Created by zhy on 16/6/22.
*/
public interface ItemViewDelegate<T> {
int getItemViewLayoutId();//这个 ItemViewDelegate 将要展示的页面
boolean isForViewType(T item, int position); //条件判断用来判断什么时候展示这个ItemViewDelegate
void convert(ViewHolder holder, T item, int position);//UI绘制与事件添加
}

查看文件

@ -0,0 +1,95 @@
package com.xuqm.base.adapter;
import androidx.collection.SparseArrayCompat;
/**
* Created by zhy on 16/6/22.
*/
public class ItemViewDelegateManager<T> {
private SparseArrayCompat<ItemViewDelegate<T>> delegates = new SparseArrayCompat<>();
public int getItemViewDelegateCount() {
return delegates.size();
}
public ItemViewDelegateManager<T> addDelegate(ItemViewDelegate<T> delegate) {
int viewType = delegates.size();
if (delegate != null) {
delegates.put(viewType, delegate);
}
return this;
}
public ItemViewDelegateManager<T> addDelegate(int viewType, ItemViewDelegate<T> delegate) {
if (delegates.get(viewType) != null) {
throw new IllegalArgumentException(
"An ItemViewDelegate is already registered for the viewType = "
+ viewType
+ ". Already registered ItemViewDelegate is "
+ delegates.get(viewType));
}
delegates.put(viewType, delegate);
return this;
}
public ItemViewDelegateManager<T> removeDelegate(ItemViewDelegate<T> delegate) {
if (delegate == null) {
throw new NullPointerException("ItemViewDelegate is null");
}
int indexToRemove = delegates.indexOfValue(delegate);
if (indexToRemove >= 0) {
delegates.removeAt(indexToRemove);
}
return this;
}
public ItemViewDelegateManager<T> removeDelegate(int itemType) {
int indexToRemove = delegates.indexOfKey(itemType);
if (indexToRemove >= 0) {
delegates.removeAt(indexToRemove);
}
return this;
}
int getItemViewType(T item, int position) {
int delegatesCount = delegates.size();
for (int i = 0; i < delegatesCount; i++) {
ItemViewDelegate<T> delegate = delegates.valueAt(i);
if (delegate.isForViewType(item, position)) {
return delegates.keyAt(i);
}
}
throw new IllegalArgumentException(
"No ItemViewDelegate added that matches position=" + position + " in data source");
}
void convert(ViewHolder holder, T item, int position) {
int delegatesCount = delegates.size();
for (int i = 0; i < delegatesCount; i++) {
ItemViewDelegate<T> delegate = delegates.valueAt(i);
if (delegate.isForViewType(item, position)) {
delegate.convert(holder, item, position);
return;
}
}
throw new IllegalArgumentException(
"No ItemViewDelegateManager added that matches position=" + position + " in data source");
}
public ItemViewDelegate getItemViewDelegate(int viewType) {
return delegates.get(viewType);
}
public int getItemViewLayoutId(int viewType) {
return getItemViewDelegate(viewType).getItemViewLayoutId();
}
public int getItemViewType(ItemViewDelegate<T> itemViewDelegate) {
return delegates.indexOfValue(itemViewDelegate);
}
}

查看文件

@ -0,0 +1,178 @@
package com.xuqm.base.adapter;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.LinearLayout.LayoutParams;
import androidx.recyclerview.widget.RecyclerView;
import com.xuqm.base.R;
/**
* @author jose.han
* @date 2019/7/19 0019
* @description 包装器再原有的adpter 基础上分装测滑功能基于
*/
public class SlipReAdapter extends RecyclerView.Adapter<SlipReAdapter.RViewHolder> {
private RecyclerView.Adapter mAdapter;
private ISlipClickAction mISlipClickAction;
private int mSlipViewId;
public final static int MODE_DELETE = 0;
public final static int MODE_CLICK = 0;
private int mMode = MODE_DELETE;
private int mSlipWidth = 0;
public static class Builder {
private RecyclerView.Adapter mAdapter;
private ISlipClickAction mISlipClickAction;
private int mSlipViewId;
private int mMode;
private int mSlipWidth;
public Builder setAdapter(RecyclerView.Adapter adapter) {
mAdapter = adapter;
return this;
}
public Builder setISlipClickAction(
ISlipClickAction ISlipClickAction) {
mISlipClickAction = ISlipClickAction;
return this;
}
public Builder setSlipViewId(int slipViewId) {
mSlipViewId = slipViewId;
return this;
}
public Builder setMode(int mode) {
mMode = mode;
return this;
}
public Builder setSlipWidth(float slipWidth) {
mSlipWidth = (int) slipWidth;
return this;
}
public SlipReAdapter build() {
SlipReAdapter slipReAdapter = new SlipReAdapter();
slipReAdapter.setAdapter(mAdapter);
slipReAdapter.setISlipClickAction(mISlipClickAction);
slipReAdapter.setMode(mMode);
slipReAdapter.setSlipViewId(mSlipViewId);
slipReAdapter.setSlipWidth(mSlipWidth);
return slipReAdapter;
}
}
public SlipReAdapter() {
}
public void setAdapter(RecyclerView.Adapter adapter) {
mAdapter = adapter;
}
public void setISlipClickAction(
ISlipClickAction ISlipClickAction) {
mISlipClickAction = ISlipClickAction;
}
public void setSlipViewId(int slipViewId) {
mSlipViewId = slipViewId;
}
public void setMode(int mode) {
mMode = mode;
}
public void setSlipWidth(int slipWidth) {
mSlipWidth = slipWidth;
}
@Override
public RViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_slip, parent, false);
LinearLayout contentLL = view.findViewById(R.id.content_ll);
LinearLayout deleteLl = view.findViewById(R.id.delete_ll);
View delete = LayoutInflater.from(parent.getContext()).inflate(mSlipViewId, null, false);
deleteLl.addView(delete);
LayoutParams layoutParams = new LayoutParams(
parent.getResources().getDisplayMetrics().widthPixels,
ViewGroup.LayoutParams.WRAP_CONTENT);
RecyclerView.ViewHolder viewHolder = mAdapter.onCreateViewHolder(parent, viewType);
viewHolder.itemView.setLayoutParams(layoutParams);
contentLL.addView(viewHolder.itemView);
return new RViewHolder(view, viewHolder, mSlipWidth);
}
@Override
public void onBindViewHolder(final RViewHolder holder, final int position) {
mAdapter.onBindViewHolder(holder.mViewHolder, position);
holder.deleteLl.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
mISlipClickAction.onAction(holder.getAdapterPosition());
holder.mElasticHorizontalScrollView.reset();
Log.i("SlipReAdapter", "slip action and the pos is:" + holder.getAdapterPosition());
if (mMode == MODE_DELETE) {
notifyItemRemoved(holder.getAdapterPosition());
} else if (mMode == MODE_CLICK) {
notifyItemChanged(holder.getAdapterPosition());
}
}
});
}
@Override
public int getItemCount() {
return mAdapter != null ? mAdapter.getItemCount() : 0;
}
public static class RViewHolder extends RecyclerView.ViewHolder {
private View deleteLl;
private ElasticHorizontalScrollView mElasticHorizontalScrollView;
private RecyclerView.ViewHolder mViewHolder;
public RViewHolder(View itemView, RecyclerView.ViewHolder viewHolder, int threshold) {
super(itemView);
mViewHolder = viewHolder;
deleteLl = itemView.findViewById(R.id.delete_ll);
mElasticHorizontalScrollView = itemView.findViewById(R.id.ElasticHorizontalScrollView);
if (threshold != 0) {
LayoutParams layoutParams = new LayoutParams(threshold,
ViewGroup.LayoutParams.WRAP_CONTENT);
deleteLl.setLayoutParams(layoutParams);
mElasticHorizontalScrollView.setThreshold(threshold);
} else {
deleteLl.post(new Runnable() {
@Override
public void run() {
int width = deleteLl.getWidth();
mElasticHorizontalScrollView.setThreshold(width);
}
});
}
}
}
public interface ISlipClickAction {
public void onAction(int position);
}
}

查看文件

@ -0,0 +1,156 @@
package com.xuqm.base.adapter;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Typeface;
import android.util.SparseArray;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.ColorInt;
import androidx.annotation.ColorRes;
import androidx.annotation.DrawableRes;
import androidx.annotation.IdRes;
import androidx.annotation.LayoutRes;
import androidx.annotation.StringRes;
import androidx.recyclerview.widget.RecyclerView;
import com.xuqm.base.adapter.callback.AdapterClickListener;
import com.xuqm.base.common.ImageHelper;
import java.util.List;
public class ViewHolder extends RecyclerView.ViewHolder {
private Context context;
private ViewGroup parent;
private int layoutId;
private SparseArray<View> views = new SparseArray<>();
public ViewHolder(Context context, ViewGroup parent, @LayoutRes int layoutId) {
super(LayoutInflater.from(context).inflate(layoutId, parent, false));
this.context = context;
this.parent = parent;
this.layoutId = layoutId;
}
public <T extends View> T getView(int viewId) {
View view = views.get(viewId);
if (null == view) {
view = itemView.findViewById(viewId);
if (null == view) throw new IllegalArgumentException("not found id");
views.put(viewId, view);
}
return (T) view;
}
public ViewHolder setText(@IdRes int viewId, CharSequence text) {
TextView textView = getView(viewId);
textView.setText(text);
return this;
}
public ViewHolder setTypeface(@IdRes int viewId, Typeface typeface) {
TextView textView = getView(viewId);
textView.setTypeface(typeface);
return this;
}
public ViewHolder setEnabled(@IdRes int viewId, boolean enabled) {
View view = getView(viewId);
view.setEnabled(enabled);
return this;
}
public ViewHolder setBackgroundResource(@IdRes int viewId, @DrawableRes int resId) {
View textView = getView(viewId);
textView.setBackgroundResource(resId);
return this;
}
public ViewHolder setBackgroundColor(@IdRes int viewId, @ColorInt int color) {
View textView = getView(viewId);
textView.setBackgroundColor(color);
return this;
}
public ViewHolder setTextColor(@IdRes int viewId, @ColorInt int color) {
TextView textView = getView(viewId);
textView.setTextColor(color);
return this;
}
public ViewHolder setText(@IdRes int viewId, @StringRes int resId) {
TextView textView = getView(viewId);
textView.setText(context.getString(resId));
return this;
}
public ViewHolder setImageResource(@IdRes int viewId, @DrawableRes int resId) {
ImageView imageView = getView(viewId);
imageView.setImageResource(resId);
return this;
}
public ViewHolder setImage(@IdRes int viewId, String url) {
ImageView imageView = getView(viewId);
ImageHelper.load(imageView, url);
return this;
}
public ViewHolder setImage(@IdRes int viewId, Bitmap bitmap) {
ImageView imageView = getView(viewId);
ImageHelper.load(imageView, bitmap);
return this;
}
public ViewHolder gone(@IdRes int viewId) {
View view = getView(viewId);
view.setVisibility(View.GONE);
return this;
}
public ViewHolder invisible(@IdRes int viewId) {
View view = getView(viewId);
view.setVisibility(View.INVISIBLE);
return this;
}
public ViewHolder gone(View view) {
view.setVisibility(View.GONE);
return this;
}
public ViewHolder visible(@IdRes int viewId) {
View view = getView(viewId);
view.setVisibility(View.VISIBLE);
return this;
}
public ViewHolder setVisibility(@IdRes int viewId, boolean isVisible) {
View view = getView(viewId);
if (isVisible) view.setVisibility(View.VISIBLE);
else view.setVisibility(View.GONE);
return this;
}
public ViewHolder visible(View view) {
view.setVisibility(View.VISIBLE);
return this;
}
public ViewHolder setClickListener(@IdRes int viewId, AdapterClickListener adapterClickListener) {
View view = getView(viewId);
if (null != view) view.setOnClickListener(adapterClickListener::onClick);
return this;
}
public ViewHolder setClickListener(List<Integer> viewIds, AdapterClickListener adapterClickListener) {
for (Integer viewId : viewIds) {
View view = getView(viewId);
if (null != view) view.setOnClickListener(adapterClickListener::onClick);
}
return this;
}
}

查看文件

@ -0,0 +1,10 @@
package com.xuqm.base.adapter.callback;
import android.view.View;
/**
* adapter中为item元素设置点击时间时候用到的监听
*/
public interface AdapterClickListener {
void onClick(View view);
}

查看文件

@ -0,0 +1,11 @@
package com.xuqm.base.adapter.callback;
import android.view.View;
/**
* item设置点击事件的监听
* @param <T>
*/
public interface AdapterItemClickListener<T> {
void onClick(View view, T item, int position);
}

查看文件

@ -0,0 +1,11 @@
package com.xuqm.base.adapter.callback;
import android.view.View;
/**
* item设置长按事件的监听
* @param <T>
*/
public interface AdapterItemLongClickListener<T> {
boolean onClick(View view, T item, int position);
}

查看文件

@ -0,0 +1,94 @@
package com.xuqm.base.common;
import android.app.Activity;
import java.util.Stack;
/**
* activity的管理栈
*/
public class AppManager {
public static AppManager getInstance() {
return APPHolder.INSTANCE;
}
private static class APPHolder {
private static final AppManager INSTANCE = new AppManager();
}
private AppManager() {
activityStack = new Stack<>();
}
private final Stack<Activity> activityStack;
//添加一个新的act
public void pushActivity(Activity activity) {
activityStack.add(activity);
}
/**
* 推出一个activity 其实toolbar的返回按钮可以直接使用这个方法
*
* @param activity 需要退出的activity
*/
public void popActivity(Activity activity) {
if (activityStack != null && activityStack.size() > 0) {
if (activity != null) {
activity.finish();
activityStack.remove(activity);
}
}
}
/**
* 获取当前最上面的那个activity
*
* @return
*/
public Activity getActivity() {
return activityStack.lastElement();
}
/**
* finish最后一个
*
* @return
*/
public void finish() {
this.popActivity(this.getActivity());
}
/**
* finish最后一个之外的所有页面
*
* @return
*/
public void logout() {
if (activityStack.size() < 1)
return;
for (int i = 0; i < activityStack.size() - 1; i++) {
Activity activity = activityStack.firstElement();
if (activity == null) break;
popActivity(activity);
}
}
/**
* 退出app
*/
public void exit() {
if (activityStack != null) {
while (activityStack.size() > 0) {
Activity activity = getActivity();
if (activity == null) break;
popActivity(activity);
}
}
android.os.Process.killProcess(android.os.Process.myPid());
}
}

查看文件

@ -0,0 +1,218 @@
package com.xuqm.base.common;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import androidx.annotation.NonNull;
import androidx.core.content.FileProvider;
import com.xuqm.base.App;
import com.xuqm.base.BuildConfig;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.UUID;
public class FileHelper {
public static String getRootFilePath() {
return App.getInstance().getExternalFilesDir(null).getPath() +
File.separator +
BuildConfig.APP_ID +
File.separator;
}
/**
* 根据路径创建文件夹
*
* @param filePath
* @return
*/
public static boolean createDirectory(String filePath) {
if (ToolsHelper.isNull(filePath)) {
return false;
}
File file = new File(filePath);
if (file.exists() && file.isDirectory()) {
return true;
}
return file.mkdirs();
}
public static void delete(String path) {
LogHelper.e(String.format("开始删除文件::%s", path));
File file = new File(path);
if (!file.exists()
|| !file.isFile())
return;
file.delete();
}
public static void delete(File file) {
LogHelper.e(String.format("开始删除文件::%s", file.getAbsoluteFile()));
if (!file.exists()
|| !file.isFile())
return;
file.delete();
}
public static String getVoicePath() {
String path = getRootFilePath() +
"voice" +
File.separator;
return createDirectory(path) ? path : "";
}
public static String getImagePath() {
String path = getRootFilePath() +
"image" +
File.separator;
return createDirectory(path) ? path : "";
}
public static String getAppPath() {
String path = getRootFilePath() +
"apps" +
File.separator;
LogHelper.e(path);
return createDirectory(path) ? path : "";
}
public static String getDownloadPath() {
String path = getRootFilePath() +
"download" +
File.separator;
LogHelper.e(path);
return createDirectory(path) ? path : "";
}
/**
* 读取assets文件夹的文件
*
* @param strFileName 文件名包含assets后面的路径
* @return 文件内容
*/
public static String readJSON(String strFileName) {
String strResult = "";
try (InputStream is = App.getInstance().getAssets().open(strFileName)) {
int size = is.available();
byte[] buffer = new byte[size];
is.read(buffer);
strResult = new String(buffer, StandardCharsets.UTF_8);
} catch (Exception ex) {
LogHelper.e("readJson", ex);
}
return strResult;
}
public static String getBitmapFilePath(String path, String suffix) {
String pathStr = getRootFilePath() + "images" + File.separator + path + File.separator;
createDirectory(pathStr);
return pathStr + UUID.randomUUID() + "." + suffix;
}
/**
* 保存图片到本地
*
* @param bitmap 图片
* @param filePath 保存到的文件 png
* @return 状态
*/
public static String saveBitmap(Bitmap bitmap, String filePath) {
if (bitmap == null)
return "";
FileOutputStream fos = null;
try {
fos = new FileOutputStream(new File(filePath));
bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos);
fos.flush();
return filePath;
} catch (Exception e) {
e.printStackTrace();
} finally {
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return "";
}
public void installAPK(String filePath) {
Intent intent = new Intent();
intent.setAction("android.intent.action.VIEW");
intent.addCategory("android.intent.category.DEFAULT");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);// 广播里面操作需要加上这句存在于一个独立的栈里
intent.setDataAndType(Uri.fromFile(new File(filePath)), "application/vnd.android.package-archive");
App.getInstance().startActivity(intent);
}
public static void openFile(Context activity, File file) {
Intent intent = new Intent();
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
// 设置intent的Action属性
intent.setAction(Intent.ACTION_VIEW);
// 获取文件file的MIME类型
String type = getMIMEType(file);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
}
// 设置intent的data和Type属性
intent.setDataAndType(/* uri */FileHelper.getFileUri(file), type);
activity.startActivity(intent);
}
public static Uri getFileUri(@NonNull File file) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
return FileProvider.getUriForFile(AppManager.getInstance().getActivity(), BuildConfig.APP_ID + ".fileprovider", file);
} else {
return Uri.fromFile(file);
}
}
private static String[][] MIME_MapTable = new String[][]{{".3gp", "video/3gpp"}, {".apk", "application/vnd.android.package-archive"}, {".asf", "video/x-ms-asf"}, {".avi", "video/x-msvideo"}, {".bin", "application/octet-stream"}, {".bmp", "image/bmp"}, {".c", "text/plain"}, {".class", "application/octet-stream"}, {".conf", "text/plain"}, {".cpp", "text/plain"}, {".doc", "application/msword"}, {".docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document"}, {".xls", "application/vnd.ms-excel"}, {".xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"}, {".exe", "application/octet-stream"}, {".gif", "image/gif"}, {".gtar", "application/x-gtar"}, {".gz", "application/x-gzip"}, {".h", "text/plain"}, {".htm", "text/html"}, {".html", "text/html"}, {".jar", "application/java-archive"}, {".java", "text/plain"}, {".jpeg", "image/jpeg"}, {".jpg", "image/jpeg"}, {".eucppic", "image/jpeg"}, {".js", "application/x-javascript"}, {".log", "text/plain"}, {".m3u", "audio/x-mpegurl"}, {".m4a", "audio/mp4a-latm"}, {".m4b", "audio/mp4a-latm"}, {".m4p", "audio/mp4a-latm"}, {".m4u", "video/vnd.mpegurl"}, {".m4v", "video/x-m4v"}, {".mov", "video/quicktime"}, {".mp2", "audio/x-mpeg"}, {".mp3", "audio/x-mpeg"}, {".mp4", "video/mp4"}, {".mpc", "application/vnd.mpohun.certificate"}, {".mpe", "video/mpeg"}, {".mpeg", "video/mpeg"}, {".mpg", "video/mpeg"}, {".mpg4", "video/mp4"}, {".mpga", "audio/mpeg"}, {".msg", "application/vnd.ms-outlook"}, {".ogg", "audio/ogg"}, {".pdf", "application/pdf"}, {".png", "image/png"}, {".pps", "application/vnd.ms-powerpoint"}, {".ppt", "application/vnd.ms-powerpoint"}, {".pptx", "application/vnd.openxmlformats-officedocument.presentationml.presentation"}, {".prop", "text/plain"}, {".rc", "text/plain"}, {".rmvb", "audio/x-pn-realaudio"}, {".rtf", "application/rtf"}, {".sh", "text/plain"}, {".tar", "application/x-tar"}, {".tgz", "application/x-compressed"}, {".txt", "text/plain"}, {".wav", "audio/x-wav"}, {".wma", "audio/x-ms-wma"}, {".wmv", "audio/x-ms-wmv"}, {".wps", "application/vnd.ms-works"}, {".xml", "text/plain"}, {".z", "application/x-compress"}, {".zip", "application/x-zip-compressed"}, {"", "*/*"}};
public static String getMIMEType(File file) {
String type = "*/*";
String fName = file.getName();
int dotIndex = fName.lastIndexOf(".");
if (dotIndex < 0) {
return type;
} else {
String end = fName.substring(dotIndex, fName.length()).toLowerCase();
if (end == "") {
return type;
} else {
for (int i = 0; i < MIME_MapTable.length; ++i) {
if (end.equals(MIME_MapTable[i][0])) {
type = MIME_MapTable[i][1];
}
}
return type;
}
}
}
}

查看文件

@ -0,0 +1,230 @@
package com.xuqm.base.common
import android.content.Context
import android.graphics.Bitmap
import android.graphics.PointF
import android.graphics.drawable.Drawable
import android.view.View
import android.widget.ImageView
import androidx.annotation.NonNull
import androidx.core.graphics.drawable.RoundedBitmapDrawable
import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory
import com.bumptech.glide.Glide
import com.bumptech.glide.request.RequestOptions
import com.bumptech.glide.request.target.BitmapImageViewTarget
import com.bumptech.glide.request.target.ImageViewTarget
import com.luck.picture.lib.engine.ImageEngine
import com.luck.picture.lib.listener.OnImageCompleteCallback
import com.luck.picture.lib.tools.MediaUtils
import com.luck.picture.lib.widget.longimage.ImageSource
import com.luck.picture.lib.widget.longimage.ImageViewState
import com.luck.picture.lib.widget.longimage.SubsamplingScaleImageView
import com.xuqm.base.R
import org.jetbrains.annotations.NotNull
class GlideEngine private constructor() : ImageEngine {
/**
* 加载图片
*
* @param context
* @param url
* @param imageView
*/
override fun loadImage(
@NotNull context: Context,
@NotNull url: String,
@NotNull imageView: ImageView
) {
Glide.with(context)
.load(url)
.into(imageView)
}
/**
* 加载网络图片适配长图方案
* # 注意此方法只有加载网络图片才会回调
*
* @param context
* @param url
* @param imageView
* @param longImageView
* @param callback 网络图片加载回调监听 {link after version 2.5.1 Please use the #OnImageCompleteCallback#}
*/
override fun loadImage(
@NotNull context: Context, @NotNull url: String,
@NotNull imageView: ImageView,
longImageView: SubsamplingScaleImageView, callback: OnImageCompleteCallback
) {
Glide.with(context)
.asBitmap()
.load(url)
.into(object : ImageViewTarget<Bitmap?>(imageView) {
override fun onLoadStarted(@NonNull placeholder: Drawable?) {
super.onLoadStarted(placeholder)
callback.onShowLoading()
}
override fun onLoadFailed(@NonNull errorDrawable: Drawable?) {
super.onLoadFailed(errorDrawable)
callback.onHideLoading()
}
override fun setResource(@NonNull resource: Bitmap?) {
callback.onHideLoading()
if (resource != null) {
val eqLongImage: Boolean = MediaUtils.isLongImg(
resource.width,
resource.height
)
longImageView.visibility = if (eqLongImage) View.VISIBLE else View.GONE
imageView.visibility = if (eqLongImage) View.GONE else View.VISIBLE
if (eqLongImage) {
// 加载长图
longImageView.isQuickScaleEnabled = true
longImageView.isZoomEnabled = true
longImageView.isPanEnabled = true
longImageView.setDoubleTapZoomDuration(100)
longImageView.setMinimumScaleType(SubsamplingScaleImageView.SCALE_TYPE_CENTER_CROP)
longImageView.setDoubleTapZoomDpi(SubsamplingScaleImageView.ZOOM_FOCUS_CENTER)
longImageView.setImage(
ImageSource.bitmap(resource),
ImageViewState(0f, PointF(0f, 0f), 0)
)
} else {
// 普通图片
imageView.setImageBitmap(resource)
}
}
}
})
}
/**
* 加载网络图片适配长图方案
* # 注意此方法只有加载网络图片才会回调
*
* @param context
* @param url
* @param imageView
* @param longImageView
* @ 已废弃
*/
override fun loadImage(
@NotNull context: Context, @NotNull url: String,
@NotNull imageView: ImageView,
longImageView: SubsamplingScaleImageView
) {
Glide.with(context)
.asBitmap()
.load(url)
.into(object : ImageViewTarget<Bitmap?>(imageView) {
override fun setResource(@NonNull resource: Bitmap?) {
if (resource != null) {
val eqLongImage: Boolean = MediaUtils.isLongImg(
resource.width,
resource.height
)
longImageView.visibility = if (eqLongImage) View.VISIBLE else View.GONE
imageView.visibility = if (eqLongImage) View.GONE else View.VISIBLE
if (eqLongImage) {
// 加载长图
longImageView.isQuickScaleEnabled = true
longImageView.isZoomEnabled = true
longImageView.isPanEnabled = true
longImageView.setDoubleTapZoomDuration(100)
longImageView.setMinimumScaleType(SubsamplingScaleImageView.SCALE_TYPE_CENTER_CROP)
longImageView.setDoubleTapZoomDpi(SubsamplingScaleImageView.ZOOM_FOCUS_CENTER)
longImageView.setImage(
ImageSource.bitmap(resource),
ImageViewState(0f, PointF(0f, 0f), 0)
)
} else {
// 普通图片
imageView.setImageBitmap(resource)
}
}
}
})
}
/**
* 加载相册目录
*
* @param context 上下文
* @param url 图片路径
* @param imageView 承载图片ImageView
*/
override fun loadFolderImage(
@NotNull context: Context,
@NotNull url: String,
@NotNull imageView: ImageView
) {
Glide.with(context)
.asBitmap()
.load(url)
.override(180, 180)
.centerCrop()
.sizeMultiplier(0.5f)
.apply(RequestOptions().placeholder(R.drawable.picture_image_placeholder))
.into(object : BitmapImageViewTarget(imageView) {
override fun setResource(resource: Bitmap?) {
val circularBitmapDrawable: RoundedBitmapDrawable =
RoundedBitmapDrawableFactory.create(context.resources, resource)
circularBitmapDrawable.cornerRadius = 8f
imageView.setImageDrawable(circularBitmapDrawable)
}
})
}
/**
* 加载gif
*
* @param context 上下文
* @param url 图片路径
* @param imageView 承载图片ImageView
*/
override fun loadAsGifImage(
@NotNull context: Context, @NotNull url: String,
@NotNull imageView: ImageView
) {
Glide.with(context)
.asGif()
.load(url)
.into(imageView)
}
/**
* 加载图片列表图片
*
* @param context 上下文
* @param url 图片路径
* @param imageView 承载图片ImageView
*/
override fun loadGridImage(
@NotNull context: Context,
@NotNull url: String,
@NotNull imageView: ImageView
) {
Glide.with(context)
.load(url)
.override(200, 200)
.centerCrop()
.apply(RequestOptions().placeholder(R.drawable.picture_image_placeholder))
.into(imageView)
}
companion object {
private var instance: GlideEngine? = null
fun createGlideEngine(): GlideEngine? {
if (null == instance) {
synchronized(GlideEngine::class.java) {
if (null == instance) {
instance = GlideEngine()
}
}
}
return instance
}
}
}

查看文件

@ -0,0 +1,54 @@
package com.xuqm.base.common;
import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonParser;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* Created by xuqm on 2016/6/3.
*/
public class GsonImplHelp extends Json {
private Gson gson = new Gson();
@Override
public String toJson(Object src) {
return gson.toJson(src);
}
@Override
public <T> T toObject(String json, Class<T> claxx) {
return gson.fromJson(json, claxx);
}
@Override
public <T> T toObject(byte[] bytes, Class<T> claxx) {
return gson.fromJson(new String(bytes), claxx);
}
public <T> List<T> toList(String json, Class<T> clazz) {
JsonArray jsonArray = new JsonParser().parse(json).getAsJsonArray();
List<T> list = new ArrayList<>();
for (JsonElement jsonElement : jsonArray) {
list.add(gson.fromJson(jsonElement, clazz)); //cls
}
return list;
}
public static <T> List<T> stringToArray(String s, Class<T[]> cls) {
T[] array = new Gson().fromJson(s, cls);
return Arrays.asList(array);
}
}

查看文件

@ -0,0 +1,65 @@
package com.xuqm.base.common;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.util.Base64;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
/***************************************************************************
* <pre></pre>
* @文件名称 ImageHelp
* @包 com.xuqm.base.common
* @版权所有北京数字医信责任有限公司 (C) 2021
*
* @类描述:
* @版本: V1.0
* @创建人 xuqm
* @创建时间2021/9/26 下午 06:11
* @修改记录
*/
public class ImageHelp {
/*
* bitmap转base64
* */
public static String bitmapToBase64(Bitmap bitmap) {
String result = null;
ByteArrayOutputStream baos = null;
try {
if (bitmap != null) {
baos = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);
baos.flush();
baos.close();
byte[] bitmapBytes = baos.toByteArray();
result = Base64.encodeToString(bitmapBytes, Base64.DEFAULT);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (baos != null) {
baos.flush();
baos.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return result;
}
/**
* base64转为bitmap
*
* @param base64Data
* @return
*/
public static Bitmap base64ToBitmap(String base64Data) {
byte[] bytes = Base64.decode(base64Data, Base64.DEFAULT);
return BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
}
}

查看文件

@ -0,0 +1,20 @@
package com.xuqm.base.common;
import android.widget.ImageView;
import com.bumptech.glide.Glide;
/**
* 一个image相关的工具类
*/
public class ImageHelper {
/**
* 给imageView添加图片的方法
*
* @param imageView 需要添加图片的控件
* @param url url地址可以是path draw等
*/
public static void load(ImageView imageView, Object url) {
Glide.with(imageView).load(url).into(imageView);
}
}

查看文件

@ -0,0 +1,29 @@
package com.xuqm.base.common;
import java.util.List;
/**
* Created by xuqm on 2016/6/3.
*/
public abstract class Json {
private static Json json;
Json() {
}
public static Json get() {
if (json == null) {
json = new GsonImplHelp();
}
return json;
}
public abstract String toJson(Object src);
public abstract <T> T toObject(String json, Class<T> claxx);
public abstract <T> T toObject(byte[] bytes, Class<T> claxx);
public abstract <T> List<T> toList(String json, Class<T> claxx);
}

查看文件

@ -0,0 +1,75 @@
package com.xuqm.base.common;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.orhanobut.logger.Logger;
import java.util.Locale;
/**
* 日志库用的是 KLog
* 平常自己调试时候不想用那么多就随便写了个类
*/
public class LogHelper {
public static void d(String tag, Object object) {
Logger.t(tag).d(object);
}
public static void d(Object object) {
StackTraceElement caller = getCallerStackTraceElement();
String tag = generateTag(caller);
Logger.t(tag).d(object);
}
public static void d(@NonNull String message, @Nullable Object... args) {
Logger.t(message).d(args);
}
public static void e(String tag, Object object) {
Logger.t(tag).e(object.toString());
}
public static void e(Object object) {
if (null == object){
return;
}
StackTraceElement caller = getCallerStackTraceElement();
String tag = generateTag(caller);
Logger.t(tag).e("=====>" + object.toString());
}
public static void e(String msg, Throwable tr) {
StackTraceElement caller = getCallerStackTraceElement();
String tag = generateTag(caller);
Logger.t(tag).e(tr, msg);
}
public static void e(String tag, String msg, Throwable tr) {
Logger.t(tag).e(tr, msg);
}
public static void json(String msg) {
StackTraceElement caller = getCallerStackTraceElement();
String tag = generateTag(caller);
Logger.t(tag).json(msg);
}
public static void json(String tag, String msg) {
Logger.t(tag).json(msg);
}
private static String generateTag(StackTraceElement caller) {
String tag = "%s.%s(L:%d)";
String callerClazzName = caller.getClassName();
callerClazzName = callerClazzName.substring(callerClazzName.lastIndexOf(".") + 1);
return String.format(Locale.getDefault(), tag, callerClazzName, caller.getMethodName(), caller.getLineNumber());
}
private static StackTraceElement getCallerStackTraceElement() {
return Thread.currentThread().getStackTrace()[4];
}
}

查看文件

@ -0,0 +1,8 @@
package com.xuqm.base.common;
/**
* 下拉刷新的状态码表
*/
public enum RefreshResult {
SUCCEED, FAILED, NO_DATA, NO_MORE
}

某些文件未显示,因为此 diff 中更改的文件太多 显示更多