From 2ab637234cf63283f41d13b5f253d2891fee77e5 Mon Sep 17 00:00:00 2001 From: Ztiany Date: Mon, 11 Nov 2019 15:31:41 +0800 Subject: [PATCH] add TriangleView, Fix RecyclerViewDataManager, remove UpgradeChecker --- .../recycler/RecyclerDataManagerImpl.java | 2 +- .../base/utils/upgrade/ApkDownloader.java | 137 ----------- .../base/utils/upgrade/AppUpgradeChecker.kt | 228 ------------------ .../android/base/utils/upgrade/UpgradeInfo.kt | 16 -- .../base/utils/upgrade/UpgradeInteractor.kt | 35 --- .../base/utils/upgrade/UpgradeService.java | 110 --------- .../android/base/widget/shape/Direction.kt | 18 ++ .../android/base/widget/shape/TriangleView.kt | 208 ++++++++++++++++ lib_base/src/main/res/values/base_attrs.xml | 24 ++ lib_coroutines/lib_coroutines.iml | 26 ++ 10 files changed, 277 insertions(+), 527 deletions(-) delete mode 100644 lib_base/src/main/java/com/android/base/utils/upgrade/ApkDownloader.java delete mode 100644 lib_base/src/main/java/com/android/base/utils/upgrade/AppUpgradeChecker.kt delete mode 100644 lib_base/src/main/java/com/android/base/utils/upgrade/UpgradeInfo.kt delete mode 100644 lib_base/src/main/java/com/android/base/utils/upgrade/UpgradeInteractor.kt delete mode 100644 lib_base/src/main/java/com/android/base/utils/upgrade/UpgradeService.java create mode 100644 lib_base/src/main/java/com/android/base/widget/shape/Direction.kt create mode 100644 lib_base/src/main/java/com/android/base/widget/shape/TriangleView.kt create mode 100644 lib_coroutines/lib_coroutines.iml diff --git a/lib_base/src/main/java/com/android/base/adapter/recycler/RecyclerDataManagerImpl.java b/lib_base/src/main/java/com/android/base/adapter/recycler/RecyclerDataManagerImpl.java index 7654d96..38494da 100644 --- a/lib_base/src/main/java/com/android/base/adapter/recycler/RecyclerDataManagerImpl.java +++ b/lib_base/src/main/java/com/android/base/adapter/recycler/RecyclerDataManagerImpl.java @@ -110,7 +110,7 @@ final class RecyclerDataManagerImpl implements DataManager { @Override public void replace(T oldElem, T newElem) { - if (mData != null && mData.contains(newElem)) { + if (mData != null && mData.contains(oldElem)) { replaceAt(mData.indexOf(oldElem), newElem); } } diff --git a/lib_base/src/main/java/com/android/base/utils/upgrade/ApkDownloader.java b/lib_base/src/main/java/com/android/base/utils/upgrade/ApkDownloader.java deleted file mode 100644 index cc0332a..0000000 --- a/lib_base/src/main/java/com/android/base/utils/upgrade/ApkDownloader.java +++ /dev/null @@ -1,137 +0,0 @@ -package com.android.base.utils.upgrade; - -import com.android.base.utils.common.Files; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; - -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.Response; -import okhttp3.ResponseBody; - -import static com.blankj.utilcode.util.CloseUtils.closeIOQuietly; - -/** - * 下载APK - * - * @author Ztiany - * Email: 1169654504@qq.com - * Date : 2017-01-04 10:40 - */ -final class ApkDownloader { - - private String mUrl; - private String mDigitalAbstract; - private ApkDownloaderListener mApkDownloaderListener; - private File mDesFile; - private File mTempDesFile; - private static final String TEMP_MASK = "temp_%s"; - private long mNotifyTime = 0; - - - ApkDownloader(String url, String desFilePath, String digitalAbstract, ApkDownloaderListener apkDownloaderListener) { - mUrl = url; - mDigitalAbstract = digitalAbstract; - mApkDownloaderListener = apkDownloaderListener; - mDesFile = new File(desFilePath); - String name = mDesFile.getName(); - mTempDesFile = new File(mDesFile.getParent(), String.format(TEMP_MASK, name)); - } - - void start() { - OkHttpClient.Builder builder = new OkHttpClient.Builder(); - builder.interceptors().clear(); - OkHttpClient okHttpClient = builder.build(); - - Request request = new Request.Builder() - .url(mUrl) - .build(); - - ResponseBody body; - - try { - Response response = okHttpClient.newCall(request).execute(); - if (response.isSuccessful()) { - body = response.body(); - } else { - mApkDownloaderListener.onFail(new RuntimeException("网络错误")); - return; - } - } catch (IOException e) { - e.printStackTrace(); - mApkDownloaderListener.onFail(e); - return; - } - - //检查body - if (body == null) { - mApkDownloaderListener.onFail(new RuntimeException("网络错误")); - return; - } - - if (mDesFile.exists() && mDesFile.length() == body.contentLength() && AppUpgradeChecker.upgradeInteractor.checkApkFile(mDesFile, mDigitalAbstract)) { - mApkDownloaderListener.onSuccess(mDesFile); - } else { - Files.makeParentPath(mDesFile); - Files.makeParentPath(mTempDesFile); - boolean success = startDownload(body); - if (success) { - boolean renameToSuccess = mTempDesFile.renameTo(mDesFile); - if (renameToSuccess) { - if (AppUpgradeChecker.upgradeInteractor.checkApkFile(mDesFile, mDigitalAbstract)) { - mApkDownloaderListener.onSuccess(mDesFile); - } else { - mApkDownloaderListener.onFail(new RuntimeException("数字摘要对比失败")); - } - } - } - } - } - - private boolean startDownload(ResponseBody body) { - InputStream is = null; - FileOutputStream fos = null; - try { - byte[] buf = new byte[1024 * 2];//缓冲器 - int len;//每次读取的长度 - assert body != null; - final long total = body.contentLength();//总的长度 - is = body.byteStream(); - long sum = 0; - fos = new FileOutputStream(mTempDesFile); - - while ((len = is.read(buf)) != -1) { - sum += len; - fos.write(buf, 0, len); - if ((System.currentTimeMillis() - mNotifyTime) >= 300) { - mNotifyTime = System.currentTimeMillis(); - mApkDownloaderListener.onProgress(total, sum); - } - } - - mApkDownloaderListener.onProgress(total, total); - fos.flush(); - return true; - } catch (IOException e) { - e.printStackTrace(); - mApkDownloaderListener.onFail(e); - return false; - } finally { - closeIOQuietly(is, fos); - } - } - - interface ApkDownloaderListener { - - void onProgress(long total, long progress); - - void onSuccess(File desFile); - - void onFail(Exception e); - - } - -} \ No newline at end of file diff --git a/lib_base/src/main/java/com/android/base/utils/upgrade/AppUpgradeChecker.kt b/lib_base/src/main/java/com/android/base/utils/upgrade/AppUpgradeChecker.kt deleted file mode 100644 index 9630849..0000000 --- a/lib_base/src/main/java/com/android/base/utils/upgrade/AppUpgradeChecker.kt +++ /dev/null @@ -1,228 +0,0 @@ -package com.android.base.utils.upgrade - -import android.app.Activity -import android.content.BroadcastReceiver -import android.content.Context -import android.content.Intent -import android.content.IntentFilter -import androidx.lifecycle.LiveData -import androidx.lifecycle.MutableLiveData -import androidx.localbroadcastmanager.content.LocalBroadcastManager -import com.android.base.app.Sword -import com.android.base.data.State -import com.android.base.rx.observeOnUI -import com.android.base.utils.BaseUtils -import com.android.base.utils.android.XAppUtils -import com.app.base.upgrade.UpgradeInteractor -import com.blankj.utilcode.util.AppUtils -import com.blankj.utilcode.util.Utils -import timber.log.Timber -import java.io.File - -/** - * A tool for checking app upgrade. - * - * usage, when automatic check new version: - * - * ``` - * AppUpgradeChecker.checkAppUpgrade() - * ``` - * - * usage, when click to check new version: - * ``` - * if (AppUpgradeChecker.isDownloading) { - * showMessage("正在下载更新") - * return@setOnClickListener - * } - * - * AppUpgradeChecker.checkAppUpgrade(false) - * - * if (!subscribed) { - * subscribeUpgradeInfo() - * subscribed = true - * } - * ``` - */ -object AppUpgradeChecker { - - private var successOnce = false - - var isDownloading = false - private set - - val isChecking: Boolean - get() = currentState.isLoading - - private var currentState = State.noChange() - set(value) { - field = value - notifyStateChanged(value) - } - - private fun notifyStateChanged(state: State) { - innerLiveState.value = state - } - - private val innerLiveState = MutableLiveData>() - - val upgradeState: LiveData> - get() = innerLiveState - - private var resultReceiver: ResultBroadcastReceiver? = null - - private val isUpgradeServiceRunning: Boolean - get() = XAppUtils.isServiceRunning(BaseUtils.getAppContext(), UpgradeService::class.java.name) - - private lateinit var upgradeInfo: UpgradeInfo - - lateinit var upgradeInteractor: UpgradeInteractor - - fun installInteractor(upgradeInteractor: UpgradeInteractor) { - AppUpgradeChecker.upgradeInteractor = upgradeInteractor - } - - fun checkAppUpgrade(silence: Boolean = true) { - Timber.d("checkAppUpgrade-->currentState == $currentState") - /*正在检查*/ - if (currentState.isLoading) { - return - } - /*已经检查过了*/ - if (silence && successOnce) { - return - } - /*正在下载*/ - if (isUpgradeServiceRunning) { - return - } - realCheck() - } - - private fun realCheck() { - currentState = State.loading() - - upgradeInteractor.checkUpgrade() - .observeOnUI() - .subscribe( - { upgradeInfo -> - successOnce = true - processUpdateInfo(upgradeInfo) - }, - { - currentState = State.error(it) - } - ) - } - - private fun processUpdateInfo(upgradeInfo: UpgradeInfo) { - currentState = State.success(upgradeInfo) - if (upgradeInfo.isNewVersion) { - AppUpgradeChecker.upgradeInfo = upgradeInfo - safeContext { - upgradeInteractor.showUpgradeDialog(it, upgradeInfo, - onCancel = { - //do nothing - }, - onConfirm = { - doUpdate() - } - ) - } - } - } - - private fun doUpdate() { - //show loading dialog - safeContext { - upgradeInteractor.showDownloadingDialog(it, upgradeInfo.isForce) - } - //register result receiver - var receiver = resultReceiver - if (receiver == null) { - receiver = ResultBroadcastReceiver() - resultReceiver = receiver - LocalBroadcastManager.getInstance(BaseUtils.getAppContext()).registerReceiver(receiver, IntentFilter(UpgradeService.DOWNLOAD_APK_RESULT_ACTION)) - } - //start downloading - isDownloading = true - UpgradeService.start(BaseUtils.getAppContext(), upgradeInfo.downloadUrl, upgradeInfo.versionName, upgradeInfo.digitalAbstract, upgradeInfo.isForce) - } - - private class ResultBroadcastReceiver : BroadcastReceiver() { - override fun onReceive(context: Context, intent: Intent) { - if (intent.action != UpgradeService.DOWNLOAD_APK_RESULT_ACTION) { - return - } - when (intent.getIntExtra(UpgradeService.NOTIFY_TYPE_KEY, -1)) { - UpgradeService.NOTIFY_TYPE_SUCCESS -> processOnDownloadingFileSuccessful(intent) - UpgradeService.NOTIFY_TYPE_FAILED -> processOnDownloadingFileFailed() - UpgradeService.NOTIFY_TYPE_PROGRESS -> { - val total = intent.getLongExtra(UpgradeService.TOTAL_PROGRESS_KEY, 0) - val progress = intent.getLongExtra(UpgradeService.PROGRESS_KEY, 0) - upgradeInteractor.onProgress(total, progress) - } - } - } - } - - private fun processOnDownloadingFileSuccessful(intent: Intent) { - isDownloading = false - //start installing - val apkFile = intent.getSerializableExtra(UpgradeService.APK_FILE_KEY) as File - startInstall(apkFile) - //dismiss download dialog - upgradeInteractor.dismissDownloadingDialog() - // if it is force upgrade, we show a no cancelable dialog to make user have to install the new apk. - safeContext { - showInstallTipsDialog(it, apkFile) - } - } - - private fun showInstallTipsDialog(topActivity: Activity, apkFile: File) { - upgradeInteractor.showInstallTipsDialog(topActivity, upgradeInfo.isForce, - onCancel = { - currentState = State.success() - }, - onConfirm = { - startInstall(apkFile) - }) - } - - private fun processOnDownloadingFileFailed() { - isDownloading = false - upgradeInteractor.dismissDownloadingDialog() - safeContext { - showDownloadingFailedTips(it, upgradeInfo.isForce) - } - } - - private fun showDownloadingFailedTips(safeContext: Activity, isForce: Boolean) { - upgradeInteractor.showDownloadingFailed(safeContext, isForce, - onConfirm = { - doUpdate() - }, - onCancel = { - currentState = State.success() - }) - } - - private fun safeContext(onContext: (Activity) -> Unit) { - val topActivity = Sword.topActivity - if (topActivity != null) { - onContext(topActivity) - } else { - AppUtils.registerAppStatusChangedListener(this, object : Utils.OnAppStatusChangedListener { - override fun onBackground() = Unit - override fun onForeground() { - AppUtils.unregisterAppStatusChangedListener(this) - Sword.topActivity?.let { onContext(it) } - } - }) - } - } - - private fun startInstall(apkFile: File) { - upgradeInteractor.installApk(apkFile, upgradeInfo) - } - -} \ No newline at end of file diff --git a/lib_base/src/main/java/com/android/base/utils/upgrade/UpgradeInfo.kt b/lib_base/src/main/java/com/android/base/utils/upgrade/UpgradeInfo.kt deleted file mode 100644 index 6d3b953..0000000 --- a/lib_base/src/main/java/com/android/base/utils/upgrade/UpgradeInfo.kt +++ /dev/null @@ -1,16 +0,0 @@ -package com.android.base.utils.upgrade - -/** - *@author Ztiany - * Email: ztiany3@gmail.com - * Date : 2019-10-29 19:17 - */ -data class UpgradeInfo( - val isNewVersion: Boolean, - val isForce: Boolean, - val versionName: String, - val downloadUrl: String, - val description: String, - val digitalAbstract: String, - val raw: Any? -) \ No newline at end of file diff --git a/lib_base/src/main/java/com/android/base/utils/upgrade/UpgradeInteractor.kt b/lib_base/src/main/java/com/android/base/utils/upgrade/UpgradeInteractor.kt deleted file mode 100644 index 9c4d4a8..0000000 --- a/lib_base/src/main/java/com/android/base/utils/upgrade/UpgradeInteractor.kt +++ /dev/null @@ -1,35 +0,0 @@ -package com.app.base.upgrade - -import android.content.Context -import com.android.base.utils.upgrade.UpgradeInfo -import io.reactivex.Flowable -import java.io.File - -/** - *@author Ztiany - * Email: ztiany3@gmail.com - * Date : 2019-10-29 19:16 - */ -interface UpgradeInteractor { - - fun checkUpgrade(): Flowable - - fun showUpgradeDialog(context: Context, upgradeInfo: UpgradeInfo, onCancel: () -> Unit, onConfirm: () -> Unit) - - fun showInstallTipsDialog(context: Context, force: Boolean, onCancel: () -> Unit, onConfirm: () -> Unit) - - fun showDownloadingFailed(context: Context, force: Boolean, onCancel: () -> Unit, onConfirm: () -> Unit) - - fun showDownloadingDialog(context: Context, force: Boolean) - - fun dismissDownloadingDialog() - - fun onProgress(total: Long, progress: Long) - - fun installApk(file: File, upgradeInfo: UpgradeInfo) - - fun checkApkFile(apkFile: File, digitalAbstract: String): Boolean - - fun generateAppDownloadPath(versionName: String): String - -} \ No newline at end of file diff --git a/lib_base/src/main/java/com/android/base/utils/upgrade/UpgradeService.java b/lib_base/src/main/java/com/android/base/utils/upgrade/UpgradeService.java deleted file mode 100644 index f86e29c..0000000 --- a/lib_base/src/main/java/com/android/base/utils/upgrade/UpgradeService.java +++ /dev/null @@ -1,110 +0,0 @@ -package com.android.base.utils.upgrade; - - -import android.app.IntentService; -import android.content.Context; -import android.content.Intent; -import android.os.Handler; -import android.os.Looper; -import android.text.TextUtils; - -import com.android.base.utils.BaseUtils; -import com.android.base.utils.common.Strings; - -import java.io.File; - -import androidx.localbroadcastmanager.content.LocalBroadcastManager; -import timber.log.Timber; - -/** - * 下载服务,不要配置在子进程。 - */ -public class UpgradeService extends IntentService { - - static final String DOWNLOAD_APK_RESULT_ACTION = BaseUtils.getAppContext().getPackageName() + ".upgrade.result"; - - static final String IS_FORCE = "is_force"; - static final String NOTIFY_TYPE_KEY = "notify_type"; - static final String APK_FILE_KEY = "apk_path_key"; - static final String URL_KEY = "url_key"; - static final String VERSION_KEY = "version_key"; - static final String TOTAL_PROGRESS_KEY = "total_progress_key"; - static final String PROGRESS_KEY = "progress_key"; - static final String DIGITAL_ABSTRACT_KEY = "digital_abstract_key"; - - public static final int NOTIFY_TYPE_FAILED = 1; - public static final int NOTIFY_TYPE_PROGRESS = 2; - public static final int NOTIFY_TYPE_SUCCESS = 3; - - private Handler mHandler; - private boolean mIsForceUpdate; - private String mDigitalAbstract; - - private class FlagDownloaderListener implements ApkDownloader.ApkDownloaderListener { - - @Override - public void onProgress(long total, long progress) { - Timber.d("onProgress() called with: total = [" + total + "], progress = [" + progress + "]"); - mHandler.post(() -> notifyDownloadResult(NOTIFY_TYPE_PROGRESS, null, total, progress)); - } - - @Override - public void onSuccess(File desFile) { - Timber.d("onSuccess() called with: desFile = [" + desFile + "]"); - mHandler.post(() -> notifyDownloadResult(NOTIFY_TYPE_SUCCESS, desFile, 0, 0)); - } - - @Override - public void onFail(Exception e) { - Timber.d("onFail() called with: e = [" + e + "]"); - mHandler.post(() -> notifyDownloadResult(NOTIFY_TYPE_FAILED, null, 0, 0)); - } - } - - public UpgradeService() { - super("GW-UpgradeService"); - } - - public static void start(Context context, String updateUrl, String versionName, String digitalAbstract, boolean isForceUpdate) { - if (Strings.isEmpty(updateUrl) || Strings.isEmpty(versionName)) { - return; - } - Intent intent = new Intent(context, UpgradeService.class); - intent.putExtra(URL_KEY, updateUrl); - intent.putExtra(IS_FORCE, isForceUpdate); - intent.putExtra(VERSION_KEY, versionName); - intent.putExtra(DIGITAL_ABSTRACT_KEY, digitalAbstract); - context.startService(intent); - } - - @Override - protected void onHandleIntent(Intent intent) { - String url = intent.getStringExtra(URL_KEY); - String versionName = intent.getStringExtra(VERSION_KEY); - mIsForceUpdate = intent.getBooleanExtra(IS_FORCE, false); - mDigitalAbstract = intent.getStringExtra(DIGITAL_ABSTRACT_KEY); - if (!TextUtils.isEmpty(url) && !TextUtils.isEmpty(versionName)) { - new ApkDownloader(url, AppUpgradeChecker.upgradeInteractor.generateAppDownloadPath(versionName), mDigitalAbstract, new FlagDownloaderListener()).start(); - } - } - - @Override - public void onCreate() { - super.onCreate(); - mHandler = new Handler(Looper.getMainLooper()); - } - - private void notifyDownloadResult(int notifyType, File desFile, long total, long progress) { - Intent intent = new Intent(); - intent.setAction(DOWNLOAD_APK_RESULT_ACTION); - intent.putExtra(IS_FORCE, mIsForceUpdate); - intent.putExtra(NOTIFY_TYPE_KEY, notifyType); - intent.putExtra(TOTAL_PROGRESS_KEY, total); - intent.putExtra(PROGRESS_KEY, progress); - if (desFile != null) { - intent.putExtra(APK_FILE_KEY, desFile); - } - LocalBroadcastManager.getInstance(this).sendBroadcast(intent); - } - -} \ No newline at end of file diff --git a/lib_base/src/main/java/com/android/base/widget/shape/Direction.kt b/lib_base/src/main/java/com/android/base/widget/shape/Direction.kt new file mode 100644 index 0000000..f16d7b5 --- /dev/null +++ b/lib_base/src/main/java/com/android/base/widget/shape/Direction.kt @@ -0,0 +1,18 @@ +package com.android.base.widget.shape + +import androidx.annotation.IntDef +import com.android.base.widget.shape.Direction.Companion.BOTTOM +import com.android.base.widget.shape.Direction.Companion.LEFT +import com.android.base.widget.shape.Direction.Companion.RIGHT +import com.android.base.widget.shape.Direction.Companion.TOP + +@IntDef(TOP, BOTTOM, LEFT, RIGHT) +@Retention(AnnotationRetention.SOURCE) +annotation class Direction { + companion object { + const val TOP = 1 + const val BOTTOM = 2 + const val LEFT = 3 + const val RIGHT = 4 + } +} \ No newline at end of file diff --git a/lib_base/src/main/java/com/android/base/widget/shape/TriangleView.kt b/lib_base/src/main/java/com/android/base/widget/shape/TriangleView.kt new file mode 100644 index 0000000..b04f8e5 --- /dev/null +++ b/lib_base/src/main/java/com/android/base/widget/shape/TriangleView.kt @@ -0,0 +1,208 @@ +package com.android.base.widget.shape + +import android.annotation.SuppressLint +import android.content.Context +import android.graphics.Canvas +import android.graphics.Color +import android.graphics.Paint +import android.graphics.Path +import android.util.AttributeSet +import android.widget.TextView +import com.android.base.R +import com.android.base.utils.android.views.use + +/** + *@author Ztiany + * Email: ztiany3@gmail.com + * Date : 2019-01-16 10:09 + */ +class TriangleView @JvmOverloads constructor( + context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 +) : TextView(context, attrs, defStyleAttr) { + + private val mPaint: Paint = Paint(Paint.ANTI_ALIAS_FLAG) + + @Suppress var bottomColor: Int = 0 + set(value) { + field = value + invalidate() + } + + var strokeColor: Int = 0 + set(value) { + field = value + invalidate() + } + + @Suppress var triangleSolidColor: Int = 0 + set(value) { + field = value + invalidate() + } + + var strokeWidth: Float = 0F + set(value) { + field = value + invalidate() + } + + @Direction var direction: Int = 0 + set(value) { + field = value + invalidate() + } + + var trianglePercent: Float = 0F + set(value) { + field = value + invalidate() + } + + private val mTrianglePath: Path = Path() + + init { + initAttribute(context, attrs) + } + + @SuppressLint("Recycle") + private fun initAttribute(context: Context, attrs: AttributeSet?) { + context.obtainStyledAttributes(attrs, R.styleable.TriangleView).use { + strokeColor = it.getColor(R.styleable.TriangleView_tv_triangle_stroke_color, Color.BLACK) + bottomColor = it.getColor(R.styleable.TriangleView_tv_triangle_bottom_color, -10) + if (bottomColor == -10) { + bottomColor = strokeColor + } + triangleSolidColor = it.getColor(R.styleable.TriangleView_tv_triangle_solid_color, Color.TRANSPARENT) + strokeWidth = it.getDimension(R.styleable.TriangleView_tv_triangle_stroke_width, 0F) + direction = it.getInt(R.styleable.TriangleView_tv_triangle_direction, Direction.TOP) + trianglePercent = it.getFloat(R.styleable.TriangleView_tv_triangle_angle_percent, 0.5F) + } + + mPaint.strokeWidth = strokeWidth + mPaint.strokeCap = Paint.Cap.ROUND + } + + override fun onDraw(canvas: Canvas) { + super.onDraw(canvas) + if (measuredHeight <= 0 || measuredWidth <= 0) { + return + } + when (direction) { + Direction.TOP -> drawTopTriangle(canvas) + Direction.BOTTOM -> drawBottomTriangle(canvas) + Direction.LEFT -> drawLeftTriangle(canvas) + Direction.RIGHT -> drawRightTriangle(canvas) + } + } + + private fun drawLeftTriangle(canvas: Canvas) { + val trianglePoint = trianglePercent * measuredHeight + val drawingHeight = measuredHeight.toFloat() + val drawingWidth = measuredWidth.toFloat() + val haftStroke = strokeWidth * 0.5F + + //draw solid + if (needDrawSolid()) { + mTrianglePath.reset() + mTrianglePath.moveTo(drawingWidth, 0F) + mTrianglePath.lineTo(drawingWidth, drawingHeight) + mTrianglePath.lineTo(0F, trianglePoint) + mTrianglePath.close() + mPaint.style = Paint.Style.FILL + mPaint.color = triangleSolidColor + canvas.drawPath(mTrianglePath, mPaint) + } + //draw stroke + if (strokeWidth != 0F) { + mPaint.color = strokeColor + canvas.drawLine(0F, trianglePoint, drawingWidth, 0F, mPaint) + canvas.drawLine(0F, trianglePoint, drawingWidth, drawingHeight, mPaint) + mPaint.color = bottomColor + canvas.drawLine(drawingWidth - haftStroke, 0F, drawingWidth - haftStroke, drawingHeight, mPaint) + } + } + + private fun drawRightTriangle(canvas: Canvas) { + val trianglePoint = trianglePercent * measuredHeight + val drawingHeight = measuredHeight.toFloat() + val drawingWidth = measuredWidth.toFloat() + val haftStroke = strokeWidth * 0.5F + + //draw solid + if (needDrawSolid()) { + mTrianglePath.reset() + mTrianglePath.moveTo(0F, 0F) + mTrianglePath.lineTo(0F, drawingHeight) + mTrianglePath.lineTo(drawingWidth, trianglePoint) + mTrianglePath.close() + mPaint.style = Paint.Style.FILL + mPaint.color = triangleSolidColor + canvas.drawPath(mTrianglePath, mPaint) + } + //draw stroke + if (strokeWidth != 0F) { + mPaint.color = strokeColor + canvas.drawLine(0F, 0F, drawingWidth, trianglePoint, mPaint) + canvas.drawLine(drawingWidth, trianglePoint, 0F, drawingHeight, mPaint) + mPaint.color = bottomColor + canvas.drawLine(haftStroke, 0F, haftStroke, drawingHeight, mPaint) + } + } + + private fun drawBottomTriangle(canvas: Canvas) { + val trianglePoint = trianglePercent * measuredWidth + val drawingHeight = measuredHeight.toFloat() + val drawingWidth = measuredWidth.toFloat() + val haftStroke = strokeWidth * 0.5F + + //draw solid + if (needDrawSolid()) { + mTrianglePath.reset() + mTrianglePath.moveTo(0F, 0F) + mTrianglePath.lineTo(trianglePoint, drawingHeight) + mTrianglePath.lineTo(drawingWidth, 0F) + mTrianglePath.close() + mPaint.style = Paint.Style.FILL + mPaint.color = triangleSolidColor + canvas.drawPath(mTrianglePath, mPaint) + } + //draw stroke + if (strokeWidth != 0F) { + mPaint.color = strokeColor + canvas.drawLine(0F, 0F, trianglePoint, drawingHeight, mPaint) + canvas.drawLine(trianglePoint, drawingHeight, drawingWidth, 0F, mPaint) + mPaint.color = bottomColor + canvas.drawLine(0F, haftStroke, drawingWidth, haftStroke, mPaint) + } + } + + private fun drawTopTriangle(canvas: Canvas) { + val trianglePoint = trianglePercent * measuredWidth + val drawingHeight = measuredHeight.toFloat() + val drawingWidth = measuredWidth.toFloat() + val haftStroke = strokeWidth * 0.5F + + //draw solid + if (needDrawSolid()) { + mTrianglePath.reset() + mTrianglePath.moveTo(0F, drawingHeight) + mTrianglePath.lineTo(drawingWidth, drawingHeight) + mTrianglePath.lineTo(trianglePoint, 0F) + mTrianglePath.close() + mPaint.style = Paint.Style.FILL + mPaint.color = triangleSolidColor + canvas.drawPath(mTrianglePath, mPaint) + } + //draw stroke + if (strokeWidth != 0F) { + mPaint.color = strokeColor + canvas.drawLine(0F, drawingHeight, trianglePoint, 0F, mPaint) + canvas.drawLine(trianglePoint, 0F, drawingWidth, drawingHeight, mPaint) + mPaint.color = bottomColor + canvas.drawLine(drawingWidth, drawingHeight - haftStroke, 0F, drawingHeight - haftStroke, mPaint) + } + } + + private fun needDrawSolid() = triangleSolidColor != Color.TRANSPARENT + +} \ No newline at end of file diff --git a/lib_base/src/main/res/values/base_attrs.xml b/lib_base/src/main/res/values/base_attrs.xml index 5c4a4fc..cab07bc 100644 --- a/lib_base/src/main/res/values/base_attrs.xml +++ b/lib_base/src/main/res/values/base_attrs.xml @@ -82,4 +82,28 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/lib_coroutines/lib_coroutines.iml b/lib_coroutines/lib_coroutines.iml new file mode 100644 index 0000000..7bfecbc --- /dev/null +++ b/lib_coroutines/lib_coroutines.iml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file