Commit 0b38225b authored by 赵鹏翔's avatar 赵鹏翔

Merge branch 'dev' into 'develop'

Dev

See merge request !5
parents 69cb9121 ce4a1f78
......@@ -27,6 +27,9 @@ android {
versionName VERSION_NAME.toString()
multiDexEnabled true
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
buildConfigField 'String', "CHANNEL", "\"$CHANNEL\""
buildConfigField "Boolean", "ISTEST", ISTEST.toString()
buildConfigField "String", "appType", "\"mpos\""
}
buildTypes {
......@@ -112,5 +115,5 @@ static String buildTime() {
}
String getAppChannel() {
return project.channel
return project.CHANNEL
}
\ No newline at end of file
......@@ -2,18 +2,16 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.miya.fastcashier">
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<application
android:name=".BaseApplication"
android:allowBackup="false"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:theme="@style/Theme.MiYaFastCashier.Dark"
android:supportsRtl="true">
android:supportsRtl="true"
android:theme="@style/Theme.MiYaFastCashier.Dark">
<activity
android:name=".ui.LoginActivity"
android:exported="true"
......@@ -21,6 +19,7 @@
android:theme="@style/Theme.MiYaFastCashier.Light">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
......@@ -58,6 +57,19 @@
<activity
android:name=".ui.ResetAuthorizePasswordActivity"
android:exported="true" />
<activity
android:name=".log.FunctionCenterActivity"
android:exported="true" />
<activity
android:name=".log.LFilePickerActivity"
android:exported="true" />
</application>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
</manifest>
\ No newline at end of file
......@@ -116,30 +116,60 @@ class BaseApplication : MultiDexApplication() {
override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {
DensityUtils.setDensity(activity, this@BaseApplication)
XLog.d(DateUtils.format18(Date()) + " onActivityCreated")
if (!LogFileUtils.isProhibitWrite) {
LogFileUtils.writeLog(ContextUtils.getContext(),
"\n${DateUtils.format18(Date())}########onActivityCreated() called with: activity = [$activity]\n")
}
}
override fun onActivityStarted(activity: Activity) {
XLog.d(DateUtils.format18(Date()) + " onActivityStarted")
if (!LogFileUtils.isProhibitWrite) {
LogFileUtils.writeLog(ContextUtils.getContext(),
"\n${DateUtils.format18(Date())}########onActivityStarted() called with: activity = [$activity]\n")
}
}
override fun onActivityResumed(activity: Activity) {
XLog.d(DateUtils.format18(Date()) + " onActivityResumed")
if (!LogFileUtils.isProhibitWrite) {
LogFileUtils.writeLog(ContextUtils.getContext(),
"\n${DateUtils.format18(Date())}########onActivityResumed() called with: activity = [$activity]\n")
}
}
override fun onActivityPaused(activity: Activity) {
XLog.d(DateUtils.format18(Date()) + " onActivityPaused")
if (!LogFileUtils.isProhibitWrite) {
LogFileUtils.writeLog(ContextUtils.getContext(),
"\n${DateUtils.format18(Date())}########onActivityPaused() called with: activity = [$activity]\n")
}
}
override fun onActivityStopped(activity: Activity) {
XLog.d(DateUtils.format18(Date()) + " onActivityStopped")
if (!LogFileUtils.isProhibitWrite) {
LogFileUtils.writeLog(ContextUtils.getContext(),
"\n${DateUtils.format18(Date())}########onActivityStopped() called with: activity = [$activity]\n")
}
}
override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) {
XLog.d(DateUtils.format18(Date()) + " onActivitySaveInstanceState")
if (!LogFileUtils.isProhibitWrite) {
val memoryStatus = "\ttotalMemory:${Runtime.getRuntime().totalMemory()}\tfreeMemory:${Runtime.getRuntime().freeMemory()}"
LogFileUtils.writeLog(ContextUtils.getContext(),
"\n${DateUtils.format18(Date())}########onActivitySaveInstanceState() called with:" +
" activity = [$activity]\nmemoryStatus: $memoryStatus")
}
}
override fun onActivityDestroyed(activity: Activity) {
XLog.d(DateUtils.format18(Date()) + " onActivityDestroyed")
if (!LogFileUtils.isProhibitWrite) {
LogFileUtils.writeLog(ContextUtils.getContext(),
"\n${DateUtils.format18(Date())}########onActivityDestroyed() called with: activity = [$activity]\n")
}
}
})
}
......
package com.miya.fastcashier.log
import android.app.Dialog
import android.content.Context
import com.miya.fastcashier.R
import android.widget.TextView
import android.graphics.Bitmap
import com.miya.fastcashier.log.CustomImageCenterDialog
import android.os.Build
import android.view.WindowManager
import android.text.TextUtils
import com.miya.print.utils.QRCodeUtil
import com.blankj.utilcode.util.SizeUtils
import android.view.Gravity
import android.view.View
import android.view.Window
import android.widget.ImageView
class CustomImageCenterDialog(context: Context) : Dialog(context, R.style.CommonDialog) {
private var tvOk: TextView? = null
private var tvHint: TextView? = null
private var ivContent: ImageView? = null
private var isFullScreen = false
private var mImageContent: String? = null
private var mHintContentText: String? = null
private var mConfirmContent: String? = null
private var mQrCodeBitmap: Bitmap? = null
init {
initWindows()
setCanceledOnTouchOutside(false)
setContentView(R.layout.dialog_center_image)
setCancelable(true)
initView()
}
protected fun initWindows() {
val win = this.window
win!!.requestFeature(Window.FEATURE_NO_TITLE)
win.decorView.setPadding(0, 0, 0, 0)
val lp = win.attributes
lp.width = WindowManager.LayoutParams.MATCH_PARENT
lp.height = WindowManager.LayoutParams.MATCH_PARENT
// lp.windowAnimations = R.style.LightInAndOutStyle;
lp.gravity = Gravity.CENTER
win.attributes = lp
win.setBackgroundDrawableResource(android.R.color.transparent)
}
private fun initView() {
tvOk = findViewById(R.id.tvOk)
tvHint = findViewById(R.id.tvSubContent)
ivContent = findViewById(R.id.ivContent)
}
override fun onWindowFocusChanged(hasFocus: Boolean) {
super.onWindowFocusChanged(hasFocus)
if (isFullScreen) {
setFullScreen()
}
}
/**
* 隐藏虚拟按键,并且全屏
*/
protected fun setFullScreen() {
if (Build.VERSION.SDK_INT > 11 && Build.VERSION.SDK_INT < 19) { // lower api
val v = this.window!!.decorView
v.systemUiVisibility = View.GONE
} else if (Build.VERSION.SDK_INT >= 19) {
//for new api versions.
val decorView = window!!.decorView
val uiOptions =
(View.SYSTEM_UI_FLAG_LAYOUT_STABLE
// | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION//暂时不需要hideNavigation
// | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION // hide nav bar
or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
or View.SYSTEM_UI_FLAG_FULLSCREEN // hide status bar
or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY)
decorView.systemUiVisibility = uiOptions
window!!.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION)
}
}
/**
* 设置是否全屏显示
*
* @param isFullScreen
* @return
*/
fun setFullScreenStatus(isFullScreen: Boolean): CustomImageCenterDialog {
this.isFullScreen = isFullScreen
return this
}
fun setQrContent(msg: String?): CustomImageCenterDialog {
mImageContent = msg
return this
}
fun setConfirmContent(msg: String?): CustomImageCenterDialog {
mConfirmContent = msg
return this
}
fun setHintContent(msg: String?): CustomImageCenterDialog {
mHintContentText = msg
return this
}
/**
* 创建dialog
*
* @return
*/
fun build(): CustomImageCenterDialog {
if (!TextUtils.isEmpty(mConfirmContent)) {
tvOk!!.text = mConfirmContent
}
if (!TextUtils.isEmpty(mHintContentText)) {
tvHint!!.text = mHintContentText
}
if (!TextUtils.isEmpty(mImageContent)) {
mQrCodeBitmap = QRCodeUtil.createQRCodeBitmap(mImageContent, SizeUtils.dp2px(300f))
ivContent!!.setImageBitmap(mQrCodeBitmap)
}
tvOk!!.setOnClickListener {
if (mQrCodeBitmap != null) {
mQrCodeBitmap!!.recycle()
}
dismiss()
}
if (isFullScreen) {
setFullScreen()
}
return this
}
}
\ No newline at end of file
package com.miya.fastcashier.log;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.RecyclerView;
/**
* 作者:Leon
* 时间:2017/3/17 13:44
*/
public class EmptyRecyclerView extends RecyclerView {
private View mEmptyView;
public EmptyRecyclerView(Context context) {
super(context);
}
public EmptyRecyclerView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
public EmptyRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
/**
* 根据数据源判断是否显示空白view
*/
private void checkIfEmpty() {
if (mEmptyView != null || getAdapter() != null) {
mEmptyView.setVisibility(getAdapter().getItemCount() > 0 ? GONE : VISIBLE);
}
}
public void setmEmptyView(View mEmptyView) {
this.mEmptyView = mEmptyView;
checkIfEmpty();
}
@Override
public void setAdapter(Adapter adapter) {
Adapter adapterOld = getAdapter();
if (adapterOld != null) {
adapterOld.unregisterAdapterDataObserver(observer);
}
super.setAdapter(adapter);
if (adapter != null) {
adapter.registerAdapterDataObserver(observer);
}
}
AdapterDataObserver observer = new AdapterDataObserver() {
@Override
public void onChanged() {
super.onChanged();
checkIfEmpty();
}
};
}
package com.miya.fastcashier.log
import java.io.File
import java.util.Comparator
/**
* Created by Dimorinny on 24.10.15.
*/
class FileComparator : Comparator<File> {
override fun compare(f1: File, f2: File): Int {
if (f1 === f2) {
return 0
}
if (f1.isDirectory && f2.isFile) {
// Show directories above files
return -1
}
return if (f1.isFile && f2.isDirectory) {
// Show files below directories
1
} else f1.name.compareTo(f2.name, ignoreCase = true)
// Sort the directories alphabetically
}
}
\ No newline at end of file
package com.miya.fastcashier.log;
import java.io.File;
import java.io.FileFilter;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
/**
* Created by Dimorinny on 24.10.15.
*/
public class FileUtils {
public static List<File> getFileListByDirPath(String path, FileFilter filter) {
File directory = new File(path);
File[] files = directory.listFiles(filter);
List<File> result = new ArrayList<>();
if (files == null) {
return new ArrayList<>();
}
for (int i = 0; i < files.length; i++) {
result.add(files[i]);
}
Collections.sort(result, new FileComparator());
return result;
}
public static String cutLastSegmentOfPath(String path) {
return path.substring(0, path.lastIndexOf("/"));
}
public static String getReadableFileSize(long size) {
if (size <= 0) return "0";
final String[] units = new String[]{"B", "KB", "MB", "GB", "TB"};
int digitGroups = (int) (Math.log10(size) / Math.log10(1024));
return new DecimalFormat("#").format(size / Math.pow(1024, digitGroups)) + " " + units[digitGroups];
}
/**
* 获取文件长度
*
* @param file 文件
* @return 文件长度
*/
public static long getFileLength(final File file) {
if (!isFile(file)) return -1;
return file.length();
}
/**
* 判断是否是文件
*
* @param file 文件
* @return {@code true}: 是<br>{@code false}: 否
*/
public static boolean isFile(final File file) {
return file != null && file.exists() && file.isFile();
}
/**
* 根据地址获取当前地址下的所有目录和文件,并且排序,同时过滤掉不符合大小要求的文件
*
* @param path
* @return List<File>
*/
public static List<File> getFileList(String path, FileFilter filter, boolean isGreater, long targetSize) {
List<File> list = FileUtils.getFileListByDirPath(path, filter);
//进行过滤文件大小
Iterator iterator = list.iterator();
while (iterator.hasNext()) {
File f = (File) iterator.next();
if (f.isFile()) {
//获取当前文件大小
long size = FileUtils.getFileLength(f);
if (isGreater) {
//当前想要留下大于指定大小的文件,所以过滤掉小于指定大小的文件
if (size < targetSize) {
iterator.remove();
}
} else {
//当前想要留下小于指定大小的文件,所以过滤掉大于指定大小的文件
if (size > targetSize) {
iterator.remove();
}
}
}
}
return list;
}
}
package com.miya.fastcashier.log
import android.content.Intent
import android.os.Bundle
import android.widget.Toast
import com.miya.fastcashier.databinding.ActivityFunctionCenterBinding
import com.miya.fastcashier.ui.BaseActivity
import com.miya.fastcashier.utils.CenterToasty
import com.miya.fastcashier.utils.LogFileUtils
import com.miya.fastcashier.utils.clickWithTrigger
/**
* 功能中心
* @author zpxiang
*/
class FunctionCenterActivity : BaseActivity() {
private lateinit var viewBinding: ActivityFunctionCenterBinding
private var systemDialog: SystemParameterDialog? = null
companion object {
fun start(context: BaseActivity) {
var intent = Intent()
intent.setClass(context, FunctionCenterActivity::class.java)
context.startActivity(intent)
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
viewBinding = ActivityFunctionCenterBinding.inflate(layoutInflater)
setContentView(viewBinding.root)
viewBinding.moreOpExit.clickWithTrigger { finish() }
viewBinding.vLog.clickWithTrigger { toUploadLog() }
viewBinding.vSystem.clickWithTrigger { showSystemParamterDialog() }
}
fun toUploadLog() {
LFilePicker()
.withActivity(this)
.withStartPath(LogFileUtils.CACHE_FILE_PATH) //指定初始显示路径
.withIsGreater(true) //过滤文件大小 小于指定大小的文件
.withFileSize(0) //指定文件大小为500K
.withMutilyMode(false)
.start()
}
fun showSystemParamterDialog() {
if (null == systemDialog) {
systemDialog = SystemParameterDialog(this@FunctionCenterActivity)
}
systemDialog!!.show()
}
}
\ No newline at end of file
package com.miya.fastcashier.log
import java.io.File
import java.io.FileFilter
/**
* 作者:Leon
* 时间:2017/3/24 13:43
*/
class LFileFilter(private val mTypes: Array<String>?) : FileFilter {
override fun accept(file: File): Boolean {
if (file.isDirectory) {
return true
}
if (mTypes != null && mTypes.size > 0) {
for (i in mTypes.indices) {
if (file.name.endsWith(mTypes[i].toLowerCase()) || file.name.endsWith(mTypes[i].toUpperCase())) {
return true
}
}
} else {
return true
}
return false
}
}
\ No newline at end of file
package com.miya.fastcashier.log
import android.app.Activity
import android.app.Fragment
import android.content.Intent
import android.os.Bundle
import androidx.annotation.StyleRes
import com.miya.fastcashier.R
/**
* 作者:Leon
* 时间:2017/3/20 16:57
*/
class LFilePicker {
private var mActivity: Activity? = null
private var mFragment: Fragment? = null
private var mTitle: String? = null
private var mTitleColor: String? = null
private var theme = R.style.LFileTheme
private var mTitleStyle = R.style.LFileToolbarTextStyle
private var mBackgroundColor: String? = null
private var mBackStyle = 0
private var mRequestCode = 0
private var mMutilyMode = true
private var mChooseMode = true
private var mAddText: String? = null
private var mIconStyle = 0
private var mFileTypes: Array<String>? = null
private var mNotFoundFiles: String? = null
private var mMaxNum = 0
private var mStartPath: String? = null
private var mIsGreater = true //是否大于
private var mFileSize: Long = 0
private var mFileName: String? = null
/**
* 绑定Activity
*
* @param activity
* @return
*/
fun withActivity(activity: Activity?): LFilePicker {
mActivity = activity
return this
}
/**
* 绑定Fragment
*
* @param fragment
* @return
*/
fun withFragment(fragment: Fragment?): LFilePicker {
mFragment = fragment
return this
}
/**
* 设置主标题
*
* @param title
* @return
*/
fun withTitle(title: String?): LFilePicker {
mTitle = title
return this
}
/**
* 设置辩题颜色
*
* @param color
* @return
*/
@Deprecated("")
fun withTitleColor(color: String?): LFilePicker {
mTitleColor = color
return this
}
/**
* 设置主题
*
* @param theme
* @return
*/
fun withTheme(@StyleRes theme: Int): LFilePicker {
this.theme = theme
return this
}
/**
* 设置标题的颜色和字体大小
*
* @param style
* @return
*/
fun withTitleStyle(@StyleRes style: Int): LFilePicker {
mTitleStyle = style
return this
}
/**
* 设置背景色
*
* @param color
* @return
*/
fun withBackgroundColor(color: String?): LFilePicker {
mBackgroundColor = color
return this
}
/**
* 请求码
*
* @param requestCode
* @return
*/
fun withRequestCode(requestCode: Int): LFilePicker {
mRequestCode = requestCode
return this
}
/**
* 设置返回图标
*
* @param backStyle
* @return
*/
fun withBackIcon(backStyle: Int): LFilePicker {
mBackStyle = 0 //默认样式
mBackStyle = backStyle
return this
}
/**
* 设置选择模式,默认为true,多选;false为单选
*
* @param isMutily
* @return
*/
fun withMutilyMode(isMutily: Boolean): LFilePicker {
mMutilyMode = isMutily
return this
}
/**
* 设置多选时按钮文字
*
* @param text
* @return
*/
fun withAddText(text: String?): LFilePicker {
mAddText = text
return this
}
/**
* 设置文件夹图标风格
*
* @param style
* @return
*/
fun withIconStyle(style: Int): LFilePicker {
mIconStyle = style
return this
}
fun withFileFilter(arrs: Array<String>): LFilePicker {
mFileTypes = arrs
return this
}
/**
* 没有选中文件时的提示信息
*
* @param notFoundFiles
* @return
*/
fun withNotFoundBooks(notFoundFiles: String?): LFilePicker {
mNotFoundFiles = notFoundFiles
return this
}
/**
* 设置最大选中数量
*
* @param num
* @return
*/
fun withMaxNum(num: Int): LFilePicker {
mMaxNum = num
return this
}
/**
* 设置选择上传的文件
*
* @param fileName
* @return
*/
fun withFileName(fileName: String?): LFilePicker {
mFileName = fileName
return this
}
/**
* 设置初始显示路径
*
* @param path
* @return
*/
fun withStartPath(path: String?): LFilePicker {
mStartPath = path
return this
}
/**
* 设置选择模式,true为文件选择模式,false为文件夹选择模式,默认为true
*
* @param chooseMode
* @return
*/
fun withChooseMode(chooseMode: Boolean): LFilePicker {
mChooseMode = chooseMode
return this
}
/**
* 设置文件大小过滤方式:大于指定大小或者小于指定大小
*
* @param isGreater true:大于 ;false:小于,同时包含指定大小在内
* @return
*/
fun withIsGreater(isGreater: Boolean): LFilePicker {
mIsGreater = isGreater
return this
}
/**
* 设置过滤文件大小
*
* @param fileSize
* @return
*/
fun withFileSize(fileSize: Long): LFilePicker {
mFileSize = fileSize
return this
}
fun start() {
if (mActivity == null && mFragment == null) {
throw RuntimeException("You must pass Activity or Fragment by withActivity or withFragment or withSupportFragment method")
}
val intent = initIntent()
val bundle = bundle
intent.putExtras(bundle)
if (mActivity != null) {
mActivity!!.startActivityForResult(intent, mRequestCode)
} else {
mFragment!!.startActivityForResult(intent, mRequestCode)
}
}
private fun initIntent(): Intent {
val intent: Intent
intent = if (mActivity != null) {
Intent(mActivity, LFilePickerActivity::class.java)
} else {
Intent(mFragment!!.activity, LFilePickerActivity::class.java)
}
return intent
}
private val bundle: Bundle
private get() {
val paramEntity = ParamEntity()
paramEntity.title = mTitle
paramEntity.theme = theme
paramEntity.titleColor = mTitleColor
paramEntity.titleStyle = mTitleStyle
paramEntity.backgroundColor = mBackgroundColor
paramEntity.backIcon = mBackStyle
paramEntity.isMutilyMode = mMutilyMode
paramEntity.addText = mAddText
paramEntity.iconStyle = mIconStyle
paramEntity.fileTypes = mFileTypes
paramEntity.notFoundFiles = mNotFoundFiles
paramEntity.maxNum = mMaxNum
paramEntity.isChooseMode = mChooseMode
paramEntity.path = mStartPath
paramEntity.fileSize = mFileSize
paramEntity.fileName = mFileName
paramEntity.isGreater = mIsGreater
val bundle = Bundle()
bundle.putSerializable("param", paramEntity)
return bundle
}
}
\ No newline at end of file
package com.miya.fastcashier.log;
import android.content.Intent;
import android.graphics.Color;
import android.os.Bundle;
import android.os.Environment;
import android.text.TextUtils;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import com.blankj.utilcode.util.EncodeUtils;
import com.blankj.utilcode.util.LogUtils;
import com.blankj.utilcode.util.StringUtils;
import com.miya.fastcashier.BuildConfig;
import com.miya.fastcashier.R;
import com.miya.fastcashier.beans.SelfCashierTerminalConfig;
import com.miya.fastcashier.net.ApiConfig;
import com.miya.fastcashier.net.ApiRequest;
import com.miya.fastcashier.net.ApiService;
import com.miya.fastcashier.net.CommonCallback;
import com.miya.fastcashier.service.AccountService;
import com.miya.fastcashier.ui.BaseActivity;
import com.miya.fastcashier.utils.LogFileUtils;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import androidx.annotation.NonNull;
import androidx.appcompat.widget.Toolbar;
import androidx.recyclerview.widget.LinearLayoutManager;
import es.dmoral.toasty.Toasty;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.RequestBody;
public class LFilePickerActivity extends BaseActivity {
private final String TAG = "FilePickerLeon";
private CustomImageCenterDialog mCustomImageCenterDialog;
private EmptyRecyclerView mRecylerView;
private View mEmptyView;
private TextView mTvPath;
private TextView mTvBack;
private Button mBtnAddBook;
private String mPath;
private PathAdapter mPathAdapter;
private Toolbar mToolbar;
private ParamEntity mParamEntity;
private boolean mIsAllSelected = false;
private Menu mMenu;
private Toast successToast;
protected SelfCashierTerminalConfig selfCashierTerminalConfig;
private LFileFilter mFilter;
private List<File> mListFiles;
private ArrayList<String> mListNumbers = new ArrayList<String>();//存放选中条目的数据地址
private String mQrCodeEncodeMsg;
@Override
protected void onCreate(Bundle savedInstanceState) {
mParamEntity = (ParamEntity) getIntent().getExtras().getSerializable("param");
setTheme(mParamEntity.getTheme());
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_lfile_picker);
selfCashierTerminalConfig = AccountService.INSTANCE.getAccountInfo().transformToSelfCashierTermianlConfig();
initView();
setSupportActionBar(mToolbar);
getSupportActionBar().setHomeButtonEnabled(true);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
initToolbar();
updateAddButton();
if (!checkSDState()) {
Toast.makeText(this, R.string.lfile_NotFoundPath, Toast.LENGTH_SHORT).show();
return;
}
mPath = mParamEntity.getPath();
if (StringUtils.isEmpty(mPath)) {
//如果没有指定路径,则使用默认路径
mPath = Environment.getExternalStorageDirectory().getAbsolutePath();
}
mTvPath.setText(mPath);
mFilter = new LFileFilter(mParamEntity.getFileTypes());
mListFiles = FileUtils.getFileList(mPath, mFilter, mParamEntity.isGreater(), mParamEntity.getFileSize());
mPathAdapter = new PathAdapter(mListFiles, this, mFilter, mParamEntity.isMutilyMode(), mParamEntity.isGreater(), mParamEntity.getFileSize());
mRecylerView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false));
mPathAdapter.setmIconStyle(mParamEntity.getIconStyle());
mRecylerView.setAdapter(mPathAdapter);
mRecylerView.setmEmptyView(mEmptyView);
mCustomImageCenterDialog = new CustomImageCenterDialog(this);
initListener();
}
/**
* 更新Toolbar展示
*/
private void initToolbar() {
if (mParamEntity.getTitle() != null) {
mToolbar.setTitle(mParamEntity.getTitle());
}
if (mParamEntity.getTitleStyle() != 0) {
mToolbar.setTitleTextAppearance(this, mParamEntity.getTitleStyle());
}
if (mParamEntity.getTitleColor() != null) {
mToolbar.setTitleTextColor(Color.parseColor(mParamEntity.getTitleColor())); //设置标题颜色
}
if (mParamEntity.getBackgroundColor() != null) {
mToolbar.setBackgroundColor(Color.parseColor(mParamEntity.getBackgroundColor()));
}
mToolbar.setNavigationOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
finish();
}
});
}
private void updateAddButton() {
if (!mParamEntity.isMutilyMode()) {
mBtnAddBook.setVisibility(View.GONE);
}
if (!mParamEntity.isChooseMode()) {
mBtnAddBook.setVisibility(View.VISIBLE);
mBtnAddBook.setText(getString(R.string.lfile_OK));
//文件夹模式默认为单选模式
mParamEntity.setMutilyMode(false);
}
}
/**
* 添加点击事件处理
*/
private void initListener() {
// 返回目录上一级
mTvBack.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String tempPath = new File(mPath).getParent();
if (tempPath == null) {
return;
}
mPath = tempPath;
mListFiles = FileUtils.getFileList(mPath, mFilter, mParamEntity.isGreater(), mParamEntity.getFileSize());
mPathAdapter.setmListData(mListFiles);
mPathAdapter.updateAllSelelcted(false);
mIsAllSelected = false;
updateMenuTitle();
mBtnAddBook.setText(getString(R.string.lfile_Selected));
mRecylerView.scrollToPosition(0);
setShowPath(mPath);
//清除添加集合中数据
mListNumbers.clear();
if (mParamEntity.getAddText() != null) {
mBtnAddBook.setText(mParamEntity.getAddText());
} else {
mBtnAddBook.setText(R.string.lfile_Selected);
}
}
});
mPathAdapter.setOnItemClickListener(new PathAdapter.OnItemClickListener() {
@Override
public void click(int position) {
if (mParamEntity.isMutilyMode()) {
if (mListFiles.get(position).isDirectory()) {
//如果当前是目录,则进入继续查看目录
chekInDirectory(position);
mPathAdapter.updateAllSelelcted(false);
mIsAllSelected = false;
updateMenuTitle();
mBtnAddBook.setText(getString(R.string.lfile_Selected));
} else {
//如果已经选择则取消,否则添加进来
if (mListNumbers.contains(mListFiles.get(position).getAbsolutePath())) {
mListNumbers.remove(mListFiles.get(position).getAbsolutePath());
} else {
mListNumbers.add(mListFiles.get(position).getAbsolutePath());
}
if (mParamEntity.getAddText() != null) {
mBtnAddBook.setText(mParamEntity.getAddText() + "( " + mListNumbers.size() + " )");
} else {
mBtnAddBook.setText(getString(R.string.lfile_Selected) + "( " + mListNumbers.size() + " )");
}
//先判断是否达到最大数量,如果数量达到上限提示,否则继续添加
if (mParamEntity.getMaxNum() > 0 && mListNumbers.size() > mParamEntity.getMaxNum()) {
Toast.makeText(LFilePickerActivity.this, R.string.lfile_OutSize, Toast.LENGTH_SHORT).show();
return;
}
}
} else {
//单选模式直接返回
if (mListFiles.get(position).isDirectory()) {
chekInDirectory(position);
return;
}
if (mParamEntity.isChooseMode()) {
//选择文件模式,需要添加文件路径,否则为文件夹模式,直接返回当前路径
mListNumbers.add(mListFiles.get(position).getAbsolutePath());
chooseDone();
} else {
Toast.makeText(LFilePickerActivity.this, R.string.lfile_ChooseTip, Toast.LENGTH_SHORT).show();
}
}
}
});
mBtnAddBook.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (mParamEntity.isChooseMode() && mListNumbers.size() < 1) {
String info = mParamEntity.getNotFoundFiles();
if (TextUtils.isEmpty(info)) {
Toast.makeText(LFilePickerActivity.this, R.string.lfile_NotFoundBooks, Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(LFilePickerActivity.this, info, Toast.LENGTH_SHORT).show();
}
} else {
//返回
chooseDone();
}
}
});
}
/**
* 点击进入目录
*
* @param position
*/
private void chekInDirectory(int position) {
mPath = mListFiles.get(position).getAbsolutePath();
setShowPath(mPath);
//更新数据源
mListFiles = FileUtils.getFileList(mPath, mFilter, mParamEntity.isGreater(), mParamEntity.getFileSize());
mPathAdapter.setmListData(mListFiles);
mPathAdapter.notifyDataSetChanged();
mRecylerView.scrollToPosition(0);
}
/**
* 完成提交
*/
private void chooseDone() {
//判断是否数量符合要求
if (mParamEntity.isChooseMode()) {
if (mParamEntity.getMaxNum() > 0 && mListNumbers.size() > mParamEntity.getMaxNum()) {
Toast.makeText(LFilePickerActivity.this, R.string.lfile_OutSize, Toast.LENGTH_SHORT).show();
return;
}
}
String path = mTvPath.getText().toString().trim();
Intent intent = new Intent();
intent.putStringArrayListExtra("paths", mListNumbers);
intent.putExtra("path", path);
setResult(RESULT_OK, intent);
showProgressDialog();
uploadFile(mListNumbers.get(0));
}
public void uploadFile(String path) {
LogFileUtils.INSTANCE.setProhibitWrite(true);
String equType = getEquType();
File file = new File(path);
RequestBody requestBody = RequestBody.create(MediaType.parse(""), file);
MultipartBody.Part part = MultipartBody.Part.createFormData("logFile", file.getName(), requestBody);
String ip = ApiConfig.INSTANCE.getDataSourceIp(selfCashierTerminalConfig, equType);
if (!TextUtils.isEmpty(selfCashierTerminalConfig.getScoRuntimeConfig().getPlatformUrl())) {
ip = selfCashierTerminalConfig.getScoRuntimeConfig().getPlatformUrl()
+ ApiService.Companion.getUPLOAD_LOG_FILE();
}
LogUtils.e("ip = " + ip);
tryGenQrCodeMsg(file.getName());
ApiRequest.Companion.getInstance().uploadFile(ip, part,
new CommonCallback<String>() {
@Override
public void onSuccess(String data) {
hidProgressDialog();
LogFileUtils.INSTANCE.setProhibitWrite(false);
successToast = Toasty.success(LFilePickerActivity.this, "文件上传成功!");
successToast.show();
showQrImageIfNeeded();
}
@Override
public void onFailure(int errorType, String errorCode, String errorMessage) {
hidProgressDialog();
LogFileUtils.INSTANCE.setProhibitWrite(false);
Toasty.error(LFilePickerActivity.this, "文件上传失败!").show();
}
});
}
@NonNull
private String getEquType() {
String equType = "";
if (BuildConfig.appType.equals("weixin")) {
//微信
equType = "WECHAT_EQU";
} else if (BuildConfig.appType.equals("standard")) {
//支付宝
equType = "ALIPAY_EQU";
} else if (BuildConfig.appType.equals("mpos")) {
//mpos
equType = "MPOS_EQU";
} else if (BuildConfig.appType.equals("miya")) {
//强制进入米雅页面
equType = "";
}
return equType;
}
private void tryGenQrCodeMsg(String fileName) {
SelfCashierTerminalConfig.HuihuaConfig huihuaConfig = selfCashierTerminalConfig.getHuihuaConfig();
if (huihuaConfig != null) {
String hhMerchant = huihuaConfig.getHhMerchant();
String storeId = huihuaConfig.getStoreId();
String username = AccountService.INSTANCE.getUserName();
String qrMsg = String.format("%s/%s/%s/%s/%s", hhMerchant, storeId, username, getUploadEq(), fileName);
mQrCodeEncodeMsg = EncodeUtils.base64Encode2String(qrMsg.getBytes());
}
}
private void showQrImageIfNeeded() {
if (TextUtils.isEmpty(mQrCodeEncodeMsg)) {
return;
}
if (mCustomImageCenterDialog == null) {
mCustomImageCenterDialog = new CustomImageCenterDialog(this);
}
mCustomImageCenterDialog.setOnDismissListener(dialog -> LFilePickerActivity.this.finish());
mCustomImageCenterDialog.setFullScreenStatus(true)
.setHintContent("请将日志二维码拍照保存")
.setQrContent(mQrCodeEncodeMsg)
.build().show();
}
private String getUploadEq() {
String eq = "";
String equType = getEquType();
switch (equType) {
case "WECHAT_EQU":
eq = "w_eq";
break;
case "MPOS_EQU":
eq = "m_eq";
break;
default:
break;
}
return eq;
}
/**
* 初始化控件
*/
private void initView() {
mRecylerView = (EmptyRecyclerView) findViewById(R.id.recylerview);
mTvPath = (TextView) findViewById(R.id.tv_path);
mTvBack = (TextView) findViewById(R.id.tv_back);
mBtnAddBook = (Button) findViewById(R.id.btn_addbook);
mEmptyView = findViewById(R.id.empty_view);
mToolbar = (Toolbar) findViewById(R.id.toolbar);
if (mParamEntity.getAddText() != null) {
mBtnAddBook.setText(mParamEntity.getAddText());
}
}
/**
* 检测SD卡是否可用
*/
private boolean checkSDState() {
return Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED);
}
/**
* 显示顶部地址
*
* @param path
*/
private void setShowPath(String path) {
mTvPath.setText(path);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_main_toolbar, menu);
this.mMenu = menu;
updateOptionsMenu(menu);
return true;
}
/**
* 更新选项菜单展示,如果是单选模式,不显示全选操作
*
* @param menu
*/
private void updateOptionsMenu(Menu menu) {
mMenu.findItem(R.id.action_selecteall_cancel).setVisible(mParamEntity.isMutilyMode());
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == R.id.action_selecteall_cancel) {
//将当前目录下所有文件选中或者取消
mPathAdapter.updateAllSelelcted(!mIsAllSelected);
mIsAllSelected = !mIsAllSelected;
if (mIsAllSelected) {
for (File mListFile : mListFiles) {
//不包含再添加,避免重复添加
if (!mListFile.isDirectory() && !mListNumbers.contains(mListFile.getAbsolutePath())) {
mListNumbers.add(mListFile.getAbsolutePath());
}
if (mParamEntity.getAddText() != null) {
mBtnAddBook.setText(mParamEntity.getAddText() + "( " + mListNumbers.size() + " )");
} else {
mBtnAddBook.setText(getString(R.string.lfile_Selected) + "( " + mListNumbers.size() + " )");
}
}
} else {
mListNumbers.clear();
mBtnAddBook.setText(getString(R.string.lfile_Selected));
}
updateMenuTitle();
}
return true;
}
/**
* 更新选项菜单文字
*/
public void updateMenuTitle() {
if (mIsAllSelected) {
mMenu.getItem(0).setTitle(getString(R.string.lfile_Cancel));
} else {
mMenu.getItem(0).setTitle(getString(R.string.lfile_SelectAll));
}
}
public void showProgressDialog() {
showProgressDialog(getString(R.string.please_wait));
}
public void hidProgressDialog() {
dismissProgressDialog();
}
@Override
protected void onDestroy() {
super.onDestroy();
if (successToast != null)
successToast.cancel();
}
}
package com.miya.fastcashier.log
import java.io.Serializable
/**
* 作者:Leon
* 时间:2017/3/21 14:50
*/
class ParamEntity : Serializable {
var title: String? = null
@get:Deprecated("")
@set:Deprecated("")
var titleColor: String? = null
var titleStyle = 0
var theme = 0
var backgroundColor: String? = null
var backIcon = 0
var isMutilyMode = false
var addText: String? = null
var iconStyle = 0
var fileTypes: Array<String>? = null
var notFoundFiles: String? = null
var maxNum = 0
var isChooseMode = true
var path: String? = null
var fileSize: Long = 0
var isGreater = false
var fileName: String? = null
}
\ No newline at end of file
package com.miya.fastcashier.log;
import android.annotation.SuppressLint;
import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import com.miya.fastcashier.R;
import java.io.File;
import java.io.FileFilter;
import java.util.List;
import androidx.recyclerview.widget.RecyclerView;
/**
* 作者:Leon
* 时间:2017/3/15 15:47
*/
public class PathAdapter extends RecyclerView.Adapter<PathAdapter.PathViewHolder> {
public interface OnItemClickListener {
void click(int position);
}
public interface OnCancelChoosedListener {
void cancelChoosed(CheckBox checkBox);
}
private final String TAG = "FilePickerLeon";
private List<File> mListData;
private Context mContext;
public OnItemClickListener onItemClickListener;
private FileFilter mFileFilter;
private boolean[] mCheckedFlags;
private boolean mMutilyMode;
private int mIconStyle;
private boolean mIsGreater;
private long mFileSize;
public PathAdapter(List<File> mListData, Context mContext, FileFilter mFileFilter, boolean mMutilyMode, boolean mIsGreater, long mFileSize) {
this.mListData = mListData;
this.mContext = mContext;
this.mFileFilter = mFileFilter;
this.mMutilyMode = mMutilyMode;
this.mIsGreater = mIsGreater;
this.mFileSize = mFileSize;
mCheckedFlags = new boolean[mListData.size()];
}
@Override
public PathViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = View.inflate(mContext, R.layout.layout_lfile_list_item, null);
PathViewHolder pathViewHolder = new PathViewHolder(view);
return pathViewHolder;
}
@Override
public int getItemCount() {
return mListData.size();
}
@Override
public void onBindViewHolder(final PathViewHolder holder, @SuppressLint("RecyclerView") int position) {
final File file = mListData.get(position);
if (file.isFile()) {
updateFileIconStyle(holder.ivType);
holder.tvName.setText(file.getName());
holder.tvDetail.setText(mContext.getString(R.string.lfile_FileSize) + " " + FileUtils.getReadableFileSize(file.length()));
holder.cbChoose.setVisibility(View.VISIBLE);
} else {
updateFloaderIconStyle(holder.ivType);
holder.tvName.setText(file.getName());
//文件大小过滤
List files = FileUtils.getFileList(file.getAbsolutePath(), mFileFilter, mIsGreater, mFileSize);
if (files == null) {
holder.tvDetail.setText("0 " + mContext.getString(R.string.lfile_LItem));
} else {
holder.tvDetail.setText(files.size() + " " + mContext.getString(R.string.lfile_LItem));
}
holder.cbChoose.setVisibility(View.GONE);
}
if (!mMutilyMode) {
holder.cbChoose.setVisibility(View.GONE);
}
holder.layoutRoot.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (file.isFile()) {
holder.cbChoose.setChecked(!holder.cbChoose.isChecked());
}
onItemClickListener.click(position);
}
});
holder.cbChoose.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//同步复选框和外部布局点击的处理
onItemClickListener.click(position);
}
});
holder.cbChoose.setOnCheckedChangeListener(null);//先设置一次CheckBox的选中监听器,传入参数null
holder.cbChoose.setChecked(mCheckedFlags[position]);//用数组中的值设置CheckBox的选中状态
//再设置一次CheckBox的选中监听器,当CheckBox的选中状态发生改变时,把改变后的状态储存在数组中
holder.cbChoose.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
mCheckedFlags[position] = b;
}
});
}
private void updateFloaderIconStyle(ImageView imageView) {
// switch (mIconStyle) {
// case Constant.ICON_STYLE_BLUE:
// imageView.setBackgroundResource(R.mipmap.lfile_folder_style_blue);
// break;
// case Constant.ICON_STYLE_GREEN:
// imageView.setBackgroundResource(R.mipmap.lfile_folder_style_green);
// break;
// case Constant.ICON_STYLE_YELLOW:
// imageView.setBackgroundResource(R.mipmap.lfile_folder_style_yellow);
// break;
// }
}
private void updateFileIconStyle(ImageView imageView) {
// switch (mIconStyle) {
// case Constant.ICON_STYLE_BLUE:
// imageView.setBackgroundResource(R.mipmap.lfile_file_style_blue);
// break;
// case Constant.ICON_STYLE_GREEN:
// imageView.setBackgroundResource(R.mipmap.lfile_file_style_green);
// break;
// case Constant.ICON_STYLE_YELLOW:
// imageView.setBackgroundResource(R.mipmap.lfile_file_style_yellow);
// break;
// }
}
/**
* 设置监听器
*
* @param onItemClickListener
*/
public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
this.onItemClickListener = onItemClickListener;
}
/**
* 设置数据源
*
* @param mListData
*/
public void setmListData(List<File> mListData) {
this.mListData = mListData;
mCheckedFlags = new boolean[mListData.size()];
}
public void setmIconStyle(int mIconStyle) {
this.mIconStyle = mIconStyle;
}
/**
* 设置是否全选
*
* @param isAllSelected
*/
public void updateAllSelelcted(boolean isAllSelected) {
for (int i = 0; i < mCheckedFlags.length; i++) {
mCheckedFlags[i] = isAllSelected;
}
notifyDataSetChanged();
}
class PathViewHolder extends RecyclerView.ViewHolder {
private RelativeLayout layoutRoot;
private ImageView ivType;
private TextView tvName;
private TextView tvDetail;
private CheckBox cbChoose;
public PathViewHolder(View itemView) {
super(itemView);
ivType = (ImageView) itemView.findViewById(R.id.iv_type);
layoutRoot = (RelativeLayout) itemView.findViewById(R.id.layout_item_root);
tvName = (TextView) itemView.findViewById(R.id.tv_name);
tvDetail = (TextView) itemView.findViewById(R.id.tv_detail);
cbChoose = (CheckBox) itemView.findViewById(R.id.cb_choose);
}
}
}
package com.miya.fastcashier.log
import android.app.Dialog
import android.content.Context
import com.miya.fastcashier.service.AccountService.getAccountInfo
import com.miya.fastcashier.utils.getVersion
import com.miya.fastcashier.net.ApiConfig.baseUrl
import com.miya.fastcashier.utils.getWifyName
import com.miya.fastcashier.utils.getNetIp
import com.miya.fastcashier.R
import com.miya.fastcashier.beans.SelfCashierAccountInfo
import com.miya.fastcashier.service.AccountService
import com.miya.fastcashier.net.ApiConfig
import com.miya.print.PrinterManager
import android.widget.TextView
import com.miya.fastcashier.log.SystemParameterDialog
import android.view.WindowManager
import android.view.Gravity
import android.view.View
import com.miya.fastcashier.BuildConfig
import com.miya.fastcashier.databinding.DialogSystemParameterBinding
class SystemParameterDialog(context: Context) : Dialog(context, R.style.CommonDialog) {
private val viewBinding: DialogSystemParameterBinding
init {
viewBinding = DialogSystemParameterBinding.inflate(
layoutInflater
)
setContentView(viewBinding.root)
setCanceledOnTouchOutside(false)
setCancelable(true)
init()
}
private fun init() {
val accountInfo = getAccountInfo()
setInfo(viewBinding.tvVersion, getVersion(context))
setInfo(viewBinding.tvStoreName, accountInfo!!.shopInfo.storeName)
setInfo(viewBinding.tvStoreNum, accountInfo.shopInfo.storeId)
setInfo(viewBinding.tvMerchantNum, accountInfo.shopInfo.hhMerchant)
setInfo(viewBinding.tvPos, accountInfo.shopInfo.posId)
setInfo(viewBinding.tvCashier, accountInfo.shopInfo.operatorId)
setInfo(viewBinding.tvVersionType, "fastCashier_" + BuildConfig.appType)
setInfo(viewBinding.tvEquipment, "sunmi_v2pro")
setInfo(viewBinding.tvServerUrl, baseUrl)
setInfo(viewBinding.tvWifiName, getWifyName(context))
setInfo(viewBinding.tvNetIp, if (getNetIp(context) == null) "未知" else getNetIp(context))
setInfo(
viewBinding.tvPrintType,
if (PrinterManager.getInstance().printer == null) context.resources.getString(R.string.app_unkown) else PrinterManager.getInstance().printer.printerName
)
setInfo(viewBinding.tvChannel, BuildConfig.CHANNEL)
viewBinding.ivClose.setOnClickListener(View.OnClickListener { dismiss() })
resize()
}
private fun setInfo(view: View, info: String?) {
(view as TextView).text = info
}
/**
* 设置对话框大小
*
* @param width 宽度,传0表示走默认宽度
* @param height 高度,传0表示走默认高度
*/
fun setSize(width: Int, height: Int): SystemParameterDialog {
if (width < 0 || height < 0) {
return this
}
val layoutParams = window!!.attributes
if (width != 0 && height != 0) {
layoutParams.width = width
layoutParams.height = height
} else if (width == 0 && height != 0) {
layoutParams.height = height
} else if (width != 0 && height == 0) {
layoutParams.width = width
}
window!!.setGravity(Gravity.CENTER)
window!!.attributes = layoutParams
return this
}
private fun resize() {
this.window!!.setLayout(
WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.MATCH_PARENT
)
}
}
\ No newline at end of file
package com.miya.fastcashier.net
import android.text.TextUtils
import com.miya.fastcashier.BuildConfig
import com.miya.fastcashier.beans.SelfCashierTerminalConfig
object ApiConfig {
private const val BASE_URL = "https://hhms.miyapay.com/"
private const val BASE_URL_4_TEST = "https://hhmspre.miyapay.com/"
@JvmStatic
val baseUrl: String
get() = if (BuildConfig.ISTEST) {
BASE_URL_4_TEST
} else BASE_URL
fun getAuthorization(token: String): String {
return "bearer $token"
}
fun getDataSourceIp(
selfCashierTerminalConfig: SelfCashierTerminalConfig,
equType: String
): String? {
if (selfCashierTerminalConfig?.scoRuntimeConfig == null) {
throw RuntimeException("DataSourceIpUtils SelfCashierTerminalConfig is null")
}
val path = "${ApiService.UPLOAD_LOG_FILE}?equType=$equType"
return if (TextUtils.isEmpty(selfCashierTerminalConfig.scoRuntimeConfig.erpIp)) (baseUrl + path)
else selfCashierTerminalConfig.scoRuntimeConfig.erpIp + path
}
}
\ No newline at end of file
package com.miya.fastcashier.service
package com.miya.fastcashier.net
import android.util.Log
import com.miya.fastcashier.BaseApplication
import com.miya.fastcashier.beans.SelfCashierAccountInfo
import com.miya.fastcashier.beans.LoginRequest;
import com.miya.fastcashier.net.BaseResult
import com.miya.fastcashier.net.MiyaHttpLoggingInterceptor
import com.miya.fastcashier.utils.LogFileUtils
import okhttp3.MultipartBody
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import retrofit2.http.Body
import retrofit2.http.POST
import java.util.concurrent.TimeUnit
import javax.net.ssl.SSLSocketFactory
import javax.net.ssl.X509TrustManager
interface LoginService {
@POST("verify/auth/token")
suspend fun login(@Body loginRequestCall: LoginRequest): BaseResult<SelfCashierAccountInfo>
class ApiRequest private constructor() {
companion object {
private const val BASE_URL = "https://hhms.miyapay.com/"
private var apiService: ApiService? = null
private var sInstance: ApiRequest? = null
private var service: LoginService? = null
@Synchronized
fun getInstance(): ApiRequest {
if (null == sInstance) {
sInstance = ApiRequest()
}
return sInstance!!
}
fun getApi(): LoginService {
if (null == service) {
private fun getApiService(): ApiService {
if (null == apiService) {
val httpLoggingInterceptor =
MiyaHttpLoggingInterceptor {
Log.e("####", it)
if (!LogFileUtils.isProhibitWrite) {
LogFileUtils.writeLog(BaseApplication.getApplication(),it)
}
}.apply { level = MiyaHttpLoggingInterceptor.Level.BODY }
val socketFactory = arrayOfNulls<SSLSocketFactory>(1)
val trustManager = arrayOfNulls<X509TrustManager>(1)
SSLCertificatesInit.init(socketFactory, trustManager)
val client = OkHttpClient.Builder()
.addInterceptor(httpLoggingInterceptor)
.addInterceptor(RequestSignInterceptor())
.sslSocketFactory(socketFactory[0]!!, trustManager[0]!!)
.build()
val retrofit = Retrofit.Builder()
.baseUrl(BASE_URL)
.baseUrl(ApiConfig.baseUrl)
.client(client)
.addConverterFactory(GsonConverterFactory.create())
.build()
service = retrofit.create(LoginService::class.java)
apiService = retrofit.create(ApiService::class.java)
}
return service!!
return apiService!!
}
}
fun login(
loginRequest: LoginRequest,
commonCallback: CommonCallback<SelfCashierAccountInfo>
) {
getApiService().login(loginRequest).enqueue(commonCallback)
}
fun uploadFile(
url: String,
part: MultipartBody.Part,
commonCallback: CommonCallback<String>
) {
getApiService().uploadFile(url, part).enqueue(commonCallback)
}
}
\ No newline at end of file
package com.miya.fastcashier.net
import com.miya.fastcashier.beans.LoginRequest
import com.miya.fastcashier.beans.SelfCashierAccountInfo
import okhttp3.MultipartBody
import retrofit2.Call
import retrofit2.http.*
/**
* 请求地址配置
*/
interface ApiService {
companion object {
/**
* 登录
*/
const val LOGIN: String = "verify/auth/token"
/**
* 上传日志文件
*/
var UPLOAD_LOG_FILE: String = "verify/r-log/upload-log-file"
fun wrapUrl(suffix: String): String {
return ApiConfig.baseUrl.plus(suffix)
}
}
@POST(LOGIN)
fun login(@Body loginRequestCall: LoginRequest): Call<BaseResponse<SelfCashierAccountInfo>>
@Multipart
@POST
fun uploadFile(@Url url: String?, @Part part: MultipartBody.Part): Call<BaseResponse<String>>
}
\ No newline at end of file
package com.miya.fastcashier.net
import java.io.Serializable
/**
* 接口请求后返回的基础response
*/
data class BaseResponse<T>(val code: String, val msg: String, val data: T) : Serializable {
fun isSuccess(): Boolean {
return code.equals("200")
}
fun getError(): String {
return msg
}
}
\ No newline at end of file
package com.miya.fastcashier.net
data class BaseResult<T>(val code: String, val msg: String, val data: T)
\ No newline at end of file
package com.miya.fastcashier.net
import android.util.Log
import com.miya.fastcashier.BaseApplication.Companion.getApplication
import com.miya.fastcashier.R
import com.miya.fastcashier.utils.isNetworkConnected
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
import java.net.SocketTimeoutException
/**
* 类描述:通用请求返回
* 创建人:zpxiang
* 创建时间:
* 修改人:
* 修改时间:
*/
abstract class CommonCallback<T> : Callback<BaseResponse<T>?> {
companion object {
private const val RESPONSE_MSG_UNKNOW = "未知异常"
private const val CALLBACK_SUCCEED_CODE = "200"
}
internal interface ErrorType {
companion object {
const val ERROR_TYPE_CUSTOM = 0
const val ERROR_TYPE_HTTP = 1
const val ERROR_TYPE_EXCEPTION = 2
}
}
internal interface ResponseCode {
companion object {
val RESPONSE_CODE_FAILED: String = "-1" // 返回数据失败
val RESPONSE_CODE_NETWORK_DISCONNECT: String = "-2" // 无网络
val RESPONSE_CODE_NETWORK_TIMEOUT: String = "-3" // 超时
}
}
override fun onResponse(call: Call<BaseResponse<T>?>, response: Response<BaseResponse<T>?>) {
if (response.isSuccessful && response.body() != null) {
val responseCode = response.body()!!.code // 业务自定义Code
if (CALLBACK_SUCCEED_CODE == responseCode) {
onSuccess(response.body()!!.data)
} else {
onFailure(
ErrorType.ERROR_TYPE_CUSTOM,
responseCode,
response.body()!!.getError()
)
}
} else if (response.errorBody() != null) {
onFailure(
ErrorType.ERROR_TYPE_HTTP, response.code().toString(),
response.errorBody().toString()
)
} else {
onFailure(// 理论上不会存在此种情况
ErrorType.ERROR_TYPE_HTTP,
ResponseCode.RESPONSE_CODE_FAILED,
RESPONSE_MSG_UNKNOW
)
}
}
override fun onFailure(call: Call<BaseResponse<T>?>, t: Throwable) {
val temp = t.message
Log.e("#### HttpLog", "请求失败:$temp")
val errorMessage: String
if (!isNetworkConnected(getApplication())) {
errorMessage = getApplication().getString(R.string.common_prompt_network_error)
onFailure(
ErrorType.ERROR_TYPE_EXCEPTION,
ResponseCode.RESPONSE_CODE_NETWORK_DISCONNECT,
errorMessage
)
return
}
if (t is SocketTimeoutException) {
errorMessage = getApplication().getString(R.string.common_prompt_network_timeout)
onFailure(
ErrorType.ERROR_TYPE_EXCEPTION,
ResponseCode.RESPONSE_CODE_NETWORK_TIMEOUT,
errorMessage
)
} else {
errorMessage = getApplication().getString(R.string.common_prompt_data_error)
onFailure(
ErrorType.ERROR_TYPE_EXCEPTION,
ResponseCode.RESPONSE_CODE_FAILED,
errorMessage
)
}
}
abstract fun onSuccess(data: T)
abstract fun onFailure(errorType: Int, errorCode: String?, errorMessage: String?)
}
\ No newline at end of file
package com.miya.fastcashier.net
import com.miya.fastcashier.net.ApiConfig.getAuthorization
import com.miya.fastcashier.net.ApiService.Companion.wrapUrl
import com.miya.fastcashier.service.AccountService.getAccountInfo
import okhttp3.Interceptor
import okhttp3.Request
import okhttp3.Response
import java.io.IOException
/**
* 签名拦截器
* 添加请求头校验 AUTHORIZATION
*/
class RequestSignInterceptor : Interceptor {
companion object {
private const val AUTHORIZATION = "Authorization"
}
@Throws(IOException::class)
override fun intercept(chain: Interceptor.Chain): Response {
val original: Request = chain.request()
val requestUrl = original.url.toString()
val requestBuilder: Request.Builder = original.newBuilder()
val accountInfo = getAccountInfo()
if (accountInfo != null && accountInfo.accessToken != null) {
val loginUrl = wrapUrl(ApiService.LOGIN)
if (requestUrl != loginUrl) {
requestBuilder.addHeader(
AUTHORIZATION,
getAuthorization(accountInfo.accessToken.accessToken)
)
}
}
val request: Request = requestBuilder.build()
return chain.proceed(request)
}
}
\ No newline at end of file
package com.miya.fastcashier.net;
import java.io.IOException;
import java.io.InputStream;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
public class SSLCertificatesInit {
public static final String TLS = "TLS";
public static final String SSL = "SSL";
public static final String SSLV2 = "SSLv2";
private static final String SERVER_CERTIFICATE_TYPE = "X.509";
private static final String CLIENT_CERTIFICATE_TYPE = "BKS";
/**
* 信任所有站点
*
* @param socketFactory 输出参数,在外部创建1个SSLSocketFactory数组
* @param trustManager 输出参数,在外部创建1个X509TrustManager数组
*/
public static void init(SSLSocketFactory[] socketFactory, X509TrustManager[] trustManager) {
try {
SSLContext sslContext = SSLContext.getInstance(TLS);
trustManager[0] = new X509TrustManager() {
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[]{};
}
public void checkClientTrusted(X509Certificate[] certs, String authType) {
}
public void checkServerTrusted(X509Certificate[] certs, String authType) {
}
};
sslContext.init(null, new TrustManager[]{trustManager[0]}, new SecureRandom());
socketFactory[0] = sslContext.getSocketFactory();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (KeyManagementException e) {
e.printStackTrace();
}
}
/**
* 单向验证
*
* @param socketFactory 输出参数,在外部创建1个SSLSocketFactory数组
* @param trustManager 输出参数,在外部创建1个X509TrustManager数组
* @param in 服务器cer证书文件的InputStream对象
*/
public static void init(SSLSocketFactory[] socketFactory, X509TrustManager[] trustManager, InputStream in) {
try {
SSLContext sslContext = SSLContext.getInstance(TLS);
TrustManager[] tmArr = createTrustManagers(genServerKeyStore(in));
sslContext.init(null, tmArr, new SecureRandom());
trustManager[0] = getX509TrustManager(tmArr);
socketFactory[0] = sslContext.getSocketFactory();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (KeyManagementException e) {
e.printStackTrace();
} catch (KeyStoreException e) {
e.printStackTrace();
} catch (CertificateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
private static TrustManager[] createTrustManagers(KeyStore ks) throws KeyStoreException, NoSuchAlgorithmException {
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(ks);
return tmf.getTrustManagers();
}
private static KeyStore genServerKeyStore(InputStream in) throws KeyStoreException, CertificateException, NoSuchAlgorithmException, IOException {
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(null);
CertificateFactory cf = CertificateFactory.getInstance(SERVER_CERTIFICATE_TYPE);
keyStore.setCertificateEntry(SERVER_CERTIFICATE_TYPE, cf.generateCertificate(in));
return keyStore;
}
/**
* 双向验证
*
* @param socketFactory 输出参数,在外部创建1个SSLSocketFactory数组
* @param trustManager 输出参数,在外部创建1个X509TrustManager数组
* @param serverIn 服务器cer证书文件的InputStream对象
* @param clientIn 客户端bks证书的InputStream对象
* @param clientPwd 客户端bks证书的密码
*/
public static void getSocketFactory(SSLSocketFactory[] socketFactory, X509TrustManager[] trustManager, InputStream serverIn, InputStream clientIn, String clientPwd) {
try {
SSLContext sslContext = SSLContext.getInstance(TLS);
TrustManager[] tmArr = createTrustManagers(genServerKeyStore(serverIn));
sslContext.init(createKeyManagers(genClientKeyStore(clientIn, clientPwd), clientPwd), tmArr, new SecureRandom());
trustManager[0] = getX509TrustManager(tmArr);
socketFactory[0] = sslContext.getSocketFactory();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (KeyManagementException e) {
e.printStackTrace();
} catch (KeyStoreException e) {
e.printStackTrace();
} catch (CertificateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (UnrecoverableKeyException e) {
e.printStackTrace();
} finally {
try {
serverIn.close();
clientIn.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
private static KeyManager[] createKeyManagers(KeyStore ks, String pwd) throws KeyStoreException, NoSuchAlgorithmException, UnrecoverableKeyException {
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(ks, pwd.toCharArray());
return kmf.getKeyManagers();
}
private static KeyStore genClientKeyStore(InputStream in, String pwd) throws KeyStoreException, CertificateException, NoSuchAlgorithmException, IOException {
KeyStore ks = KeyStore.getInstance(CLIENT_CERTIFICATE_TYPE);
ks.load(in, pwd.toCharArray());
return ks;
}
private static X509TrustManager getX509TrustManager(TrustManager[] tmArr) {
for (TrustManager tm : tmArr) {
if (tm instanceof X509TrustManager) {
return (X509TrustManager) tm;
}
}
return null;
}
}
......@@ -10,14 +10,12 @@ import com.miya.fastcashier.databinding.ActivityMainBinding
import com.miya.fastcashier.service.AccountService
import com.miya.fastcashier.service.PrintService
import com.miya.fastcashier.ui.dialog.AuthorizePasswordInputDialog
import com.miya.fastcashier.utils.CenterToasty
import com.miya.fastcashier.utils.DateSelectHelper
import com.miya.fastcashier.utils.DateUtils
import com.miya.fastcashier.utils.clickWithTrigger
import com.miya.fastcashier.utils.*
import com.miya.fastcashier.utils.manage.AccountPasswordManageKit
import com.miya.fastcashier.utils.manage.LocalKeyDataMKManageKit
import com.miya.fastcashier.utils.manage.OrderRecordManageKit
import com.miya.fastcashier.viewmodel.MainViewModel
import com.miya.print.utils.PrintLogger
import java.util.*
class MainActivity : BaseActivity() {
......@@ -109,6 +107,7 @@ class MainActivity : BaseActivity() {
initData()
checkAccountPassword()
OrderRecordManageKit.clearOrderDataYeaterday()
LogFileUtils.deleteLog(LogFileUtils.DAYS_INTERVAL_LOG_DELETE)
}
private fun toRefund() {
......
......@@ -3,18 +3,27 @@ package com.miya.fastcashier.ui
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.util.Log
import android.view.Gravity
import androidx.fragment.app.FragmentManager
import com.miya.fastcashier.BaseApplication
import com.miya.fastcashier.R
import com.miya.fastcashier.databinding.ActivitySettingBinding
import com.miya.fastcashier.log.FunctionCenterActivity
import com.miya.fastcashier.ui.dialog.AuthorizePasswordInputDialog
import com.miya.fastcashier.ui.dialog.CommonDialog
import com.miya.fastcashier.utils.click
import com.miya.fastcashier.utils.clickWithTrigger
import es.dmoral.toasty.Toasty
class SettingActivity : BaseActivity() {
private lateinit var viewBinding: ActivitySettingBinding
private var alertDialog: CommonDialog? = null
private var countClick = 0
private var lastClickTime: Long = 0
companion object {
@JvmStatic
fun start(context: Context) {
......@@ -35,6 +44,58 @@ class SettingActivity : BaseActivity() {
viewBinding.llBack.clickWithTrigger { finish() }
viewBinding.vLoginOut.clickWithTrigger { loginOut() }
viewBinding.vUpdatePassword.clickWithTrigger { ResetAuthorizePasswordActivity.start(this) }
viewBinding.vFunction.click { checkBeforeEnterFunction() }
}
private fun checkBeforeEnterFunction() {
var currentTime = System.currentTimeMillis()
if (currentTime - lastClickTime > 1000 && lastClickTime != 0L){
countClick = 0
}
countClick++
lastClickTime = currentTime
// HideClickUtil.getInstance().countClick()
// .subscribeOn(Schedulers.io())
// .observeOn(AndroidSchedulers.mainThread())
// .subscribe { integer ->
// if (integer === HideClickUtil.CLICK_TWO) {
// //进入隐藏操作,弹出身份验证对话框
// if (verifyDialog != null) {
// verifyDialog.show()
// }
// } else if (integer > HideClickUtil.CLICK_ONE && integer < HideClickUtil.CLICK_TWO) {
// //吐司提示
//
// }
// }
if (countClick < 5) {
if (countClick >= 2 && countClick < 5) {
Toasty.info(
applicationContext,
getString(R.string.toast_click_again, 5 - countClick)
).show()
}
return
}
showAuthorizedDialog()
}
private fun showAuthorizedDialog() {
val FRAGMENT_TAG = "Authorize_Password"
val fm: FragmentManager = getSupportFragmentManager()
val oldFrag = fm.findFragmentByTag(FRAGMENT_TAG)
if (oldFrag != null) {
fm.beginTransaction().remove(oldFrag).commitAllowingStateLoss()
}
AuthorizePasswordInputDialog.newInstance().show(fm, FRAGMENT_TAG,object :AuthorizePasswordInputDialog.OnAuthorizedFinishListener{
override fun onAuthorizedFinished(isSucceed: Boolean) {
if (isSucceed){
FunctionCenterActivity.start(this@SettingActivity)
}
}
})
}
private fun loginOut() {
......
......@@ -8,9 +8,8 @@ import android.text.TextWatcher
import android.view.*
import android.widget.EditText
import androidx.appcompat.app.AppCompatActivity
import androidx.core.widget.doAfterTextChanged
import androidx.fragment.app.DialogFragment
import com.blankj.utilcode.util.ScreenUtils
import androidx.fragment.app.FragmentManager
import com.miya.fastcashier.databinding.DialogAuthorizePasswordInputBinding
import com.miya.fastcashier.ui.BaseActivity
import com.miya.fastcashier.ui.RefundActivity
......@@ -18,9 +17,10 @@ import com.miya.fastcashier.utils.CenterToasty
import com.miya.fastcashier.utils.dp2px
import com.miya.fastcashier.utils.manage.AccountPasswordManageKit
class AuthorizePasswordInputDialog() : DialogFragment(), View.OnClickListener {
class AuthorizePasswordInputDialog : DialogFragment(), View.OnClickListener {
private lateinit var viewBinding: DialogAuthorizePasswordInputBinding
private var callback: OnAuthorizedFinishListener? = null
companion object {
......@@ -84,7 +84,7 @@ class AuthorizePasswordInputDialog() : DialogFragment(), View.OnClickListener {
val accountPassword = AccountPasswordManageKit.get().accountPassword
if (TextUtils.isEmpty(accountPassword)) {
AccountPasswordManageKit.get().loadAccountPassword(context as AppCompatActivity,
object :AccountPasswordManageKit.AccountPasswordManageCallback{
object : AccountPasswordManageKit.AccountPasswordManageCallback {
override fun onPasswordGet(password: String?) {
password?.let { checkPasswordAndDoNext(it, inputPassword) }
}
......@@ -98,6 +98,11 @@ class AuthorizePasswordInputDialog() : DialogFragment(), View.OnClickListener {
if (!accountPassword.equals(password)) {
viewBinding.tvError.visibility = View.VISIBLE
} else {
if (null != callback){
callback!!.onAuthorizedFinished(true)
dismissAllowingStateLoss()
return
}
RefundActivity.start(context as BaseActivity)
dismissAllowingStateLoss()
}
......@@ -123,4 +128,13 @@ class AuthorizePasswordInputDialog() : DialogFragment(), View.OnClickListener {
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {}
})
}
fun show(manager: FragmentManager, tag: String?, callback: OnAuthorizedFinishListener) {
this.callback = callback
super.show(manager, tag)
}
interface OnAuthorizedFinishListener {
fun onAuthorizedFinished(isSucceed: Boolean)
}
}
\ No newline at end of file
package com.miya.fastcashier.utils
import android.content.Context
import android.content.pm.PackageInfo
import android.content.pm.PackageManager
import android.net.ConnectivityManager
import android.net.NetworkInfo
import android.net.wifi.WifiInfo
import android.net.wifi.WifiManager
import android.text.TextUtils
import java.net.Inet4Address
import java.net.NetworkInterface
import java.net.SocketException
fun isEmpty(s: String?): Boolean {
return TextUtils.isEmpty(s)
......@@ -23,3 +32,90 @@ fun dp2px(context: Context, dpValue: Float): Int {
val scale = context.resources.displayMetrics.density
return (dpValue * scale + 0.5f).toInt()
}
fun getNetIp(c: Context): String? {
val info =
(c.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager).activeNetworkInfo
if (info != null && info.isConnected) {
if (info.type == ConnectivityManager.TYPE_MOBILE) { //当前使用2G/3G/4G网络
try {
//Enumeration<NetworkInterface> en=NetworkInterface.getNetworkInterfaces();
val en = NetworkInterface.getNetworkInterfaces()
while (en.hasMoreElements()) {
val intf = en.nextElement()
val enumIpAddr = intf.inetAddresses
while (enumIpAddr.hasMoreElements()) {
val inetAddress = enumIpAddr.nextElement()
if (!inetAddress.isLoopbackAddress && inetAddress is Inet4Address) {
return inetAddress.getHostAddress()
}
}
}
} catch (e: SocketException) {
e.printStackTrace()
}
} else if (info.type == ConnectivityManager.TYPE_WIFI) { //当前使用无线网络
val wifiManager = c.getSystemService(Context.WIFI_SERVICE) as WifiManager
val wifiInfo = wifiManager.connectionInfo
return intIP2StringIP(wifiInfo.ipAddress) //得到IPV4地址
}
} else {
//当前无网络连接,请在设置中打开网络
}
return null
}
/**
* 将得到的int类型的IP转换为String类型
*
* @param ip
* @return
*/
fun intIP2StringIP(ip: Int): String? {
return (ip and 0xFF).toString() + "." +
(ip shr 8 and 0xFF) + "." +
(ip shr 16 and 0xFF) + "." +
(ip shr 24 and 0xFF)
}
/**
* 获取wifi名称(即ssid)
*
* @param c
* @return
*/
fun getWifyName(c: Context): String? {
val mWifiManager = c.getSystemService(Context.WIFI_SERVICE) as WifiManager
return mWifiManager.connectionInfo.ssid
}
fun getVersion(context: Context): String? {
val packageManager = context.packageManager
val packageInfo: PackageInfo
var version = ""
try {
packageInfo = packageManager.getPackageInfo(context.packageName, 0)
version = "${packageInfo.versionCode}_v${packageInfo.versionName}"
} catch (e: PackageManager.NameNotFoundException) {
e.printStackTrace()
}
return version
}
/**
* 判断是否有网络连接
* @param context
*/
fun isNetworkConnected(context: Context?): Boolean {
if (context != null) {
val mConnectivityManager = context
.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
val mNetworkInfo = mConnectivityManager.activeNetworkInfo
if (mNetworkInfo != null) {
return mNetworkInfo.isAvailable
}
}
return false
}
......@@ -29,6 +29,7 @@ object LogFileUtils {
File.separator +
"log" +
File.separator
val DAYS_INTERVAL_LOG_DELETE = 10 //本地log删除时间间隔
var isProhibitWrite = false //是否禁止写入文件
private var allFileBeanList //所有的文件列表
: MutableList<FileBean>? = null
......@@ -36,6 +37,7 @@ object LogFileUtils {
: MutableList<File>? = null
private const val logSuffix = ".txt"
private const val logLink = "_"
fun writeLog(c: Context, input: String): Boolean {
sExecutor.execute { writeLogToFile(c, input) }
return false
......
......@@ -8,9 +8,8 @@ import com.miya.fastcashier.R
import com.miya.fastcashier.beans.LoginFormState
import com.miya.fastcashier.beans.LoginRequest
import com.miya.fastcashier.beans.SelfCashierAccountInfo
import com.miya.fastcashier.net.BaseResult
import com.miya.fastcashier.service.LoginService
import com.miya.fastcashier.utils.manage.LocalKeyDataMKManageKit
import com.miya.fastcashier.net.ApiRequest
import com.miya.fastcashier.net.CommonCallback
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
......@@ -20,32 +19,25 @@ class LoginViewModel : ViewModel() {
val _loginForm = MutableLiveData<LoginFormState>()
val loginFormState: LiveData<LoginFormState> = _loginForm
fun login(userName: String, passWord: String) {
viewModelScope.launch(Dispatchers.IO) {
try {
val result = Result.success(
errorHandle(LoginService.getApi().login(LoginRequest(userName, passWord, "")))
)
// val balanceDate = LocalKeyDataMKManageKit.getBalanceDate()
// if (balanceDate <= 0L) {
// //todo 改成服务器时间
// LocalKeyDataMKManageKit.putBalanceDate(System.currentTimeMillis())
// }
loginLiveData.postValue(result)
} catch (e: Exception) {
loginLiveData.postValue(Result.failure(e))
}
}
}
viewModelScope.launch(Dispatchers.IO) {
//TODO 待优化
private fun <T> errorHandle(result: BaseResult<T>): T {
if (result.code != "200") {
throw RuntimeException(result.msg)
ApiRequest.getInstance().login(LoginRequest(userName, passWord, ""),
object : CommonCallback<SelfCashierAccountInfo>(){
override fun onSuccess(data: SelfCashierAccountInfo) {
loginLiveData.postValue(Result.success(data))
}
override fun onFailure(
errorType: Int,
errorCode: String?,
errorMessage: String?
) {
loginLiveData.postValue(Result.failure(RuntimeException(errorMessage)))
}
})
}
return result.data;
}
fun loginDataChanged(username: String, password: String) {
......
......@@ -3,18 +3,15 @@ package com.miya.fastcashier.viewmodel
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.miya.fastcashier.beans.LoginRequest
import com.miya.fastcashier.beans.SelfCashierAccountInfo
import com.miya.fastcashier.beans.ViewOrderStatisticsInfo
import com.miya.fastcashier.repository.PayRepository
import com.miya.fastcashier.service.AccountService
import com.miya.fastcashier.service.LoginService
import com.miya.fastcashier.service.PrintService
import com.miya.fastcashier.utils.DateUtils
import com.sdy.miya.moblie.component.pay.platform.bean.MiyaOrderRefundResponse
import kotlinx.coroutines.*
import java.lang.Exception
import java.lang.RuntimeException
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import java.util.*
import kotlin.collections.HashMap
......
......@@ -5,25 +5,16 @@ import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.alibaba.fastjson.JSON
import com.blankj.utilcode.util.LogUtils
import com.blankj.utilcode.util.NumberUtils
import com.elvishew.xlog.XLog
import com.miya.fastcashier.beans.LoginRequest
import com.miya.fastcashier.beans.SelfCashierAccountInfo
import com.miya.fastcashier.beans.ViewPayOrderData
import com.miya.fastcashier.dao.DatabaseKeeper
import com.miya.fastcashier.repository.PayRepository
import com.miya.fastcashier.service.AccountService
import com.miya.fastcashier.service.LoginService
import com.miya.fastcashier.service.PrintService
import com.miya.fastcashier.utils.DateUtils
import com.sdy.miya.moblie.component.pay.core.error.ParamInvalidException
import com.sdy.miya.moblie.component.pay.platform.bean.MiyaOrderRefundResponse
import com.sdy.miya.moblie.component.pay.platform.bean.PayServiceResponse
import kotlinx.coroutines.*
import java.lang.RuntimeException
import java.util.*
import kotlin.collections.HashMap
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
class PayViewModel : ViewModel() {
......
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Button正常状态下的背景 -->
<item android:drawable="@drawable/shape_dialog_btn_normal_bg" android:state_pressed="false" />
<!-- Button按下时的背景 -->
<item android:drawable="@drawable/shape_dialog_btn_pressed_bg" android:state_pressed="true"/>
</selector>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@color/lfile_lightgray" android:state_pressed="true" />
<item android:drawable="@color/lfile_lightgray" android:state_selected="true" />
<item android:drawable="@color/lfile_white" />
</selector>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="#FFFFFF"/>
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="12dp" />
<solid android:color="#ffe5e5e5"/>
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@color/lfile_gray" android:state_pressed="true"/>
<item android:drawable="@color/lfile_gray" android:state_selected="true"/>
<item android:drawable="@color/lfile_lightgray"/>
</selector>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@color/lfile_defaultColor" android:state_pressed="true"/>
<item android:drawable="@color/lfile_defaultColor" android:state_selected="true"/>
<item android:drawable="@color/lfile_defaultColor"/>
</selector>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="@color/commonColorPrimary">
<TextView
android:id="@+id/tv_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="功能中心"
android:textColor="@color/white"
android:textSize="40sp"
android:textStyle="bold"
android:layout_marginStart="30dp"
android:layout_marginTop="40dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<ImageView
android:id="@+id/moreOpExit"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_gravity="end"
android:scaleType="centerInside"
android:layout_marginEnd="30dp"
android:layout_marginTop="40dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:src="@mipmap/icon_function_center_close" />
<View
android:id="@+id/v_content"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintTop_toBottomOf="@id/tv_title"
app:layout_constraintStart_toStartOf="parent"
android:layout_margin="30dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:background="@drawable/shape_border_d1d1dc_solid_white_radius16"/>
<View
android:id="@+id/v_log"
android:layout_width="140dp"
android:layout_height="0dp"
android:layout_marginTop="40dp"
android:layout_marginStart="40dp"
app:layout_constraintStart_toStartOf="@id/v_content"
app:layout_constraintBottom_toBottomOf="@id/tv_upload_log"
app:layout_constraintTop_toTopOf="@id/v_content"
android:src="@mipmap/icon_function_center_log"/>
<ImageView
android:id="@+id/iv_log"
android:layout_width="100dp"
android:layout_height="100dp"
app:layout_constraintStart_toStartOf="@id/v_log"
app:layout_constraintEnd_toEndOf="@id/v_log"
app:layout_constraintTop_toTopOf="@id/v_log"
android:src="@mipmap/icon_function_center_log"/>
<TextView
android:id="@+id/tv_upload_log"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="@id/v_log"
app:layout_constraintEnd_toEndOf="@id/v_log"
android:layout_marginTop="8dp"
app:layout_constraintTop_toBottomOf="@id/iv_log"
android:text="查看日志"
android:textColor="@color/color_333333"
android:textStyle="bold"
android:textSize="26sp"/>
<View
android:id="@+id/v_system"
android:layout_width="140dp"
android:layout_height="0dp"
android:layout_marginTop="40dp"
android:layout_marginStart="40dp"
app:layout_constraintStart_toEndOf="@+id/v_log"
app:layout_constraintBottom_toBottomOf="@id/tv_system"
app:layout_constraintTop_toTopOf="@id/v_content"
android:src="@mipmap/icon_function_center_log"/>
<ImageView
android:id="@+id/iv_system"
android:layout_width="100dp"
android:layout_height="100dp"
app:layout_constraintStart_toStartOf="@id/v_system"
app:layout_constraintEnd_toEndOf="@id/v_system"
app:layout_constraintTop_toTopOf="@id/v_system"
android:src="@mipmap/icon_function_center_about_system"/>
<TextView
android:id="@+id/tv_system"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="@id/v_system"
app:layout_constraintEnd_toEndOf="@id/v_system"
android:layout_marginTop="8dp"
app:layout_constraintTop_toBottomOf="@id/iv_system"
android:text="关于系统"
android:textColor="@color/color_333333"
android:textStyle="bold"
android:textSize="26sp"/>
</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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="@color/lfile_white">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?android:attr/actionBarSize"
android:background="?attr/colorPrimary"
android:minHeight="?android:attr/actionBarSize"
app:navigationIcon="?attr/navigationIcon" />
<LinearLayout
android:id="@+id/layout_path"
android:layout_width="match_parent"
android:layout_height="44dp"
android:layout_below="@id/toolbar"
android:background="#dddddd"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
android:id="@+id/tv_path"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_marginLeft="8dp"
android:layout_weight="1"
android:ellipsize="middle"
android:gravity="left|center"
android:singleLine="true"
android:textSize="14sp" />
<TextView
android:visibility="gone"
android:id="@+id/tv_back"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="center_vertical"
android:background="@drawable/shape_lfile_back_bg"
android:clickable="true"
android:drawableLeft="@mipmap/app_icon_lfile_up"
android:drawablePadding="4dp"
android:gravity="center"
android:paddingLeft="8dp"
android:paddingRight="8dp"
android:text="@string/lfile_UpOneLevel" />
</LinearLayout>
<Button
android:id="@+id/btn_addbook"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:background="@drawable/shape_lfile_btn_bg"
android:text="@string/lfile_Selected"
android:textColor="@color/lfile_white"
android:textSize="18sp" />
<com.miya.fastcashier.log.EmptyRecyclerView
android:id="@+id/recylerview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="@id/btn_addbook"
android:layout_below="@id/layout_path" />
<include
android:id="@+id/empty_view"
layout="@layout/layout_lfile_emptyview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@id/layout_path" />
</RelativeLayout>
......@@ -120,4 +120,12 @@
android:drawableRight="@mipmap/app_icon_arrow_right_grey"
android:text="@string/app_login_out"/>
<View
android:id="@+id/v_function"
android:layout_width="80dp"
android:layout_height="80dp"
android:background="@color/color_F8F8F8"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintBottom_toBottomOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<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="#11000000">
<android.widget.LinearLayout
android:id="@+id/llDialog"
android:layout_width="600dp"
android:layout_height="wrap_content"
android:background="@drawable/shape_border_d1d1dc_solid_white_radius16"
android:orientation="vertical"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<ImageView
android:id="@+id/ivContent"
android:layout_width="match_parent"
android:layout_height="500dp"
android:layout_gravity="center_vertical"
android:layout_marginTop="75dp"
android:gravity="center_horizontal"
android:paddingLeft="60dp"
android:paddingRight="60dp"
tools:src="@tools:sample/avatars"/>
<TextView
android:id="@+id/tvSubContent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginLeft="60dp"
android:layout_marginTop="20dp"
android:layout_marginRight="60dp"
android:textColor="@color/black"
android:textSize="30sp"
android:visibility="visible"
tools:text="请将日志二维码拍照保存" />
<TextView
android:id="@+id/tvOk"
android:layout_width="match_parent"
android:layout_gravity="center"
android:padding="20dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="@drawable/selector_dialog_btn"
android:gravity="center"
android:text="保存好了"
android:textColor="@color/green"
android:textSize="40sp" />
</android.widget.LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<View
android:id="@+id/v_content"
android:layout_width="0dp"
android:layout_height="920dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_marginLeft="30dp"
android:layout_marginRight="30dp"
android:background="@drawable/shape_border_d1d1dc_solid_white_radius16" />
<TextView
android:id="@+id/tv_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="40dp"
android:text="关于系统"
android:textColor="@color/color_333333"
android:textSize="36dp"
app:layout_constraintEnd_toEndOf="@id/v_content"
app:layout_constraintStart_toStartOf="@id/v_content"
app:layout_constraintTop_toTopOf="@id/v_content" />
<ImageView
android:id="@+id/iv_close"
android:layout_width="60dp"
android:layout_height="60dp"
android:layout_marginEnd="30dp"
android:layout_marginTop="40dp"
android:padding="8dp"
android:src="@mipmap/app_icon_dialog_authoize_password_close"
app:layout_constraintEnd_toEndOf="@id/v_content"
app:layout_constraintTop_toTopOf="@id/v_content" />
<ScrollView
android:layout_width="0dp"
android:layout_height="0dp"
android:scrollbars="none"
android:layout_marginLeft="30dp"
android:layout_marginRight="30dp"
android:layout_marginTop="20dp"
android:layout_marginBottom="20dp"
app:layout_constraintBottom_toBottomOf="@id/v_content"
app:layout_constraintStart_toStartOf="@id/v_content"
app:layout_constraintEnd_toEndOf="@id/v_content"
app:layout_constraintTop_toBottomOf="@id/tv_title">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/tv_version_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="版本号"
android:textColor="@color/color_333333"
android:textSize="30sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tv_version"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="right"
android:text=""
android:textColor="@color/color_333333"
android:textSize="30sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@id/tv_version_text" />
<TextView
android:id="@+id/tv_store_name_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:text="店铺名称"
android:textColor="@color/color_333333"
android:textSize="30sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_version_text" />
<TextView
android:id="@+id/tv_store_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="right"
android:text=""
android:textColor="@color/color_333333"
android:textSize="30sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@id/tv_store_name_text" />
<TextView
android:id="@+id/tv_store_num_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:text="店铺号"
android:textColor="@color/color_333333"
android:textSize="30sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_store_name_text" />
<TextView
android:id="@+id/tv_store_num"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="right"
android:text=""
android:textColor="@color/color_333333"
android:textSize="30sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@id/tv_store_num_text" />
<TextView
android:id="@+id/tv_merchant_num_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:text="商户号"
android:textColor="@color/color_333333"
android:textSize="30sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_store_num_text" />
<TextView
android:id="@+id/tv_merchant_num"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="right"
android:text=""
android:textColor="@color/color_333333"
android:textSize="30sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@id/tv_merchant_num_text" />
<TextView
android:id="@+id/tv_pos_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:text="机具号"
android:textColor="@color/color_333333"
android:textSize="30sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_merchant_num_text" />
<TextView
android:id="@+id/tv_pos"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="right"
android:text=""
android:textColor="@color/color_333333"
android:textSize="30sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@id/tv_pos_text" />
<TextView
android:id="@+id/tv_cashier_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:text="收银员号"
android:textColor="@color/color_333333"
android:textSize="30sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_pos_text" />
<TextView
android:id="@+id/tv_cashier"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="right"
android:text=""
android:textColor="@color/color_333333"
android:textSize="30sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@id/tv_cashier_text" />
<TextView
android:id="@+id/tv_version_type_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:text="版本类型"
android:textColor="@color/color_333333"
android:textSize="30sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_cashier_text" />
<TextView
android:id="@+id/tv_version_type"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="right"
android:text=""
android:textColor="@color/color_333333"
android:textSize="30sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@id/tv_version_type_text" />
<TextView
android:id="@+id/tv_equipment_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:text="设备类型"
android:textColor="@color/color_333333"
android:textSize="30sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_version_type_text" />
<TextView
android:id="@+id/tv_equipment"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="right"
android:text=""
android:textColor="@color/color_333333"
android:textSize="30sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@id/tv_equipment_text" />
<TextView
android:id="@+id/tv_server_url_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:text="服务器地址"
android:textColor="@color/color_333333"
android:textSize="30sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_equipment_text" />
<TextView
android:id="@+id/tv_server_url"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="right"
android:text=""
android:textColor="@color/color_333333"
android:textSize="30sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@id/tv_server_url_text" />
<TextView
android:id="@+id/tv_wifi_name_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:text="wify名称"
android:textColor="@color/color_333333"
android:textSize="30sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_server_url_text" />
<TextView
android:id="@+id/tv_wifi_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="right"
android:text=""
android:textColor="@color/color_333333"
android:textSize="30sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@id/tv_wifi_name_text" />
<TextView
android:id="@+id/tv_net_ip_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:text="网络IP"
android:textColor="@color/color_333333"
android:textSize="30sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_wifi_name_text" />
<TextView
android:id="@+id/tv_net_ip"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="right"
android:text=""
android:textColor="@color/color_333333"
android:textSize="30sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@id/tv_net_ip_text" />
<TextView
android:id="@+id/tv_print_type_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:text="打印机类型"
android:textColor="@color/color_333333"
android:textSize="30sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_net_ip_text" />
<TextView
android:id="@+id/tv_print_type"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="right"
android:text=""
android:textColor="@color/color_333333"
android:textSize="30sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@id/tv_print_type_text" />
<TextView
android:id="@+id/tv_channel_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:text="品牌"
android:textColor="@color/color_333333"
android:textSize="30sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_print_type_text" />
<TextView
android:id="@+id/tv_channel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="right"
android:text=""
android:textColor="@color/color_333333"
android:textSize="30sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@id/tv_channel_text" />
</androidx.constraintlayout.widget.ConstraintLayout>
</ScrollView>
</androidx.constraintlayout.widget.ConstraintLayout>
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/lfile_white">
<ImageView
android:layout_width="120dp"
android:layout_height="120dp"
android:layout_above="@id/tv_empty"
android:layout_centerHorizontal="true"
android:background="@mipmap/lfile_emptyimg" />
<TextView
android:id="@+id/tv_empty"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:gravity="center"
android:padding="12dp"
android:text="暂无数据"
android:textColor="@color/lfile_gray"
android:textSize="18sp" />
</RelativeLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/layout_item_root"
android:layout_width="match_parent"
android:layout_height="60dp"
android:layout_marginTop="10dp"
android:background="@drawable/selector_file_item_bg"
android:clickable="true"
android:paddingLeft="12dp"
android:paddingRight="12dp">
<CheckBox
android:id="@+id/cb_choose"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:theme="@style/LFileCheckBoxTheme" />
<ImageView
android:id="@+id/iv_type"
android:layout_width="42dp"
android:layout_height="42dp"
android:layout_centerVertical="true"
android:background="@mipmap/app_icon_lfile_file_style_green" />
<LinearLayout
android:id="@+id/layout_info"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="10dp"
android:layout_toLeftOf="@id/cb_choose"
android:layout_toRightOf="@id/iv_type"
android:orientation="vertical"
android:padding="10dp">
<TextView
android:id="@+id/tv_name"
style="@style/LFile_item_text_name"
android:text="鬼吹灯" />
<TextView
android:id="@+id/tv_detail"
style="@style/LFile_item_text_detail"
android:text="类型:txt 大小:1024KB" />
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="1px"
android:layout_below="@id/layout_info"
android:layout_marginTop="6dp"
android:background="@color/lfile_lightgray" />
</RelativeLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/action_selecteall_cancel"
android:title="全选"
app:showAsAction="always"/>
</menu>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="commonColorPrimary">#FF8000</color>
<color name="colorPrimary">#111235</color>
<color name="black">#FF000000</color>
<color name="white">#FFFFFFFF</color>
......@@ -24,4 +25,12 @@
<color name="color_141C30">#141C30</color>
<color name="color_D1D1DC">#D1D1DC</color>
<color name="color_323233">#323233</color>
<color name="lfile_colorAccent">#418CE2</color>
<color name="lfile_colorPrimary">#418CE2</color>
<color name="lfile_colorPrimaryDark">#418CE2</color>
<color name="lfile_defaultColor">#418CE2</color>
<color name="lfile_gray">#cccccc</color>
<color name="lfile_lightgray">#dddddd</color>
<color name="lfile_white">#ffffff</color>
</resources>
\ No newline at end of file
<resources>
<string name="app_name">匡威收银宝</string>
<string name="common_prompt_network_error">网络异常,请检查后再试</string>
<string name="common_prompt_network_timeout">请求超时,请重试</string>
<string name="common_prompt_data_error">加载失败,请重新加载</string>
<string name="title_activity_login">LoginActivity</string>
<string name="prompt_email">Email</string>
<string name="prompt_password">Password</string>
......@@ -31,5 +35,21 @@
<string name="app_setting_confirm_password">确认密码</string>
<string name="app_confirm_update">确认修改</string>
<string name="app_confirm">确认</string>
<string name="app_unkown">未知</string>
<string name="toast_click_again">再点击%1$d次进入身份验证</string>
<!--日志上传字段-->
<string name="lfile_Cancel">取消全选</string>
<string name="lfile_ChooseTip">请选择文件夹</string>
<string name="lfile_FileSize">文件大小:</string>
<string name="lfile_LItem"></string>
<string name="lfile_NotFoundBooks">请选择需要上传的日志</string>
<string name="lfile_NotFoundPath">SD 存储卡状态不可用</string>
<string name="lfile_OK">确定</string>
<string name="lfile_OutSize">已经达到最大选择数量</string>
<string name="lfile_SelectAll">全选</string>
<string name="lfile_Selected">上传</string>
<string name="lfile_UpOneLevel">上一级</string>
<string name="please_wait">请稍候...</string>
</resources>
\ No newline at end of file
......@@ -33,4 +33,29 @@
<item name="android:backgroundDimAmount">0.7</item>
</style>
<style name="LFileToolbarTextStyle" parent="ThemeOverlay.AppCompat.Dark.ActionBar">
<item name="android:textColor">@color/lfile_white</item>
<item name="android:textSize">16sp</item>
</style>
<style name="LFile_item_text_detail">
<item name="android:layout_width">match_parent</item>
<item name="android:layout_height">0dp</item>
<item name="android:textColor">#999999</item>
<item name="android:layout_weight">1</item>
<item name="android:gravity">left</item>
<item name="android:textSize">14sp</item>
</style>
<style name="LFile_item_text_name">
<item name="android:layout_width">match_parent</item>
<item name="android:layout_height">0dp</item>
<item name="android:layout_weight">1</item>
<item name="android:maxLines">1</item>
<item name="android:ellipsize">end</item>
<item name="android:textColor">#101010</item>
<item name="android:gravity">left</item>
<item name="android:textSize">16sp</item>
</style>
</resources>
......@@ -16,4 +16,21 @@
<item name="android:statusBarColor" tools:targetApi="l">@color/green</item>
</style>
<style name="LFileTheme" parent="Theme.AppCompat.Light.NoActionBar">
<item name="colorPrimary">@color/lfile_colorPrimary</item>
<item name="colorPrimaryDark">@color/lfile_colorPrimaryDark</item>
<item name="colorAccent">@color/lfile_colorAccent</item>
<item name="homeAsUpIndicator">@mipmap/app_icon_lfile_back</item>
<item name="actionBarSize">36dp</item>
<item name="navigationIcon">@mipmap/app_icon_lfile_back</item><!--返回icon-->
<!-- 溢出菜单图标颜色-->
<item name="colorControlNormal">@android:color/white</item>
<item name="actionMenuTextColor">@android:color/white</item>
</style>
<style name="LFileCheckBoxTheme" parent="LFileTheme">
<!-- 溢出菜单图标颜色-->
<item name="colorControlNormal">@color/lfile_gray</item>
</style>
</resources>
\ No newline at end of file
# 版本历史
## tag
#### 优化版本:
-添加日志上传功能
## tag
####v2.1.4:
-统计打印、结算打印优化
## tag
####v2.1.3:
-订单查询本地数据库优化(分账户处理)
......
......@@ -22,4 +22,6 @@ android.jetifier.blacklist=miya-print
android.useDeprecatedNdk=true
#区别品牌
channel=CONVERSE
\ No newline at end of file
CHANNEL=converse
#区别环境 true:是测试环境,仅供内部人员测试使用;false:非测试包,供外部人员、渠道推广、应用商店等使用
ISTEST=false
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment