├── .gitignore
├── README.md
├── app
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── matt
│ │ └── demo
│ │ └── ExampleInstrumentedTest.kt
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── com
│ │ │ └── matt
│ │ │ └── demo
│ │ │ ├── App.kt
│ │ │ └── MainActivity.kt
│ └── res
│ │ ├── drawable-v24
│ │ └── ic_launcher_foreground.xml
│ │ ├── drawable
│ │ └── ic_launcher_background.xml
│ │ ├── layout
│ │ └── activity_main.xml
│ │ ├── mipmap-anydpi-v26
│ │ ├── ic_launcher.xml
│ │ └── ic_launcher_round.xml
│ │ ├── mipmap-hdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-mdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xxhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xxxhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── values
│ │ ├── colors.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ │ └── xml
│ │ └── network_security_config.xml
│ └── test
│ └── java
│ └── com
│ └── matt
│ └── demo
│ └── ExampleUnitTest.kt
├── build.gradle
├── doc
└── 常用股票指标计算公式及简单应用.pdf
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── lib_common.gradle
├── lib_kt.gradle
├── mpwrapper
├── .gitignore
├── build.gradle
├── consumer-rules.pro
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── matt
│ │ └── mpwrapper
│ │ └── ExampleInstrumentedTest.kt
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── com
│ │ │ └── matt
│ │ │ └── mpwrapper
│ │ │ ├── bean
│ │ │ ├── Boll.kt
│ │ │ ├── Config.kt
│ │ │ ├── KViewBaseData.kt
│ │ │ ├── KViewConstant.java
│ │ │ ├── KViewData.kt
│ │ │ ├── Kdj.kt
│ │ │ ├── Ma.kt
│ │ │ ├── Macd.kt
│ │ │ ├── MasterData.kt
│ │ │ ├── MinorData.kt
│ │ │ ├── Price.kt
│ │ │ ├── Rsi.kt
│ │ │ ├── Vol.kt
│ │ │ └── VolData.kt
│ │ │ ├── ktx
│ │ │ ├── Any.kt
│ │ │ └── View.kt
│ │ │ ├── utils
│ │ │ ├── MathUtil.kt
│ │ │ ├── NumberUtils.kt
│ │ │ ├── ObjectUtils.java
│ │ │ ├── ScreenUtils.java
│ │ │ ├── TimeConstants.java
│ │ │ ├── TimeUtils.java
│ │ │ └── XFormatUtil.kt
│ │ │ └── view
│ │ │ ├── FinancialAlgorithm.kt
│ │ │ ├── FinancialAlgorithmConvert.kt
│ │ │ ├── KView.kt
│ │ │ ├── MasterView.kt
│ │ │ ├── MinorView.kt
│ │ │ ├── MpWrapperConfig.kt
│ │ │ ├── VolView.kt
│ │ │ ├── base
│ │ │ ├── BaseInit.kt
│ │ │ ├── BaseKView.kt
│ │ │ ├── IBaseLoadData.kt
│ │ │ ├── IChartLoadData.kt
│ │ │ └── IKLoadData.kt
│ │ │ ├── charts
│ │ │ └── BaseCombinedChart.kt
│ │ │ ├── components
│ │ │ └── MasterViewMarker.kt
│ │ │ ├── data
│ │ │ ├── BaseBarDataSet.kt
│ │ │ ├── BaseCandleDataSet.kt
│ │ │ ├── BaseCombinedData.kt
│ │ │ ├── BaseLineDataSet.kt
│ │ │ └── CombinedDataControl.kt
│ │ │ ├── delegate
│ │ │ ├── BaseKViewDelegate.kt
│ │ │ ├── DataSetDelegate.kt
│ │ │ ├── IChartViewDelegate.kt
│ │ │ ├── MasterViewDelegate.kt
│ │ │ ├── MinorViewDelegate.kt
│ │ │ └── VolViewDelegate.kt
│ │ │ ├── listener
│ │ │ ├── BaseBarLineChartTouchListener.kt
│ │ │ └── LinkChartListener.kt
│ │ │ ├── renderer
│ │ │ ├── BaseCombinedChartRenderer.kt
│ │ │ ├── BaseLegendRenderer.kt
│ │ │ ├── BaseLineChartRenderer.kt
│ │ │ ├── MasterViewCandleStickChartRenderer.kt
│ │ │ └── MasterViewYAxisRenderer.kt
│ │ │ └── type
│ │ │ ├── BollType.kt
│ │ │ ├── KType.java
│ │ │ ├── KdjType.kt
│ │ │ ├── MaType.kt
│ │ │ ├── MacdType.kt
│ │ │ ├── MasterIndicatorType.kt
│ │ │ ├── MasterViewType.kt
│ │ │ ├── MinorIndicatorType.kt
│ │ │ ├── RsiType.kt
│ │ │ ├── VolIndicatorType.kt
│ │ │ └── VolType.kt
│ └── res
│ │ ├── drawable
│ │ ├── shape_gradient_filled.xml
│ │ └── shape_markerview_bg.xml
│ │ ├── layout
│ │ ├── markerview_k_view_shell.xml
│ │ └── mp_widget_kview.xml
│ │ └── values
│ │ ├── colors.xml
│ │ └── strings.xml
│ └── test
│ └── java
│ └── com
│ └── matt
│ └── mpwrapper
│ ├── ExampleUnitTest.kt
│ ├── utils
│ └── MathUtilTest.kt
│ └── view
│ └── FinancialAlgorithmTest.kt
├── sample_base
├── .gitignore
├── build.gradle
├── consumer-rules.pro
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── matt
│ │ └── sample_base
│ │ └── ExampleInstrumentedTest.kt
│ ├── main
│ ├── AndroidManifest.xml
│ └── java
│ │ └── com
│ │ └── matt
│ │ └── sample_base
│ │ └── SampleBaseInit.kt
│ └── test
│ └── java
│ └── com
│ └── matt
│ └── sample_base
│ └── ExampleUnitTest.kt
├── sample_binance
├── .gitignore
├── README.md
├── build.gradle
├── consumer-rules.pro
├── proguard-rules.pro
├── screenshots
│ ├── bin_竖屏_分时.png
│ ├── bin_竖屏_蜡烛图.png
│ ├── origin_bin_landscape.png
│ ├── origin_bin_portrait.png
│ ├── origin_bin_portrait_ktype.png
│ └── wrapper_bin_portrait_master_vol_minor.png
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── example
│ │ └── sample_binance
│ │ └── ExampleInstrumentedTest.kt
│ ├── main
│ ├── AndroidManifest.xml
│ ├── assets
│ │ └── exchangeInfo.json
│ ├── java
│ │ └── com
│ │ │ └── example
│ │ │ └── sample_binance
│ │ │ ├── SampleBinanceInit.kt
│ │ │ ├── model
│ │ │ ├── api
│ │ │ │ ├── Api24Hr.java
│ │ │ │ ├── ApiPriceFilter.java
│ │ │ │ ├── ApiSymbol.java
│ │ │ │ └── ApiSymbolWrapper.java
│ │ │ ├── kview
│ │ │ │ └── BinKType.kt
│ │ │ └── ws
│ │ │ │ ├── WsBase.java
│ │ │ │ ├── WsData.java
│ │ │ │ ├── WsLatestKLinWrapper.java
│ │ │ │ ├── WsLatestKLine.java
│ │ │ │ ├── WsReqBase.kt
│ │ │ │ └── WsSimpleTicker.java
│ │ │ ├── repository
│ │ │ ├── memory
│ │ │ │ └── GlobalCache.kt
│ │ │ ├── net
│ │ │ │ ├── BinObserver.kt
│ │ │ │ ├── BinanceRetrofitBuilder.kt
│ │ │ │ ├── BinanceServiceWrapper.kt
│ │ │ │ └── service
│ │ │ │ │ └── BinanceService.kt
│ │ │ ├── sp
│ │ │ │ └── BinSpHelper.kt
│ │ │ └── ws
│ │ │ │ ├── BinWs.kt
│ │ │ │ ├── BinWsApi.kt
│ │ │ │ ├── BinWsImpl.kt
│ │ │ │ └── BinWsListener.kt
│ │ │ └── ui
│ │ │ ├── activity
│ │ │ ├── BinChartActivity.kt
│ │ │ └── BinListActivity.kt
│ │ │ ├── fragment
│ │ │ ├── BinChartFragment.kt
│ │ │ └── BinListFragment.kt
│ │ │ ├── pop
│ │ │ ├── IndicatorPop.kt
│ │ │ └── KViewTypePop.kt
│ │ │ └── viewmodel
│ │ │ └── BinViewModel.kt
│ └── res
│ │ ├── drawable-xhdpi
│ │ ├── ic_markets_indicator_default.png
│ │ ├── ic_markets_indicator_disable.png
│ │ ├── ic_markets_reset_active.png
│ │ ├── ic_markets_reset_disable.png
│ │ ├── ic_triangle_down.png
│ │ └── ic_triangle_up.png
│ │ ├── drawable-xxhdpi
│ │ ├── ic_markets_indicator_default.png
│ │ ├── ic_markets_indicator_disable.png
│ │ ├── ic_markets_reset_active.png
│ │ └── ic_markets_reset_disable.png
│ │ ├── layout
│ │ ├── bin_activity_bin_chart.xml
│ │ ├── bin_activity_bin_list.xml
│ │ ├── bin_fragment_bin_list.xml
│ │ ├── bin_fragment_chart.xml
│ │ ├── bin_item_fragment_bin_list.xml
│ │ ├── bin_item_pop_kview_type.xml
│ │ ├── bin_pop_indicator.xml
│ │ └── bin_pop_kview_type.xml
│ │ └── values
│ │ ├── colors.xml
│ │ └── strings.xml
│ └── test
│ └── java
│ └── com
│ └── example
│ └── sample_binance
│ └── ExampleUnitTest.kt
├── sample_zm
├── .gitignore
├── build.gradle
├── consumer-rules.pro
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── matt
│ │ └── sample_zm
│ │ └── ExampleInstrumentedTest.kt
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── com
│ │ │ └── matt
│ │ │ └── sample_zm
│ │ │ ├── bean
│ │ │ ├── ApiData.java
│ │ │ ├── ApiProduct.java
│ │ │ └── ApiQuote.java
│ │ │ ├── config
│ │ │ └── GlobalConfig.kt
│ │ │ ├── net
│ │ │ ├── MarketRetrofitBuilder.kt
│ │ │ ├── MarketService.java
│ │ │ ├── ServiceWrapper.kt
│ │ │ ├── TradeRetrofitBuilder.kt
│ │ │ ├── TradeService.java
│ │ │ └── base
│ │ │ │ └── SimpleTObserver.kt
│ │ │ ├── ui
│ │ │ ├── activity
│ │ │ │ ├── ChartActivity.kt
│ │ │ │ └── SymbolListActivity.kt
│ │ │ └── fragment
│ │ │ │ ├── ChartContainerFragment.kt
│ │ │ │ └── ChartFragment.kt
│ │ │ └── vm
│ │ │ ├── BaseViewModel.kt
│ │ │ └── ChartViewModel.kt
│ └── res
│ │ ├── layout
│ │ ├── zm_activity_chart.xml
│ │ ├── zm_activity_symbol_list.xml
│ │ ├── zm_fragment_chart.xml
│ │ ├── zm_fragment_chart_container.xml
│ │ └── zm_item_activity_symbol_list.xml
│ │ └── values
│ │ ├── colors.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ └── test
│ └── java
│ └── com
│ └── matt
│ └── sample_zm
│ └── ExampleUnitTest.kt
├── screenshots
├── kview_竖屏_高亮线.png
└── kview_竖屏_默认.png
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | ## 系统默认生成
2 | *.iml
3 | .gradle
4 | /local.properties
5 | /.idea/*
6 | .DS_Store
7 | /build
8 | /captures
9 | .externalNativeBuild
10 |
11 |
12 | #### https://github.com/github/gitignore/blob/master/Android.gitignore
13 | # Built application files
14 | *.apk
15 | *.ap_
16 | *.aab
17 |
18 | # Files for the ART/Dalvik VM
19 | *.dex
20 |
21 | # Java class files
22 | *.class
23 |
24 | # Generated files
25 | bin/
26 | gen/
27 | out/
28 | release/
29 |
30 | # Gradle files
31 | .gradle/
32 | build/
33 |
34 | # Local configuration file (sdk path, etc)
35 | local.properties
36 |
37 | # Proguard folder generated by Eclipse
38 | proguard/
39 |
40 | # Log Files
41 | *.log
42 |
43 | # Android Studio Navigation editor temp files
44 | .navigation/
45 |
46 | # Android Studio captures folder
47 | captures/
48 |
49 | # IntelliJ
50 | .idea/
51 |
52 | # Keystore files
53 | # Uncomment the following lines if you do not want to check your keystore files in.
54 | #*.jks
55 | #*.keystore
56 |
57 | # Google Services (e.g. APIs or Firebase)
58 | # google-services.json
59 |
60 | # Freeline
61 | freeline.py
62 | freeline/
63 | freeline_project_description.json
64 |
65 | # fastlane
66 | fastlane/report.xml
67 | fastlane/Preview.html
68 | fastlane/screenshots
69 | fastlane/test_output
70 | fastlane/readme.md
71 |
72 | # Version control
73 | vcs.xml
74 |
75 | # lint
76 | lint/intermediates/
77 | lint/generated/
78 | lint/outputs/
79 | lint/tmp/
80 | # lint/reports/
81 |
82 | # note
83 | # .ignore不起作用解决方案
84 | # git rm -r --cached .
85 | # git add .
86 | # git commit -m "update .ignore"
87 |
88 | #### 个性化设置
89 | ## app
90 | app/proguardMapping.txt
91 | app/release
92 | app/bugly
93 | app/debug/*
94 | ## 正式签名不能上传,保证应用安全
95 | app/sign/etrade_key.jks
96 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## MPAndroidChartWrapper
2 | [MPAndroidChartWrapper](https://github.com/scsfwgy/MPAndroidChartWrapper),高度封装[MPAndroidChart](https://github.com/PhilJay/MPAndroidChart),提供开箱即用的MPAndroidChart。两大原则:1.不修改MPAndroidChart源码,只继承封装原有功能实现扩展。2. 开箱即用。
3 |
4 |
5 | ##DEMO
6 | 1. 币安 注意:目前该Demo必须**科学上网**才能看
7 |
8 | ## 已完成
9 | 1. 主图、副图整体功能
10 | 2. 主图:分时图、蜡烛图、ma、boll
11 | 3. 副图:macd、rsi、kdj
12 | 4. 主副图指标长按和非长按对应的处理
13 | 4. 主副图联动、点击切换主图、副图指标
14 |
15 | ## TODO
16 | 1. 校验指标算法是否正确;指标算法支持单独算指定个数,而非全部遍历。
17 | 2. 量图相关绘制【ok】
18 | 3. 数据加载更多、ws接入【todo:加载更多,ws接入ok】
19 | 4. 接入火币或者币安开源数据源【币安 Demo ok】
20 | 5. demo样式按照火币或者币安样式绘制,保证一致性。
21 |
22 | ## 效果图
23 | 
24 | 
25 | 
26 | 
27 | 
28 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 | apply from: rootProject.file('lib_common.gradle')
3 |
4 | android {
5 | defaultConfig {
6 | applicationId "com.matt.demo"
7 | versionCode 1
8 | versionName "1.0"
9 | }
10 | }
11 |
12 | dependencies {
13 | api project(path: ':sample_binance')
14 | api project(path: ':sample_zm')
15 | }
16 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/matt/demo/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package com.matt.demo
2 |
3 | import androidx.test.ext.junit.runners.AndroidJUnit4
4 | import androidx.test.platform.app.InstrumentationRegistry
5 | import org.junit.Assert.assertEquals
6 | import org.junit.Test
7 | import org.junit.runner.RunWith
8 |
9 | /**
10 | * Instrumented test, which will execute on an Android device.
11 | *
12 | * See [testing documentation](http://d.android.com/tools/testing).
13 | */
14 | @RunWith(AndroidJUnit4::class)
15 | class ExampleInstrumentedTest {
16 | @Test
17 | fun useAppContext() {
18 | // Context of the app under test.
19 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext
20 | assertEquals("com.matt.demo", appContext.packageName)
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/app/src/main/java/com/matt/demo/App.kt:
--------------------------------------------------------------------------------
1 | package com.matt.demo
2 |
3 | import android.app.Application
4 | import com.blankj.utilcode.util.Utils
5 | import com.example.sample_binance.SampleBinanceInit
6 |
7 | /**
8 | * ============================================================
9 | * 作 者 : matt
10 | * 更新时间 :2020/03/07 10:34
11 | * 描 述 :
12 | * ============================================================
13 | */
14 | class App : Application() {
15 | override fun onCreate() {
16 | super.onCreate()
17 | Utils.init(this)
18 | SampleBinanceInit.init(this)
19 | }
20 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/matt/demo/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package com.matt.demo
2 |
3 | import android.os.Bundle
4 | import android.view.View
5 | import com.example.sample_binance.ui.activity.BinListActivity
6 | import com.matt.libwrapper.ui.base.HandleExceptionActivity
7 | import com.matt.libwrapper.ui.base.template.Template
8 | import com.matt.libwrapper.ui.base.template.TemplateBarActivity
9 | import com.matt.sample_zm.ui.activity.SymbolListActivity
10 | import kotlinx.android.synthetic.main.activity_main.*
11 |
12 | class MainActivity : TemplateBarActivity() {
13 |
14 | private fun initListener() {
15 | am_b_kview.setOnClickListener {
16 | SymbolListActivity.goIntent(mContext)
17 | }
18 | am_b_bin.setOnClickListener {
19 | BinListActivity.goIntent(mContext)
20 | }
21 | }
22 |
23 | override fun templateType(): Int {
24 | return Template.TEMPLATETYPE_DEFVIEW
25 | }
26 |
27 | override fun addChildrenView(): Any {
28 | return R.layout.activity_main
29 | }
30 |
31 | override fun renderTitle(): Any {
32 | return "MPAndroidChartWrapper Demo"
33 | }
34 |
35 | override fun onCatchCreate(savedInstanceState: Bundle?) {
36 | super.onCatchCreate(savedInstanceState)
37 | initView()
38 | initListener()
39 |
40 | }
41 |
42 | private fun initView() {
43 | getLeftImageView().visibility = View.INVISIBLE
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
15 |
18 |
21 |
22 |
23 |
24 |
30 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
15 |
16 |
21 |
22 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/scsfwgy/MPAndroidChartWrapper/a074ff292811a2b6307b150d6bdbd8ef7fcdbea1/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/scsfwgy/MPAndroidChartWrapper/a074ff292811a2b6307b150d6bdbd8ef7fcdbea1/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/scsfwgy/MPAndroidChartWrapper/a074ff292811a2b6307b150d6bdbd8ef7fcdbea1/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/scsfwgy/MPAndroidChartWrapper/a074ff292811a2b6307b150d6bdbd8ef7fcdbea1/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/scsfwgy/MPAndroidChartWrapper/a074ff292811a2b6307b150d6bdbd8ef7fcdbea1/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/scsfwgy/MPAndroidChartWrapper/a074ff292811a2b6307b150d6bdbd8ef7fcdbea1/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/scsfwgy/MPAndroidChartWrapper/a074ff292811a2b6307b150d6bdbd8ef7fcdbea1/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/scsfwgy/MPAndroidChartWrapper/a074ff292811a2b6307b150d6bdbd8ef7fcdbea1/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/scsfwgy/MPAndroidChartWrapper/a074ff292811a2b6307b150d6bdbd8ef7fcdbea1/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/scsfwgy/MPAndroidChartWrapper/a074ff292811a2b6307b150d6bdbd8ef7fcdbea1/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #6200EE
4 | #3700B3
5 | #03DAC5
6 |
7 |
8 | #4281ff
9 |
10 | #292c33
11 |
12 | #596580
13 |
14 | #a3afcc
15 |
16 | #b2b2b2
17 |
18 |
19 | #ebf2ff
20 |
21 |
22 | #ffffff
23 | #fbfbfb
24 | #b2b2b2
25 | #b2b2b2
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | MPAndroidChartWrapper
3 |
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/network_security_config.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 | android.bugly.qq.com
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/app/src/test/java/com/matt/demo/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package com.matt.demo
2 |
3 | import org.junit.Assert.assertEquals
4 | import org.junit.Test
5 |
6 | /**
7 | * Example local unit test, which will execute on the development machine (host).
8 | *
9 | * See [testing documentation](http://d.android.com/tools/testing).
10 | */
11 | class ExampleUnitTest {
12 | @Test
13 | fun addition_isCorrect() {
14 | assertEquals(4, 2 + 2)
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | ext {
5 | compileSdkVersion = 29
6 | minSdkVersion = 21
7 | targetSdkVersion = 29
8 | junitVersion = '4.12'
9 | kotlin_version = '1.3.72'
10 | }
11 | repositories {
12 | google()
13 | jcenter()
14 |
15 | }
16 | dependencies {
17 | classpath 'com.android.tools.build:gradle:4.1.0'
18 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
19 |
20 | // NOTE: Do not place your application dependencies here; they belong
21 | // in the individual module build.gradle files
22 | }
23 | }
24 |
25 | allprojects {
26 | repositories {
27 | google()
28 | jcenter()
29 | maven { url 'https://jitpack.io' }
30 | }
31 | }
32 |
33 | task clean(type: Delete) {
34 | delete rootProject.buildDir
35 | }
36 |
--------------------------------------------------------------------------------
/doc/常用股票指标计算公式及简单应用.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/scsfwgy/MPAndroidChartWrapper/a074ff292811a2b6307b150d6bdbd8ef7fcdbea1/doc/常用股票指标计算公式及简单应用.pdf
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | org.gradle.jvmargs=-Xmx1536m
10 | # When configured, Gradle will run in incubating parallel mode.
11 | # This option should only be used with decoupled projects. More details, visit
12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
13 | # org.gradle.parallel=true
14 | # AndroidX package structure to make it clearer which packages are bundled with the
15 | # Android operating system, and which are packaged with your app's APK
16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn
17 | android.useAndroidX=true
18 | # Automatically convert third-party libraries to use AndroidX
19 | android.enableJetifier=true
20 | # Kotlin code style for this project: "official" or "obsolete":
21 | kotlin.code.style=official
22 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/scsfwgy/MPAndroidChartWrapper/a074ff292811a2b6307b150d6bdbd8ef7fcdbea1/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Thu Oct 15 11:23:08 CST 2020
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 |
53 | :win9xME_args
54 | @rem Slurp the command line arguments.
55 | set CMD_LINE_ARGS=
56 | set _SKIP=2
57 |
58 | :win9xME_args_slurp
59 | if "x%~1" == "x" goto execute
60 |
61 | set CMD_LINE_ARGS=%*
62 |
63 | :execute
64 | @rem Setup the command line
65 |
66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67 |
68 | @rem Execute Gradle
69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70 |
71 | :end
72 | @rem End local scope for the variables with windows NT shell
73 | if "%ERRORLEVEL%"=="0" goto mainEnd
74 |
75 | :fail
76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77 | rem the _cmd.exe /c_ return code!
78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79 | exit /b 1
80 |
81 | :mainEnd
82 | if "%OS%"=="Windows_NT" endlocal
83 |
84 | :omega
85 |
--------------------------------------------------------------------------------
/lib_common.gradle:
--------------------------------------------------------------------------------
1 | apply from: rootProject.file('lib_kt.gradle')
2 |
3 | android {
4 | compileSdkVersion rootProject.ext.compileSdkVersion
5 |
6 | defaultConfig {
7 | minSdkVersion rootProject.ext.minSdkVersion
8 | targetSdkVersion rootProject.ext.targetSdkVersion
9 | multiDexEnabled true
10 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
11 | }
12 |
13 | buildTypes {
14 | release {
15 | minifyEnabled false
16 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
17 | }
18 | debug {
19 |
20 | }
21 | }
22 |
23 | compileOptions {
24 | sourceCompatibility JavaVersion.VERSION_1_8
25 | targetCompatibility JavaVersion.VERSION_1_8
26 | }
27 |
28 | lintOptions {
29 | abortOnError false
30 | }
31 | }
32 |
33 | dependencies {
34 | implementation fileTree(dir: 'libs', include: ['*.jar'])
35 | testApi 'junit:junit:4.13'
36 | androidTestApi 'androidx.test.ext:junit:1.1.1'
37 | androidTestApi('androidx.test.espresso:espresso-core:3.2.0')
38 |
39 | implementation 'androidx.appcompat:appcompat:1.1.0'
40 | implementation 'androidx.core:core-ktx:1.3.0'
41 | implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
42 | }
43 |
--------------------------------------------------------------------------------
/lib_kt.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'kotlin-android'
2 | apply plugin: 'kotlin-android-extensions'
3 | apply plugin: 'kotlin-kapt'
4 |
5 | android {
6 | }
7 |
8 | dependencies {
9 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
10 | }
11 |
--------------------------------------------------------------------------------
/mpwrapper/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/mpwrapper/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 | apply from: rootProject.file('lib_common.gradle')
3 |
4 |
5 | android {
6 | defaultConfig {
7 | versionCode 1
8 | versionName "1.0"
9 | }
10 | }
11 |
12 | dependencies {
13 | //https://github.com/PhilJay/MPAndroidChart
14 | api 'com.github.PhilJay:MPAndroidChart:v3.1.0'
15 | }
16 |
--------------------------------------------------------------------------------
/mpwrapper/consumer-rules.pro:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/scsfwgy/MPAndroidChartWrapper/a074ff292811a2b6307b150d6bdbd8ef7fcdbea1/mpwrapper/consumer-rules.pro
--------------------------------------------------------------------------------
/mpwrapper/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/mpwrapper/src/androidTest/java/com/matt/mpwrapper/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package com.matt.mpwrapper
2 |
3 | import androidx.test.ext.junit.runners.AndroidJUnit4
4 | import androidx.test.platform.app.InstrumentationRegistry
5 | import org.junit.Assert.assertEquals
6 | import org.junit.Test
7 | import org.junit.runner.RunWith
8 |
9 | /**
10 | * Instrumented test, which will execute on an Android device.
11 | *
12 | * See [testing documentation](http://d.android.com/tools/testing).
13 | */
14 | @RunWith(AndroidJUnit4::class)
15 | class ExampleInstrumentedTest {
16 | @Test
17 | fun useAppContext() {
18 | // Context of the app under test.
19 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext
20 | assertEquals("com.matt.mpwrapper.test", appContext.packageName)
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/mpwrapper/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/mpwrapper/src/main/java/com/matt/mpwrapper/bean/Boll.kt:
--------------------------------------------------------------------------------
1 | package com.matt.mpwrapper.bean
2 |
3 | /**
4 | * ============================================================
5 | * 作 者 : matt@163.com
6 | * 更新时间 :2018/09/14 15:21
7 | * 描 述 :
8 | * ============================================================
9 | */
10 | data class Boll(val up: Float, val mb: Float, val dn: Float)
--------------------------------------------------------------------------------
/mpwrapper/src/main/java/com/matt/mpwrapper/bean/Config.kt:
--------------------------------------------------------------------------------
1 | package com.matt.mpwrapper.bean
2 |
3 | /**
4 | * ============================================================
5 | * 作 者 : matt
6 | * 更新时间 :2020/03/07 12:26
7 | * 描 述 :
8 | * ============================================================
9 | */
10 | class Config {
11 | var debug = true
12 | var greenUp = false
13 |
14 | companion object {
15 | fun def(): Config {
16 | val config = Config()
17 | config.debug = true
18 | config.greenUp = false
19 | return config
20 | }
21 | }
22 | }
--------------------------------------------------------------------------------
/mpwrapper/src/main/java/com/matt/mpwrapper/bean/KViewBaseData.kt:
--------------------------------------------------------------------------------
1 | package com.matt.mpwrapper.bean
2 |
3 | /**
4 | * ============================================================
5 | * 作 者 : matt
6 | * 更新时间 :2020/03/23 09:53
7 | * 描 述 :
8 | * ============================================================
9 | */
10 | abstract class KViewBaseData {
11 | var price: Price? = null
12 | }
--------------------------------------------------------------------------------
/mpwrapper/src/main/java/com/matt/mpwrapper/bean/KViewConstant.java:
--------------------------------------------------------------------------------
1 | package com.matt.mpwrapper.bean;
2 |
3 | /**
4 | * ============================================================
5 | * 作 者 : matt@163.com
6 | * 更新时间 :2018/10/22 11:41
7 | * 描 述 :
8 | * ============================================================
9 | */
10 | public class KViewConstant {
11 | public static final int VALUE_DEF = Integer.MIN_VALUE;
12 | public static final String VALUE_NULL_PLACEHOLDER = "--";
13 | }
14 |
--------------------------------------------------------------------------------
/mpwrapper/src/main/java/com/matt/mpwrapper/bean/KViewData.kt:
--------------------------------------------------------------------------------
1 | package com.matt.mpwrapper.bean
2 |
3 | /**
4 | * ============================================================
5 | * 作 者 : matt
6 | * 更新时间 :2020/03/09 14:56
7 | * 描 述 :
8 | * ============================================================
9 | */
10 | class KViewData {
11 | var price: Price? = null
12 | var masterData: MasterData? = null
13 | var minorData: MinorData? = null
14 | var volData: VolData? = null
15 | }
--------------------------------------------------------------------------------
/mpwrapper/src/main/java/com/matt/mpwrapper/bean/Kdj.kt:
--------------------------------------------------------------------------------
1 | package com.matt.mpwrapper.bean
2 |
3 | /**
4 | * ============================================================
5 | * 作 者 : matt@163.com
6 | * 更新时间 :2018/09/14 15:22
7 | * 描 述 :
8 | * ============================================================
9 | */
10 | class Kdj(val k: Float, val d: Float, val j: Float)
--------------------------------------------------------------------------------
/mpwrapper/src/main/java/com/matt/mpwrapper/bean/Ma.kt:
--------------------------------------------------------------------------------
1 | package com.matt.mpwrapper.bean
2 |
3 | /**
4 | * ============================================================
5 | * 作 者 : matt@163.com
6 | * 更新时间 :2018/09/14 15:20
7 | * 描 述 :
8 | * ============================================================
9 | */
10 | data class Ma(val ma5: Float, val ma10: Float, val ma20: Float)
--------------------------------------------------------------------------------
/mpwrapper/src/main/java/com/matt/mpwrapper/bean/Macd.kt:
--------------------------------------------------------------------------------
1 | package com.matt.mpwrapper.bean
2 |
3 | /**
4 | * ============================================================
5 | * 作 者 : matt@163.com
6 | * 更新时间 :2018/09/14 15:22
7 | * 描 述 :
8 | * ============================================================
9 | */
10 | data class Macd(val dif: Float, val dea: Float, val macd: Float)
--------------------------------------------------------------------------------
/mpwrapper/src/main/java/com/matt/mpwrapper/bean/MasterData.kt:
--------------------------------------------------------------------------------
1 | package com.matt.mpwrapper.bean
2 |
3 | /**
4 | * ============================================================
5 | * 作 者 : matt
6 | * 更新时间 :2020/03/23 09:52
7 | * 描 述 :
8 | * ============================================================
9 | */
10 | class MasterData {
11 | //主图
12 | var ma: Ma? = null
13 | var boll: Boll? = null
14 | }
--------------------------------------------------------------------------------
/mpwrapper/src/main/java/com/matt/mpwrapper/bean/MinorData.kt:
--------------------------------------------------------------------------------
1 | package com.matt.mpwrapper.bean
2 |
3 | /**
4 | * ============================================================
5 | * 作 者 : matt
6 | * 更新时间 :2020/03/23 09:52
7 | * 描 述 :
8 | * ============================================================
9 | */
10 | class MinorData {
11 | //副图
12 | var macd: Macd? = null
13 | var kdj: Kdj? = null
14 | var rsi: Rsi? = null
15 | }
--------------------------------------------------------------------------------
/mpwrapper/src/main/java/com/matt/mpwrapper/bean/Price.kt:
--------------------------------------------------------------------------------
1 | package com.matt.mpwrapper.bean
2 |
3 | /**
4 | * ============================================================
5 | * 作 者 : matt@163.com
6 | * 更新时间 :2018/09/14 15:20
7 | * 描 述 :所有数据请提供原始数据,不要进行任何加工
8 | * ============================================================
9 | */
10 | data class Price(
11 | /**
12 | * 原始数据
13 | */
14 | var t: Long,//开始时间
15 | val o: Float,
16 | val h: Float,
17 | val l: Float,
18 | var c: Float
19 | )
--------------------------------------------------------------------------------
/mpwrapper/src/main/java/com/matt/mpwrapper/bean/Rsi.kt:
--------------------------------------------------------------------------------
1 | package com.matt.mpwrapper.bean
2 |
3 | /**
4 | * ============================================================
5 | * 作 者 : matt@163.com
6 | * 更新时间 :2018/09/14 15:22
7 | * 描 述 :
8 | * ============================================================
9 | */
10 | data class Rsi(val rsi6: Float, val rsi12: Float, val rsi24: Float)
--------------------------------------------------------------------------------
/mpwrapper/src/main/java/com/matt/mpwrapper/bean/Vol.kt:
--------------------------------------------------------------------------------
1 | package com.matt.mpwrapper.bean
2 |
3 | /**
4 | * ============================================================
5 | * 作 者 : matt@163.com
6 | * 更新时间 :2018/09/14 15:28
7 | * 描 述 :量图,对于量图有两条ma线,作用和主图的ma基本一致。
8 | * ============================================================
9 | */
10 | data class Vol(var vol: Float, val volMa5: Float, val volMa10: Float)
--------------------------------------------------------------------------------
/mpwrapper/src/main/java/com/matt/mpwrapper/bean/VolData.kt:
--------------------------------------------------------------------------------
1 | package com.matt.mpwrapper.bean
2 |
3 | /**
4 | * ============================================================
5 | * 作 者 : matt
6 | * 更新时间 :2020/03/23 09:52
7 | * 描 述 :
8 | * ============================================================
9 | */
10 | class VolData {
11 | //量图
12 | var vol: Vol? = null
13 | }
--------------------------------------------------------------------------------
/mpwrapper/src/main/java/com/matt/mpwrapper/ktx/Any.kt:
--------------------------------------------------------------------------------
1 | package com.matt.mpwrapper.ktx
2 |
3 | import com.github.mikephil.charting.utils.Utils
4 |
5 | /**
6 | * ============================================================
7 | * 作 者 : matt
8 | * 更新时间 :2020/03/07 13:06
9 | * 描 述 :
10 | * ============================================================
11 | */
12 |
13 | fun Any.dip2px(dp: Float): Float {
14 | return Utils.convertDpToPixel(dp)
15 | }
16 |
17 | fun Any.px2dp(px: Float): Float {
18 | return Utils.convertPixelsToDp(px)
19 | }
--------------------------------------------------------------------------------
/mpwrapper/src/main/java/com/matt/mpwrapper/ktx/View.kt:
--------------------------------------------------------------------------------
1 | package com.matt.mpwrapper.ktx
2 |
3 | import android.graphics.drawable.Drawable
4 | import android.view.View
5 | import androidx.annotation.ColorRes
6 | import androidx.annotation.DrawableRes
7 | import androidx.core.content.ContextCompat
8 |
9 | /**
10 | * ============================================================
11 | * 作 者 : matt
12 | * 更新时间 :2020/03/07 11:31
13 | * 描 述 :
14 | * ============================================================
15 | */
16 |
17 | fun View.getColor(@ColorRes colorId: Int): Int {
18 | return ContextCompat.getColor(context, colorId)
19 | }
20 |
21 | fun View.getDrawable(@DrawableRes drawableId: Int): Drawable {
22 | return ContextCompat.getDrawable(context, drawableId)
23 | ?: throw IllegalArgumentException("getDrawable cannnot not null")
24 | }
25 |
26 |
27 |
--------------------------------------------------------------------------------
/mpwrapper/src/main/java/com/matt/mpwrapper/utils/MathUtil.kt:
--------------------------------------------------------------------------------
1 | package com.matt.mpwrapper.utils
2 |
3 | import java.math.BigDecimal
4 |
5 | /**
6 | *
7 | * 保证精度加减乘除
8 | * @author matt
9 | */
10 | object MathUtil {
11 | private const val TAG = "MathUtil"
12 |
13 | /**
14 | * double 保证精度相加
15 | */
16 | fun add(number1: Any?, number2: Any?): Double {
17 | return calculate(0, true, number1, number2)
18 | }
19 |
20 | /**
21 | * double 保证精度相减
22 | */
23 | fun subtract(number1: Any?, number2: Any?): Double {
24 | return calculate(1, true, number1, number2)
25 | }
26 |
27 | /**
28 | * double 保证精度相乘
29 | */
30 | fun multiply(number1: Any?, number2: Any?): Double {
31 | return calculate(2, true, number1, number2)
32 | }
33 |
34 | /**
35 | * 保证精度相除
36 | */
37 | @JvmStatic
38 | fun divide(number: Any?, nums: Any): Double {
39 | return calculate(3, true, number, nums)
40 | }
41 |
42 | private fun calculate(type: Int, safe: Boolean = true, number1: Any?, number2: Any?): Double {
43 | return if (safe) {
44 | try {
45 | mathData(type, number1, number2)
46 | } catch (e: Exception) {
47 | e.printStackTrace()
48 | 0.0
49 | }
50 | } else {
51 | mathData(type,number1, number2)
52 | }
53 | }
54 |
55 | private fun mathData(type: Int, number1: Any?, number2: Any?): Double {
56 | val num1 = number1?.toString() ?: "0.0"
57 | val num2 = number2?.toString() ?: "0.0"
58 | val bigDecimal1 = BigDecimal(num1)
59 | val bigDecimal2 = BigDecimal(num2)
60 | val result = when (type) {
61 | 0 -> {
62 | bigDecimal1.add(bigDecimal2)
63 | }
64 | 1 -> {
65 | bigDecimal1.subtract(bigDecimal2)
66 | }
67 | 2 -> {
68 | bigDecimal1.multiply(bigDecimal2)
69 | }
70 | 3 -> {
71 | bigDecimal1.divide(bigDecimal2, 10, BigDecimal.ROUND_HALF_UP)
72 | }
73 | else -> throw IllegalArgumentException("参数不合法")
74 | }
75 | return result.toDouble()
76 | }
77 | }
--------------------------------------------------------------------------------
/mpwrapper/src/main/java/com/matt/mpwrapper/utils/NumberUtils.kt:
--------------------------------------------------------------------------------
1 | package com.matt.mpwrapper.utils
2 |
3 | object NumberUtils {
4 | @JvmOverloads
5 | fun toInt(str: String?, defaultValue: Int = 0): Int {
6 | return if (str == null) {
7 | defaultValue
8 | } else {
9 | try {
10 | str.toInt()
11 | } catch (numberFormatException: NumberFormatException) {
12 | defaultValue
13 | }
14 | }
15 | }
16 |
17 | @JvmOverloads
18 | fun toLong(str: String?, defaultValue: Long = 0L): Long {
19 | return if (str == null) {
20 | defaultValue
21 | } else {
22 | try {
23 | str.toLong()
24 | } catch (numberFormatException: NumberFormatException) {
25 | defaultValue
26 | }
27 | }
28 | }
29 |
30 | @JvmOverloads
31 | fun toFloat(str: String?, defaultValue: Float = 0.0f): Float {
32 | return if (str == null) {
33 | defaultValue
34 | } else {
35 | try {
36 | str.toFloat()
37 | } catch (numberFormatException: NumberFormatException) {
38 | defaultValue
39 | }
40 | }
41 | }
42 |
43 | @JvmOverloads
44 | fun toDouble(str: String?, defaultValue: Double = 0.0): Double {
45 | return if (str == null) {
46 | defaultValue
47 | } else {
48 | try {
49 | str.toDouble()
50 | } catch (numberFormatException: NumberFormatException) {
51 | defaultValue
52 | }
53 | }
54 | }
55 |
56 | @JvmOverloads
57 | fun toByte(str: String?, defaultValue: Byte = 0.toByte()): Byte {
58 | return if (str == null) {
59 | defaultValue
60 | } else {
61 | try {
62 | str.toByte()
63 | } catch (numberFormatException: NumberFormatException) {
64 | defaultValue
65 | }
66 | }
67 | }
68 |
69 | @JvmOverloads
70 | fun toShort(str: String?, defaultValue: Short = 0.toShort()): Short {
71 | return if (str == null) {
72 | defaultValue
73 | } else {
74 | try {
75 | str.toShort()
76 | } catch (numberFormatException: NumberFormatException) {
77 | defaultValue
78 | }
79 | }
80 | }
81 | }
--------------------------------------------------------------------------------
/mpwrapper/src/main/java/com/matt/mpwrapper/utils/TimeConstants.java:
--------------------------------------------------------------------------------
1 | package com.matt.mpwrapper.utils;
2 |
3 | import androidx.annotation.IntDef;
4 |
5 | import java.lang.annotation.Retention;
6 | import java.lang.annotation.RetentionPolicy;
7 |
8 | /**
9 | *
10 | * author: Blankj
11 | * blog : http://blankj.com
12 | * time : 2017/03/13
13 | * desc : constants of time
14 | *
15 | */
16 | public final class TimeConstants {
17 |
18 | public static final int MSEC = 1;
19 | public static final int SEC = 1000;
20 | public static final int MIN = 60000;
21 | public static final int HOUR = 3600000;
22 | public static final int DAY = 86400000;
23 |
24 | @IntDef({MSEC, SEC, MIN, HOUR, DAY})
25 | @Retention(RetentionPolicy.SOURCE)
26 | public @interface Unit {
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/mpwrapper/src/main/java/com/matt/mpwrapper/utils/XFormatUtil.kt:
--------------------------------------------------------------------------------
1 | package com.matt.mpwrapper.utils
2 |
3 | import java.math.BigDecimal
4 |
5 | /**
6 | * 测试用例:[XFormatUtilTest],修改这里的方法注意跑一下测试用例,因为修改会影响整个应用
7 | */
8 | object XFormatUtil {
9 | val TAG = XFormatUtil::class.java.simpleName
10 | private const val DEF_GLOBAL_FORMAT = "0.00"
11 |
12 | /**
13 | * 账户资金相关计算显示
14 | */
15 | private fun double2BigDecimalByScale(
16 | num: String,
17 | scale: Int,
18 | stripTrailingZeros: Boolean = true,
19 | roundDown: Boolean = true
20 | ): BigDecimal {
21 | val roundType = if (roundDown) {
22 | BigDecimal.ROUND_DOWN
23 | } else {
24 | BigDecimal.ROUND_UP
25 | }
26 | val decimal = BigDecimal(num)
27 | val scaled =
28 | decimal.setScale(scale, roundType)
29 | return if (stripTrailingZeros) {
30 | scaled.stripTrailingZeros()
31 | } else {
32 | scaled
33 | }
34 | }
35 |
36 | private fun double2BigDecimalByScaleToString(
37 | num: String,
38 | scale: Int,
39 | stripTrailingZeros: Boolean = true,
40 | roundDown: Boolean = true,
41 | safe: Boolean = false
42 | ): String {
43 | if (!safe) {
44 | return double2BigDecimalByScale(num, scale, stripTrailingZeros, roundDown).toPlainString().toString()
45 | }
46 | return try {
47 | double2BigDecimalByScale(num, scale, stripTrailingZeros, roundDown).toPlainString().toString()
48 | } catch (e: Exception) {
49 | e.printStackTrace()
50 | DEF_GLOBAL_FORMAT
51 | }
52 | }
53 |
54 | @JvmOverloads
55 | @JvmStatic
56 | fun globalFormat(number: Any?, scale: Int = 2,
57 | stripTrailingZeros: Boolean = true,
58 | roundDown: Boolean = true
59 | ): String {
60 | if (number == null) return DEF_GLOBAL_FORMAT
61 | val finalParam = when (number) {
62 | is String -> {
63 | number
64 | }
65 | is Number -> {
66 | number.toString()
67 | }
68 | else -> {
69 | DEF_GLOBAL_FORMAT
70 | }
71 | }
72 | return double2BigDecimalByScaleToString(finalParam, scale, stripTrailingZeros, roundDown, true)
73 | }
74 | }
--------------------------------------------------------------------------------
/mpwrapper/src/main/java/com/matt/mpwrapper/view/FinancialAlgorithmConvert.kt:
--------------------------------------------------------------------------------
1 | package com.matt.mpwrapper.view
2 |
3 | import com.matt.mpwrapper.bean.*
4 |
5 | /**
6 | *
7 | * Author : wgyscsf@163.com
8 | * Github : https://github.com/scsfwgy
9 | * Date : 2020/8/9 3:14 PM
10 | * 描 述 :
11 | *
12 | **/
13 | object FinancialAlgorithmConvert {
14 |
15 | fun simpleDataList2KViewDataList(
16 | priceList: List,
17 | volList: List? = null
18 | ): List {
19 | val map = priceList.map { it.c }
20 | //主图
21 | val calculateMA5 = FinancialAlgorithm.calculateMA(map, 5)
22 | val calculateMA10 = FinancialAlgorithm.calculateMA(map, 10)
23 | val calculateMA20 = FinancialAlgorithm.calculateMA(map, 20)
24 | val calculateBOLL = FinancialAlgorithm.calculateBOLL(map)
25 | //副图
26 | val calculateMACD = FinancialAlgorithm.calculateMACD(map)
27 | val calculateRSI6 = FinancialAlgorithm.calculateRSI(map, 6)
28 | val calculateRSI12 = FinancialAlgorithm.calculateRSI(map, 12)
29 | val calculateRSI24 = FinancialAlgorithm.calculateRSI(map, 24)
30 | val calculateKDJ = FinancialAlgorithm.calculateKDJ(map)
31 | //量图
32 | val calculateVolMA5 = if (volList != null) {
33 | FinancialAlgorithm.calculateMA(volList, 5)
34 | } else {
35 | null
36 | }
37 |
38 | val calculateVolMA10 = if (volList != null) {
39 | FinancialAlgorithm.calculateMA(volList, 10)
40 | } else {
41 | null
42 | }
43 |
44 | val kViewDataList = ArrayList(priceList.size)
45 | priceList.forEachIndexed { index, it ->
46 | val ma5 = calculateMA5[index]
47 | val ma10 = calculateMA10[index]
48 | val ma20 = calculateMA20[index]
49 | val boll = calculateBOLL[index]
50 | val kViewData = KViewData()
51 | kViewData.price = it
52 |
53 | //主图
54 | val masterData = MasterData()
55 | masterData.ma = Ma(ma5, ma10, ma20)
56 | masterData.boll = boll
57 | kViewData.masterData = masterData
58 |
59 | //副图
60 | val minData = MinorData()
61 | minData.macd = calculateMACD[index]
62 | val rsi6 = calculateRSI6[index]
63 | val rsi12 = calculateRSI12[index]
64 | val rsi24 = calculateRSI24[index]
65 | minData.rsi = Rsi(rsi6, rsi12, rsi24)
66 | minData.kdj = calculateKDJ[index]
67 | kViewData.minorData = minData
68 |
69 | //量图
70 | val vols = volList?.get(index)
71 | val volMa5 = calculateVolMA5?.get(index)
72 | val volMa10 = calculateVolMA10?.get(index)
73 | if (vols != null && volMa5 != null && volMa10 != null) {
74 | val volData = VolData()
75 | volData.vol = Vol(vols, volMa5, volMa10)
76 | kViewData.volData = volData
77 | }
78 | kViewDataList.add(kViewData)
79 | }
80 | return kViewDataList
81 | }
82 | }
--------------------------------------------------------------------------------
/mpwrapper/src/main/java/com/matt/mpwrapper/view/MinorView.kt:
--------------------------------------------------------------------------------
1 | package com.matt.mpwrapper.view
2 |
3 | import android.content.Context
4 | import android.util.AttributeSet
5 | import com.github.mikephil.charting.data.BarEntry
6 | import com.github.mikephil.charting.data.Entry
7 | import com.matt.mpwrapper.bean.KViewData
8 | import com.matt.mpwrapper.view.base.BaseKView
9 | import com.matt.mpwrapper.view.delegate.BaseKViewDelegate
10 | import com.matt.mpwrapper.view.delegate.MinorViewDelegate
11 |
12 | /**
13 | * ============================================================
14 | * 作 者 : matt
15 | * 更新时间 :2020/03/07 12:22
16 | * 描 述 :
17 | * ============================================================
18 | */
19 | class MinorView @JvmOverloads constructor(
20 | context: Context,
21 | attributeSet: AttributeSet? = null,
22 | defStyle: Int = 0
23 | ) : BaseKView(context, attributeSet, defStyle) {
24 |
25 | val mMinorViewDelegate by lazy {
26 | MinorViewDelegate(this)
27 | }
28 |
29 | init {
30 | mMinorViewDelegate.initChart()
31 | }
32 |
33 | override fun getChartViewDelegate(): BaseKViewDelegate {
34 | return mMinorViewDelegate
35 | }
36 |
37 | override fun renderTemplateItemView(
38 | realIndex: Int,
39 | newDataIndex: Int,
40 | it: KViewData,
41 | reload: Boolean,
42 | append: Boolean,
43 | loadMore: Boolean
44 | ) {
45 |
46 | val invalidData = FinancialAlgorithm.invalidData
47 | val minorViewDelegate = mMinorViewDelegate
48 |
49 |
50 | val minorData =
51 | it.minorData ?: throw IllegalArgumentException("minorData字段为null,不允许为null")
52 | val xValue = realIndex.toFloat()
53 |
54 | //展示高亮线的
55 | minorViewDelegate.mShowHighlightLineData.addEntry(Entry(xValue, 0f))
56 |
57 | val macd = minorData.macd
58 | if (macd != null) {
59 | val dif = macd.dif
60 | if (dif != invalidData) {
61 | minorViewDelegate.mMacdLineDataSetArr[0].addEntry(Entry(xValue, dif))
62 | }
63 | val dea = macd.dea
64 | if (dea != invalidData) {
65 | minorViewDelegate.mMacdLineDataSetArr[1].addEntry(Entry(xValue, dea))
66 | }
67 | val m = macd.macd
68 | if (m != invalidData) {
69 | val macdBarEntryListArr = minorViewDelegate.mMacdBarDataSetArr
70 | if (m >= 0) {
71 | macdBarEntryListArr[0].addEntry(BarEntry(xValue, m))
72 | } else {
73 | macdBarEntryListArr[1].addEntry(BarEntry(xValue, m))
74 | }
75 | }
76 |
77 | }
78 |
79 | val kdj = minorData.kdj
80 | if (kdj != null) {
81 | val k = kdj.k
82 | if (k != invalidData) {
83 | minorViewDelegate.mKdjLineDataSetArr[0].addEntry(Entry(xValue, k))
84 | }
85 | val d = kdj.d
86 | if (d != invalidData) {
87 | minorViewDelegate.mKdjLineDataSetArr[1].addEntry(Entry(xValue, d))
88 | }
89 | val j = kdj.j
90 | if (j != invalidData) {
91 | minorViewDelegate.mKdjLineDataSetArr[2].addEntry(Entry(xValue, j))
92 | }
93 | }
94 |
95 | val rsi = minorData.rsi
96 | if (rsi != null) {
97 | val rsi6 = rsi.rsi6
98 | if (rsi6 != invalidData) {
99 | minorViewDelegate.mRsiLineDataSetArr[0].addEntry(Entry(xValue, rsi6))
100 | }
101 | val rsi12 = rsi.rsi12
102 | if (rsi12 != invalidData) {
103 | minorViewDelegate.mRsiLineDataSetArr[1].addEntry(Entry(xValue, rsi12))
104 | }
105 | val rsi24 = rsi.rsi24
106 | if (rsi24 != invalidData) {
107 | minorViewDelegate.mRsiLineDataSetArr[2].addEntry(Entry(xValue, rsi24))
108 | }
109 | }
110 |
111 | }
112 |
113 | override fun refreshData(kViewData: KViewData) {
114 |
115 | }
116 |
117 | override fun renderTemplateFinal(
118 | kViewDataList: List,
119 | reload: Boolean,
120 | loadMore: Boolean,
121 | pushData: Boolean
122 | ) {
123 | val minorViewDelegate = mMinorViewDelegate
124 | val combinedData = minorViewDelegate.mCombinedData
125 | val lineData = minorViewDelegate.mLineData
126 | val barData = minorViewDelegate.mBarData
127 |
128 | minorViewDelegate.showIndicatorType(false)
129 | combinedData.setData(lineData)
130 | combinedData.setData(barData)
131 | }
132 | }
--------------------------------------------------------------------------------
/mpwrapper/src/main/java/com/matt/mpwrapper/view/MpWrapperConfig.kt:
--------------------------------------------------------------------------------
1 | package com.matt.mpwrapper.view
2 |
3 | import com.matt.mpwrapper.bean.Config
4 |
5 | /**
6 | * ============================================================
7 | * 作 者 : matt
8 | * 更新时间 :2020/03/07 11:40
9 | * 描 述 :
10 | * ============================================================
11 | */
12 | object MpWrapperConfig {
13 | var mConfig: Config = Config.def()
14 | fun init(config: Config) {
15 | mConfig = config
16 | }
17 | }
--------------------------------------------------------------------------------
/mpwrapper/src/main/java/com/matt/mpwrapper/view/VolView.kt:
--------------------------------------------------------------------------------
1 | package com.matt.mpwrapper.view
2 |
3 | import android.content.Context
4 | import android.util.AttributeSet
5 | import com.github.mikephil.charting.data.BarEntry
6 | import com.github.mikephil.charting.data.Entry
7 | import com.matt.mpwrapper.bean.KViewData
8 | import com.matt.mpwrapper.view.base.BaseKView
9 | import com.matt.mpwrapper.view.delegate.BaseKViewDelegate
10 | import com.matt.mpwrapper.view.delegate.VolViewDelegate
11 |
12 | /**
13 | * ============================================================
14 | * 作 者 : matt
15 | * 更新时间 :2020/03/07 12:22
16 | * 描 述 :
17 | * ============================================================
18 | */
19 | class VolView @JvmOverloads constructor(
20 | context: Context,
21 | attributeSet: AttributeSet? = null,
22 | defStyle: Int = 0
23 | ) : BaseKView(context, attributeSet, defStyle) {
24 |
25 | val mVolViewDelegate by lazy {
26 | VolViewDelegate(this)
27 | }
28 |
29 | init {
30 | mVolViewDelegate.initChart()
31 | }
32 |
33 | override fun getChartViewDelegate(): BaseKViewDelegate {
34 | return mVolViewDelegate
35 | }
36 |
37 | override fun renderTemplateItemView(
38 | realIndex: Int,
39 | newDataIndex: Int,
40 | it: KViewData,
41 | reload: Boolean,
42 | append: Boolean,
43 | loadMore: Boolean
44 | ) {
45 |
46 | val invalidData = FinancialAlgorithm.invalidData
47 | val volViewDelegate = mVolViewDelegate
48 |
49 | val price = it.price ?: throw IllegalArgumentException("price字段为null,不允许为null")
50 | val volData =
51 | it.volData ?: throw IllegalArgumentException("volData字段为null,不允许为null")
52 | val xValue = realIndex.toFloat()
53 |
54 | //展示高亮线的
55 | volViewDelegate.mShowHighlightLineData.addEntry(Entry(xValue, 0f))
56 |
57 | val vol = volData.vol ?: throw IllegalArgumentException("volData.vol字段为null,不允许为null")
58 | val volMa5 = vol.volMa5
59 | if (volMa5 != invalidData) {
60 | volViewDelegate.mVolMaLineDataSetArr[0].addEntry(Entry(xValue, volMa5))
61 | }
62 | val volMa10 = vol.volMa10
63 | if (volMa10 != invalidData) {
64 | volViewDelegate.mVolMaLineDataSetArr[1].addEntry(Entry(xValue, volMa10))
65 | }
66 | val up = if (realIndex != 0) {
67 | val c = mBaseInit.kViewDataList()[realIndex - 1].price?.c ?: 0f
68 | price.c - c >= 0
69 | } else {
70 | false
71 | }
72 | val m = vol.vol
73 | if (m != invalidData) {
74 | val volBarEntryListArr = volViewDelegate.mVolBarDataSetArr
75 | if (up) {
76 | volBarEntryListArr[0].addEntry(BarEntry(xValue, m))
77 | } else {
78 | volBarEntryListArr[1].addEntry(BarEntry(xValue, m))
79 | }
80 | }
81 |
82 | }
83 |
84 | override fun refreshData(kViewData: KViewData) {
85 |
86 | }
87 |
88 | override fun renderTemplateFinal(
89 | kViewDataList: List,
90 | reload: Boolean,
91 | loadMore: Boolean,
92 | pushData: Boolean
93 | ) {
94 | val volViewDelegate = mVolViewDelegate
95 | val combinedData = volViewDelegate.mCombinedData
96 | val lineData = volViewDelegate.mLineData
97 | val barData = volViewDelegate.mBarData
98 |
99 | volViewDelegate.showIndicatorType(false)
100 | combinedData.setData(lineData)
101 | combinedData.setData(barData)
102 | }
103 |
104 | }
--------------------------------------------------------------------------------
/mpwrapper/src/main/java/com/matt/mpwrapper/view/base/BaseInit.kt:
--------------------------------------------------------------------------------
1 | package com.matt.mpwrapper.view.base
2 |
3 | import com.matt.mpwrapper.bean.KViewData
4 |
5 | /**
6 | *
7 | * Author : wgyscsf@163.com
8 | * Github : https://github.com/scsfwgy
9 | * Date : 2020/6/21 11:28 AM
10 | * 描 述 :
11 | *
12 | **/
13 | interface BaseInit {
14 | fun kViewDataList(): MutableList
15 | fun digit(): Int
16 | }
--------------------------------------------------------------------------------
/mpwrapper/src/main/java/com/matt/mpwrapper/view/base/BaseKView.kt:
--------------------------------------------------------------------------------
1 | package com.matt.mpwrapper.view.base
2 |
3 | import android.content.Context
4 | import android.util.AttributeSet
5 | import android.util.Log
6 | import com.github.mikephil.charting.data.CombinedData
7 | import com.matt.mpwrapper.bean.KViewData
8 | import com.matt.mpwrapper.view.charts.BaseCombinedChart
9 | import com.matt.mpwrapper.view.delegate.IChartViewDelegate
10 |
11 | /**
12 | * ============================================================
13 | * 作 者 : matt
14 | * 更新时间 :2020/03/07 11:39
15 | * 描 述 :
16 | * ============================================================
17 | */
18 | abstract class BaseKView @JvmOverloads constructor(
19 | context: Context,
20 | attributeSet: AttributeSet? = null,
21 | defStyle: Int = 0
22 | ) :
23 | BaseCombinedChart(context, attributeSet, defStyle), IChartLoadData, IChartViewDelegate {
24 |
25 | protected val mDefMinCount = 40
26 | protected val mDefMaxCount = 100
27 | protected val mDefShowCount = 70
28 |
29 | lateinit var mBaseInit: BaseInit
30 |
31 | fun initBaseK(baseInit: BaseInit) {
32 | this.mBaseInit = baseInit
33 | }
34 |
35 | /**
36 | * 设置X轴放大系数
37 | */
38 | open fun showDefCount(size: Int) {
39 | var scale: Float = size / mDefShowCount.toFloat()
40 | if (scale < 1) {
41 | scale = 1f
42 | }
43 | //设置右边距离
44 | mXAxis.spaceMax = size * 0.15f / scale
45 | Log.d("BaseChart", "postScaleX: $size scale= $scale")
46 | mViewPortHandler.zoom(scale, 1f, mViewPortHandler.matrixTouch)
47 | }
48 |
49 |
50 | /**
51 | * 设置最终数据
52 | */
53 | fun setKViewData(
54 | data: CombinedData,
55 | reload: Boolean = true,
56 | loadMore: Boolean = false
57 | ) {
58 | val allDataSize = mBaseInit.kViewDataList().size
59 | showDefCount(allDataSize)
60 | //调用系统方法
61 | setData(data)
62 | //设置最大和最小值
63 | setVisibleXRange(mDefMaxCount.toFloat(), mDefMinCount.toFloat())
64 | if (reload) {
65 | //移动到尾部
66 | moveViewToX(getData().entryCount.toFloat())
67 | }
68 | }
69 |
70 | /**
71 | * 重置数据
72 | */
73 | open fun resetALl() {
74 | getChartViewDelegate().mCombinedDataControl.resetAll()
75 | lineData?.dataSets?.clear()
76 | candleData?.dataSets?.clear()
77 | barData?.dataSets?.clear()
78 | scatterData?.dataSets?.clear()
79 | bubbleData?.dataSets?.clear()
80 | combinedData?.dataSets?.clear()
81 | updateAll()
82 | }
83 |
84 | override fun onLoading(loadingMsg: String?) {
85 | //一定要先清空数据
86 | resetALl()
87 | //只有mData=null,setNoDataText才会绘制
88 | mData = null
89 | setNoDataText(loadingMsg ?: "加载中...")
90 | invalidate()
91 | }
92 |
93 | override fun onLoadingFail(loadingFailMsg: String?) {
94 | setNoDataText(loadingFailMsg ?: "加载失败")
95 | invalidate()
96 | }
97 |
98 | override fun loadData(
99 | kViewDataList: List,
100 | reload: Boolean,
101 | append: Boolean,
102 | loadMore: Boolean
103 | ) {
104 | renderView(kViewDataList, reload, append, loadMore)
105 | }
106 |
107 | /**
108 | * 真正的渲染逻辑
109 | */
110 | open fun renderView(
111 | kViewDataList: List,
112 | reload: Boolean,
113 | append: Boolean,
114 | loadMore: Boolean
115 | ) {
116 | kViewDataList.forEachIndexed { index, kViewData ->
117 | renderTemplateItemView(index, index, kViewData, reload, loadMore, append)
118 | }
119 |
120 | if (!append) {
121 | renderTemplateFinal(kViewDataList, reload, loadMore, append)
122 |
123 | //设置数据
124 | val combinedData = getChartViewDelegate().mCombinedData
125 | setKViewData(combinedData)
126 | //触发值未选择,进而触发未选择值对应的Legend
127 | mSelectionListener.onNothingSelected()
128 | } else {
129 | data?.notifyDataChanged()
130 | notifyDataSetChanged()
131 | moveViewToX(data?.entryCount?.toFloat() ?: 0f)
132 | }
133 |
134 | }
135 |
136 | /**
137 | * 渲染最后的动作
138 | */
139 | abstract fun renderTemplateFinal(
140 | kViewDataList: List,
141 | reload: Boolean,
142 | loadMore: Boolean,
143 | pushData: Boolean
144 | )
145 |
146 | /**
147 | * 具体渲染单项,子类去实现
148 | *
149 | * @param realIndex 真实的渲染item的下标
150 | * @param newDataIndex 当前数据集合的item的下标
151 | * @param it 当前item
152 | * @param reload 重新加载
153 | * @param loadMore 加载更多
154 | */
155 | abstract fun renderTemplateItemView(
156 | realIndex: Int,
157 | newDataIndex: Int,
158 | it: KViewData,
159 | reload: Boolean,
160 | append: Boolean,
161 | loadMore: Boolean
162 | )
163 | }
--------------------------------------------------------------------------------
/mpwrapper/src/main/java/com/matt/mpwrapper/view/base/IBaseLoadData.kt:
--------------------------------------------------------------------------------
1 | package com.matt.mpwrapper.view.base
2 |
3 | /**
4 | * ============================================================
5 | * 作 者 : wgyscsf@163.com
6 | * 创建日期 :2020/9/15 6:56 PM
7 | * 描 述 :
8 | * ============================================================
9 | **/
10 | interface IBaseLoadData {
11 | /**
12 | * 在加载前调用
13 | */
14 | fun onLoading(loadingMsg: String? = null)
15 |
16 | /**
17 | * 加载失败后调用
18 | */
19 | fun onLoadingFail(loadingFailMsg: String? = null)
20 |
21 | }
--------------------------------------------------------------------------------
/mpwrapper/src/main/java/com/matt/mpwrapper/view/base/IChartLoadData.kt:
--------------------------------------------------------------------------------
1 | package com.matt.mpwrapper.view.base
2 |
3 | import com.matt.mpwrapper.bean.KViewData
4 |
5 | /**
6 | * ============================================================
7 | * 作 者 : matt
8 | * 更新时间 :2020/03/23 09:48
9 | * 描 述 :
10 | * ============================================================
11 | */
12 | interface IChartLoadData : IBaseLoadData {
13 |
14 | fun loadData(
15 | kViewDataList: List,
16 | reload: Boolean = true,
17 | append: Boolean = false,
18 | loadMore: Boolean = false
19 | )
20 |
21 | /**
22 | * 刷新最新数据,只会刷新不会追加
23 | */
24 | fun refreshData(kViewData: KViewData)
25 | }
--------------------------------------------------------------------------------
/mpwrapper/src/main/java/com/matt/mpwrapper/view/base/IKLoadData.kt:
--------------------------------------------------------------------------------
1 | package com.matt.mpwrapper.view.base
2 |
3 | import com.matt.mpwrapper.bean.Price
4 | import com.matt.mpwrapper.view.type.MasterIndicatorType
5 | import com.matt.mpwrapper.view.type.MasterViewType
6 | import com.matt.mpwrapper.view.type.MinorIndicatorType
7 | import com.matt.mpwrapper.view.type.VolIndicatorType
8 |
9 | /**
10 | * ============================================================
11 | * 作 者 : matt
12 | * 更新时间 :2020/03/23 09:48
13 | * 描 述 :
14 | * ============================================================
15 | */
16 | interface IKLoadData : IBaseLoadData {
17 |
18 | /**
19 | * 一些基础配置信息,可以动态更新
20 | */
21 | fun updateConfig(
22 | yDataDigit: Int = 4,
23 | masterViewType: MasterViewType = MasterViewType.CANDLE,
24 | masterIndicatorType: MasterIndicatorType = MasterIndicatorType.MA,
25 | minorIndicatorType: MinorIndicatorType = MinorIndicatorType.MACD,
26 | volIndicatorType: VolIndicatorType = VolIndicatorType.VOL_MA
27 | )
28 |
29 | /**
30 | * 数据加载
31 | * @param priceList 价格
32 | * @param volList 量
33 | * @param reload
34 | */
35 | fun loadData(
36 | priceList: List, volList: List? = null,
37 | reload: Boolean = true,
38 | append: Boolean = false,
39 | loadMore: Boolean = false
40 | )
41 |
42 | /**
43 | * 刷新最新数据,只会刷新不会追加
44 | */
45 | fun refreshData(latestTime: Long, latestPrice: Float, latestVol: Float? = null)
46 | }
--------------------------------------------------------------------------------
/mpwrapper/src/main/java/com/matt/mpwrapper/view/charts/BaseCombinedChart.kt:
--------------------------------------------------------------------------------
1 | package com.matt.mpwrapper.view.charts
2 |
3 | import android.content.Context
4 | import android.util.AttributeSet
5 | import com.github.mikephil.charting.charts.CombinedChart
6 |
7 | /**
8 | * ============================================================
9 | * 作 者 : matt
10 | * 更新时间 :2020/03/07 11:16
11 | * 描 述 :
12 | * ============================================================
13 | */
14 | abstract class BaseCombinedChart(
15 | context: Context,
16 | attributeSet: AttributeSet? = null,
17 | defStyle: Int = 0
18 | ) :
19 | CombinedChart(context, attributeSet, defStyle) {
20 |
21 | val TAG by lazy {
22 | javaClass.simpleName
23 | }
24 | val mContext by lazy {
25 | getContext() ?: throw IllegalArgumentException("getContext() cannot be null")
26 | }
27 |
28 | fun updateAll() {
29 | //刷新数据
30 | data?.notifyDataChanged()
31 | //刷新view
32 | notifyDataSetChanged()
33 | invalidate()
34 | }
35 | }
--------------------------------------------------------------------------------
/mpwrapper/src/main/java/com/matt/mpwrapper/view/data/BaseBarDataSet.kt:
--------------------------------------------------------------------------------
1 | package com.matt.mpwrapper.view.data
2 |
3 | import com.github.mikephil.charting.data.BarDataSet
4 | import com.github.mikephil.charting.data.BarEntry
5 | import com.matt.mpwrapper.view.delegate.DataSetDelegate
6 |
7 | /**
8 | * ============================================================
9 | * 作 者 : matt@163.com
10 | * 更新时间 :2018/09/28 18:17
11 | * 描 述 :线性数据集合的基类,设置一些通用属性。
12 | * ============================================================
13 | */
14 | class BaseBarDataSet(yValue: List, label: String) : BarDataSet(yValue, label) {
15 |
16 | init {
17 | initAttrs()
18 | }
19 |
20 | private fun initAttrs() {
21 | DataSetDelegate().init(this)
22 | }
23 |
24 | override fun getEntryIndex(e: BarEntry): Int {
25 | return mValues.indexOf(e);
26 | }
27 | }
--------------------------------------------------------------------------------
/mpwrapper/src/main/java/com/matt/mpwrapper/view/data/BaseCandleDataSet.kt:
--------------------------------------------------------------------------------
1 | package com.matt.mpwrapper.view.data
2 |
3 | import android.graphics.Paint
4 | import com.github.mikephil.charting.data.CandleDataSet
5 | import com.github.mikephil.charting.data.CandleEntry
6 | import com.matt.mpwrapper.view.delegate.DataSetDelegate
7 |
8 | /**
9 | * ============================================================
10 | * 作 者 : matt@163.com
11 | * 更新时间 :2018/09/28 18:17
12 | * 描 述 :线性数据集合的基类,设置一些通用属性。
13 | * ============================================================
14 | */
15 | class BaseCandleDataSet(yValue: List, label: String) : CandleDataSet(yValue, label) {
16 |
17 | init {
18 | initAttrs()
19 | }
20 |
21 | private fun initAttrs() {
22 | DataSetDelegate().init(this)
23 | //允许高亮线
24 | isHighlightEnabled = true
25 | //允许x轴绘制高亮线
26 | setDrawHorizontalHighlightIndicator(true)
27 |
28 | shadowColorSameAsCandle = true
29 | shadowWidth = 1f
30 |
31 | decreasingPaintStyle = Paint.Style.FILL
32 | increasingPaintStyle = Paint.Style.FILL
33 | }
34 |
35 | override fun getEntryIndex(e: CandleEntry): Int {
36 | return mValues.indexOf(e);
37 | }
38 | }
--------------------------------------------------------------------------------
/mpwrapper/src/main/java/com/matt/mpwrapper/view/data/BaseCombinedData.kt:
--------------------------------------------------------------------------------
1 | package com.matt.mpwrapper.view.data
2 |
3 | import com.github.mikephil.charting.data.*
4 |
5 | /**
6 | *
7 | * Author : wgyscsf@163.com
8 | * Github : https://github.com/scsfwgy
9 | * Date : 2020/7/26 7:08 PM
10 | * 描 述 :
11 | *
12 | **/
13 | class BaseCombinedData : CombinedData() {
14 |
15 | fun setAllData(
16 | lineData: LineData? = null,
17 | candleData: CandleData? = null,
18 | barData: BarData? = null,
19 | scatterData: ScatterData? = null,
20 | bubbleData: BubbleData? = null
21 | ) {
22 | setData(lineData)
23 | setData(candleData)
24 | setData(barData)
25 | setData(scatterData)
26 | setData(bubbleData)
27 | notifyDataChanged2()
28 | }
29 |
30 | override fun notifyDataChanged() {
31 | //super.notifyDataChanged()
32 | }
33 |
34 | fun notifyDataChanged2() {
35 | lineData?.notifyDataChanged()
36 | candleData?.notifyDataChanged()
37 | barData?.notifyDataChanged()
38 | scatterData?.notifyDataChanged()
39 | bubbleData?.notifyDataChanged()
40 | calcMinMax()
41 | }
42 | }
--------------------------------------------------------------------------------
/mpwrapper/src/main/java/com/matt/mpwrapper/view/data/BaseLineDataSet.kt:
--------------------------------------------------------------------------------
1 | package com.matt.mpwrapper.view.data
2 |
3 | import com.github.mikephil.charting.data.Entry
4 | import com.github.mikephil.charting.data.LineDataSet
5 | import com.matt.mpwrapper.view.delegate.DataSetDelegate
6 |
7 | /**
8 | * ============================================================
9 | * 作 者 : matt@163.com
10 | * 更新时间 :2018/09/28 18:17
11 | * 描 述 :线性数据集合的基类,设置一些通用属性。
12 | * ============================================================
13 | */
14 | class BaseLineDataSet(
15 | yValue: List,
16 | label: String
17 | ) : LineDataSet(yValue, label) {
18 |
19 | init {
20 | initAttrs()
21 | }
22 |
23 | private fun initAttrs() {
24 | DataSetDelegate().init(this)
25 |
26 | /**
27 | * 线涨跌相关设置
28 | */
29 | //模式
30 | mode = Mode.LINEAR
31 | setDrawCircles(false)
32 | setDrawCircleHole(false)
33 | circleRadius = 3f
34 | circleHoleRadius = 1f
35 | lineWidth = 0.75f
36 | }
37 | }
--------------------------------------------------------------------------------
/mpwrapper/src/main/java/com/matt/mpwrapper/view/data/CombinedDataControl.kt:
--------------------------------------------------------------------------------
1 | package com.matt.mpwrapper.view.data
2 |
3 | /**
4 | *
5 | * Author : wgyscsf@163.com
6 | * Github : https://github.com/scsfwgy
7 | * Date : 2020/8/8 5:03 PM
8 | * 描 述 :数据源控制器,保证数据源唯一且可控
9 | *
10 | **/
11 | class CombinedDataControl {
12 |
13 | val lineDataSetMap by lazy {
14 | HashMap()
15 | }
16 | val candleDataSetMap by lazy {
17 | HashMap()
18 | }
19 | val barDataSetMap by lazy {
20 | HashMap()
21 | }
22 |
23 | fun getLineDataSets(labels: Array): List {
24 | return labels.map {
25 | getLineDataSet(it)
26 | }
27 | }
28 |
29 |
30 | fun getLineDataSet(label: String, key: String? = null): BaseLineDataSet {
31 | val realKey = key ?: label
32 | val baseLineDataSet = lineDataSetMap[realKey]
33 | return if (baseLineDataSet == null) {
34 | val newBaseLineDataSet = BaseLineDataSet(ArrayList(), label)
35 | lineDataSetMap[realKey] = newBaseLineDataSet
36 | newBaseLineDataSet
37 | } else {
38 | baseLineDataSet
39 | }
40 | }
41 |
42 | fun getCandleDataSet(label: String, key: String? = null): BaseCandleDataSet {
43 | val realKey = key ?: label
44 | val baseLineDataSet = candleDataSetMap[realKey]
45 | return if (baseLineDataSet == null) {
46 | val newBaseLineDataSet = BaseCandleDataSet(ArrayList(), label)
47 | candleDataSetMap[realKey] = newBaseLineDataSet
48 | newBaseLineDataSet
49 | } else {
50 | baseLineDataSet
51 | }
52 | }
53 |
54 | fun getBarDataSets(labels: Array): List {
55 | return labels.map {
56 | getBarDataSet(it)
57 | }
58 | }
59 |
60 | fun getBarDataSet(label: String, key: String? = null): BaseBarDataSet {
61 | val realKey = key ?: label
62 | val baseLineDataSet = barDataSetMap[realKey]
63 | return if (baseLineDataSet == null) {
64 | val newBaseLineDataSet = BaseBarDataSet(ArrayList(), label)
65 | barDataSetMap[realKey] = newBaseLineDataSet
66 | newBaseLineDataSet
67 | } else {
68 | baseLineDataSet
69 | }
70 | }
71 |
72 | fun resetAll() {
73 | //清空数据,但是数据结构保留
74 | lineDataSetMap.forEach { entry ->
75 | entry.value.clear()
76 | }
77 | candleDataSetMap.forEach { entry ->
78 | entry.value.clear()
79 | }
80 | barDataSetMap.forEach { entry ->
81 | entry.value.clear()
82 | }
83 | }
84 |
85 | }
--------------------------------------------------------------------------------
/mpwrapper/src/main/java/com/matt/mpwrapper/view/delegate/DataSetDelegate.kt:
--------------------------------------------------------------------------------
1 | package com.matt.mpwrapper.view.delegate
2 |
3 | import com.github.mikephil.charting.components.YAxis
4 | import com.github.mikephil.charting.data.BarLineScatterCandleBubbleDataSet
5 | import com.github.mikephil.charting.data.Entry
6 | import com.github.mikephil.charting.data.LineScatterCandleRadarDataSet
7 |
8 | /**
9 | *
10 | * Author : wgyscsf@163.com
11 | * Github : https://github.com/scsfwgy
12 | * Date : 2020/7/12 12:03 PM
13 | * 描 述 :
14 | *
15 | **/
16 | class DataSetDelegate {
17 | fun init(dataSet: BarLineScatterCandleBubbleDataSet) {
18 | dataSet.run {
19 | //y轴模式
20 | axisDependency = YAxis.AxisDependency.RIGHT
21 |
22 | //每个item上绘制的值
23 | valueTextSize = 10f
24 | setDrawValues(false)
25 | setDrawIcons(false)
26 |
27 | //高亮线
28 | isHighlightEnabled = false
29 | }
30 | if (dataSet is LineScatterCandleRadarDataSet) {
31 | dataSet.run {
32 | setDrawHorizontalHighlightIndicator(false)
33 | setDrawVerticalHighlightIndicator(true)
34 | highlightLineWidth = 0.5f
35 | }
36 | }
37 | }
38 | }
--------------------------------------------------------------------------------
/mpwrapper/src/main/java/com/matt/mpwrapper/view/delegate/IChartViewDelegate.kt:
--------------------------------------------------------------------------------
1 | package com.matt.mpwrapper.view.delegate
2 |
3 | /**
4 | *
5 | * Author : wgyscsf@163.com
6 | * Github : https://github.com/scsfwgy
7 | * Date : 2020/8/9 10:56 AM
8 | * 描 述 :
9 | *
10 | **/
11 | interface IChartViewDelegate {
12 | fun getChartViewDelegate(): BaseKViewDelegate
13 | }
--------------------------------------------------------------------------------
/mpwrapper/src/main/java/com/matt/mpwrapper/view/delegate/VolViewDelegate.kt:
--------------------------------------------------------------------------------
1 | package com.matt.mpwrapper.view.delegate
2 |
3 | import com.github.mikephil.charting.components.AxisBase
4 | import com.github.mikephil.charting.components.LegendEntry
5 | import com.github.mikephil.charting.data.Entry
6 | import com.github.mikephil.charting.formatter.ValueFormatter
7 | import com.github.mikephil.charting.highlight.Highlight
8 | import com.github.mikephil.charting.listener.OnChartValueSelectedListener
9 | import com.matt.mpwrapper.R
10 | import com.matt.mpwrapper.bean.Vol
11 | import com.matt.mpwrapper.bean.VolData
12 | import com.matt.mpwrapper.utils.TimeUtils
13 | import com.matt.mpwrapper.view.VolView
14 | import com.matt.mpwrapper.view.type.VolIndicatorType
15 | import com.matt.mpwrapper.view.type.VolType
16 |
17 | /**
18 | * ============================================================
19 | * 作 者 : matt
20 | * 更新时间 :2020/03/07 15:14
21 | * 描 述 :
22 | * ============================================================
23 | */
24 | class VolViewDelegate(val mVolView: VolView) : BaseKViewDelegate(mVolView) {
25 |
26 | var mVolIndicatorType: VolIndicatorType = VolIndicatorType.VOL_MA
27 |
28 | val mVolBarColorArr by lazy {
29 | arrayOf(
30 | mUpColor,
31 | mDownColor
32 | )
33 | }
34 |
35 | val mVolMaColorArr by lazy {
36 | arrayOf(
37 | getColor(R.color.mp_volview_ma5),
38 | getColor(R.color.mp_volview_ma10)
39 | )
40 | }
41 |
42 |
43 | val mVolBarDataSetArr by lazy {
44 | mCombinedDataControl.getBarDataSets(
45 | arrayOf(
46 | VolType.VOL.toString() + 0,
47 | VolType.VOL.toString() + 1
48 | )
49 | ).mapIndexed { index, baseLineDataSet ->
50 | baseLineDataSet.color = mVolBarColorArr[index]
51 | baseLineDataSet
52 | }.toTypedArray()
53 | }
54 |
55 | val mVolMaLineDataSetArr by lazy {
56 | mCombinedDataControl.getLineDataSets(
57 | arrayOf(
58 | VolType.MA5.toString(),
59 | VolType.MA10.toString()
60 | )
61 | ).mapIndexed { index, baseLineDataSet ->
62 | baseLineDataSet.color = mVolMaColorArr[index]
63 | baseLineDataSet
64 | }.toTypedArray()
65 | }
66 |
67 |
68 | override fun initChart() {
69 | super.initChart()
70 | mVolView.run {
71 | axisRight.setLabelCount(3, true)
72 |
73 | xAxis.setDrawLabels(true)
74 | xAxis.valueFormatter = object : ValueFormatter() {
75 | override fun getAxisLabel(value: Float, axis: AxisBase): String {
76 | val kViewData = mBaseInit.kViewDataList()
77 | val valueInt = value.toInt()
78 | val size = kViewData.size
79 | val index = if (valueInt < size) valueInt else size - 1
80 | val price = kViewData[index].price
81 | ?: throw IllegalArgumentException("price字段为null,不允许为null")
82 | return TimeUtils.millis2String(price.t, TimeUtils.getFormat("HH:mm:ss"))
83 | }
84 | }
85 |
86 | setOnChartValueSelectedListener(object : OnChartValueSelectedListener {
87 | override fun onNothingSelected() {
88 | showLegend(
89 | getVolDataByIndex(mBaseKView.mBaseInit.kViewDataList().size - 1),
90 | false
91 | )
92 | }
93 |
94 | override fun onValueSelected(e: Entry, h: Highlight) {
95 | //这样使用的前提是设置值的时候x轴是用的list的索引
96 | val index = e.x.toInt()
97 | showLegend(getVolDataByIndex(index), true)
98 | }
99 |
100 | })
101 | }
102 | }
103 |
104 | fun showLegend(volData: VolData?, press: Boolean) {
105 | val volView = mVolView
106 | val vol = volData?.vol ?: throw IllegalArgumentException("VolData or vol is null")
107 | val legend = generateLegend(volView.legend)
108 | val legendEntryArr = getVolLegend(vol, press)
109 | legend.isEnabled = true
110 | legend.setCustom(legendEntryArr)
111 | volView.legendRenderer.computeLegend(mBaseKView.data)
112 | }
113 |
114 | fun getVolLegend(vol: Vol, press: Boolean): Array {
115 | return if (press) {
116 | val dif =
117 | generateLegendEntry(mVolMaColorArr[0], "MA5 " + numFormat(vol.volMa5))
118 | val dea = generateLegendEntry(mVolMaColorArr[1], "MA10 " + numFormat(vol.volMa10))
119 | val vols = vol.vol ?: 0.0f
120 | val volData =
121 | generateLegendEntry(
122 | if (vols > 0.0f) mVolBarColorArr[0] else mVolBarColorArr[1],
123 | "VOL " + numFormat(vols)
124 | )
125 | arrayOf(dif, dea, volData)
126 | } else {
127 | getUnPressLegend("VOL,MA(5,10)")
128 | }
129 | }
130 |
131 | fun setVolDataSetArrVisible(visible: Boolean) {
132 | setLineDataSetArrVisible(mVolMaLineDataSetArr, visible)
133 | setBarDataSetArrVisible(mVolBarDataSetArr, visible)
134 | }
135 |
136 | fun showIndicatorType(toNext: Boolean) {
137 | setVolDataSetArrVisible(true)
138 | //默认高亮线对应的line一定要显示
139 | setLineDataSetArrVisible(arrayOf(mShowHighlightLineData), true)
140 | }
141 | }
--------------------------------------------------------------------------------
/mpwrapper/src/main/java/com/matt/mpwrapper/view/listener/BaseBarLineChartTouchListener.kt:
--------------------------------------------------------------------------------
1 | package com.matt.mpwrapper.view.listener
2 |
3 | import android.graphics.Matrix
4 | import android.view.MotionEvent
5 | import android.view.View
6 | import com.github.mikephil.charting.charts.BarLineChartBase
7 | import com.github.mikephil.charting.charts.CombinedChart
8 | import com.github.mikephil.charting.data.BarLineScatterCandleBubbleData
9 | import com.github.mikephil.charting.data.Entry
10 | import com.github.mikephil.charting.interfaces.datasets.IBarLineScatterCandleBubbleDataSet
11 | import com.github.mikephil.charting.listener.BarLineChartTouchListener
12 | import com.github.mikephil.charting.listener.ChartTouchListener
13 |
14 | /**
15 | *
16 | * Author : wgyscsf@163.com
17 | * Github : https://github.com/scsfwgy
18 | * Date : 2020/6/26 11:49 AM
19 | * 描 述 :
20 | *
21 | **/
22 | open class BaseBarLineChartTouchListener(
23 | chart: BarLineChartBase>>,
24 | touchMatrix: Matrix, dragTriggerDistance: Float
25 | ) :
26 | BarLineChartTouchListener(chart, touchMatrix, dragTriggerDistance) {
27 |
28 | override fun onTouch(v: View, event: MotionEvent): Boolean {
29 | when (event.action) {
30 | MotionEvent.ACTION_DOWN -> {
31 |
32 | }
33 | MotionEvent.ACTION_MOVE -> {
34 | onActionMove(v, event)
35 | }
36 | MotionEvent.ACTION_UP -> {
37 |
38 | }
39 | }
40 | return super.onTouch(v, event)
41 | }
42 |
43 | open fun onActionMove(v: View, event: MotionEvent) {
44 | highlightByMove(event)
45 | }
46 |
47 | /**
48 | * 滑动时展示高亮线,触发条件:当[mChart.valuesToHighlight()]触发才会触发此动作
49 | */
50 | open fun highlightByMove(event: MotionEvent) {
51 | val chart = mChart
52 | val valuesToHighlight = chart.valuesToHighlight()
53 | if (valuesToHighlight) {
54 | triggerHighlight(event, true)
55 | }
56 | }
57 |
58 | override fun startAction(me: MotionEvent) {
59 | super.startAction(me)
60 | }
61 |
62 | override fun endAction(me: MotionEvent) {
63 | super.endAction(me)
64 | }
65 |
66 | override fun onDoubleTapEvent(e: MotionEvent): Boolean {
67 | return super.onDoubleTapEvent(e)
68 | }
69 |
70 | override fun onDoubleTap(e: MotionEvent): Boolean {
71 | return super.onDoubleTap(e)
72 | }
73 |
74 | /**
75 | * 触发单击,不会继续出发双击
76 | */
77 | override fun onSingleTapConfirmed(e: MotionEvent): Boolean {
78 | return super.onSingleTapConfirmed(e)
79 | }
80 |
81 | /**
82 | * 单击抬起手指,可能会继续出发双击
83 | */
84 | override fun onSingleTapUp(e: MotionEvent): Boolean {
85 | triggerHighlight(e, false)
86 | return super.onSingleTapUp(e)
87 | }
88 |
89 | /**
90 | * 长按触发
91 | */
92 | override fun onLongPress(e: MotionEvent) {
93 | super.onLongPress(e)
94 | val touchMode = touchMode
95 | //拖动时不触发高亮线
96 | if (touchMode == ChartTouchListener.DRAG ||
97 | touchMode == MotionEvent.ACTION_UP ||
98 | touchMode == MotionEvent.ACTION_CANCEL ||
99 | touchMode == MotionEvent.ACTION_MOVE
100 | ) {
101 | return
102 | }
103 | triggerHighlight(e, true)
104 | }
105 |
106 | open fun triggerHighlight(e: MotionEvent, showHighlight: Boolean) {
107 | val chart = mChart
108 | if (chart !is CombinedChart) {
109 | throw IllegalArgumentException("BaseBarLineChartTouchListener只允许用在CombinedChart中,请检查")
110 | }
111 | val followCharts = getFollowCharts()
112 | triggerHighlightByChart(chart, e, showHighlight)
113 | followCharts.forEach {
114 | triggerHighlightByChart(it, e, showHighlight)
115 | }
116 | }
117 |
118 | fun triggerHighlightByChart(chart: CombinedChart, e: MotionEvent, showHighlight: Boolean) {
119 | if (showHighlight) {
120 | chart.isDragEnabled = false
121 | val highlightByTouchPoint = chart.getHighlightByTouchPoint(e.x, e.y)
122 | chart.highlightValue(highlightByTouchPoint, true)
123 | } else {
124 | chart.isDragEnabled = true
125 | chart.highlightValue(null, true)
126 |
127 | }
128 | }
129 |
130 | private fun getFollowCharts(): Array {
131 | val chart = mChart
132 | val onChartGestureListener = chart.onChartGestureListener
133 | if (onChartGestureListener is LinkChartListener) {
134 | return onChartGestureListener.getFollowCharts()
135 | } else {
136 | throw IllegalArgumentException(
137 | "onChartGestureListener类型错误," +
138 | "LinkChartListener没有继承OnChartGestureListener实现联动。"
139 | )
140 | }
141 | }
142 |
143 | }
--------------------------------------------------------------------------------
/mpwrapper/src/main/java/com/matt/mpwrapper/view/listener/LinkChartListener.kt:
--------------------------------------------------------------------------------
1 | package com.matt.mpwrapper.view.listener
2 |
3 | import android.view.MotionEvent
4 | import com.github.mikephil.charting.charts.CombinedChart
5 | import com.github.mikephil.charting.listener.ChartTouchListener
6 | import com.github.mikephil.charting.listener.OnChartGestureListener
7 |
8 | /**
9 | *
10 | * Author : wgyscsf@163.com
11 | * Github : https://github.com/scsfwgy
12 | * Date : 2020/6/27 8:58 PM
13 | * 描 述 :
14 | *
15 | **/
16 | class LinkChartListener(
17 | private val mMasterChart: CombinedChart,
18 | private val mFollowCharts: Array
19 | ) :
20 | OnChartGestureListener {
21 |
22 | fun getFollowCharts(): Array {
23 | return mFollowCharts
24 | }
25 |
26 |
27 | fun linkCharts() {
28 | val masterMatrix = mMasterChart.viewPortHandler.matrixTouch
29 | val masterValue = FloatArray(9) {
30 | 0f
31 | }
32 | masterMatrix.getValues(masterValue)
33 |
34 | val followValue = FloatArray(9) {
35 | 0f
36 | }
37 |
38 | mFollowCharts.forEach {
39 | it.viewPortHandler.matrixTouch.getValues(followValue)
40 | }
41 |
42 | masterValue.forEachIndexed { index, fl ->
43 | followValue[index] = fl
44 | }
45 |
46 | mFollowCharts.forEach {
47 | it.viewPortHandler.matrixTouch.setValues(followValue)
48 | }
49 |
50 | mFollowCharts.forEach {
51 | it.viewPortHandler.refresh(it.viewPortHandler.matrixTouch, it, true)
52 | }
53 | }
54 |
55 | override fun onChartGestureEnd(
56 | me: MotionEvent,
57 | lastPerformedGesture: ChartTouchListener.ChartGesture
58 | ) {
59 | linkCharts()
60 | }
61 |
62 | override fun onChartFling(
63 | me1: MotionEvent,
64 | me2: MotionEvent,
65 | velocityX: Float,
66 | velocityY: Float
67 | ) {
68 | linkCharts()
69 |
70 | }
71 |
72 | override fun onChartSingleTapped(me: MotionEvent) {
73 | linkCharts()
74 |
75 | }
76 |
77 | override fun onChartGestureStart(
78 | me: MotionEvent,
79 | lastPerformedGesture: ChartTouchListener.ChartGesture
80 | ) {
81 | linkCharts()
82 |
83 | }
84 |
85 | override fun onChartScale(me: MotionEvent, scaleX: Float, scaleY: Float) {
86 | linkCharts()
87 |
88 | }
89 |
90 | override fun onChartLongPressed(me: MotionEvent) {
91 | linkCharts()
92 |
93 | }
94 |
95 | override fun onChartDoubleTapped(me: MotionEvent) {
96 | linkCharts()
97 |
98 | }
99 |
100 | override fun onChartTranslate(me: MotionEvent, dX: Float, dY: Float) {
101 | linkCharts()
102 | }
103 | }
--------------------------------------------------------------------------------
/mpwrapper/src/main/java/com/matt/mpwrapper/view/renderer/BaseCombinedChartRenderer.kt:
--------------------------------------------------------------------------------
1 | package com.matt.mpwrapper.view.renderer
2 |
3 | import com.github.mikephil.charting.animation.ChartAnimator
4 | import com.github.mikephil.charting.charts.CombinedChart
5 | import com.github.mikephil.charting.charts.CombinedChart.DrawOrder
6 | import com.github.mikephil.charting.renderer.BarChartRenderer
7 | import com.github.mikephil.charting.renderer.BubbleChartRenderer
8 | import com.github.mikephil.charting.renderer.CombinedChartRenderer
9 | import com.github.mikephil.charting.renderer.ScatterChartRenderer
10 | import com.github.mikephil.charting.utils.ViewPortHandler
11 |
12 | /**
13 | * ============================================================
14 | * 作 者 : matt@163.com
15 | * 更新时间 :2018/09/30 14:41
16 | * 描 述 :CombinedChart的渲染器,本质上来说只是一个容器,主要作用遍历子组件获取子组件的渲染器。
17 | * 因此想要重写子组件渲染器,需要重写这个渲染器进而添加子组件的渲染器。
18 | * ============================================================
19 | */
20 | class BaseCombinedChartRenderer(
21 | chart: CombinedChart,
22 | animator: ChartAnimator,
23 | viewPortHandler: ViewPortHandler
24 | ) : CombinedChartRenderer(chart, animator, viewPortHandler) {
25 | private var mDrawLineRenderLastCircle = false
26 |
27 | /**
28 | * 重写这个方法主要为了重写内部子渲染器
29 | */
30 | override fun createRenderers() {
31 | mRenderers.clear()
32 | val chart = mChart.get()
33 | if (chart !is CombinedChart) return
34 | val orders = chart.drawOrder
35 | for (order in orders) {
36 | if (order == null) continue
37 | val dataRenderer = when (order) {
38 | DrawOrder.BAR -> {
39 | if (chart.barData != null) {
40 | BarChartRenderer(chart, mAnimator, mViewPortHandler)
41 | } else {
42 | null
43 | }
44 | }
45 | DrawOrder.BUBBLE -> {
46 | if (chart.bubbleData != null) {
47 | BubbleChartRenderer(chart, mAnimator, mViewPortHandler)
48 | } else {
49 | null
50 | }
51 | }
52 | DrawOrder.LINE -> {
53 | if (chart.lineData != null) {
54 | val baseLineChartRenderer =
55 | BaseLineChartRenderer(chart, mAnimator, mViewPortHandler)
56 | baseLineChartRenderer.setDrawLastCircles(isDrawLineRenderLastCircle())
57 | baseLineChartRenderer
58 | } else {
59 | null
60 | }
61 | }
62 | DrawOrder.CANDLE -> {
63 | if (chart.candleData != null) {
64 | MasterViewCandleStickChartRenderer(chart, mAnimator, mViewPortHandler)
65 | } else {
66 | null
67 | }
68 | }
69 | DrawOrder.SCATTER -> {
70 | if (chart.scatterData != null) {
71 | ScatterChartRenderer(chart, mAnimator, mViewPortHandler)
72 | } else {
73 | null
74 | }
75 | }
76 | else -> null
77 | }
78 | if (dataRenderer != null) {
79 | mRenderers.add(dataRenderer)
80 | }
81 | }
82 | }
83 |
84 | fun isDrawLineRenderLastCircle(): Boolean {
85 | return mDrawLineRenderLastCircle
86 | }
87 |
88 | fun setDrawLineRenderLastCircle(mDrawLineRenderLastCircle: Boolean): BaseCombinedChartRenderer {
89 | this.mDrawLineRenderLastCircle = mDrawLineRenderLastCircle
90 | return this
91 | }
92 | }
--------------------------------------------------------------------------------
/mpwrapper/src/main/java/com/matt/mpwrapper/view/renderer/BaseLineChartRenderer.kt:
--------------------------------------------------------------------------------
1 | package com.matt.mpwrapper.view.renderer
2 |
3 | import android.graphics.Canvas
4 | import android.graphics.Paint
5 | import com.github.mikephil.charting.animation.ChartAnimator
6 | import com.github.mikephil.charting.interfaces.dataprovider.LineDataProvider
7 | import com.github.mikephil.charting.renderer.LineChartRenderer
8 | import com.github.mikephil.charting.utils.ViewPortHandler
9 |
10 | /**
11 | * ============================================================
12 | * 作 者 : matt@163.com
13 | * 更新时间 :2018/10/16 17:37
14 | * 描 述 :实现可以只绘制最后一个小圆点,如果设置mDrawLastCircles=true则不再走原有逻辑,只绘制最后一个小圆点。
15 | */
16 | open class BaseLineChartRenderer(
17 | chart: LineDataProvider,
18 | val animator: ChartAnimator,
19 | viewPortHandler: ViewPortHandler
20 | ) : LineChartRenderer(chart, animator, viewPortHandler) {
21 | /**
22 | * 是否只绘制最后一个小圆点
23 | */
24 | var mDrawLastCircles = false
25 |
26 | private val mCirclesBuffer = FloatArray(2)
27 | override fun drawExtras(c: Canvas) {
28 | if (isDrawLastCircles()) {
29 | drawLastCircle(c)
30 | }
31 | super.drawExtras(c)
32 | }
33 |
34 | /**
35 | * 绘制最后一个小圆点
36 | *
37 | * @param c
38 | */
39 | fun drawLastCircle(c: Canvas) {
40 | mRenderPaint.style = Paint.Style.FILL
41 | val phaseY: Float = animator.phaseY
42 | mCirclesBuffer[0] = 0f
43 | mCirclesBuffer[1] = 0f
44 | val dataSets = mChart.lineData.dataSets
45 | if (dataSets == null || dataSets.isEmpty()) return
46 | val dataSet = dataSets[dataSets.size - 1]
47 | if (!dataSet.isVisible || dataSet.entryCount == 0) return
48 | mRenderPaint.color = dataSet.getCircleColor(0)
49 | mCirclePaintInner.color = dataSet.circleHoleColor
50 | val trans = mChart.getTransformer(dataSet.axisDependency)
51 | mXBounds[mChart] = dataSet
52 | val circleRadius = dataSet.circleRadius
53 | val circleHoleRadius = dataSet.circleHoleRadius
54 | val drawCircleHole =
55 | dataSet.isDrawCircleHoleEnabled && circleHoleRadius < circleRadius && circleHoleRadius > 0f
56 | val e = dataSet.getEntryForIndex(dataSet.entryCount - 1) ?: return
57 | mCirclesBuffer[0] = e.x
58 | mCirclesBuffer[1] = e.y * phaseY
59 | trans.pointValuesToPixel(mCirclesBuffer)
60 | if (!mViewPortHandler.isInBoundsRight(mCirclesBuffer[0])) return
61 | if (!mViewPortHandler.isInBoundsLeft(mCirclesBuffer[0]) ||
62 | !mViewPortHandler.isInBoundsY(mCirclesBuffer[1])
63 | ) return
64 | c.drawCircle(
65 | mCirclesBuffer[0],
66 | mCirclesBuffer[1],
67 | circleRadius,
68 | mRenderPaint
69 | )
70 | if (drawCircleHole) {
71 | c.drawCircle(mCirclesBuffer[0], mCirclesBuffer[1], circleHoleRadius, mCirclePaintInner)
72 | }
73 | }
74 |
75 | fun isDrawLastCircles(): Boolean {
76 | return mDrawLastCircles
77 | }
78 |
79 | fun setDrawLastCircles(mDrawLastCircles: Boolean): BaseLineChartRenderer {
80 | this.mDrawLastCircles = mDrawLastCircles
81 | return this
82 | }
83 | }
--------------------------------------------------------------------------------
/mpwrapper/src/main/java/com/matt/mpwrapper/view/renderer/MasterViewCandleStickChartRenderer.kt:
--------------------------------------------------------------------------------
1 | package com.matt.mpwrapper.view.renderer
2 |
3 | import android.graphics.Canvas
4 | import com.github.mikephil.charting.animation.ChartAnimator
5 | import com.github.mikephil.charting.highlight.Highlight
6 | import com.github.mikephil.charting.interfaces.dataprovider.CandleDataProvider
7 | import com.github.mikephil.charting.renderer.CandleStickChartRenderer
8 | import com.github.mikephil.charting.utils.ViewPortHandler
9 |
10 | /**
11 | * ============================================================
12 | * 作 者 : matt@163.com
13 | * 更新时间 :2018/09/30 14:35
14 | * 描 述 :长按高亮线交叉点显示(最大值+最小值)/2.0f,修改为显示收盘价。
15 | * ============================================================
16 | */
17 | class MasterViewCandleStickChartRenderer(
18 | chart: CandleDataProvider,
19 | animator: ChartAnimator,
20 | viewPortHandler: ViewPortHandler
21 | ) : CandleStickChartRenderer(chart, animator, viewPortHandler) {
22 |
23 |
24 | override fun drawHighlighted(c: Canvas, indices: Array) {
25 | val candleData = mChart.candleData
26 | for (high in indices) {
27 | val set = candleData.getDataSetByIndex(high.dataSetIndex)
28 | if (set == null || !set.isHighlightEnabled) continue
29 | val e = set.getEntryForXValue(high.x, high.y)
30 | if (!isInBoundsX(e, set)) continue
31 | //float lowValue = e.getLow() * mAnimator.getPhaseY();
32 | //float highValue = e.getHigh() * mAnimator.getPhaseY();
33 | //float y = (lowValue + highValue) / 2f;
34 | //重写这个值
35 | val closeValue = e.close * mAnimator.phaseY
36 | val pix =
37 | mChart.getTransformer(set.axisDependency).getPixelForValues(e.x, closeValue)
38 | high.setDraw(pix.x.toFloat(), pix.y.toFloat())
39 | // draw the lines
40 | drawHighlightLines(c, pix.x.toFloat(), pix.y.toFloat(), set)
41 | }
42 | }
43 | }
--------------------------------------------------------------------------------
/mpwrapper/src/main/java/com/matt/mpwrapper/view/type/BollType.kt:
--------------------------------------------------------------------------------
1 | package com.matt.mpwrapper.view.type
2 |
3 | /**
4 | * ============================================================
5 | * 作 者 : matt
6 | * 更新时间 :2020/03/07 15:50
7 | * 描 述 :
8 | * ============================================================
9 | */
10 | enum class BollType {
11 | UP,
12 | MD,
13 | DN,
14 | }
--------------------------------------------------------------------------------
/mpwrapper/src/main/java/com/matt/mpwrapper/view/type/KType.java:
--------------------------------------------------------------------------------
1 | package com.matt.mpwrapper.view.type;
2 |
3 | import androidx.annotation.NonNull;
4 |
5 | import java.util.ArrayList;
6 | import java.util.List;
7 |
8 | /**
9 | * ============================================================
10 | * 作 者 : freer-2
11 | * 更新时间 :2019/09/09 17:41
12 | * 描 述 :
13 | * ============================================================
14 | */
15 | public enum KType {
16 | K_TIMESHARE("分时", 1, "1m"),
17 | K_1MIN("1分", 2, "1m"),
18 | K_5MIN("5分", 3, "5m"),
19 | K_15MIN("15分", 4, "15m"),
20 | K_30MIN("30分", 5, "30m"),
21 | K_1HOUR("1小时", 6, "1h"),
22 | K_4HOUR("4小时", 7, "4h"),
23 | K_1D("1天", 8, "1d"),
24 | K_1W("1周", 9, "1w"),
25 | K_1M("1月", 10, "1mon");
26 |
27 | private String mLable;
28 | private int mId;
29 | private String mApiType;
30 |
31 | KType(String lable, int id, String apiType) {
32 | this.mLable = lable;
33 | this.mId = id;
34 | this.mApiType = apiType;
35 | }
36 |
37 | @NonNull
38 | public static List getKTypeList() {
39 | List kTypeList = new ArrayList<>();
40 | kTypeList.add(K_TIMESHARE);
41 | kTypeList.add(K_1MIN);
42 | kTypeList.add(K_5MIN);
43 | kTypeList.add(K_15MIN);
44 | kTypeList.add(K_30MIN);
45 | kTypeList.add(K_1HOUR);
46 | kTypeList.add(K_4HOUR);
47 | kTypeList.add(K_1D);
48 | kTypeList.add(K_1W);
49 | kTypeList.add(K_1M);
50 | return kTypeList;
51 | }
52 |
53 | @NonNull
54 | public static List getTitleList() {
55 | List kTypeList = getKTypeList();
56 | List titleList = new ArrayList<>();
57 | for (KType kType : kTypeList) {
58 | titleList.add(kType.mLable);
59 | }
60 | return titleList;
61 | }
62 |
63 | public String getmLable() {
64 | return mLable;
65 | }
66 |
67 | public int getmId() {
68 | return mId;
69 | }
70 |
71 | public String getmApiType() {
72 | return mApiType;
73 | }
74 |
75 | public boolean isTimeShare() {
76 | return mId == 1;
77 | }
78 |
79 | /**
80 | * 是否是大日期
81 | *
82 | * @return
83 | */
84 | public boolean isMaxLenDate() {
85 | return this == KType.K_1D || this == KType.K_1W || this == KType.K_1M;
86 | }
87 | }
--------------------------------------------------------------------------------
/mpwrapper/src/main/java/com/matt/mpwrapper/view/type/KdjType.kt:
--------------------------------------------------------------------------------
1 | package com.matt.mpwrapper.view.type
2 |
3 | /**
4 | * ============================================================
5 | * 作 者 : matt
6 | * 更新时间 :2020/03/07 15:50
7 | * 描 述 :
8 | * ============================================================
9 | */
10 | enum class KdjType {
11 | K,
12 | D,
13 | J,
14 | }
--------------------------------------------------------------------------------
/mpwrapper/src/main/java/com/matt/mpwrapper/view/type/MaType.kt:
--------------------------------------------------------------------------------
1 | package com.matt.mpwrapper.view.type
2 |
3 | /**
4 | * ============================================================
5 | * 作 者 : matt
6 | * 更新时间 :2020/03/07 15:50
7 | * 描 述 :
8 | * ============================================================
9 | */
10 | enum class MaType {
11 | MA5,
12 | MA10,
13 | MA20,
14 | }
--------------------------------------------------------------------------------
/mpwrapper/src/main/java/com/matt/mpwrapper/view/type/MacdType.kt:
--------------------------------------------------------------------------------
1 | package com.matt.mpwrapper.view.type
2 |
3 | /**
4 | * ============================================================
5 | * 作 者 : matt
6 | * 更新时间 :2020/03/07 15:50
7 | * 描 述 :
8 | * ============================================================
9 | */
10 | enum class MacdType {
11 | DIF,
12 | DEA,
13 | MACD,
14 | }
--------------------------------------------------------------------------------
/mpwrapper/src/main/java/com/matt/mpwrapper/view/type/MasterIndicatorType.kt:
--------------------------------------------------------------------------------
1 | package com.matt.mpwrapper.view.type
2 |
3 | /**
4 | * ============================================================
5 | * 作 者 : matt
6 | * 更新时间 :2020/03/10 12:21
7 | * 描 述 :
8 | * ============================================================
9 | */
10 | enum class MasterIndicatorType {
11 | //无
12 | NONE,
13 |
14 | //MA5、10、20
15 | MA,
16 |
17 | //BOLL(26)
18 | BOLL
19 | }
--------------------------------------------------------------------------------
/mpwrapper/src/main/java/com/matt/mpwrapper/view/type/MasterViewType.kt:
--------------------------------------------------------------------------------
1 | package com.matt.mpwrapper.view.type
2 |
3 | /**
4 | * ============================================================
5 | * 作 者 : matt
6 | * 更新时间 :2020/03/07 15:21
7 | * 描 述 :
8 | * ============================================================
9 | */
10 | enum class MasterViewType {
11 | TIMESHARING,
12 | CANDLE
13 | }
--------------------------------------------------------------------------------
/mpwrapper/src/main/java/com/matt/mpwrapper/view/type/MinorIndicatorType.kt:
--------------------------------------------------------------------------------
1 | package com.matt.mpwrapper.view.type
2 |
3 | /**
4 | * ============================================================
5 | * 作 者 : matt
6 | * 更新时间 :2020/03/10 12:21
7 | * 描 述 :
8 | * ============================================================
9 | */
10 | enum class MinorIndicatorType {
11 | MACD,
12 | RSI,
13 | KDJ
14 | }
--------------------------------------------------------------------------------
/mpwrapper/src/main/java/com/matt/mpwrapper/view/type/RsiType.kt:
--------------------------------------------------------------------------------
1 | package com.matt.mpwrapper.view.type
2 |
3 | /**
4 | * ============================================================
5 | * 作 者 : matt
6 | * 更新时间 :2020/03/07 15:50
7 | * 描 述 :
8 | * ============================================================
9 | */
10 | enum class RsiType {
11 | RSI6,
12 | RSI12,
13 | RSI24,
14 | }
--------------------------------------------------------------------------------
/mpwrapper/src/main/java/com/matt/mpwrapper/view/type/VolIndicatorType.kt:
--------------------------------------------------------------------------------
1 | package com.matt.mpwrapper.view.type
2 |
3 | /**
4 | * ============================================================
5 | * 作 者 : wgyscsf@163.com
6 | * 创建日期 :2020/9/15 7:09 PM
7 | * 描 述 :
8 | * ============================================================
9 | **/
10 | enum class VolIndicatorType {
11 | GONE,
12 | VOL,
13 | VOL_MA
14 | }
--------------------------------------------------------------------------------
/mpwrapper/src/main/java/com/matt/mpwrapper/view/type/VolType.kt:
--------------------------------------------------------------------------------
1 | package com.matt.mpwrapper.view.type
2 |
3 | /**
4 | *
5 | * Author : wgyscsf@163.com
6 | * Github : https://github.com/scsfwgy
7 | * Date : 2020/7/25 9:17 PM
8 | * 描 述 :
9 | *
10 | **/
11 | enum class VolType {
12 | VOL,
13 | MA5,
14 | MA10,
15 | }
--------------------------------------------------------------------------------
/mpwrapper/src/main/res/drawable/shape_gradient_filled.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
11 |
--------------------------------------------------------------------------------
/mpwrapper/src/main/res/drawable/shape_markerview_bg.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/mpwrapper/src/main/res/layout/mp_widget_kview.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
13 |
14 |
19 |
20 |
25 |
26 |
--------------------------------------------------------------------------------
/mpwrapper/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #ff000000
4 | #303F9F
5 | #FF4081
6 |
7 |
8 | #ec3627
9 | #5dab52
10 | #959599
11 | #4c9ff4
12 | #e8f1fe
13 | #ff0000
14 |
15 | #1e15c7
16 | #ff000000
17 | #ff000000
18 | #8a8a8b
19 | #8a8a8b
20 | #8a8a8b
21 | #8a8a8b
22 | #8a8a8b
23 | #8a8a8b
24 | #8a8a8b
25 |
26 | #8a8a8b
27 |
28 |
29 | #ffffff
30 | #CC000000
31 | #ed3820
32 | #ffffff
33 |
34 |
35 |
36 |
37 | #f29b3d
38 | #f347f9
39 | #4dfd9f
40 |
41 | #ed978f
42 | #136ad6
43 | #7897b9
44 |
45 | #f7462e
46 | #1666fa
47 |
48 | #f29b3d
49 |
50 |
51 |
52 |
53 | #f29b3d
54 | #f347f9
55 | #4dfd9f
56 |
57 | #ed978f
58 | #136ad6
59 | #7897b9
60 |
61 | #ed978f
62 | #136ad6
63 | #7897b9
64 |
65 |
66 | #f29b3d
67 | #f347f9
68 |
69 |
70 |
71 |
--------------------------------------------------------------------------------
/mpwrapper/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | --
4 |
--------------------------------------------------------------------------------
/mpwrapper/src/test/java/com/matt/mpwrapper/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package com.matt.mpwrapper
2 |
3 | import org.junit.Assert.assertEquals
4 | import org.junit.Test
5 |
6 | /**
7 | * Example local unit test, which will execute on the development machine (host).
8 | *
9 | * See [testing documentation](http://d.android.com/tools/testing).
10 | */
11 | class ExampleUnitTest {
12 | @Test
13 | fun addition_isCorrect() {
14 | assertEquals(4, 2 + 2)
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/mpwrapper/src/test/java/com/matt/mpwrapper/utils/MathUtilTest.kt:
--------------------------------------------------------------------------------
1 | package com.matt.mpwrapper.utils
2 |
3 | import org.junit.Test
4 |
5 | import org.junit.Assert.*
6 |
7 | /**
8 | * ============================================================
9 | * 作 者 : wgyscsf@163.com
10 | * 创建日期 :2020/8/10 11:35 AM
11 | * 描 述 :
12 | * ============================================================
13 | */
14 | class MathUtilTest {
15 |
16 | @Test
17 | fun add() {
18 | }
19 |
20 | @Test
21 | fun subtract() {
22 | }
23 |
24 | @Test
25 | fun multiply() {
26 | }
27 |
28 | @Test
29 | fun divide() {
30 | val divide = MathUtil.divide(1.0, 0.001)
31 | println(divide)
32 | }
33 | }
--------------------------------------------------------------------------------
/mpwrapper/src/test/java/com/matt/mpwrapper/view/FinancialAlgorithmTest.kt:
--------------------------------------------------------------------------------
1 | package com.matt.mpwrapper.view
2 |
3 | import org.junit.Test
4 |
5 | /**
6 | *
7 | * Author : wgyscsf@163.com
8 | * Github : https://github.com/scsfwgy
9 | * Date : 2020/6/26 5:13 PM
10 | * 描 述 :
11 | *
12 | **/
13 | class FinancialAlgorithmTest {
14 | @Test
15 | fun calculateMATest() {
16 | val list = listOf(1f, 2f, 3f, 4f, 5f, 6f, 7f, 8f, 9f, 10f)
17 | val calculateMA = FinancialAlgorithm.calculateMA(list, 5)
18 | println(calculateMA)
19 |
20 | val calculateBOLL = FinancialAlgorithm.calculateBOLL(list)
21 | println(calculateBOLL)
22 | }
23 | }
--------------------------------------------------------------------------------
/sample_base/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/sample_base/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 | apply from: rootProject.file('lib_common.gradle')
3 |
4 |
5 | android {
6 | defaultConfig {
7 | versionCode 1
8 | versionName "1.0"
9 | }
10 | }
11 |
12 | dependencies {
13 | //https://github.com/scsfwgy/TemplateApp
14 | api 'com.github.scsfwgy:TemplateApp:0.0.7'
15 |
16 | //核心k线包装库
17 | api project(path: ':mpwrapper')
18 |
19 |
20 | //本地依赖方式
21 | //api project(path: ':lib_wrapper')
22 | //mp包装库
23 | }
--------------------------------------------------------------------------------
/sample_base/consumer-rules.pro:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/scsfwgy/MPAndroidChartWrapper/a074ff292811a2b6307b150d6bdbd8ef7fcdbea1/sample_base/consumer-rules.pro
--------------------------------------------------------------------------------
/sample_base/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
--------------------------------------------------------------------------------
/sample_base/src/androidTest/java/com/matt/sample_base/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package com.matt.sample_base
2 |
3 | import androidx.test.ext.junit.runners.AndroidJUnit4
4 | import androidx.test.platform.app.InstrumentationRegistry
5 | import org.junit.Assert.assertEquals
6 | import org.junit.Test
7 | import org.junit.runner.RunWith
8 |
9 | /**
10 | * Instrumented test, which will execute on an Android device.
11 | *
12 | * See [testing documentation](http://d.android.com/tools/testing).
13 | */
14 | @RunWith(AndroidJUnit4::class)
15 | class ExampleInstrumentedTest {
16 | @Test
17 | fun useAppContext() {
18 | // Context of the app under test.
19 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext
20 | assertEquals("com.matt.sample_base.test", appContext.packageName)
21 | }
22 | }
--------------------------------------------------------------------------------
/sample_base/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/sample_base/src/main/java/com/matt/sample_base/SampleBaseInit.kt:
--------------------------------------------------------------------------------
1 | package com.matt.sample_base
2 |
3 | /**
4 | * ============================================================
5 | * 作 者 : wgyscsf@163.com
6 | * 创建日期 :2020/7/14 11:04 AM
7 | * 描 述 :
8 | * ============================================================
9 | **/
10 | object SampleBaseInit {
11 | const val TAG="SampleBaseInit"
12 |
13 | fun init(){
14 |
15 | }
16 | }
--------------------------------------------------------------------------------
/sample_base/src/test/java/com/matt/sample_base/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package com.matt.sample_base
2 |
3 | import org.junit.Assert.assertEquals
4 | import org.junit.Test
5 |
6 | /**
7 | * Example local unit test, which will execute on the development machine (host).
8 | *
9 | * See [testing documentation](http://d.android.com/tools/testing).
10 | */
11 | class ExampleUnitTest {
12 | @Test
13 | fun addition_isCorrect() {
14 | assertEquals(4, 2 + 2)
15 | }
16 | }
--------------------------------------------------------------------------------
/sample_binance/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/sample_binance/README.md:
--------------------------------------------------------------------------------
1 | ## 币安Demo
2 | * 文档:https://binance-docs.github.io/apidocs/spot/cn/#185368440e
3 | * k线间隔:https://binance-docs.github.io/apidocs/spot/cn/#api-2
--------------------------------------------------------------------------------
/sample_binance/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 | apply from: rootProject.file('lib_common.gradle')
3 |
4 |
5 | android {
6 | defaultConfig {
7 | resourcePrefix "bin_"
8 | versionCode 1
9 | versionName "1.0"
10 | }
11 | }
12 |
13 | dependencies {
14 | api project(path: ':sample_base')
15 | }
--------------------------------------------------------------------------------
/sample_binance/consumer-rules.pro:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/scsfwgy/MPAndroidChartWrapper/a074ff292811a2b6307b150d6bdbd8ef7fcdbea1/sample_binance/consumer-rules.pro
--------------------------------------------------------------------------------
/sample_binance/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
--------------------------------------------------------------------------------
/sample_binance/screenshots/bin_竖屏_分时.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/scsfwgy/MPAndroidChartWrapper/a074ff292811a2b6307b150d6bdbd8ef7fcdbea1/sample_binance/screenshots/bin_竖屏_分时.png
--------------------------------------------------------------------------------
/sample_binance/screenshots/bin_竖屏_蜡烛图.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/scsfwgy/MPAndroidChartWrapper/a074ff292811a2b6307b150d6bdbd8ef7fcdbea1/sample_binance/screenshots/bin_竖屏_蜡烛图.png
--------------------------------------------------------------------------------
/sample_binance/screenshots/origin_bin_landscape.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/scsfwgy/MPAndroidChartWrapper/a074ff292811a2b6307b150d6bdbd8ef7fcdbea1/sample_binance/screenshots/origin_bin_landscape.png
--------------------------------------------------------------------------------
/sample_binance/screenshots/origin_bin_portrait.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/scsfwgy/MPAndroidChartWrapper/a074ff292811a2b6307b150d6bdbd8ef7fcdbea1/sample_binance/screenshots/origin_bin_portrait.png
--------------------------------------------------------------------------------
/sample_binance/screenshots/origin_bin_portrait_ktype.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/scsfwgy/MPAndroidChartWrapper/a074ff292811a2b6307b150d6bdbd8ef7fcdbea1/sample_binance/screenshots/origin_bin_portrait_ktype.png
--------------------------------------------------------------------------------
/sample_binance/screenshots/wrapper_bin_portrait_master_vol_minor.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/scsfwgy/MPAndroidChartWrapper/a074ff292811a2b6307b150d6bdbd8ef7fcdbea1/sample_binance/screenshots/wrapper_bin_portrait_master_vol_minor.png
--------------------------------------------------------------------------------
/sample_binance/src/androidTest/java/com/example/sample_binance/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package com.example.sample_binance
2 |
3 | import androidx.test.platform.app.InstrumentationRegistry
4 | import androidx.test.ext.junit.runners.AndroidJUnit4
5 |
6 | import org.junit.Test
7 | import org.junit.runner.RunWith
8 |
9 | import org.junit.Assert.*
10 |
11 | /**
12 | * Instrumented test, which will execute on an Android device.
13 | *
14 | * See [testing documentation](http://d.android.com/tools/testing).
15 | */
16 | @RunWith(AndroidJUnit4::class)
17 | class ExampleInstrumentedTest {
18 | @Test
19 | fun useAppContext() {
20 | // Context of the app under test.
21 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext
22 | assertEquals("com.example.sample_binance.test", appContext.packageName)
23 | }
24 | }
--------------------------------------------------------------------------------
/sample_binance/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/sample_binance/src/main/java/com/example/sample_binance/SampleBinanceInit.kt:
--------------------------------------------------------------------------------
1 | package com.example.sample_binance
2 |
3 | import android.app.Application
4 | import com.example.sample_binance.repository.ws.BinWsImpl
5 |
6 | /**
7 | * ============================================================
8 | * 作 者 : wgyscsf@163.com
9 | * 创建日期 :2020/7/15 3:11 PM
10 | * 描 述 :
11 | * ============================================================
12 | **/
13 | object SampleBinanceInit {
14 | val TAG = SampleBinanceInit.javaClass.simpleName
15 |
16 | //不需要翻墙
17 | const val BASE_URL = "https://api.binance.com/"
18 | const val BASE_URL_WS = "wss://stream.binance.com:9443/stream"
19 | //const val BASE_URL_WS = "wss://stream.binancezh.com:9443/stream"
20 |
21 | fun init(application: Application) {
22 | BinWsImpl.binWs.conn()
23 | }
24 | }
--------------------------------------------------------------------------------
/sample_binance/src/main/java/com/example/sample_binance/model/api/Api24Hr.java:
--------------------------------------------------------------------------------
1 | package com.example.sample_binance.model.api;
2 |
3 | /**
4 | * ============================================================
5 | * 作 者 : wgyscsf@163.com
6 | * 创建日期 :2020/8/5 10:46 AM
7 | * 描 述 :
8 | * ============================================================
9 | **/
10 | public class Api24Hr {
11 |
12 | /**
13 | * priceChange : -0.00027100
14 | * symbol : ETHBTC
15 | * askPrice : 0.03471900
16 | * bidQty : 0.88200000
17 | * count : 211112
18 | * openPrice : 0.03498500
19 | * lastId : 185873200
20 | * quoteVolume : 20158.46874519
21 | * bidPrice : 0.03471400
22 | * firstId : 185662089
23 | * volume : 580056.67900000
24 | * lastQty : 0.13700000
25 | * askQty : 26.99900000
26 | * weightedAvgPrice : 0.03475258
27 | * lowPrice : 0.03435900
28 | * highPrice : 0.03512200
29 | * closeTime : 1596595456486
30 | * prevClosePrice : 0.03498500
31 | * openTime : 1596509056486
32 | * priceChangePercent : -0.775
33 | * lastPrice : 0.03471400
34 | */
35 | public double priceChange;
36 | public String symbol;
37 | public double askPrice;
38 | public double bidQty;
39 | public int count;
40 | public double openPrice;
41 | public int lastId;
42 | public double quoteVolume;
43 | public double bidPrice;
44 | public int firstId;
45 | public double volume;
46 | public double lastQty;
47 | public double askQty;
48 | public double weightedAvgPrice;
49 | public double lowPrice;
50 | public double highPrice;
51 | public long closeTime;
52 | public double prevClosePrice;
53 | public long openTime;
54 | public double priceChangePercent;
55 | public double lastPrice;
56 | }
57 |
--------------------------------------------------------------------------------
/sample_binance/src/main/java/com/example/sample_binance/model/api/ApiPriceFilter.java:
--------------------------------------------------------------------------------
1 | package com.example.sample_binance.model.api;
2 |
3 | /**
4 | * ============================================================
5 | * 作 者 : wgyscsf@163.com
6 | * 创建日期 :2020/8/10 11:04 AM
7 | * 描 述 :
8 | * ============================================================
9 | **/
10 | public class ApiPriceFilter {
11 | /**
12 | * minPrice : 0.00000100
13 | * maxPrice : 100000.00000000
14 | * filterType : PRICE_FILTER
15 | * tickSize : 0.00000100
16 | */
17 | public double minPrice;
18 | public double maxPrice;
19 | public String filterType;
20 | public double tickSize;
21 | }
22 |
--------------------------------------------------------------------------------
/sample_binance/src/main/java/com/example/sample_binance/model/api/ApiSymbol.java:
--------------------------------------------------------------------------------
1 | package com.example.sample_binance.model.api;
2 |
3 | import com.matt.mpwrapper.utils.MathUtil;
4 | import com.matt.mpwrapper.utils.NumberUtils;
5 |
6 | import java.io.Serializable;
7 | import java.util.List;
8 |
9 | /**
10 | * ============================================================
11 | * 作 者 : wgyscsf@163.com
12 | * 创建日期 :2020/7/15 3:35 PM
13 | * 描 述 :
14 | * ============================================================
15 | **/
16 | public class ApiSymbol implements Serializable {
17 |
18 | /**
19 | * symbol : ETHBTC
20 | * quoteOrderQtyMarketAllowed : true
21 | * baseAsset : ETH
22 | * baseAssetPrecision : 8
23 | * isSpotTradingAllowed : true
24 | * quoteAssetPrecision : 8
25 | * quoteCommissionPrecision : 8
26 | * ocoAllowed : true
27 | * quotePrecision : 8
28 | * icebergAllowed : true
29 | * isMarginTradingAllowed : true
30 | * quoteAsset : BTC
31 | * baseCommissionPrecision : 8
32 | * status : TRADING
33 | */
34 | public String symbol;
35 | public boolean quoteOrderQtyMarketAllowed;
36 | public String baseAsset;
37 | public int baseAssetPrecision;
38 | public boolean isSpotTradingAllowed;
39 | public int quoteAssetPrecision;
40 | public int quoteCommissionPrecision;
41 | public boolean ocoAllowed;
42 | public int quotePrecision;
43 | public boolean icebergAllowed;
44 | public boolean isMarginTradingAllowed;
45 | public String quoteAsset;
46 | public int baseCommissionPrecision;
47 | public String status;
48 | public List filters;
49 |
50 | //internal
51 | private ApiPriceFilter getApiPriceFilter() {
52 | if (filters == null) return null;
53 | for (ApiPriceFilter filter : filters) {
54 | if ("PRICE_FILTER".equals(filter.filterType)) {
55 | return filter;
56 | }
57 | }
58 | return null;
59 | }
60 |
61 | /**
62 | * 获取产品精度,获取方式很扯,但是没办法
63 | *
64 | * @return
65 | */
66 | public int getPriceDigit() {
67 | ApiPriceFilter apiPriceFilter = getApiPriceFilter();
68 | if (apiPriceFilter == null) return 2;
69 | double minPrice = apiPriceFilter.minPrice;
70 | double divide = MathUtil.divide(1.0, minPrice);
71 | int i = (int) divide;
72 | return String.valueOf(i).length();
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/sample_binance/src/main/java/com/example/sample_binance/model/api/ApiSymbolWrapper.java:
--------------------------------------------------------------------------------
1 | package com.example.sample_binance.model.api;
2 |
3 | import java.util.List;
4 |
5 | /**
6 | * ============================================================
7 | * 作 者 : wgyscsf@163.com
8 | * 创建日期 :2020/7/15 3:35 PM
9 | * 描 述 :
10 | * ============================================================
11 | **/
12 | public class ApiSymbolWrapper {
13 | public List symbols;
14 | }
15 |
--------------------------------------------------------------------------------
/sample_binance/src/main/java/com/example/sample_binance/model/kview/BinKType.kt:
--------------------------------------------------------------------------------
1 | package com.example.sample_binance.model.kview
2 |
3 | import java.util.*
4 |
5 | /**
6 | * ============================================================
7 | * 作 者 : freer-2
8 | * 更新时间 :2019/09/09 17:41
9 | * 描 述 :
10 | * ============================================================
11 | */
12 | enum class BinKType(val id: Int, val label: String, val apiKey: String) {
13 | K_TIMESHARE(1, "分时", "1m"),
14 | K_1M(2, "1分", "1m"),
15 | K_3M(3, "3分", "3m"),
16 | K_5M(4, "5分", "5m"),
17 | K_15M(5, "15分", "15m"),
18 | K_30M(6, "30分", "30m"),
19 | K_1H(7, "1小时", "1h"),
20 | K_2H(8, "2小时", "2h"),
21 | K_4H(9, "4小时", "4h"),
22 | K_6H(10, "6小时", "6h"),
23 | K_8H(11, "8小时", "8h"),
24 | K_12H(12, "12小时", "12h"),
25 | K_1D(13, "1天", "1d"),
26 | K_3D(14, "3天", "3d"),
27 | K_1W(15, "1周", "1w"),
28 | K_1MONTH(16, "1月", "1M");
29 |
30 | companion object {
31 |
32 | fun binKTypeList(): List {
33 | val kTypeList: MutableList = ArrayList()
34 | kTypeList.add(K_TIMESHARE)
35 | kTypeList.add(K_1M)
36 | kTypeList.add(K_3M)
37 | kTypeList.add(K_5M)
38 | kTypeList.add(K_15M)
39 | kTypeList.add(K_30M)
40 | kTypeList.add(K_1H)
41 | kTypeList.add(K_2H)
42 | kTypeList.add(K_4H)
43 | kTypeList.add(K_6H)
44 | kTypeList.add(K_8H)
45 | kTypeList.add(K_12H)
46 | kTypeList.add(K_1D)
47 | kTypeList.add(K_3D)
48 | kTypeList.add(K_1W)
49 | kTypeList.add(K_1MONTH)
50 | return kTypeList
51 | }
52 |
53 | fun getBinKTypeTitleList(): List {
54 | val binKTypeList =
55 | binKTypeList()
56 | return binKTypeList.map { it.label }
57 | }
58 | }
59 |
60 | }
--------------------------------------------------------------------------------
/sample_binance/src/main/java/com/example/sample_binance/model/ws/WsBase.java:
--------------------------------------------------------------------------------
1 | package com.example.sample_binance.model.ws;
2 |
3 | /**
4 | * ============================================================
5 | * 作 者 : wgyscsf@163.com
6 | * 创建日期 :2020/8/6 10:59 AM
7 | * 描 述 :
8 | * ============================================================
9 | **/
10 | abstract public class WsBase {
11 |
12 | /**
13 | * {
14 | * "e": "kline", // 事件类型
15 | * "E": 123456789, // 事件时间
16 | * "s": "BNBBTC", // 交易对
17 | * }
18 | */
19 | public String s;
20 | public String e;
21 | public long E;
22 | }
23 |
--------------------------------------------------------------------------------
/sample_binance/src/main/java/com/example/sample_binance/model/ws/WsData.java:
--------------------------------------------------------------------------------
1 | package com.example.sample_binance.model.ws;
2 |
3 | /**
4 | * ============================================================
5 | * 作 者 : wgyscsf@163.com
6 | * 创建日期 :2020/8/6 8:13 PM
7 | * 描 述 :
8 | * ============================================================
9 | **/
10 | public class WsData {
11 | public String stream;
12 | public T data;
13 | }
14 |
--------------------------------------------------------------------------------
/sample_binance/src/main/java/com/example/sample_binance/model/ws/WsLatestKLinWrapper.java:
--------------------------------------------------------------------------------
1 | package com.example.sample_binance.model.ws;
2 |
3 | /**
4 | * ============================================================
5 | * 作 者 : wgyscsf@163.com
6 | * 创建日期 :2020/8/6 11:01 AM
7 | * 描 述 :
8 | * ============================================================
9 | **/
10 | public class WsLatestKLinWrapper extends WsBase {
11 | public WsLatestKLine k;
12 | }
13 |
--------------------------------------------------------------------------------
/sample_binance/src/main/java/com/example/sample_binance/model/ws/WsLatestKLine.java:
--------------------------------------------------------------------------------
1 | package com.example.sample_binance.model.ws;
2 |
3 | /**
4 | * ============================================================
5 | * 作 者 : wgyscsf@163.com
6 | * 创建日期 :2020/7/15 3:35 PM
7 | * 描 述 :
8 | * ============================================================
9 | **/
10 | public class WsLatestKLine {
11 | /**
12 | * {
13 | * "t": 123400000, // 这根K线的起始时间
14 | * "T": 123460000, // 这根K线的结束时间
15 | * "s": "BNBBTC", // 交易对
16 | * "i": "1m", // K线间隔
17 | * "f": 100, // 这根K线期间第一笔成交ID
18 | * "L": 200, // 这根K线期间末一笔成交ID
19 | * "o": "0.0010", // 这根K线期间第一笔成交价
20 | * "c": "0.0020", // 这根K线期间末一笔成交价
21 | * "h": "0.0025", // 这根K线期间最高成交价
22 | * "l": "0.0015", // 这根K线期间最低成交价
23 | * "v": "1000", // 这根K线期间成交量
24 | * "n": 100, // 这根K线期间成交数量
25 | * "x": false, // 这根K线是否完结(是否已经开始下一根K线)
26 | * "q": "1.0000", // 这根K线期间成交额
27 | * "V": "500", // 主动买入的成交量
28 | * "Q": "0.500", // 主动买入的成交额
29 | * "B": "123456" // 忽略此参数
30 | * }
31 | */
32 | public float c;
33 | public int f;
34 | public float h;
35 | public String i;
36 | public int L;
37 | public float l;
38 | public int n;
39 | public float o;
40 | public float q;
41 | public float Q;
42 | public String s;
43 | public long t;
44 | public long T;
45 | public float v;
46 | public float V;
47 | public boolean x;
48 | }
49 |
--------------------------------------------------------------------------------
/sample_binance/src/main/java/com/example/sample_binance/model/ws/WsReqBase.kt:
--------------------------------------------------------------------------------
1 | package com.example.sample_binance.model.ws
2 |
3 | import com.blankj.utilcode.util.GsonUtils
4 |
5 | /**
6 | * ============================================================
7 | * 作 者 : wgyscsf@163.com
8 | * 创建日期 :2020/8/4 11:31 AM
9 | * 描 述 :
10 | * ============================================================
11 | */
12 | class WsReqBase(
13 | val method: String,
14 | val params: Array,
15 | val id: Int
16 | ) {
17 | companion object {
18 | fun binWsApi(params: Array, subscribe: Boolean, id: Int = 10): String {
19 | val wsBase =
20 | WsReqBase(if (subscribe) "SUBSCRIBE" else "UNSUBSCRIBE", params, id)
21 | return GsonUtils.toJson(wsBase)
22 | }
23 |
24 | fun binWsApi(params: String, subscribe: Boolean): String {
25 | return binWsApi(arrayOf(params), subscribe)
26 | }
27 | }
28 | }
--------------------------------------------------------------------------------
/sample_binance/src/main/java/com/example/sample_binance/model/ws/WsSimpleTicker.java:
--------------------------------------------------------------------------------
1 | package com.example.sample_binance.model.ws;
2 |
3 | /**
4 | * ============================================================
5 | * 作 者 : wgyscsf@163.com
6 | * 创建日期 :2020/8/6 11:32 AM
7 | * 描 述 :
8 | * ============================================================
9 | **/
10 | public class WsSimpleTicker extends WsBase {
11 |
12 | /**
13 | * {
14 | * "e": "24hrMiniTicker", // 事件类型
15 | * "E": 123456789, // 事件时间
16 | * "s": "BNBBTC", // 交易对
17 | * "c": "0.0025", // 最新成交价格
18 | * "o": "0.0010", // 24小时前开始第一笔成交价格
19 | * "h": "0.0025", // 24小时内最高成交价
20 | * "l": "0.0010", // 24小时内最低成交加
21 | * "v": "10000", // 成交量
22 | * "q": "18" // 成交额
23 | * }
24 | */
25 | public double q;
26 | public double c;
27 | public double v;
28 | public double h;
29 | public double l;
30 | public double o;
31 | }
32 |
--------------------------------------------------------------------------------
/sample_binance/src/main/java/com/example/sample_binance/repository/memory/GlobalCache.kt:
--------------------------------------------------------------------------------
1 | package com.example.sample_binance.repository.memory
2 |
3 | import com.example.sample_binance.model.api.Api24Hr
4 | import com.example.sample_binance.model.api.ApiSymbol
5 |
6 | /**
7 | * ============================================================
8 | * 作 者 : wgyscsf@163.com
9 | * 创建日期 :2020/8/5 11:10 AM
10 | * 描 述 :
11 | * ============================================================
12 | **/
13 | object GlobalCache {
14 | const val COUNT_SYMBOL = 1024
15 |
16 | private val m24HrMap by lazy {
17 | HashMap(COUNT_SYMBOL)
18 | }
19 |
20 | private val mSymbolMap by lazy {
21 | HashMap(COUNT_SYMBOL)
22 | }
23 |
24 |
25 | fun update24Hr(list: List) {
26 | list?.forEach {
27 | m24HrMap[it.symbol] = it
28 | }
29 | }
30 |
31 | fun get24HrBySymbol(symbol: String?): Api24Hr? {
32 | if (symbol == null) return null
33 | return m24HrMap[symbol]
34 | }
35 |
36 | fun updateSymbol(list: List?) {
37 | list?.forEach {
38 | mSymbolMap[it.symbol] = it
39 | }
40 | }
41 |
42 | fun getSymbolBySymbol(symbol: String?): ApiSymbol? {
43 | if (symbol == null) return null
44 | return mSymbolMap[symbol]
45 | }
46 |
47 | fun getSymbolMap(): HashMap {
48 | return mSymbolMap
49 | }
50 |
51 | fun get24HrMap(): HashMap {
52 | return m24HrMap
53 | }
54 | }
--------------------------------------------------------------------------------
/sample_binance/src/main/java/com/example/sample_binance/repository/net/BinObserver.kt:
--------------------------------------------------------------------------------
1 | package com.example.sample_binance.repository.net
2 |
3 | import com.blankj.utilcode.util.ToastUtils
4 | import com.matt.libwrapper.ui.base.loading.IDisposable
5 | import com.matt.libwrapper.widget.ObserverWrapper
6 | import java.net.SocketTimeoutException
7 |
8 | /**
9 | * ============================================================
10 | * 作 者 : wgyscsf@163.com
11 | * 创建日期 :2020/7/15 5:17 PM
12 | * 描 述 :
13 | * ============================================================
14 | **/
15 | abstract class BinObserver(iDisposable: IDisposable) : ObserverWrapper(iDisposable) {
16 |
17 | override fun onCatchNext(t: T) {
18 | super.onCatchNext(t)
19 | onFinalSuccess(t)
20 | }
21 |
22 | override fun onCatchError(e: Throwable) {
23 | super.onCatchError(e)
24 | onHandlerException(e)
25 | }
26 |
27 |
28 | override fun onHandlerException(e: Throwable) {
29 | if (e is SocketTimeoutException) {
30 | ToastUtils.showLong("连接超时,币安api需要科学上网,请检查")
31 | } else {
32 | super.onHandlerException(e)
33 | }
34 |
35 | }
36 |
37 | abstract fun onFinalSuccess(t: T)
38 |
39 | }
--------------------------------------------------------------------------------
/sample_binance/src/main/java/com/example/sample_binance/repository/net/BinanceRetrofitBuilder.kt:
--------------------------------------------------------------------------------
1 | package com.example.sample_binance.repository.net
2 |
3 | import com.example.sample_binance.SampleBinanceInit
4 | import com.matt.libwrapper.repository.net.AbstractRetrofitBuilder
5 | import com.matt.libwrapper.repository.net.DefOkHttpClient
6 | import okhttp3.OkHttpClient
7 | import retrofit2.Retrofit
8 |
9 | /**
10 | * ============================================================
11 | * 作 者 : wgyscsf@163.com
12 | * 创建日期 :2020/7/15 3:08 PM
13 | * 描 述 :
14 | * ============================================================
15 | **/
16 | class BinanceRetrofitBuilder : AbstractRetrofitBuilder() {
17 |
18 | override fun apiBaseUrl(): String {
19 | return SampleBinanceInit.BASE_URL
20 | }
21 |
22 | companion object {
23 | val mRetrofit: Retrofit by lazy(LazyThreadSafetyMode.SYNCHRONIZED) {
24 | BinanceRetrofitBuilder().mRetrofit
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/sample_binance/src/main/java/com/example/sample_binance/repository/net/BinanceServiceWrapper.kt:
--------------------------------------------------------------------------------
1 | package com.example.sample_binance.repository.net
2 |
3 | import com.example.sample_binance.repository.net.service.BinanceService
4 |
5 | /**
6 | * ============================================================
7 | * 作 者 : wgyscsf@163.com
8 | * 创建日期 :2020/7/15 3:53 PM
9 | * 描 述 :
10 | * ============================================================
11 | **/
12 | object BinanceServiceWrapper {
13 |
14 | val sBinanceService by lazy {
15 | BinanceRetrofitBuilder.mRetrofit.create(BinanceService::class.java)
16 | }
17 | }
--------------------------------------------------------------------------------
/sample_binance/src/main/java/com/example/sample_binance/repository/net/service/BinanceService.kt:
--------------------------------------------------------------------------------
1 | package com.example.sample_binance.repository.net.service
2 |
3 | import com.example.sample_binance.model.api.Api24Hr
4 | import com.example.sample_binance.model.api.ApiSymbolWrapper
5 | import io.reactivex.Observable
6 | import retrofit2.http.GET
7 | import retrofit2.http.QueryMap
8 |
9 | /**
10 | * ============================================================
11 | * 作 者 : wgyscsf@163.com
12 | * 创建日期 :2020/7/15 3:15 PM
13 | * 描 述 :
14 | * ============================================================
15 | **/
16 | interface BinanceService {
17 | @GET("/api/v3/exchangeInfo")
18 | fun exchangeInfo(): Observable
19 |
20 | @GET("/api/v3/ticker/24hr")
21 | fun _24hr(): Observable>
22 |
23 | @GET("/api/v3/klines")
24 | fun klines(@QueryMap params: MutableMap): Observable>>
25 | }
--------------------------------------------------------------------------------
/sample_binance/src/main/java/com/example/sample_binance/repository/sp/BinSpHelper.kt:
--------------------------------------------------------------------------------
1 | package com.example.sample_binance.repository.sp
2 |
3 | import com.blankj.utilcode.util.SPUtils
4 | import com.example.sample_binance.model.kview.BinKType
5 | import com.matt.mpwrapper.view.type.MasterIndicatorType
6 | import com.matt.mpwrapper.view.type.MinorIndicatorType
7 |
8 | /**
9 | *
10 | * Author : wgyscsf@163.com
11 | * Github : https://github.com/scsfwgy
12 | * Date : 2020/7/25 8:46 PM
13 | * 描 述 :
14 | *
15 | **/
16 | object BinSpHelper {
17 | const val SP_MAIN_INDICATOR = "SP_MAIN_INDICATOR"
18 | const val SP_MINOR_INDICATOR = "SP_MINOR_INDICATOR"
19 | const val SP_BIN_KTYPE = "SP_BIN_KTYPE"
20 |
21 | fun getMainIndicator(): MasterIndicatorType {
22 | val string =
23 | SPUtils.getInstance().getString(SP_MAIN_INDICATOR, null)
24 | ?: return MasterIndicatorType.NONE
25 | return MasterIndicatorType.valueOf(string)
26 | }
27 |
28 | fun updateMainIndicator(masterIndicatorType: MasterIndicatorType) {
29 | SPUtils.getInstance().put(SP_MAIN_INDICATOR, masterIndicatorType.name)
30 | }
31 |
32 | fun getMinorIndicator(): MinorIndicatorType {
33 | val string =
34 | SPUtils.getInstance().getString(SP_MINOR_INDICATOR, null)
35 | ?: return MinorIndicatorType.MACD
36 | return MinorIndicatorType.valueOf(string)
37 | }
38 |
39 | fun updateMinorIndicator(minorIndicatorType: MinorIndicatorType) {
40 | SPUtils.getInstance().put(SP_MINOR_INDICATOR, minorIndicatorType.name)
41 | }
42 |
43 | fun getBinKType(): BinKType {
44 | val string =
45 | SPUtils.getInstance().getString(SP_BIN_KTYPE, null) ?: return BinKType.K_1D
46 | return BinKType.valueOf(string)
47 | }
48 |
49 | fun updateBinKType(binKType: BinKType) {
50 | SPUtils.getInstance().put(SP_BIN_KTYPE, binKType.name)
51 | }
52 | }
--------------------------------------------------------------------------------
/sample_binance/src/main/java/com/example/sample_binance/repository/ws/BinWs.kt:
--------------------------------------------------------------------------------
1 | package com.example.sample_binance.repository.ws
2 |
3 | import okhttp3.WebSocket
4 |
5 | /**
6 | * ============================================================
7 | * 作 者 : wgyscsf@163.com
8 | * 创建日期 :2020/7/30 8:00 PM
9 | * 描 述 :
10 | * ============================================================
11 | **/
12 | interface BinWs {
13 | fun conn()
14 | fun disConn()
15 | fun send(msg: String?): Boolean
16 | fun getWebSocket(): WebSocket?
17 | fun setWebSocket(webSocket: WebSocket?)
18 | }
--------------------------------------------------------------------------------
/sample_binance/src/main/java/com/example/sample_binance/repository/ws/BinWsApi.kt:
--------------------------------------------------------------------------------
1 | package com.example.sample_binance.repository.ws
2 |
3 | import com.example.sample_binance.model.ws.WsReqBase
4 |
5 | /**
6 | * ============================================================
7 | * 作 者 : wgyscsf@163.com
8 | * 创建日期 :2020/8/4 11:07 AM
9 | * 描 述 :
10 | * ============================================================
11 | **/
12 | object BinWsApi {
13 |
14 | fun kline(symbols: Array, interval: String, sub: Boolean): Boolean {
15 | val api = symbols.map { "${it.toLowerCase()}@kline_${interval}" }.toTypedArray()
16 | val binWsApi = WsReqBase.binWsApi(api, sub)
17 | return send(binWsApi)
18 | }
19 |
20 | fun simpleTicker(symbols: Array, sub: Boolean): Boolean {
21 | val api = symbols.map { "${it.toLowerCase()}@miniTicker" }.toTypedArray()
22 | val binWsApi = WsReqBase.binWsApi(api, sub)
23 | return send(binWsApi)
24 | }
25 |
26 | fun send(msg: String?): Boolean {
27 | return BinWsImpl.binWs.send(msg)
28 | }
29 | }
--------------------------------------------------------------------------------
/sample_binance/src/main/java/com/example/sample_binance/repository/ws/BinWsImpl.kt:
--------------------------------------------------------------------------------
1 | package com.example.sample_binance.repository.ws
2 |
3 | import android.util.Log
4 | import com.example.sample_binance.SampleBinanceInit
5 | import com.matt.libwrapper.repository.net.DefOkHttpClient
6 | import okhttp3.Request
7 | import okhttp3.WebSocket
8 |
9 | /**
10 | * ============================================================
11 | * 作 者 : wgyscsf@163.com
12 | * 创建日期 :2020/7/30 7:59 PM
13 | * 描 述 :
14 | * ============================================================
15 | **/
16 | class BinWsImpl : BinWs {
17 | val TAG = BinWsImpl::class.java.simpleName
18 |
19 | companion object {
20 | val binWs: BinWs by lazy {
21 | BinWsImpl()
22 | }
23 | }
24 |
25 | var mWebSocket: WebSocket? = null
26 |
27 | override fun conn() {
28 | val request =
29 | Request
30 | .Builder()
31 | .url(SampleBinanceInit.BASE_URL_WS)
32 | .build()
33 | DefOkHttpClient.instance.defOkHttpClient().newWebSocket(request, BinWsListener(this))
34 | }
35 |
36 | override fun disConn() {
37 | }
38 |
39 | fun log(msg: String) {
40 | Log.d(TAG, msg)
41 | }
42 |
43 | override fun send(msg: String?): Boolean {
44 | log("send:$msg")
45 | val webSocket = getWebSocket()
46 | if (webSocket == null) {
47 | log("webSocket == null,取消发送消息")
48 | return false
49 | }
50 | if (msg == null) {
51 | log("msg == null,取消发送消息")
52 | return false
53 | }
54 | return webSocket.send(msg)
55 |
56 | }
57 |
58 | override fun getWebSocket(): WebSocket? {
59 | return mWebSocket
60 | }
61 |
62 | override fun setWebSocket(webSocket: WebSocket?) {
63 | mWebSocket = webSocket
64 | }
65 | }
--------------------------------------------------------------------------------
/sample_binance/src/main/java/com/example/sample_binance/repository/ws/BinWsListener.kt:
--------------------------------------------------------------------------------
1 | package com.example.sample_binance.repository.ws
2 |
3 | import android.util.Log
4 | import com.blankj.utilcode.util.GsonUtils
5 | import com.example.sample_binance.model.ws.WsLatestKLinWrapper
6 | import com.example.sample_binance.model.ws.WsSimpleTicker
7 | import com.google.gson.JsonParser
8 | import okhttp3.Response
9 | import okhttp3.WebSocket
10 | import okhttp3.WebSocketListener
11 | import org.greenrobot.eventbus.EventBus
12 |
13 | /**
14 | * ============================================================
15 | * 作 者 : wgyscsf@163.com
16 | * 创建日期 :2020/8/6 11:54 AM
17 | * 描 述 :
18 | * ============================================================
19 | **/
20 | class BinWsListener(val binWs: BinWs) : WebSocketListener() {
21 | val TAG = BinWsImpl::class.java.simpleName
22 |
23 | companion object {
24 | const val COUNT_RETRY = 10
25 | var retry = 0
26 | }
27 |
28 | fun log(msg: String) {
29 | Log.d(TAG, msg)
30 | }
31 |
32 | override fun onOpen(webSocket: WebSocket, response: Response) {
33 | super.onOpen(webSocket, response)
34 | binWs.setWebSocket(webSocket)
35 | log("onOpen:$response,$webSocket")
36 | reset()
37 | }
38 |
39 | override fun onMessage(webSocket: WebSocket, text: String) {
40 | super.onMessage(webSocket, text)
41 | onMsg(text)
42 | }
43 |
44 | override fun onFailure(webSocket: WebSocket, t: Throwable, response: Response?) {
45 | super.onFailure(webSocket, t, response)
46 | log("onFailure:$t")
47 | onConnFail()
48 | }
49 |
50 | override fun onClosed(webSocket: WebSocket, code: Int, reason: String) {
51 | super.onClosed(webSocket, code, reason)
52 | log("onClosed:$code,$reason")
53 | onConnFail()
54 | }
55 |
56 | fun onMsg(text: String) {
57 | try {
58 | onSafeMsg(text)
59 | } catch (e: Exception) {
60 | log("解析出错:${e.localizedMessage}")
61 | e.printStackTrace()
62 | }
63 | }
64 |
65 | fun onSafeMsg(text: String) {
66 | log("onMessage:$text")
67 | if (text.contains("result") || !text.contains("stream")) {
68 | log("收到了不包含事件类型的事件,终止解析:$text")
69 | return
70 | }
71 | val orginElement = JsonParser.parseString(text)
72 | if (!orginElement.isJsonObject) throw IllegalArgumentException("收到的信息:!json.isJsonObject,非法")
73 | val jsonObject = orginElement.asJsonObject
74 | val dataElement = jsonObject["data"]
75 | if (!dataElement.isJsonObject) throw IllegalArgumentException("收到的信息:!dataElement.isJsonObject,非法")
76 | val dataObject = dataElement.asJsonObject
77 | val type = dataObject["e"].asString ?: throw IllegalArgumentException("type不允许为null")
78 | val json = dataObject.toString()
79 | dispatchMsgByType(json, type)
80 | }
81 |
82 | fun dispatchMsgByType(json: String, type: String) {
83 | if (type == "kline") {
84 | val fromJson =
85 | GsonUtils.fromJson(
86 | json,
87 | WsLatestKLinWrapper::class.java
88 | )
89 | postMsg(fromJson)
90 | } else if (type == "24hrMiniTicker") {
91 | val fromJson =
92 | GsonUtils.fromJson(
93 | json,
94 | WsSimpleTicker::class.java
95 | )
96 | postMsg(fromJson)
97 | } else {
98 | log("dispatchMsgByType:未知消息类型:$type,数据:$json")
99 | }
100 | }
101 |
102 | fun postMsg(any: Any) {
103 | EventBus.getDefault().post(any)
104 | }
105 |
106 | private fun onConnFail() {
107 | binWs.setWebSocket(null)
108 | if (retry >= COUNT_RETRY) {
109 | log("重试次数大于最大可重试次数:${COUNT_RETRY},停止重试")
110 | return
111 | }
112 | retry++
113 | log("断开连接,开始第${retry}次重试" + this)
114 | binWs.conn()
115 | }
116 |
117 | fun reset() {
118 | retry = 0
119 | }
120 | }
--------------------------------------------------------------------------------
/sample_binance/src/main/java/com/example/sample_binance/ui/activity/BinListActivity.kt:
--------------------------------------------------------------------------------
1 | package com.example.sample_binance.ui.activity
2 |
3 | import android.content.Context
4 | import android.content.Intent
5 | import android.os.Bundle
6 | import com.example.sample_binance.R
7 | import com.example.sample_binance.model.api.Api24Hr
8 | import com.example.sample_binance.model.api.ApiSymbol
9 | import com.example.sample_binance.model.api.ApiSymbolWrapper
10 | import com.example.sample_binance.repository.memory.GlobalCache
11 | import com.example.sample_binance.repository.net.BinObserver
12 | import com.example.sample_binance.repository.net.BinanceServiceWrapper
13 | import com.example.sample_binance.ui.fragment.BinListFragment
14 | import com.matt.libwrapper.ui.base.template.Template
15 | import com.matt.libwrapper.ui.base.template.TemplateBarActivity
16 | import com.matt.libwrapper.utils.RxUtils
17 | import com.matt.libwrapper.widget.simple.SimpleCatchObserver
18 | import com.matt.libwrapper.widget.simple.SimpleFragmentPagerAdapter
19 | import io.reactivex.Observable
20 | import kotlinx.android.synthetic.main.bin_activity_bin_list.*
21 |
22 | class BinListActivity : TemplateBarActivity() {
23 | companion object {
24 | fun goIntent(context: Context) {
25 | val intent = Intent(context, BinListActivity::class.java)
26 | context.startActivity(intent)
27 | }
28 | }
29 |
30 | override fun templateType(): Int {
31 | return Template.TEMPLATETYPE_DEFVIEW
32 | }
33 |
34 | override fun addChildrenView(): Any {
35 | return R.layout.bin_activity_bin_list
36 | }
37 |
38 | override fun renderTitle(): Any {
39 | return "币安产品列表"
40 | }
41 |
42 | override fun onCatchCreate(savedInstanceState: Bundle?) {
43 | super.onCatchCreate(savedInstanceState)
44 | //loadKLine()
45 | loadExchangeInfo()
46 | }
47 |
48 | private fun loadExchangeInfo() {
49 | val exchangeInfo = BinanceServiceWrapper.sBinanceService.exchangeInfo()
50 | val _24hr = BinanceServiceWrapper.sBinanceService._24hr()
51 | Observable.merge(exchangeInfo, _24hr)
52 | .compose(RxUtils.rxObSchedulerHelper())
53 | .subscribe(object : BinObserver(this) {
54 | override fun onFinalSuccess(t: Any) {
55 | if (t is ApiSymbolWrapper) {
56 | GlobalCache.updateSymbol(t.symbols)
57 | } else if (t is List<*>) {
58 | GlobalCache.update24Hr(t as List)
59 | }
60 | }
61 |
62 | override fun onCatchComplete() {
63 | super.onCatchComplete()
64 | renderTabLayout(GlobalCache.getSymbolMap().values.toList())
65 | }
66 | })
67 | }
68 |
69 | private fun renderTabLayout(symbols: List) {
70 | val groupMap = symbols.groupBy {
71 | it.quoteAsset
72 | }.toSortedMap(Comparator { item1, _ ->
73 | when (item1) {
74 | "USDT" -> {
75 | -1
76 | }
77 | "BTC" -> {
78 | -1
79 | }
80 | else -> {
81 | 1
82 | }
83 | }
84 | })
85 | val titles = groupMap.keys
86 | val fragments = titles.map {
87 | BinListFragment.newInstance(it)
88 | }
89 | babl_vp_viewPager.adapter =
90 | SimpleFragmentPagerAdapter(supportFragmentManager, fragments, titles.toList())
91 | babl_stl_tabLayout.setViewPager(babl_vp_viewPager)
92 | }
93 |
94 | }
--------------------------------------------------------------------------------
/sample_binance/src/main/java/com/example/sample_binance/ui/pop/KViewTypePop.kt:
--------------------------------------------------------------------------------
1 | package com.example.sample_binance.ui.pop
2 |
3 | import android.content.Context
4 | import android.view.View
5 | import androidx.recyclerview.widget.GridLayoutManager
6 | import com.chad.library.adapter.base.BaseQuickAdapter
7 | import com.chad.library.adapter.base.viewholder.BaseViewHolder
8 | import com.example.sample_binance.R
9 | import com.example.sample_binance.model.kview.BinKType
10 | import com.example.sample_binance.repository.sp.BinSpHelper
11 | import com.matt.libwrapper.ui.base.BasePopWindow
12 | import com.matt.mpwrapper.ktx.getColor
13 | import kotlinx.android.synthetic.main.bin_item_pop_kview_type.view.*
14 | import kotlinx.android.synthetic.main.bin_pop_kview_type.view.*
15 |
16 | /**
17 | *
18 | * Author : wgyscsf@163.com
19 | * Github : https://github.com/scsfwgy
20 | * Date : 2020/7/19 11:13 AM
21 | * 描 述 :
22 | *
23 | **/
24 | class KViewTypePop(
25 | context: Context,
26 | var mCurrKType: BinKType,
27 | val kTypeListener: KTypeListener
28 | ) :
29 | BasePopWindow(context) {
30 | override fun onCreateContentView(): View {
31 | return createPopupById(R.layout.bin_pop_kview_type)
32 | }
33 |
34 | val mBaseQuickAdapter by lazy {
35 | object :
36 | BaseQuickAdapter(R.layout.bin_item_pop_kview_type, null) {
37 | override fun convert(holder: BaseViewHolder, item: BinKType) {
38 | holder.itemView.run {
39 | bipkt_tv_txt.text = item.label
40 | if (item == mCurrKType) {
41 | bipkt_tv_txt.setTextColor(getColor(R.color.bin_global_yellow))
42 | } else {
43 | bipkt_tv_txt.setTextColor(getColor(R.color.bin_txt_first))
44 | }
45 | }
46 | }
47 | }
48 | }
49 |
50 | init {
51 | initAdapter()
52 | initListener()
53 | loadData()
54 | }
55 |
56 | private fun initListener() {
57 | mBaseQuickAdapter.setOnItemClickListener { _, _, position ->
58 | dismiss()
59 | val binKType = mBaseQuickAdapter.data[position]
60 | BinSpHelper.updateBinKType(binKType)
61 | kTypeListener.onClick(binKType)
62 | mCurrKType = binKType
63 | mBaseQuickAdapter.notifyDataSetChanged()
64 | }
65 | }
66 |
67 | private fun loadData() {
68 | val list = BinKType.binKTypeList().toMutableList()
69 | mBaseQuickAdapter.setNewInstance(list)
70 | }
71 |
72 | private fun initAdapter() {
73 | val quickAdapter = mBaseQuickAdapter
74 | contentView.run {
75 | bpkt_rv_recycle.layoutManager = GridLayoutManager(mContext, 5)
76 | bpkt_rv_recycle.adapter = quickAdapter
77 | }
78 | }
79 |
80 | interface KTypeListener {
81 | fun onClick(binKType: BinKType)
82 | }
83 | }
--------------------------------------------------------------------------------
/sample_binance/src/main/java/com/example/sample_binance/ui/viewmodel/BinViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.example.sample_binance.ui.viewmodel
2 |
3 | import androidx.lifecycle.ViewModel
4 |
5 | /**
6 | * ============================================================
7 | * 作 者 : wgyscsf@163.com
8 | * 创建日期 :2020/8/5 11:28 AM
9 | * 描 述 :
10 | * ============================================================
11 | **/
12 | class BinViewModel :ViewModel(){
13 |
14 | }
--------------------------------------------------------------------------------
/sample_binance/src/main/res/drawable-xhdpi/ic_markets_indicator_default.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/scsfwgy/MPAndroidChartWrapper/a074ff292811a2b6307b150d6bdbd8ef7fcdbea1/sample_binance/src/main/res/drawable-xhdpi/ic_markets_indicator_default.png
--------------------------------------------------------------------------------
/sample_binance/src/main/res/drawable-xhdpi/ic_markets_indicator_disable.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/scsfwgy/MPAndroidChartWrapper/a074ff292811a2b6307b150d6bdbd8ef7fcdbea1/sample_binance/src/main/res/drawable-xhdpi/ic_markets_indicator_disable.png
--------------------------------------------------------------------------------
/sample_binance/src/main/res/drawable-xhdpi/ic_markets_reset_active.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/scsfwgy/MPAndroidChartWrapper/a074ff292811a2b6307b150d6bdbd8ef7fcdbea1/sample_binance/src/main/res/drawable-xhdpi/ic_markets_reset_active.png
--------------------------------------------------------------------------------
/sample_binance/src/main/res/drawable-xhdpi/ic_markets_reset_disable.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/scsfwgy/MPAndroidChartWrapper/a074ff292811a2b6307b150d6bdbd8ef7fcdbea1/sample_binance/src/main/res/drawable-xhdpi/ic_markets_reset_disable.png
--------------------------------------------------------------------------------
/sample_binance/src/main/res/drawable-xhdpi/ic_triangle_down.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/scsfwgy/MPAndroidChartWrapper/a074ff292811a2b6307b150d6bdbd8ef7fcdbea1/sample_binance/src/main/res/drawable-xhdpi/ic_triangle_down.png
--------------------------------------------------------------------------------
/sample_binance/src/main/res/drawable-xhdpi/ic_triangle_up.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/scsfwgy/MPAndroidChartWrapper/a074ff292811a2b6307b150d6bdbd8ef7fcdbea1/sample_binance/src/main/res/drawable-xhdpi/ic_triangle_up.png
--------------------------------------------------------------------------------
/sample_binance/src/main/res/drawable-xxhdpi/ic_markets_indicator_default.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/scsfwgy/MPAndroidChartWrapper/a074ff292811a2b6307b150d6bdbd8ef7fcdbea1/sample_binance/src/main/res/drawable-xxhdpi/ic_markets_indicator_default.png
--------------------------------------------------------------------------------
/sample_binance/src/main/res/drawable-xxhdpi/ic_markets_indicator_disable.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/scsfwgy/MPAndroidChartWrapper/a074ff292811a2b6307b150d6bdbd8ef7fcdbea1/sample_binance/src/main/res/drawable-xxhdpi/ic_markets_indicator_disable.png
--------------------------------------------------------------------------------
/sample_binance/src/main/res/drawable-xxhdpi/ic_markets_reset_active.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/scsfwgy/MPAndroidChartWrapper/a074ff292811a2b6307b150d6bdbd8ef7fcdbea1/sample_binance/src/main/res/drawable-xxhdpi/ic_markets_reset_active.png
--------------------------------------------------------------------------------
/sample_binance/src/main/res/drawable-xxhdpi/ic_markets_reset_disable.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/scsfwgy/MPAndroidChartWrapper/a074ff292811a2b6307b150d6bdbd8ef7fcdbea1/sample_binance/src/main/res/drawable-xxhdpi/ic_markets_reset_disable.png
--------------------------------------------------------------------------------
/sample_binance/src/main/res/layout/bin_activity_bin_chart.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
15 |
16 |
21 |
22 |
23 |
24 |
32 |
33 |
37 |
38 |
49 |
50 |
63 |
64 |
65 |
66 |
67 |
68 |
74 |
75 |
81 |
82 |
87 |
88 |
89 |
90 |
91 |
--------------------------------------------------------------------------------
/sample_binance/src/main/res/layout/bin_activity_bin_list.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
17 |
18 |
19 |
23 |
24 |
--------------------------------------------------------------------------------
/sample_binance/src/main/res/layout/bin_fragment_bin_list.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
13 |
14 |
--------------------------------------------------------------------------------
/sample_binance/src/main/res/layout/bin_fragment_chart.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/sample_binance/src/main/res/layout/bin_item_fragment_bin_list.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
16 |
17 |
25 |
26 |
35 |
36 |
51 |
52 |
53 |
54 |
59 |
--------------------------------------------------------------------------------
/sample_binance/src/main/res/layout/bin_item_pop_kview_type.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
14 |
15 |
--------------------------------------------------------------------------------
/sample_binance/src/main/res/layout/bin_pop_kview_type.xml:
--------------------------------------------------------------------------------
1 |
2 |
14 |
15 |
20 |
21 |
--------------------------------------------------------------------------------
/sample_binance/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | #FF0F1216
5 | #151820
6 | #4E5055
7 | #FFFA9B40
8 | #FFE0E3E5
9 | #FFE0E3E5
10 | #FF7D8491
11 |
12 |
--------------------------------------------------------------------------------
/sample_binance/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/sample_binance/src/test/java/com/example/sample_binance/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package com.example.sample_binance
2 |
3 | import org.junit.Test
4 |
5 | import org.junit.Assert.*
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * See [testing documentation](http://d.android.com/tools/testing).
11 | */
12 | class ExampleUnitTest {
13 | @Test
14 | fun addition_isCorrect() {
15 | assertEquals(4, 2 + 2)
16 | }
17 | }
--------------------------------------------------------------------------------
/sample_zm/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/sample_zm/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 | apply from: rootProject.file('lib_common.gradle')
3 | apply plugin: 'kotlin-android'
4 |
5 |
6 | android {
7 | defaultConfig {
8 | resourcePrefix "zm_"
9 | versionCode 1
10 | versionName "1.0"
11 | }
12 | }
13 |
14 | dependencies {
15 | api project(path: ':sample_base')
16 | implementation 'androidx.appcompat:appcompat:1.1.0'
17 | implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
18 | }
--------------------------------------------------------------------------------
/sample_zm/consumer-rules.pro:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/scsfwgy/MPAndroidChartWrapper/a074ff292811a2b6307b150d6bdbd8ef7fcdbea1/sample_zm/consumer-rules.pro
--------------------------------------------------------------------------------
/sample_zm/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
--------------------------------------------------------------------------------
/sample_zm/src/androidTest/java/com/matt/sample_zm/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package com.matt.sample_zm
2 |
3 | import androidx.test.platform.app.InstrumentationRegistry
4 | import androidx.test.ext.junit.runners.AndroidJUnit4
5 |
6 | import org.junit.Test
7 | import org.junit.runner.RunWith
8 |
9 | import org.junit.Assert.*
10 |
11 | /**
12 | * Instrumented test, which will execute on an Android device.
13 | *
14 | * See [testing documentation](http://d.android.com/tools/testing).
15 | */
16 | @RunWith(AndroidJUnit4::class)
17 | class ExampleInstrumentedTest {
18 | @Test
19 | fun useAppContext() {
20 | // Context of the app under test.
21 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext
22 | assertEquals("com.matt.sample_zm.test", appContext.packageName)
23 | }
24 | }
--------------------------------------------------------------------------------
/sample_zm/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/sample_zm/src/main/java/com/matt/sample_zm/bean/ApiData.java:
--------------------------------------------------------------------------------
1 | package com.matt.sample_zm.bean;
2 |
3 | import androidx.annotation.NonNull;
4 | import androidx.annotation.Nullable;
5 |
6 | import com.blankj.utilcode.util.Utils;
7 | import com.matt.sample_zm.R;
8 |
9 |
10 | /**
11 | * ============================================================
12 | * 作 者 : freer-2
13 | * 更新时间 :2019/08/09 11:25
14 | * 描 述 :
15 | * ============================================================
16 | */
17 | public class ApiData {
18 | @Nullable
19 | public T data;
20 | private int code;
21 | private int bizCode;
22 | @Nullable
23 | private String message;
24 |
25 | public static ApiData newErrorIns(ApiData apiData, Class kClass) {
26 | ApiData kApiData = new ApiData<>();
27 | kApiData.message = apiData.message;
28 | kApiData.code = apiData.code;
29 | kApiData.bizCode = apiData.bizCode;
30 | return kApiData;
31 | }
32 |
33 | public static ApiData newSuccessIns(Class kClass) {
34 | ApiData kApiData = new ApiData<>();
35 | kApiData.code = 200;
36 | kApiData.bizCode = 0;
37 | return kApiData;
38 | }
39 |
40 | public boolean isSuccess() {
41 | return code == 200 && bizCode == 0;
42 | }
43 |
44 | @NonNull
45 | public String getMessage() {
46 | if (message != null) return message;
47 | return Utils.getApp().getString(R.string.wrapper_CODE_UNKNOWN);
48 | }
49 |
50 | public ApiData setMessage(@Nullable String message) {
51 | this.message = message;
52 | return this;
53 | }
54 |
55 | public int getInnerCode() {
56 | if (bizCode != 0) return bizCode;
57 | return code;
58 | }
59 |
60 | public int getCode() {
61 | return code;
62 | }
63 |
64 | public ApiData setCode(int code) {
65 | this.code = code;
66 | return this;
67 | }
68 |
69 | public int getBizCode() {
70 | return bizCode;
71 | }
72 |
73 | public ApiData setBizCode(int bizCode) {
74 | this.bizCode = bizCode;
75 | return this;
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/sample_zm/src/main/java/com/matt/sample_zm/bean/ApiProduct.java:
--------------------------------------------------------------------------------
1 | package com.matt.sample_zm.bean;
2 |
3 | import com.blankj.utilcode.util.TimeUtils;
4 | import com.matt.mpwrapper.utils.MathUtil;
5 | import com.matt.mpwrapper.utils.XFormatUtil;
6 |
7 | import java.io.Serializable;
8 |
9 |
10 | /**
11 | * ============================================================
12 | * 作 者 : freer-2
13 | * 更新时间 :2019/08/09 17:34
14 | * 描 述 :
15 | * ============================================================
16 | */
17 | public class ApiProduct implements Serializable {
18 |
19 | /**
20 | * cnName : string
21 | * createTime : 0
22 | * currency : string
23 | * currentPrice : 0
24 | * enName : string
25 | * exchanger : 0
26 | * hintSpread : 0
27 | * leverage : 0
28 | * pc : 0
29 | * previousClose : 0
30 | * productCode : string
31 | * ratePercentage : 0
32 | * satoshi : 0
33 | * sequence : 0
34 | * updateTime : 0
35 | * zoneId : string
36 | */
37 |
38 | public String cnName;
39 | public long createTime;
40 | public String currency;
41 | public String enName;
42 | public int exchanger;
43 | public long extraId;
44 | public double hintSpread;
45 | public int leverage;
46 | public int pc;
47 | public String productCode;
48 | public int satoshi;
49 | public long sequence;
50 | public long updateTime;
51 | public String zoneId;
52 | public double previousClose;
53 | //万4=>返回4
54 | public double ratePercentage;
55 | public double askPrice;
56 | public double bidPrice;
57 | //lot
58 | public double lot;
59 | public String lotDesc;
60 | //产品详情中才会有
61 | //是否开市
62 | @Deprecated
63 | public boolean open;
64 | public boolean close;
65 | //下一次的开闭市时间
66 | public long openTimestamp;
67 | public long closeTimestamp;
68 | private double currentPrice;
69 |
70 | public String getOpenTimeFormat() {
71 | return TimeUtils.millis2String(openTimestamp, "MM-dd HH:mm");
72 | }
73 |
74 | public String getFormatAskPrice() {
75 | return XFormatUtil.globalFormat(askPrice, pc);
76 | }
77 |
78 | public String getFormatBidPrice() {
79 | return XFormatUtil.globalFormat(bidPrice, pc);
80 | }
81 |
82 | public String getFormatSpread() {
83 | double v = askPrice - bidPrice;
84 | int v1 = (int) (v * Math.pow(10, pc));
85 | return String.valueOf(v1);
86 | }
87 |
88 | public double getCurrentPrice() {
89 | if (askPrice != 0 && bidPrice != 0) {
90 | currentPrice = (askPrice + bidPrice) / 2.0;
91 | }
92 | return currentPrice;
93 | }
94 |
95 | public String getCurrentPriceFormat() {
96 | double currentPrice = getCurrentPrice();
97 | return XFormatUtil.globalFormat(currentPrice, pc);
98 | }
99 |
100 | public double getRate() {
101 | return MathUtil.divide(getCurrentPrice() - previousClose, previousClose) * 100;
102 | }
103 |
104 | public String getFormatRate() {
105 | return XFormatUtil.globalFormat(getRate(), 2);
106 | }
107 |
108 | public String getFormatDis() {
109 | return XFormatUtil.globalFormat(getCurrentPrice() - previousClose, pc);
110 | }
111 |
112 | public boolean up() {
113 | return getCurrentPrice() > previousClose;
114 | }
115 |
116 | public int getQtyDigit() {
117 | if (satoshi <= 1) return 0;
118 | int len = String.valueOf(satoshi).length() - 1;
119 | return len <= 1 ? 1 : len;
120 | }
121 |
122 | @Override
123 | public String toString() {
124 | return "ApiProduct{" +
125 | "cnName='" + cnName + '\'' + "rate=" + getRate() +
126 | '}';
127 | }
128 | }
129 |
--------------------------------------------------------------------------------
/sample_zm/src/main/java/com/matt/sample_zm/bean/ApiQuote.java:
--------------------------------------------------------------------------------
1 | package com.matt.sample_zm.bean;
2 |
3 | /**
4 | * ============================================================
5 | * 作 者 : matt
6 | * 更新时间 :2020/03/24 10:26
7 | * 描 述 :
8 | * ============================================================
9 | */
10 | public class ApiQuote {
11 |
12 | /**
13 | * t : 202003231355
14 | * o : 1.07601
15 | * c : 1.07516
16 | * h : 1.07601
17 | * l : 1.07499
18 | * s : 1584986100051
19 | * e : 1584986159844
20 | */
21 |
22 | public long t;
23 | public float o;
24 | public float c;
25 | public float h;
26 | public float l;
27 | public long s;
28 | public long e;
29 | }
30 |
--------------------------------------------------------------------------------
/sample_zm/src/main/java/com/matt/sample_zm/config/GlobalConfig.kt:
--------------------------------------------------------------------------------
1 | package com.matt.sample_zm.config
2 |
3 | /**
4 | * ============================================================
5 | * 作 者 : matt
6 | * 更新时间 :2020/03/11 10:14
7 | * 描 述 :
8 | * ============================================================
9 | */
10 | object GlobalConfig {
11 | fun getTradeUrl(): String {
12 | return "https://api-trade.tradeode.com"
13 | }
14 |
15 | fun getMarketUrl(): String {
16 | return "https://api-market.tradeode.com"
17 | }
18 | }
--------------------------------------------------------------------------------
/sample_zm/src/main/java/com/matt/sample_zm/net/MarketRetrofitBuilder.kt:
--------------------------------------------------------------------------------
1 | package com.matt.sample_zm.net
2 |
3 | import com.matt.sample_zm.config.GlobalConfig
4 | import com.matt.libwrapper.repository.net.AbstractRetrofitBuilder
5 | import retrofit2.Retrofit
6 |
7 |
8 | /**
9 | * ============================================================
10 | * 作 者 : freer-2
11 | * 更新时间 :2019/11/13 13:41
12 | * 描 述 :一个Retrofit实例
13 | * ============================================================
14 | */
15 | class MarketRetrofitBuilder : AbstractRetrofitBuilder() {
16 |
17 | override fun apiBaseUrl(): String {
18 | return GlobalConfig.getMarketUrl()
19 | }
20 |
21 | companion object {
22 | val mRetrofit: Retrofit by lazy(LazyThreadSafetyMode.SYNCHRONIZED) {
23 | MarketRetrofitBuilder().mRetrofit
24 | }
25 | }
26 |
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/sample_zm/src/main/java/com/matt/sample_zm/net/MarketService.java:
--------------------------------------------------------------------------------
1 | package com.matt.sample_zm.net;
2 |
3 |
4 |
5 | import com.matt.sample_zm.bean.ApiData;
6 | import com.matt.sample_zm.bean.ApiQuote;
7 |
8 | import java.util.List;
9 | import java.util.Map;
10 |
11 | import io.reactivex.Observable;
12 | import retrofit2.http.GET;
13 | import retrofit2.http.Path;
14 | import retrofit2.http.QueryMap;
15 |
16 | /**
17 | * ============================================================
18 | * 作 者 : freer-2
19 | * 更新时间 :2019/08/09 11:18
20 | * 描 述 :
21 | * ============================================================
22 | */
23 | public interface MarketService {
24 | @GET("kline/{productCode}/{type}")
25 | Observable>> chartQuotes(@Path("productCode") String productCode, @Path("type") String type, @QueryMap Map params);
26 | }
27 |
--------------------------------------------------------------------------------
/sample_zm/src/main/java/com/matt/sample_zm/net/ServiceWrapper.kt:
--------------------------------------------------------------------------------
1 | package com.matt.sample_zm.net
2 |
3 |
4 | /**
5 | * ============================================================
6 | * 作 者 : matt@163.com
7 | * 更新时间 :2019/06/20 16:28
8 | * 描 述 :
9 | * ============================================================
10 | */
11 | object ServiceWrapper {
12 | val TRADE_SERVICE: TradeService by lazy {
13 | TradeRetrofitBuilder.mRetrofit.create(TradeService::class.java)
14 | }
15 |
16 | val MARKET_SERVICE: MarketService by lazy {
17 | MarketRetrofitBuilder.mRetrofit.create(MarketService::class.java)
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/sample_zm/src/main/java/com/matt/sample_zm/net/TradeRetrofitBuilder.kt:
--------------------------------------------------------------------------------
1 | package com.matt.sample_zm.net
2 |
3 | import com.matt.sample_zm.config.GlobalConfig
4 | import com.matt.libwrapper.repository.net.AbstractRetrofitBuilder
5 | import retrofit2.Retrofit
6 |
7 |
8 | /**
9 | * ============================================================
10 | * 作 者 : freer-2
11 | * 更新时间 :2019/11/13 13:41
12 | * 描 述 :一个Retrofit实例
13 | * ============================================================
14 | */
15 | class TradeRetrofitBuilder : AbstractRetrofitBuilder() {
16 |
17 | override fun apiBaseUrl(): String {
18 | return GlobalConfig.getTradeUrl()
19 | }
20 |
21 | companion object {
22 | val mRetrofit: Retrofit by lazy(LazyThreadSafetyMode.SYNCHRONIZED) {
23 | TradeRetrofitBuilder().mRetrofit
24 | }
25 | }
26 |
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/sample_zm/src/main/java/com/matt/sample_zm/net/TradeService.java:
--------------------------------------------------------------------------------
1 | package com.matt.sample_zm.net;
2 |
3 |
4 |
5 | import com.matt.sample_zm.bean.ApiData;
6 | import com.matt.sample_zm.bean.ApiProduct;
7 |
8 | import java.util.List;
9 | import java.util.Map;
10 |
11 | import io.reactivex.Observable;
12 | import retrofit2.http.GET;
13 | import retrofit2.http.Path;
14 | import retrofit2.http.QueryMap;
15 |
16 | /**
17 | * ============================================================
18 | * 作 者 : freer-2
19 | * 更新时间 :2019/08/09 11:18
20 | * 描 述 :
21 | * ============================================================
22 | */
23 | public interface TradeService {
24 |
25 | @GET("/product/details")
26 | Observable>> getProductList(@QueryMap Map params);
27 |
28 | @GET("/product/detail/{productCode}")
29 | Observable> getProductDetails(@Path("productCode") String productCode);
30 | }
31 |
--------------------------------------------------------------------------------
/sample_zm/src/main/java/com/matt/sample_zm/net/base/SimpleTObserver.kt:
--------------------------------------------------------------------------------
1 | package com.matt.sample_zm.net.base
2 |
3 | import com.matt.libwrapper.exception.ApiSuccessNullException
4 | import com.matt.libwrapper.exception.ExceptionManager
5 | import com.matt.libwrapper.exception.ExceptionType
6 | import com.matt.libwrapper.ui.base.loading.IDisposable
7 | import com.matt.libwrapper.widget.ObserverWrapper
8 | import com.matt.sample_zm.bean.ApiData
9 |
10 | /**
11 | * ============================================================
12 | * 作 者 : matt
13 | * 更新时间 :2020/03/11 10:16
14 | * 描 述 :
15 | * ============================================================
16 | */
17 | abstract class SimpleTObserver(iDisposable: IDisposable) :
18 | ObserverWrapper>(iDisposable) {
19 |
20 | override fun onCatchNext(t: ApiData) {
21 | super.onCatchNext(t)
22 | if (t.isSuccess) {
23 | onInnerSuccess(t.data)
24 | } else {
25 | onFinalFail(t.code, null)
26 | }
27 | }
28 |
29 | override fun onCatchError(e: Throwable) {
30 | super.onCatchError(e)
31 | onFinalFail(null, e)
32 | }
33 |
34 | override fun onHandlerException(e: Throwable) {
35 | //super.onHandlerException(e)
36 | onFinalFail(null, e)
37 | }
38 |
39 | open fun onInnerSuccess(data: T?) {
40 | if (data == null) throw ApiSuccessNullException("data不允许为null")
41 | onFinalSuccess(data)
42 | }
43 |
44 | open fun onFinalFail(code: Int?, throwable: Throwable?) {
45 | ExceptionManager.handlerException(throwable, null, ExceptionType.NET)
46 | }
47 |
48 | abstract fun onFinalSuccess(data: T)
49 |
50 | }
--------------------------------------------------------------------------------
/sample_zm/src/main/java/com/matt/sample_zm/ui/activity/ChartActivity.kt:
--------------------------------------------------------------------------------
1 | package com.matt.sample_zm.ui.activity
2 |
3 | import android.content.Context
4 | import android.content.Intent
5 | import android.os.Bundle
6 | import com.matt.sample_zm.ui.fragment.ChartContainerFragment
7 | import com.matt.sample_zm.vm.ChartViewModel
8 | import com.matt.libwrapper.ui.base.HandleExceptionActivity
9 | import com.matt.libwrapper.ui.base.template.Template
10 | import com.matt.libwrapper.ui.base.template.TemplateBarActivity
11 | import com.matt.sample_zm.R
12 |
13 | class ChartActivity : TemplateBarActivity() {
14 | companion object {
15 | const val KEY_SYMBOL = "KEY_SYMBOL"
16 | fun goIntent(context: Context, symbol: String) {
17 | val intent = Intent(context, ChartActivity::class.java)
18 | intent.putExtra(KEY_SYMBOL, symbol)
19 | context.startActivity(intent)
20 | }
21 | }
22 |
23 |
24 | val mCharViewMode by lazy {
25 | getVM(ChartViewModel::class.java)
26 | }
27 |
28 | override fun templateType(): Int {
29 | return Template.TEMPLATETYPE_DEFVIEW
30 | }
31 |
32 | override fun addChildrenView(): Any {
33 | return R.layout.zm_activity_chart
34 | }
35 |
36 | override fun renderTitle(): Any {
37 | return mCharViewMode.mSymbol
38 | }
39 |
40 | override fun onCatchCreate(savedInstanceState: Bundle?) {
41 | super.onCatchCreate(savedInstanceState)
42 | initView()
43 | initListener()
44 | }
45 |
46 | override fun getIntentExtras(intent: Intent) {
47 | super.getIntentExtras(intent)
48 | val symbol =
49 | intent.getStringExtra(KEY_SYMBOL) ?: throw IllegalArgumentException("mSymbol不允许为null")
50 | mCharViewMode.mSymbol = symbol
51 | }
52 |
53 | private fun initView() {
54 | addFragment(
55 | ChartContainerFragment.newInstance(),
56 | R.id.ac_fl_chartContainer
57 | )
58 | }
59 |
60 | private fun initListener() {
61 |
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/sample_zm/src/main/java/com/matt/sample_zm/ui/activity/SymbolListActivity.kt:
--------------------------------------------------------------------------------
1 | package com.matt.sample_zm.ui.activity
2 |
3 | import android.content.Context
4 | import android.content.Intent
5 | import android.os.Bundle
6 | import androidx.recyclerview.widget.LinearLayoutManager
7 | import com.chad.library.adapter.base.BaseQuickAdapter
8 | import com.chad.library.adapter.base.viewholder.BaseViewHolder
9 | import com.matt.sample_zm.net.ServiceWrapper
10 | import com.matt.sample_zm.net.base.SimpleTObserver
11 | import com.matt.libwrapper.ui.base.HandleExceptionActivity
12 | import com.matt.libwrapper.ui.base.template.Template
13 | import com.matt.libwrapper.ui.base.template.TemplateBarActivity
14 | import com.matt.libwrapper.utils.RxUtils
15 | import com.matt.sample_zm.R
16 | import com.matt.sample_zm.bean.ApiProduct
17 | import kotlinx.android.synthetic.main.zm_activity_symbol_list.*
18 | import kotlinx.android.synthetic.main.zm_item_activity_symbol_list.view.*
19 |
20 | class SymbolListActivity : TemplateBarActivity() {
21 |
22 | companion object {
23 | fun goIntent(context: Context) {
24 | val intent = Intent(context, SymbolListActivity::class.java)
25 | context.startActivity(intent)
26 | }
27 | }
28 |
29 | val mDataList by lazy {
30 | ArrayList()
31 | }
32 |
33 | val mAdapter by lazy {
34 | object : BaseQuickAdapter(
35 | R.layout.zm_item_activity_symbol_list,
36 | mDataList
37 | ) {
38 | override fun convert(holder: BaseViewHolder, item: ApiProduct) {
39 | holder.itemView.run {
40 | iasl_tv_cnName.text = item.cnName
41 | iasl_tv_enName.text = item.enName
42 | iasl_tv_currPrice.text = item.currentPriceFormat
43 | }
44 |
45 | }
46 | }
47 | }
48 |
49 | override fun templateType(): Int {
50 | return Template.TEMPLATETYPE_DEFVIEW
51 | }
52 |
53 | override fun addChildrenView(): Any {
54 | return R.layout.zm_activity_symbol_list
55 | }
56 |
57 | override fun renderTitle(): Any {
58 | return "ZM 列表"
59 | }
60 |
61 | override fun onCatchCreate(savedInstanceState: Bundle?) {
62 | super.onCatchCreate(savedInstanceState)
63 | initAdapter()
64 | initListener()
65 | asl_srl_refresh.isRefreshing = true
66 | loadData()
67 | }
68 |
69 | private fun loadData() {
70 | val map = HashMap()
71 | map["limit"] = 50
72 | map["offset"] = 0
73 | map["category"] = 1
74 | ServiceWrapper.TRADE_SERVICE.getProductList(map)
75 | .compose(RxUtils.rxObSchedulerHelper())
76 | .subscribe(object : SimpleTObserver>(mActivity) {
77 | override fun onFinalSuccess(data: List) {
78 | asl_srl_refresh.isRefreshing = false
79 | mDataList.clear()
80 | mDataList.addAll(data)
81 | mAdapter.notifyDataSetChanged()
82 | }
83 | })
84 | }
85 |
86 | private fun initAdapter() {
87 | asl_rv_recycle.layoutManager = LinearLayoutManager(mContext)
88 | asl_rv_recycle.adapter = mAdapter
89 | }
90 |
91 | private fun initListener() {
92 | asl_srl_refresh.setOnRefreshListener {
93 | loadData()
94 | }
95 | mAdapter.setOnItemClickListener { _, _, position ->
96 | val apiProduct = mDataList[position]
97 | ChartActivity.goIntent(mContext, apiProduct.productCode)
98 | }
99 | }
100 | }
101 |
--------------------------------------------------------------------------------
/sample_zm/src/main/java/com/matt/sample_zm/ui/fragment/ChartContainerFragment.kt:
--------------------------------------------------------------------------------
1 | package com.matt.sample_zm.ui.fragment
2 |
3 | import android.util.Log
4 | import android.view.View
5 | import androidx.fragment.app.Fragment
6 | import com.matt.sample_zm.vm.ChartViewModel
7 | import com.matt.libwrapper.ui.base.LazyLoadBaseFragment
8 | import com.matt.mpwrapper.view.type.KType
9 | import com.matt.sample_zm.R
10 | import kotlinx.android.synthetic.main.zm_fragment_chart_container.view.*
11 |
12 | /**
13 | * ============================================================
14 | * 作 者 : matt
15 | * 更新时间 :2020/03/16 11:44
16 | * 描 述 :
17 | * ============================================================
18 | */
19 | class ChartContainerFragment : LazyLoadBaseFragment() {
20 | companion object {
21 | fun newInstance(): ChartContainerFragment {
22 | return ChartContainerFragment()
23 | }
24 | }
25 |
26 | override fun layoutId(): Int {
27 | return R.layout.zm_fragment_chart_container
28 | }
29 |
30 | val mCharViewMode by lazy {
31 | getVMByActivity(ChartViewModel::class.java)
32 | }
33 |
34 | override fun safeInitAll(rootView: View) {
35 | Log.d(TAG, "symbol:${mCharViewMode.mSymbol}")
36 | initView()
37 | }
38 |
39 | private fun initView() {
40 | val kTypeList = KType.getKTypeList()
41 | val titles = Array(kTypeList.size) {
42 | kTypeList[it].getmLable()
43 | }
44 | val fragments = ArrayList()
45 | kTypeList.forEach {
46 | fragments.add(ChartFragment.newInstance(it, mCharViewMode.mSymbol))
47 | }
48 | mRootView.run {
49 | fcc_stl_tab.setViewPager(
50 | fcc_fl_viewPager,
51 | titles,
52 | mBaseActivity,
53 | fragments
54 | )
55 | }
56 | }
57 | }
--------------------------------------------------------------------------------
/sample_zm/src/main/java/com/matt/sample_zm/ui/fragment/ChartFragment.kt:
--------------------------------------------------------------------------------
1 | package com.matt.sample_zm.ui.fragment
2 |
3 | import android.os.Bundle
4 | import android.util.Log
5 | import android.view.View
6 | import com.matt.libwrapper.ui.base.LazyLoadBaseFragment
7 | import com.matt.libwrapper.utils.RxUtils
8 | import com.matt.mpwrapper.bean.Price
9 | import com.matt.mpwrapper.view.type.KType
10 | import com.matt.mpwrapper.view.type.MasterViewType
11 | import com.matt.mpwrapper.view.type.MinorIndicatorType
12 | import com.matt.mpwrapper.view.type.VolIndicatorType
13 | import com.matt.sample_zm.R
14 | import com.matt.sample_zm.net.base.SimpleTObserver
15 | import com.matt.sample_zm.ui.activity.ChartActivity
16 | import com.matt.sample_zm.vm.ChartViewModel
17 | import kotlinx.android.synthetic.main.zm_fragment_chart.view.*
18 |
19 | /**
20 | * ============================================================
21 | * 作 者 : matt
22 | * 更新时间 :2020/03/16 11:44
23 | * 描 述 :
24 | * ============================================================
25 | */
26 | class ChartFragment : LazyLoadBaseFragment() {
27 | companion object {
28 | const val KEY_KTYPE = "KEY_KTYPE"
29 | fun newInstance(kType: KType, symbol: String): ChartFragment {
30 | return ChartFragment().apply {
31 | arguments = Bundle().apply {
32 | putString(ChartActivity.KEY_SYMBOL, symbol)
33 | putSerializable(KEY_KTYPE, kType)
34 | }
35 | }
36 | }
37 | }
38 |
39 | override fun layoutId(): Int {
40 | return R.layout.zm_fragment_chart
41 | }
42 |
43 | val mChartViewMode by lazy {
44 | getVMByFragment(ChartViewModel::class.java)
45 | }
46 |
47 | lateinit var kType: KType
48 |
49 | override fun getBundleExtras(bundle: Bundle?) {
50 | super.getBundleExtras(bundle)
51 | val serializable =
52 | bundle?.getSerializable(KEY_KTYPE)
53 | ?: throw IllegalArgumentException("KEY_KTYPE 不允许为null")
54 | kType = serializable as KType
55 | val symbol = bundle.getString(ChartActivity.KEY_SYMBOL)
56 | ?: throw IllegalArgumentException("KEY_SYMBOL 不允许为null")
57 | mChartViewMode.mSymbol = symbol
58 | }
59 |
60 |
61 | override fun safeInitAll(rootView: View) {
62 | Log.d(TAG, "symbol:${mChartViewMode.mSymbol}")
63 | initView()
64 | loadData()
65 | }
66 |
67 | private fun initView() {
68 | mRootView.run {
69 | val masterViewType = if (kType == KType.K_TIMESHARE)
70 | MasterViewType.TIMESHARING
71 | else
72 | MasterViewType.CANDLE
73 | fc_kv_kview.updateConfig(
74 | 4,
75 | masterViewType,
76 | minorIndicatorType = MinorIndicatorType.MACD,
77 | volIndicatorType = VolIndicatorType.GONE
78 | )
79 | }
80 | }
81 |
82 | private fun loadData() {
83 | mChartViewMode.getQuoteListByNet(mChartViewMode.mSymbol, kType)
84 | .compose(RxUtils.rxObSchedulerHelper())
85 | .subscribe(object : SimpleTObserver>(mBaseActivity) {
86 | override fun onFinalSuccess(data: List) {
87 | Log.d(TAG, data.toString())
88 | renderChart(data)
89 | }
90 | })
91 | }
92 |
93 | private fun renderChart(it: List) {
94 | mRootView.run {
95 | fc_kv_kview.loadData(it)
96 | }
97 | }
98 | }
--------------------------------------------------------------------------------
/sample_zm/src/main/java/com/matt/sample_zm/vm/BaseViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.matt.sample_zm.vm
2 |
3 | import androidx.lifecycle.ViewModel
4 |
5 | /**
6 | * ============================================================
7 | * 作 者 : matt
8 | * 更新时间 :2020/03/16 12:49
9 | * 描 述 :
10 | * ============================================================
11 | */
12 | abstract class BaseViewModel : ViewModel() {
13 | override fun onCleared() {
14 | super.onCleared()
15 | }
16 | }
--------------------------------------------------------------------------------
/sample_zm/src/main/java/com/matt/sample_zm/vm/ChartViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.matt.sample_zm.vm
2 |
3 | import com.matt.sample_zm.net.ServiceWrapper
4 | import com.matt.mpwrapper.bean.Price
5 | import com.matt.mpwrapper.view.type.KType
6 | import com.matt.sample_zm.bean.ApiData
7 | import io.reactivex.Observable
8 |
9 | /**
10 | * ============================================================
11 | * 作 者 : matt
12 | * 更新时间 :2020/03/16 12:48
13 | * 描 述 :
14 | * ============================================================
15 | */
16 | class ChartViewModel : BaseViewModel() {
17 | lateinit var mSymbol: String
18 |
19 | /**
20 | * 从网络加载数据
21 | */
22 | fun getQuoteListByNet(
23 | symbol: String,
24 | kType: KType
25 | ): Observable>> {
26 | val params = HashMap()
27 | params["count"] = getQueryLimit(kType)
28 | return ServiceWrapper.MARKET_SERVICE.chartQuotes(symbol, kType.getmApiType(), params)
29 | .flatMap {
30 | if (!it.isSuccess) {
31 | Observable.just(
32 | ApiData.newErrorIns(
33 | it,
34 | List::class.java
35 | )
36 | ) as Observable>>
37 | } else {
38 | val data = it.data ?: throw IllegalArgumentException("it.data不允许为null")
39 | val list = ArrayList()
40 | data.forEach { item ->
41 | val price = Price(item.s, item.o, item.h, item.l, item.c)
42 | list.add(price)
43 | }
44 | val apiData = ApiData.newSuccessIns(List::class.java)
45 | apiData.data = list
46 | Observable.just(apiData) as Observable>>
47 | }
48 | }
49 | }
50 |
51 | private fun getQueryLimit(type: KType): Int {
52 | return if (type == KType.K_TIMESHARE || type == KType.K_1MIN) {
53 | 500
54 | } else if (type == KType.K_5MIN) {
55 | 288
56 | } else
57 | 200
58 | }
59 | }
--------------------------------------------------------------------------------
/sample_zm/src/main/res/layout/zm_activity_chart.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
15 |
16 |
20 |
21 |
22 |
23 |
29 |
30 |
36 |
37 |
41 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/sample_zm/src/main/res/layout/zm_activity_symbol_list.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
12 |
--------------------------------------------------------------------------------
/sample_zm/src/main/res/layout/zm_fragment_chart.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/sample_zm/src/main/res/layout/zm_fragment_chart_container.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
25 |
26 |
30 |
31 |
35 |
--------------------------------------------------------------------------------
/sample_zm/src/main/res/layout/zm_item_activity_symbol_list.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
16 |
17 |
24 |
25 |
32 |
33 |
34 |
35 |
43 |
--------------------------------------------------------------------------------
/sample_zm/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #6200EE
4 | #3700B3
5 | #03DAC5
6 |
7 |
8 | #4281ff
9 |
10 | #292c33
11 |
12 | #596580
13 |
14 | #a3afcc
15 |
16 | #b2b2b2
17 |
18 |
19 | #ebf2ff
20 |
21 |
22 | #ffffff
23 | #fbfbfb
24 | #b2b2b2
25 | #b2b2b2
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/sample_zm/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | MPAndroidChartWrapper
3 | 当前网络不稳定,请检查后重试
4 |
5 |
--------------------------------------------------------------------------------
/sample_zm/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/sample_zm/src/test/java/com/matt/sample_zm/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package com.matt.sample_zm
2 |
3 | import org.junit.Test
4 |
5 | import org.junit.Assert.*
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * See [testing documentation](http://d.android.com/tools/testing).
11 | */
12 | class ExampleUnitTest {
13 | @Test
14 | fun addition_isCorrect() {
15 | assertEquals(4, 2 + 2)
16 | }
17 | }
--------------------------------------------------------------------------------
/screenshots/kview_竖屏_高亮线.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/scsfwgy/MPAndroidChartWrapper/a074ff292811a2b6307b150d6bdbd8ef7fcdbea1/screenshots/kview_竖屏_高亮线.png
--------------------------------------------------------------------------------
/screenshots/kview_竖屏_默认.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/scsfwgy/MPAndroidChartWrapper/a074ff292811a2b6307b150d6bdbd8ef7fcdbea1/screenshots/kview_竖屏_默认.png
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | rootProject.name='MPAndroidChartWrapper'
2 | include ':mpwrapper'
3 | include ':sample_base'
4 | include ':sample_zm'
5 | include ':sample_binance'
6 | include ':app'
7 |
8 |
9 |
10 | /**
11 | * 本地依赖方式,把当前项目和 https://github.com/scsfwgy/TemplateApp 放到一个根目录下,
12 | * 同时需要注释掉https://github.com/scsfwgy/TemplateApp 和远程库jitpack相关的代码,
13 | * 然后打开一下注释即可
14 | */
15 | //include ':lib_wrapper'
16 | //project(':lib_wrapper').projectDir = new File(settingsDir, "../TemplateApp/lib_wrapper")
17 | //
18 | //include ':lib_import'
19 | //project(':lib_import').projectDir = new File(settingsDir, "../TemplateApp/lib_import")
20 |
--------------------------------------------------------------------------------