From 54127ffd102ed962a04324441ea77977dbc12a37 Mon Sep 17 00:00:00 2001
From: 陶汉栋 <2821744554@qq.com>
Date: Mon, 5 Mar 2018 17:33:43 +0800
Subject: [PATCH] no message
---
.gitignore | 9 +++++++++
.idea/gradle.xml | 19 +++++++++++++++++++
.idea/misc.xml | 33 +++++++++++++++++++++++++++++++++
.idea/modules.xml | 10 ++++++++++
.idea/runConfigurations.xml | 12 ++++++++++++
.idea/vcs.xml | 6 ++++++
app/.gitignore | 1 +
app/build.gradle | 30 ++++++++++++++++++++++++++++++
app/proguard-rules.pro | 21 +++++++++++++++++++++
app/src/androidTest/java/com/shunzhi/parent/ExampleInstrumentedTest.java | 26 ++++++++++++++++++++++++++
app/src/main/AndroidManifest.xml | 24 ++++++++++++++++++++++++
app/src/main/java/com/shunzhi/parent/MyApplication.java | 17 +++++++++++++++++
app/src/main/java/com/shunzhi/parent/ui/MainActivity.java | 15 +++++++++++++++
app/src/main/java/com/shunzhi/parent/ui/activity/LoginAndRegistActivity.java | 15 +++++++++++++++
app/src/main/java/com/shunzhi/parent/ui/activity/StartActivity.java | 15 +++++++++++++++
app/src/main/java/com/shunzhi/parent/ui/fragment/CePingFragment.java | 109 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
app/src/main/java/com/shunzhi/parent/ui/fragment/ConsultFragment.java | 109 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
app/src/main/java/com/shunzhi/parent/ui/fragment/MineFragment.java | 109 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
app/src/main/java/com/shunzhi/parent/ui/fragment/ReportFragment.java | 109 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
app/src/main/java/com/shunzhi/parent/ui/fragment/loginandregistfragment/LoginAndRegistFragment.java | 109 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
app/src/main/res/drawable-v24/ic_launcher_foreground.xml | 34 ++++++++++++++++++++++++++++++++++
app/src/main/res/drawable/ic_launcher_background.xml | 170 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
app/src/main/res/layout/activity_main.xml | 18 ++++++++++++++++++
app/src/main/res/layout/activity_regist.xml | 9 +++++++++
app/src/main/res/layout/activity_start.xml | 9 +++++++++
app/src/main/res/layout/fragment_ce_ping.xml | 13 +++++++++++++
app/src/main/res/layout/fragment_login_and_regist.xml | 13 +++++++++++++
app/src/main/res/layout/fragment_mine.xml | 13 +++++++++++++
app/src/main/res/layout/fragment_report.xml | 13 +++++++++++++
app/src/main/res/layout/fragment_zi_xun.xml | 13 +++++++++++++
app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml | 5 +++++
app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml | 5 +++++
app/src/main/res/mipmap-hdpi/ic_launcher.png | Bin 0 -> 3056 bytes
app/src/main/res/mipmap-hdpi/ic_launcher_round.png | Bin 0 -> 5024 bytes
app/src/main/res/mipmap-mdpi/ic_launcher.png | Bin 0 -> 2096 bytes
app/src/main/res/mipmap-mdpi/ic_launcher_round.png | Bin 0 -> 2858 bytes
app/src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 0 -> 4569 bytes
app/src/main/res/mipmap-xhdpi/ic_launcher_round.png | Bin 0 -> 7098 bytes
app/src/main/res/mipmap-xxhdpi/ic_launcher.png | Bin 0 -> 6464 bytes
app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png | Bin 0 -> 10676 bytes
app/src/main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 0 -> 9250 bytes
app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png | Bin 0 -> 15523 bytes
app/src/main/res/values/colors.xml | 6 ++++++
app/src/main/res/values/strings.xml | 6 ++++++
app/src/main/res/values/styles.xml | 11 +++++++++++
app/src/test/java/com/shunzhi/parent/ExampleUnitTest.java | 17 +++++++++++++++++
build.gradle | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
gradle.properties | 17 +++++++++++++++++
gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 53636 bytes
gradle/wrapper/gradle-wrapper.properties | 6 ++++++
gradlew | 160 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
gradlew.bat | 90 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
mvpsdk/.gitignore | 1 +
mvpsdk/build.gradle | 102 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
mvpsdk/proguard-rules.pro | 21 +++++++++++++++++++++
mvpsdk/src/androidTest/java/com/share/mvpsdk/ExampleInstrumentedTest.java | 26 ++++++++++++++++++++++++++
mvpsdk/src/main/AndroidManifest.xml | 2 ++
mvpsdk/src/main/java/com/share/mvpsdk/AppManager.java | 111 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
mvpsdk/src/main/java/com/share/mvpsdk/RxManager.java | 23 +++++++++++++++++++++++
mvpsdk/src/main/java/com/share/mvpsdk/adapter/FragmentAdapter.java | 42 ++++++++++++++++++++++++++++++++++++++++++
mvpsdk/src/main/java/com/share/mvpsdk/anim/AnimManager.java | 75 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
mvpsdk/src/main/java/com/share/mvpsdk/anim/AnimUtils.java | 330 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
mvpsdk/src/main/java/com/share/mvpsdk/anim/ToolbarAnimManager.java | 93 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
mvpsdk/src/main/java/com/share/mvpsdk/base/BaseModel.java | 11 +++++++++++
mvpsdk/src/main/java/com/share/mvpsdk/base/BasePresenter.java | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++
mvpsdk/src/main/java/com/share/mvpsdk/base/IBaseActivity.java | 35 +++++++++++++++++++++++++++++++++++
mvpsdk/src/main/java/com/share/mvpsdk/base/IBaseFragment.java | 92 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
mvpsdk/src/main/java/com/share/mvpsdk/base/IBaseModel.java | 9 +++++++++
mvpsdk/src/main/java/com/share/mvpsdk/base/IBaseView.java | 47 +++++++++++++++++++++++++++++++++++++++++++++++
mvpsdk/src/main/java/com/share/mvpsdk/base/activity/BaseCompatActivity.java | 249 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
mvpsdk/src/main/java/com/share/mvpsdk/base/activity/BaseMVPCompatActivity.java | 94 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
mvpsdk/src/main/java/com/share/mvpsdk/base/adapter/BaseRecyclerViewAdapter.java | 79 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
mvpsdk/src/main/java/com/share/mvpsdk/base/adapter/BaseRecyclerViewHolder.java | 22 ++++++++++++++++++++++
mvpsdk/src/main/java/com/share/mvpsdk/base/adapter/OnItemClickListener.java | 10 ++++++++++
mvpsdk/src/main/java/com/share/mvpsdk/base/adapter/OnItemLongClickListener.java | 10 ++++++++++
mvpsdk/src/main/java/com/share/mvpsdk/base/entity/BaseEntity.java | 47 +++++++++++++++++++++++++++++++++++++++++++++++
mvpsdk/src/main/java/com/share/mvpsdk/base/entity/BaseListEntity.java | 48 ++++++++++++++++++++++++++++++++++++++++++++++++
mvpsdk/src/main/java/com/share/mvpsdk/base/fragment/BaseCompatFragment.java | 153 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
mvpsdk/src/main/java/com/share/mvpsdk/base/fragment/BaseMVPCompatFragment.java | 128 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
mvpsdk/src/main/java/com/share/mvpsdk/base/fragment/BaseRecycleFragment.java | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
mvpsdk/src/main/java/com/share/mvpsdk/config/DBConfig.java | 16 ++++++++++++++++
mvpsdk/src/main/java/com/share/mvpsdk/config/ItemState.java | 19 +++++++++++++++++++
mvpsdk/src/main/java/com/share/mvpsdk/global/GlobalApplication.java | 67 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
mvpsdk/src/main/java/com/share/mvpsdk/helper/BottomNavigationViewHelper.java | 37 +++++++++++++++++++++++++++++++++++++
mvpsdk/src/main/java/com/share/mvpsdk/helper/RetrofitCreateHelper.java | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
mvpsdk/src/main/java/com/share/mvpsdk/helper/RxHelper.java | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
mvpsdk/src/main/java/com/share/mvpsdk/helper/okhttp/CacheInterceptor.java | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
mvpsdk/src/main/java/com/share/mvpsdk/helper/okhttp/HttpCache.java | 28 ++++++++++++++++++++++++++++
mvpsdk/src/main/java/com/share/mvpsdk/helper/okhttp/NetInterceptor.java | 49 +++++++++++++++++++++++++++++++++++++++++++++++++
mvpsdk/src/main/java/com/share/mvpsdk/helper/okhttp/NoNetInterceptor.java | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++
mvpsdk/src/main/java/com/share/mvpsdk/helper/okhttp/TrustManager.java | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
mvpsdk/src/main/java/com/share/mvpsdk/rxbus/BusData.java | 34 ++++++++++++++++++++++++++++++++++
mvpsdk/src/main/java/com/share/mvpsdk/rxbus/RxBus.java | 355 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
mvpsdk/src/main/java/com/share/mvpsdk/rxbus/Subscribe.java | 21 +++++++++++++++++++++
mvpsdk/src/main/java/com/share/mvpsdk/rxbus/SubscriberMethod.java | 44 ++++++++++++++++++++++++++++++++++++++++++++
mvpsdk/src/main/java/com/share/mvpsdk/rxbus/ThreadMode.java | 23 +++++++++++++++++++++++
mvpsdk/src/main/java/com/share/mvpsdk/utils/AppUtils.java | 185 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
mvpsdk/src/main/java/com/share/mvpsdk/utils/DBUtils.java | 108 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
mvpsdk/src/main/java/com/share/mvpsdk/utils/DateUtils.java | 250 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
mvpsdk/src/main/java/com/share/mvpsdk/utils/DialogUtils.java | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
mvpsdk/src/main/java/com/share/mvpsdk/utils/DisplayUtils.java | 195 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
mvpsdk/src/main/java/com/share/mvpsdk/utils/FileUtils.java | 291 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
mvpsdk/src/main/java/com/share/mvpsdk/utils/HtmlUtils.java | 93 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
mvpsdk/src/main/java/com/share/mvpsdk/utils/HttpUtils.java | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
mvpsdk/src/main/java/com/share/mvpsdk/utils/IOUtils.java | 25 +++++++++++++++++++++++++
mvpsdk/src/main/java/com/share/mvpsdk/utils/ImageUtils.java | 339 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
mvpsdk/src/main/java/com/share/mvpsdk/utils/JsonUtils.java | 65 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
mvpsdk/src/main/java/com/share/mvpsdk/utils/LogUtils.java | 168 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
mvpsdk/src/main/java/com/share/mvpsdk/utils/MD5Utils.java | 38 ++++++++++++++++++++++++++++++++++++++
mvpsdk/src/main/java/com/share/mvpsdk/utils/NavigationUtils.java | 23 +++++++++++++++++++++++
mvpsdk/src/main/java/com/share/mvpsdk/utils/NetworkConnectionUtils.java | 236 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
mvpsdk/src/main/java/com/share/mvpsdk/utils/PermissionUtils.java | 323 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
mvpsdk/src/main/java/com/share/mvpsdk/utils/ResourcesUtils.java | 83 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
mvpsdk/src/main/java/com/share/mvpsdk/utils/ScreenUtils.java | 151 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
mvpsdk/src/main/java/com/share/mvpsdk/utils/SnackbarUtils.java | 189 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
mvpsdk/src/main/java/com/share/mvpsdk/utils/SpUtils.java | 212 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
mvpsdk/src/main/java/com/share/mvpsdk/utils/StatusBarUtils.java | 139 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
mvpsdk/src/main/java/com/share/mvpsdk/utils/StringUtils.java | 125 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
mvpsdk/src/main/java/com/share/mvpsdk/utils/ThemeUtils.java | 75 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
mvpsdk/src/main/java/com/share/mvpsdk/utils/TimestampUtils.java | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
mvpsdk/src/main/java/com/share/mvpsdk/utils/ToastUtils.java | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
mvpsdk/src/main/java/com/share/mvpsdk/utils/UnicodeUtils.java | 108 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
mvpsdk/src/main/java/com/share/mvpsdk/utils/WifiAutoConnectManager.java | 224 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
mvpsdk/src/main/java/com/share/mvpsdk/view/MyEyeView.java | 71 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
mvpsdk/src/main/java/com/share/mvpsdk/view/MyViewView.java | 368 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
mvpsdk/src/main/java/com/share/mvpsdk/widgets/CompatNestedScrollView.java | 86 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
mvpsdk/src/main/java/com/share/mvpsdk/widgets/HistoryChartView.java | 719 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
mvpsdk/src/main/java/com/share/mvpsdk/widgets/HistoryModeView.java | 107 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
mvpsdk/src/main/java/com/share/mvpsdk/widgets/HistoryTipView.java | 95 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
mvpsdk/src/main/java/com/share/mvpsdk/widgets/MovingImageView.java | 332 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
mvpsdk/src/main/java/com/share/mvpsdk/widgets/MovingViewAnimator.java | 448 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
mvpsdk/src/main/java/com/share/mvpsdk/widgets/NestedScrollWebView.java | 168 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
mvpsdk/src/main/java/com/share/mvpsdk/widgets/PickerView.java | 314 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
mvpsdk/src/main/java/com/share/mvpsdk/widgets/ProgressButton.java | 79 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
mvpsdk/src/main/java/com/share/mvpsdk/widgets/SlideSwitchView.java | 259 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
mvpsdk/src/main/java/com/share/mvpsdk/widgets/WaitPorgressDialog.java | 22 ++++++++++++++++++++++
mvpsdk/src/main/java/com/share/mvpsdk/widgets/headclip/ClipView.java | 157 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
mvpsdk/src/main/java/com/share/mvpsdk/widgets/headclip/ClipViewLayout.java | 485 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
mvpsdk/src/main/res/anim/activity_finish_trans_in.xml | 11 +++++++++++
mvpsdk/src/main/res/anim/activity_finish_trans_out.xml | 21 +++++++++++++++++++++
mvpsdk/src/main/res/anim/activity_finish_zoom_in.xml | 12 ++++++++++++
mvpsdk/src/main/res/anim/activity_finish_zoom_out.xml | 18 ++++++++++++++++++
mvpsdk/src/main/res/anim/activity_start_trans_in.xml | 21 +++++++++++++++++++++
mvpsdk/src/main/res/anim/activity_start_trans_out.xml | 11 +++++++++++
mvpsdk/src/main/res/anim/activity_start_zoom_in.xml | 12 ++++++++++++
mvpsdk/src/main/res/anim/activity_start_zoom_out.xml | 17 +++++++++++++++++
mvpsdk/src/main/res/drawable/ic_vector_empty.xml | 30 ++++++++++++++++++++++++++++++
mvpsdk/src/main/res/drawable/ic_vector_loading.xml | 8 ++++++++
mvpsdk/src/main/res/drawable/ic_vector_net_error.xml | 15 +++++++++++++++
mvpsdk/src/main/res/drawable/indoor_temp.png | Bin 0 -> 617 bytes
mvpsdk/src/main/res/drawable/item_touch_bg.xml | 5 +++++
mvpsdk/src/main/res/drawable/stackblur_default.png | Bin 0 -> 32876 bytes
mvpsdk/src/main/res/drawable/week_normal.png | Bin 0 -> 904 bytes
mvpsdk/src/main/res/drawable/week_selector.png | Bin 0 -> 3101 bytes
mvpsdk/src/main/res/drawable/week_status.xml | 9 +++++++++
mvpsdk/src/main/res/drawable/week_tv_status.xml | 7 +++++++
mvpsdk/src/main/res/layout/sub_history_click_view.xml | 25 +++++++++++++++++++++++++
mvpsdk/src/main/res/layout/sub_history_tips.xml | 35 +++++++++++++++++++++++++++++++++++
mvpsdk/src/main/res/layout/view_empty.xml | 19 +++++++++++++++++++
mvpsdk/src/main/res/layout/view_loading.xml | 32 ++++++++++++++++++++++++++++++++
mvpsdk/src/main/res/layout/view_network_error.xml | 19 +++++++++++++++++++
mvpsdk/src/main/res/mipmap-xhdpi/ic_arrow_back_white.png | Bin 0 -> 233 bytes
mvpsdk/src/main/res/mipmap-xxhdpi/ic_arrow_back_white.png | Bin 0 -> 374 bytes
mvpsdk/src/main/res/values-v21/styles.xml | 13 +++++++++++++
mvpsdk/src/main/res/values-zh-rCN/strings.xml | 38 ++++++++++++++++++++++++++++++++++++++
mvpsdk/src/main/res/values/arrays.xml | 24 ++++++++++++++++++++++++
mvpsdk/src/main/res/values/attrs.xml | 81 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
mvpsdk/src/main/res/values/colors.xml | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
mvpsdk/src/main/res/values/dimens.xml | 45 +++++++++++++++++++++++++++++++++++++++++++++
mvpsdk/src/main/res/values/strings.xml | 38 ++++++++++++++++++++++++++++++++++++++
mvpsdk/src/main/res/values/styles.xml | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++
mvpsdk/src/main/res/values/themes.xml | 265 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
mvpsdk/src/main/res/values/themes_colors.xml | 85 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
mvpsdk/src/test/java/com/share/mvpsdk/ExampleUnitTest.java | 17 +++++++++++++++++
settings.gradle | 1 +
175 files changed, 13161 insertions(+), 0 deletions(-)
create mode 100644 .gitignore
create mode 100644 .idea/gradle.xml
create mode 100644 .idea/misc.xml
create mode 100644 .idea/modules.xml
create mode 100644 .idea/runConfigurations.xml
create mode 100644 .idea/vcs.xml
create mode 100644 app/.gitignore
create mode 100644 app/build.gradle
create mode 100644 app/proguard-rules.pro
create mode 100644 app/src/androidTest/java/com/shunzhi/parent/ExampleInstrumentedTest.java
create mode 100644 app/src/main/AndroidManifest.xml
create mode 100644 app/src/main/java/com/shunzhi/parent/MyApplication.java
create mode 100644 app/src/main/java/com/shunzhi/parent/ui/MainActivity.java
create mode 100644 app/src/main/java/com/shunzhi/parent/ui/activity/LoginAndRegistActivity.java
create mode 100644 app/src/main/java/com/shunzhi/parent/ui/activity/StartActivity.java
create mode 100644 app/src/main/java/com/shunzhi/parent/ui/fragment/CePingFragment.java
create mode 100644 app/src/main/java/com/shunzhi/parent/ui/fragment/ConsultFragment.java
create mode 100644 app/src/main/java/com/shunzhi/parent/ui/fragment/MineFragment.java
create mode 100644 app/src/main/java/com/shunzhi/parent/ui/fragment/ReportFragment.java
create mode 100644 app/src/main/java/com/shunzhi/parent/ui/fragment/loginandregistfragment/LoginAndRegistFragment.java
create mode 100644 app/src/main/res/drawable-v24/ic_launcher_foreground.xml
create mode 100644 app/src/main/res/drawable/ic_launcher_background.xml
create mode 100644 app/src/main/res/layout/activity_main.xml
create mode 100644 app/src/main/res/layout/activity_regist.xml
create mode 100644 app/src/main/res/layout/activity_start.xml
create mode 100644 app/src/main/res/layout/fragment_ce_ping.xml
create mode 100644 app/src/main/res/layout/fragment_login_and_regist.xml
create mode 100644 app/src/main/res/layout/fragment_mine.xml
create mode 100644 app/src/main/res/layout/fragment_report.xml
create mode 100644 app/src/main/res/layout/fragment_zi_xun.xml
create mode 100644 app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
create mode 100644 app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
create mode 100644 app/src/main/res/mipmap-hdpi/ic_launcher.png
create mode 100644 app/src/main/res/mipmap-hdpi/ic_launcher_round.png
create mode 100644 app/src/main/res/mipmap-mdpi/ic_launcher.png
create mode 100644 app/src/main/res/mipmap-mdpi/ic_launcher_round.png
create mode 100644 app/src/main/res/mipmap-xhdpi/ic_launcher.png
create mode 100644 app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
create mode 100644 app/src/main/res/mipmap-xxhdpi/ic_launcher.png
create mode 100644 app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
create mode 100644 app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
create mode 100644 app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
create mode 100644 app/src/main/res/values/colors.xml
create mode 100644 app/src/main/res/values/strings.xml
create mode 100644 app/src/main/res/values/styles.xml
create mode 100644 app/src/test/java/com/shunzhi/parent/ExampleUnitTest.java
create mode 100644 build.gradle
create mode 100644 gradle.properties
create mode 100644 gradle/wrapper/gradle-wrapper.jar
create mode 100644 gradle/wrapper/gradle-wrapper.properties
create mode 100644 gradlew
create mode 100644 gradlew.bat
create mode 100644 mvpsdk/.gitignore
create mode 100644 mvpsdk/build.gradle
create mode 100644 mvpsdk/proguard-rules.pro
create mode 100644 mvpsdk/src/androidTest/java/com/share/mvpsdk/ExampleInstrumentedTest.java
create mode 100644 mvpsdk/src/main/AndroidManifest.xml
create mode 100644 mvpsdk/src/main/java/com/share/mvpsdk/AppManager.java
create mode 100644 mvpsdk/src/main/java/com/share/mvpsdk/RxManager.java
create mode 100644 mvpsdk/src/main/java/com/share/mvpsdk/adapter/FragmentAdapter.java
create mode 100644 mvpsdk/src/main/java/com/share/mvpsdk/anim/AnimManager.java
create mode 100644 mvpsdk/src/main/java/com/share/mvpsdk/anim/AnimUtils.java
create mode 100644 mvpsdk/src/main/java/com/share/mvpsdk/anim/ToolbarAnimManager.java
create mode 100644 mvpsdk/src/main/java/com/share/mvpsdk/base/BaseModel.java
create mode 100644 mvpsdk/src/main/java/com/share/mvpsdk/base/BasePresenter.java
create mode 100644 mvpsdk/src/main/java/com/share/mvpsdk/base/IBaseActivity.java
create mode 100644 mvpsdk/src/main/java/com/share/mvpsdk/base/IBaseFragment.java
create mode 100644 mvpsdk/src/main/java/com/share/mvpsdk/base/IBaseModel.java
create mode 100644 mvpsdk/src/main/java/com/share/mvpsdk/base/IBaseView.java
create mode 100644 mvpsdk/src/main/java/com/share/mvpsdk/base/activity/BaseCompatActivity.java
create mode 100644 mvpsdk/src/main/java/com/share/mvpsdk/base/activity/BaseMVPCompatActivity.java
create mode 100644 mvpsdk/src/main/java/com/share/mvpsdk/base/adapter/BaseRecyclerViewAdapter.java
create mode 100644 mvpsdk/src/main/java/com/share/mvpsdk/base/adapter/BaseRecyclerViewHolder.java
create mode 100644 mvpsdk/src/main/java/com/share/mvpsdk/base/adapter/OnItemClickListener.java
create mode 100644 mvpsdk/src/main/java/com/share/mvpsdk/base/adapter/OnItemLongClickListener.java
create mode 100644 mvpsdk/src/main/java/com/share/mvpsdk/base/entity/BaseEntity.java
create mode 100644 mvpsdk/src/main/java/com/share/mvpsdk/base/entity/BaseListEntity.java
create mode 100644 mvpsdk/src/main/java/com/share/mvpsdk/base/fragment/BaseCompatFragment.java
create mode 100644 mvpsdk/src/main/java/com/share/mvpsdk/base/fragment/BaseMVPCompatFragment.java
create mode 100644 mvpsdk/src/main/java/com/share/mvpsdk/base/fragment/BaseRecycleFragment.java
create mode 100644 mvpsdk/src/main/java/com/share/mvpsdk/config/DBConfig.java
create mode 100644 mvpsdk/src/main/java/com/share/mvpsdk/config/ItemState.java
create mode 100644 mvpsdk/src/main/java/com/share/mvpsdk/global/GlobalApplication.java
create mode 100644 mvpsdk/src/main/java/com/share/mvpsdk/helper/BottomNavigationViewHelper.java
create mode 100644 mvpsdk/src/main/java/com/share/mvpsdk/helper/RetrofitCreateHelper.java
create mode 100644 mvpsdk/src/main/java/com/share/mvpsdk/helper/RxHelper.java
create mode 100644 mvpsdk/src/main/java/com/share/mvpsdk/helper/okhttp/CacheInterceptor.java
create mode 100644 mvpsdk/src/main/java/com/share/mvpsdk/helper/okhttp/HttpCache.java
create mode 100644 mvpsdk/src/main/java/com/share/mvpsdk/helper/okhttp/NetInterceptor.java
create mode 100644 mvpsdk/src/main/java/com/share/mvpsdk/helper/okhttp/NoNetInterceptor.java
create mode 100644 mvpsdk/src/main/java/com/share/mvpsdk/helper/okhttp/TrustManager.java
create mode 100644 mvpsdk/src/main/java/com/share/mvpsdk/rxbus/BusData.java
create mode 100644 mvpsdk/src/main/java/com/share/mvpsdk/rxbus/RxBus.java
create mode 100644 mvpsdk/src/main/java/com/share/mvpsdk/rxbus/Subscribe.java
create mode 100644 mvpsdk/src/main/java/com/share/mvpsdk/rxbus/SubscriberMethod.java
create mode 100644 mvpsdk/src/main/java/com/share/mvpsdk/rxbus/ThreadMode.java
create mode 100644 mvpsdk/src/main/java/com/share/mvpsdk/utils/AppUtils.java
create mode 100644 mvpsdk/src/main/java/com/share/mvpsdk/utils/DBUtils.java
create mode 100644 mvpsdk/src/main/java/com/share/mvpsdk/utils/DateUtils.java
create mode 100644 mvpsdk/src/main/java/com/share/mvpsdk/utils/DialogUtils.java
create mode 100644 mvpsdk/src/main/java/com/share/mvpsdk/utils/DisplayUtils.java
create mode 100644 mvpsdk/src/main/java/com/share/mvpsdk/utils/FileUtils.java
create mode 100644 mvpsdk/src/main/java/com/share/mvpsdk/utils/HtmlUtils.java
create mode 100644 mvpsdk/src/main/java/com/share/mvpsdk/utils/HttpUtils.java
create mode 100644 mvpsdk/src/main/java/com/share/mvpsdk/utils/IOUtils.java
create mode 100644 mvpsdk/src/main/java/com/share/mvpsdk/utils/ImageUtils.java
create mode 100644 mvpsdk/src/main/java/com/share/mvpsdk/utils/JsonUtils.java
create mode 100644 mvpsdk/src/main/java/com/share/mvpsdk/utils/LogUtils.java
create mode 100644 mvpsdk/src/main/java/com/share/mvpsdk/utils/MD5Utils.java
create mode 100644 mvpsdk/src/main/java/com/share/mvpsdk/utils/NavigationUtils.java
create mode 100644 mvpsdk/src/main/java/com/share/mvpsdk/utils/NetworkConnectionUtils.java
create mode 100644 mvpsdk/src/main/java/com/share/mvpsdk/utils/PermissionUtils.java
create mode 100644 mvpsdk/src/main/java/com/share/mvpsdk/utils/ResourcesUtils.java
create mode 100644 mvpsdk/src/main/java/com/share/mvpsdk/utils/ScreenUtils.java
create mode 100644 mvpsdk/src/main/java/com/share/mvpsdk/utils/SnackbarUtils.java
create mode 100644 mvpsdk/src/main/java/com/share/mvpsdk/utils/SpUtils.java
create mode 100644 mvpsdk/src/main/java/com/share/mvpsdk/utils/StatusBarUtils.java
create mode 100644 mvpsdk/src/main/java/com/share/mvpsdk/utils/StringUtils.java
create mode 100644 mvpsdk/src/main/java/com/share/mvpsdk/utils/ThemeUtils.java
create mode 100644 mvpsdk/src/main/java/com/share/mvpsdk/utils/TimestampUtils.java
create mode 100644 mvpsdk/src/main/java/com/share/mvpsdk/utils/ToastUtils.java
create mode 100644 mvpsdk/src/main/java/com/share/mvpsdk/utils/UnicodeUtils.java
create mode 100644 mvpsdk/src/main/java/com/share/mvpsdk/utils/WifiAutoConnectManager.java
create mode 100644 mvpsdk/src/main/java/com/share/mvpsdk/view/MyEyeView.java
create mode 100644 mvpsdk/src/main/java/com/share/mvpsdk/view/MyViewView.java
create mode 100644 mvpsdk/src/main/java/com/share/mvpsdk/widgets/CompatNestedScrollView.java
create mode 100644 mvpsdk/src/main/java/com/share/mvpsdk/widgets/HistoryChartView.java
create mode 100644 mvpsdk/src/main/java/com/share/mvpsdk/widgets/HistoryModeView.java
create mode 100644 mvpsdk/src/main/java/com/share/mvpsdk/widgets/HistoryTipView.java
create mode 100644 mvpsdk/src/main/java/com/share/mvpsdk/widgets/MovingImageView.java
create mode 100644 mvpsdk/src/main/java/com/share/mvpsdk/widgets/MovingViewAnimator.java
create mode 100644 mvpsdk/src/main/java/com/share/mvpsdk/widgets/NestedScrollWebView.java
create mode 100644 mvpsdk/src/main/java/com/share/mvpsdk/widgets/PickerView.java
create mode 100644 mvpsdk/src/main/java/com/share/mvpsdk/widgets/ProgressButton.java
create mode 100644 mvpsdk/src/main/java/com/share/mvpsdk/widgets/SlideSwitchView.java
create mode 100644 mvpsdk/src/main/java/com/share/mvpsdk/widgets/WaitPorgressDialog.java
create mode 100644 mvpsdk/src/main/java/com/share/mvpsdk/widgets/headclip/ClipView.java
create mode 100644 mvpsdk/src/main/java/com/share/mvpsdk/widgets/headclip/ClipViewLayout.java
create mode 100644 mvpsdk/src/main/res/anim/activity_finish_trans_in.xml
create mode 100644 mvpsdk/src/main/res/anim/activity_finish_trans_out.xml
create mode 100644 mvpsdk/src/main/res/anim/activity_finish_zoom_in.xml
create mode 100644 mvpsdk/src/main/res/anim/activity_finish_zoom_out.xml
create mode 100644 mvpsdk/src/main/res/anim/activity_start_trans_in.xml
create mode 100644 mvpsdk/src/main/res/anim/activity_start_trans_out.xml
create mode 100644 mvpsdk/src/main/res/anim/activity_start_zoom_in.xml
create mode 100644 mvpsdk/src/main/res/anim/activity_start_zoom_out.xml
create mode 100644 mvpsdk/src/main/res/drawable/ic_vector_empty.xml
create mode 100644 mvpsdk/src/main/res/drawable/ic_vector_loading.xml
create mode 100644 mvpsdk/src/main/res/drawable/ic_vector_net_error.xml
create mode 100644 mvpsdk/src/main/res/drawable/indoor_temp.png
create mode 100644 mvpsdk/src/main/res/drawable/item_touch_bg.xml
create mode 100644 mvpsdk/src/main/res/drawable/stackblur_default.png
create mode 100644 mvpsdk/src/main/res/drawable/week_normal.png
create mode 100644 mvpsdk/src/main/res/drawable/week_selector.png
create mode 100644 mvpsdk/src/main/res/drawable/week_status.xml
create mode 100644 mvpsdk/src/main/res/drawable/week_tv_status.xml
create mode 100644 mvpsdk/src/main/res/layout/sub_history_click_view.xml
create mode 100644 mvpsdk/src/main/res/layout/sub_history_tips.xml
create mode 100644 mvpsdk/src/main/res/layout/view_empty.xml
create mode 100644 mvpsdk/src/main/res/layout/view_loading.xml
create mode 100644 mvpsdk/src/main/res/layout/view_network_error.xml
create mode 100644 mvpsdk/src/main/res/mipmap-xhdpi/ic_arrow_back_white.png
create mode 100644 mvpsdk/src/main/res/mipmap-xxhdpi/ic_arrow_back_white.png
create mode 100644 mvpsdk/src/main/res/values-v21/styles.xml
create mode 100644 mvpsdk/src/main/res/values-zh-rCN/strings.xml
create mode 100644 mvpsdk/src/main/res/values/arrays.xml
create mode 100644 mvpsdk/src/main/res/values/attrs.xml
create mode 100644 mvpsdk/src/main/res/values/colors.xml
create mode 100644 mvpsdk/src/main/res/values/dimens.xml
create mode 100644 mvpsdk/src/main/res/values/strings.xml
create mode 100644 mvpsdk/src/main/res/values/styles.xml
create mode 100644 mvpsdk/src/main/res/values/themes.xml
create mode 100644 mvpsdk/src/main/res/values/themes_colors.xml
create mode 100644 mvpsdk/src/test/java/com/share/mvpsdk/ExampleUnitTest.java
create mode 100644 settings.gradle
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..39fb081
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,9 @@
+*.iml
+.gradle
+/local.properties
+/.idea/workspace.xml
+/.idea/libraries
+.DS_Store
+/build
+/captures
+.externalNativeBuild
diff --git a/.idea/gradle.xml b/.idea/gradle.xml
new file mode 100644
index 0000000..1887e74
--- /dev/null
+++ b/.idea/gradle.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 0000000..3963879
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,33 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 0000000..69c30e2
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml
new file mode 100644
index 0000000..7f68460
--- /dev/null
+++ b/.idea/runConfigurations.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..94a25f7
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/.gitignore b/app/.gitignore
new file mode 100644
index 0000000..796b96d
--- /dev/null
+++ b/app/.gitignore
@@ -0,0 +1 @@
+/build
diff --git a/app/build.gradle b/app/build.gradle
new file mode 100644
index 0000000..2786678
--- /dev/null
+++ b/app/build.gradle
@@ -0,0 +1,30 @@
+apply plugin: 'com.android.application'
+
+android {
+ compileSdkVersion 26
+ defaultConfig {
+ applicationId "com.shunzhi.parent"
+ minSdkVersion 16
+ targetSdkVersion 26
+ versionCode 1
+ versionName "1.0"
+ testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
+ }
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+ }
+ }
+}
+
+dependencies {
+ implementation fileTree(include: ['*.jar'], dir: 'libs')
+ implementation 'com.android.support:appcompat-v7:26.1.0'
+ implementation 'com.android.support.constraint:constraint-layout:1.0.2'
+ implementation 'com.android.support:support-v4:26.1.0'
+ testImplementation 'junit:junit:4.12'
+ androidTestImplementation 'com.android.support.test:runner:1.0.1'
+ androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
+ implementation project(':mvpsdk')
+}
diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro
new file mode 100644
index 0000000..f1b4245
--- /dev/null
+++ b/app/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
diff --git a/app/src/androidTest/java/com/shunzhi/parent/ExampleInstrumentedTest.java b/app/src/androidTest/java/com/shunzhi/parent/ExampleInstrumentedTest.java
new file mode 100644
index 0000000..c6f8c6e
--- /dev/null
+++ b/app/src/androidTest/java/com/shunzhi/parent/ExampleInstrumentedTest.java
@@ -0,0 +1,26 @@
+package com.shunzhi.parent;
+
+import android.content.Context;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.junit.Assert.*;
+
+/**
+ * Instrumented test, which will execute on an Android device.
+ *
+ * @see Testing documentation
+ */
+@RunWith(AndroidJUnit4.class)
+public class ExampleInstrumentedTest {
+ @Test
+ public void useAppContext() throws Exception {
+ // Context of the app under test.
+ Context appContext = InstrumentationRegistry.getTargetContext();
+
+ assertEquals("com.shunzhi.parent", appContext.getPackageName());
+ }
+}
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..b2ebf1d
--- /dev/null
+++ b/app/src/main/AndroidManifest.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/com/shunzhi/parent/MyApplication.java b/app/src/main/java/com/shunzhi/parent/MyApplication.java
new file mode 100644
index 0000000..ce05905
--- /dev/null
+++ b/app/src/main/java/com/shunzhi/parent/MyApplication.java
@@ -0,0 +1,17 @@
+package com.shunzhi.parent;
+
+import com.share.mvpsdk.global.GlobalApplication;
+
+/**
+ * Created by ToaHanDong on 2018/3/2.
+ */
+
+public class MyApplication extends GlobalApplication {
+
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+
+ }
+}
diff --git a/app/src/main/java/com/shunzhi/parent/ui/MainActivity.java b/app/src/main/java/com/shunzhi/parent/ui/MainActivity.java
new file mode 100644
index 0000000..8a0fa33
--- /dev/null
+++ b/app/src/main/java/com/shunzhi/parent/ui/MainActivity.java
@@ -0,0 +1,15 @@
+package com.shunzhi.parent.ui;
+
+import android.support.v7.app.AppCompatActivity;
+import android.os.Bundle;
+
+import com.shunzhi.parent.R;
+
+public class MainActivity extends AppCompatActivity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_main);
+ }
+}
diff --git a/app/src/main/java/com/shunzhi/parent/ui/activity/LoginAndRegistActivity.java b/app/src/main/java/com/shunzhi/parent/ui/activity/LoginAndRegistActivity.java
new file mode 100644
index 0000000..3d7a8bb
--- /dev/null
+++ b/app/src/main/java/com/shunzhi/parent/ui/activity/LoginAndRegistActivity.java
@@ -0,0 +1,15 @@
+package com.shunzhi.parent.ui.activity;
+
+import android.support.v7.app.AppCompatActivity;
+import android.os.Bundle;
+
+import com.shunzhi.parent.R;
+
+public class LoginAndRegistActivity extends AppCompatActivity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_regist);
+ }
+}
diff --git a/app/src/main/java/com/shunzhi/parent/ui/activity/StartActivity.java b/app/src/main/java/com/shunzhi/parent/ui/activity/StartActivity.java
new file mode 100644
index 0000000..5c1dc77
--- /dev/null
+++ b/app/src/main/java/com/shunzhi/parent/ui/activity/StartActivity.java
@@ -0,0 +1,15 @@
+package com.shunzhi.parent.ui.activity;
+
+import android.support.v7.app.AppCompatActivity;
+import android.os.Bundle;
+
+import com.shunzhi.parent.R;
+
+public class StartActivity extends AppCompatActivity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_start);
+ }
+}
diff --git a/app/src/main/java/com/shunzhi/parent/ui/fragment/CePingFragment.java b/app/src/main/java/com/shunzhi/parent/ui/fragment/CePingFragment.java
new file mode 100644
index 0000000..9a5617b
--- /dev/null
+++ b/app/src/main/java/com/shunzhi/parent/ui/fragment/CePingFragment.java
@@ -0,0 +1,109 @@
+package com.shunzhi.parent.ui.fragment;
+
+import android.content.Context;
+import android.net.Uri;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.shunzhi.parent.R;
+
+/**
+ * A simple {@link Fragment} subclass.
+ * Activities that contain this fragment must implement the
+ * {@link CePingFragment.OnFragmentInteractionListener} interface
+ * to handle interaction events.
+ * Use the {@link CePingFragment#newInstance} factory method to
+ * create an instance of this fragment.
+ */
+public class CePingFragment extends Fragment {
+ // TODO: Rename parameter arguments, choose names that match
+ // the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
+ private static final String ARG_PARAM1 = "param1";
+ private static final String ARG_PARAM2 = "param2";
+
+ // TODO: Rename and change types of parameters
+ private String mParam1;
+ private String mParam2;
+
+ private OnFragmentInteractionListener mListener;
+
+ public CePingFragment() {
+ // Required empty public constructor
+ }
+
+ /**
+ * Use this factory method to create a new instance of
+ * this fragment using the provided parameters.
+ *
+ * @param param1 Parameter 1.
+ * @param param2 Parameter 2.
+ * @return A new instance of fragment CePingFragment.
+ */
+ // TODO: Rename and change types and number of parameters
+ public static CePingFragment newInstance(String param1, String param2) {
+ CePingFragment fragment = new CePingFragment();
+ Bundle args = new Bundle();
+ args.putString(ARG_PARAM1, param1);
+ args.putString(ARG_PARAM2, param2);
+ fragment.setArguments(args);
+ return fragment;
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ if (getArguments() != null) {
+ mParam1 = getArguments().getString(ARG_PARAM1);
+ mParam2 = getArguments().getString(ARG_PARAM2);
+ }
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ // Inflate the layout for this fragment
+ return inflater.inflate(R.layout.fragment_ce_ping, container, false);
+ }
+
+ // TODO: Rename method, update argument and hook method into UI event
+ public void onButtonPressed(Uri uri) {
+ if (mListener != null) {
+ mListener.onFragmentInteraction(uri);
+ }
+ }
+
+ @Override
+ public void onAttach(Context context) {
+ super.onAttach(context);
+ if (context instanceof OnFragmentInteractionListener) {
+ mListener = (OnFragmentInteractionListener) context;
+ } else {
+ throw new RuntimeException(context.toString()
+ + " must implement OnFragmentInteractionListener");
+ }
+ }
+
+ @Override
+ public void onDetach() {
+ super.onDetach();
+ mListener = null;
+ }
+
+ /**
+ * This interface must be implemented by activities that contain this
+ * fragment to allow an interaction in this fragment to be communicated
+ * to the activity and potentially other fragments contained in that
+ * activity.
+ *
+ * See the Android Training lesson Communicating with Other Fragments for more information.
+ */
+ public interface OnFragmentInteractionListener {
+ // TODO: Update argument type and name
+ void onFragmentInteraction(Uri uri);
+ }
+}
diff --git a/app/src/main/java/com/shunzhi/parent/ui/fragment/ConsultFragment.java b/app/src/main/java/com/shunzhi/parent/ui/fragment/ConsultFragment.java
new file mode 100644
index 0000000..13b0279
--- /dev/null
+++ b/app/src/main/java/com/shunzhi/parent/ui/fragment/ConsultFragment.java
@@ -0,0 +1,109 @@
+package com.shunzhi.parent.ui.fragment;
+
+import android.content.Context;
+import android.net.Uri;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.shunzhi.parent.R;
+
+/**
+ * A simple {@link Fragment} subclass.
+ * Activities that contain this fragment must implement the
+ * {@link ConsultFragment.OnFragmentInteractionListener} interface
+ * to handle interaction events.
+ * Use the {@link ConsultFragment#newInstance} factory method to
+ * create an instance of this fragment.
+ */
+public class ConsultFragment extends Fragment {
+ // TODO: Rename parameter arguments, choose names that match
+ // the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
+ private static final String ARG_PARAM1 = "param1";
+ private static final String ARG_PARAM2 = "param2";
+
+ // TODO: Rename and change types of parameters
+ private String mParam1;
+ private String mParam2;
+
+ private OnFragmentInteractionListener mListener;
+
+ public ConsultFragment() {
+ // Required empty public constructor
+ }
+
+ /**
+ * Use this factory method to create a new instance of
+ * this fragment using the provided parameters.
+ *
+ * @param param1 Parameter 1.
+ * @param param2 Parameter 2.
+ * @return A new instance of fragment ConsultFragment.
+ */
+ // TODO: Rename and change types and number of parameters
+ public static ConsultFragment newInstance(String param1, String param2) {
+ ConsultFragment fragment = new ConsultFragment();
+ Bundle args = new Bundle();
+ args.putString(ARG_PARAM1, param1);
+ args.putString(ARG_PARAM2, param2);
+ fragment.setArguments(args);
+ return fragment;
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ if (getArguments() != null) {
+ mParam1 = getArguments().getString(ARG_PARAM1);
+ mParam2 = getArguments().getString(ARG_PARAM2);
+ }
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ // Inflate the layout for this fragment
+ return inflater.inflate(R.layout.fragment_zi_xun, container, false);
+ }
+
+ // TODO: Rename method, update argument and hook method into UI event
+ public void onButtonPressed(Uri uri) {
+ if (mListener != null) {
+ mListener.onFragmentInteraction(uri);
+ }
+ }
+
+ @Override
+ public void onAttach(Context context) {
+ super.onAttach(context);
+ if (context instanceof OnFragmentInteractionListener) {
+ mListener = (OnFragmentInteractionListener) context;
+ } else {
+ throw new RuntimeException(context.toString()
+ + " must implement OnFragmentInteractionListener");
+ }
+ }
+
+ @Override
+ public void onDetach() {
+ super.onDetach();
+ mListener = null;
+ }
+
+ /**
+ * This interface must be implemented by activities that contain this
+ * fragment to allow an interaction in this fragment to be communicated
+ * to the activity and potentially other fragments contained in that
+ * activity.
+ *
+ * See the Android Training lesson Communicating with Other Fragments for more information.
+ */
+ public interface OnFragmentInteractionListener {
+ // TODO: Update argument type and name
+ void onFragmentInteraction(Uri uri);
+ }
+}
diff --git a/app/src/main/java/com/shunzhi/parent/ui/fragment/MineFragment.java b/app/src/main/java/com/shunzhi/parent/ui/fragment/MineFragment.java
new file mode 100644
index 0000000..a5b12cd
--- /dev/null
+++ b/app/src/main/java/com/shunzhi/parent/ui/fragment/MineFragment.java
@@ -0,0 +1,109 @@
+package com.shunzhi.parent.ui.fragment;
+
+import android.content.Context;
+import android.net.Uri;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.shunzhi.parent.R;
+
+/**
+ * A simple {@link Fragment} subclass.
+ * Activities that contain this fragment must implement the
+ * {@link MineFragment.OnFragmentInteractionListener} interface
+ * to handle interaction events.
+ * Use the {@link MineFragment#newInstance} factory method to
+ * create an instance of this fragment.
+ */
+public class MineFragment extends Fragment {
+ // TODO: Rename parameter arguments, choose names that match
+ // the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
+ private static final String ARG_PARAM1 = "param1";
+ private static final String ARG_PARAM2 = "param2";
+
+ // TODO: Rename and change types of parameters
+ private String mParam1;
+ private String mParam2;
+
+ private OnFragmentInteractionListener mListener;
+
+ public MineFragment() {
+ // Required empty public constructor
+ }
+
+ /**
+ * Use this factory method to create a new instance of
+ * this fragment using the provided parameters.
+ *
+ * @param param1 Parameter 1.
+ * @param param2 Parameter 2.
+ * @return A new instance of fragment MineFragment.
+ */
+ // TODO: Rename and change types and number of parameters
+ public static MineFragment newInstance(String param1, String param2) {
+ MineFragment fragment = new MineFragment();
+ Bundle args = new Bundle();
+ args.putString(ARG_PARAM1, param1);
+ args.putString(ARG_PARAM2, param2);
+ fragment.setArguments(args);
+ return fragment;
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ if (getArguments() != null) {
+ mParam1 = getArguments().getString(ARG_PARAM1);
+ mParam2 = getArguments().getString(ARG_PARAM2);
+ }
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ // Inflate the layout for this fragment
+ return inflater.inflate(R.layout.fragment_mine, container, false);
+ }
+
+ // TODO: Rename method, update argument and hook method into UI event
+ public void onButtonPressed(Uri uri) {
+ if (mListener != null) {
+ mListener.onFragmentInteraction(uri);
+ }
+ }
+
+ @Override
+ public void onAttach(Context context) {
+ super.onAttach(context);
+ if (context instanceof OnFragmentInteractionListener) {
+ mListener = (OnFragmentInteractionListener) context;
+ } else {
+ throw new RuntimeException(context.toString()
+ + " must implement OnFragmentInteractionListener");
+ }
+ }
+
+ @Override
+ public void onDetach() {
+ super.onDetach();
+ mListener = null;
+ }
+
+ /**
+ * This interface must be implemented by activities that contain this
+ * fragment to allow an interaction in this fragment to be communicated
+ * to the activity and potentially other fragments contained in that
+ * activity.
+ *
+ * See the Android Training lesson Communicating with Other Fragments for more information.
+ */
+ public interface OnFragmentInteractionListener {
+ // TODO: Update argument type and name
+ void onFragmentInteraction(Uri uri);
+ }
+}
diff --git a/app/src/main/java/com/shunzhi/parent/ui/fragment/ReportFragment.java b/app/src/main/java/com/shunzhi/parent/ui/fragment/ReportFragment.java
new file mode 100644
index 0000000..f49edca
--- /dev/null
+++ b/app/src/main/java/com/shunzhi/parent/ui/fragment/ReportFragment.java
@@ -0,0 +1,109 @@
+package com.shunzhi.parent.ui.fragment;
+
+import android.content.Context;
+import android.net.Uri;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.shunzhi.parent.R;
+
+/**
+ * A simple {@link Fragment} subclass.
+ * Activities that contain this fragment must implement the
+ * {@link ReportFragment.OnFragmentInteractionListener} interface
+ * to handle interaction events.
+ * Use the {@link ReportFragment#newInstance} factory method to
+ * create an instance of this fragment.
+ */
+public class ReportFragment extends Fragment {
+ // TODO: Rename parameter arguments, choose names that match
+ // the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
+ private static final String ARG_PARAM1 = "param1";
+ private static final String ARG_PARAM2 = "param2";
+
+ // TODO: Rename and change types of parameters
+ private String mParam1;
+ private String mParam2;
+
+ private OnFragmentInteractionListener mListener;
+
+ public ReportFragment() {
+ // Required empty public constructor
+ }
+
+ /**
+ * Use this factory method to create a new instance of
+ * this fragment using the provided parameters.
+ *
+ * @param param1 Parameter 1.
+ * @param param2 Parameter 2.
+ * @return A new instance of fragment ReportFragment.
+ */
+ // TODO: Rename and change types and number of parameters
+ public static ReportFragment newInstance(String param1, String param2) {
+ ReportFragment fragment = new ReportFragment();
+ Bundle args = new Bundle();
+ args.putString(ARG_PARAM1, param1);
+ args.putString(ARG_PARAM2, param2);
+ fragment.setArguments(args);
+ return fragment;
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ if (getArguments() != null) {
+ mParam1 = getArguments().getString(ARG_PARAM1);
+ mParam2 = getArguments().getString(ARG_PARAM2);
+ }
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ // Inflate the layout for this fragment
+ return inflater.inflate(R.layout.fragment_report, container, false);
+ }
+
+ // TODO: Rename method, update argument and hook method into UI event
+ public void onButtonPressed(Uri uri) {
+ if (mListener != null) {
+ mListener.onFragmentInteraction(uri);
+ }
+ }
+
+ @Override
+ public void onAttach(Context context) {
+ super.onAttach(context);
+ if (context instanceof OnFragmentInteractionListener) {
+ mListener = (OnFragmentInteractionListener) context;
+ } else {
+ throw new RuntimeException(context.toString()
+ + " must implement OnFragmentInteractionListener");
+ }
+ }
+
+ @Override
+ public void onDetach() {
+ super.onDetach();
+ mListener = null;
+ }
+
+ /**
+ * This interface must be implemented by activities that contain this
+ * fragment to allow an interaction in this fragment to be communicated
+ * to the activity and potentially other fragments contained in that
+ * activity.
+ *
+ * See the Android Training lesson Communicating with Other Fragments for more information.
+ */
+ public interface OnFragmentInteractionListener {
+ // TODO: Update argument type and name
+ void onFragmentInteraction(Uri uri);
+ }
+}
diff --git a/app/src/main/java/com/shunzhi/parent/ui/fragment/loginandregistfragment/LoginAndRegistFragment.java b/app/src/main/java/com/shunzhi/parent/ui/fragment/loginandregistfragment/LoginAndRegistFragment.java
new file mode 100644
index 0000000..bfa05d5
--- /dev/null
+++ b/app/src/main/java/com/shunzhi/parent/ui/fragment/loginandregistfragment/LoginAndRegistFragment.java
@@ -0,0 +1,109 @@
+package com.shunzhi.parent.ui.fragment.loginandregistfragment;
+
+import android.content.Context;
+import android.net.Uri;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.shunzhi.parent.R;
+
+/**
+ * A simple {@link Fragment} subclass.
+ * Activities that contain this fragment must implement the
+ * {@link LoginAndRegistFragment.OnFragmentInteractionListener} interface
+ * to handle interaction events.
+ * Use the {@link LoginAndRegistFragment#newInstance} factory method to
+ * create an instance of this fragment.
+ */
+public class LoginAndRegistFragment extends Fragment {
+ // TODO: Rename parameter arguments, choose names that match
+ // the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
+ private static final String ARG_PARAM1 = "param1";
+ private static final String ARG_PARAM2 = "param2";
+
+ // TODO: Rename and change types of parameters
+ private String mParam1;
+ private String mParam2;
+
+ private OnFragmentInteractionListener mListener;
+
+ public LoginAndRegistFragment() {
+ // Required empty public constructor
+ }
+
+ /**
+ * Use this factory method to create a new instance of
+ * this fragment using the provided parameters.
+ *
+ * @param param1 Parameter 1.
+ * @param param2 Parameter 2.
+ * @return A new instance of fragment LoginAndRegistFragment.
+ */
+ // TODO: Rename and change types and number of parameters
+ public static LoginAndRegistFragment newInstance(String param1, String param2) {
+ LoginAndRegistFragment fragment = new LoginAndRegistFragment();
+ Bundle args = new Bundle();
+ args.putString(ARG_PARAM1, param1);
+ args.putString(ARG_PARAM2, param2);
+ fragment.setArguments(args);
+ return fragment;
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ if (getArguments() != null) {
+ mParam1 = getArguments().getString(ARG_PARAM1);
+ mParam2 = getArguments().getString(ARG_PARAM2);
+ }
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ // Inflate the layout for this fragment
+ return inflater.inflate(R.layout.fragment_login_and_regist, container, false);
+ }
+
+ // TODO: Rename method, update argument and hook method into UI event
+ public void onButtonPressed(Uri uri) {
+ if (mListener != null) {
+ mListener.onFragmentInteraction(uri);
+ }
+ }
+
+ @Override
+ public void onAttach(Context context) {
+ super.onAttach(context);
+ if (context instanceof OnFragmentInteractionListener) {
+ mListener = (OnFragmentInteractionListener) context;
+ } else {
+ throw new RuntimeException(context.toString()
+ + " must implement OnFragmentInteractionListener");
+ }
+ }
+
+ @Override
+ public void onDetach() {
+ super.onDetach();
+ mListener = null;
+ }
+
+ /**
+ * This interface must be implemented by activities that contain this
+ * fragment to allow an interaction in this fragment to be communicated
+ * to the activity and potentially other fragments contained in that
+ * activity.
+ *
+ * See the Android Training lesson Communicating with Other Fragments for more information.
+ */
+ public interface OnFragmentInteractionListener {
+ // TODO: Update argument type and name
+ void onFragmentInteraction(Uri uri);
+ }
+}
diff --git a/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
new file mode 100644
index 0000000..c7bd21d
--- /dev/null
+++ b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml
new file mode 100644
index 0000000..d5fccc5
--- /dev/null
+++ b/app/src/main/res/drawable/ic_launcher_background.xml
@@ -0,0 +1,170 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
new file mode 100644
index 0000000..d252704
--- /dev/null
+++ b/app/src/main/res/layout/activity_main.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/activity_regist.xml b/app/src/main/res/layout/activity_regist.xml
new file mode 100644
index 0000000..beac382
--- /dev/null
+++ b/app/src/main/res/layout/activity_regist.xml
@@ -0,0 +1,9 @@
+
+
+
+
diff --git a/app/src/main/res/layout/activity_start.xml b/app/src/main/res/layout/activity_start.xml
new file mode 100644
index 0000000..0ec5e68
--- /dev/null
+++ b/app/src/main/res/layout/activity_start.xml
@@ -0,0 +1,9 @@
+
+
+
+
diff --git a/app/src/main/res/layout/fragment_ce_ping.xml b/app/src/main/res/layout/fragment_ce_ping.xml
new file mode 100644
index 0000000..67700f1
--- /dev/null
+++ b/app/src/main/res/layout/fragment_ce_ping.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/fragment_login_and_regist.xml b/app/src/main/res/layout/fragment_login_and_regist.xml
new file mode 100644
index 0000000..9eb78e1
--- /dev/null
+++ b/app/src/main/res/layout/fragment_login_and_regist.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/fragment_mine.xml b/app/src/main/res/layout/fragment_mine.xml
new file mode 100644
index 0000000..253fc19
--- /dev/null
+++ b/app/src/main/res/layout/fragment_mine.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/fragment_report.xml b/app/src/main/res/layout/fragment_report.xml
new file mode 100644
index 0000000..f97eea6
--- /dev/null
+++ b/app/src/main/res/layout/fragment_report.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/fragment_zi_xun.xml b/app/src/main/res/layout/fragment_zi_xun.xml
new file mode 100644
index 0000000..507f4d9
--- /dev/null
+++ b/app/src/main/res/layout/fragment_zi_xun.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
new file mode 100644
index 0000000..eca70cf
--- /dev/null
+++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
new file mode 100644
index 0000000..eca70cf
--- /dev/null
+++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.png b/app/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 0000000..a2f5908
Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
new file mode 100644
index 0000000..1b52399
Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher_round.png differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.png b/app/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 0000000..ff10afd
Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
new file mode 100644
index 0000000..115a4c7
Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher_round.png differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/app/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..dcd3cd8
Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..459ca60
Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..8ca12fe
Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..8e19b41
Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 0000000..b824ebd
Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..4c19a13
Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png differ
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
new file mode 100644
index 0000000..3ab3e9c
--- /dev/null
+++ b/app/src/main/res/values/colors.xml
@@ -0,0 +1,6 @@
+
+
+ #3F51B5
+ #303F9F
+ #FF4081
+
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
new file mode 100644
index 0000000..b577c32
--- /dev/null
+++ b/app/src/main/res/values/strings.xml
@@ -0,0 +1,6 @@
+
+ parent
+
+
+ Hello blank fragment
+
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
new file mode 100644
index 0000000..5885930
--- /dev/null
+++ b/app/src/main/res/values/styles.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
diff --git a/app/src/test/java/com/shunzhi/parent/ExampleUnitTest.java b/app/src/test/java/com/shunzhi/parent/ExampleUnitTest.java
new file mode 100644
index 0000000..1fd5dc3
--- /dev/null
+++ b/app/src/test/java/com/shunzhi/parent/ExampleUnitTest.java
@@ -0,0 +1,17 @@
+package com.shunzhi.parent;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * @see Testing documentation
+ */
+public class ExampleUnitTest {
+ @Test
+ public void addition_isCorrect() throws Exception {
+ assertEquals(4, 2 + 2);
+ }
+}
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
new file mode 100644
index 0000000..43d23d9
--- /dev/null
+++ b/build.gradle
@@ -0,0 +1,66 @@
+// Top-level build file where you can add configuration options common to all sub-projects/modules.
+
+buildscript {
+
+ repositories {
+ google()
+ jcenter()
+ }
+ dependencies {
+ classpath 'com.android.tools.build:gradle:3.0.1'
+
+
+ // NOTE: Do not place your application dependencies here; they belong
+ // in the individual module build.gradle files
+ }
+}
+
+allprojects {
+ repositories {
+ google()
+ jcenter()
+ }
+}
+
+task clean(type: Delete) {
+ delete rootProject.buildDir
+}
+
+ext {
+ // Sdk and tools
+ minSdkVersion = 16
+ targetSdkVersion = 26
+ compileSdkVersion = 26
+ buildToolsVersion = '26.0.2'
+
+ // App dependencies
+ supportLibraryVersion = '26.1.0'
+ guavaVersion = '18.0'
+ junitVersion = '4.12'
+ mockitoVersion = '1.10.19'
+ powerMockito = '1.6.2'
+ hamcrestVersion = '1.3'
+ runnerVersion = '0.4.1'
+ rulesVersion = '0.4.1'
+ espressoVersion = '2.2.1'
+ retrofitVersion = '2.2.0'
+ okhttploggingVersion = '3.4.1'
+ okhttpVersion = '3.4.1'
+ rxjavaVersion = '2.0.1'
+ rxandroidVersion = '2.0.1'
+ rxbindingVersion = '2.0.0'
+ rxPerssionsVersion = '0.9.4@aar'
+ glideVersion = '3.6.1'
+ glideokhttpVersion = '1.3.1'
+ photoviewVersion = '1.2.4'
+ butterknifeVersion = '8.4.0'
+ fragmentationVersion = '1.1.6'
+ loggerVersion = '1.15'
+ circleImageviewVersion = '2.1.0'
+ BaseRecyclerViewAdapterHelperVersion = '2.9.34'
+ SwtichButtonVersion = '1.4.6'
+ PhotoViewVersion = '1.4.1'
+ BottomSheetVersion = '1.3.0@aar'
+ glideTransformationVersion = '2.0.1'
+}
+
diff --git a/gradle.properties b/gradle.properties
new file mode 100644
index 0000000..aac7c9b
--- /dev/null
+++ b/gradle.properties
@@ -0,0 +1,17 @@
+# Project-wide Gradle settings.
+
+# IDE (e.g. Android Studio) users:
+# Gradle settings configured through the IDE *will override*
+# any settings specified in this file.
+
+# For more details on how to configure your build environment visit
+# http://www.gradle.org/docs/current/userguide/build_environment.html
+
+# Specifies the JVM arguments used for the daemon process.
+# The setting is particularly useful for tweaking memory settings.
+org.gradle.jvmargs=-Xmx1536m
+
+# When configured, Gradle will run in incubating parallel mode.
+# This option should only be used with decoupled projects. More details, visit
+# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
+# org.gradle.parallel=true
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..13372ae
Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..39d0fb2
--- /dev/null
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Tue Feb 27 14:00:51 CST 2018
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip
diff --git a/gradlew b/gradlew
new file mode 100644
index 0000000..9d82f78
--- /dev/null
+++ b/gradlew
@@ -0,0 +1,160 @@
+#!/usr/bin/env bash
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn ( ) {
+ echo "$*"
+}
+
+die ( ) {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+esac
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=$((i+1))
+ done
+ case $i in
+ (0) set -- ;;
+ (1) set -- "$args0" ;;
+ (2) set -- "$args0" "$args1" ;;
+ (3) set -- "$args0" "$args1" "$args2" ;;
+ (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
+function splitJvmOpts() {
+ JVM_OPTS=("$@")
+}
+eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
+JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
+
+exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
diff --git a/gradlew.bat b/gradlew.bat
new file mode 100644
index 0000000..8a0b282
--- /dev/null
+++ b/gradlew.bat
@@ -0,0 +1,90 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windowz variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+if "%@eval[2+2]" == "4" goto 4NT_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+goto execute
+
+:4NT_args
+@rem Get arguments from the 4NT Shell from JP Software
+set CMD_LINE_ARGS=%$
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/mvpsdk/.gitignore b/mvpsdk/.gitignore
new file mode 100644
index 0000000..796b96d
--- /dev/null
+++ b/mvpsdk/.gitignore
@@ -0,0 +1 @@
+/build
diff --git a/mvpsdk/build.gradle b/mvpsdk/build.gradle
new file mode 100644
index 0000000..30a25ba
--- /dev/null
+++ b/mvpsdk/build.gradle
@@ -0,0 +1,102 @@
+apply plugin: 'com.android.library'
+
+android {
+ compileSdkVersion rootProject.ext.compileSdkVersion
+ buildToolsVersion rootProject.ext.buildToolsVersion
+
+
+ defaultConfig {
+ minSdkVersion rootProject.ext.minSdkVersion
+ targetSdkVersion rootProject.ext.targetSdkVersion
+ versionCode 1
+ versionName "1.0"
+
+ testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
+
+ }
+
+ buildTypes {
+ def BOOLEAN = "boolean"
+ def TRUE = "true"
+ def FALSE = "false"
+ def IS_SHOW_LOG = "IS_SHOW_LOG"
+
+ release {
+ minifyEnabled false
+ buildConfigField BOOLEAN, IS_SHOW_LOG, FALSE
+ proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+ }
+ }
+ publishNonDefault true
+}
+//repositories {
+// flatDir {
+// dirs 'libs' //this way we can find the .aar file in libs folder
+// }
+// google()
+//}
+dependencies {
+ implementation fileTree(dir: 'libs', include: ['*.jar'])
+
+ implementation 'com.android.support:appcompat-v7:26.1.0'
+ testImplementation 'junit:junit:4.12'
+ androidTestImplementation 'com.android.support.test:runner:1.0.1'
+ androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
+
+ // Android support
+ compile "com.android.support:appcompat-v7:$rootProject.supportLibraryVersion"
+ compile "com.android.support:cardview-v7:$rootProject.supportLibraryVersion"
+ compile "com.android.support:design:$rootProject.supportLibraryVersion"
+ compile "com.android.support:recyclerview-v7:$rootProject.supportLibraryVersion"
+
+ // Retrofit
+ compile "com.squareup.retrofit2:retrofit:$rootProject.retrofitVersion"
+ compile "com.squareup.retrofit2:converter-gson:$rootProject.retrofitVersion"
+ compile "com.squareup.retrofit2:adapter-rxjava2:$rootProject.retrofitVersion"
+ compile "com.squareup.okhttp3:logging-interceptor:$rootProject.okhttploggingVersion"
+ compile "com.squareup.okhttp3:okhttp:$rootProject.okhttpVersion"
+
+ // RxJava
+ compile "io.reactivex.rxjava2:rxjava:$rootProject.rxjavaVersion"
+ compile "io.reactivex.rxjava2:rxandroid:$rootProject.rxandroidVersion"
+ compile "com.jakewharton.rxbinding2:rxbinding:$rootProject.rxbindingVersion"
+
+ // Glide
+ compile "com.github.bumptech.glide:glide:$rootProject.glideVersion"
+ compile "com.github.bumptech.glide:okhttp-integration:$rootProject.glideokhttpVersion"
+ compile "jp.wasabeef:glide-transformations:$rootProject.glideTransformationVersion"
+
+ //Butterknife
+ compile "com.jakewharton:butterknife:$rootProject.butterknifeVersion"
+ annotationProcessor 'com.jakewharton:butterknife-compiler:8.4.0'
+
+ //fragmentation
+ compile "me.yokeyword:fragmentation:$rootProject.fragmentationVersion"
+
+ //Logger
+ compile "com.orhanobut:logger:$rootProject.loggerVersion"
+
+ //circle imageview
+ compile "de.hdodenhof:circleimageview:$rootProject.circleImageviewVersion"
+
+ //BaseRecyclerViewAdapterHelper
+ compile "com.github.CymChad:BaseRecyclerViewAdapterHelper:$rootProject.BaseRecyclerViewAdapterHelperVersion"
+
+ //SwitchButton
+ compile "com.kyleduo.switchbutton:library:$rootProject.SwtichButtonVersion"
+
+ //PhotoView
+ compile "com.bm.photoview:library:$rootProject.PhotoViewVersion"
+
+ compile "com.cocosw:bottomsheet:$rootProject.BottomSheetVersion"
+
+ //permissions
+ compile "com.tbruyelle.rxpermissions2:rxpermissions:$rootProject.rxPerssionsVersion"
+
+ //timber
+ compile 'com.jakewharton.timber:timber:4.5.1'
+
+ //jiaozivideoplayer
+ compile 'cn.jzvd:jiaozivideoplayer:6.2.7'
+// compile(name: 'jiaozivideoplayer-6.2.3', ext: 'aar')
+}
diff --git a/mvpsdk/proguard-rules.pro b/mvpsdk/proguard-rules.pro
new file mode 100644
index 0000000..f1b4245
--- /dev/null
+++ b/mvpsdk/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
diff --git a/mvpsdk/src/androidTest/java/com/share/mvpsdk/ExampleInstrumentedTest.java b/mvpsdk/src/androidTest/java/com/share/mvpsdk/ExampleInstrumentedTest.java
new file mode 100644
index 0000000..efd1849
--- /dev/null
+++ b/mvpsdk/src/androidTest/java/com/share/mvpsdk/ExampleInstrumentedTest.java
@@ -0,0 +1,26 @@
+package com.share.mvpsdk;
+
+import android.content.Context;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.junit.Assert.*;
+
+/**
+ * Instrumented test, which will execute on an Android device.
+ *
+ * @see Testing documentation
+ */
+@RunWith(AndroidJUnit4.class)
+public class ExampleInstrumentedTest {
+ @Test
+ public void useAppContext() throws Exception {
+ // Context of the app under test.
+ Context appContext = InstrumentationRegistry.getTargetContext();
+
+ assertEquals("com.share.mvpsdk.test", appContext.getPackageName());
+ }
+}
diff --git a/mvpsdk/src/main/AndroidManifest.xml b/mvpsdk/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..4cf5ec6
--- /dev/null
+++ b/mvpsdk/src/main/AndroidManifest.xml
@@ -0,0 +1,2 @@
+
diff --git a/mvpsdk/src/main/java/com/share/mvpsdk/AppManager.java b/mvpsdk/src/main/java/com/share/mvpsdk/AppManager.java
new file mode 100644
index 0000000..34073cb
--- /dev/null
+++ b/mvpsdk/src/main/java/com/share/mvpsdk/AppManager.java
@@ -0,0 +1,111 @@
+package com.share.mvpsdk;
+
+import android.annotation.SuppressLint;
+import android.app.Activity;
+import android.app.ActivityManager;
+import android.content.Context;
+
+import java.util.Stack;
+
+/**
+ * Created by Horrarndoo on 2017/4/5.
+ *
+ * AppManager 管理Activity栈
+ */
+
+public class AppManager {
+ private static Stack activityStack;
+ private static AppManager instance;
+
+ private AppManager() {
+ }
+
+ /**
+ * 单一实例
+ */
+ public static AppManager getAppManager() {
+ if (instance == null) {
+ instance = new AppManager();
+ }
+ return instance;
+ }
+
+ /**
+ * 添加Activity到堆栈
+ */
+ public void addActivity(Activity activity) {
+ if (activityStack == null) {
+ activityStack = new Stack();
+ }
+ activityStack.add(activity);
+ }
+
+ /**
+ * 获取当前Activity(堆栈中最后一个压入的)
+ */
+ public Activity currentActivity() {
+ Activity activity = activityStack.lastElement();
+ return activity;
+ }
+
+ /**
+ * 结束当前Activity(堆栈中最后一个压入的)
+ */
+ public void finishActivity() {
+ Activity activity = activityStack.lastElement();
+ finishActivity(activity);
+ }
+
+ /**
+ * 结束指定的Activity
+ */
+ public void finishActivity(Activity activity) {
+ if (activity != null) {
+ activityStack.remove(activity);
+ activity.finish();
+ activity = null;
+ }
+ }
+
+ /**
+ * 结束指定类名的Activity
+ */
+ public void finishActivity(Class> cls) {
+ for (Activity activity : activityStack) {
+ if (activity.getClass().equals(cls)) {
+ finishActivity(activity);
+ }
+ }
+ }
+
+ /**
+ * 结束所有Activity
+ */
+ public void finishAllActivity() {
+ for (int i = 0, size = activityStack.size(); i < size; i++) {
+ if (null != activityStack.get(i)) {
+ activityStack.get(i).finish();
+ }
+ }
+ activityStack.clear();
+ }
+
+ /**
+ * 退出应用程序
+ */
+ @SuppressLint("MissingPermission")
+ public void AppExit(Context context) {
+ try {
+ finishAllActivity();
+ ActivityManager activityMgr =
+ (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
+ activityMgr.killBackgroundProcesses(context.getPackageName());
+ System.exit(0);
+ } catch (Exception e) {
+ }
+ }
+
+ public boolean isAppExit() {
+ return activityStack == null || activityStack.isEmpty();
+ }
+}
diff --git a/mvpsdk/src/main/java/com/share/mvpsdk/RxManager.java b/mvpsdk/src/main/java/com/share/mvpsdk/RxManager.java
new file mode 100644
index 0000000..5c910ca
--- /dev/null
+++ b/mvpsdk/src/main/java/com/share/mvpsdk/RxManager.java
@@ -0,0 +1,23 @@
+package com.share.mvpsdk;
+
+
+import io.reactivex.disposables.CompositeDisposable;
+import io.reactivex.disposables.Disposable;
+
+/**
+ * Created by Horrarndoo on 2017/9/12.
+ *
+ * 用于管理Rxjava 注册订阅和取消订阅
+ */
+
+public class RxManager {
+ private CompositeDisposable mCompositeDisposable = new CompositeDisposable();// 管理订阅者者
+
+ public void register(Disposable d) {
+ mCompositeDisposable.add(d);
+ }
+
+ public void unSubscribe() {
+ mCompositeDisposable.dispose();// 取消订阅
+ }
+}
\ No newline at end of file
diff --git a/mvpsdk/src/main/java/com/share/mvpsdk/adapter/FragmentAdapter.java b/mvpsdk/src/main/java/com/share/mvpsdk/adapter/FragmentAdapter.java
new file mode 100644
index 0000000..807bbc5
--- /dev/null
+++ b/mvpsdk/src/main/java/com/share/mvpsdk/adapter/FragmentAdapter.java
@@ -0,0 +1,42 @@
+package com.share.mvpsdk.adapter;
+
+
+import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentManager;
+import android.support.v4.app.FragmentStatePagerAdapter;
+import android.support.v4.view.PagerAdapter;
+import android.view.ViewGroup;
+
+import java.util.List;
+
+/**
+ * Created by Horrarndoo on 2017/9/7.
+ *
+ */
+public class FragmentAdapter extends FragmentStatePagerAdapter {
+ private List fragments;
+
+ public FragmentAdapter(FragmentManager fm, List fragments) {
+ super(fm);
+ this.fragments = fragments;
+ }
+
+ @Override
+ public Fragment getItem(int position) {
+ return fragments.get(position);
+ }
+
+ @Override
+ public int getCount() {
+ return fragments == null ? 0 : fragments.size();
+ }
+
+ public int getItemPosition(Object object) {
+ return PagerAdapter.POSITION_NONE;
+ }
+
+ @Override
+ public void destroyItem(ViewGroup container, int position, Object object) {
+ // super.destroyItem(container, position, object);
+ }
+}
\ No newline at end of file
diff --git a/mvpsdk/src/main/java/com/share/mvpsdk/anim/AnimManager.java b/mvpsdk/src/main/java/com/share/mvpsdk/anim/AnimManager.java
new file mode 100644
index 0000000..6fc18a1
--- /dev/null
+++ b/mvpsdk/src/main/java/com/share/mvpsdk/anim/AnimManager.java
@@ -0,0 +1,75 @@
+package com.share.mvpsdk.anim;
+
+import android.content.Context;
+import android.os.Build;
+import android.support.annotation.NonNull;
+import android.view.View;
+import android.view.animation.AnimationUtils;
+
+/**
+ * Created by Horrarndoo on 2017/9/11.
+ *
+ */
+
+public class AnimManager {
+ /**
+ * Alpha and scaleX 动画
+ * Alpha 0->1
+ * ScaleX 0.8->1
+ *
+ * @param context context
+ * @param view view
+ * @param startDelay 动画开始前延时(ms)
+ * @param duration 动画持续时间(ms)
+ */
+ public static void animAlphaAndScaleX(Context context, @NonNull View view, int startDelay, int
+ duration) {
+ view.setAlpha(0f);
+ view.setScaleX(0.8f);
+
+ if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ view.animate()
+ .alpha(1f)
+ .scaleX(1f)
+ .setStartDelay(startDelay)
+ .setDuration(duration)
+ .setInterpolator(AnimUtils.getFastOutSlowInInterpolator(context))
+ .start();
+ }else{
+ view.animate()
+ .alpha(1f)
+ .scaleX(1f)
+ .setStartDelay(startDelay)
+ .setDuration(duration)
+ .setInterpolator(AnimationUtils.loadInterpolator(context, android.R.interpolator.linear))
+ .start();
+ }
+ }
+
+ /**
+ * Alpha and scale X Y 动画
+ * Alpha 0->1
+ * ScaleX 0->1
+ * ScaleY 0->1
+ *
+ * @param context context
+ * @param view view
+ * @param startDelay 动画开始前延时(ms)
+ * @param duration 动画持续时间(ms)
+ */
+ public static void animAlphaAndScale(Context context, @NonNull View view, int startDelay, int
+ duration) {
+ view.setAlpha(0f);
+ view.setScaleX(0f);
+ view.setScaleY(0f);
+
+ view.animate()
+ .alpha(1f)
+ .scaleX(1f)
+ .scaleY(1f)
+ .setStartDelay(startDelay)
+ .setDuration(duration)
+ .setInterpolator(AnimationUtils.loadInterpolator(context,
+ android.R.interpolator.overshoot)).start();
+ }
+}
diff --git a/mvpsdk/src/main/java/com/share/mvpsdk/anim/AnimUtils.java b/mvpsdk/src/main/java/com/share/mvpsdk/anim/AnimUtils.java
new file mode 100644
index 0000000..e018177
--- /dev/null
+++ b/mvpsdk/src/main/java/com/share/mvpsdk/anim/AnimUtils.java
@@ -0,0 +1,330 @@
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.share.mvpsdk.anim;
+
+import android.animation.Animator;
+import android.animation.TimeInterpolator;
+import android.content.Context;
+import android.os.Build;
+import android.support.annotation.RequiresApi;
+import android.transition.Transition;
+import android.util.ArrayMap;
+import android.util.Property;
+import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
+
+import java.util.ArrayList;
+
+/**
+ * Utility methods for working with animations.
+ */
+public class AnimUtils {
+
+ private AnimUtils() { }
+
+ private static Interpolator fastOutSlowIn;
+ private static Interpolator fastOutLinearIn;
+ private static Interpolator linearOutSlowIn;
+
+ public static Interpolator getFastOutSlowInInterpolator(Context context) {
+ if (fastOutSlowIn == null) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ fastOutSlowIn = AnimationUtils.loadInterpolator(context,
+ android.R.interpolator.fast_out_slow_in);
+ }
+ }
+ return fastOutSlowIn;
+ }
+
+ public static Interpolator getFastOutLinearInInterpolator(Context context) {
+ if (fastOutLinearIn == null) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ fastOutLinearIn = AnimationUtils.loadInterpolator(context,
+ android.R.interpolator.fast_out_linear_in);
+ }
+ }
+ return fastOutLinearIn;
+ }
+
+ public static Interpolator getLinearOutSlowInInterpolator(Context context) {
+ if (linearOutSlowIn == null) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ linearOutSlowIn = AnimationUtils.loadInterpolator(context,
+ android.R.interpolator.linear_out_slow_in);
+ }
+ }
+ return linearOutSlowIn;
+ }
+
+ /**
+ * Linear interpolate between a and b with parameter t.
+ */
+ public static float lerp(float a, float b, float t) {
+ return a + (b - a) * t;
+ }
+
+
+ /**
+ * An implementation of {@link Property} to be used specifically with fields of
+ * type
+ * float
. This type-specific subclass enables performance benefit by allowing
+ * calls to a {@link #set(Object, Float) set()} function that takes the primitive
+ * float
type and avoids autoboxing and other overhead associated with the
+ * Float
class.
+ *
+ * @param The class on which the Property is declared.
+ **/
+ public static abstract class FloatProperty extends Property {
+ public FloatProperty(String name) {
+ super(Float.class, name);
+ }
+
+ /**
+ * A type-specific override of the {@link #set(Object, Float)} that is faster when dealing
+ * with fields of type float
.
+ */
+ public abstract void setValue(T object, float value);
+
+ @Override
+ final public void set(T object, Float value) {
+ setValue(object, value);
+ }
+ }
+
+ /**
+ * An implementation of {@link Property} to be used specifically with fields of
+ * type
+ * int
. This type-specific subclass enables performance benefit by allowing
+ * calls to a {@link #set(Object, Integer) set()} function that takes the primitive
+ * int
type and avoids autoboxing and other overhead associated with the
+ * Integer
class.
+ *
+ * @param The class on which the Property is declared.
+ */
+ public static abstract class IntProperty extends Property {
+
+ public IntProperty(String name) {
+ super(Integer.class, name);
+ }
+
+ /**
+ * A type-specific override of the {@link #set(Object, Integer)} that is faster when dealing
+ * with fields of type int
.
+ */
+ public abstract void setValue(T object, int value);
+
+ @Override
+ final public void set(T object, Integer value) {
+ setValue(object, value.intValue());
+ }
+
+ }
+
+ /**
+ * https://halfthought.wordpress.com/2014/11/07/reveal-transition/
+ *
+ * Interrupting Activity transitions can yield an OperationNotSupportedException when the
+ * transition tries to pause the animator. Yikes! We can fix this by wrapping the Animator:
+ */
+ @RequiresApi(api = Build.VERSION_CODES.KITKAT)
+ public static class NoPauseAnimator extends Animator {
+ private final Animator mAnimator;
+ private final ArrayMap mListeners =
+ new ArrayMap();
+
+ public NoPauseAnimator(Animator animator) {
+ mAnimator = animator;
+ }
+
+ @RequiresApi(api = Build.VERSION_CODES.KITKAT)
+ @Override
+ public void addListener(AnimatorListener listener) {
+ AnimatorListener wrapper = new AnimatorListenerWrapper(this, listener);
+ if (!mListeners.containsKey(listener)) {
+ mListeners.put(listener, wrapper);
+ mAnimator.addListener(wrapper);
+ }
+ }
+
+ @Override
+ public void cancel() {
+ mAnimator.cancel();
+ }
+
+ @Override
+ public void end() {
+ mAnimator.end();
+ }
+
+ @Override
+ public long getDuration() {
+ return mAnimator.getDuration();
+ }
+
+ @Override
+ public TimeInterpolator getInterpolator() {
+ return mAnimator.getInterpolator();
+ }
+
+ @Override
+ public void setInterpolator(TimeInterpolator timeInterpolator) {
+ mAnimator.setInterpolator(timeInterpolator);
+ }
+
+ @Override
+ public ArrayList getListeners() {
+ return new ArrayList(mListeners.keySet());
+ }
+
+ @Override
+ public long getStartDelay() {
+ return mAnimator.getStartDelay();
+ }
+
+ @Override
+ public void setStartDelay(long delayMS) {
+ mAnimator.setStartDelay(delayMS);
+ }
+
+ @Override
+ public boolean isPaused() {
+ return mAnimator.isPaused();
+ }
+
+ @Override
+ public boolean isRunning() {
+ return mAnimator.isRunning();
+ }
+
+ @Override
+ public boolean isStarted() {
+ return mAnimator.isStarted();
+ }
+
+ /* We don't want to override pause or resume methods because we don't want them
+ * to affect mAnimator.
+ public void pause();
+
+ public void resume();
+
+ public void addPauseListener(AnimatorPauseListener listener);
+
+ public void removePauseListener(AnimatorPauseListener listener);
+ */
+
+ @Override
+ public void removeAllListeners() {
+ mListeners.clear();
+ mAnimator.removeAllListeners();
+ }
+
+ @Override
+ public void removeListener(AnimatorListener listener) {
+ AnimatorListener wrapper = mListeners.get(listener);
+ if (wrapper != null) {
+ mListeners.remove(listener);
+ mAnimator.removeListener(wrapper);
+ }
+ }
+
+ @Override
+ public Animator setDuration(long durationMS) {
+ mAnimator.setDuration(durationMS);
+ return this;
+ }
+
+ @Override
+ public void setTarget(Object target) {
+ mAnimator.setTarget(target);
+ }
+
+ @Override
+ public void setupEndValues() {
+ mAnimator.setupEndValues();
+ }
+
+ @Override
+ public void setupStartValues() {
+ mAnimator.setupStartValues();
+ }
+
+ @Override
+ public void start() {
+ mAnimator.start();
+ }
+ }
+
+ static class AnimatorListenerWrapper implements Animator.AnimatorListener {
+ private final Animator mAnimator;
+ private final Animator.AnimatorListener mListener;
+
+ public AnimatorListenerWrapper(Animator animator, Animator.AnimatorListener listener) {
+ mAnimator = animator;
+ mListener = listener;
+ }
+
+ @Override
+ public void onAnimationStart(Animator animator) {
+ mListener.onAnimationStart(mAnimator);
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animator) {
+ mListener.onAnimationEnd(mAnimator);
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animator) {
+ mListener.onAnimationCancel(mAnimator);
+ }
+
+ @Override
+ public void onAnimationRepeat(Animator animator) {
+ mListener.onAnimationRepeat(mAnimator);
+ }
+ }
+
+ @RequiresApi(api = Build.VERSION_CODES.KITKAT)
+ public static class TransitionListenerAdapter implements Transition.TransitionListener {
+
+ @Override
+ public void onTransitionStart(Transition transition) {
+
+ }
+
+ @Override
+ public void onTransitionEnd(Transition transition) {
+
+ }
+
+ @Override
+ public void onTransitionCancel(Transition transition) {
+
+ }
+
+ @Override
+ public void onTransitionPause(Transition transition) {
+
+ }
+
+ @Override
+ public void onTransitionResume(Transition transition) {
+
+ }
+ }
+
+}
diff --git a/mvpsdk/src/main/java/com/share/mvpsdk/anim/ToolbarAnimManager.java b/mvpsdk/src/main/java/com/share/mvpsdk/anim/ToolbarAnimManager.java
new file mode 100644
index 0000000..7db1c9c
--- /dev/null
+++ b/mvpsdk/src/main/java/com/share/mvpsdk/anim/ToolbarAnimManager.java
@@ -0,0 +1,93 @@
+package com.share.mvpsdk.anim;
+
+import android.content.Context;
+import android.support.annotation.NonNull;
+import android.support.v7.widget.ActionMenuView;
+import android.support.v7.widget.Toolbar;
+import android.view.View;
+import android.widget.ImageButton;
+import android.widget.TextView;
+
+/**
+ * Created by Horrarndoo on 2017/9/11.
+ *
+ * Toolbar动画Manager
+ */
+
+public class ToolbarAnimManager {
+ /**
+ * Toolbar 进场动画
+ *
+ * Textview&ActionMenuView渐变动画
+ *
+ * @param context context
+ * @param toolbar toolbar
+ */
+ public static void animIn(Context context, @NonNull Toolbar toolbar) {
+ ImageButton ibIcon = null;
+ TextView tvTitle = null;
+ ActionMenuView amvTheme = null;
+ int childCount = toolbar.getChildCount();
+ for (int i = 0; i < childCount; i++) {
+ View child = toolbar.getChildAt(i);
+ if(child instanceof ImageButton) {
+ ibIcon = (ImageButton) child;
+ continue;
+ }
+
+ if (child instanceof ActionMenuView) {
+ amvTheme = (ActionMenuView) child;
+ continue;
+ }
+
+ if (child instanceof TextView)
+ tvTitle = (TextView) child;
+ }
+
+ if(ibIcon != null)
+ animNavigationIcon(context, ibIcon);
+
+ if(tvTitle != null)
+ animTitle(context, tvTitle);
+
+ if(amvTheme != null)
+ animMenu(context, amvTheme);
+ }
+
+ /**
+ * Toolbar Title动画
+ *
+ * NavigationIcon渐变动画
+ *
+ * @param context context
+ * @param imageButton 执行动画的view
+ */
+ public static void animNavigationIcon(Context context, @NonNull ImageButton imageButton) {
+ AnimManager.animAlphaAndScaleX(context, imageButton, 500, 900);
+ }
+
+ /**
+ * Toolbar Title动画
+ *
+ * ActionMenuView渐变动画
+ *
+ * @param context context
+ * @param textView 执行动画的view
+ */
+ public static void animTitle(Context context, @NonNull TextView textView) {
+ AnimManager.animAlphaAndScaleX(context, textView, 500, 900);
+ }
+
+ /**
+ * Toolbar ActionMenuView动画
+ *
+ * ActionMenuView渐变动画
+ *
+ * @param context context
+ * @param avm 执行动画的view
+ */
+ public static void animMenu(Context context, @NonNull ActionMenuView avm) {
+ AnimManager.animAlphaAndScale(context, avm, 500, 200); // filter
+ AnimManager.animAlphaAndScale(context, avm, 700, 200); // overflow
+ }
+}
diff --git a/mvpsdk/src/main/java/com/share/mvpsdk/base/BaseModel.java b/mvpsdk/src/main/java/com/share/mvpsdk/base/BaseModel.java
new file mode 100644
index 0000000..4954d36
--- /dev/null
+++ b/mvpsdk/src/main/java/com/share/mvpsdk/base/BaseModel.java
@@ -0,0 +1,11 @@
+package com.share.mvpsdk.base;
+
+/**
+ * Created by Horrarndoo on 2017/4/25.
+ * base model类
+ */
+
+public abstract class BaseModel {
+ public BaseModel() {
+ }
+}
diff --git a/mvpsdk/src/main/java/com/share/mvpsdk/base/BasePresenter.java b/mvpsdk/src/main/java/com/share/mvpsdk/base/BasePresenter.java
new file mode 100644
index 0000000..e0f5940
--- /dev/null
+++ b/mvpsdk/src/main/java/com/share/mvpsdk/base/BasePresenter.java
@@ -0,0 +1,53 @@
+package com.share.mvpsdk.base;
+
+import android.support.annotation.NonNull;
+
+import com.share.mvpsdk.RxManager;
+
+
+/**
+ * Created by Horrarndoo on 2017/4/25.
+ *
+ * base presenter
+ */
+
+public abstract class BasePresenter {
+ public M mIModel;
+ public V mIView;
+ protected RxManager mRxManager = new RxManager();
+
+ /**
+ * 返回presenter想持有的Model引用
+ *
+ * @return presenter持有的Model引用
+ */
+ public abstract M getModel();
+
+ /**
+ * 绑定IModel和IView的引用
+ *
+ * @param m model
+ * @param v view
+ */
+ public void attachMV(@NonNull M m, @NonNull V v) {
+ this.mIModel = m;
+ this.mIView = v;
+ this.onStart();
+ }
+
+ /**
+ * 解绑IModel和IView
+ */
+ public void detachMV() {
+ mRxManager.unSubscribe();
+ mIView = null;
+ mIModel = null;
+ }
+
+ /**
+ * IView和IModel绑定完成立即执行
+ *
+ * 实现类实现绑定完成后的逻辑,例如数据初始化等,界面初始化, 更新等
+ */
+ public abstract void onStart();
+}
diff --git a/mvpsdk/src/main/java/com/share/mvpsdk/base/IBaseActivity.java b/mvpsdk/src/main/java/com/share/mvpsdk/base/IBaseActivity.java
new file mode 100644
index 0000000..7d9191f
--- /dev/null
+++ b/mvpsdk/src/main/java/com/share/mvpsdk/base/IBaseActivity.java
@@ -0,0 +1,35 @@
+package com.share.mvpsdk.base;
+
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+
+/**
+ * Created by Horrarndoo on 2017/9/6.
+ *
+ * BaseActivity接口
+ */
+
+public interface IBaseActivity extends IBaseView {
+ /**
+ * 跳往新的Activity
+ *
+ * @param clz 要跳往的Activity
+ */
+ void startNewActivity(@NonNull Class> clz);
+
+ /**
+ * 跳往新的Activity
+ *
+ * @param clz 要跳往的Activity
+ * @param bundle 携带的bundle数据
+ */
+ void startNewActivity(@NonNull Class> clz, Bundle bundle);
+
+ /**
+ * 跳往新的Activity
+ * @param clz 要跳转的Activity
+ * @param bundle bundel数据
+ * @param requestCode requestCode
+ */
+ void startNewActivityForResult(@NonNull Class> clz, Bundle bundle, int requestCode);
+}
diff --git a/mvpsdk/src/main/java/com/share/mvpsdk/base/IBaseFragment.java b/mvpsdk/src/main/java/com/share/mvpsdk/base/IBaseFragment.java
new file mode 100644
index 0000000..676ca67
--- /dev/null
+++ b/mvpsdk/src/main/java/com/share/mvpsdk/base/IBaseFragment.java
@@ -0,0 +1,92 @@
+package com.share.mvpsdk.base;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+
+import me.yokeyword.fragmentation.SupportFragment;
+
+/**
+ * Created by Horrarndoo on 2017/9/6.
+ *
+ * BaseFragment接口
+ */
+
+public interface IBaseFragment extends IBaseView {
+ /**
+ * 出栈到目标fragment
+ *
+ * @param targetFragmentClass 目标fragment
+ * @param includeTargetFragment 是否包含该fragment
+ * true 目标fragment也出栈
+ *
+ * false 出栈到目标fragment,目标fragment不出栈
+ */
+ void popToFragment(Class> targetFragmentClass, boolean includeTargetFragment);
+
+ /**
+ * 跳往新的Fragment
+ *
+ * @param supportFragment 要跳往的Fragment(继承自supportFragment)
+ */
+ void startNewFragment(@NonNull SupportFragment supportFragment);
+
+ /**
+ * 跳往新的Fragment,并出栈当前fragment
+ *
+ * @param supportFragment 要跳往的Fragment(继承自supportFragment)
+ */
+ void startNewFragmentWithPop(@NonNull SupportFragment supportFragment);
+
+ /**
+ * 跳往新的Fragment
+ *
+ * @param supportFragment 要跳往的Fragment(继承自supportFragment)
+ * @param requestCode requestCode
+ */
+ void startNewFragmentForResult(@NonNull SupportFragment supportFragment, int requestCode);
+
+ /**
+ * 设置Fragment返回Result
+ *
+ * @param resultCode resultCode
+ * @param data result data
+ */
+ void setOnFragmentResult(int resultCode, Bundle data);
+
+ /**
+ * 跳往新的Activity
+ *
+ * @param clz 要跳往的Activity
+ */
+ void startNewActivity(@NonNull Class> clz);
+
+ /**
+ * 跳往新的Activity
+ *
+ * @param clz 要跳往的Activity
+ * @param bundle 携带的bundle数据
+ */
+ void startNewActivity(@NonNull Class> clz, Bundle bundle);
+
+ /**
+ * 跳往新的Activity
+ *
+ * @param clz 要跳转的Activity
+ * @param bundle bundel数据
+ * @param requestCode requestCode
+ */
+ void startNewActivityForResult(@NonNull Class> clz, Bundle bundle, int requestCode);
+
+ /**
+ * 返回当前fragment是否可见
+ * @return 当前fragment是否可见
+ */
+ boolean isVisiable();
+
+ /**
+ * 返回当前fragment绑定的activity
+ * @return activity
+ */
+ Activity getBindActivity();
+}
diff --git a/mvpsdk/src/main/java/com/share/mvpsdk/base/IBaseModel.java b/mvpsdk/src/main/java/com/share/mvpsdk/base/IBaseModel.java
new file mode 100644
index 0000000..cd33c23
--- /dev/null
+++ b/mvpsdk/src/main/java/com/share/mvpsdk/base/IBaseModel.java
@@ -0,0 +1,9 @@
+package com.share.mvpsdk.base;
+
+/**
+ * Created by Horrarndoo on 2017/4/25.
+ * base model接口
+ */
+
+public interface IBaseModel {
+}
diff --git a/mvpsdk/src/main/java/com/share/mvpsdk/base/IBaseView.java b/mvpsdk/src/main/java/com/share/mvpsdk/base/IBaseView.java
new file mode 100644
index 0000000..fb56316
--- /dev/null
+++ b/mvpsdk/src/main/java/com/share/mvpsdk/base/IBaseView.java
@@ -0,0 +1,47 @@
+package com.share.mvpsdk.base;
+
+import android.support.annotation.NonNull;
+
+/**
+ * Created by Horrarndoo on 2017/5/2.
+ * fragment base view接口
+ */
+
+public interface IBaseView {
+ /**
+ * 初始化presenter
+ *
+ * 此方法返回的presenter对象不可为空
+ */
+ @NonNull
+ BasePresenter initPresenter();
+
+ /**
+ * 显示toast消息
+ *
+ * @param msg 要显示的toast消息字符串
+ */
+ void showToast(String msg);
+
+ /**
+ * 显示等待dialog
+ *
+ * @param waitMsg 等待消息字符串
+ */
+ void showWaitDialog(String waitMsg);
+
+ /**
+ * 隐藏等待dialog
+ */
+ void hideWaitDialog();
+
+ /**
+ * 隐藏键盘
+ */
+ void hideKeybord();
+
+ /**
+ * 回退
+ */
+ void back();
+}
diff --git a/mvpsdk/src/main/java/com/share/mvpsdk/base/activity/BaseCompatActivity.java b/mvpsdk/src/main/java/com/share/mvpsdk/base/activity/BaseCompatActivity.java
new file mode 100644
index 0000000..8485743
--- /dev/null
+++ b/mvpsdk/src/main/java/com/share/mvpsdk/base/activity/BaseCompatActivity.java
@@ -0,0 +1,249 @@
+package com.share.mvpsdk.base.activity;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.os.Bundle;
+import android.support.v7.app.AppCompatDelegate;
+import android.support.v7.widget.Toolbar;
+import android.view.View;
+import android.view.inputmethod.InputMethodManager;
+
+
+import com.share.mvpsdk.AppManager;
+import com.share.mvpsdk.R;
+import com.share.mvpsdk.global.GlobalApplication;
+import com.share.mvpsdk.utils.AppUtils;
+import com.share.mvpsdk.utils.SpUtils;
+import com.share.mvpsdk.utils.StatusBarUtils;
+import com.share.mvpsdk.utils.ThemeUtils;
+import com.share.mvpsdk.widgets.WaitPorgressDialog;
+
+import butterknife.ButterKnife;
+import me.yokeyword.fragmentation.SupportActivity;
+import me.yokeyword.fragmentation.anim.DefaultVerticalAnimator;
+import me.yokeyword.fragmentation.anim.FragmentAnimator;
+
+/**
+ * Created by Horrarndoo on 2017/9/7.
+ *
+ * BaseActivity
+ */
+
+public abstract class BaseCompatActivity extends SupportActivity {
+ protected GlobalApplication mApplication;
+ protected WaitPorgressDialog mWaitPorgressDialog;
+ protected Context mContext;//全局上下文对象
+ protected boolean isTransAnim;
+
+ static {
+ //5.0以下兼容vector
+ AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ init(savedInstanceState);
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ AppManager.getAppManager().finishActivity(this);
+ }
+
+ @Override
+ public FragmentAnimator onCreateFragmentAnimator() {
+ //fragment切换使用默认Vertical动画
+ return new DefaultVerticalAnimator();
+ }
+
+ private void init(Bundle savedInstanceState) {
+ setTheme(ThemeUtils.themeArr[SpUtils.getThemeIndex(this)][
+ SpUtils.getNightModel(this) ? 1 : 0]);
+ setContentView(getLayoutId());
+ ButterKnife.bind(this);
+ StatusBarUtils.setTransparent(this);
+ setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
+ initData();
+ initView(savedInstanceState);
+ AppManager.getAppManager().addActivity(this);
+ }
+
+ public void reload() {
+ Intent intent = getIntent();
+ overridePendingTransition(0, 0);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
+ finish();
+ overridePendingTransition(0, 0);
+ startActivity(intent);
+ }
+
+ /**
+ * 初始化数据
+ *
+ * 子类可以复写此方法初始化子类数据
+ */
+ protected void initData() {
+ mContext = AppUtils.getContext();
+ mApplication = GlobalApplication.getInstance();
+ mWaitPorgressDialog = new WaitPorgressDialog(this);
+ isTransAnim = true;
+ }
+
+ /**
+ * 初始化view
+ *
+ * 子类实现 控件绑定、视图初始化等内容
+ *
+ * @param savedInstanceState savedInstanceState
+ */
+ protected abstract void initView(Bundle savedInstanceState);
+
+ /**
+ * 获取当前layouty的布局ID,用于设置当前布局
+ *
+ * 交由子类实现
+ *
+ * @return layout Id
+ */
+ protected abstract int getLayoutId();
+
+ /**
+ * 显示提示框
+ *
+ * @param msg 提示框内容字符串
+ */
+ protected void showProgressDialog(String msg) {
+ mWaitPorgressDialog.setMessage(msg);
+ mWaitPorgressDialog.show();
+ }
+
+ /**
+ * 隐藏提示框
+ */
+ protected void hideProgressDialog() {
+ if (mWaitPorgressDialog != null) {
+ mWaitPorgressDialog.dismiss();
+ }
+ }
+
+ /**
+ * [页面跳转]
+ *
+ * @param clz 要跳转的Activity
+ */
+ public void startActivity(Class> clz) {
+ startActivity(new Intent(this, clz));
+ if (isTransAnim)
+ overridePendingTransition(R.anim.activity_start_zoom_in, R.anim
+ .activity_start_zoom_out);
+ }
+
+ /**
+ * [页面跳转]
+ *
+ * @param clz 要跳转的Activity
+ * @param intent intent
+ */
+ public void startActivity(Class> clz, Intent intent) {
+ intent.setClass(this, clz);
+ startActivity(intent);
+ if (isTransAnim)
+ overridePendingTransition(R.anim.activity_start_zoom_in, R.anim
+ .activity_start_zoom_out);
+ }
+
+ /**
+ * [携带数据的页面跳转]
+ *
+ * @param clz 要跳转的Activity
+ * @param bundle bundel数据
+ */
+ public void startActivity(Class> clz, Bundle bundle) {
+ Intent intent = new Intent();
+ intent.setClass(this, clz);
+ if (bundle != null) {
+ intent.putExtras(bundle);
+ }
+ startActivity(intent);
+ if (isTransAnim)
+ overridePendingTransition(R.anim.activity_start_zoom_in, R.anim
+ .activity_start_zoom_out);
+ }
+
+ /**
+ * [含有Bundle通过Class打开编辑界面]
+ *
+ * @param clz 要跳转的Activity
+ * @param bundle bundel数据
+ * @param requestCode requestCode
+ */
+ public void startActivityForResult(Class> clz, Bundle bundle,
+ int requestCode) {
+ Intent intent = new Intent();
+ intent.setClass(this, clz);
+ if (bundle != null) {
+ intent.putExtras(bundle);
+ }
+ startActivityForResult(intent, requestCode);
+ if (isTransAnim)
+ overridePendingTransition(R.anim.activity_start_zoom_in, R.anim
+ .activity_start_zoom_out);
+ }
+
+ @Override
+ public void finish() {
+ super.finish();
+ if (isTransAnim)
+ overridePendingTransition(R.anim.activity_finish_trans_in, R.anim
+ .activity_finish_trans_out);
+ }
+
+ /**
+ * 隐藏键盘
+ *
+ * @return 隐藏键盘结果
+ *
+ * true:隐藏成功
+ *
+ * false:隐藏失败
+ */
+ protected boolean hiddenKeyboard() {
+ //点击空白位置 隐藏软键盘
+ InputMethodManager mInputMethodManager = (InputMethodManager) getSystemService
+ (INPUT_METHOD_SERVICE);
+ return mInputMethodManager.hideSoftInputFromWindow(this
+ .getCurrentFocus().getWindowToken(), 0);
+ }
+
+ protected void initTitleBar(Toolbar toolbar, String title) {
+ toolbar.setTitle(title);
+ setSupportActionBar(toolbar);
+ getSupportActionBar().setDisplayHomeAsUpEnabled(true);
+ getSupportActionBar().setDisplayShowHomeEnabled(true);
+ toolbar.setNavigationIcon(R.mipmap.ic_arrow_back_white);
+ toolbar.setNavigationOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ onBackPressedSupport();
+ }
+ });
+ }
+
+ /**
+ * 是否使用overridePendingTransition过度动画
+ * @return 是否使用overridePendingTransition过度动画,默认使用
+ */
+ protected boolean isTransAnim() {
+ return isTransAnim;
+ }
+
+ /**
+ * 设置是否使用overridePendingTransition过度动画
+ */
+ protected void setIsTransAnim(boolean b){
+ isTransAnim = b;
+ }
+}
diff --git a/mvpsdk/src/main/java/com/share/mvpsdk/base/activity/BaseMVPCompatActivity.java b/mvpsdk/src/main/java/com/share/mvpsdk/base/activity/BaseMVPCompatActivity.java
new file mode 100644
index 0000000..63edbf1
--- /dev/null
+++ b/mvpsdk/src/main/java/com/share/mvpsdk/base/activity/BaseMVPCompatActivity.java
@@ -0,0 +1,94 @@
+package com.share.mvpsdk.base.activity;
+
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+
+import com.share.mvpsdk.base.BasePresenter;
+import com.share.mvpsdk.base.IBaseActivity;
+import com.share.mvpsdk.base.IBaseModel;
+import com.share.mvpsdk.utils.ToastUtils;
+
+
+/**
+ * Created by Horrarndoo on 2017/4/6.
+ *
+ * Mvp Activity基类
+ */
+public abstract class BaseMVPCompatActivity
extends
+ BaseCompatActivity implements IBaseActivity {
+ /**
+ * presenter 具体的presenter由子类确定
+ */
+ protected P mPresenter;
+
+ /**
+ * model 具体的model由子类确定
+ */
+ private M mIMode;
+
+ /**
+ * 初始化数据
+ *
+ * 子类可以复写此方法初始化子类数据
+ */
+ protected void initData() {
+ super.initData();
+ mPresenter = (P) initPresenter();
+ if (mPresenter != null) {
+ mIMode = (M) mPresenter.getModel();
+ if (mIMode != null) {
+ mPresenter.attachMV(mIMode, this);
+ }
+ //Logger.d("attach M V success.");
+ }
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ if (mPresenter != null) {
+ mPresenter.detachMV();
+ //Logger.d("detach M V success.");
+ }
+ }
+
+ @Override
+ public void showWaitDialog(String msg) {
+ showProgressDialog(msg);
+ }
+
+ @Override
+ public void hideWaitDialog() {
+ hideProgressDialog();
+ }
+
+ @Override
+ public void showToast(String msg) {
+ ToastUtils.showToast(msg);
+ }
+
+ @Override
+ public void startNewActivity(@NonNull Class> clz) {
+ startActivity(clz);
+ }
+
+ @Override
+ public void startNewActivity(@NonNull Class> clz, Bundle bundle) {
+ startActivity(clz, bundle);
+ }
+
+ @Override
+ public void startNewActivityForResult(@NonNull Class> clz, Bundle bundle, int requestCode) {
+ startActivityForResult(clz, bundle, requestCode);
+ }
+
+ @Override
+ public void hideKeybord() {
+ hiddenKeyboard();
+ }
+
+ @Override
+ public void back() {
+ super.onBackPressedSupport();
+ }
+}
diff --git a/mvpsdk/src/main/java/com/share/mvpsdk/base/adapter/BaseRecyclerViewAdapter.java b/mvpsdk/src/main/java/com/share/mvpsdk/base/adapter/BaseRecyclerViewAdapter.java
new file mode 100644
index 0000000..1ec06da
--- /dev/null
+++ b/mvpsdk/src/main/java/com/share/mvpsdk/base/adapter/BaseRecyclerViewAdapter.java
@@ -0,0 +1,79 @@
+package com.share.mvpsdk.base.adapter;
+
+import android.support.v7.widget.RecyclerView;
+import android.view.ViewGroup;
+
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Created by ToaHanDong on 2017/3/23.
+ */
+
+public abstract class BaseRecyclerViewAdapter extends RecyclerView.Adapter {
+
+ private List data = new ArrayList<>();
+ public OnItemClickListener onItemClickListener;
+ public OnItemLongClickListener onItemLongClickListener;
+
+ @Override
+ public BaseRecyclerViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+ return null;
+ }
+
+ @Override
+ public void onBindViewHolder(BaseRecyclerViewHolder holder, int position) {
+ holder.onBindViewHolder(data.get(getPosition(position)), getPosition(position));
+ }
+
+
+ @Override
+ public int getItemCount() {
+ return data.size();
+ }
+
+ public void addAll(List data) {
+ removeAll();
+ if (data!=null)
+ this.data.addAll(data);
+ notifyDataSetChanged();
+ }
+
+ public void removeAll() {
+ data.clear();
+ }
+
+ public void remove(int position) {
+ data.remove(position);
+ }
+
+ public void notift() {
+ notifyDataSetChanged();
+ }
+
+ public void remove(T object) {
+ data.remove(object);
+ }
+
+ public List getData() {
+ return data;
+ }
+
+ public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
+ this.onItemClickListener = onItemClickListener;
+ }
+
+ public void setOnItemLongClickListener(OnItemLongClickListener onItemLongClickListener) {
+ this.onItemLongClickListener = onItemLongClickListener;
+ }
+
+ private int getPosition(int position) {
+ return position;
+// if (data.size() <= 9) {
+// return position;
+// }
+// return position % (data.size());
+ }
+
+}
diff --git a/mvpsdk/src/main/java/com/share/mvpsdk/base/adapter/BaseRecyclerViewHolder.java b/mvpsdk/src/main/java/com/share/mvpsdk/base/adapter/BaseRecyclerViewHolder.java
new file mode 100644
index 0000000..39bde5a
--- /dev/null
+++ b/mvpsdk/src/main/java/com/share/mvpsdk/base/adapter/BaseRecyclerViewHolder.java
@@ -0,0 +1,22 @@
+package com.share.mvpsdk.base.adapter;
+
+import android.support.v7.widget.RecyclerView;
+import android.view.View;
+
+/**
+ * Created by ToaHanDong on 2017/3/23.
+ */
+
+public abstract class BaseRecyclerViewHolder extends RecyclerView.ViewHolder {
+
+ public BaseRecyclerViewHolder(View itemView) {
+ super(itemView);
+ }
+
+ public abstract void onBindViewHolder(T object, final int position);
+
+ void OnBaseBindViewHolder(T Object,int position){
+ onBindViewHolder(Object,position);
+ }
+
+}
diff --git a/mvpsdk/src/main/java/com/share/mvpsdk/base/adapter/OnItemClickListener.java b/mvpsdk/src/main/java/com/share/mvpsdk/base/adapter/OnItemClickListener.java
new file mode 100644
index 0000000..874e278
--- /dev/null
+++ b/mvpsdk/src/main/java/com/share/mvpsdk/base/adapter/OnItemClickListener.java
@@ -0,0 +1,10 @@
+package com.share.mvpsdk.base.adapter;
+
+/**
+ * Created by ToaHanDong on 2017/3/23.
+ */
+
+public interface OnItemClickListener {
+
+ void onItemClickListener(T object, int position);
+}
diff --git a/mvpsdk/src/main/java/com/share/mvpsdk/base/adapter/OnItemLongClickListener.java b/mvpsdk/src/main/java/com/share/mvpsdk/base/adapter/OnItemLongClickListener.java
new file mode 100644
index 0000000..c05bf3c
--- /dev/null
+++ b/mvpsdk/src/main/java/com/share/mvpsdk/base/adapter/OnItemLongClickListener.java
@@ -0,0 +1,10 @@
+package com.share.mvpsdk.base.adapter;
+
+/**
+ * Created by ToaHanDong on 2017/3/23.
+ */
+
+public interface OnItemLongClickListener {
+
+ void onItemLongClickListener(T object, int position);
+}
diff --git a/mvpsdk/src/main/java/com/share/mvpsdk/base/entity/BaseEntity.java b/mvpsdk/src/main/java/com/share/mvpsdk/base/entity/BaseEntity.java
new file mode 100644
index 0000000..48f3c17
--- /dev/null
+++ b/mvpsdk/src/main/java/com/share/mvpsdk/base/entity/BaseEntity.java
@@ -0,0 +1,47 @@
+package com.share.mvpsdk.base.entity;
+
+import java.io.Serializable;
+
+/**
+ * Created by ToaHanDong on 2017/4/27.
+ */
+
+public class BaseEntity implements Serializable {
+
+ private int status;
+ private String message;
+ private T data;
+
+ public int getStatus() {
+ return status;
+ }
+
+ public void setStatus(int status) {
+ this.status = status;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+
+ public void setMessage(String message) {
+ this.message = message;
+ }
+
+ public T getData() {
+ return data;
+ }
+
+ public void setData(T data) {
+ this.data = data;
+ }
+
+ @Override
+ public String toString() {
+ return "BaseEntity{" +
+ "status=" + status +
+ ", message='" + message + '\'' +
+ ", data=" + data +
+ '}';
+ }
+}
diff --git a/mvpsdk/src/main/java/com/share/mvpsdk/base/entity/BaseListEntity.java b/mvpsdk/src/main/java/com/share/mvpsdk/base/entity/BaseListEntity.java
new file mode 100644
index 0000000..5bfdfef
--- /dev/null
+++ b/mvpsdk/src/main/java/com/share/mvpsdk/base/entity/BaseListEntity.java
@@ -0,0 +1,48 @@
+package com.share.mvpsdk.base.entity;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * Created by ToaHanDong on 2017/6/6.
+ */
+
+public class BaseListEntity implements Serializable {
+
+ private int status;
+ private String message;
+ private List data;
+
+ public int getStatus() {
+ return status;
+ }
+
+ public void setStatus(int status) {
+ this.status = status;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+
+ public void setMessage(String message) {
+ this.message = message;
+ }
+
+ public List getData() {
+ return data;
+ }
+
+ public void setData(List data) {
+ this.data = data;
+ }
+
+ @Override
+ public String toString() {
+ return "BaseListEntity{" +
+ "status=" + status +
+ ", message='" + message + '\'' +
+ ", data=" + data +
+ '}';
+ }
+}
diff --git a/mvpsdk/src/main/java/com/share/mvpsdk/base/fragment/BaseCompatFragment.java b/mvpsdk/src/main/java/com/share/mvpsdk/base/fragment/BaseCompatFragment.java
new file mode 100644
index 0000000..128a89e
--- /dev/null
+++ b/mvpsdk/src/main/java/com/share/mvpsdk/base/fragment/BaseCompatFragment.java
@@ -0,0 +1,153 @@
+package com.share.mvpsdk.base.fragment;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.pm.ActivityInfo;
+import android.os.Bundle;
+import android.support.annotation.LayoutRes;
+import android.support.annotation.Nullable;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+
+import com.share.mvpsdk.global.GlobalApplication;
+import com.share.mvpsdk.utils.AppUtils;
+import com.share.mvpsdk.widgets.WaitPorgressDialog;
+
+import butterknife.ButterKnife;
+import butterknife.Unbinder;
+import me.yokeyword.fragmentation.SupportFragment;
+import timber.log.Timber;
+
+/**
+ * Created by Horrarndoo on 2017/9/26.
+ *
+ */
+
+public abstract class BaseCompatFragment extends SupportFragment {
+
+ protected String TAG;
+ protected Context mContext;
+ protected Activity mActivity;
+ protected GlobalApplication mApplication;
+ protected WaitPorgressDialog mWaitPorgressDialog;
+// private Unbinder binder;
+
+ @Override
+ public void onAttach(Context context) {
+ mActivity = (Activity) context;
+ mContext = context;
+ super.onAttach(context);
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable
+ Bundle savedInstanceState) {
+ if (getLayoutView() != null) {
+ return getLayoutView();
+ } else {
+ // return inflater.inflate(getLayoutId(), null);
+ return inflater.inflate(getLayoutId(), container, false);
+ }
+ }
+
+ @Override
+ public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
+ ButterKnife.bind(this, view);
+ super.onViewCreated(view, savedInstanceState);
+ mActivity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
+ TAG = getClass().getSimpleName();
+ getBundle(getArguments());
+ initData();
+ initUI(view, savedInstanceState);
+ }
+
+
+ @Override
+ public void onDestroyView() {
+ super.onDestroyView();
+// if (binder != null)
+// binder.unbind();
+ }
+
+ @Override
+ public void onDetach() {
+ super.onDetach();
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ }
+
+ @LayoutRes
+ public abstract int getLayoutId();
+
+ public View getLayoutView() {
+ return null;
+ }
+
+ /**
+ * 得到Activity传进来的值
+ */
+ public void getBundle(Bundle bundle) {
+ }
+
+ /**
+ * 初始化UI
+ */
+ public abstract void initUI(View view, @Nullable Bundle savedInstanceState);
+
+ /**
+ * 在监听器之前把数据准备好
+ */
+ public void initData() {
+ mWaitPorgressDialog = new WaitPorgressDialog(mActivity);
+ mContext = AppUtils.getContext();
+ mApplication = GlobalApplication.getInstance();
+ }
+
+ /**
+ * 处理回退事件
+ *
+ * @return true 事件已消费
+ *
+ * false 事件向上传递
+ */
+ @Override
+ public boolean onBackPressedSupport() {
+ if (getFragmentManager().getBackStackEntryCount() > 1) {
+ //如果当前存在fragment>1,当前fragment出栈
+ pop();
+ } else {
+ //已经退栈到root fragment,交由Activity处理回退事件
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * 显示提示框
+ *
+ * @param msg 提示框内容字符串
+ */
+ protected void showProgressDialog(String msg) {
+ if (mWaitPorgressDialog.isShowing()) {
+ mWaitPorgressDialog.dismiss();
+ }
+
+ mWaitPorgressDialog.setMessage(msg);
+ mWaitPorgressDialog.show();
+ }
+
+ /**
+ * 隐藏提示框
+ */
+ protected void hideProgressDialog() {
+ if (mWaitPorgressDialog != null) {
+ mWaitPorgressDialog.dismiss();
+ }
+ }
+}
diff --git a/mvpsdk/src/main/java/com/share/mvpsdk/base/fragment/BaseMVPCompatFragment.java b/mvpsdk/src/main/java/com/share/mvpsdk/base/fragment/BaseMVPCompatFragment.java
new file mode 100644
index 0000000..d70cbcd
--- /dev/null
+++ b/mvpsdk/src/main/java/com/share/mvpsdk/base/fragment/BaseMVPCompatFragment.java
@@ -0,0 +1,128 @@
+package com.share.mvpsdk.base.fragment;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.widget.Toast;
+
+
+import com.share.mvpsdk.base.BasePresenter;
+import com.share.mvpsdk.base.IBaseFragment;
+import com.share.mvpsdk.base.IBaseModel;
+import com.share.mvpsdk.base.activity.BaseCompatActivity;
+import com.share.mvpsdk.utils.ToastUtils;
+
+import me.yokeyword.fragmentation.SupportFragment;
+
+/**
+ * Created by Horrarndoo on 2017/9/6.
+ *
+ * Mvp Fragment基类
+ *
+ * 实现IBaseView方法、绑定butterknife
+ */
+
+public abstract class BaseMVPCompatFragment
extends
+ BaseCompatFragment implements IBaseFragment {
+ public P mPresenter;
+ public M mIMode;
+
+ /**
+ * 在监听器之前把数据准备好
+ */
+ public void initData() {
+ super.initData();
+
+ mPresenter = (P) initPresenter();
+ if (mPresenter != null) {
+ mIMode = (M) mPresenter.getModel();
+ if (mIMode != null) {
+ mPresenter.attachMV(mIMode, this);
+ }
+ }
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ if (mPresenter != null) {
+ mPresenter.detachMV();
+ }
+ }
+
+ @Override
+ public void showWaitDialog(String msg) {
+ showProgressDialog(msg);
+ }
+
+ @Override
+ public void hideWaitDialog() {
+ hideProgressDialog();
+ }
+
+ @Override
+ public void showToast(String msg) {
+ ToastUtils.showToast(mContext, msg, Toast.LENGTH_SHORT);
+ }
+
+ @Override
+ public void back() {
+ this.onBackPressedSupport();
+ }
+
+ @Override
+ public void startNewFragment(@NonNull SupportFragment supportFragment) {
+ start(supportFragment);
+ }
+
+ @Override
+ public void startNewFragmentWithPop(@NonNull SupportFragment supportFragment) {
+ startWithPop(supportFragment);
+ }
+
+ @Override
+ public void startNewFragmentForResult(@NonNull SupportFragment supportFragment, int
+ requestCode) {
+ startForResult(supportFragment, requestCode);
+ }
+
+ @Override
+ public void popToFragment(Class> targetFragmentClass, boolean includeTargetFragment) {
+ popTo(targetFragmentClass, includeTargetFragment);
+ }
+
+ @Override
+ public void hideKeybord() {
+ hideSoftInput();
+ }
+
+ @Override
+ public void setOnFragmentResult(int ResultCode, Bundle data) {
+ setFragmentResult(ResultCode, data);
+ }
+
+ @Override
+ public void startNewActivity(@NonNull Class> clz) {
+ ((BaseCompatActivity) mActivity).startActivity(clz);
+ }
+
+ @Override
+ public void startNewActivity(@NonNull Class> clz, Bundle bundle) {
+ ((BaseCompatActivity) mActivity).startActivity(clz, bundle);
+ }
+
+ @Override
+ public void startNewActivityForResult(@NonNull Class> clz, Bundle bundle, int requestCode) {
+ ((BaseCompatActivity) mActivity).startActivityForResult(clz, bundle, requestCode);
+ }
+
+ @Override
+ public boolean isVisiable() {
+ return isSupportVisible();
+ }
+
+ @Override
+ public Activity getBindActivity() {
+ return mActivity;
+ }
+}
\ No newline at end of file
diff --git a/mvpsdk/src/main/java/com/share/mvpsdk/base/fragment/BaseRecycleFragment.java b/mvpsdk/src/main/java/com/share/mvpsdk/base/fragment/BaseRecycleFragment.java
new file mode 100644
index 0000000..188c20f
--- /dev/null
+++ b/mvpsdk/src/main/java/com/share/mvpsdk/base/fragment/BaseRecycleFragment.java
@@ -0,0 +1,68 @@
+package com.share.mvpsdk.base.fragment;
+
+import android.os.Bundle;
+import android.support.annotation.Nullable;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.share.mvpsdk.R;
+import com.share.mvpsdk.base.BasePresenter;
+import com.share.mvpsdk.base.IBaseModel;
+
+
+/**
+ * Created by Horrarndoo on 2017/10/17.
+ *
+ * 带RecycleView加载状态view的fragment,主要用于显示加载中、空界面、加载失败等状态界面显示
+ */
+
+public abstract class BaseRecycleFragment
extends
+ BaseMVPCompatFragment
{
+ /**
+ * 网络异常View
+ */
+ protected View errorView;
+ /**
+ * loadingView
+ */
+ protected View loadingView;
+ /**
+ * 没有内容view
+ */
+ protected View emptyView;
+
+ @Override
+ public void onLazyInitView(@Nullable Bundle savedInstanceState) {
+ super.onLazyInitView(savedInstanceState);
+ showLoading();
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable
+ Bundle savedInstanceState) {
+ errorView = inflater.inflate(R.layout.view_network_error, container, false);
+ loadingView = inflater.inflate(R.layout.view_loading, container, false);
+ emptyView = inflater.inflate(R.layout.view_empty, container, false);
+ errorView.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ showLoading();
+ onErrorViewClick(v);
+ }
+ });
+ return super.onCreateView(inflater, container, savedInstanceState);
+ }
+
+ /**
+ * 网络异常view被点击时触发,由子类实现
+ *
+ * @param view view
+ */
+ protected abstract void onErrorViewClick(View view);
+
+ /**
+ * 显示加载中view,由子类实现
+ */
+ protected abstract void showLoading();
+}
diff --git a/mvpsdk/src/main/java/com/share/mvpsdk/config/DBConfig.java b/mvpsdk/src/main/java/com/share/mvpsdk/config/DBConfig.java
new file mode 100644
index 0000000..f480cb7
--- /dev/null
+++ b/mvpsdk/src/main/java/com/share/mvpsdk/config/DBConfig.java
@@ -0,0 +1,16 @@
+package com.share.mvpsdk.config;
+
+/**
+ * Created by Horrarndoo on 2017/9/13.
+ *
+ * 数据库全局常量
+ */
+
+public class DBConfig {
+ public static final String DB_NAME = "db_name_yizhi";
+ public static final String TABLE_ZHIHU = "table_zhihu";
+ public static final String TABLE_WANGYI = "table_top_news";
+ public static final String TABLE_WEIXIN = "table_weixin";
+ public static final String TABLE_GANKIO_DAY = "table_gank_io_day";
+ public static final String TABLE_GANKIO_CUSTOM = "table_gank_io_custom";
+}
diff --git a/mvpsdk/src/main/java/com/share/mvpsdk/config/ItemState.java b/mvpsdk/src/main/java/com/share/mvpsdk/config/ItemState.java
new file mode 100644
index 0000000..d03b788
--- /dev/null
+++ b/mvpsdk/src/main/java/com/share/mvpsdk/config/ItemState.java
@@ -0,0 +1,19 @@
+package com.share.mvpsdk.config;
+
+/**
+ * Created by Horrarndoo on 2017/9/13.
+ *
+ * item状态全局常量
+ */
+
+public class ItemState {
+ /**
+ * 已读状态
+ */
+ public static final int STATE_IS_READ = 1;
+
+ /**
+ * 非已读状态
+ */
+ public static final int STATE_IS_NO_READ = 0;
+}
diff --git a/mvpsdk/src/main/java/com/share/mvpsdk/global/GlobalApplication.java b/mvpsdk/src/main/java/com/share/mvpsdk/global/GlobalApplication.java
new file mode 100644
index 0000000..5e4b301
--- /dev/null
+++ b/mvpsdk/src/main/java/com/share/mvpsdk/global/GlobalApplication.java
@@ -0,0 +1,67 @@
+package com.share.mvpsdk.global;
+
+import android.app.Application;
+import android.content.Context;
+import android.os.Handler;
+
+import com.orhanobut.logger.LogLevel;
+import com.orhanobut.logger.Logger;
+
+import timber.log.Timber;
+
+
+/**
+ * Created by Horrarndoo on 2017/9/1.
+ *
+ * 全局Application
+ */
+
+public class GlobalApplication extends Application {
+ private static final String LOG_TAG = "YZ_LOGGER";
+ protected static Context context;
+ protected static Handler handler;
+ protected static int mainThreadId;
+ private static GlobalApplication mApp;
+
+ public static synchronized GlobalApplication getInstance() {
+ return mApp;
+ }
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ context = getApplicationContext();
+ handler = new Handler();
+ mainThreadId = android.os.Process.myTid();
+ mApp=this;
+ //LogLevel.FULL : LogLevel.NONE
+ Logger.init(LOG_TAG).logLevel(LogLevel.FULL);
+ }
+
+ /**
+ * 获取上下文对象
+ *
+ * @return context
+ */
+ public static Context getContext() {
+ return context;
+ }
+
+ /**
+ * 获取全局handler
+ *
+ * @return 全局handler
+ */
+ public static Handler getHandler() {
+ return handler;
+ }
+
+ /**
+ * 获取主线程id
+ *
+ * @return 主线程id
+ */
+ public static int getMainThreadId() {
+ return mainThreadId;
+ }
+}
diff --git a/mvpsdk/src/main/java/com/share/mvpsdk/helper/BottomNavigationViewHelper.java b/mvpsdk/src/main/java/com/share/mvpsdk/helper/BottomNavigationViewHelper.java
new file mode 100644
index 0000000..75c1839
--- /dev/null
+++ b/mvpsdk/src/main/java/com/share/mvpsdk/helper/BottomNavigationViewHelper.java
@@ -0,0 +1,37 @@
+package com.share.mvpsdk.helper;
+
+import android.support.design.internal.BottomNavigationItemView;
+import android.support.design.internal.BottomNavigationMenuView;
+import android.support.design.widget.BottomNavigationView;
+import android.util.Log;
+
+import java.lang.reflect.Field;
+
+/**
+ * Created by Horrarndoo on 2017/9/22.
+ *
+ * BottomNavigationView禁止3个item以上动画切换效果
+ */
+public class BottomNavigationViewHelper {
+ public static void disableShiftMode(BottomNavigationView view) {
+ BottomNavigationMenuView menuView = (BottomNavigationMenuView) view.getChildAt(0);
+ try {
+ Field shiftingMode = menuView.getClass().getDeclaredField("mShiftingMode");
+ shiftingMode.setAccessible(true);
+ shiftingMode.setBoolean(menuView, false);
+ shiftingMode.setAccessible(false);
+ for (int i = 0; i < menuView.getChildCount(); i++) {
+ BottomNavigationItemView item = (BottomNavigationItemView) menuView.getChildAt(i);
+ //noinspection RestrictedApi
+ item.setShiftingMode(false);
+ // set once again checked value, so view will be updated
+ //noinspection RestrictedApi
+ item.setChecked(item.getItemData().isChecked());
+ }
+ } catch (NoSuchFieldException e) {
+ Log.e("BNVHelper", "Unable to get shift mode field", e);
+ } catch (IllegalAccessException e) {
+ Log.e("BNVHelper", "Unable to change value of shift mode", e);
+ }
+ }
+}
diff --git a/mvpsdk/src/main/java/com/share/mvpsdk/helper/RetrofitCreateHelper.java b/mvpsdk/src/main/java/com/share/mvpsdk/helper/RetrofitCreateHelper.java
new file mode 100644
index 0000000..178d58e
--- /dev/null
+++ b/mvpsdk/src/main/java/com/share/mvpsdk/helper/RetrofitCreateHelper.java
@@ -0,0 +1,56 @@
+package com.share.mvpsdk.helper;
+
+
+
+import com.share.mvpsdk.helper.okhttp.CacheInterceptor;
+import com.share.mvpsdk.helper.okhttp.HttpCache;
+import com.share.mvpsdk.helper.okhttp.TrustManager;
+
+import java.util.concurrent.TimeUnit;
+
+import okhttp3.OkHttpClient;
+import okhttp3.logging.HttpLoggingInterceptor;
+import retrofit2.Retrofit;
+import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
+import retrofit2.converter.gson.GsonConverterFactory;
+
+/**
+ * Created by Horrarndoo on 2017/9/7.
+ *
+ */
+
+public class RetrofitCreateHelper {
+ private static final int TIMEOUT_READ = 20;
+ private static final int TIMEOUT_CONNECTION = 10;
+ private static final HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor()
+ .setLevel(HttpLoggingInterceptor.Level.BODY);
+ private static CacheInterceptor cacheInterceptor = new CacheInterceptor();
+ private static OkHttpClient okHttpClient = new OkHttpClient.Builder()
+ //SSL证书
+ .sslSocketFactory(TrustManager.getUnsafeOkHttpClient())
+ .hostnameVerifier(org.apache.http.conn.ssl.SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER)
+ //打印日志
+ .addInterceptor(interceptor)
+ //设置Cache拦截器
+ .addNetworkInterceptor(cacheInterceptor)
+ .addInterceptor(cacheInterceptor)
+ .cache(HttpCache.getCache())
+ //time out
+ .connectTimeout(TIMEOUT_CONNECTION, TimeUnit.SECONDS)
+ .readTimeout(TIMEOUT_READ, TimeUnit.SECONDS)
+ .writeTimeout(TIMEOUT_READ, TimeUnit.SECONDS)
+ //失败重连
+ .retryOnConnectionFailure(true)
+ .build();
+
+ public static T createApi(Class clazz, String url) {
+ Retrofit retrofit = new Retrofit.Builder()
+ .baseUrl(url)
+ .client(okHttpClient)
+ .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
+ .addConverterFactory(GsonConverterFactory.create())
+ .build();
+ return retrofit.create(clazz);
+ }
+}
+
diff --git a/mvpsdk/src/main/java/com/share/mvpsdk/helper/RxHelper.java b/mvpsdk/src/main/java/com/share/mvpsdk/helper/RxHelper.java
new file mode 100644
index 0000000..1483ab4
--- /dev/null
+++ b/mvpsdk/src/main/java/com/share/mvpsdk/helper/RxHelper.java
@@ -0,0 +1,76 @@
+package com.share.mvpsdk.helper;
+
+
+import io.reactivex.BackpressureStrategy;
+import io.reactivex.Flowable;
+import io.reactivex.FlowableEmitter;
+import io.reactivex.FlowableOnSubscribe;
+import io.reactivex.Observable;
+import io.reactivex.ObservableEmitter;
+import io.reactivex.ObservableOnSubscribe;
+import io.reactivex.ObservableSource;
+import io.reactivex.ObservableTransformer;
+import io.reactivex.android.schedulers.AndroidSchedulers;
+import io.reactivex.schedulers.Schedulers;
+
+/**
+ * Created by Horrarndoo on 2017/9/12.
+ *
+ */
+public class RxHelper {
+ /**
+ * 统一线程处理
+ *
+ * 发布事件io线程,接收事件主线程
+ */
+ public static ObservableTransformer rxSchedulerHelper() {//compose处理线程
+ return new ObservableTransformer() {
+
+ @Override
+ public ObservableSource apply(Observable upstream) {
+ return upstream.subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread());
+ }
+ };
+ }
+
+ /**
+ * 生成Flowable
+ *
+ * @param t
+ * @return Flowable
+ */
+ public static Flowable createFlowable(final T t) {
+ return Flowable.create(new FlowableOnSubscribe() {
+ @Override
+ public void subscribe(FlowableEmitter emitter) throws Exception {
+ try {
+ emitter.onNext(t);
+ emitter.onComplete();
+ } catch (Exception e) {
+ emitter.onError(e);
+ }
+ }
+ }, BackpressureStrategy.BUFFER);
+ }
+
+ /**
+ * 生成Observable
+ *
+ * @param t
+ * @return Flowable
+ */
+ public static Observable createObservable(final T t) {
+ return Observable.create(new ObservableOnSubscribe() {
+ @Override
+ public void subscribe(ObservableEmitter emitter) throws Exception {
+ try {
+ emitter.onNext(t);
+ emitter.onComplete();
+ } catch (Exception e) {
+ emitter.onError(e);
+ }
+ }
+ });
+ }
+}
diff --git a/mvpsdk/src/main/java/com/share/mvpsdk/helper/okhttp/CacheInterceptor.java b/mvpsdk/src/main/java/com/share/mvpsdk/helper/okhttp/CacheInterceptor.java
new file mode 100644
index 0000000..9194d3d
--- /dev/null
+++ b/mvpsdk/src/main/java/com/share/mvpsdk/helper/okhttp/CacheInterceptor.java
@@ -0,0 +1,84 @@
+package com.share.mvpsdk.helper.okhttp;
+
+
+
+import com.share.mvpsdk.utils.AppUtils;
+import com.share.mvpsdk.utils.NetworkConnectionUtils;
+
+import java.io.IOException;
+
+import okhttp3.CacheControl;
+import okhttp3.Interceptor;
+import okhttp3.Request;
+import okhttp3.Response;
+
+import static com.share.mvpsdk.utils.HttpUtils.getUserAgent;
+
+
+/**
+ * Created by Horrarndoo on 2017/9/12.
+ *
+ * CacheInterceptor
+ */
+public class CacheInterceptor implements Interceptor {
+
+ @Override
+ public Response intercept(Chain chain) throws IOException {
+ Request request = chain.request();
+ if (NetworkConnectionUtils.isNetworkConnected(AppUtils.getContext())) {
+ // 有网络时, 缓存1小时
+ int maxAge = 60 * 60;
+ request = request.newBuilder()
+ .removeHeader("User-Agent")
+ .header("User-Agent", getUserAgent())
+ .build();
+
+ Response response = chain.proceed(request);
+ return response.newBuilder()
+ .removeHeader("Pragma")
+ .removeHeader("Cache-Control")
+ .header("Cache-Control", "public, max-age=" + maxAge)
+ .build();
+ } else {
+ // 无网络时,缓存为4周
+ int maxStale = 60 * 60 * 24 * 28;
+ request = request.newBuilder()
+ .cacheControl(CacheControl.FORCE_CACHE)
+ .removeHeader("User-Agent")
+ .header("User-Agent", getUserAgent())
+ .build();
+
+ Response response = chain.proceed(request);
+ return response.newBuilder()
+ .removeHeader("Pragma")
+ .removeHeader("Cache-Control")
+ .header("Cache-Control", "public, only-if-cached, max-stale=" + maxStale)
+ .build();
+ }
+
+ // Request request = chain.request();
+ // if (!NetworkConnectionUtils.isConnected(AppUtils.getContext())) {
+ // request = request.newBuilder()
+ // .cacheControl(CacheControl.FORCE_CACHE)
+ // .build();
+ // }
+ // Response response = chain.proceed(request);
+ // if (NetworkConnectionUtils.isConnected(AppUtils.getContext())) {
+ // int maxAge = 0;
+ // // 有网络时, 不缓存, 最大保存时长为0
+ // response.newBuilder()
+ // .header("Cache-Control", "public, max-age=" + maxAge)
+ // .removeHeader("Pragma")
+ // .build();
+ // } else {
+ // // 无网络时,设置超时为4周
+ // int maxStale = 60 * 60 * 24 * 28;
+ // response.newBuilder()
+ // .header("Cache-Control", "public, only-if-cached, max-stale=" +
+ // maxStale)
+ // .removeHeader("Pragma")
+ // .build();
+ // }
+ // return response;
+ }
+}
diff --git a/mvpsdk/src/main/java/com/share/mvpsdk/helper/okhttp/HttpCache.java b/mvpsdk/src/main/java/com/share/mvpsdk/helper/okhttp/HttpCache.java
new file mode 100644
index 0000000..5c56799
--- /dev/null
+++ b/mvpsdk/src/main/java/com/share/mvpsdk/helper/okhttp/HttpCache.java
@@ -0,0 +1,28 @@
+package com.share.mvpsdk.helper.okhttp;
+
+
+import android.os.Environment;
+
+import com.share.mvpsdk.utils.AppUtils;
+
+import java.io.File;
+
+import okhttp3.Cache;
+
+/**
+ * Created by Horrarndoo on 2017/9/12.
+ *
+ */
+public class HttpCache {
+
+ private static final int HTTP_RESPONSE_DISK_CACHE_MAX_SIZE = 50 * 1024 * 1024;
+
+ public static Cache getCache() {
+ File file=new File(Environment.getExternalStorageDirectory() + File
+ .separator + "data/NetCache");
+ if (!file.getParentFile().exists())file.getParentFile().mkdirs();
+ if (!file.exists())file.mkdirs();
+ return new Cache(file,
+ HTTP_RESPONSE_DISK_CACHE_MAX_SIZE);
+ }
+}
diff --git a/mvpsdk/src/main/java/com/share/mvpsdk/helper/okhttp/NetInterceptor.java b/mvpsdk/src/main/java/com/share/mvpsdk/helper/okhttp/NetInterceptor.java
new file mode 100644
index 0000000..7add9d8
--- /dev/null
+++ b/mvpsdk/src/main/java/com/share/mvpsdk/helper/okhttp/NetInterceptor.java
@@ -0,0 +1,49 @@
+package com.share.mvpsdk.helper.okhttp;
+
+
+import com.share.mvpsdk.utils.AppUtils;
+import com.share.mvpsdk.utils.NetworkConnectionUtils;
+
+import java.io.IOException;
+
+import okhttp3.Interceptor;
+import okhttp3.Request;
+import okhttp3.Response;
+
+import static com.share.mvpsdk.utils.HttpUtils.getUserAgent;
+
+
+/**
+ * Created by Horrarndoo on 2017/9/18.
+ *
+ * 有网络时的缓存拦截器
+ */
+
+public class NetInterceptor implements Interceptor{
+ @Override
+ public Response intercept(Chain chain) throws IOException {
+ // 有网络时, 缓存1分钟, 最大保存时长为60s
+ int maxAge = 60;
+ Request request = chain.request();
+
+ if (NetworkConnectionUtils.isNetworkConnected(AppUtils.getContext())) {
+ request = request.newBuilder()
+ .removeHeader("User-Agent")
+ .header("User-Agent", getUserAgent())
+ // .header("User-Agent", "Mozilla/5.0 (Windows NT 6.1;
+ // WOW64) AppleWebKit/537.36" +
+ // " (KHTML, like Gecko) Chrome/50.0.2661.102
+ // Safari/537.36")
+ .build();
+
+ Response response = chain.proceed(request);
+ return response.newBuilder()
+ .removeHeader("Pragma")
+ .removeHeader("Cache-Control")
+ .header("Cache-Control", "public, max-age=" + maxAge)
+ .build();
+ }
+
+ return chain.proceed(request);
+ }
+}
diff --git a/mvpsdk/src/main/java/com/share/mvpsdk/helper/okhttp/NoNetInterceptor.java b/mvpsdk/src/main/java/com/share/mvpsdk/helper/okhttp/NoNetInterceptor.java
new file mode 100644
index 0000000..6f82e97
--- /dev/null
+++ b/mvpsdk/src/main/java/com/share/mvpsdk/helper/okhttp/NoNetInterceptor.java
@@ -0,0 +1,50 @@
+package com.share.mvpsdk.helper.okhttp;
+
+
+import com.share.mvpsdk.utils.AppUtils;
+import com.share.mvpsdk.utils.NetworkConnectionUtils;
+
+import java.io.IOException;
+
+import okhttp3.CacheControl;
+import okhttp3.Interceptor;
+import okhttp3.Request;
+import okhttp3.Response;
+
+import static com.share.mvpsdk.utils.HttpUtils.getUserAgent;
+
+/**
+ * Created by Horrarndoo on 2017/9/18.
+ *
+ * 无网络时的缓存拦截器
+ */
+
+public class NoNetInterceptor implements Interceptor {
+ @Override
+ public Response intercept(Chain chain) throws IOException {
+ // 无网络时,设置超时为4周
+ int maxStale = 60 * 60 * 24 * 28;
+ Request request = chain.request();
+
+ if (!NetworkConnectionUtils.isNetworkConnected(AppUtils.getContext())) {
+ request = request.newBuilder()
+ .cacheControl(CacheControl.FORCE_CACHE)
+ .removeHeader("User-Agent")
+ .header("User-Agent", getUserAgent())
+ // .header("User-Agent", "Mozilla/5.0 (Windows NT 6.1;
+ // WOW64) AppleWebKit/537.36" +
+ // " (KHTML, like Gecko) Chrome/50.0.2661.102
+ // Safari/537.36")
+ .build();
+
+ Response response = chain.proceed(request);
+ return response.newBuilder()
+ .removeHeader("Pragma")
+ .removeHeader("Cache-Control")
+ .header("Cache-Control", "public, only-if-cached, max-stale=" + maxStale)
+ .build();
+ }
+
+ return chain.proceed(request);
+ }
+}
diff --git a/mvpsdk/src/main/java/com/share/mvpsdk/helper/okhttp/TrustManager.java b/mvpsdk/src/main/java/com/share/mvpsdk/helper/okhttp/TrustManager.java
new file mode 100644
index 0000000..cc35751
--- /dev/null
+++ b/mvpsdk/src/main/java/com/share/mvpsdk/helper/okhttp/TrustManager.java
@@ -0,0 +1,54 @@
+package com.share.mvpsdk.helper.okhttp;
+
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSocketFactory;
+import javax.net.ssl.X509TrustManager;
+
+/**
+ * Created by Horrarndoo on 2017/9/12.
+ *
+ */
+public class TrustManager {
+
+ public static SSLSocketFactory getUnsafeOkHttpClient() {
+ try {
+ // Create a trust manager that does not validate certificate chains
+ final X509TrustManager[] trustAllCerts = new X509TrustManager[]{new X509TrustManager() {
+ @Override
+ public void checkClientTrusted(
+ X509Certificate[] chain,
+ String authType) throws CertificateException {
+ }
+
+ @Override
+ public void checkServerTrusted(
+ X509Certificate[] chain,
+ String authType) throws CertificateException {
+ }
+
+ @Override
+ public X509Certificate[] getAcceptedIssuers() {
+ return new X509Certificate[0];
+ }
+ }};
+
+ // Install the all-trusting trust manager
+ final SSLContext sslContext = SSLContext.getInstance("TLS");
+ sslContext.init(null, trustAllCerts,
+ new java.security.SecureRandom());
+ // Create an ssl socket factory with our all-trusting manager
+ final SSLSocketFactory sslSocketFactory = sslContext
+ .getSocketFactory();
+
+
+ return sslSocketFactory;
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+
+ }
+}
+
diff --git a/mvpsdk/src/main/java/com/share/mvpsdk/rxbus/BusData.java b/mvpsdk/src/main/java/com/share/mvpsdk/rxbus/BusData.java
new file mode 100644
index 0000000..1e06a74
--- /dev/null
+++ b/mvpsdk/src/main/java/com/share/mvpsdk/rxbus/BusData.java
@@ -0,0 +1,34 @@
+package com.share.mvpsdk.rxbus;
+
+/**
+ * RxBus data
+ * Created by gorden on 2016/7/8.
+ */
+public class BusData {
+ String id;
+ String status;
+
+ public BusData() {
+ }
+
+ public BusData(String id, String status) {
+ this.id = id;
+ this.status = status;
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public String getStatus() {
+ return status;
+ }
+
+ public void setStatus(String status) {
+ this.status = status;
+ }
+}
\ No newline at end of file
diff --git a/mvpsdk/src/main/java/com/share/mvpsdk/rxbus/RxBus.java b/mvpsdk/src/main/java/com/share/mvpsdk/rxbus/RxBus.java
new file mode 100644
index 0000000..03a440c
--- /dev/null
+++ b/mvpsdk/src/main/java/com/share/mvpsdk/rxbus/RxBus.java
@@ -0,0 +1,355 @@
+package com.share.mvpsdk.rxbus;
+
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import io.reactivex.BackpressureStrategy;
+import io.reactivex.Flowable;
+import io.reactivex.Scheduler;
+import io.reactivex.android.schedulers.AndroidSchedulers;
+import io.reactivex.disposables.Disposable;
+import io.reactivex.functions.Consumer;
+import io.reactivex.functions.Function;
+import io.reactivex.functions.Predicate;
+import io.reactivex.schedulers.Schedulers;
+import io.reactivex.subjects.PublishSubject;
+import io.reactivex.subjects.Subject;
+
+/**
+ * RxBus
+ * Created by gorden on 2016/5/12.
+ * update 2017/3/1
+ */
+@SuppressWarnings("unused")
+public class RxBus {
+ public static final String LOG_BUS = "RXBUS_LOG";
+ private static volatile RxBus defaultInstance;
+
+ private Map> subscriptionsByEventType = new HashMap<>();
+
+ private Map> eventTypesBySubscriber = new HashMap<>();
+
+ private Map> subscriberMethodByEventType = new HashMap<>();
+
+ private final Subject bus;
+
+ private RxBus() {
+ this.bus = PublishSubject.create().toSerialized();
+ }
+
+ public static RxBus get() {
+ RxBus rxBus = defaultInstance;
+ if (defaultInstance == null) {
+ synchronized (RxBus.class) {
+ rxBus = defaultInstance;
+ if (defaultInstance == null) {
+ rxBus = new RxBus();
+ defaultInstance = rxBus;
+ }
+ }
+ }
+ return rxBus;
+ }
+
+ /**
+ * 根据传递的 eventType 类型返回特定类型(eventType)的 被观察者
+ *
+ * @param eventType 事件类型
+ * @return return
+ */
+ private Flowable toObservable(Class eventType) {
+ return bus.toFlowable(BackpressureStrategy.BUFFER).ofType(eventType);
+ }
+
+ /**
+ * 根据传递的code和 eventType 类型返回特定类型(eventType)的 被观察者
+ *
+ * @param code 事件code
+ * @param eventType 事件类型
+ */
+ private Flowable toObservable(final int code, final Class eventType) {
+ return bus.toFlowable(BackpressureStrategy.BUFFER).ofType(Message.class)
+ .filter(new Predicate() {
+ @Override
+ public boolean test(Message o) throws Exception {
+ return o.getCode() == code && eventType.isInstance(o.getObject());
+ }
+ }).map(new Function() {
+ @Override
+ public Object apply(Message o) throws Exception {
+ return o.getObject();
+ }
+ }).cast(eventType);
+ }
+
+ /**
+ * 注册
+ *
+ * @param subscriber 订阅者
+ */
+ public void register(Object subscriber) {
+ Class> subClass = subscriber.getClass();
+ Method[] methods = subClass.getDeclaredMethods();
+ for (Method method : methods) {
+ if (method.isAnnotationPresent(Subscribe.class)) {
+ //获得参数类型
+ Class[] parameterType = method.getParameterTypes();
+ //参数不为空 且参数个数为1
+ if (parameterType != null && parameterType.length == 1) {
+
+ Class eventType = parameterType[0];
+
+ addEventTypeToMap(subscriber, eventType);
+ Subscribe sub = method.getAnnotation(Subscribe.class);
+ int code = sub.code();
+ ThreadMode threadMode = sub.threadMode();
+
+ SubscriberMethod subscriberMethod = new SubscriberMethod(subscriber, method, eventType, code, threadMode);
+ addSubscriberToMap(eventType, subscriberMethod);
+
+ addSubscriber(subscriberMethod);
+ } else if (parameterType == null || parameterType.length == 0) {
+
+ Class eventType = BusData.class;
+
+ addEventTypeToMap(subscriber, eventType);
+ Subscribe sub = method.getAnnotation(Subscribe.class);
+ int code = sub.code();
+ ThreadMode threadMode = sub.threadMode();
+
+ SubscriberMethod subscriberMethod = new SubscriberMethod(subscriber, method, eventType, code, threadMode);
+ addSubscriberToMap(eventType, subscriberMethod);
+
+ addSubscriber(subscriberMethod);
+
+ }
+ }
+ }
+ }
+
+
+ /**
+ * 将event的类型以订阅中subscriber为key保存到map里
+ *
+ * @param subscriber 订阅者
+ * @param eventType event类型
+ */
+ private void addEventTypeToMap(Object subscriber, Class eventType) {
+ List eventTypes = eventTypesBySubscriber.get(subscriber);
+ if (eventTypes == null) {
+ eventTypes = new ArrayList<>();
+ eventTypesBySubscriber.put(subscriber, eventTypes);
+ }
+
+ if (!eventTypes.contains(eventType)) {
+ eventTypes.add(eventType);
+ }
+ }
+
+ /**
+ * 将注解方法信息以event类型为key保存到map中
+ *
+ * @param eventType event类型
+ * @param subscriberMethod 注解方法信息
+ */
+ private void addSubscriberToMap(Class eventType, SubscriberMethod subscriberMethod) {
+ List subscriberMethods = subscriberMethodByEventType.get(eventType);
+ if (subscriberMethods == null) {
+ subscriberMethods = new ArrayList<>();
+ subscriberMethodByEventType.put(eventType, subscriberMethods);
+ }
+
+ if (!subscriberMethods.contains(subscriberMethod)) {
+ subscriberMethods.add(subscriberMethod);
+ }
+ }
+
+ /**
+ * 将订阅事件以event类型为key保存到map,用于取消订阅时用
+ *
+ * @param eventType event类型
+ * @param disposable 订阅事件
+ */
+ private void addSubscriptionToMap(Class eventType, Disposable disposable) {
+ List disposables = subscriptionsByEventType.get(eventType);
+ if (disposables == null) {
+ disposables = new ArrayList<>();
+ subscriptionsByEventType.put(eventType, disposables);
+ }
+
+ if (!disposables.contains(disposable)) {
+ disposables.add(disposable);
+ }
+ }
+
+ /**
+ * 用RxJava添加订阅者
+ *
+ * @param subscriberMethod d
+ */
+ @SuppressWarnings("unchecked")
+ private void addSubscriber(final SubscriberMethod subscriberMethod) {
+ Flowable flowable;
+ if (subscriberMethod.code == -1) {
+ flowable = toObservable(subscriberMethod.eventType);
+ } else {
+ flowable = toObservable(subscriberMethod.code, subscriberMethod.eventType);
+ }
+ Disposable subscription = postToObservable(flowable, subscriberMethod)
+ .subscribe(new Consumer() {
+ @Override
+ public void accept(Object o) throws Exception {
+ callEvent(subscriberMethod, o);
+ }
+ });
+
+ addSubscriptionToMap(subscriberMethod.subscriber.getClass(), subscription);
+ }
+
+ /**
+ * 用于处理订阅事件在那个线程中执行
+ *
+ * @param observable d
+ * @param subscriberMethod d
+ * @return Observable
+ */
+ private Flowable postToObservable(Flowable observable, SubscriberMethod subscriberMethod) {
+ Scheduler scheduler;
+ switch (subscriberMethod.threadMode) {
+ case MAIN:
+ scheduler = AndroidSchedulers.mainThread();
+ break;
+
+ case NEW_THREAD:
+ scheduler = Schedulers.newThread();
+ break;
+
+ case CURRENT_THREAD:
+ scheduler = Schedulers.trampoline();
+ break;
+ default:
+ throw new IllegalStateException("Unknown thread mode: " + subscriberMethod.threadMode);
+ }
+ return observable.observeOn(scheduler);
+ }
+
+ /**
+ * 回调到订阅者的方法中
+ *
+ * @param method code
+ * @param object obj
+ */
+ private void callEvent(SubscriberMethod method, Object object) {
+ Class eventClass = object.getClass();
+ List methods = subscriberMethodByEventType.get(eventClass);
+ if (methods != null && methods.size() > 0) {
+ for (SubscriberMethod subscriberMethod : methods) {
+ Subscribe sub = subscriberMethod.method.getAnnotation(Subscribe.class);
+ int c = sub.code();
+ if (c == method.code && method.subscriber.equals(subscriberMethod.subscriber) && method.method.equals(subscriberMethod.method)) {
+ subscriberMethod.invoke(object);
+ }
+
+ }
+ }
+ }
+
+ /**
+ * 取消注册
+ *
+ * @param subscriber object
+ */
+ public void unRegister(Object subscriber) {
+ List subscribedTypes = eventTypesBySubscriber.get(subscriber);
+ if (subscribedTypes != null) {
+ for (Class> eventType : subscribedTypes) {
+ unSubscribeByEventType(subscriber.getClass());
+ unSubscribeMethodByEventType(subscriber, eventType);
+ }
+ eventTypesBySubscriber.remove(subscriber);
+ }
+ }
+
+ /**
+ * subscriptions unsubscribe
+ *
+ * @param eventType eventType
+ */
+ private void unSubscribeByEventType(Class eventType) {
+ List disposables = subscriptionsByEventType.get(eventType);
+ if (disposables != null) {
+ Iterator iterator = disposables.iterator();
+ while (iterator.hasNext()) {
+ Disposable disposable = iterator.next();
+ if (disposable != null && !disposable.isDisposed()) {
+ disposable.dispose();
+ iterator.remove();
+ }
+ }
+ }
+ }
+
+ /**
+ * 移除subscriber对应的subscriberMethods
+ *
+ * @param subscriber subscriber
+ * @param eventType eventType
+ */
+ private void unSubscribeMethodByEventType(Object subscriber, Class eventType) {
+ List subscriberMethods = subscriberMethodByEventType.get(eventType);
+ if (subscriberMethods != null) {
+ Iterator iterator = subscriberMethods.iterator();
+ while (iterator.hasNext()) {
+ SubscriberMethod subscriberMethod = iterator.next();
+ if (subscriberMethod.subscriber.equals(subscriber)) {
+ iterator.remove();
+ }
+ }
+ }
+ }
+
+ public void send(int code, Object o) {
+ bus.onNext(new Message(code, o));
+ }
+
+ public void send(Object o) {
+ bus.onNext(o);
+ }
+
+ public void send(int code) {
+ bus.onNext(new Message(code, new BusData()));
+ }
+
+ private class Message {
+ private int code;
+ private Object object;
+
+ public Message() {
+ }
+
+ private Message(int code, Object o) {
+ this.code = code;
+ this.object = o;
+ }
+
+ private int getCode() {
+ return code;
+ }
+
+ public void setCode(int code) {
+ this.code = code;
+ }
+
+ private Object getObject() {
+ return object;
+ }
+
+ public void setObject(Object object) {
+ this.object = object;
+ }
+ }
+}
\ No newline at end of file
diff --git a/mvpsdk/src/main/java/com/share/mvpsdk/rxbus/Subscribe.java b/mvpsdk/src/main/java/com/share/mvpsdk/rxbus/Subscribe.java
new file mode 100644
index 0000000..fa30077
--- /dev/null
+++ b/mvpsdk/src/main/java/com/share/mvpsdk/rxbus/Subscribe.java
@@ -0,0 +1,21 @@
+package com.share.mvpsdk.rxbus;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+
+/**
+ * Rxbus
+ * Created by gorden on 2016/7/23.
+ */
+@Documented
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Subscribe {
+ int code() default -1;
+
+ ThreadMode threadMode() default ThreadMode.CURRENT_THREAD;
+}
\ No newline at end of file
diff --git a/mvpsdk/src/main/java/com/share/mvpsdk/rxbus/SubscriberMethod.java b/mvpsdk/src/main/java/com/share/mvpsdk/rxbus/SubscriberMethod.java
new file mode 100644
index 0000000..f7ee260
--- /dev/null
+++ b/mvpsdk/src/main/java/com/share/mvpsdk/rxbus/SubscriberMethod.java
@@ -0,0 +1,44 @@
+package com.share.mvpsdk.rxbus;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+/**
+ *
+ * Created by gorden on 2016/7/23.
+ */
+public class SubscriberMethod {
+ public Method method;
+ public ThreadMode threadMode;
+ public Class> eventType;
+ public Object subscriber;
+ public int code;
+
+ public SubscriberMethod(Object subscriber, Method method, Class> eventType, int code,ThreadMode threadMode) {
+ this.method = method;
+ this.threadMode = threadMode;
+ this.eventType = eventType;
+ this.subscriber = subscriber;
+ this.code = code;
+ }
+
+
+ /**
+ * 调用方法
+ * @param o 参数
+ */
+ public void invoke(Object o){
+ try {
+ Class[] parameterType = method.getParameterTypes();
+ if(parameterType != null && parameterType.length == 1){
+ method.invoke(subscriber, o);
+ }else if(parameterType == null || parameterType.length == 0){
+ method.invoke(subscriber);
+ }
+ } catch (IllegalAccessException e) {
+ e.printStackTrace();
+ } catch (InvocationTargetException e) {
+ e.printStackTrace();
+ }
+ }
+}
\ No newline at end of file
diff --git a/mvpsdk/src/main/java/com/share/mvpsdk/rxbus/ThreadMode.java b/mvpsdk/src/main/java/com/share/mvpsdk/rxbus/ThreadMode.java
new file mode 100644
index 0000000..e21d5bb
--- /dev/null
+++ b/mvpsdk/src/main/java/com/share/mvpsdk/rxbus/ThreadMode.java
@@ -0,0 +1,23 @@
+package com.share.mvpsdk.rxbus;
+
+/**
+ *
+ * Created by gorden on 2016/7/23.
+ */
+public enum ThreadMode {
+ /**
+ * current thread
+ */
+ CURRENT_THREAD,
+
+ /**
+ * android main thread
+ */
+ MAIN,
+
+
+ /**
+ * new thread
+ */
+ NEW_THREAD
+}
diff --git a/mvpsdk/src/main/java/com/share/mvpsdk/utils/AppUtils.java b/mvpsdk/src/main/java/com/share/mvpsdk/utils/AppUtils.java
new file mode 100644
index 0000000..1589c75
--- /dev/null
+++ b/mvpsdk/src/main/java/com/share/mvpsdk/utils/AppUtils.java
@@ -0,0 +1,185 @@
+package com.share.mvpsdk.utils;
+
+import android.annotation.SuppressLint;
+import android.content.ClipData;
+import android.content.ClipboardManager;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.net.Uri;
+import android.os.Environment;
+import android.os.Handler;
+import android.telephony.TelephonyManager;
+import android.util.Log;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.EditText;
+
+
+import com.share.mvpsdk.global.GlobalApplication;
+
+import java.io.File;
+
+import timber.log.Timber;
+
+/**
+ * Created by Horrarndoo on 2017/8/31.
+ *
+ * App工具类
+ */
+public class AppUtils {
+
+ /**
+ * 获取上下文对象
+ *
+ * @return 上下文对象
+ */
+ public static Context getContext() {
+ return GlobalApplication.getContext();
+ }
+
+ /**
+ * 获取全局handler
+ *
+ * @return 全局handler
+ */
+ public static Handler getHandler() {
+ return GlobalApplication.getHandler();
+ }
+
+ /**
+ * 获取主线程id
+ *
+ * @return 主线程id
+ */
+ public static int getMainThreadId() {
+ return GlobalApplication.getMainThreadId();
+ }
+
+ /**
+ * 获取版本名称
+ */
+ public static String getAppVersionName(Context context) {
+ String versionName = "";
+ try {
+ // ---get the package info---
+ PackageManager pm = context.getPackageManager();
+ PackageInfo pi = pm.getPackageInfo(context.getPackageName(), 0);
+ versionName = pi.versionName;
+ if (versionName == null || versionName.length() <= 0) {
+ return "";
+ }
+ } catch (Exception e) {
+ Log.e("VersionInfo", "Exception", e);
+ }
+ return versionName;
+ }
+
+ /**
+ * 获取版本号
+ */
+ public static int getAppVersionCode(Context context) {
+ int versioncode = -1;
+ try {
+ // ---get the package info---
+ PackageManager pm = context.getPackageManager();
+ PackageInfo pi = pm.getPackageInfo(context.getPackageName(), 0);
+ versioncode = pi.versionCode;
+ } catch (Exception e) {
+ Log.e("VersionInfo", "Exception", e);
+ }
+ return versioncode;
+ }
+
+ @SuppressLint("MissingPermission")
+ public static String getIMEI(Context context) {
+ TelephonyManager tm = (TelephonyManager) context.getSystemService(Context
+ .TELEPHONY_SERVICE);
+ return tm.getDeviceId();
+ }
+
+ /**
+ * 显示软键盘
+ */
+ public static void openSoftInput(EditText et) {
+ InputMethodManager inputMethodManager = (InputMethodManager) et.getContext()
+ .getSystemService(Context.INPUT_METHOD_SERVICE);
+ inputMethodManager.showSoftInput(et, InputMethodManager.HIDE_NOT_ALWAYS);
+ }
+
+ /**
+ * 隐藏软键盘
+ */
+ public static void hideSoftInput(EditText et) {
+ InputMethodManager inputMethodManager = (InputMethodManager) et.getContext()
+ .getSystemService(Context.INPUT_METHOD_SERVICE);
+ inputMethodManager.hideSoftInputFromWindow(et.getWindowToken(), InputMethodManager
+ .HIDE_NOT_ALWAYS);
+ }
+
+ /**
+ * 获取SD卡路径
+ *
+ * @return 如果sd卡不存在则返回null
+ */
+ public static File getSDPath() {
+ File sdDir = null;
+ boolean sdCardExist = Environment.getExternalStorageState().equals(Environment
+ .MEDIA_MOUNTED); //判断sd卡是否存在
+ if (sdCardExist) {
+ sdDir = Environment.getExternalStorageDirectory();//获取跟目录
+ }
+ return sdDir;
+ }
+
+ /**
+ * 安装文件
+ *
+ * @param data
+ */
+ public static void promptInstall(Context context, Uri data) {
+ Intent promptInstall = new Intent(Intent.ACTION_VIEW)
+ .setDataAndType(data, "application/vnd.android.package-archive");
+ // FLAG_ACTIVITY_NEW_TASK 可以保证安装成功时可以正常打开 app
+ promptInstall.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ context.startActivity(promptInstall);
+ }
+
+ public static void copy2clipboard(Context context, String text) {
+ ClipboardManager cm = (ClipboardManager) context.getSystemService(Context
+ .CLIPBOARD_SERVICE);
+ ClipData clip = ClipData.newPlainText("clip", text);
+ cm.setPrimaryClip(clip);
+ }
+
+ /**
+ * 判断是否运行在主线程
+ *
+ * @return true:当前线程运行在主线程
+ * fasle:当前线程没有运行在主线程
+ */
+ public static boolean isRunOnUIThread() {
+ // 获取当前线程id, 如果当前线程id和主线程id相同, 那么当前就是主线程
+ int myTid = android.os.Process.myTid();
+ if (myTid == getMainThreadId()) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * 运行在主线程
+ *
+ * @param r 运行的Runnable对象
+ */
+ public static void runOnUIThread(Runnable r) {
+ if (isRunOnUIThread()) {
+ // 已经是主线程, 直接运行
+ r.run();
+ } else {
+ // 如果是子线程, 借助handler让其运行在主线程
+ Log.d("66666","getHander="+getHandler()+"r="+r);
+ getHandler().post(r);
+ }
+ }
+}
diff --git a/mvpsdk/src/main/java/com/share/mvpsdk/utils/DBUtils.java b/mvpsdk/src/main/java/com/share/mvpsdk/utils/DBUtils.java
new file mode 100644
index 0000000..663b4f5
--- /dev/null
+++ b/mvpsdk/src/main/java/com/share/mvpsdk/utils/DBUtils.java
@@ -0,0 +1,108 @@
+package com.share.mvpsdk.utils;
+
+import android.content.ContentValues;
+import android.content.Context;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteOpenHelper;
+
+import com.share.mvpsdk.config.DBConfig;
+
+
+/**
+ * Created by Horrarndoo on 2017/8/31.
+ *
+ * 数据库工具类
+ */
+public class DBUtils {
+ public static final String CREATE_TABLE_IF_NOT_EXISTS = "create table if not exists %s " +
+ "(id integer primary key autoincrement,key text unique,is_read integer)";
+
+ private static DBUtils sDBUtis;
+ private SQLiteDatabase mSQLiteDatabase;
+
+ private DBUtils(Context context) {
+ mSQLiteDatabase = new DBHelper(context, DBConfig.DB_NAME + ".db")
+ .getWritableDatabase();
+ }
+
+ public static synchronized DBUtils getDB(Context context) {
+ if (sDBUtis == null) {
+ synchronized (DBUtils.class) {
+ if (sDBUtis == null)
+ sDBUtis = new DBUtils(context);
+ }
+ }
+ return sDBUtis;
+ }
+
+ /**
+ * 插入一个item已读状态到数据表
+ *
+ * @param table 数据表名
+ * @param key key值
+ * @param value 数据值
+ * @return 插入结果
+ */
+ public boolean insertRead(final String table, String key, int value) {
+ Cursor cursor = mSQLiteDatabase.query(table, null, null, null, null, null, "id asc");
+ //最多缓存200条
+ if (cursor.getCount() > 200 && cursor.moveToNext()) {
+ mSQLiteDatabase.delete(table, "id=?", new String[]{String.valueOf(cursor.getInt
+ (cursor.getColumnIndex("id")))});
+ }
+ cursor.close();
+ final ContentValues contentValues = new ContentValues();
+ contentValues.put("key", key);
+ contentValues.put("is_read", value);
+ return (mSQLiteDatabase.insertWithOnConflict(table, null, contentValues, SQLiteDatabase
+ .CONFLICT_REPLACE) > 0);
+ }
+
+ /**
+ * 判断item是否已经阅读过
+ *
+ * @param table 数据表名
+ * @param key key值
+ * @param value
+ * @return
+ */
+ public boolean isRead(String table, String key, int value) {
+ boolean isRead = false;
+ Cursor cursor = mSQLiteDatabase.query(table, null, "key=?", new String[]{key}, null,
+ null, null);
+ if (cursor.moveToNext() && (cursor.getInt(cursor.getColumnIndex("is_read")) == value)) {
+ isRead = true;
+ }
+ cursor.close();
+ return isRead;
+ }
+
+ public class DBHelper extends SQLiteOpenHelper {
+
+ public DBHelper(Context context, String name) {
+ super(context, name, null, 1);
+ }
+
+ @Override
+ public void onCreate(SQLiteDatabase db) {
+ //onCreate()方法只有数据库第一次被创建时才会调用,若数据库已存在,此方法不会被调用
+ }
+
+ @Override
+ public void onOpen(SQLiteDatabase db) {
+ super.onOpen(db);
+ //数据库打开时就会被调用,将插入新表的操作方到onOpen中
+ db.execSQL(String.format(CREATE_TABLE_IF_NOT_EXISTS, DBConfig.TABLE_ZHIHU));
+ db.execSQL(String.format(CREATE_TABLE_IF_NOT_EXISTS, DBConfig.TABLE_WANGYI));
+ db.execSQL(String.format(CREATE_TABLE_IF_NOT_EXISTS, DBConfig.TABLE_WEIXIN));
+ db.execSQL(String.format(CREATE_TABLE_IF_NOT_EXISTS, DBConfig.TABLE_GANKIO_DAY));
+ db.execSQL(String.format(CREATE_TABLE_IF_NOT_EXISTS, DBConfig.TABLE_GANKIO_CUSTOM));
+ }
+
+ @Override
+ public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+ //只有数据库进行版本升级时被调用
+ }
+ }
+}
diff --git a/mvpsdk/src/main/java/com/share/mvpsdk/utils/DateUtils.java b/mvpsdk/src/main/java/com/share/mvpsdk/utils/DateUtils.java
new file mode 100644
index 0000000..d9af2e0
--- /dev/null
+++ b/mvpsdk/src/main/java/com/share/mvpsdk/utils/DateUtils.java
@@ -0,0 +1,250 @@
+package com.share.mvpsdk.utils;
+
+import android.text.TextUtils;
+import android.text.format.DateFormat;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.Locale;
+
+/**
+ * Created by Horrarndoo on 2017/8/31.
+ *
+ * 日期时间工具类
+ */
+public class DateUtils {
+
+ public static final long ONE_SECOND_MILLIONS = 1000;
+ public static final long ONE_MINUTE_MILLIONS = 60 * ONE_SECOND_MILLIONS;
+ public static final long ONE_HOUR_MILLIONS = 60 * ONE_MINUTE_MILLIONS;
+ public static final long ONE_DAY_MILLIONS = 24 * ONE_HOUR_MILLIONS;
+ public static final int DAY_OF_YEAR = 365;
+
+ // 日期格式为 2016-02-03 17:04:58
+ public static final String PATTERN_DATE = "yyyy年MM月dd日";
+ public static final String PATTERN_TIME = "HH:mm:ss";
+ public static final String PATTERN_SPLIT = " ";
+ public static final String PATTERN = PATTERN_DATE + PATTERN_SPLIT + PATTERN_TIME;
+
+ public static String getShortTime(String dateStr) {
+ String str;
+
+ Date date = str2date(dateStr);
+ Date curDate = new Date();
+
+ long durTime = curDate.getTime() - date.getTime();
+ int dayDiff = calculateDayDiff(date, curDate);
+
+ if (durTime <= 10 * ONE_MINUTE_MILLIONS) {
+ str = "刚刚";
+ } else if (durTime < ONE_HOUR_MILLIONS) {
+ str = durTime / ONE_MINUTE_MILLIONS + "分钟前";
+ } else if (dayDiff == 0) {
+ str = durTime / ONE_HOUR_MILLIONS + "小时前";
+ } else if (dayDiff == -1) {
+ str = "昨天" + DateFormat.format("HH:mm", date);
+ } else if (isSameYear(date, curDate) && dayDiff < -1) {
+ str = DateFormat.format("MM-dd", date).toString();
+ } else {
+ str = DateFormat.format("yyyy-MM", date).toString();
+ }
+
+ return str;
+ }
+
+
+
+ /**
+ * 获取日期 PATTERN_DATE 部分
+ */
+ public static String getDate(String date) {
+ if (TextUtils.isEmpty(date) || !date.contains(PATTERN_SPLIT)) {
+ return "";
+ }
+ return date.split(PATTERN_SPLIT)[0];
+ }
+
+ /**
+ * 原有日期上累加月
+ *
+ * @return 累加后的日期 PATTERN_DATE 部分
+ */
+ public static String addMonth(String date, int moonCount) {
+ //如果date为空 就用当前时间
+ if (TextUtils.isEmpty(date)) {
+ SimpleDateFormat df = new SimpleDateFormat(PATTERN_DATE + PATTERN_SPLIT + PATTERN_TIME);
+ date = df.format(new Date());
+ }
+ Calendar calendar = str2calendar(date);
+ calendar.add(Calendar.MONTH, moonCount);
+ return getDate(calendar2str(calendar));
+ }
+
+ /**
+ * 计算天数差
+ */
+ public static int calculateDayDiff(Date targetTime, Date compareTime) {
+ boolean sameYear = isSameYear(targetTime, compareTime);
+ if (sameYear) {
+ return calculateDayDiffOfSameYear(targetTime, compareTime);
+ } else {
+ int dayDiff = 0;
+
+ // 累计年数差的整年天数
+ int yearDiff = calculateYearDiff(targetTime, compareTime);
+ dayDiff += yearDiff * DAY_OF_YEAR;
+
+ // 累计同一年内的天数
+ dayDiff += calculateDayDiffOfSameYear(targetTime, compareTime);
+
+ return dayDiff;
+ }
+ }
+
+ /**
+ * 计算同一年内的天数差
+ */
+ public static int calculateDayDiffOfSameYear(Date targetTime, Date compareTime) {
+ if (targetTime == null || compareTime == null) {
+ return 0;
+ }
+
+ Calendar tarCalendar = Calendar.getInstance();
+ tarCalendar.setTime(targetTime);
+ int tarDayOfYear = tarCalendar.get(Calendar.DAY_OF_YEAR);
+
+ Calendar compareCalendar = Calendar.getInstance();
+ compareCalendar.setTime(compareTime);
+ int comDayOfYear = compareCalendar.get(Calendar.DAY_OF_YEAR);
+
+ return tarDayOfYear - comDayOfYear;
+ }
+
+ /**
+ * 计算年数差
+ */
+ public static int calculateYearDiff(Date targetTime, Date compareTime) {
+ if (targetTime == null || compareTime == null) {
+ return 0;
+ }
+
+ Calendar tarCalendar = Calendar.getInstance();
+ tarCalendar.setTime(targetTime);
+ int tarYear = tarCalendar.get(Calendar.YEAR);
+
+ Calendar compareCalendar = Calendar.getInstance();
+ compareCalendar.setTime(compareTime);
+ int comYear = compareCalendar.get(Calendar.YEAR);
+
+ return tarYear - comYear;
+ }
+
+ /**
+ * 计算月数差
+ *
+ * @param targetTime
+ * @param compareTime
+ * @return
+ */
+ public static int calculateMonthDiff(String targetTime, String compareTime) {
+ return calculateMonthDiff(str2date(targetTime, PATTERN_DATE),
+ str2date(compareTime, PATTERN_DATE));
+ }
+
+ /**
+ * 计算月数差
+ *
+ * @param targetTime
+ * @param compareTime
+ * @return
+ */
+ public static int calculateMonthDiff(Date targetTime, Date compareTime) {
+ Calendar tarCalendar = Calendar.getInstance();
+ tarCalendar.setTime(targetTime);
+ int tarYear = tarCalendar.get(Calendar.YEAR);
+ int tarMonth = tarCalendar.get(Calendar.MONTH);
+
+ Calendar compareCalendar = Calendar.getInstance();
+ compareCalendar.setTime(compareTime);
+ int comYear = compareCalendar.get(Calendar.YEAR);
+ int comMonth = compareCalendar.get(Calendar.MONTH);
+ return ((tarYear - comYear) * 12 + tarMonth - comMonth);
+
+ }
+
+ /**
+ * 是否为同一年
+ */
+ public static boolean isSameYear(Date targetTime, Date compareTime) {
+ if (targetTime == null || compareTime == null) {
+ return false;
+ }
+
+ Calendar tarCalendar = Calendar.getInstance();
+ tarCalendar.setTime(targetTime);
+ int tarYear = tarCalendar.get(Calendar.YEAR);
+
+ Calendar compareCalendar = Calendar.getInstance();
+ compareCalendar.setTime(compareTime);
+ int comYear = compareCalendar.get(Calendar.YEAR);
+
+ return tarYear == comYear;
+ }
+
+ public static Date str2date(String str, String format) {
+ Date date = null;
+ try {
+ if (str != null) {
+ SimpleDateFormat sdf = new SimpleDateFormat(format);
+ date = sdf.parse(str);
+ }
+ } catch (ParseException e) {
+ e.printStackTrace();
+ }
+ return date;
+ }
+
+ public static Date str2date(String str) {
+ return str2date(str, PATTERN);
+ }
+
+ public static String date2str(Date date) {
+ return date2str(date, PATTERN);
+ }
+
+ public static String date2str(Date date, String format) {
+ SimpleDateFormat sdf = new SimpleDateFormat(format, Locale.CHINA);
+ return sdf.format(date);
+ }
+
+ public static Calendar str2calendar(String str) {
+ Calendar calendar = null;
+ Date date = str2date(str);
+ if (date != null) {
+ calendar = Calendar.getInstance();
+ calendar.setTime(date);
+ }
+ return calendar;
+ }
+
+
+ public static Calendar str2calendar(String str, String format) {
+ Calendar calendar = null;
+ Date date = str2date(str, format);
+ if (date != null) {
+ calendar = Calendar.getInstance();
+ calendar.setTime(date);
+ }
+ return calendar;
+ }
+
+ public static String calendar2str(Calendar calendar) {
+ return date2str(calendar.getTime());
+ }
+
+ public static String calendar2str(Calendar calendar, String format) {
+ return date2str(calendar.getTime(), format);
+ }
+}
diff --git a/mvpsdk/src/main/java/com/share/mvpsdk/utils/DialogUtils.java b/mvpsdk/src/main/java/com/share/mvpsdk/utils/DialogUtils.java
new file mode 100644
index 0000000..83d188c
--- /dev/null
+++ b/mvpsdk/src/main/java/com/share/mvpsdk/utils/DialogUtils.java
@@ -0,0 +1,60 @@
+package com.share.mvpsdk.utils;
+
+import android.app.Dialog;
+import android.app.ProgressDialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.support.v7.app.AlertDialog;
+
+import com.share.mvpsdk.R;
+
+
+/**
+ * Created by Horrarndoo on 2017/8/31.
+ *
+ * 对话框工具类, 提供常用对话框显示, 使用support.v7包内的AlertDialog样式
+ */
+public class DialogUtils {
+
+ public static Dialog createProgressDialog(Context context) {
+ return createProgressDialog(context, true);
+ }
+
+ public static Dialog createProgressDialog(Context context, boolean needCancle) {
+ ProgressDialog dialog = new ProgressDialog(context);
+ dialog.setMessage("Loading ...");
+ dialog.setCancelable(needCancle);
+ dialog.setCanceledOnTouchOutside(false);
+ return dialog;
+ }
+
+ public static Dialog showCommonDialog(Context context, String message,
+ DialogInterface.OnClickListener listener) {
+ return showCommonDialog(context, message, context.getString(R.string.dialog_positive),
+ context.getString(R.string.dialog_negative), listener);
+ }
+
+ public static Dialog showCommonDialog(Context context, String message, String positiveText,
+ String negativeText, DialogInterface.OnClickListener
+ listener) {
+ return new AlertDialog.Builder(context)
+ .setMessage(message)
+ .setPositiveButton(positiveText, listener)
+ .setNegativeButton(negativeText, null)
+ .show();
+ }
+
+ public static Dialog showConfirmDialog(Context context, String message,
+ DialogInterface.OnClickListener listener) {
+ return showConfirmDialog(context, message, context.getString(R.string.dialog_positive),
+ listener);
+ }
+
+ public static Dialog showConfirmDialog(Context context, String message, String positiveText,
+ DialogInterface.OnClickListener listener) {
+ return new AlertDialog.Builder(context)
+ .setMessage(message)
+ .setPositiveButton(positiveText, listener)
+ .show();
+ }
+}
diff --git a/mvpsdk/src/main/java/com/share/mvpsdk/utils/DisplayUtils.java b/mvpsdk/src/main/java/com/share/mvpsdk/utils/DisplayUtils.java
new file mode 100644
index 0000000..5b27e0c
--- /dev/null
+++ b/mvpsdk/src/main/java/com/share/mvpsdk/utils/DisplayUtils.java
@@ -0,0 +1,195 @@
+package com.share.mvpsdk.utils;
+
+import android.app.Activity;
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.os.Build;
+import android.renderscript.Allocation;
+import android.renderscript.Element;
+import android.renderscript.RenderScript;
+import android.renderscript.ScriptIntrinsicBlur;
+import android.util.DisplayMetrics;
+import android.view.View;
+import android.widget.ImageView;
+
+import com.bumptech.glide.Glide;
+import com.share.mvpsdk.R;
+
+import java.io.File;
+
+import jp.wasabeef.glide.transformations.BlurTransformation;
+
+/**
+ * Created by Horrarndoo on 2017/8/31.
+ *
+ * 显示相关工具类
+ */
+public class DisplayUtils {
+ /**
+ * 将px值转换为dp值
+ */
+ public static int px2dp(float pxValue) {
+ final float scale = AppUtils.getContext().getResources().getDisplayMetrics().density;
+ return (int) (pxValue / scale + 0.5f);
+ }
+
+ /**
+ * 将dp值转换为px值
+ */
+ public static int dp2px(float dpValue) {
+ final float scale = AppUtils.getContext().getResources().getDisplayMetrics().density;
+ return (int) (dpValue * scale + 0.5f);
+ }
+
+ /**
+ * 将px值转换为sp值
+ */
+ public static int px2sp(float pxValue) {
+ final float scale = AppUtils.getContext().getResources().getDisplayMetrics().scaledDensity;
+ return (int) (pxValue / scale + 0.5f);
+ }
+
+ /**
+ * 将sp值转换为px值
+ */
+ public static int sp2px(float dpValue) {
+ final float scale = AppUtils.getContext().getResources().getDisplayMetrics().scaledDensity;
+ return (int) (dpValue * scale + 0.5f);
+ }
+
+ /**
+ * 获取屏幕宽度
+ */
+ public static int getScreenWidthPixels(Activity context) {
+ DisplayMetrics metric = new DisplayMetrics();
+ context.getWindowManager().getDefaultDisplay().getMetrics(metric);
+ return metric.widthPixels;
+ }
+
+ /**
+ * 获取屏幕高度
+ */
+ public static int getScreenHeightPixels(Activity context) {
+ DisplayMetrics metric = new DisplayMetrics();
+ context.getWindowManager().getDefaultDisplay().getMetrics(metric);
+ return metric.heightPixels;
+ }
+
+ /**
+ * 将一个view转换成bitmap位图
+ *
+ * @param view 要转换的View
+ * @return view转换的bitmap
+ */
+ public static Bitmap viewToBitmap(View view) {
+ Bitmap bitmap = Bitmap.createBitmap(view.getMeasuredWidth(), view.getMeasuredHeight(),
+ Bitmap.Config.ARGB_8888);
+ view.draw(new Canvas(bitmap));
+ return bitmap;
+ }
+
+ /**
+ * 获取模糊虚化的bitmap
+ *
+ * @param context
+ * @param bitmap 要模糊的图片
+ * @param radius 模糊等级 >=0 && <=25
+ * @return
+ */
+ public static Bitmap getBlurBitmap(Context context, Bitmap bitmap, int radius) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
+ return blurBitmap(context, bitmap, radius);
+ }
+ return bitmap;
+ }
+
+ /**
+ * android系统的模糊方法
+ *
+ * @param bitmap 要模糊的图片
+ * @param radius 模糊等级 >=0 && <=25
+ */
+ public static Bitmap blurBitmap(Context context, Bitmap bitmap, int radius) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
+ //Let's create an empty bitmap with the same size of the bitmap we want to blur
+ Bitmap outBitmap = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap
+ .Config.ARGB_8888);
+ //Instantiate a new Renderscript
+ RenderScript rs = RenderScript.create(context);
+ //Create an Intrinsic Blur Script using the Renderscript
+ ScriptIntrinsicBlur blurScript = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs));
+ //Create the Allocations (in/out) with the Renderscript and the in/out bitmaps
+ Allocation allIn = Allocation.createFromBitmap(rs, bitmap);
+ Allocation allOut = Allocation.createFromBitmap(rs, outBitmap);
+ //Set the radius of the blur
+ blurScript.setRadius(radius);
+ //Perform the Renderscript
+ blurScript.setInput(allIn);
+ blurScript.forEach(allOut);
+ //Copy the final bitmap created by the out Allocation to the outBitmap
+ allOut.copyTo(outBitmap);
+ //recycle the original bitmap
+ bitmap.recycle();
+ //After finishing everything, we destroy the Renderscript.
+ rs.destroy();
+ return outBitmap;
+ } else {
+ return bitmap;
+ }
+ }
+
+ /**
+ * 显示网络虚化图片
+ *
+ * @param context context
+ * @param imgUrl 图片url
+ * @param imageView 要显示的imageview
+ */
+ public static void displayBlurImg(Context context, final String imgUrl, ImageView imageView) {
+ // "23":模糊度;"4":图片缩放4倍后再进行模糊
+ Glide.with(context)
+ .load(imgUrl)
+ .error(R.drawable.stackblur_default)
+ .placeholder(R.drawable.stackblur_default)
+ .crossFade(300)
+ .bitmapTransform(new BlurTransformation(context, 23, 4))
+ .into(imageView);
+ }
+
+ /**
+ * 显示本地虚化图片
+ *
+ * @param context context
+ * @param file 本地图片file
+ * @param imageView 要显示的imageview
+ */
+ public static void displayBlurImg(Context context, File file, ImageView imageView) {
+ // "23":模糊度;"4":图片缩放4倍后再进行模糊
+ Glide.with(context)
+ .load(file)
+ .error(R.drawable.stackblur_default)
+ .placeholder(R.drawable.stackblur_default)
+ .crossFade(300)
+ .bitmapTransform(new BlurTransformation(context, 23, 4))
+ .into(imageView);
+ }
+
+ /**
+ * 显示资源虚化图片
+ *
+ * @param context context
+ * @param resourceId 图片资源id
+ * @param imageView 要显示的imageview
+ */
+ public static void displayBlurImg(Context context, Integer resourceId, ImageView imageView) {
+ // "23":模糊度;"4":图片缩放4倍后再进行模糊
+ Glide.with(context)
+ .load(resourceId)
+ .error(R.drawable.stackblur_default)
+ .placeholder(R.drawable.stackblur_default)
+ .crossFade(300)
+ .bitmapTransform(new BlurTransformation(context, 23, 4))
+ .into(imageView);
+ }
+}
diff --git a/mvpsdk/src/main/java/com/share/mvpsdk/utils/FileUtils.java b/mvpsdk/src/main/java/com/share/mvpsdk/utils/FileUtils.java
new file mode 100644
index 0000000..fc42307
--- /dev/null
+++ b/mvpsdk/src/main/java/com/share/mvpsdk/utils/FileUtils.java
@@ -0,0 +1,291 @@
+package com.share.mvpsdk.utils;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.database.Cursor;
+import android.graphics.Bitmap;
+import android.net.Uri;
+import android.os.Environment;
+import android.provider.MediaStore;
+import android.text.TextUtils;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * Created by Horrarndoo on 2017/8/31.
+ *
+ * 读取文件工具类
+ */
+public class FileUtils {
+ private static final String TAG = "FileUtils";
+
+ /**
+ * Convert byte[] to hex string.将byte转换成int,
+ * 然后利用Integer.toHexString(int)来转换成16进制字符串。
+ *
+ * @param src byte[] data
+ * @return hex string
+ */
+ public static String bytesToHexString(byte[] src) {
+ StringBuilder stringBuilder = new StringBuilder("");
+ if (src == null || src.length <= 0) {
+ return null;
+ }
+ for (int i = 0; i < src.length; i++) {
+ int v = src[i] & 0xFF;
+ String hv = Integer.toHexString(v);
+ if (hv.length() < 2) {
+ stringBuilder.append(0);
+ }
+ stringBuilder.append(hv);
+ }
+ return stringBuilder.toString();
+ }
+
+ /**
+ * 根据文件名称和路径,获取sd卡中的文件,以File形式返回byte
+ */
+ public static File getFile(String fileName, String folder)
+ throws IOException {
+ String state = Environment.getExternalStorageState();
+ if (state.equals(Environment.MEDIA_MOUNTED)) {
+ File pathFile = new File(Environment.getExternalStorageDirectory()
+ + folder);
+ // && !pathFile .isDirectory()
+ if (!pathFile.exists()) {
+ pathFile.mkdirs();
+ }
+ File file = new File(pathFile, fileName);
+ return file;
+ }
+ return null;
+ }
+
+ /**
+ * 根据文件名称和路径,获取sd卡中的文件,判断文件是否存在,存在返回true
+ */
+ public static Boolean checkFile(String fileName, String folder)
+ throws IOException {
+
+ File targetFile = getFile(fileName, folder);
+
+ if (!targetFile.exists()) {
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ /**
+ * 根据Uri返回文件绝对路径
+ * 兼容了file:///开头的 和 content://开头的情况
+ */
+ public static String getRealFilePathFromUri(final Context context, final Uri uri) {
+ if (null == uri)
+ return null;
+ final String scheme = uri.getScheme();
+ String data = null;
+ if (scheme == null) {
+ data = uri.getPath();
+ } else if (ContentResolver.SCHEME_FILE.equalsIgnoreCase(scheme)) {
+ data = uri.getPath();
+ } else if (ContentResolver.SCHEME_CONTENT.equalsIgnoreCase(scheme)) {
+ Cursor cursor = context.getContentResolver().query(uri, new String[]{MediaStore
+ .Images.ImageColumns.DATA}, null, null, null);
+ if (null != cursor) {
+ if (cursor.moveToFirst()) {
+ int index = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA);
+ if (index > -1) {
+ data = cursor.getString(index);
+ }
+ }
+ cursor.close();
+ }
+ }
+ return data;
+ }
+
+ /**
+ * 检查文件是否存在
+ */
+ public static String checkDirPath(String dirPath) {
+ if (TextUtils.isEmpty(dirPath)) {
+ return "";
+ }
+ File dir = new File(dirPath);
+ if (!dir.exists()) {
+ dir.mkdirs();
+ }
+ return dirPath;
+ }
+
+ public static void copyFile(File sourcefile, File targetFile) {
+ FileInputStream input = null;
+ BufferedInputStream inbuff = null;
+ FileOutputStream out = null;
+ BufferedOutputStream outbuff = null;
+
+ try {
+
+ input = new FileInputStream(sourcefile);
+ inbuff = new BufferedInputStream(input);
+
+ out = new FileOutputStream(targetFile);
+ outbuff = new BufferedOutputStream(out);
+
+ byte[] b = new byte[1024 * 5];
+ int len = 0;
+ while ((len = inbuff.read(b)) != -1) {
+ outbuff.write(b, 0, len);
+ }
+ outbuff.flush();
+ } catch (Exception ex) {
+ } finally {
+ try {
+ if (inbuff != null)
+ inbuff.close();
+ if (outbuff != null)
+ outbuff.close();
+ if (out != null)
+ out.close();
+ if (input != null)
+ input.close();
+ } catch (Exception ex) {
+
+ }
+ }
+ }
+
+ /**
+ * 保存图片到本机
+ *
+ * @param context context
+ * @param fileName 文件名
+ * @param file file
+ * @param saveResultCallback 保存结果callback
+ */
+ public static void saveImage(final Context context, final String fileName, final File file,
+ final SaveResultCallback saveResultCallback) {
+ new Thread(new Runnable() {
+ @Override
+ public void run() {
+ File appDir = new File(Environment.getExternalStorageDirectory(), "yizhi");
+ if (!appDir.exists()) {
+ appDir.mkdir();
+ }
+ String saveFileName = "yizhi_pic";
+ if (fileName.contains(".png") || fileName.contains(".gif")) {
+ String fileFormat = fileName.substring(fileName.lastIndexOf("."));
+ saveFileName = MD5Utils.getMD5("yizhi_pic" + fileName) + fileFormat;
+ } else {
+ saveFileName = MD5Utils.getMD5("yizhi_pic" + fileName) + ".png";
+ }
+ saveFileName = saveFileName.substring(20);//取前20位作为SaveName
+ File savefile = new File(appDir, saveFileName);
+ try {
+ InputStream is = new FileInputStream(file);
+ FileOutputStream fos = new FileOutputStream(savefile);
+ byte[] buffer = new byte[1024 * 1024];//1M缓冲区
+ int count = 0;
+ while ((count = is.read(buffer)) > 0) {
+ fos.write(buffer, 0, count);
+ }
+ fos.close();
+ is.close();
+ saveResultCallback.onSavedSuccess();
+ } catch (FileNotFoundException e) {
+ saveResultCallback.onSavedFailed();
+ e.printStackTrace();
+ } catch (IOException e) {
+ saveResultCallback.onSavedFailed();
+ e.printStackTrace();
+ }
+ //保存图片后发送广播通知更新数据库
+ Uri uri = Uri.fromFile(savefile);
+ context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, uri));
+ }
+ }).start();
+ }
+
+ /**
+ * 保存Bitmap到本机
+ *
+ * @param context context
+ * @param fileName bitmap文件名
+ * @param bmp bitmap
+ * @param saveResultCallback 保存结果callback
+ */
+ public static void saveBitmap(final Context context, final String fileName, final Bitmap bmp,
+ final SaveResultCallback
+ saveResultCallback) {
+ new Thread(new Runnable() {
+ @Override
+ public void run() {
+ File appDir = new File(Environment.getExternalStorageDirectory(), "yizhi");
+ if (!appDir.exists()) {
+ appDir.mkdir();
+ }
+ // SimpleDateFormat df = new SimpleDateFormat("yyyyMMddHHmmss");
+ // 设置以当前时间格式为图片名称
+ String saveFileName = MD5Utils.getMD5("yizhi_pic" + fileName) + ".png";
+ saveFileName = saveFileName.substring(20);//取前20位作为SaveName
+ File file = new File(appDir, saveFileName);
+ try {
+ FileOutputStream fos = new FileOutputStream(file);
+ bmp.compress(Bitmap.CompressFormat.PNG, 100, fos);
+ fos.flush();
+ fos.close();
+ saveResultCallback.onSavedSuccess();
+ } catch (FileNotFoundException e) {
+ saveResultCallback.onSavedFailed();
+ e.printStackTrace();
+ } catch (IOException e) {
+ saveResultCallback.onSavedFailed();
+ e.printStackTrace();
+ }
+ //保存图片后发送广播通知更新数据库
+ Uri uri = Uri.fromFile(file);
+ context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, uri));
+ }
+ }).start();
+ }
+
+ //保存webview缓存的
+ public static String getCache() {
+ String cacheFilePath=Environment.getExternalStorageDirectory()+File.separator+"Cache";
+ File cacheFile=new File(cacheFilePath);
+ if (!cacheFile.exists())cacheFile.mkdirs();
+ return cacheFile.toString();
+ }
+
+ public static boolean webViewCacheIsExit(){
+ File file=new File(getCache());
+ FileInputStream fileInputStream=null;
+ try {
+ fileInputStream=new FileInputStream(file);
+ if (fileInputStream.available()>0)
+ return true;
+ } catch (FileNotFoundException e) {
+ e.printStackTrace();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return false;
+ }
+
+ public interface SaveResultCallback {
+ void onSavedSuccess();
+
+ void onSavedFailed();
+ }
+}
+
+
diff --git a/mvpsdk/src/main/java/com/share/mvpsdk/utils/HtmlUtils.java b/mvpsdk/src/main/java/com/share/mvpsdk/utils/HtmlUtils.java
new file mode 100644
index 0000000..74c1402
--- /dev/null
+++ b/mvpsdk/src/main/java/com/share/mvpsdk/utils/HtmlUtils.java
@@ -0,0 +1,93 @@
+package com.share.mvpsdk.utils;
+
+import java.util.List;
+
+/**
+ * Created by Horrarndoo on 2017/8/31.
+ *
+ * Html工具类
+ */
+public class HtmlUtils {
+
+ //css样式,隐藏header
+ private static final String HIDE_HEADER_STYLE = "";
+
+ //css style tag,需要格式化
+ private static final String NEEDED_FORMAT_CSS_TAG = " ";
+
+ // js script tag,需要格式化
+ private static final String NEEDED_FORMAT_JS_TAG = "";
+
+ public static final String MIME_TYPE = "text/html; charset=utf-8";
+
+ public static final String ENCODING = "utf-8";
+
+ private HtmlUtils() {
+
+ }
+
+ /**
+ * 根据css链接生成Link标签
+ *
+ * @param url String
+ * @return String
+ */
+ public static String createCssTag(String url) {
+
+ return String.format(NEEDED_FORMAT_CSS_TAG, url);
+ }
+
+ /**
+ * 根据多个css链接生成Link标签
+ *
+ * @param urls List
+ * @return String
+ */
+ public static String createCssTag(List urls) {
+
+ final StringBuilder sb = new StringBuilder();
+ for (String url : urls) {
+ sb.append(createCssTag(url));
+ }
+ return sb.toString();
+ }
+
+ /**
+ * 根据js链接生成Script标签
+ *
+ * @param url String
+ * @return String
+ */
+ public static String createJsTag(String url) {
+
+ return String.format(NEEDED_FORMAT_JS_TAG, url);
+ }
+
+ /**
+ * 根据多个js链接生成Script标签
+ *
+ * @param urls List
+ * @return String
+ */
+ public static String createJsTag(List urls) {
+
+ final StringBuilder sb = new StringBuilder();
+ for (String url : urls) {
+ sb.append(createJsTag(url));
+ }
+ return sb.toString();
+ }
+
+ /**
+ * 根据样式标签,html字符串,js标签
+ * 生成完整的HTML文档
+ */
+
+ public static String createHtmlData(String html, List cssList, List jsList) {
+ final String css = HtmlUtils.createCssTag(cssList);
+ final String js = HtmlUtils.createJsTag(jsList);
+ return css.concat(HIDE_HEADER_STYLE).concat(html).concat(js);
+ }
+}
+
diff --git a/mvpsdk/src/main/java/com/share/mvpsdk/utils/HttpUtils.java b/mvpsdk/src/main/java/com/share/mvpsdk/utils/HttpUtils.java
new file mode 100644
index 0000000..de47e25
--- /dev/null
+++ b/mvpsdk/src/main/java/com/share/mvpsdk/utils/HttpUtils.java
@@ -0,0 +1,76 @@
+package com.share.mvpsdk.utils;
+
+import android.os.Build;
+import android.support.annotation.NonNull;
+import android.webkit.WebSettings;
+
+import com.orhanobut.logger.Logger;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Created by Horrarndoo on 2017/9/18.
+ *
+ * HttpUtils 主要用于获取UserAgent
+ */
+
+public class HttpUtils {
+ /**
+ * 获取UserAgent
+ *
+ * @return UserAgent
+ */
+ @NonNull
+ public static String getUserAgent() {
+ String userAgent = "";
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
+ try {
+ userAgent = WebSettings.getDefaultUserAgent(AppUtils.getContext());
+ } catch (Exception e) {
+ userAgent = System.getProperty("http.agent");
+ }
+ } else {
+ userAgent = System.getProperty("http.agent");
+ }
+ StringBuffer sb = new StringBuffer();
+ for (int i = 0, length = userAgent.length(); i < length; i++) {
+ char c = userAgent.charAt(i);
+ if (c <= '\u001f' || c >= '\u007f') {
+ sb.append(String.format("\\u%04x", (int) c));
+ } else {
+ sb.append(c);
+ }
+ }
+ return sb.toString();
+ }
+
+ public static String makeUA() {
+ final String ua = Build.BRAND + "/" + Build.MODEL + "/" + Build.VERSION.RELEASE;
+ return ua;
+ }
+
+ public static String[] returnImageUrlsFromHtml(String html) {
+ List imageSrcList = new ArrayList();
+ Pattern p = Pattern.compile(" ]*\\bsrc\\b\\s*=\\s*('|\")?([^'\"\n\r\f>]+(\\" +
+ ".jpg|\\.bmp|\\.eps|\\.gif|\\.mif|\\.miff|\\.png|\\.tif|\\.tiff|\\.svg|\\.wmf|\\" +
+ ".jpe|\\.jpeg|\\.dib|\\.ico|\\.tga|\\.cut|\\.pic|\\b)\\b)[^>]*>", Pattern
+ .CASE_INSENSITIVE);
+ Matcher m = p.matcher(html);
+ String quote = null;
+ String src = null;
+ while (m.find()) {
+ quote = m.group(1);
+ src = (quote == null || quote.trim().length() == 0) ? m.group(2).split("//s+")[0] : m
+ .group(2);
+ imageSrcList.add(src);
+ }
+ if (imageSrcList.size() == 0) {
+ Logger.e("资讯中未匹配到图片链接");
+ return null;
+ }
+ return imageSrcList.toArray(new String[imageSrcList.size()]);
+ }
+}
diff --git a/mvpsdk/src/main/java/com/share/mvpsdk/utils/IOUtils.java b/mvpsdk/src/main/java/com/share/mvpsdk/utils/IOUtils.java
new file mode 100644
index 0000000..32b2f04
--- /dev/null
+++ b/mvpsdk/src/main/java/com/share/mvpsdk/utils/IOUtils.java
@@ -0,0 +1,25 @@
+package com.share.mvpsdk.utils;
+
+import java.io.Closeable;
+import java.io.IOException;
+
+/**
+ * Created by Horrarndoo on 2017/8/31.
+ *
+ * IO流工具类
+ */
+public class IOUtils {
+ /**
+ * 关闭流
+ */
+ public static boolean close(Closeable io) {
+ if (io != null) {
+ try {
+ io.close();
+ } catch (IOException e) {
+ LogUtils.e(e);
+ }
+ }
+ return true;
+ }
+}
diff --git a/mvpsdk/src/main/java/com/share/mvpsdk/utils/ImageUtils.java b/mvpsdk/src/main/java/com/share/mvpsdk/utils/ImageUtils.java
new file mode 100644
index 0000000..d423900
--- /dev/null
+++ b/mvpsdk/src/main/java/com/share/mvpsdk/utils/ImageUtils.java
@@ -0,0 +1,339 @@
+package com.share.mvpsdk.utils;
+
+import android.annotation.TargetApi;
+import android.app.Activity;
+import android.content.ContentUris;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Build;
+import android.os.Environment;
+import android.provider.DocumentsContract;
+import android.provider.MediaStore;
+import android.support.v7.app.AlertDialog;
+
+import com.bumptech.glide.Glide;
+import com.bumptech.glide.request.FutureTarget;
+
+import io.reactivex.Observable;
+import io.reactivex.ObservableSource;
+import io.reactivex.functions.Function;
+
+/**
+ * 图片工具类
+ */
+public class ImageUtils {
+
+ /**
+ * 拍照
+ */
+ public static final int REQUEST_CODE_FROM_CAMERA = 1 << 10;
+
+ /**
+ * 相册
+ */
+ public static final int REQUEST_CODE_FROM_ALBUM = 1 << 12;
+
+ /**
+ * 裁剪
+ */
+ public static final int REQUEST_CODE_CROP_IMAGE = 1 << 14;
+
+ /**
+ * 存放拍照图片的uri地址
+ */
+ public static Uri imageUriFromCamera;
+
+ /**
+ * 存放裁剪图片的uri地址
+ */
+ public static Uri cropImageUri;
+
+ /**
+ * 显示获取照片不同方式对话框
+ */
+ public static void showImagePickDialog(final Activity activity) {
+ showImagePickDialog(activity, 0);
+ }
+
+ /**
+ * 显示获取照片不同方式对话框
+ */
+ public static void showImagePickDialog(final Activity activity, final int addRequest) {
+ String title = "选择获取图片方式";
+ String[] items = new String[]{"拍照", "相册"};
+ new AlertDialog.Builder(activity)
+ .setTitle(title)
+ .setItems(items, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ dialog.dismiss();
+ switch (which) {
+ case 0:
+ pickImageFromCamera(activity, addRequest);
+ break;
+ case 1:
+ pickImageFromAlbum(activity, addRequest);
+ break;
+ default:
+ break;
+ }
+ }
+ })
+ .setNegativeButton("取消", null)
+ .show();
+ }
+
+ /**
+ * 打开相机拍照获取图片
+ */
+ @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
+ public static void pickImageFromCamera(final Activity activity, int addRequest) {
+ // 先生成一个uri地址用于存放拍照获取的图片
+ imageUriFromCamera = createImageUri(activity);
+
+ Intent intent = new Intent();
+ intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE);
+ intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUriFromCamera);
+ activity.startActivityForResult(intent, REQUEST_CODE_FROM_CAMERA + addRequest);
+ }
+
+ /**
+ * 打开相机拍照获取图片
+ */
+ public static void pickImageFromCamera(final Activity activity) {
+ pickImageFromCamera(activity, 0);
+ }
+
+ /**
+ * 打开本地相册选取图片
+ */
+ @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
+ public static void pickImageFromAlbum(final Activity activity, int addRequest) {
+ Intent intent = new Intent();
+ intent.setAction(Intent.ACTION_GET_CONTENT);
+ intent.setType("image/*");
+ activity.startActivityForResult(intent, REQUEST_CODE_FROM_ALBUM + addRequest);
+ }
+
+ /**
+ * 打开本地相册选取图片
+ */
+ public static void pickImageFromAlbum(final Activity activity) {
+ pickImageFromAlbum(activity, 0);
+ }
+
+ /**
+ * 压缩图片
+ *
+ * @param context context
+ * @param uri 图片uri
+ * @param reqW 上传图片需要压缩的宽度
+ * @param reqH 上传图片需要压缩的高度
+ * @return 上传成功回调
+ */
+ public static Observable compressImage(final Context context,
+ Uri uri,
+ final int reqW,
+ final int reqH) {
+ // 先从本地获取图片,利用Glide压缩图片后获取byte[]
+ return Observable.just(uri)
+ .flatMap(new Function>() {
+ @Override
+ public ObservableSource apply(Uri uri) throws Exception {
+ // 在work线程中,同步压缩图片,然后Observable返回
+ // 即将Glide的回调封装成RxJava的Observable
+ FutureTarget future = Glide.with(context)
+ .load(uri)
+ .asBitmap()
+ .toBytes()
+ .into(reqW, reqH);
+
+ byte[] bytes;
+ try {
+ bytes = future.get();
+ } catch (Exception e) {
+ // 获取失败时,抛出runtime异常
+ // 该异常会被Subscriber捕捉,进onError
+ throw new RuntimeException(e);
+ }
+ return Observable.just(bytes);
+ }
+ });
+ }
+
+ /**
+ * 图片裁剪
+ */
+ public static void cropImage(Activity activity, Uri srcUri) {
+ cropImageUri = createImageUri(activity);
+
+ Intent intent = new Intent("com.android.camera.action.CROP");
+ intent.setDataAndType(srcUri, "image/*");
+ intent.putExtra("crop", "true");
+
+ ////////////////////////////////////////////////////////////////
+ // 1.宽高和比例都不设置时,裁剪框可以自行调整(比例和大小都可以随意调整)
+ ////////////////////////////////////////////////////////////////
+ // 2.只设置裁剪框宽高比(aspect)后,裁剪框比例固定不可调整,只能调整大小
+ /////////////////////////////////
+ // 3.裁剪后生成图片宽高(output)的设置和裁剪框无关,只决定最终生成图片大小
+ ////////////////////////////////////////////////////////////////
+ // 4.裁剪框宽高比例(aspect)可以和裁剪后生成图片比例(output)不同,此时,
+ // 会以裁剪框的宽为准,按照裁剪宽高比例生成一个图片,该图和框选部分可能不同,
+ // 不同的情况可能是截取框选的一部分,也可能超出框选部分,向下延伸补足
+ ////////////////////////////////////////////////////////////////
+
+ // aspectX aspectY 是裁剪框宽高的比例
+ intent.putExtra("aspectX", 1);
+ intent.putExtra("aspectY", 1);
+ // outputX outputY 是裁剪后生成图片的宽高
+ // intent.putExtra("outputX", 300);
+ // intent.putExtra("outputY", 100);
+
+ // return-data为true时,会直接返回bitmap数据,但是大图裁剪时会出现OOM,推荐下面为false时的方式
+ // return-data为false时,不会返回bitmap,但需要指定一个MediaStore.EXTRA_OUTPUT保存图片uri
+ intent.putExtra("return-data", false);
+ intent.putExtra(MediaStore.EXTRA_OUTPUT, cropImageUri);
+
+ activity.startActivityForResult(intent, REQUEST_CODE_CROP_IMAGE);
+ }
+
+ /**
+ * 创建一条图片uri,用于保存拍照后的照片
+ */
+ private static Uri createImageUri(Context context) {
+ String name = "boreImg" + System.currentTimeMillis();
+ ContentValues values = new ContentValues();
+ values.put(MediaStore.Images.Media.TITLE, name);
+ values.put(MediaStore.Images.Media.DISPLAY_NAME, name + ".jpeg");
+ values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg");
+ Uri uri = context.getContentResolver().insert(MediaStore.Images.Media
+ .EXTERNAL_CONTENT_URI, values);
+ return uri;
+ }
+
+ /**
+ * 删除一条图片
+ */
+ public static void deleteImageUri(Context context, Uri uri) {
+ context.getContentResolver().delete(uri, null, null);
+ }
+
+ /**
+ * 用第三方应用app打开图片
+ */
+ public static void openImageByOtherApp(Context context, Uri imageUri) {
+ Intent intent = new Intent();
+ intent.setAction(Intent.ACTION_VIEW);
+ intent.setDataAndType(imageUri, "image/*");
+ context.startActivity(intent);
+ }
+
+ /**
+ * 根据Uri获取图片绝对路径,解决Android4.4以上版本Uri转换
+ */
+ public static String getImageAbsolutePath19(Context context, Uri imageUri) {
+ if (context == null || imageUri == null)
+ return null;
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT
+ && DocumentsContract.isDocumentUri(context, imageUri)) {
+ if (isExternalStorageDocument(imageUri)) {
+ String docId = DocumentsContract.getDocumentId(imageUri);
+ String[] split = docId.split(":");
+ String type = split[0];
+ if ("primary".equalsIgnoreCase(type)) {
+ return Environment.getExternalStorageDirectory() + "/" + split[1];
+ }
+ } else if (isDownloadsDocument(imageUri)) {
+ String id = DocumentsContract.getDocumentId(imageUri);
+ Uri contentUri = ContentUris.withAppendedId(Uri.parse
+ ("content://downloads/public_downloads"), Long.valueOf(id));
+ return getDataColumn(context, contentUri, null, null);
+ } else if (isMediaDocument(imageUri)) {
+ String docId = DocumentsContract.getDocumentId(imageUri);
+ String[] split = docId.split(":");
+ String type = split[0];
+ Uri contentUri = null;
+ if ("image".equals(type)) {
+ contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
+ } else if ("video".equals(type)) {
+ contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
+ } else if ("audio".equals(type)) {
+ contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
+ }
+ String selection = MediaStore.Images.Media._ID + "=?";
+ String[] selectionArgs = new String[]{split[1]};
+ return getDataColumn(context, contentUri, selection, selectionArgs);
+ }
+ }
+
+ // MediaStore (and general)
+ if ("content".equalsIgnoreCase(imageUri.getScheme())) {
+ // Return the remote address
+ if (isGooglePhotosUri(imageUri))
+ return imageUri.getLastPathSegment();
+ return getDataColumn(context, imageUri, null, null);
+ }
+ // File
+ else if ("file".equalsIgnoreCase(imageUri.getScheme())) {
+ return imageUri.getPath();
+ }
+ return null;
+ }
+
+ private static String getDataColumn(Context context, Uri uri, String selection, String[]
+ selectionArgs) {
+ Cursor cursor = null;
+ String column = MediaStore.Images.Media.DATA;
+ String[] projection = {column};
+ try {
+ cursor = context.getContentResolver().query(uri, projection, selection,
+ selectionArgs, null);
+ if (cursor != null && cursor.moveToFirst()) {
+ int index = cursor.getColumnIndexOrThrow(column);
+ return cursor.getString(index);
+ }
+ } finally {
+ if (cursor != null)
+ cursor.close();
+ }
+ return null;
+ }
+
+ /**
+ * @param uri The Uri to check.
+ * @return Whether the Uri authority is ExternalStorageProvider.
+ */
+ private static boolean isExternalStorageDocument(Uri uri) {
+ return "com.android.externalstorage.documents".equals(uri.getAuthority());
+ }
+
+ /**
+ * @param uri The Uri to check.
+ * @return Whether the Uri authority is DownloadsProvider.
+ */
+ private static boolean isDownloadsDocument(Uri uri) {
+ return "com.android.providers.downloads.documents".equals(uri.getAuthority());
+ }
+
+ /**
+ * @param uri The Uri to check.
+ * @return Whether the Uri authority is MediaProvider.
+ */
+ private static boolean isMediaDocument(Uri uri) {
+ return "com.android.providers.media.documents".equals(uri.getAuthority());
+ }
+
+ /**
+ * @param uri The Uri to check.
+ * @return Whether the Uri authority is Google Photos.
+ */
+ private static boolean isGooglePhotosUri(Uri uri) {
+ return "com.google.android.apps.photos.content".equals(uri.getAuthority());
+ }
+
+}
diff --git a/mvpsdk/src/main/java/com/share/mvpsdk/utils/JsonUtils.java b/mvpsdk/src/main/java/com/share/mvpsdk/utils/JsonUtils.java
new file mode 100644
index 0000000..c8aeefc
--- /dev/null
+++ b/mvpsdk/src/main/java/com/share/mvpsdk/utils/JsonUtils.java
@@ -0,0 +1,65 @@
+package com.share.mvpsdk.utils;
+
+import com.google.gson.Gson;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonSyntaxException;
+
+import java.lang.reflect.Type;
+
+/**
+ * Created by Horrarndoo on 2017/9/20.
+ *
+ * Json转换工具类
+ */
+public class JsonUtils {
+
+ private static Gson mGson = new Gson();
+
+ /**
+ * 将对象准换为json字符串
+ *
+ * @param object
+ * @param
+ * @return
+ */
+ public static String serialize(T object) {
+ return mGson.toJson(object);
+ }
+
+ /**
+ * 将json字符串转换为对象
+ *
+ * @param json
+ * @param clz
+ * @param
+ * @return
+ */
+ public static T deserialize(String json, Class clz) throws JsonSyntaxException {
+ return mGson.fromJson(json, clz);
+ }
+
+ /**
+ * 将json对象转换为实体对象
+ *
+ * @param json
+ * @param clz
+ * @param
+ * @return
+ * @throws JsonSyntaxException
+ */
+ public static T deserialize(JsonObject json, Class clz) throws JsonSyntaxException {
+ return mGson.fromJson(json, clz);
+ }
+
+ /**
+ * 将json字符串转换为对象
+ *
+ * @param json
+ * @param type
+ * @param
+ * @return
+ */
+ public static T deserialize(String json, Type type) throws JsonSyntaxException {
+ return mGson.fromJson(json, type);
+ }
+}
diff --git a/mvpsdk/src/main/java/com/share/mvpsdk/utils/LogUtils.java b/mvpsdk/src/main/java/com/share/mvpsdk/utils/LogUtils.java
new file mode 100644
index 0000000..140e0fc
--- /dev/null
+++ b/mvpsdk/src/main/java/com/share/mvpsdk/utils/LogUtils.java
@@ -0,0 +1,168 @@
+package com.share.mvpsdk.utils;
+
+import android.util.Log;
+
+
+/**
+ * Created by Horrarndoo on 2017/4/5.
+ *
+ * Log工具类
+ */
+public class LogUtils {
+ /**
+ * 日志输出级别NONE
+ */
+ public static final int LEVEL_NONE = 0;
+ /**
+ * 日志输出级别E
+ */
+ public static final int LEVEL_ERROR = 1;
+ /**
+ * 日志输出级别W
+ */
+ public static final int LEVEL_WARN = 2;
+ /**
+ * 日志输出级别I
+ */
+ public static final int LEVEL_INFO = 3;
+ /**
+ * 日志输出级别D
+ */
+ public static final int LEVEL_DEBUG = 4;
+ /**
+ * 日志输出级别V
+ */
+ public static final int LEVEL_VERBOSE = 5;
+
+ /**
+ * 日志输出时的TAG
+ */
+ private static String mTag = "LogUtils";
+
+ /**
+ * 是否允许输出log
+ */
+ private static int mDebuggable = LEVEL_VERBOSE;
+
+ /**
+ * 设置调试Log开关
+ *
+ * @param isEnable 是否允许log
+ */
+ public static void setDebuggable(boolean isEnable) {
+ mDebuggable = isEnable ? LEVEL_VERBOSE : LEVEL_NONE;
+ }
+
+ /**
+ * 以级别为 d 的形式输出LOG
+ */
+ public static void v(String msg) {
+ if (mDebuggable >= LEVEL_VERBOSE) {
+ Log.v(mTag, msg);
+ }
+ }
+
+ /**
+ * 以级别为 d 的形式输出LOG
+ */
+ public static void d(String msg) {
+ if (mDebuggable >= LEVEL_DEBUG) {
+ Log.d(mTag, msg);
+ }
+ }
+
+ /**
+ * 以级别为 i 的形式输出LOG
+ */
+ public static void i(String msg) {
+ if (mDebuggable >= LEVEL_INFO) {
+ Log.i(mTag, msg);
+ }
+ }
+
+ /**
+ * 以级别为 w 的形式输出LOG
+ */
+ public static void w(String msg) {
+ if (mDebuggable >= LEVEL_WARN) {
+ Log.w(mTag, msg);
+ }
+ }
+
+ /**
+ * 以级别为 e 的形式输出LOG
+ */
+ public static void e(String msg) {
+ if (mDebuggable >= LEVEL_ERROR) {
+ Log.e(mTag, msg);
+ }
+ }
+
+ /**
+ * 以级别为 w 的形式输出Throwable
+ */
+ public static void w(Throwable tr) {
+ w("", tr);
+ }
+
+ /**
+ * 以级别为 w 的形式输出LOG信息和Throwable
+ */
+ public static void w(String msg, Throwable tr) {
+ Log.w(mTag, msg, tr);
+ }
+
+ /**
+ * 以级别为 e 的形式输出Throwable
+ */
+ public static void e(Throwable tr) {
+ e("", tr);
+ }
+
+ /**
+ * 以级别为 e 的形式输出LOG信息和Throwable
+ */
+ public static void e(String msg, Throwable tr) {
+ if (mDebuggable >= LEVEL_ERROR && null != msg) {
+ Log.e(mTag, msg, tr);
+ }
+ }
+
+ private static int originStackIndex = 2;
+
+ /**
+ * 获取当前方法所在的文件名
+ *
+ * @return 当前方法所在的文件名
+ */
+ public static String getFileName() {
+ return Thread.currentThread().getStackTrace()[originStackIndex].getFileName();
+ }
+
+ /**
+ * 获取当前方法所在的Class名
+ *
+ * @return 当前方法所在的Class名
+ */
+ public static String getClassName() {
+ return Thread.currentThread().getStackTrace()[originStackIndex].getClassName();
+ }
+
+ /**
+ * 获取当前方法名
+ *
+ * @return 当前方法名
+ */
+ public static String getMethodName() {
+ return Thread.currentThread().getStackTrace()[originStackIndex].getMethodName();
+ }
+
+ /**
+ * 获取当前代码执行处行数
+ *
+ * @return 当前代码执行处行数
+ */
+ public static int getLineNumber() {
+ return Thread.currentThread().getStackTrace()[originStackIndex].getLineNumber();
+ }
+}
\ No newline at end of file
diff --git a/mvpsdk/src/main/java/com/share/mvpsdk/utils/MD5Utils.java b/mvpsdk/src/main/java/com/share/mvpsdk/utils/MD5Utils.java
new file mode 100644
index 0000000..8cd25d5
--- /dev/null
+++ b/mvpsdk/src/main/java/com/share/mvpsdk/utils/MD5Utils.java
@@ -0,0 +1,38 @@
+package com.share.mvpsdk.utils;
+
+import java.security.MessageDigest;
+
+/**
+ * Created by Horrarndoo on 2017/4/5.
+ *
+ * MD5加密工具类
+ */
+public class MD5Utils {
+ /*
+ * MD5加密,32位
+ */
+ public static String getMD5(String str) {
+ MessageDigest md5 = null;
+ try {
+ md5 = MessageDigest.getInstance("MD5");
+ } catch (Exception e) {
+ e.printStackTrace();
+ return "";
+ }
+ char[] charArray = str.toCharArray();
+ byte[] byteArray = new byte[charArray.length];
+ for (int i = 0; i < charArray.length; i++) {
+ byteArray[i] = (byte) charArray[i];
+ }
+ byte[] md5Bytes = md5.digest(byteArray);
+ StringBuffer hexValue = new StringBuffer();
+ for (int i = 0; i < md5Bytes.length; i++) {
+ int val = ((int) md5Bytes[i]) & 0xff;
+ if (val < 16) {
+ hexValue.append("0");
+ }
+ hexValue.append(Integer.toHexString(val));
+ }
+ return hexValue.toString();
+ }
+}
\ No newline at end of file
diff --git a/mvpsdk/src/main/java/com/share/mvpsdk/utils/NavigationUtils.java b/mvpsdk/src/main/java/com/share/mvpsdk/utils/NavigationUtils.java
new file mode 100644
index 0000000..11758d4
--- /dev/null
+++ b/mvpsdk/src/main/java/com/share/mvpsdk/utils/NavigationUtils.java
@@ -0,0 +1,23 @@
+package com.share.mvpsdk.utils;
+
+import android.support.design.internal.NavigationMenuView;
+import android.support.design.widget.NavigationView;
+
+/**
+ * Created by Horrarndoo on 2017/12/12.
+ *
+ * NavigationView utils
+ */
+
+public class NavigationUtils {
+
+ public static void disableNavigationViewScrollbars(NavigationView navigationView) {
+ if (navigationView != null) {
+ NavigationMenuView navigationMenuView = (NavigationMenuView) navigationView
+ .getChildAt(0);
+ if (navigationMenuView != null) {
+ navigationMenuView.setVerticalScrollBarEnabled(false);
+ }
+ }
+ }
+}
diff --git a/mvpsdk/src/main/java/com/share/mvpsdk/utils/NetworkConnectionUtils.java b/mvpsdk/src/main/java/com/share/mvpsdk/utils/NetworkConnectionUtils.java
new file mode 100644
index 0000000..371fbc3
--- /dev/null
+++ b/mvpsdk/src/main/java/com/share/mvpsdk/utils/NetworkConnectionUtils.java
@@ -0,0 +1,236 @@
+package com.share.mvpsdk.utils;
+
+import android.app.Activity;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
+import android.net.wifi.ScanResult;
+import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiConfiguration.KeyMgmt;
+import android.net.wifi.WifiManager;
+import android.os.Build;
+
+import java.io.IOException;
+import java.util.List;
+
+import static com.share.mvpsdk.utils.LogUtils.e;
+
+/**
+ * Created by Horrarndoo on 2017/8/31.
+ *
+ * Wifi连接工具类
+ */
+public class NetworkConnectionUtils {
+ private final static String TAG = "NetworkConnectionUtils";
+
+ public NetworkConnectionUtils() {
+ }
+
+ /**
+ * 连接指定
+ *
+ * @param manager
+ * @param wifiSSID
+ * @return
+ */
+ public static boolean connectToSocketWifi(WifiManager manager, String wifiSSID) {
+ LogUtils.i("要连接的socket wifi====>" + wifiSSID);
+ WifiConfiguration wifiConfiguration = new WifiConfiguration();
+ wifiConfiguration.SSID = "\"" + wifiSSID + "\"";
+ wifiConfiguration.allowedKeyManagement.set(KeyMgmt.NONE);
+ wifiConfiguration.wepKeys[0] = "\"" + "\""; //小米手机MIUI7/华为EMUI4.1 需要webKey
+
+ int networkId = manager.addNetwork(wifiConfiguration);
+
+ if (networkId != -1) {
+ manager.enableNetwork(networkId, true);
+ e("连接设备成功");
+ return true;
+ } else {
+ e("第一次连接失败,尝试第二次。");
+ WifiConfiguration wifiConfiguration2 = new WifiConfiguration();
+ wifiConfiguration2.SSID = "\"" + wifiSSID + "\"";
+ //wifiConfiguration.wepKeys[0] = "\"" + "\"";//去掉webKey //小米手机MIUI8不能有webKey
+ wifiConfiguration2.allowedKeyManagement.set(KeyMgmt.NONE);
+ networkId = manager.addNetwork(wifiConfiguration2);
+ if (networkId != -1) {
+ manager.enableNetwork(networkId, true);
+ e("连接设备成功");
+ return true;
+ }
+ e("连接设备失败");
+ }
+ return false;
+ }
+
+ /**
+ * 获取要连接的wifi节点各个配置选项的加密类型
+ *
+ * @param ssid
+ * @return wifiConfiguration
+ */
+ public static WifiConfiguration getWifiConfiguration(WifiManager manager, String ssid, String
+ password) {
+ WifiConfiguration wifiConfiguration = new WifiConfiguration();
+ wifiConfiguration.SSID = "\"" + ssid + "\"";
+
+ List list = manager.getScanResults();
+ for (ScanResult scResult : list) {
+ if (ssid.equals(scResult.SSID)) {
+ String capabilities = scResult.capabilities;
+ LogUtils.i("capabilities=" + capabilities);
+ if (capabilities.contains("WEP") || capabilities.contains("wep")) {
+ wifiConfiguration.allowedKeyManagement.set(KeyMgmt.WPA_EAP);
+ wifiConfiguration.preSharedKey = "\"" + password + "\"";
+ LogUtils.i("wep");
+ } else if (capabilities.contains("WPA") || capabilities.contains("wpa")) {
+ wifiConfiguration.allowedKeyManagement.set(KeyMgmt.WPA_PSK);
+ wifiConfiguration.preSharedKey = "\"" + password + "\"";
+ LogUtils.i("wpa");
+ } else {
+ wifiConfiguration.allowedKeyManagement.set(KeyMgmt.NONE);
+ LogUtils.i("none");
+ }
+ }
+ }
+ return wifiConfiguration;
+ }
+
+ /**
+ * 给温控器成功发送联网命令后,连接温控器连接的wifi节点
+ *
+ * @param context 上下文对象
+ * @param ssid ssid
+ * @param password 密码
+ */
+ public static void connectWifiSSID(Context context, WifiManager manager, String ssid, String
+ password) {
+ e("reSetNetwork----------连接设备连入的路由---" + ssid);
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ e("当前手机系统>=Android6.0,采取兼容模式");
+ new WifiAutoConnectManager(manager).connect(ssid, password, WifiAutoConnectManager
+ .getCipherType(context, ssid));
+ } else {
+ int networkId = manager.addNetwork(getWifiConfiguration(manager, ssid, password));
+ if (networkId != -1) {
+ manager.enableNetwork(networkId, true);
+ }
+ }
+ }
+
+ /**
+ * 格式化RouterSSID
+ *
+ * @param strRouterSSID 要格式化的当前连接的路由ssid
+ * @return 去除"\"后的RouterSSID字符串
+ */
+ public static String formatRouterSSID(String strRouterSSID) {
+ //e("formate routerSSID before---" + strRouterSSID);
+ if (strRouterSSID.contains("\"")) {
+ strRouterSSID = strRouterSSID.replaceAll("\"", "");
+ //e("formate routerSSID after---" + strRouterSSID);
+ }
+ return strRouterSSID;
+ }
+
+ /**
+ * Ping
+ * 用于确定手机是否已经连接上指定设备ip地址
+ */
+ public static boolean pingTest(String IPOrDomainName) {
+
+ boolean isSuccess = false;
+ int status;
+ String result = "failed";
+ Process p;
+ try {
+ p = Runtime.getRuntime().exec("ping -c 1 " + IPOrDomainName);//
+ // m_strForNetAddress是输入的网址或者Ip地址
+ status = p.waitFor();// status 只能获取是否成功,无法获取更多的信息
+
+ if (status == 0) {
+ result = "success";
+ isSuccess = true;
+ }
+
+ } catch (IOException | InterruptedException e) {
+ e(e);
+ }
+ LogUtils.d("Ping result = " + result);
+ return isSuccess;
+ }
+
+ /**
+ * 判断网络是否连接
+ */
+ public static boolean isConnected(Context context) {
+ ConnectivityManager cm = (ConnectivityManager)
+ context.getSystemService(Context.CONNECTIVITY_SERVICE);
+
+ if (null == cm) {
+ return false;
+ }
+
+ NetworkInfo info = cm.getActiveNetworkInfo();
+ if (null != info && info.isConnected()) {
+ if (info.getState() == NetworkInfo.State.CONNECTED) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * 判断是否有网络
+ *
+ * @return 返回值
+ */
+ public static boolean isNetworkConnected(Context context) {
+ if (context != null) {
+ ConnectivityManager mConnectivityManager = (ConnectivityManager) context
+ .getSystemService(Context.CONNECTIVITY_SERVICE);
+ NetworkInfo mNetworkInfo = mConnectivityManager.getActiveNetworkInfo();
+
+ if (mNetworkInfo != null) {
+ return mNetworkInfo.isAvailable();
+ }
+ }
+ return false;
+ }
+
+ /**
+ * 判断是否是wifi连接
+ */
+ public static boolean isWifi(Context context) {
+ ConnectivityManager cm = (ConnectivityManager)
+ context.getSystemService(Context.CONNECTIVITY_SERVICE);
+
+ if (null == cm) {
+ return false;
+ }
+
+ NetworkInfo info = cm.getActiveNetworkInfo();
+ if (null != info) {
+ if (info.getType() == ConnectivityManager.TYPE_WIFI) {
+ return true;
+ }
+ }
+ return false;
+
+ }
+
+
+ /**
+ * 打开网络设置界面
+ */
+ public static void openSetting(Activity activity, int requestCode) {
+ Intent intent = new Intent("/");
+ ComponentName cm = new ComponentName("com.android.settings",
+ "com.android.settings.WirelessSettings");
+ intent.setComponent(cm);
+ intent.setAction(Intent.ACTION_VIEW);
+ activity.startActivityForResult(intent, requestCode);
+ }
+}
diff --git a/mvpsdk/src/main/java/com/share/mvpsdk/utils/PermissionUtils.java b/mvpsdk/src/main/java/com/share/mvpsdk/utils/PermissionUtils.java
new file mode 100644
index 0000000..6b9de71
--- /dev/null
+++ b/mvpsdk/src/main/java/com/share/mvpsdk/utils/PermissionUtils.java
@@ -0,0 +1,323 @@
+package com.share.mvpsdk.utils;
+
+import android.Manifest;
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.net.Uri;
+import android.provider.Settings;
+import android.support.annotation.NonNull;
+import android.support.v4.app.ActivityCompat;
+import android.util.Log;
+import android.widget.Toast;
+
+
+import com.share.mvpsdk.R;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Created by ToaHanDong on 2017/11/3.
+ */
+
+public class PermissionUtils {
+ private static final String TAG = PermissionUtils.class.getSimpleName();
+ public static final int CODE_RECORD_AUDIO = 0;
+ public static final int CODE_GET_ACCOUNTS = 1;
+ public static final int CODE_READ_PHONE_STATE = 2;
+ public static final int CODE_CALL_PHONE = 3;
+ public static final int CODE_CAMERA = 4;
+ public static final int CODE_ACCESS_FINE_LOCATION = 5;
+ public static final int CODE_ACCESS_COARSE_LOCATION = 6;
+ public static final int CODE_READ_EXTERNAL_STORAGE = 7;
+ public static final int CODE_WRITE_EXTERNAL_STORAGE = 8;
+ public static final int CODE_MULTI_PERMISSION = 100;
+
+ //com.huawei.permission.sec.PERMISSION_MDM_SDCARD
+// public static final String PERMISSION_MDM_SDCARD = "PERMISSION_MDM_SDCARD";
+ public static final String PERMISSION_RECORD_AUDIO = Manifest.permission.RECORD_AUDIO;
+ public static final String PERMISSION_GET_ACCOUNTS = Manifest.permission.GET_ACCOUNTS;
+ public static final String PERMISSION_READ_PHONE_STATE = Manifest.permission.READ_PHONE_STATE;
+ public static final String PERMISSION_CALL_PHONE = Manifest.permission.CALL_PHONE;
+ public static final String PERMISSION_CAMERA = Manifest.permission.CAMERA;
+ public static final String PERMISSION_ACCESS_FINE_LOCATION = Manifest.permission.ACCESS_FINE_LOCATION;
+ public static final String PERMISSION_ACCESS_COARSE_LOCATION = Manifest.permission.ACCESS_COARSE_LOCATION;
+ public static final String PERMISSION_READ_EXTERNAL_STORAGE = Manifest.permission.READ_EXTERNAL_STORAGE;
+ public static final String PERMISSION_WRITE_EXTERNAL_STORAGE = Manifest.permission.WRITE_EXTERNAL_STORAGE;
+
+ private static final String[] requestPermissions = {
+ PERMISSION_RECORD_AUDIO,
+ PERMISSION_GET_ACCOUNTS,
+ PERMISSION_READ_PHONE_STATE,
+ PERMISSION_CALL_PHONE,
+ PERMISSION_CAMERA,
+ PERMISSION_ACCESS_FINE_LOCATION,
+ PERMISSION_ACCESS_COARSE_LOCATION,
+ PERMISSION_READ_EXTERNAL_STORAGE,
+ PERMISSION_WRITE_EXTERNAL_STORAGE
+// PERMISSION_MDM_SDCARD
+ };
+
+ public interface PermissionGrant {
+ void onPermissionGranted(int requestCode);
+ }
+
+ /**
+ * Requests permission.
+ *
+ * @param activity
+ * @param requestCode request code, e.g. if you need request CAMERA permission,parameters is PermissionUtils.CODE_CAMERA
+ */
+ public static void requestPermission(final Activity activity, final int requestCode, PermissionGrant permissionGrant) {
+ if (activity == null) {
+ return;
+ }
+
+ Log.i(TAG, "requestPermission requestCode:" + requestCode);
+ if (requestCode < 0 || requestCode >= requestPermissions.length) {
+ Log.w(TAG, "requestPermission illegal requestCode:" + requestCode);
+ return;
+ }
+
+ final String requestPermission = requestPermissions[requestCode];
+
+ //如果是6.0以下的手机,ActivityCompat.checkSelfPermission()会始终等于PERMISSION_GRANTED,
+ // 但是,如果用户关闭了你申请的权限,ActivityCompat.checkSelfPermission(),会导致程序崩溃(java.lang.RuntimeException: Unknown exception code: 1 msg null),
+ // 你可以使用try{}catch(){},处理异常,也可以在这个地方,低于23就什么都不做,
+ // 个人建议try{}catch(){}单独处理,提示用户开启权限。
+// if (Build.VERSION.SDK_INT < 23) {
+// return;
+// }
+
+ int checkSelfPermission;
+ try {
+ checkSelfPermission = ActivityCompat.checkSelfPermission(activity, requestPermission);
+ } catch (RuntimeException e) {
+// Toast.makeText(activity, "please open this permission", Toast.LENGTH_SHORT)
+// .show();
+ Log.e(TAG, "RuntimeException:" + e.getMessage());
+ return;
+ }
+
+ if (checkSelfPermission != PackageManager.PERMISSION_GRANTED) {
+ Log.i(TAG, "ActivityCompat.checkSelfPermission != PackageManager.PERMISSION_GRANTED");
+
+
+ if (ActivityCompat.shouldShowRequestPermissionRationale(activity, requestPermission)) {
+ Log.i(TAG, "requestPermission shouldShowRequestPermissionRationale");
+ shouldShowRationale(activity, requestCode, requestPermission);
+
+ } else {
+ Log.d(TAG, "requestCameraPermission else");
+ ActivityCompat.requestPermissions(activity, new String[]{requestPermission}, requestCode);
+ }
+
+ } else {
+ Log.d(TAG, "ActivityCompat.checkSelfPermission ==== PackageManager.PERMISSION_GRANTED");
+// Toast.makeText(activity, "opened:" + requestPermissions[requestCode], Toast.LENGTH_SHORT).show();
+ permissionGrant.onPermissionGranted(requestCode);
+ }
+ }
+
+ private static void requestMultiResult(Activity activity, String[] permissions, int[] grantResults, PermissionGrant permissionGrant) {
+
+ if (activity == null) {
+ return;
+ }
+
+ //TODO
+ Log.d(TAG, "onRequestPermissionsResult permissions length:" + permissions.length);
+ Map perms = new HashMap<>();
+
+ ArrayList notGranted = new ArrayList<>();
+ for (int i = 0; i < permissions.length; i++) {
+ Log.d(TAG, "permissions: [i]:" + i + ", permissions[i]" + permissions[i] + ",grantResults[i]:" + grantResults[i]);
+ perms.put(permissions[i], grantResults[i]);
+ if (grantResults[i] != PackageManager.PERMISSION_GRANTED) {
+ notGranted.add(permissions[i]);
+ }
+ }
+
+ if (notGranted.size() == 0) {
+// Toast.makeText(activity, "all permission success" + notGranted, Toast.LENGTH_SHORT)
+// .show();
+ permissionGrant.onPermissionGranted(CODE_MULTI_PERMISSION);
+ } else {
+ openSettingActivity(activity, "those permission need granted!");
+ }
+
+ }
+
+
+ /**
+ * 一次申请多个权限
+ */
+ public static void requestMultiPermissions(final Activity activity, PermissionGrant grant) {
+
+ final List permissionsList = getNoGrantedPermission(activity, false);
+ final List shouldRationalePermissionsList = getNoGrantedPermission(activity, true);
+
+ //TODO checkSelfPermission
+ if (permissionsList == null || shouldRationalePermissionsList == null) {
+ return;
+ }
+ Log.d(TAG, "requestMultiPermissions permissionsList:" + permissionsList.size() + ",shouldRationalePermissionsList:" + shouldRationalePermissionsList.size());
+
+ if (permissionsList.size() > 0) {
+ ActivityCompat.requestPermissions(activity, permissionsList.toArray(new String[permissionsList.size()]),
+ CODE_MULTI_PERMISSION);
+ Log.d(TAG, "showMessageOKCancel requestPermissions");
+
+ } else if (shouldRationalePermissionsList.size() > 0) {
+ showMessageOKCancel(activity, "should open those permission",
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ ActivityCompat.requestPermissions(activity, shouldRationalePermissionsList.toArray(new String[shouldRationalePermissionsList.size()]),
+ CODE_MULTI_PERMISSION);
+ Log.d(TAG, "showMessageOKCancel requestPermissions");
+ }
+ });
+ } else {
+ grant.onPermissionGranted(CODE_MULTI_PERMISSION);
+ }
+
+ }
+
+
+ private static void shouldShowRationale(final Activity activity, final int requestCode, final String requestPermission) {
+ //TODO
+ String[] permissionsHint = activity.getResources().getStringArray(R.array.permissions);
+ showMessageOKCancel(activity, "Rationale: " + permissionsHint[requestCode], new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ ActivityCompat.requestPermissions(activity,
+ new String[]{requestPermission},
+ requestCode);
+ Log.d(TAG, "showMessageOKCancel requestPermissions:" + requestPermission);
+ }
+ });
+ }
+
+ private static void showMessageOKCancel(final Activity context, String message, DialogInterface.OnClickListener okListener) {
+ new AlertDialog.Builder(context)
+ .setMessage(message)
+ .setPositiveButton("OK", okListener)
+ .setNegativeButton("Cancel", null)
+ .create()
+ .show();
+
+ }
+
+ /**
+ * @param activity
+ * @param requestCode Need consistent with requestPermission
+ * @param permissions
+ * @param grantResults
+ */
+ public static void requestPermissionsResult(final Activity activity, final int requestCode, @NonNull String[] permissions,
+ @NonNull int[] grantResults, PermissionGrant permissionGrant) {
+
+ if (activity == null) {
+ return;
+ }
+ Log.d(TAG, "requestPermissionsResult requestCode:" + requestCode);
+
+ if (requestCode == CODE_MULTI_PERMISSION) {
+ requestMultiResult(activity, permissions, grantResults, permissionGrant);
+ return;
+ }
+
+ if (requestCode < 0 || requestCode >= requestPermissions.length) {
+ Log.w(TAG, "requestPermissionsResult illegal requestCode:" + requestCode);
+// Toast.makeText(activity, "illegal requestCode:" + requestCode, Toast.LENGTH_SHORT).show();
+ return;
+ }
+
+ Log.i(TAG, "onRequestPermissionsResult requestCode:" + requestCode + ",permissions:" + permissions.toString()
+ + ",grantResults:" + grantResults.toString() + ",length:" + grantResults.length);
+
+ if (grantResults.length == 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
+ Log.i(TAG, "onRequestPermissionsResult PERMISSION_GRANTED");
+ //TODO success, do something, can use callback
+ permissionGrant.onPermissionGranted(requestCode);
+
+ } else {
+ //TODO hint user this permission function
+ Log.i(TAG, "onRequestPermissionsResult PERMISSION NOT GRANTED");
+ //TODO
+ String[] permissionsHint = activity.getResources().getStringArray(R.array.permissions);
+ openSettingActivity(activity, "Result" + permissionsHint[requestCode]);
+ }
+
+ }
+
+ private static void openSettingActivity(final Activity activity, String message) {
+
+ showMessageOKCancel(activity, message, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ Intent intent = new Intent();
+ intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
+ Log.d(TAG, "getPackageName(): " + activity.getPackageName());
+ Uri uri = Uri.fromParts("package", activity.getPackageName(), null);
+ intent.setData(uri);
+ activity.startActivity(intent);
+ }
+ });
+ }
+
+
+ /**
+ * @param activity
+ * @param isShouldRationale true: return no granted and shouldShowRequestPermissionRationale permissions, false:return no granted and !shouldShowRequestPermissionRationale
+ * @return
+ */
+ public static ArrayList getNoGrantedPermission(Activity activity, boolean isShouldRationale) {
+
+ ArrayList permissions = new ArrayList<>();
+
+ for (int i = 0; i < requestPermissions.length; i++) {
+ String requestPermission = requestPermissions[i];
+
+
+ //TODO checkSelfPermission
+ int checkSelfPermission = -1;
+ try {
+ checkSelfPermission = ActivityCompat.checkSelfPermission(activity, requestPermission);
+ } catch (RuntimeException e) {
+ Toast.makeText(activity, "please open those permission", Toast.LENGTH_SHORT)
+ .show();
+ Log.e(TAG, "RuntimeException:" + e.getMessage());
+ return null;
+ }
+
+ if (checkSelfPermission != PackageManager.PERMISSION_GRANTED) {
+ Log.i(TAG, "getNoGrantedPermission ActivityCompat.checkSelfPermission != PackageManager.PERMISSION_GRANTED:" + requestPermission);
+
+ if (ActivityCompat.shouldShowRequestPermissionRationale(activity, requestPermission)) {
+ Log.d(TAG, "shouldShowRequestPermissionRationale if");
+ if (isShouldRationale) {
+ permissions.add(requestPermission);
+ }
+
+ } else {
+
+ if (!isShouldRationale) {
+ permissions.add(requestPermission);
+ }
+ Log.d(TAG, "shouldShowRequestPermissionRationale else");
+ }
+
+ }
+ }
+
+ return permissions;
+ }
+
+}
diff --git a/mvpsdk/src/main/java/com/share/mvpsdk/utils/ResourcesUtils.java b/mvpsdk/src/main/java/com/share/mvpsdk/utils/ResourcesUtils.java
new file mode 100644
index 0000000..98e48d7
--- /dev/null
+++ b/mvpsdk/src/main/java/com/share/mvpsdk/utils/ResourcesUtils.java
@@ -0,0 +1,83 @@
+package com.share.mvpsdk.utils;
+
+import android.content.res.ColorStateList;
+import android.graphics.drawable.Drawable;
+import android.view.View;
+
+/**
+ * Created by Horrarndoo on 2017/9/1.
+ *
+ * 资源工具类-加载资源文件
+ */
+
+public class ResourcesUtils {
+ /**
+ * 获取strings.xml资源文件字符串
+ *
+ * @param id 资源文件id
+ * @return 资源文件对应字符串
+ */
+ public static String getString(int id) {
+ return AppUtils.getContext().getResources().getString(id);
+ }
+
+ /**
+ * 获取strings.xml资源文件字符串数组
+ *
+ * @param id 资源文件id
+ * @return 资源文件对应字符串数组
+ */
+ public static String[] getStringArray(int id) {
+ return AppUtils.getContext().getResources().getStringArray(id);
+ }
+
+ /**
+ * 获取drawable资源文件图片
+ *
+ * @param id 资源文件id
+ * @return 资源文件对应图片
+ */
+ public static Drawable getDrawable(int id) {
+ return AppUtils.getContext().getResources().getDrawable(id);
+ }
+
+ /**
+ * 获取colors.xml资源文件颜色
+ *
+ * @param id 资源文件id
+ * @return 资源文件对应颜色值
+ */
+ public static int getColor(int id) {
+ return AppUtils.getContext().getResources().getColor(id);
+ }
+
+ /**
+ * 获取颜色的状态选择器
+ *
+ * @param id 资源文件id
+ * @return 资源文件对应颜色状态
+ */
+ public static ColorStateList getColorStateList(int id) {
+ return AppUtils.getContext().getResources().getColorStateList(id);
+ }
+
+ /**
+ * 获取dimens资源文件中具体像素值
+ *
+ * @param id 资源文件id
+ * @return 资源文件对应像素值
+ */
+ public static int getDimen(int id) {
+ return AppUtils.getContext().getResources().getDimensionPixelSize(id);// 返回具体像素值
+ }
+
+ /**
+ * 加载布局文件
+ *
+ * @param id 布局文件id
+ * @return 布局view
+ */
+ public static View inflate(int id) {
+ return View.inflate(AppUtils.getContext(), id, null);
+ }
+}
diff --git a/mvpsdk/src/main/java/com/share/mvpsdk/utils/ScreenUtils.java b/mvpsdk/src/main/java/com/share/mvpsdk/utils/ScreenUtils.java
new file mode 100644
index 0000000..3e13c0f
--- /dev/null
+++ b/mvpsdk/src/main/java/com/share/mvpsdk/utils/ScreenUtils.java
@@ -0,0 +1,151 @@
+package com.share.mvpsdk.utils;
+
+import android.app.Activity;
+import android.app.ActivityGroup;
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Rect;
+import android.os.Build;
+import android.support.v7.app.AppCompatActivity;
+import android.util.Log;
+import android.util.TypedValue;
+import android.view.Display;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+
+/**
+ * Created by Horrarndoo on 2017/9/7.
+ *
+ * 屏幕相关工具类
+ */
+
+public class ScreenUtils {
+ private ScreenUtils() {
+ /* cannot be instantiated */
+ throw new UnsupportedOperationException("cannot be instantiated");
+ }
+
+
+ private static int mStatusHeight = -1;
+
+ /**
+ * 获取屏幕的宽度
+ *
+ * @param context
+ * @return
+ */
+ public static int getScreenWidth(Context context) {
+ WindowManager manager = (WindowManager) context
+ .getSystemService(Context.WINDOW_SERVICE);
+ Display display = manager.getDefaultDisplay();
+ return display.getWidth();
+ }
+
+ /**
+ * 获取屏幕的高度
+ *
+ * @param context
+ * @return
+ */
+ public static int getScreenHeight(Context context) {
+ WindowManager manager = (WindowManager) context
+ .getSystemService(Context.WINDOW_SERVICE);
+ Display display = manager.getDefaultDisplay();
+ return display.getHeight();
+ }
+
+ /**
+ * 获取当前屏幕截图,不包含状态栏
+ *
+ * @param activity
+ * @return bp
+ */
+ public static Bitmap snapShotWithoutStatusBar(Activity activity) {
+ View view = activity.getWindow().getDecorView();
+ view.setDrawingCacheEnabled(true);
+ view.buildDrawingCache();
+ Bitmap bmp = view.getDrawingCache();
+ if (bmp == null) {
+ return null;
+ }
+ Rect frame = new Rect();
+ activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(frame);
+ int statusBarHeight = frame.top;
+ Bitmap bp = Bitmap.createBitmap(bmp, 0, statusBarHeight, bmp.getWidth(), bmp.getHeight()
+ - statusBarHeight);
+ view.destroyDrawingCache();
+ view.setDrawingCacheEnabled(false);
+
+ return bp;
+ }
+
+ /**
+ * 获取actionbar的像素高度,默认使用android官方兼容包做actionbar兼容
+ *
+ * @return
+ */
+ public static int getActionBarHeight(Context context) {
+ int actionBarHeight = 0;
+ if (context instanceof AppCompatActivity && ((AppCompatActivity) context)
+ .getSupportActionBar() != null) {
+ Log.d("isAppCompatActivity", "==AppCompatActivity");
+ actionBarHeight = ((AppCompatActivity) context).getSupportActionBar().getHeight();
+ } else if (context instanceof Activity && ((Activity) context).getActionBar() != null) {
+ Log.d("isActivity", "==Activity");
+ actionBarHeight = ((Activity) context).getActionBar().getHeight();
+ } else if (context instanceof ActivityGroup) {
+ Log.d("ActivityGroup", "==ActivityGroup");
+ if (((ActivityGroup) context).getCurrentActivity() instanceof AppCompatActivity && (
+ (AppCompatActivity) ((ActivityGroup) context).getCurrentActivity())
+ .getSupportActionBar() != null) {
+ actionBarHeight = ((AppCompatActivity) ((ActivityGroup) context)
+ .getCurrentActivity()).getSupportActionBar().getHeight();
+ } else if (((ActivityGroup) context).getCurrentActivity() instanceof Activity && (
+ (Activity) ((ActivityGroup) context).getCurrentActivity()).getActionBar() !=
+ null) {
+ actionBarHeight = ((Activity) ((ActivityGroup) context).getCurrentActivity())
+ .getActionBar().getHeight();
+ }
+ }
+ if (actionBarHeight != 0)
+ return actionBarHeight;
+ final TypedValue tv = new TypedValue();
+ if (context.getTheme().resolveAttribute(android.support.v7.appcompat.R.attr
+ .actionBarSize, tv, true)) {
+ if (context.getTheme().resolveAttribute(android.support.v7.appcompat.R.attr
+ .actionBarSize, tv, true))
+ actionBarHeight = TypedValue.complexToDimensionPixelSize(tv.data, context
+ .getResources().getDisplayMetrics());
+ } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
+ if (context.getTheme().resolveAttribute(android.R.attr.actionBarSize, tv, true))
+ actionBarHeight = TypedValue.complexToDimensionPixelSize(tv.data, context
+ .getResources().getDisplayMetrics());
+ } else {
+ if (context.getTheme().resolveAttribute(android.support.v7.appcompat.R.attr
+ .actionBarSize, tv, true))
+ actionBarHeight = TypedValue.complexToDimensionPixelSize(tv.data, context
+ .getResources().getDisplayMetrics());
+ }
+ Log.d("actionBarHeight", "====" + actionBarHeight);
+ return actionBarHeight;
+ }
+
+
+ /**
+ * 设置view margin
+ *
+ * @param v
+ * @param l
+ * @param t
+ * @param r
+ * @param b
+ */
+ public static void setMargins(View v, int l, int t, int r, int b) {
+ if (v.getLayoutParams() instanceof ViewGroup.MarginLayoutParams) {
+ ViewGroup.MarginLayoutParams p = (ViewGroup.MarginLayoutParams) v.getLayoutParams();
+ p.setMargins(l, t, r, b);
+ v.requestLayout();
+ }
+ }
+}
diff --git a/mvpsdk/src/main/java/com/share/mvpsdk/utils/SnackbarUtils.java b/mvpsdk/src/main/java/com/share/mvpsdk/utils/SnackbarUtils.java
new file mode 100644
index 0000000..6834796
--- /dev/null
+++ b/mvpsdk/src/main/java/com/share/mvpsdk/utils/SnackbarUtils.java
@@ -0,0 +1,189 @@
+package com.share.mvpsdk.utils;
+
+import android.graphics.Color;
+import android.support.design.widget.Snackbar;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import com.share.mvpsdk.R;
+
+
+/**
+ * Created by Horrarndoo on 2017/8/31.
+ *
+ * Snackbar工具类
+ */
+public class SnackbarUtils {
+
+ public static final int Info = 1;
+ public static final int Confirm = 2;
+ public static final int Warning = 3;
+ public static final int Alert = 4;
+
+
+ public static int red = 0xfff44336;
+ public static int green = 0xff4caf50;
+ public static int blue = 0xff2195f3;
+ public static int orange = 0xffffc107;
+
+ /**
+ * 短显示Snackbar,自定义颜色
+ *
+ * @param view
+ * @param message
+ * @param messageColor
+ * @param backgroundColor
+ * @return
+ */
+ public static Snackbar getShort(View view, String message, int messageColor, int
+ backgroundColor) {
+ Snackbar snackbar = Snackbar.make(view, message, Snackbar.LENGTH_SHORT);
+ setSnackbarColor(snackbar, messageColor, backgroundColor);
+ return snackbar;
+ }
+
+ /**
+ * 长显示Snackbar,自定义颜色
+ *
+ * @param view
+ * @param message
+ * @param messageColor
+ * @param backgroundColor
+ * @return
+ */
+ public static Snackbar getLong(View view, String message, int messageColor, int
+ backgroundColor) {
+ Snackbar snackbar = Snackbar.make(view, message, Snackbar.LENGTH_LONG);
+ setSnackbarColor(snackbar, messageColor, backgroundColor);
+ return snackbar;
+ }
+
+ /**
+ * 自定义时常显示Snackbar,自定义颜色
+ *
+ * @param view
+ * @param message
+ * @param messageColor
+ * @param backgroundColor
+ * @return
+ */
+ public static Snackbar getIndefinite(View view, String message, int duration, int
+ messageColor, int backgroundColor) {
+ Snackbar snackbar = Snackbar.make(view, message, Snackbar.LENGTH_INDEFINITE).setDuration
+ (duration);
+ setSnackbarColor(snackbar, messageColor, backgroundColor);
+ return snackbar;
+ }
+
+ /**
+ * 短显示Snackbar,可选预设类型
+ *
+ * @param view
+ * @param message
+ * @param type
+ * @return
+ */
+ public static Snackbar getShort(View view, String message, int type) {
+ Snackbar snackbar = Snackbar.make(view, message, Snackbar.LENGTH_SHORT);
+ switchType(snackbar, type);
+ return snackbar;
+ }
+
+ /**
+ * 长显示Snackbar,可选预设类型
+ *
+ * @param view
+ * @param message
+ * @param type
+ * @return
+ */
+ public static Snackbar getLong(View view, String message, int type) {
+ Snackbar snackbar = Snackbar.make(view, message, Snackbar.LENGTH_LONG);
+ switchType(snackbar, type);
+ return snackbar;
+ }
+
+ /**
+ * 自定义时常显示Snackbar,可选预设类型
+ *
+ * @param view
+ * @param message
+ * @param type
+ * @return
+ */
+ public static Snackbar getIndefinite(View view, String message, int duration, int type) {
+ Snackbar snackbar = Snackbar.make(view, message, Snackbar.LENGTH_INDEFINITE).setDuration
+ (duration);
+ switchType(snackbar, type);
+ return snackbar;
+ }
+
+ //选择预设类型
+ private static void switchType(Snackbar snackbar, int type) {
+ switch (type) {
+ case Info:
+ setSnackbarColor(snackbar, blue);
+ break;
+ case Confirm:
+ setSnackbarColor(snackbar, green);
+ break;
+ case Warning:
+ setSnackbarColor(snackbar, orange);
+ break;
+ case Alert:
+ setSnackbarColor(snackbar, Color.YELLOW, red);
+ break;
+ }
+ }
+
+ /**
+ * 设置Snackbar背景颜色
+ *
+ * @param snackbar
+ * @param backgroundColor
+ */
+ public static void setSnackbarColor(Snackbar snackbar, int backgroundColor) {
+ View view = snackbar.getView();
+ if (view != null) {
+ view.setBackgroundColor(backgroundColor);
+ }
+ }
+
+ /**
+ * 设置Snackbar文字和背景颜色
+ *
+ * @param snackbar
+ * @param messageColor
+ * @param backgroundColor
+ */
+ public static void setSnackbarColor(Snackbar snackbar, int messageColor, int backgroundColor) {
+ View view = snackbar.getView();
+ if (view != null) {
+ view.setBackgroundColor(backgroundColor);
+ ((TextView) view.findViewById(R.id.snackbar_text)).setTextColor(messageColor);
+ }
+ }
+
+ /**
+ * 向Snackbar中添加view
+ *
+ * @param snackbar
+ * @param layoutId
+ * @param index 新加布局在Snackbar中的位置
+ */
+ public static void addView(Snackbar snackbar, int layoutId, int index) {
+ View snackbarview = snackbar.getView();
+ Snackbar.SnackbarLayout snackbarLayout = (Snackbar.SnackbarLayout) snackbarview;
+
+ View add_view = LayoutInflater.from(snackbarview.getContext()).inflate(layoutId, null);
+
+ LinearLayout.LayoutParams p = new LinearLayout.LayoutParams(LinearLayout.LayoutParams
+ .WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
+ p.gravity = Gravity.CENTER_VERTICAL;
+
+ snackbarLayout.addView(add_view, index, p);
+ }
+}
\ No newline at end of file
diff --git a/mvpsdk/src/main/java/com/share/mvpsdk/utils/SpUtils.java b/mvpsdk/src/main/java/com/share/mvpsdk/utils/SpUtils.java
new file mode 100644
index 0000000..fc81c46
--- /dev/null
+++ b/mvpsdk/src/main/java/com/share/mvpsdk/utils/SpUtils.java
@@ -0,0 +1,212 @@
+package com.share.mvpsdk.utils;
+
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.preference.PreferenceManager;
+
+import com.google.gson.Gson;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonParser;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * SharedPreferences工具类封装
+ */
+public class SpUtils {
+ private static SharedPreferences sp;
+ private static String mPreferencesName = "share_preference_default";
+
+ /**
+ * 设置preferencesName
+ *
+ * @param preferencesName preferencesName
+ */
+ private void setPreferencesName(String preferencesName) {
+ mPreferencesName = preferencesName;
+ }
+
+ /**
+ * 写入boolean变量至sp中
+ *
+ * @param ctx 上下文环境
+ * @param key 存储节点名称
+ * @param value 存储节点的值
+ */
+ public static void putBoolean(Context ctx, String key, boolean value) {
+ //(存储节点文件名称,读写方式)
+ if (sp == null) {
+ sp = ctx.getSharedPreferences(mPreferencesName, Context
+ .MODE_PRIVATE);
+ }
+ sp.edit().putBoolean(key, value).apply();
+ }
+
+ /**
+ * 读取boolean标示从sp中
+ *
+ * @param ctx 上下文环境
+ * @param key 存储节点名称
+ * @param defValue 没有此节点默认值
+ * @return 默认值或者此节点读取到的结果
+ */
+ public static boolean getBoolean(Context ctx, String key, boolean defValue) {
+ //(存储节点文件名称,读写方式)
+ if (sp == null) {
+ sp = ctx.getSharedPreferences(mPreferencesName, Context
+ .MODE_PRIVATE);
+ }
+ return sp.getBoolean(key, defValue);
+ }
+
+ /**
+ * 写入String变量至sp中
+ *
+ * @param ctx 上下文环境
+ * @param key 存储节点名称
+ * @param value 存储节点的值
+ */
+ public static void putString(Context ctx, String key, String value) {
+ //(存储节点文件名称,读写方式)
+ if (sp == null) {
+ sp = ctx.getSharedPreferences(mPreferencesName, Context
+ .MODE_PRIVATE);
+ }
+ sp.edit().putString(key, value).apply();
+ }
+
+ /**
+ * 读取String标示从sp中
+ *
+ * @param ctx 上下文环境
+ * @param key 存储节点名称
+ * @param defValue 没有此节点默认值
+ * @return 默认值或者此节点读取到的结果
+ */
+ public static String getString(Context ctx, String key, String defValue) {
+ //(存储节点文件名称,读写方式)
+ if (sp == null) {
+ sp = ctx.getSharedPreferences(mPreferencesName, Context
+ .MODE_PRIVATE);
+ }
+ return sp.getString(key, defValue);
+ }
+
+
+ /**
+ * 写入int变量至sp中
+ *
+ * @param ctx 上下文环境
+ * @param key 存储节点名称
+ * @param value 存储节点的值
+ */
+ public static void putInt(Context ctx, String key, int value) {
+ //(存储节点文件名称,读写方式)
+ if (sp == null) {
+ sp = ctx.getSharedPreferences(mPreferencesName, Context
+ .MODE_PRIVATE);
+ }
+ sp.edit().putInt(key, value).apply();
+ }
+
+ /**
+ * 读取int标示从sp中
+ *
+ * @param ctx 上下文环境
+ * @param key 存储节点名称
+ * @param defValue 没有此节点默认值
+ * @return 默认值或者此节点读取到的结果
+ */
+ public static int getInt(Context ctx, String key, int defValue) {
+ //(存储节点文件名称,读写方式)
+ if (sp == null) {
+ sp = ctx.getSharedPreferences(mPreferencesName, Context
+ .MODE_PRIVATE);
+ }
+ return sp.getInt(key, defValue);
+ }
+
+
+ /**
+ * 从sp中移除指定节点
+ *
+ * @param ctx 上下文环境
+ * @param key 需要移除节点的名称
+ */
+ public static void remove(Context ctx, String key) {
+ if (sp == null) {
+ sp = ctx.getSharedPreferences(mPreferencesName, Context
+ .MODE_PRIVATE);
+ }
+ sp.edit().remove(key).apply();
+ }
+
+ /**
+ * 保存List
+ *
+ * @param key sp key值
+ * @param datalist list
+ * @param item 类型
+ */
+ public static void setDataList(String key, List datalist) {
+ if (null == datalist || datalist.size() <= 0)
+ return;
+
+ Gson gson = new Gson();
+ //转换成json数据,再保存
+ String strJson = gson.toJson(datalist);
+ SpUtils.putString(AppUtils.getContext(), key, strJson);
+ }
+
+ /**
+ * 获取List
+ *
+ * @param key sp key值
+ * @param item 类型
+ * @return list
+ */
+ public static List getDataList(String key, Class cls) {
+ List datalist = new ArrayList();
+ String strJson = SpUtils.getString(AppUtils.getContext(), key, null);
+
+ if (null == strJson) {
+ return datalist;
+ }
+
+ try {
+ Gson gson = new Gson();
+ // datalist = gson.fromJson(strJson, new TypeToken>(){}.getType());
+ JsonArray array = new JsonParser().parse(strJson).getAsJsonArray();
+ for (final JsonElement elem : array) {
+ datalist.add(gson.fromJson(elem, cls));
+ }
+ }catch (Exception e){
+ e.printStackTrace();
+ }
+
+ return datalist;
+ }
+
+ public static int getThemeIndex(Context context) {
+ SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
+ return prefs.getInt("ThemeIndex", 5);
+ }
+
+ public static void setThemeIndex(Context context, int index) {
+ SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
+ prefs.edit().putInt("ThemeIndex", index).apply();
+ }
+
+ public static boolean getNightModel(Context context) {
+ SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
+ return prefs.getBoolean("pNightMode", false);
+ }
+
+ public static void setNightModel(Context context, boolean nightModel) {
+ SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
+ prefs.edit().putBoolean("pNightMode", nightModel).apply();
+ }
+}
diff --git a/mvpsdk/src/main/java/com/share/mvpsdk/utils/StatusBarUtils.java b/mvpsdk/src/main/java/com/share/mvpsdk/utils/StatusBarUtils.java
new file mode 100644
index 0000000..2abc82c
--- /dev/null
+++ b/mvpsdk/src/main/java/com/share/mvpsdk/utils/StatusBarUtils.java
@@ -0,0 +1,139 @@
+package com.share.mvpsdk.utils;
+
+import android.app.Activity;
+import android.content.Context;
+import android.graphics.Color;
+import android.os.Build;
+import android.support.annotation.ColorInt;
+import android.support.v7.widget.Toolbar;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.Window;
+import android.view.WindowManager;
+
+import java.lang.reflect.Field;
+
+
+/**
+ * Created by Horrarndoo on 2017/8/31.
+ *
+ * StatusBar工具类
+ */
+public class StatusBarUtils {
+
+ private static final int DEFAULT_STATUS_BAR_ALPHA = 0;
+
+ /**
+ * 设置状态栏颜色
+ *
+ * @param activity 需要设置的 activity
+ * @param color 状态栏颜色值
+ */
+ public static void setColor(Activity activity, @ColorInt int color) {
+ setBarColor(activity, color);
+ }
+
+ /**
+ * 设置状态栏背景色
+ * 4.4以下不处理
+ * 4.4使用默认沉浸式状态栏
+ *
+ * @param color 要为状态栏设置的颜色值
+ */
+ public static void setBarColor(Activity activity, int color) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
+ Window win = activity.getWindow();
+ View decorView = win.getDecorView();
+ win.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);//沉浸式状态栏(4.4-5.0透明,5.0以上半透明)
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {//android5.0以上设置透明效果
+ win.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);//清除flag,为了android5.0以上也全透明效果
+ //让应用的主体内容占用系统状态栏的空间
+ int option = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
+ | View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
+ decorView.setSystemUiVisibility(decorView.getSystemUiVisibility() | option);
+ win.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
+ win.setStatusBarColor(color);//设置状态栏背景色
+ }
+ }
+ }
+
+ /**
+ * 设置状态栏全透明
+ *
+ * @param activity 需要设置的activity
+ */
+ public static void setTransparent(Activity activity) {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
+ return;
+ }
+ setColor(activity, Color.TRANSPARENT);
+ }
+
+ /**
+ * 修正 Toolbar 的位置
+ * 在 Android 4.4 版本下无法显示内容在 StatusBar 下,所以无需修正 Toolbar 的位置
+ *
+ * @param toolbar
+ */
+ public static void fixToolbar(Toolbar toolbar, Activity activity) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
+ int statusHeight = getStatusBarHeight(activity);
+ ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) toolbar.getLayoutParams();
+ layoutParams.setMargins(0, statusHeight, 0, 0);
+ }
+ }
+
+ /**
+ * 获取系统状态栏高度
+ *
+ * @param context
+ * @return
+ */
+ public static int getStatusBarHeight(Context context) {
+ Class> c = null;
+ Object obj = null;
+ Field field = null;
+ int x = 0, statusBarHeight = 0;
+ try {
+ c = Class.forName("com.android.internal.R$dimen");
+ obj = c.newInstance();
+ field = c.getField("status_bar_height");
+ x = Integer.parseInt(field.get(obj).toString());
+ statusBarHeight = context.getResources().getDimensionPixelSize(x);
+ } catch (Exception e1) {
+ e1.printStackTrace();
+ }
+ return statusBarHeight;
+ }
+
+// /**
+// * 获取状态栏高度
+// *
+// * @param context context
+// * @return 状态栏高度
+// */
+// private static int getStatusBarHeight(Context context) {
+// // 获得状态栏高度
+// int resourceId = context.getResources().getIdentifier("status_bar_height", "dimen",
+// "android");
+// return context.getResources().getDimensionPixelSize(resourceId);
+// }
+
+ /**
+ * 计算状态栏颜色
+ *
+ * @param color color值
+ * @param alpha alpha值
+ * @return 最终的状态栏颜色
+ */
+ private static int calculateStatusColor(@ColorInt int color, int alpha) {
+ float a = 1 - alpha / 255f;
+ int red = color >> 16 & 0xff;
+ int green = color >> 8 & 0xff;
+ int blue = color & 0xff;
+ red = (int) (red * a + 0.5);
+ green = (int) (green * a + 0.5);
+ blue = (int) (blue * a + 0.5);
+ return 0xff << 24 | red << 16 | green << 8 | blue;
+ }
+}
diff --git a/mvpsdk/src/main/java/com/share/mvpsdk/utils/StringUtils.java b/mvpsdk/src/main/java/com/share/mvpsdk/utils/StringUtils.java
new file mode 100644
index 0000000..57486fa
--- /dev/null
+++ b/mvpsdk/src/main/java/com/share/mvpsdk/utils/StringUtils.java
@@ -0,0 +1,125 @@
+package com.share.mvpsdk.utils;
+
+import android.text.TextUtils;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Created by Horrarndoo on 2017/4/5.
+ * 字符串工具类
+ */
+public class StringUtils {
+ /**
+ * 判断字符串是否有值,如果为null或者是空字符串或者只有空格或者为"null"字符串,则返回true,否则则返回false
+ */
+ public static boolean isEmpty(String value) {
+ return !(value != null && !"".equalsIgnoreCase(value.trim())
+ && !"null".equalsIgnoreCase(value.trim()));
+ }
+
+ /**
+ * 判断字符串是否是邮箱
+ *
+ * @param email email
+ * @return 字符串是否是邮箱
+ */
+ public static boolean isEmail(String email) {
+ String str = "^([a-zA-Z0-9_\\-\\.]+)@((\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.)|(" +
+ "([a-zA-Z0-9\\-]+\\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\\]?)$";
+ Pattern p = Pattern.compile(str);
+ Matcher m = p.matcher(email);
+ return m.matches();
+ }
+
+ /**
+ * 判断手机号字符串是否合法
+ *
+ * @param phoneNumber 手机号字符串
+ * @return 手机号字符串是否合法
+ */
+ public static boolean isPhoneNumberValid(String phoneNumber) {
+ boolean isValid = false;
+ String expression = "^1[3|4|5|7|8]\\d{9}$";
+ CharSequence inputStr = phoneNumber;
+ Pattern pattern = Pattern.compile(expression);
+ Matcher matcher = pattern.matcher(inputStr);
+ if (matcher.matches()) {
+ isValid = true;
+ }
+ return isValid;
+ }
+
+ /**
+ * 判断手机号字符串是否合法
+ *
+ * @param areaCode 区号
+ * @param phoneNumber 手机号字符串
+ * @return 手机号字符串是否合法
+ */
+ public static boolean isPhoneNumberValid(String areaCode, String phoneNumber) {
+ if (TextUtils.isEmpty(phoneNumber)) {
+ return false;
+ }
+
+ if (phoneNumber.length() < 5) {
+ return false;
+ }
+
+ if (TextUtils.equals(areaCode, "+86") || TextUtils.equals(areaCode, "86")) {
+ return isPhoneNumberValid(phoneNumber);
+ }
+
+ boolean isValid = false;
+ String expression = "^[0-9]*$";
+ CharSequence inputStr = phoneNumber;
+ Pattern pattern = Pattern.compile(expression);
+ Matcher matcher = pattern.matcher(inputStr);
+ if (matcher.matches()) {
+ isValid = true;
+ }
+ return isValid;
+ }
+
+ /**
+ * 判断字符串是否是手机号格式
+ *
+ * @param areaCode 区号
+ * @param phoneNumber 手机号字符串
+ * @return 字符串是否是手机号格式
+ */
+ public static boolean isPhoneFormat(String areaCode, String phoneNumber) {
+ if (TextUtils.isEmpty(phoneNumber)) {
+ return false;
+ }
+
+ if (phoneNumber.length() < 7) {
+ return false;
+ }
+
+ boolean isValid = false;
+ String expression = "^[0-9]*$";
+ CharSequence inputStr = phoneNumber;
+ Pattern pattern = Pattern.compile(expression);
+ Matcher matcher = pattern.matcher(inputStr);
+ if (matcher.matches()) {
+ isValid = true;
+ }
+ return isValid;
+ }
+
+ /**
+ * 判断字符串是否为纯数字
+ *
+ * @param str 字符串
+ * @return 是否纯数字
+ */
+ public static boolean isNumber(String str) {
+ for (int i = 0; i < str.length(); i++) {
+ if (!Character.isDigit(str.charAt(i))) {
+ return false;
+ }
+ }
+ return true;
+ }
+}
diff --git a/mvpsdk/src/main/java/com/share/mvpsdk/utils/ThemeUtils.java b/mvpsdk/src/main/java/com/share/mvpsdk/utils/ThemeUtils.java
new file mode 100644
index 0000000..cb743c5
--- /dev/null
+++ b/mvpsdk/src/main/java/com/share/mvpsdk/utils/ThemeUtils.java
@@ -0,0 +1,75 @@
+package com.share.mvpsdk.utils;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.support.annotation.AttrRes;
+import android.support.annotation.NonNull;
+
+import com.share.mvpsdk.R;
+
+
+/**
+ * 作者:杭鹏伟
+ * 日期:16-7-8 15:15
+ * 邮箱:424346976@qq.com
+ */
+public class ThemeUtils {
+ public static int[][] themeArr = {
+ {R.style.AppThemeLight_Red, R.style.AppThemeDark_Red},
+ {R.style.AppThemeLight_Pink, R.style.AppThemeDark_Pink},
+ {R.style.AppThemeLight_Purple, R.style.AppThemeDark_Purple},
+ {R.style.AppThemeLight_DeepPurple, R.style.AppThemeDark_DeepPurple},
+ {R.style.AppThemeLight_Indigo, R.style.AppThemeDark_Indigo},
+ {R.style.AppThemeLight_Blue, R.style.AppThemeDark_Blue},
+ {R.style.AppThemeLight_LightBlue, R.style.AppThemeDark_LightBlue},
+ {R.style.AppThemeLight_Cyan, R.style.AppThemeDark_Cyan},
+ {R.style.AppThemeLight_Teal, R.style.AppThemeDark_Teal},
+ {R.style.AppThemeLight_Green, R.style.AppThemeDark_Green},
+ {R.style.AppThemeLight_LightGreen, R.style.AppThemeDark_LightGreen},
+ {R.style.AppThemeLight_Lime, R.style.AppThemeDark_Lime},
+ {R.style.AppThemeLight_Yellow, R.style.AppThemeDark_Yellow},
+ {R.style.AppThemeLight_Amber, R.style.AppThemeDark_Amber},
+ {R.style.AppThemeLight_Orange, R.style.AppThemeDark_Orange},
+ {R.style.AppThemeLight_DeepOrange, R.style.AppThemeDark_DeepOrange},
+ {R.style.AppThemeLight_Brown, R.style.AppThemeDark_Brown},
+ {R.style.AppThemeLight_Grey, R.style.AppThemeDark_Grey},
+ {R.style.AppThemeLight_BlueGrey, R.style.AppThemeDark_BlueGrey}
+ };
+
+ public static int[][] themeColorArr = {
+ {R.color.md_red_500, R.color.md_red_700}, {R.color.md_pink_500, R.color.md_pink_700},
+ {R.color.md_purple_500, R.color.md_purple_700},
+ {R.color.md_deep_purple_500, R.color.md_deep_purple_700},
+ {R.color.md_indigo_500, R.color.md_indigo_700},
+ {R.color.md_blue_500, R.color.md_blue_700},
+ {R.color.md_light_blue_500, R.color.md_light_blue_700},
+ {R.color.md_cyan_500, R.color.md_cyan_700}, {R.color.md_teal_500, R.color.md_teal_500},
+ {R.color.md_green_500, R.color.md_green_500},
+ {R.color.md_light_green_500, R.color.md_light_green_500},
+ {R.color.md_lime_500, R.color.md_lime_700},
+ {R.color.md_yellow_500, R.color.md_yellow_700},
+ {R.color.md_amber_500, R.color.md_amber_700},
+ {R.color.md_orange_500, R.color.md_orange_700},
+ {R.color.md_deep_orange_500, R.color.md_deep_orange_700},
+ {R.color.md_brown_500, R.color.md_brown_700}, {R.color.md_grey_500, R.color.md_grey_700},
+ {R.color.md_blue_grey_500, R.color.md_blue_grey_700}
+ };
+
+ public static int getTheme(Context context) {
+ return context.getResources()
+ .getColor(themeColorArr[SpUtils.getThemeIndex(context)][0]);
+ }
+
+ public static int getThemeColor(@NonNull Context context) {
+ return getThemeAttrColor(context, R.attr.colorPrimary);
+ }
+
+ public static int getThemeAttrColor(@NonNull Context context, @AttrRes int attr) {
+ TypedArray a = context.obtainStyledAttributes(null, new int[]{attr});
+ try {
+ return a.getColor(0, 0);
+ } finally {
+ a.recycle();
+ }
+ }
+}
diff --git a/mvpsdk/src/main/java/com/share/mvpsdk/utils/TimestampUtils.java b/mvpsdk/src/main/java/com/share/mvpsdk/utils/TimestampUtils.java
new file mode 100644
index 0000000..355308a
--- /dev/null
+++ b/mvpsdk/src/main/java/com/share/mvpsdk/utils/TimestampUtils.java
@@ -0,0 +1,57 @@
+package com.share.mvpsdk.utils;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.TimeZone;
+
+public class TimestampUtils {
+ /**
+ * 获取当前的时间戳,时区为北京
+ *
+ * @return
+ */
+ public static String getCurrentTimestamp() {
+ //时间戳的格式必须为 yyyy-MM-dd HH:mm:ss
+ String timestamp = null;
+ SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+ timestamp = format.format(new Date());
+ return timestamp;
+ }
+
+ /**
+ * 获取当前的时间戳,时区为北京
+ *
+ * @return
+ */
+ public static String getCurrentTime(long times) {
+ //时间戳的格式必须为 yyyy-MM-dd HH:mm:ss
+ Date date = new Date(Long.valueOf(times));
+ SimpleDateFormat format = new SimpleDateFormat(
+ "yyyy-MM-dd HH:mm:ss");
+ String time = format.format(date);
+ LogUtils.e("timetimetimetimetimetimetime为:" + time);
+
+ new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
+ .format(new Date());
+
+ return time;
+ }
+
+ //法国时间:东一区
+ public static String getDateTimeByGMT(int timeZone) {
+ SimpleDateFormat dff = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+ switch (timeZone) {
+ case 1:
+ dff.setTimeZone(TimeZone.getTimeZone("GMT+1"));
+ break;
+ case 8:
+ dff.setTimeZone(TimeZone.getTimeZone("GMT+8"));
+ //LogUtils.i("采用东八区时区");
+ break;
+ }
+
+ String time = dff.format(new Date());
+ //LogUtils.i("东八区时区时间为--》》" + time);
+ return time;
+ }
+}
diff --git a/mvpsdk/src/main/java/com/share/mvpsdk/utils/ToastUtils.java b/mvpsdk/src/main/java/com/share/mvpsdk/utils/ToastUtils.java
new file mode 100644
index 0000000..26c212e
--- /dev/null
+++ b/mvpsdk/src/main/java/com/share/mvpsdk/utils/ToastUtils.java
@@ -0,0 +1,66 @@
+package com.share.mvpsdk.utils;
+
+import android.content.Context;
+import android.widget.Toast;
+
+/**
+ * Created by Horrarndoo on 2017/4/5.
+ *
+ * toast工具类封装
+ */
+public class ToastUtils {
+ private static Toast mToast = null;
+
+ /**
+ * 显示一个toast提示
+ *
+ * @param resouceId toast字符串资源id
+ */
+ public static void showToast(int resouceId) {
+ showToast(ResourcesUtils.getString(resouceId));
+ }
+
+ /**
+ * 显示一个toast提示
+ *
+ * @param text toast字符串
+ */
+ public static void showToast(String text) {
+ showToast(text, Toast.LENGTH_SHORT);
+ }
+
+ /**
+ * 显示一个toast提示
+ *
+ * @param text toast字符串
+ * @param duration toast显示时间
+ */
+ public static void showToast(String text, int duration) {
+ showToast(AppUtils.getContext(), text, duration);
+ }
+
+ /**
+ * 显示一个toast提示
+ *
+ * @param context context 上下文对象
+ * @param text toast字符串
+ * @param duration toast显示时间
+ */
+ public static void showToast(final Context context, final String text, final int duration) {
+ /**
+ * 保证运行在主线程
+ */
+ AppUtils.runOnUIThread(new Runnable() {
+ @Override
+ public void run() {
+ if (mToast == null) {
+ mToast = Toast.makeText(context, text, duration);
+ } else {
+ mToast.setText(text);
+ mToast.setDuration(duration);
+ }
+ mToast.show();
+ }
+ });
+ }
+}
diff --git a/mvpsdk/src/main/java/com/share/mvpsdk/utils/UnicodeUtils.java b/mvpsdk/src/main/java/com/share/mvpsdk/utils/UnicodeUtils.java
new file mode 100644
index 0000000..59fc277
--- /dev/null
+++ b/mvpsdk/src/main/java/com/share/mvpsdk/utils/UnicodeUtils.java
@@ -0,0 +1,108 @@
+package com.share.mvpsdk.utils;
+
+/**
+ * Created by Horrarndoo on 2017/10/11.
+ *
+ */
+public class UnicodeUtils {
+ /**
+ * utf-8 转换成 unicode
+ *
+ * @param inStr
+ * @return
+ */
+ public static String utf8ToUnicode(String inStr) {
+ char[] myBuffer = inStr.toCharArray();
+
+ StringBuffer sb = new StringBuffer();
+ for (int i = 0; i < inStr.length(); i++) {
+ Character.UnicodeBlock ub = Character.UnicodeBlock.of(myBuffer[i]);
+ if (ub == Character.UnicodeBlock.BASIC_LATIN) {
+ //英文及数字等
+ sb.append(myBuffer[i]);
+ } else if (ub == Character.UnicodeBlock.HALFWIDTH_AND_FULLWIDTH_FORMS) {
+ //全角半角字符
+ int j = (int) myBuffer[i] - 65248;
+ sb.append((char) j);
+ } else {
+ //汉字
+ short s = (short) myBuffer[i];
+ String hexS = Integer.toHexString(s);
+ String unicode = "\\u" + hexS;
+ sb.append(unicode.toLowerCase());
+ }
+ }
+ return sb.toString();
+ }
+
+ /**
+ * unicode 转换成 utf-8
+ *
+ * @param theString
+ * @return
+ */
+ public static String unicodeToUtf8(String theString) {
+ char aChar;
+ int len = theString.length();
+ StringBuffer outBuffer = new StringBuffer(len);
+ for (int x = 0; x < len; ) {
+ aChar = theString.charAt(x++);
+ if (aChar == '\\') {
+ aChar = theString.charAt(x++);
+ if (aChar == 'u') {
+ // Read the xxxx
+ int value = 0;
+ for (int i = 0; i < 4; i++) {
+ aChar = theString.charAt(x++);
+ switch (aChar) {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ value = (value << 4) + aChar - '0';
+ break;
+ case 'a':
+ case 'b':
+ case 'c':
+ case 'd':
+ case 'e':
+ case 'f':
+ value = (value << 4) + 10 + aChar - 'a';
+ break;
+ case 'A':
+ case 'B':
+ case 'C':
+ case 'D':
+ case 'E':
+ case 'F':
+ value = (value << 4) + 10 + aChar - 'A';
+ break;
+ default:
+ throw new IllegalArgumentException(
+ "Malformed \\uxxxx encoding.");
+ }
+ }
+ outBuffer.append((char) value);
+ } else {
+ if (aChar == 't')
+ aChar = '\t';
+ else if (aChar == 'r')
+ aChar = '\r';
+ else if (aChar == 'n')
+ aChar = '\n';
+ else if (aChar == 'f')
+ aChar = '\f';
+ outBuffer.append(aChar);
+ }
+ } else
+ outBuffer.append(aChar);
+ }
+ return outBuffer.toString();
+ }
+}
\ No newline at end of file
diff --git a/mvpsdk/src/main/java/com/share/mvpsdk/utils/WifiAutoConnectManager.java b/mvpsdk/src/main/java/com/share/mvpsdk/utils/WifiAutoConnectManager.java
new file mode 100644
index 0000000..7a8320b
--- /dev/null
+++ b/mvpsdk/src/main/java/com/share/mvpsdk/utils/WifiAutoConnectManager.java
@@ -0,0 +1,224 @@
+package com.share.mvpsdk.utils;
+
+import android.content.Context;
+import android.net.wifi.ScanResult;
+import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiManager;
+
+import java.util.List;
+
+/**
+ * Created by Horrarndoo on 2017/8/10.
+ *
+ * 兼容Android 6.0以上手机连接wifi
+ */
+
+public class WifiAutoConnectManager {
+
+ private static final String TAG = WifiAutoConnectManager.class
+ .getSimpleName();
+
+ WifiManager wifiManager;
+
+ // 定义几种加密方式,一种是WEP,一种是WPA,还有没有密码的情况
+ public enum WifiCipherType {
+ WIFICIPHER_WEP, WIFICIPHER_WPA, WIFICIPHER_NOPASS, WIFICIPHER_INVALID
+ }
+
+ // 构造函数
+ public WifiAutoConnectManager(WifiManager wifiManager) {
+ this.wifiManager = wifiManager;
+ }
+
+ // 提供一个外部接口,传入要连接的无线网
+ public void connect(String ssid, String password, WifiCipherType type) {
+ Thread thread = new Thread(new ConnectRunnable(ssid, password, type));
+ thread.start();
+ }
+
+ // 查看以前是否也配置过这个网络
+ private WifiConfiguration isExsits(String SSID) {
+ List existingConfigs = wifiManager
+ .getConfiguredNetworks();
+ for (WifiConfiguration existingConfig : existingConfigs) {
+ if (existingConfig.SSID.equals("\"" + SSID + "\"")) {
+ return existingConfig;
+ }
+ }
+ return null;
+ }
+
+ private WifiConfiguration createWifiInfo(String SSID, String Password,
+ WifiCipherType Type) {
+ WifiConfiguration config = new WifiConfiguration();
+ config.allowedAuthAlgorithms.clear();
+ config.allowedGroupCiphers.clear();
+ config.allowedKeyManagement.clear();
+ config.allowedPairwiseCiphers.clear();
+ config.allowedProtocols.clear();
+ config.SSID = "\"" + SSID + "\"";
+ // config.SSID = SSID;
+ // nopass
+ if (Type == WifiCipherType.WIFICIPHER_NOPASS) {
+ // config.wepKeys[0] = "";
+ config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
+ // config.wepTxKeyIndex = 0;
+ }
+ // wep
+ if (Type == WifiCipherType.WIFICIPHER_WEP) {
+ if (!StringUtils.isEmpty(Password)) {
+ if (isHexWepKey(Password)) {
+ config.wepKeys[0] = Password;
+ } else {
+ config.wepKeys[0] = "\"" + Password + "\"";
+ }
+ }
+ config.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN);
+ config.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.SHARED);
+ config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
+ config.wepTxKeyIndex = 0;
+ }
+ // wpa
+ if (Type == WifiCipherType.WIFICIPHER_WPA) {
+ config.preSharedKey = "\"" + Password + "\"";
+ config.hiddenSSID = true;
+ config.allowedAuthAlgorithms
+ .set(WifiConfiguration.AuthAlgorithm.OPEN);
+ config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP);
+ config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
+ config.allowedPairwiseCiphers
+ .set(WifiConfiguration.PairwiseCipher.TKIP);
+ // 此处需要修改否则不能自动重联
+ // config.allowedProtocols.set(WifiConfiguration.Protocol.WPA);
+ config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
+ config.allowedPairwiseCiphers
+ .set(WifiConfiguration.PairwiseCipher.CCMP);
+ config.status = WifiConfiguration.Status.ENABLED;
+
+ }
+ return config;
+ }
+
+ // 打开wifi功能
+ private boolean openWifi() {
+ boolean bRet = true;
+ if (!wifiManager.isWifiEnabled()) {
+ bRet = wifiManager.setWifiEnabled(true);
+ }
+ return bRet;
+ }
+
+ // 关闭WIFI
+ private void closeWifi() {
+ if (wifiManager.isWifiEnabled()) {
+ wifiManager.setWifiEnabled(false);
+ }
+ }
+
+ class ConnectRunnable implements Runnable {
+ private String ssid;
+
+ private String password;
+
+ private WifiCipherType type;
+
+ public ConnectRunnable(String ssid, String password, WifiCipherType type) {
+ this.ssid = ssid;
+ this.password = password;
+ this.type = type;
+ }
+
+ @Override
+ public void run() {
+ // 打开wifi
+ openWifi();
+ // 开启wifi功能需要一段时间(我在手机上测试一般需要1-3秒左右),所以要等到wifi
+ // 状态变成WIFI_STATE_ENABLED的时候才能执行下面的语句
+ while (wifiManager.getWifiState() == WifiManager.WIFI_STATE_ENABLING) {
+ try {
+ // 为了避免程序一直while循环,让它睡个100毫秒检测……
+ Thread.sleep(100);
+
+ } catch (InterruptedException ie) {
+ LogUtils.e(ie.toString());
+ }
+ }
+
+ WifiConfiguration tempConfig = isExsits(ssid);
+
+ if (tempConfig != null) {
+ boolean b = wifiManager.enableNetwork(tempConfig.networkId,
+ true);
+ } else {
+ WifiConfiguration wifiConfig = createWifiInfo(ssid, password,
+ type);
+ if (wifiConfig == null) {
+ LogUtils.d("wifiConfig is null!");
+ return;
+ }
+
+ int netID = wifiManager.addNetwork(wifiConfig);
+ boolean enabled = wifiManager.enableNetwork(netID, true);
+ LogUtils.d("enableNetwork status enable=" + enabled);
+ boolean connected = wifiManager.reconnect();
+ LogUtils.d("enableNetwork connected=" + connected);
+ }
+
+ }
+ }
+
+ private static boolean isHexWepKey(String wepKey) {
+ final int len = wepKey.length();
+
+ // WEP-40, WEP-104, and some vendors using 256-bit WEP (WEP-232?)
+ if (len != 10 && len != 26 && len != 58) {
+ return false;
+ }
+
+ return isHex(wepKey);
+ }
+
+ private static boolean isHex(String key) {
+ for (int i = key.length() - 1; i >= 0; i--) {
+ final char c = key.charAt(i);
+ if (!(c >= '0' && c <= '9' || c >= 'A' && c <= 'F' || c >= 'a'
+ && c <= 'f')) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ // 获取ssid的加密方式
+ public static WifiCipherType getCipherType(Context context, String ssid) {
+ WifiManager wifiManager = (WifiManager) context
+ .getSystemService(Context.WIFI_SERVICE);
+
+ List list = wifiManager.getScanResults();
+
+ for (ScanResult scResult : list) {
+
+ if (!StringUtils.isEmpty(scResult.SSID) && scResult.SSID.equals(ssid)) {
+ String capabilities = scResult.capabilities;
+
+ if (!StringUtils.isEmpty(capabilities)) {
+
+ if (capabilities.contains("WPA")
+ || capabilities.contains("wpa")) {
+ LogUtils.i("wpa");
+ return WifiCipherType.WIFICIPHER_WPA;
+ } else if (capabilities.contains("WEP")
+ || capabilities.contains("wep")) {
+ LogUtils.i("wep");
+ return WifiCipherType.WIFICIPHER_WEP;
+ } else {
+ LogUtils.i("no");
+ return WifiCipherType.WIFICIPHER_NOPASS;
+ }
+ }
+ }
+ }
+ return WifiCipherType.WIFICIPHER_INVALID;
+ }
+}
\ No newline at end of file
diff --git a/mvpsdk/src/main/java/com/share/mvpsdk/view/MyEyeView.java b/mvpsdk/src/main/java/com/share/mvpsdk/view/MyEyeView.java
new file mode 100644
index 0000000..4c7dcf7
--- /dev/null
+++ b/mvpsdk/src/main/java/com/share/mvpsdk/view/MyEyeView.java
@@ -0,0 +1,71 @@
+package com.share.mvpsdk.view;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Shader;
+import android.support.annotation.Nullable;
+import android.util.AttributeSet;
+import android.view.View;
+
+/**
+ * Created by ToaHanDong on 2018/2/7.
+ */
+
+public class MyEyeView extends View {
+
+ Paint myPaint;
+
+ int mypaintWidth=2;
+
+ int centerLeft=0,centerTop=0,centerRight=0,centerBottom=0;
+ public MyEyeView(Context context) {
+ super(context);
+ init(context);
+ }
+
+ public MyEyeView(Context context, @Nullable AttributeSet attrs) {
+ super(context, attrs);
+ init(context);
+ }
+
+ public MyEyeView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ init(context);
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+ while (centerLeft>0){
+ centerLeft-=10;
+ centerTop-=10;
+ centerRight+=10;
+ centerBottom+=10;
+ canvas.drawRect(centerLeft,centerTop,centerRight,centerBottom,myPaint);
+ }
+ }
+
+ private void init(Context context) {
+ myPaint=new Paint();
+ myPaint.setColor(Color.WHITE);
+ myPaint.setAntiAlias(true);
+ myPaint.setStyle(Paint.Style.STROKE);
+ myPaint.setStrokeWidth(mypaintWidth);
+// myPaint.setShader(new Shader());
+ }
+
+ public void setMyPaintWidth(int paintWidth){
+ mypaintWidth=paintWidth;
+ }
+
+ public void setIndexPoint(int centerLeft,int centerTop,int centerRight,int centerBottom){
+ this.centerLeft=centerLeft;
+ this.centerTop=centerTop;
+ this.centerRight=centerRight;
+ this.centerBottom=centerBottom;
+ invalidate();
+ }
+
+}
diff --git a/mvpsdk/src/main/java/com/share/mvpsdk/view/MyViewView.java b/mvpsdk/src/main/java/com/share/mvpsdk/view/MyViewView.java
new file mode 100644
index 0000000..95486bd
--- /dev/null
+++ b/mvpsdk/src/main/java/com/share/mvpsdk/view/MyViewView.java
@@ -0,0 +1,368 @@
+package com.share.mvpsdk.view;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.net.http.SslError;
+import android.os.Build;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.View;
+import android.webkit.JavascriptInterface;
+import android.webkit.JsPromptResult;
+import android.webkit.JsResult;
+import android.webkit.SslErrorHandler;
+import android.webkit.WebChromeClient;
+import android.webkit.WebResourceError;
+import android.webkit.WebResourceRequest;
+import android.webkit.WebResourceResponse;
+import android.webkit.WebSettings;
+import android.webkit.WebView;
+import android.webkit.WebViewClient;
+import android.widget.FrameLayout;
+
+import com.share.mvpsdk.utils.FileUtils;
+import com.share.mvpsdk.utils.NetworkConnectionUtils;
+
+/**
+ * Created by ToaHanDong on 2018/1/25.
+ */
+
+public class MyViewView extends WebView {
+
+ public MyViewView(Context context) {
+ super(context);
+ init(context);
+ }
+
+ public MyViewView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ init(context);
+ }
+
+ public MyViewView(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ init(context);
+ }
+
+ private String TAG="MyWebView";
+ //WebView的设置类
+ private WebSettings webSettings = null;
+
+ private void init(Context context) {
+
+ initWebSetting(context);
+
+ }
+
+ private void initWebSetting(Context context) {
+
+ webSettings = getSettings();//初始化websettings
+
+ //如果访问的页面中要与Javascript交互,则webview必须设置支持Javascript
+ webSettings.setJavaScriptEnabled(true);
+ //支持插件
+ webSettings.setPluginState(WebSettings.PluginState.ON);
+ //设置自适应屏幕,两者合用
+ webSettings.setUseWideViewPort(true);//将图片调整适合WebView的大小
+ webSettings.setLoadWithOverviewMode(true);//缩放至屏幕的大小
+ //缩放操作
+ webSettings.setSupportZoom(true); //支持缩放,默认为true。是下面那个的前提。
+ webSettings.setBuiltInZoomControls(true);//设置内置的缩放控件。若为false,则该WebView不可缩放
+ webSettings.setDisplayZoomControls(true);//隐藏原生的缩放控件
+ //其他细节操作
+ //LOAD_CACHE_ONLY: 不使用网络,只读取本地缓存数据
+ //LOAD_DEFAULT: (默认)根据cache-control决定是否从网络上取数据。
+ //LOAD_NO_CACHE: 不使用缓存,只从网络获取数据.
+ //LOAD_CACHE_ELSE_NETWORK,只要本地有,无论是否过期,或者no-cache,都使用缓存中的数据。
+// webSettings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK); //关闭webview中缓存
+ webSettings.setAllowFileAccess(true);//设置可以访问文件
+ webSettings.setJavaScriptCanOpenWindowsAutomatically(true);//支持通过js打开新窗口
+ webSettings.setLoadsImagesAutomatically(true);//设置自动加载图片
+ webSettings.setDefaultTextEncodingName("utf-8");//设置编码格式为ytf-8
+ if (NetworkConnectionUtils.isConnected(context))
+ webSettings.setCacheMode(WebSettings.LOAD_DEFAULT);
+ else webSettings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);
+ webSettings.setDomStorageEnabled(true); // 开启 DOM storage API 功能
+ webSettings.setDatabaseEnabled(true); //开启 database storage API 功能
+ webSettings.setAppCacheEnabled(true);//开启 Application Caches 功能
+ if (!FileUtils.webViewCacheIsExit()) {
+ webSettings.setAppCachePath(FileUtils.getCache()); //设置 Application Caches 缓存目录,只能设置一次
+ webSettings.setAppCacheMaxSize(8 * 1024 * 1024);
+ }
+ }
+
+ FrameLayout frame;
+ public void setView(FrameLayout frame) {
+ this.frame=frame;
+ }
+
+ /**
+ * js接口
+ */
+ public class SupportJavascriptInterface {
+ private Context context;
+
+ public SupportJavascriptInterface(Context context) {
+ this.context = context;
+ }
+
+ @JavascriptInterface
+ public void openImage(final String img) {
+ Log.d(TAG,"openImage="+img);
+// goBackOrForward(-1);
+// AppUtils.runOnUIThread(new Runnable() {
+// @Override
+// public void run() {
+// gotoImageBrowse(img);
+// }
+// });
+ }
+ }
+
+ // WebViewClient类(主要作用是:处理各种通知 & 请求事件)
+ public void setMyWebViewClient(String url) {
+ //步骤1: 选择加载方式
+//方式a. 加载一个网页:
+ loadUrl(url);
+//方式b:加载apk包中的html页面
+// loadUrl("file:///android_asset/test.html");
+//方式c:加载手机本地的html页面
+// loadUrl("content://com.android.htmlfileprovider/sdcard/test.html");
+ addJavascriptInterface(new SupportJavascriptInterface(getContext()),"imagelistener");
+ setWebViewClient(new WebViewClient() {
+
+ //设定加载开始的操作
+ @Override
+ public void onPageStarted(WebView view, String url, Bitmap favicon) {
+ super.onPageStarted(view, url, favicon);
+ Log.d(TAG,"onPageStarted="+url+"favicon="+favicon);
+ }
+
+ //html加载完成
+ @Override
+ public void onPageFinished(WebView view, String url) {
+ super.onPageFinished(view, url);
+ Log.d(TAG,"onPageFinished="+url);
+ addWebImageClickListner(view);
+ }
+
+ // 注入js函数监听
+ protected void addWebImageClickListner(WebView webView) {
+ // 这段js函数的功能就是,遍历所有的img节点,并添加onclick函数,
+ // 函数的功能是在图片点击的时候调用本地java接口并传递url过去
+ webView.loadUrl("javascript:(function(){" +
+ "var objs = document.getElementsByTagName(\"img\"); " +
+ "for(var i=0;i= Build.VERSION_CODES.M) {
+// switch (error.getErrorCode())
+// }
+// }
+
+ @Override
+ public boolean shouldOverrideUrlLoading(WebView view, String url) {
+ view.loadUrl(url);
+ return true;
+ }
+
+ //webView默认是不处理https请求的,页面显示空白,需要进行如下设置:
+ @Override
+ public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
+ super.onReceivedSslError(view, handler, error);
+ Log.d(TAG,"onReceivedSslError");
+ handler.proceed();//表示等待证书响应
+ }
+ });
+
+ }
+
+ //辅助 WebView 处理 Javascript 的对话框,网站图标,网站标题等等。
+ public void setMyWebChromeClient(){
+ setWebChromeClient(new WebChromeClient(){
+
+ @Override
+ public void onShowCustomView(View view, CustomViewCallback callback) {
+ super.onShowCustomView(view, callback);
+ Log.d(TAG,"onShowCustomView=");
+ }
+
+ @Override
+ public void onProgressChanged(WebView view, int newProgress) {
+ super.onProgressChanged(view, newProgress);
+ Log.d(TAG,"newProgress="+newProgress);
+ }
+
+ @Override
+ public void onReceivedTitle(WebView view, String title) {
+ super.onReceivedTitle(view, title);
+ Log.d(TAG,"onReceivedTitle="+title);
+ }
+
+ /**
+ * js中的弹出框
+ * @param view
+ * @param url
+ * @param message
+ * @param result 可以对弹出框做取消和确认操作
+ * @return
+ */
+ @Override
+ public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
+ Log.d(TAG,"onJsAlert="+message+"url="+url);
+ return super.onJsAlert(view, url, message, result);
+ }
+
+// 支持javascript输入框,点击确认返回输入框中的值,点击取消返回 null。
+ @Override
+ public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) {
+ return super.onJsPrompt(view, url, message, defaultValue, result);
+ }
+ });
+ }
+
+
+ //WebView的状态
+
+ /**
+ * 激活webView为活跃状态,能正常执行网页的响应
+ */
+ public void setonResume() {
+ onResume();
+ }
+
+ /**
+ * 当页面被失去焦点被切换到后台不可见状态,需要执行onPause
+ * 通过onPause动作通知内核暂停所有的动作,比如DOM的解析、plugin的执行、JavaScript执行。
+ */
+ public void setOnPause() {
+ onPause();
+ }
+
+ /**
+ * 当应用程序(存在webview)被切换到后台时,这个方法不仅仅针对当前的webview而是全局的全应用程序的webview
+ * 它会暂停所有webview的layout,parsing,javascripttimer。降低CPU功耗。
+ */
+ public void setPauseTimers() {
+ pauseTimers();
+ }
+
+ /**
+ * 恢复pauseTimers状态
+ */
+ public void setResumeTimers() {
+ resumeTimers();
+ }
+
+ public void destroyWebView() {
+ removeView(this);
+ destroy();
+ }
+
+ //WebView的简单操作
+
+ /**
+ * 判断网页是否可以回退
+ *
+ * @return
+ */
+ public boolean getCanGoBack() {
+ return canGoBack();
+ }
+
+ /**
+ * 回退网页
+ */
+ public void setGoBack() {
+ goBack();
+ }
+
+ /**
+ * 设置是否可以前进
+ *
+ * @return
+ */
+ public boolean setCanForward() {
+ return canGoForward();
+ }
+
+ /**
+ * 前进网页
+ */
+ public void setGoForward() {
+ goForward();
+ }
+
+ /**
+ * 以当前的index为起始点前进或者后退到历史记录中指定的steps
+ * 如果steps为负数则为后退,正数则为前进
+ *
+ * @param steps
+ */
+ public void setGoBackOrForward(int steps) {
+ goBackOrForward(steps);
+ }
+
+ //清除缓存数据
+
+ /**
+ * 清除网页访问留下的缓存
+ * 由于内核缓存是全局的因此这个方法不仅仅针对webview而是针对整个应用程序.
+ *
+ * @param isClear
+ */
+ public void clearMyCache(boolean isClear) {
+ clearCache(isClear);
+ }
+
+ /**
+ * 清除当前webview访问的历史记录
+ * 只会webview访问历史记录里的所有记录除了当前访问记录
+ */
+ public void clearMyHistory() {
+
+ }
+
+ /**
+ * 这个api仅仅清除自动完成填充的表单数据,并不会清除WebView存储到本地的数据
+ */
+ public void clearMyFormData() {
+ clearFormData();
+ }
+
+
+}
diff --git a/mvpsdk/src/main/java/com/share/mvpsdk/widgets/CompatNestedScrollView.java b/mvpsdk/src/main/java/com/share/mvpsdk/widgets/CompatNestedScrollView.java
new file mode 100644
index 0000000..6ebaf09
--- /dev/null
+++ b/mvpsdk/src/main/java/com/share/mvpsdk/widgets/CompatNestedScrollView.java
@@ -0,0 +1,86 @@
+package com.share.mvpsdk.widgets;
+
+import android.content.Context;
+import android.support.v4.widget.NestedScrollView;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.share.mvpsdk.utils.AppUtils;
+import com.share.mvpsdk.utils.DisplayUtils;
+import com.share.mvpsdk.utils.StatusBarUtils;
+
+
+/**
+ * Created by Horrarndoo on 2017/10/19.
+ *
+ * 自定义NestedScrollView,主要实现根据滑动距离控制绑定View的alpha值
+ */
+
+public class CompatNestedScrollView extends NestedScrollView {
+ private ViewGroup childViewGroup;
+ private View headView;
+ private View bindView;
+
+ public CompatNestedScrollView(Context context) {
+ super(context);
+ }
+
+ public CompatNestedScrollView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public CompatNestedScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ if (getChildCount() > 1) {
+ throw new IllegalArgumentException("only can 1 child in this view");
+ } else {
+ if (getChildAt(0) instanceof ViewGroup) {
+ childViewGroup = (ViewGroup) getChildAt(0);
+ if (childViewGroup != null) {
+ headView = childViewGroup.getChildAt(0);
+ }
+ } else {
+ throw new IllegalArgumentException("child must be instanceof ViewGroup");
+ }
+ }
+ }
+
+ @Override
+ protected void onScrollChanged(int l, int t, int oldl, int oldt) {
+ super.onScrollChanged(l, t, oldl, oldt);
+ float alpha = 1.f;
+ if (headView != null && bindView != null) {
+ //如果上滑超过toolbar高度,开启伴随动画
+ //Logger.e("t = " + t);
+ //Logger.e("headView.getHeight = " + headView.getHeight());
+ float slideValue = t - (DisplayUtils.dp2px(56) + StatusBarUtils.getStatusBarHeight
+ (AppUtils.getContext()));
+
+ if (slideValue < 0)
+ slideValue = 0;
+
+ float fraction = slideValue / (headView.getHeight() / 2.f);
+ if (fraction > 1) {
+ fraction = 1;
+ }
+
+ alpha *= fraction;
+ bindView.setAlpha(alpha);
+ }
+ }
+
+ /**
+ * 绑定要变化Alpha的view
+ *
+ * @param view 要变化Alpha的view
+ */
+ public void bindAlphaView(View view) {
+ bindView = view;
+ }
+}
diff --git a/mvpsdk/src/main/java/com/share/mvpsdk/widgets/HistoryChartView.java b/mvpsdk/src/main/java/com/share/mvpsdk/widgets/HistoryChartView.java
new file mode 100644
index 0000000..b59bed1
--- /dev/null
+++ b/mvpsdk/src/main/java/com/share/mvpsdk/widgets/HistoryChartView.java
@@ -0,0 +1,719 @@
+package com.share.mvpsdk.widgets;
+
+
+import android.animation.ValueAnimator;
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.DashPathEffect;
+import android.graphics.Paint;
+import android.graphics.Path;
+import android.graphics.PathEffect;
+import android.graphics.PathMeasure;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.animation.DecelerateInterpolator;
+
+import com.share.mvpsdk.R;
+import com.share.mvpsdk.utils.DisplayUtils;
+
+
+/**
+ * 历史记录查询图表 基于pathMeasure+DashPathEffect+属性动画实现
+ * 绘制时采取双缓冲绘制
+ *
+ * @author zyw
+ * @creation 2017-03-06
+ */
+public class HistoryChartView extends View {
+
+ private String TAG = "HistoryChartView";
+
+ TypedArray ta;
+
+ private float MarginTop = 100;
+
+ private float MarginBottom = 100;
+
+ private float MarginLeft = 100;
+
+ private float MarginRight = 100;
+
+ private float mYLabelSize = 50;
+
+ private float mXlabelSize = 35;
+
+ private float mXUnitTextSize;
+
+ private float mYUnitTextSize;
+
+ // 圆半径
+ private int circleRadius = 8;
+
+ private int lineStrokeWidth = 3;
+
+ private int dataStrokeWidth = 3;
+
+ private static final long ANIM_DURATION = 1500;
+ private PathMeasure mRoomTempPathMeasure;
+ private PathMeasure mTargetTempPathMeasure;
+ private Path mRoomTempPath;
+ private Path mTargetTempPath;
+ private Paint mBmpPaint;
+ /**
+ * 柱形绘制进度
+ */
+ private float mRectFration;
+
+ // X,Y轴的单位长度
+ private float Xscale = 20;
+ private float Yscale = 20;
+
+ // 绘制X轴总长度
+ private float xLength;
+ // 绘制Y轴总长度
+ private float yLength;
+
+ // X轴第1个节点的偏移位置
+ private float xFirstPointOffset;
+
+ // y轴显示的节点间隔距离
+ private int yScaleForData = 1;
+
+ // x轴显示的节点间隔距离
+ private int xScaleForData = 1;
+
+ // 画线颜色
+ private int lineColor;
+
+ private int roomTempLineColor;
+ private int targetTempLineColor;
+ private int powerTimeLineColor;
+ private int mUnitColor;
+
+ private String mXUnitText;
+ private String mY1UnitText;
+ private String mY2UnitText;
+
+ private int mMode = 1;// 从Activity传过来的模式值 1:天 2:周 3:月 4:年
+
+ // 原点坐标
+ private float Xpoint;
+ private float Ypoint;
+
+ // X,Y轴上面的显示文字
+ private String[] Xlabel = {"1", "2", "3", "4", "5", "6", "7"};
+ private String[] Ylabel = {"0", "9", "18", "27", "36"};
+ private String[] Ylabel2 = {"0", "25", "50", "75", "100"};
+
+ private final static int X_SCALE_FOR_DATA_DAY = 2;
+ private final static int X_SCALE_FOR_DATA_WEEK = 1;
+ private final static int X_SCALE_FOR_DATA_YEAR = 1;
+ private final static int X_SCALE_FOR_DATA_MOUNTH = 5;
+
+ private final static int DAY_MODE = 0;
+ private final static int WEEK_MODE = 1;
+ private final static int MONTH_MODE = 2;
+ private final static int YEAR_MODE = 3;
+
+ // 曲线数据
+ private float[] roomTempDataArray = {15, 15, 15, 15, 15, 15, 15};
+ private float[] targetTempDataArray = {16, 16, 16, 16, 16, 16, 16};
+ private float[] powerOnTimeDataArray = {100, 100, 100, 100, 100, 100, 100};
+
+ /**
+ * 各条柱形图当前top值数组
+ */
+ private Float[] rectCurrentTops;
+
+ private ValueAnimator mValueAnimator;
+
+ private Paint linePaint;
+ private Paint targetTempPaint;
+ private Paint roomTempPaint;
+ private PathEffect mRoomTempEffect;
+ private PathEffect mtargetTempEffect;
+ //定义一个内存中的图片,该图片将作为缓冲区
+ Bitmap mCacheBitmap = null;
+ //定义cacheBitmap上的Canvas对象
+ Canvas mCacheCanvas = null;
+
+ public HistoryChartView(Context context, String[] xlabel, String[] ylabel,
+ float[] roomDataArray) {
+ super(context);
+ this.Xlabel = xlabel;
+ this.Ylabel = ylabel;
+ this.roomTempDataArray = roomDataArray;
+ }
+
+ public HistoryChartView(Context context, AttributeSet attrs,
+ int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ //Logger.e("HistoryChartView(Context context, AttributeSet attrs, int defStyleAttr)");
+
+ ta = context.obtainStyledAttributes(attrs, R.styleable.HistoryChartView);
+
+ setDefaultAttrrbutesValue();
+
+ initPaint();
+
+ initData();
+
+ initParams();
+
+ initPath();
+
+ ta.recycle();
+ }
+
+ public HistoryChartView(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public HistoryChartView(Context context) {
+ this(context, null);
+ }
+
+ /**
+ * 设置显示数据
+ *
+ * @param strAlldata 历史数据全状态
+ * @param mode 历史数据模式
+ */
+ public void setData(String strAlldata, int mode) {
+ //Logger.e("history chart view strAlldata = " + strAlldata);
+ String[] allHistroyArray = strAlldata.split("-");
+
+ String[] arrayRoomTempData = allHistroyArray[0].split(",");
+ String[] arraySetTempData = allHistroyArray[1].split(",");
+ String[] arrayPowerTimeData = allHistroyArray[2].split(",");
+
+ mMode = mode;
+
+ initXData(arrayRoomTempData);
+
+ initRoomTempData(arrayRoomTempData);
+
+ initTargetTempData(arraySetTempData);
+
+ initPowerOnTimeData(arrayPowerTimeData);
+
+ initData();
+
+ initParams();
+
+ initPath();
+
+ startAnimation();
+ }
+
+ private void initPaint() {
+ linePaint = new Paint();
+ linePaint.setStyle(Paint.Style.STROKE);
+ linePaint.setAntiAlias(true);
+ linePaint.setColor(lineColor);
+ linePaint.setDither(true);
+ linePaint.setStrokeWidth(lineStrokeWidth);
+
+ roomTempPaint = new Paint();
+ roomTempPaint.setStyle(Paint.Style.STROKE);
+ roomTempPaint.setAntiAlias(true);
+ roomTempPaint.setColor(roomTempLineColor);
+ roomTempPaint.setDither(true);
+ roomTempPaint.setStrokeWidth(dataStrokeWidth);
+
+ targetTempPaint = new Paint();
+ targetTempPaint.setStyle(Paint.Style.STROKE);
+ targetTempPaint.setAntiAlias(true);
+ targetTempPaint.setColor(targetTempLineColor);
+ targetTempPaint.setDither(true);
+ targetTempPaint.setStrokeWidth(dataStrokeWidth);
+
+ mBmpPaint = new Paint();
+ }
+
+ /**
+ * 初始化数据
+ */
+ private void initData() {
+
+ mRoomTempPath = new Path();
+ mTargetTempPath = new Path();
+
+ rectCurrentTops = new Float[roomTempDataArray.length];
+ }
+
+ /**
+ * 初始化宽高比例等数据
+ */
+ public void initParams() {
+ // LogUtils.error(TAG, "initParams");
+ Xpoint = MarginLeft;
+
+ xLength = this.getWidth() - MarginLeft - MarginRight
+ - (MarginRight + MarginLeft) / 16;
+ yLength = this.getHeight() - MarginTop - MarginBottom;
+
+ Ypoint = this.getHeight() - MarginBottom + mYLabelSize / 3;
+ Xscale = (xLength - xFirstPointOffset * 2) / (this.Xlabel.length - 1);
+ Yscale = yLength / (this.Ylabel.length - 1);
+ }
+
+ /**
+ * 初始化path
+ */
+ private void initPath() {
+ initRoomTempPath(roomTempDataArray);
+ initTargetTempPath(targetTempDataArray);
+ }
+
+ /**
+ * 初始化设定温度数据
+ *
+ * @param arraySetTempData 设定温度数据
+ */
+ private void initTargetTempData(String[] arraySetTempData) {
+ targetTempDataArray = new float[arraySetTempData.length];
+ for (int i = 0; i < arraySetTempData.length; i++) {
+ if (arraySetTempData[i].length() > 0) {
+ targetTempDataArray[i] = Float.parseFloat(arraySetTempData[i]);
+ }
+ }
+ }
+
+ /**
+ * 初始化房间温度数据
+ *
+ * @param arrayRoomTempData 房间温度数据
+ */
+ private void initRoomTempData(String[] arrayRoomTempData) {
+ roomTempDataArray = new float[arrayRoomTempData.length];
+ for (int i = 0; i < arrayRoomTempData.length; i++) {
+ if (arrayRoomTempData[i].length() > 0) {
+ roomTempDataArray[i] = Float.parseFloat(arrayRoomTempData[i]);
+ // LogUtils.error(TAG, "" + roomTempDataArray[i]);
+ }
+ }
+ }
+
+ /**
+ * 初始化开机时间数据
+ *
+ * @param arrayPowerTimeData 开机时间数据
+ */
+ private void initPowerOnTimeData(String[] arrayPowerTimeData) {
+ powerOnTimeDataArray = new float[arrayPowerTimeData.length];
+ for (int i = 0; i < arrayPowerTimeData.length; i++) {
+ if (arrayPowerTimeData[i].length() > 0) {
+ powerOnTimeDataArray[i] = Float
+ .parseFloat(arrayPowerTimeData[i]);
+ }
+ }
+ }
+
+ /**
+ * 初始化X轴数据
+ */
+ private void initXData(String[] tempData) {
+ switch (mMode) {
+ case DAY_MODE:
+ xScaleForData = X_SCALE_FOR_DATA_DAY;
+ setXUnitText(getResources().getString(R.string.history_x_unit_hour));
+ break;
+ case WEEK_MODE:
+ xScaleForData = X_SCALE_FOR_DATA_WEEK;
+ setXUnitText(getResources().getString(R.string.history_x_unit_day));
+ break;
+ case MONTH_MODE:
+ xScaleForData = X_SCALE_FOR_DATA_MOUNTH;
+ setXUnitText(getResources().getString(R.string.history_x_unit_day));
+ break;
+ case YEAR_MODE:
+ xScaleForData = X_SCALE_FOR_DATA_YEAR;
+ setXUnitText(getResources()
+ .getString(R.string.history_x_unit_month));
+ break;
+ default:
+ break;
+ }
+
+ Xlabel = new String[tempData.length];
+ for (int i = 0; i < Xlabel.length; i++) {
+ Xlabel[i] = Integer.toString(i + 1);
+ }
+ }
+
+ private void setDefaultAttrrbutesValue() {
+ float MarginTopPx = ta.getDimension(
+ R.styleable.HistoryChartView_margin_top, 50);
+ float MarginBottomPx = ta.getDimension(
+ R.styleable.HistoryChartView_margin_bottom, 50);
+ float MarginLeftPx = ta.getDimension(
+ R.styleable.HistoryChartView_margin_left, 50);
+ float MarginRightPx = ta.getDimension(
+ R.styleable.HistoryChartView_margin_right, 50);
+
+ float yLabelSizePx = ta.getDimension(
+ R.styleable.HistoryChartView_ylabel_text_size, 30);
+ float xlabelSizePx = ta.getDimension(
+ R.styleable.HistoryChartView_xlabel_text_size, 20);
+ float xUnitSizePx = ta.getDimension(
+ R.styleable.HistoryChartView_x_unit_text_size, 30);
+ float yUnitSizePx = ta.getDimension(
+ R.styleable.HistoryChartView_y_unit_text_size, 30);
+
+ float xFirstPointOffsetPx = ta.getDimension(
+ R.styleable.HistoryChartView_x_first_point_offset, 30);
+ float lineStrokeWidthPx = ta.getDimension(
+ R.styleable.HistoryChartView_line_stroke_width, 5);
+ float dataStrokeWidthPx = ta.getDimension(
+ R.styleable.HistoryChartView_data_stroke_width, 5);
+ float circleRadiusPx = ta.getDimension(
+ R.styleable.HistoryChartView_circle_radius, 6);
+
+ xFirstPointOffset = DisplayUtils.px2sp(xFirstPointOffsetPx);
+
+ MarginTop = DisplayUtils.px2dp(MarginTopPx);
+ MarginBottom = DisplayUtils.px2dp(MarginBottomPx);
+ MarginLeft = DisplayUtils.px2dp(MarginLeftPx);
+ MarginRight = DisplayUtils.px2dp(MarginRightPx);
+
+ mYLabelSize = DisplayUtils.px2sp(yLabelSizePx);
+ mXlabelSize = DisplayUtils.px2sp(xlabelSizePx);
+
+ mXUnitTextSize = DisplayUtils.px2sp(xUnitSizePx);
+ mYUnitTextSize = DisplayUtils.px2sp(yUnitSizePx);
+
+ lineStrokeWidth = DisplayUtils.px2sp(lineStrokeWidthPx);
+ dataStrokeWidth = DisplayUtils.px2sp(dataStrokeWidthPx);
+ circleRadius = DisplayUtils.px2sp(circleRadiusPx);
+
+ lineColor = ta.getColor(R.styleable.HistoryChartView_line_color,
+ getResources().getColor(R.color.light_yellow));
+ roomTempLineColor = ta.getColor(
+ R.styleable.HistoryChartView_first_data_line_color,
+ getResources().getColor(R.color.indoor_temp));
+ targetTempLineColor = ta.getColor(
+ R.styleable.HistoryChartView_second_data_line_color,
+ getResources().getColor(R.color.setpoint_temp));
+
+ powerTimeLineColor = ta.getColor(
+ R.styleable.HistoryChartView_rect_background_color,
+ getResources().getColor(R.color.power_time));
+
+ mUnitColor = ta.getColor(R.styleable.HistoryChartView_unit_color,
+ getResources().getColor(R.color.light_grey));
+
+ mXUnitText = ta.getString(R.styleable.HistoryChartView_x_unit_text);
+ mY1UnitText = ta.getString(R.styleable.HistoryChartView_y1_unit_text);
+ mY2UnitText = ta.getString(R.styleable.HistoryChartView_y2_unit_text);
+ }
+
+ /**
+ * 设置X轴单位符号
+ *
+ * @param xUnit x轴单位符号
+ */
+ public void setXUnitText(String xUnit) {
+ mXUnitText = xUnit;
+ }
+
+ /**
+ * 绘制单位符号
+ *
+ * @param canvas canvas
+ */
+ private void drawUnit(Canvas canvas) {
+ Paint p = new Paint();
+ p.setAntiAlias(true);
+ p.setStrokeWidth(dataStrokeWidth);
+ p.setColor(mUnitColor);
+
+ drawXUnit(canvas, p);
+ drawY1Unit(canvas, p);
+ drawY2Unit(canvas, p);
+ }
+
+ // 画横轴
+ private void drawXLine(Canvas canvas, Paint p) {
+ p.setColor(getResources().getColor(R.color.light_yellow));
+ canvas.drawLine(Xpoint, Ypoint, xLength + MarginLeft, Ypoint, p);
+ }
+
+ // 画灰色横轴
+ private void drawGreyXLine(Canvas canvas, Paint p) {
+ p.setColor(getResources().getColor(R.color.grey_line));
+ float startX = Xpoint + MarginLeft / 4;
+ // 纵向
+ for (int i = yScaleForData; (yLength - i * Yscale) >= 0; i += yScaleForData) {
+ float startY = Ypoint - i * Yscale;
+ canvas.drawLine(startX - MarginLeft / 4, startY, xLength
+ + MarginLeft, startY, p);
+ }
+ }
+
+ // 画数据
+ private void drawData(Canvas canvas, float[] data, int dataColor) {
+ Paint p = new Paint();
+ p.setAntiAlias(true);
+ p.setStrokeWidth(dataStrokeWidth);
+ p.setTextSize(mXlabelSize);
+ // 横向
+ for (int i = 0; i < Xlabel.length; i++) {
+ int xLableInt = Integer.parseInt(Xlabel[i]);
+ float startX = Xpoint + i * Xscale + xFirstPointOffset;
+ if (xLableInt % xScaleForData == 0) {
+ p.setColor(lineColor);
+ canvas.drawText(this.Xlabel[i], startX - mXlabelSize / 3,
+ Ypoint + mXlabelSize * 3 / 2, p);
+ }
+ p.setColor(dataColor);
+ canvas.drawCircle(startX, getDataY(data[i], Ylabel), circleRadius,
+ p);
+ }
+
+ p.setTextSize(mYLabelSize);
+ // 纵向
+ for (int i = 0; (yLength - i * Yscale) >= 0; i += yScaleForData) {
+ p.setColor(lineColor);
+ canvas.drawText(this.Ylabel[i], MarginLeft / 4,
+ getDataY(Float.valueOf(Ylabel[i]), Ylabel) + mYLabelSize
+ / 3, p);
+ canvas.drawText(this.Ylabel2[i], this.getWidth() - MarginLeft,
+ getDataY(Float.valueOf(Ylabel2[i]), Ylabel2) + mYLabelSize
+ / 3, p);
+ }
+ }
+
+ // 获取room temp绘线Path数据
+ private void initRoomTempPath(float[] data) {
+ mRoomTempPath.reset();
+ // Path path = new Path();
+ float pointX;
+ float pointY;
+ // 横向
+ mRoomTempPath.moveTo(Xpoint + xFirstPointOffset,
+ getDataY(data[0], Ylabel));
+ mRoomTempPath.moveTo(Xpoint + xFirstPointOffset,
+ getDataY(data[0], Ylabel));
+ for (int i = 0; i < Xlabel.length; i++) {
+ float startX = Xpoint + i * Xscale + xFirstPointOffset;
+ // 绘制数据连线
+ if (i != 0) {
+ pointX = Xpoint + (i - 1) * Xscale + xFirstPointOffset;
+ pointY = getDataY(data[i - 1], Ylabel);
+ mRoomTempPath.lineTo(pointX, pointY);
+ }
+ if (i == Xlabel.length - 1) {
+ pointX = startX;
+ pointY = getDataY(data[i], Ylabel);
+ mRoomTempPath.lineTo(pointX, pointY);
+ }
+ }
+ mRoomTempPathMeasure = new PathMeasure(mRoomTempPath, false);
+ }
+
+ /**
+ * 获取target temp绘线Path数据
+ *
+ * @param data target temp绘线Path数据
+ */
+ private void initTargetTempPath(float[] data) {
+ mTargetTempPath.reset();
+ float pointX;
+ float pointY;
+ // 横向
+ mTargetTempPath.moveTo(Xpoint + xFirstPointOffset,
+ getDataY(data[0], Ylabel));
+ for (int i = 0; i < Xlabel.length; i++) {
+ float startX = Xpoint + i * Xscale + xFirstPointOffset;
+ // 绘制数据连线
+ if (i != 0) {
+ pointX = Xpoint + (i - 1) * Xscale + xFirstPointOffset;
+ pointY = getDataY(data[i - 1], Ylabel);
+ mTargetTempPath.lineTo(pointX, pointY);
+ }
+ if (i == Xlabel.length - 1) {
+ pointX = startX;
+ pointY = getDataY(data[i], Ylabel);
+ mTargetTempPath.lineTo(pointX, pointY);
+ }
+ }
+ mTargetTempPathMeasure = new PathMeasure(mTargetTempPath, false);
+ }
+
+ // 绘制矩形图
+ private void drawRect(Canvas canvas, float[] data, int dataColor) {
+ Paint p = new Paint();
+ float left;
+ float top;
+ float right;
+ float bottom;
+ float stopY = getDataY(Float.parseFloat(Ylabel[Ylabel.length - 1]),
+ Ylabel);// 灰色线Y轴位置
+ float rectYScale = (Ypoint - stopY) / 100;
+
+ p.setAntiAlias(true);
+ p.setStrokeWidth(dataStrokeWidth);
+ p.setColor(dataColor);
+
+ // 横向
+ for (int i = 0; i < Xlabel.length; i++) {
+ // 绘制柱形图
+ if (i != 0) {
+ left = Xpoint + (i - 1) * Xscale + xFirstPointOffset + Xscale
+ / 6;
+ top = Ypoint - data[i - 1] * rectYScale + lineStrokeWidth;// 要绘制的rect最终top值
+ // 起点top + (起点top - 终点top) * mRectFration
+ rectCurrentTops[i] = Ypoint - (Ypoint - top) * mRectFration;// 根据fraction动态更新top值
+ right = left + Xscale * 4 / 6;
+ bottom = Ypoint;
+ canvas.drawRect(left, rectCurrentTops[i], right, bottom, p);//
+ // 每次valueAnimator更新时重绘最新top值
+ }
+ }
+ }
+
+ private void drawY1Unit(Canvas canvas, Paint p) {
+ int maxYLabelValue = Integer.valueOf(Ylabel[Ylabel.length - 1]);
+ p.setTextSize(mYUnitTextSize);
+ float textWidth = p.measureText(mY1UnitText);
+ canvas.drawText(mY1UnitText, MarginLeft / 2 - textWidth / 2,
+ getDataY(maxYLabelValue, Ylabel) - mYLabelSize - mYLabelSize
+ / 5, p);
+ }
+
+ private void drawY2Unit(Canvas canvas, Paint p) {
+ int maxYLabel2Value = Integer.valueOf(Ylabel2[Ylabel2.length - 1]);
+ p.setTextSize(mYUnitTextSize);
+ float textWidth = p.measureText(mY2UnitText);
+ canvas.drawText(mY2UnitText, this.getWidth() - MarginRight / 2
+ - textWidth * 3 / 4, getDataY(maxYLabel2Value, Ylabel2)
+ - mYLabelSize - mYLabelSize / 5, p);
+ }
+
+ private void drawXUnit(Canvas canvas, Paint p) {
+ p.setTextSize(mXUnitTextSize);
+ float textWidth = p.measureText(mXUnitText);
+ canvas.drawText(mXUnitText, this.getWidth() / 2 - textWidth / 2, Ypoint
+ + mXlabelSize * 3 + mXlabelSize / 5, p);
+ }
+
+ /**
+ * 获取data对应绘制Y点值
+ */
+ private float getDataY(float dataY, String[] Ylabel) {
+ float y0 = 0;
+ float y1 = 0;
+ try {
+ y0 = Float.parseFloat(Ylabel[0]);
+ y1 = Float.parseFloat(Ylabel[1]);
+ } catch (Exception e) {
+ return 0;
+ }
+ try {
+ return Ypoint - ((dataY - y0) * Yscale / (y1 - y0));
+ } catch (Exception e) {
+ return 0;
+ }
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int left, int top, int right,
+ int bottom) {
+ super.onLayout(changed, left, top, right, bottom);
+ // LogUtils.error(TAG, "onLayout");
+ initParams();
+
+ if (onViewLayoutListener != null) {
+ onViewLayoutListener.onLayoutSuccess();
+ }
+
+ //创建一个与该View相同大小的缓冲区
+ mCacheBitmap = Bitmap.createBitmap(this.getWidth(), this.getHeight(), Bitmap.Config
+ .ARGB_8888);
+ mCacheCanvas = new Canvas();
+ //设置cacheCanvas将会绘制到内存中cacheBitmap上
+ mCacheCanvas.setBitmap(mCacheBitmap);
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+ mCacheCanvas.drawColor(Color.BLACK);
+
+ drawGreyXLine(mCacheCanvas, linePaint);
+
+ drawUnit(mCacheCanvas);
+
+ if (powerOnTimeDataArray.length > 1) {
+ drawRect(mCacheCanvas, powerOnTimeDataArray, powerTimeLineColor);
+ }
+
+ mCacheCanvas.drawPath(mRoomTempPath, roomTempPaint);
+
+ if (roomTempDataArray.length > 1) {
+ drawData(mCacheCanvas, roomTempDataArray, roomTempLineColor);
+ }
+
+ mCacheCanvas.drawPath(mTargetTempPath, targetTempPaint);
+
+ if (targetTempDataArray.length > 1) {
+ drawData(mCacheCanvas, targetTempDataArray, targetTempLineColor);
+ }
+
+ drawXLine(mCacheCanvas, linePaint);
+
+ //将cacheBitmap绘制到该View组件
+ canvas.drawBitmap(mCacheBitmap, 0, 0, mBmpPaint);
+ }
+
+ /**
+ * 开启动画
+ */
+ private void startAnimation() {
+ if (mValueAnimator != null) {
+ mValueAnimator.cancel();
+ }
+ final float targetTempLength = mTargetTempPathMeasure.getLength();
+ final float roomTempLength = mRoomTempPathMeasure.getLength();
+ mValueAnimator = ValueAnimator.ofFloat(1, 0);
+ mValueAnimator.setDuration(ANIM_DURATION);
+ // 减速插值器
+ mValueAnimator.setInterpolator(new DecelerateInterpolator());
+ mValueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ float fraction = (Float) animation.getAnimatedValue();
+ // 更新mtargetTempEffect
+ mtargetTempEffect = new DashPathEffect(new float[]{
+ targetTempLength, targetTempLength}, fraction
+ * targetTempLength);
+ targetTempPaint.setPathEffect(mtargetTempEffect);
+ // 更新mRoomTempEffect
+ mRoomTempEffect = new DashPathEffect(new float[]{
+ roomTempLength, roomTempLength}, fraction
+ * roomTempLength);
+ roomTempPaint.setPathEffect(mRoomTempEffect);
+ // 更新rect绘制fraction进度
+ mRectFration = 1 - fraction;// fraction是1->0 我们需要的柱形图绘制比例是0->1
+ postInvalidate();
+ }
+ });
+ mValueAnimator.start();
+ }
+
+ public interface OnViewLayoutListener {
+ void onLayoutSuccess();
+ }
+
+ public void setOnViewLayoutListener(
+ OnViewLayoutListener onViewLayoutListener) {
+ this.onViewLayoutListener = onViewLayoutListener;
+ }
+
+ private OnViewLayoutListener onViewLayoutListener;
+}
+
diff --git a/mvpsdk/src/main/java/com/share/mvpsdk/widgets/HistoryModeView.java b/mvpsdk/src/main/java/com/share/mvpsdk/widgets/HistoryModeView.java
new file mode 100644
index 0000000..ef019af
--- /dev/null
+++ b/mvpsdk/src/main/java/com/share/mvpsdk/widgets/HistoryModeView.java
@@ -0,0 +1,107 @@
+package com.share.mvpsdk.widgets;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import com.share.mvpsdk.R;
+import com.share.mvpsdk.utils.ResourcesUtils;
+
+
+/**
+ * 历史数据查询界面模式自定义View
+ * @author zyw
+ * @creation 2016-12-26
+ */
+public class HistoryModeView extends LinearLayout {
+ private LinearLayout ll_click_view;
+ private TextView tv_mode;
+ private float mSelectTextSize;
+ private float mUnSelectTextSize;
+
+ public HistoryModeView(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+
+ ll_click_view = (LinearLayout) View.inflate(context, R.layout.sub_history_click_view, this);
+ tv_mode = (TextView) findViewById(R.id.tv_click_view);
+
+ TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.HistoryModeView);
+
+ setText(ta.getString(R.styleable.HistoryModeView_android_text));
+ setSelectTextSize(ta.getDimension(R.styleable.HistoryModeView_select_text_size, 16));
+ setUnSelectTextSize(ta.getDimension(R.styleable.HistoryModeView_un_select_text_size, 12));
+ setViewTextSize();
+
+ ta.recycle();
+ }
+
+ public HistoryModeView(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ //init(context);
+ }
+
+ public HistoryModeView(Context context) {
+ this(context, null);
+ //init(context);
+ }
+
+ /**
+ * 设置控件选中状态
+ * @param isSelected 控件是否选中
+ */
+ public void setHistoryViewSelected(boolean isSelected){
+ ll_click_view.setSelected(isSelected);
+ setViewTextSize();
+ if(isSelected){
+ setTextColor(ResourcesUtils.getColor(R.color.light_yellow));
+ }else {
+ setTextColor(ResourcesUtils.getColor(R.color.light_grey));
+ }
+ }
+
+ /**
+ * 设置控件文字
+ * @param str 控件文字
+ */
+ public void setText(String str){
+ tv_mode.setText(str);
+ }
+
+ /**
+ * 设置控件文字颜色
+ * @param color 控件文字颜色
+ */
+ public void setTextColor(int color){
+ tv_mode.setTextColor(color);
+ }
+
+ /**
+ * 设置根据view的选中状态更新text字号
+ */
+ public void setViewTextSize() {
+ if(ll_click_view.isSelected()){
+ tv_mode.getPaint().setTextSize(mSelectTextSize);
+ }else{
+ tv_mode.getPaint().setTextSize(mUnSelectTextSize);
+ }
+ }
+
+ /**
+ * 设置view选中的字体大小
+ * @param selectSize 选中字体大小
+ */
+ public void setSelectTextSize(float selectSize){
+ mSelectTextSize = selectSize;
+ }
+
+ /**
+ * 设置view没有选中的字体大小
+ * @param unSelectSize 非选中字体大小
+ */
+ public void setUnSelectTextSize(float unSelectSize){
+ mUnSelectTextSize = unSelectSize;
+ }
+}
\ No newline at end of file
diff --git a/mvpsdk/src/main/java/com/share/mvpsdk/widgets/HistoryTipView.java b/mvpsdk/src/main/java/com/share/mvpsdk/widgets/HistoryTipView.java
new file mode 100644
index 0000000..f9a28ae
--- /dev/null
+++ b/mvpsdk/src/main/java/com/share/mvpsdk/widgets/HistoryTipView.java
@@ -0,0 +1,95 @@
+package com.share.mvpsdk.widgets;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Color;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import com.share.mvpsdk.R;
+
+
+/**
+ * 历史数据查询界面Tips自定义View
+ * @author zyw
+ * @creation 2016-12-27
+ */
+public class HistoryTipView extends LinearLayout {
+ private TextView tv_tips1;
+ private TextView tv_tips2;
+ private ImageView iv_tips;
+ private TypedArray ta;
+
+ public HistoryTipView(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+
+ ta = context.obtainStyledAttributes(attrs, R.styleable.HistoryTipsView);
+ init(context);
+ ta.recycle();
+ }
+
+ public HistoryTipView(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ //init(context);
+ }
+
+ public HistoryTipView(Context context) {
+ this(context, null);
+ //init(context);
+ }
+
+ public void init(Context context){
+ View.inflate(context, R.layout.sub_history_tips, this);
+
+ tv_tips1 = (TextView) findViewById(R.id.tv_tip1);
+ tv_tips2 = (TextView) findViewById(R.id.tv_tip2);
+ iv_tips = (ImageView) findViewById(R.id.iv_tip);
+
+ setTipOneText(ta.getString(R.styleable.HistoryTipsView_tip_one_text));
+ setTipTwoText(ta.getString(R.styleable.HistoryTipsView_tip_two_text));
+ setTextColor(ta.getColor(R.styleable.HistoryTipsView_android_textColor, Color.WHITE));
+ setTextSize(ta.getDimension(R.styleable.HistoryTipsView_android_textSize, 12));
+ setBackground(ta.getResourceId(R.styleable.HistoryTipsView_android_src, 0));
+ }
+
+ /**
+ * 设置控件Tip1文字
+ * @param str
+ */
+ public void setTipOneText(String str){
+ tv_tips1.setText(str);
+ }
+
+ /**
+ * 设置控件Tip2s文字
+ * @param str
+ */
+ public void setTipTwoText(String str){
+ tv_tips2.setText(str);
+ }
+
+ /**
+ * 设置控件Tip1 2文字颜色
+ * @param color
+ */
+ public void setTextColor(int color){
+ tv_tips1.setTextColor(color);
+ tv_tips2.setTextColor(color);
+ }
+
+ /**
+ * 设置根据view的选中状态更新text字号
+ */
+ public void setTextSize(float textSize) {
+ tv_tips1.getPaint().setTextSize(textSize);
+ tv_tips2.getPaint().setTextSize(textSize);
+ }
+
+ public void setBackground(int resId){
+ iv_tips.setImageResource(resId);
+ }
+}
+
diff --git a/mvpsdk/src/main/java/com/share/mvpsdk/widgets/MovingImageView.java b/mvpsdk/src/main/java/com/share/mvpsdk/widgets/MovingImageView.java
new file mode 100644
index 0000000..d4dd66b
--- /dev/null
+++ b/mvpsdk/src/main/java/com/share/mvpsdk/widgets/MovingImageView.java
@@ -0,0 +1,332 @@
+/*
+ * Copyright (C) 2014 Albert Grobas
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.share.mvpsdk.widgets;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Bitmap;
+import android.graphics.Matrix;
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
+import android.util.AttributeSet;
+import android.widget.ImageView;
+
+import com.share.mvpsdk.R;
+
+
+/**
+ * Created by Horrarndoo on 2017/9/7.
+ *
+ * 自定义可以背景滚动的ImageView
+ */
+public class MovingImageView extends ImageView {
+
+ private float canvasWidth, canvasHeight;
+ private float imageWidth, imageHeight;
+ private float offsetWidth, offsetHeight;
+ /**
+ * 移动类型
+ */
+ private int movementType;
+
+ /**
+ * 限定最大比值
+ * canvasHeight/drawableHeight 或者 canvasWidth/drawableWidth
+ */
+ private float maxRelativeSize;
+ /**
+ * 最小相对偏移值,图片最起码可以位移图*0.2的距离
+ */
+ private float minRelativeOffset;
+ private int mSpeed;
+ private long startDelay;
+ private int mRepetitions;
+ private boolean loadOnCreate;//load完毕后是否移动
+
+ private MovingViewAnimator mAnimator;
+
+ public MovingImageView(Context context) {
+ this(context, null);
+ }
+
+ public MovingImageView(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public MovingImageView(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+
+ TypedArray ta = context.getTheme().obtainStyledAttributes(attrs,
+ R.styleable.MovingImageView, defStyle, 0);
+
+ try {
+ maxRelativeSize = ta.getFloat(R.styleable.MovingImageView_miv_max_relative_size, 3.0f);
+ minRelativeOffset = ta.getFloat(R.styleable.MovingImageView_miv_min_relative_offset,
+ 0.2f);
+ mSpeed = ta.getInt(R.styleable.MovingImageView_miv_speed, 50);
+ mRepetitions = ta.getInt(R.styleable.MovingImageView_miv_repetitions, -1);
+ startDelay = ta.getInt(R.styleable.MovingImageView_miv_start_delay, 0);
+ loadOnCreate = ta.getBoolean(R.styleable.MovingImageView_miv_load_on_create, true);
+ } finally {
+ ta.recycle();
+ }
+
+ init();
+ }
+
+ private void init() {
+ super.setScaleType(ScaleType.MATRIX);
+ mAnimator = new MovingViewAnimator(this);
+ }
+
+ /**
+ * 更新canvas size
+ *
+ * @param w new width.
+ * @param h new height.
+ * @param oldW old width.
+ * @param oldH old height.
+ */
+ @Override
+ protected void onSizeChanged(int w, int h, int oldW, int oldH) {
+ super.onSizeChanged(w, h, oldW, oldH);
+ canvasWidth = (float) w - (float) (getPaddingLeft() + getPaddingRight());
+ canvasHeight = (float) h - (float) (getPaddingTop() + getPaddingBottom());
+ updateAll();
+ }
+
+ private void updateAll() {
+ if (getDrawable() != null) {
+ updateImageSize();
+ updateOffsets();
+ updateAnimatorValues();
+ }
+ }
+
+ /**
+ * 更新图片Size
+ */
+ private void updateImageSize() {
+ imageWidth = getDrawable().getIntrinsicWidth();//获取图片高度
+ imageHeight = getDrawable().getIntrinsicHeight();//获取图片宽度
+ }
+
+ /**
+ * 更新偏移量,确定动画范围
+ */
+ private void updateOffsets() {
+ float minSizeX = imageWidth * minRelativeOffset;
+ float minSizeY = imageHeight * minRelativeOffset;
+ offsetWidth = (imageWidth - canvasWidth - minSizeX) > 0 ? imageWidth - canvasWidth : 0;
+ offsetHeight = (imageHeight - canvasHeight - minSizeY) > 0 ? imageHeight - canvasHeight : 0;
+ }
+
+ /**
+ * 更新动画基本数据
+ */
+ private void updateAnimatorValues() {
+ if (canvasHeight == 0 && canvasWidth == 0)
+ return;
+
+ float scale = calculateTypeAndScale();
+ if (scale == 0)
+ return;
+
+ float w = (imageWidth * scale) - canvasWidth;
+ float h = (imageHeight * scale) - canvasHeight;
+
+ mAnimator.updateValues(movementType, w, h);
+ mAnimator.setStartDelay(startDelay);
+ mAnimator.setSpeed(mSpeed);
+ mAnimator.setRepetition(mRepetitions);
+
+ if (loadOnCreate) {
+ startMoving();
+ }
+ }
+
+ /**
+ * 设置最佳的运动类型
+ * 计算缩放比例
+ *
+ * @return image scale.
+ */
+ private float calculateTypeAndScale() {
+ movementType = MovingViewAnimator.AUTO_MOVE;
+ float scale = 1f;
+ float scaleByImage = Math.max(imageWidth / canvasWidth, imageHeight / canvasHeight);
+ Matrix matrix = new Matrix();
+
+ if (offsetWidth == 0 && offsetHeight == 0) {//图片太小,无法动画,需要放大
+ //画布宽度/图片宽度
+ float sW = canvasWidth / imageWidth;
+ //画布高度/图片高度
+ float sH = canvasHeight / imageHeight;
+
+ if (sW > sH) {
+ scale = Math.min(sW, maxRelativeSize);//限定最大缩放值
+ matrix.setTranslate((canvasWidth - imageWidth * scale) / 2f, 0);
+ movementType = MovingViewAnimator.VERTICAL_MOVE;//垂直移动
+
+ } else if (sW < sH) {
+ scale = Math.min(sH, maxRelativeSize);//限定最大缩放值
+ matrix.setTranslate(0, (canvasHeight - imageHeight * scale) / 2f);
+ movementType = MovingViewAnimator.HORIZONTAL_MOVE;//水平移动
+
+ } else {
+ scale = Math.max(sW, maxRelativeSize);//限定最大缩放值
+ movementType = (scale == sW) ? MovingViewAnimator.NONE_MOVE :
+ MovingViewAnimator.DIAGONAL_MOVE;//对角线移动
+ }
+ } else if (offsetWidth == 0) {//宽度太小,无法执行水平动画,放大宽度
+ scale = canvasWidth / imageWidth;
+ movementType = MovingViewAnimator.VERTICAL_MOVE;
+
+ } else if (offsetHeight == 0) {//高度太小,无法执行垂直动画,放大高度
+ scale = canvasHeight / imageHeight;//求出画布高度和图片高度的比值用于确定画布起始坐标
+ movementType = MovingViewAnimator.HORIZONTAL_MOVE;
+
+ } else if (scaleByImage > maxRelativeSize) {//图片太大,根据最大比值设定图片缩放值
+ scale = maxRelativeSize / scaleByImage;
+ if (imageWidth * scale < canvasWidth || imageHeight * scale < canvasHeight) {
+ scale = Math.max(canvasWidth / imageWidth, canvasHeight / imageHeight);
+ }
+ }
+
+ matrix.preScale(scale, scale);
+ setImageMatrix(matrix);
+ return scale;
+ }
+
+ /**
+ * 禁止设置ScaleType
+ *
+ * @param scaleType
+ */
+ @Override
+ @Deprecated
+ public void setScaleType(ScaleType scaleType) {
+ //super.setScaleType(scaleType);
+ }
+
+ @Override
+ public void setImageResource(int resId) {
+ super.setImageResource(resId);
+ updateAll();
+ }
+
+ @Override
+ public void setImageURI(Uri uri) {
+ super.setImageURI(uri);
+ updateAll();
+ }
+
+ @Override
+ public void setImageDrawable(Drawable drawable) {
+ super.setImageDrawable(drawable);
+ updateAll();
+ }
+
+ @Override
+ public void setImageBitmap(Bitmap bm) {
+ super.setImageBitmap(bm);
+ updateAll();
+ }
+
+ /**
+ * 获取animator
+ *
+ * @return
+ */
+ public MovingViewAnimator getMovingAnimator() {
+ return mAnimator;
+ }
+
+ public float getMaxRelativeSize() {
+ return maxRelativeSize;
+ }
+
+ public void setMaxRelativeSize(float max) {
+ maxRelativeSize = max;
+ updateAnimatorValues();
+ }
+
+ public float getMinRelativeOffset() {
+ return minRelativeOffset;
+ }
+
+ public void setMinRelativeOffset(float min) {
+ minRelativeOffset = min;
+ updateAnimatorValues();
+ }
+
+ public boolean isLoadOnCreate() {
+ return loadOnCreate;
+ }
+
+ public void setLoadOnCreate(boolean loadOnCreate) {
+ this.loadOnCreate = loadOnCreate;
+ }
+
+ /**
+ * 开始移动
+ * 默认不停的移动
+ */
+ public void startMoving() {
+ startMoving(-1);
+ }
+
+ /**
+ * 开始移动
+ *
+ * @param repetition 循环模式
+ */
+ public void startMoving(int repetition) {
+ mAnimator.setRepetition(repetition);
+ mAnimator.start();
+ }
+
+ /**
+ * 恢复移动
+ */
+ public void resumeMoving() {
+ mAnimator.resume();
+ }
+
+ /**
+ * 暂停移动
+ */
+ public void pauseMoving() {
+ mAnimator.pause();
+ }
+
+ /**
+ * 停止移动
+ */
+ public void stopMoving() {
+ mAnimator.stop();
+ }
+
+ /**
+ * 获取当前状态
+ *
+ * @return
+ */
+ public MovingViewAnimator.MovingState getMovingState() {
+ return mAnimator.getMovingState();
+ }
+}
diff --git a/mvpsdk/src/main/java/com/share/mvpsdk/widgets/MovingViewAnimator.java b/mvpsdk/src/main/java/com/share/mvpsdk/widgets/MovingViewAnimator.java
new file mode 100644
index 0000000..2fad1d0
--- /dev/null
+++ b/mvpsdk/src/main/java/com/share/mvpsdk/widgets/MovingViewAnimator.java
@@ -0,0 +1,448 @@
+/*
+ * Copyright (C) 2014 Albert Grobas
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.share.mvpsdk.widgets;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.animation.PropertyValuesHolder;
+import android.annotation.TargetApi;
+import android.os.Build;
+import android.view.View;
+import android.view.animation.AccelerateDecelerateInterpolator;
+import android.view.animation.Interpolator;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Created by Horrarndoo on 2017/9/7.
+ *
+ * 滚动view动画
+ */
+public class MovingViewAnimator {
+ /**
+ * 水平移动
+ */
+ public static final int HORIZONTAL_MOVE = 1;
+ /**
+ * 垂直移动
+ */
+ public static final int VERTICAL_MOVE = 2;
+ /**
+ * 对角线移动
+ */
+ public static final int DIAGONAL_MOVE = 3;
+ /**
+ * 自动移动
+ */
+ public static final int AUTO_MOVE = 0;
+ /**
+ * 不移动
+ */
+ public static final int NONE_MOVE = -1;
+
+ private AnimatorSet mAnimatorSet;
+ private View mView;
+
+ private boolean isRunning;
+ private int currentLoop;
+ private boolean infiniteRepetition = true;
+ private ArrayList pathDistances;
+
+ private int loopCount = -1;
+ private int movementType;
+ private float offsetWidth, offsetHeight;
+ private int mSpeed = 50;
+ private long mDelay = 0;
+ private Interpolator mInterpolator;
+
+ private MovingState currentState = MovingState.stop;
+
+ public enum MovingState {
+ stop,
+ moving,
+ pause
+ }
+
+ private Animator.AnimatorListener animatorListener = new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(final Animator animation) {
+ //super.onAnimationEnd(animation);
+ //运行在主线程
+ mView.post((new Runnable() {
+ public void run() {
+ if (isRunning) {
+ if (infiniteRepetition) {
+ mAnimatorSet.start();
+ } else {
+ currentLoop--;
+ if (currentLoop > 0) {
+ mAnimatorSet.start();
+ }
+ }
+ }
+ }
+ }));
+ }
+ };
+
+ public MovingViewAnimator(View imgView) {
+ mView = imgView;
+ isRunning = false;
+ mAnimatorSet = new AnimatorSet();
+ pathDistances = new ArrayList<>();
+ mInterpolator = new AccelerateDecelerateInterpolator();
+ }
+
+ public MovingViewAnimator(View imgView, int type, float width, float height) {
+ this(imgView);
+ updateValues(type, width, height);
+ }
+
+ private void init() {
+ setUpAnimator();
+ setUpValues();
+ }
+
+ /**
+ * 根据移动类型设置不同的动画
+ */
+ private void setUpAnimator() {
+ AnimatorSet animatorSet = new AnimatorSet();
+ pathDistances.clear();
+
+ switch (movementType) {
+ case HORIZONTAL_MOVE:
+ animatorSet.playSequentially(createHorizontalAnimator(0, offsetWidth),
+ createHorizontalAnimator(offsetWidth, 0));
+ break;
+ case VERTICAL_MOVE:
+ animatorSet.playSequentially(createVerticalAnimator(0, offsetHeight),
+ createVerticalAnimator(offsetHeight, 0));
+ break;
+ case DIAGONAL_MOVE:
+ animatorSet.playSequentially(createDiagonalAnimator(0, offsetWidth, 0,
+ offsetHeight),
+ createDiagonalAnimator(offsetWidth, 0, offsetHeight, 0));
+ break;
+ case AUTO_MOVE:
+ animatorSet.playSequentially(
+ createVerticalAnimator(0, offsetHeight),
+ createDiagonalAnimator(0, offsetWidth, offsetHeight, 0),
+ createHorizontalAnimator(offsetWidth, 0),
+ createDiagonalAnimator(0, offsetWidth, 0, offsetHeight),
+ createHorizontalAnimator(offsetWidth, 0),
+ createVerticalAnimator(offsetHeight, 0));
+ }
+
+ if (mAnimatorSet != null) {
+ mAnimatorSet.removeAllListeners();
+ stop();
+ }
+ mAnimatorSet = animatorSet;
+ }
+
+ /**
+ * 设置参数数据
+ */
+ private void setUpValues() {
+ setSpeed(mSpeed);
+ setStartDelay(mDelay);
+ setRepetition(loopCount);
+ setInterpolator(mInterpolator);
+ }
+
+ private void setListener() {
+ mAnimatorSet.addListener(animatorListener);
+ }
+
+ /**
+ * 更新动画值.
+ *
+ * @param type
+ * @param w
+ * @param h
+ */
+ public void updateValues(int type, float w, float h) {
+ this.movementType = type;
+ this.offsetWidth = w;
+ this.offsetHeight = h;
+ init();
+ }
+
+ public void setMovementType(int type) {
+ updateValues(type, offsetWidth, offsetHeight);
+ }
+
+ public void setOffsets(float w, float h) {
+ updateValues(movementType, w, h);
+ }
+
+ public void start() {
+ //Log.e("tag", "start.");
+ if (movementType != NONE_MOVE) {
+ isRunning = true;
+ if (!infiniteRepetition)
+ currentLoop = loopCount;
+ setListener();
+ mAnimatorSet.start();
+ currentState = MovingState.moving;
+ }
+ }
+
+ public void cancel() {
+ if (isRunning) {
+ mAnimatorSet.removeListener(animatorListener);
+ mAnimatorSet.cancel();
+ currentState = MovingState.stop;
+ }
+ }
+
+ @TargetApi(19)
+ public void pause() {
+ //Log.e("tag", "pause.");
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT)
+ return;
+
+ if (mAnimatorSet.isStarted()) {
+ mAnimatorSet.pause();
+ currentState = MovingState.pause;
+ }
+ }
+
+ @TargetApi(19)
+ public void resume() {
+ //Log.e("tag", "resume.");
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT)
+ return;
+
+ if (mAnimatorSet.isPaused()) {
+ mAnimatorSet.resume();
+ currentState = MovingState.moving;
+ }
+ }
+
+ public void stop() {
+ //Log.e("tag", "stop.");
+ isRunning = false;
+ mAnimatorSet.removeListener(animatorListener);
+ mAnimatorSet.end();
+ mView.clearAnimation();
+ currentState = MovingState.stop;
+ }
+
+ /**
+ * 设置重复模式
+ *
+ * @param repetition repetition < 0 循环播放
+ * repetition > 0 循环repetition次
+ */
+ public void setRepetition(int repetition) {
+ if (repetition < 0)
+ infiniteRepetition = true;
+ else {
+ loopCount = repetition;
+ currentLoop = loopCount;
+ infiniteRepetition = false;
+ }
+ }
+
+ public Builder addCustomMovement() {
+ return new Builder();
+ }
+
+ public void clearCustomMovement() {
+ init();
+ start();
+ }
+
+ public int getMovementType() {
+ return movementType;
+ }
+
+ public int getRemainingRepetitions() {
+ return (infiniteRepetition) ? -1 : currentLoop;
+ }
+
+ public void setInterpolator(Interpolator interpolator) {
+ mInterpolator = interpolator;
+ mAnimatorSet.setInterpolator(interpolator);
+ }
+
+ /**
+ * 设置动画播放之前的延时时间
+ *
+ * @param time
+ */
+ public void setStartDelay(long time) {
+ mDelay = time;
+ mAnimatorSet.setStartDelay(time);
+ }
+
+ /**
+ * 设置每个动画对应的持续时间
+ *
+ * @param speed
+ */
+ public void setSpeed(int speed) {
+ mSpeed = speed;
+ List listAnimator = mAnimatorSet.getChildAnimations();
+ for (int i = 0; i < listAnimator.size(); i++) {
+ Animator a = listAnimator.get(i);
+ a.setDuration(parseSpeed(pathDistances.get(i)));
+ }
+ }
+
+ /**
+ * 将速度设置值转换成秒
+ *
+ * @param distance
+ * @return
+ */
+ private long parseSpeed(float distance) {
+ return (long) ((distance / (float) mSpeed) * 1000f);
+ }
+
+ /**
+ * 创建水平移动动画
+ *
+ * @param startValue
+ * @param endValue
+ * @return
+ */
+ private ObjectAnimator createHorizontalAnimator(float startValue, float endValue) {
+ pathDistances.add(Math.abs(startValue - endValue));
+ return createObjectAnimation("scrollX", startValue, endValue);
+ }
+
+ /**
+ * 创建垂直移动动画
+ *
+ * @param startValue
+ * @param endValue
+ * @return
+ */
+ private ObjectAnimator createVerticalAnimator(float startValue, float endValue) {
+ pathDistances.add(Math.abs(startValue - endValue));
+ return createObjectAnimation("scrollY", startValue, endValue);
+ }
+
+ /**
+ * 创建对角线移动动画
+ *
+ * @param startW
+ * @param endW
+ * @param startH
+ * @param endH
+ * @return
+ */
+ private ObjectAnimator createDiagonalAnimator(float startW, float endW, float startH, float
+ endH) {
+ float diagonal = Pythagoras(Math.abs(startW - endW), Math.abs(startH - endH));
+ pathDistances.add(diagonal);
+ PropertyValuesHolder pvhX = createPropertyValuesHolder("scrollX", startW, endW);
+ PropertyValuesHolder pvhY = createPropertyValuesHolder("scrollY", startH, endH);
+ return ObjectAnimator.ofPropertyValuesHolder(mView, pvhX, pvhY);
+ }
+
+ private ObjectAnimator createObjectAnimation(String prop, float startValue, float endValue) {
+ return ObjectAnimator.ofInt(mView, prop, (int) startValue, (int) endValue);
+ }
+
+ private PropertyValuesHolder createPropertyValuesHolder(String prop, float startValue, float
+ endValue) {
+ return PropertyValuesHolder.ofInt(prop, (int) startValue, (int) endValue);
+ }
+
+ private static float Pythagoras(float a, float b) {
+ return (float) Math.sqrt((a * a) + (b * b));
+ }
+
+ /**
+ * 自定义自动移动方式
+ */
+ public class Builder {
+
+ private ArrayList mList;
+
+ private Builder() {
+ mList = new ArrayList<>();
+ pathDistances.clear();
+ }
+
+ public Builder addHorizontalMoveToRight() {
+ mList.add(createHorizontalAnimator(0, offsetWidth));
+ return this;
+ }
+
+ public Builder addHorizontalMoveToLeft() {
+ mList.add(createHorizontalAnimator(offsetWidth, 0));
+ return this;
+ }
+
+ public Builder addVerticalMoveToDown() {
+ mList.add(createVerticalAnimator(0, offsetHeight));
+ return this;
+ }
+
+ public Builder addVerticalMoveToUp() {
+ mList.add(createVerticalAnimator(offsetHeight, 0));
+ return this;
+ }
+
+ public Builder addDiagonalMoveToDownRight() {
+ mList.add(createDiagonalAnimator(0, offsetWidth, 0, offsetHeight));
+ return this;
+ }
+
+ public Builder addDiagonalMoveToDownLeft() {
+ mList.add(createDiagonalAnimator(offsetWidth, 0, 0, offsetHeight));
+ return this;
+ }
+
+ public Builder addDiagonalMoveToUpRight() {
+ mList.add(createDiagonalAnimator(0, offsetWidth, offsetHeight, 0));
+ return this;
+ }
+
+ public Builder addDiagonalMoveToUpLeft() {
+ mList.add(createDiagonalAnimator(offsetWidth, 0, offsetHeight, 0));
+ return this;
+ }
+
+ public void start() {
+ mAnimatorSet.removeAllListeners();
+ stop();
+ mAnimatorSet = new AnimatorSet();
+ mAnimatorSet.playSequentially(mList);
+ setListener();
+ setUpValues();
+ MovingViewAnimator.this.start();
+ }
+ }
+
+ /**
+ * 获取当前状态
+ *
+ * @return
+ */
+ public MovingState getMovingState() {
+ return currentState;
+ }
+}
\ No newline at end of file
diff --git a/mvpsdk/src/main/java/com/share/mvpsdk/widgets/NestedScrollWebView.java b/mvpsdk/src/main/java/com/share/mvpsdk/widgets/NestedScrollWebView.java
new file mode 100644
index 0000000..9cc9691
--- /dev/null
+++ b/mvpsdk/src/main/java/com/share/mvpsdk/widgets/NestedScrollWebView.java
@@ -0,0 +1,168 @@
+package com.share.mvpsdk.widgets;
+
+import android.content.Context;
+import android.support.v4.view.MotionEventCompat;
+import android.support.v4.view.NestedScrollingChild;
+import android.support.v4.view.NestedScrollingChildHelper;
+import android.support.v4.view.ViewCompat;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.webkit.WebView;
+
+/**
+ * Created by Horrarndoo on 2017/9/27.
+ *
+ * 继承原生WebView,目的是为了和AppBarLayout、CollapsingToolbarLayout等Android Design Support Library控件配合使用。
+ *
+ * 避免AppBarLayout+NestSrollView+WebView嵌套导致的WebView高度判断异常导致WebView跳转后高度异常的问题;
+ */
+public class NestedScrollWebView extends WebView implements NestedScrollingChild {
+
+ public static final String TAG = NestedScrollWebView.class.getSimpleName();
+
+ private int mLastMotionY;
+
+ private final int[] mScrollOffset = new int[2];
+ private final int[] mScrollConsumed = new int[2];
+
+ private int mNestedYOffset;
+ private boolean mChange;
+
+ private NestedScrollingChildHelper mChildHelper;
+
+ public NestedScrollWebView(Context context) {
+ super(context);
+ init();
+ }
+
+ public NestedScrollWebView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ init();
+ }
+
+ public NestedScrollWebView(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ init();
+ }
+
+ private void init() {
+ mChildHelper = new NestedScrollingChildHelper(this);
+ setNestedScrollingEnabled(true);
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ boolean result = false;
+
+ MotionEvent trackedEvent = MotionEvent.obtain(event);
+
+ final int action = MotionEventCompat.getActionMasked(event);
+
+ if (action == MotionEvent.ACTION_DOWN) {
+ mNestedYOffset = 0;
+ }
+
+ int y = (int) event.getY();
+
+ event.offsetLocation(0, mNestedYOffset);
+
+ switch (action) {
+ case MotionEvent.ACTION_DOWN:
+ mLastMotionY = y;
+ startNestedScroll(ViewCompat.SCROLL_AXIS_VERTICAL);
+ result = super.onTouchEvent(event);
+ mChange = false;
+ break;
+ case MotionEvent.ACTION_MOVE:
+ int deltaY = mLastMotionY - y;
+
+ if (dispatchNestedPreScroll(0, deltaY, mScrollConsumed, mScrollOffset)) {
+ deltaY -= mScrollConsumed[1];
+ trackedEvent.offsetLocation(0, mScrollOffset[1]);
+ mNestedYOffset += mScrollOffset[1];
+ }
+
+ int oldY = getScrollY();
+ mLastMotionY = y - mScrollOffset[1];
+ int newScrollY = Math.max(0, oldY + deltaY);
+ deltaY -= newScrollY - oldY;
+ if (dispatchNestedScroll(0, newScrollY - deltaY, 0, deltaY, mScrollOffset)) {
+ mLastMotionY -= mScrollOffset[1];
+ trackedEvent.offsetLocation(0, mScrollOffset[1]);
+ mNestedYOffset += mScrollOffset[1];
+ }
+ if (mScrollConsumed[1] == 0 && mScrollOffset[1] == 0) {
+ if (mChange) {
+ mChange = false;
+ trackedEvent.setAction(MotionEvent.ACTION_DOWN);
+ super.onTouchEvent(trackedEvent);
+ } else {
+ result = super.onTouchEvent(trackedEvent);
+ }
+ trackedEvent.recycle();
+ } else {
+ if (!mChange) {
+ mChange = true;
+ super.onTouchEvent(MotionEvent.obtain(0, 0, MotionEvent.ACTION_CANCEL, 0,
+ 0, 0));
+ }
+ }
+ break;
+ case MotionEvent.ACTION_POINTER_DOWN:
+ case MotionEvent.ACTION_UP:
+ case MotionEvent.ACTION_CANCEL:
+ stopNestedScroll();
+ result = super.onTouchEvent(event);
+ break;
+ }
+ return result;
+ }
+
+ // NestedScrollingChild
+ @Override
+ public void setNestedScrollingEnabled(boolean enabled) {
+ mChildHelper.setNestedScrollingEnabled(enabled);
+ }
+
+ @Override
+ public boolean isNestedScrollingEnabled() {
+ return mChildHelper.isNestedScrollingEnabled();
+ }
+
+ @Override
+ public boolean startNestedScroll(int axes) {
+ return mChildHelper.startNestedScroll(axes);
+ }
+
+ @Override
+ public void stopNestedScroll() {
+ mChildHelper.stopNestedScroll();
+ }
+
+ @Override
+ public boolean hasNestedScrollingParent() {
+ return mChildHelper.hasNestedScrollingParent();
+ }
+
+ @Override
+ public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed, int dxUnconsumed, int
+ dyUnconsumed, int[] offsetInWindow) {
+ return mChildHelper.dispatchNestedScroll(dxConsumed, dyConsumed, dxUnconsumed,
+ dyUnconsumed, offsetInWindow);
+ }
+
+ @Override
+ public boolean dispatchNestedPreScroll(int dx, int dy, int[] consumed, int[] offsetInWindow) {
+ return mChildHelper.dispatchNestedPreScroll(dx, dy, consumed, offsetInWindow);
+ }
+
+ @Override
+ public boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed) {
+ return mChildHelper.dispatchNestedFling(velocityX, velocityY, consumed);
+ }
+
+ @Override
+ public boolean dispatchNestedPreFling(float velocityX, float velocityY) {
+ return mChildHelper.dispatchNestedPreFling(velocityX, velocityY);
+ }
+}
\ No newline at end of file
diff --git a/mvpsdk/src/main/java/com/share/mvpsdk/widgets/PickerView.java b/mvpsdk/src/main/java/com/share/mvpsdk/widgets/PickerView.java
new file mode 100644
index 0000000..092e775
--- /dev/null
+++ b/mvpsdk/src/main/java/com/share/mvpsdk/widgets/PickerView.java
@@ -0,0 +1,314 @@
+package com.share.mvpsdk.widgets;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Paint.Align;
+import android.graphics.Paint.FontMetricsInt;
+import android.graphics.Paint.Style;
+import android.os.Handler;
+import android.os.Message;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.View;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Timer;
+import java.util.TimerTask;
+
+/**
+ * Created by Horrarndoo on 2017/4/5.
+ *
+ * 滚动选择器
+ */
+public class PickerView extends View {
+
+ public static final String TAG = "PickerView";
+ /**
+ * text之间间距和minTextSize之比
+ */
+ public static final float MARGIN_ALPHA = 2.8f;
+ /**
+ * 自动回滚到中间的速度
+ */
+ public static final float SPEED = 2;
+
+ private List mDataList;
+ /**
+ * 选中的位置,这个位置是mDataList的中心位置,一直不变
+ */
+ private int mCurrentSelected;
+ private Paint mPaint;
+
+ private float mMaxTextSize = 80;
+ private float mMinTextSize = 50;
+ // private float mMinTextSize = 40;
+
+ private float mMaxTextAlpha = 255;
+ private float mMinTextAlpha = 120;
+
+ private int mColorText = 0xFF9500;// 森威尔的黄色
+
+ private int mViewHeight;
+ private int mViewWidth;
+
+ private float mLastDownY;
+ /**
+ * 滑动的距离
+ */
+ private float mMoveLen = 0;
+ private boolean isInit = false;
+ private onSelectListener mSelectListener;
+ private Timer timer;
+ private MyTimerTask mTask;
+
+ Handler updateHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ if (Math.abs(mMoveLen) < SPEED) {
+ mMoveLen = 0;
+ if (mTask != null) {
+ mTask.cancel();
+ mTask = null;
+ performSelect();
+ }
+ } else
+ // 这里mMoveLen / Math.abs(mMoveLen)是为了保有mMoveLen的正负号,以实现上滚或下滚
+ mMoveLen = mMoveLen - mMoveLen / Math.abs(mMoveLen) * SPEED;
+ invalidate();
+ }
+
+ };
+
+ public PickerView(Context context) {
+ super(context);
+ init();
+ }
+
+ public PickerView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ init();
+ }
+
+ public void setOnSelectListener(onSelectListener listener) {
+ mSelectListener = listener;
+ }
+
+ private void performSelect() {
+ if (mSelectListener != null)
+ mSelectListener.onSelect(mDataList.get(mCurrentSelected));
+ }
+
+ public void setData(List datas) {
+ mDataList = datas;
+ mCurrentSelected = datas.size() / 2;
+ invalidate();
+ }
+
+ /**
+ * 选择选中的item的index
+ *
+ * @param selected
+ */
+ public void setSelected(int selected) {
+ mCurrentSelected = selected;
+ int distance = mDataList.size() / 2 - mCurrentSelected;
+ if (distance < 0)
+ for (int i = 0; i < -distance; i++) {
+ moveHeadToTail();
+ mCurrentSelected--;
+ }
+ else if (distance > 0)
+ for (int i = 0; i < distance; i++) {
+ moveTailToHead();
+ mCurrentSelected++;
+ }
+ invalidate();
+ }
+
+ /**
+ * 选择选中的内容
+ *
+ * @param mSelectItem
+ */
+ public void setSelected(String mSelectItem) {
+ for (int i = 0; i < mDataList.size(); i++)
+ if (mDataList.get(i).equals(mSelectItem)) {
+ setSelected(i);
+ break;
+ }
+ }
+
+ private void moveHeadToTail() {
+ String head = mDataList.get(0);
+ mDataList.remove(0);
+ mDataList.add(head);
+ }
+
+ private void moveTailToHead() {
+ String tail = mDataList.get(mDataList.size() - 1);
+ mDataList.remove(mDataList.size() - 1);
+ mDataList.add(0, tail);
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ mViewHeight = getMeasuredHeight();
+ mViewWidth = getMeasuredWidth();
+ // 按照View的高度计算字体大小
+ mMaxTextSize = mViewHeight / 4.0f;
+ mMinTextSize = mMaxTextSize / 2f;
+ isInit = true;
+ invalidate();
+ }
+
+ private void init() {
+ timer = new Timer();
+ mDataList = new ArrayList();
+ mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ mPaint.setStyle(Style.FILL);
+ mPaint.setTextAlign(Align.CENTER);
+ mPaint.setColor(mColorText);
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+ // 根据index绘制view
+ if (isInit)
+ drawData(canvas);
+ }
+
+ private void drawData(Canvas canvas) {
+ // 先绘制选中的text再往上往下绘制其余的text
+ float scale = parabola(mViewHeight / 4.0f, mMoveLen);
+ float size = (mMaxTextSize - mMinTextSize) * scale + mMinTextSize;
+ mPaint.setTextSize(size);
+ mPaint.setAlpha((int) ((mMaxTextAlpha - mMinTextAlpha) * scale + mMinTextAlpha));
+ // text居中绘制,注意baseline的计算才能达到居中,y值是text中心坐标
+ float x = (float) (mViewWidth / 2.0);
+ float y = (float) (mViewHeight / 2.0 + mMoveLen);
+ FontMetricsInt fmi = mPaint.getFontMetricsInt();
+ float baseline = (float) (y - (fmi.bottom / 2.0 + fmi.top / 2.0));
+ if (mDataList.size() > 0) {
+ canvas.drawText(mDataList.get(mCurrentSelected), x, baseline,
+ mPaint);
+ }
+ // 绘制上方data
+ for (int i = 1; (mCurrentSelected - i) >= 0; i++) {
+ drawOtherText(canvas, i, -1);
+ }
+ // 绘制下方data
+ for (int i = 1; (mCurrentSelected + i) < mDataList.size(); i++) {
+ drawOtherText(canvas, i, 1);
+ }
+ }
+
+ /**
+ * @param canvas
+ * @param position 距离mCurrentSelected的差值
+ * @param type 1表示向下绘制,-1表示向上绘制
+ */
+ private void drawOtherText(Canvas canvas, int position, int type) {
+ float d = (float) (MARGIN_ALPHA * mMinTextSize * position + type
+ * mMoveLen);
+ float scale = parabola(mViewHeight / 4.0f, d);
+ float size = (mMaxTextSize - mMinTextSize) * scale + mMinTextSize;
+ mPaint.setTextSize(size);
+ mPaint.setAlpha((int) ((mMaxTextAlpha - mMinTextAlpha) * scale + mMinTextAlpha));
+ float y = (float) (mViewHeight / 2.0 + type * d);
+ FontMetricsInt fmi = mPaint.getFontMetricsInt();
+ float baseline = (float) (y - (fmi.bottom / 2.0 + fmi.top / 2.0));
+ canvas.drawText(mDataList.get(mCurrentSelected + type * position),
+ (float) (mViewWidth / 2.0), baseline, mPaint);
+ }
+
+ /**
+ * 抛物线
+ *
+ * @param zero 零点坐标
+ * @param x 偏移量
+ * @return scale
+ */
+ private float parabola(float zero, float x) {
+ float f = (float) (1 - Math.pow(x / zero, 2));
+ return f < 0 ? 0 : f;
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ switch (event.getActionMasked()) {
+ case MotionEvent.ACTION_DOWN:
+ doDown(event);
+ break;
+ case MotionEvent.ACTION_MOVE:
+ doMove(event);
+ break;
+ case MotionEvent.ACTION_UP:
+ doUp(event);
+ break;
+ }
+ return true;
+ }
+
+ private void doDown(MotionEvent event) {
+ if (mTask != null) {
+ mTask.cancel();
+ mTask = null;
+ }
+ mLastDownY = event.getY();
+ }
+
+ private void doMove(MotionEvent event) {
+
+ mMoveLen += (event.getY() - mLastDownY);
+
+ if (mMoveLen > MARGIN_ALPHA * mMinTextSize / 2) {
+ // 往下滑超过离开距离
+ moveTailToHead();
+ mMoveLen = mMoveLen - MARGIN_ALPHA * mMinTextSize;
+ } else if (mMoveLen < -MARGIN_ALPHA * mMinTextSize / 2) {
+ // 往上滑超过离开距离
+ moveHeadToTail();
+ mMoveLen = mMoveLen + MARGIN_ALPHA * mMinTextSize;
+ }
+
+ mLastDownY = event.getY();
+ invalidate();
+ }
+
+ private void doUp(MotionEvent event) {
+ // 抬起手后mCurrentSelected的位置由当前位置move到中间选中位置
+ if (Math.abs(mMoveLen) < 0.0001) {
+ mMoveLen = 0;
+ return;
+ }
+ if (mTask != null) {
+ mTask.cancel();
+ mTask = null;
+ }
+ mTask = new MyTimerTask(updateHandler);
+ timer.schedule(mTask, 0, 10);
+ }
+
+ class MyTimerTask extends TimerTask {
+ Handler handler;
+
+ public MyTimerTask(Handler handler) {
+ this.handler = handler;
+ }
+
+ @Override
+ public void run() {
+ handler.sendMessage(handler.obtainMessage());
+ }
+
+ }
+
+ public interface onSelectListener {
+ void onSelect(String text);
+ }
+}
+
diff --git a/mvpsdk/src/main/java/com/share/mvpsdk/widgets/ProgressButton.java b/mvpsdk/src/main/java/com/share/mvpsdk/widgets/ProgressButton.java
new file mode 100644
index 0000000..7dbd39f
--- /dev/null
+++ b/mvpsdk/src/main/java/com/share/mvpsdk/widgets/ProgressButton.java
@@ -0,0 +1,79 @@
+package com.share.mvpsdk.widgets;
+
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Paint.Style;
+import android.graphics.RectF;
+import android.util.AttributeSet;
+import android.widget.Button;
+
+import com.share.mvpsdk.R;
+
+
+/**
+ * Created by Horrarndoo on 2017/4/5.
+ *
+ * 带有进度变化的button
+ */
+public class ProgressButton extends Button {
+ public static final int MAX_PROGRESS = 1000;
+ private boolean isAdding = false;
+ private int progress = 0;
+ private int progressStrokeWidth = 6;
+
+ private Paint mPaint;
+ private RectF dst;
+
+ private Context context;
+
+ public ProgressButton(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ dst = new RectF();
+ mPaint = new Paint();
+ mPaint.setAntiAlias(true);
+ mPaint.setStyle(Style.STROKE);
+ mPaint.setStrokeWidth(progressStrokeWidth);
+ this.context = context;
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+
+ int width = this.getWidth();
+ int height = this.getHeight();
+
+ if (width != height) {
+ int min = Math.min(width, height);
+ width = min;
+ height = min;
+ }
+
+ mPaint.setColor(context.getResources().getColor(R.color.dark_grey));
+ canvas.drawColor(Color.TRANSPARENT);
+
+ dst.left = progressStrokeWidth / 2; // 左上角x
+ dst.top = progressStrokeWidth / 2; // 左上角y
+ dst.right = width - progressStrokeWidth / 2; // 左下角x
+ dst.bottom = height - progressStrokeWidth / 2; // 右下角y
+
+ canvas.drawArc(dst, -90, 360, false, mPaint);
+
+ if (isAdding) {
+ mPaint.setColor(context.getResources().getColor(R.color.light_yellow));
+ canvas.drawArc(dst, -90, ((float) progress / MAX_PROGRESS) * 360, false, mPaint);
+ }
+ }
+
+ /**
+ * 非UI线程调用
+ */
+ public void setProgressNotInUiThread(int progress, boolean isAdding) {
+ this.isAdding = isAdding;
+ this.progress = progress;
+ this.postInvalidate();
+ }
+}
\ No newline at end of file
diff --git a/mvpsdk/src/main/java/com/share/mvpsdk/widgets/SlideSwitchView.java b/mvpsdk/src/main/java/com/share/mvpsdk/widgets/SlideSwitchView.java
new file mode 100644
index 0000000..cd956d4
--- /dev/null
+++ b/mvpsdk/src/main/java/com/share/mvpsdk/widgets/SlideSwitchView.java
@@ -0,0 +1,259 @@
+package com.share.mvpsdk.widgets;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.View;
+
+import com.share.mvpsdk.R;
+
+
+/**
+ * Created by Horrarndoo on 2017/6/1.
+ *
+ * 自定义滑动开关
+ *
+ * Android 的界面绘制流程
+ * 测量 摆放 绘制
+ * measure -> layout -> draw
+ * | | |
+ * onMeasure -> onLayout -> onDraw 重写这些方法, 实现自定义控件
+ *
+ * onResume()之后执行
+ *
+ * View
+ * onMeasure() (在这个方法里指定自己的宽高) -> onDraw() (绘制自己的内容)
+ *
+ * ViewGroup
+ * onMeasure() (指定自己的宽高, 所有子View的宽高)-> onLayout() (摆放所有子View) -> onDraw() (绘制内容)
+ */
+public class SlideSwitchView extends View {
+ private Bitmap slideButtonBitmap; // 滑块图片
+ private Paint mPaint; // 画笔
+ private float currentX; //当前滑动的x坐标
+ private int mBaseLineY; // text基准线
+ private String mTextContent; //text内容
+
+ public SlideSwitchView(Context context) {
+ this(context, null);
+ }
+
+ public SlideSwitchView(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public SlideSwitchView(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ initPaint();
+ TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.SlideSwitchView);
+ setSlideButtonResource(ta.getResourceId(R.styleable.SlideSwitchView_slide_button, -1));
+ setText(ta.getString(R.styleable.SlideSwitchView_android_text));
+ setTextSize(ta.getDimension(R.styleable.SlideSwitchView_android_textSize, 30));
+ setTextColor(ta.getColor(R.styleable.SlideSwitchView_android_textColor, Color.BLACK));
+ ta.recycle();
+ }
+
+ /**
+ * 初始化画笔
+ */
+ private void initPaint() {
+ mPaint = new Paint();
+ mPaint.setStyle(Paint.Style.FILL);
+ mPaint.setTextAlign(Paint.Align.LEFT);
+ mPaint.setAntiAlias(true);
+ }
+
+ /**
+ * 初始化text居中基准线
+ */
+ private void initTextBaseLine() {
+ Paint.FontMetrics fontMetrics = mPaint.getFontMetrics();
+ float top = fontMetrics.top;//为基线到字体上边框的距离,即上图中的top
+ float bottom = fontMetrics.bottom;//为基线到字体下边框的距离,即上图中的bottom
+ mBaseLineY = (int) (getMeasuredHeight() / 2 - top / 2 - bottom / 2);//基线中间点的y轴计算公式
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ int widthMode = MeasureSpec.getMode(widthMeasureSpec);
+ int heightMode = MeasureSpec.getMode(heightMeasureSpec);
+ int width = MeasureSpec.getSize(widthMeasureSpec);
+ int height = MeasureSpec.getSize(heightMeasureSpec);
+
+ if (widthMode == MeasureSpec.AT_MOST) {
+ int newWidth = (int) (slideButtonBitmap.getWidth() * 2 + getTextWidth());
+ if (width >= newWidth)
+ width = newWidth;
+ }
+
+ if (heightMode == MeasureSpec.EXACTLY) {
+ if (height < slideButtonBitmap.getHeight()) {
+ // 获得图片的宽高
+ int widthSlide = slideButtonBitmap.getWidth();
+ int heightSlide = slideButtonBitmap.getHeight();
+ float scaleHeight = height * 1.0f / slideButtonBitmap.getHeight();
+ Matrix matrix = new Matrix();
+ matrix.postScale(scaleHeight, scaleHeight);
+ slideButtonBitmap = Bitmap.createBitmap(slideButtonBitmap, 0, 0, widthSlide,
+ heightSlide, matrix, true);
+ invalidate();
+ }
+ }
+
+ if (slideButtonBitmap.getWidth() > (width - getTextWidth()) / 2) {
+ // 获得图片的宽高
+ int widthSlide = slideButtonBitmap.getWidth();
+ int heightSlide = slideButtonBitmap.getHeight();
+ float scaleWidth = (width - getTextWidth()) / 2 / slideButtonBitmap.getWidth();
+ Matrix matrix = new Matrix();
+ matrix.postScale(scaleWidth, scaleWidth);
+ slideButtonBitmap = Bitmap.createBitmap(slideButtonBitmap, 0, 0, widthSlide,
+ heightSlide, matrix, true);
+ invalidate();
+ }
+
+ setMeasuredDimension(width, slideButtonBitmap.getHeight());
+ initTextBaseLine();
+ }
+
+ // Canvas 画布, 画板. 在上边绘制的内容都会显示到界面上.
+ @Override
+ protected void onDraw(Canvas canvas) {
+ // 1. 绘制text
+ canvas.drawText(mTextContent, slideButtonBitmap.getWidth(), mBaseLineY, mPaint);
+
+ // 2. 绘制滑块
+ if (isTouchMode) {
+ // 根据当前用户触摸到的位置画滑块
+ // 让滑块向左移动自身一半大小的位置
+ float newLeft = currentX - slideButtonBitmap.getWidth() / 2.0f;
+
+ int maxLeft = getMeasuredWidth() - slideButtonBitmap.getWidth();
+
+ // 限定滑块范围
+ if (newLeft < 0) {
+ newLeft = 0; // 左边范围
+ } else if (newLeft > maxLeft) {
+ newLeft = maxLeft; // 右边范围
+ }
+
+ canvas.drawBitmap(slideButtonBitmap, newLeft, 0, mPaint);
+ } else {
+ //还原button位置
+ canvas.drawBitmap(slideButtonBitmap, 0, 0, mPaint);
+ }
+
+ }
+
+ boolean isTouchMode = false;
+ private OnSwitchStateUpdateListener onSwitchStateUpdateListener;
+
+ // 重写触摸事件, 响应用户的触摸.
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+
+ switch (event.getAction()) {
+ case MotionEvent.ACTION_DOWN:
+ isTouchMode = true;
+ currentX = event.getX();
+ break;
+ case MotionEvent.ACTION_MOVE:
+ currentX = event.getX();
+ break;
+ case MotionEvent.ACTION_UP:
+ isTouchMode = false;
+ currentX = event.getX();
+
+ float center = getMeasuredWidth() / 2.0f;
+
+ // 根据当前按下的位置, 和控件中心的位置进行比较.
+ boolean isStateChanged = currentX > center;
+
+ // 如果开关状态变化了, 通知界面
+ if (isStateChanged && onSwitchStateUpdateListener != null) {
+ onSwitchStateUpdateListener.onStateUpdate();
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ // 重绘界面
+ invalidate(); // 会引发onDraw()被调用, 里边的变量会重新生效.界面会更新
+
+ return true; // 消费了用户的触摸事件, 才可以收到其他的事件.
+ }
+
+ /**
+ * 设置滑块图片资源
+ *
+ * @param slideButton 滑块图片资源
+ */
+ public void setSlideButtonResource(int slideButton) {
+ slideButtonBitmap = BitmapFactory.decodeResource(getResources(), slideButton);
+ }
+
+ /**
+ * 设置text字号大小
+ *
+ * @param textSize text字号大小
+ */
+ public void setTextSize(float textSize) {
+ mPaint.setTextSize(textSize);
+ mPaint.setStrokeWidth(textSize / 15.f);
+ }
+
+ /**
+ * 设置text内容
+ *
+ * @param text text内容
+ */
+ public void setText(String text) {
+ mTextContent = text;
+ }
+
+ /**
+ * 设置text颜色
+ *
+ * @param color text颜色资源
+ */
+ public void setTextColor(int color) {
+ mPaint.setColor(color);
+ }
+
+ /**
+ * 获取text文字宽度
+ *
+ * @return text文字宽度
+ */
+ private float getTextWidth() {
+ return mPaint.measureText(mTextContent);
+ }
+
+ /**
+ * 获取text文字高度
+ *
+ * @return text文字高度
+ */
+ private float getTextHeight() {
+ return mPaint.getFontMetrics().bottom - mPaint.getFontMetrics().top;
+ }
+
+ public interface OnSwitchStateUpdateListener {
+ // 状态回调
+ void onStateUpdate();
+ }
+
+ public void setOnSwitchStateUpdateListener(
+ OnSwitchStateUpdateListener onSwitchStateUpdateListener) {
+ this.onSwitchStateUpdateListener = onSwitchStateUpdateListener;
+ }
+}
\ No newline at end of file
diff --git a/mvpsdk/src/main/java/com/share/mvpsdk/widgets/WaitPorgressDialog.java b/mvpsdk/src/main/java/com/share/mvpsdk/widgets/WaitPorgressDialog.java
new file mode 100644
index 0000000..86e5d19
--- /dev/null
+++ b/mvpsdk/src/main/java/com/share/mvpsdk/widgets/WaitPorgressDialog.java
@@ -0,0 +1,22 @@
+package com.share.mvpsdk.widgets;
+
+import android.app.ProgressDialog;
+import android.content.Context;
+
+/**
+ * Created by Horrarndoo on 2017/4/17.
+ *
+ * 等待提示dialog
+ */
+
+public class WaitPorgressDialog extends ProgressDialog {
+
+ public WaitPorgressDialog(Context context) {
+ this(context, 0);
+ }
+
+ public WaitPorgressDialog(Context context, int theme) {
+ super(context, theme);
+ setCanceledOnTouchOutside(false);
+ }
+}
diff --git a/mvpsdk/src/main/java/com/share/mvpsdk/widgets/headclip/ClipView.java b/mvpsdk/src/main/java/com/share/mvpsdk/widgets/headclip/ClipView.java
new file mode 100644
index 0000000..d7762c7
--- /dev/null
+++ b/mvpsdk/src/main/java/com/share/mvpsdk/widgets/headclip/ClipView.java
@@ -0,0 +1,157 @@
+package com.share.mvpsdk.widgets.headclip;
+
+/**
+ * Created by Horrarndoo on 2017/9/25.
+ *
+ */
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffXfermode;
+import android.graphics.Rect;
+import android.graphics.Xfermode;
+import android.util.AttributeSet;
+import android.util.DisplayMetrics;
+import android.view.View;
+import android.view.WindowManager;
+
+/**
+ * 头像上传裁剪框
+ */
+public class ClipView extends View {
+ private Paint paint = new Paint();
+ //画裁剪区域边框的画笔
+ private Paint borderPaint = new Paint();
+ //裁剪框水平方向间距
+ private float mHorizontalPadding;
+ //裁剪框边框宽度
+ private int clipBorderWidth;
+ //裁剪圆框的半径
+ private int clipRadiusWidth;
+ //裁剪框矩形宽度
+ private int clipWidth;
+ //裁剪框类别,(圆形、矩形),默认为圆形
+ private ClipType clipType = ClipType.CIRCLE;
+ private Xfermode xfermode;
+
+ public ClipView(Context context) {
+ this(context, null);
+ }
+
+ public ClipView(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public ClipView(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ //去锯齿
+ paint.setAntiAlias(true);
+ borderPaint.setStyle(Paint.Style.STROKE);
+ borderPaint.setColor(Color.WHITE);
+ borderPaint.setStrokeWidth(clipBorderWidth);
+ borderPaint.setAntiAlias(true);
+ xfermode = new PorterDuffXfermode(PorterDuff.Mode.DST_OUT);
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+ int LAYER_FLAGS = Canvas.MATRIX_SAVE_FLAG | Canvas.CLIP_SAVE_FLAG
+ | Canvas.HAS_ALPHA_LAYER_SAVE_FLAG | Canvas.FULL_COLOR_LAYER_SAVE_FLAG
+ | Canvas.CLIP_TO_LAYER_SAVE_FLAG;
+ //通过Xfermode的DST_OUT来产生中间的透明裁剪区域,一定要另起一个Layer(层)
+ canvas.saveLayer(0, 0, this.getWidth(), this.getHeight(), null, LAYER_FLAGS);
+ //设置背景
+ canvas.drawColor(Color.parseColor("#a8000000"));
+ paint.setXfermode(xfermode);
+ //绘制圆形裁剪框
+ if (clipType == ClipType.CIRCLE) {
+ //中间的透明的圆
+ canvas.drawCircle(this.getWidth() / 2, this.getHeight() / 2, clipRadiusWidth, paint);
+ //白色的圆边框
+ canvas.drawCircle(this.getWidth() / 2, this.getHeight() / 2, clipRadiusWidth, borderPaint);
+ } else if (clipType == ClipType.RECTANGLE) { //绘制矩形裁剪框
+ //绘制中间的矩形
+ canvas.drawRect(mHorizontalPadding, this.getHeight() / 2 - clipWidth / 2,
+ this.getWidth() - mHorizontalPadding, this.getHeight() / 2 + clipWidth / 2, paint);
+ //绘制白色的矩形边框
+ canvas.drawRect(mHorizontalPadding, this.getHeight() / 2 - clipWidth / 2,
+ this.getWidth() - mHorizontalPadding, this.getHeight() / 2 + clipWidth / 2, borderPaint);
+ }
+ //出栈,恢复到之前的图层,意味着新建的图层会被删除,新建图层上的内容会被绘制到canvas (or the previous layer)
+ canvas.restore();
+ }
+
+ /**
+ * 获取裁剪区域的Rect
+ *
+ * @return
+ */
+ public Rect getClipRect() {
+ Rect rect = new Rect();
+ //宽度的一半 - 圆的半径
+ rect.left = (this.getWidth() / 2 - clipRadiusWidth);
+ //宽度的一半 + 圆的半径
+ rect.right = (this.getWidth() / 2 + clipRadiusWidth);
+ //高度的一半 - 圆的半径
+ rect.top = (this.getHeight() / 2 - clipRadiusWidth);
+ //高度的一半 + 圆的半径
+ rect.bottom = (this.getHeight() / 2 + clipRadiusWidth);
+ return rect;
+ }
+
+ /**
+ * 设置裁剪框边框宽度
+ *
+ * @param clipBorderWidth
+ */
+ public void setClipBorderWidth(int clipBorderWidth) {
+ this.clipBorderWidth = clipBorderWidth;
+ borderPaint.setStrokeWidth(clipBorderWidth);
+ invalidate();
+ }
+
+ /**
+ * 设置裁剪框水平间距
+ *
+ * @param mHorizontalPadding
+ */
+ public void setmHorizontalPadding(float mHorizontalPadding) {
+ this.mHorizontalPadding = mHorizontalPadding;
+ this.clipRadiusWidth = (int) (getScreenWidth(getContext()) - 2 * mHorizontalPadding) / 2;
+ this.clipWidth = clipRadiusWidth * 2;
+ }
+
+ /**
+ * 获得屏幕高度
+ *
+ * @param context
+ * @return
+ */
+ public static int getScreenWidth(Context context) {
+ WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
+ DisplayMetrics outMetrics = new DisplayMetrics();
+ wm.getDefaultDisplay().getMetrics(outMetrics);
+ return outMetrics.widthPixels;
+ }
+
+
+ /**
+ * 设置裁剪框类别
+ *
+ * @param clipType
+ */
+ public void setClipType(ClipType clipType) {
+ this.clipType = clipType;
+ }
+
+ /**
+ * 裁剪框类别,圆形、矩形
+ */
+ public enum ClipType {
+ CIRCLE, RECTANGLE
+ }
+}
\ No newline at end of file
diff --git a/mvpsdk/src/main/java/com/share/mvpsdk/widgets/headclip/ClipViewLayout.java b/mvpsdk/src/main/java/com/share/mvpsdk/widgets/headclip/ClipViewLayout.java
new file mode 100644
index 0000000..5126345
--- /dev/null
+++ b/mvpsdk/src/main/java/com/share/mvpsdk/widgets/headclip/ClipViewLayout.java
@@ -0,0 +1,485 @@
+package com.share.mvpsdk.widgets.headclip;
+
+/**
+ * Created by Horrarndoo on 2017/9/25.
+ *
+ */
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Matrix;
+import android.graphics.PointF;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.graphics.drawable.Drawable;
+import android.media.ExifInterface;
+import android.net.Uri;
+import android.text.TextUtils;
+import android.util.AttributeSet;
+import android.util.TypedValue;
+import android.view.MotionEvent;
+import android.view.ViewTreeObserver;
+import android.widget.ImageView;
+import android.widget.RelativeLayout;
+
+
+import com.share.mvpsdk.R;
+import com.share.mvpsdk.utils.LogUtils;
+
+import java.io.IOException;
+
+import static com.share.mvpsdk.utils.FileUtils.getRealFilePathFromUri;
+
+
+/**
+ * 头像上传原图裁剪容器
+ */
+public class ClipViewLayout extends RelativeLayout {
+ //裁剪原图
+ private ImageView imageView;
+ //裁剪框
+ private ClipView clipView;
+ //裁剪框水平方向间距,xml布局文件中指定
+ private float mHorizontalPadding;
+ //裁剪框垂直方向间距,计算得出
+ private float mVerticalPadding;
+ //图片缩放、移动操作矩阵
+ private Matrix matrix = new Matrix();
+ //图片原来已经缩放、移动过的操作矩阵
+ private Matrix savedMatrix = new Matrix();
+ //动作标志:无
+ private static final int NONE = 0;
+ //动作标志:拖动
+ private static final int DRAG = 1;
+ //动作标志:缩放
+ private static final int ZOOM = 2;
+ //初始化动作标志
+ private int mode = NONE;
+ //记录起始坐标
+ private PointF start = new PointF();
+ //记录缩放时两指中间点坐标
+ private PointF mid = new PointF();
+ private float oldDist = 1f;
+ //用于存放矩阵的9个值
+ private final float[] matrixValues = new float[9];
+ //最小缩放比例
+ private float minScale;
+ //最大缩放比例
+ private float maxScale = 4;
+
+
+ public ClipViewLayout(Context context) {
+ this(context, null);
+ }
+
+ public ClipViewLayout(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public ClipViewLayout(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ init(context, attrs);
+ }
+
+ //初始化控件自定义的属性
+ public void init(Context context, AttributeSet attrs) {
+ TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.ClipViewLayout);
+
+ //获取剪切框距离左右的边距, 默认为50dp
+ mHorizontalPadding = array.getDimensionPixelSize(R.styleable.ClipViewLayout_mHorizontalPadding,
+ (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 50, getResources().getDisplayMetrics()));
+ //获取裁剪框边框宽度,默认1dp
+ int clipBorderWidth = array.getDimensionPixelSize(R.styleable.ClipViewLayout_clipBorderWidth,
+ (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 1, getResources().getDisplayMetrics()));
+ //裁剪框类型(圆或者矩形)
+ int clipType = array.getInt(R.styleable.ClipViewLayout_clipType, 1);
+
+ //回收
+ array.recycle();
+ clipView = new ClipView(context);
+ //设置裁剪框类型
+ clipView.setClipType(clipType == 1 ? ClipView.ClipType.CIRCLE : ClipView.ClipType.RECTANGLE);
+ //设置剪切框边框
+ clipView.setClipBorderWidth(clipBorderWidth);
+ //设置剪切框水平间距
+ clipView.setmHorizontalPadding(mHorizontalPadding);
+ imageView = new ImageView(context);
+ //相对布局布局参数
+ android.view.ViewGroup.LayoutParams lp = new LayoutParams(
+ android.view.ViewGroup.LayoutParams.MATCH_PARENT,
+ android.view.ViewGroup.LayoutParams.MATCH_PARENT);
+ this.addView(imageView, lp);
+ this.addView(clipView, lp);
+ }
+
+
+ /**
+ * 初始化图片
+ */
+ public void setImageSrc(final Uri uri) {
+ //需要等到imageView绘制完毕再初始化原图
+ ViewTreeObserver observer = imageView.getViewTreeObserver();
+ observer.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
+ public void onGlobalLayout() {
+ initSrcPic(uri);
+ imageView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
+ }
+ });
+ }
+
+ /**
+ * 初始化图片
+ * step 1: decode 出 720*1280 左右的照片 因为原图可能比较大 直接加载出来会OOM
+ * step 2: 将图片缩放 移动到imageView 中间
+ */
+ public void initSrcPic(Uri uri) {
+ if (uri == null) {
+ return;
+ }
+ LogUtils.d("**********clip_view uri******* " + uri);
+ String path = getRealFilePathFromUri(getContext(), uri);
+ LogUtils.d("**********clip_view path******* " + path);
+ if (TextUtils.isEmpty(path)) {
+ return;
+ }
+
+ //这里decode出720*1280 左右的照片,防止OOM
+ Bitmap bitmap = decodeSampledBitmap(path, 720, 1280);
+ if (bitmap == null) {
+ return;
+ }
+
+ //竖屏拍照的照片,直接使用的话,会旋转90度,下面代码把角度旋转过来
+ int rotation = getExifOrientation(path); //查询旋转角度
+ Matrix m = new Matrix();
+ m.setRotate(rotation);
+ bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), m, true);
+
+ //图片的缩放比
+ float scale;
+ if (bitmap.getWidth() >= bitmap.getHeight()) {//宽图
+ scale = (float) imageView.getWidth() / bitmap.getWidth();
+ //如果高缩放后小于裁剪区域 则将裁剪区域与高的缩放比作为最终的缩放比
+ Rect rect = clipView.getClipRect();
+ //高的最小缩放比
+ minScale = rect.height() / (float) bitmap.getHeight();
+ if (scale < minScale) {
+ scale = minScale;
+ }
+ } else {//高图
+ //高的缩放比
+ scale = (float) imageView.getHeight() / bitmap.getHeight();
+ //如果宽缩放后小于裁剪区域 则将裁剪区域与宽的缩放比作为最终的缩放比
+ Rect rect = clipView.getClipRect();
+ //宽的最小缩放比
+ minScale = rect.width() / (float) bitmap.getWidth();
+ if (scale < minScale) {
+ scale = minScale;
+ }
+ }
+ // 缩放
+ matrix.postScale(scale, scale);
+ // 平移,将缩放后的图片平移到imageview的中心
+ //imageView的中心x
+ int midX = imageView.getWidth() / 2;
+ //imageView的中心y
+ int midY = imageView.getHeight() / 2;
+ //bitmap的中心x
+ int imageMidX = (int) (bitmap.getWidth() * scale / 2);
+ //bitmap的中心y
+ int imageMidY = (int) (bitmap.getHeight() * scale / 2);
+ matrix.postTranslate(midX - imageMidX, midY - imageMidY);
+ imageView.setScaleType(ImageView.ScaleType.MATRIX);
+ imageView.setImageMatrix(matrix);
+ imageView.setImageBitmap(bitmap);
+ }
+
+ /**
+ * 查询图片旋转角度
+ */
+ public static int getExifOrientation(String filepath) {// YOUR MEDIA PATH AS STRING
+ int degree = 0;
+ ExifInterface exif = null;
+ try {
+ exif = new ExifInterface(filepath);
+ } catch (IOException ex) {
+ ex.printStackTrace();
+ }
+ if (exif != null) {
+ int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, -1);
+ if (orientation != -1) {
+ switch (orientation) {
+ case ExifInterface.ORIENTATION_ROTATE_90:
+ degree = 90;
+ break;
+ case ExifInterface.ORIENTATION_ROTATE_180:
+ degree = 180;
+ break;
+ case ExifInterface.ORIENTATION_ROTATE_270:
+ degree = 270;
+ break;
+ }
+
+ }
+ }
+ return degree;
+ }
+
+
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ switch (event.getAction() & MotionEvent.ACTION_MASK) {
+ case MotionEvent.ACTION_DOWN:
+ savedMatrix.set(matrix);
+ //设置开始点位置
+ start.set(event.getX(), event.getY());
+ mode = DRAG;
+ break;
+ case MotionEvent.ACTION_POINTER_DOWN:
+ //开始放下时候两手指间的距离
+ oldDist = spacing(event);
+ if (oldDist > 10f) {
+ savedMatrix.set(matrix);
+ midPoint(mid, event);
+ mode = ZOOM;
+ }
+ break;
+ case MotionEvent.ACTION_UP:
+ break;
+ case MotionEvent.ACTION_POINTER_UP:
+ mode = NONE;
+ break;
+ case MotionEvent.ACTION_MOVE:
+ if (mode == DRAG) { //拖动
+ matrix.set(savedMatrix);
+ float dx = event.getX() - start.x;
+ float dy = event.getY() - start.y;
+ mVerticalPadding = clipView.getClipRect().top;
+ matrix.postTranslate(dx, dy);
+ //检查边界
+ checkBorder();
+ } else if (mode == ZOOM) { //缩放
+ //缩放后两手指间的距离
+ float newDist = spacing(event);
+ if (newDist > 10f) {
+ //手势缩放比例
+ float scale = newDist / oldDist;
+ if (scale < 1) { //缩小
+ if (getScale() > minScale) {
+ matrix.set(savedMatrix);
+ mVerticalPadding = clipView.getClipRect().top;
+ matrix.postScale(scale, scale, mid.x, mid.y);
+ //缩放到最小范围下面去了,则返回到最小范围大小
+ while (getScale() < minScale) {
+ //返回到最小范围的放大比例
+ scale = 1 + 0.01F;
+ matrix.postScale(scale, scale, mid.x, mid.y);
+ }
+ }
+ //边界检查
+ checkBorder();
+ } else { //放大
+ if (getScale() <= maxScale) {
+ matrix.set(savedMatrix);
+ mVerticalPadding = clipView.getClipRect().top;
+ matrix.postScale(scale, scale, mid.x, mid.y);
+ }
+ }
+ }
+ }
+ imageView.setImageMatrix(matrix);
+ break;
+ }
+ return true;
+ }
+
+ /**
+ * 根据当前图片的Matrix获得图片的范围
+ */
+ private RectF getMatrixRectF(Matrix matrix) {
+ RectF rect = new RectF();
+ Drawable d = imageView.getDrawable();
+ if (null != d) {
+ rect.set(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight());
+ matrix.mapRect(rect);
+ }
+ return rect;
+ }
+
+ /**
+ * 边界检测
+ */
+ private void checkBorder() {
+ RectF rect = getMatrixRectF(matrix);
+ float deltaX = 0;
+ float deltaY = 0;
+ int width = imageView.getWidth();
+ int height = imageView.getHeight();
+ // 如果宽或高大于屏幕,则控制范围 ; 这里的0.001是因为精度丢失会产生问题,但是误差一般很小,所以我们直接加了一个0.01
+ if (rect.width() >= width - 2 * mHorizontalPadding) {
+ if (rect.left > mHorizontalPadding) {
+ deltaX = -rect.left + mHorizontalPadding;
+ }
+ if (rect.right < width - mHorizontalPadding) {
+ deltaX = width - mHorizontalPadding - rect.right;
+ }
+ }
+ if (rect.height() >= height - 2 * mVerticalPadding) {
+ if (rect.top > mVerticalPadding) {
+ deltaY = -rect.top + mVerticalPadding;
+ }
+ if (rect.bottom < height - mVerticalPadding) {
+ deltaY = height - mVerticalPadding - rect.bottom;
+ }
+ }
+ matrix.postTranslate(deltaX, deltaY);
+ }
+
+ /**
+ * 获得当前的缩放比例
+ */
+ public final float getScale() {
+ matrix.getValues(matrixValues);
+ return matrixValues[Matrix.MSCALE_X];
+ }
+
+
+ /**
+ * 多点触控时,计算最先放下的两指距离
+ */
+ private float spacing(MotionEvent event) {
+ float x = event.getX(0) - event.getX(1);
+ float y = event.getY(0) - event.getY(1);
+ return (float) Math.sqrt(x * x + y * y);
+ }
+
+ /**
+ * 多点触控时,计算最先放下的两指中心坐标
+ */
+ private void midPoint(PointF point, MotionEvent event) {
+ float x = event.getX(0) + event.getX(1);
+ float y = event.getY(0) + event.getY(1);
+ point.set(x / 2, y / 2);
+ }
+
+
+ /**
+ * 获取剪切图
+ */
+ public Bitmap clip() {
+ imageView.setDrawingCacheEnabled(true);
+ imageView.buildDrawingCache();
+ Rect rect = clipView.getClipRect();
+ Bitmap cropBitmap = null;
+ Bitmap zoomedCropBitmap = null;
+ try {
+ cropBitmap = Bitmap.createBitmap(imageView.getDrawingCache(), rect.left, rect.top, rect.width(), rect.height());
+ zoomedCropBitmap = zoomBitmap(cropBitmap, 200, 200);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ if (cropBitmap != null) {
+ cropBitmap.recycle();
+ }
+ // 释放资源
+ imageView.destroyDrawingCache();
+ return zoomedCropBitmap;
+ }
+
+
+ /**
+ * 图片等比例压缩
+ *
+ * @param filePath
+ * @param reqWidth 期望的宽
+ * @param reqHeight 期望的高
+ * @return
+ */
+ public static Bitmap decodeSampledBitmap(String filePath, int reqWidth,
+ int reqHeight) {
+
+ // First decode with inJustDecodeBounds=true to check dimensions
+ final BitmapFactory.Options options = new BitmapFactory.Options();
+ options.inJustDecodeBounds = true;
+ options.inPreferredConfig = Bitmap.Config.RGB_565;
+ //bitmap is null
+ Bitmap bitmap = BitmapFactory.decodeFile(filePath, options);
+
+ // Calculate inSampleSize
+ options.inSampleSize = calculateInSampleSize(options, reqWidth,
+ reqHeight);
+
+ // Decode bitmap with inSampleSize set
+ options.inJustDecodeBounds = false;
+ return BitmapFactory.decodeFile(filePath, options);
+ }
+
+ /**
+ * 计算InSampleSize
+ * 宽的压缩比和高的压缩比的较小值 取接近的2的次幂的值
+ * 比如宽的压缩比是3 高的压缩比是5 取较小值3 而InSampleSize必须是2的次幂,取接近的2的次幂4
+ *
+ * @param options
+ * @param reqWidth
+ * @param reqHeight
+ * @return
+ */
+ public static int calculateInSampleSize(BitmapFactory.Options options,
+ int reqWidth, int reqHeight) {
+ // Raw height and width of image
+ final int height = options.outHeight;
+ final int width = options.outWidth;
+ int inSampleSize = 1;
+
+ if (height > reqHeight || width > reqWidth) {
+
+ // Calculate ratios of height and width to requested height and
+ // width
+ final int heightRatio = Math.round((float) height
+ / (float) reqHeight);
+ final int widthRatio = Math.round((float) width / (float) reqWidth);
+
+ // Choose the smallest ratio as inSampleSize value, this will
+ // guarantee
+ // a final image with both dimensions larger than or equal to the
+ // requested height and width.
+ int ratio = heightRatio < widthRatio ? heightRatio : widthRatio;
+ // inSampleSize只能是2的次幂 将ratio就近取2的次幂的值
+ if (ratio < 3)
+ inSampleSize = ratio;
+ else if (ratio < 6.5)
+ inSampleSize = 4;
+ else if (ratio < 8)
+ inSampleSize = 8;
+ else
+ inSampleSize = ratio;
+ }
+
+ return inSampleSize;
+ }
+
+ /**
+ * 图片缩放到指定宽高
+ *
+ * 非等比例压缩,图片会被拉伸
+ *
+ * @param bitmap 源位图对象
+ * @param w 要缩放的宽度
+ * @param h 要缩放的高度
+ * @return 新Bitmap对象
+ */
+ public static Bitmap zoomBitmap(Bitmap bitmap, int w, int h) {
+ int width = bitmap.getWidth();
+ int height = bitmap.getHeight();
+ Matrix matrix = new Matrix();
+ float scaleWidth = ((float) w / width);
+ float scaleHeight = ((float) h / height);
+ matrix.postScale(scaleWidth, scaleHeight);
+ Bitmap newBmp = Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, false);
+ return newBmp;
+ }
+
+
+}
\ No newline at end of file
diff --git a/mvpsdk/src/main/res/anim/activity_finish_trans_in.xml b/mvpsdk/src/main/res/anim/activity_finish_trans_in.xml
new file mode 100644
index 0000000..2bca8d2
--- /dev/null
+++ b/mvpsdk/src/main/res/anim/activity_finish_trans_in.xml
@@ -0,0 +1,11 @@
+
+
+
\ No newline at end of file
diff --git a/mvpsdk/src/main/res/anim/activity_finish_trans_out.xml b/mvpsdk/src/main/res/anim/activity_finish_trans_out.xml
new file mode 100644
index 0000000..d583d15
--- /dev/null
+++ b/mvpsdk/src/main/res/anim/activity_finish_trans_out.xml
@@ -0,0 +1,21 @@
+
+
+
+
\ No newline at end of file
diff --git a/mvpsdk/src/main/res/anim/activity_finish_zoom_in.xml b/mvpsdk/src/main/res/anim/activity_finish_zoom_in.xml
new file mode 100644
index 0000000..d89e6f2
--- /dev/null
+++ b/mvpsdk/src/main/res/anim/activity_finish_zoom_in.xml
@@ -0,0 +1,12 @@
+
+
+
+
\ No newline at end of file
diff --git a/mvpsdk/src/main/res/anim/activity_finish_zoom_out.xml b/mvpsdk/src/main/res/anim/activity_finish_zoom_out.xml
new file mode 100644
index 0000000..7aee74c
--- /dev/null
+++ b/mvpsdk/src/main/res/anim/activity_finish_zoom_out.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mvpsdk/src/main/res/anim/activity_start_trans_in.xml b/mvpsdk/src/main/res/anim/activity_start_trans_in.xml
new file mode 100644
index 0000000..3f414b1
--- /dev/null
+++ b/mvpsdk/src/main/res/anim/activity_start_trans_in.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/mvpsdk/src/main/res/anim/activity_start_trans_out.xml b/mvpsdk/src/main/res/anim/activity_start_trans_out.xml
new file mode 100644
index 0000000..22d8ccb
--- /dev/null
+++ b/mvpsdk/src/main/res/anim/activity_start_trans_out.xml
@@ -0,0 +1,11 @@
+
+
+
\ No newline at end of file
diff --git a/mvpsdk/src/main/res/anim/activity_start_zoom_in.xml b/mvpsdk/src/main/res/anim/activity_start_zoom_in.xml
new file mode 100644
index 0000000..53be488
--- /dev/null
+++ b/mvpsdk/src/main/res/anim/activity_start_zoom_in.xml
@@ -0,0 +1,12 @@
+
+
+
+
\ No newline at end of file
diff --git a/mvpsdk/src/main/res/anim/activity_start_zoom_out.xml b/mvpsdk/src/main/res/anim/activity_start_zoom_out.xml
new file mode 100644
index 0000000..b33cd1d
--- /dev/null
+++ b/mvpsdk/src/main/res/anim/activity_start_zoom_out.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mvpsdk/src/main/res/drawable/ic_vector_empty.xml b/mvpsdk/src/main/res/drawable/ic_vector_empty.xml
new file mode 100644
index 0000000..5537e7b
--- /dev/null
+++ b/mvpsdk/src/main/res/drawable/ic_vector_empty.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/mvpsdk/src/main/res/drawable/ic_vector_loading.xml b/mvpsdk/src/main/res/drawable/ic_vector_loading.xml
new file mode 100644
index 0000000..185a813
--- /dev/null
+++ b/mvpsdk/src/main/res/drawable/ic_vector_loading.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
diff --git a/mvpsdk/src/main/res/drawable/ic_vector_net_error.xml b/mvpsdk/src/main/res/drawable/ic_vector_net_error.xml
new file mode 100644
index 0000000..1e05a45
--- /dev/null
+++ b/mvpsdk/src/main/res/drawable/ic_vector_net_error.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
diff --git a/mvpsdk/src/main/res/drawable/indoor_temp.png b/mvpsdk/src/main/res/drawable/indoor_temp.png
new file mode 100644
index 0000000..7057fb6
Binary files /dev/null and b/mvpsdk/src/main/res/drawable/indoor_temp.png differ
diff --git a/mvpsdk/src/main/res/drawable/item_touch_bg.xml b/mvpsdk/src/main/res/drawable/item_touch_bg.xml
new file mode 100644
index 0000000..00ea33d
--- /dev/null
+++ b/mvpsdk/src/main/res/drawable/item_touch_bg.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/mvpsdk/src/main/res/drawable/stackblur_default.png b/mvpsdk/src/main/res/drawable/stackblur_default.png
new file mode 100644
index 0000000..f182b41
Binary files /dev/null and b/mvpsdk/src/main/res/drawable/stackblur_default.png differ
diff --git a/mvpsdk/src/main/res/drawable/week_normal.png b/mvpsdk/src/main/res/drawable/week_normal.png
new file mode 100644
index 0000000..0a5dd1e
Binary files /dev/null and b/mvpsdk/src/main/res/drawable/week_normal.png differ
diff --git a/mvpsdk/src/main/res/drawable/week_selector.png b/mvpsdk/src/main/res/drawable/week_selector.png
new file mode 100644
index 0000000..5903030
Binary files /dev/null and b/mvpsdk/src/main/res/drawable/week_selector.png differ
diff --git a/mvpsdk/src/main/res/drawable/week_status.xml b/mvpsdk/src/main/res/drawable/week_status.xml
new file mode 100644
index 0000000..3d3a16c
--- /dev/null
+++ b/mvpsdk/src/main/res/drawable/week_status.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mvpsdk/src/main/res/drawable/week_tv_status.xml b/mvpsdk/src/main/res/drawable/week_tv_status.xml
new file mode 100644
index 0000000..2f631f3
--- /dev/null
+++ b/mvpsdk/src/main/res/drawable/week_tv_status.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mvpsdk/src/main/res/layout/sub_history_click_view.xml b/mvpsdk/src/main/res/layout/sub_history_click_view.xml
new file mode 100644
index 0000000..18dc813
--- /dev/null
+++ b/mvpsdk/src/main/res/layout/sub_history_click_view.xml
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mvpsdk/src/main/res/layout/sub_history_tips.xml b/mvpsdk/src/main/res/layout/sub_history_tips.xml
new file mode 100644
index 0000000..e46deda
--- /dev/null
+++ b/mvpsdk/src/main/res/layout/sub_history_tips.xml
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mvpsdk/src/main/res/layout/view_empty.xml b/mvpsdk/src/main/res/layout/view_empty.xml
new file mode 100644
index 0000000..030fdb3
--- /dev/null
+++ b/mvpsdk/src/main/res/layout/view_empty.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mvpsdk/src/main/res/layout/view_loading.xml b/mvpsdk/src/main/res/layout/view_loading.xml
new file mode 100644
index 0000000..54760be
--- /dev/null
+++ b/mvpsdk/src/main/res/layout/view_loading.xml
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mvpsdk/src/main/res/layout/view_network_error.xml b/mvpsdk/src/main/res/layout/view_network_error.xml
new file mode 100644
index 0000000..77e6790
--- /dev/null
+++ b/mvpsdk/src/main/res/layout/view_network_error.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mvpsdk/src/main/res/mipmap-xhdpi/ic_arrow_back_white.png b/mvpsdk/src/main/res/mipmap-xhdpi/ic_arrow_back_white.png
new file mode 100644
index 0000000..8214d9d
Binary files /dev/null and b/mvpsdk/src/main/res/mipmap-xhdpi/ic_arrow_back_white.png differ
diff --git a/mvpsdk/src/main/res/mipmap-xxhdpi/ic_arrow_back_white.png b/mvpsdk/src/main/res/mipmap-xxhdpi/ic_arrow_back_white.png
new file mode 100644
index 0000000..0e43ff9
Binary files /dev/null and b/mvpsdk/src/main/res/mipmap-xxhdpi/ic_arrow_back_white.png differ
diff --git a/mvpsdk/src/main/res/values-v21/styles.xml b/mvpsdk/src/main/res/values-v21/styles.xml
new file mode 100644
index 0000000..52975c6
--- /dev/null
+++ b/mvpsdk/src/main/res/values-v21/styles.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
diff --git a/mvpsdk/src/main/res/values-zh-rCN/strings.xml b/mvpsdk/src/main/res/values-zh-rCN/strings.xml
new file mode 100644
index 0000000..bd06b22
--- /dev/null
+++ b/mvpsdk/src/main/res/values-zh-rCN/strings.xml
@@ -0,0 +1,38 @@
+
+ 确定
+ 取消
+ 正在加载中……
+ 加载失败,请点我重试
+ 再按一次退出
+
+
+ 天
+ 周
+ 月
+ 年
+ 室内
+ 温度
+ 目标
+ 加热
+ 时间
+ (天)
+ (小时)
+ (月)
+ (℃)
+ (%)
+
+
+ (分)
+ (小时)
+ (小时)
+ (小时)
+ (天)
+ (天)
+ (千瓦/时)
+ 天
+ 周
+ 月
+
+ 网络异常,点击重试
+ 没有数据,点击重试
+
diff --git a/mvpsdk/src/main/res/values/arrays.xml b/mvpsdk/src/main/res/values/arrays.xml
new file mode 100644
index 0000000..c40d7cd
--- /dev/null
+++ b/mvpsdk/src/main/res/values/arrays.xml
@@ -0,0 +1,24 @@
+
+
+
+ - @string/permission_recode_audio_hint
+ - @string/permission_get_accounts_hint
+ - @string/permission_read_phone_hint
+ - @string/permission_call_phone_hint
+ - @string/permission_camera_hint
+ - @string/permission_access_fine_location_hint
+ - @string/permission_access_coarse_location_hint
+ - @string/permission_read_external_hint
+ - @string/permission_white_external_hint
+
+ 没有此权限,无法开启这个功能,请开启权限。PERMISSION_GET_ACCOUNTS
+ 没有此权限,无法开启这个功能,请开启权限。PERMISSION_READ_PHONE_STATE
+ 没有此权限,无法开启这个功能,请开启权限。PERMISSION_CALL_PHONE
+ 没有此权限,无法开启这个功能,请开启权限。PERMISSION_CAMERA
+ 没有此权限,无法开启这个功能,请开启权限。PERMISSION_ACCESS_FINE_LOCATION
+ 没有此权限,无法开启这个功能,请开启权限。PERMISSION_ACCESS_COARSE_LOCATION
+ 没有此权限,无法开启这个功能,请开启权限。PERMISSION_READ_EXTERNAL_STORAGE
+ 没有此权限,无法开启这个功能,请开启权限。PERMISSION_WRITE_EXTERNAL_STORAGE
+ 没有此权限,无法开启这个功能,请开启权限。PERMISSION_RECORD_AUDIO
+
+
\ No newline at end of file
diff --git a/mvpsdk/src/main/res/values/attrs.xml b/mvpsdk/src/main/res/values/attrs.xml
new file mode 100644
index 0000000..cd76c60
--- /dev/null
+++ b/mvpsdk/src/main/res/values/attrs.xml
@@ -0,0 +1,81 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mvpsdk/src/main/res/values/colors.xml b/mvpsdk/src/main/res/values/colors.xml
new file mode 100644
index 0000000..488c181
--- /dev/null
+++ b/mvpsdk/src/main/res/values/colors.xml
@@ -0,0 +1,76 @@
+
+
+
+
+ #ffeeeeee
+
+ #ffeeeeee
+ #ff303030
+ #b3ffffff
+ #de000000
+ #ffe0e0e0
+ #ff666666
+ @android:color/white
+ #ffeeeeee
+ #ffcccccc
+ #ff3c3c3c
+ #ff444444
+ #ff666666
+
+ #212121
+
+ #808080
+
+ #CCCCCC
+
+ #f1f1f1
+
+ #e8e8e8
+
+ #d54c1c
+
+ #cbcbcb
+
+ #1ea5ff
+
+
+ #C7C7C7
+
+
+ #ffffff
+ #cccccc
+
+ #8BC34A
+ #808080
+
+ #88888888
+ #f1f1f1
+ #8BC34A
+
+
+ #0D8BC34A
+ #1A8BC34A
+ #8f000000
+
+ #FF9500
+ #808080
+ #333333
+
+ #80FF9500
+
+ #808080
+ #FF9500
+ #ffffff
+ #4a2317
+ #AAAAAA
+
+ #88000000
+ #88000000
+ #707070
+
+ #F0F0F0
+ #48495F
+
+
+ #FB5B81
+
diff --git a/mvpsdk/src/main/res/values/dimens.xml b/mvpsdk/src/main/res/values/dimens.xml
new file mode 100644
index 0000000..7b556b6
--- /dev/null
+++ b/mvpsdk/src/main/res/values/dimens.xml
@@ -0,0 +1,45 @@
+
+
+
+ 16dp
+ 16dp
+
+
+ 4dp
+ 8dp
+ 16dp
+ 32dp
+ 64dp
+ 48dp
+
+
+ 34sp
+ 24sp
+ 20sp
+ 16sp
+ 14sp
+ 12sp
+
+
+ 2dp
+ 136dp
+
+ 50dp
+ 50dp
+ 6dp
+
+ 0.66dp
+ 4dp
+ 10dp
+ 14dp
+ 22dp
+ 36dp
+ 40dp
+ 60dp
+ 72dp
+
+ 12sp
+ 14sp
+ 16sp
+ 18sp
+
\ No newline at end of file
diff --git a/mvpsdk/src/main/res/values/strings.xml b/mvpsdk/src/main/res/values/strings.xml
new file mode 100644
index 0000000..b98c96e
--- /dev/null
+++ b/mvpsdk/src/main/res/values/strings.xml
@@ -0,0 +1,38 @@
+
+ Confirm
+ Cancel
+ Loading……
+ Load failed. Please click me again
+ Press again to exit
+
+
+ Day
+ Week
+ Month
+ Year
+ Indoor
+ Temp
+ Setpoint
+ Cumulative
+ Time
+ (DAY)
+ (HOUR)
+ (MONTH)
+ (℃)
+ (%)
+
+
+ (min)
+ (hour)
+ (hour)
+ (hour)
+ (day)
+ (day)
+ (KW/H)
+ DAY
+ WEEK
+ MONTH
+
+ Network error, Click Retry
+ There is no data, Click Retry
+
diff --git a/mvpsdk/src/main/res/values/styles.xml b/mvpsdk/src/main/res/values/styles.xml
new file mode 100644
index 0000000..31fbc40
--- /dev/null
+++ b/mvpsdk/src/main/res/values/styles.xml
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mvpsdk/src/main/res/values/themes.xml b/mvpsdk/src/main/res/values/themes.xml
new file mode 100644
index 0000000..4445fc8
--- /dev/null
+++ b/mvpsdk/src/main/res/values/themes.xml
@@ -0,0 +1,265 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mvpsdk/src/main/res/values/themes_colors.xml b/mvpsdk/src/main/res/values/themes_colors.xml
new file mode 100644
index 0000000..d5c000c
--- /dev/null
+++ b/mvpsdk/src/main/res/values/themes_colors.xml
@@ -0,0 +1,85 @@
+
+
+
+ #e51c23
+ #d01716
+
+
+ #e91e63
+ #c2185b
+
+
+ #9c27b0
+ #7b1fa2
+
+
+ #673ab7
+ #512da8
+
+
+ #3f51b5
+ #303f9f
+
+
+ #5677fc
+ #455ede
+
+
+ #03a9f4
+ #0288d1
+
+
+ #00bcd4
+ #0097a7
+
+
+ #009688
+ #00796b
+
+
+ #259b24
+ #0a7e07
+
+
+
+ #8bc34a
+ #689f38
+
+
+ #cddc39
+ #afb42b
+
+
+ #ffeb3b
+ #fbc02d
+
+
+ #ffc107
+ #ffa000
+
+
+ #ff9800
+ #f57c00
+
+
+ #ff5722
+ #e64a19
+
+
+ #795548
+ #5d4037
+
+
+ #9e9e9e
+ #616161
+
+
+ #ffffff
+
+
+ #607d8b
+ #455a64
+
+ #03a9f4
+ #ff3c3c3c
+
\ No newline at end of file
diff --git a/mvpsdk/src/test/java/com/share/mvpsdk/ExampleUnitTest.java b/mvpsdk/src/test/java/com/share/mvpsdk/ExampleUnitTest.java
new file mode 100644
index 0000000..b538286
--- /dev/null
+++ b/mvpsdk/src/test/java/com/share/mvpsdk/ExampleUnitTest.java
@@ -0,0 +1,17 @@
+package com.share.mvpsdk;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * @see Testing documentation
+ */
+public class ExampleUnitTest {
+ @Test
+ public void addition_isCorrect() throws Exception {
+ assertEquals(4, 2 + 2);
+ }
+}
\ No newline at end of file
diff --git a/settings.gradle b/settings.gradle
new file mode 100644
index 0000000..670125b
--- /dev/null
+++ b/settings.gradle
@@ -0,0 +1 @@
+include ':app', ':mvpsdk'
--
libgit2 0.21.0